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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [net/] [decnet/] [dn_dev.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 Device Layer
7
 *
8
 * Authors:     Steve Whitehouse <SteveW@ACM.org>
9
 *              Eduardo Marcelo Serrat <emserrat@geocities.com>
10
 *
11
 * Changes:
12
 *          Steve Whitehouse : Devices now see incoming frames so they
13
 *                             can mark on who it came from.
14
 *          Steve Whitehouse : Fixed bug in creating neighbours. Each neighbour
15
 *                             can now have a device specific setup func.
16
 *          Steve Whitehouse : Added /proc/sys/net/decnet/conf/<dev>/
17
 *          Steve Whitehouse : Fixed bug which sometimes killed timer
18
 *          Steve Whitehouse : Multiple ifaddr support
19
 *          Steve Whitehouse : SIOCGIFCONF is now a compile time option
20
 *          Steve Whitehouse : /proc/sys/net/decnet/conf/<sys>/forwarding
21
 *          Steve Whitehouse : Removed timer1 - its a user space issue now
22
 *         Patrick Caulfield : Fixed router hello message format
23
 */
24
 
25
#include <linux/config.h>
26
#include <linux/net.h>
27
#include <linux/netdevice.h>
28
#include <linux/proc_fs.h>
29
#include <linux/timer.h>
30
#include <linux/string.h>
31
#include <linux/if_arp.h>
32
#include <linux/if_ether.h>
33
#include <linux/init.h>
34
#include <linux/skbuff.h>
35
#include <linux/rtnetlink.h>
36
#include <linux/sysctl.h>
37
#include <asm/uaccess.h>
38
#include <net/neighbour.h>
39
#include <net/dst.h>
40
#include <net/dn.h>
41
#include <net/dn_dev.h>
42
#include <net/dn_route.h>
43
#include <net/dn_neigh.h>
44
#include <net/dn_fib.h>
45
 
46
#define DN_IFREQ_SIZE (sizeof(struct ifreq) - sizeof(struct sockaddr) + sizeof(struct sockaddr_dn))
47
 
48
static char dn_rt_all_end_mcast[ETH_ALEN] = {0xAB,0x00,0x00,0x04,0x00,0x00};
49
static char dn_rt_all_rt_mcast[ETH_ALEN]  = {0xAB,0x00,0x00,0x03,0x00,0x00};
50
static char dn_hiord[ETH_ALEN]            = {0xAA,0x00,0x04,0x00,0x00,0x00};
51
static unsigned char dn_eco_version[3]    = {0x02,0x00,0x00};
52
 
53
extern struct neigh_table dn_neigh_table;
54
 
55
struct net_device *decnet_default_device;
56
 
57
static struct dn_dev *dn_dev_create(struct net_device *dev, int *err);
58
static void dn_dev_delete(struct net_device *dev);
59
static void rtmsg_ifa(int event, struct dn_ifaddr *ifa);
60
 
61
static int dn_eth_up(struct net_device *);
62
static void dn_send_brd_hello(struct net_device *dev);
63
#if 0
64
static void dn_send_ptp_hello(struct net_device *dev);
65
#endif
66
 
67
static struct dn_dev_parms dn_dev_list[] =  {
68
{
69
        type:           ARPHRD_ETHER, /* Ethernet */
70
        mode:           DN_DEV_BCAST,
71
        state:          DN_DEV_S_RU,
72
        blksize:        1498,
73
        t2:             1,
74
        t3:             10,
75
        name:           "ethernet",
76
        ctl_name:       NET_DECNET_CONF_ETHER,
77
        up:             dn_eth_up,
78
        timer3:         dn_send_brd_hello,
79
},
80
{
81
        type:           ARPHRD_IPGRE, /* DECnet tunneled over GRE in IP */
82
        mode:           DN_DEV_BCAST,
83
        state:          DN_DEV_S_RU,
84
        blksize:        1400,
85
        t2:             1,
86
        t3:             10,
87
        name:           "ipgre",
88
        ctl_name:       NET_DECNET_CONF_GRE,
89
        timer3:         dn_send_brd_hello,
90
},
91
#if 0
92
{
93
        type:           ARPHRD_X25, /* Bog standard X.25 */
94
        mode:           DN_DEV_UCAST,
95
        state:          DN_DEV_S_DS,
96
        blksize:        230,
97
        t2:             1,
98
        t3:             120,
99
        name:           "x25",
100
        ctl_name:       NET_DECNET_CONF_X25,
101
        timer3:         dn_send_ptp_hello,
102
},
103
#endif
104
#if 0
105
{
106
        type:           ARPHRD_PPP, /* DECnet over PPP */
107
        mode:           DN_DEV_BCAST,
108
        state:          DN_DEV_S_RU,
109
        blksize:        230,
110
        t2:             1,
111
        t3:             10,
112
        name:           "ppp",
113
        ctl_name:       NET_DECNET_CONF_PPP,
114
        timer3:         dn_send_brd_hello,
115
},
116
#endif
117
#if 0
118
{
119
        type:           ARPHRD_DDCMP, /* DECnet over DDCMP */
120
        mode:           DN_DEV_UCAST,
121
        state:          DN_DEV_S_DS,
122
        blksize:        230,
123
        t2:             1,
124
        t3:             120,
125
        name:           "ddcmp",
126
        ctl_name:       NET_DECNET_CONF_DDCMP,
127
        timer3:         dn_send_ptp_hello,
128
},
129
#endif
130
{
131
        type:           ARPHRD_LOOPBACK, /* Loopback interface - always last */
132
        mode:           DN_DEV_BCAST,
133
        state:          DN_DEV_S_RU,
134
        blksize:        1498,
135
        t2:             1,
136
        t3:             10,
137
        name:           "loopback",
138
        ctl_name:       NET_DECNET_CONF_LOOPBACK,
139
        timer3:         dn_send_brd_hello,
140
}
141
};
142
 
143
#define DN_DEV_LIST_SIZE (sizeof(dn_dev_list)/sizeof(struct dn_dev_parms))
144
 
145
#define DN_DEV_PARMS_OFFSET(x) ((int) ((char *) &((struct dn_dev_parms *)0)->x))
146
 
147
#ifdef CONFIG_SYSCTL
148
 
149
static int min_t2[] = { 1 };
150
static int max_t2[] = { 60 }; /* No max specified, but this seems sensible */
151
static int min_t3[] = { 1 };
152
static int max_t3[] = { 8191 }; /* Must fit in 16 bits when multiplied by BCT3MULT or T3MULT */
153
 
154
static int min_priority[1];
155
static int max_priority[] = { 127 }; /* From DECnet spec */
156
 
157
static int dn_forwarding_proc(ctl_table *, int, struct file *,
158
                        void *, size_t *);
159
static int dn_forwarding_sysctl(ctl_table *table, int *name, int nlen,
160
                        void *oldval, size_t *oldlenp,
161
                        void *newval, size_t newlen,
162
                        void **context);
163
 
164
static struct dn_dev_sysctl_table {
165
        struct ctl_table_header *sysctl_header;
166
        ctl_table dn_dev_vars[5];
167
        ctl_table dn_dev_dev[2];
168
        ctl_table dn_dev_conf_dir[2];
169
        ctl_table dn_dev_proto_dir[2];
170
        ctl_table dn_dev_root_dir[2];
171
} dn_dev_sysctl = {
172
        NULL,
173
        {
174
        {NET_DECNET_CONF_DEV_FORWARDING, "forwarding",
175
        (void *)DN_DEV_PARMS_OFFSET(forwarding),
176
        sizeof(int), 0644, NULL,
177
        dn_forwarding_proc, dn_forwarding_sysctl,
178
        NULL, NULL, NULL},
179
        {NET_DECNET_CONF_DEV_PRIORITY, "priority",
180
        (void *)DN_DEV_PARMS_OFFSET(priority),
181
        sizeof(int), 0644, NULL,
182
        proc_dointvec_minmax, sysctl_intvec,
183
        NULL, &min_priority, &max_priority},
184
        {NET_DECNET_CONF_DEV_T2, "t2", (void *)DN_DEV_PARMS_OFFSET(t2),
185
        sizeof(int), 0644, NULL,
186
        proc_dointvec_minmax, sysctl_intvec,
187
        NULL, &min_t2, &max_t2},
188
        {NET_DECNET_CONF_DEV_T3, "t3", (void *)DN_DEV_PARMS_OFFSET(t3),
189
        sizeof(int), 0644, NULL,
190
        proc_dointvec_minmax, sysctl_intvec,
191
        NULL, &min_t3, &max_t3},
192
        {0}
193
        },
194
        {{0, "", NULL, 0, 0555, dn_dev_sysctl.dn_dev_vars}, {0}},
195
        {{NET_DECNET_CONF, "conf", NULL, 0, 0555, dn_dev_sysctl.dn_dev_dev}, {0}},
196
        {{NET_DECNET, "decnet", NULL, 0, 0555, dn_dev_sysctl.dn_dev_conf_dir}, {0}},
197
        {{CTL_NET, "net", NULL, 0, 0555, dn_dev_sysctl.dn_dev_proto_dir}, {0}}
198
};
199
 
200
static void dn_dev_sysctl_register(struct net_device *dev, struct dn_dev_parms *parms)
201
{
202
        struct dn_dev_sysctl_table *t;
203
        int i;
204
 
205
        t = kmalloc(sizeof(*t), GFP_KERNEL);
206
        if (t == NULL)
207
                return;
208
 
209
        memcpy(t, &dn_dev_sysctl, sizeof(*t));
210
 
211
        for(i = 0; i < (sizeof(t->dn_dev_vars)/sizeof(t->dn_dev_vars[0]) - 1); i++) {
212
                long offset = (long)t->dn_dev_vars[i].data;
213
                t->dn_dev_vars[i].data = ((char *)parms) + offset;
214
                t->dn_dev_vars[i].de = NULL;
215
        }
216
 
217
        if (dev) {
218
                t->dn_dev_dev[0].procname = dev->name;
219
                t->dn_dev_dev[0].ctl_name = dev->ifindex;
220
        } else {
221
                t->dn_dev_dev[0].procname = parms->name;
222
                t->dn_dev_dev[0].ctl_name = parms->ctl_name;
223
        }
224
 
225
        t->dn_dev_dev[0].child = t->dn_dev_vars;
226
        t->dn_dev_dev[0].de = NULL;
227
        t->dn_dev_conf_dir[0].child = t->dn_dev_dev;
228
        t->dn_dev_conf_dir[0].de = NULL;
229
        t->dn_dev_proto_dir[0].child = t->dn_dev_conf_dir;
230
        t->dn_dev_proto_dir[0].de = NULL;
231
        t->dn_dev_root_dir[0].child = t->dn_dev_proto_dir;
232
        t->dn_dev_root_dir[0].de = NULL;
233
        t->dn_dev_vars[0].extra1 = (void *)dev;
234
 
235
        t->sysctl_header = register_sysctl_table(t->dn_dev_root_dir, 0);
236
        if (t->sysctl_header == NULL)
237
                kfree(t);
238
        else
239
                parms->sysctl = t;
240
}
241
 
242
static void dn_dev_sysctl_unregister(struct dn_dev_parms *parms)
243
{
244
        if (parms->sysctl) {
245
                struct dn_dev_sysctl_table *t = parms->sysctl;
246
                parms->sysctl = NULL;
247
                unregister_sysctl_table(t->sysctl_header);
248
                kfree(t);
249
        }
250
}
251
 
252
 
253
static int dn_forwarding_proc(ctl_table *table, int write,
254
                                struct file *filep,
255
                                void *buffer, size_t *lenp)
256
{
257
#ifdef CONFIG_DECNET_ROUTER
258
        struct net_device *dev = table->extra1;
259
        struct dn_dev *dn_db;
260
        int err;
261
        int tmp, old;
262
 
263
        if (table->extra1 == NULL)
264
                return -EINVAL;
265
 
266
        dn_db = dev->dn_ptr;
267
        old = dn_db->parms.forwarding;
268
 
269
        err = proc_dointvec(table, write, filep, buffer, lenp);
270
 
271
        if ((err >= 0) && write) {
272
                if (dn_db->parms.forwarding < 0)
273
                        dn_db->parms.forwarding = 0;
274
                if (dn_db->parms.forwarding > 2)
275
                        dn_db->parms.forwarding = 2;
276
                /*
277
                 * What an ugly hack this is... its works, just. It
278
                 * would be nice if sysctl/proc were just that little
279
                 * bit more flexible so I don't have to write a special
280
                 * routine, or suffer hacks like this - SJW
281
                 */
282
                tmp = dn_db->parms.forwarding;
283
                dn_db->parms.forwarding = old;
284
                if (dn_db->parms.down)
285
                        dn_db->parms.down(dev);
286
                dn_db->parms.forwarding = tmp;
287
                if (dn_db->parms.up)
288
                        dn_db->parms.up(dev);
289
        }
290
 
291
        return err;
292
#else
293
        return -EINVAL;
294
#endif
295
}
296
 
297
static int dn_forwarding_sysctl(ctl_table *table, int *name, int nlen,
298
                        void *oldval, size_t *oldlenp,
299
                        void *newval, size_t newlen,
300
                        void **context)
301
{
302
#ifdef CONFIG_DECNET_ROUTER
303
        struct net_device *dev = table->extra1;
304
        struct dn_dev *dn_db;
305
        int value;
306
 
307
        if (table->extra1 == NULL)
308
                return -EINVAL;
309
 
310
        dn_db = dev->dn_ptr;
311
 
312
        if (newval && newlen) {
313
                if (newlen != sizeof(int))
314
                        return -EINVAL;
315
 
316
                if (get_user(value, (int *)newval))
317
                        return -EFAULT;
318
                if (value < 0)
319
                        return -EINVAL;
320
                if (value > 2)
321
                        return -EINVAL;
322
 
323
                if (dn_db->parms.down)
324
                        dn_db->parms.down(dev);
325
                dn_db->parms.forwarding = value;
326
                if (dn_db->parms.up)
327
                        dn_db->parms.up(dev);
328
        }
329
 
330
        return 0;
331
#else
332
        return -EINVAL;
333
#endif
334
}
335
 
336
#else /* CONFIG_SYSCTL */
337
static void dn_dev_sysctl_unregister(struct dn_dev_parms *parms)
338
{
339
}
340
static void dn_dev_sysctl_register(struct net_device *dev, struct dn_dev_parms *parms)
341
{
342
}
343
 
344
#endif /* CONFIG_SYSCTL */
345
 
346
static struct dn_ifaddr *dn_dev_alloc_ifa(void)
347
{
348
        struct dn_ifaddr *ifa;
349
 
350
        ifa = kmalloc(sizeof(*ifa), GFP_KERNEL);
351
 
352
        if (ifa) {
353
                memset(ifa, 0, sizeof(*ifa));
354
        }
355
 
356
        return ifa;
357
}
358
 
359
static __inline__ void dn_dev_free_ifa(struct dn_ifaddr *ifa)
360
{
361
        kfree(ifa);
362
}
363
 
364
static void dn_dev_del_ifa(struct dn_dev *dn_db, struct dn_ifaddr **ifap, int destroy)
365
{
366
        struct dn_ifaddr *ifa1 = *ifap;
367
 
368
        *ifap = ifa1->ifa_next;
369
 
370
        rtmsg_ifa(RTM_DELADDR, ifa1);
371
 
372
        if (destroy) {
373
                dn_dev_free_ifa(ifa1);
374
 
375
                if (dn_db->ifa_list == NULL)
376
                        dn_dev_delete(dn_db->dev);
377
        }
378
}
379
 
380
static int dn_dev_insert_ifa(struct dn_dev *dn_db, struct dn_ifaddr *ifa)
381
{
382
        /*
383
         * FIXME: Duplicate check here.
384
         */
385
 
386
        ifa->ifa_next = dn_db->ifa_list;
387
        dn_db->ifa_list = ifa;
388
 
389
        rtmsg_ifa(RTM_NEWADDR, ifa);
390
 
391
        return 0;
392
}
393
 
394
static int dn_dev_set_ifa(struct net_device *dev, struct dn_ifaddr *ifa)
395
{
396
        struct dn_dev *dn_db = dev->dn_ptr;
397
 
398
        if (dn_db == NULL) {
399
                int err;
400
                dn_db = dn_dev_create(dev, &err);
401
                if (dn_db == NULL)
402
                        return err;
403
        }
404
 
405
        ifa->ifa_dev = dn_db;
406
 
407
        if (dev->flags & IFF_LOOPBACK)
408
                ifa->ifa_scope = RT_SCOPE_HOST;
409
 
410
        return dn_dev_insert_ifa(dn_db, ifa);
411
}
412
 
413
 
414
int dn_dev_ioctl(unsigned int cmd, void *arg)
415
{
416
        char buffer[DN_IFREQ_SIZE];
417
        struct ifreq *ifr = (struct ifreq *)buffer;
418
        struct sockaddr_dn *sdn = (struct sockaddr_dn *)&ifr->ifr_addr;
419
        struct dn_dev *dn_db;
420
        struct net_device *dev;
421
        struct dn_ifaddr *ifa = NULL, **ifap = NULL;
422
        int exclusive = 0;
423
        int ret = 0;
424
 
425
        if (copy_from_user(ifr, arg, DN_IFREQ_SIZE))
426
                return -EFAULT;
427
        ifr->ifr_name[IFNAMSIZ-1] = 0;
428
 
429
#ifdef CONFIG_KMOD
430
        dev_load(ifr->ifr_name);
431
#endif
432
 
433
        switch(cmd) {
434
                case SIOCGIFADDR:
435
                        break;
436
                case SIOCSIFADDR:
437
                        if (!capable(CAP_NET_ADMIN))
438
                                return -EACCES;
439
                        if (sdn->sdn_family != AF_DECnet)
440
                                return -EINVAL;
441
                        rtnl_lock();
442
                        exclusive = 1;
443
                        break;
444
                default:
445
                        return -EINVAL;
446
        }
447
 
448
        if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL) {
449
                ret = -ENODEV;
450
                goto done;
451
        }
452
 
453
        if ((dn_db = dev->dn_ptr) != NULL) {
454
                for (ifap = &dn_db->ifa_list; (ifa=*ifap) != NULL; ifap = &ifa->ifa_next)
455
                        if (strcmp(ifr->ifr_name, ifa->ifa_label) == 0)
456
                                break;
457
        }
458
 
459
        if (ifa == NULL && cmd != SIOCSIFADDR) {
460
                ret = -EADDRNOTAVAIL;
461
                goto done;
462
        }
463
 
464
        switch(cmd) {
465
                case SIOCGIFADDR:
466
                        *((dn_address *)sdn->sdn_nodeaddr) = ifa->ifa_local;
467
                        goto rarok;
468
 
469
                case SIOCSIFADDR:
470
                        if (!ifa) {
471
                                if ((ifa = dn_dev_alloc_ifa()) == NULL) {
472
                                        ret = -ENOBUFS;
473
                                        break;
474
                                }
475
                                memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
476
                        } else {
477
                                if (ifa->ifa_local == dn_saddr2dn(sdn))
478
                                        break;
479
                                dn_dev_del_ifa(dn_db, ifap, 0);
480
                        }
481
 
482
                        ifa->ifa_local = dn_saddr2dn(sdn);
483
 
484
                        ret = dn_dev_set_ifa(dev, ifa);
485
        }
486
done:
487
        if (exclusive)
488
                rtnl_unlock();
489
 
490
        return ret;
491
rarok:
492
        if (copy_to_user(arg, ifr, DN_IFREQ_SIZE))
493
                return -EFAULT;
494
 
495
        return 0;
496
}
497
 
498
static struct dn_dev *dn_dev_by_index(int ifindex)
499
{
500
        struct net_device *dev;
501
        struct dn_dev *dn_dev = NULL;
502
        dev = dev_get_by_index(ifindex);
503
        if (dev) {
504
                dn_dev = dev->dn_ptr;
505
                dev_put(dev);
506
        }
507
 
508
        return dn_dev;
509
}
510
 
511
static int dn_dev_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
512
{
513
        struct rtattr **rta = arg;
514
        struct dn_dev *dn_db;
515
        struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
516
        struct dn_ifaddr *ifa, **ifap;
517
 
518
        if ((dn_db = dn_dev_by_index(ifm->ifa_index)) == NULL)
519
                return -EADDRNOTAVAIL;
520
 
521
        for(ifap = &dn_db->ifa_list; (ifa=*ifap) != NULL; ifap = &ifa->ifa_next) {
522
                void *tmp = rta[IFA_LOCAL-1];
523
                if ((tmp && memcmp(RTA_DATA(tmp), &ifa->ifa_local, 2)) ||
524
                                (rta[IFA_LABEL-1] && strcmp(RTA_DATA(rta[IFA_LABEL-1]), ifa->ifa_label)))
525
                        continue;
526
 
527
                dn_dev_del_ifa(dn_db, ifap, 1);
528
                return 0;
529
        }
530
 
531
        return -EADDRNOTAVAIL;
532
}
533
 
534
static int dn_dev_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
535
{
536
        struct rtattr **rta = arg;
537
        struct net_device *dev;
538
        struct dn_dev *dn_db;
539
        struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
540
        struct dn_ifaddr *ifa;
541
 
542
        if (rta[IFA_LOCAL-1] == NULL)
543
                return -EINVAL;
544
 
545
        if ((dev = __dev_get_by_index(ifm->ifa_index)) == NULL)
546
                return -ENODEV;
547
 
548
        if ((dn_db = dev->dn_ptr) == NULL) {
549
                int err;
550
                dn_db = dn_dev_create(dev, &err);
551
                if (!dn_db)
552
                        return err;
553
        }
554
 
555
        if ((ifa = dn_dev_alloc_ifa()) == NULL)
556
                return -ENOBUFS;
557
 
558
        memcpy(&ifa->ifa_local, RTA_DATA(rta[IFA_LOCAL-1]), 2);
559
        ifa->ifa_flags = ifm->ifa_flags;
560
        ifa->ifa_scope = ifm->ifa_scope;
561
        ifa->ifa_dev = dn_db;
562
        if (rta[IFA_LABEL-1])
563
                memcpy(ifa->ifa_label, RTA_DATA(rta[IFA_LABEL-1]), IFNAMSIZ);
564
        else
565
                memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
566
 
567
        return dn_dev_insert_ifa(dn_db, ifa);
568
}
569
 
570
static int dn_dev_fill_ifaddr(struct sk_buff *skb, struct dn_ifaddr *ifa,
571
                                u32 pid, u32 seq, int event)
572
{
573
        struct ifaddrmsg *ifm;
574
        struct nlmsghdr *nlh;
575
        unsigned char *b = skb->tail;
576
 
577
        nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*ifm));
578
        ifm = NLMSG_DATA(nlh);
579
 
580
        ifm->ifa_family = AF_DECnet;
581
        ifm->ifa_prefixlen = 16;
582
        ifm->ifa_flags = ifa->ifa_flags | IFA_F_PERMANENT;
583
        ifm->ifa_scope = ifa->ifa_scope;
584
        ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
585
        RTA_PUT(skb, IFA_LOCAL, 2, &ifa->ifa_local);
586
        if (ifa->ifa_label[0])
587
                RTA_PUT(skb, IFA_LABEL, IFNAMSIZ, &ifa->ifa_label);
588
        nlh->nlmsg_len = skb->tail - b;
589
        return skb->len;
590
 
591
nlmsg_failure:
592
rtattr_failure:
593
        skb_trim(skb, b - skb->data);
594
        return -1;
595
}
596
 
597
static void rtmsg_ifa(int event, struct dn_ifaddr *ifa)
598
{
599
        struct sk_buff *skb;
600
        int size = NLMSG_SPACE(sizeof(struct ifaddrmsg)+128);
601
 
602
        skb = alloc_skb(size, GFP_KERNEL);
603
        if (!skb) {
604
                netlink_set_err(rtnl, 0, RTMGRP_DECnet_IFADDR, ENOBUFS);
605
                return;
606
        }
607
        if (dn_dev_fill_ifaddr(skb, ifa, 0, 0, event) < 0) {
608
                kfree_skb(skb);
609
                netlink_set_err(rtnl, 0, RTMGRP_DECnet_IFADDR, EINVAL);
610
                return;
611
        }
612
        NETLINK_CB(skb).dst_groups = RTMGRP_DECnet_IFADDR;
613
        netlink_broadcast(rtnl, skb, 0, RTMGRP_DECnet_IFADDR, GFP_KERNEL);
614
}
615
 
616
static int dn_dev_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
617
{
618
        int idx, dn_idx;
619
        int s_idx, s_dn_idx;
620
        struct net_device *dev;
621
        struct dn_dev *dn_db;
622
        struct dn_ifaddr *ifa;
623
 
624
        s_idx = cb->args[0];
625
        s_dn_idx = dn_idx = cb->args[1];
626
        read_lock(&dev_base_lock);
627
        for(dev = dev_base, idx = 0; dev; dev = dev->next) {
628
                if ((dn_db = dev->dn_ptr) == NULL)
629
                        continue;
630
                idx++;
631
                if (idx < s_idx)
632
                        continue;
633
                if (idx > s_idx)
634
                        s_dn_idx = 0;
635
                if ((dn_db = dev->dn_ptr) == NULL)
636
                        continue;
637
 
638
                for(ifa = dn_db->ifa_list, dn_idx = 0; ifa; ifa = ifa->ifa_next, dn_idx++) {
639
                        if (dn_idx < s_dn_idx)
640
                                continue;
641
 
642
                        if (dn_dev_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, RTM_NEWADDR) <= 0)
643
                                goto done;
644
                }
645
        }
646
done:
647
        read_unlock(&dev_base_lock);
648
        cb->args[0] = idx;
649
        cb->args[1] = dn_idx;
650
 
651
        return skb->len;
652
}
653
 
654
static void dn_send_endnode_hello(struct net_device *dev)
655
{
656
        struct endnode_hello_message *msg;
657
        struct sk_buff *skb = NULL;
658
        unsigned short int *pktlen;
659
        struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr;
660
 
661
        if ((skb = dn_alloc_skb(NULL, sizeof(*msg), GFP_ATOMIC)) == NULL)
662
                return;
663
 
664
        skb->dev = dev;
665
 
666
        msg = (struct endnode_hello_message *)skb_put(skb,sizeof(*msg));
667
 
668
        msg->msgflg  = 0x0D;
669
        memcpy(msg->tiver, dn_eco_version, 3);
670
        memcpy(msg->id, decnet_ether_address, 6);
671
        msg->iinfo   = DN_RT_INFO_ENDN;
672
        msg->blksize = dn_htons(dn_db->parms.blksize);
673
        msg->area    = 0x00;
674
        memset(msg->seed, 0, 8);
675
        memcpy(msg->neighbor, dn_hiord, ETH_ALEN);
676
 
677
        if (dn_db->router) {
678
                struct dn_neigh *dn = (struct dn_neigh *)dn_db->router;
679
                dn_dn2eth(msg->neighbor, dn->addr);
680
        }
681
 
682
        msg->timer   = dn_htons((unsigned short)dn_db->parms.t3);
683
        msg->mpd     = 0x00;
684
        msg->datalen = 0x02;
685
        memset(msg->data, 0xAA, 2);
686
 
687
        pktlen = (unsigned short *)skb_push(skb,2);
688
        *pktlen = dn_htons(skb->len - 2);
689
 
690
        skb->nh.raw = skb->data;
691
 
692
        dn_rt_finish_output(skb, dn_rt_all_rt_mcast);
693
}
694
 
695
 
696
#ifdef CONFIG_DECNET_ROUTER
697
 
698
#define DRDELAY (5 * HZ)
699
 
700
static int dn_am_i_a_router(struct dn_neigh *dn, struct dn_dev *dn_db)
701
{
702
        /* First check time since device went up */
703
        if ((jiffies - dn_db->uptime) < DRDELAY)
704
                return 0;
705
 
706
        /* If there is no router, then yes... */
707
        if (!dn_db->router)
708
                return 1;
709
 
710
        /* otherwise only if we have a higher priority or.. */
711
        if (dn->priority < dn_db->parms.priority)
712
                return 1;
713
 
714
        /* if we have equal priority and a higher node number */
715
        if (dn->priority != dn_db->parms.priority)
716
                return 0;
717
 
718
        if (dn_ntohs(dn->addr) < dn_ntohs(decnet_address))
719
                return 1;
720
 
721
        return 0;
722
}
723
 
724
static void dn_send_router_hello(struct net_device *dev)
725
{
726
        int n;
727
        struct dn_dev *dn_db = dev->dn_ptr;
728
        struct dn_neigh *dn = (struct dn_neigh *)dn_db->router;
729
        struct sk_buff *skb;
730
        size_t size;
731
        unsigned char *ptr;
732
        unsigned char *i1, *i2;
733
        unsigned short *pktlen;
734
 
735
        if (dn_db->parms.blksize < (26 + 7))
736
                return;
737
 
738
        n = dn_db->parms.blksize - 26;
739
        n /= 7;
740
 
741
        if (n > 32)
742
                n = 32;
743
 
744
        size = 2 + 26 + 7 * n;
745
 
746
        if ((skb = dn_alloc_skb(NULL, size, GFP_ATOMIC)) == NULL)
747
                return;
748
 
749
        skb->dev = dev;
750
        ptr = skb_put(skb, size);
751
 
752
        *ptr++ = DN_RT_PKT_CNTL | DN_RT_PKT_ERTH;
753
        *ptr++ = 2; /* ECO */
754
        *ptr++ = 0;
755
        *ptr++ = 0;
756
        memcpy(ptr, decnet_ether_address, ETH_ALEN);
757
        ptr += ETH_ALEN;
758
        *ptr++ = dn_db->parms.forwarding == 1 ?
759
                        DN_RT_INFO_L1RT : DN_RT_INFO_L2RT;
760
        *((unsigned short *)ptr) = dn_htons(dn_db->parms.blksize);
761
        ptr += 2;
762
        *ptr++ = dn_db->parms.priority; /* Priority */
763
        *ptr++ = 0; /* Area: Reserved */
764
        *((unsigned short *)ptr) = dn_htons((unsigned short)dn_db->parms.t3);
765
        ptr += 2;
766
        *ptr++ = 0; /* MPD: Reserved */
767
        i1 = ptr++;
768
        memset(ptr, 0, 7); /* Name: Reserved */
769
        ptr += 7;
770
        i2 = ptr++;
771
 
772
        n = dn_neigh_elist(dev, ptr, n);
773
 
774
        *i2 = 7 * n;
775
        *i1 = 8 + *i2;
776
 
777
        skb_trim(skb, (27 + *i2));
778
 
779
        pktlen = (unsigned short *)skb_push(skb, 2);
780
        *pktlen = dn_htons(skb->len - 2);
781
 
782
        skb->nh.raw = skb->data;
783
 
784
        if (dn_am_i_a_router(dn, dn_db)) {
785
                struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
786
                if (skb2) {
787
                        dn_rt_finish_output(skb2, dn_rt_all_end_mcast);
788
                }
789
        }
790
 
791
        dn_rt_finish_output(skb, dn_rt_all_rt_mcast);
792
}
793
 
794
static void dn_send_brd_hello(struct net_device *dev)
795
{
796
        struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr;
797
 
798
        if (dn_db->parms.forwarding == 0)
799
                dn_send_endnode_hello(dev);
800
        else
801
                dn_send_router_hello(dev);
802
}
803
#else
804
static void dn_send_brd_hello(struct net_device *dev)
805
{
806
        dn_send_endnode_hello(dev);
807
}
808
#endif
809
 
810
#if 0
811
static void dn_send_ptp_hello(struct net_device *dev)
812
{
813
        int tdlen = 16;
814
        int size = dev->hard_header_len + 2 + 4 + tdlen;
815
        struct sk_buff *skb = dn_alloc_skb(NULL, size, GFP_ATOMIC);
816
        struct dn_dev *dn_db = dev->dn_ptr;
817
        int i;
818
        unsigned char *ptr;
819
        struct dn_neigh *dn = (struct dn_neigh *)dn_db->router;
820
 
821
        if (skb == NULL)
822
                return ;
823
 
824
        skb->dev = dev;
825
        skb_push(skb, dev->hard_header_len);
826
        ptr = skb_put(skb, 2 + 4 + tdlen);
827
 
828
        *ptr++ = DN_RT_PKT_HELO;
829
        *((dn_address *)ptr) = decnet_address;
830
        ptr += 2;
831
        *ptr++ = tdlen;
832
 
833
        for(i = 0; i < tdlen; i++)
834
                *ptr++ = 0252;
835
 
836
        if (dn_am_i_a_router(dn, dn_db)) {
837
                struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
838
                if (skb2) {
839
                        dn_rt_finish_output(skb2, dn_rt_all_end_mcast);
840
                }
841
        }
842
 
843
        dn_rt_finish_output(skb, dn_rt_all_rt_mcast);
844
}
845
#endif
846
 
847
static int dn_eth_up(struct net_device *dev)
848
{
849
        struct dn_dev *dn_db = dev->dn_ptr;
850
 
851
        if (dn_db->parms.forwarding == 0)
852
                dev_mc_add(dev, dn_rt_all_end_mcast, ETH_ALEN, 0);
853
        else
854
                dev_mc_add(dev, dn_rt_all_rt_mcast, ETH_ALEN, 0);
855
 
856
        dev_mc_upload(dev);
857
 
858
        dn_db->use_long = 1;
859
 
860
        return 0;
861
}
862
 
863
static void dn_dev_set_timer(struct net_device *dev);
864
 
865
static void dn_dev_timer_func(unsigned long arg)
866
{
867
        struct net_device *dev = (struct net_device *)arg;
868
        struct dn_dev *dn_db = dev->dn_ptr;
869
 
870
        if (dn_db->t3 <= dn_db->parms.t2) {
871
                if (dn_db->parms.timer3)
872
                        dn_db->parms.timer3(dev);
873
                dn_db->t3 = dn_db->parms.t3;
874
        } else {
875
                dn_db->t3 -= dn_db->parms.t2;
876
        }
877
 
878
        dn_dev_set_timer(dev);
879
}
880
 
881
static void dn_dev_set_timer(struct net_device *dev)
882
{
883
        struct dn_dev *dn_db = dev->dn_ptr;
884
 
885
        if (dn_db->parms.t2 > dn_db->parms.t3)
886
                dn_db->parms.t2 = dn_db->parms.t3;
887
 
888
        dn_db->timer.data = (unsigned long)dev;
889
        dn_db->timer.function = dn_dev_timer_func;
890
        dn_db->timer.expires = jiffies + (dn_db->parms.t2 * HZ);
891
 
892
        add_timer(&dn_db->timer);
893
}
894
 
895
struct dn_dev *dn_dev_create(struct net_device *dev, int *err)
896
{
897
        int i;
898
        struct dn_dev_parms *p = dn_dev_list;
899
        struct dn_dev *dn_db;
900
 
901
        for(i = 0; i < DN_DEV_LIST_SIZE; i++, p++) {
902
                if (p->type == dev->type)
903
                        break;
904
        }
905
 
906
        *err = -ENODEV;
907
        if (i == DN_DEV_LIST_SIZE)
908
                return NULL;
909
 
910
        *err = -ENOBUFS;
911
        if ((dn_db = kmalloc(sizeof(struct dn_dev), GFP_ATOMIC)) == NULL)
912
                return NULL;
913
 
914
        memset(dn_db, 0, sizeof(struct dn_dev));
915
        memcpy(&dn_db->parms, p, sizeof(struct dn_dev_parms));
916
        dev->dn_ptr = dn_db;
917
        dn_db->dev = dev;
918
        init_timer(&dn_db->timer);
919
 
920
        memcpy(dn_db->addr, decnet_ether_address, ETH_ALEN); /* To go... */
921
 
922
        dn_db->uptime = jiffies;
923
        if (dn_db->parms.up) {
924
                if (dn_db->parms.up(dev) < 0) {
925
                        dev->dn_ptr = NULL;
926
                        kfree(dn_db);
927
                        return NULL;
928
                }
929
        }
930
 
931
        dn_db->neigh_parms = neigh_parms_alloc(dev, &dn_neigh_table);
932
        /* dn_db->neigh_parms->neigh_setup = dn_db->parms.neigh_setup; */
933
 
934
        dn_dev_sysctl_register(dev, &dn_db->parms);
935
 
936
        dn_dev_set_timer(dev);
937
 
938
        *err = 0;
939
        return dn_db;
940
}
941
 
942
 
943
/*
944
 * This processes a device up event. We only start up
945
 * the loopback device & ethernet devices with correct
946
 * MAC addreses automatically. Others must be started
947
 * specifically.
948
 */
949
void dn_dev_up(struct net_device *dev)
950
{
951
        struct dn_ifaddr *ifa;
952
 
953
        if ((dev->type != ARPHRD_ETHER) && (dev->type != ARPHRD_LOOPBACK))
954
                return;
955
 
956
        if (dev->type == ARPHRD_ETHER)
957
                if (memcmp(dev->dev_addr, decnet_ether_address, ETH_ALEN) != 0)
958
                        return;
959
 
960
        if ((ifa = dn_dev_alloc_ifa()) == NULL)
961
                return;
962
 
963
        ifa->ifa_local = decnet_address;
964
        ifa->ifa_flags = 0;
965
        ifa->ifa_scope = RT_SCOPE_UNIVERSE;
966
        strcpy(ifa->ifa_label, dev->name);
967
 
968
        dn_dev_set_ifa(dev, ifa);
969
}
970
 
971
static void dn_dev_delete(struct net_device *dev)
972
{
973
        struct dn_dev *dn_db = dev->dn_ptr;
974
 
975
        if (dn_db == NULL)
976
                return;
977
 
978
        del_timer_sync(&dn_db->timer);
979
 
980
        dn_dev_sysctl_unregister(&dn_db->parms);
981
 
982
        neigh_ifdown(&dn_neigh_table, dev);
983
 
984
        if (dev == decnet_default_device)
985
                decnet_default_device = NULL;
986
 
987
        if (dn_db->parms.down)
988
                dn_db->parms.down(dev);
989
 
990
        dev->dn_ptr = NULL;
991
 
992
        neigh_parms_release(&dn_neigh_table, dn_db->neigh_parms);
993
 
994
        if (dn_db->router)
995
                neigh_release(dn_db->router);
996
        if (dn_db->peer)
997
                neigh_release(dn_db->peer);
998
 
999
        kfree(dn_db);
1000
}
1001
 
1002
void dn_dev_down(struct net_device *dev)
1003
{
1004
        struct dn_dev *dn_db = dev->dn_ptr;
1005
        struct dn_ifaddr *ifa;
1006
 
1007
        if (dn_db == NULL)
1008
                return;
1009
 
1010
        while((ifa = dn_db->ifa_list) != NULL) {
1011
                dn_dev_del_ifa(dn_db, &dn_db->ifa_list, 0);
1012
                dn_dev_free_ifa(ifa);
1013
        }
1014
 
1015
        dn_dev_delete(dev);
1016
}
1017
 
1018
void dn_dev_init_pkt(struct sk_buff *skb)
1019
{
1020
        return;
1021
}
1022
 
1023
void dn_dev_veri_pkt(struct sk_buff *skb)
1024
{
1025
        return;
1026
}
1027
 
1028
void dn_dev_hello(struct sk_buff *skb)
1029
{
1030
        return;
1031
}
1032
 
1033
void dn_dev_devices_off(void)
1034
{
1035
        struct net_device *dev;
1036
 
1037
        for(dev = dev_base; dev; dev = dev->next)
1038
                dn_dev_down(dev);
1039
 
1040
}
1041
 
1042
void dn_dev_devices_on(void)
1043
{
1044
        struct net_device *dev;
1045
 
1046
        for(dev = dev_base; dev; dev = dev->next) {
1047
                if (dev->flags & IFF_UP)
1048
                        dn_dev_up(dev);
1049
        }
1050
}
1051
 
1052
 
1053
#ifdef CONFIG_DECNET_SIOCGIFCONF
1054
/*
1055
 * Now we support multiple addresses per interface.
1056
 * Since we don't want to break existing code, you have to enable
1057
 * it as a compile time option. Probably you should use the
1058
 * rtnetlink interface instead.
1059
 */
1060
int dnet_gifconf(struct net_device *dev, char *buf, int len)
1061
{
1062
        struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr;
1063
        struct dn_ifaddr *ifa;
1064
        struct ifreq *ifr = (struct ifreq *)buf;
1065
        int done = 0;
1066
 
1067
        if ((dn_db == NULL) || ((ifa = dn_db->ifa_list) == NULL))
1068
                return 0;
1069
 
1070
        for(; ifa; ifa = ifa->ifa_next) {
1071
                if (!ifr) {
1072
                        done += sizeof(DN_IFREQ_SIZE);
1073
                        continue;
1074
                }
1075
                if (len < DN_IFREQ_SIZE)
1076
                        return done;
1077
                memset(ifr, 0, DN_IFREQ_SIZE);
1078
 
1079
                if (ifa->ifa_label)
1080
                        strcpy(ifr->ifr_name, ifa->ifa_label);
1081
                else
1082
                        strcpy(ifr->ifr_name, dev->name);
1083
 
1084
                (*(struct sockaddr_dn *) &ifr->ifr_addr).sdn_family = AF_DECnet;
1085
                (*(struct sockaddr_dn *) &ifr->ifr_addr).sdn_add.a_len = 2;
1086
                (*(dn_address *)(*(struct sockaddr_dn *) &ifr->ifr_addr).sdn_add.a_addr) = ifa->ifa_local;
1087
 
1088
                ifr = (struct ifreq *)((char *)ifr + DN_IFREQ_SIZE);
1089
                len  -= DN_IFREQ_SIZE;
1090
                done += DN_IFREQ_SIZE;
1091
        }
1092
 
1093
        return done;
1094
}
1095
#endif /* CONFIG_DECNET_SIOCGIFCONF */
1096
 
1097
 
1098
#ifdef CONFIG_PROC_FS
1099
 
1100
static char *dn_type2asc(char type)
1101
{
1102
        switch(type) {
1103
                case DN_DEV_BCAST:
1104
                        return "B";
1105
                case DN_DEV_UCAST:
1106
                        return "U";
1107
                case DN_DEV_MPOINT:
1108
                        return "M";
1109
        }
1110
 
1111
        return "?";
1112
}
1113
 
1114
static int decnet_dev_get_info(char *buffer, char **start, off_t offset, int length)
1115
{
1116
        struct dn_dev *dn_db;
1117
        struct net_device *dev;
1118
        int len = 0;
1119
        off_t pos = 0;
1120
        off_t begin = 0;
1121
        char peer_buf[DN_ASCBUF_LEN];
1122
        char router_buf[DN_ASCBUF_LEN];
1123
 
1124
 
1125
        len += sprintf(buffer, "Name     Flags T1   Timer1 T3   Timer3 BlkSize Pri State DevType    Router Peer\n");
1126
 
1127
        read_lock(&dev_base_lock);
1128
        for (dev = dev_base; dev; dev = dev->next) {
1129
                if ((dn_db = (struct dn_dev *)dev->dn_ptr) == NULL)
1130
                        continue;
1131
 
1132
                len += sprintf(buffer + len, "%-8s %1s     %04u %04u   %04lu %04lu   %04hu    %03d %02x    %-10s %-7s %-7s\n",
1133
                                dev->name ? dev->name : "???",
1134
                                dn_type2asc(dn_db->parms.mode),
1135
                                0, 0,
1136
                                dn_db->t3, dn_db->parms.t3,
1137
                                dn_db->parms.blksize,
1138
                                dn_db->parms.priority,
1139
                                dn_db->parms.state, dn_db->parms.name,
1140
                                dn_db->router ? dn_addr2asc(dn_ntohs(*(dn_address *)dn_db->router->primary_key), router_buf) : "",
1141
                                dn_db->peer ? dn_addr2asc(dn_ntohs(*(dn_address *)dn_db->peer->primary_key), peer_buf) : "");
1142
 
1143
 
1144
                pos = begin + len;
1145
 
1146
                if (pos < offset) {
1147
                        len   = 0;
1148
                        begin = pos;
1149
                }
1150
                if (pos > offset + length)
1151
                        break;
1152
        }
1153
 
1154
        read_unlock(&dev_base_lock);
1155
 
1156
        *start = buffer + (offset - begin);
1157
        len   -= (offset - begin);
1158
 
1159
        if (len > length) len = length;
1160
 
1161
        return(len);
1162
}
1163
 
1164
#endif /* CONFIG_PROC_FS */
1165
 
1166
static struct rtnetlink_link dnet_rtnetlink_table[RTM_MAX-RTM_BASE+1] =
1167
{
1168
        { NULL,                 NULL,                   },
1169
        { NULL,                 NULL,                   },
1170
        { NULL,                 NULL,                   },
1171
        { NULL,                 NULL,                   },
1172
 
1173
        { dn_dev_rtm_newaddr,   NULL,                   },
1174
        { dn_dev_rtm_deladdr,   NULL,                   },
1175
        { NULL,                 dn_dev_dump_ifaddr,     },
1176
        { NULL,                 NULL,                   },
1177
 
1178
#ifdef CONFIG_DECNET_ROUTER
1179
        { dn_fib_rtm_newroute,  NULL,                   },
1180
        { dn_fib_rtm_delroute,  NULL,                   },
1181
        { dn_cache_getroute,    dn_fib_dump,            },
1182
        { NULL,                 NULL,                   },
1183
#else
1184
        { NULL,                 NULL,                   },
1185
        { NULL,                 NULL,                   },
1186
        { dn_cache_getroute,    dn_cache_dump,          },
1187
        { NULL,                 NULL,                   },
1188
#endif
1189
        { NULL,                 NULL,                   },
1190
        { NULL,                 NULL,                   },
1191
        { NULL,                 NULL,                   },
1192
        { NULL,                 NULL,                   },
1193
 
1194
#ifdef CONFIG_DECNET_ROUTER
1195
        { dn_fib_rtm_newrule,   NULL,                   },
1196
        { dn_fib_rtm_delrule,   NULL,                   },
1197
        { NULL,                 dn_fib_dump_rules,      },
1198
        { NULL,                 NULL,                   }
1199
#else
1200
        { NULL,                 NULL,                   },
1201
        { NULL,                 NULL,                   },
1202
        { NULL,                 NULL,                   },
1203
        { NULL,                 NULL,                   }
1204
#endif
1205
};
1206
 
1207
void __init dn_dev_init(void)
1208
{
1209
 
1210
        dn_dev_devices_on();
1211
#ifdef CONFIG_DECNET_SIOCGIFCONF
1212
        register_gifconf(PF_DECnet, dnet_gifconf);
1213
#endif /* CONFIG_DECNET_SIOCGIFCONF */
1214
 
1215
        rtnetlink_links[PF_DECnet] = dnet_rtnetlink_table;
1216
 
1217
#ifdef CONFIG_PROC_FS
1218
        proc_net_create("decnet_dev", 0, decnet_dev_get_info);
1219
#endif /* CONFIG_PROC_FS */
1220
 
1221
#ifdef CONFIG_SYSCTL
1222
        {
1223
                int i;
1224
                for(i = 0; i < DN_DEV_LIST_SIZE; i++)
1225
                        dn_dev_sysctl_register(NULL, &dn_dev_list[i]);
1226
        }
1227
#endif /* CONFIG_SYSCTL */
1228
}
1229
 
1230
void __exit dn_dev_cleanup(void)
1231
{
1232
        rtnetlink_links[PF_DECnet] = NULL;
1233
 
1234
#ifdef CONFIG_DECNET_SIOCGIFCONF
1235
        unregister_gifconf(PF_DECnet);
1236
#endif /* CONFIG_DECNET_SIOCGIFCONF */
1237
 
1238
#ifdef CONFIG_SYSCTL
1239
        {
1240
                int i;
1241
                for(i = 0; i < DN_DEV_LIST_SIZE; i++)
1242
                        dn_dev_sysctl_unregister(&dn_dev_list[i]);
1243
        }
1244
#endif /* CONFIG_SYSCTL */
1245
 
1246
        proc_net_remove("decnet_dev");
1247
 
1248
        dn_dev_devices_off();
1249
}

powered by: WebSVN 2.1.0

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