Sweep-fix comparing pointers with 0 (and assigning 0 to pointers).
[games.git] / usr.sbin / IPXrouted / input.c
1 /*
2  * Copyright (c) 1985, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Copyright (c) 1995 John Hay.  All rights reserved.
6  *
7  * This file includes significant work done at Cornell University by
8  * Bill Nesheim.  That work included by permission.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *      This product includes software developed by the University of
21  *      California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  * $FreeBSD: src/usr.sbin/IPXrouted/input.c,v 1.7 1999/08/28 01:15:02 peter Exp $
39  *
40  * @(#)input.c  8.1 (Berkeley) 6/5/93
41  */
42
43 /*
44  * IPX Routing Table Management Daemon
45  */
46 #include "defs.h"
47
48 struct sockaddr *
49 ipx_nettosa(union ipx_net net)
50 {
51         static struct sockaddr_ipx sxn;
52         
53         bzero(&sxn, sizeof (struct sockaddr_ipx));
54         sxn.sipx_family = AF_IPX;
55         sxn.sipx_len = sizeof (sxn);
56         sxn.sipx_addr.x_net = net;
57         return( (struct sockaddr *)&sxn);
58         
59 }
60
61 /*
62  * Process a newly received packet.
63  */
64 void
65 rip_input(struct sockaddr *from, int size)
66 {
67         int newsize;
68         int rtchanged = 0;
69         struct rt_entry *rt;
70         struct netinfo *n;
71         struct interface *ifp = NULL;
72         struct afswitch *afp;
73         struct sockaddr_ipx *ipxp;
74
75         ifp = if_ifwithnet(from);
76         ipxp = (struct sockaddr_ipx *)from;
77         if (ifp == NULL) {
78                 if(ftrace) {
79                         fprintf(ftrace, "Received bogus packet from %s\n",
80                                 ipxdp_ntoa(&ipxp->sipx_addr));
81                 }
82                 return;
83         }
84
85         TRACE_INPUT(ifp, from, size);
86         if (from->sa_family >= AF_MAX)
87                 return;
88         afp = &afswitch[from->sa_family];
89         
90         size -= sizeof (u_short)        /* command */;
91         n = msg->rip_nets;
92
93         switch (ntohs(msg->rip_cmd)) {
94
95         case RIPCMD_REQUEST:
96                 if (ipx_hosteq(satoipx_addr(ifp->int_addr), ipxp->sipx_addr))
97                         return;
98                 newsize = 0;
99                 while (size > 0) {
100                         if (size < sizeof (struct netinfo))
101                                 break;
102                         size -= sizeof (struct netinfo);
103
104                         /* 
105                          * A single entry with rip_dst == DSTNETS_ALL and
106                          * metric ``infinity'' means ``all routes''.
107                          *
108                          * XXX According to the IPX RIP spec the metric
109                          * and tick fields can be anything. So maybe we
110                          * should not check the metric???
111                          */
112                         if (ipx_neteqnn(n->rip_dst, ipx_anynet) &&
113                             ntohs(n->rip_metric) == HOPCNT_INFINITY &&
114                             size == 0) {
115                                 supply(from, 0, ifp, 0);
116                                 return;
117                         }
118                         /*
119                          * request for specific nets
120                          */
121                         rt = rtlookup(ipx_nettosa(n->rip_dst));
122                         if (ftrace) {
123                                 fprintf(ftrace,
124                                         "specific request for %s",
125                                         ipxdp_nettoa(n->rip_dst));
126                                 fprintf(ftrace,
127                                         " yields route %p\n",
128                                         rt);
129                         }
130                         /*
131                          * XXX We break out on the first net that isn't
132                          * found. The specs is a bit vague here. I'm not
133                          * sure what we should do.
134                          */
135                         if (rt == NULL)
136                                 return;
137                         /* XXX
138                          * According to the spec we should not include
139                          * information about networks for which the number
140                          * of hops is 16.
141                          */
142                         if (rt->rt_metric == (HOPCNT_INFINITY-1))
143                                 return;
144                         n->rip_metric = htons( rt == NULL ? HOPCNT_INFINITY :
145                                 min(rt->rt_metric+1, HOPCNT_INFINITY));
146                         n->rip_ticks = htons(rt->rt_ticks+1);
147
148                         /*
149                          * We use split horizon with a twist. If the requested
150                          * net is the directly connected net we supply an
151                          * answer. This is so that the host can learn about
152                          * the routers on its net.
153                          */
154                         {
155                                 struct rt_entry *trt = rt;
156
157                                 while (trt) {
158                                         if ((trt->rt_ifp == ifp) && 
159                                             !ipx_neteqnn(n->rip_dst, 
160                                                 satoipx_addr(ifp->int_addr).x_net))
161                                                 return;
162                                         trt = trt->rt_clone;
163                                 }
164                                 n++;
165                                 newsize += sizeof (struct netinfo);
166                         }
167                 }
168                 if (newsize > 0) {
169                         msg->rip_cmd = htons(RIPCMD_RESPONSE);
170                         newsize += sizeof (u_short);
171                         /* should check for if with dstaddr(from) first */
172                         (*afp->af_output)(ripsock, 0, from, newsize);
173                         TRACE_OUTPUT(ifp, from, newsize);
174                         if (ftrace) {
175                                 /* XXX This should not happen anymore. */
176                                 if(ifp == NULL)
177                                         fprintf(ftrace, "--- ifp = 0\n");
178                                 else
179                                         fprintf(ftrace,
180                                                 "request arrived on interface %s\n",
181                                                 ifp->int_name);
182                         }
183                 }
184                 return;
185
186         case RIPCMD_RESPONSE:
187                 /* verify message came from a router */
188                 if ((*afp->af_portmatch)(from) == 0)
189                         return;
190                 (*afp->af_canon)(from);
191                 /* are we talking to ourselves? */
192                 if ((ifp = if_ifwithaddr(from)) != NULL) {
193                         rt = rtfind(from);
194                         if (rt == NULL || (rt->rt_state & RTS_INTERFACE) == 0) {
195                                 addrouteforif(ifp);
196                                 rtchanged = 1;
197                         } else
198                                 rt->rt_timer = 0;
199                         return;
200                 }
201                 /* Update timer for interface on which the packet arrived.
202                  * If from other end of a point-to-point link that isn't
203                  * in the routing tables, (re-)add the route.
204                  */
205                 if ((rt = rtfind(from)) && (rt->rt_state & RTS_INTERFACE)) {
206                         if(ftrace) fprintf(ftrace, "Got route\n");
207                         rt->rt_timer = 0;
208                 } else if ((ifp = if_ifwithdstaddr(from)) != NULL) {
209                         if(ftrace) fprintf(ftrace, "Got partner\n");
210                         addrouteforif(ifp);
211                         rtchanged = 1;
212                 }
213                 for (; size > 0; size -= sizeof (struct netinfo), n++) {
214                         struct sockaddr *sa;
215                         if (size < sizeof (struct netinfo))
216                                 break;
217                         if ((unsigned) ntohs(n->rip_metric) > HOPCNT_INFINITY)
218                                 continue;
219                         rt = rtfind(sa = ipx_nettosa(n->rip_dst));
220                         if (rt == NULL) {
221                                 if (ntohs(n->rip_metric) == HOPCNT_INFINITY)
222                                         continue;
223                                 rtadd(sa, from, ntohs(n->rip_metric),
224                                         ntohs(n->rip_ticks), 0);
225                                 rtchanged = 1;
226                                 continue;
227                         }
228
229                         /*
230                          * A clone is a different route to the same net
231                          * with exactly the same cost (ticks and metric).
232                          * They must all be recorded because those interfaces
233                          * must be handled in the same way as the first route
234                          * to that net. ie When using the split horizon
235                          * algorithm we must look at these interfaces also.
236                          *
237                          * Update if from gateway and different,
238                          * from anywhere and less ticks or
239                          * if same ticks and shorter,
240                          * or getting stale and equivalent.
241                          */
242                         if (!equal(from, &rt->rt_router) &&
243                             ntohs(n->rip_ticks) == rt->rt_ticks &&
244                             ntohs(n->rip_metric) == rt->rt_metric &&
245                             ntohs(n->rip_metric) != HOPCNT_INFINITY) {
246                                 struct rt_entry *trt = rt->rt_clone;
247
248                                 while (trt) {
249                                         if (equal(from, &trt->rt_router)) {
250                                                 trt->rt_timer = 0;
251                                                 break;
252                                         }
253                                         trt = trt->rt_clone;
254                                 }
255                                 if (trt == NULL) {
256                                         rtadd_clone(rt, sa, from, 
257                                                     ntohs(n->rip_metric),
258                                                     ntohs(n->rip_ticks), 0);
259                                 }
260                                 continue;
261                         }
262                         if ((equal(from, &rt->rt_router) &&
263                             ((ntohs(n->rip_ticks) != rt->rt_ticks) ||
264                             (ntohs(n->rip_metric) != rt->rt_metric))) ||
265                             (ntohs(n->rip_ticks) < rt->rt_ticks) ||
266                             ((ntohs(n->rip_ticks) == rt->rt_ticks) &&
267                             (ntohs(n->rip_metric) < rt->rt_metric)) ||
268                             (rt->rt_timer > (EXPIRE_TIME*2/3) &&
269                             rt->rt_metric == ntohs(n->rip_metric) &&
270                             ntohs(n->rip_metric) != HOPCNT_INFINITY)) {
271                                 rtchange(rt, from, ntohs(n->rip_metric),
272                                         ntohs(n->rip_ticks));
273                                 if (ntohs(n->rip_metric) == HOPCNT_INFINITY)
274                                         rt->rt_timer = EXPIRE_TIME;
275                                 else
276                                         rt->rt_timer = 0;
277                                 rtchanged = 1;
278                         } else if (equal(from, &rt->rt_router) &&
279                                    (ntohs(n->rip_ticks) == rt->rt_ticks) &&
280                                    (ntohs(n->rip_metric) == rt->rt_metric) &&
281                                    (ntohs(n->rip_metric) != HOPCNT_INFINITY)) {
282                                 rt->rt_timer = 0;
283                         }
284                 }
285                 if (rtchanged) {
286                         struct rthash *rh;
287                         struct rt_entry *rt;
288
289                         toall(supply, NULL, 1);
290                         for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
291                                 for (rt = rh->rt_forw;
292                                     rt != (struct rt_entry *)rh;
293                                     rt = rt->rt_forw)
294                                         rt->rt_state &= ~RTS_CHANGED;
295                 }
296
297                 return;
298         }
299 }