]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.sbin/IPXrouted/input.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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$
39  */
40
41 #ifndef lint
42 static const char sccsid[] = "@(#)input.c       8.1 (Berkeley) 6/5/93";
43 #endif /* not lint */
44
45 /*
46  * IPX Routing Table Management Daemon
47  */
48 #include "defs.h"
49
50 struct sockaddr *
51 ipx_nettosa(net)
52 union ipx_net net;
53 {
54         static struct sockaddr_ipx sxn;
55         
56         bzero(&sxn, sizeof (struct sockaddr_ipx));
57         sxn.sipx_family = AF_IPX;
58         sxn.sipx_len = sizeof (sxn);
59         sxn.sipx_addr.x_net = net;
60         return( (struct sockaddr *)&sxn);
61         
62 }
63
64 /*
65  * Process a newly received packet.
66  */
67 void
68 rip_input(from, size)
69         struct sockaddr *from;
70         int size;
71 {
72         int newsize;
73         int rtchanged = 0;
74         struct rt_entry *rt;
75         struct netinfo *n;
76         struct interface *ifp = 0;
77         struct afswitch *afp;
78         struct sockaddr_ipx *ipxp;
79
80         ifp = if_ifwithnet(from);
81         ipxp = (struct sockaddr_ipx *)from;
82         if (ifp == 0) {
83                 if(ftrace) {
84                         fprintf(ftrace, "Received bogus packet from %s\n",
85                                 ipxdp_ntoa(&ipxp->sipx_addr));
86                 }
87                 return;
88         }
89
90         TRACE_INPUT(ifp, from, size);
91         if (from->sa_family >= AF_MAX)
92                 return;
93         afp = &afswitch[from->sa_family];
94         
95         size -= sizeof (u_short)        /* command */;
96         n = msg->rip_nets;
97
98         switch (ntohs(msg->rip_cmd)) {
99
100         case RIPCMD_REQUEST:
101                 if (ipx_hosteq(satoipx_addr(ifp->int_addr), ipxp->sipx_addr))
102                         return;
103                 newsize = 0;
104                 while (size > 0) {
105                         if (size < sizeof (struct netinfo))
106                                 break;
107                         size -= sizeof (struct netinfo);
108
109                         /* 
110                          * A single entry with rip_dst == DSTNETS_ALL and
111                          * metric ``infinity'' means ``all routes''.
112                          *
113                          * XXX According to the IPX RIP spec the metric
114                          * and tick fields can be anything. So maybe we
115                          * should not check the metric???
116                          */
117                         if (ipx_neteqnn(n->rip_dst, ipx_anynet) &&
118                             ntohs(n->rip_metric) == HOPCNT_INFINITY &&
119                             size == 0) {
120                                 supply(from, 0, ifp, 0);
121                                 return;
122                         }
123                         /*
124                          * request for specific nets
125                          */
126                         rt = rtlookup(ipx_nettosa(n->rip_dst));
127                         if (ftrace) {
128                                 fprintf(ftrace,
129                                         "specific request for %s",
130                                         ipxdp_nettoa(n->rip_dst));
131                                 fprintf(ftrace,
132                                         " yields route %lx\n",
133                                         (u_long)rt);
134                         }
135                         /*
136                          * XXX We break out on the first net that isn't
137                          * found. The specs is a bit vague here. I'm not
138                          * sure what we should do.
139                          */
140                         if (rt == 0)
141                                 return;
142                         /* XXX
143                          * According to the spec we should not include
144                          * information about networks for which the number
145                          * of hops is 16.
146                          */
147                         if (rt->rt_metric == (HOPCNT_INFINITY-1))
148                                 return;
149                         n->rip_metric = htons( rt == 0 ? HOPCNT_INFINITY :
150                                 min(rt->rt_metric+1, HOPCNT_INFINITY));
151                         n->rip_ticks = htons(rt->rt_ticks+1);
152
153                         /*
154                          * We use split horizon with a twist. If the requested
155                          * net is the directly connected net we supply an
156                          * answer. This is so that the host can learn about
157                          * the routers on its net.
158                          */
159                         {
160                                 register struct rt_entry *trt = rt;
161
162                                 while (trt) {
163                                         if ((trt->rt_ifp == ifp) && 
164                                             !ipx_neteqnn(n->rip_dst, 
165                                                 satoipx_addr(ifp->int_addr).x_net))
166                                                 return;
167                                         trt = trt->rt_clone;
168                                 }
169                                 n++;
170                                 newsize += sizeof (struct netinfo);
171                         }
172                 }
173                 if (newsize > 0) {
174                         msg->rip_cmd = htons(RIPCMD_RESPONSE);
175                         newsize += sizeof (u_short);
176                         /* should check for if with dstaddr(from) first */
177                         (*afp->af_output)(ripsock, 0, from, newsize);
178                         TRACE_OUTPUT(ifp, from, newsize);
179                         if (ftrace) {
180                                 /* XXX This should not happen anymore. */
181                                 if(ifp == 0)
182                                         fprintf(ftrace, "--- ifp = 0\n");
183                                 else
184                                         fprintf(ftrace,
185                                                 "request arrived on interface %s\n",
186                                                 ifp->int_name);
187                         }
188                 }
189                 return;
190
191         case RIPCMD_RESPONSE:
192                 /* verify message came from a router */
193                 if ((*afp->af_portmatch)(from) == 0)
194                         return;
195                 (*afp->af_canon)(from);
196                 /* are we talking to ourselves? */
197                 if ((ifp = if_ifwithaddr(from)) != 0) {
198                         rt = rtfind(from);
199                         if (rt == 0 || (rt->rt_state & RTS_INTERFACE) == 0) {
200                                 addrouteforif(ifp);
201                                 rtchanged = 1;
202                         } else
203                                 rt->rt_timer = 0;
204                         return;
205                 }
206                 /* Update timer for interface on which the packet arrived.
207                  * If from other end of a point-to-point link that isn't
208                  * in the routing tables, (re-)add the route.
209                  */
210                 if ((rt = rtfind(from)) && (rt->rt_state & RTS_INTERFACE)) {
211                         if(ftrace) fprintf(ftrace, "Got route\n");
212                         rt->rt_timer = 0;
213                 } else if ((ifp = if_ifwithdstaddr(from)) != 0) {
214                         if(ftrace) fprintf(ftrace, "Got partner\n");
215                         addrouteforif(ifp);
216                         rtchanged = 1;
217                 }
218                 for (; size > 0; size -= sizeof (struct netinfo), n++) {
219                         struct sockaddr *sa;
220                         if (size < sizeof (struct netinfo))
221                                 break;
222                         if ((unsigned) ntohs(n->rip_metric) > HOPCNT_INFINITY)
223                                 continue;
224                         rt = rtfind(sa = ipx_nettosa(n->rip_dst));
225                         if (rt == 0) {
226                                 if (ntohs(n->rip_metric) == HOPCNT_INFINITY)
227                                         continue;
228                                 rtadd(sa, from, ntohs(n->rip_metric),
229                                         ntohs(n->rip_ticks), 0);
230                                 rtchanged = 1;
231                                 continue;
232                         }
233
234                         /*
235                          * A clone is a different route to the same net
236                          * with exactly the same cost (ticks and metric).
237                          * They must all be recorded because those interfaces
238                          * must be handled in the same way as the first route
239                          * to that net. ie When using the split horizon
240                          * algorithm we must look at these interfaces also.
241                          *
242                          * Update if from gateway and different,
243                          * from anywhere and less ticks or
244                          * if same ticks and shorter,
245                          * or getting stale and equivalent.
246                          */
247                         if (!equal(from, &rt->rt_router) &&
248                             ntohs(n->rip_ticks) == rt->rt_ticks &&
249                             ntohs(n->rip_metric) == rt->rt_metric &&
250                             ntohs(n->rip_metric) != HOPCNT_INFINITY) {
251                                 register struct rt_entry *trt = rt->rt_clone;
252
253                                 while (trt) {
254                                         if (equal(from, &trt->rt_router)) {
255                                                 trt->rt_timer = 0;
256                                                 break;
257                                         }
258                                         trt = trt->rt_clone;
259                                 }
260                                 if (trt == NULL) {
261                                         rtadd_clone(rt, sa, from, 
262                                                     ntohs(n->rip_metric),
263                                                     ntohs(n->rip_ticks), 0);
264                                 }
265                                 continue;
266                         }
267                         if ((equal(from, &rt->rt_router) &&
268                             ((ntohs(n->rip_ticks) != rt->rt_ticks) ||
269                             (ntohs(n->rip_metric) != rt->rt_metric))) ||
270                             (ntohs(n->rip_ticks) < rt->rt_ticks) ||
271                             ((ntohs(n->rip_ticks) == rt->rt_ticks) &&
272                             (ntohs(n->rip_metric) < rt->rt_metric)) ||
273                             (rt->rt_timer > (EXPIRE_TIME*2/3) &&
274                             rt->rt_metric == ntohs(n->rip_metric) &&
275                             ntohs(n->rip_metric) != HOPCNT_INFINITY)) {
276                                 rtchange(rt, from, ntohs(n->rip_metric),
277                                         ntohs(n->rip_ticks));
278                                 if (ntohs(n->rip_metric) == HOPCNT_INFINITY)
279                                         rt->rt_timer = EXPIRE_TIME;
280                                 else
281                                         rt->rt_timer = 0;
282                                 rtchanged = 1;
283                         } else if (equal(from, &rt->rt_router) &&
284                                    (ntohs(n->rip_ticks) == rt->rt_ticks) &&
285                                    (ntohs(n->rip_metric) == rt->rt_metric) &&
286                                    (ntohs(n->rip_metric) != HOPCNT_INFINITY)) {
287                                 rt->rt_timer = 0;
288                         }
289                 }
290                 if (rtchanged) {
291                         register struct rthash *rh;
292                         register struct rt_entry *rt;
293
294                         toall(supply, NULL, 1);
295                         for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
296                                 for (rt = rh->rt_forw;
297                                     rt != (struct rt_entry *)rh;
298                                     rt = rt->rt_forw)
299                                         rt->rt_state &= ~RTS_CHANGED;
300                 }
301
302                 return;
303         }
304 }