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 /* @(#)esis.c 7.6 (Berkeley) 04/05/90 */ 28 #ifndef lint 29 static char *rcsid = "$Header: esis.c,v 4.10 88/09/15 18:57:03 hagens Exp $"; 30 #endif 31 32 #ifdef ISO 33 34 #include "types.h" 35 #include "param.h" 36 #include "mbuf.h" 37 #include "domain.h" 38 #include "protosw.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 "esis.h" 56 #include "argo_debug.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, control) 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 *control; /* optional control */ 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, 0); 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 #define ESIS_EXTRACT_ADDR(d, b) { d = (struct iso_addr *)(b); b += (1 + *b); \ 379 if (b > buflim) {esis_stat.es_toosmall++; goto bad;}} 380 #define ESIS_NEXT_OPTION(b) { b += (2 + b[1]); \ 381 if (b > buflim) {esis_stat.es_toosmall++; goto bad;}} 382 int ESHonly = 1; 383 /* 384 385 /* 386 * FUNCTION: esis_eshinput 387 * 388 * PURPOSE: Process an incoming ESH pdu 389 * 390 * RETURNS: nothing 391 * 392 * SIDE EFFECTS: 393 * 394 * NOTES: 395 */ 396 esis_eshinput(m, shp) 397 struct mbuf *m; /* esh pdu */ 398 struct snpa_hdr *shp; /* subnetwork header */ 399 { 400 struct esis_fixed *pdu = mtod(m, struct esis_fixed *); 401 u_short ht; /* holding time */ 402 struct iso_addr *nsap; 403 int naddr; 404 u_char *buf = (u_char *)(pdu + 1); 405 u_char *buflim = pdu->esis_hdr_len + (u_char *)pdu; 406 int new_entry; 407 408 esis_stat.es_eshrcvd++; 409 410 CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); 411 412 naddr = *buf++; 413 if (buf >= buflim) 414 goto bad; 415 416 IFDEBUG(D_ESISINPUT) 417 printf("esis_eshinput: esh: ht %d, naddr %d\n", ht, naddr); 418 ENDDEBUG 419 420 while (naddr-- > 0) { 421 ESIS_EXTRACT_ADDR(nsap, buf); 422 new_entry = (snpac_look(nsap) == NULL); 423 424 IFDEBUG(D_ESISINPUT) 425 printf("esis_eshinput: nsap %s is %s\n", 426 clnp_iso_addrp(nsap), new_entry ? "new" : "old"); 427 ENDDEBUG 428 429 snpac_add(shp->snh_ifp, nsap, shp->snh_shost, 6, SNPA_ES, ht); 430 if (new_entry) 431 esis_shoutput(shp->snh_ifp, 432 iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH, 433 esis_holding_time, shp->snh_shost, 6); 434 } 435 bad: 436 m_freem(m); 437 return; 438 } 439 440 /* 441 * FUNCTION: esis_ishinput 442 * 443 * PURPOSE: process an incoming ISH pdu 444 * 445 * RETURNS: 446 * 447 * SIDE EFFECTS: 448 * 449 * NOTES: 450 */ 451 esis_ishinput(m, shp) 452 struct mbuf *m; /* esh pdu */ 453 struct snpa_hdr *shp; /* subnetwork header */ 454 { 455 struct esis_fixed *pdu = mtod(m, struct esis_fixed *); 456 u_short ht; /* holding time */ 457 struct iso_addr *nsap; /* Network Entity Title */ 458 register u_char *buf = (u_char *) (pdu + 1); 459 register u_char *buflim = pdu->esis_hdr_len + (u_char *)pdu; 460 int new_entry; 461 462 esis_stat.es_ishrcvd++; 463 CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); 464 465 IFDEBUG(D_ESISINPUT) 466 printf("esis_ishinput: ish: ht %d\n", ht); 467 ENDDEBUG 468 if (ESHonly) 469 goto bad; 470 471 ESIS_EXTRACT_ADDR(nsap, buf); 472 473 while (buf < buflim) { 474 switch (*buf) { 475 case ESISOVAL_ESCT: 476 if (buf[1] != 2) 477 goto bad; 478 CTOH(buf[2], buf[3], esis_config_time); 479 break; 480 481 default: 482 printf("Unknown ISH option: %x\n", *buf); 483 } 484 ESIS_NEXT_OPTION(buf); 485 } 486 new_entry = (snpac_look(nsap) == NULL); 487 488 IFDEBUG(D_ESISINPUT) 489 printf("esis_ishinput: nsap %s is %s\n", 490 clnp_iso_addrp(nsap), new_entry ? "new" : "old"); 491 ENDDEBUG 492 493 snpac_add(shp->snh_ifp, nsap, shp->snh_shost, 6, SNPA_IS, ht); 494 if (new_entry) 495 esis_shoutput(shp->snh_ifp, 496 iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH, 497 esis_holding_time, shp->snh_shost, 6); 498 bad: 499 m_freem(m); 500 return; 501 } 502 503 /* 504 * FUNCTION: esis_rdinput 505 * 506 * PURPOSE: Process an incoming RD pdu 507 * 508 * RETURNS: 509 * 510 * SIDE EFFECTS: 511 * 512 * NOTES: 513 */ 514 esis_rdinput(m0, shp) 515 struct mbuf *m0; /* esh pdu */ 516 struct snpa_hdr *shp; /* subnetwork header */ 517 { 518 struct esis_fixed *pdu = mtod(m0, struct esis_fixed *); 519 u_short ht; /* holding time */ 520 struct iso_addr *da, *net = 0, *netmask = 0, *snpamask = 0; 521 register struct iso_addr *bsnpa; 522 register u_char *buf = (u_char *)(pdu + 1); 523 register u_char *buflim = pdu->esis_hdr_len + (u_char *)pdu; 524 525 esis_stat.es_rdrcvd++; 526 527 /* intermediate systems ignore redirects */ 528 if (iso_systype & SNPA_IS) 529 goto bad; 530 if (ESHonly) 531 goto bad; 532 533 CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); 534 if (buf >= buflim) 535 goto bad; 536 537 /* Extract DA */ 538 ESIS_EXTRACT_ADDR(da, buf); 539 540 /* Extract better snpa */ 541 ESIS_EXTRACT_ADDR(bsnpa, buf); 542 543 /* Extract NET if present */ 544 if (buf < buflim) { 545 ESIS_EXTRACT_ADDR(net, buf); 546 } 547 548 /* process options */ 549 while (buf < buflim) { 550 switch (*buf) { 551 case ESISOVAL_SNPAMASK: 552 if (snpamask) /* duplicate */ 553 goto bad; 554 snpamask = (struct iso_addr *)(buf + 1); 555 break; 556 557 case ESISOVAL_NETMASK: 558 if (netmask) /* duplicate */ 559 goto bad; 560 netmask = (struct iso_addr *)(buf + 1); 561 break; 562 563 default: 564 printf("Unknown option in ESIS RD (0x%x)\n", buf[-1]); 565 } 566 ESIS_NEXT_OPTION(buf); 567 } 568 569 IFDEBUG(D_ESISINPUT) 570 printf("esis_rdinput: rd: ht %d, da %s\n", ht, clnp_iso_addrp(da)); 571 if (net) 572 printf("\t: net %s\n", clnp_iso_addrp(net)); 573 ENDDEBUG 574 /* 575 * If netl is zero, then redirect is to an ES. We need to add an entry 576 * to the snpa cache for (destination, better snpa). 577 * If netl is not zero, then the redirect is to an IS. In this 578 * case, add an snpa cache entry for (net, better snpa). 579 * 580 * If the redirect is to an IS, add a route entry towards that 581 * IS. 582 */ 583 if (net == 0 || net->isoa_len == 0 || snpamask) { 584 /* redirect to an ES */ 585 snpac_add(shp->snh_ifp, da, 586 bsnpa->isoa_genaddr, bsnpa->isoa_len, SNPA_ES, ht); 587 } else { 588 snpac_add(shp->snh_ifp, net, 589 bsnpa->isoa_genaddr, bsnpa->isoa_len, SNPA_IS, ht); 590 snpac_addrt(shp->snh_ifp, da, net, netmask); 591 } 592 bad: 593 m_freem(m0); 594 } 595 596 /* 597 * FUNCTION: esis_config 598 * 599 * PURPOSE: Report configuration 600 * 601 * RETURNS: 602 * 603 * SIDE EFFECTS: 604 * 605 * NOTES: Called every esis_config_time seconds 606 */ 607 esis_config() 608 { 609 register struct ifnet *ifp; 610 611 timeout(esis_config, (caddr_t)0, hz * esis_config_time); 612 613 /* 614 * Report configuration for each interface that 615 * - is UP 616 * - is not loopback 617 * - has broadcast capabilities 618 * - has an ISO address 619 */ 620 621 for (ifp = ifnet; ifp; ifp = ifp->if_next) { 622 if ((ifp->if_flags & IFF_UP) && 623 (ifp->if_flags & IFF_BROADCAST) && 624 ((ifp->if_flags & IFF_LOOPBACK) == 0)) { 625 /* search for an ISO address family */ 626 struct ifaddr *ia; 627 628 for (ia = ifp->if_addrlist; ia; ia = ia->ifa_next) { 629 if (ia->ifa_addr->sa_family == AF_ISO) { 630 esis_shoutput(ifp, 631 iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH, 632 esis_holding_time, 633 (caddr_t)(iso_systype & SNPA_ES ? all_is.sc_snpa : 634 all_es.sc_snpa), 6); 635 break; 636 } 637 } 638 } 639 } 640 } 641 642 /* 643 * FUNCTION: esis_shoutput 644 * 645 * PURPOSE: Transmit an esh or ish pdu 646 * 647 * RETURNS: nothing 648 * 649 * SIDE EFFECTS: 650 * 651 * NOTES: 652 */ 653 esis_shoutput(ifp, type, ht, sn_addr, sn_len) 654 struct ifnet *ifp; 655 int type; 656 short ht; 657 caddr_t sn_addr; 658 int sn_len; 659 { 660 struct mbuf *m, *m0; 661 caddr_t cp, naddrp; 662 int naddr = 0; 663 struct esis_fixed *pdu; 664 struct ifaddr *ifa; 665 int len; 666 struct sockaddr_iso siso; 667 668 if (type == ESIS_ESH) 669 esis_stat.es_eshsent++; 670 else if (type == ESIS_ISH) 671 esis_stat.es_ishsent++; 672 else { 673 printf("esis_shoutput: bad pdu type\n"); 674 return; 675 } 676 677 IFDEBUG(D_ESISOUTPUT) 678 int i; 679 printf("esis_shoutput: ifp x%x (%s%d), %s, ht %d, to: [%d] ", 680 ifp, ifp->if_name, ifp->if_unit, type == ESIS_ESH ? "esh" : "ish", 681 ht, sn_len); 682 for (i=0; i<sn_len; i++) 683 printf("%x%c", *(sn_addr+i), i < (sn_len-1) ? ':' : ' '); 684 printf("\n"); 685 ENDDEBUG 686 687 if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) { 688 esis_stat.es_nomem++; 689 return; 690 } 691 bzero(mtod(m, caddr_t), MHLEN); 692 693 pdu = mtod(m, struct esis_fixed *); 694 naddrp = cp = (caddr_t)(pdu + 1); 695 len = sizeof(struct esis_fixed); 696 697 /* 698 * Build fixed part of header 699 */ 700 pdu->esis_proto_id = ISO9542_ESIS; 701 pdu->esis_vers = ESIS_VERSION; 702 pdu->esis_type = type; 703 HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); 704 705 if (type == ESIS_ESH) { 706 cp++; 707 len++; 708 } 709 710 m->m_len = len; 711 for (ifa = ifp->if_addrlist; ifa; ifa=ifa->ifa_next) { 712 if (ifa->ifa_addr->sa_family == AF_ISO) { 713 IFDEBUG(D_ESISOUTPUT) 714 printf("esis_shoutput: adding nsap %s\n", 715 clnp_iso_addrp(&IA_SIS(ifa)->siso_addr)); 716 ENDDEBUG 717 if (!esis_insert_addr(&cp, &len, &IA_SIS(ifa)->siso_addr, m)) { 718 EXTEND_PACKET(m, m0, cp); 719 (void) esis_insert_addr(&cp, &len, &IA_SIS(ifa)->siso_addr, m); 720 } 721 naddr++; 722 if (type == ESIS_ISH) 723 break; 724 } 725 } 726 727 if (type == ESIS_ESH) 728 *naddrp = naddr; 729 730 m0->m_pkthdr.len = len; 731 pdu->esis_hdr_len = len; 732 iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len); 733 734 bzero((caddr_t)&siso, sizeof(siso)); 735 siso.siso_family = AF_ISO; 736 siso.siso_data[0] = AFI_SNA; 737 siso.siso_nlen = sn_len + 1; 738 siso.siso_len = sn_len + 6; 739 bcopy(sn_addr, siso.siso_data + 1, (unsigned)sn_len); 740 (ifp->if_output)(ifp, m0, &siso, 0); 741 } 742 743 /* 744 * FUNCTION: esis_ctlinput 745 * 746 * PURPOSE: Handle the PRC_IFDOWN transition 747 * 748 * RETURNS: nothing 749 * 750 * SIDE EFFECTS: 751 * 752 * NOTES: Calls snpac_flush for interface specified. 753 * The loop through iso_ifaddr is stupid because 754 * back in if_down, we knew the ifp... 755 */ 756 esis_ctlinput(req, siso) 757 int req; /* request: we handle only PRC_IFDOWN */ 758 struct sockaddr_iso *siso; /* address of ifp */ 759 { 760 register struct iso_ifaddr *ia; /* scan through interface addresses */ 761 762 if (req == PRC_IFDOWN) 763 for (ia = iso_ifaddr; ia; ia = ia->ia_next) { 764 if (iso_addrmatch(IA_SIS(ia), siso)) 765 snpac_flushifp(ia->ia_ifp); 766 } 767 } 768 769 #endif ISO 770