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