2 * Copyright (c) 1995 John Hay. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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
31 * $FreeBSD: src/usr.sbin/IPXrouted/sap_tables.c,v 1.7 1999/08/28 01:15:04 peter Exp $
32 * $DragonFly: src/usr.sbin/IPXrouted/sap_tables.c,v 1.3 2004/03/11 09:38:59 hmp Exp $
40 #define FIXLEN(s) { if ((s)->sa_len == 0) (s)->sa_len = sizeof (*(s));}
42 sap_hash sap_head
[SAPHASHSIZ
];
49 for (i
=0; i
<SAPHASHSIZ
; i
++)
50 sap_head
[i
].forw
= sap_head
[i
].back
=
51 (struct sap_entry
*)&sap_head
[i
];
55 * This hash use the first 14 letters of the ServName and the ServType
56 * to create a 32 bit hash value.
59 saphash(u_short ServType
, char *ServName
)
62 char name
[SERVNAMELEN
];
64 bzero(name
, SERVNAMELEN
);
65 strncpy(name
, ServName
, SERVNAMELEN
);
72 hsh
= hsh
* SMVAL
+ (ServType
& 0xff);
73 hsh
= hsh
* SMVAL
+ (ServType
>> 8);
76 hsh
= hsh
* SMVAL
+ *ServName
++;
86 * Look for an exact match on ServType and ServName. It is
87 * mostly used by the function that process SAP RESPONSE packets.
89 * A hash is created and used to index into the hash table. Then
90 * that list is walk through searching for a match.
92 * If no match is found NULL is returned.
95 sap_lookup(u_short ServType
, char *ServName
)
97 struct sap_entry
*sap
;
101 hsh
= saphash(ServType
, ServName
);
102 sh
= &sap_head
[hsh
& SAPHASHMASK
];
104 for(sap
= sh
->forw
; sap
!= (sap_entry
*)sh
; sap
= sap
->forw
) {
105 if ((hsh
== sap
->hash
) &&
106 (ServType
== sap
->sap
.ServType
) &&
107 (strncmp(ServName
, sap
->sap
.ServName
, SERVNAMELEN
) == 0)) {
115 * This returns the nearest service of the specified type. If no
116 * suitable service is found or if that service is on the interface
117 * where the request came from, NULL is returned.
119 * When checking interfaces clones must be considered also.
122 * Maybe we can use RIP tables to get the fastest service (ticks).
125 sap_nearestserver(ushort ServType
, struct interface
*ifp
)
127 struct sap_entry
*sap
;
129 struct sap_entry
*best
= NULL
;
130 int besthops
= HOPCNT_INFINITY
;
134 for (; sh
< &sap_head
[SAPHASHSIZ
]; sh
++)
135 for(sap
= sh
->forw
; sap
!= (sap_entry
*)sh
; sap
= sap
->forw
) {
136 if (ServType
!= sap
->sap
.ServType
)
139 if (ntohs(sap
->sap
.hops
) < besthops
) {
141 besthops
= ntohs(best
->sap
.hops
);
148 * Add a entry to the SAP table.
150 * If the malloc fail, the entry will silently be thrown away.
153 sap_add(struct sap_info
*si
, struct sockaddr
*from
)
155 struct sap_entry
*nsap
;
158 if (ntohs(si
->hops
) == HOPCNT_INFINITY
)
162 nsap
= malloc(sizeof(struct sap_entry
));
167 nsap
->source
= *from
;
169 nsap
->ifp
= if_ifwithnet(from
);
170 nsap
->state
= RTS_CHANGED
;
172 nsap
->hash
= saphash(si
->ServType
, si
->ServName
);
174 sh
= &sap_head
[nsap
->hash
& SAPHASHMASK
];
177 TRACE_SAP_ACTION("ADD", nsap
);
181 * Change an existing SAP entry. If a clone exist for the old one,
182 * check if it is cheaper. If it is change tothe clone, otherwise
183 * delete all the clones.
186 sap_change(struct sap_entry
*sap
,
188 struct sockaddr
*from
)
190 struct sap_entry
*osap
= NULL
;
193 TRACE_SAP_ACTION("CHANGE FROM", sap
);
195 * If the hopcount (metric) is HOPCNT_INFINITY (16) it means that
196 * a service has gone down. We should keep it like that for 30
197 * seconds, so that it will get broadcast and then change to a
198 * clone if one exist.
200 if (sap
->clone
&& (ntohs(si
->hops
) != HOPCNT_INFINITY
)) {
202 * There are three possibilities:
203 * 1. The new path is cheaper than the old one.
204 * Free all the clones.
206 * 2. The new path is the same cost as the old ones.
207 * If it is on the list of clones remove it
208 * from the clone list and free it.
210 * 3. The new path is more expensive than the old one.
211 * Use the values of the first clone and take it
212 * out of the list, to be freed at the end.
215 if (ntohs(osap
->sap
.hops
) > ntohs(si
->hops
)) {
216 struct sap_entry
*nsap
;
220 TRACE_SAP_ACTION("DELETE", osap
);
225 } else if (ntohs(osap
->sap
.hops
) == ntohs(si
->hops
)) {
226 struct sap_entry
*psap
;
230 if (equal(&osap
->source
, from
)) {
231 psap
->clone
= osap
->clone
;
232 TRACE_SAP_ACTION("DELETE", osap
);
241 from
= &osap
->source
;
243 sap
->clone
= osap
->clone
;
248 sap
->ifp
= if_ifwithnet(from
);
249 sap
->state
= RTS_CHANGED
;
250 if (ntohs(si
->hops
) == HOPCNT_INFINITY
)
251 sap
->timer
= EXPIRE_TIME
;
256 TRACE_SAP_ACTION("DELETE", osap
);
259 TRACE_SAP_ACTION("CHANGE TO", sap
);
263 * Add a clone to the specified SAP entry. A clone is a different
264 * route to the same service. We must know about them when we use
265 * the split horizon algorithm.
267 * If the malloc fail, the entry will silently be thrown away.
270 sap_add_clone(struct sap_entry
*sap
,
271 struct sap_info
*clone
,
272 struct sockaddr
*from
)
274 struct sap_entry
*nsap
;
275 struct sap_entry
*csap
;
277 if (ntohs(clone
->hops
) == HOPCNT_INFINITY
)
281 nsap
= malloc(sizeof(struct sap_entry
));
286 fprintf(ftrace
, "CLONE ADD %4.4X %s.\n",
287 ntohs(clone
->ServType
),
291 nsap
->source
= *from
;
293 nsap
->ifp
= if_ifwithnet(from
);
294 nsap
->state
= RTS_CHANGED
;
296 nsap
->hash
= saphash(clone
->ServType
, clone
->ServName
);
302 TRACE_SAP_ACTION("ADD CLONE", nsap
);
306 * Remove a SAP entry from the table and free the memory
309 * If the service have clone, do a sap_change to it and free
313 sap_delete(struct sap_entry
*sap
)
316 sap_change(sap
, &sap
->clone
->sap
, &sap
->clone
->source
);
320 TRACE_SAP_ACTION("DELETE", sap
);