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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *      AX.25 release 037
3
 *
4
 *      This code REQUIRES 2.1.15 or higher/ NET3.038
5
 *
6
 *      This module:
7
 *              This module is free software; you can redistribute it and/or
8
 *              modify it under the terms of the GNU General Public License
9
 *              as published by the Free Software Foundation; either version
10
 *              2 of the License, or (at your option) any later version.
11
 *
12
 *      Other kernels modules in this kit are generally BSD derived. See the copyright headers.
13
 *
14
 *
15
 *      History
16
 *      AX.25 020       Jonathan(G4KLX) First go.
17
 *      AX.25 022       Jonathan(G4KLX) Added the actual meat to this - we now have a nice heard list.
18
 *      AX.25 025       Alan(GW4PTS)    First cut at autobinding by route scan.
19
 *      AX.25 028b      Jonathan(G4KLX) Extracted AX25 control block from the
20
 *                                      sock structure. Device removal now
21
 *                                      removes the heard structure.
22
 *      AX.25 029       Steven(GW7RRM)  Added /proc information for uid/callsign mapping.
23
 *                      Jonathan(G4KLX) Handling of IP mode in the routing list and /proc entry.
24
 *      AX.25 030       Jonathan(G4KLX) Added digi-peaters to routing table, and
25
 *                                      ioctls to manipulate them. Added port
26
 *                                      configuration.
27
 *      AX.25 031       Jonathan(G4KLX) Added concept of default route.
28
 *                      Joerg(DL1BKE)   ax25_rt_build_path() find digipeater list and device by
29
 *                                      destination call. Needed for IP routing via digipeater
30
 *                      Jonathan(G4KLX) Added routing for IP datagram packets.
31
 *                      Joerg(DL1BKE)   Changed routing for IP datagram and VC to use a default
32
 *                                      route if available. Does not overwrite default routes
33
 *                                      on route-table overflow anymore.
34
 *                      Joerg(DL1BKE)   Fixed AX.25 routing of IP datagram and VC, new ioctl()
35
 *                                      "SIOCAX25OPTRT" to set IP mode and a 'permanent' flag
36
 *                                      on routes.
37
 *      AX.25 033       Jonathan(G4KLX) Remove auto-router.
38
 *                      Joerg(DL1BKE)   Moved BPQ Ethernet driver to separate device.
39
 *      AX.25 035       Frederic(F1OAT) Support for pseudo-digipeating.
40
 *                      Jonathan(G4KLX) Support for packet forwarding.
41
 *                      Arnaldo C. Melo s/suser/capable/
42
 */
43
 
44
#include <linux/errno.h>
45
#include <linux/types.h>
46
#include <linux/socket.h>
47
#include <linux/in.h>
48
#include <linux/kernel.h>
49
#include <linux/sched.h>
50
#include <linux/timer.h>
51
#include <linux/string.h>
52
#include <linux/sockios.h>
53
#include <linux/net.h>
54
#include <net/ax25.h>
55
#include <linux/inet.h>
56
#include <linux/netdevice.h>
57
#include <linux/if_arp.h>
58
#include <linux/skbuff.h>
59
#include <net/sock.h>
60
#include <asm/uaccess.h>
61
#include <asm/system.h>
62
#include <linux/fcntl.h>
63
#include <linux/mm.h>
64
#include <linux/interrupt.h>
65
#include <linux/init.h>
66
 
67
static ax25_route *ax25_route_list;
68
 
69
static ax25_route *ax25_find_route(ax25_address *, struct net_device *);
70
 
71
/*
72
 * small macro to drop non-digipeated digipeaters and reverse path
73
 */
74
static inline void ax25_route_invert(ax25_digi *in, ax25_digi *out)
75
{
76
        int k;
77
 
78
        for (k = 0; k < in->ndigi; k++)
79
                if (!in->repeated[k])
80
                        break;
81
 
82
        in->ndigi = k;
83
 
84
        ax25_digi_invert(in, out);
85
}
86
 
87
void ax25_rt_device_down(struct net_device *dev)
88
{
89
        ax25_route *s, *t, *ax25_rt = ax25_route_list;
90
 
91
        while (ax25_rt != NULL) {
92
                s       = ax25_rt;
93
                ax25_rt = ax25_rt->next;
94
 
95
                if (s->dev == dev) {
96
                        if (ax25_route_list == s) {
97
                                ax25_route_list = s->next;
98
                                if (s->digipeat != NULL)
99
                                        kfree(s->digipeat);
100
                                kfree(s);
101
                        } else {
102
                                for (t = ax25_route_list; t != NULL; t = t->next) {
103
                                        if (t->next == s) {
104
                                                t->next = s->next;
105
                                                if (s->digipeat != NULL)
106
                                                        kfree(s->digipeat);
107
                                                kfree(s);
108
                                                break;
109
                                        }
110
                                }
111
                        }
112
                }
113
        }
114
}
115
 
116
int ax25_rt_ioctl(unsigned int cmd, void *arg)
117
{
118
        unsigned long flags;
119
        ax25_route *s, *t, *ax25_rt;
120
        struct ax25_routes_struct route;
121
        struct ax25_route_opt_struct rt_option;
122
        ax25_dev *ax25_dev;
123
        int i;
124
 
125
        switch (cmd) {
126
                case SIOCADDRT:
127
                        if (copy_from_user(&route, arg, sizeof(route)))
128
                                return -EFAULT;
129
                        if ((ax25_dev = ax25_addr_ax25dev(&route.port_addr)) == NULL)
130
                                return -EINVAL;
131
                        if (route.digi_count > AX25_MAX_DIGIS)
132
                                return -EINVAL;
133
                        for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
134
                                if (ax25cmp(&ax25_rt->callsign, &route.dest_addr) == 0 && ax25_rt->dev == ax25_dev->dev) {
135
                                        if (ax25_rt->digipeat != NULL) {
136
                                                kfree(ax25_rt->digipeat);
137
                                                ax25_rt->digipeat = NULL;
138
                                        }
139
                                        if (route.digi_count != 0) {
140
                                                if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL)
141
                                                        return -ENOMEM;
142
                                                ax25_rt->digipeat->lastrepeat = -1;
143
                                                ax25_rt->digipeat->ndigi      = route.digi_count;
144
                                                for (i = 0; i < route.digi_count; i++) {
145
                                                        ax25_rt->digipeat->repeated[i] = 0;
146
                                                        ax25_rt->digipeat->calls[i]    = route.digi_addr[i];
147
                                                }
148
                                        }
149
                                        return 0;
150
                                }
151
                        }
152
                        if ((ax25_rt = kmalloc(sizeof(ax25_route), GFP_ATOMIC)) == NULL)
153
                                return -ENOMEM;
154
                        ax25_rt->callsign     = route.dest_addr;
155
                        ax25_rt->dev          = ax25_dev->dev;
156
                        ax25_rt->digipeat     = NULL;
157
                        ax25_rt->ip_mode      = ' ';
158
                        if (route.digi_count != 0) {
159
                                if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
160
                                        kfree(ax25_rt);
161
                                        return -ENOMEM;
162
                                }
163
                                ax25_rt->digipeat->lastrepeat = -1;
164
                                ax25_rt->digipeat->ndigi      = route.digi_count;
165
                                for (i = 0; i < route.digi_count; i++) {
166
                                        ax25_rt->digipeat->repeated[i] = 0;
167
                                        ax25_rt->digipeat->calls[i]    = route.digi_addr[i];
168
                                }
169
                        }
170
                        save_flags(flags); cli();
171
                        ax25_rt->next   = ax25_route_list;
172
                        ax25_route_list = ax25_rt;
173
                        restore_flags(flags);
174
                        break;
175
 
176
                case SIOCDELRT:
177
                        if (copy_from_user(&route, arg, sizeof(route)))
178
                                return -EFAULT;
179
                        if ((ax25_dev = ax25_addr_ax25dev(&route.port_addr)) == NULL)
180
                                return -EINVAL;
181
                        ax25_rt = ax25_route_list;
182
                        while (ax25_rt != NULL) {
183
                                s       = ax25_rt;
184
                                ax25_rt = ax25_rt->next;
185
                                if (s->dev == ax25_dev->dev && ax25cmp(&route.dest_addr, &s->callsign) == 0) {
186
                                        if (ax25_route_list == s) {
187
                                                ax25_route_list = s->next;
188
                                                if (s->digipeat != NULL)
189
                                                        kfree(s->digipeat);
190
                                                kfree(s);
191
                                        } else {
192
                                                for (t = ax25_route_list; t != NULL; t = t->next) {
193
                                                        if (t->next == s) {
194
                                                                t->next = s->next;
195
                                                                if (s->digipeat != NULL)
196
                                                                        kfree(s->digipeat);
197
                                                                kfree(s);
198
                                                                break;
199
                                                        }
200
                                                }
201
                                        }
202
                                }
203
                        }
204
                        break;
205
 
206
                case SIOCAX25OPTRT:
207
                        if (copy_from_user(&rt_option, arg, sizeof(rt_option)))
208
                                return -EFAULT;
209
                        if ((ax25_dev = ax25_addr_ax25dev(&rt_option.port_addr)) == NULL)
210
                                return -EINVAL;
211
                        for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
212
                                if (ax25_rt->dev == ax25_dev->dev && ax25cmp(&rt_option.dest_addr, &ax25_rt->callsign) == 0) {
213
                                        switch (rt_option.cmd) {
214
                                                case AX25_SET_RT_IPMODE:
215
                                                        switch (rt_option.arg) {
216
                                                                case ' ':
217
                                                                case 'D':
218
                                                                case 'V':
219
                                                                        ax25_rt->ip_mode = rt_option.arg;
220
                                                                        break;
221
                                                                default:
222
                                                                        return -EINVAL;
223
                                                        }
224
                                                        break;
225
                                                default:
226
                                                        return -EINVAL;
227
                                        }
228
                                }
229
                        }
230
                        break;
231
 
232
                default:
233
                        return -EINVAL;
234
        }
235
 
236
        return 0;
237
}
238
 
239
int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length)
240
{
241
        ax25_route *ax25_rt;
242
        int len     = 0;
243
        off_t pos   = 0;
244
        off_t begin = 0;
245
        char *callsign;
246
        int i;
247
 
248
        cli();
249
 
250
        len += sprintf(buffer, "callsign  dev  mode digipeaters\n");
251
 
252
        for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
253
                if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0)
254
                        callsign = "default";
255
                else
256
                        callsign = ax2asc(&ax25_rt->callsign);
257
                len += sprintf(buffer + len, "%-9s %-4s",
258
                        callsign,
259
                        ax25_rt->dev ? ax25_rt->dev->name : "???");
260
 
261
                switch (ax25_rt->ip_mode) {
262
                        case 'V':
263
                                len += sprintf(buffer + len, "   vc");
264
                                break;
265
                        case 'D':
266
                                len += sprintf(buffer + len, "   dg");
267
                                break;
268
                        default:
269
                                len += sprintf(buffer + len, "    *");
270
                                break;
271
                }
272
 
273
                if (ax25_rt->digipeat != NULL)
274
                        for (i = 0; i < ax25_rt->digipeat->ndigi; i++)
275
                                len += sprintf(buffer + len, " %s", ax2asc(&ax25_rt->digipeat->calls[i]));
276
 
277
                len += sprintf(buffer + len, "\n");
278
 
279
                pos = begin + len;
280
 
281
                if (pos < offset) {
282
                        len   = 0;
283
                        begin = pos;
284
                }
285
 
286
                if (pos > offset + length)
287
                        break;
288
        }
289
 
290
        sti();
291
 
292
        *start = buffer + (offset - begin);
293
        len   -= (offset - begin);
294
 
295
        if (len > length) len = length;
296
 
297
        return len;
298
}
299
 
300
/*
301
 *      Find AX.25 route
302
 */
303
static ax25_route *ax25_find_route(ax25_address *addr, struct net_device *dev)
304
{
305
        ax25_route *ax25_spe_rt = NULL;
306
        ax25_route *ax25_def_rt = NULL;
307
        ax25_route *ax25_rt;
308
 
309
        /*
310
         *      Bind to the physical interface we heard them on, or the default
311
         *      route if none is found;
312
         */
313
        for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
314
                if (dev == NULL) {
315
                        if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev != NULL)
316
                                ax25_spe_rt = ax25_rt;
317
                        if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0 && ax25_rt->dev != NULL)
318
                                ax25_def_rt = ax25_rt;
319
                } else {
320
                        if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev == dev)
321
                                ax25_spe_rt = ax25_rt;
322
                        if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0 && ax25_rt->dev == dev)
323
                                ax25_def_rt = ax25_rt;
324
                }
325
        }
326
 
327
        if (ax25_spe_rt != NULL)
328
                return ax25_spe_rt;
329
 
330
        return ax25_def_rt;
331
}
332
 
333
/*
334
 *      Adjust path: If you specify a default route and want to connect
335
 *      a target on the digipeater path but w/o having a special route
336
 *      set before, the path has to be truncated from your target on.
337
 */
338
static inline void ax25_adjust_path(ax25_address *addr, ax25_digi *digipeat)
339
{
340
        int k;
341
 
342
        for (k = 0; k < digipeat->ndigi; k++) {
343
                if (ax25cmp(addr, &digipeat->calls[k]) == 0)
344
                        break;
345
        }
346
 
347
        digipeat->ndigi = k;
348
}
349
 
350
 
351
/*
352
 *      Find which interface to use.
353
 */
354
int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr)
355
{
356
        ax25_route *ax25_rt;
357
        ax25_address *call;
358
 
359
        if ((ax25_rt = ax25_find_route(addr, NULL)) == NULL)
360
                return -EHOSTUNREACH;
361
 
362
        if ((ax25->ax25_dev = ax25_dev_ax25dev(ax25_rt->dev)) == NULL)
363
                return -EHOSTUNREACH;
364
 
365
        if ((call = ax25_findbyuid(current->euid)) == NULL) {
366
                if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE))
367
                        return -EPERM;
368
                call = (ax25_address *)ax25->ax25_dev->dev->dev_addr;
369
        }
370
 
371
        ax25->source_addr = *call;
372
 
373
        if (ax25_rt->digipeat != NULL) {
374
                if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL)
375
                        return -ENOMEM;
376
                memcpy(ax25->digipeat, ax25_rt->digipeat, sizeof(ax25_digi));
377
                ax25_adjust_path(addr, ax25->digipeat);
378
        }
379
 
380
        if (ax25->sk != NULL)
381
                ax25->sk->zapped = 0;
382
 
383
        return 0;
384
}
385
 
386
/*
387
 *      dl1bke 960117: build digipeater path
388
 *      dl1bke 960301: use the default route if it exists
389
 */
390
ax25_route *ax25_rt_find_route(ax25_address *addr, struct net_device *dev)
391
{
392
        static ax25_route route;
393
        ax25_route *ax25_rt;
394
 
395
        if ((ax25_rt = ax25_find_route(addr, dev)) == NULL) {
396
                route.next     = NULL;
397
                route.callsign = *addr;
398
                route.dev      = dev;
399
                route.digipeat = NULL;
400
                route.ip_mode  = ' ';
401
                return &route;
402
        }
403
 
404
        return ax25_rt;
405
}
406
 
407
struct sk_buff *ax25_rt_build_path(struct sk_buff *skb, ax25_address *src, ax25_address *dest, ax25_digi *digi)
408
{
409
        struct sk_buff *skbn;
410
        unsigned char *bp;
411
        int len;
412
 
413
        len = digi->ndigi * AX25_ADDR_LEN;
414
 
415
        if (skb_headroom(skb) < len) {
416
                if ((skbn = skb_realloc_headroom(skb, len)) == NULL) {
417
                        printk(KERN_CRIT "AX.25: ax25_dg_build_path - out of memory\n");
418
                        return NULL;
419
                }
420
 
421
                if (skb->sk != NULL)
422
                        skb_set_owner_w(skbn, skb->sk);
423
 
424
                kfree_skb(skb);
425
 
426
                skb = skbn;
427
        }
428
 
429
        bp = skb_push(skb, len);
430
 
431
        ax25_addr_build(bp, src, dest, digi, AX25_COMMAND, AX25_MODULUS);
432
 
433
        return skb;
434
}
435
 
436
/*
437
 *      Free all memory associated with routing structures.
438
 */
439
void __exit ax25_rt_free(void)
440
{
441
        ax25_route *s, *ax25_rt = ax25_route_list;
442
 
443
        while (ax25_rt != NULL) {
444
                s       = ax25_rt;
445
                ax25_rt = ax25_rt->next;
446
 
447
                if (s->digipeat != NULL)
448
                        kfree(s->digipeat);
449
 
450
                kfree(s);
451
        }
452
}

powered by: WebSVN 2.1.0

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