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