Commit | Line | Data |
---|---|---|
7c0bf99b | 1 | #ifndef lint |
6db0b3a4 | 2 | static char sccsid[] = "@(#)routed.c 4.14 82/06/09"; |
7c0bf99b SL |
3 | #endif |
4 | ||
3cec0c76 SL |
5 | /* |
6 | * Routing Table Management Daemon | |
7 | */ | |
8 | #include <sys/types.h> | |
7c0bf99b SL |
9 | #include <sys/ioctl.h> |
10 | #include <sys/socket.h> | |
11 | #include <net/in.h> | |
7c0bf99b SL |
12 | #include <net/if.h> |
13 | #include <errno.h> | |
14 | #include <stdio.h> | |
15 | #include <nlist.h> | |
16 | #include <signal.h> | |
6d0df65e | 17 | #include <time.h> |
7c0bf99b SL |
18 | #include "rip.h" |
19 | #include "router.h" | |
20 | ||
21 | #define LOOPBACKNET 0177 | |
22 | /* casts to keep lint happy */ | |
23 | #define insque(q,p) _insque((caddr_t)q,(caddr_t)p) | |
24 | #define remque(q) _remque((caddr_t)q) | |
25 | #define equal(a1, a2) \ | |
26 | (bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof (struct sockaddr)) == 0) | |
77df73ca | 27 | #define min(a,b) ((a)>(b)?(b):(a)) |
7c0bf99b SL |
28 | |
29 | struct nlist nl[] = { | |
30 | #define N_IFNET 0 | |
31 | { "_ifnet" }, | |
32 | 0, | |
33 | }; | |
34 | ||
35 | struct sockaddr_in myaddr = { AF_INET, IPPORT_ROUTESERVER }; | |
36 | ||
37 | int s; | |
74d7f201 | 38 | int snoroute; /* socket with no routing */ |
77df73ca | 39 | int kmem = -1; |
6db0b3a4 | 40 | int supplier = -1; /* process should supply updates */ |
b7fcdb03 | 41 | int install = 1; /* if 1 call kernel */ |
6db0b3a4 | 42 | int timeval = -TIMER_RATE; |
7c0bf99b SL |
43 | int timer(); |
44 | int cleanup(); | |
6db0b3a4 BJ |
45 | |
46 | #define tprintf if (trace) printf | |
7c0bf99b | 47 | int trace = 0; |
6d0df65e | 48 | FILE *ftrace; |
7c0bf99b | 49 | |
6db0b3a4 BJ |
50 | char packet[MAXPACKETSIZE+1]; |
51 | struct rip *msg = (struct rip *)packet; | |
7c0bf99b | 52 | |
3cec0c76 SL |
53 | struct in_addr if_makeaddr(); |
54 | struct ifnet *if_ifwithaddr(), *if_ifwithnet(); | |
7c0bf99b | 55 | extern char *malloc(); |
c5f8709e | 56 | extern int errno, exit(); |
6db0b3a4 BJ |
57 | char **argv0; |
58 | ||
59 | int sndmsg(), supply(); | |
7c0bf99b SL |
60 | |
61 | main(argc, argv) | |
62 | int argc; | |
63 | char *argv[]; | |
64 | { | |
65 | int cc; | |
66 | struct sockaddr from; | |
67 | ||
6db0b3a4 | 68 | argv0 = argv; |
6d0df65e SL |
69 | #ifndef DEBUG |
70 | if (fork()) | |
71 | exit(0); | |
72 | for (cc = 0; cc < 10; cc++) | |
73 | (void) close(cc); | |
74 | (void) open("/", 0); | |
75 | (void) dup2(0, 1); | |
76 | (void) dup2(0, 2); | |
77 | { int t = open("/dev/tty", 2); | |
78 | if (t >= 0) { | |
79 | ioctl(t, TIOCNOTTY, (char *)0); | |
80 | (void) close(t); | |
81 | } | |
7c0bf99b | 82 | } |
6d0df65e | 83 | #endif |
7c0bf99b | 84 | if (trace) { |
6d0df65e SL |
85 | ftrace = fopen("/etc/routerlog", "w"); |
86 | dup2(fileno(ftrace), 1); | |
87 | dup2(fileno(ftrace), 2); | |
7c0bf99b | 88 | } |
e6b5ed24 | 89 | #ifdef vax || pdp11 |
7c0bf99b SL |
90 | myaddr.sin_port = htons(myaddr.sin_port); |
91 | #endif | |
92 | again: | |
93 | s = socket(SOCK_DGRAM, 0, &myaddr, 0); | |
94 | if (s < 0) { | |
95 | perror("socket"); | |
96 | sleep(30); | |
97 | goto again; | |
98 | } | |
74d7f201 BJ |
99 | again2: |
100 | snoroute = socket(SOCK_DGRAM, 0, 0, SO_DONTROUTE); | |
101 | if (snoroute < 0) { | |
102 | perror("socket"); | |
103 | sleep(30); | |
104 | goto again2; | |
105 | } | |
7c0bf99b | 106 | argv++, argc--; |
6db0b3a4 BJ |
107 | while (argc > 0 && **argv == '-') { |
108 | if (!strcmp(*argv, "-s") == 0) { | |
77df73ca | 109 | supplier = 1; |
6db0b3a4 BJ |
110 | argv++, argc--; |
111 | continue; | |
112 | } | |
113 | if (!strcmp(*argv, "-q") == 0) { | |
7c0bf99b | 114 | supplier = 0; |
6db0b3a4 BJ |
115 | argv++, argc--; |
116 | continue; | |
117 | } | |
118 | goto usage; | |
119 | } | |
120 | if (argc > 0) { | |
121 | usage: | |
122 | fprintf(stderr, "usage: routed [ -s ]\n"); | |
123 | exit(1); | |
7c0bf99b | 124 | } |
6db0b3a4 BJ |
125 | rtinit(); |
126 | ifinit(); | |
127 | if (supplier < 0) | |
128 | supplier = 0; | |
129 | gwkludge(); | |
130 | msg->rip_cmd = RIPCMD_REQUEST; | |
131 | msg->rip_nets[0].rip_dst.sa_family = AF_UNSPEC; | |
132 | msg->rip_nets[0].rip_metric = HOPCNT_INFINITY; | |
133 | toall(sendmsg); | |
7c0bf99b | 134 | sigset(SIGALRM, timer); |
77df73ca | 135 | timer(); |
7c0bf99b | 136 | |
7c0bf99b SL |
137 | for (;;) { |
138 | cc = receive(s, &from, packet, sizeof (packet)); | |
139 | if (cc <= 0) { | |
140 | if (cc < 0 && errno != EINTR) | |
141 | perror("receive"); | |
142 | continue; | |
143 | } | |
144 | sighold(SIGALRM); | |
145 | rip_input(&from, cc); | |
146 | sigrelse(SIGALRM); | |
147 | } | |
148 | } | |
149 | ||
6db0b3a4 | 150 | rtinit() |
7c0bf99b | 151 | { |
3cec0c76 | 152 | register struct rthash *rh; |
7c0bf99b | 153 | |
6db0b3a4 BJ |
154 | for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++) |
155 | rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; | |
156 | for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++) | |
157 | rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; | |
7c0bf99b SL |
158 | } |
159 | ||
3cec0c76 | 160 | struct ifnet *ifnet; |
6db0b3a4 BJ |
161 | |
162 | ifinit() | |
7c0bf99b | 163 | { |
6db0b3a4 | 164 | struct ifnet *ifp, *next; |
77df73ca | 165 | register struct sockaddr *dst; |
6db0b3a4 | 166 | int uniquemultihostinterfaces = 0; |
7c0bf99b | 167 | |
6db0b3a4 BJ |
168 | nlist("/vmunix", nl); |
169 | if (nl[N_IFNET].n_value == 0) { | |
170 | printf("ifnet: not in namelist\n"); | |
171 | goto bad; | |
7c0bf99b | 172 | } |
6db0b3a4 | 173 | kmem = open("/dev/kmem", 0); |
7c0bf99b | 174 | if (kmem < 0) { |
6db0b3a4 BJ |
175 | perror("/dev/kmem"); |
176 | goto bad; | |
77df73ca SL |
177 | } |
178 | if (lseek(kmem, (long)nl[N_IFNET].n_value, 0) == -1 || | |
6db0b3a4 BJ |
179 | read(kmem, (char *)&next, sizeof (next)) != sizeof (next)) { |
180 | printf("ifnet: error reading kmem\n"); | |
181 | goto bad; | |
7c0bf99b | 182 | } |
6db0b3a4 | 183 | while (next) { |
77df73ca SL |
184 | ifp = (struct ifnet *)malloc(sizeof (struct ifnet)); |
185 | if (ifp == 0) { | |
186 | printf("routed: out of memory\n"); | |
187 | break; | |
188 | } | |
6db0b3a4 BJ |
189 | if (lseek(kmem, (long)next, 0) == -1 || |
190 | read(kmem, (char *)ifp, sizeof (*ifp)) != sizeof (*ifp)) { | |
191 | perror("read"); | |
192 | goto bad; | |
77df73ca SL |
193 | } |
194 | next = ifp->if_next; | |
6db0b3a4 BJ |
195 | if (ifp->if_addr.sa_family != AF_INET) |
196 | continue; | |
197 | if (ifp->if_net == LOOPBACKNET) | |
198 | continue; | |
199 | if ((ifp->if_flags & IFF_POINTOPOINT) == 0 || | |
200 | if_ifwithaddr(&ifp->if_dstaddr) == 0) | |
201 | uniquemultihostinterfaces++; | |
77df73ca SL |
202 | ifp->if_next = ifnet; |
203 | ifnet = ifp; | |
6db0b3a4 BJ |
204 | addrouteforif(ifp); |
205 | } | |
206 | if (uniquemultihostinterfaces > 1 && supplier < 0) | |
207 | supplier = 1; | |
208 | return; | |
209 | bad: | |
210 | sleep(60); | |
211 | execv("/etc/routed", argv0); | |
212 | _exit(0177); | |
213 | } | |
74d7f201 | 214 | |
6db0b3a4 BJ |
215 | addrouteforif(ifp) |
216 | struct ifnet *ifp; | |
217 | { | |
218 | struct sockaddr_in net; | |
219 | struct sockaddr *dst; | |
220 | ||
221 | if (ifp->if_flags & IFF_POINTOPOINT) | |
222 | dst = &ifp->if_dstaddr; | |
223 | else { | |
224 | bzero((char *)&net, sizeof (net)); | |
225 | net.sin_family = AF_INET; | |
226 | net.sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY); | |
227 | dst = (struct sockaddr *)&net; | |
7c0bf99b | 228 | } |
6db0b3a4 | 229 | rtadd(dst, &ifp->if_addr, 0, RTS_INTERFACE); |
74d7f201 BJ |
230 | } |
231 | ||
6db0b3a4 | 232 | gwkludge() |
74d7f201 BJ |
233 | { |
234 | struct sockaddr_in dst, gate; | |
235 | FILE *fp; | |
236 | struct rt_entry *rt; | |
6db0b3a4 | 237 | char flags[BUFSIZ]; |
74d7f201 BJ |
238 | |
239 | fp = fopen("/etc/gateways", "r"); | |
240 | if (fp == NULL) | |
241 | return; | |
242 | bzero((char *)&dst, sizeof (dst)); | |
243 | bzero((char *)&gate, sizeof (gate)); | |
244 | dst.sin_family = AF_INET; | |
245 | gate.sin_family = AF_INET; | |
6db0b3a4 BJ |
246 | for (;;) { |
247 | if (fscanf(fp, "dst %x gateway %x\n", &dst.sin_addr.s_addr, | |
248 | &gate.sin_addr.s_addr, flags) == EOF) | |
249 | break; | |
250 | rtadd((struct sockaddr *)&dst, (struct sockaddr *)&gate, 1, | |
251 | RTS_GLOBAL|(!strcmp(flags, "passive") ? RTS_PASSIVE : 0)); | |
74d7f201 BJ |
252 | } |
253 | fclose(fp); | |
7c0bf99b SL |
254 | } |
255 | ||
6db0b3a4 | 256 | timer() |
7c0bf99b | 257 | { |
3cec0c76 | 258 | register struct rthash *rh; |
7c0bf99b | 259 | register struct rt_entry *rt; |
3cec0c76 | 260 | struct rthash *base = hosthash; |
6db0b3a4 | 261 | int doinghost = 1, state; |
7c0bf99b | 262 | |
6db0b3a4 BJ |
263 | timeval += TIMER_RATE; |
264 | tprintf(">>> time %d >>>\n", timeval); | |
7c0bf99b | 265 | again: |
6db0b3a4 BJ |
266 | for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) { |
267 | rt = rh->rt_forw; | |
268 | for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { | |
269 | if (!(rt->rt_state & RTS_GLOBAL)) | |
270 | rt->rt_timer += TIMER_RATE; | |
271 | log("", rt); | |
272 | if (rt->rt_timer >= EXPIRE_TIME) | |
273 | rt->rt_metric = HOPCNT_INFINITY; | |
274 | if ((rt->rt_state & RTS_DELRT) || | |
275 | rt->rt_timer >= GARBAGE_TIME) { | |
276 | if (rt->rt_state&(RTS_INTERFACE|RTS_GLOBAL)) { | |
277 | if (rt->rt_timer > 9999) | |
278 | rt->rt_timer = 9999; | |
279 | continue; | |
280 | } | |
281 | rt = rt->rt_back; | |
282 | rtdelete(rt->rt_forw); | |
283 | continue; | |
284 | } | |
285 | state = rt->rt_state; | |
286 | if (rt->rt_state & RTS_ADDRT) { | |
287 | if (ioctl(s, SIOCADDRT,(char *)&rt->rt_rt) < 0) | |
288 | perror("SIOCADDRT"); | |
289 | rt->rt_state &= ~RTS_ADDRT; | |
290 | } | |
291 | if (rt->rt_state & RTS_CHGRT) { | |
292 | struct rtentry oldroute; | |
293 | ||
294 | oldroute = rt->rt_rt; | |
295 | rt->rt_router = rt->rt_newrouter; | |
296 | if (ioctl(s, SIOCADDRT,(char *)&rt->rt_rt) < 0) | |
297 | perror("SIOCADDRT"); | |
298 | if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0) | |
299 | perror("SIOCDELRT"); | |
300 | rt->rt_state &= ~RTS_CHGRT; | |
301 | } | |
302 | if (supplier && (state & (RTS_CHGRT|RTS_ADDRT))) { | |
303 | log("broadcast", rt); | |
304 | msg->rip_cmd = RIPCMD_RESPONSE; | |
305 | msg->rip_nets[0].rip_dst = rt->rt_dst; | |
306 | msg->rip_nets[0].rip_metric = | |
307 | min(rt->rt_metric+1, HOPCNT_INFINITY); | |
308 | sendmsgtoall(); | |
309 | } | |
310 | } | |
7c0bf99b SL |
311 | } |
312 | if (doinghost) { | |
77df73ca | 313 | doinghost = 0; |
6db0b3a4 | 314 | base = nethash; |
7c0bf99b SL |
315 | goto again; |
316 | } | |
6db0b3a4 BJ |
317 | if (supplier && (timeval % SUPPLY_INTERVAL) == 0) |
318 | toall(supply); | |
319 | tprintf("<<< time %d <<<\n", timeval); | |
320 | alarm(TIMER_RATE); | |
7c0bf99b SL |
321 | } |
322 | ||
6db0b3a4 BJ |
323 | toall(f) |
324 | int (*f)(); | |
7c0bf99b | 325 | { |
3cec0c76 | 326 | register struct rthash *rh; |
6db0b3a4 | 327 | register struct rt_entry *rt; |
7c0bf99b | 328 | register struct sockaddr *dst; |
3cec0c76 | 329 | struct rthash *base = hosthash; |
7c0bf99b SL |
330 | int doinghost = 1; |
331 | ||
332 | again: | |
333 | for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) | |
334 | for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { | |
6db0b3a4 | 335 | if ((rt->rt_state&RTS_PASSIVE) || rt->rt_metric > 0) |
7c0bf99b SL |
336 | continue; |
337 | if (rt->rt_ifp && (rt->rt_ifp->if_flags & IFF_BROADCAST)) | |
338 | dst = &rt->rt_ifp->if_broadaddr; | |
339 | else | |
74d7f201 | 340 | dst = &rt->rt_router; |
6db0b3a4 | 341 | (*f)(rt, dst); |
7c0bf99b SL |
342 | } |
343 | if (doinghost) { | |
344 | base = nethash; | |
345 | doinghost = 0; | |
346 | goto again; | |
347 | } | |
348 | } | |
349 | ||
6db0b3a4 BJ |
350 | sendmsg(rt, dst) |
351 | register struct rt_entry *rt; | |
352 | struct sockaddr *dst; | |
353 | { | |
354 | ||
355 | (*afswitch[dst->sa_family].af_output)(s, dst, sizeof (struct rip)); | |
356 | } | |
357 | ||
358 | supply(rt, sa) | |
359 | register struct rt_entry *rt; | |
7c0bf99b SL |
360 | struct sockaddr *sa; |
361 | { | |
7c0bf99b | 362 | struct netinfo *n = msg->rip_nets; |
3cec0c76 | 363 | register struct rthash *rh; |
3cec0c76 | 364 | struct rthash *base = hosthash; |
77df73ca | 365 | int doinghost = 1, size; |
7c0bf99b | 366 | int (*output)() = afswitch[sa->sa_family].af_output; |
6db0b3a4 | 367 | int sto = (rt->rt_state&RTS_INTERFACE) ? snoroute : s; |
7c0bf99b | 368 | |
6db0b3a4 | 369 | log("supply", rt); |
7c0bf99b SL |
370 | msg->rip_cmd = RIPCMD_RESPONSE; |
371 | again: | |
372 | for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) | |
373 | for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { | |
77df73ca SL |
374 | size = (char *)n - packet; |
375 | if (size > MAXPACKETSIZE - sizeof (struct netinfo)) { | |
6db0b3a4 | 376 | (*output)(sto, sa, size); |
7c0bf99b SL |
377 | n = msg->rip_nets; |
378 | } | |
379 | n->rip_dst = rt->rt_dst; | |
77df73ca SL |
380 | n->rip_metric = min(rt->rt_metric + 1, HOPCNT_INFINITY); |
381 | n++; | |
7c0bf99b SL |
382 | } |
383 | if (doinghost) { | |
384 | doinghost = 0; | |
385 | base = nethash; | |
386 | goto again; | |
387 | } | |
77df73ca | 388 | if (n != msg->rip_nets) |
6db0b3a4 | 389 | (*output)(sto, sa, (char *)n - packet); |
7c0bf99b SL |
390 | } |
391 | ||
392 | /* | |
393 | * Respond to a routing info request. | |
394 | */ | |
395 | rip_respond(from, size) | |
396 | struct sockaddr *from; | |
397 | int size; | |
398 | { | |
7c0bf99b SL |
399 | struct netinfo *np = msg->rip_nets; |
400 | struct rt_entry *rt; | |
401 | int newsize = 0; | |
402 | ||
77df73ca | 403 | size -= 4 * sizeof (char); |
7c0bf99b SL |
404 | while (size > 0) { |
405 | if (size < sizeof (struct netinfo)) | |
406 | break; | |
407 | size -= sizeof (struct netinfo); | |
408 | if (np->rip_dst.sa_family == AF_UNSPEC && | |
409 | np->rip_metric == HOPCNT_INFINITY && size == 0) { | |
74d7f201 | 410 | supply(s, from); |
7c0bf99b SL |
411 | return; |
412 | } | |
413 | rt = rtlookup(&np->rip_dst); | |
77df73ca SL |
414 | np->rip_metric = rt == 0 ? |
415 | HOPCNT_INFINITY : min(rt->rt_metric+1, HOPCNT_INFINITY); | |
7c0bf99b SL |
416 | np++, newsize += sizeof (struct netinfo); |
417 | } | |
418 | if (newsize > 0) { | |
419 | msg->rip_cmd = RIPCMD_RESPONSE; | |
420 | newsize += sizeof (int); | |
74d7f201 | 421 | (*afswitch[from->sa_family].af_output)(s, from, newsize); |
7c0bf99b SL |
422 | } |
423 | } | |
424 | ||
425 | /* | |
426 | * Handle an incoming routing packet. | |
427 | */ | |
428 | rip_input(from, size) | |
429 | struct sockaddr *from; | |
430 | int size; | |
431 | { | |
7c0bf99b SL |
432 | struct rt_entry *rt; |
433 | struct netinfo *n; | |
6db0b3a4 BJ |
434 | struct ifnet *ifp; |
435 | time_t t; | |
7c0bf99b | 436 | |
e6b5ed24 | 437 | switch (msg->rip_cmd) { |
7c0bf99b | 438 | |
e6b5ed24 | 439 | default: |
7c0bf99b | 440 | return; |
e6b5ed24 SL |
441 | |
442 | case RIPCMD_REQUEST: | |
7c0bf99b SL |
443 | rip_respond(from, size); |
444 | return; | |
e6b5ed24 | 445 | |
6d0df65e | 446 | case RIPCMD_TRACEON: |
6d0df65e SL |
447 | if ((*afswitch[from->sa_family].af_portcheck)(from) == 0) |
448 | return; | |
6db0b3a4 BJ |
449 | if (trace) |
450 | return; | |
451 | packet[size] = '\0'; | |
452 | ftrace = fopen(msg->rip_tracefile, "a"); | |
453 | if (ftrace == NULL) | |
e6b5ed24 | 454 | return; |
6db0b3a4 BJ |
455 | (void) dup2(fileno(ftrace), 1); |
456 | (void) dup2(fileno(ftrace), 2); | |
457 | trace = 1; | |
458 | t = time(0); | |
459 | printf("*** Tracing turned on at %.24s ***\n", ctime(&t)); | |
7c0bf99b | 460 | return; |
7c0bf99b | 461 | |
6db0b3a4 BJ |
462 | case RIPCMD_TRACEOFF: |
463 | /* verify message came from a priviledged port */ | |
464 | if ((*afswitch[from->sa_family].af_portcheck)(from) == 0) | |
465 | return; | |
6d0df65e SL |
466 | if (!trace) |
467 | return; | |
468 | t = time(0); | |
469 | printf("*** Tracing turned off at %.24s ***\n", ctime(&t)); | |
470 | fflush(stdout), fflush(stderr); | |
471 | if (ftrace) | |
472 | fclose(ftrace); | |
473 | (void) close(1), (void) close(2); | |
474 | trace = 0; | |
475 | return; | |
6d0df65e | 476 | |
6db0b3a4 BJ |
477 | case RIPCMD_RESPONSE: |
478 | /* verify message came from a router */ | |
479 | if ((*afswitch[from->sa_family].af_portmatch)(from) == 0) | |
480 | return; | |
481 | (*afswitch[from->sa_family].af_canon)(from); | |
482 | tprintf("input from %x\n", | |
483 | ((struct sockaddr_in *)from)->sin_addr); | |
484 | /* are we talking to ourselves? */ | |
485 | ifp = if_ifwithaddr(from); | |
486 | if (ifp) { | |
487 | rt = rtfind(from); | |
488 | if (rt) | |
489 | rt->rt_timer = 0; | |
490 | else | |
491 | addrouteforif(ifp); | |
492 | return; | |
493 | } | |
494 | size -= 4 * sizeof (char); | |
495 | n = msg->rip_nets; | |
496 | for (; size > 0; size -= sizeof (struct netinfo), n++) { | |
497 | if (size < sizeof (struct netinfo)) | |
498 | break; | |
499 | if (n->rip_metric >= HOPCNT_INFINITY) | |
500 | continue; | |
501 | tprintf("dst %x hc %d...", | |
502 | ((struct sockaddr_in *)&n->rip_dst)->sin_addr, | |
503 | n->rip_metric); | |
504 | rt = rtlookup(&n->rip_dst); | |
505 | if (rt == 0) { | |
506 | rtadd(&n->rip_dst, from, n->rip_metric, 0); | |
507 | tprintf("new\n"); | |
508 | continue; | |
509 | } | |
510 | tprintf("ours: gate %x hc %d timer %d\n", | |
511 | ((struct sockaddr_in *)&rt->rt_router)->sin_addr, | |
512 | rt->rt_metric, rt->rt_timer); | |
513 | /* | |
514 | * update if from gateway, shorter, or getting stale | |
515 | * and equivalent. | |
516 | */ | |
517 | if (equal(from, &rt->rt_router) || | |
518 | n->rip_metric < rt->rt_metric || | |
519 | (rt->rt_timer > (EXPIRE_TIME/2) && | |
520 | rt->rt_metric == n->rip_metric)) { | |
521 | rtchange(rt, from, n->rip_metric); | |
522 | rt->rt_timer = 0; | |
523 | } | |
524 | } | |
525 | return; | |
526 | } | |
3cec0c76 SL |
527 | } |
528 | ||
7c0bf99b SL |
529 | struct rt_entry * |
530 | rtlookup(dst) | |
531 | struct sockaddr *dst; | |
532 | { | |
533 | register struct rt_entry *rt; | |
3cec0c76 | 534 | register struct rthash *rh; |
eae14a37 | 535 | register int hash; |
7c0bf99b | 536 | struct afhash h; |
eae14a37 SL |
537 | int doinghost = 1; |
538 | ||
539 | if (dst->sa_family >= AF_MAX) | |
540 | return (0); | |
541 | (*afswitch[dst->sa_family].af_hash)(dst, &h); | |
542 | hash = h.afh_hosthash; | |
543 | rh = &hosthash[hash % ROUTEHASHSIZ]; | |
544 | again: | |
545 | for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { | |
546 | if (rt->rt_hash != hash) | |
547 | continue; | |
548 | if (equal(&rt->rt_dst, dst)) | |
549 | return (rt); | |
550 | } | |
551 | if (doinghost) { | |
552 | doinghost = 0; | |
553 | hash = h.afh_nethash; | |
554 | rh = &nethash[hash % ROUTEHASHSIZ]; | |
555 | goto again; | |
556 | } | |
557 | return (0); | |
558 | } | |
559 | ||
eae14a37 SL |
560 | struct rt_entry * |
561 | rtfind(dst) | |
562 | struct sockaddr *dst; | |
563 | { | |
564 | register struct rt_entry *rt; | |
565 | register struct rthash *rh; | |
566 | register int hash; | |
567 | struct afhash h; | |
568 | int af = dst->sa_family; | |
569 | int doinghost = 1, (*match)(); | |
7c0bf99b SL |
570 | |
571 | if (af >= AF_MAX) | |
572 | return (0); | |
573 | (*afswitch[af].af_hash)(dst, &h); | |
574 | hash = h.afh_hosthash; | |
575 | rh = &hosthash[hash % ROUTEHASHSIZ]; | |
576 | ||
577 | again: | |
578 | for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { | |
579 | if (rt->rt_hash != hash) | |
580 | continue; | |
581 | if (doinghost) { | |
582 | if (equal(&rt->rt_dst, dst)) | |
583 | return (rt); | |
584 | } else { | |
585 | if (rt->rt_dst.sa_family == af && | |
586 | (*match)(&rt->rt_dst, dst)) | |
587 | return (rt); | |
588 | } | |
589 | } | |
590 | if (doinghost) { | |
591 | doinghost = 0; | |
592 | hash = h.afh_nethash; | |
7c0bf99b | 593 | rh = &nethash[hash % ROUTEHASHSIZ]; |
eae14a37 | 594 | match = afswitch[af].af_netmatch; |
7c0bf99b SL |
595 | goto again; |
596 | } | |
597 | return (0); | |
598 | } | |
599 | ||
6db0b3a4 | 600 | rtadd(dst, gate, metric, iflags) |
7c0bf99b | 601 | struct sockaddr *dst, *gate; |
6db0b3a4 | 602 | int metric, iflags; |
7c0bf99b SL |
603 | { |
604 | struct afhash h; | |
605 | register struct rt_entry *rt; | |
3cec0c76 | 606 | struct rthash *rh; |
7c0bf99b SL |
607 | int af = dst->sa_family, flags, hash; |
608 | ||
609 | if (af >= AF_MAX) | |
610 | return; | |
611 | (*afswitch[af].af_hash)(dst, &h); | |
612 | flags = (*afswitch[af].af_checkhost)(dst) ? RTF_HOST : 0; | |
613 | if (flags & RTF_HOST) { | |
614 | hash = h.afh_hosthash; | |
615 | rh = &hosthash[hash % ROUTEHASHSIZ]; | |
616 | } else { | |
617 | hash = h.afh_nethash; | |
618 | rh = &nethash[hash % ROUTEHASHSIZ]; | |
619 | } | |
620 | rt = (struct rt_entry *)malloc(sizeof (*rt)); | |
621 | if (rt == 0) | |
622 | return; | |
623 | rt->rt_hash = hash; | |
624 | rt->rt_dst = *dst; | |
74d7f201 | 625 | rt->rt_router = *gate; |
7c0bf99b SL |
626 | rt->rt_metric = metric; |
627 | rt->rt_timer = 0; | |
6db0b3a4 | 628 | rt->rt_flags = RTF_UP | flags | iflags; |
e6b5ed24 | 629 | rt->rt_state = 0; |
74d7f201 BJ |
630 | rt->rt_ifp = if_ifwithnet(&rt->rt_router); |
631 | if (metric) | |
632 | rt->rt_flags |= RTF_GATEWAY; | |
7c0bf99b | 633 | insque(rt, rh); |
77df73ca | 634 | log("add", rt); |
74d7f201 | 635 | if (install) |
e6b5ed24 | 636 | rt->rt_state |= RTS_ADDRT; |
7c0bf99b SL |
637 | } |
638 | ||
7c0bf99b SL |
639 | rtchange(rt, gate, metric) |
640 | struct rt_entry *rt; | |
641 | struct sockaddr *gate; | |
642 | short metric; | |
643 | { | |
644 | int change = 0; | |
645 | ||
74d7f201 BJ |
646 | if (!equal(&rt->rt_router, gate)) { |
647 | rt->rt_newrouter = *gate; | |
7c0bf99b SL |
648 | change++; |
649 | } | |
7c0bf99b | 650 | if (metric != rt->rt_metric) { |
74d7f201 BJ |
651 | if (metric == 0) |
652 | rt->rt_flags |= RTF_GATEWAY; | |
7c0bf99b | 653 | rt->rt_metric = metric; |
7c0bf99b SL |
654 | change++; |
655 | } | |
7c0bf99b SL |
656 | if (!change) |
657 | return; | |
77df73ca | 658 | log("change", rt); |
74d7f201 | 659 | if (install) |
e6b5ed24 | 660 | rt->rt_state |= RTS_CHGRT; |
7c0bf99b SL |
661 | } |
662 | ||
7c0bf99b SL |
663 | rtdelete(rt) |
664 | struct rt_entry *rt; | |
665 | { | |
6db0b3a4 | 666 | |
77df73ca | 667 | log("delete", rt); |
74d7f201 BJ |
668 | if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt)) |
669 | perror("SIOCDELRT"); | |
670 | /* don't delete interface entries so we can poll them later */ | |
671 | if (rt->rt_state & RTS_INTERFACE) | |
672 | return; | |
7c0bf99b SL |
673 | remque(rt); |
674 | free((char *)rt); | |
675 | } | |
676 | ||
7c0bf99b SL |
677 | log(operation, rt) |
678 | char *operation; | |
679 | struct rt_entry *rt; | |
680 | { | |
681 | time_t t = time(0); | |
682 | struct sockaddr_in *dst, *gate; | |
e6b5ed24 | 683 | static struct bits { |
7c0bf99b SL |
684 | int t_bits; |
685 | char *t_name; | |
e6b5ed24 | 686 | } flagbits[] = { |
7c0bf99b | 687 | { RTF_UP, "UP" }, |
74d7f201 | 688 | { RTF_GATEWAY, "GATEWAY" }, |
7c0bf99b | 689 | { RTF_HOST, "HOST" }, |
e6b5ed24 SL |
690 | { 0 } |
691 | }, statebits[] = { | |
692 | { RTS_DELRT, "DELETE" }, | |
693 | { RTS_CHGRT, "CHANGE" }, | |
74d7f201 BJ |
694 | { RTS_PASSIVE, "PASSIVE" }, |
695 | { RTS_INTERFACE,"INTERFACE" }, | |
6db0b3a4 | 696 | { RTS_GLOBAL, "GLOBAL" }, |
7c0bf99b SL |
697 | { 0 } |
698 | }; | |
e6b5ed24 | 699 | register struct bits *p; |
7c0bf99b SL |
700 | register int first; |
701 | char *cp; | |
702 | ||
77df73ca SL |
703 | if (trace == 0) |
704 | return; | |
7c0bf99b SL |
705 | printf("%s ", operation); |
706 | dst = (struct sockaddr_in *)&rt->rt_dst; | |
74d7f201 | 707 | gate = (struct sockaddr_in *)&rt->rt_router; |
e6b5ed24 | 708 | printf("dst %x, router %x, metric %d, flags", |
7c0bf99b | 709 | dst->sin_addr, gate->sin_addr, rt->rt_metric); |
e6b5ed24 SL |
710 | cp = " %s"; |
711 | for (first = 1, p = flagbits; p->t_bits > 0; p++) { | |
7c0bf99b SL |
712 | if ((rt->rt_flags & p->t_bits) == 0) |
713 | continue; | |
714 | printf(cp, p->t_name); | |
715 | if (first) { | |
716 | cp = "|%s"; | |
717 | first = 0; | |
718 | } | |
719 | } | |
e6b5ed24 SL |
720 | printf(" state"); |
721 | cp = " %s"; | |
722 | for (first = 1, p = statebits; p->t_bits > 0; p++) { | |
723 | if ((rt->rt_state & p->t_bits) == 0) | |
724 | continue; | |
725 | printf(cp, p->t_name); | |
726 | if (first) { | |
727 | cp = "|%s"; | |
728 | first = 0; | |
729 | } | |
730 | } | |
7c0bf99b SL |
731 | putchar('\n'); |
732 | } | |
77df73ca SL |
733 | |
734 | struct ifnet * | |
735 | if_ifwithaddr(addr) | |
736 | struct sockaddr *addr; | |
737 | { | |
738 | register struct ifnet *ifp; | |
739 | ||
740 | #define same(a1, a2) \ | |
741 | (bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0) | |
742 | for (ifp = ifnet; ifp; ifp = ifp->if_next) { | |
743 | if (ifp->if_addr.sa_family != addr->sa_family) | |
744 | continue; | |
745 | if (same(&ifp->if_addr, addr)) | |
746 | break; | |
747 | if ((ifp->if_flags & IFF_BROADCAST) && | |
748 | same(&ifp->if_broadaddr, addr)) | |
749 | break; | |
750 | } | |
751 | return (ifp); | |
752 | #undef same | |
753 | } | |
754 | ||
755 | struct ifnet * | |
756 | if_ifwithnet(addr) | |
757 | register struct sockaddr *addr; | |
758 | { | |
759 | register struct ifnet *ifp; | |
760 | register int af = addr->sa_family; | |
761 | register int (*netmatch)(); | |
762 | ||
763 | if (af >= AF_MAX) | |
764 | return (0); | |
765 | netmatch = afswitch[af].af_netmatch; | |
766 | for (ifp = ifnet; ifp; ifp = ifp->if_next) { | |
767 | if (af != ifp->if_addr.sa_family) | |
768 | continue; | |
769 | if ((*netmatch)(addr, &ifp->if_addr)) | |
770 | break; | |
771 | } | |
772 | return (ifp); | |
773 | } | |
774 | ||
775 | struct in_addr | |
776 | if_makeaddr(net, host) | |
777 | int net, host; | |
778 | { | |
779 | u_long addr; | |
780 | ||
781 | if (net < 128) | |
782 | addr = (net << 24) | host; | |
783 | else if (net < 65536) | |
784 | addr = (net << 16) | host; | |
785 | else | |
786 | addr = (net << 8) | host; | |
787 | #ifdef vax | |
788 | addr = htonl(addr); | |
789 | #endif | |
790 | return (*(struct in_addr *)&addr); | |
791 | } |