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*68259Scgd * @(#)esis.c 8.2 (Berkeley) 02/09/95 849268Sbostic */ 949268Sbostic 1036379Ssklower /*********************************************************** 1136379Ssklower Copyright IBM Corporation 1987 1236379Ssklower 1336379Ssklower All Rights Reserved 1436379Ssklower 1536379Ssklower Permission to use, copy, modify, and distribute this software and its 1636379Ssklower documentation for any purpose and without fee is hereby granted, 1736379Ssklower provided that the above copyright notice appear in all copies and that 1836379Ssklower both that copyright notice and this permission notice appear in 1936379Ssklower supporting documentation, and that the name of IBM not be 2036379Ssklower used in advertising or publicity pertaining to distribution of the 2136379Ssklower software without specific, written prior permission. 2236379Ssklower 2336379Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 2436379Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 2536379Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 2636379Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 2736379Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 2836379Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 2936379Ssklower SOFTWARE. 3036379Ssklower 3136379Ssklower ******************************************************************/ 3236379Ssklower 3336379Ssklower /* 3436379Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 3536379Ssklower */ 3636379Ssklower 3736379Ssklower #ifdef ISO 3836379Ssklower 3956533Sbostic #include <sys/param.h> 4056533Sbostic #include <sys/systm.h> 4156533Sbostic #include <sys/mbuf.h> 4256533Sbostic #include <sys/domain.h> 4356533Sbostic #include <sys/protosw.h> 4456533Sbostic #include <sys/socket.h> 4556533Sbostic #include <sys/socketvar.h> 4656533Sbostic #include <sys/errno.h> 4756533Sbostic #include <sys/kernel.h> 4836379Ssklower 4956533Sbostic #include <net/if.h> 5056533Sbostic #include <net/if_dl.h> 5156533Sbostic #include <net/route.h> 5256533Sbostic #include <net/raw_cb.h> 5336379Ssklower 5456533Sbostic #include <netiso/iso.h> 5556533Sbostic #include <netiso/iso_pcb.h> 5656533Sbostic #include <netiso/iso_var.h> 5756533Sbostic #include <netiso/iso_snpac.h> 5856533Sbostic #include <netiso/clnl.h> 5956533Sbostic #include <netiso/clnp.h> 6056533Sbostic #include <netiso/clnp_stat.h> 6156533Sbostic #include <netiso/esis.h> 6256533Sbostic #include <netiso/argo_debug.h> 6336379Ssklower 6436379Ssklower /* 6536379Ssklower * Global variables to esis implementation 6636379Ssklower * 6736379Ssklower * esis_holding_time - the holding time (sec) parameter for outgoing pdus 6836379Ssklower * esis_config_time - the frequency (sec) that hellos are generated 6943421Ssklower * esis_esconfig_time - suggested es configuration time placed in the 7043421Ssklower * ish. 7136379Ssklower * 7236379Ssklower */ 7343421Ssklower struct rawcb esis_pcb; 7458988Ssklower void esis_config(), snpac_age(); 7536379Ssklower int esis_sendspace = 2048; 7636379Ssklower int esis_recvspace = 2048; 7736379Ssklower short esis_holding_time = ESIS_HT; 7836379Ssklower short esis_config_time = ESIS_CONFIG; 7943421Ssklower short esis_esconfig_time = ESIS_CONFIG; 8036379Ssklower extern int iso_systype; 8143421Ssklower struct sockaddr_dl esis_dl = { sizeof(esis_dl), AF_LINK }; 8243332Ssklower extern char all_es_snpa[], all_is_snpa[]; 8336379Ssklower 8437469Ssklower #define EXTEND_PACKET(m, mhdr, cp)\ 8536379Ssklower if (((m)->m_next = m_getclr(M_DONTWAIT, MT_HEADER)) == NULL) {\ 8636379Ssklower esis_stat.es_nomem++;\ 8736379Ssklower m_freem(mhdr);\ 8836379Ssklower return;\ 8936379Ssklower } else {\ 9036379Ssklower (m) = (m)->m_next;\ 9136379Ssklower (cp) = mtod((m), caddr_t);\ 9236379Ssklower } 9336379Ssklower /* 9436379Ssklower * FUNCTION: esis_init 9536379Ssklower * 9636379Ssklower * PURPOSE: Initialize the kernel portion of esis protocol 9736379Ssklower * 9836379Ssklower * RETURNS: nothing 9936379Ssklower * 10036379Ssklower * SIDE EFFECTS: 10136379Ssklower * 10236379Ssklower * NOTES: 10336379Ssklower */ 10436379Ssklower esis_init() 10536379Ssklower { 10636379Ssklower extern struct clnl_protosw clnl_protox[256]; 10743892Ssklower int esis_input(), isis_input(); 10836379Ssklower #ifdef ISO_X25ESIS 10943892Ssklower int x25esis_input(); 11061300Ssklower #endif /* ISO_X25ESIS */ 11136379Ssklower 11243421Ssklower esis_pcb.rcb_next = esis_pcb.rcb_prev = &esis_pcb; 11343421Ssklower llinfo_llc.lc_next = llinfo_llc.lc_prev = &llinfo_llc; 11436379Ssklower 11536379Ssklower timeout(snpac_age, (caddr_t)0, hz); 11636379Ssklower timeout(esis_config, (caddr_t)0, hz); 11736379Ssklower 11843892Ssklower clnl_protox[ISO9542_ESIS].clnl_input = esis_input; 11943892Ssklower clnl_protox[ISO10589_ISIS].clnl_input = isis_input; 12036379Ssklower #ifdef ISO_X25ESIS 12136379Ssklower clnl_protox[ISO9542X25_ESIS].clnl_input = x25esis_input; 12261300Ssklower #endif /* ISO_X25ESIS */ 12336379Ssklower } 12436379Ssklower 12536379Ssklower /* 12636379Ssklower * FUNCTION: esis_usrreq 12736379Ssklower * 12836379Ssklower * PURPOSE: Handle user level esis requests 12936379Ssklower * 13036379Ssklower * RETURNS: 0 or appropriate errno 13136379Ssklower * 13236379Ssklower * SIDE EFFECTS: 13336379Ssklower * 13436379Ssklower */ 13537469Ssklower /*ARGSUSED*/ 13640775Ssklower esis_usrreq(so, req, m, nam, control) 13736379Ssklower struct socket *so; /* socket: used only to get to this code */ 13836379Ssklower int req; /* request */ 13936379Ssklower struct mbuf *m; /* data for request */ 14036379Ssklower struct mbuf *nam; /* optional name */ 14140775Ssklower struct mbuf *control; /* optional control */ 14236379Ssklower { 14343421Ssklower struct rawcb *rp = sotorawcb(so); 14443421Ssklower int error = 0; 14543421Ssklower 14650234Ssklower if ((so->so_state & SS_PRIV) == 0) { 14743421Ssklower error = EACCES; 14843421Ssklower goto release; 14943421Ssklower } 15043421Ssklower if (rp == NULL && req != PRU_ATTACH) { 15143421Ssklower error = EINVAL; 15243421Ssklower goto release; 15343421Ssklower } 15443421Ssklower 15543421Ssklower switch (req) { 15643421Ssklower case PRU_ATTACH: 15743421Ssklower if (rp != NULL) { 15843421Ssklower error = EINVAL; 15943421Ssklower break; 16043421Ssklower } 16143421Ssklower MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK); 16243421Ssklower if (so->so_pcb = (caddr_t)rp) { 16343421Ssklower bzero(so->so_pcb, sizeof(*rp)); 16443421Ssklower insque(rp, &esis_pcb); 16544946Ssklower rp->rcb_socket = so; 16643421Ssklower error = soreserve(so, esis_sendspace, esis_recvspace); 16743421Ssklower } else 16843421Ssklower error = ENOBUFS; 16943421Ssklower break; 17043421Ssklower 17143421Ssklower case PRU_SEND: 17243421Ssklower if (nam == NULL) { 17343421Ssklower error = EINVAL; 17443421Ssklower break; 17543421Ssklower } 17643421Ssklower /* error checking here */ 17743421Ssklower error = isis_output(mtod(nam,struct sockaddr_dl *), m); 17843421Ssklower m = NULL; 17943421Ssklower break; 18043421Ssklower 18143421Ssklower case PRU_DETACH: 18243421Ssklower raw_detach(rp); 18343421Ssklower break; 18443421Ssklower 18543421Ssklower case PRU_SHUTDOWN: 18643421Ssklower socantsendmore(so); 18743421Ssklower break; 18843421Ssklower 18943421Ssklower case PRU_ABORT: 19043421Ssklower soisdisconnected(so); 19143421Ssklower raw_detach(rp); 19243421Ssklower break; 19343421Ssklower 19443421Ssklower case PRU_SENSE: 19543421Ssklower return (0); 19643421Ssklower 19743421Ssklower default: 19843421Ssklower return (EOPNOTSUPP); 19943421Ssklower } 20043421Ssklower release: 20136379Ssklower if (m != NULL) 20236379Ssklower m_freem(m); 20336379Ssklower 20443421Ssklower return (error); 20536379Ssklower } 20636379Ssklower 20736379Ssklower /* 20836379Ssklower * FUNCTION: esis_input 20936379Ssklower * 21036379Ssklower * PURPOSE: Process an incoming esis packet 21136379Ssklower * 21236379Ssklower * RETURNS: nothing 21336379Ssklower * 21436379Ssklower * SIDE EFFECTS: 21536379Ssklower * 21636379Ssklower * NOTES: 21736379Ssklower */ 21836379Ssklower esis_input(m0, shp) 21936379Ssklower struct mbuf *m0; /* ptr to first mbuf of pkt */ 22036379Ssklower struct snpa_hdr *shp; /* subnetwork header */ 22136379Ssklower { 22243421Ssklower register struct esis_fixed *pdu = mtod(m0, struct esis_fixed *); 22337469Ssklower register int type; 22436379Ssklower 22536379Ssklower /* 22636379Ssklower * check checksum if necessary 22736379Ssklower */ 22837469Ssklower if (ESIS_CKSUM_REQUIRED(pdu) && iso_check_csum(m0, (int)pdu->esis_hdr_len)) { 22936379Ssklower esis_stat.es_badcsum++; 23036379Ssklower goto bad; 23136379Ssklower } 23236379Ssklower 23336379Ssklower /* check version */ 23436379Ssklower if (pdu->esis_vers != ESIS_VERSION) { 23536379Ssklower esis_stat.es_badvers++; 23636379Ssklower goto bad; 23736379Ssklower } 23837469Ssklower type = pdu->esis_type & 0x1f; 23937469Ssklower switch (type) { 24036379Ssklower case ESIS_ESH: 24136379Ssklower esis_eshinput(m0, shp); 24243421Ssklower break; 24336379Ssklower 24436379Ssklower case ESIS_ISH: 24536379Ssklower esis_ishinput(m0, shp); 24643421Ssklower break; 24736379Ssklower 24836379Ssklower case ESIS_RD: 24936379Ssklower esis_rdinput(m0, shp); 25043421Ssklower break; 25136379Ssklower 25243421Ssklower default: 25336379Ssklower esis_stat.es_badtype++; 25436379Ssklower } 25536379Ssklower 25636379Ssklower bad: 25743421Ssklower if (esis_pcb.rcb_next != &esis_pcb) 25843421Ssklower isis_input(m0, shp); 25943421Ssklower else 26043421Ssklower m_freem(m0); 26136379Ssklower } 26236379Ssklower 26336379Ssklower /* 26436379Ssklower * FUNCTION: esis_rdoutput 26536379Ssklower * 26636379Ssklower * PURPOSE: Transmit a redirect pdu 26736379Ssklower * 26836379Ssklower * RETURNS: nothing 26936379Ssklower * 27036379Ssklower * SIDE EFFECTS: 27136379Ssklower * 27236379Ssklower * NOTES: Assumes there is enough space for fixed part of header, 27336379Ssklower * DA, BSNPA and NET in first mbuf. 27436379Ssklower */ 27543332Ssklower esis_rdoutput(inbound_shp, inbound_m, inbound_oidx, rd_dstnsap, rt) 27636379Ssklower struct snpa_hdr *inbound_shp; /* snpa hdr from incoming packet */ 27736379Ssklower struct mbuf *inbound_m; /* incoming pkt itself */ 27836379Ssklower struct clnp_optidx *inbound_oidx; /* clnp options assoc with incoming pkt */ 27936379Ssklower struct iso_addr *rd_dstnsap; /* ultimate destination of pkt */ 28043332Ssklower struct rtentry *rt; /* snpa cache info regarding next hop of 28136379Ssklower pkt */ 28236379Ssklower { 28336379Ssklower struct mbuf *m, *m0; 28436379Ssklower caddr_t cp; 28536379Ssklower struct esis_fixed *pdu; 28636379Ssklower int len, total_len = 0; 28736379Ssklower struct sockaddr_iso siso; 28836379Ssklower struct ifnet *ifp = inbound_shp->snh_ifp; 28943332Ssklower struct sockaddr_dl *sdl; 29043332Ssklower struct iso_addr *rd_gwnsap; 29136379Ssklower 29243332Ssklower if (rt->rt_flags & RTF_GATEWAY) { 29343332Ssklower rd_gwnsap = &((struct sockaddr_iso *)rt->rt_gateway)->siso_addr; 29443332Ssklower rt = rtalloc1(rt->rt_gateway, 0); 29543332Ssklower } else 29643332Ssklower rd_gwnsap = &((struct sockaddr_iso *)rt_key(rt))->siso_addr; 29743332Ssklower if (rt == 0 || (sdl = (struct sockaddr_dl *)rt->rt_gateway) == 0 || 29843332Ssklower sdl->sdl_family != AF_LINK) { 29943332Ssklower /* maybe we should have a function that you 30043332Ssklower could put in the iso_ifaddr structure 30143332Ssklower which could translate iso_addrs into snpa's 30243332Ssklower where there is a known mapping for that address type */ 30343332Ssklower esis_stat.es_badtype++; 30443332Ssklower return; 30543332Ssklower } 30636379Ssklower esis_stat.es_rdsent++; 30736379Ssklower IFDEBUG(D_ESISOUTPUT) 30836379Ssklower printf("esis_rdoutput: ifp x%x (%s%d), ht %d, m x%x, oidx x%x\n", 30936379Ssklower ifp, ifp->if_name, ifp->if_unit, esis_holding_time, inbound_m, 31036379Ssklower inbound_oidx); 31136379Ssklower printf("\tdestination: %s\n", clnp_iso_addrp(rd_dstnsap)); 31243332Ssklower printf("\tredirected toward:%s\n", clnp_iso_addrp(rd_gwnsap)); 31336379Ssklower ENDDEBUG 31436379Ssklower 31537469Ssklower if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) { 31636379Ssklower esis_stat.es_nomem++; 31736379Ssklower return; 31836379Ssklower } 31937469Ssklower bzero(mtod(m, caddr_t), MHLEN); 32036379Ssklower 32136379Ssklower pdu = mtod(m, struct esis_fixed *); 32237469Ssklower cp = (caddr_t)(pdu + 1); /*pointer arith.; 1st byte after header */ 32336379Ssklower len = sizeof(struct esis_fixed); 32436379Ssklower 32536379Ssklower /* 32636379Ssklower * Build fixed part of header 32736379Ssklower */ 32836379Ssklower pdu->esis_proto_id = ISO9542_ESIS; 32936379Ssklower pdu->esis_vers = ESIS_VERSION; 33036379Ssklower pdu->esis_type = ESIS_RD; 33136379Ssklower HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, esis_holding_time); 33236379Ssklower 33336379Ssklower /* Insert destination address */ 33443072Ssklower (void) esis_insert_addr(&cp, &len, rd_dstnsap, m, 0); 33536379Ssklower 33636379Ssklower /* Insert the snpa of better next hop */ 33743332Ssklower *cp++ = sdl->sdl_alen; 33843332Ssklower bcopy(LLADDR(sdl), cp, sdl->sdl_alen); 33943332Ssklower cp += sdl->sdl_alen; 34043332Ssklower len += (sdl->sdl_alen + 1); 34136379Ssklower 34236379Ssklower /* 34336379Ssklower * If the next hop is not the destination, then it ought to be 34436379Ssklower * an IS and it should be inserted next. Else, set the 34536379Ssklower * NETL to 0 34636379Ssklower */ 34736379Ssklower /* PHASE2 use mask from ifp of outgoing interface */ 34843332Ssklower if (!iso_addrmatch1(rd_dstnsap, rd_gwnsap)) { 34943332Ssklower /* this should not happen: 35036379Ssklower if ((nhop_sc->sc_flags & SNPA_IS) == 0) { 35136379Ssklower printf("esis_rdoutput: next hop is not dst and not an IS\n"); 35236379Ssklower m_freem(m0); 35336379Ssklower return; 35443332Ssklower } */ 35543332Ssklower (void) esis_insert_addr(&cp, &len, rd_gwnsap, m, 0); 35636379Ssklower } else { 35736379Ssklower *cp++ = 0; /* NETL */ 35836379Ssklower len++; 35936379Ssklower } 36037469Ssklower m->m_len = len; 36136379Ssklower 36236379Ssklower /* 36336379Ssklower * PHASE2 36436379Ssklower * If redirect is to an IS, add an address mask. The mask to be 36536379Ssklower * used should be the mask present in the routing entry used to 36636379Ssklower * forward the original data packet. 36736379Ssklower */ 36836379Ssklower 36936379Ssklower /* 37036379Ssklower * Copy Qos, priority, or security options present in original npdu 37136379Ssklower */ 37236379Ssklower if (inbound_oidx) { 37343332Ssklower /* THIS CODE IS CURRENTLY (mostly) UNTESTED */ 37436379Ssklower int optlen = 0; 37536379Ssklower if (inbound_oidx->cni_qos_formatp) 37636379Ssklower optlen += (inbound_oidx->cni_qos_len + 2); 37736379Ssklower if (inbound_oidx->cni_priorp) /* priority option is 1 byte long */ 37836379Ssklower optlen += 3; 37936379Ssklower if (inbound_oidx->cni_securep) 38036379Ssklower optlen += (inbound_oidx->cni_secure_len + 2); 38137469Ssklower if (M_TRAILINGSPACE(m) < optlen) { 38237469Ssklower EXTEND_PACKET(m, m0, cp); 38337469Ssklower m->m_len = 0; 38436379Ssklower /* assumes MLEN > optlen */ 38536379Ssklower } 38636379Ssklower /* assume MLEN-len > optlen */ 38736379Ssklower /* 38836379Ssklower * When copying options, copy from ptr - 2 in order to grab 38936379Ssklower * the option code and length 39036379Ssklower */ 39136379Ssklower if (inbound_oidx->cni_qos_formatp) { 39243332Ssklower bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_qos_formatp - 2, 39343332Ssklower cp, (unsigned)(inbound_oidx->cni_qos_len + 2)); 39443332Ssklower cp += inbound_oidx->cni_qos_len + 2; 39536379Ssklower } 39636379Ssklower if (inbound_oidx->cni_priorp) { 39743332Ssklower bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_priorp - 2, 39843332Ssklower cp, 3); 39943332Ssklower cp += 3; 40036379Ssklower } 40136379Ssklower if (inbound_oidx->cni_securep) { 40243332Ssklower bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_securep - 2, cp, 40337469Ssklower (unsigned)(inbound_oidx->cni_secure_len + 2)); 40443332Ssklower cp += inbound_oidx->cni_secure_len + 2; 40536379Ssklower } 40637469Ssklower m->m_len += optlen; 40743332Ssklower len += optlen; 40836379Ssklower } 40936379Ssklower 41037469Ssklower pdu->esis_hdr_len = m0->m_pkthdr.len = len; 41136379Ssklower iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len); 41236379Ssklower 41337469Ssklower bzero((caddr_t)&siso, sizeof(siso)); 41436379Ssklower siso.siso_family = AF_ISO; 41537469Ssklower siso.siso_data[0] = AFI_SNA; 41637469Ssklower siso.siso_nlen = 6 + 1; /* should be taken from snpa_hdr */ 41736379Ssklower /* +1 is for AFI */ 41837469Ssklower bcopy(inbound_shp->snh_shost, siso.siso_data + 1, 6); 41952625Ssklower (ifp->if_output)(ifp, m0, (struct sockaddr *)&siso, 0); 42036379Ssklower } 42136379Ssklower 42236379Ssklower /* 42336379Ssklower * FUNCTION: esis_insert_addr 42436379Ssklower * 42536379Ssklower * PURPOSE: Insert an iso_addr into a buffer 42636379Ssklower * 42736379Ssklower * RETURNS: true if buffer was big enough, else false 42836379Ssklower * 42936379Ssklower * SIDE EFFECTS: Increment buf & len according to size of iso_addr 43036379Ssklower * 43136379Ssklower * NOTES: Plus 1 here is for length byte 43236379Ssklower */ 43343072Ssklower esis_insert_addr(buf, len, isoa, m, nsellen) 43443332Ssklower register caddr_t *buf; /* ptr to buffer to put address into */ 43543332Ssklower int *len; /* ptr to length of buffer so far */ 43643332Ssklower register struct iso_addr *isoa; /* ptr to address */ 43743332Ssklower register struct mbuf *m; /* determine if there remains space */ 43843332Ssklower int nsellen; 43936379Ssklower { 44043332Ssklower register int newlen, result = 0; 44136379Ssklower 44243332Ssklower isoa->isoa_len -= nsellen; 44343332Ssklower newlen = isoa->isoa_len + 1; 44443332Ssklower if (newlen <= M_TRAILINGSPACE(m)) { 44543332Ssklower bcopy((caddr_t)isoa, *buf, newlen); 44643332Ssklower *len += newlen; 44743332Ssklower *buf += newlen; 44843332Ssklower m->m_len += newlen; 44943332Ssklower result = 1; 45043332Ssklower } 45143332Ssklower isoa->isoa_len += nsellen; 45243332Ssklower return (result); 45336379Ssklower } 45436379Ssklower 45539950Ssklower #define ESIS_EXTRACT_ADDR(d, b) { d = (struct iso_addr *)(b); b += (1 + *b); \ 45639950Ssklower if (b > buflim) {esis_stat.es_toosmall++; goto bad;}} 45739950Ssklower #define ESIS_NEXT_OPTION(b) { b += (2 + b[1]); \ 45839950Ssklower if (b > buflim) {esis_stat.es_toosmall++; goto bad;}} 45943430Ssklower int ESHonly = 0; 46036379Ssklower /* 46136379Ssklower 46236379Ssklower /* 46336379Ssklower * FUNCTION: esis_eshinput 46436379Ssklower * 46536379Ssklower * PURPOSE: Process an incoming ESH pdu 46636379Ssklower * 46736379Ssklower * RETURNS: nothing 46836379Ssklower * 46936379Ssklower * SIDE EFFECTS: 47036379Ssklower * 47136379Ssklower * NOTES: 47236379Ssklower */ 47336379Ssklower esis_eshinput(m, shp) 47436379Ssklower struct mbuf *m; /* esh pdu */ 47536379Ssklower struct snpa_hdr *shp; /* subnetwork header */ 47636379Ssklower { 47743072Ssklower struct esis_fixed *pdu = mtod(m, struct esis_fixed *); 47836379Ssklower u_short ht; /* holding time */ 47943072Ssklower struct iso_addr *nsap; 48039950Ssklower int naddr; 48137469Ssklower u_char *buf = (u_char *)(pdu + 1); 48239950Ssklower u_char *buflim = pdu->esis_hdr_len + (u_char *)pdu; 48343332Ssklower int new_entry = 0; 48436379Ssklower 48536379Ssklower esis_stat.es_eshrcvd++; 48636379Ssklower 48736379Ssklower CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); 48836379Ssklower 48939950Ssklower naddr = *buf++; 49039950Ssklower if (buf >= buflim) 49136379Ssklower goto bad; 49243332Ssklower if (naddr == 1) { 49339950Ssklower ESIS_EXTRACT_ADDR(nsap, buf); 49443332Ssklower new_entry = snpac_add(shp->snh_ifp, 49543332Ssklower nsap, shp->snh_shost, SNPA_ES, ht, 0); 49643332Ssklower } else { 49743332Ssklower int nsellength = 0, nlen = 0; 49843332Ssklower { 49943332Ssklower /* See if we want to compress out multiple nsaps differing 50043332Ssklower only by nsel */ 50143332Ssklower register struct ifaddr *ifa = shp->snh_ifp->if_addrlist; 50243332Ssklower for (; ifa; ifa = ifa->ifa_next) 50343332Ssklower if (ifa->ifa_addr->sa_family == AF_ISO) { 50443332Ssklower nsellength = ((struct iso_ifaddr *)ifa)->ia_addr.siso_tlen; 50543332Ssklower break; 50643332Ssklower } 50743332Ssklower } 50839950Ssklower IFDEBUG(D_ESISINPUT) 50943332Ssklower printf("esis_eshinput: esh: ht %d, naddr %d nsellength %d\n", 51043332Ssklower ht, naddr, nsellength); 51139950Ssklower ENDDEBUG 51243332Ssklower while (naddr-- > 0) { 51343332Ssklower struct iso_addr *nsap2; u_char *buf2; 51443332Ssklower ESIS_EXTRACT_ADDR(nsap, buf); 51543332Ssklower /* see if there is at least one more nsap in ESH differing 51643332Ssklower only by nsel */ 51743332Ssklower if (nsellength != 0) for (buf2 = buf; buf2 < buflim;) { 51843332Ssklower ESIS_EXTRACT_ADDR(nsap2, buf2); 51943332Ssklower IFDEBUG(D_ESISINPUT) 52043332Ssklower printf("esis_eshinput: comparing %s ", 52143332Ssklower clnp_iso_addrp(nsap)); 52243332Ssklower printf("and %s\n", clnp_iso_addrp(nsap2)); 52343332Ssklower ENDDEBUG 52443332Ssklower if (Bcmp(nsap->isoa_genaddr, nsap2->isoa_genaddr, 52543332Ssklower nsap->isoa_len - nsellength) == 0) { 52643332Ssklower nlen = nsellength; 52743332Ssklower break; 52843332Ssklower } 52943332Ssklower } 53043332Ssklower new_entry |= snpac_add(shp->snh_ifp, 53143332Ssklower nsap, shp->snh_shost, SNPA_ES, ht, nlen); 53243332Ssklower nlen = 0; 53343332Ssklower } 53439950Ssklower } 53543332Ssklower IFDEBUG(D_ESISINPUT) 53643332Ssklower printf("esis_eshinput: nsap %s is %s\n", 53743332Ssklower clnp_iso_addrp(nsap), new_entry ? "new" : "old"); 53843332Ssklower ENDDEBUG 53943332Ssklower if (new_entry && (iso_systype & SNPA_IS)) 54043332Ssklower esis_shoutput(shp->snh_ifp, ESIS_ISH, esis_holding_time, 54143332Ssklower shp->snh_shost, 6, (struct iso_addr *)0); 54237469Ssklower bad: 54339950Ssklower return; 54436379Ssklower } 54536379Ssklower 54636379Ssklower /* 54736379Ssklower * FUNCTION: esis_ishinput 54836379Ssklower * 54936379Ssklower * PURPOSE: process an incoming ISH pdu 55036379Ssklower * 55136379Ssklower * RETURNS: 55236379Ssklower * 55336379Ssklower * SIDE EFFECTS: 55436379Ssklower * 55536379Ssklower * NOTES: 55636379Ssklower */ 55736379Ssklower esis_ishinput(m, shp) 55836379Ssklower struct mbuf *m; /* esh pdu */ 55936379Ssklower struct snpa_hdr *shp; /* subnetwork header */ 56036379Ssklower { 56136379Ssklower struct esis_fixed *pdu = mtod(m, struct esis_fixed *); 56243430Ssklower u_short ht, newct; /* holding time */ 56339950Ssklower struct iso_addr *nsap; /* Network Entity Title */ 56439950Ssklower register u_char *buf = (u_char *) (pdu + 1); 56539950Ssklower register u_char *buflim = pdu->esis_hdr_len + (u_char *)pdu; 56639950Ssklower int new_entry; 56736379Ssklower 56836379Ssklower esis_stat.es_ishrcvd++; 56936379Ssklower CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); 57036379Ssklower 57136379Ssklower IFDEBUG(D_ESISINPUT) 57236379Ssklower printf("esis_ishinput: ish: ht %d\n", ht); 57336379Ssklower ENDDEBUG 57439950Ssklower if (ESHonly) 57537469Ssklower goto bad; 57636379Ssklower 57739950Ssklower ESIS_EXTRACT_ADDR(nsap, buf); 57839950Ssklower 57939950Ssklower while (buf < buflim) { 58039950Ssklower switch (*buf) { 58137469Ssklower case ESISOVAL_ESCT: 58244946Ssklower if (iso_systype & SNPA_IS) 58344946Ssklower break; 58439950Ssklower if (buf[1] != 2) 58537469Ssklower goto bad; 58643430Ssklower CTOH(buf[2], buf[3], newct); 58743430Ssklower if (esis_config_time != newct) { 58843430Ssklower untimeout(esis_config,0); 58943430Ssklower esis_config_time = newct; 59043430Ssklower esis_config(); 59143430Ssklower } 59239950Ssklower break; 59339950Ssklower 59439950Ssklower default: 59539950Ssklower printf("Unknown ISH option: %x\n", *buf); 59637469Ssklower } 59739950Ssklower ESIS_NEXT_OPTION(buf); 59837469Ssklower } 59943332Ssklower new_entry = snpac_add(shp->snh_ifp, nsap, shp->snh_shost, SNPA_IS, ht, 0); 60037469Ssklower IFDEBUG(D_ESISINPUT) 60137469Ssklower printf("esis_ishinput: nsap %s is %s\n", 60237469Ssklower clnp_iso_addrp(nsap), new_entry ? "new" : "old"); 60337469Ssklower ENDDEBUG 60437469Ssklower 60537469Ssklower if (new_entry) 60637469Ssklower esis_shoutput(shp->snh_ifp, 60737469Ssklower iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH, 60843332Ssklower esis_holding_time, shp->snh_shost, 6, (struct iso_addr *)0); 60939950Ssklower bad: 61039950Ssklower return; 61136379Ssklower } 61236379Ssklower 61336379Ssklower /* 61436379Ssklower * FUNCTION: esis_rdinput 61536379Ssklower * 61636379Ssklower * PURPOSE: Process an incoming RD pdu 61736379Ssklower * 61836379Ssklower * RETURNS: 61936379Ssklower * 62036379Ssklower * SIDE EFFECTS: 62136379Ssklower * 62236379Ssklower * NOTES: 62336379Ssklower */ 62436379Ssklower esis_rdinput(m0, shp) 62536379Ssklower struct mbuf *m0; /* esh pdu */ 62636379Ssklower struct snpa_hdr *shp; /* subnetwork header */ 62736379Ssklower { 62836379Ssklower struct esis_fixed *pdu = mtod(m0, struct esis_fixed *); 62936379Ssklower u_short ht; /* holding time */ 63039950Ssklower struct iso_addr *da, *net = 0, *netmask = 0, *snpamask = 0; 63139950Ssklower register struct iso_addr *bsnpa; 63239950Ssklower register u_char *buf = (u_char *)(pdu + 1); 63339950Ssklower register u_char *buflim = pdu->esis_hdr_len + (u_char *)pdu; 63436379Ssklower 63536379Ssklower esis_stat.es_rdrcvd++; 63636379Ssklower 63736379Ssklower /* intermediate systems ignore redirects */ 63836379Ssklower if (iso_systype & SNPA_IS) 63943421Ssklower return; 64039950Ssklower if (ESHonly) 64143421Ssklower return; 64236379Ssklower 64336379Ssklower CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); 64439950Ssklower if (buf >= buflim) 64543421Ssklower return; 64636379Ssklower 64736379Ssklower /* Extract DA */ 64839950Ssklower ESIS_EXTRACT_ADDR(da, buf); 64937469Ssklower 65036379Ssklower /* Extract better snpa */ 65139950Ssklower ESIS_EXTRACT_ADDR(bsnpa, buf); 65239950Ssklower 65337469Ssklower /* Extract NET if present */ 65439950Ssklower if (buf < buflim) { 65543332Ssklower if (*buf == 0) 65643332Ssklower buf++; /* no NET present, skip NETL anyway */ 65743332Ssklower else 65843332Ssklower ESIS_EXTRACT_ADDR(net, buf); 65936379Ssklower } 66036379Ssklower 66137469Ssklower /* process options */ 66239950Ssklower while (buf < buflim) { 66339950Ssklower switch (*buf) { 66437469Ssklower case ESISOVAL_SNPAMASK: 66537469Ssklower if (snpamask) /* duplicate */ 66643421Ssklower return; 66739950Ssklower snpamask = (struct iso_addr *)(buf + 1); 66837469Ssklower break; 66937469Ssklower 67037469Ssklower case ESISOVAL_NETMASK: 67137469Ssklower if (netmask) /* duplicate */ 67243421Ssklower return; 67339950Ssklower netmask = (struct iso_addr *)(buf + 1); 67439950Ssklower break; 67539950Ssklower 67639950Ssklower default: 67739950Ssklower printf("Unknown option in ESIS RD (0x%x)\n", buf[-1]); 67837469Ssklower } 67939950Ssklower ESIS_NEXT_OPTION(buf); 68036379Ssklower } 68136379Ssklower 68236379Ssklower IFDEBUG(D_ESISINPUT) 68337469Ssklower printf("esis_rdinput: rd: ht %d, da %s\n", ht, clnp_iso_addrp(da)); 68437469Ssklower if (net) 68537469Ssklower printf("\t: net %s\n", clnp_iso_addrp(net)); 68636379Ssklower ENDDEBUG 68736379Ssklower /* 68836379Ssklower * If netl is zero, then redirect is to an ES. We need to add an entry 68936379Ssklower * to the snpa cache for (destination, better snpa). 69036379Ssklower * If netl is not zero, then the redirect is to an IS. In this 69136379Ssklower * case, add an snpa cache entry for (net, better snpa). 69236379Ssklower * 69336379Ssklower * If the redirect is to an IS, add a route entry towards that 69436379Ssklower * IS. 69536379Ssklower */ 69639950Ssklower if (net == 0 || net->isoa_len == 0 || snpamask) { 69736379Ssklower /* redirect to an ES */ 69839950Ssklower snpac_add(shp->snh_ifp, da, 69943332Ssklower bsnpa->isoa_genaddr, SNPA_ES, ht, 0); 70036379Ssklower } else { 70139950Ssklower snpac_add(shp->snh_ifp, net, 70243332Ssklower bsnpa->isoa_genaddr, SNPA_IS, ht, 0); 70339950Ssklower snpac_addrt(shp->snh_ifp, da, net, netmask); 70436379Ssklower } 70543421Ssklower bad: ; /* Needed by ESIS_NEXT_OPTION */ 70636379Ssklower } 70736379Ssklower 70836379Ssklower /* 70936379Ssklower * FUNCTION: esis_config 71036379Ssklower * 71136379Ssklower * PURPOSE: Report configuration 71236379Ssklower * 71336379Ssklower * RETURNS: 71436379Ssklower * 71536379Ssklower * SIDE EFFECTS: 71636379Ssklower * 71736379Ssklower * NOTES: Called every esis_config_time seconds 71836379Ssklower */ 71958988Ssklower void 72036379Ssklower esis_config() 72136379Ssklower { 72236379Ssklower register struct ifnet *ifp; 72336379Ssklower 72436379Ssklower timeout(esis_config, (caddr_t)0, hz * esis_config_time); 72536379Ssklower 72636379Ssklower /* 72736379Ssklower * Report configuration for each interface that 72836379Ssklower * - is UP 72948963Ssklower * - has BROADCAST capability 73036379Ssklower * - has an ISO address 73136379Ssklower */ 73248963Ssklower /* Todo: a better way would be to construct the esh or ish 73348963Ssklower * once and copy it out for all devices, possibly calling 73448963Ssklower * a method in the iso_ifaddr structure to encapsulate and 73548963Ssklower * transmit it. This could work to advantage for non-broadcast media 73648963Ssklower */ 73736379Ssklower 73836379Ssklower for (ifp = ifnet; ifp; ifp = ifp->if_next) { 73936379Ssklower if ((ifp->if_flags & IFF_UP) && 74048963Ssklower (ifp->if_flags & IFF_BROADCAST)) { 74136379Ssklower /* search for an ISO address family */ 74236379Ssklower struct ifaddr *ia; 74336379Ssklower 74436379Ssklower for (ia = ifp->if_addrlist; ia; ia = ia->ifa_next) { 74537469Ssklower if (ia->ifa_addr->sa_family == AF_ISO) { 74636379Ssklower esis_shoutput(ifp, 74736379Ssklower iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH, 74836379Ssklower esis_holding_time, 74943332Ssklower (caddr_t)(iso_systype & SNPA_ES ? all_is_snpa : 75043332Ssklower all_es_snpa), 6, (struct iso_addr *)0); 75136379Ssklower break; 75236379Ssklower } 75336379Ssklower } 75436379Ssklower } 75536379Ssklower } 75636379Ssklower } 75736379Ssklower 75836379Ssklower /* 75936379Ssklower * FUNCTION: esis_shoutput 76036379Ssklower * 76136379Ssklower * PURPOSE: Transmit an esh or ish pdu 76236379Ssklower * 76336379Ssklower * RETURNS: nothing 76436379Ssklower * 76536379Ssklower * SIDE EFFECTS: 76636379Ssklower * 76736379Ssklower * NOTES: 76836379Ssklower */ 76943332Ssklower esis_shoutput(ifp, type, ht, sn_addr, sn_len, isoa) 77036379Ssklower struct ifnet *ifp; 77136379Ssklower int type; 77236379Ssklower short ht; 77336379Ssklower caddr_t sn_addr; 77436379Ssklower int sn_len; 77543332Ssklower struct iso_addr *isoa; 77636379Ssklower { 77736379Ssklower struct mbuf *m, *m0; 77836379Ssklower caddr_t cp, naddrp; 77936379Ssklower int naddr = 0; 78036379Ssklower struct esis_fixed *pdu; 78143332Ssklower struct iso_ifaddr *ia; 78237469Ssklower int len; 78336379Ssklower struct sockaddr_iso siso; 78436379Ssklower 78536379Ssklower if (type == ESIS_ESH) 78636379Ssklower esis_stat.es_eshsent++; 78736379Ssklower else if (type == ESIS_ISH) 78836379Ssklower esis_stat.es_ishsent++; 78936379Ssklower else { 79036379Ssklower printf("esis_shoutput: bad pdu type\n"); 79136379Ssklower return; 79236379Ssklower } 79336379Ssklower 79436379Ssklower IFDEBUG(D_ESISOUTPUT) 79536379Ssklower int i; 79636379Ssklower printf("esis_shoutput: ifp x%x (%s%d), %s, ht %d, to: [%d] ", 79736379Ssklower ifp, ifp->if_name, ifp->if_unit, type == ESIS_ESH ? "esh" : "ish", 79836379Ssklower ht, sn_len); 79936379Ssklower for (i=0; i<sn_len; i++) 80036379Ssklower printf("%x%c", *(sn_addr+i), i < (sn_len-1) ? ':' : ' '); 80136379Ssklower printf("\n"); 80236379Ssklower ENDDEBUG 80336379Ssklower 80437469Ssklower if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) { 80536379Ssklower esis_stat.es_nomem++; 80636379Ssklower return; 80736379Ssklower } 80837469Ssklower bzero(mtod(m, caddr_t), MHLEN); 80936379Ssklower 81036379Ssklower pdu = mtod(m, struct esis_fixed *); 81137469Ssklower naddrp = cp = (caddr_t)(pdu + 1); 81236379Ssklower len = sizeof(struct esis_fixed); 81336379Ssklower 81436379Ssklower /* 81536379Ssklower * Build fixed part of header 81636379Ssklower */ 81736379Ssklower pdu->esis_proto_id = ISO9542_ESIS; 81836379Ssklower pdu->esis_vers = ESIS_VERSION; 81936379Ssklower pdu->esis_type = type; 82036379Ssklower HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); 82136379Ssklower 82236379Ssklower if (type == ESIS_ESH) { 82336379Ssklower cp++; 82436379Ssklower len++; 82536379Ssklower } 82636379Ssklower 82737469Ssklower m->m_len = len; 82843332Ssklower if (isoa) { 82943332Ssklower /* 83043332Ssklower * Here we are responding to a clnp packet sent to an NSAP 83143332Ssklower * that is ours which was sent to the MAC addr all_es's. 83243332Ssklower * It is possible that we did not specifically advertise this 83343332Ssklower * NSAP, even though it is ours, so we will respond 83443332Ssklower * directly to the sender that we are here. If we do have 83543332Ssklower * multiple NSEL's we'll tack them on so he can compress them out. 83643332Ssklower */ 83743332Ssklower (void) esis_insert_addr(&cp, &len, isoa, m, 0); 83843332Ssklower naddr = 1; 83943332Ssklower } 84043332Ssklower for (ia = iso_ifaddr; ia; ia = ia->ia_next) { 84143332Ssklower int nsellen = (type == ESIS_ISH ? ia->ia_addr.siso_tlen : 0); 84243332Ssklower int n = ia->ia_addr.siso_nlen; 84343332Ssklower register struct iso_ifaddr *ia2; 84443332Ssklower 84543332Ssklower if (type == ESIS_ISH && naddr > 0) 84643332Ssklower break; 84743332Ssklower for (ia2 = iso_ifaddr; ia2 != ia; ia2 = ia2->ia_next) 84843332Ssklower if (Bcmp(ia->ia_addr.siso_data, ia2->ia_addr.siso_data, n) == 0) 84943332Ssklower break; 85043332Ssklower if (ia2 != ia) 85143332Ssklower continue; /* Means we have previously copied this nsap */ 85243332Ssklower if (isoa && Bcmp(ia->ia_addr.siso_data, isoa->isoa_genaddr, n) == 0) { 85343332Ssklower isoa = 0; 85443332Ssklower continue; /* Ditto */ 85536379Ssklower } 85643332Ssklower IFDEBUG(D_ESISOUTPUT) 85743332Ssklower printf("esis_shoutput: adding NSAP %s\n", 85843332Ssklower clnp_iso_addrp(&ia->ia_addr.siso_addr)); 85943332Ssklower ENDDEBUG 86043332Ssklower if (!esis_insert_addr(&cp, &len, 86143332Ssklower &ia->ia_addr.siso_addr, m, nsellen)) { 86243332Ssklower EXTEND_PACKET(m, m0, cp); 86343332Ssklower (void) esis_insert_addr(&cp, &len, &ia->ia_addr.siso_addr, m, 86443332Ssklower nsellen); 86543332Ssklower } 86643332Ssklower naddr++; 86736379Ssklower } 86836379Ssklower 86936379Ssklower if (type == ESIS_ESH) 87036379Ssklower *naddrp = naddr; 87144254Ssklower else { 87244254Ssklower /* add suggested es config timer option to ISH */ 87344254Ssklower if (M_TRAILINGSPACE(m) < 4) { 87444254Ssklower printf("esis_shoutput: extending packet\n"); 87544254Ssklower EXTEND_PACKET(m, m0, cp); 87644254Ssklower } 87744254Ssklower *cp++ = ESISOVAL_ESCT; 87844254Ssklower *cp++ = 2; 87944254Ssklower HTOC(*cp, *(cp+1), esis_esconfig_time); 88044254Ssklower len += 4; 88144254Ssklower m->m_len += 4; 88244254Ssklower IFDEBUG(D_ESISOUTPUT) 88344254Ssklower printf("m0 0x%x, m 0x%x, data 0x%x, len %d, cp 0x%x\n", 88444254Ssklower m0, m, m->m_data, m->m_len, cp); 88544254Ssklower ENDDEBUG 88644254Ssklower } 88736379Ssklower 88837469Ssklower m0->m_pkthdr.len = len; 88937469Ssklower pdu->esis_hdr_len = len; 89036379Ssklower iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len); 89136379Ssklower 89237469Ssklower bzero((caddr_t)&siso, sizeof(siso)); 89336379Ssklower siso.siso_family = AF_ISO; 89437469Ssklower siso.siso_data[0] = AFI_SNA; 89537469Ssklower siso.siso_nlen = sn_len + 1; 89637469Ssklower bcopy(sn_addr, siso.siso_data + 1, (unsigned)sn_len); 89752625Ssklower (ifp->if_output)(ifp, m0, (struct sockaddr *)&siso, 0); 89836379Ssklower } 89936379Ssklower 90036379Ssklower /* 90143421Ssklower * FUNCTION: isis_input 90243421Ssklower * 90343421Ssklower * PURPOSE: Process an incoming isis packet 90443421Ssklower * 90543421Ssklower * RETURNS: nothing 90643421Ssklower * 90743421Ssklower * SIDE EFFECTS: 90843421Ssklower * 90943421Ssklower * NOTES: 91043421Ssklower */ 91143421Ssklower isis_input(m0, shp) 91243421Ssklower struct mbuf *m0; /* ptr to first mbuf of pkt */ 91343421Ssklower struct snpa_hdr *shp; /* subnetwork header */ 91443421Ssklower { 91543421Ssklower register int type; 91643961Ssklower register struct rawcb *rp, *first_rp = 0; 91743421Ssklower struct ifnet *ifp = shp->snh_ifp; 91843421Ssklower char workbuf[16]; 91943421Ssklower struct mbuf *mm; 92043421Ssklower 92143421Ssklower IFDEBUG(D_ISISINPUT) 92243421Ssklower int i; 92343421Ssklower 92443421Ssklower printf("isis_input: pkt on ifp x%x (%s%d): from:", ifp, 92543421Ssklower ifp->if_name, ifp->if_unit); 92643421Ssklower for (i=0; i<6; i++) 92743421Ssklower printf("%x%c", shp->snh_shost[i]&0xff, (i<5) ? ':' : ' '); 92843421Ssklower printf(" to:"); 92943421Ssklower for (i=0; i<6; i++) 93043421Ssklower printf("%x%c", shp->snh_dhost[i]&0xff, (i<5) ? ':' : ' '); 93143421Ssklower printf("\n"); 93243421Ssklower ENDDEBUG 93343421Ssklower esis_dl.sdl_alen = ifp->if_addrlen; 93443421Ssklower esis_dl.sdl_index = ifp->if_index; 93543421Ssklower bcopy(shp->snh_shost, (caddr_t)esis_dl.sdl_data, esis_dl.sdl_alen); 93643421Ssklower for (rp = esis_pcb.rcb_next; rp != &esis_pcb; rp = rp->rcb_next) { 93743961Ssklower if (first_rp == 0) { 93843961Ssklower first_rp = rp; 93943421Ssklower continue; 94043421Ssklower } 94143421Ssklower if (mm = m_copy(m0, 0, M_COPYALL)) { /*can't block at interrupt level */ 94243421Ssklower if (sbappendaddr(&rp->rcb_socket->so_rcv, 943*68259Scgd (struct sockaddr *)&esis_dl, mm, 944*68259Scgd (struct mbuf *)0) != 0) { 94543421Ssklower sorwakeup(rp->rcb_socket); 94652114Ssklower } else { 94743421Ssklower IFDEBUG(D_ISISINPUT) 94843421Ssklower printf("Error in sbappenaddr, mm = 0x%x\n", mm); 94943421Ssklower ENDDEBUG 95043421Ssklower m_freem(mm); 95143421Ssklower } 95243421Ssklower } 95343421Ssklower } 95443961Ssklower if (first_rp && sbappendaddr(&first_rp->rcb_socket->so_rcv, 955*68259Scgd (struct sockaddr *)&esis_dl, m0, 956*68259Scgd (struct mbuf *)0) != 0) { 95743961Ssklower sorwakeup(first_rp->rcb_socket); 95843961Ssklower return; 95943421Ssklower } 96043961Ssklower m_freem(m0); 96143421Ssklower } 96243421Ssklower 96343421Ssklower isis_output(sdl, m) 96443421Ssklower register struct sockaddr_dl *sdl; 96543421Ssklower struct mbuf *m; 96643421Ssklower { 96743421Ssklower register struct ifnet *ifp; 96843421Ssklower struct ifaddr *ifa, *ifa_ifwithnet(); 96943421Ssklower struct sockaddr_iso siso; 97043421Ssklower int error = 0; 97143421Ssklower unsigned sn_len; 97243421Ssklower 97352625Ssklower ifa = ifa_ifwithnet((struct sockaddr *)sdl); /* get ifp from sdl */ 97443421Ssklower if (ifa == 0) { 97543421Ssklower IFDEBUG(D_ISISOUTPUT) 97643421Ssklower printf("isis_output: interface not found\n"); 97743421Ssklower ENDDEBUG 97843421Ssklower error = EINVAL; 97943421Ssklower goto release; 98043421Ssklower } 98143421Ssklower ifp = ifa->ifa_ifp; 98245896Ssklower sn_len = sdl->sdl_alen; 98343421Ssklower IFDEBUG(D_ISISOUTPUT) 98443421Ssklower u_char *cp = (u_char *)LLADDR(sdl), *cplim = cp + sn_len; 98543421Ssklower printf("isis_output: ifp 0x%x (%s%d), to: ", 98643421Ssklower ifp, ifp->if_name, ifp->if_unit); 98743421Ssklower while (cp < cplim) { 98843421Ssklower printf("%x", *cp++); 98943421Ssklower printf("%c", (cp < cplim) ? ':' : ' '); 99043421Ssklower } 99143421Ssklower printf("\n"); 99243421Ssklower ENDDEBUG 99343421Ssklower bzero((caddr_t)&siso, sizeof(siso)); 99443421Ssklower siso.siso_family = AF_ISO; /* This convention may be useful for X.25 */ 99543421Ssklower siso.siso_data[0] = AFI_SNA; 99643421Ssklower siso.siso_nlen = sn_len + 1; 99743421Ssklower bcopy(LLADDR(sdl), siso.siso_data + 1, sn_len); 99843421Ssklower error = (ifp->if_output)(ifp, m, (struct sockaddr *)&siso, 0); 99943421Ssklower if (error) { 100043421Ssklower IFDEBUG(D_ISISOUTPUT) 100143421Ssklower printf("isis_output: error from ether_output is %d\n", error); 100243421Ssklower ENDDEBUG 100343421Ssklower } 100443421Ssklower return (error); 100543421Ssklower 100643421Ssklower release: 100743421Ssklower if (m != NULL) 100843421Ssklower m_freem(m); 100943421Ssklower return(error); 101043421Ssklower } 101143421Ssklower 101243421Ssklower 101343421Ssklower /* 101436379Ssklower * FUNCTION: esis_ctlinput 101536379Ssklower * 101636379Ssklower * PURPOSE: Handle the PRC_IFDOWN transition 101736379Ssklower * 101836379Ssklower * RETURNS: nothing 101936379Ssklower * 102036379Ssklower * SIDE EFFECTS: 102136379Ssklower * 102236379Ssklower * NOTES: Calls snpac_flush for interface specified. 102336379Ssklower * The loop through iso_ifaddr is stupid because 102436379Ssklower * back in if_down, we knew the ifp... 102536379Ssklower */ 102636379Ssklower esis_ctlinput(req, siso) 102736379Ssklower int req; /* request: we handle only PRC_IFDOWN */ 102836379Ssklower struct sockaddr_iso *siso; /* address of ifp */ 102936379Ssklower { 103036379Ssklower register struct iso_ifaddr *ia; /* scan through interface addresses */ 103136379Ssklower 103237469Ssklower if (req == PRC_IFDOWN) 103337469Ssklower for (ia = iso_ifaddr; ia; ia = ia->ia_next) { 103437469Ssklower if (iso_addrmatch(IA_SIS(ia), siso)) 103537469Ssklower snpac_flushifp(ia->ia_ifp); 103637469Ssklower } 103736379Ssklower } 103836379Ssklower 103961300Ssklower #endif /* ISO */ 1040