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