149268Sbostic /*- 2*63222Sbostic * Copyright (c) 1991, 1993 3*63222Sbostic * The Regents of the University of California. All rights reserved. 449268Sbostic * 549268Sbostic * %sccs.include.redist.c% 649268Sbostic * 7*63222Sbostic * @(#)iso_snpac.c 8.1 (Berkeley) 06/10/93 849268Sbostic */ 949268Sbostic 1036392Ssklower /*********************************************************** 1136392Ssklower Copyright IBM Corporation 1987 1236392Ssklower 1336392Ssklower All Rights Reserved 1436392Ssklower 1536392Ssklower Permission to use, copy, modify, and distribute this software and its 1636392Ssklower documentation for any purpose and without fee is hereby granted, 1736392Ssklower provided that the above copyright notice appear in all copies and that 1836392Ssklower both that copyright notice and this permission notice appear in 1936392Ssklower supporting documentation, and that the name of IBM not be 2036392Ssklower used in advertising or publicity pertaining to distribution of the 2136392Ssklower software without specific, written prior permission. 2236392Ssklower 2336392Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 2436392Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 2536392Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 2636392Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 2736392Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 2836392Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 2936392Ssklower SOFTWARE. 3036392Ssklower 3136392Ssklower ******************************************************************/ 3236392Ssklower 3336392Ssklower /* 3436392Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 3536392Ssklower */ 3636392Ssklower /* $Header: iso_snpac.c,v 1.8 88/09/19 13:51:36 hagens Exp $ */ 3736392Ssklower /* $Source: /usr/argo/sys/netiso/RCS/iso_snpac.c,v $ */ 3836392Ssklower 3936392Ssklower #ifdef ISO 4036392Ssklower 4156533Sbostic #include <sys/param.h> 4256533Sbostic #include <sys/systm.h> 4356533Sbostic #include <sys/mbuf.h> 4456533Sbostic #include <sys/domain.h> 4556533Sbostic #include <sys/protosw.h> 4656533Sbostic #include <sys/socket.h> 4756533Sbostic #include <sys/socketvar.h> 4856533Sbostic #include <sys/errno.h> 4956533Sbostic #include <sys/ioctl.h> 5056533Sbostic #include <sys/syslog.h> 5136392Ssklower 5256533Sbostic #include <net/if.h> 5356533Sbostic #include <net/if_dl.h> 5456533Sbostic #include <net/route.h> 5536392Ssklower 5656533Sbostic #include <netiso/iso.h> 5756533Sbostic #include <netiso/iso_var.h> 5856533Sbostic #include <netiso/iso_snpac.h> 5956533Sbostic #include <netiso/clnp.h> 6056533Sbostic #include <netiso/clnp_stat.h> 6156533Sbostic #include <netiso/esis.h> 6256533Sbostic #include <netiso/argo_debug.h> 6336392Ssklower 6436392Ssklower int iso_systype = SNPA_ES; /* default to be an ES */ 6543423Ssklower extern short esis_holding_time, esis_config_time, esis_esconfig_time; 6650230Ssklower extern struct timeval time; 6758990Ssklower extern void esis_config(); 6858990Ssklower extern int hz; 6950230Ssklower static void snpac_fixdstandmask(); 7036392Ssklower 7137469Ssklower struct sockaddr_iso blank_siso = {sizeof(blank_siso), AF_ISO}; 7237469Ssklower extern u_long iso_hashchar(); 7337469Ssklower static struct sockaddr_iso 7437469Ssklower dst = {sizeof(dst), AF_ISO}, 7537469Ssklower gte = {sizeof(dst), AF_ISO}, 7637469Ssklower src = {sizeof(dst), AF_ISO}, 7737469Ssklower msk = {sizeof(dst), AF_ISO}, 7853691Ssklower zmk = {0}; 7937469Ssklower #define zsi blank_siso 8037469Ssklower #define zero_isoa zsi.siso_addr 8150230Ssklower #define zap_isoaddr(a, b) {Bzero(&a.siso_addr, sizeof(*r)); r = b; \ 8250230Ssklower Bcopy(r, &a.siso_addr, 1 + (r)->isoa_len);} 8337469Ssklower #define S(x) ((struct sockaddr *)&(x)) 8437469Ssklower 8543071Ssklower static struct sockaddr_dl blank_dl = {sizeof(blank_dl), AF_LINK}; 8643071Ssklower static struct sockaddr_dl gte_dl; 8743071Ssklower #define zap_linkaddr(a, b, c, i) \ 8843071Ssklower (*a = blank_dl, bcopy(b, a->sdl_data, a->sdl_alen = c), a->sdl_index = i) 8936392Ssklower 9036392Ssklower /* 9136392Ssklower * We only keep track of a single IS at a time. 9236392Ssklower */ 9343071Ssklower struct rtentry *known_is; 9436392Ssklower 9536392Ssklower /* 9636392Ssklower * Addresses taken from NBS agreements, December 1987. 9736392Ssklower * 9836392Ssklower * These addresses assume on-the-wire transmission of least significant 9936392Ssklower * bit first. This is the method used by 802.3. When these 10036392Ssklower * addresses are passed to the token ring driver, (802.5), they 10136392Ssklower * must be bit-swaped because 802.5 transmission order is MSb first. 10236392Ssklower * 10336392Ssklower * Furthermore, according to IBM Austin, these addresses are not 10436392Ssklower * true token ring multicast addresses. More work is necessary 10536392Ssklower * to get multicast to work right on token ring. 10636392Ssklower * 10736392Ssklower * Currently, the token ring driver does not handle multicast, so 10836392Ssklower * these addresses are converted into the broadcast address in 10936392Ssklower * lan_output() That means that if these multicast addresses change 11036392Ssklower * the token ring driver must be altered. 11136392Ssklower */ 11243334Ssklower char all_es_snpa[] = { 0x09, 0x00, 0x2b, 0x00, 0x00, 0x04 }; 11343334Ssklower char all_is_snpa[] = { 0x09, 0x00, 0x2b, 0x00, 0x00, 0x05 }; 11445898Ssklower char all_l1is_snpa[] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x14}; 11545898Ssklower char all_l2is_snpa[] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x15}; 11636392Ssklower 11743071Ssklower union sockunion { 11843071Ssklower struct sockaddr_iso siso; 11943071Ssklower struct sockaddr_dl sdl; 12043071Ssklower struct sockaddr sa; 12143071Ssklower }; 12236392Ssklower 12336392Ssklower /* 12443071Ssklower * FUNCTION: llc_rtrequest 12543071Ssklower * 12643071Ssklower * PURPOSE: Manage routing table entries specific to LLC for ISO. 12743071Ssklower * 12843071Ssklower * NOTES: This does a lot of obscure magic; 12943071Ssklower */ 13043071Ssklower llc_rtrequest(req, rt, sa) 13143071Ssklower int req; 13243071Ssklower register struct rtentry *rt; 13343071Ssklower struct sockaddr *sa; 13443071Ssklower { 13543071Ssklower register union sockunion *gate = (union sockunion *)rt->rt_gateway; 13643071Ssklower register struct llinfo_llc *lc = (struct llinfo_llc *)rt->rt_llinfo, *lc2; 13743071Ssklower struct rtentry *rt2; 13843071Ssklower struct ifnet *ifp = rt->rt_ifp; 13943071Ssklower int addrlen = ifp->if_addrlen; 14048732Ssklower #define LLC_SIZE 3 /* XXXXXX do this right later */ 14143071Ssklower 14243334Ssklower IFDEBUG (D_SNPA) 14343334Ssklower printf("llc_rtrequest(%d, %x, %x)\n", req, rt, sa); 14443334Ssklower ENDDEBUG 14550231Ssklower if (rt->rt_flags & RTF_GATEWAY) 14650231Ssklower return; 14750231Ssklower else switch (req) { 14843071Ssklower case RTM_ADD: 14943334Ssklower /* 15043334Ssklower * Case 1: This route may come from a route to iface with mask 15143334Ssklower * or from a default route. 15243334Ssklower */ 15343071Ssklower if (rt->rt_flags & RTF_CLONING) { 15454717Ssklower iso_setmcasts(ifp, req); 15550231Ssklower rt_setgate(rt, rt_key(rt), &blank_dl); 15650231Ssklower return; 15743071Ssklower } 15850231Ssklower if (lc != 0) 15950231Ssklower return; /* happens on a route change */ 16043334Ssklower /* FALLTHROUGH */ 16143334Ssklower case RTM_RESOLVE: 16243334Ssklower /* 16343334Ssklower * Case 2: This route may come from cloning, or a manual route 16443334Ssklower * add with a LL address. 16543334Ssklower */ 16643334Ssklower if (gate->sdl.sdl_family != AF_LINK) { 16747274Ssklower log(LOG_DEBUG, "llc_rtrequest: got non-link non-gateway route\n"); 16848732Ssklower break; 16943334Ssklower } 17043334Ssklower R_Malloc(lc, struct llinfo_llc *, sizeof (*lc)); 17143334Ssklower rt->rt_llinfo = (caddr_t)lc; 17243334Ssklower if (lc == 0) { 17347274Ssklower log(LOG_DEBUG, "llc_rtrequest: malloc failed\n"); 17448732Ssklower break; 17543334Ssklower } 17643334Ssklower Bzero(lc, sizeof(*lc)); 17743334Ssklower lc->lc_rt = rt; 17843334Ssklower rt->rt_flags |= RTF_LLINFO; 17943334Ssklower insque(lc, &llinfo_llc); 18043334Ssklower if (gate->sdl.sdl_alen == sizeof(struct esis_req) + addrlen) { 18143334Ssklower gate->sdl.sdl_alen -= sizeof(struct esis_req); 18243334Ssklower bcopy(addrlen + LLADDR(&gate->sdl), 18343334Ssklower (caddr_t)&lc->lc_er, sizeof(lc->lc_er)); 18443334Ssklower } else if (gate->sdl.sdl_alen == addrlen) 18543334Ssklower lc->lc_flags = (SNPA_ES | SNPA_VALID | SNPA_PERM); 18643071Ssklower break; 18743071Ssklower case RTM_DELETE: 18854717Ssklower if (rt->rt_flags & RTF_CLONING) 18954717Ssklower iso_setmcasts(ifp, req); 19054717Ssklower if (lc == 0) 19143334Ssklower return; 19243334Ssklower remque(lc); 19343334Ssklower Free(lc); 19443334Ssklower rt->rt_llinfo = 0; 19543334Ssklower rt->rt_flags &= ~RTF_LLINFO; 19643071Ssklower break; 19743071Ssklower } 19848732Ssklower if (rt->rt_rmx.rmx_mtu == 0) { 19948732Ssklower rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu - LLC_SIZE; 20048732Ssklower } 20143071Ssklower } 20243071Ssklower /* 20354717Ssklower * FUNCTION: iso_setmcasts 20454717Ssklower * 20554717Ssklower * PURPOSE: Enable/Disable ESIS/ISIS multicast reception on interfaces. 20654717Ssklower * 20754717Ssklower * NOTES: This also does a lot of obscure magic; 20854717Ssklower */ 20954717Ssklower iso_setmcasts(ifp, req) 21054717Ssklower struct ifnet *ifp; 21154717Ssklower int req; 21254717Ssklower { 21354717Ssklower static char *addrlist[] = 21454717Ssklower { all_es_snpa, all_is_snpa, all_l1is_snpa, all_l2is_snpa, 0}; 21554717Ssklower struct ifreq ifr; 21654717Ssklower register caddr_t *cpp; 21754717Ssklower int doreset = 0; 21854717Ssklower 21954717Ssklower bzero((caddr_t)&ifr, sizeof(ifr)); 22055903Ssklower for (cpp = (caddr_t *)addrlist; *cpp; cpp++) { 22154717Ssklower bcopy(*cpp, (caddr_t)ifr.ifr_addr.sa_data, 6); 22254717Ssklower if (req == RTM_ADD) 22354717Ssklower if (ether_addmulti(&ifr, (struct arpcom *)ifp) == ENETRESET) 22454717Ssklower doreset++; 22554717Ssklower else 22657952Ssklower if (ether_delmulti(&ifr, (struct arpcom *)ifp) == ENETRESET) 22754717Ssklower doreset++; 22854717Ssklower } 22957952Ssklower if (doreset) { 23057952Ssklower if (ifp->if_reset) 23157952Ssklower (*ifp->if_reset)(ifp->if_unit); 23257952Ssklower else 23357952Ssklower printf("iso_setmcasts: %s%d needs reseting to receive iso mcasts\n", 23457952Ssklower ifp->if_name, ifp->if_unit); 23557952Ssklower } 23654717Ssklower } 23754717Ssklower /* 23836392Ssklower * FUNCTION: iso_snparesolve 23936392Ssklower * 24036392Ssklower * PURPOSE: Resolve an iso address into snpa address 24136392Ssklower * 24236392Ssklower * RETURNS: 0 if addr is resolved 24336392Ssklower * errno if addr is unknown 24436392Ssklower * 24536392Ssklower * SIDE EFFECTS: 24636392Ssklower * 24743071Ssklower * NOTES: Now that we have folded the snpa cache into the routing 24843071Ssklower * table, we know there is no snpa address known for this 24943071Ssklower * destination. If we know of a default IS, then the address 25043071Ssklower * of the IS is returned. If no IS is known, then return the 25143071Ssklower * multi-cast address for "all ES" for this interface. 25236392Ssklower * 25336392Ssklower * NB: the last case described above constitutes the 25436392Ssklower * query configuration function 9542, sec 6.5 25536392Ssklower * A mechanism is needed to prevent this function from 25636392Ssklower * being invoked if the system is an IS. 25736392Ssklower */ 25837469Ssklower iso_snparesolve(ifp, dest, snpa, snpa_len) 25943071Ssklower struct ifnet *ifp; /* outgoing interface */ 26043071Ssklower struct sockaddr_iso *dest; /* destination */ 26143071Ssklower caddr_t snpa; /* RESULT: snpa to be used */ 26243071Ssklower int *snpa_len; /* RESULT: length of snpa */ 26336392Ssklower { 26443071Ssklower struct llinfo_llc *sc; /* ptr to snpa table entry */ 26543071Ssklower caddr_t found_snpa; 26643071Ssklower int addrlen; 26736392Ssklower 26836392Ssklower /* 26936392Ssklower * This hack allows us to send esis packets that have the destination snpa 27036392Ssklower * addresss embedded in the destination nsap address 27136392Ssklower */ 27243071Ssklower if (dest->siso_data[0] == AFI_SNA) { 27336392Ssklower /* 27436392Ssklower * This is a subnetwork address. Return it immediately 27536392Ssklower */ 27636392Ssklower IFDEBUG(D_SNPA) 27736392Ssklower printf("iso_snparesolve: return SN address\n"); 27836392Ssklower ENDDEBUG 27943071Ssklower addrlen = dest->siso_nlen - 1; /* subtract size of AFI */ 28043071Ssklower found_snpa = (caddr_t) dest->siso_data + 1; 28136392Ssklower /* 28243071Ssklower * If we are an IS, we can't do much with the packet; 28343071Ssklower * Check if we know about an IS. 28436392Ssklower */ 28543071Ssklower } else if (iso_systype != SNPA_IS && known_is != 0 && 28643071Ssklower (sc = (struct llinfo_llc *)known_is->rt_llinfo) && 28743071Ssklower (sc->lc_flags & SNPA_VALID)) { 28843071Ssklower register struct sockaddr_dl *sdl = 28943071Ssklower (struct sockaddr_dl *)(known_is->rt_gateway); 29043071Ssklower found_snpa = LLADDR(sdl); 29143071Ssklower addrlen = sdl->sdl_alen; 29243071Ssklower } else if (ifp->if_flags & IFF_BROADCAST) { 29343071Ssklower /* 29443071Ssklower * no IS, no match. Return "all es" multicast address for this 29543071Ssklower * interface, as per Query Configuration Function (9542 sec 6.5) 29643071Ssklower * 29743071Ssklower * Note: there is a potential problem here. If the destination 29843071Ssklower * is on the subnet and it does not respond with a ESH, but 29943071Ssklower * does send back a TP CC, a connection could be established 30043071Ssklower * where we always transmit the CLNP packet to "all es" 30136392Ssklower */ 30243071Ssklower addrlen = ifp->if_addrlen; 30343071Ssklower found_snpa = (caddr_t)all_es_snpa; 30443071Ssklower } else 30543071Ssklower return (ENETUNREACH); 30643071Ssklower bcopy(found_snpa, snpa, *snpa_len = addrlen); 30736392Ssklower return (0); 30836392Ssklower } 30936392Ssklower 31036392Ssklower 31136392Ssklower /* 31236392Ssklower * FUNCTION: snpac_free 31336392Ssklower * 31436392Ssklower * PURPOSE: free an entry in the iso address map table 31536392Ssklower * 31636392Ssklower * RETURNS: nothing 31736392Ssklower * 31836392Ssklower * SIDE EFFECTS: 31936392Ssklower * 32036392Ssklower * NOTES: If there is a route entry associated with cache 32136392Ssklower * entry, then delete that as well 32236392Ssklower */ 32343071Ssklower snpac_free(lc) 32443071Ssklower register struct llinfo_llc *lc; /* entry to free */ 32536392Ssklower { 32643071Ssklower register struct rtentry *rt = lc->lc_rt; 32737469Ssklower register struct iso_addr *r; 32836392Ssklower 32943071Ssklower if (known_is == rt) 33043071Ssklower known_is = 0; 33143071Ssklower if (rt && (rt->rt_flags & RTF_UP) && 33243071Ssklower (rt->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED))) { 33337469Ssklower RTFREE(rt); 33437469Ssklower rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt), 33537469Ssklower rt->rt_flags, (struct rtentry **)0); 33637469Ssklower RTFREE(rt); 33736392Ssklower } 33836392Ssklower } 33936392Ssklower 34036392Ssklower /* 34136392Ssklower * FUNCTION: snpac_add 34236392Ssklower * 34336392Ssklower * PURPOSE: Add an entry to the snpa cache 34436392Ssklower * 34536392Ssklower * RETURNS: 34636392Ssklower * 34736392Ssklower * SIDE EFFECTS: 34836392Ssklower * 34936392Ssklower * NOTES: If entry already exists, then update holding time. 35036392Ssklower */ 35143334Ssklower snpac_add(ifp, nsap, snpa, type, ht, nsellength) 35236392Ssklower struct ifnet *ifp; /* interface info is related to */ 35336392Ssklower struct iso_addr *nsap; /* nsap to add */ 35436392Ssklower caddr_t snpa; /* translation */ 35536392Ssklower char type; /* SNPA_IS or SNPA_ES */ 35637469Ssklower u_short ht; /* holding time (in seconds) */ 35743334Ssklower int nsellength; /* nsaps may differ only in trailing bytes */ 35836392Ssklower { 35943071Ssklower register struct llinfo_llc *lc; 36043334Ssklower register struct rtentry *rt; 36143334Ssklower struct rtentry *mrt = 0; 36243071Ssklower register struct iso_addr *r; /* for zap_isoaddr macro */ 36343071Ssklower int snpalen = min(ifp->if_addrlen, MAX_SNPALEN); 36452625Ssklower int new_entry = 0, index = ifp->if_index, iftype = ifp->if_type; 36536392Ssklower 36643334Ssklower IFDEBUG(D_SNPA) 36743334Ssklower printf("snpac_add(%x, %x, %x, %x, %x, %x)\n", 36843334Ssklower ifp, nsap, snpa, type, ht, nsellength); 36943334Ssklower ENDDEBUG 37043071Ssklower zap_isoaddr(dst, nsap); 37143071Ssklower rt = rtalloc1(S(dst), 0); 37243334Ssklower IFDEBUG(D_SNPA) 37343334Ssklower printf("snpac_add: rtalloc1 returns %x\n", rt); 37443334Ssklower ENDDEBUG 37543071Ssklower if (rt == 0) { 37643334Ssklower struct sockaddr *netmask; 37743334Ssklower int flags; 37843334Ssklower add: 37943334Ssklower if (nsellength) { 38043334Ssklower netmask = S(msk); flags = RTF_UP; 38143334Ssklower snpac_fixdstandmask(nsellength); 38243334Ssklower } else { 38343334Ssklower netmask = 0; flags = RTF_UP | RTF_HOST; 38443334Ssklower } 38543071Ssklower new_entry = 1; 38643071Ssklower zap_linkaddr((>e_dl), snpa, snpalen, index); 38752625Ssklower gte_dl.sdl_type = iftype; 38843334Ssklower if (rtrequest(RTM_ADD, S(dst), S(gte_dl), netmask, flags, &mrt) || 38943334Ssklower mrt == 0) 39043071Ssklower return (0); 39143334Ssklower rt = mrt; 39243334Ssklower rt->rt_refcnt--; 39343071Ssklower } else { 39443071Ssklower register struct sockaddr_dl *sdl = (struct sockaddr_dl *)rt->rt_gateway; 39543334Ssklower rt->rt_refcnt--; 39643334Ssklower if ((rt->rt_flags & RTF_LLINFO) == 0) 39743334Ssklower goto add; 39843334Ssklower if (nsellength && (rt->rt_flags & RTF_HOST)) { 39943334Ssklower if (rt->rt_refcnt == 0) { 40043334Ssklower rtrequest(RTM_DELETE, S(dst), (struct sockaddr *)0, 40143334Ssklower (struct sockaddr *)0, 0, (struct rtentry *)0); 40243334Ssklower rt = 0; 40343334Ssklower goto add; 40443334Ssklower } else { 40543334Ssklower static struct iso_addr nsap2; register char *cp; 40643334Ssklower nsap2 = *nsap; 40743334Ssklower cp = nsap2.isoa_genaddr + nsap->isoa_len - nsellength; 40843334Ssklower while (cp < (char *)(1 + &nsap2)) 40943334Ssklower *cp++ = 0; 41043334Ssklower (void) snpac_add(ifp, &nsap2, snpa, type, ht, nsellength); 41143334Ssklower } 41243334Ssklower } 41343071Ssklower if (sdl->sdl_family != AF_LINK || sdl->sdl_alen == 0) { 41443071Ssklower int old_sdl_len = sdl->sdl_len; 41543334Ssklower if (old_sdl_len < sizeof(*sdl)) { 41647274Ssklower log(LOG_DEBUG, "snpac_add: cant make room for lladdr\n"); 41743071Ssklower return (0); 41843334Ssklower } 41943071Ssklower zap_linkaddr(sdl, snpa, snpalen, index); 42043071Ssklower sdl->sdl_len = old_sdl_len; 42152625Ssklower sdl->sdl_type = iftype; 42243071Ssklower new_entry = 1; 42343071Ssklower } 42436392Ssklower } 42543334Ssklower if ((lc = (struct llinfo_llc *)rt->rt_llinfo) == 0) 42643334Ssklower panic("snpac_rtrequest"); 42750230Ssklower rt->rt_rmx.rmx_expire = ht + time.tv_sec; 42843071Ssklower lc->lc_flags = SNPA_VALID | type; 42953691Ssklower if ((type & SNPA_IS) && !(iso_systype & SNPA_IS)) 43043071Ssklower snpac_logdefis(rt); 43143334Ssklower return (new_entry); 43236392Ssklower } 43336392Ssklower 43450230Ssklower static void 43550230Ssklower snpac_fixdstandmask(nsellength) 43643334Ssklower { 43743334Ssklower register char *cp = msk.siso_data, *cplim; 43843334Ssklower 43943334Ssklower cplim = cp + (dst.siso_nlen -= nsellength); 44043334Ssklower msk.siso_len = cplim - (char *)&msk; 44143334Ssklower msk.siso_nlen = 0; 44243334Ssklower while (cp < cplim) 44343334Ssklower *cp++ = -1; 44443334Ssklower while (cp < (char *)msk.siso_pad) 44543334Ssklower *cp++ = 0; 44643334Ssklower for (cp = dst.siso_data + dst.siso_nlen; cp < (char *)dst.siso_pad; ) 44743334Ssklower *cp++ = 0; 44843334Ssklower } 44943334Ssklower 45036392Ssklower /* 45136392Ssklower * FUNCTION: snpac_ioctl 45236392Ssklower * 45336392Ssklower * PURPOSE: Set/Get the system type and esis parameters 45436392Ssklower * 45536392Ssklower * RETURNS: 0 on success, or unix error code 45636392Ssklower * 45736392Ssklower * SIDE EFFECTS: 45836392Ssklower * 45936392Ssklower * NOTES: 46036392Ssklower */ 46150230Ssklower snpac_ioctl (so, cmd, data) 46250230Ssklower struct socket *so; 46336392Ssklower int cmd; /* ioctl to process */ 46436392Ssklower caddr_t data; /* data for the cmd */ 46536392Ssklower { 46636392Ssklower register struct systype_req *rq = (struct systype_req *)data; 46736392Ssklower 46843334Ssklower IFDEBUG(D_IOCTL) 46936392Ssklower if (cmd == SIOCSSTYPE) 47043071Ssklower printf("snpac_ioctl: cmd set, type x%x, ht %d, ct %d\n", 47136392Ssklower rq->sr_type, rq->sr_holdt, rq->sr_configt); 47236392Ssklower else 47343071Ssklower printf("snpac_ioctl: cmd get\n"); 47436392Ssklower ENDDEBUG 47536392Ssklower 47636392Ssklower if (cmd == SIOCSSTYPE) { 47750230Ssklower if ((so->so_state & SS_PRIV) == 0) 47850230Ssklower return (EPERM); 47936392Ssklower if ((rq->sr_type & (SNPA_ES|SNPA_IS)) == (SNPA_ES|SNPA_IS)) 48036392Ssklower return(EINVAL); 48136392Ssklower if (rq->sr_type & SNPA_ES) { 48236392Ssklower iso_systype = SNPA_ES; 48336392Ssklower } else if (rq->sr_type & SNPA_IS) { 48436392Ssklower iso_systype = SNPA_IS; 48536392Ssklower } else { 48636392Ssklower return(EINVAL); 48736392Ssklower } 48836392Ssklower esis_holding_time = rq->sr_holdt; 48936392Ssklower esis_config_time = rq->sr_configt; 49043423Ssklower if (esis_esconfig_time != rq->sr_esconfigt) { 49143423Ssklower untimeout(esis_config, (caddr_t)0); 49243423Ssklower esis_esconfig_time = rq->sr_esconfigt; 49343423Ssklower esis_config(); 49443423Ssklower } 49536392Ssklower } else if (cmd == SIOCGSTYPE) { 49636392Ssklower rq->sr_type = iso_systype; 49736392Ssklower rq->sr_holdt = esis_holding_time; 49836392Ssklower rq->sr_configt = esis_config_time; 49943423Ssklower rq->sr_esconfigt = esis_esconfig_time; 50036392Ssklower } else { 50143071Ssklower return (EINVAL); 50236392Ssklower } 50343071Ssklower return (0); 50436392Ssklower } 50536392Ssklower 50636392Ssklower /* 50736392Ssklower * FUNCTION: snpac_logdefis 50836392Ssklower * 50936392Ssklower * PURPOSE: Mark the IS passed as the default IS 51036392Ssklower * 51136392Ssklower * RETURNS: nothing 51236392Ssklower * 51336392Ssklower * SIDE EFFECTS: 51436392Ssklower * 51536392Ssklower * NOTES: 51636392Ssklower */ 51736392Ssklower snpac_logdefis(sc) 51843071Ssklower register struct rtentry *sc; 51936392Ssklower { 52037469Ssklower register struct iso_addr *r; 52143071Ssklower register struct sockaddr_dl *sdl = (struct sockaddr_dl *)sc->rt_gateway; 52253691Ssklower register struct rtentry *rt; 52343071Ssklower 52453691Ssklower if (known_is == sc || !(sc->rt_flags & RTF_HOST)) 52537469Ssklower return; 52653691Ssklower if (known_is) { 52753691Ssklower RTFREE(known_is); 52837469Ssklower } 52953691Ssklower known_is = sc; 53053691Ssklower sc->rt_refcnt++; 53153691Ssklower rt = rtalloc1((struct sockaddr *)&zsi, 0); 53253691Ssklower if (rt == 0) 53353691Ssklower rtrequest(RTM_ADD, S(zsi), rt_key(sc), S(zmk), 53453691Ssklower RTF_DYNAMIC|RTF_GATEWAY, 0); 53553691Ssklower else { 53653691Ssklower if ((rt->rt_flags & RTF_DYNAMIC) && 53753691Ssklower (rt->rt_flags & RTF_GATEWAY) && rt_mask(rt)->sa_len == 0) 53853691Ssklower rt_setgate(rt, rt_key(rt), rt_key(sc)); 53937469Ssklower } 54036392Ssklower } 54136392Ssklower 54236392Ssklower /* 54336392Ssklower * FUNCTION: snpac_age 54436392Ssklower * 54536392Ssklower * PURPOSE: Time out snpac entries 54636392Ssklower * 54736392Ssklower * RETURNS: 54836392Ssklower * 54936392Ssklower * SIDE EFFECTS: 55036392Ssklower * 55136392Ssklower * NOTES: When encountering an entry for the first time, snpac_age 55236392Ssklower * may delete up to SNPAC_AGE too many seconds. Ie. 55336392Ssklower * if the entry is added a moment before snpac_age is 55436392Ssklower * called, the entry will immediately have SNPAC_AGE 55536392Ssklower * seconds taken off the holding time, even though 55636392Ssklower * it has only been held a brief moment. 55736392Ssklower * 55836392Ssklower * The proper way to do this is set an expiry timeval 55936392Ssklower * equal to current time + holding time. Then snpac_age 56036392Ssklower * would time out entries where expiry date is older 56136392Ssklower * than the current time. 56236392Ssklower */ 56358990Ssklower void 56436392Ssklower snpac_age() 56536392Ssklower { 56650230Ssklower register struct llinfo_llc *lc, *nlc; 56750230Ssklower register struct rtentry *rt; 56836392Ssklower 56936392Ssklower timeout(snpac_age, (caddr_t)0, SNPAC_AGE * hz); 57036392Ssklower 57150230Ssklower for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = nlc) { 57250230Ssklower nlc = lc->lc_next; 57353691Ssklower if (lc->lc_flags & SNPA_VALID) { 57450230Ssklower rt = lc->lc_rt; 57550230Ssklower if (rt->rt_rmx.rmx_expire && rt->rt_rmx.rmx_expire < time.tv_sec) 57650230Ssklower snpac_free(lc); 57736392Ssklower } 57836392Ssklower } 57936392Ssklower } 58036392Ssklower 58136392Ssklower /* 58236392Ssklower * FUNCTION: snpac_ownmulti 58336392Ssklower * 58436392Ssklower * PURPOSE: Determine if the snpa address is a multicast address 58536392Ssklower * of the same type as the system. 58636392Ssklower * 58736392Ssklower * RETURNS: true or false 58836392Ssklower * 58936392Ssklower * SIDE EFFECTS: 59036392Ssklower * 59136392Ssklower * NOTES: Used by interface drivers when not in eavesdrop mode 59236392Ssklower * as interm kludge until 59336392Ssklower * real multicast addresses can be configured 59436392Ssklower */ 59536392Ssklower snpac_ownmulti(snpa, len) 59643071Ssklower caddr_t snpa; 59743071Ssklower u_int len; 59836392Ssklower { 59937469Ssklower return (((iso_systype & SNPA_ES) && 60043071Ssklower (!bcmp(snpa, (caddr_t)all_es_snpa, len))) || 60137469Ssklower ((iso_systype & SNPA_IS) && 60243071Ssklower (!bcmp(snpa, (caddr_t)all_is_snpa, len)))); 60336392Ssklower } 60436392Ssklower 60536392Ssklower /* 60636392Ssklower * FUNCTION: snpac_flushifp 60736392Ssklower * 60836392Ssklower * PURPOSE: Flush entries associated with specific ifp 60936392Ssklower * 61036392Ssklower * RETURNS: nothing 61136392Ssklower * 61236392Ssklower * SIDE EFFECTS: 61336392Ssklower * 61436392Ssklower * NOTES: 61536392Ssklower */ 61636392Ssklower snpac_flushifp(ifp) 61736392Ssklower struct ifnet *ifp; 61836392Ssklower { 61943071Ssklower register struct llinfo_llc *lc; 62036392Ssklower 62143071Ssklower for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = lc->lc_next) { 62243071Ssklower if (lc->lc_rt->rt_ifp == ifp && (lc->lc_flags & SNPA_VALID)) 62343071Ssklower snpac_free(lc); 62436392Ssklower } 62536392Ssklower } 62636392Ssklower 62736392Ssklower /* 62836392Ssklower * FUNCTION: snpac_rtrequest 62936392Ssklower * 63036392Ssklower * PURPOSE: Make a routing request 63136392Ssklower * 63236392Ssklower * RETURNS: nothing 63336392Ssklower * 63436392Ssklower * SIDE EFFECTS: 63536392Ssklower * 63636392Ssklower * NOTES: In the future, this should make a request of a user 63736392Ssklower * level routing daemon. 63836392Ssklower */ 63937469Ssklower snpac_rtrequest(req, host, gateway, netmask, flags, ret_nrt) 64036392Ssklower int req; 64137469Ssklower struct iso_addr *host; 64236392Ssklower struct iso_addr *gateway; 64337469Ssklower struct iso_addr *netmask; 64436392Ssklower short flags; 64537469Ssklower struct rtentry **ret_nrt; 64636392Ssklower { 64737469Ssklower register struct iso_addr *r; 64836392Ssklower 64936392Ssklower IFDEBUG(D_SNPA) 65036392Ssklower printf("snpac_rtrequest: "); 65137469Ssklower if (req == RTM_ADD) 65236392Ssklower printf("add"); 65337469Ssklower else if (req == RTM_DELETE) 65436392Ssklower printf("delete"); 65536392Ssklower else 65636392Ssklower printf("unknown command"); 65737469Ssklower printf(" dst: %s\n", clnp_iso_addrp(host)); 65836392Ssklower printf("\tgateway: %s\n", clnp_iso_addrp(gateway)); 65936392Ssklower ENDDEBUG 66036392Ssklower 66136392Ssklower 66237469Ssklower zap_isoaddr(dst, host); 66337469Ssklower zap_isoaddr(gte, gateway); 66443334Ssklower if (netmask) { 66543334Ssklower zap_isoaddr(msk, netmask); 66643334Ssklower msk.siso_nlen = 0; 66743334Ssklower msk.siso_len = msk.siso_pad - (u_char *)&msk; 66843334Ssklower } 66937469Ssklower 67037469Ssklower rtrequest(req, S(dst), S(gte), (netmask ? S(msk) : (struct sockaddr *)0), 67137469Ssklower flags, ret_nrt); 67236392Ssklower } 67336392Ssklower 67436392Ssklower /* 67536392Ssklower * FUNCTION: snpac_addrt 67636392Ssklower * 67736392Ssklower * PURPOSE: Associate a routing entry with an snpac entry 67836392Ssklower * 67936392Ssklower * RETURNS: nothing 68036392Ssklower * 68136392Ssklower * SIDE EFFECTS: 68236392Ssklower * 68336392Ssklower * NOTES: If a cache entry exists for gateway, then 68436392Ssklower * make a routing entry (host, gateway) and associate 68536392Ssklower * with gateway. 68636392Ssklower * 68736392Ssklower * If a route already exists and is different, first delete 68836392Ssklower * it. 68936392Ssklower * 69036392Ssklower * This could be made more efficient by checking 69136392Ssklower * the existing route before adding a new one. 69236392Ssklower */ 69339950Ssklower snpac_addrt(ifp, host, gateway, netmask) 69439950Ssklower struct ifnet *ifp; 69539950Ssklower struct iso_addr *host, *gateway, *netmask; 69636392Ssklower { 69737469Ssklower register struct iso_addr *r; 69836392Ssklower 69943071Ssklower zap_isoaddr(dst, host); 70043071Ssklower zap_isoaddr(gte, gateway); 70143071Ssklower if (netmask) { 70243334Ssklower zap_isoaddr(msk, netmask); 70343334Ssklower msk.siso_nlen = 0; 70443334Ssklower msk.siso_len = msk.siso_pad - (u_char *)&msk; 70543071Ssklower rtredirect(S(dst), S(gte), S(msk), RTF_DONE, S(gte), 0); 70643071Ssklower } else 70743071Ssklower rtredirect(S(dst), S(gte), (struct sockaddr *)0, 70843071Ssklower RTF_DONE | RTF_HOST, S(gte), 0); 70936392Ssklower } 71061288Ssklower #endif /* ISO */ 711