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.13 (Berkeley) 04/05/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 44 int rttrash; /* routes not in table but not freed */ 45 struct sockaddr wildcard; /* zero valued cookie for wildcard searches */ 46 int rthashsize = RTHASHSIZ; /* for netstat, etc. */ 47 48 static int rtinits_done = 0; 49 struct radix_node_head *ns_rnhead, *in_rnhead; 50 struct radix_node *rn_match(), *rn_delete(), *rn_addroute(); 51 rtinitheads() 52 { 53 if (rtinits_done == 0 && 54 rn_inithead(&ns_rnhead, 16, AF_NS) && 55 rn_inithead(&in_rnhead, 32, AF_INET)) 56 rtinits_done = 1; 57 } 58 59 /* 60 * Packet routing routines. 61 */ 62 rtalloc(ro) 63 register struct route *ro; 64 { 65 if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP)) 66 return; /* XXX */ 67 ro->ro_rt = rtalloc1(&ro->ro_dst, 1); 68 } 69 70 struct rtentry * 71 rtalloc1(dst, report) 72 struct sockaddr *dst; 73 int report; 74 { 75 register struct radix_node_head *rnh; 76 register struct radix_node *rn; 77 register struct rtentry *rt = 0; 78 u_char af = dst->sa_family; 79 int s = splnet(); 80 81 for (rnh = radix_node_head; rnh && (af != rnh->rnh_af); ) 82 rnh = rnh->rnh_next; 83 if (rnh && rnh->rnh_treetop && 84 (rn = rn_match((caddr_t)dst, rnh->rnh_treetop)) && 85 ((rn->rn_flags & RNF_ROOT) == 0)) { 86 rt = (struct rtentry *)rn; 87 if (report && (rt->rt_flags & RTF_CLONING)) { 88 struct rtentry *newrt = 0; 89 int flags = rt->rt_flags & ~RTF_CLONING; 90 91 if (rt->rt_genmask == 0) flags |= RTF_HOST; 92 (void) rtrequest(RTM_ADD, dst, rt->rt_gateway, 93 rt->rt_genmask, flags, &newrt); 94 rt = newrt; 95 } else 96 rt->rt_refcnt++; 97 if (rt == 0) 98 goto miss; 99 } else { 100 rtstat.rts_unreach++; 101 miss: if (report) 102 rt_missmsg(RTM_MISS, dst, (struct sockaddr *)0, 103 (struct sockaddr *)0, (struct sockaddr *)0, 0, 0); 104 } 105 splx(s); 106 return (rt); 107 } 108 109 rtfree(rt) 110 register struct rtentry *rt; 111 { 112 register struct ifaddr *ifa; 113 if (rt == 0) 114 panic("rtfree"); 115 rt->rt_refcnt--; 116 if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) { 117 rttrash--; 118 if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT)) 119 panic ("rtfree 2"); 120 free((caddr_t)rt, M_RTABLE); 121 } 122 } 123 124 /* 125 * Force a routing table entry to the specified 126 * destination to go through the given gateway. 127 * Normally called as a result of a routing redirect 128 * message from the network layer. 129 * 130 * N.B.: must be called at splnet 131 * 132 */ 133 rtredirect(dst, gateway, netmask, flags, src, rtp) 134 struct sockaddr *dst, *gateway, *netmask, *src; 135 int flags; 136 struct rtentry **rtp; 137 { 138 register struct rtentry *rt; 139 int error = 0; 140 short *stat = 0; 141 142 /* verify the gateway is directly reachable */ 143 if (ifa_ifwithnet(gateway) == 0) { 144 error = ENETUNREACH; 145 goto done; 146 } 147 rt = rtalloc1(dst, 0); 148 /* 149 * If the redirect isn't from our current router for this dst, 150 * it's either old or wrong. If it redirects us to ourselves, 151 * we have a routing loop, perhaps as a result of an interface 152 * going down recently. 153 */ 154 #define equal(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0) 155 if (!(flags & RTF_DONE) && rt && !equal(src, rt->rt_gateway)) 156 error = EINVAL; 157 else if (ifa_ifwithaddr(gateway)) 158 error = EHOSTUNREACH; 159 if (error) 160 goto done; 161 /* 162 * Create a new entry if we just got back a wildcard entry 163 * or the the lookup failed. This is necessary for hosts 164 * which use routing redirects generated by smart gateways 165 * to dynamically build the routing tables. 166 */ 167 if ((rt == 0) || (rt_mask(rt) && rt_mask(rt)->sa_len < 2)) 168 goto create; 169 /* 170 * Don't listen to the redirect if it's 171 * for a route to an interface. 172 */ 173 if (rt->rt_flags & RTF_GATEWAY) { 174 if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) { 175 /* 176 * Changing from route to net => route to host. 177 * Create new route, rather than smashing route to net. 178 */ 179 create: 180 flags |= RTF_GATEWAY | RTF_DYNAMIC; 181 error = rtrequest((int)RTM_ADD, dst, gateway, 182 (struct sockaddr *)0, flags, 183 (struct rtentry **)0); 184 stat = &rtstat.rts_dynamic; 185 } else { 186 /* 187 * Smash the current notion of the gateway to 188 * this destination. Should check about netmask!!! 189 */ 190 if (gateway->sa_len <= rt->rt_gateway->sa_len) { 191 Bcopy(gateway, rt->rt_gateway, gateway->sa_len); 192 rt->rt_flags |= RTF_MODIFIED; 193 flags |= RTF_MODIFIED; 194 stat = &rtstat.rts_newgateway; 195 } else 196 error = ENOSPC; 197 } 198 } else 199 error = EHOSTUNREACH; 200 done: 201 if (rt) { 202 if (rtp && !error) 203 *rtp = rt; 204 else 205 rtfree(rt); 206 } 207 if (error) 208 rtstat.rts_badredirect++; 209 else 210 (stat && (*stat)++); 211 rt_missmsg(RTM_REDIRECT, dst, gateway, netmask, src, flags, error); 212 } 213 214 /* 215 * Routing table ioctl interface. 216 */ 217 rtioctl(req, data) 218 int req; 219 caddr_t data; 220 { 221 #ifndef COMPAT_43 222 return (EOPNOTSUPP); 223 #else 224 register struct ortentry *entry = (struct ortentry *)data; 225 int error; 226 struct sockaddr *netmask = 0; 227 228 if (req == SIOCADDRT) 229 req = RTM_ADD; 230 else if (req == SIOCDELRT) 231 req = RTM_DELETE; 232 else 233 return (EINVAL); 234 235 if (error = suser(u.u_cred, &u.u_acflag)) 236 return (error); 237 #if BYTE_ORDER != BIG_ENDIAN 238 if (entry->rt_dst.sa_family == 0 && entry->rt_dst.sa_len < 16) { 239 entry->rt_dst.sa_family = entry->rt_dst.sa_len; 240 entry->rt_dst.sa_len = 16; 241 } 242 if (entry->rt_gateway.sa_family == 0 && entry->rt_gateway.sa_len < 16) { 243 entry->rt_gateway.sa_family = entry->rt_gateway.sa_len; 244 entry->rt_gateway.sa_len = 16; 245 } 246 #else 247 if (entry->rt_dst.sa_len == 0) 248 entry->rt_dst.sa_len = 16; 249 if (entry->rt_gateway.sa_len == 0) 250 entry->rt_gateway.sa_len = 16; 251 #endif 252 if ((entry->rt_flags & RTF_HOST) == 0) 253 switch (entry->rt_dst.sa_family) { 254 #ifdef INET 255 case AF_INET: 256 { 257 extern struct sockaddr_in icmpmask; 258 struct sockaddr_in *dst_in = 259 (struct sockaddr_in *)&entry->rt_dst; 260 261 in_sockmaskof(dst_in->sin_addr, &icmpmask); 262 netmask = (struct sockaddr *)&icmpmask; 263 } 264 break; 265 #endif 266 #ifdef NS 267 case AF_NS: 268 { 269 extern struct sockaddr_ns ns_netmask; 270 netmask = (struct sockaddr *)&ns_netmask; 271 } 272 #endif 273 } 274 error = rtrequest(req, &(entry->rt_dst), &(entry->rt_gateway), netmask, 275 entry->rt_flags, (struct rtentry **)0); 276 rt_missmsg((req == RTM_ADD ? RTM_OLDADD : RTM_OLDDEL), 277 &(entry->rt_dst), &(entry->rt_gateway), 278 netmask, (struct sockaddr *)0, entry->rt_flags, error); 279 return (error); 280 #endif 281 } 282 #define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1))) 283 284 rtrequest(req, dst, gateway, netmask, flags, ret_nrt) 285 int req, flags; 286 struct sockaddr *dst, *gateway, *netmask; 287 struct rtentry **ret_nrt; 288 { 289 int s = splnet(), len, error = 0; 290 register struct rtentry *rt; 291 register struct radix_node *rn; 292 register struct radix_node_head *rnh; 293 struct ifaddr *ifa, *ifa_ifwithdstaddr(); 294 struct sockaddr *ndst; 295 u_char af = dst->sa_family; 296 #define senderr(x) { error = x ; goto bad; } 297 298 if (rtinits_done == 0) 299 rtinitheads(); 300 for (rnh = radix_node_head; rnh && (af != rnh->rnh_af); ) 301 rnh = rnh->rnh_next; 302 if (rnh == 0) 303 senderr(ESRCH); 304 if (flags & RTF_HOST) 305 netmask = 0; 306 switch (req) { 307 case RTM_DELETE: 308 if (ret_nrt && (rt = *ret_nrt)) { 309 RTFREE(rt); 310 *ret_nrt = 0; 311 } 312 if ((rn = rn_delete((caddr_t)dst, (caddr_t)netmask, 313 rnh->rnh_treetop)) == 0) 314 senderr(ESRCH); 315 if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT)) 316 panic ("rtrequest delete"); 317 rt = (struct rtentry *)rn; 318 rt->rt_flags &= ~RTF_UP; 319 if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest) 320 ifa->ifa_rtrequest(RTM_DELETE, rt, (struct sockaddr *)0); 321 rttrash++; 322 if (rt->rt_refcnt <= 0) 323 rtfree(rt); 324 break; 325 326 case RTM_ADD: 327 if ((flags & RTF_GATEWAY) == 0) { 328 /* 329 * If we are adding a route to an interface, 330 * and the interface is a pt to pt link 331 * we should search for the destination 332 * as our clue to the interface. Otherwise 333 * we can use the local address. 334 */ 335 ifa = 0; 336 if (flags & RTF_HOST) 337 ifa = ifa_ifwithdstaddr(dst); 338 if (ifa == 0) 339 ifa = ifa_ifwithaddr(gateway); 340 } else { 341 /* 342 * If we are adding a route to a remote net 343 * or host, the gateway may still be on the 344 * other end of a pt to pt link. 345 */ 346 ifa = ifa_ifwithdstaddr(gateway); 347 } 348 if (ifa == 0) { 349 ifa = ifa_ifwithnet(gateway); 350 if (ifa == 0 && req == RTM_ADD) 351 senderr(ENETUNREACH); 352 } 353 len = sizeof (*rt) + ROUNDUP(gateway->sa_len) 354 + ROUNDUP(dst->sa_len) + ROUNDUP(ifa->ifa_llinfolen); 355 R_Malloc(rt, struct rtentry *, len); 356 if (rt == 0) 357 senderr(ENOBUFS); 358 Bzero(rt, len); 359 ndst = (struct sockaddr *)(rt + 1); 360 if (netmask) { 361 rt_maskedcopy(dst, ndst, netmask); 362 } else 363 Bcopy(dst, ndst, dst->sa_len); 364 rn = rn_addroute((caddr_t)ndst, (caddr_t)netmask, 365 rnh->rnh_treetop, rt->rt_nodes); 366 if (rn == 0) { 367 free((caddr_t)rt, M_RTABLE); 368 senderr(EEXIST); 369 } 370 rt->rt_ifp = ifa->ifa_ifp; 371 rt->rt_ifa = ifa; 372 if (ret_nrt) { 373 *ret_nrt = rt; 374 rt->rt_refcnt++; 375 } 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) + (caddr_t)gateway; 382 if (ifa->ifa_rtrequest) 383 ifa->ifa_rtrequest(RTM_ADD, rt, (struct sockaddr *)0); 384 break; 385 } 386 bad: 387 splx(s); 388 return (error); 389 } 390 391 rt_maskedcopy(src, dst, netmask) 392 struct sockaddr *src, *dst, *netmask; 393 { 394 register caddr_t cp1 = (caddr_t)src, cp2 = (caddr_t)dst, 395 cp3 = 2 + (caddr_t)netmask, cplim = cp1 + *(u_char *)cp1; 396 397 *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */ 398 while (cp1 < cplim) 399 *cp2++ = *cp1++ & *cp3++; 400 } 401 /* 402 * Set up a routing table entry, normally 403 * for an interface. 404 */ 405 rtinit(ifa, cmd, flags) 406 register struct ifaddr *ifa; 407 int cmd, flags; 408 { 409 return rtrequest(cmd, ifa->ifa_dstaddr, ifa->ifa_addr, 410 ifa->ifa_netmask, flags | ifa->ifa_flags, &ifa->ifa_rt); 411 } 412