This source file includes following definitions.
- rt_del
- ip_rt_flush
- default_mask
- guess_mask
- get_gw_dev
- ip_rt_add
- bad_mask
- rt_new
- rt_kill
- rt_get_info
- ip_rt_route
- ip_rt_local
- ip_get_old_rtent
- ip_rt_ioctl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 #include <asm/segment.h>
32 #include <asm/system.h>
33 #include <linux/types.h>
34 #include <linux/kernel.h>
35 #include <linux/sched.h>
36 #include <linux/string.h>
37 #include <linux/socket.h>
38 #include <linux/sockios.h>
39 #include <linux/errno.h>
40 #include <linux/in.h>
41 #include <linux/inet.h>
42 #include <linux/netdevice.h>
43 #include "ip.h"
44 #include "protocol.h"
45 #include "route.h"
46 #include "tcp.h"
47 #include <linux/skbuff.h>
48 #include "sock.h"
49 #include "icmp.h"
50
51
52
53
54
55 static struct rtable *rt_base = NULL;
56
57
58
59
60
61 static struct rtable *rt_loopback = NULL;
62
63
64
65
66
67 static void rt_del(unsigned long dst)
68 {
69 struct rtable *r, **rp;
70 unsigned long flags;
71
72 rp = &rt_base;
73
74
75
76
77
78
79 save_flags(flags);
80 cli();
81 while((r = *rp) != NULL)
82 {
83 if (r->rt_dst != dst)
84 {
85 rp = &r->rt_next;
86 continue;
87 }
88 *rp = r->rt_next;
89
90
91
92
93
94 if (rt_loopback == r)
95 rt_loopback = NULL;
96 kfree_s(r, sizeof(struct rtable));
97 }
98 restore_flags(flags);
99 }
100
101
102
103
104
105
106
107 void ip_rt_flush(struct device *dev)
108 {
109 struct rtable *r;
110 struct rtable **rp;
111 unsigned long flags;
112
113 rp = &rt_base;
114 cli();
115 save_flags(flags);
116 while ((r = *rp) != NULL) {
117 if (r->rt_dev != dev) {
118 rp = &r->rt_next;
119 continue;
120 }
121 *rp = r->rt_next;
122 if (rt_loopback == r)
123 rt_loopback = NULL;
124 kfree_s(r, sizeof(struct rtable));
125 }
126 restore_flags(flags);
127 }
128
129
130
131
132
133
134
135
136
137 static inline unsigned long default_mask(unsigned long dst)
138 {
139 dst = ntohl(dst);
140 if (IN_CLASSA(dst))
141 return htonl(IN_CLASSA_NET);
142 if (IN_CLASSB(dst))
143 return htonl(IN_CLASSB_NET);
144 return htonl(IN_CLASSC_NET);
145 }
146
147
148
149
150
151
152 static unsigned long guess_mask(unsigned long dst, struct device * dev)
153 {
154 unsigned long mask;
155
156 if (!dst)
157 return 0;
158 mask = default_mask(dst);
159 if ((dst ^ dev->pa_addr) & mask)
160 return mask;
161 return dev->pa_mask;
162 }
163
164
165
166
167
168
169 static inline struct device * get_gw_dev(unsigned long gw)
170 {
171 struct rtable * rt;
172
173 for (rt = rt_base ; ; rt = rt->rt_next)
174 {
175 if (!rt)
176 return NULL;
177 if ((gw ^ rt->rt_dst) & rt->rt_mask)
178 continue;
179
180
181
182
183 if (rt->rt_flags & RTF_GATEWAY)
184 return NULL;
185 return rt->rt_dev;
186 }
187 }
188
189
190
191
192
193
194
195
196
197 void ip_rt_add(short flags, unsigned long dst, unsigned long mask,
198 unsigned long gw, struct device *dev, unsigned short mtu)
199 {
200 struct rtable *r, *rt;
201 struct rtable **rp;
202 unsigned long cpuflags;
203
204
205
206
207
208 if (flags & RTF_HOST)
209 {
210 mask = 0xffffffff;
211 }
212
213
214
215
216
217 else if (!mask)
218 {
219 if (!((dst ^ dev->pa_addr) & dev->pa_mask))
220 {
221 mask = dev->pa_mask;
222 flags &= ~RTF_GATEWAY;
223 if (flags & RTF_DYNAMIC)
224 {
225
226 return;
227 }
228 }
229 else
230 mask = guess_mask(dst, dev);
231 dst &= mask;
232 }
233
234
235
236
237
238 if (gw == dev->pa_addr)
239 flags &= ~RTF_GATEWAY;
240
241 if (flags & RTF_GATEWAY)
242 {
243
244
245
246
247 if (dev != get_gw_dev(gw))
248 return;
249
250 flags |= RTF_GATEWAY;
251 }
252 else
253 gw = 0;
254
255
256
257
258
259 rt = (struct rtable *) kmalloc(sizeof(struct rtable), GFP_ATOMIC);
260 if (rt == NULL)
261 {
262 return;
263 }
264 memset(rt, 0, sizeof(struct rtable));
265 rt->rt_flags = flags | RTF_UP;
266 rt->rt_dst = dst;
267 rt->rt_dev = dev;
268 rt->rt_gateway = gw;
269 rt->rt_mask = mask;
270 rt->rt_mtu = dev->mtu;
271
272
273
274 if(rt->rt_flags & RTF_MTU)
275 rt->rt_mtu = mtu;
276
277
278
279
280
281
282
283
284 save_flags(cpuflags);
285 cli();
286
287
288
289
290
291 rp = &rt_base;
292 while ((r = *rp) != NULL)
293 {
294 if (r->rt_dst != dst)
295 {
296 rp = &r->rt_next;
297 continue;
298 }
299 *rp = r->rt_next;
300 if (rt_loopback == r)
301 rt_loopback = NULL;
302 kfree_s(r, sizeof(struct rtable));
303 }
304
305
306
307
308
309 rp = &rt_base;
310 while ((r = *rp) != NULL) {
311 if ((r->rt_mask & mask) != mask)
312 break;
313 rp = &r->rt_next;
314 }
315 rt->rt_next = r;
316 *rp = rt;
317
318
319
320
321
322 if (rt->rt_dev->flags & IFF_LOOPBACK)
323 rt_loopback = rt;
324
325
326
327
328
329 restore_flags(cpuflags);
330 return;
331 }
332
333
334
335
336
337
338 static inline int bad_mask(unsigned long mask, unsigned long addr)
339 {
340 if (addr & (mask = ~mask))
341 return 1;
342 mask = ntohl(mask);
343 if (mask & (mask+1))
344 return 1;
345 return 0;
346 }
347
348
349
350
351
352 static int rt_new(struct rtentry *r)
353 {
354 int err;
355 char * devname;
356 struct device * dev = NULL;
357 unsigned long flags, daddr, mask, gw;
358
359
360
361
362
363 if ((devname = r->rt_dev) != NULL)
364 {
365 err = getname(devname, &devname);
366 if (err)
367 return err;
368 dev = dev_get(devname);
369 putname(devname);
370 if (!dev)
371 return -EINVAL;
372 }
373
374
375
376
377
378 if (r->rt_dst.sa_family != AF_INET)
379 return -EAFNOSUPPORT;
380
381
382
383
384
385 flags = r->rt_flags;
386 daddr = ((struct sockaddr_in *) &r->rt_dst)->sin_addr.s_addr;
387 mask = ((struct sockaddr_in *) &r->rt_genmask)->sin_addr.s_addr;
388 gw = ((struct sockaddr_in *) &r->rt_gateway)->sin_addr.s_addr;
389
390
391
392
393
394
395
396
397 if (!dev && (flags & RTF_GATEWAY))
398 {
399 struct device *dev2;
400 for (dev2 = dev_base ; dev2 != NULL ; dev2 = dev2->next)
401 {
402 if ((dev2->flags & IFF_UP) && dev2->pa_addr == gw)
403 {
404 flags &= ~RTF_GATEWAY;
405 dev = dev2;
406 break;
407 }
408 }
409 }
410
411
412
413
414
415 if (bad_mask(mask, daddr))
416 mask = 0;
417
418
419
420
421
422 if (flags & RTF_HOST)
423 mask = 0xffffffff;
424 else if (mask && r->rt_genmask.sa_family != AF_INET)
425 return -EAFNOSUPPORT;
426
427
428
429
430
431 if (flags & RTF_GATEWAY)
432 {
433 if (r->rt_gateway.sa_family != AF_INET)
434 return -EAFNOSUPPORT;
435 if (!dev)
436 dev = get_gw_dev(gw);
437 }
438 else if (!dev)
439 dev = ip_dev_check(daddr);
440
441
442
443
444
445 if (dev == NULL)
446 return -ENETUNREACH;
447
448
449
450
451
452 ip_rt_add(flags, daddr, mask, gw, dev, r->rt_mtu);
453 return 0;
454 }
455
456
457
458
459
460
461 static int rt_kill(struct rtentry *r)
462 {
463 struct sockaddr_in *trg;
464
465 trg = (struct sockaddr_in *) &r->rt_dst;
466 rt_del(trg->sin_addr.s_addr);
467 return 0;
468 }
469
470
471
472
473
474
475 int rt_get_info(char *buffer, char **start, off_t offset, int length)
476 {
477 struct rtable *r;
478 int len=0;
479 off_t pos=0;
480 off_t begin=0;
481 int size;
482
483 len += sprintf(buffer,
484 "Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\tMask\tMTU\n");
485 pos=len;
486
487
488
489
490
491 for (r = rt_base; r != NULL; r = r->rt_next)
492 {
493 size = sprintf(buffer+len, "%s\t%08lX\t%08lX\t%02X\t%d\t%lu\t%d\t%08lX\t%d\n",
494 r->rt_dev->name, r->rt_dst, r->rt_gateway,
495 r->rt_flags, r->rt_refcnt, r->rt_use, r->rt_metric,
496 r->rt_mask, (int)r->rt_mtu);
497 len+=size;
498 pos+=size;
499 if(pos<offset)
500 {
501 len=0;
502 begin=pos;
503 }
504 if(pos>offset+length)
505 break;
506 }
507
508 *start=buffer+(offset-begin);
509 len-=(offset-begin);
510 if(len>length)
511 len=length;
512 return len;
513 }
514
515
516
517
518
519 #define early_out ({ goto no_route; 1; })
520
521
522
523
524
525
526
527
528 struct rtable * ip_rt_route(unsigned long daddr, struct options *opt, unsigned long *src_addr)
529 {
530 struct rtable *rt;
531
532 for (rt = rt_base; rt != NULL || early_out ; rt = rt->rt_next)
533 {
534 if (!((rt->rt_dst ^ daddr) & rt->rt_mask))
535 break;
536
537
538
539
540 if ((rt->rt_dev->flags & IFF_BROADCAST) &&
541 rt->rt_dev->pa_brdaddr == daddr)
542 break;
543 }
544
545 if(src_addr!=NULL)
546 *src_addr= rt->rt_dev->pa_addr;
547
548 if (daddr == rt->rt_dev->pa_addr) {
549 if ((rt = rt_loopback) == NULL)
550 goto no_route;
551 }
552 rt->rt_use++;
553 return rt;
554 no_route:
555 return NULL;
556 }
557
558 struct rtable * ip_rt_local(unsigned long daddr, struct options *opt, unsigned long *src_addr)
559 {
560 struct rtable *rt;
561
562 for (rt = rt_base; rt != NULL || early_out ; rt = rt->rt_next)
563 {
564
565
566
567 if (rt->rt_flags&RTF_GATEWAY)
568 continue;
569
570 if (!((rt->rt_dst ^ daddr) & rt->rt_mask))
571 break;
572
573
574
575
576 if ((rt->rt_dev->flags & IFF_BROADCAST) &&
577 rt->rt_dev->pa_brdaddr == daddr)
578 break;
579 }
580
581 if(src_addr!=NULL)
582 *src_addr= rt->rt_dev->pa_addr;
583
584 if (daddr == rt->rt_dev->pa_addr) {
585 if ((rt = rt_loopback) == NULL)
586 goto no_route;
587 }
588 rt->rt_use++;
589 return rt;
590 no_route:
591 return NULL;
592 }
593
594
595
596
597
598 static int ip_get_old_rtent(struct old_rtentry * src, struct rtentry * rt)
599 {
600 int err;
601 struct old_rtentry tmp;
602
603 err=verify_area(VERIFY_READ, src, sizeof(*src));
604 if (err)
605 return err;
606 memcpy_fromfs(&tmp, src, sizeof(*src));
607 memset(rt, 0, sizeof(*rt));
608 rt->rt_dst = tmp.rt_dst;
609 rt->rt_gateway = tmp.rt_gateway;
610 rt->rt_genmask.sa_family = AF_INET;
611 ((struct sockaddr_in *) &rt->rt_genmask)->sin_addr.s_addr = tmp.rt_genmask;
612 rt->rt_flags = tmp.rt_flags;
613 rt->rt_dev = tmp.rt_dev;
614 printk("Warning: obsolete routing request made.\n");
615 return 0;
616 }
617
618
619
620
621
622 int ip_rt_ioctl(unsigned int cmd, void *arg)
623 {
624 int err;
625 struct rtentry rt;
626
627 switch(cmd)
628 {
629 case SIOCADDRTOLD:
630 case SIOCDELRTOLD:
631 if (!suser())
632 return -EPERM;
633 err = ip_get_old_rtent((struct old_rtentry *) arg, &rt);
634 if (err)
635 return err;
636 return (cmd == SIOCDELRTOLD) ? rt_kill(&rt) : rt_new(&rt);
637
638 case SIOCADDRT:
639 case SIOCDELRT:
640 if (!suser())
641 return -EPERM;
642 err=verify_area(VERIFY_READ, arg, sizeof(struct rtentry));
643 if (err)
644 return err;
645 memcpy_fromfs(&rt, arg, sizeof(struct rtentry));
646 return (cmd == SIOCDELRT) ? rt_kill(&rt) : rt_new(&rt);
647 }
648
649 return -EINVAL;
650 }