Index: head/usr.sbin/IPXrouted/sap_tables.c =================================================================== --- head/usr.sbin/IPXrouted/sap_tables.c (revision 27126) +++ head/usr.sbin/IPXrouted/sap_tables.c (revision 27127) @@ -1,326 +1,323 @@ /* * Copyright (c) 1995 John Hay. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by John Hay. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY John Hay AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL John Hay OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id$ + * $Id: sap_tables.c,v 1.3 1997/02/22 16:01:01 peter Exp $ */ #include "defs.h" #include #include -/* XXX I thought that this should work! #include */ -#include #define FIXLEN(s) { if ((s)->sa_len == 0) (s)->sa_len = sizeof (*(s));} sap_hash sap_head[SAPHASHSIZ]; void sapinit(void) { int i; for (i=0; i> 8); hsh = rol(hsh) + (ServType & 0xff); hsh = (hsh >> 7) ^ hsh; return hsh; } /* * Look for an exact match on ServType and ServName. It is * mostly used by the function that process SAP RESPONSE packets. * * A hash is created and used to index into the hash table. Then * that list is walk through searching for a match. * * If no match is found NULL is returned. */ struct sap_entry * sap_lookup(u_short ServType, char *ServName) { register struct sap_entry *sap; register struct sap_hash *sh; int hsh; hsh = saphash(ServType, ServName); sh = &sap_head[hsh & SAPHASHMASK]; for(sap = sh->forw; sap != (sap_entry *)sh; sap = sap->forw) { if ((hsh == sap->hash) && (ServType == sap->sap.ServType) && (strncmp(ServName, sap->sap.ServName, SERVNAMELEN) == 0)) { return sap; } } return NULL; } /* * This returns the nearest service of the specified type. If no * suitable service is found or if that service is on the interface * where the request came from, NULL is returned. * * When checking interfaces clones must be considered also. * * XXX TODO: * Maybe we can use RIP tables to get the fastest service (ticks). */ struct sap_entry * sap_nearestserver(ushort ServType, struct interface *ifp) { register struct sap_entry *sap; register struct sap_entry *csap; struct sap_hash *sh; register struct sap_entry *best = NULL; register int besthops = HOPCNT_INFINITY; sh = sap_head; for (; sh < &sap_head[SAPHASHSIZ]; sh++) for(sap = sh->forw; sap != (sap_entry *)sh; sap = sap->forw) { if (ServType != sap->sap.ServType) continue; if (ifp == sap->ifp) continue; csap = sap->clone; while (csap) { if (ifp == csap->ifp) /* * I would have loved to use * something else here. */ goto next; csap = csap->clone; } if (ntohs(sap->sap.hops) < besthops) { best = sap; besthops = ntohs(best->sap.hops); } next:; } return best; } /* * Add a entry to the SAP table. * * If the malloc fail, the entry will silently be thrown away. */ void sap_add(struct sap_info *si, struct sockaddr *from) { register struct sap_entry *nsap; register struct sap_hash *sh; FIXLEN(from); nsap = malloc(sizeof(struct sap_entry)); if (nsap == NULL) return; nsap->sap = *si; nsap->source = *from; nsap->clone = NULL; nsap->ifp = if_ifwithnet(from); nsap->state = RTS_CHANGED; nsap->timer = 0; nsap->hash = saphash(si->ServType, si->ServName); sh = &sap_head[nsap->hash & SAPHASHMASK]; insque(nsap, sh); } /* * Change an existing SAP entry. If a clone exist for the old one, * check if it is cheaper. If it is change tothe clone, otherwise * delete all the clones. */ void sap_change(struct sap_entry *sap, struct sap_info *si, struct sockaddr *from) { struct sap_entry *osap = NULL; FIXLEN(from); /* * If the hopcount (metric) is HOPCNT_INFINITY (16) it means that * a service has gone down. We should keep it like that for 30 * seconds, so that it will get broadcast and then change to a * clone if one exist. */ if (sap->clone && (ntohs(si->hops) != HOPCNT_INFINITY)) { /* * There are three possibilities: * 1. The new path is cheaper than the old one. * Free all the clones. * * 2. The new path is the same cost as the old ones. * If it is on the list of clones remove it * from the clone list and free it. * * 3. The new path is more expensive than the old one. * Use the values of the first clone and take it * out of the list, to be freed at the end. */ osap = sap->clone; if (ntohs(osap->sap.hops) > ntohs(si->hops)) { struct sap_entry *nsap; while (osap) { nsap = osap->clone; free(osap); osap = nsap; } sap->clone = NULL; } else if (ntohs(osap->sap.hops) == ntohs(si->hops)) { struct sap_entry *psap; psap = sap; while (osap) { if (equal(&osap->source, from)) { psap->clone = osap->clone; free(osap); osap = psap->clone; } else { psap = osap; osap = osap->clone; } } } else { from = &osap->source; si = &osap->sap; sap->clone = osap->clone; } } sap->sap = *si; sap->source = *from; sap->ifp = if_ifwithnet(from); sap->state = RTS_CHANGED; if (ntohs(si->hops) == HOPCNT_INFINITY) sap->timer = EXPIRE_TIME; else sap->timer = 0; if (osap) free(osap); } /* * Add a clone to the specified SAP entry. A clone is a different * route to the same service. We must know about them when we use * the split horizon algorithm. * * If the malloc fail, the entry will silently be thrown away. */ void sap_add_clone(struct sap_entry *sap, struct sap_info *clone, struct sockaddr *from) { register struct sap_entry *nsap; register struct sap_entry *csap; FIXLEN(from); nsap = malloc(sizeof(struct sap_entry)); if (nsap == NULL) return; if (ftrace) fprintf(ftrace, "CLONE ADD %04.4X %s.\n", ntohs(clone->ServType), clone->ServName); nsap->sap = *clone; nsap->source = *from; nsap->clone = NULL; nsap->ifp = if_ifwithnet(from); nsap->state = RTS_CHANGED; nsap->timer = 0; nsap->hash = saphash(clone->ServType, clone->ServName); csap = sap; while (csap->clone) csap = csap->clone; csap->clone = nsap; } /* * Remove a SAP entry from the table and free the memory * used by it. * * If the service have clone, do a sap_change to it and free * the clone. */ void sap_delete(struct sap_entry *sap) { if (sap->clone) { sap_change(sap, &sap->clone->sap, &sap->clone->source); return; } remque(sap); free(sap); } - Index: head/usr.sbin/IPXrouted/tables.c =================================================================== --- head/usr.sbin/IPXrouted/tables.c (revision 27126) +++ head/usr.sbin/IPXrouted/tables.c (revision 27127) @@ -1,470 +1,467 @@ /* * Copyright (c) 1985, 1993 * The Regents of the University of California. All rights reserved. * * Copyright (c) 1995 John Hay. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id$ + * $Id: tables.c,v 1.4 1997/02/22 16:01:03 peter Exp $ */ #ifndef lint static char sccsid[] = "@(#)tables.c 8.1 (Berkeley) 6/5/93"; #endif /* not lint */ /* * Routing Table Management Daemon */ #include "defs.h" #include #include #include #include -/* XXX I thought that this should work! #include */ -#include #ifndef DEBUG #define DEBUG 0 #endif #define FIXLEN(s) { if ((s)->sa_len == 0) (s)->sa_len = sizeof (*(s));} int install = !DEBUG; /* if 1 call kernel */ int delete = 1; struct rthash nethash[ROUTEHASHSIZ]; struct rthash hosthash[ROUTEHASHSIZ]; /* * Lookup dst in the tables for an exact match. */ struct rt_entry * rtlookup(dst) struct sockaddr *dst; { register struct rt_entry *rt; register struct rthash *rh; register u_int hash; struct afhash h; int doinghost = 1; if (dst->sa_family >= AF_MAX) return (0); (*afswitch[dst->sa_family].af_hash)(dst, &h); hash = h.afh_hosthash; rh = &hosthash[hash & ROUTEHASHMASK]; again: for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { if (rt->rt_hash != hash) continue; if (equal(&rt->rt_dst, dst)) return (rt); } if (doinghost) { doinghost = 0; hash = h.afh_nethash; rh = &nethash[hash & ROUTEHASHMASK]; goto again; } return (0); } /* * Find a route to dst as the kernel would. */ struct rt_entry * rtfind(dst) struct sockaddr *dst; { register struct rt_entry *rt; register struct rthash *rh; register u_int hash; struct afhash h; int af = dst->sa_family; int doinghost = 1, (*match)() = 0; if (af >= AF_MAX) return (0); (*afswitch[af].af_hash)(dst, &h); hash = h.afh_hosthash; rh = &hosthash[hash & ROUTEHASHMASK]; again: for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { if (rt->rt_hash != hash) continue; if (doinghost) { if (equal(&rt->rt_dst, dst)) return (rt); } else { if (rt->rt_dst.sa_family == af && (match != 0) && (*match)(&rt->rt_dst, dst)) return (rt); } } if (doinghost) { doinghost = 0; hash = h.afh_nethash; rh = &nethash[hash & ROUTEHASHMASK]; match = afswitch[af].af_netmatch; goto again; } return (0); } void rtadd(dst, gate, metric, ticks, state) struct sockaddr *dst, *gate; short metric, ticks; int state; { struct afhash h; register struct rt_entry *rt; struct rthash *rh; int af = dst->sa_family, flags; u_int hash; FIXLEN(dst); FIXLEN(gate); if (af >= AF_MAX) return; (*afswitch[af].af_hash)(dst, &h); flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0; if (flags & RTF_HOST) { hash = h.afh_hosthash; rh = &hosthash[hash & ROUTEHASHMASK]; } else { hash = h.afh_nethash; rh = &nethash[hash & ROUTEHASHMASK]; } rt = (struct rt_entry *)malloc(sizeof (*rt)); if (rt == 0) return; rt->rt_hash = hash; rt->rt_dst = *dst; rt->rt_router = *gate; rt->rt_metric = metric; rt->rt_ticks = ticks; rt->rt_timer = 0; rt->rt_flags = RTF_UP | flags; rt->rt_state = state | RTS_CHANGED; rt->rt_ifp = if_ifwithnet(&rt->rt_router); rt->rt_clone = NULL; if (metric) rt->rt_flags |= RTF_GATEWAY; insque(rt, rh); TRACE_ACTION(ADD, rt); /* * If the ioctl fails because the gateway is unreachable * from this host, discard the entry. This should only * occur because of an incorrect entry in /etc/gateways. */ if (install && rtioctl(ADD, &rt->rt_rt) < 0) { if (errno != EEXIST) perror("SIOCADDRT"); if (errno == ENETUNREACH) { TRACE_ACTION(DELETE, rt); remque(rt); free((char *)rt); } } } void rtadd_clone(ort, dst, gate, metric, ticks, state) struct rt_entry *ort; struct sockaddr *dst, *gate; short metric, ticks; int state; { struct afhash h; register struct rt_entry *rt; struct rthash *rh; int af = dst->sa_family, flags; u_int hash; FIXLEN(dst); FIXLEN(gate); if (af >= AF_MAX) return; (*afswitch[af].af_hash)(dst, &h); flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0; if (flags & RTF_HOST) { hash = h.afh_hosthash; rh = &hosthash[hash & ROUTEHASHMASK]; } else { hash = h.afh_nethash; rh = &nethash[hash & ROUTEHASHMASK]; } rt = (struct rt_entry *)malloc(sizeof (*rt)); if (rt == 0) return; rt->rt_hash = hash; rt->rt_dst = *dst; rt->rt_router = *gate; rt->rt_metric = metric; rt->rt_ticks = ticks; rt->rt_timer = 0; rt->rt_flags = RTF_UP | flags; rt->rt_state = state | RTS_CHANGED; rt->rt_ifp = if_ifwithnet(&rt->rt_router); rt->rt_clone = NULL; rt->rt_forw = NULL; rt->rt_back = NULL; if (metric) rt->rt_flags |= RTF_GATEWAY; while(ort->rt_clone != NULL) ort = ort->rt_clone; ort->rt_clone = rt; TRACE_ACTION(ADD_CLONE, rt); } void rtchange(rt, gate, metric, ticks) struct rt_entry *rt; struct sockaddr *gate; short metric, ticks; { int doioctl = 0, metricchanged = 0; struct rtuentry oldroute; FIXLEN(gate); /* * Handling of clones. * When the route changed and it had clones, handle it special. * 1. If the new route is cheaper than the clone(s), free the clones. * 2. If the new route is the same cost, it may be one of the clones, * search for it and free it. * 3. If the new route is more expensive than the clone(s), use the * values of the clone(s). */ if (rt->rt_clone) { if ((ticks < rt->rt_clone->rt_ticks) || ((ticks == rt->rt_clone->rt_ticks) && (metric < rt->rt_clone->rt_metric))) { /* * Free all clones. */ struct rt_entry *trt, *nrt; trt = rt->rt_clone; rt->rt_clone = NULL; while(trt) { nrt = trt->rt_clone; free((char *)trt); trt = nrt; } } else if ((ticks == rt->rt_clone->rt_ticks) && (metric == rt->rt_clone->rt_metric)) { struct rt_entry *prt, *trt; prt = rt; trt = rt->rt_clone; while(trt) { if (equal(&trt->rt_router, gate)) { prt->rt_clone = trt->rt_clone; free(trt); trt = prt->rt_clone; } else { prt = trt; trt = trt->rt_clone; } } } else { /* * Use the values of the first clone. * Delete the corresponding clone. */ struct rt_entry *trt; trt = rt->rt_clone; rt->rt_clone = rt->rt_clone->rt_clone; metric = trt->rt_metric; ticks = trt->rt_ticks; *gate = trt->rt_router; free((char *)trt); } } if (!equal(&rt->rt_router, gate)) doioctl++; if ((metric != rt->rt_metric) || (ticks != rt->rt_ticks)) metricchanged++; if (doioctl || metricchanged) { TRACE_ACTION(CHANGE FROM, rt); if (doioctl) { oldroute = rt->rt_rt; rt->rt_router = *gate; } rt->rt_metric = metric; rt->rt_ticks = ticks; if ((rt->rt_state & RTS_INTERFACE) && metric) { rt->rt_state &= ~RTS_INTERFACE; if(rt->rt_ifp) syslog(LOG_ERR, "changing route from interface %s (timed out)", rt->rt_ifp->int_name); else syslog(LOG_ERR, "changing route from interface ??? (timed out)"); } if (metric) rt->rt_flags |= RTF_GATEWAY; else rt->rt_flags &= ~RTF_GATEWAY; rt->rt_state |= RTS_CHANGED; TRACE_ACTION(CHANGE TO, rt); } if (doioctl && install) { #ifndef RTM_ADD if (rtioctl(ADD, &rt->rt_rt) < 0) syslog(LOG_ERR, "rtioctl ADD dst %s, gw %s: %m", xns_ntoa(&((struct sockaddr_ns *)&rt->rt_dst)->sns_addr), xns_ntoa(&((struct sockaddr_ns *)&rt->rt_router)->sns_addr)); if (delete && rtioctl(DELETE, &oldroute) < 0) perror("rtioctl DELETE"); #else if (delete == 0) { if (rtioctl(ADD, &rt->rt_rt) >= 0) return; } else { if (rtioctl(CHANGE, &rt->rt_rt) >= 0) return; } syslog(LOG_ERR, "rtioctl ADD dst %s, gw %s: %m", ipxdp_ntoa(&((struct sockaddr_ipx *)&rt->rt_dst)->sipx_addr), ipxdp_ntoa(&((struct sockaddr_ipx *)&rt->rt_router)->sipx_addr)); #endif } } void rtdelete(rt) struct rt_entry *rt; { struct sockaddr *sa = &(rt->rt_router); FIXLEN(sa); sa = &(rt->rt_dst); FIXLEN(sa); if (rt->rt_clone) { /* * If there is a clone we just do a rt_change to it. */ struct rt_entry *trt = rt->rt_clone; rtchange(rt, &trt->rt_router, trt->rt_metric, trt->rt_ticks); return; } if (rt->rt_state & RTS_INTERFACE) { if (rt->rt_ifp) syslog(LOG_ERR, "deleting route to interface %s (timed out)", rt->rt_ifp->int_name); else syslog(LOG_ERR, "deleting route to interface ??? (timed out)"); } TRACE_ACTION(DELETE, rt); if (install && rtioctl(DELETE, &rt->rt_rt) < 0) perror("rtioctl DELETE"); remque(rt); free((char *)rt); } void rtinit(void) { register struct rthash *rh; for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++) rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++) rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; } int seqno; int rtioctl(action, ort) int action; struct rtuentry *ort; { #ifndef RTM_ADD if (install == 0) return (errno = 0); ort->rtu_rtflags = ort->rtu_flags; switch (action) { case ADD: return (ioctl(s, SIOCADDRT, (char *)ort)); case DELETE: return (ioctl(s, SIOCDELRT, (char *)ort)); default: return (-1); } #else /* RTM_ADD */ struct { struct rt_msghdr w_rtm; struct sockaddr w_dst; struct sockaddr w_gate; struct sockaddr_ipx w_netmask; } w; #define rtm w.w_rtm bzero((char *)&w, sizeof(w)); rtm.rtm_msglen = sizeof(w); rtm.rtm_version = RTM_VERSION; rtm.rtm_type = (action == ADD ? RTM_ADD : (action == DELETE ? RTM_DELETE : RTM_CHANGE)); rtm.rtm_flags = ort->rtu_flags; rtm.rtm_seq = ++seqno; rtm.rtm_addrs = RTA_DST|RTA_GATEWAY; bcopy((char *)&ort->rtu_dst, (char *)&w.w_dst, sizeof(w.w_dst)); bcopy((char *)&ort->rtu_router, (char *)&w.w_gate, sizeof(w.w_gate)); w.w_gate.sa_family = w.w_dst.sa_family = AF_IPX; w.w_gate.sa_len = w.w_dst.sa_len = sizeof(w.w_dst); if (rtm.rtm_flags & RTF_HOST) { rtm.rtm_msglen -= sizeof(w.w_netmask); } else { rtm.rtm_addrs |= RTA_NETMASK; w.w_netmask = ipx_netmask; rtm.rtm_msglen -= sizeof(w.w_netmask) - ipx_netmask.sipx_len; } errno = 0; return write(r, (char *)&w, rtm.rtm_msglen); #endif /* RTM_ADD */ } -