1 /* 2 * Copyright (c) 1980, 1986 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 * 17 * @(#)route.c 7.16 (Berkeley) 06/20/90 18 */ 19 #include "machine/reg.h" 20 21 #include "param.h" 22 #include "systm.h" 23 #include "user.h" 24 #include "proc.h" 25 #include "mbuf.h" 26 #include "socket.h" 27 #include "socketvar.h" 28 #include "domain.h" 29 #include "protosw.h" 30 #include "errno.h" 31 #include "ioctl.h" 32 33 #include "if.h" 34 #include "af.h" 35 #include "route.h" 36 #include "raw_cb.h" 37 #include "../netinet/in.h" 38 #include "../netinet/in_var.h" 39 40 #include "../netns/ns.h" 41 #include "machine/mtpr.h" 42 #include "netisr.h" 43 #define SA(p) ((struct sockaddr *)(p)) 44 45 int rttrash; /* routes not in table but not freed */ 46 struct sockaddr wildcard; /* zero valued cookie for wildcard searches */ 47 int rthashsize = RTHASHSIZ; /* for netstat, etc. */ 48 49 static int rtinits_done = 0; 50 struct radix_node_head *ns_rnhead, *in_rnhead; 51 struct radix_node *rn_match(), *rn_delete(), *rn_addroute(); 52 rtinitheads() 53 { 54 if (rtinits_done == 0 && 55 rn_inithead(&ns_rnhead, 16, AF_NS) && 56 rn_inithead(&in_rnhead, 32, AF_INET)) 57 rtinits_done = 1; 58 } 59 60 /* 61 * Packet routing routines. 62 */ 63 rtalloc(ro) 64 register struct route *ro; 65 { 66 if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP)) 67 return; /* XXX */ 68 ro->ro_rt = rtalloc1(&ro->ro_dst, 1); 69 } 70 71 struct rtentry * 72 rtalloc1(dst, report) 73 register struct sockaddr *dst; 74 int report; 75 { 76 register struct radix_node_head *rnh; 77 register struct rtentry *rt; 78 register struct radix_node *rn; 79 struct rtentry *newrt = 0; 80 int s = splnet(), err = 0; 81 82 for (rnh = radix_node_head; rnh && (dst->sa_family != rnh->rnh_af); ) 83 rnh = rnh->rnh_next; 84 if (rnh && rnh->rnh_treetop && 85 (rn = rn_match((caddr_t)dst, rnh->rnh_treetop)) && 86 ((rn->rn_flags & RNF_ROOT) == 0)) { 87 newrt = rt = (struct rtentry *)rn; 88 if (report && (rt->rt_flags & RTF_CLONING)) { 89 if (err = rtrequest(RTM_RESOLVE, dst, SA(0), 90 SA(0), 0, &newrt)) 91 goto miss; 92 } else 93 rt->rt_refcnt++; 94 } else { 95 rtstat.rts_unreach++; 96 miss: if (report) 97 rt_missmsg(RTM_MISS, dst, SA(0), SA(0), SA(0), 0, err); 98 } 99 splx(s); 100 return (newrt); 101 } 102 103 rtfree(rt) 104 register struct rtentry *rt; 105 { 106 register struct ifaddr *ifa; 107 if (rt == 0) 108 panic("rtfree"); 109 rt->rt_refcnt--; 110 if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) { 111 rttrash--; 112 if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT)) 113 panic ("rtfree 2"); 114 free((caddr_t)rt, M_RTABLE); 115 } 116 } 117 118 /* 119 * Force a routing table entry to the specified 120 * destination to go through the given gateway. 121 * Normally called as a result of a routing redirect 122 * message from the network layer. 123 * 124 * N.B.: must be called at splnet 125 * 126 */ 127 rtredirect(dst, gateway, netmask, flags, src, rtp) 128 struct sockaddr *dst, *gateway, *netmask, *src; 129 int flags; 130 struct rtentry **rtp; 131 { 132 register struct rtentry *rt; 133 int error = 0; 134 short *stat = 0; 135 136 /* verify the gateway is directly reachable */ 137 if (ifa_ifwithnet(gateway) == 0) { 138 error = ENETUNREACH; 139 goto done; 140 } 141 rt = rtalloc1(dst, 0); 142 /* 143 * If the redirect isn't from our current router for this dst, 144 * it's either old or wrong. If it redirects us to ourselves, 145 * we have a routing loop, perhaps as a result of an interface 146 * going down recently. 147 */ 148 #define equal(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0) 149 if (!(flags & RTF_DONE) && rt && !equal(src, rt->rt_gateway)) 150 error = EINVAL; 151 else if (ifa_ifwithaddr(gateway)) 152 error = EHOSTUNREACH; 153 if (error) 154 goto done; 155 /* 156 * Create a new entry if we just got back a wildcard entry 157 * or the the lookup failed. This is necessary for hosts 158 * which use routing redirects generated by smart gateways 159 * to dynamically build the routing tables. 160 */ 161 if ((rt == 0) || (rt_mask(rt) && rt_mask(rt)->sa_len < 2)) 162 goto create; 163 /* 164 * Don't listen to the redirect if it's 165 * for a route to an interface. 166 */ 167 if (rt->rt_flags & RTF_GATEWAY) { 168 if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) { 169 /* 170 * Changing from route to net => route to host. 171 * Create new route, rather than smashing route to net. 172 */ 173 create: 174 flags |= RTF_GATEWAY | RTF_DYNAMIC; 175 error = rtrequest((int)RTM_ADD, dst, gateway, 176 SA(0), flags, 177 (struct rtentry **)0); 178 stat = &rtstat.rts_dynamic; 179 } else { 180 /* 181 * Smash the current notion of the gateway to 182 * this destination. Should check about netmask!!! 183 */ 184 if (gateway->sa_len <= rt->rt_gateway->sa_len) { 185 Bcopy(gateway, rt->rt_gateway, gateway->sa_len); 186 rt->rt_flags |= RTF_MODIFIED; 187 flags |= RTF_MODIFIED; 188 stat = &rtstat.rts_newgateway; 189 } else 190 error = ENOSPC; 191 } 192 } else 193 error = EHOSTUNREACH; 194 done: 195 if (rt) { 196 if (rtp && !error) 197 *rtp = rt; 198 else 199 rtfree(rt); 200 } 201 if (error) 202 rtstat.rts_badredirect++; 203 else 204 (stat && (*stat)++); 205 rt_missmsg(RTM_REDIRECT, dst, gateway, netmask, src, flags, error); 206 } 207 208 /* 209 * Routing table ioctl interface. 210 */ 211 rtioctl(req, data) 212 int req; 213 caddr_t data; 214 { 215 #ifndef COMPAT_43 216 return (EOPNOTSUPP); 217 #else 218 register struct ortentry *entry = (struct ortentry *)data; 219 int error; 220 struct sockaddr *netmask = 0; 221 222 if (req == SIOCADDRT) 223 req = RTM_ADD; 224 else if (req == SIOCDELRT) 225 req = RTM_DELETE; 226 else 227 return (EINVAL); 228 229 if (error = suser(u.u_cred, &u.u_acflag)) 230 return (error); 231 #if BYTE_ORDER != BIG_ENDIAN 232 if (entry->rt_dst.sa_family == 0 && entry->rt_dst.sa_len < 16) { 233 entry->rt_dst.sa_family = entry->rt_dst.sa_len; 234 entry->rt_dst.sa_len = 16; 235 } 236 if (entry->rt_gateway.sa_family == 0 && entry->rt_gateway.sa_len < 16) { 237 entry->rt_gateway.sa_family = entry->rt_gateway.sa_len; 238 entry->rt_gateway.sa_len = 16; 239 } 240 #else 241 if (entry->rt_dst.sa_len == 0) 242 entry->rt_dst.sa_len = 16; 243 if (entry->rt_gateway.sa_len == 0) 244 entry->rt_gateway.sa_len = 16; 245 #endif 246 if ((entry->rt_flags & RTF_HOST) == 0) 247 switch (entry->rt_dst.sa_family) { 248 #ifdef INET 249 case AF_INET: 250 { 251 extern struct sockaddr_in icmpmask; 252 struct sockaddr_in *dst_in = 253 (struct sockaddr_in *)&entry->rt_dst; 254 255 in_sockmaskof(dst_in->sin_addr, &icmpmask); 256 netmask = (struct sockaddr *)&icmpmask; 257 } 258 break; 259 #endif 260 #ifdef NS 261 case AF_NS: 262 { 263 extern struct sockaddr_ns ns_netmask; 264 netmask = (struct sockaddr *)&ns_netmask; 265 } 266 #endif 267 } 268 error = rtrequest(req, &(entry->rt_dst), &(entry->rt_gateway), netmask, 269 entry->rt_flags, (struct rtentry **)0); 270 rt_missmsg((req == RTM_ADD ? RTM_OLDADD : RTM_OLDDEL), 271 &(entry->rt_dst), &(entry->rt_gateway), 272 netmask, SA(0), entry->rt_flags, error); 273 return (error); 274 #endif 275 } 276 277 struct ifaddr * 278 ifa_ifwithroute(flags, dst, gateway) 279 int flags; 280 struct sockaddr *dst, *gateway; 281 { 282 struct ifaddr *ifa; 283 if ((flags & RTF_GATEWAY) == 0) { 284 /* 285 * If we are adding a route to an interface, 286 * and the interface is a pt to pt link 287 * we should search for the destination 288 * as our clue to the interface. Otherwise 289 * we can use the local address. 290 */ 291 ifa = 0; 292 if (flags & RTF_HOST) 293 ifa = ifa_ifwithdstaddr(dst); 294 if (ifa == 0) 295 ifa = ifa_ifwithaddr(gateway); 296 } else { 297 /* 298 * If we are adding a route to a remote net 299 * or host, the gateway may still be on the 300 * other end of a pt to pt link. 301 */ 302 ifa = ifa_ifwithdstaddr(gateway); 303 } 304 if (ifa == 0) 305 ifa = ifa_ifwithnet(gateway); 306 return (ifa); 307 } 308 309 #define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1))) 310 311 rtrequest(req, dst, gateway, netmask, flags, ret_nrt) 312 int req, flags; 313 struct sockaddr *dst, *gateway, *netmask; 314 struct rtentry **ret_nrt; 315 { 316 int s = splnet(), len, error = 0; 317 register struct rtentry *rt; 318 register struct radix_node *rn; 319 register struct radix_node_head *rnh; 320 struct ifaddr *ifa, *ifa_ifwithdstaddr(); 321 struct sockaddr *ndst; 322 u_char af = dst->sa_family; 323 #define senderr(x) { error = x ; goto bad; } 324 325 if (rtinits_done == 0) 326 rtinitheads(); 327 for (rnh = radix_node_head; rnh && (af != rnh->rnh_af); ) 328 rnh = rnh->rnh_next; 329 if (rnh == 0) 330 senderr(ESRCH); 331 if (flags & RTF_HOST) 332 netmask = 0; 333 switch (req) { 334 case RTM_DELETE: 335 if (ret_nrt && (rt = *ret_nrt)) { 336 RTFREE(rt); 337 *ret_nrt = 0; 338 } 339 if ((rn = rn_delete((caddr_t)dst, (caddr_t)netmask, 340 rnh->rnh_treetop)) == 0) 341 senderr(ESRCH); 342 if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT)) 343 panic ("rtrequest delete"); 344 rt = (struct rtentry *)rn; 345 rt->rt_flags &= ~RTF_UP; 346 if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest) 347 ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0)); 348 rttrash++; 349 if (rt->rt_refcnt <= 0) 350 rtfree(rt); 351 break; 352 353 case RTM_RESOLVE: 354 if (ret_nrt == 0 || (rt = *ret_nrt) == 0) 355 senderr(EINVAL); 356 ifa = rt->rt_ifa; 357 flags = rt->rt_flags & ~RTF_CLONING; 358 gateway = rt->rt_gateway; 359 if ((netmask = rt->rt_genmask) == 0) 360 flags |= RTF_HOST; 361 goto makeroute; 362 363 case RTM_ADD: 364 if ((ifa = ifa_ifwithroute(flags, dst, gateway)) == 0) 365 senderr(ENETUNREACH); 366 makeroute: 367 len = sizeof (*rt) + ROUNDUP(gateway->sa_len) 368 + ROUNDUP(dst->sa_len); 369 R_Malloc(rt, struct rtentry *, len); 370 if (rt == 0) 371 senderr(ENOBUFS); 372 Bzero(rt, len); 373 ndst = (struct sockaddr *)(rt + 1); 374 if (netmask) { 375 rt_maskedcopy(dst, ndst, netmask); 376 } else 377 Bcopy(dst, ndst, dst->sa_len); 378 rn = rn_addroute((caddr_t)ndst, (caddr_t)netmask, 379 rnh->rnh_treetop, rt->rt_nodes); 380 if (rn == 0) { 381 free((caddr_t)rt, M_RTABLE); 382 senderr(EEXIST); 383 } 384 rt->rt_ifa = ifa; 385 rt->rt_ifp = ifa->ifa_ifp; 386 rt->rt_flags = RTF_UP | flags; 387 rn->rn_key = (caddr_t) ndst; /* == rt_dst */ 388 rt->rt_gateway = (struct sockaddr *) 389 (rn->rn_key + ROUNDUP(dst->sa_len)); 390 Bcopy(gateway, rt->rt_gateway, gateway->sa_len); 391 if (req == RTM_RESOLVE) 392 rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */ 393 if (ifa->ifa_rtrequest) 394 ifa->ifa_rtrequest(req, rt, SA(ret_nrt ? *ret_nrt : 0)); 395 if (ret_nrt) { 396 *ret_nrt = rt; 397 rt->rt_refcnt++; 398 } 399 break; 400 } 401 bad: 402 splx(s); 403 return (error); 404 } 405 406 rt_maskedcopy(src, dst, netmask) 407 struct sockaddr *src, *dst, *netmask; 408 { 409 register u_char *cp1 = (u_char *)src; 410 register u_char *cp2 = (u_char *)dst; 411 register u_char *cp3 = (u_char *)netmask; 412 u_char *cplim = cp2 + *cp3; 413 u_char *cplim2 = cp2 + *cp1; 414 415 *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */ 416 cp3 += 2; 417 if (cplim > cplim2) 418 cplim = cplim2; 419 while (cp2 < cplim) 420 *cp2++ = *cp1++ & *cp3++; 421 if (cp2 < cplim2) 422 bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2)); 423 } 424 /* 425 * Set up a routing table entry, normally 426 * for an interface. 427 */ 428 rtinit(ifa, cmd, flags) 429 register struct ifaddr *ifa; 430 int cmd, flags; 431 { 432 return rtrequest(cmd, ifa->ifa_dstaddr, ifa->ifa_addr, 433 ifa->ifa_netmask, flags | ifa->ifa_flags, &ifa->ifa_rt); 434 } 435