149268Sbostic /*- 249268Sbostic * Copyright (c) 1991 The Regents of the University of California. 349268Sbostic * All rights reserved. 449268Sbostic * 549268Sbostic * %sccs.include.redist.c% 649268Sbostic * 7*56533Sbostic * @(#)iso_snpac.c 7.21 (Berkeley) 10/11/92 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 41*56533Sbostic #include <sys/param.h> 42*56533Sbostic #include <sys/systm.h> 43*56533Sbostic #include <sys/mbuf.h> 44*56533Sbostic #include <sys/domain.h> 45*56533Sbostic #include <sys/protosw.h> 46*56533Sbostic #include <sys/socket.h> 47*56533Sbostic #include <sys/socketvar.h> 48*56533Sbostic #include <sys/errno.h> 49*56533Sbostic #include <sys/ioctl.h> 50*56533Sbostic #include <sys/syslog.h> 5136392Ssklower 52*56533Sbostic #include <net/if.h> 53*56533Sbostic #include <net/if_dl.h> 54*56533Sbostic #include <net/route.h> 5536392Ssklower 56*56533Sbostic #include <netiso/iso.h> 57*56533Sbostic #include <netiso/iso_var.h> 58*56533Sbostic #include <netiso/iso_snpac.h> 59*56533Sbostic #include <netiso/clnp.h> 60*56533Sbostic #include <netiso/clnp_stat.h> 61*56533Sbostic #include <netiso/esis.h> 62*56533Sbostic #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; 6750230Ssklower extern int esis_config(), hz; 6850230Ssklower static void snpac_fixdstandmask(); 6936392Ssklower 7037469Ssklower struct sockaddr_iso blank_siso = {sizeof(blank_siso), AF_ISO}; 7137469Ssklower extern u_long iso_hashchar(); 7237469Ssklower static struct sockaddr_iso 7337469Ssklower dst = {sizeof(dst), AF_ISO}, 7437469Ssklower gte = {sizeof(dst), AF_ISO}, 7537469Ssklower src = {sizeof(dst), AF_ISO}, 7637469Ssklower msk = {sizeof(dst), AF_ISO}, 7753691Ssklower zmk = {0}; 7837469Ssklower #define zsi blank_siso 7937469Ssklower #define zero_isoa zsi.siso_addr 8050230Ssklower #define zap_isoaddr(a, b) {Bzero(&a.siso_addr, sizeof(*r)); r = b; \ 8150230Ssklower Bcopy(r, &a.siso_addr, 1 + (r)->isoa_len);} 8237469Ssklower #define S(x) ((struct sockaddr *)&(x)) 8337469Ssklower 8443071Ssklower static struct sockaddr_dl blank_dl = {sizeof(blank_dl), AF_LINK}; 8543071Ssklower static struct sockaddr_dl gte_dl; 8643071Ssklower #define zap_linkaddr(a, b, c, i) \ 8743071Ssklower (*a = blank_dl, bcopy(b, a->sdl_data, a->sdl_alen = c), a->sdl_index = i) 8836392Ssklower 8936392Ssklower /* 9036392Ssklower * We only keep track of a single IS at a time. 9136392Ssklower */ 9243071Ssklower struct rtentry *known_is; 9336392Ssklower 9436392Ssklower /* 9536392Ssklower * Addresses taken from NBS agreements, December 1987. 9636392Ssklower * 9736392Ssklower * These addresses assume on-the-wire transmission of least significant 9836392Ssklower * bit first. This is the method used by 802.3. When these 9936392Ssklower * addresses are passed to the token ring driver, (802.5), they 10036392Ssklower * must be bit-swaped because 802.5 transmission order is MSb first. 10136392Ssklower * 10236392Ssklower * Furthermore, according to IBM Austin, these addresses are not 10336392Ssklower * true token ring multicast addresses. More work is necessary 10436392Ssklower * to get multicast to work right on token ring. 10536392Ssklower * 10636392Ssklower * Currently, the token ring driver does not handle multicast, so 10736392Ssklower * these addresses are converted into the broadcast address in 10836392Ssklower * lan_output() That means that if these multicast addresses change 10936392Ssklower * the token ring driver must be altered. 11036392Ssklower */ 11143334Ssklower char all_es_snpa[] = { 0x09, 0x00, 0x2b, 0x00, 0x00, 0x04 }; 11243334Ssklower char all_is_snpa[] = { 0x09, 0x00, 0x2b, 0x00, 0x00, 0x05 }; 11345898Ssklower char all_l1is_snpa[] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x14}; 11445898Ssklower char all_l2is_snpa[] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x15}; 11536392Ssklower 11643071Ssklower union sockunion { 11743071Ssklower struct sockaddr_iso siso; 11843071Ssklower struct sockaddr_dl sdl; 11943071Ssklower struct sockaddr sa; 12043071Ssklower }; 12136392Ssklower 12236392Ssklower /* 12343071Ssklower * FUNCTION: llc_rtrequest 12443071Ssklower * 12543071Ssklower * PURPOSE: Manage routing table entries specific to LLC for ISO. 12643071Ssklower * 12743071Ssklower * NOTES: This does a lot of obscure magic; 12843071Ssklower */ 12943071Ssklower llc_rtrequest(req, rt, sa) 13043071Ssklower int req; 13143071Ssklower register struct rtentry *rt; 13243071Ssklower struct sockaddr *sa; 13343071Ssklower { 13443071Ssklower register union sockunion *gate = (union sockunion *)rt->rt_gateway; 13543071Ssklower register struct llinfo_llc *lc = (struct llinfo_llc *)rt->rt_llinfo, *lc2; 13643071Ssklower struct rtentry *rt2; 13743071Ssklower struct ifnet *ifp = rt->rt_ifp; 13843071Ssklower int addrlen = ifp->if_addrlen; 13948732Ssklower #define LLC_SIZE 3 /* XXXXXX do this right later */ 14043071Ssklower 14143334Ssklower IFDEBUG (D_SNPA) 14243334Ssklower printf("llc_rtrequest(%d, %x, %x)\n", req, rt, sa); 14343334Ssklower ENDDEBUG 14450231Ssklower if (rt->rt_flags & RTF_GATEWAY) 14550231Ssklower return; 14650231Ssklower else switch (req) { 14743071Ssklower case RTM_ADD: 14843334Ssklower /* 14943334Ssklower * Case 1: This route may come from a route to iface with mask 15043334Ssklower * or from a default route. 15143334Ssklower */ 15243071Ssklower if (rt->rt_flags & RTF_CLONING) { 15354717Ssklower iso_setmcasts(ifp, req); 15450231Ssklower rt_setgate(rt, rt_key(rt), &blank_dl); 15550231Ssklower return; 15643071Ssklower } 15750231Ssklower if (lc != 0) 15850231Ssklower return; /* happens on a route change */ 15943334Ssklower /* FALLTHROUGH */ 16043334Ssklower case RTM_RESOLVE: 16143334Ssklower /* 16243334Ssklower * Case 2: This route may come from cloning, or a manual route 16343334Ssklower * add with a LL address. 16443334Ssklower */ 16543334Ssklower if (gate->sdl.sdl_family != AF_LINK) { 16647274Ssklower log(LOG_DEBUG, "llc_rtrequest: got non-link non-gateway route\n"); 16748732Ssklower break; 16843334Ssklower } 16943334Ssklower R_Malloc(lc, struct llinfo_llc *, sizeof (*lc)); 17043334Ssklower rt->rt_llinfo = (caddr_t)lc; 17143334Ssklower if (lc == 0) { 17247274Ssklower log(LOG_DEBUG, "llc_rtrequest: malloc failed\n"); 17348732Ssklower break; 17443334Ssklower } 17543334Ssklower Bzero(lc, sizeof(*lc)); 17643334Ssklower lc->lc_rt = rt; 17743334Ssklower rt->rt_flags |= RTF_LLINFO; 17843334Ssklower insque(lc, &llinfo_llc); 17943334Ssklower if (gate->sdl.sdl_alen == sizeof(struct esis_req) + addrlen) { 18043334Ssklower gate->sdl.sdl_alen -= sizeof(struct esis_req); 18143334Ssklower bcopy(addrlen + LLADDR(&gate->sdl), 18243334Ssklower (caddr_t)&lc->lc_er, sizeof(lc->lc_er)); 18343334Ssklower } else if (gate->sdl.sdl_alen == addrlen) 18443334Ssklower lc->lc_flags = (SNPA_ES | SNPA_VALID | SNPA_PERM); 18543071Ssklower break; 18643071Ssklower case RTM_DELETE: 18754717Ssklower if (rt->rt_flags & RTF_CLONING) 18854717Ssklower iso_setmcasts(ifp, req); 18954717Ssklower if (lc == 0) 19043334Ssklower return; 19143334Ssklower remque(lc); 19243334Ssklower Free(lc); 19343334Ssklower rt->rt_llinfo = 0; 19443334Ssklower rt->rt_flags &= ~RTF_LLINFO; 19543071Ssklower break; 19643071Ssklower } 19748732Ssklower if (rt->rt_rmx.rmx_mtu == 0) { 19848732Ssklower rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu - LLC_SIZE; 19948732Ssklower } 20043071Ssklower } 20143071Ssklower /* 20254717Ssklower * FUNCTION: iso_setmcasts 20354717Ssklower * 20454717Ssklower * PURPOSE: Enable/Disable ESIS/ISIS multicast reception on interfaces. 20554717Ssklower * 20654717Ssklower * NOTES: This also does a lot of obscure magic; 20754717Ssklower */ 20854717Ssklower iso_setmcasts(ifp, req) 20954717Ssklower struct ifnet *ifp; 21054717Ssklower int req; 21154717Ssklower { 21254717Ssklower static char *addrlist[] = 21354717Ssklower { all_es_snpa, all_is_snpa, all_l1is_snpa, all_l2is_snpa, 0}; 21454717Ssklower struct ifreq ifr; 21554717Ssklower register caddr_t *cpp; 21654717Ssklower int doreset = 0; 21754717Ssklower 21854717Ssklower bzero((caddr_t)&ifr, sizeof(ifr)); 21955903Ssklower for (cpp = (caddr_t *)addrlist; *cpp; cpp++) { 22054717Ssklower bcopy(*cpp, (caddr_t)ifr.ifr_addr.sa_data, 6); 22154717Ssklower if (req == RTM_ADD) 22254717Ssklower if (ether_addmulti(&ifr, (struct arpcom *)ifp) == ENETRESET) 22354717Ssklower doreset++; 22454717Ssklower else 22554717Ssklower if (ether_addmulti(&ifr, (struct arpcom *)ifp) == ENETRESET) 22654717Ssklower doreset++; 22754717Ssklower } 22854717Ssklower if (doreset) 22954717Ssklower (*ifp->if_reset)(ifp->if_unit); 23054717Ssklower } 23154717Ssklower /* 23236392Ssklower * FUNCTION: iso_snparesolve 23336392Ssklower * 23436392Ssklower * PURPOSE: Resolve an iso address into snpa address 23536392Ssklower * 23636392Ssklower * RETURNS: 0 if addr is resolved 23736392Ssklower * errno if addr is unknown 23836392Ssklower * 23936392Ssklower * SIDE EFFECTS: 24036392Ssklower * 24143071Ssklower * NOTES: Now that we have folded the snpa cache into the routing 24243071Ssklower * table, we know there is no snpa address known for this 24343071Ssklower * destination. If we know of a default IS, then the address 24443071Ssklower * of the IS is returned. If no IS is known, then return the 24543071Ssklower * multi-cast address for "all ES" for this interface. 24636392Ssklower * 24736392Ssklower * NB: the last case described above constitutes the 24836392Ssklower * query configuration function 9542, sec 6.5 24936392Ssklower * A mechanism is needed to prevent this function from 25036392Ssklower * being invoked if the system is an IS. 25136392Ssklower */ 25237469Ssklower iso_snparesolve(ifp, dest, snpa, snpa_len) 25343071Ssklower struct ifnet *ifp; /* outgoing interface */ 25443071Ssklower struct sockaddr_iso *dest; /* destination */ 25543071Ssklower caddr_t snpa; /* RESULT: snpa to be used */ 25643071Ssklower int *snpa_len; /* RESULT: length of snpa */ 25736392Ssklower { 25843071Ssklower struct llinfo_llc *sc; /* ptr to snpa table entry */ 25943071Ssklower caddr_t found_snpa; 26043071Ssklower int addrlen; 26136392Ssklower 26236392Ssklower /* 26336392Ssklower * This hack allows us to send esis packets that have the destination snpa 26436392Ssklower * addresss embedded in the destination nsap address 26536392Ssklower */ 26643071Ssklower if (dest->siso_data[0] == AFI_SNA) { 26736392Ssklower /* 26836392Ssklower * This is a subnetwork address. Return it immediately 26936392Ssklower */ 27036392Ssklower IFDEBUG(D_SNPA) 27136392Ssklower printf("iso_snparesolve: return SN address\n"); 27236392Ssklower ENDDEBUG 27343071Ssklower addrlen = dest->siso_nlen - 1; /* subtract size of AFI */ 27443071Ssklower found_snpa = (caddr_t) dest->siso_data + 1; 27536392Ssklower /* 27643071Ssklower * If we are an IS, we can't do much with the packet; 27743071Ssklower * Check if we know about an IS. 27836392Ssklower */ 27943071Ssklower } else if (iso_systype != SNPA_IS && known_is != 0 && 28043071Ssklower (sc = (struct llinfo_llc *)known_is->rt_llinfo) && 28143071Ssklower (sc->lc_flags & SNPA_VALID)) { 28243071Ssklower register struct sockaddr_dl *sdl = 28343071Ssklower (struct sockaddr_dl *)(known_is->rt_gateway); 28443071Ssklower found_snpa = LLADDR(sdl); 28543071Ssklower addrlen = sdl->sdl_alen; 28643071Ssklower } else if (ifp->if_flags & IFF_BROADCAST) { 28743071Ssklower /* 28843071Ssklower * no IS, no match. Return "all es" multicast address for this 28943071Ssklower * interface, as per Query Configuration Function (9542 sec 6.5) 29043071Ssklower * 29143071Ssklower * Note: there is a potential problem here. If the destination 29243071Ssklower * is on the subnet and it does not respond with a ESH, but 29343071Ssklower * does send back a TP CC, a connection could be established 29443071Ssklower * where we always transmit the CLNP packet to "all es" 29536392Ssklower */ 29643071Ssklower addrlen = ifp->if_addrlen; 29743071Ssklower found_snpa = (caddr_t)all_es_snpa; 29843071Ssklower } else 29943071Ssklower return (ENETUNREACH); 30043071Ssklower bcopy(found_snpa, snpa, *snpa_len = addrlen); 30136392Ssklower return (0); 30236392Ssklower } 30336392Ssklower 30436392Ssklower 30536392Ssklower /* 30636392Ssklower * FUNCTION: snpac_free 30736392Ssklower * 30836392Ssklower * PURPOSE: free an entry in the iso address map table 30936392Ssklower * 31036392Ssklower * RETURNS: nothing 31136392Ssklower * 31236392Ssklower * SIDE EFFECTS: 31336392Ssklower * 31436392Ssklower * NOTES: If there is a route entry associated with cache 31536392Ssklower * entry, then delete that as well 31636392Ssklower */ 31743071Ssklower snpac_free(lc) 31843071Ssklower register struct llinfo_llc *lc; /* entry to free */ 31936392Ssklower { 32043071Ssklower register struct rtentry *rt = lc->lc_rt; 32137469Ssklower register struct iso_addr *r; 32236392Ssklower 32343071Ssklower if (known_is == rt) 32443071Ssklower known_is = 0; 32543071Ssklower if (rt && (rt->rt_flags & RTF_UP) && 32643071Ssklower (rt->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED))) { 32737469Ssklower RTFREE(rt); 32837469Ssklower rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt), 32937469Ssklower rt->rt_flags, (struct rtentry **)0); 33037469Ssklower RTFREE(rt); 33136392Ssklower } 33236392Ssklower } 33336392Ssklower 33436392Ssklower /* 33536392Ssklower * FUNCTION: snpac_add 33636392Ssklower * 33736392Ssklower * PURPOSE: Add an entry to the snpa cache 33836392Ssklower * 33936392Ssklower * RETURNS: 34036392Ssklower * 34136392Ssklower * SIDE EFFECTS: 34236392Ssklower * 34336392Ssklower * NOTES: If entry already exists, then update holding time. 34436392Ssklower */ 34543334Ssklower snpac_add(ifp, nsap, snpa, type, ht, nsellength) 34636392Ssklower struct ifnet *ifp; /* interface info is related to */ 34736392Ssklower struct iso_addr *nsap; /* nsap to add */ 34836392Ssklower caddr_t snpa; /* translation */ 34936392Ssklower char type; /* SNPA_IS or SNPA_ES */ 35037469Ssklower u_short ht; /* holding time (in seconds) */ 35143334Ssklower int nsellength; /* nsaps may differ only in trailing bytes */ 35236392Ssklower { 35343071Ssklower register struct llinfo_llc *lc; 35443334Ssklower register struct rtentry *rt; 35543334Ssklower struct rtentry *mrt = 0; 35643071Ssklower register struct iso_addr *r; /* for zap_isoaddr macro */ 35743071Ssklower int snpalen = min(ifp->if_addrlen, MAX_SNPALEN); 35852625Ssklower int new_entry = 0, index = ifp->if_index, iftype = ifp->if_type; 35936392Ssklower 36043334Ssklower IFDEBUG(D_SNPA) 36143334Ssklower printf("snpac_add(%x, %x, %x, %x, %x, %x)\n", 36243334Ssklower ifp, nsap, snpa, type, ht, nsellength); 36343334Ssklower ENDDEBUG 36443071Ssklower zap_isoaddr(dst, nsap); 36543071Ssklower rt = rtalloc1(S(dst), 0); 36643334Ssklower IFDEBUG(D_SNPA) 36743334Ssklower printf("snpac_add: rtalloc1 returns %x\n", rt); 36843334Ssklower ENDDEBUG 36943071Ssklower if (rt == 0) { 37043334Ssklower struct sockaddr *netmask; 37143334Ssklower int flags; 37243334Ssklower add: 37343334Ssklower if (nsellength) { 37443334Ssklower netmask = S(msk); flags = RTF_UP; 37543334Ssklower snpac_fixdstandmask(nsellength); 37643334Ssklower } else { 37743334Ssklower netmask = 0; flags = RTF_UP | RTF_HOST; 37843334Ssklower } 37943071Ssklower new_entry = 1; 38043071Ssklower zap_linkaddr((>e_dl), snpa, snpalen, index); 38152625Ssklower gte_dl.sdl_type = iftype; 38243334Ssklower if (rtrequest(RTM_ADD, S(dst), S(gte_dl), netmask, flags, &mrt) || 38343334Ssklower mrt == 0) 38443071Ssklower return (0); 38543334Ssklower rt = mrt; 38643334Ssklower rt->rt_refcnt--; 38743071Ssklower } else { 38843071Ssklower register struct sockaddr_dl *sdl = (struct sockaddr_dl *)rt->rt_gateway; 38943334Ssklower rt->rt_refcnt--; 39043334Ssklower if ((rt->rt_flags & RTF_LLINFO) == 0) 39143334Ssklower goto add; 39243334Ssklower if (nsellength && (rt->rt_flags & RTF_HOST)) { 39343334Ssklower if (rt->rt_refcnt == 0) { 39443334Ssklower rtrequest(RTM_DELETE, S(dst), (struct sockaddr *)0, 39543334Ssklower (struct sockaddr *)0, 0, (struct rtentry *)0); 39643334Ssklower rt = 0; 39743334Ssklower goto add; 39843334Ssklower } else { 39943334Ssklower static struct iso_addr nsap2; register char *cp; 40043334Ssklower nsap2 = *nsap; 40143334Ssklower cp = nsap2.isoa_genaddr + nsap->isoa_len - nsellength; 40243334Ssklower while (cp < (char *)(1 + &nsap2)) 40343334Ssklower *cp++ = 0; 40443334Ssklower (void) snpac_add(ifp, &nsap2, snpa, type, ht, nsellength); 40543334Ssklower } 40643334Ssklower } 40743071Ssklower if (sdl->sdl_family != AF_LINK || sdl->sdl_alen == 0) { 40843071Ssklower int old_sdl_len = sdl->sdl_len; 40943334Ssklower if (old_sdl_len < sizeof(*sdl)) { 41047274Ssklower log(LOG_DEBUG, "snpac_add: cant make room for lladdr\n"); 41143071Ssklower return (0); 41243334Ssklower } 41343071Ssklower zap_linkaddr(sdl, snpa, snpalen, index); 41443071Ssklower sdl->sdl_len = old_sdl_len; 41552625Ssklower sdl->sdl_type = iftype; 41643071Ssklower new_entry = 1; 41743071Ssklower } 41836392Ssklower } 41943334Ssklower if ((lc = (struct llinfo_llc *)rt->rt_llinfo) == 0) 42043334Ssklower panic("snpac_rtrequest"); 42150230Ssklower rt->rt_rmx.rmx_expire = ht + time.tv_sec; 42243071Ssklower lc->lc_flags = SNPA_VALID | type; 42353691Ssklower if ((type & SNPA_IS) && !(iso_systype & SNPA_IS)) 42443071Ssklower snpac_logdefis(rt); 42543334Ssklower return (new_entry); 42636392Ssklower } 42736392Ssklower 42850230Ssklower static void 42950230Ssklower snpac_fixdstandmask(nsellength) 43043334Ssklower { 43143334Ssklower register char *cp = msk.siso_data, *cplim; 43243334Ssklower 43343334Ssklower cplim = cp + (dst.siso_nlen -= nsellength); 43443334Ssklower msk.siso_len = cplim - (char *)&msk; 43543334Ssklower msk.siso_nlen = 0; 43643334Ssklower while (cp < cplim) 43743334Ssklower *cp++ = -1; 43843334Ssklower while (cp < (char *)msk.siso_pad) 43943334Ssklower *cp++ = 0; 44043334Ssklower for (cp = dst.siso_data + dst.siso_nlen; cp < (char *)dst.siso_pad; ) 44143334Ssklower *cp++ = 0; 44243334Ssklower } 44343334Ssklower 44436392Ssklower /* 44536392Ssklower * FUNCTION: snpac_ioctl 44636392Ssklower * 44736392Ssklower * PURPOSE: Set/Get the system type and esis parameters 44836392Ssklower * 44936392Ssklower * RETURNS: 0 on success, or unix error code 45036392Ssklower * 45136392Ssklower * SIDE EFFECTS: 45236392Ssklower * 45336392Ssklower * NOTES: 45436392Ssklower */ 45550230Ssklower snpac_ioctl (so, cmd, data) 45650230Ssklower struct socket *so; 45736392Ssklower int cmd; /* ioctl to process */ 45836392Ssklower caddr_t data; /* data for the cmd */ 45936392Ssklower { 46036392Ssklower register struct systype_req *rq = (struct systype_req *)data; 46136392Ssklower 46243334Ssklower IFDEBUG(D_IOCTL) 46336392Ssklower if (cmd == SIOCSSTYPE) 46443071Ssklower printf("snpac_ioctl: cmd set, type x%x, ht %d, ct %d\n", 46536392Ssklower rq->sr_type, rq->sr_holdt, rq->sr_configt); 46636392Ssklower else 46743071Ssklower printf("snpac_ioctl: cmd get\n"); 46836392Ssklower ENDDEBUG 46936392Ssklower 47036392Ssklower if (cmd == SIOCSSTYPE) { 47150230Ssklower if ((so->so_state & SS_PRIV) == 0) 47250230Ssklower return (EPERM); 47336392Ssklower if ((rq->sr_type & (SNPA_ES|SNPA_IS)) == (SNPA_ES|SNPA_IS)) 47436392Ssklower return(EINVAL); 47536392Ssklower if (rq->sr_type & SNPA_ES) { 47636392Ssklower iso_systype = SNPA_ES; 47736392Ssklower } else if (rq->sr_type & SNPA_IS) { 47836392Ssklower iso_systype = SNPA_IS; 47936392Ssklower } else { 48036392Ssklower return(EINVAL); 48136392Ssklower } 48236392Ssklower esis_holding_time = rq->sr_holdt; 48336392Ssklower esis_config_time = rq->sr_configt; 48443423Ssklower if (esis_esconfig_time != rq->sr_esconfigt) { 48543423Ssklower untimeout(esis_config, (caddr_t)0); 48643423Ssklower esis_esconfig_time = rq->sr_esconfigt; 48743423Ssklower esis_config(); 48843423Ssklower } 48936392Ssklower } else if (cmd == SIOCGSTYPE) { 49036392Ssklower rq->sr_type = iso_systype; 49136392Ssklower rq->sr_holdt = esis_holding_time; 49236392Ssklower rq->sr_configt = esis_config_time; 49343423Ssklower rq->sr_esconfigt = esis_esconfig_time; 49436392Ssklower } else { 49543071Ssklower return (EINVAL); 49636392Ssklower } 49743071Ssklower return (0); 49836392Ssklower } 49936392Ssklower 50036392Ssklower /* 50136392Ssklower * FUNCTION: snpac_logdefis 50236392Ssklower * 50336392Ssklower * PURPOSE: Mark the IS passed as the default IS 50436392Ssklower * 50536392Ssklower * RETURNS: nothing 50636392Ssklower * 50736392Ssklower * SIDE EFFECTS: 50836392Ssklower * 50936392Ssklower * NOTES: 51036392Ssklower */ 51136392Ssklower snpac_logdefis(sc) 51243071Ssklower register struct rtentry *sc; 51336392Ssklower { 51437469Ssklower register struct iso_addr *r; 51543071Ssklower register struct sockaddr_dl *sdl = (struct sockaddr_dl *)sc->rt_gateway; 51653691Ssklower register struct rtentry *rt; 51743071Ssklower 51853691Ssklower if (known_is == sc || !(sc->rt_flags & RTF_HOST)) 51937469Ssklower return; 52053691Ssklower if (known_is) { 52153691Ssklower RTFREE(known_is); 52237469Ssklower } 52353691Ssklower known_is = sc; 52453691Ssklower sc->rt_refcnt++; 52553691Ssklower rt = rtalloc1((struct sockaddr *)&zsi, 0); 52653691Ssklower if (rt == 0) 52753691Ssklower rtrequest(RTM_ADD, S(zsi), rt_key(sc), S(zmk), 52853691Ssklower RTF_DYNAMIC|RTF_GATEWAY, 0); 52953691Ssklower else { 53053691Ssklower if ((rt->rt_flags & RTF_DYNAMIC) && 53153691Ssklower (rt->rt_flags & RTF_GATEWAY) && rt_mask(rt)->sa_len == 0) 53253691Ssklower rt_setgate(rt, rt_key(rt), rt_key(sc)); 53337469Ssklower } 53436392Ssklower } 53536392Ssklower 53636392Ssklower /* 53736392Ssklower * FUNCTION: snpac_age 53836392Ssklower * 53936392Ssklower * PURPOSE: Time out snpac entries 54036392Ssklower * 54136392Ssklower * RETURNS: 54236392Ssklower * 54336392Ssklower * SIDE EFFECTS: 54436392Ssklower * 54536392Ssklower * NOTES: When encountering an entry for the first time, snpac_age 54636392Ssklower * may delete up to SNPAC_AGE too many seconds. Ie. 54736392Ssklower * if the entry is added a moment before snpac_age is 54836392Ssklower * called, the entry will immediately have SNPAC_AGE 54936392Ssklower * seconds taken off the holding time, even though 55036392Ssklower * it has only been held a brief moment. 55136392Ssklower * 55236392Ssklower * The proper way to do this is set an expiry timeval 55336392Ssklower * equal to current time + holding time. Then snpac_age 55436392Ssklower * would time out entries where expiry date is older 55536392Ssklower * than the current time. 55636392Ssklower */ 55736392Ssklower snpac_age() 55836392Ssklower { 55950230Ssklower register struct llinfo_llc *lc, *nlc; 56050230Ssklower register struct rtentry *rt; 56136392Ssklower 56236392Ssklower timeout(snpac_age, (caddr_t)0, SNPAC_AGE * hz); 56336392Ssklower 56450230Ssklower for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = nlc) { 56550230Ssklower nlc = lc->lc_next; 56653691Ssklower if (lc->lc_flags & SNPA_VALID) { 56750230Ssklower rt = lc->lc_rt; 56850230Ssklower if (rt->rt_rmx.rmx_expire && rt->rt_rmx.rmx_expire < time.tv_sec) 56950230Ssklower snpac_free(lc); 57036392Ssklower } 57136392Ssklower } 57236392Ssklower } 57336392Ssklower 57436392Ssklower /* 57536392Ssklower * FUNCTION: snpac_ownmulti 57636392Ssklower * 57736392Ssklower * PURPOSE: Determine if the snpa address is a multicast address 57836392Ssklower * of the same type as the system. 57936392Ssklower * 58036392Ssklower * RETURNS: true or false 58136392Ssklower * 58236392Ssklower * SIDE EFFECTS: 58336392Ssklower * 58436392Ssklower * NOTES: Used by interface drivers when not in eavesdrop mode 58536392Ssklower * as interm kludge until 58636392Ssklower * real multicast addresses can be configured 58736392Ssklower */ 58836392Ssklower snpac_ownmulti(snpa, len) 58943071Ssklower caddr_t snpa; 59043071Ssklower u_int len; 59136392Ssklower { 59237469Ssklower return (((iso_systype & SNPA_ES) && 59343071Ssklower (!bcmp(snpa, (caddr_t)all_es_snpa, len))) || 59437469Ssklower ((iso_systype & SNPA_IS) && 59543071Ssklower (!bcmp(snpa, (caddr_t)all_is_snpa, len)))); 59636392Ssklower } 59736392Ssklower 59836392Ssklower /* 59936392Ssklower * FUNCTION: snpac_flushifp 60036392Ssklower * 60136392Ssklower * PURPOSE: Flush entries associated with specific ifp 60236392Ssklower * 60336392Ssklower * RETURNS: nothing 60436392Ssklower * 60536392Ssklower * SIDE EFFECTS: 60636392Ssklower * 60736392Ssklower * NOTES: 60836392Ssklower */ 60936392Ssklower snpac_flushifp(ifp) 61036392Ssklower struct ifnet *ifp; 61136392Ssklower { 61243071Ssklower register struct llinfo_llc *lc; 61336392Ssklower 61443071Ssklower for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = lc->lc_next) { 61543071Ssklower if (lc->lc_rt->rt_ifp == ifp && (lc->lc_flags & SNPA_VALID)) 61643071Ssklower snpac_free(lc); 61736392Ssklower } 61836392Ssklower } 61936392Ssklower 62036392Ssklower /* 62136392Ssklower * FUNCTION: snpac_rtrequest 62236392Ssklower * 62336392Ssklower * PURPOSE: Make a routing request 62436392Ssklower * 62536392Ssklower * RETURNS: nothing 62636392Ssklower * 62736392Ssklower * SIDE EFFECTS: 62836392Ssklower * 62936392Ssklower * NOTES: In the future, this should make a request of a user 63036392Ssklower * level routing daemon. 63136392Ssklower */ 63237469Ssklower snpac_rtrequest(req, host, gateway, netmask, flags, ret_nrt) 63336392Ssklower int req; 63437469Ssklower struct iso_addr *host; 63536392Ssklower struct iso_addr *gateway; 63637469Ssklower struct iso_addr *netmask; 63736392Ssklower short flags; 63837469Ssklower struct rtentry **ret_nrt; 63936392Ssklower { 64037469Ssklower register struct iso_addr *r; 64136392Ssklower 64236392Ssklower IFDEBUG(D_SNPA) 64336392Ssklower printf("snpac_rtrequest: "); 64437469Ssklower if (req == RTM_ADD) 64536392Ssklower printf("add"); 64637469Ssklower else if (req == RTM_DELETE) 64736392Ssklower printf("delete"); 64836392Ssklower else 64936392Ssklower printf("unknown command"); 65037469Ssklower printf(" dst: %s\n", clnp_iso_addrp(host)); 65136392Ssklower printf("\tgateway: %s\n", clnp_iso_addrp(gateway)); 65236392Ssklower ENDDEBUG 65336392Ssklower 65436392Ssklower 65537469Ssklower zap_isoaddr(dst, host); 65637469Ssklower zap_isoaddr(gte, gateway); 65743334Ssklower if (netmask) { 65843334Ssklower zap_isoaddr(msk, netmask); 65943334Ssklower msk.siso_nlen = 0; 66043334Ssklower msk.siso_len = msk.siso_pad - (u_char *)&msk; 66143334Ssklower } 66237469Ssklower 66337469Ssklower rtrequest(req, S(dst), S(gte), (netmask ? S(msk) : (struct sockaddr *)0), 66437469Ssklower flags, ret_nrt); 66536392Ssklower } 66636392Ssklower 66736392Ssklower /* 66836392Ssklower * FUNCTION: snpac_addrt 66936392Ssklower * 67036392Ssklower * PURPOSE: Associate a routing entry with an snpac entry 67136392Ssklower * 67236392Ssklower * RETURNS: nothing 67336392Ssklower * 67436392Ssklower * SIDE EFFECTS: 67536392Ssklower * 67636392Ssklower * NOTES: If a cache entry exists for gateway, then 67736392Ssklower * make a routing entry (host, gateway) and associate 67836392Ssklower * with gateway. 67936392Ssklower * 68036392Ssklower * If a route already exists and is different, first delete 68136392Ssklower * it. 68236392Ssklower * 68336392Ssklower * This could be made more efficient by checking 68436392Ssklower * the existing route before adding a new one. 68536392Ssklower */ 68639950Ssklower snpac_addrt(ifp, host, gateway, netmask) 68739950Ssklower struct ifnet *ifp; 68839950Ssklower struct iso_addr *host, *gateway, *netmask; 68936392Ssklower { 69037469Ssklower register struct iso_addr *r; 69136392Ssklower 69243071Ssklower zap_isoaddr(dst, host); 69343071Ssklower zap_isoaddr(gte, gateway); 69443071Ssklower if (netmask) { 69543334Ssklower zap_isoaddr(msk, netmask); 69643334Ssklower msk.siso_nlen = 0; 69743334Ssklower msk.siso_len = msk.siso_pad - (u_char *)&msk; 69843071Ssklower rtredirect(S(dst), S(gte), S(msk), RTF_DONE, S(gte), 0); 69943071Ssklower } else 70043071Ssklower rtredirect(S(dst), S(gte), (struct sockaddr *)0, 70143071Ssklower RTF_DONE | RTF_HOST, S(gte), 0); 70236392Ssklower } 70336392Ssklower #endif ISO 704