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.9 (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 = 1; 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; /* 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], esis_config_time); 580 break; 581 582 default: 583 printf("Unknown ISH option: %x\n", *buf); 584 } 585 ESIS_NEXT_OPTION(buf); 586 } 587 new_entry = snpac_add(shp->snh_ifp, nsap, shp->snh_shost, SNPA_IS, ht, 0); 588 IFDEBUG(D_ESISINPUT) 589 printf("esis_ishinput: nsap %s is %s\n", 590 clnp_iso_addrp(nsap), new_entry ? "new" : "old"); 591 ENDDEBUG 592 593 if (new_entry) 594 esis_shoutput(shp->snh_ifp, 595 iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH, 596 esis_holding_time, shp->snh_shost, 6, (struct iso_addr *)0); 597 bad: 598 return; 599 } 600 601 /* 602 * FUNCTION: esis_rdinput 603 * 604 * PURPOSE: Process an incoming RD pdu 605 * 606 * RETURNS: 607 * 608 * SIDE EFFECTS: 609 * 610 * NOTES: 611 */ 612 esis_rdinput(m0, shp) 613 struct mbuf *m0; /* esh pdu */ 614 struct snpa_hdr *shp; /* subnetwork header */ 615 { 616 struct esis_fixed *pdu = mtod(m0, struct esis_fixed *); 617 u_short ht; /* holding time */ 618 struct iso_addr *da, *net = 0, *netmask = 0, *snpamask = 0; 619 register struct iso_addr *bsnpa; 620 register u_char *buf = (u_char *)(pdu + 1); 621 register u_char *buflim = pdu->esis_hdr_len + (u_char *)pdu; 622 623 esis_stat.es_rdrcvd++; 624 625 /* intermediate systems ignore redirects */ 626 if (iso_systype & SNPA_IS) 627 return; 628 if (ESHonly) 629 return; 630 631 CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); 632 if (buf >= buflim) 633 return; 634 635 /* Extract DA */ 636 ESIS_EXTRACT_ADDR(da, buf); 637 638 /* Extract better snpa */ 639 ESIS_EXTRACT_ADDR(bsnpa, buf); 640 641 /* Extract NET if present */ 642 if (buf < buflim) { 643 if (*buf == 0) 644 buf++; /* no NET present, skip NETL anyway */ 645 else 646 ESIS_EXTRACT_ADDR(net, buf); 647 } 648 649 /* process options */ 650 while (buf < buflim) { 651 switch (*buf) { 652 case ESISOVAL_SNPAMASK: 653 if (snpamask) /* duplicate */ 654 return; 655 snpamask = (struct iso_addr *)(buf + 1); 656 break; 657 658 case ESISOVAL_NETMASK: 659 if (netmask) /* duplicate */ 660 return; 661 netmask = (struct iso_addr *)(buf + 1); 662 break; 663 664 default: 665 printf("Unknown option in ESIS RD (0x%x)\n", buf[-1]); 666 } 667 ESIS_NEXT_OPTION(buf); 668 } 669 670 IFDEBUG(D_ESISINPUT) 671 printf("esis_rdinput: rd: ht %d, da %s\n", ht, clnp_iso_addrp(da)); 672 if (net) 673 printf("\t: net %s\n", clnp_iso_addrp(net)); 674 ENDDEBUG 675 /* 676 * If netl is zero, then redirect is to an ES. We need to add an entry 677 * to the snpa cache for (destination, better snpa). 678 * If netl is not zero, then the redirect is to an IS. In this 679 * case, add an snpa cache entry for (net, better snpa). 680 * 681 * If the redirect is to an IS, add a route entry towards that 682 * IS. 683 */ 684 if (net == 0 || net->isoa_len == 0 || snpamask) { 685 /* redirect to an ES */ 686 snpac_add(shp->snh_ifp, da, 687 bsnpa->isoa_genaddr, SNPA_ES, ht, 0); 688 } else { 689 snpac_add(shp->snh_ifp, net, 690 bsnpa->isoa_genaddr, SNPA_IS, ht, 0); 691 snpac_addrt(shp->snh_ifp, da, net, netmask); 692 } 693 bad: ; /* Needed by ESIS_NEXT_OPTION */ 694 } 695 696 /* 697 * FUNCTION: esis_config 698 * 699 * PURPOSE: Report configuration 700 * 701 * RETURNS: 702 * 703 * SIDE EFFECTS: 704 * 705 * NOTES: Called every esis_config_time seconds 706 */ 707 esis_config() 708 { 709 register struct ifnet *ifp; 710 711 timeout(esis_config, (caddr_t)0, hz * esis_config_time); 712 713 /* 714 * Report configuration for each interface that 715 * - is UP 716 * - is not loopback 717 * - has an ISO address 718 */ 719 720 for (ifp = ifnet; ifp; ifp = ifp->if_next) { 721 if ((ifp->if_flags & IFF_UP) && 722 ((ifp->if_flags & IFF_LOOPBACK) == 0)) { 723 /* search for an ISO address family */ 724 struct ifaddr *ia; 725 726 for (ia = ifp->if_addrlist; ia; ia = ia->ifa_next) { 727 if (ia->ifa_addr->sa_family == AF_ISO) { 728 esis_shoutput(ifp, 729 iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH, 730 esis_holding_time, 731 (caddr_t)(iso_systype & SNPA_ES ? all_is_snpa : 732 all_es_snpa), 6, (struct iso_addr *)0); 733 break; 734 } 735 } 736 } 737 } 738 } 739 740 /* 741 * FUNCTION: esis_shoutput 742 * 743 * PURPOSE: Transmit an esh or ish pdu 744 * 745 * RETURNS: nothing 746 * 747 * SIDE EFFECTS: 748 * 749 * NOTES: 750 */ 751 esis_shoutput(ifp, type, ht, sn_addr, sn_len, isoa) 752 struct ifnet *ifp; 753 int type; 754 short ht; 755 caddr_t sn_addr; 756 int sn_len; 757 struct iso_addr *isoa; 758 { 759 struct mbuf *m, *m0; 760 caddr_t cp, naddrp; 761 int naddr = 0; 762 struct esis_fixed *pdu; 763 struct iso_ifaddr *ia; 764 int len; 765 struct sockaddr_iso siso; 766 767 if (type == ESIS_ESH) 768 esis_stat.es_eshsent++; 769 else if (type == ESIS_ISH) 770 esis_stat.es_ishsent++; 771 else { 772 printf("esis_shoutput: bad pdu type\n"); 773 return; 774 } 775 776 IFDEBUG(D_ESISOUTPUT) 777 int i; 778 printf("esis_shoutput: ifp x%x (%s%d), %s, ht %d, to: [%d] ", 779 ifp, ifp->if_name, ifp->if_unit, type == ESIS_ESH ? "esh" : "ish", 780 ht, sn_len); 781 for (i=0; i<sn_len; i++) 782 printf("%x%c", *(sn_addr+i), i < (sn_len-1) ? ':' : ' '); 783 printf("\n"); 784 ENDDEBUG 785 786 if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) { 787 esis_stat.es_nomem++; 788 return; 789 } 790 bzero(mtod(m, caddr_t), MHLEN); 791 792 pdu = mtod(m, struct esis_fixed *); 793 naddrp = cp = (caddr_t)(pdu + 1); 794 len = sizeof(struct esis_fixed); 795 796 /* 797 * Build fixed part of header 798 */ 799 pdu->esis_proto_id = ISO9542_ESIS; 800 pdu->esis_vers = ESIS_VERSION; 801 pdu->esis_type = type; 802 HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); 803 804 if (type == ESIS_ESH) { 805 cp++; 806 len++; 807 } 808 809 m->m_len = len; 810 if (isoa) { 811 /* 812 * Here we are responding to a clnp packet sent to an NSAP 813 * that is ours which was sent to the MAC addr all_es's. 814 * It is possible that we did not specifically advertise this 815 * NSAP, even though it is ours, so we will respond 816 * directly to the sender that we are here. If we do have 817 * multiple NSEL's we'll tack them on so he can compress them out. 818 */ 819 (void) esis_insert_addr(&cp, &len, isoa, m, 0); 820 naddr = 1; 821 } 822 for (ia = iso_ifaddr; ia; ia = ia->ia_next) { 823 int nsellen = (type == ESIS_ISH ? ia->ia_addr.siso_tlen : 0); 824 int n = ia->ia_addr.siso_nlen; 825 register struct iso_ifaddr *ia2; 826 827 if (type == ESIS_ISH && naddr > 0) 828 break; 829 for (ia2 = iso_ifaddr; ia2 != ia; ia2 = ia2->ia_next) 830 if (Bcmp(ia->ia_addr.siso_data, ia2->ia_addr.siso_data, n) == 0) 831 break; 832 if (ia2 != ia) 833 continue; /* Means we have previously copied this nsap */ 834 if (isoa && Bcmp(ia->ia_addr.siso_data, isoa->isoa_genaddr, n) == 0) { 835 isoa = 0; 836 continue; /* Ditto */ 837 } 838 IFDEBUG(D_ESISOUTPUT) 839 printf("esis_shoutput: adding NSAP %s\n", 840 clnp_iso_addrp(&ia->ia_addr.siso_addr)); 841 ENDDEBUG 842 if (!esis_insert_addr(&cp, &len, 843 &ia->ia_addr.siso_addr, m, nsellen)) { 844 EXTEND_PACKET(m, m0, cp); 845 (void) esis_insert_addr(&cp, &len, &ia->ia_addr.siso_addr, m, 846 nsellen); 847 } 848 naddr++; 849 } 850 851 if (type == ESIS_ESH) 852 *naddrp = naddr; 853 854 m0->m_pkthdr.len = len; 855 pdu->esis_hdr_len = len; 856 iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len); 857 858 bzero((caddr_t)&siso, sizeof(siso)); 859 siso.siso_family = AF_ISO; 860 siso.siso_data[0] = AFI_SNA; 861 siso.siso_nlen = sn_len + 1; 862 bcopy(sn_addr, siso.siso_data + 1, (unsigned)sn_len); 863 (ifp->if_output)(ifp, m0, &siso, 0); 864 } 865 866 /* 867 * FUNCTION: isis_input 868 * 869 * PURPOSE: Process an incoming isis packet 870 * 871 * RETURNS: nothing 872 * 873 * SIDE EFFECTS: 874 * 875 * NOTES: 876 */ 877 isis_input(m0, shp) 878 struct mbuf *m0; /* ptr to first mbuf of pkt */ 879 struct snpa_hdr *shp; /* subnetwork header */ 880 { 881 register int type; 882 struct rawcb *rp; 883 struct ifnet *ifp = shp->snh_ifp; 884 struct sockbuf *sb = 0; 885 char workbuf[16]; 886 struct mbuf *mm; 887 888 IFDEBUG(D_ISISINPUT) 889 int i; 890 891 printf("isis_input: pkt on ifp x%x (%s%d): from:", ifp, 892 ifp->if_name, ifp->if_unit); 893 for (i=0; i<6; i++) 894 printf("%x%c", shp->snh_shost[i]&0xff, (i<5) ? ':' : ' '); 895 printf(" to:"); 896 for (i=0; i<6; i++) 897 printf("%x%c", shp->snh_dhost[i]&0xff, (i<5) ? ':' : ' '); 898 printf("\n"); 899 ENDDEBUG 900 esis_dl.sdl_alen = ifp->if_addrlen; 901 esis_dl.sdl_index = ifp->if_index; 902 bcopy(shp->snh_shost, (caddr_t)esis_dl.sdl_data, esis_dl.sdl_alen); 903 for (rp = esis_pcb.rcb_next; rp != &esis_pcb; rp = rp->rcb_next) { 904 if (sb == 0) { 905 sb = &rp->rcb_socket->so_rcv; 906 continue; 907 } 908 if (mm = m_copy(m0, 0, M_COPYALL)) { /*can't block at interrupt level */ 909 if (sbappendaddr(&rp->rcb_socket->so_rcv, 910 &esis_dl, mm, (struct mbuf *)0) != 0) 911 sorwakeup(rp->rcb_socket); 912 else { 913 IFDEBUG(D_ISISINPUT) 914 printf("Error in sbappenaddr, mm = 0x%x\n", mm); 915 ENDDEBUG 916 m_freem(mm); 917 } 918 } 919 } 920 if (sb) { 921 if (sbappendaddr(&rp->rcb_socket->so_rcv, 922 &esis_dl, mm, (struct mbuf *)0) != 0) 923 sorwakeup(rp->rcb_socket); 924 else 925 m_freem(m0); 926 } 927 } 928 929 isis_output(sdl, m) 930 register struct sockaddr_dl *sdl; 931 struct mbuf *m; 932 { 933 register struct ifnet *ifp; 934 struct ifaddr *ifa, *ifa_ifwithnet(); 935 struct sockaddr_iso siso; 936 int error = 0; 937 unsigned sn_len; 938 939 ifa = ifa_ifwithnet(sdl); /* extract ifp from sockaddr_dl */ 940 if (ifa == 0) { 941 IFDEBUG(D_ISISOUTPUT) 942 printf("isis_output: interface not found\n"); 943 ENDDEBUG 944 error = EINVAL; 945 goto release; 946 } 947 ifp = ifa->ifa_ifp; 948 sn_len = ifp->if_addrlen; 949 IFDEBUG(D_ISISOUTPUT) 950 u_char *cp = (u_char *)LLADDR(sdl), *cplim = cp + sn_len; 951 printf("isis_output: ifp 0x%x (%s%d), to: ", 952 ifp, ifp->if_name, ifp->if_unit); 953 while (cp < cplim) { 954 printf("%x", *cp++); 955 printf("%c", (cp < cplim) ? ':' : ' '); 956 } 957 printf("\n"); 958 ENDDEBUG 959 bzero((caddr_t)&siso, sizeof(siso)); 960 siso.siso_family = AF_ISO; /* This convention may be useful for X.25 */ 961 siso.siso_data[0] = AFI_SNA; 962 siso.siso_nlen = sn_len + 1; 963 bcopy(LLADDR(sdl), siso.siso_data + 1, sn_len); 964 error = (ifp->if_output)(ifp, m, (struct sockaddr *)&siso, 0); 965 if (error) { 966 IFDEBUG(D_ISISOUTPUT) 967 printf("isis_output: error from ether_output is %d\n", error); 968 ENDDEBUG 969 } 970 return (error); 971 972 release: 973 if (m != NULL) 974 m_freem(m); 975 return(error); 976 } 977 978 979 /* 980 * FUNCTION: esis_ctlinput 981 * 982 * PURPOSE: Handle the PRC_IFDOWN transition 983 * 984 * RETURNS: nothing 985 * 986 * SIDE EFFECTS: 987 * 988 * NOTES: Calls snpac_flush for interface specified. 989 * The loop through iso_ifaddr is stupid because 990 * back in if_down, we knew the ifp... 991 */ 992 esis_ctlinput(req, siso) 993 int req; /* request: we handle only PRC_IFDOWN */ 994 struct sockaddr_iso *siso; /* address of ifp */ 995 { 996 register struct iso_ifaddr *ia; /* scan through interface addresses */ 997 998 if (req == PRC_IFDOWN) 999 for (ia = iso_ifaddr; ia; ia = ia->ia_next) { 1000 if (iso_addrmatch(IA_SIS(ia), siso)) 1001 snpac_flushifp(ia->ia_ifp); 1002 } 1003 } 1004 1005 #endif ISO 1006