OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [net/] [decnet/] [dn_fib.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
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 <SteveW@ACM.org>
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
 *
16
 */
17
#include <linux/config.h>
18
#include <linux/string.h>
19
#include <linux/net.h>
20
#include <linux/socket.h>
21
#include <linux/sockios.h>
22
#include <linux/init.h>
23
#include <linux/skbuff.h>
24
#include <linux/netlink.h>
25
#include <linux/rtnetlink.h>
26
#include <linux/proc_fs.h>
27
#include <linux/netdevice.h>
28
#include <linux/timer.h>
29
#include <linux/spinlock.h>
30
#include <asm/atomic.h>
31
#include <asm/uaccess.h>
32
#include <net/neighbour.h>
33
#include <net/dst.h>
34
#include <net/dn.h>
35
#include <net/dn_route.h>
36
#include <net/dn_fib.h>
37
#include <net/dn_neigh.h>
38
#include <net/dn_dev.h>
39
 
40
 
41
#define for_fib_info() { struct dn_fib_info *fi;\
42
        for(fi = dn_fib_info_list; fi; fi = fi->fib_next)
43
#define endfor_fib_info() }
44
 
45
#define for_nexthops(fi) { int nhsel; const struct dn_fib_nh *nh;\
46
        for(nhsel = 0, nh = (fi)->fib_nh; nhsel < (fi)->fib_nhs; nh++, nhsel++)
47
 
48
#define change_nexthops(fi) { int nhsel; struct dn_fib_nh *nh;\
49
        for(nhsel = 0, nh = (struct dn_fib_nh *)((fi)->fib_nh); nhsel < (fi)->fib_nhs; nh++, nhsel++)
50
 
51
#define endfor_nexthops(fi) }
52
 
53
extern int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb);
54
 
55
 
56
static struct dn_fib_info *dn_fib_info_list;
57
static rwlock_t dn_fib_info_lock = RW_LOCK_UNLOCKED;
58
int dn_fib_info_cnt;
59
 
60
static struct
61
{
62
        int error;
63
        u8 scope;
64
} dn_fib_props[RTA_MAX+1] = {
65
        { 0, RT_SCOPE_NOWHERE },         /* RTN_UNSPEC */
66
        { 0, RT_SCOPE_UNIVERSE },                /* RTN_UNICAST */
67
        { 0, RT_SCOPE_HOST },                    /* RTN_LOCAL */
68
        { -EINVAL, RT_SCOPE_NOWHERE },          /* RTN_BROADCAST */
69
        { -EINVAL, RT_SCOPE_NOWHERE },          /* RTN_ANYCAST */
70
        { -EINVAL, RT_SCOPE_NOWHERE },          /* RTN_MULTICAST */
71
        { -EINVAL, RT_SCOPE_UNIVERSE },         /* RTN_BLACKHOLE */
72
        { -EHOSTUNREACH, RT_SCOPE_UNIVERSE },   /* RTN_UNREACHABLE */
73
        { -EACCES, RT_SCOPE_UNIVERSE },         /* RTN_PROHIBIT */
74
        { -EAGAIN, RT_SCOPE_UNIVERSE },         /* RTN_THROW */
75
        { -EINVAL, RT_SCOPE_NOWHERE },          /* RTN_NAT */
76
        { -EINVAL, RT_SCOPE_NOWHERE }           /* RTN_XRESOLVE */
77
};
78
 
79
void dn_fib_free_info(struct dn_fib_info *fi)
80
{
81
        if (fi->fib_dead == 0) {
82
                printk(KERN_DEBUG "DECnet: BUG! Attempt to free alive dn_fib_info\n");
83
                return;
84
        }
85
 
86
        change_nexthops(fi) {
87
                if (nh->nh_dev)
88
                        dev_put(nh->nh_dev);
89
                nh->nh_dev = NULL;
90
        } endfor_nexthops(fi);
91
        dn_fib_info_cnt--;
92
        kfree(fi);
93
}
94
 
95
void dn_fib_release_info(struct dn_fib_info *fi)
96
{
97
        write_lock(&dn_fib_info_lock);
98
        if (fi && --fi->fib_treeref == 0) {
99
                if (fi->fib_next)
100
                        fi->fib_next->fib_prev = fi->fib_prev;
101
                if (fi->fib_prev)
102
                        fi->fib_prev->fib_next = fi->fib_next;
103
                if (fi == dn_fib_info_list)
104
                        dn_fib_info_list = fi->fib_next;
105
                fi->fib_dead = 1;
106
                dn_fib_info_put(fi);
107
        }
108
        write_unlock(&dn_fib_info_lock);
109
}
110
 
111
static __inline__ int dn_fib_nh_comp(const struct dn_fib_info *fi, const struct dn_fib_info *ofi)
112
{
113
        const struct dn_fib_nh *onh = ofi->fib_nh;
114
 
115
        for_nexthops(fi) {
116
                if (nh->nh_oif != onh->nh_oif ||
117
                        nh->nh_gw != onh->nh_gw ||
118
                        nh->nh_scope != onh->nh_scope ||
119
                        nh->nh_weight != onh->nh_weight ||
120
                        ((nh->nh_flags^onh->nh_flags)&~RTNH_F_DEAD))
121
                                return -1;
122
                onh++;
123
        } endfor_nexthops(fi);
124
        return 0;
125
}
126
 
127
static __inline__ struct dn_fib_info *dn_fib_find_info(const struct dn_fib_info *nfi)
128
{
129
        for_fib_info() {
130
                if (fi->fib_nhs != nfi->fib_nhs)
131
                        continue;
132
                if (nfi->fib_protocol == fi->fib_protocol &&
133
                        nfi->fib_prefsrc == fi->fib_prefsrc &&
134
                        nfi->fib_priority == fi->fib_priority &&
135
                        ((nfi->fib_flags^fi->fib_flags)&~RTNH_F_DEAD) == 0 &&
136
                        (nfi->fib_nhs == 0 || dn_fib_nh_comp(fi, nfi) == 0))
137
                                return fi;
138
        } endfor_fib_info();
139
        return NULL;
140
}
141
 
142
u16 dn_fib_get_attr16(struct rtattr *attr, int attrlen, int type)
143
{
144
        while(RTA_OK(attr,attrlen)) {
145
                if (attr->rta_type == type)
146
                        return *(u16*)RTA_DATA(attr);
147
                attr = RTA_NEXT(attr, attrlen);
148
        }
149
 
150
        return 0;
151
}
152
 
153
static int dn_fib_count_nhs(struct rtattr *rta)
154
{
155
        int nhs = 0;
156
        struct rtnexthop *nhp = RTA_DATA(rta);
157
        int nhlen = RTA_PAYLOAD(rta);
158
 
159
        while(nhlen >= (int)sizeof(struct rtnexthop)) {
160
                if ((nhlen -= nhp->rtnh_len) < 0)
161
                        return 0;
162
                nhs++;
163
                nhp = RTNH_NEXT(nhp);
164
        }
165
 
166
        return nhs;
167
}
168
 
169
static int dn_fib_get_nhs(struct dn_fib_info *fi, const struct rtattr *rta, const struct rtmsg *r)
170
{
171
        struct rtnexthop *nhp = RTA_DATA(rta);
172
        int nhlen = RTA_PAYLOAD(rta);
173
 
174
        change_nexthops(fi) {
175
                int attrlen = nhlen - sizeof(struct rtnexthop);
176
                if (attrlen < 0 || (nhlen -= nhp->rtnh_len) < 0)
177
                        return -EINVAL;
178
 
179
                nh->nh_flags  = (r->rtm_flags&~0xFF) | nhp->rtnh_flags;
180
                nh->nh_oif    = nhp->rtnh_ifindex;
181
                nh->nh_weight = nhp->rtnh_hops + 1;
182
 
183
                if (attrlen) {
184
                        nh->nh_gw = dn_fib_get_attr16(RTNH_DATA(nhp), attrlen, RTA_GATEWAY);
185
                }
186
                nhp = RTNH_NEXT(nhp);
187
        } endfor_nexthops(fi);
188
 
189
        return 0;
190
}
191
 
192
 
193
static int dn_fib_check_nh(const struct rtmsg *r, struct dn_fib_info *fi, struct dn_fib_nh *nh)
194
{
195
        int err;
196
 
197
        if (nh->nh_gw) {
198
                struct dn_fib_key key;
199
                struct dn_fib_res res;
200
 
201
                if (nh->nh_flags&RTNH_F_ONLINK) {
202
                        struct net_device *dev;
203
 
204
                        if (r->rtm_scope >= RT_SCOPE_LINK)
205
                                return -EINVAL;
206
                        if ((dev = __dev_get_by_index(nh->nh_oif)) == NULL)
207
                                return -ENODEV;
208
                        if (!(dev->flags&IFF_UP))
209
                                return -ENETDOWN;
210
                        nh->nh_dev = dev;
211
                        atomic_inc(&dev->refcnt);
212
                        nh->nh_scope = RT_SCOPE_LINK;
213
                        return 0;
214
                }
215
 
216
                memset(&key, 0, sizeof(key));
217
                key.dst = nh->nh_gw;
218
                key.oif = nh->nh_oif;
219
                key.scope = r->rtm_scope + 1;
220
 
221
                if (key.scope < RT_SCOPE_LINK)
222
                        key.scope = RT_SCOPE_LINK;
223
 
224
                if ((err = dn_fib_lookup(&key, &res)) != 0)
225
                        return err;
226
 
227
                nh->nh_scope = res.scope;
228
                nh->nh_oif = DN_FIB_RES_OIF(res);
229
                nh->nh_dev = DN_FIB_RES_DEV(res);
230
                if (nh->nh_dev)
231
                        atomic_inc(&nh->nh_dev->refcnt);
232
                dn_fib_res_put(&res);
233
        } else {
234
                struct net_device *dev;
235
 
236
                if (nh->nh_flags&(RTNH_F_PERVASIVE|RTNH_F_ONLINK))
237
                        return -EINVAL;
238
 
239
                dev = __dev_get_by_index(nh->nh_oif);
240
                if (dev == NULL || dev->dn_ptr == NULL)
241
                        return -ENODEV;
242
                if (!(dev->flags&IFF_UP))
243
                        return -ENETDOWN;
244
                nh->nh_dev = dev;
245
                atomic_inc(&nh->nh_dev->refcnt);
246
                nh->nh_scope = RT_SCOPE_HOST;
247
        }
248
 
249
        return 0;
250
}
251
 
252
 
253
struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct dn_kern_rta *rta, const struct nlmsghdr *nlh, int *errp)
254
{
255
        int err;
256
        struct dn_fib_info *fi = NULL;
257
        struct dn_fib_info *ofi;
258
        int nhs = 1;
259
 
260
        if (dn_fib_props[r->rtm_type].scope > r->rtm_scope)
261
                goto err_inval;
262
 
263
        if (rta->rta_mp) {
264
                nhs = dn_fib_count_nhs(rta->rta_mp);
265
                if (nhs == 0)
266
                        goto err_inval;
267
        }
268
 
269
        fi = kmalloc(sizeof(*fi)+nhs*sizeof(struct dn_fib_nh), GFP_KERNEL);
270
        err = -ENOBUFS;
271
        if (fi == NULL)
272
                goto failure;
273
        memset(fi, 0, sizeof(*fi)+nhs*sizeof(struct dn_fib_nh));
274
 
275
        fi->fib_protocol = r->rtm_protocol;
276
        fi->fib_nhs = nhs;
277
        fi->fib_flags = r->rtm_flags;
278
        if (rta->rta_priority)
279
                fi->fib_priority = *rta->rta_priority;
280
        if (rta->rta_prefsrc)
281
                memcpy(&fi->fib_prefsrc, rta->rta_prefsrc, 2);
282
 
283
        if (rta->rta_mp) {
284
                if ((err = dn_fib_get_nhs(fi, rta->rta_mp, r)) != 0)
285
                        goto failure;
286
                if (rta->rta_oif && fi->fib_nh->nh_oif != *rta->rta_oif)
287
                        goto err_inval;
288
                if (rta->rta_gw && memcmp(&fi->fib_nh->nh_gw, rta->rta_gw, 2))
289
                        goto err_inval;
290
        } else {
291
                struct dn_fib_nh *nh = fi->fib_nh;
292
                if (rta->rta_oif)
293
                        nh->nh_oif = *rta->rta_oif;
294
                if (rta->rta_gw)
295
                        memcpy(&nh->nh_gw, rta->rta_gw, 2);
296
                nh->nh_flags = r->rtm_flags;
297
                nh->nh_weight = 1;
298
        }
299
 
300
        if (dn_fib_props[r->rtm_type].error) {
301
                if (rta->rta_gw || rta->rta_oif || rta->rta_mp)
302
                        goto err_inval;
303
                goto link_it;
304
        }
305
 
306
        if (r->rtm_scope > RT_SCOPE_HOST)
307
                goto err_inval;
308
 
309
        if (r->rtm_scope == RT_SCOPE_HOST) {
310
                struct dn_fib_nh *nh = fi->fib_nh;
311
 
312
                /* Local address is added */
313
                if (nhs != 1 || nh->nh_gw)
314
                        goto err_inval;
315
                nh->nh_scope = RT_SCOPE_NOWHERE;
316
                nh->nh_dev = dev_get_by_index(fi->fib_nh->nh_oif);
317
                err = -ENODEV;
318
                if (nh->nh_dev == NULL)
319
                        goto failure;
320
        } else {
321
                change_nexthops(fi) {
322
                        if ((err = dn_fib_check_nh(r, fi, nh)) != 0)
323
                                goto failure;
324
                } endfor_nexthops(fi)
325
        }
326
 
327
#if I_GET_AROUND_TO_FIXING_PREFSRC
328
        if (fi->fib_prefsrc) {
329
                if (r->rtm_type != RTN_LOCAL || rta->rta_dst == NULL ||
330
                    memcmp(&fi->fib_prefsrc, rta->rta_dst, 2))
331
                        if (dn_addr_type(fi->fib_prefsrc) != RTN_LOCAL)
332
                                goto err_inval;
333
        }
334
#endif
335
 
336
link_it:
337
        if ((ofi = dn_fib_find_info(fi)) != NULL) {
338
                fi->fib_dead = 1;
339
                dn_fib_free_info(fi);
340
                ofi->fib_treeref++;
341
                return ofi;
342
        }
343
 
344
        fi->fib_treeref++;
345
        atomic_inc(&fi->fib_clntref);
346
        write_lock(&dn_fib_info_lock);
347
        fi->fib_next = dn_fib_info_list;
348
        fi->fib_prev = NULL;
349
        if (dn_fib_info_list)
350
                dn_fib_info_list->fib_prev = fi;
351
        dn_fib_info_list = fi;
352
        dn_fib_info_cnt++;
353
        write_unlock(&dn_fib_info_lock);
354
        return fi;
355
 
356
err_inval:
357
        err = -EINVAL;
358
 
359
failure:
360
        *errp = err;
361
        if (fi) {
362
                fi->fib_dead = 1;
363
                dn_fib_free_info(fi);
364
        }
365
 
366
        return NULL;
367
}
368
 
369
 
370
void dn_fib_select_multipath(const struct dn_fib_key *key, struct dn_fib_res *res)
371
{
372
        struct dn_fib_info *fi = res->fi;
373
        int w;
374
 
375
        if (fi->fib_power <= 0) {
376
                int power = 0;
377
                change_nexthops(fi) {
378
                        if (!(nh->nh_flags&RTNH_F_DEAD)) {
379
                                power += nh->nh_weight;
380
                                nh->nh_power = nh->nh_weight;
381
                        }
382
                } endfor_nexthops(fi);
383
                fi->fib_power = power;
384
        }
385
 
386
        w = jiffies % fi->fib_power;
387
 
388
        change_nexthops(fi) {
389
                if (!(nh->nh_flags&RTNH_F_DEAD) && nh->nh_power) {
390
                        if ((w -= nh->nh_power) <= 0) {
391
                                nh->nh_power--;
392
                                fi->fib_power--;
393
                                res->nh_sel = nhsel;
394
                                return;
395
                        }
396
                }
397
        } endfor_nexthops(fi);
398
 
399
        printk(KERN_DEBUG "DECnet: BUG! dn_fib_select_multipath\n");
400
}
401
 
402
 
403
 
404
/*
405
 * Punt to user via netlink for example, but for now
406
 * we just drop it.
407
 */
408
int dn_fib_rt_message(struct sk_buff *skb)
409
{
410
        kfree_skb(skb);
411
 
412
        return 0;
413
}
414
 
415
 
416
static int dn_fib_check_attr(struct rtmsg *r, struct rtattr **rta)
417
{
418
        int i;
419
 
420
        for(i = 1; i <= RTA_MAX; i++) {
421
                struct rtattr *attr = rta[i-1];
422
                if (attr) {
423
                        if (RTA_PAYLOAD(attr) < 4 && RTA_PAYLOAD(attr) != 2)
424
                                return -EINVAL;
425
                        if (i != RTA_MULTIPATH && i != RTA_METRICS)
426
                                rta[i-1] = (struct rtattr *)RTA_DATA(attr);
427
                }
428
        }
429
 
430
        return 0;
431
}
432
 
433
int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
434
{
435
        struct dn_fib_table *tb;
436
        struct rtattr **rta = arg;
437
        struct rtmsg *r = NLMSG_DATA(nlh);
438
 
439
        if (dn_fib_check_attr(r, rta))
440
                return -EINVAL;
441
 
442
        tb = dn_fib_get_table(r->rtm_table, 0);
443
        if (tb)
444
                return tb->delete(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb));
445
 
446
        return -ESRCH;
447
}
448
 
449
int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
450
{
451
        struct dn_fib_table *tb;
452
        struct rtattr **rta = arg;
453
        struct rtmsg *r = NLMSG_DATA(nlh);
454
 
455
        if (dn_fib_check_attr(r, rta))
456
                return -EINVAL;
457
 
458
        tb = dn_fib_get_table(r->rtm_table, 1);
459
        if (tb)
460
                return tb->insert(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb));
461
 
462
        return -ENOBUFS;
463
}
464
 
465
 
466
int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb)
467
{
468
        int t;
469
        int s_t;
470
        struct dn_fib_table *tb;
471
 
472
        if (NLMSG_PAYLOAD(cb->nlh, 0) >= sizeof(struct rtmsg) &&
473
                ((struct rtmsg *)NLMSG_DATA(cb->nlh))->rtm_flags&RTM_F_CLONED)
474
                        return dn_cache_dump(skb, cb);
475
 
476
        s_t = cb->args[0];
477
        if (s_t == 0)
478
                s_t = cb->args[0] = DN_MIN_TABLE;
479
 
480
        for(t = s_t; t < DN_NUM_TABLES; t++) {
481
                if (t < s_t)
482
                        continue;
483
                if (t > s_t)
484
                        memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(int));
485
                tb = dn_fib_get_table(t, 0);
486
                if (tb == NULL)
487
                        continue;
488
                if (tb->dump(tb, skb, cb) < 0)
489
                        break;
490
        }
491
 
492
        cb->args[0] = t;
493
 
494
        return skb->len;
495
}
496
 
497
int dn_fib_sync_down(dn_address local, struct net_device *dev, int force)
498
{
499
        int ret = 0;
500
        int scope = RT_SCOPE_NOWHERE;
501
 
502
        if (force)
503
                scope = -1;
504
 
505
        for_fib_info() {
506
                /*
507
                 * This makes no sense for DECnet.... we will almost
508
                 * certainly have more than one local address the same
509
                 * over all our interfaces. It needs thinking about
510
                 * some more.
511
                 */
512
                if (local && fi->fib_prefsrc == local) {
513
                        fi->fib_flags |= RTNH_F_DEAD;
514
                        ret++;
515
                } else if (dev && fi->fib_nhs) {
516
                        int dead = 0;
517
 
518
                        change_nexthops(fi) {
519
                                if (nh->nh_flags&RTNH_F_DEAD)
520
                                        dead++;
521
                                else if (nh->nh_dev == dev &&
522
                                                nh->nh_scope != scope) {
523
                                        nh->nh_flags |= RTNH_F_DEAD;
524
                                        fi->fib_power -= nh->nh_power;
525
                                        nh->nh_power = 0;
526
                                        dead++;
527
                                }
528
                        } endfor_nexthops(fi)
529
                        if (dead == fi->fib_nhs) {
530
                                fi->fib_flags |= RTNH_F_DEAD;
531
                                ret++;
532
                        }
533
                }
534
        } endfor_fib_info();
535
        return ret;
536
}
537
 
538
 
539
int dn_fib_sync_up(struct net_device *dev)
540
{
541
        int ret = 0;
542
 
543
        if (!(dev->flags&IFF_UP))
544
                return 0;
545
 
546
        for_fib_info() {
547
                int alive = 0;
548
 
549
                change_nexthops(fi) {
550
                        if (!(nh->nh_flags&RTNH_F_DEAD)) {
551
                                alive++;
552
                                continue;
553
                        }
554
                        if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP))
555
                                continue;
556
                        if (nh->nh_dev != dev || dev->dn_ptr == NULL)
557
                                continue;
558
                        alive++;
559
                        nh->nh_power = 0;
560
                        nh->nh_flags &= ~RTNH_F_DEAD;
561
                } endfor_nexthops(fi);
562
 
563
                if (alive == fi->fib_nhs) {
564
                        fi->fib_flags &= ~RTNH_F_DEAD;
565
                        ret++;
566
                }
567
        } endfor_fib_info();
568
        return ret;
569
}
570
 
571
void dn_fib_flush(void)
572
{
573
        int flushed = 0;
574
        struct dn_fib_table *tb;
575
        int id;
576
 
577
        for(id = DN_NUM_TABLES; id > 0; id--) {
578
                if ((tb = dn_fib_get_table(id, 0)) == NULL)
579
                        continue;
580
                flushed += tb->flush(tb);
581
        }
582
 
583
        if (flushed)
584
                dn_rt_cache_flush(-1);
585
}
586
 
587
int dn_fib_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
588
{
589
 
590
        if (!capable(CAP_NET_ADMIN))
591
                return -EPERM;
592
 
593
        switch(cmd) {
594
                case SIOCADDRT:
595
                case SIOCDELRT:
596
                        return 0;
597
        }
598
 
599
        return -EINVAL;
600
}
601
 
602
#ifdef CONFIG_PROC_FS
603
 
604
static int decnet_rt_get_info(char *buffer, char **start, off_t offset, int length)
605
{
606
        int first = offset / 128;
607
        char *ptr = buffer;
608
        int count = (length + 127) / 128;
609
        int len;
610
        int i;
611
        struct dn_fib_table *tb;
612
 
613
        *start = buffer + (offset % 128);
614
 
615
        if (--first < 0) {
616
                sprintf(buffer, "%-127s\n", "Iface\tDest\tGW  \tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU\tWindow\tIRTT");
617
                --count;
618
                ptr += 128;
619
                first = 0;
620
        }
621
 
622
 
623
        for(i = DN_MIN_TABLE; (i <= DN_NUM_TABLES) && (count > 0); i++) {
624
                if ((tb = dn_fib_get_table(i, 0)) != NULL) {
625
                        int n = tb->get_info(tb, ptr, first, count);
626
                        count -= n;
627
                        ptr += n * 128;
628
                }
629
        }
630
 
631
        len = ptr - *start;
632
        if (len >= length)
633
                return length;
634
        if (len >= 0)
635
                return len;
636
 
637
        return 0;
638
}
639
#endif /* CONFIG_PROC_FS */
640
 
641
void __exit dn_fib_cleanup(void)
642
{
643
        proc_net_remove("decnet_route");
644
 
645
        dn_fib_table_cleanup();
646
        dn_fib_rules_cleanup();
647
}
648
 
649
 
650
void __init dn_fib_init(void)
651
{
652
 
653
#ifdef CONFIG_PROC_FS
654
        proc_net_create("decnet_route", 0, decnet_rt_get_info);
655
#endif
656
 
657
        dn_fib_table_init();
658
        dn_fib_rules_init();
659
}
660
 
661
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.