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