?? route.c
字號(hào):
1 /*
2 * INET An implementation of the TCP/IP protocol suite for the LINUX
3 * operating system. INET is implemented using the BSD Socket
4 * interface as the means of communication with the user level.
5 *
6 * ROUTE - implementation of the IP router.
7 *
8 * Version: @(#)route.c 1.0.14 05/31/93
9 *
10 * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
11 * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
12 *
13 * Fixes:
14 * Alan Cox : Verify area fixes.
15 * Alan Cox : cli() protects routing changes
16 * Rui Oliveira : ICMP routing table updates
17 * (rco@di.uminho.pt) Routing table insertion and update
18 * Linus Torvalds : Rewrote bits to be sensible
19 *
20 * This program is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU General Public License
22 * as published by the Free Software Foundation; either version
23 * 2 of the License, or (at your option) any later version.
24 */
25 #include <asm/segment.h>
26 #include <asm/system.h>
27 #include <linux/types.h>
28 #include <linux/kernel.h>
29 #include <linux/sched.h>
30 #include <linux/string.h>
31 #include <linux/socket.h>
32 #include <linux/sockios.h>
33 #include <linux/errno.h>
34 #include <linux/in.h>
35 #include "inet.h"
36 #include "dev.h"
37 #include "ip.h"
38 #include "protocol.h"
39 #include "route.h"
40 #include "tcp.h"
41 #include "skbuff.h"
42 #include "sock.h"
43 #include "arp.h"
44 #include "icmp.h"
45
46
47 static struct rtable *rt_base = NULL;
48 static struct rtable *rt_loopback = NULL;
49
50 /* Dump the contents of a routing table entry. */
51 static void
52 rt_print(struct rtable *rt)
53 {
54 if (rt == NULL || inet_debug != DBG_RT) return;
55
56 printk("RT: %06lx NXT=%06lx FLAGS=0x%02x\n",
57 (long) rt, (long) rt->rt_next, rt->rt_flags);
58 printk(" TARGET=%s ", in_ntoa(rt->rt_dst));
59 printk("GW=%s ", in_ntoa(rt->rt_gateway));
60 printk(" DEV=%s USE=%ld REF=%d\n",
61 (rt->rt_dev == NULL) ? "NONE" : rt->rt_dev->name,
62 rt->rt_use, rt->rt_refcnt);
63 }
64
65
66 /*
67 * Remove a routing table entry.
68 */
69 static void rt_del(unsigned long dst)
70 {
71 struct rtable *r, **rp;
72 unsigned long flags;
73
74 DPRINTF((DBG_RT, "RT: flushing for dst %s\n", in_ntoa(dst)));
75 rp = &rt_base;
76 save_flags(flags);
77 cli();
78 while((r = *rp) != NULL) {
79 if (r->rt_dst != dst) {
80 rp = &r->rt_next;
81 continue;
82 }
83 *rp = r->rt_next;
84 if (rt_loopback == r)
85 rt_loopback = NULL;
86 kfree_s(r, sizeof(struct rtable));
87 }
88 restore_flags(flags);
89 }
90
91
92 /*
93 * Remove all routing table entries for a device.
94 */
95 void rt_flush(struct device *dev)
96 {
97 struct rtable *r;
98 struct rtable **rp;
99 unsigned long flags;
100
101 DPRINTF((DBG_RT, "RT: flushing for dev 0x%08lx (%s)\n", (long)dev, dev->name));
102 rp = &rt_base;
103 cli();
104 save_flags(flags);
105 while ((r = *rp) != NULL) {
106 if (r->rt_dev != dev) {
107 rp = &r->rt_next;
108 continue;
109 }
110 *rp = r->rt_next;
111 if (rt_loopback == r)
112 rt_loopback = NULL;
113 kfree_s(r, sizeof(struct rtable));
114 }
115 restore_flags(flags);
116 }
117
118 /*
119 * Used by 'rt_add()' when we can't get the netmask any other way..
120 *
121 * If the lower byte or two are zero, we guess the mask based on the
122 * number of zero 8-bit net numbers, otherwise we use the "default"
123 * masks judging by the destination address and our device netmask.
124 */
125 static inline unsigned long default_mask(unsigned long dst)
126 {
127 dst = ntohl(dst);
128 if (IN_CLASSA(dst))
129 return htonl(IN_CLASSA_NET);
130 if (IN_CLASSB(dst))
131 return htonl(IN_CLASSB_NET);
132 return htonl(IN_CLASSC_NET);
133 }
134
135 static unsigned long guess_mask(unsigned long dst, struct device * dev)
136 {
137 unsigned long mask;
138
139 if (!dst)
140 return 0;
141 mask = default_mask(dst);
142 if ((dst ^ dev->pa_addr) & mask)
143 return mask;
144 return dev->pa_mask;
145 }
146
147 static inline struct device * get_gw_dev(unsigned long gw)
148 {
149 struct rtable * rt;
150
151 for (rt = rt_base ; ; rt = rt->rt_next) {
152 if (!rt)
153 return NULL;
154 if ((gw ^ rt->rt_dst) & rt->rt_mask)
155 continue;
156 /* gateways behind gateways are a no-no */
157 if (rt->rt_flags & RTF_GATEWAY)
158 return NULL;
159 return rt->rt_dev;
160 }
161 }
162
163 /*
164 * rewrote rt_add(), as the old one was weird. Linus
165 */
166 void rt_add(short flags, unsigned long dst, unsigned long mask,
167 unsigned long gw, struct device *dev)
168 {
169 struct rtable *r, *rt;
170 struct rtable **rp;
171 unsigned long cpuflags;
172
173 if (flags & RTF_HOST) {
174 mask = 0xffffffff;
175 } else if (!mask) {
176 if (!((dst ^ dev->pa_addr) & dev->pa_mask)) {
177 mask = dev->pa_mask;
178 flags &= ~RTF_GATEWAY;
179 if (flags & RTF_DYNAMIC) {
180 /*printk("Dynamic route to my own net rejected\n");*/
181 return;
182 }
183 } else
184 mask = guess_mask(dst, dev);
185 dst &= mask;
186 }
187 if (gw == dev->pa_addr)
188 flags &= ~RTF_GATEWAY;
189 if (flags & RTF_GATEWAY) {
190 /* don't try to add a gateway we can't reach.. */
191 if (dev != get_gw_dev(gw))
192 return;
193 flags |= RTF_GATEWAY;
194 } else
195 gw = 0;
196 /* Allocate an entry. */
197 rt = (struct rtable *) kmalloc(sizeof(struct rtable), GFP_ATOMIC);
198 if (rt == NULL) {
199 DPRINTF((DBG_RT, "RT: no memory for new route!\n"));
200 return;
201 }
202 memset(rt, 0, sizeof(struct rtable));
203 rt->rt_flags = flags | RTF_UP;
204 rt->rt_dst = dst;
205 rt->rt_dev = dev;
206 rt->rt_gateway = gw;
207 rt->rt_mask = mask;
208 rt->rt_mtu = dev->mtu;
209 rt_print(rt);
210 /*
211 * What we have to do is loop though this until we have
212 * found the first address which has a higher generality than
213 * the one in rt. Then we can put rt in right before it.
214 */
215 save_flags(cpuflags);
216 cli();
217 /* remove old route if we are getting a duplicate. */
218 rp = &rt_base;
219 while ((r = *rp) != NULL) {
220 if (r->rt_dst != dst) {
221 rp = &r->rt_next;
222 continue;
223 }
224 *rp = r->rt_next;
225 if (rt_loopback == r)
226 rt_loopback = NULL;
227 kfree_s(r, sizeof(struct rtable));
228 }
229 /* add the new route */
230 rp = &rt_base;
231 while ((r = *rp) != NULL) {
232 if ((r->rt_mask & mask) != mask)
233 break;
234 rp = &r->rt_next;
235 }
236 rt->rt_next = r;
237 *rp = rt;
238 if (rt->rt_dev->flags & IFF_LOOPBACK)
239 rt_loopback = rt;
240 restore_flags(cpuflags);
241 return;
242 }
243
244 static inline int bad_mask(unsigned long mask, unsigned long addr)
245 {
246 if (addr & (mask = ~mask))
247 return 1;
248 mask = ntohl(mask);
249 if (mask & (mask+1))
250 return 1;
251 return 0;
252 }
253
254 static int rt_new(struct rtentry *r)
255 {
256 int err;
257 char * devname;
258 struct device * dev = NULL;
259 unsigned long flags, daddr, mask, gw;
260
261 if ((devname = r->rt_dev) != NULL) {
262 err = getname(devname, &devname);
263 if (err)
264 return err;
265 dev = dev_get(devname);
266 putname(devname);
267 if (!dev)
268 return -EINVAL;
269 }
270
271 if (r->rt_dst.sa_family != AF_INET)
272 return -EAFNOSUPPORT;
273
274 flags = r->rt_flags;
275 daddr = ((struct sockaddr_in *) &r->rt_dst)->sin_addr.s_addr;
276 mask = ((struct sockaddr_in *) &r->rt_genmask)->sin_addr.s_addr;
277 gw = ((struct sockaddr_in *) &r->rt_gateway)->sin_addr.s_addr;
278
279 /* BSD emulation: Permits route add someroute gw one-of-my-addresses
280 to indicate which iface. Not as clean as the nice Linux dev technique
281 but people keep using it... */
282 if (!dev && (flags & RTF_GATEWAY)) {
283 struct device *dev2;
284 for (dev2 = dev_base ; dev2 != NULL ; dev2 = dev2->next) {
285 if ((dev2->flags & IFF_UP) && dev2->pa_addr == gw) {
286 flags &= ~RTF_GATEWAY;
287 dev = dev2;
288 break;
289 }
290 }
291 }
292
293 if (bad_mask(mask, daddr))
294 mask = 0;
295
296 if (flags & RTF_HOST)
297 mask = 0xffffffff;
298 else if (mask && r->rt_genmask.sa_family != AF_INET)
299 return -EAFNOSUPPORT;
300
301 if (flags & RTF_GATEWAY) {
302 if (r->rt_gateway.sa_family != AF_INET)
303 return -EAFNOSUPPORT;
304 if (!dev)
305 dev = get_gw_dev(gw);
306 } else if (!dev)
307 dev = dev_check(daddr);
308
309 if (dev == NULL)
310 return -ENETUNREACH;
311
312 rt_add(flags, daddr, mask, gw, dev);
313 return 0;
314 }
315
316
317 static int rt_kill(struct rtentry *r)
318 {
319 struct sockaddr_in *trg;
320
321 trg = (struct sockaddr_in *) &r->rt_dst;
322 rt_del(trg->sin_addr.s_addr);
323 return 0;
324 }
325
326
327 /* Called from the PROCfs module. */
328 int
329 rt_get_info(char *buffer)
330 {
331 struct rtable *r;
332 char *pos;
333
334 pos = buffer;
335
336 pos += sprintf(pos,
337 "Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\tMask\n");
338
339 /* This isn't quite right -- r->rt_dst is a struct! */
340 for (r = rt_base; r != NULL; r = r->rt_next) {
341 pos += sprintf(pos, "%s\t%08lX\t%08lX\t%02X\t%d\t%lu\t%d\t%08lX\n",
342 r->rt_dev->name, r->rt_dst, r->rt_gateway,
343 r->rt_flags, r->rt_refcnt, r->rt_use, r->rt_metric,
344 r->rt_mask);
345 }
346 return(pos - buffer);
347 }
348
349 /*
350 * This is hackish, but results in better code. Use "-S" to see why.
351 */
352 #define early_out ({ goto no_route; 1; })
353
354 struct rtable * rt_route(unsigned long daddr, struct options *opt)
355 {
356 struct rtable *rt;
357
358 for (rt = rt_base; rt != NULL || early_out ; rt = rt->rt_next) {
359 if (!((rt->rt_dst ^ daddr) & rt->rt_mask))
360 break;
361 /* broadcast addresses can be special cases.. */
362 if ((rt->rt_dev->flags & IFF_BROADCAST) &&
363 rt->rt_dev->pa_brdaddr == daddr)
364 break;
365 }
366 if (daddr == rt->rt_dev->pa_addr) {
367 if ((rt = rt_loopback) == NULL)
368 goto no_route;
369 }
370 rt->rt_use++;
371 return rt;
372 no_route:
373 return NULL;
374 }
375
376 static int get_old_rtent(struct old_rtentry * src, struct rtentry * rt)
377 {
378 int err;
379 struct old_rtentry tmp;
380
381 err=verify_area(VERIFY_READ, src, sizeof(*src));
382 if (err)
383 return err;
384 memcpy_fromfs(&tmp, src, sizeof(*src));
385 memset(rt, 0, sizeof(*rt));
386 rt->rt_dst = tmp.rt_dst;
387 rt->rt_gateway = tmp.rt_gateway;
388 rt->rt_genmask.sa_family = AF_INET;
389 ((struct sockaddr_in *) &rt->rt_genmask)->sin_addr.s_addr = tmp.rt_genmask;
390 rt->rt_flags = tmp.rt_flags;
391 rt->rt_dev = tmp.rt_dev;
392 return 0;
393 }
394
395 int rt_ioctl(unsigned int cmd, void *arg)
396 {
397 int err;
398 struct rtentry rt;
399
400 switch(cmd) {
401 case DDIOCSDBG:
402 return dbg_ioctl(arg, DBG_RT);
403 case SIOCADDRTOLD:
404 case SIOCDELRTOLD:
405 if (!suser())
406 return -EPERM;
407 err = get_old_rtent((struct old_rtentry *) arg, &rt);
408 if (err)
409 return err;
410 return (cmd == SIOCDELRTOLD) ? rt_kill(&rt) : rt_new(&rt);
411 case SIOCADDRT:
412 case SIOCDELRT:
413 if (!suser())
414 return -EPERM;
415 err=verify_area(VERIFY_READ, arg, sizeof(struct rtentry));
416 if (err)
417 return err;
418 memcpy_fromfs(&rt, arg, sizeof(struct rtentry));
419 return (cmd == SIOCDELRT) ? rt_kill(&rt) : rt_new(&rt);
420 }
421
422 return -EINVAL;
423 }
424
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -