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 /* $Header: iso_snpac.c,v 1.8 88/09/19 13:51:36 hagens Exp $ */ 28 /* $Source: /usr/argo/sys/netiso/RCS/iso_snpac.c,v $ */ 29 /* @(#)iso_snpac.c 7.7 (Berkeley) 06/09/90 */ 30 31 #ifndef lint 32 static char *rcsid = "$Header: iso_snpac.c,v 1.8 88/09/19 13:51:36 hagens Exp $"; 33 #endif lint 34 35 #ifdef ISO 36 37 #include "types.h" 38 #include "param.h" 39 #include "systm.h" 40 #include "user.h" 41 #include "mbuf.h" 42 #include "domain.h" 43 #include "protosw.h" 44 #include "socket.h" 45 #include "socketvar.h" 46 #include "errno.h" 47 #include "ioctl.h" 48 #include "kernel.h" 49 50 #include "../net/if.h" 51 #include "../net/if_dl.h" 52 #include "../net/route.h" 53 54 #include "iso.h" 55 #include "iso_var.h" 56 #include "iso_snpac.h" 57 #include "clnp.h" 58 #include "clnp_stat.h" 59 #include "esis.h" 60 #include "argo_debug.h" 61 62 #define SNPAC_BSIZ 20 /* bucket size */ 63 #define SNPAC_NB 13 /* number of buckets */ 64 #define SNPAC_SIZE (SNPAC_BSIZ * SNPAC_NB) 65 struct snpa_cache iso_snpac[SNPAC_SIZE]; 66 u_int iso_snpac_size = SNPAC_SIZE;/* for iso_map command */ 67 int iso_systype = SNPA_ES; /* default to be an ES */ 68 69 struct sockaddr_iso blank_siso = {sizeof(blank_siso), AF_ISO}; 70 extern u_long iso_hashchar(); 71 static struct sockaddr_iso 72 dst = {sizeof(dst), AF_ISO}, 73 gte = {sizeof(dst), AF_ISO}, 74 src = {sizeof(dst), AF_ISO}, 75 msk = {sizeof(dst), AF_ISO}, 76 zmk = {1}; 77 #define zsi blank_siso 78 #define zero_isoa zsi.siso_addr 79 #define zap_isoaddr(a, b) (bzero((caddr_t)&a.siso_addr, sizeof(*r)), \ 80 ((r = b) && bcopy((caddr_t)r, (caddr_t)&a.siso_addr, 1 + (r)->isoa_len))) 81 #define S(x) ((struct sockaddr *)&(x)) 82 83 static struct sockaddr_dl blank_dl = {sizeof(blank_dl), AF_LINK}; 84 static struct sockaddr_dl gte_dl; 85 #define zap_linkaddr(a, b, c, i) \ 86 (*a = blank_dl, bcopy(b, a->sdl_data, a->sdl_alen = c), a->sdl_index = i) 87 88 /* 89 * We only keep track of a single IS at a time. 90 */ 91 struct rtentry *known_is; 92 93 /* 94 * Addresses taken from NBS agreements, December 1987. 95 * 96 * These addresses assume on-the-wire transmission of least significant 97 * bit first. This is the method used by 802.3. When these 98 * addresses are passed to the token ring driver, (802.5), they 99 * must be bit-swaped because 802.5 transmission order is MSb first. 100 * 101 * Furthermore, according to IBM Austin, these addresses are not 102 * true token ring multicast addresses. More work is necessary 103 * to get multicast to work right on token ring. 104 * 105 * Currently, the token ring driver does not handle multicast, so 106 * these addresses are converted into the broadcast address in 107 * lan_output() That means that if these multicast addresses change 108 * the token ring driver must be altered. 109 */ 110 struct snpa_cache all_es = { 111 { { 0x0 }, /* sc_nsap */ 112 6, /* sc_len */ 113 { 0x09, 0x00, 0x2b, 0x00, 0x00, 0x04 }, /* sc_snpa */ 114 SNPA_VALID, /* sc_flags */ 115 0 } /* sc_ht */ 116 }; 117 struct snpa_cache all_is = { 118 { { 0x0 }, /* sc_nsap */ 119 6, /* sc_len */ 120 { 0x09, 0x00, 0x2b, 0x00, 0x00, 0x05 }, /* sc_snpa */ 121 SNPA_VALID, /* sc_flags */ 122 0 } /* sc_ht */ 123 }; 124 char all_es_snpa[] = { 0x09, 0x00, 0x2b, 0x00, 0x00, 0x04 }; /* sc_snpa */ 125 char all_is_snpa[] = { 0x09, 0x00, 0x2b, 0x00, 0x00, 0x05 }; /* sc_snpa */ 126 127 union sockunion { 128 struct sockaddr_iso siso; 129 struct sockaddr_dl sdl; 130 struct sockaddr sa; 131 }; 132 133 /* 134 * FUNCTION: llc_rtrequest 135 * 136 * PURPOSE: Manage routing table entries specific to LLC for ISO. 137 * 138 * NOTES: This does a lot of obscure magic; 139 */ 140 llc_rtrequest(req, rt, sa) 141 int req; 142 register struct rtentry *rt; 143 struct sockaddr *sa; 144 { 145 register union sockunion *gate = (union sockunion *)rt->rt_gateway; 146 register struct llinfo_llc *lc = (struct llinfo_llc *)rt->rt_llinfo, *lc2; 147 struct rtentry *rt2; 148 struct ifnet *ifp = rt->rt_ifp; 149 int addrlen = ifp->if_addrlen; 150 151 if (lc == 0) 152 panic("llc_rtrequest 1"); 153 switch (req) { 154 case RTM_RESOLVE: 155 if (gate->sdl.sdl_family == AF_LINK) { 156 /* We have just cloned a route to a host presumed to be on 157 our local net */ 158 gate->sdl.sdl_alen = 0; 159 } 160 /* Fall Through */ 161 case RTM_ADD: 162 lc->lc_rt = rt; 163 if (rt->rt_flags & RTF_CLONING) { 164 /* 165 * Case 1: This route may come from a route to iface with mask 166 * or from a default IS. 167 */ 168 rt->rt_gateway = ifp->if_addrlist->ifa_addr; 169 } else if ((rt->rt_flags & RTF_GATEWAY == 0) && 170 gate->sdl.sdl_family == AF_LINK) { 171 /* 172 * Case 2: This route may come from ESIS or a manual route 173 * add with a LL address. 174 */ 175 insque(lc, &llinfo_llc); 176 if (gate->sdl.sdl_alen == sizeof(struct esis_req) + addrlen) { 177 gate->sdl.sdl_alen -= sizeof(struct esis_req); 178 bcopy(addrlen + LLADDR(&gate->sdl), 179 (caddr_t)&lc->lc_er, sizeof(lc->lc_er)); 180 } else if (gate->sdl.sdl_alen == addrlen) 181 lc->lc_flags = (SNPA_ES | SNPA_VALID | SNPA_PERM); 182 } else { 183 /* 184 * Case 3: Told to add route via a gateway; 185 * try to provoke LL route to exist for gateway by cloning. 186 */ 187 if (gate->siso.siso_family == AF_ISO && 188 (rt->rt_flags & RTF_GATEWAY) && 189 (rt2 = rtalloc1(&gate->sa, 1)) && 190 (lc2 = (struct llinfo_llc *)rt2->rt_llinfo)) { 191 lc->lc_rtgate = rt2; 192 rt2->rt_use++; 193 if (lc2->lc_rtgate == 0) { 194 lc->lc_prev = lc->lc_next = lc; 195 lc2->lc_rtgate = rt; 196 rt->rt_use++; 197 } else { 198 if (lc2->lc_rtgate->rt_llinfo == 0) 199 panic("llc_rtrequest 2"); 200 insque(lc, lc2->lc_rtgate->rt_llinfo); 201 } 202 } 203 } 204 break; 205 case RTM_DELETE: 206 if (rt->rt_flags & RTF_GATEWAY) { 207 if (rt2 = lc->lc_rtgate) { 208 if ((lc2 = (struct llinfo_llc *)rt2->rt_llinfo) && 209 (lc2->lc_rtgate == rt)) { 210 rt->rt_use--; 211 lc2->lc_rtgate = (lc->lc_next != lc->lc_prev) ? 212 lc->lc_next->lc_rt : 0; 213 } 214 RTFREE(rt2); 215 } 216 } else { 217 if ((rt2 = lc->lc_rtgate) && 218 (lc2 == (struct llinfo_llc *)rt2->rt_llinfo)) { 219 struct llinfo_llc *head = lc2; 220 do { 221 rt->rt_use--; 222 lc2->lc_rtgate = 0; 223 lc2 = lc2->lc_next; 224 } while (lc2 != head); 225 } 226 } 227 if (lc->lc_next) 228 remque(lc); 229 break; 230 } 231 } 232 /* 233 * FUNCTION: iso_snparesolve 234 * 235 * PURPOSE: Resolve an iso address into snpa address 236 * 237 * RETURNS: 0 if addr is resolved 238 * errno if addr is unknown 239 * 240 * SIDE EFFECTS: 241 * 242 * NOTES: Now that we have folded the snpa cache into the routing 243 * table, we know there is no snpa address known for this 244 * destination. If we know of a default IS, then the address 245 * of the IS is returned. If no IS is known, then return the 246 * multi-cast address for "all ES" for this interface. 247 * 248 * NB: the last case described above constitutes the 249 * query configuration function 9542, sec 6.5 250 * A mechanism is needed to prevent this function from 251 * being invoked if the system is an IS. 252 */ 253 iso_snparesolve(ifp, dest, snpa, snpa_len) 254 struct ifnet *ifp; /* outgoing interface */ 255 struct sockaddr_iso *dest; /* destination */ 256 caddr_t snpa; /* RESULT: snpa to be used */ 257 int *snpa_len; /* RESULT: length of snpa */ 258 { 259 struct llinfo_llc *sc; /* ptr to snpa table entry */ 260 caddr_t found_snpa; 261 int addrlen; 262 263 /* 264 * This hack allows us to send esis packets that have the destination snpa 265 * addresss embedded in the destination nsap address 266 */ 267 if (dest->siso_data[0] == AFI_SNA) { 268 /* 269 * This is a subnetwork address. Return it immediately 270 */ 271 IFDEBUG(D_SNPA) 272 printf("iso_snparesolve: return SN address\n"); 273 ENDDEBUG 274 addrlen = dest->siso_nlen - 1; /* subtract size of AFI */ 275 found_snpa = (caddr_t) dest->siso_data + 1; 276 /* 277 * If we are an IS, we can't do much with the packet; 278 * Check if we know about an IS. 279 */ 280 } else if (iso_systype != SNPA_IS && known_is != 0 && 281 (sc = (struct llinfo_llc *)known_is->rt_llinfo) && 282 (sc->lc_flags & SNPA_VALID)) { 283 register struct sockaddr_dl *sdl = 284 (struct sockaddr_dl *)(known_is->rt_gateway); 285 found_snpa = LLADDR(sdl); 286 addrlen = sdl->sdl_alen; 287 } else if (ifp->if_flags & IFF_BROADCAST) { 288 /* 289 * no IS, no match. Return "all es" multicast address for this 290 * interface, as per Query Configuration Function (9542 sec 6.5) 291 * 292 * Note: there is a potential problem here. If the destination 293 * is on the subnet and it does not respond with a ESH, but 294 * does send back a TP CC, a connection could be established 295 * where we always transmit the CLNP packet to "all es" 296 */ 297 addrlen = ifp->if_addrlen; 298 found_snpa = (caddr_t)all_es_snpa; 299 } else 300 return (ENETUNREACH); 301 bcopy(found_snpa, snpa, *snpa_len = addrlen); 302 return (0); 303 } 304 305 306 /* 307 * FUNCTION: snpac_free 308 * 309 * PURPOSE: free an entry in the iso address map table 310 * 311 * RETURNS: nothing 312 * 313 * SIDE EFFECTS: 314 * 315 * NOTES: If there is a route entry associated with cache 316 * entry, then delete that as well 317 */ 318 snpac_free(lc) 319 register struct llinfo_llc *lc; /* entry to free */ 320 { 321 register struct rtentry *rt = lc->lc_rt; 322 register struct iso_addr *r; 323 324 if (known_is == rt) 325 known_is = 0; 326 if (rt && (rt->rt_flags & RTF_UP) && 327 (rt->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED))) { 328 RTFREE(rt); 329 rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt), 330 rt->rt_flags, (struct rtentry **)0); 331 RTFREE(rt); 332 } 333 } 334 335 /* 336 * FUNCTION: snpac_add 337 * 338 * PURPOSE: Add an entry to the snpa cache 339 * 340 * RETURNS: 341 * 342 * SIDE EFFECTS: 343 * 344 * NOTES: If entry already exists, then update holding time. 345 */ 346 snpac_add(ifp, nsap, snpa, type, ht) 347 struct ifnet *ifp; /* interface info is related to */ 348 struct iso_addr *nsap; /* nsap to add */ 349 caddr_t snpa; /* translation */ 350 char type; /* SNPA_IS or SNPA_ES */ 351 u_short ht; /* holding time (in seconds) */ 352 { 353 register struct llinfo_llc *lc; 354 struct rtentry *rt; 355 register struct iso_addr *r; /* for zap_isoaddr macro */ 356 int snpalen = min(ifp->if_addrlen, MAX_SNPALEN); 357 int new_entry = 0, index = ifp->if_index; 358 359 zap_isoaddr(dst, nsap); 360 rt = rtalloc1(S(dst), 0); 361 if (rt == 0) { 362 new_entry = 1; 363 zap_linkaddr((>e_dl), snpa, snpalen, index); 364 if (rtrequest(RTM_ADD, S(dst), S(gte_dl), (struct sockaddr *)0, 365 RTF_UP | RTF_HOST, &rt) || rt == 0) 366 return (0); 367 } else { 368 register struct sockaddr_dl *sdl = (struct sockaddr_dl *)rt->rt_gateway; 369 if (sdl->sdl_family != AF_LINK || sdl->sdl_alen == 0) { 370 int old_sdl_len = sdl->sdl_len; 371 if (old_sdl_len < sizeof(*sdl)) 372 return (0); 373 zap_linkaddr(sdl, snpa, snpalen, index); 374 sdl->sdl_len = old_sdl_len; 375 new_entry = 1; 376 } 377 } 378 lc = (struct llinfo_llc *)rt->rt_llinfo; 379 lc->lc_ht = ht; 380 lc->lc_flags = SNPA_VALID | type; 381 if (type & SNPA_IS) 382 snpac_logdefis(rt); 383 } 384 385 /* 386 * FUNCTION: snpac_ioctl 387 * 388 * PURPOSE: Set/Get the system type and esis parameters 389 * 390 * RETURNS: 0 on success, or unix error code 391 * 392 * SIDE EFFECTS: 393 * 394 * NOTES: 395 */ 396 snpac_ioctl (cmd, data) 397 int cmd; /* ioctl to process */ 398 caddr_t data; /* data for the cmd */ 399 { 400 register struct systype_req *rq = (struct systype_req *)data; 401 extern short esis_holding_time, esis_config_time; 402 403 IFDEBUG (D_IOCTL) 404 if (cmd == SIOCSSTYPE) 405 printf("snpac_ioctl: cmd set, type x%x, ht %d, ct %d\n", 406 rq->sr_type, rq->sr_holdt, rq->sr_configt); 407 else 408 printf("snpac_ioctl: cmd get\n"); 409 ENDDEBUG 410 411 if (cmd == SIOCSSTYPE) { 412 if (suser(u.u_cred, &u.u_acflag)) 413 return(EACCES); 414 if ((rq->sr_type & (SNPA_ES|SNPA_IS)) == (SNPA_ES|SNPA_IS)) 415 return(EINVAL); 416 if (rq->sr_type & SNPA_ES) { 417 iso_systype = SNPA_ES; 418 } else if (rq->sr_type & SNPA_IS) { 419 iso_systype = SNPA_IS; 420 } else { 421 return(EINVAL); 422 } 423 esis_holding_time = rq->sr_holdt; 424 esis_config_time = rq->sr_configt; 425 } else if (cmd == SIOCGSTYPE) { 426 rq->sr_type = iso_systype; 427 rq->sr_holdt = esis_holding_time; 428 rq->sr_configt = esis_config_time; 429 } else { 430 return (EINVAL); 431 } 432 return (0); 433 } 434 435 /* 436 * FUNCTION: snpac_logdefis 437 * 438 * PURPOSE: Mark the IS passed as the default IS 439 * 440 * RETURNS: nothing 441 * 442 * SIDE EFFECTS: 443 * 444 * NOTES: 445 */ 446 snpac_logdefis(sc) 447 register struct rtentry *sc; 448 { 449 register struct iso_addr *r; 450 register struct sockaddr_dl *sdl = (struct sockaddr_dl *)sc->rt_gateway; 451 register struct rtentry *rt = rtalloc1((struct sockaddr *)&zsi, 0); 452 453 zap_linkaddr((>e_dl), LLADDR(sdl), sdl->sdl_alen, sdl->sdl_index); 454 if (known_is == 0) 455 known_is = sc; 456 if (known_is != sc) { 457 rtfree(known_is); 458 known_is = sc; 459 } 460 if (rt == 0) { 461 rtrequest(RTM_ADD, S(zsi), S(gte_dl), S(zmk), 462 RTF_DYNAMIC|RTF_GATEWAY|RTF_CLONING, 0); 463 return; 464 } 465 if (rt->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED)) { 466 *((struct sockaddr_dl *)rt->rt_gateway) = gte_dl; 467 } 468 } 469 470 /* 471 * FUNCTION: snpac_age 472 * 473 * PURPOSE: Time out snpac entries 474 * 475 * RETURNS: 476 * 477 * SIDE EFFECTS: 478 * 479 * NOTES: When encountering an entry for the first time, snpac_age 480 * may delete up to SNPAC_AGE too many seconds. Ie. 481 * if the entry is added a moment before snpac_age is 482 * called, the entry will immediately have SNPAC_AGE 483 * seconds taken off the holding time, even though 484 * it has only been held a brief moment. 485 * 486 * The proper way to do this is set an expiry timeval 487 * equal to current time + holding time. Then snpac_age 488 * would time out entries where expiry date is older 489 * than the current time. 490 */ 491 snpac_age() 492 { 493 register struct llinfo_llc *lc; 494 495 timeout(snpac_age, (caddr_t)0, SNPAC_AGE * hz); 496 497 for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = lc->lc_next) { 498 if (((lc->lc_flags & SNPA_PERM) == 0) && (lc->lc_flags & SNPA_VALID)) { 499 lc->lc_ht -= SNPAC_AGE; 500 if (lc->lc_ht > 0) 501 continue; 502 else 503 snpac_free(lc); 504 } 505 } 506 } 507 508 /* 509 * FUNCTION: snpac_ownmulti 510 * 511 * PURPOSE: Determine if the snpa address is a multicast address 512 * of the same type as the system. 513 * 514 * RETURNS: true or false 515 * 516 * SIDE EFFECTS: 517 * 518 * NOTES: Used by interface drivers when not in eavesdrop mode 519 * as interm kludge until 520 * real multicast addresses can be configured 521 */ 522 snpac_ownmulti(snpa, len) 523 caddr_t snpa; 524 u_int len; 525 { 526 return (((iso_systype & SNPA_ES) && 527 (!bcmp(snpa, (caddr_t)all_es_snpa, len))) || 528 ((iso_systype & SNPA_IS) && 529 (!bcmp(snpa, (caddr_t)all_is_snpa, len)))); 530 } 531 532 /* 533 * FUNCTION: snpac_flushifp 534 * 535 * PURPOSE: Flush entries associated with specific ifp 536 * 537 * RETURNS: nothing 538 * 539 * SIDE EFFECTS: 540 * 541 * NOTES: 542 */ 543 snpac_flushifp(ifp) 544 struct ifnet *ifp; 545 { 546 register struct llinfo_llc *lc; 547 548 for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = lc->lc_next) { 549 if (lc->lc_rt->rt_ifp == ifp && (lc->lc_flags & SNPA_VALID)) 550 snpac_free(lc); 551 } 552 } 553 554 /* 555 * FUNCTION: snpac_rtrequest 556 * 557 * PURPOSE: Make a routing request 558 * 559 * RETURNS: nothing 560 * 561 * SIDE EFFECTS: 562 * 563 * NOTES: In the future, this should make a request of a user 564 * level routing daemon. 565 */ 566 snpac_rtrequest(req, host, gateway, netmask, flags, ret_nrt) 567 int req; 568 struct iso_addr *host; 569 struct iso_addr *gateway; 570 struct iso_addr *netmask; 571 short flags; 572 struct rtentry **ret_nrt; 573 { 574 register struct iso_addr *r; 575 576 IFDEBUG(D_SNPA) 577 printf("snpac_rtrequest: "); 578 if (req == RTM_ADD) 579 printf("add"); 580 else if (req == RTM_DELETE) 581 printf("delete"); 582 else 583 printf("unknown command"); 584 printf(" dst: %s\n", clnp_iso_addrp(host)); 585 printf("\tgateway: %s\n", clnp_iso_addrp(gateway)); 586 ENDDEBUG 587 588 589 zap_isoaddr(dst, host); 590 zap_isoaddr(gte, gateway); 591 zap_isoaddr(msk, netmask); 592 593 rtrequest(req, S(dst), S(gte), (netmask ? S(msk) : (struct sockaddr *)0), 594 flags, ret_nrt); 595 } 596 597 /* 598 * FUNCTION: snpac_addrt 599 * 600 * PURPOSE: Associate a routing entry with an snpac entry 601 * 602 * RETURNS: nothing 603 * 604 * SIDE EFFECTS: 605 * 606 * NOTES: If a cache entry exists for gateway, then 607 * make a routing entry (host, gateway) and associate 608 * with gateway. 609 * 610 * If a route already exists and is different, first delete 611 * it. 612 * 613 * This could be made more efficient by checking 614 * the existing route before adding a new one. 615 */ 616 snpac_addrt(ifp, host, gateway, netmask) 617 struct ifnet *ifp; 618 struct iso_addr *host, *gateway, *netmask; 619 { 620 register struct iso_addr *r; 621 622 zap_isoaddr(dst, host); 623 zap_isoaddr(gte, gateway); 624 zap_isoaddr(msk, netmask); 625 if (netmask) { 626 rtredirect(S(dst), S(gte), S(msk), RTF_DONE, S(gte), 0); 627 } else 628 rtredirect(S(dst), S(gte), (struct sockaddr *)0, 629 RTF_DONE | RTF_HOST, S(gte), 0); 630 } 631 #endif ISO 632