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