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