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