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.7 (Berkeley) 11/09/88 18 */ 19 20 #include "param.h" 21 #include "systm.h" 22 #include "mbuf.h" 23 #include "protosw.h" 24 #include "socket.h" 25 #include "dir.h" 26 #include "user.h" 27 #include "ioctl.h" 28 #include "errno.h" 29 30 #include "if.h" 31 #include "af.h" 32 #include "route.h" 33 #include "radix.h" 34 35 #include "radix.c" 36 #ifdef INET 37 #include "../netinet/in.h" 38 #include "../netinet/in_var.h" 39 #endif 40 41 int rttrash; /* routes not in table but not freed */ 42 struct sockaddr wildcard; /* zero valued cookie for wildcard searches */ 43 int rthashsize = RTHASHSIZ; /* for netstat, etc. */ 44 45 static int rtinits_done = 0; 46 struct radix_node_head *ns_rnhead, *in_rnhead; 47 rtinitheads() 48 { 49 if (rtinits_done == 0 && 50 rn_inithead(&ns_rnhead, 16, AF_NS) && 51 rn_inithead(&in_rnhead, 32, AF_INET)) 52 rtinits_done = 1; 53 } 54 55 /* 56 * Packet routing routines. 57 */ 58 rtalloc(ro) 59 register struct route *ro; 60 { 61 register struct radix_node_head *rnh; 62 register struct radix_node *rn; 63 register struct rtentry *rt = 0; 64 u_char af = ro->ro_dst.sa_family; 65 int s; 66 67 if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP)) 68 return; /* XXX */ 69 s = splnet(); 70 for (rnh = radix_node_head; rnh && (af != rnh->rnh_af); ) 71 rnh = rnh->rnh_next; 72 if (rnh && rnh->rnh_treetop && 73 (rn = rn_match((char *)&(ro->ro_dst), rnh->rnh_treetop)) && 74 ((rn->rn_flags & RNF_ROOT) == 0)) { 75 rt = &(((struct nrtentry *)rn)->nrt_rt); 76 rt->rt_refcnt++; 77 } else 78 rtstat.rts_unreach++; 79 ro->ro_rt = rt; 80 splx(s); 81 } 82 83 rtfree(rt) 84 register struct rtentry *rt; 85 { 86 register struct nrtentry *nrt; 87 u_char *af; 88 if (rt == 0) 89 panic("rtfree"); 90 rt->rt_refcnt--; 91 if (rt->rt_refcnt <= 0 && (rt->rt_flags&RTF_UP) == 0) { 92 rttrash--; 93 nrt = (struct nrtentry *) (((struct radix_node *)rt) - 2); 94 if (nrt->nrt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT)) 95 panic ("rtfree 2"); 96 free((caddr_t)nrt, M_RTABLE); 97 } 98 } 99 100 /* 101 * Force a routing table entry to the specified 102 * destination to go through the given gateway. 103 * Normally called as a result of a routing redirect 104 * message from the network layer. 105 * 106 * N.B.: must be called at splnet 107 * 108 */ 109 rtredirect(dst, gateway, flags, src) 110 struct sockaddr *dst, *gateway, *src; 111 int flags; 112 { 113 struct route ro; 114 register struct rtentry *rt; 115 116 /* verify the gateway is directly reachable */ 117 if (ifa_ifwithnet(gateway) == 0) { 118 rtstat.rts_badredirect++; 119 return; 120 } 121 ro.ro_dst = *dst; 122 ro.ro_rt = 0; 123 rtalloc(&ro); 124 rt = ro.ro_rt; 125 #define equal(a1, a2) \ 126 (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0) 127 /* 128 * If the redirect isn't from our current router for this dst, 129 * it's either old or wrong. If it redirects us to ourselves, 130 * we have a routing loop, perhaps as a result of an interface 131 * going down recently. 132 */ 133 if ((rt && !equal(src, &rt->rt_gateway)) || ifa_ifwithaddr(gateway)) { 134 rtstat.rts_badredirect++; 135 if (rt) 136 rtfree(rt); 137 return; 138 } 139 /* 140 * Old comment: 141 * Create a new entry if we just got back a wildcard entry 142 * or the the lookup failed. This is necessary for hosts 143 * which use routing redirects generated by smart gateways 144 * to dynamically build the routing tables. 145 * 146 * New comment: 147 * If we survived the previous tests, it doesn't matter 148 * what sort of entry we got when we looked it up; 149 * we should just go ahead and free the reference to 150 * the route we created. rtalloc will not give a 151 * pointer to the root node. And if we got a pointer 152 * to a default gateway, we should free the reference 153 * in any case. 154 if (rt) { 155 rtfree(rt); 156 rt = 0; 157 } 158 */ 159 if (rt == 0) { 160 rtinit(dst, gateway, (int)SIOCADDRT, 161 (flags & RTF_HOST) | RTF_GATEWAY | RTF_DYNAMIC); 162 rtstat.rts_dynamic++; 163 return; 164 } 165 /* 166 * Don't listen to the redirect if it's 167 * for a route to an interface. 168 */ 169 if (rt->rt_flags & RTF_GATEWAY) { 170 if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) { 171 /* 172 * Changing from route to net => route to host. 173 * Create new route, rather than smashing route to net. 174 */ 175 rtinit(dst, gateway, (int)SIOCADDRT, 176 flags | RTF_DYNAMIC); 177 rtstat.rts_dynamic++; 178 } else { 179 /* 180 * Smash the current notion of the gateway to 181 * this destination. 182 */ 183 rt->rt_gateway = *gateway; /*XXX -- size? */ 184 rt->rt_flags |= RTF_MODIFIED; 185 rtstat.rts_newgateway++; 186 } 187 } else 188 rtstat.rts_badredirect++; 189 rtfree(rt); 190 } 191 192 /* 193 * Routing table ioctl interface. 194 */ 195 rtioctl(cmd, data) 196 int cmd; 197 caddr_t data; 198 { 199 200 if (cmd != SIOCADDRT && cmd != SIOCDELRT) 201 return (EINVAL); 202 if (!suser()) 203 return (u.u_error); 204 return (rtrequest(cmd, (struct rtentry *)data)); 205 } 206 /* 207 * This routine will go away soon. 208 * Tries to guess which netmask is appropriate for a given net. 209 */ 210 static struct sockaddr_in rtgmask = { 8, 0 }; 211 212 char * 213 rtgetmask(sa, ifa) 214 register struct sockaddr *sa; 215 register struct ifaddr *ifa; 216 { 217 u_long i, net, mask, subnet; 218 219 switch (sa->sa_family) { 220 #ifdef INET 221 register struct in_ifaddr *ia; 222 223 case AF_INET: 224 225 i = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr); 226 if (i == 0) { 227 rtgmask.sin_addr.s_addr = 0; 228 return ((char *)&rtgmask); 229 } else if (IN_CLASSA(i)) { 230 net = i & IN_CLASSA_NET; 231 mask = IN_CLASSA_NET; 232 } else if (IN_CLASSB(i)) { 233 net = i & IN_CLASSB_NET; 234 mask = IN_CLASSB_NET; 235 } else if (IN_CLASSC(i)) { 236 net = i & IN_CLASSC_NET; 237 mask = IN_CLASSC_NET; 238 } else { 239 net = i; 240 mask = 0xffffffff; 241 } 242 243 /* 244 * Check whether network is a subnet; 245 * if so, return subnet number. 246 */ 247 for (ia = in_ifaddr; ia; ia = ia->ia_next) 248 if (net == ia->ia_net) { 249 ifa = &ia->ia_ifa; 250 break; 251 } 252 if (ia == 0) { 253 rtgmask.sin_addr.s_addr = ntohl(mask); 254 return ((char *)&rtgmask); 255 } 256 #endif 257 } 258 return ((char *)ifa->ifa_netmask); 259 } 260 261 /* 262 * Carry out a request to change the routing table. Called by 263 * interfaces at boot time to make their ``local routes'' known, 264 * for ioctl's, and as the result of routing redirects. 265 */ 266 rtrequest(req, entry) 267 int req; 268 register struct rtentry *entry; 269 { 270 register struct rtentry *rt; 271 int s, error = 0, found; 272 u_char af; 273 struct ifaddr *ifa; 274 struct ifaddr *ifa_ifwithdstaddr(); 275 register struct nrtentry *nrt; 276 register struct radix_node *rn; 277 register struct radix_node_head *rnh; 278 struct radix_node *head; 279 char *netmask; 280 281 #ifdef COMPAT_43 282 #if BYTE_ORDER != BIG_ENDIAN 283 s = splnet(); 284 if (entry->rt_dst.sa_family == 0 && entry->rt_dst.sa_len < 16) { 285 entry->rt_dst.sa_family = entry->rt_dst.sa_len; 286 entry->rt_dst.sa_len = 16; 287 } 288 if (entry->rt_gateway.sa_family == 0 && entry->rt_gateway.sa_len < 16) { 289 entry->rt_gateway.sa_family = entry->rt_gateway.sa_len; 290 entry->rt_gateway.sa_len = 16; 291 } 292 #else 293 if (entry->rt_dst.sa_len == 0) 294 entry->rt_dst.sa_len = 16; 295 if (entry->rt_gateway.sa_len == 0) 296 entry->rt_gateway.sa_len = 16; 297 #endif 298 #endif 299 if (rtinits_done == 0) 300 rtinitheads(); 301 af = entry->rt_dst.sa_family; 302 for (rnh = radix_node_head; rnh && (af != rnh->rnh_af); ) 303 rnh = rnh->rnh_next; 304 if (rnh == 0) { 305 error = ESRCH; 306 goto bad; 307 } 308 head = rnh->rnh_treetop; 309 if ((entry->rt_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 (entry->rt_flags & RTF_HOST) 319 ifa = ifa_ifwithdstaddr(&entry->rt_dst); 320 if (ifa == 0) 321 ifa = ifa_ifwithaddr(&entry->rt_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(&entry->rt_gateway); 329 } 330 if (ifa == 0) { 331 ifa = ifa_ifwithnet(&entry->rt_gateway); 332 if (ifa == 0 && req == SIOCADDRT) { 333 error = ENETUNREACH; 334 goto bad; 335 } 336 } 337 if (entry->rt_flags & RTF_HOST) 338 netmask = 0; 339 else 340 netmask = rtgetmask(&entry->rt_dst, ifa); 341 switch (req) { 342 343 case SIOCDELRT: 344 if ((rn = rn_delete((char *)&entry->rt_dst, 345 netmask, head)) == 0) { 346 error = ESRCH; 347 goto bad; 348 } 349 if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT)) 350 panic ("rtrequest delete"); 351 nrt = (struct nrtentry *)rn; 352 nrt->nrt_rt.rt_flags &= ~RTF_UP; 353 if (nrt->nrt_rt.rt_refcnt > 0) 354 rttrash++; 355 else 356 free((caddr_t)nrt, M_RTABLE); 357 break; 358 359 case SIOCADDRT: 360 Malloc(nrt, struct nrtentry *, sizeof *nrt); 361 if (nrt == 0) { 362 error = ENOBUFS; 363 goto bad; 364 } 365 Bzero(nrt, sizeof *nrt); 366 rn = rn_addroute((char *)&entry->rt_dst, netmask, 367 head, nrt->nrt_nodes); 368 if (rn == 0) { 369 free((caddr_t)nrt, M_RTABLE); 370 error = EEXIST; 371 goto bad; 372 } 373 rt = &nrt->nrt_rt; 374 rn->rn_key = (char *)&(nrt->nrt_rt.rt_dst); 375 rt->rt_dst = entry->rt_dst; 376 rt->rt_gateway = entry->rt_gateway; 377 rt->rt_flags = RTF_UP | 378 (entry->rt_flags & (RTF_HOST|RTF_GATEWAY|RTF_DYNAMIC)); 379 rt->rt_use = 0; 380 rt->rt_refcnt = 0; 381 rt->rt_ifp = ifa->ifa_ifp; 382 break; 383 } 384 bad: 385 splx(s); 386 return (error); 387 } 388 389 /* 390 * Set up a routing table entry, normally 391 * for an interface. 392 */ 393 rtinit(dst, gateway, cmd, flags) 394 struct sockaddr *dst, *gateway; 395 int cmd, flags; 396 { 397 struct rtentry route; 398 399 bzero((caddr_t)&route, sizeof (route)); 400 route.rt_dst = *dst; 401 route.rt_gateway = *gateway; 402 route.rt_flags = flags; 403 (void) rtrequest(cmd, &route); 404 } 405