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