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.
6 * DECnet Routing Forwarding Information Base
8 * Author: Steve Whitehouse <SteveW@ACM.org>
12 * Alexey Kuznetsov : SMP locking changes
15 #include <linux/config.h>
16 #include <linux/string.h>
17 #include <linux/net.h>
18 #include <linux/socket.h>
19 #include <linux/sockios.h>
20 #include <linux/init.h>
21 #include <linux/skbuff.h>
22 #include <linux/netlink.h>
23 #include <linux/rtnetlink.h>
24 #include <linux/proc_fs.h>
25 #include <linux/netdevice.h>
26 #include <linux/timer.h>
27 #include <linux/spinlock.h>
28 #include <asm/atomic.h>
29 #include <asm/uaccess.h>
30 #include <net/neighbour.h>
33 #include <net/dn_fib.h>
34 #include <net/dn_neigh.h>
35 #include <net/dn_dev.h>
38 * N.B. Some of the functions here should really be inlines, but
39 * I'll sort out that when its all working properly, for now the
40 * stack frames will be useful for debugging.
42 #define DN_NUM_TABLES 255
43 #define DN_MIN_TABLE 1
47 #ifdef CONFIG_RTNETLINK
48 static int dn_fib_table_dump(struct dn_fib_table
*t
, struct sk_buff
*skb
, struct netlink_callback
*cb
);
49 static void dn_rtmsg_fib(int event
, int table
, struct dn_fib_action
*fa
, struct nlmsghdr
*nlh
, struct netlink_skb_parms
*req
);
50 extern int dn_cache_dump(struct sk_buff
*skb
, struct netlink_callback
*cb
);
51 #endif /* CONFIG_RTNETLINK */
53 static void dn_fib_del_tree(struct dn_fib_table
*t
);
55 static struct dn_fib_table
*dn_fib_tables
[DN_NUM_TABLES
+ 1];
56 static int dn_fib_allocs
= 0;
57 static int dn_fib_actions
= 0;
59 static struct dn_fib_node
*dn_fib_alloc(void)
61 struct dn_fib_node
*fn
;
63 fn
= kmalloc(sizeof(struct dn_fib_node
), GFP_KERNEL
);
66 memset(fn
, 0, sizeof(struct dn_fib_node
));
74 static __inline__
void dn_fib_free(struct dn_fib_node
*fn
)
76 kfree_s(fn
, sizeof(struct dn_fib_node
));
80 static struct dn_fib_action
*dn_fib_new_action(void)
82 struct dn_fib_action
*fa
;
84 fa
= kmalloc(sizeof(struct dn_fib_action
), GFP_KERNEL
);
87 memset(fa
, 0, sizeof(struct dn_fib_action
));
94 static __inline__
void dn_fib_del_action(struct dn_fib_action
*fa
)
96 if ((fa
->fa_type
== RTN_UNICAST
) && fa
->fa_neigh
)
97 neigh_release(fa
->fa_neigh
);
99 kfree_s(fa
, sizeof(struct dn_fib_action
));
103 static struct dn_fib_node
*dn_fib_follow(struct dn_fib_node
*fn
, dn_address key
)
105 while(fn
->fn_action
== NULL
)
106 fn
= DN_FIB_NEXT(fn
, key
);
112 static struct dn_fib_node
*dn_fib_follow1(struct dn_fib_node
*fn
, dn_address key
)
114 while((fn
->fn_action
== NULL
) && (((key
^ fn
->fn_key
) >> fn
->fn_shift
) == 0))
115 fn
= DN_FIB_NEXT(fn
, key
);
121 static int dn_fib_table_insert1(struct dn_fib_table
*t
, struct dn_fib_node
*leaf
)
123 struct dn_fib_node
*fn
, *fn1
, *fn2
;
126 dn_address cmpmask
= 1;
134 fn1
= dn_fib_follow1(t
->root
, leaf
->fn_key
);
137 if (fn1
->fn_key
== leaf
->fn_key
)
140 if ((fn
= dn_fib_alloc()) == NULL
)
143 fn
->fn_key
= leaf
->fn_key
;
144 match
= fn1
->fn_key
^ fn
->fn_key
;
152 fn
->fn_cmpmask
= cmpmask
;
153 fn
->fn_shift
= shift
;
156 DN_FIB_NEXT(fn2
, fn
->fn_key
) = fn
;
163 DN_FIB_NEXT(fn
, fn1
->fn_key
) = fn1
;
164 DN_FIB_NEXT(fn
, leaf
->fn_key
) = leaf
;
169 static __inline__
int dn_maskcmp(dn_address m1
, dn_address m2
)
186 static int dn_fib_table_insert(struct dn_fib_table
*t
, struct dn_fib_action
*fa
)
188 struct dn_fib_node
*fn
;
189 struct dn_fib_action
**fap
;
193 if (t
->root
&& ((fn
= dn_fib_follow(t
->root
, fa
->fa_key
)) != NULL
) &&
194 (fn
->fn_key
== fa
->fa_key
))
197 if ((fn
= dn_fib_alloc()) == NULL
)
200 fn
->fn_key
= fa
->fa_key
;
203 if ((err
= dn_fib_table_insert1(t
, fn
)) < 0)
206 #ifdef CONFIG_RTNETLINK
208 dn_rtmsg_fib(RTM_NEWROUTE
, t
->n
, fa
, NULL
, NULL
);
209 #endif /* CONFIG_RTNETLINK */
214 fap
= &fn
->fn_action
;
216 for(; *fap
; fap
= &((*fap
)->fa_next
)) {
217 if ((cmp
= dn_maskcmp((*fap
)->fa_mask
, fa
->fa_mask
)) > 0)
221 if ((*fap
)->fa_cost
> fa
->fa_cost
)
228 #ifdef CONFIG_RTNETLINK
229 dn_rtmsg_fib(RTM_NEWROUTE
, t
->n
, fa
, NULL
, NULL
);
230 #endif /* CONFIG_RTNETLINK */
235 static int dn_fib_table_delete1(struct dn_fib_table
*t
, struct dn_fib_node
*fn
)
237 struct dn_fib_node
*fn1
= fn
->fn_up
;
238 struct dn_fib_node
*fn2
;
239 struct dn_fib_node
*fn3
;
251 fn3
= DN_FIB_NEXT(fn1
, ~fn
->fn_key
);
254 DN_FIB_NEXT(fn2
, fn1
->fn_key
) = fn3
;
265 static int dn_fib_table_delete(struct dn_fib_table
*t
, struct dn_fib_action
*fa
)
267 struct dn_fib_res res
;
268 struct dn_fib_node
*fn
;
269 struct dn_fib_action
**fap
, *old
;
273 res
.res_addr
= fa
->fa_key
;
274 res
.res_mask
= fa
->fa_mask
;
275 res
.res_ifindex
= fa
->fa_ifindex
;
276 res
.res_proto
= fa
->fa_proto
;
277 res
.res_cost
= fa
->fa_cost
;
279 if ((err
= t
->lookup(t
, &res
)) < 0)
283 fap
= &fn
->fn_action
;
284 while((*fap
) != res
.res_fa
)
285 fap
= &((*fap
)->fa_next
);
287 *fap
= (*fap
)->fa_next
;
289 if (fn
->fn_action
== NULL
)
290 dn_fib_table_delete1(t
, fn
);
295 #ifdef CONFIG_RTNETLINK
296 dn_rtmsg_fib(RTM_DELROUTE
, t
->n
, old
, NULL
, NULL
);
297 #endif /* CONFIG_RTNETLINK */
299 dn_fib_del_action(old
);
304 static int dn_fib_search(struct dn_fib_node
*fn
, struct dn_fib_res
*res
)
306 struct dn_fib_action
*fa
= fn
->fn_action
;
308 for(; fa
; fa
= fa
->fa_next
) {
309 if ((fa
->fa_key
^ res
->res_addr
) & fa
->fa_mask
)
311 if (res
->res_ifindex
&& (res
->res_ifindex
!= fa
->fa_ifindex
))
313 if (res
->res_mask
&& (res
->res_mask
!= fa
->fa_mask
))
315 if (res
->res_proto
&& (res
->res_proto
!= fa
->fa_proto
))
317 if (res
->res_cost
&& (res
->res_cost
!= fa
->fa_cost
))
328 static int dn_fib_recurse(struct dn_fib_node
*fn
, struct dn_fib_res
*res
)
330 struct dn_fib_node
*fn1
;
333 fn1
= dn_fib_follow(fn
, res
->res_addr
);
335 if (dn_fib_search(fn1
, res
))
338 while((fn1
= fn1
->fn_up
) != fn
)
339 if ((err
= dn_fib_recurse(DN_FIB_NEXT(fn1
, ~res
->res_addr
), res
)) == 0)
345 static int dn_fib_table_lookup(struct dn_fib_table
*t
, struct dn_fib_res
*res
)
347 struct dn_fib_node
*fn
= t
->root
;
353 fn
= dn_fib_follow(t
->root
, res
->res_addr
);
355 if (dn_fib_search(fn
, res
))
358 while((fn
= fn
->fn_up
) != NULL
)
359 if ((err
= dn_fib_recurse(DN_FIB_NEXT(fn
, ~res
->res_addr
), res
)) == 0)
365 static int dn_fib_table_walk_recurse(struct dn_fib_walker_t
*fwt
, struct dn_fib_node
*fn
)
367 struct dn_fib_table
*t
= fwt
->table
;
372 dn_fib_table_walk_recurse(fwt
, t
->root
->fn_children
[0]);
373 dn_fib_table_walk_recurse(fwt
, t
->root
->fn_children
[1]);
379 static int dn_fib_table_walk(struct dn_fib_walker_t
*fwt
)
381 struct dn_fib_table
*t
= fwt
->table
;
383 if (t
->root
!= NULL
) {
384 if (t
->root
->fn_action
) {
385 fwt
->fxn(fwt
, t
->root
);
387 dn_fib_table_walk_recurse(fwt
, t
->root
->fn_children
[0]);
388 dn_fib_table_walk_recurse(fwt
, t
->root
->fn_children
[1]);
395 static struct dn_fib_table
*dn_fib_get_tree(int n
, int create
)
397 struct dn_fib_table
*t
;
399 if (n
< DN_MIN_TABLE
)
402 if (n
> DN_NUM_TABLES
)
405 if (dn_fib_tables
[n
])
406 return dn_fib_tables
[n
];
411 if ((t
= kmalloc(sizeof(struct dn_fib_table
), GFP_KERNEL
)) == NULL
)
414 dn_fib_tables
[n
] = t
;
415 memset(t
, 0, sizeof(struct dn_fib_table
));
418 t
->insert
= dn_fib_table_insert
;
419 t
->delete = dn_fib_table_delete
;
420 t
->lookup
= dn_fib_table_lookup
;
421 t
->walk
= dn_fib_table_walk
;
422 #ifdef CONFIG_RTNETLINK
423 t
->dump
= dn_fib_table_dump
;
429 static void dn_fib_del_tree(struct dn_fib_table
*t
)
431 dn_fib_tables
[t
->n
] = NULL
;
434 kfree_s(t
, sizeof(struct dn_fib_table
));
439 int dn_fib_resolve(struct dn_fib_res
*res
)
441 int table
= DN_L1_TABLE
;
443 struct dn_fib_action
*fa
;
446 if ((res
->res_addr
^ dn_ntohs(decnet_address
)) & 0xfc00)
450 struct dn_fib_table
*t
= dn_fib_get_tree(table
, 0);
455 if ((err
= t
->lookup(t
, res
)) < 0)
458 if ((fa
= res
->res_fa
) == NULL
)
461 if (fa
->fa_type
!= RTN_THROW
)
464 table
= fa
->fa_table
;
466 if (count
++ > DN_NUM_TABLES
)
470 switch(fa
->fa_type
) {
472 case RTN_UNREACHABLE
:
473 return -fa
->fa_error
;
480 * Punt to user via netlink for example, but for now
483 int dn_fib_rt_message(struct sk_buff
*skb
)
491 #ifdef CONFIG_RTNETLINK
492 static int dn_fib_convert_rtm(struct dn_fib_action
*fa
,
493 struct rtmsg
*r
, struct rtattr
**rta
,
495 struct netlink_skb_parms
*req
)
497 dn_address dst
, gw
, mask
= 0xffff;
499 struct neighbour
*neigh
;
500 struct net_device
*dev
;
501 unsigned char addr
[ETH_ALEN
];
503 if (r
->rtm_family
!= AF_DECnet
)
507 memcpy(&dst
, RTA_DATA(rta
[RTA_DST
-1]), 2);
510 memcpy(&ifindex
, RTA_DATA(rta
[RTA_OIF
-1]), sizeof(int));
512 if (rta
[RTA_GATEWAY
-1])
513 memcpy(&gw
, RTA_DATA(rta
[RTA_GATEWAY
-1]), 2);
515 fa
->fa_key
= dn_ntohs(dst
);
516 fa
->fa_mask
= dn_ntohs(mask
);
517 fa
->fa_ifindex
= ifindex
;
518 fa
->fa_proto
= r
->rtm_protocol
;
519 fa
->fa_type
= r
->rtm_type
;
521 switch(fa
->fa_type
) {
523 if ((dev
= __dev_get_by_index(ifindex
)) == NULL
)
525 dn_dn2eth(addr
, dn_ntohs(gw
));
526 if ((neigh
= __neigh_lookup(&dn_neigh_table
, &addr
, dev
, 1)) == NULL
)
527 return -EHOSTUNREACH
;
528 fa
->fa_neigh
= neigh
;
534 fa
->fa_error
= EPERM
;
536 case RTN_UNREACHABLE
:
537 fa
->fa_error
= EHOSTUNREACH
;
540 fa
->fa_error
= EINVAL
;
547 static int dn_fib_check_attr(struct rtmsg
*r
, struct rtattr
**rta
)
549 switch(r
->rtm_type
) {
553 case RTN_UNREACHABLE
:
563 int dn_fib_rtm_delroute(struct sk_buff
*skb
, struct nlmsghdr
*nlh
, void *arg
)
565 struct dn_fib_table
*t
;
566 struct rtattr
**rta
= arg
;
567 struct rtmsg
*r
= NLMSG_DATA(nlh
);
568 struct dn_fib_action
*fa
;
571 if (dn_fib_check_attr(r
, rta
))
574 if ((fa
= dn_fib_new_action()) == NULL
)
577 t
= dn_fib_get_tree(r
->rtm_table
, 0);
579 if ((err
= dn_fib_convert_rtm(fa
, r
, rta
, nlh
, &NETLINK_CB(skb
))) < 0) {
580 dn_fib_del_action(fa
);
583 err
= t
->delete(t
, fa
);
584 dn_fib_del_action(fa
);
590 int dn_fib_rtm_newroute(struct sk_buff
*skb
, struct nlmsghdr
*nlh
, void *arg
)
592 struct dn_fib_table
*t
;
593 struct rtattr
**rta
= arg
;
594 struct rtmsg
*r
= NLMSG_DATA(nlh
);
595 struct dn_fib_action
*fa
;
598 if (dn_fib_check_attr(r
, rta
))
601 if ((fa
= dn_fib_new_action()) == NULL
)
604 t
= dn_fib_get_tree(r
->rtm_table
, 1);
606 if ((err
= dn_fib_convert_rtm(fa
, r
, rta
, nlh
, &NETLINK_CB(skb
))) < 0) {
607 dn_fib_del_action(fa
);
610 return t
->insert(t
, fa
);
615 int dn_fib_dump_info(struct sk_buff
*skb
, u32 pid
, u32 seq
, int event
,
616 int table
, struct dn_fib_action
*fa
)
619 struct nlmsghdr
*nlh
;
620 unsigned char *b
= skb
->tail
;
622 nlh
= NLMSG_PUT(skb
, pid
, seq
, event
, sizeof(*rtm
));
623 rtm
= NLMSG_DATA(nlh
);
624 rtm
->rtm_family
= AF_DECnet
;
625 rtm
->rtm_dst_len
= 16;
626 rtm
->rtm_src_len
= 16;
628 rtm
->rtm_table
= table
;
629 rtm
->rtm_type
= fa
->fa_type
;
631 rtm
->rtm_protocol
= fa
->fa_proto
;
632 RTA_PUT(skb
, RTA_DST
, 2, &fa
->fa_key
);
634 RTA_PUT(skb
, RTA_OIF
, sizeof(int), &fa
->fa_ifindex
);
636 nlh
->nlmsg_len
= skb
->tail
- b
;
641 skb_trim(skb
, b
- skb
->data
);
645 static void dn_rtmsg_fib(int event
, int table
, struct dn_fib_action
*fa
,
646 struct nlmsghdr
*nlh
, struct netlink_skb_parms
*req
)
649 u32 pid
= req
? req
->pid
: 0;
650 int size
= NLMSG_SPACE(sizeof(struct rtmsg
) + 256);
652 skb
= alloc_skb(size
, GFP_KERNEL
);
656 if (dn_fib_dump_info(skb
, pid
, nlh
->nlmsg_seq
, event
, table
, fa
) < 0) {
660 NETLINK_CB(skb
).dst_groups
= RTMGRP_DECnet_ROUTE
;
661 if (nlh
->nlmsg_flags
& NLM_F_ECHO
)
662 atomic_inc(&skb
->users
);
663 netlink_broadcast(rtnl
, skb
, pid
, RTMGRP_DECnet_ROUTE
, GFP_KERNEL
);
664 if (nlh
->nlmsg_flags
& NLM_F_ECHO
)
665 netlink_unicast(rtnl
, skb
, pid
, MSG_DONTWAIT
);
668 static int dn_fib_table_dump(struct dn_fib_table
*t
, struct sk_buff
*skb
, struct netlink_callback
*cb
)
674 int dn_fib_dump(struct sk_buff
*skb
, struct netlink_callback
*cb
)
678 struct dn_fib_table
*tb
;
680 if (NLMSG_PAYLOAD(cb
->nlh
, 0) >= sizeof(struct rtmsg
) &&
681 ((struct rtmsg
*)NLMSG_DATA(cb
->nlh
))->rtm_flags
&RTM_F_CLONED
)
682 return dn_cache_dump(skb
, cb
);
686 s_t
= cb
->args
[0] = DN_MIN_TABLE
;
688 for(t
= s_t
; t
< DN_NUM_TABLES
; t
++) {
692 memset(&cb
->args
[1], 0, sizeof(cb
->args
)-sizeof(int));
693 tb
= dn_fib_get_tree(t
, 0);
696 if (tb
->dump(tb
, skb
, cb
) < 0)
704 #endif /* CONFIG_RTNETLINK */
706 int dn_fib_ioctl(struct socket
*sock
, unsigned int cmd
, unsigned long arg
)
709 if (!capable(CAP_NET_ADMIN
))
721 #ifdef CONFIG_PROC_FS
723 struct dn_fib_procfs
{
732 static int dn_proc_action_list(struct dn_fib_walker_t
*fwt
, struct dn_fib_node
*fn
)
734 struct dn_fib_procfs
*pinfo
= (struct dn_fib_procfs
*)fwt
->arg
;
735 struct dn_fib_action
*fa
;
736 char ab
[DN_ASCBUF_LEN
];
738 if (pinfo
->pos
> pinfo
->offset
+ pinfo
->length
)
741 for(fa
= fn
->fn_action
; fa
; fa
= fa
->fa_next
) {
743 pinfo
->len
+= sprintf(pinfo
->buffer
+ pinfo
->len
,
744 "%s/%04hx %02x %02x\n",
745 dn_addr2asc(fa
->fa_key
, ab
),
750 pinfo
->pos
= pinfo
->begin
+ pinfo
->len
;
751 if (pinfo
->pos
< pinfo
->offset
) {
753 pinfo
->begin
= pinfo
->pos
;
755 if (pinfo
->pos
> pinfo
->offset
+ pinfo
->length
)
762 static int decnet_rt_get_info(char *buffer
, char **start
, off_t offset
, int length
, int dummy
)
764 struct dn_fib_procfs pinfo
;
766 struct dn_fib_table
*t
;
767 struct dn_fib_walker_t fwt
;
772 pinfo
.offset
= offset
;
773 pinfo
.length
= length
;
774 pinfo
.buffer
= buffer
;
777 fwt
.fxn
= dn_proc_action_list
;
780 for(i
= 0; i
< DN_NUM_TABLES
; i
++) {
781 if ((t
= dn_fib_get_tree(i
, 0)) == NULL
)
787 if (pinfo
.pos
> pinfo
.offset
+ pinfo
.length
)
792 *start
= pinfo
.buffer
+ (pinfo
.offset
- pinfo
.begin
);
793 pinfo
.len
-= (pinfo
.offset
- pinfo
.begin
);
795 if (pinfo
.len
> pinfo
.length
)
796 pinfo
.len
= pinfo
.length
;
801 static struct proc_dir_entry proc_net_decnet_route
= {
802 PROC_NET_DN_ROUTE
, 12, "decnet_route",
803 S_IFREG
| S_IRUGO
, 1, 0, 0,
804 0, &proc_net_inode_operations
,
808 #endif /* CONFIG_PROC_FS */
810 #ifdef CONFIG_DECNET_MODULE
811 void dn_fib_cleanup(void)
813 #ifdef CONFIG_PROC_FS
814 proc_net_unregister(PROC_NET_DN_ROUTE
);
815 #endif /* CONFIG_PROC_FS */
817 #endif /* CONFIG_DECNET_MODULE */
820 void __init
dn_fib_init(void)
822 memset(dn_fib_tables
, 0, DN_NUM_TABLES
* sizeof(struct dn_fib_table
*));
824 #ifdef CONFIG_PROC_FS
825 proc_net_register(&proc_net_decnet_route
);