Commit | Line | Data |
---|---|---|
5ff67f98 DF |
1 | /* |
2 | * Copyright (c) 1983 Regents of the University of California. | |
3 | * All rights reserved. The Berkeley software License Agreement | |
4 | * specifies the terms and conditions for redistribution. | |
5 | */ | |
6 | ||
2e74322d | 7 | #ifndef lint |
eb39c032 | 8 | static char sccsid[] = "@(#)input.c 5.7 (Berkeley) %G%"; |
5ff67f98 | 9 | #endif not lint |
2e74322d SL |
10 | |
11 | /* | |
12 | * Routing Table Management Daemon | |
13 | */ | |
7fe7fe74 | 14 | #include "defs.h" |
17fe297f | 15 | #include <sys/syslog.h> |
2e74322d SL |
16 | |
17 | /* | |
18 | * Process a newly received packet. | |
19 | */ | |
20 | rip_input(from, size) | |
21 | struct sockaddr *from; | |
22 | int size; | |
23 | { | |
20df59f1 MK |
24 | register struct rt_entry *rt; |
25 | register struct netinfo *n; | |
26 | register struct interface *ifp; | |
27 | struct interface *if_ifwithdstaddr(); | |
2e74322d | 28 | int newsize; |
20df59f1 | 29 | register struct afswitch *afp; |
eb39c032 | 30 | static struct sockaddr badfrom; |
2e74322d SL |
31 | |
32 | ifp = 0; | |
33 | TRACE_INPUT(ifp, from, size); | |
17fe297f MK |
34 | if (from->sa_family >= af_max || |
35 | (afp = &afswitch[from->sa_family])->af_hash == (int (*)())0) { | |
36 | syslog(LOG_INFO, | |
37 | "\"from\" address in unsupported address family (%d), cmd %d\n", | |
38 | from->sa_family, msg->rip_cmd); | |
2e74322d | 39 | return; |
17fe297f | 40 | } |
2e74322d SL |
41 | switch (msg->rip_cmd) { |
42 | ||
43 | case RIPCMD_REQUEST: | |
44 | newsize = 0; | |
45 | size -= 4 * sizeof (char); | |
46 | n = msg->rip_nets; | |
47 | while (size > 0) { | |
48 | if (size < sizeof (struct netinfo)) | |
49 | break; | |
50 | size -= sizeof (struct netinfo); | |
51 | ||
55d340a4 SL |
52 | if (msg->rip_vers > 0) { |
53 | n->rip_dst.sa_family = | |
54 | ntohs(n->rip_dst.sa_family); | |
55 | n->rip_metric = ntohl(n->rip_metric); | |
56 | } | |
2e74322d SL |
57 | /* |
58 | * A single entry with sa_family == AF_UNSPEC and | |
59 | * metric ``infinity'' means ``all routes''. | |
17fe297f MK |
60 | * We respond to routers only if we are acting |
61 | * as a supplier, or to anyone other than a router | |
62 | * (eg, query). | |
2e74322d SL |
63 | */ |
64 | if (n->rip_dst.sa_family == AF_UNSPEC && | |
17deb420 MK |
65 | n->rip_metric == HOPCNT_INFINITY && size == 0) { |
66 | if (supplier || (*afp->af_portmatch)(from) == 0) | |
4fad5a6e | 67 | supply(from, 0, 0); |
2e74322d SL |
68 | return; |
69 | } | |
17deb420 MK |
70 | if (n->rip_dst.sa_family < af_max && |
71 | afswitch[n->rip_dst.sa_family].af_hash) | |
72 | rt = rtlookup(&n->rip_dst); | |
73 | else | |
74 | rt = 0; | |
2e74322d SL |
75 | n->rip_metric = rt == 0 ? HOPCNT_INFINITY : |
76 | min(rt->rt_metric+1, HOPCNT_INFINITY); | |
55d340a4 SL |
77 | if (msg->rip_vers > 0) { |
78 | n->rip_dst.sa_family = | |
79 | htons(n->rip_dst.sa_family); | |
80 | n->rip_metric = htonl(n->rip_metric); | |
81 | } | |
2e74322d SL |
82 | n++, newsize += sizeof (struct netinfo); |
83 | } | |
84 | if (newsize > 0) { | |
85 | msg->rip_cmd = RIPCMD_RESPONSE; | |
86 | newsize += sizeof (int); | |
4f4bffaa | 87 | (*afp->af_output)(s, 0, from, newsize); |
2e74322d SL |
88 | } |
89 | return; | |
90 | ||
91 | case RIPCMD_TRACEON: | |
92 | case RIPCMD_TRACEOFF: | |
b7e4f8be | 93 | /* verify message came from a privileged port */ |
2e74322d SL |
94 | if ((*afp->af_portcheck)(from) == 0) |
95 | return; | |
09069ad0 MK |
96 | if (if_iflookup(from) == 0) { |
97 | syslog(LOG_ERR, "trace command from unknown router, %s", | |
eb39c032 | 98 | (*afswitch[from->sa_family].af_format)(from)); |
09069ad0 MK |
99 | return; |
100 | } | |
2e74322d SL |
101 | packet[size] = '\0'; |
102 | if (msg->rip_cmd == RIPCMD_TRACEON) | |
103 | traceon(msg->rip_tracefile); | |
104 | else | |
105 | traceoff(); | |
106 | return; | |
107 | ||
108 | case RIPCMD_RESPONSE: | |
109 | /* verify message came from a router */ | |
110 | if ((*afp->af_portmatch)(from) == 0) | |
111 | return; | |
112 | (*afp->af_canon)(from); | |
113 | /* are we talking to ourselves? */ | |
114 | ifp = if_ifwithaddr(from); | |
115 | if (ifp) { | |
116 | rt = rtfind(from); | |
b7e4f8be | 117 | if (rt == 0 || (rt->rt_state & RTS_INTERFACE) == 0) |
2e74322d SL |
118 | addrouteforif(ifp); |
119 | else | |
120 | rt->rt_timer = 0; | |
121 | return; | |
122 | } | |
f1e15e15 MK |
123 | /* |
124 | * Update timer for interface on which the packet arrived. | |
125 | * If from other end of a point-to-point link that isn't | |
126 | * in the routing tables, (re-)add the route. | |
127 | */ | |
09069ad0 MK |
128 | if ((rt = rtfind(from)) && |
129 | (rt->rt_state & (RTS_INTERFACE | RTS_REMOTE))) | |
b7e4f8be | 130 | rt->rt_timer = 0; |
f1e15e15 MK |
131 | else if (ifp = if_ifwithdstaddr(from)) |
132 | addrouteforif(ifp); | |
09069ad0 | 133 | else if (if_iflookup(from) == 0) { |
eb39c032 MK |
134 | if (bcmp((char *)from, (char *)&badfrom, |
135 | sizeof(badfrom)) != 0) { | |
136 | syslog(LOG_ERR, | |
137 | "packet from unknown router, %s", | |
138 | (*afswitch[from->sa_family].af_format)(from)); | |
139 | badfrom = *from; | |
140 | } | |
09069ad0 MK |
141 | return; |
142 | } | |
2e74322d SL |
143 | size -= 4 * sizeof (char); |
144 | n = msg->rip_nets; | |
145 | for (; size > 0; size -= sizeof (struct netinfo), n++) { | |
146 | if (size < sizeof (struct netinfo)) | |
147 | break; | |
55d340a4 SL |
148 | if (msg->rip_vers > 0) { |
149 | n->rip_dst.sa_family = | |
150 | ntohs(n->rip_dst.sa_family); | |
151 | n->rip_metric = ntohl(n->rip_metric); | |
152 | } | |
20df59f1 | 153 | if ((unsigned) n->rip_metric > HOPCNT_INFINITY) |
d5568f13 | 154 | continue; |
17fe297f MK |
155 | if (n->rip_dst.sa_family >= af_max || |
156 | (afp = &afswitch[n->rip_dst.sa_family])->af_hash == | |
157 | (int (*)())0) { | |
158 | syslog(LOG_INFO, | |
159 | "route in unsupported address family (%d), from %s (af %d)\n", | |
160 | n->rip_dst.sa_family, | |
161 | (*afswitch[from->sa_family].af_format)(from), | |
162 | from->sa_family); | |
ed36994a | 163 | continue; |
17fe297f MK |
164 | } |
165 | if (((*afp->af_checkhost)(&n->rip_dst)) == 0) { | |
166 | syslog(LOG_DEBUG, | |
167 | "bad host in route from %s (af %d)\n", | |
168 | (*afswitch[from->sa_family].af_format)(from), | |
169 | from->sa_family); | |
2e74322d | 170 | continue; |
17fe297f | 171 | } |
2e74322d | 172 | rt = rtlookup(&n->rip_dst); |
97cb3618 MK |
173 | if (rt == 0 || |
174 | (rt->rt_state & (RTS_INTERNAL|RTS_INTERFACE)) == | |
175 | (RTS_INTERNAL|RTS_INTERFACE)) { | |
09069ad0 MK |
176 | rt = rtfind(&n->rip_dst); |
177 | if (rt && equal(from, &rt->rt_router) && | |
178 | rt->rt_metric == n->rip_metric) | |
179 | continue; | |
20df59f1 MK |
180 | if (n->rip_metric < HOPCNT_INFINITY) |
181 | rtadd(&n->rip_dst, from, n->rip_metric, 0); | |
2e74322d SL |
182 | continue; |
183 | } | |
184 | ||
185 | /* | |
38ca17a8 MK |
186 | * Update if from gateway and different, |
187 | * shorter, or getting stale and equivalent. | |
2e74322d | 188 | */ |
15e56604 MK |
189 | if (equal(from, &rt->rt_router)) { |
190 | if (n->rip_metric != rt->rt_metric) | |
191 | rtchange(rt, from, n->rip_metric); | |
192 | rt->rt_timer = 0; | |
193 | } else if ((unsigned) (n->rip_metric) < rt->rt_metric || | |
2e74322d SL |
194 | (rt->rt_timer > (EXPIRE_TIME/2) && |
195 | rt->rt_metric == n->rip_metric)) { | |
196 | rtchange(rt, from, n->rip_metric); | |
197 | rt->rt_timer = 0; | |
198 | } | |
199 | } | |
200 | return; | |
201 | } | |
202 | } |