File: /usr/src/linux/net/decnet/dn_neigh.c
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 Neighbour Functions (Adjacency Database and
7 * On-Ethernet Cache)
8 *
9 * Author: Steve Whitehouse <SteveW@ACM.org>
10 *
11 *
12 * Changes:
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
19 * working.
20 * Steve Whitehouse : Fixed neighbour states (for now anyway).
21 * Steve Whitehouse : Made error_report functions dummies. This
22 * is not the right place to return skbs.
23 *
24 */
25
26 #include <linux/config.h>
27 #include <linux/net.h>
28 #include <linux/socket.h>
29 #include <linux/if_arp.h>
30 #include <linux/if_ether.h>
31 #include <linux/init.h>
32 #include <linux/proc_fs.h>
33 #include <linux/string.h>
34 #include <linux/netfilter_decnet.h>
35 #include <linux/spinlock.h>
36 #include <asm/atomic.h>
37 #include <net/neighbour.h>
38 #include <net/dst.h>
39 #include <net/dn.h>
40 #include <net/dn_dev.h>
41 #include <net/dn_neigh.h>
42 #include <net/dn_route.h>
43
44 static u32 dn_neigh_hash(const void *pkey, const struct net_device *dev);
45 static int dn_neigh_construct(struct neighbour *);
46 static void dn_long_error_report(struct neighbour *, struct sk_buff *);
47 static void dn_short_error_report(struct neighbour *, struct sk_buff *);
48 static int dn_long_output(struct sk_buff *);
49 static int dn_short_output(struct sk_buff *);
50 static int dn_phase3_output(struct sk_buff *);
51
52
53 /*
54 * For talking to broadcast devices: Ethernet & PPP
55 */
56 static struct neigh_ops dn_long_ops = {
57 family: AF_DECnet,
58 error_report: dn_long_error_report,
59 output: dn_long_output,
60 connected_output: dn_long_output,
61 hh_output: dev_queue_xmit,
62 queue_xmit: dev_queue_xmit,
63 };
64
65 /*
66 * For talking to pointopoint and multidrop devices: DDCMP and X.25
67 */
68 static struct neigh_ops dn_short_ops = {
69 family: AF_DECnet,
70 error_report: dn_short_error_report,
71 output: dn_short_output,
72 connected_output: dn_short_output,
73 hh_output: dev_queue_xmit,
74 queue_xmit: dev_queue_xmit,
75 };
76
77 /*
78 * For talking to DECnet phase III nodes
79 */
80 static struct neigh_ops dn_phase3_ops = {
81 family: AF_DECnet,
82 error_report: dn_short_error_report, /* Can use short version here */
83 output: dn_phase3_output,
84 connected_output: dn_phase3_output,
85 hh_output: dev_queue_xmit,
86 queue_xmit: dev_queue_xmit
87 };
88
89 struct neigh_table dn_neigh_table = {
90 family: PF_DECnet,
91 entry_size: sizeof(struct dn_neigh),
92 key_len: sizeof(dn_address),
93 hash: dn_neigh_hash,
94 constructor: dn_neigh_construct,
95 id: "dn_neigh_cache",
96 parms: {
97 tbl: &dn_neigh_table,
98 entries: 0,
99 base_reachable_time: 30 * HZ,
100 retrans_time: 1 * HZ,
101 gc_staletime: 60 * HZ,
102 reachable_time: 30 * HZ,
103 delay_probe_time: 5 * HZ,
104 queue_len: 3,
105 ucast_probes: 0,
106 app_probes: 0,
107 mcast_probes: 0,
108 anycast_delay: 0,
109 proxy_delay: 0,
110 proxy_qlen: 0,
111 locktime: 1 * HZ,
112 },
113 gc_interval: 30 * HZ,
114 gc_thresh1: 128,
115 gc_thresh2: 512,
116 gc_thresh3: 1024,
117 };
118
119 static u32 dn_neigh_hash(const void *pkey, const struct net_device *dev)
120 {
121 u32 hash_val;
122
123 hash_val = *(dn_address *)pkey;
124 hash_val ^= (hash_val >> 10);
125 hash_val ^= (hash_val >> 3);
126
127 return hash_val & NEIGH_HASHMASK;
128 }
129
130 static int dn_neigh_construct(struct neighbour *neigh)
131 {
132 struct net_device *dev = neigh->dev;
133 struct dn_neigh *dn = (struct dn_neigh *)neigh;
134 struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr;
135
136 if (dn_db == NULL)
137 return -EINVAL;
138
139 if (dn_db->neigh_parms)
140 neigh->parms = dn_db->neigh_parms;
141
142 if (dn_db->use_long)
143 neigh->ops = &dn_long_ops;
144 else
145 neigh->ops = &dn_short_ops;
146
147 if (dn->flags & DN_NDFLAG_P3)
148 neigh->ops = &dn_phase3_ops;
149
150 neigh->nud_state = NUD_NOARP;
151 neigh->output = neigh->ops->connected_output;
152
153 if ((dev->type == ARPHRD_IPGRE) || (dev->flags & IFF_POINTOPOINT))
154 memcpy(neigh->ha, dev->broadcast, dev->addr_len);
155 else if ((dev->type == ARPHRD_ETHER) || (dev->type == ARPHRD_LOOPBACK))
156 dn_dn2eth(neigh->ha, dn->addr);
157 else {
158 if (net_ratelimit())
159 printk(KERN_DEBUG "Trying to create neigh for hw %d\n", dev->type);
160 return -EINVAL;
161 }
162
163 dn->blksize = 230;
164
165 return 0;
166 }
167
168 static void dn_long_error_report(struct neighbour *neigh, struct sk_buff *skb)
169 {
170 printk(KERN_DEBUG "dn_long_error_report: called\n");
171 kfree_skb(skb);
172 }
173
174
175 static void dn_short_error_report(struct neighbour *neigh, struct sk_buff *skb)
176 {
177 printk(KERN_DEBUG "dn_short_error_report: called\n");
178 kfree_skb(skb);
179 }
180
181 static int dn_neigh_output_packet(struct sk_buff *skb)
182 {
183 struct dst_entry *dst = skb->dst;
184 struct neighbour *neigh = dst->neighbour;
185 struct net_device *dev = neigh->dev;
186
187 if (!dev->hard_header || dev->hard_header(skb, dev, ntohs(skb->protocol), neigh->ha, NULL, skb->len) >= 0)
188 return neigh->ops->queue_xmit(skb);
189
190 if (net_ratelimit())
191 printk(KERN_DEBUG "dn_neigh_output_packet: oops, can't send packet\n");
192
193 kfree_skb(skb);
194 return -EINVAL;
195 }
196
197 static int dn_long_output(struct sk_buff *skb)
198 {
199 struct dst_entry *dst = skb->dst;
200 struct neighbour *neigh = dst->neighbour;
201 struct net_device *dev = neigh->dev;
202 int headroom = dev->hard_header_len + sizeof(struct dn_long_packet) + 3;
203 unsigned char *data;
204 struct dn_long_packet *lp;
205 struct dn_skb_cb *cb = DN_SKB_CB(skb);
206
207
208 if (skb_headroom(skb) < headroom) {
209 struct sk_buff *skb2 = skb_realloc_headroom(skb, headroom);
210 if (skb2 == NULL) {
211 if (net_ratelimit())
212 printk(KERN_CRIT "dn_long_output: no memory\n");
213 kfree_skb(skb);
214 return -ENOBUFS;
215 }
216 kfree_skb(skb);
217 skb = skb2;
218 if (net_ratelimit())
219 printk(KERN_INFO "dn_long_output: Increasing headroom\n");
220 }
221
222 data = skb_push(skb, sizeof(struct dn_long_packet) + 3);
223 lp = (struct dn_long_packet *)(data+3);
224
225 *((unsigned short *)data) = dn_htons(skb->len - 2);
226 *(data + 2) = 1 | DN_RT_F_PF; /* Padding */
227
228 lp->msgflg = DN_RT_PKT_LONG|(cb->rt_flags&(DN_RT_F_IE|DN_RT_F_RQR|DN_RT_F_RTS));
229 lp->d_area = lp->d_subarea = 0;
230 dn_dn2eth(lp->d_id, dn_ntohs(cb->dst));
231 lp->s_area = lp->s_subarea = 0;
232 dn_dn2eth(lp->s_id, dn_ntohs(cb->src));
233 lp->nl2 = 0;
234 lp->visit_ct = cb->hops & 0x3f;
235 lp->s_class = 0;
236 lp->pt = 0;
237
238 skb->nh.raw = skb->data;
239
240 return NF_HOOK(PF_DECnet, NF_DN_POST_ROUTING, skb, NULL, neigh->dev, dn_neigh_output_packet);
241 }
242
243 static int dn_short_output(struct sk_buff *skb)
244 {
245 struct dst_entry *dst = skb->dst;
246 struct neighbour *neigh = dst->neighbour;
247 struct net_device *dev = neigh->dev;
248 int headroom = dev->hard_header_len + sizeof(struct dn_short_packet) + 2;
249 struct dn_short_packet *sp;
250 unsigned char *data;
251 struct dn_skb_cb *cb = DN_SKB_CB(skb);
252
253
254 if (skb_headroom(skb) < headroom) {
255 struct sk_buff *skb2 = skb_realloc_headroom(skb, headroom);
256 if (skb2 == NULL) {
257 if (net_ratelimit())
258 printk(KERN_CRIT "dn_short_output: no memory\n");
259 kfree_skb(skb);
260 return -ENOBUFS;
261 }
262 kfree_skb(skb);
263 skb = skb2;
264 if (net_ratelimit())
265 printk(KERN_INFO "dn_short_output: Increasing headroom\n");
266 }
267
268 data = skb_push(skb, sizeof(struct dn_short_packet) + 2);
269 *((unsigned short *)data) = dn_htons(skb->len - 2);
270 sp = (struct dn_short_packet *)(data+2);
271
272 sp->msgflg = DN_RT_PKT_SHORT|(cb->rt_flags&(DN_RT_F_RQR|DN_RT_F_RTS));
273 sp->dstnode = cb->dst;
274 sp->srcnode = cb->src;
275 sp->forward = cb->hops & 0x3f;
276
277 skb->nh.raw = skb->data;
278
279 return NF_HOOK(PF_DECnet, NF_DN_POST_ROUTING, skb, NULL, neigh->dev, dn_neigh_output_packet);
280 }
281
282 /*
283 * Phase 3 output is the same is short output, execpt that
284 * it clears the area bits before transmission.
285 */
286 static int dn_phase3_output(struct sk_buff *skb)
287 {
288 struct dst_entry *dst = skb->dst;
289 struct neighbour *neigh = dst->neighbour;
290 struct net_device *dev = neigh->dev;
291 int headroom = dev->hard_header_len + sizeof(struct dn_short_packet) + 2;
292 struct dn_short_packet *sp;
293 unsigned char *data;
294 struct dn_skb_cb *cb = DN_SKB_CB(skb);
295
296 if (skb_headroom(skb) < headroom) {
297 struct sk_buff *skb2 = skb_realloc_headroom(skb, headroom);
298 if (skb2 == NULL) {
299 if (net_ratelimit())
300 printk(KERN_CRIT "dn_phase3_output: no memory\n");
301 kfree_skb(skb);
302 return -ENOBUFS;
303 }
304 kfree_skb(skb);
305 skb = skb2;
306 if (net_ratelimit())
307 printk(KERN_INFO "dn_phase3_output: Increasing headroom\n");
308 }
309
310 data = skb_push(skb, sizeof(struct dn_short_packet) + 2);
311 ((unsigned short *)data) = dn_htons(skb->len - 2);
312 sp = (struct dn_short_packet *)(data + 2);
313
314 sp->msgflg = DN_RT_PKT_SHORT|(cb->rt_flags&(DN_RT_F_RQR|DN_RT_F_RTS));
315 sp->dstnode = cb->dst & dn_htons(0x03ff);
316 sp->srcnode = cb->src & dn_htons(0x03ff);
317 sp->forward = cb->hops & 0x3f;
318
319 skb->nh.raw = skb->data;
320
321 return NF_HOOK(PF_DECnet, NF_DN_POST_ROUTING, skb, NULL, neigh->dev, dn_neigh_output_packet);
322 }
323
324 /*
325 * Unfortunately, the neighbour code uses the device in its hash
326 * function, so we don't get any advantage from it. This function
327 * basically does a neigh_lookup(), but without comparing the device
328 * field. This is required for the On-Ethernet cache
329 */
330 struct neighbour *dn_neigh_lookup(struct neigh_table *tbl, void *ptr)
331 {
332 struct neighbour *neigh;
333 u32 hash_val;
334
335 hash_val = tbl->hash(ptr, NULL);
336
337 read_lock_bh(&tbl->lock);
338 for(neigh = tbl->hash_buckets[hash_val]; neigh != NULL; neigh = neigh->next) {
339 if (memcmp(neigh->primary_key, ptr, tbl->key_len) == 0) {
340 atomic_inc(&neigh->refcnt);
341 read_unlock_bh(&tbl->lock);
342 return neigh;
343 }
344 }
345 read_unlock_bh(&tbl->lock);
346
347 return NULL;
348 }
349
350
351 /*
352 * Any traffic on a pointopoint link causes the timer to be reset
353 * for the entry in the neighbour table.
354 */
355 void dn_neigh_pointopoint_notify(struct sk_buff *skb)
356 {
357 return;
358 }
359
360 /*
361 * Pointopoint link receives a hello message
362 */
363 void dn_neigh_pointopoint_hello(struct sk_buff *skb)
364 {
365 kfree_skb(skb);
366 }
367
368 /*
369 * Ethernet router hello message received
370 */
371 int dn_neigh_router_hello(struct sk_buff *skb)
372 {
373 struct rtnode_hello_message *msg = (struct rtnode_hello_message *)skb->data;
374
375 struct neighbour *neigh;
376 struct dn_neigh *dn;
377 struct dn_dev *dn_db;
378 dn_address src;
379
380 src = dn_htons(dn_eth2dn(msg->id));
381
382 neigh = __neigh_lookup(&dn_neigh_table, &src, skb->dev, 1);
383
384 dn = (struct dn_neigh *)neigh;
385
386 if (neigh) {
387 write_lock(&neigh->lock);
388
389 neigh->used = jiffies;
390 dn_db = (struct dn_dev *)neigh->dev->dn_ptr;
391
392 if (!(neigh->nud_state & NUD_PERMANENT)) {
393 neigh->updated = jiffies;
394
395 if (neigh->dev->type == ARPHRD_ETHER)
396 memcpy(neigh->ha, &skb->mac.ethernet->h_source, ETH_ALEN);
397
398 dn->blksize = dn_ntohs(msg->blksize);
399 dn->priority = msg->priority;
400
401 dn->flags &= ~DN_NDFLAG_P3;
402
403 switch(msg->iinfo & DN_RT_INFO_TYPE) {
404 case DN_RT_INFO_L1RT:
405 dn->flags &=~DN_NDFLAG_R2;
406 dn->flags |= DN_NDFLAG_R1;
407 break;
408 case DN_RT_INFO_L2RT:
409 dn->flags |= DN_NDFLAG_R2;
410 }
411 }
412
413 if (!dn_db->router) {
414 dn_db->router = neigh_clone(neigh);
415 } else {
416 if (msg->priority > ((struct dn_neigh *)dn_db->router)->priority)
417 neigh_release(xchg(&dn_db->router, neigh_clone(neigh)));
418 }
419 write_unlock(&neigh->lock);
420 neigh_release(neigh);
421 }
422
423 kfree_skb(skb);
424 return 0;
425 }
426
427 /*
428 * Endnode hello message received
429 */
430 int dn_neigh_endnode_hello(struct sk_buff *skb)
431 {
432 struct endnode_hello_message *msg = (struct endnode_hello_message *)skb->data;
433 struct neighbour *neigh;
434 struct dn_neigh *dn;
435 dn_address src;
436
437 src = dn_htons(dn_eth2dn(msg->id));
438
439 neigh = __neigh_lookup(&dn_neigh_table, &src, skb->dev, 1);
440
441 dn = (struct dn_neigh *)neigh;
442
443 if (neigh) {
444 write_lock(&neigh->lock);
445
446 neigh->used = jiffies;
447
448 if (!(neigh->nud_state & NUD_PERMANENT)) {
449 neigh->updated = jiffies;
450
451 if (neigh->dev->type == ARPHRD_ETHER)
452 memcpy(neigh->ha, &skb->mac.ethernet->h_source, ETH_ALEN);
453 dn->flags &= ~(DN_NDFLAG_R1 | DN_NDFLAG_R2);
454 dn->blksize = dn_ntohs(msg->blksize);
455 dn->priority = 0;
456 }
457
458 write_unlock(&neigh->lock);
459 neigh_release(neigh);
460 }
461
462 kfree_skb(skb);
463 return 0;
464 }
465
466
467 #ifdef CONFIG_DECNET_ROUTER
468 static char *dn_find_slot(char *base, int max, int priority)
469 {
470 int i;
471 unsigned char *min = NULL;
472
473 base += 6; /* skip first id */
474
475 for(i = 0; i < max; i++) {
476 if (!min || (*base < *min))
477 min = base;
478 base += 7; /* find next priority */
479 }
480
481 if (!min)
482 return NULL;
483
484 return (*min < priority) ? (min - 6) : NULL;
485 }
486
487 int dn_neigh_elist(struct net_device *dev, unsigned char *ptr, int n)
488 {
489 int t = 0;
490 int i;
491 struct neighbour *neigh;
492 struct dn_neigh *dn;
493 struct neigh_table *tbl = &dn_neigh_table;
494 unsigned char *rs = ptr;
495 struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr;
496
497 read_lock_bh(&tbl->lock);
498
499 for(i = 0; i < NEIGH_HASHMASK; i++) {
500 for(neigh = tbl->hash_buckets[i]; neigh != NULL; neigh = neigh->next) {
501 if (neigh->dev != dev)
502 continue;
503 dn = (struct dn_neigh *)neigh;
504 if (!(dn->flags & (DN_NDFLAG_R1|DN_NDFLAG_R2)))
505 continue;
506 if (dn_db->parms.forwarding == 1 && (dn->flags & DN_NDFLAG_R2))
507 continue;
508 if (t == n)
509 rs = dn_find_slot(ptr, n, dn->priority);
510 else
511 t++;
512 if (rs == NULL)
513 continue;
514 dn_dn2eth(rs, dn->addr);
515 rs += 6;
516 *rs = neigh->nud_state & NUD_CONNECTED ? 0x80 : 0x0;
517 *rs |= dn->priority;
518 rs++;
519 }
520 }
521
522 read_unlock_bh(&tbl->lock);
523
524 return t;
525 }
526 #endif /* CONFIG_DECNET_ROUTER */
527
528
529
530 #ifdef CONFIG_PROC_FS
531 static int dn_neigh_get_info(char *buffer, char **start, off_t offset, int length)
532 {
533 int len = 0;
534 off_t pos = 0;
535 off_t begin = 0;
536 struct neighbour *n;
537 int i;
538 char buf[DN_ASCBUF_LEN];
539
540 len += sprintf(buffer + len, "Addr Flags State Use Blksize Dev\n");
541
542 for(i=0;i <= NEIGH_HASHMASK; i++) {
543 read_lock_bh(&dn_neigh_table.lock);
544 n = dn_neigh_table.hash_buckets[i];
545 for(; n != NULL; n = n->next) {
546 struct dn_neigh *dn = (struct dn_neigh *)n;
547
548 read_lock(&n->lock);
549 len += sprintf(buffer+len, "%-7s %s%s%s %02x %02d %07ld %-8s\n",
550 dn_addr2asc(dn_ntohs(dn->addr), buf),
551 (dn->flags&DN_NDFLAG_R1) ? "1" : "-",
552 (dn->flags&DN_NDFLAG_R2) ? "2" : "-",
553 (dn->flags&DN_NDFLAG_P3) ? "3" : "-",
554 dn->n.nud_state,
555 atomic_read(&dn->n.refcnt),
556 dn->blksize,
557 (dn->n.dev) ? dn->n.dev->name : "?");
558 read_unlock(&n->lock);
559
560 pos = begin + len;
561
562 if (pos < offset) {
563 len = 0;
564 begin = pos;
565 }
566
567 if (pos > offset + length) {
568 read_unlock_bh(&dn_neigh_table.lock);
569 goto done;
570 }
571 }
572 read_unlock_bh(&dn_neigh_table.lock);
573 }
574
575 done:
576
577 *start = buffer + (offset - begin);
578 len -= offset - begin;
579
580 if (len > length) len = length;
581
582 return len;
583 }
584
585 #endif
586
587 void __init dn_neigh_init(void)
588 {
589 neigh_table_init(&dn_neigh_table);
590
591 #ifdef CONFIG_PROC_FS
592 proc_net_create("decnet_neigh",0,dn_neigh_get_info);
593 #endif /* CONFIG_PROC_FS */
594 }
595
596 void __exit dn_neigh_cleanup(void)
597 {
598 proc_net_remove("decnet_neigh");
599 neigh_table_clear(&dn_neigh_table);
600 }
601