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