149268Sbostic /*- 263222Sbostic * Copyright (c) 1991, 1993 363222Sbostic * The Regents of the University of California. All rights reserved. 449268Sbostic * 549268Sbostic * %sccs.include.redist.c% 649268Sbostic * 7*68261Scgd * @(#)iso_snpac.c 8.3 (Berkeley) 02/09/95 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); 155*68261Scgd rt_setgate(rt, rt_key(rt), 156*68261Scgd (struct sockaddr *)&blank_dl); 15750231Ssklower return; 15843071Ssklower } 15950231Ssklower if (lc != 0) 16050231Ssklower return; /* happens on a route change */ 16143334Ssklower /* FALLTHROUGH */ 16243334Ssklower case RTM_RESOLVE: 16343334Ssklower /* 16443334Ssklower * Case 2: This route may come from cloning, or a manual route 16543334Ssklower * add with a LL address. 16643334Ssklower */ 16743334Ssklower if (gate->sdl.sdl_family != AF_LINK) { 16847274Ssklower log(LOG_DEBUG, "llc_rtrequest: got non-link non-gateway route\n"); 16948732Ssklower break; 17043334Ssklower } 17143334Ssklower R_Malloc(lc, struct llinfo_llc *, sizeof (*lc)); 17243334Ssklower rt->rt_llinfo = (caddr_t)lc; 17343334Ssklower if (lc == 0) { 17447274Ssklower log(LOG_DEBUG, "llc_rtrequest: malloc failed\n"); 17548732Ssklower break; 17643334Ssklower } 17743334Ssklower Bzero(lc, sizeof(*lc)); 17843334Ssklower lc->lc_rt = rt; 17943334Ssklower rt->rt_flags |= RTF_LLINFO; 18043334Ssklower insque(lc, &llinfo_llc); 18143334Ssklower if (gate->sdl.sdl_alen == sizeof(struct esis_req) + addrlen) { 18243334Ssklower gate->sdl.sdl_alen -= sizeof(struct esis_req); 18343334Ssklower bcopy(addrlen + LLADDR(&gate->sdl), 18443334Ssklower (caddr_t)&lc->lc_er, sizeof(lc->lc_er)); 18543334Ssklower } else if (gate->sdl.sdl_alen == addrlen) 18643334Ssklower lc->lc_flags = (SNPA_ES | SNPA_VALID | SNPA_PERM); 18743071Ssklower break; 18843071Ssklower case RTM_DELETE: 18954717Ssklower if (rt->rt_flags & RTF_CLONING) 19054717Ssklower iso_setmcasts(ifp, req); 19154717Ssklower if (lc == 0) 19243334Ssklower return; 19343334Ssklower remque(lc); 19443334Ssklower Free(lc); 19543334Ssklower rt->rt_llinfo = 0; 19643334Ssklower rt->rt_flags &= ~RTF_LLINFO; 19743071Ssklower break; 19843071Ssklower } 19948732Ssklower if (rt->rt_rmx.rmx_mtu == 0) { 20048732Ssklower rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu - LLC_SIZE; 20148732Ssklower } 20243071Ssklower } 20343071Ssklower /* 20454717Ssklower * FUNCTION: iso_setmcasts 20554717Ssklower * 20654717Ssklower * PURPOSE: Enable/Disable ESIS/ISIS multicast reception on interfaces. 20754717Ssklower * 20854717Ssklower * NOTES: This also does a lot of obscure magic; 20954717Ssklower */ 21054717Ssklower iso_setmcasts(ifp, req) 21154717Ssklower struct ifnet *ifp; 21254717Ssklower int req; 21354717Ssklower { 21454717Ssklower static char *addrlist[] = 21554717Ssklower { all_es_snpa, all_is_snpa, all_l1is_snpa, all_l2is_snpa, 0}; 21654717Ssklower struct ifreq ifr; 21754717Ssklower register caddr_t *cpp; 21854717Ssklower int doreset = 0; 21954717Ssklower 22054717Ssklower bzero((caddr_t)&ifr, sizeof(ifr)); 22155903Ssklower for (cpp = (caddr_t *)addrlist; *cpp; cpp++) { 22254717Ssklower bcopy(*cpp, (caddr_t)ifr.ifr_addr.sa_data, 6); 22354717Ssklower if (req == RTM_ADD) 22454717Ssklower if (ether_addmulti(&ifr, (struct arpcom *)ifp) == ENETRESET) 22554717Ssklower doreset++; 22654717Ssklower else 22757952Ssklower if (ether_delmulti(&ifr, (struct arpcom *)ifp) == ENETRESET) 22854717Ssklower doreset++; 22954717Ssklower } 23057952Ssklower if (doreset) { 23157952Ssklower if (ifp->if_reset) 23257952Ssklower (*ifp->if_reset)(ifp->if_unit); 23357952Ssklower else 23457952Ssklower printf("iso_setmcasts: %s%d needs reseting to receive iso mcasts\n", 23557952Ssklower ifp->if_name, ifp->if_unit); 23657952Ssklower } 23754717Ssklower } 23854717Ssklower /* 23936392Ssklower * FUNCTION: iso_snparesolve 24036392Ssklower * 24136392Ssklower * PURPOSE: Resolve an iso address into snpa address 24236392Ssklower * 24336392Ssklower * RETURNS: 0 if addr is resolved 24436392Ssklower * errno if addr is unknown 24536392Ssklower * 24636392Ssklower * SIDE EFFECTS: 24736392Ssklower * 24843071Ssklower * NOTES: Now that we have folded the snpa cache into the routing 24943071Ssklower * table, we know there is no snpa address known for this 25043071Ssklower * destination. If we know of a default IS, then the address 25143071Ssklower * of the IS is returned. If no IS is known, then return the 25243071Ssklower * multi-cast address for "all ES" for this interface. 25336392Ssklower * 25436392Ssklower * NB: the last case described above constitutes the 25536392Ssklower * query configuration function 9542, sec 6.5 25636392Ssklower * A mechanism is needed to prevent this function from 25736392Ssklower * being invoked if the system is an IS. 25836392Ssklower */ 25937469Ssklower iso_snparesolve(ifp, dest, snpa, snpa_len) 26043071Ssklower struct ifnet *ifp; /* outgoing interface */ 26143071Ssklower struct sockaddr_iso *dest; /* destination */ 26243071Ssklower caddr_t snpa; /* RESULT: snpa to be used */ 26343071Ssklower int *snpa_len; /* RESULT: length of snpa */ 26436392Ssklower { 26543071Ssklower struct llinfo_llc *sc; /* ptr to snpa table entry */ 26643071Ssklower caddr_t found_snpa; 26743071Ssklower int addrlen; 26836392Ssklower 26936392Ssklower /* 27036392Ssklower * This hack allows us to send esis packets that have the destination snpa 27136392Ssklower * addresss embedded in the destination nsap address 27236392Ssklower */ 27343071Ssklower if (dest->siso_data[0] == AFI_SNA) { 27436392Ssklower /* 27536392Ssklower * This is a subnetwork address. Return it immediately 27636392Ssklower */ 27736392Ssklower IFDEBUG(D_SNPA) 27836392Ssklower printf("iso_snparesolve: return SN address\n"); 27936392Ssklower ENDDEBUG 28043071Ssklower addrlen = dest->siso_nlen - 1; /* subtract size of AFI */ 28143071Ssklower found_snpa = (caddr_t) dest->siso_data + 1; 28236392Ssklower /* 28343071Ssklower * If we are an IS, we can't do much with the packet; 28443071Ssklower * Check if we know about an IS. 28536392Ssklower */ 28643071Ssklower } else if (iso_systype != SNPA_IS && known_is != 0 && 28743071Ssklower (sc = (struct llinfo_llc *)known_is->rt_llinfo) && 28843071Ssklower (sc->lc_flags & SNPA_VALID)) { 28943071Ssklower register struct sockaddr_dl *sdl = 29043071Ssklower (struct sockaddr_dl *)(known_is->rt_gateway); 29143071Ssklower found_snpa = LLADDR(sdl); 29243071Ssklower addrlen = sdl->sdl_alen; 29343071Ssklower } else if (ifp->if_flags & IFF_BROADCAST) { 29443071Ssklower /* 29543071Ssklower * no IS, no match. Return "all es" multicast address for this 29643071Ssklower * interface, as per Query Configuration Function (9542 sec 6.5) 29743071Ssklower * 29843071Ssklower * Note: there is a potential problem here. If the destination 29943071Ssklower * is on the subnet and it does not respond with a ESH, but 30043071Ssklower * does send back a TP CC, a connection could be established 30143071Ssklower * where we always transmit the CLNP packet to "all es" 30236392Ssklower */ 30343071Ssklower addrlen = ifp->if_addrlen; 30443071Ssklower found_snpa = (caddr_t)all_es_snpa; 30543071Ssklower } else 30643071Ssklower return (ENETUNREACH); 30743071Ssklower bcopy(found_snpa, snpa, *snpa_len = addrlen); 30836392Ssklower return (0); 30936392Ssklower } 31036392Ssklower 31136392Ssklower 31236392Ssklower /* 31336392Ssklower * FUNCTION: snpac_free 31436392Ssklower * 31536392Ssklower * PURPOSE: free an entry in the iso address map table 31636392Ssklower * 31736392Ssklower * RETURNS: nothing 31836392Ssklower * 31936392Ssklower * SIDE EFFECTS: 32036392Ssklower * 32136392Ssklower * NOTES: If there is a route entry associated with cache 32236392Ssklower * entry, then delete that as well 32336392Ssklower */ 32443071Ssklower snpac_free(lc) 32543071Ssklower register struct llinfo_llc *lc; /* entry to free */ 32636392Ssklower { 32743071Ssklower register struct rtentry *rt = lc->lc_rt; 32837469Ssklower register struct iso_addr *r; 32936392Ssklower 33043071Ssklower if (known_is == rt) 33143071Ssklower known_is = 0; 33243071Ssklower if (rt && (rt->rt_flags & RTF_UP) && 33343071Ssklower (rt->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED))) { 33437469Ssklower RTFREE(rt); 33537469Ssklower rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt), 33637469Ssklower rt->rt_flags, (struct rtentry **)0); 33737469Ssklower RTFREE(rt); 33836392Ssklower } 33936392Ssklower } 34036392Ssklower 34136392Ssklower /* 34236392Ssklower * FUNCTION: snpac_add 34336392Ssklower * 34436392Ssklower * PURPOSE: Add an entry to the snpa cache 34536392Ssklower * 34636392Ssklower * RETURNS: 34736392Ssklower * 34836392Ssklower * SIDE EFFECTS: 34936392Ssklower * 35036392Ssklower * NOTES: If entry already exists, then update holding time. 35136392Ssklower */ 35243334Ssklower snpac_add(ifp, nsap, snpa, type, ht, nsellength) 35336392Ssklower struct ifnet *ifp; /* interface info is related to */ 35436392Ssklower struct iso_addr *nsap; /* nsap to add */ 35536392Ssklower caddr_t snpa; /* translation */ 35636392Ssklower char type; /* SNPA_IS or SNPA_ES */ 35737469Ssklower u_short ht; /* holding time (in seconds) */ 35843334Ssklower int nsellength; /* nsaps may differ only in trailing bytes */ 35936392Ssklower { 36043071Ssklower register struct llinfo_llc *lc; 36143334Ssklower register struct rtentry *rt; 36243334Ssklower struct rtentry *mrt = 0; 36343071Ssklower register struct iso_addr *r; /* for zap_isoaddr macro */ 36443071Ssklower int snpalen = min(ifp->if_addrlen, MAX_SNPALEN); 36552625Ssklower int new_entry = 0, index = ifp->if_index, iftype = ifp->if_type; 36636392Ssklower 36743334Ssklower IFDEBUG(D_SNPA) 36843334Ssklower printf("snpac_add(%x, %x, %x, %x, %x, %x)\n", 36943334Ssklower ifp, nsap, snpa, type, ht, nsellength); 37043334Ssklower ENDDEBUG 37143071Ssklower zap_isoaddr(dst, nsap); 37243071Ssklower rt = rtalloc1(S(dst), 0); 37343334Ssklower IFDEBUG(D_SNPA) 37443334Ssklower printf("snpac_add: rtalloc1 returns %x\n", rt); 37543334Ssklower ENDDEBUG 37643071Ssklower if (rt == 0) { 37743334Ssklower struct sockaddr *netmask; 37843334Ssklower int flags; 37943334Ssklower add: 38043334Ssklower if (nsellength) { 38143334Ssklower netmask = S(msk); flags = RTF_UP; 38243334Ssklower snpac_fixdstandmask(nsellength); 38343334Ssklower } else { 38443334Ssklower netmask = 0; flags = RTF_UP | RTF_HOST; 38543334Ssklower } 38643071Ssklower new_entry = 1; 38743071Ssklower zap_linkaddr((>e_dl), snpa, snpalen, index); 38852625Ssklower gte_dl.sdl_type = iftype; 38943334Ssklower if (rtrequest(RTM_ADD, S(dst), S(gte_dl), netmask, flags, &mrt) || 39043334Ssklower mrt == 0) 39143071Ssklower return (0); 39243334Ssklower rt = mrt; 39343334Ssklower rt->rt_refcnt--; 39443071Ssklower } else { 39543071Ssklower register struct sockaddr_dl *sdl = (struct sockaddr_dl *)rt->rt_gateway; 39643334Ssklower rt->rt_refcnt--; 39743334Ssklower if ((rt->rt_flags & RTF_LLINFO) == 0) 39843334Ssklower goto add; 39943334Ssklower if (nsellength && (rt->rt_flags & RTF_HOST)) { 40043334Ssklower if (rt->rt_refcnt == 0) { 40143334Ssklower rtrequest(RTM_DELETE, S(dst), (struct sockaddr *)0, 402*68261Scgd (struct sockaddr *)0, 0, (struct rtentry **)0); 40343334Ssklower rt = 0; 40443334Ssklower goto add; 40543334Ssklower } else { 40643334Ssklower static struct iso_addr nsap2; register char *cp; 40743334Ssklower nsap2 = *nsap; 40843334Ssklower cp = nsap2.isoa_genaddr + nsap->isoa_len - nsellength; 40943334Ssklower while (cp < (char *)(1 + &nsap2)) 41043334Ssklower *cp++ = 0; 41143334Ssklower (void) snpac_add(ifp, &nsap2, snpa, type, ht, nsellength); 41243334Ssklower } 41343334Ssklower } 41443071Ssklower if (sdl->sdl_family != AF_LINK || sdl->sdl_alen == 0) { 41543071Ssklower int old_sdl_len = sdl->sdl_len; 41643334Ssklower if (old_sdl_len < sizeof(*sdl)) { 41747274Ssklower log(LOG_DEBUG, "snpac_add: cant make room for lladdr\n"); 41843071Ssklower return (0); 41943334Ssklower } 42043071Ssklower zap_linkaddr(sdl, snpa, snpalen, index); 42143071Ssklower sdl->sdl_len = old_sdl_len; 42252625Ssklower sdl->sdl_type = iftype; 42343071Ssklower new_entry = 1; 42443071Ssklower } 42536392Ssklower } 42643334Ssklower if ((lc = (struct llinfo_llc *)rt->rt_llinfo) == 0) 42743334Ssklower panic("snpac_rtrequest"); 42850230Ssklower rt->rt_rmx.rmx_expire = ht + time.tv_sec; 42943071Ssklower lc->lc_flags = SNPA_VALID | type; 43053691Ssklower if ((type & SNPA_IS) && !(iso_systype & SNPA_IS)) 43143071Ssklower snpac_logdefis(rt); 43243334Ssklower return (new_entry); 43336392Ssklower } 43436392Ssklower 43550230Ssklower static void 43650230Ssklower snpac_fixdstandmask(nsellength) 43743334Ssklower { 43843334Ssklower register char *cp = msk.siso_data, *cplim; 43943334Ssklower 44043334Ssklower cplim = cp + (dst.siso_nlen -= nsellength); 44143334Ssklower msk.siso_len = cplim - (char *)&msk; 44243334Ssklower msk.siso_nlen = 0; 44343334Ssklower while (cp < cplim) 44443334Ssklower *cp++ = -1; 44543334Ssklower while (cp < (char *)msk.siso_pad) 44643334Ssklower *cp++ = 0; 44743334Ssklower for (cp = dst.siso_data + dst.siso_nlen; cp < (char *)dst.siso_pad; ) 44843334Ssklower *cp++ = 0; 44943334Ssklower } 45043334Ssklower 45136392Ssklower /* 45236392Ssklower * FUNCTION: snpac_ioctl 45336392Ssklower * 45436392Ssklower * PURPOSE: Set/Get the system type and esis parameters 45536392Ssklower * 45636392Ssklower * RETURNS: 0 on success, or unix error code 45736392Ssklower * 45836392Ssklower * SIDE EFFECTS: 45936392Ssklower * 46036392Ssklower * NOTES: 46136392Ssklower */ 46250230Ssklower snpac_ioctl (so, cmd, data) 46350230Ssklower struct socket *so; 46468165Scgd u_long cmd; /* ioctl to process */ 46536392Ssklower caddr_t data; /* data for the cmd */ 46636392Ssklower { 46736392Ssklower register struct systype_req *rq = (struct systype_req *)data; 46836392Ssklower 46943334Ssklower IFDEBUG(D_IOCTL) 47036392Ssklower if (cmd == SIOCSSTYPE) 47143071Ssklower printf("snpac_ioctl: cmd set, type x%x, ht %d, ct %d\n", 47236392Ssklower rq->sr_type, rq->sr_holdt, rq->sr_configt); 47336392Ssklower else 47443071Ssklower printf("snpac_ioctl: cmd get\n"); 47536392Ssklower ENDDEBUG 47636392Ssklower 47736392Ssklower if (cmd == SIOCSSTYPE) { 47850230Ssklower if ((so->so_state & SS_PRIV) == 0) 47950230Ssklower return (EPERM); 48036392Ssklower if ((rq->sr_type & (SNPA_ES|SNPA_IS)) == (SNPA_ES|SNPA_IS)) 48136392Ssklower return(EINVAL); 48236392Ssklower if (rq->sr_type & SNPA_ES) { 48336392Ssklower iso_systype = SNPA_ES; 48436392Ssklower } else if (rq->sr_type & SNPA_IS) { 48536392Ssklower iso_systype = SNPA_IS; 48636392Ssklower } else { 48736392Ssklower return(EINVAL); 48836392Ssklower } 48936392Ssklower esis_holding_time = rq->sr_holdt; 49036392Ssklower esis_config_time = rq->sr_configt; 49143423Ssklower if (esis_esconfig_time != rq->sr_esconfigt) { 49243423Ssklower untimeout(esis_config, (caddr_t)0); 49343423Ssklower esis_esconfig_time = rq->sr_esconfigt; 49443423Ssklower esis_config(); 49543423Ssklower } 49636392Ssklower } else if (cmd == SIOCGSTYPE) { 49736392Ssklower rq->sr_type = iso_systype; 49836392Ssklower rq->sr_holdt = esis_holding_time; 49936392Ssklower rq->sr_configt = esis_config_time; 50043423Ssklower rq->sr_esconfigt = esis_esconfig_time; 50136392Ssklower } else { 50243071Ssklower return (EINVAL); 50336392Ssklower } 50443071Ssklower return (0); 50536392Ssklower } 50636392Ssklower 50736392Ssklower /* 50836392Ssklower * FUNCTION: snpac_logdefis 50936392Ssklower * 51036392Ssklower * PURPOSE: Mark the IS passed as the default IS 51136392Ssklower * 51236392Ssklower * RETURNS: nothing 51336392Ssklower * 51436392Ssklower * SIDE EFFECTS: 51536392Ssklower * 51636392Ssklower * NOTES: 51736392Ssklower */ 51836392Ssklower snpac_logdefis(sc) 51943071Ssklower register struct rtentry *sc; 52036392Ssklower { 52137469Ssklower register struct iso_addr *r; 52243071Ssklower register struct sockaddr_dl *sdl = (struct sockaddr_dl *)sc->rt_gateway; 52353691Ssklower register struct rtentry *rt; 52443071Ssklower 52553691Ssklower if (known_is == sc || !(sc->rt_flags & RTF_HOST)) 52637469Ssklower return; 52753691Ssklower if (known_is) { 52853691Ssklower RTFREE(known_is); 52937469Ssklower } 53053691Ssklower known_is = sc; 53153691Ssklower sc->rt_refcnt++; 53253691Ssklower rt = rtalloc1((struct sockaddr *)&zsi, 0); 53353691Ssklower if (rt == 0) 53453691Ssklower rtrequest(RTM_ADD, S(zsi), rt_key(sc), S(zmk), 53553691Ssklower RTF_DYNAMIC|RTF_GATEWAY, 0); 53653691Ssklower else { 53753691Ssklower if ((rt->rt_flags & RTF_DYNAMIC) && 53853691Ssklower (rt->rt_flags & RTF_GATEWAY) && rt_mask(rt)->sa_len == 0) 53953691Ssklower rt_setgate(rt, rt_key(rt), rt_key(sc)); 54037469Ssklower } 54136392Ssklower } 54236392Ssklower 54336392Ssklower /* 54436392Ssklower * FUNCTION: snpac_age 54536392Ssklower * 54636392Ssklower * PURPOSE: Time out snpac entries 54736392Ssklower * 54836392Ssklower * RETURNS: 54936392Ssklower * 55036392Ssklower * SIDE EFFECTS: 55136392Ssklower * 55236392Ssklower * NOTES: When encountering an entry for the first time, snpac_age 55336392Ssklower * may delete up to SNPAC_AGE too many seconds. Ie. 55436392Ssklower * if the entry is added a moment before snpac_age is 55536392Ssklower * called, the entry will immediately have SNPAC_AGE 55636392Ssklower * seconds taken off the holding time, even though 55736392Ssklower * it has only been held a brief moment. 55836392Ssklower * 55936392Ssklower * The proper way to do this is set an expiry timeval 56036392Ssklower * equal to current time + holding time. Then snpac_age 56136392Ssklower * would time out entries where expiry date is older 56236392Ssklower * than the current time. 56336392Ssklower */ 56458990Ssklower void 56536392Ssklower snpac_age() 56636392Ssklower { 56750230Ssklower register struct llinfo_llc *lc, *nlc; 56850230Ssklower register struct rtentry *rt; 56936392Ssklower 57036392Ssklower timeout(snpac_age, (caddr_t)0, SNPAC_AGE * hz); 57136392Ssklower 57250230Ssklower for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = nlc) { 57350230Ssklower nlc = lc->lc_next; 57453691Ssklower if (lc->lc_flags & SNPA_VALID) { 57550230Ssklower rt = lc->lc_rt; 57650230Ssklower if (rt->rt_rmx.rmx_expire && rt->rt_rmx.rmx_expire < time.tv_sec) 57750230Ssklower snpac_free(lc); 57836392Ssklower } 57936392Ssklower } 58036392Ssklower } 58136392Ssklower 58236392Ssklower /* 58336392Ssklower * FUNCTION: snpac_ownmulti 58436392Ssklower * 58536392Ssklower * PURPOSE: Determine if the snpa address is a multicast address 58636392Ssklower * of the same type as the system. 58736392Ssklower * 58836392Ssklower * RETURNS: true or false 58936392Ssklower * 59036392Ssklower * SIDE EFFECTS: 59136392Ssklower * 59236392Ssklower * NOTES: Used by interface drivers when not in eavesdrop mode 59336392Ssklower * as interm kludge until 59436392Ssklower * real multicast addresses can be configured 59536392Ssklower */ 59636392Ssklower snpac_ownmulti(snpa, len) 59743071Ssklower caddr_t snpa; 59843071Ssklower u_int len; 59936392Ssklower { 60037469Ssklower return (((iso_systype & SNPA_ES) && 60143071Ssklower (!bcmp(snpa, (caddr_t)all_es_snpa, len))) || 60237469Ssklower ((iso_systype & SNPA_IS) && 60343071Ssklower (!bcmp(snpa, (caddr_t)all_is_snpa, len)))); 60436392Ssklower } 60536392Ssklower 60636392Ssklower /* 60736392Ssklower * FUNCTION: snpac_flushifp 60836392Ssklower * 60936392Ssklower * PURPOSE: Flush entries associated with specific ifp 61036392Ssklower * 61136392Ssklower * RETURNS: nothing 61236392Ssklower * 61336392Ssklower * SIDE EFFECTS: 61436392Ssklower * 61536392Ssklower * NOTES: 61636392Ssklower */ 61736392Ssklower snpac_flushifp(ifp) 61836392Ssklower struct ifnet *ifp; 61936392Ssklower { 62043071Ssklower register struct llinfo_llc *lc; 62136392Ssklower 62243071Ssklower for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = lc->lc_next) { 62343071Ssklower if (lc->lc_rt->rt_ifp == ifp && (lc->lc_flags & SNPA_VALID)) 62443071Ssklower snpac_free(lc); 62536392Ssklower } 62636392Ssklower } 62736392Ssklower 62836392Ssklower /* 62936392Ssklower * FUNCTION: snpac_rtrequest 63036392Ssklower * 63136392Ssklower * PURPOSE: Make a routing request 63236392Ssklower * 63336392Ssklower * RETURNS: nothing 63436392Ssklower * 63536392Ssklower * SIDE EFFECTS: 63636392Ssklower * 63736392Ssklower * NOTES: In the future, this should make a request of a user 63836392Ssklower * level routing daemon. 63936392Ssklower */ 64037469Ssklower snpac_rtrequest(req, host, gateway, netmask, flags, ret_nrt) 64136392Ssklower int req; 64237469Ssklower struct iso_addr *host; 64336392Ssklower struct iso_addr *gateway; 64437469Ssklower struct iso_addr *netmask; 64536392Ssklower short flags; 64637469Ssklower struct rtentry **ret_nrt; 64736392Ssklower { 64837469Ssklower register struct iso_addr *r; 64936392Ssklower 65036392Ssklower IFDEBUG(D_SNPA) 65136392Ssklower printf("snpac_rtrequest: "); 65237469Ssklower if (req == RTM_ADD) 65336392Ssklower printf("add"); 65437469Ssklower else if (req == RTM_DELETE) 65536392Ssklower printf("delete"); 65636392Ssklower else 65736392Ssklower printf("unknown command"); 65837469Ssklower printf(" dst: %s\n", clnp_iso_addrp(host)); 65936392Ssklower printf("\tgateway: %s\n", clnp_iso_addrp(gateway)); 66036392Ssklower ENDDEBUG 66136392Ssklower 66236392Ssklower 66337469Ssklower zap_isoaddr(dst, host); 66437469Ssklower zap_isoaddr(gte, gateway); 66543334Ssklower if (netmask) { 66643334Ssklower zap_isoaddr(msk, netmask); 66743334Ssklower msk.siso_nlen = 0; 66843334Ssklower msk.siso_len = msk.siso_pad - (u_char *)&msk; 66943334Ssklower } 67037469Ssklower 67137469Ssklower rtrequest(req, S(dst), S(gte), (netmask ? S(msk) : (struct sockaddr *)0), 67237469Ssklower flags, ret_nrt); 67336392Ssklower } 67436392Ssklower 67536392Ssklower /* 67636392Ssklower * FUNCTION: snpac_addrt 67736392Ssklower * 67836392Ssklower * PURPOSE: Associate a routing entry with an snpac entry 67936392Ssklower * 68036392Ssklower * RETURNS: nothing 68136392Ssklower * 68236392Ssklower * SIDE EFFECTS: 68336392Ssklower * 68436392Ssklower * NOTES: If a cache entry exists for gateway, then 68536392Ssklower * make a routing entry (host, gateway) and associate 68636392Ssklower * with gateway. 68736392Ssklower * 68836392Ssklower * If a route already exists and is different, first delete 68936392Ssklower * it. 69036392Ssklower * 69136392Ssklower * This could be made more efficient by checking 69236392Ssklower * the existing route before adding a new one. 69336392Ssklower */ 69439950Ssklower snpac_addrt(ifp, host, gateway, netmask) 69539950Ssklower struct ifnet *ifp; 69639950Ssklower struct iso_addr *host, *gateway, *netmask; 69736392Ssklower { 69837469Ssklower register struct iso_addr *r; 69936392Ssklower 70043071Ssklower zap_isoaddr(dst, host); 70143071Ssklower zap_isoaddr(gte, gateway); 70243071Ssklower if (netmask) { 70343334Ssklower zap_isoaddr(msk, netmask); 70443334Ssklower msk.siso_nlen = 0; 70543334Ssklower msk.siso_len = msk.siso_pad - (u_char *)&msk; 70643071Ssklower rtredirect(S(dst), S(gte), S(msk), RTF_DONE, S(gte), 0); 70743071Ssklower } else 70843071Ssklower rtredirect(S(dst), S(gte), (struct sockaddr *)0, 70943071Ssklower RTF_DONE | RTF_HOST, S(gte), 0); 71036392Ssklower } 71161288Ssklower #endif /* ISO */ 712