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 "types.h" 34 #include "param.h" 35 #include "mbuf.h" 36 #include "domain.h" 37 #include "protosw.h" 38 #include "dir.h" 39 #include "user.h" 40 #include "socket.h" 41 #include "socketvar.h" 42 #include "errno.h" 43 #include "kernel.h" 44 45 #include "../net/if.h" 46 #include "../net/route.h" 47 48 #include "iso.h" 49 #include "iso_pcb.h" 50 #include "iso_var.h" 51 #include "iso_snpac.h" 52 #include "clnl.h" 53 #include "clnp.h" 54 #include "clnp_stat.h" 55 #include "argo_debug.h" 56 #include "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, 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)->m_next;\ 80 (cp) = mtod((m), caddr_t);\ 81 } 82 /* 83 * FUNCTION: esis_init 84 * 85 * PURPOSE: Initialize the kernel portion of esis protocol 86 * 87 * RETURNS: nothing 88 * 89 * SIDE EFFECTS: 90 * 91 * NOTES: 92 */ 93 esis_init() 94 { 95 extern struct clnl_protosw clnl_protox[256]; 96 int esis_input(); 97 int snpac_age(); 98 int esis_config(); 99 #ifdef ISO_X25ESIS 100 x25esis_input(); 101 #endif ISO_X25ESIS 102 103 esis_pcb.isop_next = esis_pcb.isop_prev = &esis_pcb; 104 105 clnl_protox[ISO9542_ESIS].clnl_input = esis_input; 106 timeout(snpac_age, (caddr_t)0, hz); 107 timeout(esis_config, (caddr_t)0, hz); 108 109 #ifdef ISO_X25ESIS 110 clnl_protox[ISO9542X25_ESIS].clnl_input = x25esis_input; 111 #endif ISO_X25ESIS 112 } 113 114 /* 115 * FUNCTION: esis_usrreq 116 * 117 * PURPOSE: Handle user level esis requests 118 * 119 * RETURNS: 0 or appropriate errno 120 * 121 * SIDE EFFECTS: 122 * 123 * NOTES: This is here only so esis gets initialized. 124 */ 125 /*ARGSUSED*/ 126 esis_usrreq(so, req, m, nam, rights) 127 struct socket *so; /* socket: used only to get to this code */ 128 int req; /* request */ 129 struct mbuf *m; /* data for request */ 130 struct mbuf *nam; /* optional name */ 131 struct mbuf *rights; /* optional rights */ 132 { 133 if (m != NULL) 134 m_freem(m); 135 136 return(EOPNOTSUPP); 137 } 138 139 /* 140 * FUNCTION: esis_input 141 * 142 * PURPOSE: Process an incoming esis packet 143 * 144 * RETURNS: nothing 145 * 146 * SIDE EFFECTS: 147 * 148 * NOTES: 149 */ 150 esis_input(m0, shp) 151 struct mbuf *m0; /* ptr to first mbuf of pkt */ 152 struct snpa_hdr *shp; /* subnetwork header */ 153 { 154 struct esis_fixed *pdu = mtod(m0, struct esis_fixed *); 155 register int type; 156 157 IFDEBUG(D_ESISINPUT) 158 int i; 159 160 printf("esis_input: pdu on ifp x%x (%s%d): from:", shp->snh_ifp, 161 shp->snh_ifp->if_name, shp->snh_ifp->if_unit); 162 for (i=0; i<6; i++) 163 printf("%x%c", shp->snh_shost[i]&0xff, (i<5) ? ':' : ' '); 164 printf(" to:"); 165 for (i=0; i<6; i++) 166 printf("%x%c", shp->snh_dhost[i]&0xff, (i<5) ? ':' : ' '); 167 printf("\n"); 168 ENDDEBUG 169 170 /* 171 * check checksum if necessary 172 */ 173 if (ESIS_CKSUM_REQUIRED(pdu) && iso_check_csum(m0, (int)pdu->esis_hdr_len)) { 174 esis_stat.es_badcsum++; 175 goto bad; 176 } 177 178 /* check version */ 179 if (pdu->esis_vers != ESIS_VERSION) { 180 esis_stat.es_badvers++; 181 goto bad; 182 } 183 184 type = pdu->esis_type & 0x1f; 185 switch (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 printf("esis_rdoutput: ifp x%x (%s%d), ht %d, m x%x, oidx x%x\n", 239 ifp, ifp->if_name, ifp->if_unit, esis_holding_time, inbound_m, 240 inbound_oidx); 241 printf("\tdestination: %s\n", clnp_iso_addrp(rd_dstnsap)); 242 printf("\tredirected toward:%s\n", clnp_iso_addrp(&nhop_sc->sc_nsap)); 243 ENDDEBUG 244 245 if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) { 246 esis_stat.es_nomem++; 247 return; 248 } 249 bzero(mtod(m, caddr_t), MHLEN); 250 251 pdu = mtod(m, struct esis_fixed *); 252 cp = (caddr_t)(pdu + 1); /*pointer arith.; 1st byte after header */ 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, m); 265 266 /* Insert the snpa of better next hop */ 267 *cp++ = nhop_sc->sc_len; 268 bcopy((caddr_t)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, m); 285 } else { 286 *cp++ = 0; /* NETL */ 287 len++; 288 } 289 m->m_len = len; 290 291 /* 292 * PHASE2 293 * If redirect is to an IS, add an address mask. The mask to be 294 * used should be the mask present in the routing entry used to 295 * forward the original data packet. 296 */ 297 298 /* 299 * Copy Qos, priority, or security options present in original npdu 300 */ 301 if (inbound_oidx) { 302 /* THIS CODE IS CURRENTLY UNTESTED */ 303 int optlen = 0; 304 if (inbound_oidx->cni_qos_formatp) 305 optlen += (inbound_oidx->cni_qos_len + 2); 306 if (inbound_oidx->cni_priorp) /* priority option is 1 byte long */ 307 optlen += 3; 308 if (inbound_oidx->cni_securep) 309 optlen += (inbound_oidx->cni_secure_len + 2); 310 if (M_TRAILINGSPACE(m) < optlen) { 311 EXTEND_PACKET(m, m0, cp); 312 m->m_len = 0; 313 /* assumes MLEN > optlen */ 314 } 315 /* assume MLEN-len > optlen */ 316 /* 317 * When copying options, copy from ptr - 2 in order to grab 318 * the option code and length 319 */ 320 if (inbound_oidx->cni_qos_formatp) { 321 bcopy((caddr_t)(inbound_m + inbound_oidx->cni_qos_formatp - 2), cp, 322 (unsigned)(inbound_oidx->cni_qos_len + 2)); 323 len += inbound_oidx->cni_qos_len + 2; 324 } 325 if (inbound_oidx->cni_priorp) { 326 bcopy((caddr_t)(inbound_m + inbound_oidx->cni_priorp - 2), cp, 3); 327 len += 3; 328 } 329 if (inbound_oidx->cni_securep) { 330 bcopy((caddr_t)(inbound_m + inbound_oidx->cni_securep - 2), cp, 331 (unsigned)(inbound_oidx->cni_secure_len + 2)); 332 len += inbound_oidx->cni_secure_len + 2; 333 } 334 m->m_len += optlen; 335 } 336 337 pdu->esis_hdr_len = m0->m_pkthdr.len = len; 338 iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len); 339 340 bzero((caddr_t)&siso, sizeof(siso)); 341 siso.siso_len = 12; 342 siso.siso_family = AF_ISO; 343 siso.siso_data[0] = AFI_SNA; 344 siso.siso_nlen = 6 + 1; /* should be taken from snpa_hdr */ 345 /* +1 is for AFI */ 346 bcopy(inbound_shp->snh_shost, siso.siso_data + 1, 6); 347 (ifp->if_output)(ifp, m0, &siso); 348 } 349 350 /* 351 * FUNCTION: esis_insert_addr 352 * 353 * PURPOSE: Insert an iso_addr into a buffer 354 * 355 * RETURNS: true if buffer was big enough, else false 356 * 357 * SIDE EFFECTS: Increment buf & len according to size of iso_addr 358 * 359 * NOTES: Plus 1 here is for length byte 360 */ 361 esis_insert_addr(buf, len, isoa, m) 362 caddr_t *buf; /* ptr to buffer to put address into */ 363 int *len; /* ptr to length of buffer so far */ 364 struct iso_addr *isoa; /* ptr to address */ 365 register struct mbuf *m; /* determine if there remains space */ 366 { 367 register int newlen = isoa->isoa_len + 1; 368 369 if (newlen > M_TRAILINGSPACE(m)) 370 return(0); 371 bcopy((caddr_t)isoa, *buf, newlen); 372 *len += newlen; 373 *buf += newlen; 374 m->m_len += newlen; 375 return(1); 376 } 377 378 /* 379 380 /* 381 * FUNCTION: esis_eshinput 382 * 383 * PURPOSE: Process an incoming ESH pdu 384 * 385 * RETURNS: nothing 386 * 387 * SIDE EFFECTS: 388 * 389 * NOTES: 390 */ 391 esis_eshinput(m, shp) 392 struct mbuf *m; /* esh pdu */ 393 struct snpa_hdr *shp; /* subnetwork header */ 394 { 395 struct esis_fixed *pdu = mtod(m, struct esis_fixed *); 396 u_short ht; /* holding time */ 397 struct iso_addr *nsap; 398 int naddr = 0; 399 u_char *buf = (u_char *)(pdu + 1); 400 int len = pdu->esis_hdr_len - sizeof(struct esis_fixed); 401 int optlen, new_entry; 402 403 esis_stat.es_eshrcvd++; 404 405 CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); 406 407 if (len > 0) { 408 naddr = *buf++; 409 len--; 410 } else 411 goto bad; 412 413 IFDEBUG(D_ESISINPUT) 414 printf("esis_eshinput: esh: ht %d, naddr %d\n", ht, naddr); 415 ENDDEBUG 416 417 while (naddr-- > 0) { 418 nsap = (struct iso_addr *)buf; 419 if ((len -= (optlen = *buf++)) >= 0) { 420 buf += optlen; 421 new_entry = (snpac_look(nsap) == NULL); 422 423 IFDEBUG(D_ESISINPUT) 424 printf("esis_eshinput: nsap %s is %s\n", 425 clnp_iso_addrp(nsap), new_entry ? "new" : "old"); 426 ENDDEBUG 427 428 snpac_add(shp->snh_ifp, nsap, shp->snh_shost, 6, SNPA_ES, ht); 429 if (new_entry) 430 esis_shoutput(shp->snh_ifp, 431 iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH, 432 esis_holding_time, shp->snh_shost, 6); 433 } else { 434 bad: 435 esis_stat.es_toosmall++; 436 break; 437 } 438 } 439 440 m_freem(m); 441 } 442 443 /* 444 * FUNCTION: esis_ishinput 445 * 446 * PURPOSE: process an incoming ISH pdu 447 * 448 * RETURNS: 449 * 450 * SIDE EFFECTS: 451 * 452 * NOTES: 453 */ 454 esis_ishinput(m, shp) 455 struct mbuf *m; /* esh pdu */ 456 struct snpa_hdr *shp; /* subnetwork header */ 457 { 458 struct esis_fixed *pdu = mtod(m, struct esis_fixed *); 459 u_short ht; /* holding time */ 460 struct iso_addr *nsap; 461 caddr_t buf = (caddr_t)pdu + sizeof(struct esis_fixed); 462 int len = pdu->esis_hdr_len - sizeof(struct esis_fixed); 463 int optlen, new_entry; 464 465 esis_stat.es_ishrcvd++; 466 CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); 467 468 IFDEBUG(D_ESISINPUT) 469 printf("esis_ishinput: ish: ht %d\n", ht); 470 ENDDEBUG 471 472 nsap = (struct iso_addr *)buf; 473 if ((len -= (optlen = *buf++)) < 0) 474 goto bad; 475 buf += optlen; 476 477 /* process options */ 478 while (len > 0) { 479 switch (*buf++) { 480 case ESISOVAL_ESCT: 481 if (*buf != 2) 482 goto bad; 483 CTOH(buf[0], buf[1], esis_config_time); 484 } 485 if ((len -= (optlen = *buf)) < 0) { 486 bad: 487 esis_stat.es_toosmall++; 488 m_freem(m); 489 return; 490 } 491 buf += 1 + optlen; 492 } 493 new_entry = (snpac_look(nsap) == NULL); 494 495 IFDEBUG(D_ESISINPUT) 496 printf("esis_ishinput: nsap %s is %s\n", 497 clnp_iso_addrp(nsap), new_entry ? "new" : "old"); 498 ENDDEBUG 499 500 snpac_add(shp->snh_ifp, nsap, shp->snh_shost, 6, SNPA_IS, ht); 501 if (new_entry) 502 esis_shoutput(shp->snh_ifp, 503 iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH, 504 esis_holding_time, shp->snh_shost, 6); 505 m_freem(m); 506 } 507 508 /* 509 * FUNCTION: esis_rdinput 510 * 511 * PURPOSE: Process an incoming RD pdu 512 * 513 * RETURNS: 514 * 515 * SIDE EFFECTS: 516 * 517 * NOTES: 518 */ 519 esis_rdinput(m0, shp) 520 struct mbuf *m0; /* esh pdu */ 521 struct snpa_hdr *shp; /* subnetwork header */ 522 { 523 struct esis_fixed *pdu = mtod(m0, struct esis_fixed *); 524 u_short ht; /* holding time */ 525 register struct iso_addr *da, *net = 0, *netmask = 0, *snpamask = 0; 526 u_char *buf = (u_char *)(pdu + 1); 527 int len = pdu->esis_hdr_len - sizeof(struct esis_fixed); 528 int optlen, bsnpalen; 529 caddr_t bsnpa; 530 531 esis_stat.es_rdrcvd++; 532 533 /* intermediate systems ignore redirects */ 534 if (iso_systype & SNPA_IS) 535 goto bad; 536 537 CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); 538 if (len <= 0) 539 goto bad; 540 541 /* Extract DA */ 542 da = (struct iso_addr *)buf; 543 if ((len -= (optlen = *buf++)) <= 0) 544 goto bad; 545 buf += optlen; 546 547 /* Extract better snpa */ 548 if ((len -= (bsnpalen = *buf++)) < 0) 549 goto bad; 550 bsnpa = (caddr_t)buf; 551 buf += optlen; 552 553 /* Extract NET if present */ 554 if (len) { 555 net = (struct iso_addr *)buf; 556 if ((len -= (optlen = *buf++)) < 0) 557 goto bad; 558 buf += optlen; 559 } 560 561 /* process options */ 562 while (len > 0) { 563 switch (*buf++) { 564 case ESISOVAL_SNPAMASK: 565 if (snpamask) /* duplicate */ 566 goto bad; 567 snpamask = (struct iso_addr *)buf; 568 break; 569 570 case ESISOVAL_NETMASK: 571 if (netmask) /* duplicate */ 572 goto bad; 573 netmask = (struct iso_addr *)buf; 574 } 575 if ((len -= (optlen = *buf)) < 0) 576 goto bad; 577 buf += 1 + optlen; 578 } 579 580 IFDEBUG(D_ESISINPUT) 581 printf("esis_rdinput: rd: ht %d, da %s\n", ht, clnp_iso_addrp(da)); 582 if (net) 583 printf("\t: net %s\n", clnp_iso_addrp(net)); 584 ENDDEBUG 585 /* 586 * If netl is zero, then redirect is to an ES. We need to add an entry 587 * to the snpa cache for (destination, better snpa). 588 * If netl is not zero, then the redirect is to an IS. In this 589 * case, add an snpa cache entry for (net, better snpa). 590 * 591 * If the redirect is to an IS, add a route entry towards that 592 * IS. 593 */ 594 if ((net == 0) || (snpamask)) { 595 /* redirect to an ES */ 596 snpac_add(shp->snh_ifp, da, bsnpa, bsnpalen, SNPA_ES, ht); 597 } else { 598 struct iso_addr bsnpa_ia; 599 600 snpac_add(shp->snh_ifp, net, bsnpa, bsnpalen, SNPA_IS, ht); 601 bcopy(bsnpa, bsnpa_ia.isoa_genaddr, bsnpa_ia.isoa_len = 1 + bsnpalen); 602 bsnpa_ia.isoa_genaddr[0] = AFI_SNA; 603 snpac_addrt(da, &bsnpa_ia, net, netmask); 604 } 605 bad: 606 m_freem(m0); 607 } 608 609 /* 610 * FUNCTION: esis_config 611 * 612 * PURPOSE: Report configuration 613 * 614 * RETURNS: 615 * 616 * SIDE EFFECTS: 617 * 618 * NOTES: Called every esis_config_time seconds 619 */ 620 esis_config() 621 { 622 register struct ifnet *ifp; 623 624 timeout(esis_config, (caddr_t)0, hz * esis_config_time); 625 626 /* 627 * Report configuration for each interface that 628 * - is UP 629 * - is not loopback 630 * - has broadcast capabilities 631 * - has an ISO address 632 */ 633 634 for (ifp = ifnet; ifp; ifp = ifp->if_next) { 635 if ((ifp->if_flags & IFF_UP) && 636 (ifp->if_flags & IFF_BROADCAST) && 637 ((ifp->if_flags & IFF_LOOPBACK) == 0)) { 638 /* search for an ISO address family */ 639 struct ifaddr *ia; 640 641 for (ia = ifp->if_addrlist; ia; ia = ia->ifa_next) { 642 if (ia->ifa_addr->sa_family == AF_ISO) { 643 esis_shoutput(ifp, 644 iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH, 645 esis_holding_time, 646 (caddr_t)(iso_systype & SNPA_ES ? all_is.sc_snpa : 647 all_es.sc_snpa), 6); 648 break; 649 } 650 } 651 } 652 } 653 } 654 655 /* 656 * FUNCTION: esis_shoutput 657 * 658 * PURPOSE: Transmit an esh or ish pdu 659 * 660 * RETURNS: nothing 661 * 662 * SIDE EFFECTS: 663 * 664 * NOTES: 665 */ 666 esis_shoutput(ifp, type, ht, sn_addr, sn_len) 667 struct ifnet *ifp; 668 int type; 669 short ht; 670 caddr_t sn_addr; 671 int sn_len; 672 { 673 struct mbuf *m, *m0; 674 caddr_t cp, naddrp; 675 int naddr = 0; 676 struct esis_fixed *pdu; 677 struct ifaddr *ifa; 678 int len; 679 struct sockaddr_iso siso; 680 681 if (type == ESIS_ESH) 682 esis_stat.es_eshsent++; 683 else if (type == ESIS_ISH) 684 esis_stat.es_ishsent++; 685 else { 686 printf("esis_shoutput: bad pdu type\n"); 687 return; 688 } 689 690 IFDEBUG(D_ESISOUTPUT) 691 int i; 692 printf("esis_shoutput: ifp x%x (%s%d), %s, ht %d, to: [%d] ", 693 ifp, ifp->if_name, ifp->if_unit, type == ESIS_ESH ? "esh" : "ish", 694 ht, sn_len); 695 for (i=0; i<sn_len; i++) 696 printf("%x%c", *(sn_addr+i), i < (sn_len-1) ? ':' : ' '); 697 printf("\n"); 698 ENDDEBUG 699 700 if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) { 701 esis_stat.es_nomem++; 702 return; 703 } 704 bzero(mtod(m, caddr_t), MHLEN); 705 706 pdu = mtod(m, struct esis_fixed *); 707 naddrp = cp = (caddr_t)(pdu + 1); 708 len = sizeof(struct esis_fixed); 709 710 /* 711 * Build fixed part of header 712 */ 713 pdu->esis_proto_id = ISO9542_ESIS; 714 pdu->esis_vers = ESIS_VERSION; 715 pdu->esis_type = type; 716 HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); 717 718 if (type == ESIS_ESH) { 719 cp++; 720 len++; 721 } 722 723 m->m_len = len; 724 for (ifa = ifp->if_addrlist; ifa; ifa=ifa->ifa_next) { 725 if (ifa->ifa_addr->sa_family == AF_ISO) { 726 IFDEBUG(D_ESISOUTPUT) 727 printf("esis_shoutput: adding nsap %s\n", 728 clnp_iso_addrp(&IA_SIS(ifa)->siso_addr)); 729 ENDDEBUG 730 if (!esis_insert_addr(&cp, &len, &IA_SIS(ifa)->siso_addr, m)) { 731 EXTEND_PACKET(m, m0, cp); 732 (void) esis_insert_addr(&cp, &len, &IA_SIS(ifa)->siso_addr, m); 733 } 734 naddr++; 735 if (type == ESIS_ISH) 736 break; 737 } 738 } 739 740 if (type == ESIS_ESH) 741 *naddrp = naddr; 742 743 m0->m_pkthdr.len = len; 744 pdu->esis_hdr_len = len; 745 iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len); 746 747 bzero((caddr_t)&siso, sizeof(siso)); 748 siso.siso_family = AF_ISO; 749 siso.siso_data[0] = AFI_SNA; 750 siso.siso_nlen = sn_len + 1; 751 siso.siso_len = sn_len + 6; 752 bcopy(sn_addr, siso.siso_data + 1, (unsigned)sn_len); 753 (ifp->if_output)(ifp, m0, &siso); 754 } 755 756 /* 757 * FUNCTION: esis_ctlinput 758 * 759 * PURPOSE: Handle the PRC_IFDOWN transition 760 * 761 * RETURNS: nothing 762 * 763 * SIDE EFFECTS: 764 * 765 * NOTES: Calls snpac_flush for interface specified. 766 * The loop through iso_ifaddr is stupid because 767 * back in if_down, we knew the ifp... 768 */ 769 esis_ctlinput(req, siso) 770 int req; /* request: we handle only PRC_IFDOWN */ 771 struct sockaddr_iso *siso; /* address of ifp */ 772 { 773 register struct iso_ifaddr *ia; /* scan through interface addresses */ 774 775 if (req == PRC_IFDOWN) 776 for (ia = iso_ifaddr; ia; ia = ia->ia_next) { 777 if (iso_addrmatch(IA_SIS(ia), siso)) 778 snpac_flushifp(ia->ia_ifp); 779 } 780 } 781 782 #endif ISO 783