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