1*36379Ssklower /*********************************************************** 2*36379Ssklower Copyright IBM Corporation 1987 3*36379Ssklower 4*36379Ssklower All Rights Reserved 5*36379Ssklower 6*36379Ssklower Permission to use, copy, modify, and distribute this software and its 7*36379Ssklower documentation for any purpose and without fee is hereby granted, 8*36379Ssklower provided that the above copyright notice appear in all copies and that 9*36379Ssklower both that copyright notice and this permission notice appear in 10*36379Ssklower supporting documentation, and that the name of IBM not be 11*36379Ssklower used in advertising or publicity pertaining to distribution of the 12*36379Ssklower software without specific, written prior permission. 13*36379Ssklower 14*36379Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 15*36379Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 16*36379Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 17*36379Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 18*36379Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 19*36379Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 20*36379Ssklower SOFTWARE. 21*36379Ssklower 22*36379Ssklower ******************************************************************/ 23*36379Ssklower 24*36379Ssklower /* 25*36379Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 26*36379Ssklower */ 27*36379Ssklower #ifndef lint 28*36379Ssklower static char *rcsid = "$Header: esis.c,v 4.10 88/09/15 18:57:03 hagens Exp $"; 29*36379Ssklower #endif 30*36379Ssklower 31*36379Ssklower #ifdef ISO 32*36379Ssklower 33*36379Ssklower #include "../h/types.h" 34*36379Ssklower #include "../h/param.h" 35*36379Ssklower #include "../h/mbuf.h" 36*36379Ssklower #include "../h/domain.h" 37*36379Ssklower #include "../h/protosw.h" 38*36379Ssklower #include "../h/dir.h" 39*36379Ssklower #include "../h/user.h" 40*36379Ssklower #include "../h/socket.h" 41*36379Ssklower #include "../h/socketvar.h" 42*36379Ssklower #include "../h/errno.h" 43*36379Ssklower #include "../h/kernel.h" 44*36379Ssklower 45*36379Ssklower #include "../net/if.h" 46*36379Ssklower #include "../net/route.h" 47*36379Ssklower 48*36379Ssklower #include "../netiso/iso.h" 49*36379Ssklower #include "../netiso/iso_pcb.h" 50*36379Ssklower #include "../netiso/iso_var.h" 51*36379Ssklower #include "../netiso/iso_snpac.h" 52*36379Ssklower #include "../netiso/clnl.h" 53*36379Ssklower #include "../netiso/clnp.h" 54*36379Ssklower #include "../netiso/clnp_stat.h" 55*36379Ssklower #include "../netiso/argo_debug.h" 56*36379Ssklower #include "../netiso/esis.h" 57*36379Ssklower 58*36379Ssklower /* 59*36379Ssklower * Global variables to esis implementation 60*36379Ssklower * 61*36379Ssklower * esis_holding_time - the holding time (sec) parameter for outgoing pdus 62*36379Ssklower * esis_config_time - the frequency (sec) that hellos are generated 63*36379Ssklower * 64*36379Ssklower */ 65*36379Ssklower struct isopcb esis_pcb; 66*36379Ssklower int esis_sendspace = 2048; 67*36379Ssklower int esis_recvspace = 2048; 68*36379Ssklower short esis_holding_time = ESIS_HT; 69*36379Ssklower short esis_config_time = ESIS_CONFIG; 70*36379Ssklower extern int iso_systype; 71*36379Ssklower extern struct snpa_cache all_es, all_is; 72*36379Ssklower 73*36379Ssklower #define EXTEND_PACKET(m, mhdr, len, cp)\ 74*36379Ssklower if (((m)->m_next = m_getclr(M_DONTWAIT, MT_HEADER)) == NULL) {\ 75*36379Ssklower esis_stat.es_nomem++;\ 76*36379Ssklower m_freem(mhdr);\ 77*36379Ssklower return;\ 78*36379Ssklower } else {\ 79*36379Ssklower (m)->m_len = (len);\ 80*36379Ssklower (m) = (m)->m_next;\ 81*36379Ssklower (len) = 0;\ 82*36379Ssklower (cp) = mtod((m), caddr_t);\ 83*36379Ssklower } 84*36379Ssklower /* 85*36379Ssklower * FUNCTION: esis_init 86*36379Ssklower * 87*36379Ssklower * PURPOSE: Initialize the kernel portion of esis protocol 88*36379Ssklower * 89*36379Ssklower * RETURNS: nothing 90*36379Ssklower * 91*36379Ssklower * SIDE EFFECTS: 92*36379Ssklower * 93*36379Ssklower * NOTES: 94*36379Ssklower */ 95*36379Ssklower esis_init() 96*36379Ssklower { 97*36379Ssklower extern struct clnl_protosw clnl_protox[256]; 98*36379Ssklower int esis_input(); 99*36379Ssklower int snpac_age(); 100*36379Ssklower int esis_config(); 101*36379Ssklower #ifdef ISO_X25ESIS 102*36379Ssklower x25esis_input(); 103*36379Ssklower #endif ISO_X25ESIS 104*36379Ssklower 105*36379Ssklower esis_pcb.isop_next = esis_pcb.isop_prev = &esis_pcb; 106*36379Ssklower 107*36379Ssklower clnl_protox[ISO9542_ESIS].clnl_input = esis_input; 108*36379Ssklower timeout(snpac_age, (caddr_t)0, hz); 109*36379Ssklower timeout(esis_config, (caddr_t)0, hz); 110*36379Ssklower 111*36379Ssklower #ifdef ISO_X25ESIS 112*36379Ssklower clnl_protox[ISO9542X25_ESIS].clnl_input = x25esis_input; 113*36379Ssklower #endif ISO_X25ESIS 114*36379Ssklower } 115*36379Ssklower 116*36379Ssklower /* 117*36379Ssklower * FUNCTION: esis_usrreq 118*36379Ssklower * 119*36379Ssklower * PURPOSE: Handle user level esis requests 120*36379Ssklower * 121*36379Ssklower * RETURNS: 0 or appropriate errno 122*36379Ssklower * 123*36379Ssklower * SIDE EFFECTS: 124*36379Ssklower * 125*36379Ssklower * NOTES: This is here only so esis gets initialized. 126*36379Ssklower */ 127*36379Ssklower esis_usrreq(so, req, m, nam, rights) 128*36379Ssklower struct socket *so; /* socket: used only to get to this code */ 129*36379Ssklower int req; /* request */ 130*36379Ssklower struct mbuf *m; /* data for request */ 131*36379Ssklower struct mbuf *nam; /* optional name */ 132*36379Ssklower struct mbuf *rights; /* optional rights */ 133*36379Ssklower { 134*36379Ssklower if (m != NULL) 135*36379Ssklower m_freem(m); 136*36379Ssklower 137*36379Ssklower return(EOPNOTSUPP); 138*36379Ssklower } 139*36379Ssklower 140*36379Ssklower /* 141*36379Ssklower * FUNCTION: esis_input 142*36379Ssklower * 143*36379Ssklower * PURPOSE: Process an incoming esis packet 144*36379Ssklower * 145*36379Ssklower * RETURNS: nothing 146*36379Ssklower * 147*36379Ssklower * SIDE EFFECTS: 148*36379Ssklower * 149*36379Ssklower * NOTES: 150*36379Ssklower */ 151*36379Ssklower esis_input(m0, shp) 152*36379Ssklower struct mbuf *m0; /* ptr to first mbuf of pkt */ 153*36379Ssklower struct snpa_hdr *shp; /* subnetwork header */ 154*36379Ssklower { 155*36379Ssklower struct isopcb *isop; 156*36379Ssklower struct esis_fixed *pdu = mtod(m0, struct esis_fixed *); 157*36379Ssklower 158*36379Ssklower IFDEBUG(D_ESISINPUT) 159*36379Ssklower int i; 160*36379Ssklower 161*36379Ssklower printf("esis_input: pdu on ifp x%x (%s%d): from:", shp->snh_ifp, 162*36379Ssklower shp->snh_ifp->if_name, shp->snh_ifp->if_unit); 163*36379Ssklower for (i=0; i<6; i++) 164*36379Ssklower printf("%x%c", shp->snh_shost[i]&0xff, (i<5) ? ':' : ' '); 165*36379Ssklower printf(" to:"); 166*36379Ssklower for (i=0; i<6; i++) 167*36379Ssklower printf("%x%c", shp->snh_dhost[i]&0xff, (i<5) ? ':' : ' '); 168*36379Ssklower printf("\n"); 169*36379Ssklower ENDDEBUG 170*36379Ssklower 171*36379Ssklower /* 172*36379Ssklower * check checksum if necessary 173*36379Ssklower */ 174*36379Ssklower if (ESIS_CKSUM_REQUIRED(pdu) && iso_check_csum(m0, pdu->esis_hdr_len)) { 175*36379Ssklower esis_stat.es_badcsum++; 176*36379Ssklower goto bad; 177*36379Ssklower } 178*36379Ssklower 179*36379Ssklower /* check version */ 180*36379Ssklower if (pdu->esis_vers != ESIS_VERSION) { 181*36379Ssklower esis_stat.es_badvers++; 182*36379Ssklower goto bad; 183*36379Ssklower } 184*36379Ssklower 185*36379Ssklower switch(pdu->esis_type) { 186*36379Ssklower case ESIS_ESH: 187*36379Ssklower esis_eshinput(m0, shp); 188*36379Ssklower return; 189*36379Ssklower 190*36379Ssklower case ESIS_ISH: 191*36379Ssklower esis_ishinput(m0, shp); 192*36379Ssklower return; 193*36379Ssklower 194*36379Ssklower case ESIS_RD: 195*36379Ssklower esis_rdinput(m0, shp); 196*36379Ssklower return; 197*36379Ssklower 198*36379Ssklower default: { 199*36379Ssklower esis_stat.es_badtype++; 200*36379Ssklower goto bad; 201*36379Ssklower } 202*36379Ssklower } 203*36379Ssklower 204*36379Ssklower bad: 205*36379Ssklower m_freem(m0); 206*36379Ssklower } 207*36379Ssklower 208*36379Ssklower /* 209*36379Ssklower * FUNCTION: esis_rdoutput 210*36379Ssklower * 211*36379Ssklower * PURPOSE: Transmit a redirect pdu 212*36379Ssklower * 213*36379Ssklower * RETURNS: nothing 214*36379Ssklower * 215*36379Ssklower * SIDE EFFECTS: 216*36379Ssklower * 217*36379Ssklower * NOTES: Assumes there is enough space for fixed part of header, 218*36379Ssklower * DA, BSNPA and NET in first mbuf. 219*36379Ssklower */ 220*36379Ssklower esis_rdoutput(inbound_shp, inbound_m, inbound_oidx, rd_dstnsap, nhop_sc) 221*36379Ssklower struct snpa_hdr *inbound_shp; /* snpa hdr from incoming packet */ 222*36379Ssklower struct mbuf *inbound_m; /* incoming pkt itself */ 223*36379Ssklower struct clnp_optidx *inbound_oidx; /* clnp options assoc with incoming pkt */ 224*36379Ssklower struct iso_addr *rd_dstnsap; /* ultimate destination of pkt */ 225*36379Ssklower struct snpa_cache *nhop_sc; /* snpa cache info regarding next hop of 226*36379Ssklower pkt */ 227*36379Ssklower { 228*36379Ssklower struct mbuf *m, *m0; 229*36379Ssklower caddr_t cp; 230*36379Ssklower struct esis_fixed *pdu; 231*36379Ssklower int len, total_len = 0; 232*36379Ssklower struct sockaddr_iso siso; 233*36379Ssklower struct ifnet *ifp = inbound_shp->snh_ifp; 234*36379Ssklower 235*36379Ssklower esis_stat.es_rdsent++; 236*36379Ssklower 237*36379Ssklower IFDEBUG(D_ESISOUTPUT) 238*36379Ssklower int i; 239*36379Ssklower printf("esis_rdoutput: ifp x%x (%s%d), ht %d, m x%x, oidx x%x\n", 240*36379Ssklower ifp, ifp->if_name, ifp->if_unit, esis_holding_time, inbound_m, 241*36379Ssklower inbound_oidx); 242*36379Ssklower printf("\tdestination: %s\n", clnp_iso_addrp(rd_dstnsap)); 243*36379Ssklower printf("\tredirected toward:%s\n", clnp_iso_addrp(&nhop_sc->sc_nsap)); 244*36379Ssklower ENDDEBUG 245*36379Ssklower 246*36379Ssklower if ((m0 = m = m_getclr(M_DONTWAIT, MT_HEADER)) == NULL) { 247*36379Ssklower esis_stat.es_nomem++; 248*36379Ssklower return; 249*36379Ssklower } 250*36379Ssklower 251*36379Ssklower pdu = mtod(m, struct esis_fixed *); 252*36379Ssklower cp = (caddr_t)pdu + sizeof(struct esis_fixed); 253*36379Ssklower len = sizeof(struct esis_fixed); 254*36379Ssklower 255*36379Ssklower /* 256*36379Ssklower * Build fixed part of header 257*36379Ssklower */ 258*36379Ssklower pdu->esis_proto_id = ISO9542_ESIS; 259*36379Ssklower pdu->esis_vers = ESIS_VERSION; 260*36379Ssklower pdu->esis_type = ESIS_RD; 261*36379Ssklower HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, esis_holding_time); 262*36379Ssklower 263*36379Ssklower /* Insert destination address */ 264*36379Ssklower (void) esis_insert_addr(&cp, &len, rd_dstnsap, MLEN - len); 265*36379Ssklower 266*36379Ssklower /* Insert the snpa of better next hop */ 267*36379Ssklower *cp++ = nhop_sc->sc_len; 268*36379Ssklower bcopy(nhop_sc->sc_snpa, cp, nhop_sc->sc_len); 269*36379Ssklower len += (nhop_sc->sc_len + 1); 270*36379Ssklower 271*36379Ssklower /* 272*36379Ssklower * If the next hop is not the destination, then it ought to be 273*36379Ssklower * an IS and it should be inserted next. Else, set the 274*36379Ssklower * NETL to 0 275*36379Ssklower */ 276*36379Ssklower /* PHASE2 use mask from ifp of outgoing interface */ 277*36379Ssklower if (!iso_addrmatch1(rd_dstnsap, &nhop_sc->sc_nsap)) { 278*36379Ssklower if ((nhop_sc->sc_flags & SNPA_IS) == 0) { 279*36379Ssklower /* this should not happen */ 280*36379Ssklower printf("esis_rdoutput: next hop is not dst and not an IS\n"); 281*36379Ssklower m_freem(m0); 282*36379Ssklower return; 283*36379Ssklower } 284*36379Ssklower (void) esis_insert_addr(&cp, &len, &nhop_sc->sc_nsap, MLEN - len); 285*36379Ssklower } else { 286*36379Ssklower *cp++ = 0; /* NETL */ 287*36379Ssklower len++; 288*36379Ssklower } 289*36379Ssklower 290*36379Ssklower /* 291*36379Ssklower * PHASE2 292*36379Ssklower * If redirect is to an IS, add an address mask. The mask to be 293*36379Ssklower * used should be the mask present in the routing entry used to 294*36379Ssklower * forward the original data packet. 295*36379Ssklower */ 296*36379Ssklower 297*36379Ssklower /* 298*36379Ssklower * Copy Qos, priority, or security options present in original npdu 299*36379Ssklower */ 300*36379Ssklower if (inbound_oidx) { 301*36379Ssklower /* THIS CODE IS CURRENTLY UNTESTED */ 302*36379Ssklower int optlen = 0; 303*36379Ssklower if (inbound_oidx->cni_qos_formatp) 304*36379Ssklower optlen += (inbound_oidx->cni_qos_len + 2); 305*36379Ssklower if (inbound_oidx->cni_priorp) /* priority option is 1 byte long */ 306*36379Ssklower optlen += 3; 307*36379Ssklower if (inbound_oidx->cni_securep) 308*36379Ssklower optlen += (inbound_oidx->cni_secure_len + 2); 309*36379Ssklower if (MLEN-len < optlen) { 310*36379Ssklower total_len += len; 311*36379Ssklower EXTEND_PACKET(m, m0, len, cp); 312*36379Ssklower /* assumes MLEN > optlen */ 313*36379Ssklower } 314*36379Ssklower /* assume MLEN-len > optlen */ 315*36379Ssklower /* 316*36379Ssklower * When copying options, copy from ptr - 2 in order to grab 317*36379Ssklower * the option code and length 318*36379Ssklower */ 319*36379Ssklower if (inbound_oidx->cni_qos_formatp) { 320*36379Ssklower bcopy(inbound_m + inbound_oidx->cni_qos_formatp - 2, cp, 321*36379Ssklower inbound_oidx->cni_qos_len + 2); 322*36379Ssklower len += inbound_oidx->cni_qos_len + 2; 323*36379Ssklower } 324*36379Ssklower if (inbound_oidx->cni_priorp) { 325*36379Ssklower bcopy(inbound_m + inbound_oidx->cni_priorp - 2, cp, 3); 326*36379Ssklower len += 3; 327*36379Ssklower } 328*36379Ssklower if (inbound_oidx->cni_securep) { 329*36379Ssklower bcopy(inbound_m + inbound_oidx->cni_securep - 2, cp, 330*36379Ssklower inbound_oidx->cni_secure_len + 2); 331*36379Ssklower len += inbound_oidx->cni_secure_len + 2; 332*36379Ssklower } 333*36379Ssklower } 334*36379Ssklower 335*36379Ssklower m->m_len = len; 336*36379Ssklower total_len += len; 337*36379Ssklower pdu->esis_hdr_len = total_len; 338*36379Ssklower iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len); 339*36379Ssklower 340*36379Ssklower siso.siso_family = AF_ISO; 341*36379Ssklower siso.siso_addr.isoa_afi = AFI_SNA; 342*36379Ssklower siso.siso_addr.isoa_len = 6 + 1; /* should be taken from snpa_hdr */ 343*36379Ssklower /* +1 is for AFI */ 344*36379Ssklower bcopy(inbound_shp->snh_shost, siso.siso_addr.sna_idi, 6); 345*36379Ssklower (ifp->if_output)(ifp, m0, &siso); 346*36379Ssklower } 347*36379Ssklower 348*36379Ssklower /* 349*36379Ssklower * FUNCTION: esis_extract_addr 350*36379Ssklower * 351*36379Ssklower * PURPOSE: Remove an addr from a buffer, and stuff in iso_addr 352*36379Ssklower * 353*36379Ssklower * RETURNS: true if the address was complete, else false 354*36379Ssklower * 355*36379Ssklower * SIDE EFFECTS: Increment buf and decrement len according to the 356*36379Ssklower * size of the iso_addr 357*36379Ssklower * 358*36379Ssklower * NOTES: 359*36379Ssklower */ 360*36379Ssklower esis_extract_addr(buf, isoa, len) 361*36379Ssklower caddr_t *buf; /* ptr to buffer to put address into */ 362*36379Ssklower struct iso_addr *isoa; /* ptr to address */ 363*36379Ssklower int *len; /* ptr to length of buffer */ 364*36379Ssklower { 365*36379Ssklower caddr_t bp = *buf; 366*36379Ssklower 367*36379Ssklower if (*len <= 0) 368*36379Ssklower return(0); 369*36379Ssklower 370*36379Ssklower bzero((caddr_t)isoa, sizeof (struct iso_addr)); 371*36379Ssklower isoa->isoa_len = *bp++; 372*36379Ssklower *len -= 1; 373*36379Ssklower if (isoa->isoa_len > *len) 374*36379Ssklower return(0); /* too big */ 375*36379Ssklower bcopy(bp, (caddr_t)isoa, isoa->isoa_len); 376*36379Ssklower *len -= isoa->isoa_len; 377*36379Ssklower bp += isoa->isoa_len; 378*36379Ssklower *buf = bp; 379*36379Ssklower 380*36379Ssklower return(1); 381*36379Ssklower } 382*36379Ssklower 383*36379Ssklower /* 384*36379Ssklower * FUNCTION: esis_insert_addr 385*36379Ssklower * 386*36379Ssklower * PURPOSE: Insert an iso_addr into a buffer 387*36379Ssklower * 388*36379Ssklower * RETURNS: true if buffer was big enough, else false 389*36379Ssklower * 390*36379Ssklower * SIDE EFFECTS: Increment buf & len according to size of iso_addr 391*36379Ssklower * 392*36379Ssklower * NOTES: Plus 1 here is for length byte 393*36379Ssklower */ 394*36379Ssklower esis_insert_addr(buf, len, isoa, remaining) 395*36379Ssklower caddr_t *buf; /* ptr to buffer to put address into */ 396*36379Ssklower int *len; /* ptr to length of buffer so far */ 397*36379Ssklower struct iso_addr *isoa; /* ptr to address */ 398*36379Ssklower int remaining; /* length of buffer */ 399*36379Ssklower { 400*36379Ssklower caddr_t bp = *buf; 401*36379Ssklower 402*36379Ssklower if ((isoa->isoa_len+1) > remaining) 403*36379Ssklower return(0); 404*36379Ssklower *bp++ = isoa->isoa_len; 405*36379Ssklower *len += 1; 406*36379Ssklower bcopy((caddr_t)isoa, bp, isoa->isoa_len); 407*36379Ssklower bp += isoa->isoa_len; 408*36379Ssklower *len += isoa->isoa_len; 409*36379Ssklower *buf = bp; 410*36379Ssklower return(1); 411*36379Ssklower } 412*36379Ssklower 413*36379Ssklower /* 414*36379Ssklower 415*36379Ssklower /* 416*36379Ssklower * FUNCTION: esis_eshinput 417*36379Ssklower * 418*36379Ssklower * PURPOSE: Process an incoming ESH pdu 419*36379Ssklower * 420*36379Ssklower * RETURNS: nothing 421*36379Ssklower * 422*36379Ssklower * SIDE EFFECTS: 423*36379Ssklower * 424*36379Ssklower * NOTES: 425*36379Ssklower */ 426*36379Ssklower esis_eshinput(m, shp) 427*36379Ssklower struct mbuf *m; /* esh pdu */ 428*36379Ssklower struct snpa_hdr *shp; /* subnetwork header */ 429*36379Ssklower { 430*36379Ssklower struct esis_fixed *pdu = mtod(m, struct esis_fixed *); 431*36379Ssklower u_short ht; /* holding time */ 432*36379Ssklower struct iso_addr nsap; 433*36379Ssklower int naddr; 434*36379Ssklower caddr_t buf = (caddr_t)pdu + sizeof(struct esis_fixed); 435*36379Ssklower int len = pdu->esis_hdr_len - sizeof(struct esis_fixed); 436*36379Ssklower 437*36379Ssklower esis_stat.es_eshrcvd++; 438*36379Ssklower 439*36379Ssklower CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); 440*36379Ssklower 441*36379Ssklower if (len > 0) { 442*36379Ssklower naddr = *buf++; 443*36379Ssklower len--; 444*36379Ssklower } else 445*36379Ssklower goto bad; 446*36379Ssklower 447*36379Ssklower IFDEBUG(D_ESISINPUT) 448*36379Ssklower printf("esis_eshinput: esh: ht %d, naddr %d\n", ht, naddr); 449*36379Ssklower ENDDEBUG 450*36379Ssklower 451*36379Ssklower while (naddr-- > 0) { 452*36379Ssklower if (esis_extract_addr(&buf, &nsap, &len)) { 453*36379Ssklower int new_entry = (snpac_look(&nsap) == NULL); 454*36379Ssklower 455*36379Ssklower IFDEBUG(D_ESISINPUT) 456*36379Ssklower printf("esis_eshinput: nsap %s is %s\n", 457*36379Ssklower clnp_iso_addrp(&nsap), new_entry ? "new" : "old"); 458*36379Ssklower ENDDEBUG 459*36379Ssklower 460*36379Ssklower snpac_add(shp->snh_ifp, &nsap, shp->snh_shost, 6, SNPA_ES, ht); 461*36379Ssklower if (new_entry) 462*36379Ssklower esis_shoutput(shp->snh_ifp, 463*36379Ssklower iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH, 464*36379Ssklower esis_holding_time, shp->snh_shost, 6); 465*36379Ssklower } else { 466*36379Ssklower esis_stat.es_toosmall++; 467*36379Ssklower break; 468*36379Ssklower } 469*36379Ssklower } 470*36379Ssklower 471*36379Ssklower bad: 472*36379Ssklower m_freem(m); 473*36379Ssklower } 474*36379Ssklower 475*36379Ssklower /* 476*36379Ssklower * FUNCTION: esis_ishinput 477*36379Ssklower * 478*36379Ssklower * PURPOSE: process an incoming ISH pdu 479*36379Ssklower * 480*36379Ssklower * RETURNS: 481*36379Ssklower * 482*36379Ssklower * SIDE EFFECTS: 483*36379Ssklower * 484*36379Ssklower * NOTES: 485*36379Ssklower */ 486*36379Ssklower esis_ishinput(m, shp) 487*36379Ssklower struct mbuf *m; /* esh pdu */ 488*36379Ssklower struct snpa_hdr *shp; /* subnetwork header */ 489*36379Ssklower { 490*36379Ssklower struct esis_fixed *pdu = mtod(m, struct esis_fixed *); 491*36379Ssklower u_short ht; /* holding time */ 492*36379Ssklower struct iso_addr nsap; 493*36379Ssklower caddr_t buf = (caddr_t)pdu + sizeof(struct esis_fixed); 494*36379Ssklower int len = pdu->esis_hdr_len - sizeof(struct esis_fixed); 495*36379Ssklower 496*36379Ssklower esis_stat.es_ishrcvd++; 497*36379Ssklower CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); 498*36379Ssklower 499*36379Ssklower IFDEBUG(D_ESISINPUT) 500*36379Ssklower printf("esis_ishinput: ish: ht %d\n", ht); 501*36379Ssklower ENDDEBUG 502*36379Ssklower 503*36379Ssklower if (esis_extract_addr(&buf, &nsap, &len)) { 504*36379Ssklower int new_entry = (snpac_look(&nsap) == NULL); 505*36379Ssklower 506*36379Ssklower IFDEBUG(D_ESISINPUT) 507*36379Ssklower printf("esis_ishinput: nsap %s is %s\n", 508*36379Ssklower clnp_iso_addrp(&nsap), new_entry ? "new" : "old"); 509*36379Ssklower ENDDEBUG 510*36379Ssklower 511*36379Ssklower snpac_add(shp->snh_ifp, &nsap, shp->snh_shost, 6, SNPA_IS, ht); 512*36379Ssklower if (new_entry) 513*36379Ssklower esis_shoutput(shp->snh_ifp, 514*36379Ssklower iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH, 515*36379Ssklower esis_holding_time, shp->snh_shost, 6); 516*36379Ssklower } else { 517*36379Ssklower esis_stat.es_toosmall++; 518*36379Ssklower } 519*36379Ssklower m_freem(m); 520*36379Ssklower } 521*36379Ssklower 522*36379Ssklower /* 523*36379Ssklower * FUNCTION: esis_rdinput 524*36379Ssklower * 525*36379Ssklower * PURPOSE: Process an incoming RD pdu 526*36379Ssklower * 527*36379Ssklower * RETURNS: 528*36379Ssklower * 529*36379Ssklower * SIDE EFFECTS: 530*36379Ssklower * 531*36379Ssklower * NOTES: 532*36379Ssklower */ 533*36379Ssklower esis_rdinput(m0, shp) 534*36379Ssklower struct mbuf *m0; /* esh pdu */ 535*36379Ssklower struct snpa_hdr *shp; /* subnetwork header */ 536*36379Ssklower { 537*36379Ssklower struct esis_fixed *pdu = mtod(m0, struct esis_fixed *); 538*36379Ssklower u_short ht; /* holding time */ 539*36379Ssklower struct iso_addr da; 540*36379Ssklower caddr_t bsnpa; 541*36379Ssklower int bsnpalen; 542*36379Ssklower struct iso_addr net; 543*36379Ssklower int netl; 544*36379Ssklower caddr_t buf = (caddr_t)pdu + sizeof(struct esis_fixed); 545*36379Ssklower int len = pdu->esis_hdr_len - sizeof(struct esis_fixed); 546*36379Ssklower 547*36379Ssklower esis_stat.es_rdrcvd++; 548*36379Ssklower 549*36379Ssklower /* intermediate systems ignore redirects */ 550*36379Ssklower if (iso_systype & SNPA_IS) 551*36379Ssklower goto bad; 552*36379Ssklower 553*36379Ssklower CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); 554*36379Ssklower 555*36379Ssklower /* Extract DA */ 556*36379Ssklower if (!esis_extract_addr(&buf, &da, &len)) { 557*36379Ssklower esis_stat.es_toosmall++; 558*36379Ssklower goto bad; 559*36379Ssklower } 560*36379Ssklower 561*36379Ssklower /* Extract better snpa */ 562*36379Ssklower bsnpalen = *buf++; 563*36379Ssklower if (bsnpalen > len) { 564*36379Ssklower esis_stat.es_toosmall++; 565*36379Ssklower goto bad; 566*36379Ssklower } else { 567*36379Ssklower bsnpa = buf; 568*36379Ssklower buf += bsnpalen; 569*36379Ssklower len -= bsnpalen; 570*36379Ssklower } 571*36379Ssklower 572*36379Ssklower /* Extract NET if present */ 573*36379Ssklower if ((netl = *buf) > 0) { 574*36379Ssklower if (!esis_extract_addr(&buf, &net, &len)) { 575*36379Ssklower esis_stat.es_toosmall++; 576*36379Ssklower goto bad; 577*36379Ssklower } 578*36379Ssklower } 579*36379Ssklower 580*36379Ssklower IFDEBUG(D_ESISINPUT) 581*36379Ssklower printf("esis_rdinput: rd: ht %d, da %s\n", ht, clnp_iso_addrp(&da)); 582*36379Ssklower if (netl) 583*36379Ssklower printf("\t: net %s\n", clnp_iso_addrp(&net)); 584*36379Ssklower ENDDEBUG 585*36379Ssklower 586*36379Ssklower /* 587*36379Ssklower * If netl is zero, then redirect is to an ES. We need to add an entry 588*36379Ssklower * to the snpa cache for (destination, better snpa). 589*36379Ssklower * If netl is not zero, then the redirect is to an IS. In this 590*36379Ssklower * case, add an snpa cache entry for (net, better snpa). 591*36379Ssklower * 592*36379Ssklower * If the redirect is to an IS, add a route entry towards that 593*36379Ssklower * IS. 594*36379Ssklower */ 595*36379Ssklower if (netl == 0) { 596*36379Ssklower /* redirect to an ES */ 597*36379Ssklower snpac_add(shp->snh_ifp, &da, bsnpa, bsnpalen, SNPA_ES, ht); 598*36379Ssklower } else { 599*36379Ssklower snpac_add(shp->snh_ifp, &net, bsnpa, bsnpalen, SNPA_IS, ht); 600*36379Ssklower snpac_addrt(&da, &net); 601*36379Ssklower } 602*36379Ssklower bad: 603*36379Ssklower m_freem(m0); 604*36379Ssklower } 605*36379Ssklower 606*36379Ssklower /* 607*36379Ssklower * FUNCTION: esis_config 608*36379Ssklower * 609*36379Ssklower * PURPOSE: Report configuration 610*36379Ssklower * 611*36379Ssklower * RETURNS: 612*36379Ssklower * 613*36379Ssklower * SIDE EFFECTS: 614*36379Ssklower * 615*36379Ssklower * NOTES: Called every esis_config_time seconds 616*36379Ssklower */ 617*36379Ssklower esis_config() 618*36379Ssklower { 619*36379Ssklower register struct ifnet *ifp; 620*36379Ssklower 621*36379Ssklower timeout(esis_config, (caddr_t)0, hz * esis_config_time); 622*36379Ssklower 623*36379Ssklower /* 624*36379Ssklower * Report configuration for each interface that 625*36379Ssklower * - is UP 626*36379Ssklower * - is not loopback 627*36379Ssklower * - has broadcast capabilities 628*36379Ssklower * - has an ISO address 629*36379Ssklower */ 630*36379Ssklower 631*36379Ssklower for (ifp = ifnet; ifp; ifp = ifp->if_next) { 632*36379Ssklower if ((ifp->if_flags & IFF_UP) && 633*36379Ssklower (ifp->if_flags & IFF_BROADCAST) && 634*36379Ssklower ((ifp->if_flags & IFF_LOOPBACK) == 0)) { 635*36379Ssklower /* search for an ISO address family */ 636*36379Ssklower struct ifaddr *ia; 637*36379Ssklower 638*36379Ssklower for (ia = ifp->if_addrlist; ia; ia = ia->ifa_next) { 639*36379Ssklower if (ia->ifa_addr.sa_family == AF_ISO) { 640*36379Ssklower esis_shoutput(ifp, 641*36379Ssklower iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH, 642*36379Ssklower esis_holding_time, 643*36379Ssklower iso_systype & SNPA_ES ? all_is.sc_snpa : 644*36379Ssklower all_es.sc_snpa, 6); 645*36379Ssklower break; 646*36379Ssklower } 647*36379Ssklower } 648*36379Ssklower } 649*36379Ssklower } 650*36379Ssklower } 651*36379Ssklower 652*36379Ssklower /* 653*36379Ssklower * FUNCTION: esis_shoutput 654*36379Ssklower * 655*36379Ssklower * PURPOSE: Transmit an esh or ish pdu 656*36379Ssklower * 657*36379Ssklower * RETURNS: nothing 658*36379Ssklower * 659*36379Ssklower * SIDE EFFECTS: 660*36379Ssklower * 661*36379Ssklower * NOTES: 662*36379Ssklower */ 663*36379Ssklower esis_shoutput(ifp, type, ht, sn_addr, sn_len) 664*36379Ssklower struct ifnet *ifp; 665*36379Ssklower int type; 666*36379Ssklower short ht; 667*36379Ssklower caddr_t sn_addr; 668*36379Ssklower int sn_len; 669*36379Ssklower { 670*36379Ssklower struct mbuf *m, *m0; 671*36379Ssklower caddr_t cp, naddrp; 672*36379Ssklower int naddr = 0; 673*36379Ssklower struct esis_fixed *pdu; 674*36379Ssklower struct ifaddr *ifa; 675*36379Ssklower int len, total_len = 0; 676*36379Ssklower struct sockaddr_iso siso; 677*36379Ssklower 678*36379Ssklower if (type == ESIS_ESH) 679*36379Ssklower esis_stat.es_eshsent++; 680*36379Ssklower else if (type == ESIS_ISH) 681*36379Ssklower esis_stat.es_ishsent++; 682*36379Ssklower else { 683*36379Ssklower printf("esis_shoutput: bad pdu type\n"); 684*36379Ssklower return; 685*36379Ssklower } 686*36379Ssklower 687*36379Ssklower IFDEBUG(D_ESISOUTPUT) 688*36379Ssklower int i; 689*36379Ssklower printf("esis_shoutput: ifp x%x (%s%d), %s, ht %d, to: [%d] ", 690*36379Ssklower ifp, ifp->if_name, ifp->if_unit, type == ESIS_ESH ? "esh" : "ish", 691*36379Ssklower ht, sn_len); 692*36379Ssklower for (i=0; i<sn_len; i++) 693*36379Ssklower printf("%x%c", *(sn_addr+i), i < (sn_len-1) ? ':' : ' '); 694*36379Ssklower printf("\n"); 695*36379Ssklower ENDDEBUG 696*36379Ssklower 697*36379Ssklower if ((m0 = m = m_getclr(M_DONTWAIT, MT_HEADER)) == NULL) { 698*36379Ssklower esis_stat.es_nomem++; 699*36379Ssklower return; 700*36379Ssklower } 701*36379Ssklower 702*36379Ssklower pdu = mtod(m, struct esis_fixed *); 703*36379Ssklower naddrp = cp = (caddr_t)pdu + sizeof(struct esis_fixed); 704*36379Ssklower len = sizeof(struct esis_fixed); 705*36379Ssklower 706*36379Ssklower /* 707*36379Ssklower * Build fixed part of header 708*36379Ssklower */ 709*36379Ssklower pdu->esis_proto_id = ISO9542_ESIS; 710*36379Ssklower pdu->esis_vers = ESIS_VERSION; 711*36379Ssklower pdu->esis_type = type; 712*36379Ssklower HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); 713*36379Ssklower 714*36379Ssklower if (type == ESIS_ESH) { 715*36379Ssklower cp++; 716*36379Ssklower len++; 717*36379Ssklower } 718*36379Ssklower 719*36379Ssklower for (ifa = ifp->if_addrlist; ifa; ifa=ifa->ifa_next) { 720*36379Ssklower if (ifa->ifa_addr.sa_family == AF_ISO) { 721*36379Ssklower IFDEBUG(D_ESISOUTPUT) 722*36379Ssklower printf("esis_shoutput: adding nsap %s\n", 723*36379Ssklower clnp_iso_addrp(&IA_SIS(ifa)->siso_addr)); 724*36379Ssklower ENDDEBUG 725*36379Ssklower if (!esis_insert_addr(&cp, &len, &IA_SIS(ifa)->siso_addr, 726*36379Ssklower MLEN - len)) { 727*36379Ssklower total_len += len; 728*36379Ssklower EXTEND_PACKET(m, m0, len, cp); 729*36379Ssklower (void) esis_insert_addr(&cp, &len, &IA_SIS(ifa)->siso_addr, 730*36379Ssklower MLEN - len); 731*36379Ssklower } 732*36379Ssklower naddr++; 733*36379Ssklower if (type == ESIS_ISH) 734*36379Ssklower break; 735*36379Ssklower } 736*36379Ssklower } 737*36379Ssklower 738*36379Ssklower if (type == ESIS_ESH) 739*36379Ssklower *naddrp = naddr; 740*36379Ssklower 741*36379Ssklower m->m_len = len; 742*36379Ssklower total_len += len; 743*36379Ssklower pdu->esis_hdr_len = total_len; 744*36379Ssklower iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len); 745*36379Ssklower 746*36379Ssklower siso.siso_family = AF_ISO; 747*36379Ssklower siso.siso_addr.isoa_afi = AFI_SNA; 748*36379Ssklower siso.siso_addr.isoa_len = sn_len + 1; 749*36379Ssklower bcopy(sn_addr, siso.siso_addr.sna_idi, sn_len); 750*36379Ssklower (ifp->if_output)(ifp, m0, &siso); 751*36379Ssklower } 752*36379Ssklower 753*36379Ssklower /* 754*36379Ssklower * FUNCTION: esis_ctlinput 755*36379Ssklower * 756*36379Ssklower * PURPOSE: Handle the PRC_IFDOWN transition 757*36379Ssklower * 758*36379Ssklower * RETURNS: nothing 759*36379Ssklower * 760*36379Ssklower * SIDE EFFECTS: 761*36379Ssklower * 762*36379Ssklower * NOTES: Calls snpac_flush for interface specified. 763*36379Ssklower * The loop through iso_ifaddr is stupid because 764*36379Ssklower * back in if_down, we knew the ifp... 765*36379Ssklower */ 766*36379Ssklower esis_ctlinput(req, siso) 767*36379Ssklower int req; /* request: we handle only PRC_IFDOWN */ 768*36379Ssklower struct sockaddr_iso *siso; /* address of ifp */ 769*36379Ssklower { 770*36379Ssklower register struct iso_ifaddr *ia; /* scan through interface addresses */ 771*36379Ssklower 772*36379Ssklower for (ia = iso_ifaddr; ia; ia = ia->ia_next) { 773*36379Ssklower if (iso_addrmatch(IA_SIS(ia), siso)) 774*36379Ssklower snpac_flushifp(ia->ia_ifp); 775*36379Ssklower } 776*36379Ssklower } 777*36379Ssklower 778*36379Ssklower #endif ISO 779