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