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 Neighbour Functions (Adjacency Database and
9 * Author: Steve Whitehouse <SteveW@ACM.org>
13 * Steve Whitehouse : Fixed router listing routine
14 * Steve Whitehouse : Added error_report functions
15 * Steve Whitehouse : Added default router detection
16 * Steve Whitehouse : Hop counts in outgoing messages
17 * Steve Whitehouse : Fixed src/dst in outgoing messages so
18 * forwarding now stands a good chance of
20 * Steve Whitehouse : Fixed neighbour states (for now anyway).
24 #include <linux/config.h>
25 #include <linux/net.h>
26 #include <linux/socket.h>
27 #include <linux/if_arp.h>
28 #include <linux/if_ether.h>
29 #include <linux/init.h>
30 #include <linux/proc_fs.h>
31 #include <linux/string.h>
32 #include <linux/netfilter_decnet.h>
33 #include <linux/spinlock.h>
34 #include <asm/atomic.h>
35 #include <net/neighbour.h>
38 #include <net/dn_dev.h>
39 #include <net/dn_neigh.h>
40 #include <net/dn_route.h>
42 static u32
dn_neigh_hash(const void *pkey
, const struct net_device
*dev
);
43 static int dn_neigh_construct(struct neighbour
*);
44 static void dn_long_error_report(struct neighbour
*, struct sk_buff
*);
45 static void dn_short_error_report(struct neighbour
*, struct sk_buff
*);
46 static int dn_long_output(struct sk_buff
*);
47 static int dn_short_output(struct sk_buff
*);
48 static int dn_phase3_output(struct sk_buff
*);
52 * For talking to broadcast devices: Ethernet & PPP
54 static struct neigh_ops dn_long_ops
= {
66 * For talking to pointopoint and multidrop devices: DDCMP and X.25
68 static struct neigh_ops dn_short_ops
= {
72 dn_short_error_report
,
80 * For talking to DECnet phase III nodes
82 static struct neigh_ops dn_phase3_ops
= {
86 dn_short_error_report
, /* Can use short version here */
93 struct neigh_table dn_neigh_table
= {
96 sizeof(struct dn_neigh
),
100 NULL
, /* pconstructor */
101 NULL
, /* pdestructor */
102 NULL
, /* proxyredo */
111 30 * HZ
, /* base_reachable_time */
112 1 * HZ
, /* retrans_time */
113 60 * HZ
, /* gc_staletime */
114 30 * HZ
, /* reachable_time */
115 5 * HZ
, /* delay_probe_time */
117 0, /* ucast_probes */
119 0, /* mcast_probes */
120 0, /* anycast_delay */
123 1 * HZ
, /* locktime */
125 30 * HZ
, /* gc_interval */
126 128, /* gc_thresh1 */
127 512, /* gc_thresh2 */
128 1024, /* gc_thresh3 */
132 static u32
dn_neigh_hash(const void *pkey
, const struct net_device
*dev
)
136 hash_val
= *(dn_address
*)pkey
;
137 hash_val
^= (hash_val
>> 10);
138 hash_val
^= (hash_val
>> 3);
140 return hash_val
& NEIGH_HASHMASK
;
143 static int dn_neigh_construct(struct neighbour
*neigh
)
145 struct net_device
*dev
= neigh
->dev
;
146 struct dn_neigh
*dn
= (struct dn_neigh
*)neigh
;
147 struct dn_dev
*dn_db
= (struct dn_dev
*)dev
->dn_ptr
;
152 if (dn_db
->neigh_parms
)
153 neigh
->parms
= dn_db
->neigh_parms
;
156 neigh
->ops
= &dn_long_ops
;
158 neigh
->ops
= &dn_short_ops
;
160 if (dn
->flags
& DN_NDFLAG_P3
)
161 neigh
->ops
= &dn_phase3_ops
;
163 neigh
->nud_state
= NUD_NOARP
;
164 neigh
->output
= neigh
->ops
->connected_output
;
166 if ((dev
->type
== ARPHRD_IPGRE
) || (dev
->flags
& IFF_POINTOPOINT
))
167 memcpy(neigh
->ha
, dev
->broadcast
, dev
->addr_len
);
168 else if ((dev
->type
== ARPHRD_ETHER
) || (dev
->type
== ARPHRD_LOOPBACK
))
169 dn_dn2eth(neigh
->ha
, dn
->addr
);
172 printk(KERN_DEBUG
"Trying to create neigh for hw %d\n", dev
->type
);
181 static void dn_long_error_report(struct neighbour
*neigh
, struct sk_buff
*skb
)
183 struct dn_skb_cb
*cb
= (struct dn_skb_cb
*)skb
->cb
;
186 printk(KERN_DEBUG
"dn_long_error_report: called\n");
188 if (!(cb
->rt_flags
& DN_RT_F_RQR
)) {
193 skb_push(skb
, skb
->data
- skb
->nh
.raw
);
196 *(unsigned short *)ptr
= dn_htons(skb
->len
- 2);
199 if (*ptr
& DN_RT_F_PF
) {
200 char padlen
= (*ptr
& ~DN_RT_F_PF
);
204 *ptr
++ |= (cb
->rt_flags
& ~DN_RT_F_RQR
) | DN_RT_F_RTS
;
207 dn_dn2eth(ptr
, dn_ntohs(cb
->src
));
209 dn_dn2eth(ptr
, dn_ntohs(cb
->dst
));
213 skb
->dst
->neighbour
->ops
->queue_xmit(skb
);
217 static void dn_short_error_report(struct neighbour
*neigh
, struct sk_buff
*skb
)
219 struct dn_skb_cb
*cb
= (struct dn_skb_cb
*)skb
->cb
;
222 printk(KERN_DEBUG
"dn_short_error_report: called\n");
224 if (!(cb
->rt_flags
& DN_RT_F_RQR
)) {
229 skb_push(skb
, skb
->data
- skb
->nh
.raw
);
232 *(unsigned short *)ptr
= dn_htons(skb
->len
- 2);
234 *ptr
++ = (cb
->rt_flags
& ~DN_RT_F_RQR
) | DN_RT_F_RTS
;
236 *(dn_address
*)ptr
= cb
->src
;
238 *(dn_address
*)ptr
= cb
->dst
;
242 skb
->dst
->neighbour
->ops
->queue_xmit(skb
);
245 static int dn_neigh_output_packet(struct sk_buff
*skb
)
247 struct dst_entry
*dst
= skb
->dst
;
248 struct neighbour
*neigh
= dst
->neighbour
;
249 struct net_device
*dev
= neigh
->dev
;
251 if (!dev
->hard_header
|| dev
->hard_header(skb
, dev
, ntohs(skb
->protocol
), neigh
->ha
, NULL
, skb
->len
) >= 0)
252 return neigh
->ops
->queue_xmit(skb
);
255 printk(KERN_DEBUG
"dn_neigh_output_packet: oops, can't send packet\n");
261 static int dn_long_output(struct sk_buff
*skb
)
263 struct dst_entry
*dst
= skb
->dst
;
264 struct neighbour
*neigh
= dst
->neighbour
;
265 struct net_device
*dev
= neigh
->dev
;
266 int headroom
= dev
->hard_header_len
+ sizeof(struct dn_long_packet
) + 3;
268 struct dn_long_packet
*lp
;
269 struct dn_skb_cb
*cb
= (struct dn_skb_cb
*)skb
->cb
;
272 if (skb_headroom(skb
) < headroom
) {
273 struct sk_buff
*skb2
= skb_realloc_headroom(skb
, headroom
);
276 printk(KERN_CRIT
"dn_long_output: no memory\n");
283 printk(KERN_INFO
"dn_long_output: Increasing headroom\n");
286 data
= skb_push(skb
, sizeof(struct dn_long_packet
) + 3);
287 lp
= (struct dn_long_packet
*)(data
+3);
289 *((unsigned short *)data
) = dn_htons(skb
->len
- 2);
290 *(data
+ 2) = 1 | DN_RT_F_PF
; /* Padding */
292 lp
->msgflg
= DN_RT_PKT_LONG
|(cb
->rt_flags
&(DN_RT_F_IE
|DN_RT_F_RQR
|DN_RT_F_RTS
));
293 lp
->d_area
= lp
->d_subarea
= 0;
294 dn_dn2eth(lp
->d_id
, dn_ntohs(cb
->dst
));
295 lp
->s_area
= lp
->s_subarea
= 0;
296 dn_dn2eth(lp
->s_id
, dn_ntohs(cb
->src
));
298 lp
->visit_ct
= cb
->hops
& 0x3f;
302 skb
->nh
.raw
= skb
->data
;
304 return NF_HOOK(PF_DECnet
, NF_DN_POST_ROUTING
, skb
, NULL
, neigh
->dev
, dn_neigh_output_packet
);
307 static int dn_short_output(struct sk_buff
*skb
)
309 struct dst_entry
*dst
= skb
->dst
;
310 struct neighbour
*neigh
= dst
->neighbour
;
311 struct net_device
*dev
= neigh
->dev
;
312 int headroom
= dev
->hard_header_len
+ sizeof(struct dn_short_packet
) + 2;
313 struct dn_short_packet
*sp
;
315 struct dn_skb_cb
*cb
= (struct dn_skb_cb
*)skb
->cb
;
318 if (skb_headroom(skb
) < headroom
) {
319 struct sk_buff
*skb2
= skb_realloc_headroom(skb
, headroom
);
322 printk(KERN_CRIT
"dn_short_output: no memory\n");
329 printk(KERN_INFO
"dn_short_output: Increasing headroom\n");
332 data
= skb_push(skb
, sizeof(struct dn_short_packet
) + 2);
333 *((unsigned short *)data
) = dn_htons(skb
->len
- 2);
334 sp
= (struct dn_short_packet
*)(data
+2);
336 sp
->msgflg
= DN_RT_PKT_SHORT
|(cb
->rt_flags
&(DN_RT_F_RQR
|DN_RT_F_RTS
));
337 sp
->dstnode
= cb
->dst
;
338 sp
->srcnode
= cb
->src
;
339 sp
->forward
= cb
->hops
& 0x3f;
341 skb
->nh
.raw
= skb
->data
;
343 return NF_HOOK(PF_DECnet
, NF_DN_POST_ROUTING
, skb
, NULL
, neigh
->dev
, dn_neigh_output_packet
);
347 * Phase 3 output is the same is short output, execpt that
348 * it clears the area bits before transmission.
350 static int dn_phase3_output(struct sk_buff
*skb
)
352 struct dst_entry
*dst
= skb
->dst
;
353 struct neighbour
*neigh
= dst
->neighbour
;
354 struct net_device
*dev
= neigh
->dev
;
355 int headroom
= dev
->hard_header_len
+ sizeof(struct dn_short_packet
) + 2;
356 struct dn_short_packet
*sp
;
358 struct dn_skb_cb
*cb
= (struct dn_skb_cb
*)skb
->cb
;
360 if (skb_headroom(skb
) < headroom
) {
361 struct sk_buff
*skb2
= skb_realloc_headroom(skb
, headroom
);
364 printk(KERN_CRIT
"dn_phase3_output: no memory\n");
371 printk(KERN_INFO
"dn_phase3_output: Increasing headroom\n");
374 data
= skb_push(skb
, sizeof(struct dn_short_packet
) + 2);
375 ((unsigned short *)data
) = dn_htons(skb
->len
- 2);
376 sp
= (struct dn_short_packet
*)(data
+ 2);
378 sp
->msgflg
= DN_RT_PKT_SHORT
|(cb
->rt_flags
&(DN_RT_F_RQR
|DN_RT_F_RTS
));
379 sp
->dstnode
= cb
->dst
& dn_htons(0x03ff);
380 sp
->srcnode
= cb
->src
& dn_htons(0x03ff);
381 sp
->forward
= cb
->hops
& 0x3f;
383 skb
->nh
.raw
= skb
->data
;
385 return NF_HOOK(PF_DECnet
, NF_DN_POST_ROUTING
, skb
, NULL
, neigh
->dev
, dn_neigh_output_packet
);
389 * Unfortunately, the neighbour code uses the device in its hash
390 * function, so we don't get any advantage from it. This function
391 * basically does a neigh_lookup(), but without comparing the device
392 * field. This is required for the On-Ethernet cache
394 struct neighbour
*dn_neigh_lookup(struct neigh_table
*tbl
, void *ptr
)
396 struct neighbour
*neigh
;
399 hash_val
= tbl
->hash(ptr
, NULL
);
401 read_lock_bh(&tbl
->lock
);
402 for(neigh
= tbl
->hash_buckets
[hash_val
]; neigh
!= NULL
; neigh
= neigh
->next
) {
403 if (memcmp(neigh
->primary_key
, ptr
, tbl
->key_len
) == 0) {
404 atomic_inc(&neigh
->refcnt
);
405 read_unlock_bh(&tbl
->lock
);
409 read_unlock_bh(&tbl
->lock
);
416 * Any traffic on a pointopoint link causes the timer to be reset
417 * for the entry in the neighbour table.
419 void dn_neigh_pointopoint_notify(struct sk_buff
*skb
)
425 * Pointopoint link receives a hello message
427 void dn_neigh_pointopoint_hello(struct sk_buff
*skb
)
433 * Ethernet router hello message received
435 void dn_neigh_router_hello(struct sk_buff
*skb
)
437 struct rtnode_hello_message
*msg
= (struct rtnode_hello_message
*)skb
->data
;
439 struct neighbour
*neigh
;
441 struct dn_dev
*dn_db
;
444 src
= dn_eth2dn(msg
->id
);
446 neigh
= __neigh_lookup(&dn_neigh_table
, &src
, skb
->dev
, 1);
448 dn
= (struct dn_neigh
*)neigh
;
451 write_lock(&neigh
->lock
);
453 neigh
->used
= jiffies
;
454 dn_db
= (struct dn_dev
*)neigh
->dev
->dn_ptr
;
456 if (!(neigh
->nud_state
& NUD_PERMANENT
)) {
457 neigh
->updated
= jiffies
;
459 if (neigh
->dev
->type
== ARPHRD_ETHER
)
460 memcpy(neigh
->ha
, &skb
->mac
.ethernet
->h_source
, ETH_ALEN
);
462 dn
->blksize
= dn_ntohs(msg
->blksize
);
463 dn
->priority
= msg
->priority
;
465 dn
->flags
&= ~DN_NDFLAG_P3
;
467 switch(msg
->iinfo
& DN_RT_INFO_TYPE
) {
468 case DN_RT_INFO_L1RT
:
469 dn
->flags
&=~DN_NDFLAG_R2
;
470 dn
->flags
|= DN_NDFLAG_R1
;
472 case DN_RT_INFO_L2RT
:
473 dn
->flags
|= DN_NDFLAG_R2
;
477 if (!dn_db
->router
) {
478 dn_db
->router
= neigh_clone(neigh
);
480 if (msg
->priority
> ((struct dn_neigh
*)dn_db
->router
)->priority
)
481 neigh_release(xchg(&dn_db
->router
, neigh_clone(neigh
)));
483 write_unlock(&neigh
->lock
);
484 neigh_release(neigh
);
491 * Endnode hello message received
493 void dn_neigh_endnode_hello(struct sk_buff
*skb
)
495 struct endnode_hello_message
*msg
= (struct endnode_hello_message
*)skb
->data
;
496 struct neighbour
*neigh
;
500 src
= dn_eth2dn(msg
->id
);
502 neigh
= __neigh_lookup(&dn_neigh_table
, &src
, skb
->dev
, 1);
504 dn
= (struct dn_neigh
*)neigh
;
507 write_lock(&neigh
->lock
);
509 neigh
->used
= jiffies
;
511 if (!(neigh
->nud_state
& NUD_PERMANENT
)) {
512 neigh
->updated
= jiffies
;
514 if (neigh
->dev
->type
== ARPHRD_ETHER
)
515 memcpy(neigh
->ha
, &skb
->mac
.ethernet
->h_source
, ETH_ALEN
);
516 dn
->flags
&= ~(DN_NDFLAG_R1
| DN_NDFLAG_R2
);
517 dn
->blksize
= dn_ntohs(msg
->blksize
);
521 write_unlock(&neigh
->lock
);
522 neigh_release(neigh
);
529 #ifdef CONFIG_DECNET_ROUTER
530 static char *dn_find_slot(char *base
, int max
, int priority
)
533 unsigned char *min
= NULL
;
535 base
+= 6; /* skip first id */
537 for(i
= 0; i
< max
; i
++) {
538 if (!min
|| (*base
< *min
))
540 base
+= 7; /* find next priority */
546 return (*min
< priority
) ? (min
- 6) : NULL
;
549 int dn_neigh_elist(struct net_device
*dev
, unsigned char *ptr
, int n
)
553 struct neighbour
*neigh
;
555 struct neigh_table
*tbl
= &dn_neigh_table
;
556 unsigned char *rs
= ptr
;
558 read_lock_bh(&tbl
->lock
);
560 for(i
= 0; i
< NEIGH_HASHMASK
; i
++) {
561 for(neigh
= tbl
->hash_buckets
[i
]; neigh
!= NULL
; neigh
= neigh
->next
) {
562 if (neigh
->dev
!= dev
)
564 dn
= (struct dn_neigh
*)neigh
;
565 if (!(dn
->flags
& (DN_NDFLAG_R1
|DN_NDFLAG_R2
)))
567 if (decnet_node_type
== DN_RT_INFO_L1RT
&& (dn
->flags
& DN_NDFLAG_R2
))
570 rs
= dn_find_slot(ptr
, n
, dn
->priority
);
575 dn_dn2eth(rs
, dn
->addr
);
577 *rs
= neigh
->nud_state
& NUD_CONNECTED
? 0x80 : 0x0;
583 read_unlock_bh(&tbl
->lock
);
587 #endif /* CONFIG_DECNET_ROUTER */
591 #ifdef CONFIG_PROC_FS
592 int dn_neigh_get_info(char *buffer
, char **start
, off_t offset
, int length
, int dummy
)
599 char buf
[DN_ASCBUF_LEN
];
601 len
+= sprintf(buffer
+ len
, "Addr Flags State Use Blksize Dev\n");
603 for(i
=0;i
<= NEIGH_HASHMASK
; i
++) {
604 read_lock_bh(&dn_neigh_table
.lock
);
605 n
= dn_neigh_table
.hash_buckets
[i
];
606 for(; n
!= NULL
; n
= n
->next
) {
607 struct dn_neigh
*dn
= (struct dn_neigh
*)n
;
610 len
+= sprintf(buffer
+len
, "%-7s %s%s%s %02x %02d %07ld %-8s\n",
611 dn_addr2asc(dn_ntohs(dn
->addr
), buf
),
612 (dn
->flags
&DN_NDFLAG_R1
) ? "1" : "-",
613 (dn
->flags
&DN_NDFLAG_R2
) ? "2" : "-",
614 (dn
->flags
&DN_NDFLAG_P3
) ? "3" : "-",
616 atomic_read(&dn
->n
.refcnt
),
618 (dn
->n
.dev
) ? dn
->n
.dev
->name
: "?");
619 read_unlock(&n
->lock
);
628 if (pos
> offset
+ length
) {
629 read_unlock_bh(&dn_neigh_table
.lock
);
633 read_unlock_bh(&dn_neigh_table
.lock
);
638 *start
= buffer
+ (offset
- begin
);
639 len
-= offset
- begin
;
641 if (len
> length
) len
= length
;
646 static struct proc_dir_entry proc_net_dn_neigh
= {
647 PROC_NET_DN_ADJ
, 12, "decnet_neigh",
648 S_IFREG
| S_IRUGO
, 1, 0, 0,
649 0, &proc_net_inode_operations
,
655 void __init
dn_neigh_init(void)
657 neigh_table_init(&dn_neigh_table
);
659 #ifdef CONFIG_PROC_FS
660 proc_net_register(&proc_net_dn_neigh
);
661 #endif /* CONFIG_PROC_FS */
664 #ifdef CONFIG_DECNET_MODULE
665 void dn_neigh_cleanup(void)
667 #ifdef CONFIG_PROC_FS
668 proc_net_unregister(PROC_NET_DN_ADJ
);
669 #endif /* CONFIG_PROC_FS */
670 neigh_table_clear(&dn_neigh_table
);
672 #endif /* CONFIG_DECNET_MODULE */