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