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