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