4.4BSD snapshot (revision 8.1); add 1993 to copyright
[unix-history] / usr / src / sbin / routed / input.c
CommitLineData
5ff67f98 1/*
b2d6cd51
KB
2 * Copyright (c) 1983, 1988, 1993
3 * The Regents of the University of California. All rights reserved.
0eb85d71 4 *
d60d530a 5 * %sccs.include.redist.c%
5ff67f98
DF
6 */
7
2e74322d 8#ifndef lint
b2d6cd51 9static char sccsid[] = "@(#)input.c 8.1 (Berkeley) %G%";
0eb85d71 10#endif /* not lint */
2e74322d
SL
11
12/*
13 * Routing Table Management Daemon
14 */
7fe7fe74 15#include "defs.h"
17fe297f 16#include <sys/syslog.h>
2e74322d
SL
17
18/*
19 * Process a newly received packet.
20 */
787d3210 21rip_input(from, rip, size)
2e74322d 22 struct sockaddr *from;
787d3210 23 register struct rip *rip;
2e74322d
SL
24 int size;
25{
20df59f1
MK
26 register struct rt_entry *rt;
27 register struct netinfo *n;
28 register struct interface *ifp;
29 struct interface *if_ifwithdstaddr();
4033c8f6 30 int count, changes = 0;
20df59f1 31 register struct afswitch *afp;
09b9aef2 32 static struct sockaddr badfrom, badfrom2;
2e74322d
SL
33
34 ifp = 0;
787d3210 35 TRACE_INPUT(ifp, from, (char *)rip, size);
17fe297f
MK
36 if (from->sa_family >= af_max ||
37 (afp = &afswitch[from->sa_family])->af_hash == (int (*)())0) {
38 syslog(LOG_INFO,
39 "\"from\" address in unsupported address family (%d), cmd %d\n",
787d3210 40 from->sa_family, rip->rip_cmd);
2e74322d 41 return;
17fe297f 42 }
787d3210 43 if (rip->rip_vers == 0) {
4033c8f6
MK
44 syslog(LOG_ERR,
45 "RIP version 0 packet received from %s! (cmd %d)",
787d3210 46 (*afswitch[from->sa_family].af_format)(from), rip->rip_cmd);
4033c8f6
MK
47 return;
48 }
787d3210 49 switch (rip->rip_cmd) {
2e74322d
SL
50
51 case RIPCMD_REQUEST:
787d3210
MK
52 n = rip->rip_nets;
53 count = size - ((char *)n - (char *)rip);
4033c8f6
MK
54 if (count < sizeof (struct netinfo))
55 return;
56 for (; count > 0; n++) {
57 if (count < sizeof (struct netinfo))
2e74322d 58 break;
4033c8f6 59 count -= sizeof (struct netinfo);
2e74322d 60
4033c8f6 61#if BSD < 198810
a33a5c17
KS
62 if (sizeof(n->rip_dst.sa_family) > 1) /* XXX */
63 n->rip_dst.sa_family = ntohs(n->rip_dst.sa_family);
64#else
65#define osa(x) ((struct osockaddr *)(&(x)))
66 n->rip_dst.sa_family =
67 ntohs(osa(n->rip_dst)->sa_family);
68 n->rip_dst.sa_len = sizeof(n->rip_dst);
4033c8f6
MK
69#endif
70 n->rip_metric = ntohl(n->rip_metric);
2e74322d
SL
71 /*
72 * A single entry with sa_family == AF_UNSPEC and
73 * metric ``infinity'' means ``all routes''.
17fe297f
MK
74 * We respond to routers only if we are acting
75 * as a supplier, or to anyone other than a router
76 * (eg, query).
2e74322d
SL
77 */
78 if (n->rip_dst.sa_family == AF_UNSPEC &&
4033c8f6 79 n->rip_metric == HOPCNT_INFINITY && count == 0) {
17deb420 80 if (supplier || (*afp->af_portmatch)(from) == 0)
4033c8f6 81 supply(from, 0, 0, 0);
2e74322d
SL
82 return;
83 }
17deb420
MK
84 if (n->rip_dst.sa_family < af_max &&
85 afswitch[n->rip_dst.sa_family].af_hash)
86 rt = rtlookup(&n->rip_dst);
87 else
88 rt = 0;
a33a5c17 89#define min(a, b) (a < b ? a : b)
2e74322d 90 n->rip_metric = rt == 0 ? HOPCNT_INFINITY :
cdf21aa5 91 min(rt->rt_metric + 1, HOPCNT_INFINITY);
4033c8f6
MK
92#if BSD < 198810
93 if (sizeof(n->rip_dst.sa_family) > 1) /* XXX */
94 n->rip_dst.sa_family = htons(n->rip_dst.sa_family);
a33a5c17
KS
95#else
96 osa(n->rip_dst)->sa_family =
97 htons(n->rip_dst.sa_family);
4033c8f6
MK
98#endif
99 n->rip_metric = htonl(n->rip_metric);
2e74322d 100 }
787d3210
MK
101 rip->rip_cmd = RIPCMD_RESPONSE;
102 bcopy((char *)rip, packet, size);
4033c8f6 103 (*afp->af_output)(s, 0, from, size);
2e74322d
SL
104 return;
105
106 case RIPCMD_TRACEON:
107 case RIPCMD_TRACEOFF:
b7e4f8be 108 /* verify message came from a privileged port */
2e74322d
SL
109 if ((*afp->af_portcheck)(from) == 0)
110 return;
71786f50 111 if ((ifp = if_iflookup(from)) == 0 || (ifp->int_flags &
98a1809a
MK
112 (IFF_BROADCAST | IFF_POINTOPOINT | IFF_REMOTE)) == 0 ||
113 ifp->int_flags & IFF_PASSIVE) {
09069ad0 114 syslog(LOG_ERR, "trace command from unknown router, %s",
eb39c032 115 (*afswitch[from->sa_family].af_format)(from));
09069ad0
MK
116 return;
117 }
787d3210
MK
118 ((char *)rip)[size] = '\0';
119 if (rip->rip_cmd == RIPCMD_TRACEON)
120 traceon(rip->rip_tracefile);
2e74322d
SL
121 else
122 traceoff();
123 return;
124
125 case RIPCMD_RESPONSE:
126 /* verify message came from a router */
127 if ((*afp->af_portmatch)(from) == 0)
128 return;
129 (*afp->af_canon)(from);
130 /* are we talking to ourselves? */
131 ifp = if_ifwithaddr(from);
132 if (ifp) {
0f7c421b
MK
133 if (ifp->int_flags & IFF_PASSIVE) {
134 syslog(LOG_ERR,
135 "bogus input (from passive interface, %s)",
136 (*afswitch[from->sa_family].af_format)(from));
137 return;
138 }
2e74322d 139 rt = rtfind(from);
7892134c
MK
140 if (rt == 0 || ((rt->rt_state & RTS_INTERFACE) == 0) &&
141 rt->rt_metric >= ifp->int_metric)
2e74322d
SL
142 addrouteforif(ifp);
143 else
144 rt->rt_timer = 0;
145 return;
146 }
f1e15e15
MK
147 /*
148 * Update timer for interface on which the packet arrived.
149 * If from other end of a point-to-point link that isn't
150 * in the routing tables, (re-)add the route.
151 */
09069ad0
MK
152 if ((rt = rtfind(from)) &&
153 (rt->rt_state & (RTS_INTERFACE | RTS_REMOTE)))
b7e4f8be 154 rt->rt_timer = 0;
7892134c
MK
155 else if ((ifp = if_ifwithdstaddr(from)) &&
156 (rt == 0 || rt->rt_metric >= ifp->int_metric))
f1e15e15 157 addrouteforif(ifp);
71786f50
MK
158 /*
159 * "Authenticate" router from which message originated.
160 * We accept routing packets from routers directly connected
161 * via broadcast or point-to-point networks,
162 * and from those listed in /etc/gateways.
163 */
164 if ((ifp = if_iflookup(from)) == 0 || (ifp->int_flags &
98a1809a
MK
165 (IFF_BROADCAST | IFF_POINTOPOINT | IFF_REMOTE)) == 0 ||
166 ifp->int_flags & IFF_PASSIVE) {
eb39c032
MK
167 if (bcmp((char *)from, (char *)&badfrom,
168 sizeof(badfrom)) != 0) {
169 syslog(LOG_ERR,
170 "packet from unknown router, %s",
171 (*afswitch[from->sa_family].af_format)(from));
172 badfrom = *from;
173 }
09069ad0
MK
174 return;
175 }
2e74322d 176 size -= 4 * sizeof (char);
787d3210 177 n = rip->rip_nets;
2e74322d
SL
178 for (; size > 0; size -= sizeof (struct netinfo), n++) {
179 if (size < sizeof (struct netinfo))
180 break;
4033c8f6
MK
181#if BSD < 198810
182 if (sizeof(n->rip_dst.sa_family) > 1) /* XXX */
55d340a4
SL
183 n->rip_dst.sa_family =
184 ntohs(n->rip_dst.sa_family);
a33a5c17
KS
185#else
186 n->rip_dst.sa_family =
187 ntohs(osa(n->rip_dst)->sa_family);
188 n->rip_dst.sa_len = sizeof(n->rip_dst);
4033c8f6
MK
189#endif
190 n->rip_metric = ntohl(n->rip_metric);
17fe297f
MK
191 if (n->rip_dst.sa_family >= af_max ||
192 (afp = &afswitch[n->rip_dst.sa_family])->af_hash ==
193 (int (*)())0) {
194 syslog(LOG_INFO,
195 "route in unsupported address family (%d), from %s (af %d)\n",
196 n->rip_dst.sa_family,
197 (*afswitch[from->sa_family].af_format)(from),
198 from->sa_family);
ed36994a 199 continue;
17fe297f
MK
200 }
201 if (((*afp->af_checkhost)(&n->rip_dst)) == 0) {
202 syslog(LOG_DEBUG,
203 "bad host in route from %s (af %d)\n",
204 (*afswitch[from->sa_family].af_format)(from),
205 from->sa_family);
2e74322d 206 continue;
17fe297f 207 }
09b9aef2
MK
208 if (n->rip_metric == 0 ||
209 (unsigned) n->rip_metric > HOPCNT_INFINITY) {
210 if (bcmp((char *)from, (char *)&badfrom2,
211 sizeof(badfrom2)) != 0) {
212 syslog(LOG_ERR,
213 "bad metric (%d) from %s\n",
214 n->rip_metric,
215 (*afswitch[from->sa_family].af_format)(from));
216 badfrom2 = *from;
217 }
218 continue;
219 }
7892134c
MK
220 /*
221 * Adjust metric according to incoming interface.
222 */
cdf21aa5 223 if ((unsigned) n->rip_metric < HOPCNT_INFINITY)
7892134c 224 n->rip_metric += ifp->int_metric;
cdf21aa5
MK
225 if ((unsigned) n->rip_metric > HOPCNT_INFINITY)
226 n->rip_metric = HOPCNT_INFINITY;
2e74322d 227 rt = rtlookup(&n->rip_dst);
97cb3618
MK
228 if (rt == 0 ||
229 (rt->rt_state & (RTS_INTERNAL|RTS_INTERFACE)) ==
230 (RTS_INTERNAL|RTS_INTERFACE)) {
7892134c
MK
231 /*
232 * If we're hearing a logical network route
233 * back from a peer to which we sent it,
234 * ignore it.
235 */
236 if (rt && rt->rt_state & RTS_SUBNET &&
237 (*afp->af_sendroute)(rt, from))
238 continue;
0f7c421b
MK
239 if ((unsigned)n->rip_metric < HOPCNT_INFINITY) {
240 /*
241 * Look for an equivalent route that
242 * includes this one before adding
243 * this route.
244 */
245 rt = rtfind(&n->rip_dst);
246 if (rt && equal(from, &rt->rt_router))
247 continue;
20df59f1 248 rtadd(&n->rip_dst, from, n->rip_metric, 0);
4033c8f6 249 changes++;
0f7c421b 250 }
2e74322d
SL
251 continue;
252 }
253
254 /*
38ca17a8 255 * Update if from gateway and different,
0f7c421b
MK
256 * shorter, or equivalent but old route
257 * is getting stale.
2e74322d 258 */
15e56604 259 if (equal(from, &rt->rt_router)) {
88709531 260 if (n->rip_metric != rt->rt_metric) {
15e56604 261 rtchange(rt, from, n->rip_metric);
4033c8f6 262 changes++;
0f7c421b 263 rt->rt_timer = 0;
7892134c 264 if (rt->rt_metric >= HOPCNT_INFINITY)
88709531
MK
265 rt->rt_timer =
266 GARBAGE_TIME - EXPIRE_TIME;
267 } else if (rt->rt_metric < HOPCNT_INFINITY)
585e6328 268 rt->rt_timer = 0;
cdf21aa5 269 } else if ((unsigned) n->rip_metric < rt->rt_metric ||
0f7c421b
MK
270 (rt->rt_metric == n->rip_metric &&
271 rt->rt_timer > (EXPIRE_TIME/2) &&
cdf21aa5 272 (unsigned) n->rip_metric < HOPCNT_INFINITY)) {
2e74322d 273 rtchange(rt, from, n->rip_metric);
4033c8f6 274 changes++;
2e74322d
SL
275 rt->rt_timer = 0;
276 }
277 }
4033c8f6
MK
278 break;
279 }
280
281 /*
282 * If changes have occurred, and if we have not sent a broadcast
283 * recently, send a dynamic update. This update is sent only
284 * on interfaces other than the one on which we received notice
285 * of the change. If we are within MIN_WAITTIME of a full update,
286 * don't bother sending; if we just sent a dynamic update
287 * and set a timer (nextbcast), delay until that time.
288 * If we just sent a full update, delay the dynamic update.
289 * Set a timer for a randomized value to suppress additional
290 * dynamic updates until it expires; if we delayed sending
291 * the current changes, set needupdate.
292 */
293 if (changes && supplier &&
294 now.tv_sec - lastfullupdate.tv_sec < SUPPLY_INTERVAL-MAX_WAITTIME) {
295 u_long delay;
296 extern long random();
297
298 if (now.tv_sec - lastbcast.tv_sec >= MIN_WAITTIME &&
299 timercmp(&nextbcast, &now, <)) {
300 if (traceactions)
301 fprintf(ftrace, "send dynamic update\n");
302 toall(supply, RTS_CHANGED, ifp);
303 lastbcast = now;
304 needupdate = 0;
305 nextbcast.tv_sec = 0;
306 } else {
307 needupdate++;
308 if (traceactions)
309 fprintf(ftrace, "delay dynamic update\n");
310 }
311#define RANDOMDELAY() (MIN_WAITTIME * 1000000 + \
312 (u_long)random() % ((MAX_WAITTIME - MIN_WAITTIME) * 1000000))
313
314 if (nextbcast.tv_sec == 0) {
315 delay = RANDOMDELAY();
316 if (traceactions)
317 fprintf(ftrace,
318 "inhibit dynamic update for %d usec\n",
319 delay);
320 nextbcast.tv_sec = delay / 1000000;
321 nextbcast.tv_usec = delay % 1000000;
322 timevaladd(&nextbcast, &now);
323 /*
324 * If the next possibly dynamic update
325 * is within MIN_WAITTIME of the next full update,
326 * force the delay past the full update,
327 * or we might send a dynamic update just before
328 * the full update.
329 */
330 if (nextbcast.tv_sec > lastfullupdate.tv_sec +
331 SUPPLY_INTERVAL - MIN_WAITTIME)
332 nextbcast.tv_sec = lastfullupdate.tv_sec +
333 SUPPLY_INTERVAL + 1;
334 }
2e74322d
SL
335 }
336}