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