sap_input.c revision 27244
1/*
2 * Copyright (c) 1995 John Hay.  All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 * 3. All advertising materials mentioning features or use of this software
13 *    must display the following acknowledgement:
14 *	This product includes software developed by John Hay.
15 * 4. Neither the name of the author nor the names of any co-contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY John Hay AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL John Hay OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 *	$Id: sap_input.c,v 1.4 1997/02/22 16:00:59 peter Exp $
32 */
33
34/*
35 * IPX Routing Table Management Daemon
36 */
37#include "defs.h"
38
39
40/*
41 * Process a newly received packet.
42 */
43void
44sap_input(from, size)
45	struct sockaddr *from;
46	int size;
47{
48	int newsize;
49	int sapchanged = 0;
50	struct sap_entry *sap;
51	struct sap_info *n;
52	struct interface *ifp = 0;
53	struct afswitch *afp;
54	struct sockaddr_ipx *ipxp;
55
56	ifp = if_ifwithnet(from);
57	ipxp = (struct sockaddr_ipx *)from;
58	if (ifp == 0) {
59		if(ftrace) {
60			fprintf(ftrace, "Received bogus packet from %s\n",
61				ipxdp_ntoa(&ipxp->sipx_addr));
62		}
63		return;
64	}
65
66	if (ftrace)
67		dumpsappacket(ftrace, "received", from, (char *)sap_msg , size);
68
69	if (from->sa_family >= AF_MAX)
70		return;
71	afp = &afswitch[from->sa_family];
72
73	size -= sizeof (u_short)	/* command */;
74	n = sap_msg->sap;
75
76	switch (ntohs(sap_msg->sap_cmd)) {
77
78	case SAP_REQ_NEAR:
79		if (ftrace)
80			fprintf(ftrace, "Received a sap REQ_NEAR packet.\n");
81		sap = sap_nearestserver(n->ServType, ifp);
82		if (sap == NULL)
83			return;
84		sap_msg->sap_cmd = htons(SAP_RESP_NEAR);
85		*n = sap->sap;
86		n->hops = htons(ntohs(n->hops) + 1);
87		if (ntohs(n->hops) >= HOPCNT_INFINITY)
88			return;
89
90		newsize = sizeof(struct sap_info) + sizeof(struct sap_packet);
91		(*afp->af_output)(sapsock, 0, from, newsize);
92		if (ftrace) {
93			fprintf(ftrace, "sap_nearestserver %X %s returned:\n",
94				ntohs(n->ServType),
95				ifp->int_name);
96			fprintf(ftrace, "  service %04X %-20.20s "
97					"addr %s.%04X metric %d\n",
98					ntohs(sap->sap.ServType),
99					sap->sap.ServName,
100					ipxdp_ntoa(&sap->sap.ipx),
101					ntohs(sap->sap.ipx.x_port),
102					ntohs(sap->sap.hops));
103		}
104		return;
105
106	case SAP_REQ:
107		if (ftrace)
108			fprintf(ftrace, "Received a sap REQ packet.\n");
109
110		sap_supply(from, 0, ifp, n->ServType, 0);
111		return;
112
113	case SAP_RESP_NEAR:
114		/* XXX We do nothing here, for the moment.
115		 * Maybe we should check if the service is in our table?
116		 *
117		 */
118		if (ftrace)
119			fprintf(ftrace, "Received a sap RESP_NEAR packet.\n");
120
121		return;
122
123	case SAP_RESP:
124		if (ftrace)
125			fprintf(ftrace, "Received a sap RESP packet.\n");
126
127		(*afp->af_canon)(from);
128
129		for (; size > 0; size -= sizeof (struct sap_info), n++) {
130			if (size < sizeof (struct netinfo))
131				break;
132			/*
133			 * The idea here is that if the hop count is more
134			 * than INFINITY it is bogus and should be discarded.
135			 * If it is equal to INFINITY it is a message to say
136			 * that a service went down. If we don't allready
137			 * have it in our tables discard it. Otherwise
138			 * update our table and set the timer to EXPIRE_TIME
139			 * so that it is removed next time we go through the
140			 * tables.
141			 */
142			if (ntohs(n->hops) > HOPCNT_INFINITY)
143				continue;
144			sap = sap_lookup(n->ServType, n->ServName);
145			if (sap == 0) {
146				if (ntohs(n->hops) == HOPCNT_INFINITY)
147					continue;
148				sap_add(n, from);
149				sapchanged = 1;
150				continue;
151			}
152
153			/*
154			 * A clone is a different route to the same service
155			 * with exactly the same cost (metric).
156			 * They must all be recorded because those interfaces
157			 * must be handled in the same way as the first route
158			 * to that service. ie When using the split horizon
159			 * algorithm we must look at these interfaces also.
160			 *
161			 * Update if from gateway and different,
162			 * from anywhere and less hops or
163			 * getting stale and equivalent.
164			 */
165			if (((ifp != sap->ifp) ||
166			     !equal(&sap->source, from)) &&
167			    (n->hops == sap->sap.hops) &&
168			    (ntohs(n->hops) != HOPCNT_INFINITY)) {
169				register struct sap_entry *tsap = sap->clone;
170
171				while (tsap) {
172					if ((ifp == tsap->ifp) &&
173					    equal(&tsap->source, from)) {
174						tsap->timer = 0;
175						break;
176					}
177					tsap = tsap->clone;
178				}
179				if (tsap == NULL) {
180					sap_add_clone(sap, n, from);
181				}
182				continue;
183			}
184			if ((ifp == sap->ifp) &&
185			    equal(&sap->source, from) &&
186			    (ntohs(n->hops) == ntohs(sap->sap.hops)))
187				sap->timer = 0;
188			else if (((ifp == sap->ifp) &&
189				  equal(&sap->source, from) &&
190				  (n->hops != sap->sap.hops)) ||
191				 (ntohs(n->hops) < ntohs(sap->sap.hops)) ||
192				 (sap->timer > (EXPIRE_TIME*2/3) &&
193				  ntohs(sap->sap.hops) == ntohs(n->hops) &&
194				  ntohs(n->hops) != HOPCNT_INFINITY)) {
195				sap_change(sap, n, from);
196				sapchanged = 1;
197			}
198		}
199		if (sapchanged) {
200			register struct sap_entry *sap;
201			register struct sap_hash *sh;
202			sap_supply_toall(1);
203
204			for (sh = sap_head; sh < &sap_head[SAPHASHSIZ]; sh++)
205				for (sap = sh->forw;
206				    sap != (struct sap_entry *)sh;
207				    sap = sap->forw)
208					sap->state &= ~RTS_CHANGED;
209		}
210		return;
211	}
212}
213