1 /* $NetBSD: rtsock.c,v 1.134 2011/02/10 07:42:18 kefren Exp $ */ 2 3 /* 4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the project nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 /* 33 * Copyright (c) 1988, 1991, 1993 34 * The Regents of the University of California. All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 3. Neither the name of the University nor the names of its contributors 45 * may be used to endorse or promote products derived from this software 46 * without specific prior written permission. 47 * 48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 * SUCH DAMAGE. 59 * 60 * @(#)rtsock.c 8.7 (Berkeley) 10/12/95 61 */ 62 63 #include <sys/cdefs.h> 64 __KERNEL_RCSID(0, "$NetBSD: rtsock.c,v 1.134 2011/02/10 07:42:18 kefren Exp $"); 65 66 #ifdef _KERNEL_OPT 67 #include "opt_inet.h" 68 #include "opt_mpls.h" 69 #include "opt_compat_netbsd.h" 70 #endif 71 72 #include <sys/param.h> 73 #include <sys/systm.h> 74 #include <sys/proc.h> 75 #include <sys/mbuf.h> 76 #include <sys/socket.h> 77 #include <sys/socketvar.h> 78 #include <sys/domain.h> 79 #include <sys/protosw.h> 80 #include <sys/sysctl.h> 81 #include <sys/kauth.h> 82 #include <sys/intr.h> 83 #ifdef RTSOCK_DEBUG 84 #include <netinet/in.h> 85 #endif /* RTSOCK_DEBUG */ 86 87 #include <net/if.h> 88 #include <net/route.h> 89 #include <net/raw_cb.h> 90 91 #include <netmpls/mpls.h> 92 93 #if defined(COMPAT_14) || defined(COMPAT_50) 94 #include <compat/net/if.h> 95 #include <compat/net/route.h> 96 #endif 97 #ifdef COMPAT_RTSOCK 98 #define RTM_XVERSION RTM_OVERSION 99 #define RT_XADVANCE(a,b) RT_OADVANCE(a,b) 100 #define RT_XROUNDUP(n) RT_OROUNDUP(n) 101 #define PF_XROUTE PF_OROUTE 102 #define rt_xmsghdr rt_msghdr50 103 #define if_xmsghdr if_msghdr /* if_msghdr50 is for RTM_OIFINFO */ 104 #define ifa_xmsghdr ifa_msghdr50 105 #define if_xannouncemsghdr if_announcemsghdr50 106 #define COMPATNAME(x) compat_50_ ## x 107 #define DOMAINNAME "oroute" 108 CTASSERT(sizeof(struct ifa_xmsghdr) == 20); 109 DOMAIN_DEFINE(compat_50_routedomain); /* forward declare and add to link set */ 110 #else 111 #define RTM_XVERSION RTM_VERSION 112 #define RT_XADVANCE(a,b) RT_ADVANCE(a,b) 113 #define RT_XROUNDUP(n) RT_ROUNDUP(n) 114 #define PF_XROUTE PF_ROUTE 115 #define rt_xmsghdr rt_msghdr 116 #define if_xmsghdr if_msghdr 117 #define ifa_xmsghdr ifa_msghdr 118 #define if_xannouncemsghdr if_announcemsghdr 119 #define COMPATNAME(x) x 120 #define DOMAINNAME "route" 121 CTASSERT(sizeof(struct ifa_xmsghdr) == 24); 122 #ifdef COMPAT_50 123 #define COMPATCALL(name, args) compat_50_ ## name args 124 #endif 125 DOMAIN_DEFINE(routedomain); /* forward declare and add to link set */ 126 #undef COMPAT_50 127 #undef COMPAT_14 128 #endif 129 130 #ifndef COMPATCALL 131 #define COMPATCALL(name, args) do { } while (/*CONSTCOND*/ 0) 132 #endif 133 134 #include <machine/stdarg.h> 135 136 struct route_info COMPATNAME(route_info) = { 137 .ri_dst = { .sa_len = 2, .sa_family = PF_XROUTE, }, 138 .ri_src = { .sa_len = 2, .sa_family = PF_XROUTE, }, 139 .ri_maxqlen = IFQ_MAXLEN, 140 }; 141 142 #define PRESERVED_RTF (RTF_UP | RTF_GATEWAY | RTF_HOST | RTF_DONE | RTF_MASK) 143 144 static void COMPATNAME(route_init)(void); 145 static int COMPATNAME(route_output)(struct mbuf *, ...); 146 static int COMPATNAME(route_usrreq)(struct socket *, 147 int, struct mbuf *, struct mbuf *, struct mbuf *, struct lwp *); 148 149 static int rt_msg2(int, struct rt_addrinfo *, void *, struct rt_walkarg *, int *); 150 static int rt_xaddrs(u_char, const char *, const char *, struct rt_addrinfo *); 151 static struct mbuf *rt_makeifannouncemsg(struct ifnet *, int, int, 152 struct rt_addrinfo *); 153 static void rt_setmetrics(int, const struct rt_xmsghdr *, struct rtentry *); 154 static void rtm_setmetrics(const struct rtentry *, struct rt_xmsghdr *); 155 static void sysctl_net_route_setup(struct sysctllog **); 156 static int sysctl_dumpentry(struct rtentry *, void *); 157 static int sysctl_iflist(int, struct rt_walkarg *, int); 158 static int sysctl_rtable(SYSCTLFN_PROTO); 159 static void rt_adjustcount(int, int); 160 161 static void 162 rt_adjustcount(int af, int cnt) 163 { 164 struct route_cb * const cb = &COMPATNAME(route_info).ri_cb; 165 166 cb->any_count += cnt; 167 168 switch (af) { 169 case AF_INET: 170 cb->ip_count += cnt; 171 return; 172 #ifdef INET6 173 case AF_INET6: 174 cb->ip6_count += cnt; 175 return; 176 #endif 177 case AF_ISO: 178 cb->iso_count += cnt; 179 return; 180 case AF_MPLS: 181 cb->mpls_count += cnt; 182 return; 183 } 184 } 185 186 /*ARGSUSED*/ 187 int 188 COMPATNAME(route_usrreq)(struct socket *so, int req, struct mbuf *m, struct mbuf *nam, 189 struct mbuf *control, struct lwp *l) 190 { 191 int error = 0; 192 struct rawcb *rp = sotorawcb(so); 193 int s; 194 195 if (req == PRU_ATTACH) { 196 sosetlock(so); 197 rp = malloc(sizeof(*rp), M_PCB, M_WAITOK|M_ZERO); 198 so->so_pcb = rp; 199 } 200 if (req == PRU_DETACH && rp) 201 rt_adjustcount(rp->rcb_proto.sp_protocol, -1); 202 s = splsoftnet(); 203 204 /* 205 * Don't call raw_usrreq() in the attach case, because 206 * we want to allow non-privileged processes to listen on 207 * and send "safe" commands to the routing socket. 208 */ 209 if (req == PRU_ATTACH) { 210 if (l == NULL) 211 error = EACCES; 212 else 213 error = raw_attach(so, (int)(long)nam); 214 } else 215 error = raw_usrreq(so, req, m, nam, control, l); 216 217 rp = sotorawcb(so); 218 if (req == PRU_ATTACH && rp) { 219 if (error) { 220 free(rp, M_PCB); 221 splx(s); 222 return error; 223 } 224 rt_adjustcount(rp->rcb_proto.sp_protocol, 1); 225 rp->rcb_laddr = &COMPATNAME(route_info).ri_src; 226 rp->rcb_faddr = &COMPATNAME(route_info).ri_dst; 227 soisconnected(so); 228 so->so_options |= SO_USELOOPBACK; 229 } 230 splx(s); 231 return error; 232 } 233 234 static const struct sockaddr * 235 intern_netmask(const struct sockaddr *mask) 236 { 237 struct radix_node *rn; 238 extern struct radix_node_head *mask_rnhead; 239 240 if (mask != NULL && 241 (rn = rn_search(mask, mask_rnhead->rnh_treetop))) 242 mask = (const struct sockaddr *)rn->rn_key; 243 244 return mask; 245 } 246 247 /*ARGSUSED*/ 248 int 249 COMPATNAME(route_output)(struct mbuf *m, ...) 250 { 251 struct sockproto proto = { .sp_family = PF_XROUTE, }; 252 struct rt_xmsghdr *rtm = NULL; 253 struct rt_xmsghdr *old_rtm = NULL; 254 struct rtentry *rt = NULL; 255 struct rtentry *saved_nrt = NULL; 256 struct rt_addrinfo info; 257 int len, error = 0; 258 struct ifnet *ifp = NULL; 259 struct ifaddr *ifa = NULL; 260 struct socket *so; 261 va_list ap; 262 sa_family_t family; 263 264 va_start(ap, m); 265 so = va_arg(ap, struct socket *); 266 va_end(ap); 267 268 #define senderr(e) do { error = e; goto flush;} while (/*CONSTCOND*/ 0) 269 if (m == NULL || ((m->m_len < sizeof(int32_t)) && 270 (m = m_pullup(m, sizeof(int32_t))) == NULL)) 271 return ENOBUFS; 272 if ((m->m_flags & M_PKTHDR) == 0) 273 panic("%s", __func__); 274 len = m->m_pkthdr.len; 275 if (len < sizeof(*rtm) || 276 len != mtod(m, struct rt_xmsghdr *)->rtm_msglen) { 277 info.rti_info[RTAX_DST] = NULL; 278 senderr(EINVAL); 279 } 280 R_Malloc(rtm, struct rt_xmsghdr *, len); 281 if (rtm == NULL) { 282 info.rti_info[RTAX_DST] = NULL; 283 senderr(ENOBUFS); 284 } 285 m_copydata(m, 0, len, rtm); 286 if (rtm->rtm_version != RTM_XVERSION) { 287 info.rti_info[RTAX_DST] = NULL; 288 senderr(EPROTONOSUPPORT); 289 } 290 rtm->rtm_pid = curproc->p_pid; 291 memset(&info, 0, sizeof(info)); 292 info.rti_addrs = rtm->rtm_addrs; 293 if (rt_xaddrs(rtm->rtm_type, (const char *)(rtm + 1), len + (char *)rtm, 294 &info)) { 295 senderr(EINVAL); 296 } 297 info.rti_flags = rtm->rtm_flags; 298 #ifdef RTSOCK_DEBUG 299 if (info.rti_info[RTAX_DST]->sa_family == AF_INET) { 300 printf("%s: extracted info.rti_info[RTAX_DST] %s\n", __func__, 301 inet_ntoa(((const struct sockaddr_in *) 302 info.rti_info[RTAX_DST])->sin_addr)); 303 } 304 #endif /* RTSOCK_DEBUG */ 305 if (info.rti_info[RTAX_DST] == NULL || 306 (info.rti_info[RTAX_DST]->sa_family >= AF_MAX)) { 307 senderr(EINVAL); 308 } 309 if (info.rti_info[RTAX_GATEWAY] != NULL && 310 (info.rti_info[RTAX_GATEWAY]->sa_family >= AF_MAX)) { 311 senderr(EINVAL); 312 } 313 314 /* 315 * Verify that the caller has the appropriate privilege; RTM_GET 316 * is the only operation the non-superuser is allowed. 317 */ 318 if (kauth_authorize_network(curlwp->l_cred, KAUTH_NETWORK_ROUTE, 319 0, rtm, NULL, NULL) != 0) 320 senderr(EACCES); 321 322 switch (rtm->rtm_type) { 323 324 case RTM_ADD: 325 if (info.rti_info[RTAX_GATEWAY] == NULL) { 326 senderr(EINVAL); 327 } 328 error = rtrequest1(rtm->rtm_type, &info, &saved_nrt); 329 if (error == 0 && saved_nrt) { 330 rt_setmetrics(rtm->rtm_inits, rtm, saved_nrt); 331 saved_nrt->rt_refcnt--; 332 } 333 break; 334 335 case RTM_DELETE: 336 error = rtrequest1(rtm->rtm_type, &info, &saved_nrt); 337 if (error == 0) { 338 (rt = saved_nrt)->rt_refcnt++; 339 goto report; 340 } 341 break; 342 343 case RTM_GET: 344 case RTM_CHANGE: 345 case RTM_LOCK: 346 /* XXX This will mask info.rti_info[RTAX_DST] with 347 * info.rti_info[RTAX_NETMASK] before 348 * searching. It did not used to do that. --dyoung 349 */ 350 error = rtrequest1(RTM_GET, &info, &rt); 351 if (error != 0) 352 senderr(error); 353 if (rtm->rtm_type != RTM_GET) {/* XXX: too grotty */ 354 struct radix_node *rn; 355 356 if (memcmp(info.rti_info[RTAX_DST], rt_getkey(rt), 357 info.rti_info[RTAX_DST]->sa_len) != 0) 358 senderr(ESRCH); 359 info.rti_info[RTAX_NETMASK] = intern_netmask( 360 info.rti_info[RTAX_NETMASK]); 361 for (rn = rt->rt_nodes; rn; rn = rn->rn_dupedkey) 362 if (info.rti_info[RTAX_NETMASK] == 363 (const struct sockaddr *)rn->rn_mask) 364 break; 365 if (rn == NULL) 366 senderr(ETOOMANYREFS); 367 rt = (struct rtentry *)rn; 368 } 369 370 switch (rtm->rtm_type) { 371 case RTM_GET: 372 report: 373 info.rti_info[RTAX_DST] = rt_getkey(rt); 374 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 375 info.rti_info[RTAX_NETMASK] = rt_mask(rt); 376 info.rti_info[RTAX_TAG] = (struct sockaddr*)rt_gettag(rt); 377 if ((rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) == 0) 378 ; 379 else if ((ifp = rt->rt_ifp) != NULL) { 380 const struct ifaddr *rtifa; 381 info.rti_info[RTAX_IFP] = ifp->if_dl->ifa_addr; 382 /* rtifa used to be simply rt->rt_ifa. 383 * If rt->rt_ifa != NULL, then 384 * rt_get_ifa() != NULL. So this 385 * ought to still be safe. --dyoung 386 */ 387 rtifa = rt_get_ifa(rt); 388 info.rti_info[RTAX_IFA] = rtifa->ifa_addr; 389 #ifdef RTSOCK_DEBUG 390 if (info.rti_info[RTAX_IFA]->sa_family == 391 AF_INET) { 392 printf("%s: copying out RTAX_IFA %s ", 393 __func__, inet_ntoa( 394 ((const struct sockaddr_in *) 395 info.rti_info[RTAX_IFA])->sin_addr) 396 ); 397 printf("for info.rti_info[RTAX_DST] %s " 398 "ifa_getifa %p ifa_seqno %p\n", 399 inet_ntoa( 400 ((const struct sockaddr_in *) 401 info.rti_info[RTAX_DST])->sin_addr), 402 (void *)rtifa->ifa_getifa, 403 rtifa->ifa_seqno); 404 } 405 #endif /* RTSOCK_DEBUG */ 406 if (ifp->if_flags & IFF_POINTOPOINT) { 407 info.rti_info[RTAX_BRD] = 408 rtifa->ifa_dstaddr; 409 } else 410 info.rti_info[RTAX_BRD] = NULL; 411 rtm->rtm_index = ifp->if_index; 412 } else { 413 info.rti_info[RTAX_IFP] = NULL; 414 info.rti_info[RTAX_IFA] = NULL; 415 } 416 (void)rt_msg2(rtm->rtm_type, &info, NULL, NULL, &len); 417 if (len > rtm->rtm_msglen) { 418 old_rtm = rtm; 419 R_Malloc(rtm, struct rt_xmsghdr *, len); 420 if (rtm == NULL) 421 senderr(ENOBUFS); 422 (void)memcpy(rtm, old_rtm, old_rtm->rtm_msglen); 423 } 424 (void)rt_msg2(rtm->rtm_type, &info, rtm, NULL, 0); 425 rtm->rtm_flags = rt->rt_flags; 426 rtm_setmetrics(rt, rtm); 427 rtm->rtm_addrs = info.rti_addrs; 428 break; 429 430 case RTM_CHANGE: 431 /* 432 * new gateway could require new ifaddr, ifp; 433 * flags may also be different; ifp may be specified 434 * by ll sockaddr when protocol address is ambiguous 435 */ 436 if ((error = rt_getifa(&info)) != 0) 437 senderr(error); 438 if (info.rti_info[RTAX_GATEWAY] && 439 rt_setgate(rt, info.rti_info[RTAX_GATEWAY])) 440 senderr(EDQUOT); 441 if (info.rti_info[RTAX_TAG]) 442 rt_settag(rt, info.rti_info[RTAX_TAG]); 443 /* new gateway could require new ifaddr, ifp; 444 flags may also be different; ifp may be specified 445 by ll sockaddr when protocol address is ambiguous */ 446 if (info.rti_info[RTAX_IFP] && 447 (ifa = ifa_ifwithnet(info.rti_info[RTAX_IFP])) && 448 (ifp = ifa->ifa_ifp) && (info.rti_info[RTAX_IFA] || 449 info.rti_info[RTAX_GATEWAY])) { 450 if (info.rti_info[RTAX_IFA] == NULL || 451 (ifa = ifa_ifwithaddr( 452 info.rti_info[RTAX_IFA])) == NULL) 453 ifa = ifaof_ifpforaddr( 454 info.rti_info[RTAX_IFA] ? 455 info.rti_info[RTAX_IFA] : 456 info.rti_info[RTAX_GATEWAY], ifp); 457 } else if ((info.rti_info[RTAX_IFA] && 458 (ifa = ifa_ifwithaddr(info.rti_info[RTAX_IFA]))) || 459 (info.rti_info[RTAX_GATEWAY] && 460 (ifa = ifa_ifwithroute(rt->rt_flags, 461 rt_getkey(rt), info.rti_info[RTAX_GATEWAY])))) { 462 ifp = ifa->ifa_ifp; 463 } 464 if (ifa) { 465 struct ifaddr *oifa = rt->rt_ifa; 466 if (oifa != ifa) { 467 if (oifa && oifa->ifa_rtrequest) { 468 oifa->ifa_rtrequest(RTM_DELETE, 469 rt, &info); 470 } 471 rt_replace_ifa(rt, ifa); 472 rt->rt_ifp = ifp; 473 } 474 } 475 if (ifp && rt->rt_ifp != ifp) 476 rt->rt_ifp = ifp; 477 rt_setmetrics(rtm->rtm_inits, rtm, rt); 478 if (rt->rt_flags != info.rti_flags) 479 rt->rt_flags = (info.rti_flags & ~PRESERVED_RTF) 480 | (rt->rt_flags & PRESERVED_RTF); 481 if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) 482 rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, &info); 483 /*FALLTHROUGH*/ 484 case RTM_LOCK: 485 rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits); 486 rt->rt_rmx.rmx_locks |= 487 (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); 488 break; 489 } 490 break; 491 492 default: 493 senderr(EOPNOTSUPP); 494 } 495 496 flush: 497 if (rtm) { 498 if (error) 499 rtm->rtm_errno = error; 500 else 501 rtm->rtm_flags |= RTF_DONE; 502 } 503 family = info.rti_info[RTAX_DST] ? info.rti_info[RTAX_DST]->sa_family : 504 0; 505 /* We cannot free old_rtm until we have stopped using the 506 * pointers in info, some of which may point to sockaddrs 507 * in old_rtm. 508 */ 509 if (old_rtm != NULL) 510 Free(old_rtm); 511 if (rt) 512 rtfree(rt); 513 { 514 struct rawcb *rp = NULL; 515 /* 516 * Check to see if we don't want our own messages. 517 */ 518 if ((so->so_options & SO_USELOOPBACK) == 0) { 519 if (COMPATNAME(route_info).ri_cb.any_count <= 1) { 520 if (rtm) 521 Free(rtm); 522 m_freem(m); 523 return error; 524 } 525 /* There is another listener, so construct message */ 526 rp = sotorawcb(so); 527 } 528 if (rtm) { 529 m_copyback(m, 0, rtm->rtm_msglen, rtm); 530 if (m->m_pkthdr.len < rtm->rtm_msglen) { 531 m_freem(m); 532 m = NULL; 533 } else if (m->m_pkthdr.len > rtm->rtm_msglen) 534 m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len); 535 Free(rtm); 536 } 537 if (rp) 538 rp->rcb_proto.sp_family = 0; /* Avoid us */ 539 if (family) 540 proto.sp_protocol = family; 541 if (m) 542 raw_input(m, &proto, &COMPATNAME(route_info).ri_src, 543 &COMPATNAME(route_info).ri_dst); 544 if (rp) 545 rp->rcb_proto.sp_family = PF_XROUTE; 546 } 547 return error; 548 } 549 550 static void 551 rt_setmetrics(int which, const struct rt_xmsghdr *in, struct rtentry *out) 552 { 553 #define metric(f, e) if (which & (f)) out->rt_rmx.e = in->rtm_rmx.e; 554 metric(RTV_RPIPE, rmx_recvpipe); 555 metric(RTV_SPIPE, rmx_sendpipe); 556 metric(RTV_SSTHRESH, rmx_ssthresh); 557 metric(RTV_RTT, rmx_rtt); 558 metric(RTV_RTTVAR, rmx_rttvar); 559 metric(RTV_HOPCOUNT, rmx_hopcount); 560 metric(RTV_MTU, rmx_mtu); 561 metric(RTV_EXPIRE, rmx_expire); 562 #undef metric 563 } 564 565 static void 566 rtm_setmetrics(const struct rtentry *in, struct rt_xmsghdr *out) 567 { 568 #define metric(e) out->rtm_rmx.e = in->rt_rmx.e; 569 metric(rmx_recvpipe); 570 metric(rmx_sendpipe); 571 metric(rmx_ssthresh); 572 metric(rmx_rtt); 573 metric(rmx_rttvar); 574 metric(rmx_hopcount); 575 metric(rmx_mtu); 576 metric(rmx_expire); 577 #undef metric 578 } 579 580 static int 581 rt_xaddrs(u_char rtmtype, const char *cp, const char *cplim, 582 struct rt_addrinfo *rtinfo) 583 { 584 const struct sockaddr *sa = NULL; /* Quell compiler warning */ 585 int i; 586 587 for (i = 0; i < RTAX_MAX && cp < cplim; i++) { 588 if ((rtinfo->rti_addrs & (1 << i)) == 0) 589 continue; 590 rtinfo->rti_info[i] = sa = (const struct sockaddr *)cp; 591 RT_XADVANCE(cp, sa); 592 } 593 594 /* 595 * Check for extra addresses specified, except RTM_GET asking 596 * for interface info. 597 */ 598 if (rtmtype == RTM_GET) { 599 if (((rtinfo->rti_addrs & 600 (~((1 << RTAX_IFP) | (1 << RTAX_IFA)))) & (~0 << i)) != 0) 601 return 1; 602 } else if ((rtinfo->rti_addrs & (~0 << i)) != 0) 603 return 1; 604 /* Check for bad data length. */ 605 if (cp != cplim) { 606 if (i == RTAX_NETMASK + 1 && sa != NULL && 607 cp - RT_XROUNDUP(sa->sa_len) + sa->sa_len == cplim) 608 /* 609 * The last sockaddr was info.rti_info[RTAX_NETMASK]. 610 * We accept this for now for the sake of old 611 * binaries or third party softwares. 612 */ 613 ; 614 else 615 return 1; 616 } 617 return 0; 618 } 619 620 static int 621 rt_getlen(int type) 622 { 623 #ifndef COMPAT_RTSOCK 624 CTASSERT(__alignof(struct ifa_msghdr) >= sizeof(uint64_t)); 625 CTASSERT(__alignof(struct if_msghdr) >= sizeof(uint64_t)); 626 CTASSERT(__alignof(struct if_announcemsghdr) >= sizeof(uint64_t)); 627 CTASSERT(__alignof(struct rt_msghdr) >= sizeof(uint64_t)); 628 #endif 629 630 switch (type) { 631 case RTM_DELADDR: 632 case RTM_NEWADDR: 633 case RTM_CHGADDR: 634 return sizeof(struct ifa_xmsghdr); 635 636 case RTM_OOIFINFO: 637 #ifdef COMPAT_14 638 return sizeof(struct if_msghdr14); 639 #else 640 #ifdef DIAGNOSTIC 641 printf("RTM_OOIFINFO\n"); 642 #endif 643 return -1; 644 #endif 645 case RTM_OIFINFO: 646 #ifdef COMPAT_50 647 return sizeof(struct if_msghdr50); 648 #else 649 #ifdef DIAGNOSTIC 650 printf("RTM_OIFINFO\n"); 651 #endif 652 return -1; 653 #endif 654 655 case RTM_IFINFO: 656 return sizeof(struct if_xmsghdr); 657 658 case RTM_IFANNOUNCE: 659 case RTM_IEEE80211: 660 return sizeof(struct if_xannouncemsghdr); 661 662 default: 663 return sizeof(struct rt_xmsghdr); 664 } 665 } 666 667 668 struct mbuf * 669 COMPATNAME(rt_msg1)(int type, struct rt_addrinfo *rtinfo, void *data, int datalen) 670 { 671 struct rt_xmsghdr *rtm; 672 struct mbuf *m; 673 int i; 674 const struct sockaddr *sa; 675 int len, dlen; 676 677 m = m_gethdr(M_DONTWAIT, MT_DATA); 678 if (m == NULL) 679 return m; 680 MCLAIM(m, &COMPATNAME(routedomain).dom_mowner); 681 682 if ((len = rt_getlen(type)) == -1) 683 goto out; 684 if (len > MHLEN + MLEN) 685 panic("%s: message too long", __func__); 686 else if (len > MHLEN) { 687 m->m_next = m_get(M_DONTWAIT, MT_DATA); 688 if (m->m_next == NULL) 689 goto out; 690 MCLAIM(m->m_next, m->m_owner); 691 m->m_pkthdr.len = len; 692 m->m_len = MHLEN; 693 m->m_next->m_len = len - MHLEN; 694 } else { 695 m->m_pkthdr.len = m->m_len = len; 696 } 697 m->m_pkthdr.rcvif = NULL; 698 m_copyback(m, 0, datalen, data); 699 if (len > datalen) 700 (void)memset(mtod(m, char *) + datalen, 0, len - datalen); 701 rtm = mtod(m, struct rt_xmsghdr *); 702 for (i = 0; i < RTAX_MAX; i++) { 703 if ((sa = rtinfo->rti_info[i]) == NULL) 704 continue; 705 rtinfo->rti_addrs |= (1 << i); 706 dlen = RT_XROUNDUP(sa->sa_len); 707 m_copyback(m, len, sa->sa_len, sa); 708 if (dlen != sa->sa_len) { 709 m_copyback(m, len + sa->sa_len, 710 dlen - sa->sa_len, "\0\0\0\0\0\0"); 711 } 712 len += dlen; 713 } 714 if (m->m_pkthdr.len != len) 715 goto out; 716 rtm->rtm_msglen = len; 717 rtm->rtm_version = RTM_XVERSION; 718 rtm->rtm_type = type; 719 return m; 720 out: 721 m_freem(m); 722 return NULL; 723 } 724 725 /* 726 * rt_msg2 727 * 728 * fills 'cp' or 'w'.w_tmem with the routing socket message and 729 * returns the length of the message in 'lenp'. 730 * 731 * if walkarg is 0, cp is expected to be 0 or a buffer large enough to hold 732 * the message 733 * otherwise walkarg's w_needed is updated and if the user buffer is 734 * specified and w_needed indicates space exists the information is copied 735 * into the temp space (w_tmem). w_tmem is [re]allocated if necessary, 736 * if the allocation fails ENOBUFS is returned. 737 */ 738 static int 739 rt_msg2(int type, struct rt_addrinfo *rtinfo, void *cpv, struct rt_walkarg *w, 740 int *lenp) 741 { 742 int i; 743 int len, dlen, second_time = 0; 744 char *cp0, *cp = cpv; 745 746 rtinfo->rti_addrs = 0; 747 again: 748 if ((len = rt_getlen(type)) == -1) 749 return EINVAL; 750 751 if ((cp0 = cp) != NULL) 752 cp += len; 753 for (i = 0; i < RTAX_MAX; i++) { 754 const struct sockaddr *sa; 755 756 if ((sa = rtinfo->rti_info[i]) == NULL) 757 continue; 758 rtinfo->rti_addrs |= (1 << i); 759 dlen = RT_XROUNDUP(sa->sa_len); 760 if (cp) { 761 (void)memcpy(cp, sa, (size_t)dlen); 762 cp += dlen; 763 } 764 len += dlen; 765 } 766 if (cp == NULL && w != NULL && !second_time) { 767 struct rt_walkarg *rw = w; 768 769 rw->w_needed += len; 770 if (rw->w_needed <= 0 && rw->w_where) { 771 if (rw->w_tmemsize < len) { 772 if (rw->w_tmem) 773 free(rw->w_tmem, M_RTABLE); 774 rw->w_tmem = malloc(len, M_RTABLE, M_NOWAIT); 775 if (rw->w_tmem) 776 rw->w_tmemsize = len; 777 else 778 rw->w_tmemsize = 0; 779 } 780 if (rw->w_tmem) { 781 cp = rw->w_tmem; 782 second_time = 1; 783 goto again; 784 } else { 785 rw->w_tmemneeded = len; 786 return ENOBUFS; 787 } 788 } 789 } 790 if (cp) { 791 struct rt_xmsghdr *rtm = (struct rt_xmsghdr *)cp0; 792 793 rtm->rtm_version = RTM_XVERSION; 794 rtm->rtm_type = type; 795 rtm->rtm_msglen = len; 796 } 797 if (lenp) 798 *lenp = len; 799 return 0; 800 } 801 802 /* 803 * This routine is called to generate a message from the routing 804 * socket indicating that a redirect has occurred, a routing lookup 805 * has failed, or that a protocol has detected timeouts to a particular 806 * destination. 807 */ 808 void 809 COMPATNAME(rt_missmsg)(int type, const struct rt_addrinfo *rtinfo, int flags, 810 int error) 811 { 812 struct rt_xmsghdr rtm; 813 struct mbuf *m; 814 const struct sockaddr *sa = rtinfo->rti_info[RTAX_DST]; 815 struct rt_addrinfo info = *rtinfo; 816 817 COMPATCALL(rt_missmsg, (type, rtinfo, flags, error)); 818 if (COMPATNAME(route_info).ri_cb.any_count == 0) 819 return; 820 memset(&rtm, 0, sizeof(rtm)); 821 rtm.rtm_flags = RTF_DONE | flags; 822 rtm.rtm_errno = error; 823 m = COMPATNAME(rt_msg1)(type, &info, &rtm, sizeof(rtm)); 824 if (m == NULL) 825 return; 826 mtod(m, struct rt_xmsghdr *)->rtm_addrs = info.rti_addrs; 827 COMPATNAME(route_enqueue)(m, sa ? sa->sa_family : 0); 828 } 829 830 /* 831 * This routine is called to generate a message from the routing 832 * socket indicating that the status of a network interface has changed. 833 */ 834 void 835 COMPATNAME(rt_ifmsg)(struct ifnet *ifp) 836 { 837 struct if_xmsghdr ifm; 838 struct mbuf *m; 839 struct rt_addrinfo info; 840 841 COMPATCALL(rt_ifmsg, (ifp)); 842 if (COMPATNAME(route_info).ri_cb.any_count == 0) 843 return; 844 (void)memset(&info, 0, sizeof(info)); 845 (void)memset(&ifm, 0, sizeof(ifm)); 846 ifm.ifm_index = ifp->if_index; 847 ifm.ifm_flags = ifp->if_flags; 848 ifm.ifm_data = ifp->if_data; 849 ifm.ifm_addrs = 0; 850 m = COMPATNAME(rt_msg1)(RTM_IFINFO, &info, &ifm, sizeof(ifm)); 851 if (m == NULL) 852 return; 853 COMPATNAME(route_enqueue)(m, 0); 854 #ifdef COMPAT_14 855 compat_14_rt_oifmsg(ifp); 856 #endif 857 #ifdef COMPAT_50 858 compat_50_rt_oifmsg(ifp); 859 #endif 860 } 861 862 863 /* 864 * This is called to generate messages from the routing socket 865 * indicating a network interface has had addresses associated with it. 866 * if we ever reverse the logic and replace messages TO the routing 867 * socket indicate a request to configure interfaces, then it will 868 * be unnecessary as the routing socket will automatically generate 869 * copies of it. 870 */ 871 void 872 COMPATNAME(rt_newaddrmsg)(int cmd, struct ifaddr *ifa, int error, 873 struct rtentry *rt) 874 { 875 #define cmdpass(__cmd, __pass) (((__cmd) << 2) | (__pass)) 876 struct rt_addrinfo info; 877 const struct sockaddr *sa; 878 int pass; 879 struct mbuf *m; 880 struct ifnet *ifp = ifa->ifa_ifp; 881 struct rt_xmsghdr rtm; 882 struct ifa_xmsghdr ifam; 883 int ncmd; 884 885 COMPATCALL(rt_newaddrmsg, (cmd, ifa, error, rt)); 886 if (COMPATNAME(route_info).ri_cb.any_count == 0) 887 return; 888 for (pass = 1; pass < 3; pass++) { 889 memset(&info, 0, sizeof(info)); 890 switch (cmdpass(cmd, pass)) { 891 case cmdpass(RTM_ADD, 1): 892 case cmdpass(RTM_CHANGE, 1): 893 case cmdpass(RTM_DELETE, 2): 894 switch (cmd) { 895 case RTM_DELETE: 896 ncmd = RTM_DELADDR; 897 break; 898 case RTM_CHANGE: 899 ncmd = RTM_CHGADDR; 900 break; 901 default: 902 ncmd = RTM_NEWADDR; 903 } 904 info.rti_info[RTAX_IFA] = sa = ifa->ifa_addr; 905 info.rti_info[RTAX_IFP] = ifp->if_dl->ifa_addr; 906 info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask; 907 info.rti_info[RTAX_BRD] = ifa->ifa_dstaddr; 908 memset(&ifam, 0, sizeof(ifam)); 909 ifam.ifam_index = ifp->if_index; 910 ifam.ifam_metric = ifa->ifa_metric; 911 ifam.ifam_flags = ifa->ifa_flags; 912 m = COMPATNAME(rt_msg1)(ncmd, &info, &ifam, sizeof(ifam)); 913 if (m == NULL) 914 continue; 915 mtod(m, struct ifa_xmsghdr *)->ifam_addrs = 916 info.rti_addrs; 917 break; 918 case cmdpass(RTM_ADD, 2): 919 case cmdpass(RTM_CHANGE, 2): 920 case cmdpass(RTM_DELETE, 1): 921 if (rt == NULL) 922 continue; 923 info.rti_info[RTAX_NETMASK] = rt_mask(rt); 924 info.rti_info[RTAX_DST] = sa = rt_getkey(rt); 925 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 926 memset(&rtm, 0, sizeof(rtm)); 927 rtm.rtm_index = ifp->if_index; 928 rtm.rtm_flags |= rt->rt_flags; 929 rtm.rtm_errno = error; 930 m = COMPATNAME(rt_msg1)(cmd, &info, &rtm, sizeof(rtm)); 931 if (m == NULL) 932 continue; 933 mtod(m, struct rt_xmsghdr *)->rtm_addrs = info.rti_addrs; 934 break; 935 default: 936 continue; 937 } 938 #ifdef DIAGNOSTIC 939 if (m == NULL) 940 panic("%s: called with wrong command", __func__); 941 #endif 942 COMPATNAME(route_enqueue)(m, sa ? sa->sa_family : 0); 943 } 944 #undef cmdpass 945 } 946 947 static struct mbuf * 948 rt_makeifannouncemsg(struct ifnet *ifp, int type, int what, 949 struct rt_addrinfo *info) 950 { 951 struct if_xannouncemsghdr ifan; 952 953 memset(info, 0, sizeof(*info)); 954 memset(&ifan, 0, sizeof(ifan)); 955 ifan.ifan_index = ifp->if_index; 956 strlcpy(ifan.ifan_name, ifp->if_xname, sizeof(ifan.ifan_name)); 957 ifan.ifan_what = what; 958 return COMPATNAME(rt_msg1)(type, info, &ifan, sizeof(ifan)); 959 } 960 961 /* 962 * This is called to generate routing socket messages indicating 963 * network interface arrival and departure. 964 */ 965 void 966 COMPATNAME(rt_ifannouncemsg)(struct ifnet *ifp, int what) 967 { 968 struct mbuf *m; 969 struct rt_addrinfo info; 970 971 COMPATCALL(rt_ifannouncemsg, (ifp, what)); 972 if (COMPATNAME(route_info).ri_cb.any_count == 0) 973 return; 974 m = rt_makeifannouncemsg(ifp, RTM_IFANNOUNCE, what, &info); 975 if (m == NULL) 976 return; 977 COMPATNAME(route_enqueue)(m, 0); 978 } 979 980 /* 981 * This is called to generate routing socket messages indicating 982 * IEEE80211 wireless events. 983 * XXX we piggyback on the RTM_IFANNOUNCE msg format in a clumsy way. 984 */ 985 void 986 COMPATNAME(rt_ieee80211msg)(struct ifnet *ifp, int what, void *data, 987 size_t data_len) 988 { 989 struct mbuf *m; 990 struct rt_addrinfo info; 991 992 COMPATCALL(rt_ieee80211msg, (ifp, what, data, data_len)); 993 if (COMPATNAME(route_info).ri_cb.any_count == 0) 994 return; 995 m = rt_makeifannouncemsg(ifp, RTM_IEEE80211, what, &info); 996 if (m == NULL) 997 return; 998 /* 999 * Append the ieee80211 data. Try to stick it in the 1000 * mbuf containing the ifannounce msg; otherwise allocate 1001 * a new mbuf and append. 1002 * 1003 * NB: we assume m is a single mbuf. 1004 */ 1005 if (data_len > M_TRAILINGSPACE(m)) { 1006 struct mbuf *n = m_get(M_NOWAIT, MT_DATA); 1007 if (n == NULL) { 1008 m_freem(m); 1009 return; 1010 } 1011 (void)memcpy(mtod(n, void *), data, data_len); 1012 n->m_len = data_len; 1013 m->m_next = n; 1014 } else if (data_len > 0) { 1015 (void)memcpy(mtod(m, uint8_t *) + m->m_len, data, data_len); 1016 m->m_len += data_len; 1017 } 1018 if (m->m_flags & M_PKTHDR) 1019 m->m_pkthdr.len += data_len; 1020 mtod(m, struct if_xannouncemsghdr *)->ifan_msglen += data_len; 1021 COMPATNAME(route_enqueue)(m, 0); 1022 } 1023 1024 /* 1025 * This is used in dumping the kernel table via sysctl(). 1026 */ 1027 static int 1028 sysctl_dumpentry(struct rtentry *rt, void *v) 1029 { 1030 struct rt_walkarg *w = v; 1031 int error = 0, size; 1032 struct rt_addrinfo info; 1033 1034 if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg)) 1035 return 0; 1036 memset(&info, 0, sizeof(info)); 1037 info.rti_info[RTAX_DST] = rt_getkey(rt); 1038 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 1039 info.rti_info[RTAX_NETMASK] = rt_mask(rt); 1040 if (rt->rt_ifp) { 1041 const struct ifaddr *rtifa; 1042 info.rti_info[RTAX_IFP] = rt->rt_ifp->if_dl->ifa_addr; 1043 /* rtifa used to be simply rt->rt_ifa. If rt->rt_ifa != NULL, 1044 * then rt_get_ifa() != NULL. So this ought to still be safe. 1045 * --dyoung 1046 */ 1047 rtifa = rt_get_ifa(rt); 1048 info.rti_info[RTAX_IFA] = rtifa->ifa_addr; 1049 if (rt->rt_ifp->if_flags & IFF_POINTOPOINT) 1050 info.rti_info[RTAX_BRD] = rtifa->ifa_dstaddr; 1051 } 1052 if ((error = rt_msg2(RTM_GET, &info, 0, w, &size))) 1053 return error; 1054 if (w->w_where && w->w_tmem && w->w_needed <= 0) { 1055 struct rt_xmsghdr *rtm = (struct rt_xmsghdr *)w->w_tmem; 1056 1057 rtm->rtm_flags = rt->rt_flags; 1058 rtm->rtm_use = rt->rt_use; 1059 rtm_setmetrics(rt, rtm); 1060 KASSERT(rt->rt_ifp != NULL); 1061 rtm->rtm_index = rt->rt_ifp->if_index; 1062 rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0; 1063 rtm->rtm_addrs = info.rti_addrs; 1064 if ((error = copyout(rtm, w->w_where, size)) != 0) 1065 w->w_where = NULL; 1066 else 1067 w->w_where = (char *)w->w_where + size; 1068 } 1069 return error; 1070 } 1071 1072 static int 1073 sysctl_iflist(int af, struct rt_walkarg *w, int type) 1074 { 1075 struct ifnet *ifp; 1076 struct ifaddr *ifa; 1077 struct rt_addrinfo info; 1078 int len, error = 0; 1079 1080 memset(&info, 0, sizeof(info)); 1081 IFNET_FOREACH(ifp) { 1082 if (w->w_arg && w->w_arg != ifp->if_index) 1083 continue; 1084 if (IFADDR_EMPTY(ifp)) 1085 continue; 1086 info.rti_info[RTAX_IFP] = ifp->if_dl->ifa_addr; 1087 switch (type) { 1088 case NET_RT_IFLIST: 1089 error = rt_msg2(RTM_IFINFO, &info, NULL, w, &len); 1090 break; 1091 #ifdef COMPAT_14 1092 case NET_RT_OOIFLIST: 1093 error = rt_msg2(RTM_OOIFINFO, &info, NULL, w, &len); 1094 break; 1095 #endif 1096 #ifdef COMPAT_50 1097 case NET_RT_OIFLIST: 1098 error = rt_msg2(RTM_OIFINFO, &info, NULL, w, &len); 1099 break; 1100 #endif 1101 default: 1102 panic("sysctl_iflist(1)"); 1103 } 1104 if (error) 1105 return error; 1106 info.rti_info[RTAX_IFP] = NULL; 1107 if (w->w_where && w->w_tmem && w->w_needed <= 0) { 1108 switch (type) { 1109 case NET_RT_IFLIST: { 1110 struct if_xmsghdr *ifm; 1111 1112 ifm = (struct if_xmsghdr *)w->w_tmem; 1113 ifm->ifm_index = ifp->if_index; 1114 ifm->ifm_flags = ifp->if_flags; 1115 ifm->ifm_data = ifp->if_data; 1116 ifm->ifm_addrs = info.rti_addrs; 1117 error = copyout(ifm, w->w_where, len); 1118 if (error) 1119 return error; 1120 w->w_where = (char *)w->w_where + len; 1121 break; 1122 } 1123 1124 #ifdef COMPAT_14 1125 case NET_RT_OOIFLIST: 1126 error = compat_14_iflist(ifp, w, &info, len); 1127 if (error) 1128 return error; 1129 break; 1130 #endif 1131 #ifdef COMPAT_50 1132 case NET_RT_OIFLIST: 1133 error = compat_50_iflist(ifp, w, &info, len); 1134 if (error) 1135 return error; 1136 break; 1137 #endif 1138 default: 1139 panic("sysctl_iflist(2)"); 1140 } 1141 } 1142 IFADDR_FOREACH(ifa, ifp) { 1143 if (af && af != ifa->ifa_addr->sa_family) 1144 continue; 1145 info.rti_info[RTAX_IFA] = ifa->ifa_addr; 1146 info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask; 1147 info.rti_info[RTAX_BRD] = ifa->ifa_dstaddr; 1148 if ((error = rt_msg2(RTM_NEWADDR, &info, 0, w, &len))) 1149 return error; 1150 if (w->w_where && w->w_tmem && w->w_needed <= 0) { 1151 struct ifa_xmsghdr *ifam; 1152 1153 ifam = (struct ifa_xmsghdr *)w->w_tmem; 1154 ifam->ifam_index = ifa->ifa_ifp->if_index; 1155 ifam->ifam_flags = ifa->ifa_flags; 1156 ifam->ifam_metric = ifa->ifa_metric; 1157 ifam->ifam_addrs = info.rti_addrs; 1158 error = copyout(w->w_tmem, w->w_where, len); 1159 if (error) 1160 return error; 1161 w->w_where = (char *)w->w_where + len; 1162 } 1163 } 1164 info.rti_info[RTAX_IFA] = info.rti_info[RTAX_NETMASK] = 1165 info.rti_info[RTAX_BRD] = NULL; 1166 } 1167 return 0; 1168 } 1169 1170 static int 1171 sysctl_rtable(SYSCTLFN_ARGS) 1172 { 1173 void *where = oldp; 1174 size_t *given = oldlenp; 1175 const void *new = newp; 1176 int i, s, error = EINVAL; 1177 u_char af; 1178 struct rt_walkarg w; 1179 1180 if (namelen == 1 && name[0] == CTL_QUERY) 1181 return sysctl_query(SYSCTLFN_CALL(rnode)); 1182 1183 if (new) 1184 return EPERM; 1185 if (namelen != 3) 1186 return EINVAL; 1187 af = name[0]; 1188 w.w_tmemneeded = 0; 1189 w.w_tmemsize = 0; 1190 w.w_tmem = NULL; 1191 again: 1192 /* we may return here if a later [re]alloc of the t_mem buffer fails */ 1193 if (w.w_tmemneeded) { 1194 w.w_tmem = malloc(w.w_tmemneeded, M_RTABLE, M_WAITOK); 1195 w.w_tmemsize = w.w_tmemneeded; 1196 w.w_tmemneeded = 0; 1197 } 1198 w.w_op = name[1]; 1199 w.w_arg = name[2]; 1200 w.w_given = *given; 1201 w.w_needed = 0 - w.w_given; 1202 w.w_where = where; 1203 1204 s = splsoftnet(); 1205 switch (w.w_op) { 1206 1207 case NET_RT_DUMP: 1208 case NET_RT_FLAGS: 1209 for (i = 1; i <= AF_MAX; i++) 1210 if ((af == 0 || af == i) && 1211 (error = rt_walktree(i, sysctl_dumpentry, &w))) 1212 break; 1213 break; 1214 1215 #ifdef COMPAT_14 1216 case NET_RT_OOIFLIST: 1217 error = sysctl_iflist(af, &w, w.w_op); 1218 break; 1219 #endif 1220 #ifdef COMPAT_50 1221 case NET_RT_OIFLIST: 1222 error = sysctl_iflist(af, &w, w.w_op); 1223 break; 1224 #endif 1225 case NET_RT_IFLIST: 1226 error = sysctl_iflist(af, &w, w.w_op); 1227 break; 1228 } 1229 splx(s); 1230 1231 /* check to see if we couldn't allocate memory with NOWAIT */ 1232 if (error == ENOBUFS && w.w_tmem == 0 && w.w_tmemneeded) 1233 goto again; 1234 1235 if (w.w_tmem) 1236 free(w.w_tmem, M_RTABLE); 1237 w.w_needed += w.w_given; 1238 if (where) { 1239 *given = (char *)w.w_where - (char *)where; 1240 if (*given < w.w_needed) 1241 return ENOMEM; 1242 } else { 1243 *given = (11 * w.w_needed) / 10; 1244 } 1245 return error; 1246 } 1247 1248 /* 1249 * Routing message software interrupt routine 1250 */ 1251 static void 1252 COMPATNAME(route_intr)(void *cookie) 1253 { 1254 struct sockproto proto = { .sp_family = PF_XROUTE, }; 1255 struct route_info * const ri = &COMPATNAME(route_info); 1256 struct mbuf *m; 1257 int s; 1258 1259 mutex_enter(softnet_lock); 1260 KERNEL_LOCK(1, NULL); 1261 while (!IF_IS_EMPTY(&ri->ri_intrq)) { 1262 s = splnet(); 1263 IF_DEQUEUE(&ri->ri_intrq, m); 1264 splx(s); 1265 if (m == NULL) 1266 break; 1267 proto.sp_protocol = M_GETCTX(m, uintptr_t); 1268 raw_input(m, &proto, &ri->ri_src, &ri->ri_dst); 1269 } 1270 KERNEL_UNLOCK_ONE(NULL); 1271 mutex_exit(softnet_lock); 1272 } 1273 1274 /* 1275 * Enqueue a message to the software interrupt routine. 1276 */ 1277 void 1278 COMPATNAME(route_enqueue)(struct mbuf *m, int family) 1279 { 1280 struct route_info * const ri = &COMPATNAME(route_info); 1281 int s, wasempty; 1282 1283 s = splnet(); 1284 if (IF_QFULL(&ri->ri_intrq)) { 1285 IF_DROP(&ri->ri_intrq); 1286 m_freem(m); 1287 } else { 1288 wasempty = IF_IS_EMPTY(&ri->ri_intrq); 1289 M_SETCTX(m, (uintptr_t)family); 1290 IF_ENQUEUE(&ri->ri_intrq, m); 1291 if (wasempty) 1292 softint_schedule(ri->ri_sih); 1293 } 1294 splx(s); 1295 } 1296 1297 static void 1298 COMPATNAME(route_init)(void) 1299 { 1300 struct route_info * const ri = &COMPATNAME(route_info); 1301 1302 #ifndef COMPAT_RTSOCK 1303 rt_init(); 1304 #endif 1305 1306 sysctl_net_route_setup(NULL); 1307 ri->ri_intrq.ifq_maxlen = ri->ri_maxqlen; 1308 ri->ri_sih = softint_establish(SOFTINT_NET | SOFTINT_MPSAFE, 1309 COMPATNAME(route_intr), NULL); 1310 } 1311 1312 /* 1313 * Definitions of protocols supported in the ROUTE domain. 1314 */ 1315 #ifndef COMPAT_RTSOCK 1316 PR_WRAP_USRREQ(route_usrreq); 1317 #else 1318 PR_WRAP_USRREQ(compat_50_route_usrreq); 1319 #endif 1320 1321 static const struct protosw COMPATNAME(route_protosw)[] = { 1322 { 1323 .pr_type = SOCK_RAW, 1324 .pr_domain = &COMPATNAME(routedomain), 1325 .pr_flags = PR_ATOMIC|PR_ADDR, 1326 .pr_input = raw_input, 1327 .pr_output = COMPATNAME(route_output), 1328 .pr_ctlinput = raw_ctlinput, 1329 .pr_usrreq = COMPATNAME(route_usrreq_wrapper), 1330 .pr_init = raw_init, 1331 }, 1332 }; 1333 1334 struct domain COMPATNAME(routedomain) = { 1335 .dom_family = PF_XROUTE, 1336 .dom_name = DOMAINNAME, 1337 .dom_init = COMPATNAME(route_init), 1338 .dom_protosw = COMPATNAME(route_protosw), 1339 .dom_protoswNPROTOSW = 1340 &COMPATNAME(route_protosw)[__arraycount(COMPATNAME(route_protosw))], 1341 }; 1342 1343 static void 1344 sysctl_net_route_setup(struct sysctllog **clog) 1345 { 1346 const struct sysctlnode *rnode = NULL; 1347 1348 sysctl_createv(clog, 0, NULL, NULL, 1349 CTLFLAG_PERMANENT, 1350 CTLTYPE_NODE, "net", NULL, 1351 NULL, 0, NULL, 0, 1352 CTL_NET, CTL_EOL); 1353 1354 sysctl_createv(clog, 0, NULL, &rnode, 1355 CTLFLAG_PERMANENT, 1356 CTLTYPE_NODE, DOMAINNAME, 1357 SYSCTL_DESCR("PF_ROUTE information"), 1358 NULL, 0, NULL, 0, 1359 CTL_NET, PF_XROUTE, CTL_EOL); 1360 1361 sysctl_createv(clog, 0, NULL, NULL, 1362 CTLFLAG_PERMANENT, 1363 CTLTYPE_NODE, "rtable", 1364 SYSCTL_DESCR("Routing table information"), 1365 sysctl_rtable, 0, NULL, 0, 1366 CTL_NET, PF_XROUTE, 0 /* any protocol */, CTL_EOL); 1367 1368 sysctl_createv(clog, 0, &rnode, NULL, 1369 CTLFLAG_PERMANENT, 1370 CTLTYPE_STRUCT, "stats", 1371 SYSCTL_DESCR("Routing statistics"), 1372 NULL, 0, &rtstat, sizeof(rtstat), 1373 CTL_CREATE, CTL_EOL); 1374 } 1375