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