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.15 (Berkeley) 06/09/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 #define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1))) 277 278 rtrequest(req, dst, gateway, netmask, flags, ret_nrt) 279 int req, flags; 280 struct sockaddr *dst, *gateway, *netmask; 281 struct rtentry **ret_nrt; 282 { 283 int s = splnet(), len, error = 0; 284 register struct rtentry *rt; 285 register struct radix_node *rn; 286 register struct radix_node_head *rnh; 287 struct ifaddr *ifa, *ifa_ifwithdstaddr(); 288 struct sockaddr *ndst; 289 u_char af = dst->sa_family; 290 #define senderr(x) { error = x ; goto bad; } 291 292 if (rtinits_done == 0) 293 rtinitheads(); 294 for (rnh = radix_node_head; rnh && (af != rnh->rnh_af); ) 295 rnh = rnh->rnh_next; 296 if (rnh == 0) 297 senderr(ESRCH); 298 if (flags & RTF_HOST) 299 netmask = 0; 300 switch (req) { 301 case RTM_DELETE: 302 if (ret_nrt && (rt = *ret_nrt)) { 303 RTFREE(rt); 304 *ret_nrt = 0; 305 } 306 if ((rn = rn_delete((caddr_t)dst, (caddr_t)netmask, 307 rnh->rnh_treetop)) == 0) 308 senderr(ESRCH); 309 if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT)) 310 panic ("rtrequest delete"); 311 rt = (struct rtentry *)rn; 312 rt->rt_flags &= ~RTF_UP; 313 if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest) 314 ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0)); 315 rttrash++; 316 if (rt->rt_refcnt <= 0) 317 rtfree(rt); 318 break; 319 320 case RTM_RESOLVE: 321 if (ret_nrt== 0 || (rt = *ret_nrt) == 0) 322 senderr(EINVAL); 323 ifa = rt->rt_ifa; 324 flags = rt->rt_flags & ~RTF_CLONING; 325 gateway = rt->rt_gateway; 326 if ((netmask = rt->rt_genmask) == 0) 327 flags |= RTF_HOST; 328 goto makeroute; 329 330 case RTM_ADD: 331 if ((flags & RTF_GATEWAY) == 0) { 332 /* 333 * If we are adding a route to an interface, 334 * and the interface is a pt to pt link 335 * we should search for the destination 336 * as our clue to the interface. Otherwise 337 * we can use the local address. 338 */ 339 ifa = 0; 340 if (flags & RTF_HOST) 341 ifa = ifa_ifwithdstaddr(dst); 342 if (ifa == 0) 343 ifa = ifa_ifwithaddr(gateway); 344 } else { 345 /* 346 * If we are adding a route to a remote net 347 * or host, the gateway may still be on the 348 * other end of a pt to pt link. 349 */ 350 ifa = ifa_ifwithdstaddr(gateway); 351 } 352 if (ifa == 0) { 353 ifa = ifa_ifwithnet(gateway); 354 if (ifa == 0 && req == RTM_ADD) 355 senderr(ENETUNREACH); 356 } 357 makeroute: len = sizeof (*rt) + ROUNDUP(gateway->sa_len) 358 + ROUNDUP(dst->sa_len) + ROUNDUP(ifa->ifa_llinfolen); 359 R_Malloc(rt, struct rtentry *, len); 360 if (rt == 0) 361 senderr(ENOBUFS); 362 Bzero(rt, len); 363 ndst = (struct sockaddr *)(rt + 1); 364 if (netmask) { 365 rt_maskedcopy(dst, ndst, netmask); 366 } else 367 Bcopy(dst, ndst, dst->sa_len); 368 rn = rn_addroute((caddr_t)ndst, (caddr_t)netmask, 369 rnh->rnh_treetop, rt->rt_nodes); 370 if (rn == 0) { 371 free((caddr_t)rt, M_RTABLE); 372 senderr(EEXIST); 373 } 374 rt->rt_ifa = ifa; 375 rt->rt_ifp = ifa->ifa_ifp; 376 rt->rt_flags = RTF_UP | flags; 377 rn->rn_key = (caddr_t) ndst; /* == rt_dst */ 378 rt->rt_gateway = (struct sockaddr *) 379 (rn->rn_key + ROUNDUP(dst->sa_len)); 380 Bcopy(gateway, rt->rt_gateway, gateway->sa_len); 381 rt->rt_llinfo = ROUNDUP(gateway->sa_len) 382 + (caddr_t)rt->rt_gateway; 383 if (req == RTM_RESOLVE) 384 rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */ 385 if (ifa->ifa_rtrequest) 386 ifa->ifa_rtrequest(req, rt, SA(ret_nrt ? *ret_nrt : 0)); 387 if (ret_nrt) { 388 *ret_nrt = rt; 389 rt->rt_refcnt++; 390 } 391 break; 392 } 393 bad: 394 splx(s); 395 return (error); 396 } 397 398 rt_maskedcopy(src, dst, netmask) 399 struct sockaddr *src, *dst, *netmask; 400 { 401 register u_char *cp1 = (u_char *)src; 402 register u_char *cp2 = (u_char *)dst; 403 register u_char *cp3 = (u_char *)netmask; 404 u_char *cplim = cp2 + *cp3; 405 u_char *cplim2 = cp2 + *cp1; 406 407 *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */ 408 cp3 += 2; 409 if (cplim > cplim2) 410 cplim = cplim2; 411 while (cp2 < cplim) 412 *cp2++ = *cp1++ & *cp3++; 413 if (cp2 < cplim2) 414 bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2)); 415 } 416 /* 417 * Set up a routing table entry, normally 418 * for an interface. 419 */ 420 rtinit(ifa, cmd, flags) 421 register struct ifaddr *ifa; 422 int cmd, flags; 423 { 424 return rtrequest(cmd, ifa->ifa_dstaddr, ifa->ifa_addr, 425 ifa->ifa_netmask, flags | ifa->ifa_flags, &ifa->ifa_rt); 426 } 427