1 /* 2 * Copyright (c) 1980, 1986, 1991 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)route.c 7.31 (Berkeley) 08/14/92 8 */ 9 #include "param.h" 10 #include "systm.h" 11 #include "proc.h" 12 #include "mbuf.h" 13 #include "socket.h" 14 #include "socketvar.h" 15 #include "domain.h" 16 #include "protosw.h" 17 #include "ioctl.h" 18 19 #include "if.h" 20 #include "af.h" 21 #include "route.h" 22 #include "raw_cb.h" 23 24 #include "../netinet/in.h" 25 #include "../netinet/in_var.h" 26 27 #ifdef NS 28 #include "../netns/ns.h" 29 #endif 30 31 #define SA(p) ((struct sockaddr *)(p)) 32 33 int rttrash; /* routes not in table but not freed */ 34 struct sockaddr wildcard; /* zero valued cookie for wildcard searches */ 35 36 rtable_init(table) 37 void **table; 38 { 39 struct domain *dom; 40 for (dom = domains; dom; dom = dom->dom_next) 41 if (dom->dom_rtattach) 42 dom->dom_rtattach(&table[dom->dom_family], 43 dom->dom_rtoffset); 44 } 45 46 route_init() 47 { 48 rn_init(); /* initialize all zeroes, all ones, mask table */ 49 rtable_init((void **)rt_tables); 50 } 51 52 /* 53 * Packet routing routines. 54 */ 55 rtalloc(ro) 56 register struct route *ro; 57 { 58 if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP)) 59 return; /* XXX */ 60 ro->ro_rt = rtalloc1(&ro->ro_dst, 1); 61 } 62 63 struct rtentry * 64 rtalloc1(dst, report) 65 register struct sockaddr *dst; 66 int report; 67 { 68 register struct radix_node_head *rnh = rt_tables[dst->sa_family]; 69 register struct rtentry *rt; 70 register struct radix_node *rn; 71 struct rtentry *newrt = 0; 72 struct rt_addrinfo info; 73 int s = splnet(), err = 0, msgtype = RTM_MISS; 74 75 if (rnh && rnh->rnh_treetop && 76 (rn = rnh->rnh_match((caddr_t)dst, rnh->rnh_treetop)) && 77 ((rn->rn_flags & RNF_ROOT) == 0)) { 78 newrt = rt = (struct rtentry *)rn; 79 if (report && (rt->rt_flags & RTF_CLONING)) { 80 err = rtrequest(RTM_RESOLVE, dst, SA(0), 81 SA(0), 0, &newrt); 82 if (err) { 83 newrt = rt; 84 rt->rt_refcnt++; 85 goto miss; 86 } 87 if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) { 88 msgtype = RTM_RESOLVE; 89 goto miss; 90 } 91 } else 92 rt->rt_refcnt++; 93 } else { 94 rtstat.rts_unreach++; 95 miss: if (report) { 96 bzero((caddr_t)&info, sizeof(info)); 97 info.rti_info[RTAX_DST] = dst; 98 rt_missmsg(msgtype, &info, 0, err); 99 } 100 } 101 splx(s); 102 return (newrt); 103 } 104 105 rtfree(rt) 106 register struct rtentry *rt; 107 { 108 register struct ifaddr *ifa; 109 110 if (rt == 0) 111 panic("rtfree"); 112 rt->rt_refcnt--; 113 if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) { 114 if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT)) 115 panic ("rtfree 2"); 116 rttrash--; 117 if (rt->rt_refcnt < 0) { 118 printf("rtfree: %x not freed (neg refs)\n", rt); 119 return; 120 } 121 ifa = rt->rt_ifa; 122 IFAFREE(ifa); 123 Free(rt_key(rt)); 124 Free(rt); 125 } 126 } 127 128 int ifafree_verbose = 1; 129 /* 130 * We are still debugging potential overfreeing of ifaddr's 131 */ 132 void 133 ifafree(ifa) 134 register struct ifaddr *ifa; 135 { 136 if (ifa == 0) 137 panic("ifafree"); 138 if (ifa->ifa_refcnt < 0) 139 printf("ifafree: %x ref %d\n", ifa, ifa->ifa_refcnt); 140 if (ifa->ifa_refcnt == 0 && ifafree_verbose) 141 printf("ifafree: %x not freed.\n", ifa); 142 ifa->ifa_refcnt--; 143 } 144 145 /* 146 * Force a routing table entry to the specified 147 * destination to go through the given gateway. 148 * Normally called as a result of a routing redirect 149 * message from the network layer. 150 * 151 * N.B.: must be called at splnet 152 * 153 */ 154 rtredirect(dst, gateway, netmask, flags, src, rtp) 155 struct sockaddr *dst, *gateway, *netmask, *src; 156 int flags; 157 struct rtentry **rtp; 158 { 159 register struct rtentry *rt; 160 int error = 0; 161 short *stat = 0; 162 struct rt_addrinfo info; 163 164 /* verify the gateway is directly reachable */ 165 if (ifa_ifwithnet(gateway) == 0) { 166 error = ENETUNREACH; 167 goto out; 168 } 169 rt = rtalloc1(dst, 0); 170 /* 171 * If the redirect isn't from our current router for this dst, 172 * it's either old or wrong. If it redirects us to ourselves, 173 * we have a routing loop, perhaps as a result of an interface 174 * going down recently. 175 */ 176 #define equal(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0) 177 if (!(flags & RTF_DONE) && rt && !equal(src, rt->rt_gateway)) 178 error = EINVAL; 179 else if (ifa_ifwithaddr(gateway)) 180 error = EHOSTUNREACH; 181 if (error) 182 goto done; 183 /* 184 * Create a new entry if we just got back a wildcard entry 185 * or the the lookup failed. This is necessary for hosts 186 * which use routing redirects generated by smart gateways 187 * to dynamically build the routing tables. 188 */ 189 if ((rt == 0) || (rt_mask(rt) && rt_mask(rt)->sa_len < 2)) 190 goto create; 191 /* 192 * Don't listen to the redirect if it's 193 * for a route to an interface. 194 */ 195 if (rt->rt_flags & RTF_GATEWAY) { 196 if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) { 197 /* 198 * Changing from route to net => route to host. 199 * Create new route, rather than smashing route to net. 200 */ 201 create: 202 flags |= RTF_GATEWAY | RTF_DYNAMIC; 203 error = rtrequest((int)RTM_ADD, dst, gateway, 204 SA(0), flags, 205 (struct rtentry **)0); 206 stat = &rtstat.rts_dynamic; 207 } else { 208 /* 209 * Smash the current notion of the gateway to 210 * this destination. Should check about netmask!!! 211 */ 212 rt->rt_flags |= RTF_MODIFIED; 213 flags |= RTF_MODIFIED; 214 stat = &rtstat.rts_newgateway; 215 rt_setgate(rt, rt_key(rt), gateway); 216 } 217 } else 218 error = EHOSTUNREACH; 219 done: 220 if (rt) { 221 if (rtp && !error) 222 *rtp = rt; 223 else 224 rtfree(rt); 225 } 226 out: 227 if (error) 228 rtstat.rts_badredirect++; 229 else if (stat != NULL) 230 (*stat)++; 231 bzero((caddr_t)&info, sizeof(info)); 232 info.rti_info[RTAX_DST] = dst; 233 info.rti_info[RTAX_GATEWAY] = gateway; 234 info.rti_info[RTAX_NETMASK] = netmask; 235 info.rti_info[RTAX_AUTHOR] = src; 236 rt_missmsg(RTM_REDIRECT, &info, flags, error); 237 } 238 239 /* 240 * Routing table ioctl interface. 241 */ 242 rtioctl(req, data, p) 243 int req; 244 caddr_t data; 245 struct proc *p; 246 { 247 #ifndef COMPAT_43 248 return (EOPNOTSUPP); 249 #else 250 register struct ortentry *entry = (struct ortentry *)data; 251 int error; 252 struct sockaddr *netmask = 0; 253 254 if (req == SIOCADDRT) 255 req = RTM_ADD; 256 else if (req == SIOCDELRT) 257 req = RTM_DELETE; 258 else 259 return (EINVAL); 260 261 if (error = suser(p->p_ucred, &p->p_acflag)) 262 return (error); 263 #if BYTE_ORDER != BIG_ENDIAN 264 if (entry->rt_dst.sa_family == 0 && entry->rt_dst.sa_len < 16) { 265 entry->rt_dst.sa_family = entry->rt_dst.sa_len; 266 entry->rt_dst.sa_len = 16; 267 } 268 if (entry->rt_gateway.sa_family == 0 && entry->rt_gateway.sa_len < 16) { 269 entry->rt_gateway.sa_family = entry->rt_gateway.sa_len; 270 entry->rt_gateway.sa_len = 16; 271 } 272 #else 273 if (entry->rt_dst.sa_len == 0) 274 entry->rt_dst.sa_len = 16; 275 if (entry->rt_gateway.sa_len == 0) 276 entry->rt_gateway.sa_len = 16; 277 #endif 278 if ((entry->rt_flags & RTF_HOST) == 0) 279 switch (entry->rt_dst.sa_family) { 280 #ifdef INET 281 case AF_INET: 282 { 283 extern struct sockaddr_in icmpmask; 284 struct sockaddr_in *dst_in = 285 (struct sockaddr_in *)&entry->rt_dst; 286 287 in_sockmaskof(dst_in->sin_addr, &icmpmask); 288 netmask = (struct sockaddr *)&icmpmask; 289 } 290 break; 291 #endif 292 #ifdef NS 293 case AF_NS: 294 { 295 extern struct sockaddr_ns ns_netmask; 296 netmask = (struct sockaddr *)&ns_netmask; 297 } 298 #endif 299 } 300 error = rtrequest(req, &(entry->rt_dst), &(entry->rt_gateway), netmask, 301 entry->rt_flags, (struct rtentry **)0); 302 /* rt_missmsg((req == RTM_ADD ? RTM_OLDADD : RTM_OLDDEL), 303 &(entry->rt_dst), &(entry->rt_gateway), 304 netmask, SA(0), entry->rt_flags, error); */ 305 return (error); 306 #endif 307 } 308 309 struct ifaddr * 310 ifa_ifwithroute(flags, dst, gateway) 311 int flags; 312 struct sockaddr *dst, *gateway; 313 { 314 register struct ifaddr *ifa; 315 if ((flags & RTF_GATEWAY) == 0) { 316 /* 317 * If we are adding a route to an interface, 318 * and the interface is a pt to pt link 319 * we should search for the destination 320 * as our clue to the interface. Otherwise 321 * we can use the local address. 322 */ 323 ifa = 0; 324 if (flags & RTF_HOST) 325 ifa = ifa_ifwithdstaddr(dst); 326 if (ifa == 0) 327 ifa = ifa_ifwithaddr(gateway); 328 } else { 329 /* 330 * If we are adding a route to a remote net 331 * or host, the gateway may still be on the 332 * other end of a pt to pt link. 333 */ 334 ifa = ifa_ifwithdstaddr(gateway); 335 } 336 if (ifa == 0) 337 ifa = ifa_ifwithnet(gateway); 338 if (ifa == 0) { 339 struct rtentry *rt = rtalloc1(dst, 0); 340 if (rt == 0) 341 return (0); 342 rt->rt_refcnt--; 343 if ((ifa = rt->rt_ifa) == 0) 344 return (0); 345 } 346 if (ifa->ifa_addr->sa_family != dst->sa_family) { 347 struct ifaddr *oifa = ifa, *ifaof_ifpforaddr(); 348 ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp); 349 if (ifa == 0) 350 ifa = oifa; 351 } 352 return (ifa); 353 } 354 355 #define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 356 357 rtrequest(req, dst, gateway, netmask, flags, ret_nrt) 358 int req, flags; 359 struct sockaddr *dst, *gateway, *netmask; 360 struct rtentry **ret_nrt; 361 { 362 int s = splnet(); int error = 0; 363 register struct rtentry *rt; 364 register struct radix_node *rn; 365 register struct radix_node_head *rnh; 366 struct ifaddr *ifa, *ifa_ifwithdstaddr(); 367 struct sockaddr *ndst; 368 #define senderr(x) { error = x ; goto bad; } 369 370 if ((rnh = rt_tables[dst->sa_family]) == 0) 371 senderr(ESRCH); 372 if (flags & RTF_HOST) 373 netmask = 0; 374 switch (req) { 375 case RTM_DELETE: 376 if ((rn = rnh->rnh_delete((caddr_t)dst, (caddr_t)netmask, 377 rnh->rnh_treetop)) == 0) 378 senderr(ESRCH); 379 if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT)) 380 panic ("rtrequest delete"); 381 rt = (struct rtentry *)rn; 382 rt->rt_flags &= ~RTF_UP; 383 if (rt->rt_gwroute) { 384 rt = rt->rt_gwroute; RTFREE(rt); 385 (rt = (struct rtentry *)rn)->rt_gwroute = 0; 386 } 387 if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest) 388 ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0)); 389 rttrash++; 390 if (ret_nrt) 391 *ret_nrt = rt; 392 else if (rt->rt_refcnt <= 0) { 393 rt->rt_refcnt++; 394 rtfree(rt); 395 } 396 break; 397 398 case RTM_RESOLVE: 399 if (ret_nrt == 0 || (rt = *ret_nrt) == 0) 400 senderr(EINVAL); 401 ifa = rt->rt_ifa; 402 flags = rt->rt_flags & ~RTF_CLONING; 403 gateway = rt->rt_gateway; 404 if ((netmask = rt->rt_genmask) == 0) 405 flags |= RTF_HOST; 406 goto makeroute; 407 408 case RTM_ADD: 409 if ((ifa = ifa_ifwithroute(flags, dst, gateway)) == 0) 410 senderr(ENETUNREACH); 411 makeroute: 412 R_Malloc(rt, struct rtentry *, sizeof(*rt)); 413 if (rt == 0) 414 senderr(ENOBUFS); 415 Bzero(rt, sizeof(*rt)); 416 rt->rt_flags = RTF_UP | flags; 417 if (rt_setgate(rt, dst, gateway)) { 418 Free(rt); 419 senderr(ENOBUFS); 420 } 421 ndst = rt_key(rt); 422 if (netmask) { 423 rt_maskedcopy(dst, ndst, netmask); 424 } else 425 Bcopy(dst, ndst, dst->sa_len); 426 rn = rnh->rnh_add((caddr_t)ndst, (caddr_t)netmask, 427 rnh->rnh_treetop, rt->rt_nodes); 428 if (rn == 0) { 429 if (rt->rt_gwroute) 430 rtfree(rt->rt_gwroute); 431 Free(rt_key(rt)); 432 Free(rt); 433 senderr(EEXIST); 434 } 435 ifa->ifa_refcnt++; 436 rt->rt_ifa = ifa; 437 rt->rt_ifp = ifa->ifa_ifp; 438 if (req == RTM_RESOLVE) 439 rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */ 440 if (ifa->ifa_rtrequest) 441 ifa->ifa_rtrequest(req, rt, SA(ret_nrt ? *ret_nrt : 0)); 442 if (ret_nrt) { 443 *ret_nrt = rt; 444 rt->rt_refcnt++; 445 } 446 break; 447 } 448 bad: 449 splx(s); 450 return (error); 451 } 452 453 rt_setgate(rt0, dst, gate) 454 struct rtentry *rt0; 455 struct sockaddr *dst, *gate; 456 { 457 caddr_t new, old; 458 int dlen = ROUNDUP(dst->sa_len), glen = ROUNDUP(gate->sa_len); 459 register struct rtentry *rt = rt0; 460 461 if (rt->rt_gateway == 0 || glen > ROUNDUP(rt->rt_gateway->sa_len)) { 462 old = (caddr_t)rt_key(rt); 463 R_Malloc(new, caddr_t, dlen + glen); 464 if (new == 0) 465 return 1; 466 rt->rt_nodes->rn_key = new; 467 } else { 468 new = rt->rt_nodes->rn_key; 469 old = 0; 470 } 471 Bcopy(gate, (rt->rt_gateway = (struct sockaddr *)(new + dlen)), glen); 472 if (old) { 473 Bcopy(dst, new, dlen); 474 Free(old); 475 } 476 if (rt->rt_gwroute) { 477 rt = rt->rt_gwroute; RTFREE(rt); 478 rt = rt0; rt->rt_gwroute = 0; 479 } 480 if (rt->rt_flags & RTF_GATEWAY) { 481 rt->rt_gwroute = rtalloc1(gate, 1); 482 } 483 return 0; 484 } 485 486 rt_maskedcopy(src, dst, netmask) 487 struct sockaddr *src, *dst, *netmask; 488 { 489 register u_char *cp1 = (u_char *)src; 490 register u_char *cp2 = (u_char *)dst; 491 register u_char *cp3 = (u_char *)netmask; 492 u_char *cplim = cp2 + *cp3; 493 u_char *cplim2 = cp2 + *cp1; 494 495 *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */ 496 cp3 += 2; 497 if (cplim > cplim2) 498 cplim = cplim2; 499 while (cp2 < cplim) 500 *cp2++ = *cp1++ & *cp3++; 501 if (cp2 < cplim2) 502 bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2)); 503 } 504 /* 505 * Set up a routing table entry, normally 506 * for an interface. 507 */ 508 rtinit(ifa, cmd, flags) 509 register struct ifaddr *ifa; 510 int cmd, flags; 511 { 512 register struct rtentry *rt; 513 register struct sockaddr *dst; 514 register struct sockaddr *deldst; 515 struct mbuf *m = 0; 516 struct rtentry *nrt = 0; 517 int error; 518 519 dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr; 520 if (cmd == RTM_DELETE) { 521 if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) { 522 m = m_get(M_WAIT, MT_SONAME); 523 deldst = mtod(m, struct sockaddr *); 524 rt_maskedcopy(dst, deldst, ifa->ifa_netmask); 525 dst = deldst; 526 } 527 if (rt = rtalloc1(dst, 0)) { 528 rt->rt_refcnt--; 529 if (rt->rt_ifa != ifa) { 530 if (m) 531 (void) m_free(m); 532 return (flags & RTF_HOST ? EHOSTUNREACH 533 : ENETUNREACH); 534 } 535 } 536 } 537 error = rtrequest(cmd, dst, ifa->ifa_addr, ifa->ifa_netmask, 538 flags | ifa->ifa_flags, &nrt); 539 if (m) 540 (void) m_free(m); 541 if (cmd == RTM_DELETE && error == 0 && (rt = nrt)) { 542 rt_newaddrmsg(cmd, ifa, error, nrt); 543 if (rt->rt_refcnt <= 0) { 544 rt->rt_refcnt++; 545 rtfree(rt); 546 } 547 } 548 if (cmd == RTM_ADD && error == 0 && (rt = nrt)) { 549 rt->rt_refcnt--; 550 if (rt->rt_ifa != ifa) { 551 printf("rtinit: wrong ifa (%x) was (%x)\n", ifa, 552 rt->rt_ifa); 553 if (rt->rt_ifa->ifa_rtrequest) 554 rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0)); 555 IFAFREE(rt->rt_ifa); 556 rt->rt_ifa = ifa; 557 rt->rt_ifp = ifa->ifa_ifp; 558 ifa->ifa_refcnt++; 559 if (ifa->ifa_rtrequest) 560 ifa->ifa_rtrequest(RTM_ADD, rt, SA(0)); 561 } 562 rt_newaddrmsg(cmd, ifa, error, nrt); 563 } 564 return (error); 565 } 566