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