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