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 */ 2736379Ssklower #ifndef lint 2836379Ssklower static char *rcsid = "$Header: esis.c,v 4.10 88/09/15 18:57:03 hagens Exp $"; 2936379Ssklower #endif 3036379Ssklower 3136379Ssklower #ifdef ISO 3236379Ssklower 33*37469Ssklower #include "types.h" 34*37469Ssklower #include "param.h" 35*37469Ssklower #include "mbuf.h" 36*37469Ssklower #include "domain.h" 37*37469Ssklower #include "protosw.h" 38*37469Ssklower #include "dir.h" 39*37469Ssklower #include "user.h" 40*37469Ssklower #include "socket.h" 41*37469Ssklower #include "socketvar.h" 42*37469Ssklower #include "errno.h" 43*37469Ssklower #include "kernel.h" 4436379Ssklower 4536379Ssklower #include "../net/if.h" 4636379Ssklower #include "../net/route.h" 4736379Ssklower 48*37469Ssklower #include "iso.h" 49*37469Ssklower #include "iso_pcb.h" 50*37469Ssklower #include "iso_var.h" 51*37469Ssklower #include "iso_snpac.h" 52*37469Ssklower #include "clnl.h" 53*37469Ssklower #include "clnp.h" 54*37469Ssklower #include "clnp_stat.h" 55*37469Ssklower #include "argo_debug.h" 56*37469Ssklower #include "esis.h" 5736379Ssklower 5836379Ssklower /* 5936379Ssklower * Global variables to esis implementation 6036379Ssklower * 6136379Ssklower * esis_holding_time - the holding time (sec) parameter for outgoing pdus 6236379Ssklower * esis_config_time - the frequency (sec) that hellos are generated 6336379Ssklower * 6436379Ssklower */ 6536379Ssklower struct isopcb esis_pcb; 6636379Ssklower int esis_sendspace = 2048; 6736379Ssklower int esis_recvspace = 2048; 6836379Ssklower short esis_holding_time = ESIS_HT; 6936379Ssklower short esis_config_time = ESIS_CONFIG; 7036379Ssklower extern int iso_systype; 7136379Ssklower extern struct snpa_cache all_es, all_is; 7236379Ssklower 73*37469Ssklower #define EXTEND_PACKET(m, mhdr, cp)\ 7436379Ssklower if (((m)->m_next = m_getclr(M_DONTWAIT, MT_HEADER)) == NULL) {\ 7536379Ssklower esis_stat.es_nomem++;\ 7636379Ssklower m_freem(mhdr);\ 7736379Ssklower return;\ 7836379Ssklower } else {\ 7936379Ssklower (m) = (m)->m_next;\ 8036379Ssklower (cp) = mtod((m), caddr_t);\ 8136379Ssklower } 8236379Ssklower /* 8336379Ssklower * FUNCTION: esis_init 8436379Ssklower * 8536379Ssklower * PURPOSE: Initialize the kernel portion of esis protocol 8636379Ssklower * 8736379Ssklower * RETURNS: nothing 8836379Ssklower * 8936379Ssklower * SIDE EFFECTS: 9036379Ssklower * 9136379Ssklower * NOTES: 9236379Ssklower */ 9336379Ssklower esis_init() 9436379Ssklower { 9536379Ssklower extern struct clnl_protosw clnl_protox[256]; 9636379Ssklower int esis_input(); 9736379Ssklower int snpac_age(); 9836379Ssklower int esis_config(); 9936379Ssklower #ifdef ISO_X25ESIS 10036379Ssklower x25esis_input(); 10136379Ssklower #endif ISO_X25ESIS 10236379Ssklower 10336379Ssklower esis_pcb.isop_next = esis_pcb.isop_prev = &esis_pcb; 10436379Ssklower 10536379Ssklower clnl_protox[ISO9542_ESIS].clnl_input = esis_input; 10636379Ssklower timeout(snpac_age, (caddr_t)0, hz); 10736379Ssklower timeout(esis_config, (caddr_t)0, hz); 10836379Ssklower 10936379Ssklower #ifdef ISO_X25ESIS 11036379Ssklower clnl_protox[ISO9542X25_ESIS].clnl_input = x25esis_input; 11136379Ssklower #endif ISO_X25ESIS 11236379Ssklower } 11336379Ssklower 11436379Ssklower /* 11536379Ssklower * FUNCTION: esis_usrreq 11636379Ssklower * 11736379Ssklower * PURPOSE: Handle user level esis requests 11836379Ssklower * 11936379Ssklower * RETURNS: 0 or appropriate errno 12036379Ssklower * 12136379Ssklower * SIDE EFFECTS: 12236379Ssklower * 12336379Ssklower * NOTES: This is here only so esis gets initialized. 12436379Ssklower */ 125*37469Ssklower /*ARGSUSED*/ 12636379Ssklower esis_usrreq(so, req, m, nam, rights) 12736379Ssklower struct socket *so; /* socket: used only to get to this code */ 12836379Ssklower int req; /* request */ 12936379Ssklower struct mbuf *m; /* data for request */ 13036379Ssklower struct mbuf *nam; /* optional name */ 13136379Ssklower struct mbuf *rights; /* optional rights */ 13236379Ssklower { 13336379Ssklower if (m != NULL) 13436379Ssklower m_freem(m); 13536379Ssklower 13636379Ssklower return(EOPNOTSUPP); 13736379Ssklower } 13836379Ssklower 13936379Ssklower /* 14036379Ssklower * FUNCTION: esis_input 14136379Ssklower * 14236379Ssklower * PURPOSE: Process an incoming esis packet 14336379Ssklower * 14436379Ssklower * RETURNS: nothing 14536379Ssklower * 14636379Ssklower * SIDE EFFECTS: 14736379Ssklower * 14836379Ssklower * NOTES: 14936379Ssklower */ 15036379Ssklower esis_input(m0, shp) 15136379Ssklower struct mbuf *m0; /* ptr to first mbuf of pkt */ 15236379Ssklower struct snpa_hdr *shp; /* subnetwork header */ 15336379Ssklower { 15436379Ssklower struct esis_fixed *pdu = mtod(m0, struct esis_fixed *); 155*37469Ssklower register int type; 15636379Ssklower 15736379Ssklower IFDEBUG(D_ESISINPUT) 15836379Ssklower int i; 15936379Ssklower 16036379Ssklower printf("esis_input: pdu on ifp x%x (%s%d): from:", shp->snh_ifp, 16136379Ssklower shp->snh_ifp->if_name, shp->snh_ifp->if_unit); 16236379Ssklower for (i=0; i<6; i++) 16336379Ssklower printf("%x%c", shp->snh_shost[i]&0xff, (i<5) ? ':' : ' '); 16436379Ssklower printf(" to:"); 16536379Ssklower for (i=0; i<6; i++) 16636379Ssklower printf("%x%c", shp->snh_dhost[i]&0xff, (i<5) ? ':' : ' '); 16736379Ssklower printf("\n"); 16836379Ssklower ENDDEBUG 16936379Ssklower 17036379Ssklower /* 17136379Ssklower * check checksum if necessary 17236379Ssklower */ 173*37469Ssklower if (ESIS_CKSUM_REQUIRED(pdu) && iso_check_csum(m0, (int)pdu->esis_hdr_len)) { 17436379Ssklower esis_stat.es_badcsum++; 17536379Ssklower goto bad; 17636379Ssklower } 17736379Ssklower 17836379Ssklower /* check version */ 17936379Ssklower if (pdu->esis_vers != ESIS_VERSION) { 18036379Ssklower esis_stat.es_badvers++; 18136379Ssklower goto bad; 18236379Ssklower } 18336379Ssklower 184*37469Ssklower type = pdu->esis_type & 0x1f; 185*37469Ssklower switch (type) { 18636379Ssklower case ESIS_ESH: 18736379Ssklower esis_eshinput(m0, shp); 18836379Ssklower return; 18936379Ssklower 19036379Ssklower case ESIS_ISH: 19136379Ssklower esis_ishinput(m0, shp); 19236379Ssklower return; 19336379Ssklower 19436379Ssklower case ESIS_RD: 19536379Ssklower esis_rdinput(m0, shp); 19636379Ssklower return; 19736379Ssklower 19836379Ssklower default: { 19936379Ssklower esis_stat.es_badtype++; 20036379Ssklower goto bad; 20136379Ssklower } 20236379Ssklower } 20336379Ssklower 20436379Ssklower bad: 20536379Ssklower m_freem(m0); 20636379Ssklower } 20736379Ssklower 20836379Ssklower /* 20936379Ssklower * FUNCTION: esis_rdoutput 21036379Ssklower * 21136379Ssklower * PURPOSE: Transmit a redirect pdu 21236379Ssklower * 21336379Ssklower * RETURNS: nothing 21436379Ssklower * 21536379Ssklower * SIDE EFFECTS: 21636379Ssklower * 21736379Ssklower * NOTES: Assumes there is enough space for fixed part of header, 21836379Ssklower * DA, BSNPA and NET in first mbuf. 21936379Ssklower */ 22036379Ssklower esis_rdoutput(inbound_shp, inbound_m, inbound_oidx, rd_dstnsap, nhop_sc) 22136379Ssklower struct snpa_hdr *inbound_shp; /* snpa hdr from incoming packet */ 22236379Ssklower struct mbuf *inbound_m; /* incoming pkt itself */ 22336379Ssklower struct clnp_optidx *inbound_oidx; /* clnp options assoc with incoming pkt */ 22436379Ssklower struct iso_addr *rd_dstnsap; /* ultimate destination of pkt */ 22536379Ssklower struct snpa_cache *nhop_sc; /* snpa cache info regarding next hop of 22636379Ssklower pkt */ 22736379Ssklower { 22836379Ssklower struct mbuf *m, *m0; 22936379Ssklower caddr_t cp; 23036379Ssklower struct esis_fixed *pdu; 23136379Ssklower int len, total_len = 0; 23236379Ssklower struct sockaddr_iso siso; 23336379Ssklower struct ifnet *ifp = inbound_shp->snh_ifp; 23436379Ssklower 23536379Ssklower esis_stat.es_rdsent++; 23636379Ssklower 23736379Ssklower IFDEBUG(D_ESISOUTPUT) 23836379Ssklower printf("esis_rdoutput: ifp x%x (%s%d), ht %d, m x%x, oidx x%x\n", 23936379Ssklower ifp, ifp->if_name, ifp->if_unit, esis_holding_time, inbound_m, 24036379Ssklower inbound_oidx); 24136379Ssklower printf("\tdestination: %s\n", clnp_iso_addrp(rd_dstnsap)); 24236379Ssklower printf("\tredirected toward:%s\n", clnp_iso_addrp(&nhop_sc->sc_nsap)); 24336379Ssklower ENDDEBUG 24436379Ssklower 245*37469Ssklower if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) { 24636379Ssklower esis_stat.es_nomem++; 24736379Ssklower return; 24836379Ssklower } 249*37469Ssklower bzero(mtod(m, caddr_t), MHLEN); 25036379Ssklower 25136379Ssklower pdu = mtod(m, struct esis_fixed *); 252*37469Ssklower cp = (caddr_t)(pdu + 1); /*pointer arith.; 1st byte after header */ 25336379Ssklower len = sizeof(struct esis_fixed); 25436379Ssklower 25536379Ssklower /* 25636379Ssklower * Build fixed part of header 25736379Ssklower */ 25836379Ssklower pdu->esis_proto_id = ISO9542_ESIS; 25936379Ssklower pdu->esis_vers = ESIS_VERSION; 26036379Ssklower pdu->esis_type = ESIS_RD; 26136379Ssklower HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, esis_holding_time); 26236379Ssklower 26336379Ssklower /* Insert destination address */ 264*37469Ssklower (void) esis_insert_addr(&cp, &len, rd_dstnsap, m); 26536379Ssklower 26636379Ssklower /* Insert the snpa of better next hop */ 26736379Ssklower *cp++ = nhop_sc->sc_len; 268*37469Ssklower bcopy((caddr_t)nhop_sc->sc_snpa, cp, nhop_sc->sc_len); 26936379Ssklower len += (nhop_sc->sc_len + 1); 27036379Ssklower 27136379Ssklower /* 27236379Ssklower * If the next hop is not the destination, then it ought to be 27336379Ssklower * an IS and it should be inserted next. Else, set the 27436379Ssklower * NETL to 0 27536379Ssklower */ 27636379Ssklower /* PHASE2 use mask from ifp of outgoing interface */ 27736379Ssklower if (!iso_addrmatch1(rd_dstnsap, &nhop_sc->sc_nsap)) { 27836379Ssklower if ((nhop_sc->sc_flags & SNPA_IS) == 0) { 27936379Ssklower /* this should not happen */ 28036379Ssklower printf("esis_rdoutput: next hop is not dst and not an IS\n"); 28136379Ssklower m_freem(m0); 28236379Ssklower return; 28336379Ssklower } 284*37469Ssklower (void) esis_insert_addr(&cp, &len, &nhop_sc->sc_nsap, m); 28536379Ssklower } else { 28636379Ssklower *cp++ = 0; /* NETL */ 28736379Ssklower len++; 28836379Ssklower } 289*37469Ssklower m->m_len = len; 29036379Ssklower 29136379Ssklower /* 29236379Ssklower * PHASE2 29336379Ssklower * If redirect is to an IS, add an address mask. The mask to be 29436379Ssklower * used should be the mask present in the routing entry used to 29536379Ssklower * forward the original data packet. 29636379Ssklower */ 29736379Ssklower 29836379Ssklower /* 29936379Ssklower * Copy Qos, priority, or security options present in original npdu 30036379Ssklower */ 30136379Ssklower if (inbound_oidx) { 30236379Ssklower /* THIS CODE IS CURRENTLY UNTESTED */ 30336379Ssklower int optlen = 0; 30436379Ssklower if (inbound_oidx->cni_qos_formatp) 30536379Ssklower optlen += (inbound_oidx->cni_qos_len + 2); 30636379Ssklower if (inbound_oidx->cni_priorp) /* priority option is 1 byte long */ 30736379Ssklower optlen += 3; 30836379Ssklower if (inbound_oidx->cni_securep) 30936379Ssklower optlen += (inbound_oidx->cni_secure_len + 2); 310*37469Ssklower if (M_TRAILINGSPACE(m) < optlen) { 311*37469Ssklower EXTEND_PACKET(m, m0, cp); 312*37469Ssklower m->m_len = 0; 31336379Ssklower /* assumes MLEN > optlen */ 31436379Ssklower } 31536379Ssklower /* assume MLEN-len > optlen */ 31636379Ssklower /* 31736379Ssklower * When copying options, copy from ptr - 2 in order to grab 31836379Ssklower * the option code and length 31936379Ssklower */ 32036379Ssklower if (inbound_oidx->cni_qos_formatp) { 321*37469Ssklower bcopy((caddr_t)(inbound_m + inbound_oidx->cni_qos_formatp - 2), cp, 322*37469Ssklower (unsigned)(inbound_oidx->cni_qos_len + 2)); 32336379Ssklower len += inbound_oidx->cni_qos_len + 2; 32436379Ssklower } 32536379Ssklower if (inbound_oidx->cni_priorp) { 326*37469Ssklower bcopy((caddr_t)(inbound_m + inbound_oidx->cni_priorp - 2), cp, 3); 32736379Ssklower len += 3; 32836379Ssklower } 32936379Ssklower if (inbound_oidx->cni_securep) { 330*37469Ssklower bcopy((caddr_t)(inbound_m + inbound_oidx->cni_securep - 2), cp, 331*37469Ssklower (unsigned)(inbound_oidx->cni_secure_len + 2)); 33236379Ssklower len += inbound_oidx->cni_secure_len + 2; 33336379Ssklower } 334*37469Ssklower m->m_len += optlen; 33536379Ssklower } 33636379Ssklower 337*37469Ssklower pdu->esis_hdr_len = m0->m_pkthdr.len = len; 33836379Ssklower iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len); 33936379Ssklower 340*37469Ssklower bzero((caddr_t)&siso, sizeof(siso)); 341*37469Ssklower siso.siso_len = 12; 34236379Ssklower siso.siso_family = AF_ISO; 343*37469Ssklower siso.siso_data[0] = AFI_SNA; 344*37469Ssklower siso.siso_nlen = 6 + 1; /* should be taken from snpa_hdr */ 34536379Ssklower /* +1 is for AFI */ 346*37469Ssklower bcopy(inbound_shp->snh_shost, siso.siso_data + 1, 6); 34736379Ssklower (ifp->if_output)(ifp, m0, &siso); 34836379Ssklower } 34936379Ssklower 35036379Ssklower /* 35136379Ssklower * FUNCTION: esis_insert_addr 35236379Ssklower * 35336379Ssklower * PURPOSE: Insert an iso_addr into a buffer 35436379Ssklower * 35536379Ssklower * RETURNS: true if buffer was big enough, else false 35636379Ssklower * 35736379Ssklower * SIDE EFFECTS: Increment buf & len according to size of iso_addr 35836379Ssklower * 35936379Ssklower * NOTES: Plus 1 here is for length byte 36036379Ssklower */ 361*37469Ssklower esis_insert_addr(buf, len, isoa, m) 36236379Ssklower caddr_t *buf; /* ptr to buffer to put address into */ 36336379Ssklower int *len; /* ptr to length of buffer so far */ 36436379Ssklower struct iso_addr *isoa; /* ptr to address */ 365*37469Ssklower register struct mbuf *m; /* determine if there remains space */ 36636379Ssklower { 367*37469Ssklower register int newlen = isoa->isoa_len + 1; 36836379Ssklower 369*37469Ssklower if (newlen > M_TRAILINGSPACE(m)) 37036379Ssklower return(0); 371*37469Ssklower bcopy((caddr_t)isoa, *buf, newlen); 372*37469Ssklower *len += newlen; 373*37469Ssklower *buf += newlen; 374*37469Ssklower m->m_len += newlen; 37536379Ssklower return(1); 37636379Ssklower } 37736379Ssklower 37836379Ssklower /* 37936379Ssklower 38036379Ssklower /* 38136379Ssklower * FUNCTION: esis_eshinput 38236379Ssklower * 38336379Ssklower * PURPOSE: Process an incoming ESH pdu 38436379Ssklower * 38536379Ssklower * RETURNS: nothing 38636379Ssklower * 38736379Ssklower * SIDE EFFECTS: 38836379Ssklower * 38936379Ssklower * NOTES: 39036379Ssklower */ 39136379Ssklower esis_eshinput(m, shp) 39236379Ssklower struct mbuf *m; /* esh pdu */ 39336379Ssklower struct snpa_hdr *shp; /* subnetwork header */ 39436379Ssklower { 39536379Ssklower struct esis_fixed *pdu = mtod(m, struct esis_fixed *); 39636379Ssklower u_short ht; /* holding time */ 397*37469Ssklower struct iso_addr *nsap; 398*37469Ssklower int naddr = 0; 399*37469Ssklower u_char *buf = (u_char *)(pdu + 1); 40036379Ssklower int len = pdu->esis_hdr_len - sizeof(struct esis_fixed); 401*37469Ssklower int optlen, new_entry; 40236379Ssklower 40336379Ssklower esis_stat.es_eshrcvd++; 40436379Ssklower 40536379Ssklower CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); 40636379Ssklower 40736379Ssklower if (len > 0) { 40836379Ssklower naddr = *buf++; 40936379Ssklower len--; 41036379Ssklower } else 41136379Ssklower goto bad; 41236379Ssklower 41336379Ssklower IFDEBUG(D_ESISINPUT) 41436379Ssklower printf("esis_eshinput: esh: ht %d, naddr %d\n", ht, naddr); 41536379Ssklower ENDDEBUG 41636379Ssklower 41736379Ssklower while (naddr-- > 0) { 418*37469Ssklower nsap = (struct iso_addr *)buf; 419*37469Ssklower if ((len -= (optlen = *buf++)) >= 0) { 420*37469Ssklower buf += optlen; 421*37469Ssklower new_entry = (snpac_look(nsap) == NULL); 42236379Ssklower 42336379Ssklower IFDEBUG(D_ESISINPUT) 42436379Ssklower printf("esis_eshinput: nsap %s is %s\n", 425*37469Ssklower clnp_iso_addrp(nsap), new_entry ? "new" : "old"); 42636379Ssklower ENDDEBUG 42736379Ssklower 428*37469Ssklower snpac_add(shp->snh_ifp, nsap, shp->snh_shost, 6, SNPA_ES, ht); 42936379Ssklower if (new_entry) 43036379Ssklower esis_shoutput(shp->snh_ifp, 43136379Ssklower iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH, 43236379Ssklower esis_holding_time, shp->snh_shost, 6); 43336379Ssklower } else { 434*37469Ssklower bad: 43536379Ssklower esis_stat.es_toosmall++; 43636379Ssklower break; 43736379Ssklower } 43836379Ssklower } 43936379Ssklower 44036379Ssklower m_freem(m); 44136379Ssklower } 44236379Ssklower 44336379Ssklower /* 44436379Ssklower * FUNCTION: esis_ishinput 44536379Ssklower * 44636379Ssklower * PURPOSE: process an incoming ISH pdu 44736379Ssklower * 44836379Ssklower * RETURNS: 44936379Ssklower * 45036379Ssklower * SIDE EFFECTS: 45136379Ssklower * 45236379Ssklower * NOTES: 45336379Ssklower */ 45436379Ssklower esis_ishinput(m, shp) 45536379Ssklower struct mbuf *m; /* esh pdu */ 45636379Ssklower struct snpa_hdr *shp; /* subnetwork header */ 45736379Ssklower { 45836379Ssklower struct esis_fixed *pdu = mtod(m, struct esis_fixed *); 45936379Ssklower u_short ht; /* holding time */ 460*37469Ssklower struct iso_addr *nsap; 46136379Ssklower caddr_t buf = (caddr_t)pdu + sizeof(struct esis_fixed); 46236379Ssklower int len = pdu->esis_hdr_len - sizeof(struct esis_fixed); 463*37469Ssklower int optlen, new_entry; 46436379Ssklower 46536379Ssklower esis_stat.es_ishrcvd++; 46636379Ssklower CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); 46736379Ssklower 46836379Ssklower IFDEBUG(D_ESISINPUT) 46936379Ssklower printf("esis_ishinput: ish: ht %d\n", ht); 47036379Ssklower ENDDEBUG 47136379Ssklower 472*37469Ssklower nsap = (struct iso_addr *)buf; 473*37469Ssklower if ((len -= (optlen = *buf++)) < 0) 474*37469Ssklower goto bad; 475*37469Ssklower buf += optlen; 47636379Ssklower 477*37469Ssklower /* process options */ 478*37469Ssklower while (len > 0) { 479*37469Ssklower switch (*buf++) { 480*37469Ssklower case ESISOVAL_ESCT: 481*37469Ssklower if (*buf != 2) 482*37469Ssklower goto bad; 483*37469Ssklower CTOH(buf[0], buf[1], esis_config_time); 484*37469Ssklower } 485*37469Ssklower if ((len -= (optlen = *buf)) < 0) { 486*37469Ssklower bad: 487*37469Ssklower esis_stat.es_toosmall++; 488*37469Ssklower m_freem(m); 489*37469Ssklower return; 490*37469Ssklower } 491*37469Ssklower buf += 1 + optlen; 492*37469Ssklower } 493*37469Ssklower new_entry = (snpac_look(nsap) == NULL); 49436379Ssklower 495*37469Ssklower IFDEBUG(D_ESISINPUT) 496*37469Ssklower printf("esis_ishinput: nsap %s is %s\n", 497*37469Ssklower clnp_iso_addrp(nsap), new_entry ? "new" : "old"); 498*37469Ssklower ENDDEBUG 499*37469Ssklower 500*37469Ssklower snpac_add(shp->snh_ifp, nsap, shp->snh_shost, 6, SNPA_IS, ht); 501*37469Ssklower if (new_entry) 502*37469Ssklower esis_shoutput(shp->snh_ifp, 503*37469Ssklower iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH, 504*37469Ssklower esis_holding_time, shp->snh_shost, 6); 50536379Ssklower m_freem(m); 50636379Ssklower } 50736379Ssklower 50836379Ssklower /* 50936379Ssklower * FUNCTION: esis_rdinput 51036379Ssklower * 51136379Ssklower * PURPOSE: Process an incoming RD pdu 51236379Ssklower * 51336379Ssklower * RETURNS: 51436379Ssklower * 51536379Ssklower * SIDE EFFECTS: 51636379Ssklower * 51736379Ssklower * NOTES: 51836379Ssklower */ 51936379Ssklower esis_rdinput(m0, shp) 52036379Ssklower struct mbuf *m0; /* esh pdu */ 52136379Ssklower struct snpa_hdr *shp; /* subnetwork header */ 52236379Ssklower { 52336379Ssklower struct esis_fixed *pdu = mtod(m0, struct esis_fixed *); 52436379Ssklower u_short ht; /* holding time */ 525*37469Ssklower register struct iso_addr *da, *net = 0, *netmask = 0, *snpamask = 0; 526*37469Ssklower u_char *buf = (u_char *)(pdu + 1); 527*37469Ssklower int len = pdu->esis_hdr_len - sizeof(struct esis_fixed); 528*37469Ssklower int optlen, bsnpalen; 52936379Ssklower caddr_t bsnpa; 53036379Ssklower 53136379Ssklower esis_stat.es_rdrcvd++; 53236379Ssklower 53336379Ssklower /* intermediate systems ignore redirects */ 53436379Ssklower if (iso_systype & SNPA_IS) 53536379Ssklower goto bad; 53636379Ssklower 53736379Ssklower CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); 538*37469Ssklower if (len <= 0) 539*37469Ssklower goto bad; 54036379Ssklower 54136379Ssklower /* Extract DA */ 542*37469Ssklower da = (struct iso_addr *)buf; 543*37469Ssklower if ((len -= (optlen = *buf++)) <= 0) 54436379Ssklower goto bad; 545*37469Ssklower buf += optlen; 546*37469Ssklower 54736379Ssklower /* Extract better snpa */ 548*37469Ssklower if ((len -= (bsnpalen = *buf++)) < 0) 54936379Ssklower goto bad; 550*37469Ssklower bsnpa = (caddr_t)buf; 551*37469Ssklower buf += optlen; 552*37469Ssklower 553*37469Ssklower /* Extract NET if present */ 554*37469Ssklower if (len) { 555*37469Ssklower net = (struct iso_addr *)buf; 556*37469Ssklower if ((len -= (optlen = *buf++)) < 0) 557*37469Ssklower goto bad; 558*37469Ssklower buf += optlen; 55936379Ssklower } 56036379Ssklower 561*37469Ssklower /* process options */ 562*37469Ssklower while (len > 0) { 563*37469Ssklower switch (*buf++) { 564*37469Ssklower case ESISOVAL_SNPAMASK: 565*37469Ssklower if (snpamask) /* duplicate */ 566*37469Ssklower goto bad; 567*37469Ssklower snpamask = (struct iso_addr *)buf; 568*37469Ssklower break; 569*37469Ssklower 570*37469Ssklower case ESISOVAL_NETMASK: 571*37469Ssklower if (netmask) /* duplicate */ 572*37469Ssklower goto bad; 573*37469Ssklower netmask = (struct iso_addr *)buf; 574*37469Ssklower } 575*37469Ssklower if ((len -= (optlen = *buf)) < 0) 57636379Ssklower goto bad; 577*37469Ssklower buf += 1 + optlen; 57836379Ssklower } 57936379Ssklower 58036379Ssklower IFDEBUG(D_ESISINPUT) 581*37469Ssklower printf("esis_rdinput: rd: ht %d, da %s\n", ht, clnp_iso_addrp(da)); 582*37469Ssklower if (net) 583*37469Ssklower printf("\t: net %s\n", clnp_iso_addrp(net)); 58436379Ssklower ENDDEBUG 58536379Ssklower /* 58636379Ssklower * If netl is zero, then redirect is to an ES. We need to add an entry 58736379Ssklower * to the snpa cache for (destination, better snpa). 58836379Ssklower * If netl is not zero, then the redirect is to an IS. In this 58936379Ssklower * case, add an snpa cache entry for (net, better snpa). 59036379Ssklower * 59136379Ssklower * If the redirect is to an IS, add a route entry towards that 59236379Ssklower * IS. 59336379Ssklower */ 594*37469Ssklower if ((net == 0) || (snpamask)) { 59536379Ssklower /* redirect to an ES */ 596*37469Ssklower snpac_add(shp->snh_ifp, da, bsnpa, bsnpalen, SNPA_ES, ht); 59736379Ssklower } else { 598*37469Ssklower struct iso_addr bsnpa_ia; 599*37469Ssklower 600*37469Ssklower snpac_add(shp->snh_ifp, net, bsnpa, bsnpalen, SNPA_IS, ht); 601*37469Ssklower bcopy(bsnpa, bsnpa_ia.isoa_genaddr, bsnpa_ia.isoa_len = 1 + bsnpalen); 602*37469Ssklower bsnpa_ia.isoa_genaddr[0] = AFI_SNA; 603*37469Ssklower snpac_addrt(da, &bsnpa_ia, net, netmask); 60436379Ssklower } 60536379Ssklower bad: 60636379Ssklower m_freem(m0); 60736379Ssklower } 60836379Ssklower 60936379Ssklower /* 61036379Ssklower * FUNCTION: esis_config 61136379Ssklower * 61236379Ssklower * PURPOSE: Report configuration 61336379Ssklower * 61436379Ssklower * RETURNS: 61536379Ssklower * 61636379Ssklower * SIDE EFFECTS: 61736379Ssklower * 61836379Ssklower * NOTES: Called every esis_config_time seconds 61936379Ssklower */ 62036379Ssklower esis_config() 62136379Ssklower { 62236379Ssklower register struct ifnet *ifp; 62336379Ssklower 62436379Ssklower timeout(esis_config, (caddr_t)0, hz * esis_config_time); 62536379Ssklower 62636379Ssklower /* 62736379Ssklower * Report configuration for each interface that 62836379Ssklower * - is UP 62936379Ssklower * - is not loopback 63036379Ssklower * - has broadcast capabilities 63136379Ssklower * - has an ISO address 63236379Ssklower */ 63336379Ssklower 63436379Ssklower for (ifp = ifnet; ifp; ifp = ifp->if_next) { 63536379Ssklower if ((ifp->if_flags & IFF_UP) && 63636379Ssklower (ifp->if_flags & IFF_BROADCAST) && 63736379Ssklower ((ifp->if_flags & IFF_LOOPBACK) == 0)) { 63836379Ssklower /* search for an ISO address family */ 63936379Ssklower struct ifaddr *ia; 64036379Ssklower 64136379Ssklower for (ia = ifp->if_addrlist; ia; ia = ia->ifa_next) { 642*37469Ssklower if (ia->ifa_addr->sa_family == AF_ISO) { 64336379Ssklower esis_shoutput(ifp, 64436379Ssklower iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH, 64536379Ssklower esis_holding_time, 646*37469Ssklower (caddr_t)(iso_systype & SNPA_ES ? all_is.sc_snpa : 647*37469Ssklower all_es.sc_snpa), 6); 64836379Ssklower break; 64936379Ssklower } 65036379Ssklower } 65136379Ssklower } 65236379Ssklower } 65336379Ssklower } 65436379Ssklower 65536379Ssklower /* 65636379Ssklower * FUNCTION: esis_shoutput 65736379Ssklower * 65836379Ssklower * PURPOSE: Transmit an esh or ish pdu 65936379Ssklower * 66036379Ssklower * RETURNS: nothing 66136379Ssklower * 66236379Ssklower * SIDE EFFECTS: 66336379Ssklower * 66436379Ssklower * NOTES: 66536379Ssklower */ 66636379Ssklower esis_shoutput(ifp, type, ht, sn_addr, sn_len) 66736379Ssklower struct ifnet *ifp; 66836379Ssklower int type; 66936379Ssklower short ht; 67036379Ssklower caddr_t sn_addr; 67136379Ssklower int sn_len; 67236379Ssklower { 67336379Ssklower struct mbuf *m, *m0; 67436379Ssklower caddr_t cp, naddrp; 67536379Ssklower int naddr = 0; 67636379Ssklower struct esis_fixed *pdu; 67736379Ssklower struct ifaddr *ifa; 678*37469Ssklower int len; 67936379Ssklower struct sockaddr_iso siso; 68036379Ssklower 68136379Ssklower if (type == ESIS_ESH) 68236379Ssklower esis_stat.es_eshsent++; 68336379Ssklower else if (type == ESIS_ISH) 68436379Ssklower esis_stat.es_ishsent++; 68536379Ssklower else { 68636379Ssklower printf("esis_shoutput: bad pdu type\n"); 68736379Ssklower return; 68836379Ssklower } 68936379Ssklower 69036379Ssklower IFDEBUG(D_ESISOUTPUT) 69136379Ssklower int i; 69236379Ssklower printf("esis_shoutput: ifp x%x (%s%d), %s, ht %d, to: [%d] ", 69336379Ssklower ifp, ifp->if_name, ifp->if_unit, type == ESIS_ESH ? "esh" : "ish", 69436379Ssklower ht, sn_len); 69536379Ssklower for (i=0; i<sn_len; i++) 69636379Ssklower printf("%x%c", *(sn_addr+i), i < (sn_len-1) ? ':' : ' '); 69736379Ssklower printf("\n"); 69836379Ssklower ENDDEBUG 69936379Ssklower 700*37469Ssklower if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) { 70136379Ssklower esis_stat.es_nomem++; 70236379Ssklower return; 70336379Ssklower } 704*37469Ssklower bzero(mtod(m, caddr_t), MHLEN); 70536379Ssklower 70636379Ssklower pdu = mtod(m, struct esis_fixed *); 707*37469Ssklower naddrp = cp = (caddr_t)(pdu + 1); 70836379Ssklower len = sizeof(struct esis_fixed); 70936379Ssklower 71036379Ssklower /* 71136379Ssklower * Build fixed part of header 71236379Ssklower */ 71336379Ssklower pdu->esis_proto_id = ISO9542_ESIS; 71436379Ssklower pdu->esis_vers = ESIS_VERSION; 71536379Ssklower pdu->esis_type = type; 71636379Ssklower HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); 71736379Ssklower 71836379Ssklower if (type == ESIS_ESH) { 71936379Ssklower cp++; 72036379Ssklower len++; 72136379Ssklower } 72236379Ssklower 723*37469Ssklower m->m_len = len; 72436379Ssklower for (ifa = ifp->if_addrlist; ifa; ifa=ifa->ifa_next) { 725*37469Ssklower if (ifa->ifa_addr->sa_family == AF_ISO) { 72636379Ssklower IFDEBUG(D_ESISOUTPUT) 72736379Ssklower printf("esis_shoutput: adding nsap %s\n", 72836379Ssklower clnp_iso_addrp(&IA_SIS(ifa)->siso_addr)); 72936379Ssklower ENDDEBUG 730*37469Ssklower if (!esis_insert_addr(&cp, &len, &IA_SIS(ifa)->siso_addr, m)) { 731*37469Ssklower EXTEND_PACKET(m, m0, cp); 732*37469Ssklower (void) esis_insert_addr(&cp, &len, &IA_SIS(ifa)->siso_addr, m); 73336379Ssklower } 73436379Ssklower naddr++; 73536379Ssklower if (type == ESIS_ISH) 73636379Ssklower break; 73736379Ssklower } 73836379Ssklower } 73936379Ssklower 74036379Ssklower if (type == ESIS_ESH) 74136379Ssklower *naddrp = naddr; 74236379Ssklower 743*37469Ssklower m0->m_pkthdr.len = len; 744*37469Ssklower pdu->esis_hdr_len = len; 74536379Ssklower iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len); 74636379Ssklower 747*37469Ssklower bzero((caddr_t)&siso, sizeof(siso)); 74836379Ssklower siso.siso_family = AF_ISO; 749*37469Ssklower siso.siso_data[0] = AFI_SNA; 750*37469Ssklower siso.siso_nlen = sn_len + 1; 751*37469Ssklower siso.siso_len = sn_len + 6; 752*37469Ssklower bcopy(sn_addr, siso.siso_data + 1, (unsigned)sn_len); 75336379Ssklower (ifp->if_output)(ifp, m0, &siso); 75436379Ssklower } 75536379Ssklower 75636379Ssklower /* 75736379Ssklower * FUNCTION: esis_ctlinput 75836379Ssklower * 75936379Ssklower * PURPOSE: Handle the PRC_IFDOWN transition 76036379Ssklower * 76136379Ssklower * RETURNS: nothing 76236379Ssklower * 76336379Ssklower * SIDE EFFECTS: 76436379Ssklower * 76536379Ssklower * NOTES: Calls snpac_flush for interface specified. 76636379Ssklower * The loop through iso_ifaddr is stupid because 76736379Ssklower * back in if_down, we knew the ifp... 76836379Ssklower */ 76936379Ssklower esis_ctlinput(req, siso) 77036379Ssklower int req; /* request: we handle only PRC_IFDOWN */ 77136379Ssklower struct sockaddr_iso *siso; /* address of ifp */ 77236379Ssklower { 77336379Ssklower register struct iso_ifaddr *ia; /* scan through interface addresses */ 77436379Ssklower 775*37469Ssklower if (req == PRC_IFDOWN) 776*37469Ssklower for (ia = iso_ifaddr; ia; ia = ia->ia_next) { 777*37469Ssklower if (iso_addrmatch(IA_SIS(ia), siso)) 778*37469Ssklower snpac_flushifp(ia->ia_ifp); 779*37469Ssklower } 78036379Ssklower } 78136379Ssklower 78236379Ssklower #endif ISO 783