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