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.17 (Berkeley) 05/02/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 * - has BROADCAST capability 726 * - has an ISO address 727 */ 728 /* Todo: a better way would be to construct the esh or ish 729 * once and copy it out for all devices, possibly calling 730 * a method in the iso_ifaddr structure to encapsulate and 731 * transmit it. This could work to advantage for non-broadcast media 732 */ 733 734 for (ifp = ifnet; ifp; ifp = ifp->if_next) { 735 if ((ifp->if_flags & IFF_UP) && 736 (ifp->if_flags & IFF_BROADCAST)) { 737 /* search for an ISO address family */ 738 struct ifaddr *ia; 739 740 for (ia = ifp->if_addrlist; ia; ia = ia->ifa_next) { 741 if (ia->ifa_addr->sa_family == AF_ISO) { 742 esis_shoutput(ifp, 743 iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH, 744 esis_holding_time, 745 (caddr_t)(iso_systype & SNPA_ES ? all_is_snpa : 746 all_es_snpa), 6, (struct iso_addr *)0); 747 break; 748 } 749 } 750 } 751 } 752 } 753 754 /* 755 * FUNCTION: esis_shoutput 756 * 757 * PURPOSE: Transmit an esh or ish pdu 758 * 759 * RETURNS: nothing 760 * 761 * SIDE EFFECTS: 762 * 763 * NOTES: 764 */ 765 esis_shoutput(ifp, type, ht, sn_addr, sn_len, isoa) 766 struct ifnet *ifp; 767 int type; 768 short ht; 769 caddr_t sn_addr; 770 int sn_len; 771 struct iso_addr *isoa; 772 { 773 struct mbuf *m, *m0; 774 caddr_t cp, naddrp; 775 int naddr = 0; 776 struct esis_fixed *pdu; 777 struct iso_ifaddr *ia; 778 int len; 779 struct sockaddr_iso siso; 780 781 if (type == ESIS_ESH) 782 esis_stat.es_eshsent++; 783 else if (type == ESIS_ISH) 784 esis_stat.es_ishsent++; 785 else { 786 printf("esis_shoutput: bad pdu type\n"); 787 return; 788 } 789 790 IFDEBUG(D_ESISOUTPUT) 791 int i; 792 printf("esis_shoutput: ifp x%x (%s%d), %s, ht %d, to: [%d] ", 793 ifp, ifp->if_name, ifp->if_unit, type == ESIS_ESH ? "esh" : "ish", 794 ht, sn_len); 795 for (i=0; i<sn_len; i++) 796 printf("%x%c", *(sn_addr+i), i < (sn_len-1) ? ':' : ' '); 797 printf("\n"); 798 ENDDEBUG 799 800 if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) { 801 esis_stat.es_nomem++; 802 return; 803 } 804 bzero(mtod(m, caddr_t), MHLEN); 805 806 pdu = mtod(m, struct esis_fixed *); 807 naddrp = cp = (caddr_t)(pdu + 1); 808 len = sizeof(struct esis_fixed); 809 810 /* 811 * Build fixed part of header 812 */ 813 pdu->esis_proto_id = ISO9542_ESIS; 814 pdu->esis_vers = ESIS_VERSION; 815 pdu->esis_type = type; 816 HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); 817 818 if (type == ESIS_ESH) { 819 cp++; 820 len++; 821 } 822 823 m->m_len = len; 824 if (isoa) { 825 /* 826 * Here we are responding to a clnp packet sent to an NSAP 827 * that is ours which was sent to the MAC addr all_es's. 828 * It is possible that we did not specifically advertise this 829 * NSAP, even though it is ours, so we will respond 830 * directly to the sender that we are here. If we do have 831 * multiple NSEL's we'll tack them on so he can compress them out. 832 */ 833 (void) esis_insert_addr(&cp, &len, isoa, m, 0); 834 naddr = 1; 835 } 836 for (ia = iso_ifaddr; ia; ia = ia->ia_next) { 837 int nsellen = (type == ESIS_ISH ? ia->ia_addr.siso_tlen : 0); 838 int n = ia->ia_addr.siso_nlen; 839 register struct iso_ifaddr *ia2; 840 841 if (type == ESIS_ISH && naddr > 0) 842 break; 843 for (ia2 = iso_ifaddr; ia2 != ia; ia2 = ia2->ia_next) 844 if (Bcmp(ia->ia_addr.siso_data, ia2->ia_addr.siso_data, n) == 0) 845 break; 846 if (ia2 != ia) 847 continue; /* Means we have previously copied this nsap */ 848 if (isoa && Bcmp(ia->ia_addr.siso_data, isoa->isoa_genaddr, n) == 0) { 849 isoa = 0; 850 continue; /* Ditto */ 851 } 852 IFDEBUG(D_ESISOUTPUT) 853 printf("esis_shoutput: adding NSAP %s\n", 854 clnp_iso_addrp(&ia->ia_addr.siso_addr)); 855 ENDDEBUG 856 if (!esis_insert_addr(&cp, &len, 857 &ia->ia_addr.siso_addr, m, nsellen)) { 858 EXTEND_PACKET(m, m0, cp); 859 (void) esis_insert_addr(&cp, &len, &ia->ia_addr.siso_addr, m, 860 nsellen); 861 } 862 naddr++; 863 } 864 865 if (type == ESIS_ESH) 866 *naddrp = naddr; 867 else { 868 /* add suggested es config timer option to ISH */ 869 if (M_TRAILINGSPACE(m) < 4) { 870 printf("esis_shoutput: extending packet\n"); 871 EXTEND_PACKET(m, m0, cp); 872 } 873 *cp++ = ESISOVAL_ESCT; 874 *cp++ = 2; 875 HTOC(*cp, *(cp+1), esis_esconfig_time); 876 len += 4; 877 m->m_len += 4; 878 IFDEBUG(D_ESISOUTPUT) 879 printf("m0 0x%x, m 0x%x, data 0x%x, len %d, cp 0x%x\n", 880 m0, m, m->m_data, m->m_len, cp); 881 ENDDEBUG 882 } 883 884 m0->m_pkthdr.len = len; 885 pdu->esis_hdr_len = len; 886 iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len); 887 888 bzero((caddr_t)&siso, sizeof(siso)); 889 siso.siso_family = AF_ISO; 890 siso.siso_data[0] = AFI_SNA; 891 siso.siso_nlen = sn_len + 1; 892 bcopy(sn_addr, siso.siso_data + 1, (unsigned)sn_len); 893 (ifp->if_output)(ifp, m0, &siso, 0); 894 } 895 896 /* 897 * FUNCTION: isis_input 898 * 899 * PURPOSE: Process an incoming isis packet 900 * 901 * RETURNS: nothing 902 * 903 * SIDE EFFECTS: 904 * 905 * NOTES: 906 */ 907 isis_input(m0, shp) 908 struct mbuf *m0; /* ptr to first mbuf of pkt */ 909 struct snpa_hdr *shp; /* subnetwork header */ 910 { 911 register int type; 912 register struct rawcb *rp, *first_rp = 0; 913 struct ifnet *ifp = shp->snh_ifp; 914 char workbuf[16]; 915 struct mbuf *mm; 916 917 IFDEBUG(D_ISISINPUT) 918 int i; 919 920 printf("isis_input: pkt on ifp x%x (%s%d): from:", ifp, 921 ifp->if_name, ifp->if_unit); 922 for (i=0; i<6; i++) 923 printf("%x%c", shp->snh_shost[i]&0xff, (i<5) ? ':' : ' '); 924 printf(" to:"); 925 for (i=0; i<6; i++) 926 printf("%x%c", shp->snh_dhost[i]&0xff, (i<5) ? ':' : ' '); 927 printf("\n"); 928 ENDDEBUG 929 esis_dl.sdl_alen = ifp->if_addrlen; 930 esis_dl.sdl_index = ifp->if_index; 931 bcopy(shp->snh_shost, (caddr_t)esis_dl.sdl_data, esis_dl.sdl_alen); 932 for (rp = esis_pcb.rcb_next; rp != &esis_pcb; rp = rp->rcb_next) { 933 if (first_rp == 0) { 934 first_rp = rp; 935 continue; 936 } 937 if (mm = m_copy(m0, 0, M_COPYALL)) { /*can't block at interrupt level */ 938 if (sbappendaddr(&rp->rcb_socket->so_rcv, 939 &esis_dl, mm, (struct mbuf *)0) != 0) 940 sorwakeup(rp->rcb_socket); 941 else { 942 IFDEBUG(D_ISISINPUT) 943 printf("Error in sbappenaddr, mm = 0x%x\n", mm); 944 ENDDEBUG 945 m_freem(mm); 946 } 947 } 948 } 949 if (first_rp && sbappendaddr(&first_rp->rcb_socket->so_rcv, 950 &esis_dl, m0, (struct mbuf *)0) != 0) { 951 sorwakeup(first_rp->rcb_socket); 952 return; 953 } 954 m_freem(m0); 955 } 956 957 isis_output(sdl, m) 958 register struct sockaddr_dl *sdl; 959 struct mbuf *m; 960 { 961 register struct ifnet *ifp; 962 struct ifaddr *ifa, *ifa_ifwithnet(); 963 struct sockaddr_iso siso; 964 int error = 0; 965 unsigned sn_len; 966 967 ifa = ifa_ifwithnet(sdl); /* extract ifp from sockaddr_dl */ 968 if (ifa == 0) { 969 IFDEBUG(D_ISISOUTPUT) 970 printf("isis_output: interface not found\n"); 971 ENDDEBUG 972 error = EINVAL; 973 goto release; 974 } 975 ifp = ifa->ifa_ifp; 976 sn_len = sdl->sdl_alen; 977 IFDEBUG(D_ISISOUTPUT) 978 u_char *cp = (u_char *)LLADDR(sdl), *cplim = cp + sn_len; 979 printf("isis_output: ifp 0x%x (%s%d), to: ", 980 ifp, ifp->if_name, ifp->if_unit); 981 while (cp < cplim) { 982 printf("%x", *cp++); 983 printf("%c", (cp < cplim) ? ':' : ' '); 984 } 985 printf("\n"); 986 ENDDEBUG 987 bzero((caddr_t)&siso, sizeof(siso)); 988 siso.siso_family = AF_ISO; /* This convention may be useful for X.25 */ 989 siso.siso_data[0] = AFI_SNA; 990 siso.siso_nlen = sn_len + 1; 991 bcopy(LLADDR(sdl), siso.siso_data + 1, sn_len); 992 error = (ifp->if_output)(ifp, m, (struct sockaddr *)&siso, 0); 993 if (error) { 994 IFDEBUG(D_ISISOUTPUT) 995 printf("isis_output: error from ether_output is %d\n", error); 996 ENDDEBUG 997 } 998 return (error); 999 1000 release: 1001 if (m != NULL) 1002 m_freem(m); 1003 return(error); 1004 } 1005 1006 1007 /* 1008 * FUNCTION: esis_ctlinput 1009 * 1010 * PURPOSE: Handle the PRC_IFDOWN transition 1011 * 1012 * RETURNS: nothing 1013 * 1014 * SIDE EFFECTS: 1015 * 1016 * NOTES: Calls snpac_flush for interface specified. 1017 * The loop through iso_ifaddr is stupid because 1018 * back in if_down, we knew the ifp... 1019 */ 1020 esis_ctlinput(req, siso) 1021 int req; /* request: we handle only PRC_IFDOWN */ 1022 struct sockaddr_iso *siso; /* address of ifp */ 1023 { 1024 register struct iso_ifaddr *ia; /* scan through interface addresses */ 1025 1026 if (req == PRC_IFDOWN) 1027 for (ia = iso_ifaddr; ia; ia = ia->ia_next) { 1028 if (iso_addrmatch(IA_SIS(ia), siso)) 1029 snpac_flushifp(ia->ia_ifp); 1030 } 1031 } 1032 1033 #endif ISO 1034