136379Ssklower /*********************************************************** 236379Ssklower Copyright IBM Corporation 1987 336379Ssklower 436379Ssklower All Rights Reserved 536379Ssklower 636379Ssklower Permission to use, copy, modify, and distribute this software and its 736379Ssklower documentation for any purpose and without fee is hereby granted, 836379Ssklower provided that the above copyright notice appear in all copies and that 936379Ssklower both that copyright notice and this permission notice appear in 1036379Ssklower supporting documentation, and that the name of IBM not be 1136379Ssklower used in advertising or publicity pertaining to distribution of the 1236379Ssklower software without specific, written prior permission. 1336379Ssklower 1436379Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 1536379Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 1636379Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 1736379Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 1836379Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 1936379Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 2036379Ssklower SOFTWARE. 2136379Ssklower 2236379Ssklower ******************************************************************/ 2336379Ssklower 2436379Ssklower /* 2536379Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 2636379Ssklower */ 27*43332Ssklower /* @(#)esis.c 7.8 (Berkeley) 06/20/90 */ 2836379Ssklower #ifndef lint 2936379Ssklower static char *rcsid = "$Header: esis.c,v 4.10 88/09/15 18:57:03 hagens Exp $"; 3036379Ssklower #endif 3136379Ssklower 3236379Ssklower #ifdef ISO 3336379Ssklower 3437469Ssklower #include "types.h" 3537469Ssklower #include "param.h" 3637469Ssklower #include "mbuf.h" 3737469Ssklower #include "domain.h" 3837469Ssklower #include "protosw.h" 3937469Ssklower #include "user.h" 4037469Ssklower #include "socket.h" 4137469Ssklower #include "socketvar.h" 4237469Ssklower #include "errno.h" 4337469Ssklower #include "kernel.h" 4436379Ssklower 4536379Ssklower #include "../net/if.h" 46*43332Ssklower #include "../net/if_dl.h" 4736379Ssklower #include "../net/route.h" 4836379Ssklower 4937469Ssklower #include "iso.h" 5037469Ssklower #include "iso_pcb.h" 5137469Ssklower #include "iso_var.h" 5237469Ssklower #include "iso_snpac.h" 5337469Ssklower #include "clnl.h" 5437469Ssklower #include "clnp.h" 5537469Ssklower #include "clnp_stat.h" 5638841Ssklower #include "esis.h" 5737469Ssklower #include "argo_debug.h" 5836379Ssklower 5936379Ssklower /* 6036379Ssklower * Global variables to esis implementation 6136379Ssklower * 6236379Ssklower * esis_holding_time - the holding time (sec) parameter for outgoing pdus 6336379Ssklower * esis_config_time - the frequency (sec) that hellos are generated 6436379Ssklower * 6536379Ssklower */ 6636379Ssklower struct isopcb esis_pcb; 6736379Ssklower int esis_sendspace = 2048; 6836379Ssklower int esis_recvspace = 2048; 6936379Ssklower short esis_holding_time = ESIS_HT; 7036379Ssklower short esis_config_time = ESIS_CONFIG; 7136379Ssklower extern int iso_systype; 72*43332Ssklower extern char all_es_snpa[], all_is_snpa[]; 7336379Ssklower 7437469Ssklower #define EXTEND_PACKET(m, mhdr, cp)\ 7536379Ssklower if (((m)->m_next = m_getclr(M_DONTWAIT, MT_HEADER)) == NULL) {\ 7636379Ssklower esis_stat.es_nomem++;\ 7736379Ssklower m_freem(mhdr);\ 7836379Ssklower return;\ 7936379Ssklower } else {\ 8036379Ssklower (m) = (m)->m_next;\ 8136379Ssklower (cp) = mtod((m), caddr_t);\ 8236379Ssklower } 8336379Ssklower /* 8436379Ssklower * FUNCTION: esis_init 8536379Ssklower * 8636379Ssklower * PURPOSE: Initialize the kernel portion of esis protocol 8736379Ssklower * 8836379Ssklower * RETURNS: nothing 8936379Ssklower * 9036379Ssklower * SIDE EFFECTS: 9136379Ssklower * 9236379Ssklower * NOTES: 9336379Ssklower */ 9436379Ssklower esis_init() 9536379Ssklower { 9636379Ssklower extern struct clnl_protosw clnl_protox[256]; 9736379Ssklower int esis_input(); 9836379Ssklower int snpac_age(); 9936379Ssklower int esis_config(); 10036379Ssklower #ifdef ISO_X25ESIS 10136379Ssklower x25esis_input(); 10236379Ssklower #endif ISO_X25ESIS 10336379Ssklower 10436379Ssklower esis_pcb.isop_next = esis_pcb.isop_prev = &esis_pcb; 10536379Ssklower 10636379Ssklower clnl_protox[ISO9542_ESIS].clnl_input = esis_input; 107*43332Ssklower llinfo_llc.lc_next = llinfo_llc.lc_prev = &llinfo_llc; 10836379Ssklower timeout(snpac_age, (caddr_t)0, hz); 10936379Ssklower timeout(esis_config, (caddr_t)0, hz); 11036379Ssklower 11136379Ssklower #ifdef ISO_X25ESIS 11236379Ssklower clnl_protox[ISO9542X25_ESIS].clnl_input = x25esis_input; 11336379Ssklower #endif ISO_X25ESIS 11436379Ssklower } 11536379Ssklower 11636379Ssklower /* 11736379Ssklower * FUNCTION: esis_usrreq 11836379Ssklower * 11936379Ssklower * PURPOSE: Handle user level esis requests 12036379Ssklower * 12136379Ssklower * RETURNS: 0 or appropriate errno 12236379Ssklower * 12336379Ssklower * SIDE EFFECTS: 12436379Ssklower * 12536379Ssklower * NOTES: This is here only so esis gets initialized. 12636379Ssklower */ 12737469Ssklower /*ARGSUSED*/ 12840775Ssklower esis_usrreq(so, req, m, nam, control) 12936379Ssklower struct socket *so; /* socket: used only to get to this code */ 13036379Ssklower int req; /* request */ 13136379Ssklower struct mbuf *m; /* data for request */ 13236379Ssklower struct mbuf *nam; /* optional name */ 13340775Ssklower struct mbuf *control; /* optional control */ 13436379Ssklower { 13536379Ssklower if (m != NULL) 13636379Ssklower m_freem(m); 13736379Ssklower 13836379Ssklower return(EOPNOTSUPP); 13936379Ssklower } 14036379Ssklower 14136379Ssklower /* 14236379Ssklower * FUNCTION: esis_input 14336379Ssklower * 14436379Ssklower * PURPOSE: Process an incoming esis packet 14536379Ssklower * 14636379Ssklower * RETURNS: nothing 14736379Ssklower * 14836379Ssklower * SIDE EFFECTS: 14936379Ssklower * 15036379Ssklower * NOTES: 15136379Ssklower */ 15236379Ssklower esis_input(m0, shp) 15336379Ssklower struct mbuf *m0; /* ptr to first mbuf of pkt */ 15436379Ssklower struct snpa_hdr *shp; /* subnetwork header */ 15536379Ssklower { 15636379Ssklower struct esis_fixed *pdu = mtod(m0, struct esis_fixed *); 15737469Ssklower register int type; 15836379Ssklower 15936379Ssklower IFDEBUG(D_ESISINPUT) 16036379Ssklower int i; 16136379Ssklower 16236379Ssklower printf("esis_input: pdu on ifp x%x (%s%d): from:", shp->snh_ifp, 16336379Ssklower shp->snh_ifp->if_name, shp->snh_ifp->if_unit); 16436379Ssklower for (i=0; i<6; i++) 16536379Ssklower printf("%x%c", shp->snh_shost[i]&0xff, (i<5) ? ':' : ' '); 16636379Ssklower printf(" to:"); 16736379Ssklower for (i=0; i<6; i++) 16836379Ssklower printf("%x%c", shp->snh_dhost[i]&0xff, (i<5) ? ':' : ' '); 16936379Ssklower printf("\n"); 17036379Ssklower ENDDEBUG 17136379Ssklower 17236379Ssklower /* 17336379Ssklower * check checksum if necessary 17436379Ssklower */ 17537469Ssklower if (ESIS_CKSUM_REQUIRED(pdu) && iso_check_csum(m0, (int)pdu->esis_hdr_len)) { 17636379Ssklower esis_stat.es_badcsum++; 17736379Ssklower goto bad; 17836379Ssklower } 17936379Ssklower 18036379Ssklower /* check version */ 18136379Ssklower if (pdu->esis_vers != ESIS_VERSION) { 18236379Ssklower esis_stat.es_badvers++; 18336379Ssklower goto bad; 18436379Ssklower } 18536379Ssklower 18637469Ssklower type = pdu->esis_type & 0x1f; 18737469Ssklower switch (type) { 18836379Ssklower case ESIS_ESH: 18936379Ssklower esis_eshinput(m0, shp); 19036379Ssklower return; 19136379Ssklower 19236379Ssklower case ESIS_ISH: 19336379Ssklower esis_ishinput(m0, shp); 19436379Ssklower return; 19536379Ssklower 19636379Ssklower case ESIS_RD: 19736379Ssklower esis_rdinput(m0, shp); 19836379Ssklower return; 19936379Ssklower 20036379Ssklower default: { 20136379Ssklower esis_stat.es_badtype++; 20236379Ssklower goto bad; 20336379Ssklower } 20436379Ssklower } 20536379Ssklower 20636379Ssklower bad: 20736379Ssklower m_freem(m0); 20836379Ssklower } 20936379Ssklower 21036379Ssklower /* 21136379Ssklower * FUNCTION: esis_rdoutput 21236379Ssklower * 21336379Ssklower * PURPOSE: Transmit a redirect pdu 21436379Ssklower * 21536379Ssklower * RETURNS: nothing 21636379Ssklower * 21736379Ssklower * SIDE EFFECTS: 21836379Ssklower * 21936379Ssklower * NOTES: Assumes there is enough space for fixed part of header, 22036379Ssklower * DA, BSNPA and NET in first mbuf. 22136379Ssklower */ 222*43332Ssklower esis_rdoutput(inbound_shp, inbound_m, inbound_oidx, rd_dstnsap, rt) 22336379Ssklower struct snpa_hdr *inbound_shp; /* snpa hdr from incoming packet */ 22436379Ssklower struct mbuf *inbound_m; /* incoming pkt itself */ 22536379Ssklower struct clnp_optidx *inbound_oidx; /* clnp options assoc with incoming pkt */ 22636379Ssklower struct iso_addr *rd_dstnsap; /* ultimate destination of pkt */ 227*43332Ssklower struct rtentry *rt; /* snpa cache info regarding next hop of 22836379Ssklower pkt */ 22936379Ssklower { 23036379Ssklower struct mbuf *m, *m0; 23136379Ssklower caddr_t cp; 23236379Ssklower struct esis_fixed *pdu; 23336379Ssklower int len, total_len = 0; 23436379Ssklower struct sockaddr_iso siso; 23536379Ssklower struct ifnet *ifp = inbound_shp->snh_ifp; 236*43332Ssklower struct sockaddr_dl *sdl; 237*43332Ssklower struct iso_addr *rd_gwnsap; 23836379Ssklower 239*43332Ssklower if (rt->rt_flags & RTF_GATEWAY) { 240*43332Ssklower rd_gwnsap = &((struct sockaddr_iso *)rt->rt_gateway)->siso_addr; 241*43332Ssklower rt = rtalloc1(rt->rt_gateway, 0); 242*43332Ssklower } else 243*43332Ssklower rd_gwnsap = &((struct sockaddr_iso *)rt_key(rt))->siso_addr; 244*43332Ssklower if (rt == 0 || (sdl = (struct sockaddr_dl *)rt->rt_gateway) == 0 || 245*43332Ssklower sdl->sdl_family != AF_LINK) { 246*43332Ssklower /* maybe we should have a function that you 247*43332Ssklower could put in the iso_ifaddr structure 248*43332Ssklower which could translate iso_addrs into snpa's 249*43332Ssklower where there is a known mapping for that address type */ 250*43332Ssklower esis_stat.es_badtype++; 251*43332Ssklower return; 252*43332Ssklower } 25336379Ssklower esis_stat.es_rdsent++; 25436379Ssklower IFDEBUG(D_ESISOUTPUT) 25536379Ssklower printf("esis_rdoutput: ifp x%x (%s%d), ht %d, m x%x, oidx x%x\n", 25636379Ssklower ifp, ifp->if_name, ifp->if_unit, esis_holding_time, inbound_m, 25736379Ssklower inbound_oidx); 25836379Ssklower printf("\tdestination: %s\n", clnp_iso_addrp(rd_dstnsap)); 259*43332Ssklower printf("\tredirected toward:%s\n", clnp_iso_addrp(rd_gwnsap)); 26036379Ssklower ENDDEBUG 26136379Ssklower 26237469Ssklower if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) { 26336379Ssklower esis_stat.es_nomem++; 26436379Ssklower return; 26536379Ssklower } 26637469Ssklower bzero(mtod(m, caddr_t), MHLEN); 26736379Ssklower 26836379Ssklower pdu = mtod(m, struct esis_fixed *); 26937469Ssklower cp = (caddr_t)(pdu + 1); /*pointer arith.; 1st byte after header */ 27036379Ssklower len = sizeof(struct esis_fixed); 27136379Ssklower 27236379Ssklower /* 27336379Ssklower * Build fixed part of header 27436379Ssklower */ 27536379Ssklower pdu->esis_proto_id = ISO9542_ESIS; 27636379Ssklower pdu->esis_vers = ESIS_VERSION; 27736379Ssklower pdu->esis_type = ESIS_RD; 27836379Ssklower HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, esis_holding_time); 27936379Ssklower 28036379Ssklower /* Insert destination address */ 28143072Ssklower (void) esis_insert_addr(&cp, &len, rd_dstnsap, m, 0); 28236379Ssklower 28336379Ssklower /* Insert the snpa of better next hop */ 284*43332Ssklower *cp++ = sdl->sdl_alen; 285*43332Ssklower bcopy(LLADDR(sdl), cp, sdl->sdl_alen); 286*43332Ssklower cp += sdl->sdl_alen; 287*43332Ssklower len += (sdl->sdl_alen + 1); 28836379Ssklower 28936379Ssklower /* 29036379Ssklower * If the next hop is not the destination, then it ought to be 29136379Ssklower * an IS and it should be inserted next. Else, set the 29236379Ssklower * NETL to 0 29336379Ssklower */ 29436379Ssklower /* PHASE2 use mask from ifp of outgoing interface */ 295*43332Ssklower if (!iso_addrmatch1(rd_dstnsap, rd_gwnsap)) { 296*43332Ssklower /* this should not happen: 29736379Ssklower if ((nhop_sc->sc_flags & SNPA_IS) == 0) { 29836379Ssklower printf("esis_rdoutput: next hop is not dst and not an IS\n"); 29936379Ssklower m_freem(m0); 30036379Ssklower return; 301*43332Ssklower } */ 302*43332Ssklower (void) esis_insert_addr(&cp, &len, rd_gwnsap, m, 0); 30336379Ssklower } else { 30436379Ssklower *cp++ = 0; /* NETL */ 30536379Ssklower len++; 30636379Ssklower } 30737469Ssklower m->m_len = len; 30836379Ssklower 30936379Ssklower /* 31036379Ssklower * PHASE2 31136379Ssklower * If redirect is to an IS, add an address mask. The mask to be 31236379Ssklower * used should be the mask present in the routing entry used to 31336379Ssklower * forward the original data packet. 31436379Ssklower */ 31536379Ssklower 31636379Ssklower /* 31736379Ssklower * Copy Qos, priority, or security options present in original npdu 31836379Ssklower */ 31936379Ssklower if (inbound_oidx) { 320*43332Ssklower /* THIS CODE IS CURRENTLY (mostly) UNTESTED */ 32136379Ssklower int optlen = 0; 32236379Ssklower if (inbound_oidx->cni_qos_formatp) 32336379Ssklower optlen += (inbound_oidx->cni_qos_len + 2); 32436379Ssklower if (inbound_oidx->cni_priorp) /* priority option is 1 byte long */ 32536379Ssklower optlen += 3; 32636379Ssklower if (inbound_oidx->cni_securep) 32736379Ssklower optlen += (inbound_oidx->cni_secure_len + 2); 32837469Ssklower if (M_TRAILINGSPACE(m) < optlen) { 32937469Ssklower EXTEND_PACKET(m, m0, cp); 33037469Ssklower m->m_len = 0; 33136379Ssklower /* assumes MLEN > optlen */ 33236379Ssklower } 33336379Ssklower /* assume MLEN-len > optlen */ 33436379Ssklower /* 33536379Ssklower * When copying options, copy from ptr - 2 in order to grab 33636379Ssklower * the option code and length 33736379Ssklower */ 33836379Ssklower if (inbound_oidx->cni_qos_formatp) { 339*43332Ssklower bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_qos_formatp - 2, 340*43332Ssklower cp, (unsigned)(inbound_oidx->cni_qos_len + 2)); 341*43332Ssklower cp += inbound_oidx->cni_qos_len + 2; 34236379Ssklower } 34336379Ssklower if (inbound_oidx->cni_priorp) { 344*43332Ssklower bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_priorp - 2, 345*43332Ssklower cp, 3); 346*43332Ssklower cp += 3; 34736379Ssklower } 34836379Ssklower if (inbound_oidx->cni_securep) { 349*43332Ssklower bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_securep - 2, cp, 35037469Ssklower (unsigned)(inbound_oidx->cni_secure_len + 2)); 351*43332Ssklower cp += inbound_oidx->cni_secure_len + 2; 35236379Ssklower } 35337469Ssklower m->m_len += optlen; 354*43332Ssklower len += optlen; 35536379Ssklower } 35636379Ssklower 35737469Ssklower pdu->esis_hdr_len = m0->m_pkthdr.len = len; 35836379Ssklower iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len); 35936379Ssklower 36037469Ssklower bzero((caddr_t)&siso, sizeof(siso)); 36137469Ssklower siso.siso_len = 12; 36236379Ssklower siso.siso_family = AF_ISO; 36337469Ssklower siso.siso_data[0] = AFI_SNA; 36437469Ssklower siso.siso_nlen = 6 + 1; /* should be taken from snpa_hdr */ 36536379Ssklower /* +1 is for AFI */ 36637469Ssklower bcopy(inbound_shp->snh_shost, siso.siso_data + 1, 6); 36740775Ssklower (ifp->if_output)(ifp, m0, &siso, 0); 36836379Ssklower } 36936379Ssklower 37036379Ssklower /* 37136379Ssklower * FUNCTION: esis_insert_addr 37236379Ssklower * 37336379Ssklower * PURPOSE: Insert an iso_addr into a buffer 37436379Ssklower * 37536379Ssklower * RETURNS: true if buffer was big enough, else false 37636379Ssklower * 37736379Ssklower * SIDE EFFECTS: Increment buf & len according to size of iso_addr 37836379Ssklower * 37936379Ssklower * NOTES: Plus 1 here is for length byte 38036379Ssklower */ 38143072Ssklower esis_insert_addr(buf, len, isoa, m, nsellen) 382*43332Ssklower register caddr_t *buf; /* ptr to buffer to put address into */ 383*43332Ssklower int *len; /* ptr to length of buffer so far */ 384*43332Ssklower register struct iso_addr *isoa; /* ptr to address */ 385*43332Ssklower register struct mbuf *m; /* determine if there remains space */ 386*43332Ssklower int nsellen; 38736379Ssklower { 388*43332Ssklower register int newlen, result = 0; 38936379Ssklower 390*43332Ssklower isoa->isoa_len -= nsellen; 391*43332Ssklower newlen = isoa->isoa_len + 1; 392*43332Ssklower if (newlen <= M_TRAILINGSPACE(m)) { 393*43332Ssklower bcopy((caddr_t)isoa, *buf, newlen); 394*43332Ssklower *len += newlen; 395*43332Ssklower *buf += newlen; 396*43332Ssklower m->m_len += newlen; 397*43332Ssklower result = 1; 398*43332Ssklower } 399*43332Ssklower isoa->isoa_len += nsellen; 400*43332Ssklower return (result); 40136379Ssklower } 40236379Ssklower 40339950Ssklower #define ESIS_EXTRACT_ADDR(d, b) { d = (struct iso_addr *)(b); b += (1 + *b); \ 40439950Ssklower if (b > buflim) {esis_stat.es_toosmall++; goto bad;}} 40539950Ssklower #define ESIS_NEXT_OPTION(b) { b += (2 + b[1]); \ 40639950Ssklower if (b > buflim) {esis_stat.es_toosmall++; goto bad;}} 40740775Ssklower int ESHonly = 1; 40836379Ssklower /* 40936379Ssklower 41036379Ssklower /* 41136379Ssklower * FUNCTION: esis_eshinput 41236379Ssklower * 41336379Ssklower * PURPOSE: Process an incoming ESH pdu 41436379Ssklower * 41536379Ssklower * RETURNS: nothing 41636379Ssklower * 41736379Ssklower * SIDE EFFECTS: 41836379Ssklower * 41936379Ssklower * NOTES: 42036379Ssklower */ 42136379Ssklower esis_eshinput(m, shp) 42236379Ssklower struct mbuf *m; /* esh pdu */ 42336379Ssklower struct snpa_hdr *shp; /* subnetwork header */ 42436379Ssklower { 42543072Ssklower struct esis_fixed *pdu = mtod(m, struct esis_fixed *); 42636379Ssklower u_short ht; /* holding time */ 42743072Ssklower struct iso_addr *nsap; 42839950Ssklower int naddr; 42937469Ssklower u_char *buf = (u_char *)(pdu + 1); 43039950Ssklower u_char *buflim = pdu->esis_hdr_len + (u_char *)pdu; 431*43332Ssklower int new_entry = 0; 43236379Ssklower 43336379Ssklower esis_stat.es_eshrcvd++; 43436379Ssklower 43536379Ssklower CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); 43636379Ssklower 43739950Ssklower naddr = *buf++; 43839950Ssklower if (buf >= buflim) 43936379Ssklower goto bad; 440*43332Ssklower if (naddr == 1) { 44139950Ssklower ESIS_EXTRACT_ADDR(nsap, buf); 442*43332Ssklower new_entry = snpac_add(shp->snh_ifp, 443*43332Ssklower nsap, shp->snh_shost, SNPA_ES, ht, 0); 444*43332Ssklower } else { 445*43332Ssklower int nsellength = 0, nlen = 0; 446*43332Ssklower { 447*43332Ssklower /* See if we want to compress out multiple nsaps differing 448*43332Ssklower only by nsel */ 449*43332Ssklower register struct ifaddr *ifa = shp->snh_ifp->if_addrlist; 450*43332Ssklower for (; ifa; ifa = ifa->ifa_next) 451*43332Ssklower if (ifa->ifa_addr->sa_family == AF_ISO) { 452*43332Ssklower nsellength = ((struct iso_ifaddr *)ifa)->ia_addr.siso_tlen; 453*43332Ssklower break; 454*43332Ssklower } 455*43332Ssklower } 45639950Ssklower IFDEBUG(D_ESISINPUT) 457*43332Ssklower printf("esis_eshinput: esh: ht %d, naddr %d nsellength %d\n", 458*43332Ssklower ht, naddr, nsellength); 45939950Ssklower ENDDEBUG 460*43332Ssklower while (naddr-- > 0) { 461*43332Ssklower struct iso_addr *nsap2; u_char *buf2; 462*43332Ssklower ESIS_EXTRACT_ADDR(nsap, buf); 463*43332Ssklower /* see if there is at least one more nsap in ESH differing 464*43332Ssklower only by nsel */ 465*43332Ssklower if (nsellength != 0) for (buf2 = buf; buf2 < buflim;) { 466*43332Ssklower ESIS_EXTRACT_ADDR(nsap2, buf2); 467*43332Ssklower IFDEBUG(D_ESISINPUT) 468*43332Ssklower printf("esis_eshinput: comparing %s ", 469*43332Ssklower clnp_iso_addrp(nsap)); 470*43332Ssklower printf("and %s\n", clnp_iso_addrp(nsap2)); 471*43332Ssklower ENDDEBUG 472*43332Ssklower if (Bcmp(nsap->isoa_genaddr, nsap2->isoa_genaddr, 473*43332Ssklower nsap->isoa_len - nsellength) == 0) { 474*43332Ssklower nlen = nsellength; 475*43332Ssklower break; 476*43332Ssklower } 477*43332Ssklower } 478*43332Ssklower new_entry |= snpac_add(shp->snh_ifp, 479*43332Ssklower nsap, shp->snh_shost, SNPA_ES, ht, nlen); 480*43332Ssklower nlen = 0; 481*43332Ssklower } 48239950Ssklower } 483*43332Ssklower IFDEBUG(D_ESISINPUT) 484*43332Ssklower printf("esis_eshinput: nsap %s is %s\n", 485*43332Ssklower clnp_iso_addrp(nsap), new_entry ? "new" : "old"); 486*43332Ssklower ENDDEBUG 487*43332Ssklower if (new_entry && (iso_systype & SNPA_IS)) 488*43332Ssklower esis_shoutput(shp->snh_ifp, ESIS_ISH, esis_holding_time, 489*43332Ssklower shp->snh_shost, 6, (struct iso_addr *)0); 49037469Ssklower bad: 49136379Ssklower m_freem(m); 49239950Ssklower return; 49336379Ssklower } 49436379Ssklower 49536379Ssklower /* 49636379Ssklower * FUNCTION: esis_ishinput 49736379Ssklower * 49836379Ssklower * PURPOSE: process an incoming ISH pdu 49936379Ssklower * 50036379Ssklower * RETURNS: 50136379Ssklower * 50236379Ssklower * SIDE EFFECTS: 50336379Ssklower * 50436379Ssklower * NOTES: 50536379Ssklower */ 50636379Ssklower esis_ishinput(m, shp) 50736379Ssklower struct mbuf *m; /* esh pdu */ 50836379Ssklower struct snpa_hdr *shp; /* subnetwork header */ 50936379Ssklower { 51036379Ssklower struct esis_fixed *pdu = mtod(m, struct esis_fixed *); 51139950Ssklower u_short ht; /* holding time */ 51239950Ssklower struct iso_addr *nsap; /* Network Entity Title */ 51339950Ssklower register u_char *buf = (u_char *) (pdu + 1); 51439950Ssklower register u_char *buflim = pdu->esis_hdr_len + (u_char *)pdu; 51539950Ssklower int new_entry; 51636379Ssklower 51736379Ssklower esis_stat.es_ishrcvd++; 51836379Ssklower CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); 51936379Ssklower 52036379Ssklower IFDEBUG(D_ESISINPUT) 52136379Ssklower printf("esis_ishinput: ish: ht %d\n", ht); 52236379Ssklower ENDDEBUG 52339950Ssklower if (ESHonly) 52437469Ssklower goto bad; 52536379Ssklower 52639950Ssklower ESIS_EXTRACT_ADDR(nsap, buf); 52739950Ssklower 52839950Ssklower while (buf < buflim) { 52939950Ssklower switch (*buf) { 53037469Ssklower case ESISOVAL_ESCT: 53139950Ssklower if (buf[1] != 2) 53237469Ssklower goto bad; 53339950Ssklower CTOH(buf[2], buf[3], esis_config_time); 53439950Ssklower break; 53539950Ssklower 53639950Ssklower default: 53739950Ssklower printf("Unknown ISH option: %x\n", *buf); 53837469Ssklower } 53939950Ssklower ESIS_NEXT_OPTION(buf); 54037469Ssklower } 541*43332Ssklower new_entry = snpac_add(shp->snh_ifp, nsap, shp->snh_shost, SNPA_IS, ht, 0); 54237469Ssklower IFDEBUG(D_ESISINPUT) 54337469Ssklower printf("esis_ishinput: nsap %s is %s\n", 54437469Ssklower clnp_iso_addrp(nsap), new_entry ? "new" : "old"); 54537469Ssklower ENDDEBUG 54637469Ssklower 54737469Ssklower if (new_entry) 54837469Ssklower esis_shoutput(shp->snh_ifp, 54937469Ssklower iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH, 550*43332Ssklower esis_holding_time, shp->snh_shost, 6, (struct iso_addr *)0); 55139950Ssklower bad: 55236379Ssklower m_freem(m); 55339950Ssklower return; 55436379Ssklower } 55536379Ssklower 55636379Ssklower /* 55736379Ssklower * FUNCTION: esis_rdinput 55836379Ssklower * 55936379Ssklower * PURPOSE: Process an incoming RD pdu 56036379Ssklower * 56136379Ssklower * RETURNS: 56236379Ssklower * 56336379Ssklower * SIDE EFFECTS: 56436379Ssklower * 56536379Ssklower * NOTES: 56636379Ssklower */ 56736379Ssklower esis_rdinput(m0, shp) 56836379Ssklower struct mbuf *m0; /* esh pdu */ 56936379Ssklower struct snpa_hdr *shp; /* subnetwork header */ 57036379Ssklower { 57136379Ssklower struct esis_fixed *pdu = mtod(m0, struct esis_fixed *); 57236379Ssklower u_short ht; /* holding time */ 57339950Ssklower struct iso_addr *da, *net = 0, *netmask = 0, *snpamask = 0; 57439950Ssklower register struct iso_addr *bsnpa; 57539950Ssklower register u_char *buf = (u_char *)(pdu + 1); 57639950Ssklower register u_char *buflim = pdu->esis_hdr_len + (u_char *)pdu; 57736379Ssklower 57836379Ssklower esis_stat.es_rdrcvd++; 57936379Ssklower 58036379Ssklower /* intermediate systems ignore redirects */ 58136379Ssklower if (iso_systype & SNPA_IS) 58236379Ssklower goto bad; 58339950Ssklower if (ESHonly) 58439950Ssklower goto bad; 58536379Ssklower 58636379Ssklower CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); 58739950Ssklower if (buf >= buflim) 58837469Ssklower goto bad; 58936379Ssklower 59036379Ssklower /* Extract DA */ 59139950Ssklower ESIS_EXTRACT_ADDR(da, buf); 59237469Ssklower 59336379Ssklower /* Extract better snpa */ 59439950Ssklower ESIS_EXTRACT_ADDR(bsnpa, buf); 59539950Ssklower 59637469Ssklower /* Extract NET if present */ 59739950Ssklower if (buf < buflim) { 598*43332Ssklower if (*buf == 0) 599*43332Ssklower buf++; /* no NET present, skip NETL anyway */ 600*43332Ssklower else 601*43332Ssklower ESIS_EXTRACT_ADDR(net, buf); 60236379Ssklower } 60336379Ssklower 60437469Ssklower /* process options */ 60539950Ssklower while (buf < buflim) { 60639950Ssklower switch (*buf) { 60737469Ssklower case ESISOVAL_SNPAMASK: 60837469Ssklower if (snpamask) /* duplicate */ 60937469Ssklower goto bad; 61039950Ssklower snpamask = (struct iso_addr *)(buf + 1); 61137469Ssklower break; 61237469Ssklower 61337469Ssklower case ESISOVAL_NETMASK: 61437469Ssklower if (netmask) /* duplicate */ 61537469Ssklower goto bad; 61639950Ssklower netmask = (struct iso_addr *)(buf + 1); 61739950Ssklower break; 61839950Ssklower 61939950Ssklower default: 62039950Ssklower printf("Unknown option in ESIS RD (0x%x)\n", buf[-1]); 62137469Ssklower } 62239950Ssklower ESIS_NEXT_OPTION(buf); 62336379Ssklower } 62436379Ssklower 62536379Ssklower IFDEBUG(D_ESISINPUT) 62637469Ssklower printf("esis_rdinput: rd: ht %d, da %s\n", ht, clnp_iso_addrp(da)); 62737469Ssklower if (net) 62837469Ssklower printf("\t: net %s\n", clnp_iso_addrp(net)); 62936379Ssklower ENDDEBUG 63036379Ssklower /* 63136379Ssklower * If netl is zero, then redirect is to an ES. We need to add an entry 63236379Ssklower * to the snpa cache for (destination, better snpa). 63336379Ssklower * If netl is not zero, then the redirect is to an IS. In this 63436379Ssklower * case, add an snpa cache entry for (net, better snpa). 63536379Ssklower * 63636379Ssklower * If the redirect is to an IS, add a route entry towards that 63736379Ssklower * IS. 63836379Ssklower */ 63939950Ssklower if (net == 0 || net->isoa_len == 0 || snpamask) { 64036379Ssklower /* redirect to an ES */ 64139950Ssklower snpac_add(shp->snh_ifp, da, 642*43332Ssklower bsnpa->isoa_genaddr, SNPA_ES, ht, 0); 64336379Ssklower } else { 64439950Ssklower snpac_add(shp->snh_ifp, net, 645*43332Ssklower bsnpa->isoa_genaddr, SNPA_IS, ht, 0); 64639950Ssklower snpac_addrt(shp->snh_ifp, da, net, netmask); 64736379Ssklower } 64836379Ssklower bad: 64936379Ssklower m_freem(m0); 65036379Ssklower } 65136379Ssklower 65236379Ssklower /* 65336379Ssklower * FUNCTION: esis_config 65436379Ssklower * 65536379Ssklower * PURPOSE: Report configuration 65636379Ssklower * 65736379Ssklower * RETURNS: 65836379Ssklower * 65936379Ssklower * SIDE EFFECTS: 66036379Ssklower * 66136379Ssklower * NOTES: Called every esis_config_time seconds 66236379Ssklower */ 66336379Ssklower esis_config() 66436379Ssklower { 66536379Ssklower register struct ifnet *ifp; 66636379Ssklower 66736379Ssklower timeout(esis_config, (caddr_t)0, hz * esis_config_time); 66836379Ssklower 66936379Ssklower /* 67036379Ssklower * Report configuration for each interface that 67136379Ssklower * - is UP 67236379Ssklower * - is not loopback 67336379Ssklower * - has broadcast capabilities 67436379Ssklower * - has an ISO address 67536379Ssklower */ 67636379Ssklower 67736379Ssklower for (ifp = ifnet; ifp; ifp = ifp->if_next) { 67836379Ssklower if ((ifp->if_flags & IFF_UP) && 67936379Ssklower (ifp->if_flags & IFF_BROADCAST) && 68036379Ssklower ((ifp->if_flags & IFF_LOOPBACK) == 0)) { 68136379Ssklower /* search for an ISO address family */ 68236379Ssklower struct ifaddr *ia; 68336379Ssklower 68436379Ssklower for (ia = ifp->if_addrlist; ia; ia = ia->ifa_next) { 68537469Ssklower if (ia->ifa_addr->sa_family == AF_ISO) { 68636379Ssklower esis_shoutput(ifp, 68736379Ssklower iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH, 68836379Ssklower esis_holding_time, 689*43332Ssklower (caddr_t)(iso_systype & SNPA_ES ? all_is_snpa : 690*43332Ssklower all_es_snpa), 6, (struct iso_addr *)0); 69136379Ssklower break; 69236379Ssklower } 69336379Ssklower } 69436379Ssklower } 69536379Ssklower } 69636379Ssklower } 69736379Ssklower 69836379Ssklower /* 69936379Ssklower * FUNCTION: esis_shoutput 70036379Ssklower * 70136379Ssklower * PURPOSE: Transmit an esh or ish pdu 70236379Ssklower * 70336379Ssklower * RETURNS: nothing 70436379Ssklower * 70536379Ssklower * SIDE EFFECTS: 70636379Ssklower * 70736379Ssklower * NOTES: 70836379Ssklower */ 709*43332Ssklower esis_shoutput(ifp, type, ht, sn_addr, sn_len, isoa) 71036379Ssklower struct ifnet *ifp; 71136379Ssklower int type; 71236379Ssklower short ht; 71336379Ssklower caddr_t sn_addr; 71436379Ssklower int sn_len; 715*43332Ssklower struct iso_addr *isoa; 71636379Ssklower { 71736379Ssklower struct mbuf *m, *m0; 71836379Ssklower caddr_t cp, naddrp; 71936379Ssklower int naddr = 0; 72036379Ssklower struct esis_fixed *pdu; 721*43332Ssklower struct iso_ifaddr *ia; 72237469Ssklower int len; 72336379Ssklower struct sockaddr_iso siso; 72436379Ssklower 72536379Ssklower if (type == ESIS_ESH) 72636379Ssklower esis_stat.es_eshsent++; 72736379Ssklower else if (type == ESIS_ISH) 72836379Ssklower esis_stat.es_ishsent++; 72936379Ssklower else { 73036379Ssklower printf("esis_shoutput: bad pdu type\n"); 73136379Ssklower return; 73236379Ssklower } 73336379Ssklower 73436379Ssklower IFDEBUG(D_ESISOUTPUT) 73536379Ssklower int i; 73636379Ssklower printf("esis_shoutput: ifp x%x (%s%d), %s, ht %d, to: [%d] ", 73736379Ssklower ifp, ifp->if_name, ifp->if_unit, type == ESIS_ESH ? "esh" : "ish", 73836379Ssklower ht, sn_len); 73936379Ssklower for (i=0; i<sn_len; i++) 74036379Ssklower printf("%x%c", *(sn_addr+i), i < (sn_len-1) ? ':' : ' '); 74136379Ssklower printf("\n"); 74236379Ssklower ENDDEBUG 74336379Ssklower 74437469Ssklower if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) { 74536379Ssklower esis_stat.es_nomem++; 74636379Ssklower return; 74736379Ssklower } 74837469Ssklower bzero(mtod(m, caddr_t), MHLEN); 74936379Ssklower 75036379Ssklower pdu = mtod(m, struct esis_fixed *); 75137469Ssklower naddrp = cp = (caddr_t)(pdu + 1); 75236379Ssklower len = sizeof(struct esis_fixed); 75336379Ssklower 75436379Ssklower /* 75536379Ssklower * Build fixed part of header 75636379Ssklower */ 75736379Ssklower pdu->esis_proto_id = ISO9542_ESIS; 75836379Ssklower pdu->esis_vers = ESIS_VERSION; 75936379Ssklower pdu->esis_type = type; 76036379Ssklower HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); 76136379Ssklower 76236379Ssklower if (type == ESIS_ESH) { 76336379Ssklower cp++; 76436379Ssklower len++; 76536379Ssklower } 76636379Ssklower 76737469Ssklower m->m_len = len; 768*43332Ssklower if (isoa) { 769*43332Ssklower /* 770*43332Ssklower * Here we are responding to a clnp packet sent to an NSAP 771*43332Ssklower * that is ours which was sent to the MAC addr all_es's. 772*43332Ssklower * It is possible that we did not specifically advertise this 773*43332Ssklower * NSAP, even though it is ours, so we will respond 774*43332Ssklower * directly to the sender that we are here. If we do have 775*43332Ssklower * multiple NSEL's we'll tack them on so he can compress them out. 776*43332Ssklower */ 777*43332Ssklower (void) esis_insert_addr(&cp, &len, isoa, m, 0); 778*43332Ssklower naddr = 1; 779*43332Ssklower } 780*43332Ssklower for (ia = iso_ifaddr; ia; ia = ia->ia_next) { 781*43332Ssklower int nsellen = (type == ESIS_ISH ? ia->ia_addr.siso_tlen : 0); 782*43332Ssklower int n = ia->ia_addr.siso_nlen; 783*43332Ssklower register struct iso_ifaddr *ia2; 784*43332Ssklower 785*43332Ssklower if (type == ESIS_ISH && naddr > 0) 786*43332Ssklower break; 787*43332Ssklower for (ia2 = iso_ifaddr; ia2 != ia; ia2 = ia2->ia_next) 788*43332Ssklower if (Bcmp(ia->ia_addr.siso_data, ia2->ia_addr.siso_data, n) == 0) 789*43332Ssklower break; 790*43332Ssklower if (ia2 != ia) 791*43332Ssklower continue; /* Means we have previously copied this nsap */ 792*43332Ssklower if (isoa && Bcmp(ia->ia_addr.siso_data, isoa->isoa_genaddr, n) == 0) { 793*43332Ssklower isoa = 0; 794*43332Ssklower continue; /* Ditto */ 79536379Ssklower } 796*43332Ssklower IFDEBUG(D_ESISOUTPUT) 797*43332Ssklower printf("esis_shoutput: adding NSAP %s\n", 798*43332Ssklower clnp_iso_addrp(&ia->ia_addr.siso_addr)); 799*43332Ssklower ENDDEBUG 800*43332Ssklower if (!esis_insert_addr(&cp, &len, 801*43332Ssklower &ia->ia_addr.siso_addr, m, nsellen)) { 802*43332Ssklower EXTEND_PACKET(m, m0, cp); 803*43332Ssklower (void) esis_insert_addr(&cp, &len, &ia->ia_addr.siso_addr, m, 804*43332Ssklower nsellen); 805*43332Ssklower } 806*43332Ssklower naddr++; 80736379Ssklower } 80836379Ssklower 80936379Ssklower if (type == ESIS_ESH) 81036379Ssklower *naddrp = naddr; 81136379Ssklower 81237469Ssklower m0->m_pkthdr.len = len; 81337469Ssklower pdu->esis_hdr_len = len; 81436379Ssklower iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len); 81536379Ssklower 81637469Ssklower bzero((caddr_t)&siso, sizeof(siso)); 81736379Ssklower siso.siso_family = AF_ISO; 81837469Ssklower siso.siso_data[0] = AFI_SNA; 81937469Ssklower siso.siso_nlen = sn_len + 1; 82037469Ssklower siso.siso_len = sn_len + 6; 82137469Ssklower bcopy(sn_addr, siso.siso_data + 1, (unsigned)sn_len); 82240775Ssklower (ifp->if_output)(ifp, m0, &siso, 0); 82336379Ssklower } 82436379Ssklower 82536379Ssklower /* 82636379Ssklower * FUNCTION: esis_ctlinput 82736379Ssklower * 82836379Ssklower * PURPOSE: Handle the PRC_IFDOWN transition 82936379Ssklower * 83036379Ssklower * RETURNS: nothing 83136379Ssklower * 83236379Ssklower * SIDE EFFECTS: 83336379Ssklower * 83436379Ssklower * NOTES: Calls snpac_flush for interface specified. 83536379Ssklower * The loop through iso_ifaddr is stupid because 83636379Ssklower * back in if_down, we knew the ifp... 83736379Ssklower */ 83836379Ssklower esis_ctlinput(req, siso) 83936379Ssklower int req; /* request: we handle only PRC_IFDOWN */ 84036379Ssklower struct sockaddr_iso *siso; /* address of ifp */ 84136379Ssklower { 84236379Ssklower register struct iso_ifaddr *ia; /* scan through interface addresses */ 84336379Ssklower 84437469Ssklower if (req == PRC_IFDOWN) 84537469Ssklower for (ia = iso_ifaddr; ia; ia = ia->ia_next) { 84637469Ssklower if (iso_addrmatch(IA_SIS(ia), siso)) 84737469Ssklower snpac_flushifp(ia->ia_ifp); 84837469Ssklower } 84936379Ssklower } 85036379Ssklower 85136379Ssklower #endif ISO 852