This source file includes following definitions.
- rt_print
- rt_del
- rt_flush
- rt_add
- rt_new
- rt_kill
- rt_get_info
- rt_route
- 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 #include <asm/segment.h>
25 #include <asm/system.h>
26 #include <linux/types.h>
27 #include <linux/kernel.h>
28 #include <linux/sched.h>
29 #include <linux/string.h>
30 #include <linux/socket.h>
31 #include <linux/sockios.h>
32 #include <linux/errno.h>
33 #include <linux/in.h>
34 #include "inet.h"
35 #include "dev.h"
36 #include "ip.h"
37 #include "protocol.h"
38 #include "route.h"
39 #include "tcp.h"
40 #include "skbuff.h"
41 #include "sock.h"
42 #include "arp.h"
43 #include "icmp.h"
44
45
46 static struct rtable *rt_base = NULL;
47
48
49
50 static void
51 rt_print(struct rtable *rt)
52 {
53 if (rt == NULL || inet_debug != DBG_RT) return;
54
55 printk("RT: %06lx NXT=%06lx FLAGS=0x%02x\n",
56 (long) rt, (long) rt->rt_next, rt->rt_flags);
57 printk(" TARGET=%s ", in_ntoa(rt->rt_dst));
58 printk("GW=%s ", in_ntoa(rt->rt_gateway));
59 printk(" DEV=%s USE=%ld REF=%d\n",
60 (rt->rt_dev == NULL) ? "NONE" : rt->rt_dev->name,
61 rt->rt_use, rt->rt_refcnt);
62 }
63
64
65
66 static void
67 rt_del(unsigned long dst)
68 {
69 struct rtable *r, *x, *p;
70 unsigned long flags;
71
72 DPRINTF((DBG_RT, "RT: flushing for dst %s\n", in_ntoa(dst)));
73 if ((r = rt_base) == NULL) return;
74
75 save_flags(flags);
76 cli();
77 p = NULL;
78 while(r != NULL) {
79 if (r->rt_dst == dst) {
80 if (p == NULL) rt_base = r->rt_next;
81 else p->rt_next = r->rt_next;
82 x = r->rt_next;
83 kfree_s(r, sizeof(struct rtable));
84 r = x;
85 } else {
86 p = r;
87 r = r->rt_next;
88 }
89 }
90 restore_flags(flags);
91 }
92
93
94
95 void
96 rt_flush(struct device *dev)
97 {
98 struct rtable *r, *x, *p;
99 unsigned long flags;
100
101 DPRINTF((DBG_RT, "RT: flushing for dev 0x%08lx (%s)\n", (long)dev, dev->name));
102 if ((r = rt_base) == NULL) return;
103
104 cli();
105 save_flags(flags);
106
107 p = NULL;
108 while(r != NULL) {
109 if (r->rt_dev == dev) {
110 if (p == NULL) rt_base = r->rt_next;
111 else p->rt_next = r->rt_next;
112 x = r->rt_next;
113 kfree_s(r, sizeof(struct rtable));
114 r = x;
115 } else {
116 p = r;
117 r = r->rt_next;
118 }
119 }
120 restore_flags(flags);
121 }
122
123
124 void
125 rt_add(short flags, unsigned long dst, unsigned long gw, struct device *dev)
126 {
127 struct rtable *r, *r1;
128 struct rtable *rt;
129 int mask;
130 unsigned long cpuflags;
131
132
133 rt = (struct rtable *) kmalloc(sizeof(struct rtable), GFP_ATOMIC);
134 if (rt == NULL) {
135 DPRINTF((DBG_RT, "RT: no memory for new route!\n"));
136 return;
137 }
138
139
140 memset(rt, 0, sizeof(struct rtable));
141 rt->rt_flags = (flags | RTF_UP);
142 if (gw != 0) rt->rt_flags |= RTF_GATEWAY;
143 rt->rt_dev = dev;
144 rt->rt_gateway = gw;
145
146
147
148
149
150
151 if (flags & RTF_DYNAMIC) {
152 if (flags & RTF_HOST)
153 rt->rt_dst = dst;
154 else{
155 rt->rt_dst = (dst & dev->pa_mask);
156
157 if(rt->rt_dst == (dev->pa_addr & dev->pa_mask)){
158 kfree_s(rt, sizeof(struct rtable));
159
160 return;
161 }
162 }
163 } else rt->rt_dst = dst;
164
165 rt_print(rt);
166
167 if (rt_base == NULL) {
168 rt->rt_next = NULL;
169 rt_base = rt;
170 return;
171 }
172
173
174
175
176
177
178 for (mask = 0xff000000L; mask != 0xffffffffL; mask = (mask >> 8) | mask) {
179 if (mask & dst) {
180 mask = mask << 8;
181 break;
182 }
183 }
184 DPRINTF((DBG_RT, "RT: mask = %X\n", mask));
185
186 save_flags(cpuflags);
187 cli();
188
189 r1 = rt_base;
190
191
192 for (r = rt_base; r != NULL; r = r->rt_next) {
193 if (r->rt_dst == dst) {
194 if (r == rt_base) {
195 rt->rt_next = r->rt_next;
196 rt_base = rt;
197 } else {
198 rt->rt_next = r->rt_next;
199 r1->rt_next = rt;
200 }
201 kfree_s(r, sizeof(struct rtable));
202 restore_flags(cpuflags);
203 return;
204 }
205 r1 = r;
206 }
207
208 r1 = rt_base;
209 for (r = rt_base; r != NULL; r = r->rt_next) {
210 if (! (r->rt_dst & mask)) {
211 DPRINTF((DBG_RT, "RT: adding before r=%X\n", r));
212 rt_print(r);
213 if (r == rt_base) {
214 rt->rt_next = rt_base;
215 rt_base = rt;
216 restore_flags(cpuflags);
217 return;
218 }
219 rt->rt_next = r;
220 r1->rt_next = rt;
221 restore_flags(cpuflags);
222 return;
223 }
224 r1 = r;
225 }
226 DPRINTF((DBG_RT, "RT: adding after r1=%X\n", r1));
227 rt_print(r1);
228
229
230 rt->rt_next = NULL;
231 r1->rt_next = rt;
232 }
233
234
235 static int
236 rt_new(struct rtentry *r)
237 {
238 struct device *dev;
239 struct rtable *rt;
240
241 if ((r->rt_dst.sa_family != AF_INET) ||
242 (r->rt_gateway.sa_family != AF_INET)) {
243 DPRINTF((DBG_RT, "RT: We only know about AF_INET !\n"));
244 return(-EAFNOSUPPORT);
245 }
246
247
248
249
250
251
252
253
254
255
256 if (!(r->rt_flags & RTF_GATEWAY))
257 dev = dev_check(((struct sockaddr_in *) &r->rt_dst)->sin_addr.s_addr);
258 else
259 if ((rt = rt_route(((struct sockaddr_in *) &r->rt_gateway)->sin_addr.
260 s_addr,NULL)))
261 dev = rt->rt_dev;
262 else
263 dev = NULL;
264
265 DPRINTF((DBG_RT, "RT: dev for %s gw ",
266 in_ntoa((*(struct sockaddr_in *)&r->rt_dst).sin_addr.s_addr)));
267 DPRINTF((DBG_RT, "%s (0x%04X) is 0x%X (%s)\n",
268 in_ntoa((*(struct sockaddr_in *)&r->rt_gateway).sin_addr.s_addr),
269 r->rt_flags, dev, (dev == NULL) ? "NONE" : dev->name));
270
271 if (dev == NULL) return(-ENETUNREACH);
272
273 rt_add(r->rt_flags, (*(struct sockaddr_in *) &r->rt_dst).sin_addr.s_addr,
274 (*(struct sockaddr_in *) &r->rt_gateway).sin_addr.s_addr, dev);
275
276 return(0);
277 }
278
279
280 static int
281 rt_kill(struct rtentry *r)
282 {
283 struct sockaddr_in *trg;
284
285 trg = (struct sockaddr_in *) &r->rt_dst;
286 rt_del(trg->sin_addr.s_addr);
287
288 return(0);
289 }
290
291
292
293 int
294 rt_get_info(char *buffer)
295 {
296 struct rtable *r;
297 char *pos;
298
299 pos = buffer;
300
301 pos += sprintf(pos,
302 "Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\n");
303
304
305 for (r = rt_base; r != NULL; r = r->rt_next) {
306 pos += sprintf(pos, "%s\t%08lX\t%08lX\t%02X\t%d\t%lu\t%d\n",
307 r->rt_dev->name, r->rt_dst, r->rt_gateway,
308 r->rt_flags, r->rt_refcnt, r->rt_use, r->rt_metric);
309 }
310 return(pos - buffer);
311 }
312
313
314 struct rtable *
315 rt_route(unsigned long daddr, struct options *opt)
316 {
317 struct rtable *rt;
318
319
320
321
322 if (chk_addr(daddr) == IS_MYADDR) daddr = my_addr();
323
324
325
326
327
328
329
330 for (rt = rt_base; rt != NULL; rt = rt->rt_next)
331 if ((rt->rt_flags & RTF_HOST) && rt->rt_dst == daddr) {
332 DPRINTF((DBG_RT, "%s (%s)\n",
333 rt->rt_dev->name, in_ntoa(rt->rt_gateway)));
334 rt->rt_use++;
335 return(rt);
336 }
337 for (rt = rt_base; rt != NULL; rt = rt->rt_next) {
338 DPRINTF((DBG_RT, "RT: %s via ", in_ntoa(daddr)));
339 if (!(rt->rt_flags & RTF_HOST) && ip_addr_match(rt->rt_dst, daddr)) {
340 DPRINTF((DBG_RT, "%s (%s)\n",
341 rt->rt_dev->name, in_ntoa(rt->rt_gateway)));
342 rt->rt_use++;
343 return(rt);
344 }
345 if ((rt->rt_dev->flags & IFF_BROADCAST) &&
346 ip_addr_match(rt->rt_dev->pa_brdaddr, daddr)) {
347 DPRINTF((DBG_RT, "%s (BCAST %s)\n",
348 rt->rt_dev->name, in_ntoa(rt->rt_dev->pa_brdaddr)));
349 rt->rt_use++;
350 return(rt);
351 }
352 }
353
354 DPRINTF((DBG_RT, "NONE\n"));
355 return(NULL);
356 };
357
358
359 int
360 rt_ioctl(unsigned int cmd, void *arg)
361 {
362 struct device *dev;
363 struct rtentry rt;
364 char namebuf[32];
365 int ret;
366 int err;
367
368 switch(cmd) {
369 case DDIOCSDBG:
370 ret = dbg_ioctl(arg, DBG_RT);
371 break;
372 case SIOCADDRT:
373 case SIOCDELRT:
374 if (!suser()) return(-EPERM);
375 err=verify_area(VERIFY_READ, arg, sizeof(struct rtentry));
376 if(err)
377 return err;
378 memcpy_fromfs(&rt, arg, sizeof(struct rtentry));
379 if (rt.rt_dev) {
380 err=verify_area(VERIFY_READ, rt.rt_dev, sizeof namebuf);
381 if(err)
382 return err;
383 memcpy_fromfs(&namebuf, rt.rt_dev, sizeof namebuf);
384 dev = dev_get(namebuf);
385 rt.rt_dev = dev;
386 }
387 ret = (cmd == SIOCDELRT) ? rt_kill(&rt) : rt_new(&rt);
388 break;
389 default:
390 ret = -EINVAL;
391 }
392
393 return(ret);
394 }