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