149268Sbostic /*- 249268Sbostic * Copyright (c) 1991 The Regents of the University of California. 349268Sbostic * All rights reserved. 449268Sbostic * 549268Sbostic * %sccs.include.redist.c% 649268Sbostic * 7*55903Ssklower * @(#)iso_snpac.c 7.20 (Berkeley) 08/14/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 4137469Ssklower #include "types.h" 4237469Ssklower #include "param.h" 4343071Ssklower #include "systm.h" 4437469Ssklower #include "mbuf.h" 4537469Ssklower #include "domain.h" 4637469Ssklower #include "protosw.h" 4737469Ssklower #include "socket.h" 4837469Ssklower #include "socketvar.h" 4937469Ssklower #include "errno.h" 5037469Ssklower #include "ioctl.h" 5147274Ssklower #include "syslog.h" 5236392Ssklower 5336392Ssklower #include "../net/if.h" 5443071Ssklower #include "../net/if_dl.h" 5536392Ssklower #include "../net/route.h" 5636392Ssklower 5737469Ssklower #include "iso.h" 5837469Ssklower #include "iso_var.h" 5937469Ssklower #include "iso_snpac.h" 6037469Ssklower #include "clnp.h" 6137469Ssklower #include "clnp_stat.h" 6238841Ssklower #include "esis.h" 6337469Ssklower #include "argo_debug.h" 6436392Ssklower 6536392Ssklower int iso_systype = SNPA_ES; /* default to be an ES */ 6643423Ssklower extern short esis_holding_time, esis_config_time, esis_esconfig_time; 6750230Ssklower extern struct timeval time; 6850230Ssklower extern int esis_config(), 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)); 220*55903Ssklower 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 22654717Ssklower if (ether_addmulti(&ifr, (struct arpcom *)ifp) == ENETRESET) 22754717Ssklower doreset++; 22854717Ssklower } 22954717Ssklower if (doreset) 23054717Ssklower (*ifp->if_reset)(ifp->if_unit); 23154717Ssklower } 23254717Ssklower /* 23336392Ssklower * FUNCTION: iso_snparesolve 23436392Ssklower * 23536392Ssklower * PURPOSE: Resolve an iso address into snpa address 23636392Ssklower * 23736392Ssklower * RETURNS: 0 if addr is resolved 23836392Ssklower * errno if addr is unknown 23936392Ssklower * 24036392Ssklower * SIDE EFFECTS: 24136392Ssklower * 24243071Ssklower * NOTES: Now that we have folded the snpa cache into the routing 24343071Ssklower * table, we know there is no snpa address known for this 24443071Ssklower * destination. If we know of a default IS, then the address 24543071Ssklower * of the IS is returned. If no IS is known, then return the 24643071Ssklower * multi-cast address for "all ES" for this interface. 24736392Ssklower * 24836392Ssklower * NB: the last case described above constitutes the 24936392Ssklower * query configuration function 9542, sec 6.5 25036392Ssklower * A mechanism is needed to prevent this function from 25136392Ssklower * being invoked if the system is an IS. 25236392Ssklower */ 25337469Ssklower iso_snparesolve(ifp, dest, snpa, snpa_len) 25443071Ssklower struct ifnet *ifp; /* outgoing interface */ 25543071Ssklower struct sockaddr_iso *dest; /* destination */ 25643071Ssklower caddr_t snpa; /* RESULT: snpa to be used */ 25743071Ssklower int *snpa_len; /* RESULT: length of snpa */ 25836392Ssklower { 25943071Ssklower struct llinfo_llc *sc; /* ptr to snpa table entry */ 26043071Ssklower caddr_t found_snpa; 26143071Ssklower int addrlen; 26236392Ssklower 26336392Ssklower /* 26436392Ssklower * This hack allows us to send esis packets that have the destination snpa 26536392Ssklower * addresss embedded in the destination nsap address 26636392Ssklower */ 26743071Ssklower if (dest->siso_data[0] == AFI_SNA) { 26836392Ssklower /* 26936392Ssklower * This is a subnetwork address. Return it immediately 27036392Ssklower */ 27136392Ssklower IFDEBUG(D_SNPA) 27236392Ssklower printf("iso_snparesolve: return SN address\n"); 27336392Ssklower ENDDEBUG 27443071Ssklower addrlen = dest->siso_nlen - 1; /* subtract size of AFI */ 27543071Ssklower found_snpa = (caddr_t) dest->siso_data + 1; 27636392Ssklower /* 27743071Ssklower * If we are an IS, we can't do much with the packet; 27843071Ssklower * Check if we know about an IS. 27936392Ssklower */ 28043071Ssklower } else if (iso_systype != SNPA_IS && known_is != 0 && 28143071Ssklower (sc = (struct llinfo_llc *)known_is->rt_llinfo) && 28243071Ssklower (sc->lc_flags & SNPA_VALID)) { 28343071Ssklower register struct sockaddr_dl *sdl = 28443071Ssklower (struct sockaddr_dl *)(known_is->rt_gateway); 28543071Ssklower found_snpa = LLADDR(sdl); 28643071Ssklower addrlen = sdl->sdl_alen; 28743071Ssklower } else if (ifp->if_flags & IFF_BROADCAST) { 28843071Ssklower /* 28943071Ssklower * no IS, no match. Return "all es" multicast address for this 29043071Ssklower * interface, as per Query Configuration Function (9542 sec 6.5) 29143071Ssklower * 29243071Ssklower * Note: there is a potential problem here. If the destination 29343071Ssklower * is on the subnet and it does not respond with a ESH, but 29443071Ssklower * does send back a TP CC, a connection could be established 29543071Ssklower * where we always transmit the CLNP packet to "all es" 29636392Ssklower */ 29743071Ssklower addrlen = ifp->if_addrlen; 29843071Ssklower found_snpa = (caddr_t)all_es_snpa; 29943071Ssklower } else 30043071Ssklower return (ENETUNREACH); 30143071Ssklower bcopy(found_snpa, snpa, *snpa_len = addrlen); 30236392Ssklower return (0); 30336392Ssklower } 30436392Ssklower 30536392Ssklower 30636392Ssklower /* 30736392Ssklower * FUNCTION: snpac_free 30836392Ssklower * 30936392Ssklower * PURPOSE: free an entry in the iso address map table 31036392Ssklower * 31136392Ssklower * RETURNS: nothing 31236392Ssklower * 31336392Ssklower * SIDE EFFECTS: 31436392Ssklower * 31536392Ssklower * NOTES: If there is a route entry associated with cache 31636392Ssklower * entry, then delete that as well 31736392Ssklower */ 31843071Ssklower snpac_free(lc) 31943071Ssklower register struct llinfo_llc *lc; /* entry to free */ 32036392Ssklower { 32143071Ssklower register struct rtentry *rt = lc->lc_rt; 32237469Ssklower register struct iso_addr *r; 32336392Ssklower 32443071Ssklower if (known_is == rt) 32543071Ssklower known_is = 0; 32643071Ssklower if (rt && (rt->rt_flags & RTF_UP) && 32743071Ssklower (rt->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED))) { 32837469Ssklower RTFREE(rt); 32937469Ssklower rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt), 33037469Ssklower rt->rt_flags, (struct rtentry **)0); 33137469Ssklower RTFREE(rt); 33236392Ssklower } 33336392Ssklower } 33436392Ssklower 33536392Ssklower /* 33636392Ssklower * FUNCTION: snpac_add 33736392Ssklower * 33836392Ssklower * PURPOSE: Add an entry to the snpa cache 33936392Ssklower * 34036392Ssklower * RETURNS: 34136392Ssklower * 34236392Ssklower * SIDE EFFECTS: 34336392Ssklower * 34436392Ssklower * NOTES: If entry already exists, then update holding time. 34536392Ssklower */ 34643334Ssklower snpac_add(ifp, nsap, snpa, type, ht, nsellength) 34736392Ssklower struct ifnet *ifp; /* interface info is related to */ 34836392Ssklower struct iso_addr *nsap; /* nsap to add */ 34936392Ssklower caddr_t snpa; /* translation */ 35036392Ssklower char type; /* SNPA_IS or SNPA_ES */ 35137469Ssklower u_short ht; /* holding time (in seconds) */ 35243334Ssklower int nsellength; /* nsaps may differ only in trailing bytes */ 35336392Ssklower { 35443071Ssklower register struct llinfo_llc *lc; 35543334Ssklower register struct rtentry *rt; 35643334Ssklower struct rtentry *mrt = 0; 35743071Ssklower register struct iso_addr *r; /* for zap_isoaddr macro */ 35843071Ssklower int snpalen = min(ifp->if_addrlen, MAX_SNPALEN); 35952625Ssklower int new_entry = 0, index = ifp->if_index, iftype = ifp->if_type; 36036392Ssklower 36143334Ssklower IFDEBUG(D_SNPA) 36243334Ssklower printf("snpac_add(%x, %x, %x, %x, %x, %x)\n", 36343334Ssklower ifp, nsap, snpa, type, ht, nsellength); 36443334Ssklower ENDDEBUG 36543071Ssklower zap_isoaddr(dst, nsap); 36643071Ssklower rt = rtalloc1(S(dst), 0); 36743334Ssklower IFDEBUG(D_SNPA) 36843334Ssklower printf("snpac_add: rtalloc1 returns %x\n", rt); 36943334Ssklower ENDDEBUG 37043071Ssklower if (rt == 0) { 37143334Ssklower struct sockaddr *netmask; 37243334Ssklower int flags; 37343334Ssklower add: 37443334Ssklower if (nsellength) { 37543334Ssklower netmask = S(msk); flags = RTF_UP; 37643334Ssklower snpac_fixdstandmask(nsellength); 37743334Ssklower } else { 37843334Ssklower netmask = 0; flags = RTF_UP | RTF_HOST; 37943334Ssklower } 38043071Ssklower new_entry = 1; 38143071Ssklower zap_linkaddr((>e_dl), snpa, snpalen, index); 38252625Ssklower gte_dl.sdl_type = iftype; 38343334Ssklower if (rtrequest(RTM_ADD, S(dst), S(gte_dl), netmask, flags, &mrt) || 38443334Ssklower mrt == 0) 38543071Ssklower return (0); 38643334Ssklower rt = mrt; 38743334Ssklower rt->rt_refcnt--; 38843071Ssklower } else { 38943071Ssklower register struct sockaddr_dl *sdl = (struct sockaddr_dl *)rt->rt_gateway; 39043334Ssklower rt->rt_refcnt--; 39143334Ssklower if ((rt->rt_flags & RTF_LLINFO) == 0) 39243334Ssklower goto add; 39343334Ssklower if (nsellength && (rt->rt_flags & RTF_HOST)) { 39443334Ssklower if (rt->rt_refcnt == 0) { 39543334Ssklower rtrequest(RTM_DELETE, S(dst), (struct sockaddr *)0, 39643334Ssklower (struct sockaddr *)0, 0, (struct rtentry *)0); 39743334Ssklower rt = 0; 39843334Ssklower goto add; 39943334Ssklower } else { 40043334Ssklower static struct iso_addr nsap2; register char *cp; 40143334Ssklower nsap2 = *nsap; 40243334Ssklower cp = nsap2.isoa_genaddr + nsap->isoa_len - nsellength; 40343334Ssklower while (cp < (char *)(1 + &nsap2)) 40443334Ssklower *cp++ = 0; 40543334Ssklower (void) snpac_add(ifp, &nsap2, snpa, type, ht, nsellength); 40643334Ssklower } 40743334Ssklower } 40843071Ssklower if (sdl->sdl_family != AF_LINK || sdl->sdl_alen == 0) { 40943071Ssklower int old_sdl_len = sdl->sdl_len; 41043334Ssklower if (old_sdl_len < sizeof(*sdl)) { 41147274Ssklower log(LOG_DEBUG, "snpac_add: cant make room for lladdr\n"); 41243071Ssklower return (0); 41343334Ssklower } 41443071Ssklower zap_linkaddr(sdl, snpa, snpalen, index); 41543071Ssklower sdl->sdl_len = old_sdl_len; 41652625Ssklower sdl->sdl_type = iftype; 41743071Ssklower new_entry = 1; 41843071Ssklower } 41936392Ssklower } 42043334Ssklower if ((lc = (struct llinfo_llc *)rt->rt_llinfo) == 0) 42143334Ssklower panic("snpac_rtrequest"); 42250230Ssklower rt->rt_rmx.rmx_expire = ht + time.tv_sec; 42343071Ssklower lc->lc_flags = SNPA_VALID | type; 42453691Ssklower if ((type & SNPA_IS) && !(iso_systype & SNPA_IS)) 42543071Ssklower snpac_logdefis(rt); 42643334Ssklower return (new_entry); 42736392Ssklower } 42836392Ssklower 42950230Ssklower static void 43050230Ssklower snpac_fixdstandmask(nsellength) 43143334Ssklower { 43243334Ssklower register char *cp = msk.siso_data, *cplim; 43343334Ssklower 43443334Ssklower cplim = cp + (dst.siso_nlen -= nsellength); 43543334Ssklower msk.siso_len = cplim - (char *)&msk; 43643334Ssklower msk.siso_nlen = 0; 43743334Ssklower while (cp < cplim) 43843334Ssklower *cp++ = -1; 43943334Ssklower while (cp < (char *)msk.siso_pad) 44043334Ssklower *cp++ = 0; 44143334Ssklower for (cp = dst.siso_data + dst.siso_nlen; cp < (char *)dst.siso_pad; ) 44243334Ssklower *cp++ = 0; 44343334Ssklower } 44443334Ssklower 44536392Ssklower /* 44636392Ssklower * FUNCTION: snpac_ioctl 44736392Ssklower * 44836392Ssklower * PURPOSE: Set/Get the system type and esis parameters 44936392Ssklower * 45036392Ssklower * RETURNS: 0 on success, or unix error code 45136392Ssklower * 45236392Ssklower * SIDE EFFECTS: 45336392Ssklower * 45436392Ssklower * NOTES: 45536392Ssklower */ 45650230Ssklower snpac_ioctl (so, cmd, data) 45750230Ssklower struct socket *so; 45836392Ssklower int cmd; /* ioctl to process */ 45936392Ssklower caddr_t data; /* data for the cmd */ 46036392Ssklower { 46136392Ssklower register struct systype_req *rq = (struct systype_req *)data; 46236392Ssklower 46343334Ssklower IFDEBUG(D_IOCTL) 46436392Ssklower if (cmd == SIOCSSTYPE) 46543071Ssklower printf("snpac_ioctl: cmd set, type x%x, ht %d, ct %d\n", 46636392Ssklower rq->sr_type, rq->sr_holdt, rq->sr_configt); 46736392Ssklower else 46843071Ssklower printf("snpac_ioctl: cmd get\n"); 46936392Ssklower ENDDEBUG 47036392Ssklower 47136392Ssklower if (cmd == SIOCSSTYPE) { 47250230Ssklower if ((so->so_state & SS_PRIV) == 0) 47350230Ssklower return (EPERM); 47436392Ssklower if ((rq->sr_type & (SNPA_ES|SNPA_IS)) == (SNPA_ES|SNPA_IS)) 47536392Ssklower return(EINVAL); 47636392Ssklower if (rq->sr_type & SNPA_ES) { 47736392Ssklower iso_systype = SNPA_ES; 47836392Ssklower } else if (rq->sr_type & SNPA_IS) { 47936392Ssklower iso_systype = SNPA_IS; 48036392Ssklower } else { 48136392Ssklower return(EINVAL); 48236392Ssklower } 48336392Ssklower esis_holding_time = rq->sr_holdt; 48436392Ssklower esis_config_time = rq->sr_configt; 48543423Ssklower if (esis_esconfig_time != rq->sr_esconfigt) { 48643423Ssklower untimeout(esis_config, (caddr_t)0); 48743423Ssklower esis_esconfig_time = rq->sr_esconfigt; 48843423Ssklower esis_config(); 48943423Ssklower } 49036392Ssklower } else if (cmd == SIOCGSTYPE) { 49136392Ssklower rq->sr_type = iso_systype; 49236392Ssklower rq->sr_holdt = esis_holding_time; 49336392Ssklower rq->sr_configt = esis_config_time; 49443423Ssklower rq->sr_esconfigt = esis_esconfig_time; 49536392Ssklower } else { 49643071Ssklower return (EINVAL); 49736392Ssklower } 49843071Ssklower return (0); 49936392Ssklower } 50036392Ssklower 50136392Ssklower /* 50236392Ssklower * FUNCTION: snpac_logdefis 50336392Ssklower * 50436392Ssklower * PURPOSE: Mark the IS passed as the default IS 50536392Ssklower * 50636392Ssklower * RETURNS: nothing 50736392Ssklower * 50836392Ssklower * SIDE EFFECTS: 50936392Ssklower * 51036392Ssklower * NOTES: 51136392Ssklower */ 51236392Ssklower snpac_logdefis(sc) 51343071Ssklower register struct rtentry *sc; 51436392Ssklower { 51537469Ssklower register struct iso_addr *r; 51643071Ssklower register struct sockaddr_dl *sdl = (struct sockaddr_dl *)sc->rt_gateway; 51753691Ssklower register struct rtentry *rt; 51843071Ssklower 51953691Ssklower if (known_is == sc || !(sc->rt_flags & RTF_HOST)) 52037469Ssklower return; 52153691Ssklower if (known_is) { 52253691Ssklower RTFREE(known_is); 52337469Ssklower } 52453691Ssklower known_is = sc; 52553691Ssklower sc->rt_refcnt++; 52653691Ssklower rt = rtalloc1((struct sockaddr *)&zsi, 0); 52753691Ssklower if (rt == 0) 52853691Ssklower rtrequest(RTM_ADD, S(zsi), rt_key(sc), S(zmk), 52953691Ssklower RTF_DYNAMIC|RTF_GATEWAY, 0); 53053691Ssklower else { 53153691Ssklower if ((rt->rt_flags & RTF_DYNAMIC) && 53253691Ssklower (rt->rt_flags & RTF_GATEWAY) && rt_mask(rt)->sa_len == 0) 53353691Ssklower rt_setgate(rt, rt_key(rt), rt_key(sc)); 53437469Ssklower } 53536392Ssklower } 53636392Ssklower 53736392Ssklower /* 53836392Ssklower * FUNCTION: snpac_age 53936392Ssklower * 54036392Ssklower * PURPOSE: Time out snpac entries 54136392Ssklower * 54236392Ssklower * RETURNS: 54336392Ssklower * 54436392Ssklower * SIDE EFFECTS: 54536392Ssklower * 54636392Ssklower * NOTES: When encountering an entry for the first time, snpac_age 54736392Ssklower * may delete up to SNPAC_AGE too many seconds. Ie. 54836392Ssklower * if the entry is added a moment before snpac_age is 54936392Ssklower * called, the entry will immediately have SNPAC_AGE 55036392Ssklower * seconds taken off the holding time, even though 55136392Ssklower * it has only been held a brief moment. 55236392Ssklower * 55336392Ssklower * The proper way to do this is set an expiry timeval 55436392Ssklower * equal to current time + holding time. Then snpac_age 55536392Ssklower * would time out entries where expiry date is older 55636392Ssklower * than the current time. 55736392Ssklower */ 55836392Ssklower snpac_age() 55936392Ssklower { 56050230Ssklower register struct llinfo_llc *lc, *nlc; 56150230Ssklower register struct rtentry *rt; 56236392Ssklower 56336392Ssklower timeout(snpac_age, (caddr_t)0, SNPAC_AGE * hz); 56436392Ssklower 56550230Ssklower for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = nlc) { 56650230Ssklower nlc = lc->lc_next; 56753691Ssklower if (lc->lc_flags & SNPA_VALID) { 56850230Ssklower rt = lc->lc_rt; 56950230Ssklower if (rt->rt_rmx.rmx_expire && rt->rt_rmx.rmx_expire < time.tv_sec) 57050230Ssklower snpac_free(lc); 57136392Ssklower } 57236392Ssklower } 57336392Ssklower } 57436392Ssklower 57536392Ssklower /* 57636392Ssklower * FUNCTION: snpac_ownmulti 57736392Ssklower * 57836392Ssklower * PURPOSE: Determine if the snpa address is a multicast address 57936392Ssklower * of the same type as the system. 58036392Ssklower * 58136392Ssklower * RETURNS: true or false 58236392Ssklower * 58336392Ssklower * SIDE EFFECTS: 58436392Ssklower * 58536392Ssklower * NOTES: Used by interface drivers when not in eavesdrop mode 58636392Ssklower * as interm kludge until 58736392Ssklower * real multicast addresses can be configured 58836392Ssklower */ 58936392Ssklower snpac_ownmulti(snpa, len) 59043071Ssklower caddr_t snpa; 59143071Ssklower u_int len; 59236392Ssklower { 59337469Ssklower return (((iso_systype & SNPA_ES) && 59443071Ssklower (!bcmp(snpa, (caddr_t)all_es_snpa, len))) || 59537469Ssklower ((iso_systype & SNPA_IS) && 59643071Ssklower (!bcmp(snpa, (caddr_t)all_is_snpa, len)))); 59736392Ssklower } 59836392Ssklower 59936392Ssklower /* 60036392Ssklower * FUNCTION: snpac_flushifp 60136392Ssklower * 60236392Ssklower * PURPOSE: Flush entries associated with specific ifp 60336392Ssklower * 60436392Ssklower * RETURNS: nothing 60536392Ssklower * 60636392Ssklower * SIDE EFFECTS: 60736392Ssklower * 60836392Ssklower * NOTES: 60936392Ssklower */ 61036392Ssklower snpac_flushifp(ifp) 61136392Ssklower struct ifnet *ifp; 61236392Ssklower { 61343071Ssklower register struct llinfo_llc *lc; 61436392Ssklower 61543071Ssklower for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = lc->lc_next) { 61643071Ssklower if (lc->lc_rt->rt_ifp == ifp && (lc->lc_flags & SNPA_VALID)) 61743071Ssklower snpac_free(lc); 61836392Ssklower } 61936392Ssklower } 62036392Ssklower 62136392Ssklower /* 62236392Ssklower * FUNCTION: snpac_rtrequest 62336392Ssklower * 62436392Ssklower * PURPOSE: Make a routing request 62536392Ssklower * 62636392Ssklower * RETURNS: nothing 62736392Ssklower * 62836392Ssklower * SIDE EFFECTS: 62936392Ssklower * 63036392Ssklower * NOTES: In the future, this should make a request of a user 63136392Ssklower * level routing daemon. 63236392Ssklower */ 63337469Ssklower snpac_rtrequest(req, host, gateway, netmask, flags, ret_nrt) 63436392Ssklower int req; 63537469Ssklower struct iso_addr *host; 63636392Ssklower struct iso_addr *gateway; 63737469Ssklower struct iso_addr *netmask; 63836392Ssklower short flags; 63937469Ssklower struct rtentry **ret_nrt; 64036392Ssklower { 64137469Ssklower register struct iso_addr *r; 64236392Ssklower 64336392Ssklower IFDEBUG(D_SNPA) 64436392Ssklower printf("snpac_rtrequest: "); 64537469Ssklower if (req == RTM_ADD) 64636392Ssklower printf("add"); 64737469Ssklower else if (req == RTM_DELETE) 64836392Ssklower printf("delete"); 64936392Ssklower else 65036392Ssklower printf("unknown command"); 65137469Ssklower printf(" dst: %s\n", clnp_iso_addrp(host)); 65236392Ssklower printf("\tgateway: %s\n", clnp_iso_addrp(gateway)); 65336392Ssklower ENDDEBUG 65436392Ssklower 65536392Ssklower 65637469Ssklower zap_isoaddr(dst, host); 65737469Ssklower zap_isoaddr(gte, gateway); 65843334Ssklower if (netmask) { 65943334Ssklower zap_isoaddr(msk, netmask); 66043334Ssklower msk.siso_nlen = 0; 66143334Ssklower msk.siso_len = msk.siso_pad - (u_char *)&msk; 66243334Ssklower } 66337469Ssklower 66437469Ssklower rtrequest(req, S(dst), S(gte), (netmask ? S(msk) : (struct sockaddr *)0), 66537469Ssklower flags, ret_nrt); 66636392Ssklower } 66736392Ssklower 66836392Ssklower /* 66936392Ssklower * FUNCTION: snpac_addrt 67036392Ssklower * 67136392Ssklower * PURPOSE: Associate a routing entry with an snpac entry 67236392Ssklower * 67336392Ssklower * RETURNS: nothing 67436392Ssklower * 67536392Ssklower * SIDE EFFECTS: 67636392Ssklower * 67736392Ssklower * NOTES: If a cache entry exists for gateway, then 67836392Ssklower * make a routing entry (host, gateway) and associate 67936392Ssklower * with gateway. 68036392Ssklower * 68136392Ssklower * If a route already exists and is different, first delete 68236392Ssklower * it. 68336392Ssklower * 68436392Ssklower * This could be made more efficient by checking 68536392Ssklower * the existing route before adding a new one. 68636392Ssklower */ 68739950Ssklower snpac_addrt(ifp, host, gateway, netmask) 68839950Ssklower struct ifnet *ifp; 68939950Ssklower struct iso_addr *host, *gateway, *netmask; 69036392Ssklower { 69137469Ssklower register struct iso_addr *r; 69236392Ssklower 69343071Ssklower zap_isoaddr(dst, host); 69443071Ssklower zap_isoaddr(gte, gateway); 69543071Ssklower if (netmask) { 69643334Ssklower zap_isoaddr(msk, netmask); 69743334Ssklower msk.siso_nlen = 0; 69843334Ssklower msk.siso_len = msk.siso_pad - (u_char *)&msk; 69943071Ssklower rtredirect(S(dst), S(gte), S(msk), RTF_DONE, S(gte), 0); 70043071Ssklower } else 70143071Ssklower rtredirect(S(dst), S(gte), (struct sockaddr *)0, 70243071Ssklower RTF_DONE | RTF_HOST, S(gte), 0); 70336392Ssklower } 70436392Ssklower #endif ISO 705