1 /* $OpenBSD: rtsock.c,v 1.76 2008/08/07 21:32:08 claudio Exp $ */ 2 /* $NetBSD: rtsock.c,v 1.18 1996/03/29 00:32:10 cgd Exp $ */ 3 4 /* 5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the project nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 /* 34 * Copyright (c) 1988, 1991, 1993 35 * The Regents of the University of California. All rights reserved. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 1. Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * 2. Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * 3. Neither the name of the University nor the names of its contributors 46 * may be used to endorse or promote products derived from this software 47 * without specific prior written permission. 48 * 49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 59 * SUCH DAMAGE. 60 * 61 * @(#)rtsock.c 8.6 (Berkeley) 2/11/95 62 */ 63 64 #include <sys/param.h> 65 #include <sys/systm.h> 66 #include <sys/proc.h> 67 #include <sys/mbuf.h> 68 #include <sys/socket.h> 69 #include <sys/socketvar.h> 70 #include <sys/domain.h> 71 #include <sys/protosw.h> 72 73 #include <uvm/uvm_extern.h> 74 #include <sys/sysctl.h> 75 76 #include <net/if.h> 77 #include <net/route.h> 78 #include <net/raw_cb.h> 79 80 #ifdef MPLS 81 #include <netmpls/mpls.h> 82 #endif /* MPLS */ 83 84 #include <sys/stdarg.h> 85 86 struct sockaddr route_dst = { 2, PF_ROUTE, }; 87 struct sockaddr route_src = { 2, PF_ROUTE, }; 88 struct sockproto route_proto = { PF_ROUTE, }; 89 90 struct walkarg { 91 int w_op, w_arg, w_given, w_needed, w_tmemsize; 92 caddr_t w_where, w_tmem; 93 }; 94 95 struct mbuf *rt_msg1(int, struct rt_addrinfo *); 96 int rt_msg2(int, int, struct rt_addrinfo *, caddr_t, 97 struct walkarg *); 98 void rt_xaddrs(caddr_t, caddr_t, struct rt_addrinfo *); 99 #ifndef SMALL_KERNEL 100 struct rt_msghdr *rtmsg_3to4(struct mbuf *, int *); 101 #endif 102 103 /* Sleazy use of local variables throughout file, warning!!!! */ 104 #define dst info.rti_info[RTAX_DST] 105 #define gate info.rti_info[RTAX_GATEWAY] 106 #define netmask info.rti_info[RTAX_NETMASK] 107 #define genmask info.rti_info[RTAX_GENMASK] 108 #define ifpaddr info.rti_info[RTAX_IFP] 109 #define ifaaddr info.rti_info[RTAX_IFA] 110 #define brdaddr info.rti_info[RTAX_BRD] 111 112 int 113 route_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam, 114 struct mbuf *control, struct proc *p) 115 { 116 int error = 0; 117 struct rawcb *rp = sotorawcb(so); 118 int s; 119 120 if (req == PRU_ATTACH) { 121 rp = malloc(sizeof(*rp), M_PCB, M_WAITOK|M_ZERO); 122 so->so_pcb = rp; 123 } 124 if (req == PRU_DETACH && rp) { 125 int af = rp->rcb_proto.sp_protocol; 126 if (af == AF_INET) 127 route_cb.ip_count--; 128 else if (af == AF_INET6) 129 route_cb.ip6_count--; 130 route_cb.any_count--; 131 } 132 s = splsoftnet(); 133 /* 134 * Don't call raw_usrreq() in the attach case, because 135 * we want to allow non-privileged processes to listen on 136 * and send "safe" commands to the routing socket. 137 */ 138 if (req == PRU_ATTACH) { 139 if (curproc == 0) 140 error = EACCES; 141 else 142 error = raw_attach(so, (int)(long)nam); 143 } else 144 error = raw_usrreq(so, req, m, nam, control, p); 145 146 rp = sotorawcb(so); 147 if (req == PRU_ATTACH && rp) { 148 int af = rp->rcb_proto.sp_protocol; 149 if (error) { 150 free(rp, M_PCB); 151 splx(s); 152 return (error); 153 } 154 if (af == AF_INET) 155 route_cb.ip_count++; 156 else if (af == AF_INET6) 157 route_cb.ip6_count++; 158 #ifdef MPLS 159 else if (af == AF_MPLS) 160 route_cb.mpls_count++; 161 #endif /* MPLS */ 162 rp->rcb_faddr = &route_src; 163 route_cb.any_count++; 164 soisconnected(so); 165 so->so_options |= SO_USELOOPBACK; 166 } 167 splx(s); 168 return (error); 169 } 170 171 int 172 route_output(struct mbuf *m, ...) 173 { 174 struct rt_msghdr *rtm = NULL; 175 struct radix_node *rn = NULL; 176 struct rtentry *rt = NULL; 177 struct rtentry *saved_nrt = NULL; 178 struct radix_node_head *rnh; 179 struct rt_addrinfo info; 180 int len, error = 0; 181 struct ifnet *ifp = NULL; 182 struct ifaddr *ifa = NULL; 183 struct socket *so; 184 struct rawcb *rp = NULL; 185 struct sockaddr_rtlabel sa_rt; 186 const char *label; 187 va_list ap; 188 u_int tableid; 189 u_int8_t prio; 190 191 va_start(ap, m); 192 so = va_arg(ap, struct socket *); 193 va_end(ap); 194 195 dst = NULL; /* for error handling (goto flush) */ 196 if (m == 0 || ((m->m_len < sizeof(int32_t)) && 197 (m = m_pullup(m, sizeof(int32_t))) == 0)) 198 return (ENOBUFS); 199 if ((m->m_flags & M_PKTHDR) == 0) 200 panic("route_output"); 201 len = m->m_pkthdr.len; 202 if (len < offsetof(struct rt_msghdr, rtm_type) + 1 || 203 len != mtod(m, struct rt_msghdr *)->rtm_msglen) { 204 error = EINVAL; 205 goto flush; 206 } 207 switch (mtod(m, struct rt_msghdr *)->rtm_version) { 208 case RTM_VERSION: 209 if (len < sizeof(struct rt_msghdr)) { 210 error = EINVAL; 211 goto flush; 212 } 213 R_Malloc(rtm, struct rt_msghdr *, len); 214 if (rtm == 0) { 215 error = ENOBUFS; 216 goto flush; 217 } 218 m_copydata(m, 0, len, (caddr_t)rtm); 219 break; 220 #ifndef SMALL_KERNEL 221 case RTM_OVERSION: 222 if (len < sizeof(struct rt_omsghdr)) { 223 error = EINVAL; 224 goto flush; 225 } 226 rtm = rtmsg_3to4(m, &len); 227 if (rtm == 0) { 228 error = ENOBUFS; 229 goto flush; 230 } 231 break; 232 #endif 233 default: 234 error = EPROTONOSUPPORT; 235 goto flush; 236 } 237 rtm->rtm_pid = curproc->p_pid; 238 if (rtm->rtm_hdrlen == 0) /* old client */ 239 rtm->rtm_hdrlen = sizeof(struct rt_msghdr); 240 if (len < rtm->rtm_hdrlen) { 241 error = EINVAL; 242 goto flush; 243 } 244 245 tableid = rtm->rtm_tableid; 246 if (!rtable_exists(tableid)) { 247 if (rtm->rtm_type == RTM_ADD) { 248 if (rtable_add(tableid)) { 249 error = EINVAL; 250 goto flush; 251 } 252 } else { 253 error = EINVAL; 254 goto flush; 255 } 256 } 257 258 if (rtm->rtm_priority != 0) { 259 if (rtm->rtm_priority > RTP_MAX) { 260 error = EINVAL; 261 goto flush; 262 } 263 prio = rtm->rtm_priority; 264 } else if (rtm->rtm_type != RTM_ADD) 265 prio = RTP_ANY; 266 else if (rtm->rtm_flags & RTF_STATIC) 267 prio = RTP_STATIC; 268 else 269 prio = RTP_DEFAULT; 270 271 bzero(&info, sizeof(info)); 272 info.rti_addrs = rtm->rtm_addrs; 273 rt_xaddrs(rtm->rtm_hdrlen + (caddr_t)rtm, len + (caddr_t)rtm, &info); 274 info.rti_flags = rtm->rtm_flags; 275 if (dst == 0 || dst->sa_family >= AF_MAX || 276 (gate != 0 && gate->sa_family >= AF_MAX)) { 277 error = EINVAL; 278 goto flush; 279 } 280 if (genmask) { 281 struct radix_node *t; 282 t = rn_addmask(genmask, 0, 1); 283 if (t && genmask->sa_len >= 284 ((struct sockaddr *)t->rn_key)->sa_len && 285 Bcmp((caddr_t *)genmask + 1, (caddr_t *)t->rn_key + 1, 286 ((struct sockaddr *)t->rn_key)->sa_len) - 1) 287 genmask = (struct sockaddr *)(t->rn_key); 288 else { 289 error = ENOBUFS; 290 goto flush; 291 } 292 } 293 294 /* 295 * Verify that the caller has the appropriate privilege; RTM_GET 296 * is the only operation the non-superuser is allowed. 297 */ 298 if (rtm->rtm_type != RTM_GET && suser(curproc, 0) != 0) { 299 error = EACCES; 300 goto flush; 301 } 302 303 switch (rtm->rtm_type) { 304 case RTM_ADD: 305 if (gate == 0) { 306 error = EINVAL; 307 goto flush; 308 } 309 error = rtrequest1(rtm->rtm_type, &info, prio, &saved_nrt, 310 tableid); 311 if (error == 0 && saved_nrt) { 312 rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, 313 &saved_nrt->rt_rmx); 314 saved_nrt->rt_refcnt--; 315 saved_nrt->rt_genmask = genmask; 316 rtm->rtm_index = saved_nrt->rt_ifp->if_index; 317 } 318 break; 319 case RTM_DELETE: 320 error = rtrequest1(rtm->rtm_type, &info, prio, &saved_nrt, 321 tableid); 322 if (error == 0) { 323 (rt = saved_nrt)->rt_refcnt++; 324 goto report; 325 } 326 break; 327 case RTM_GET: 328 case RTM_CHANGE: 329 case RTM_LOCK: 330 if ((rnh = rt_gettable(dst->sa_family, tableid)) == NULL) { 331 error = EAFNOSUPPORT; 332 goto flush; 333 } 334 rn = rt_lookup(dst, netmask, tableid); 335 if (rn == NULL || (rn->rn_flags & RNF_ROOT) != 0) { 336 error = ESRCH; 337 goto flush; 338 } 339 rt = (struct rtentry *)rn; 340 #ifndef SMALL_KERNEL 341 /* 342 * for RTM_CHANGE/LOCK, if we got multipath routes, 343 * we require users to specify a matching RTAX_GATEWAY. 344 * 345 * for RTM_GET, gate is optional even with multipath. 346 * if gate == NULL the first match is returned. 347 * (no need to call rt_mpath_matchgate if gate == NULL) 348 */ 349 if (rn_mpath_capable(rnh)) { 350 /* first find correct priority bucket */ 351 rn = rn_mpath_prio(rn, prio); 352 rt = (struct rtentry *)rn; 353 if (prio != RTP_ANY && rt->rt_priority != prio) { 354 error = ESRCH; 355 goto flush; 356 } 357 358 /* if multipath routes */ 359 if (rn_mpath_next(rn)) { 360 if (gate) 361 rt = rt_mpath_matchgate(rt, gate, prio); 362 else if (rtm->rtm_type != RTM_GET) 363 /* 364 * only RTM_GET may use an empty gate 365 * on multipath ... 366 */ 367 rt = NULL; 368 } else if (gate && (rtm->rtm_type == RTM_GET || 369 rtm->rtm_type == RTM_LOCK)) 370 /* 371 * ... but if a gate is specified RTM_GET 372 * and RTM_LOCK must match the gate no matter 373 * what. 374 */ 375 rt = rt_mpath_matchgate(rt, gate, prio); 376 377 if (!rt) { 378 error = ESRCH; 379 goto flush; 380 } 381 rn = (struct radix_node *)rt; 382 } 383 #endif 384 rt->rt_refcnt++; 385 386 /* 387 * RTM_CHANGE/LOCK need a perfect match, rn_lookup() 388 * returns a perfect match in case a netmask is specified. 389 * For host routes only a longest prefix match is returned 390 * so it is necessary to compare the existence of the netmaks. 391 * If both have a netmask rn_lookup() did a perfect match and 392 * if none of them have a netmask both are host routes which is 393 * also a perfect match. 394 */ 395 if (rtm->rtm_type != RTM_GET && !rt_mask(rt) != !netmask) { 396 error = ESRCH; 397 goto flush; 398 } 399 400 switch (rtm->rtm_type) { 401 case RTM_GET: 402 report: 403 dst = rt_key(rt); 404 gate = rt->rt_gateway; 405 netmask = rt_mask(rt); 406 genmask = rt->rt_genmask; 407 408 if (rt->rt_labelid) { 409 bzero(&sa_rt, sizeof(sa_rt)); 410 sa_rt.sr_len = sizeof(sa_rt); 411 label = rtlabel_id2name(rt->rt_labelid); 412 if (label != NULL) 413 strlcpy(sa_rt.sr_label, label, 414 sizeof(sa_rt.sr_label)); 415 info.rti_info[RTAX_LABEL] = 416 (struct sockaddr *)&sa_rt; 417 } 418 419 ifpaddr = 0; 420 ifaaddr = 0; 421 if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA) && 422 (ifp = rt->rt_ifp) != NULL) { 423 ifpaddr = 424 TAILQ_FIRST(&ifp->if_addrlist)->ifa_addr; 425 ifaaddr = rt->rt_ifa->ifa_addr; 426 if (ifp->if_flags & IFF_POINTOPOINT) 427 brdaddr = rt->rt_ifa->ifa_dstaddr; 428 else 429 brdaddr = 0; 430 rtm->rtm_index = ifp->if_index; 431 } 432 len = rt_msg2(rtm->rtm_type, RTM_VERSION, &info, NULL, 433 NULL); 434 if (len > rtm->rtm_msglen) { 435 struct rt_msghdr *new_rtm; 436 R_Malloc(new_rtm, struct rt_msghdr *, len); 437 if (new_rtm == 0) { 438 error = ENOBUFS; 439 goto flush; 440 } 441 Bcopy(rtm, new_rtm, rtm->rtm_msglen); 442 Free(rtm); rtm = new_rtm; 443 } 444 rt_msg2(rtm->rtm_type, RTM_VERSION, &info, (caddr_t)rtm, 445 NULL); 446 rtm->rtm_flags = rt->rt_flags; 447 rtm->rtm_use = 0; 448 rtm->rtm_priority = rt->rt_priority; 449 rt_getmetrics(&rt->rt_rmx, &rtm->rtm_rmx); 450 rtm->rtm_addrs = info.rti_addrs; 451 break; 452 453 case RTM_CHANGE: 454 /* 455 * new gateway could require new ifaddr, ifp; 456 * flags may also be different; ifp may be specified 457 * by ll sockaddr when protocol address is ambiguous 458 */ 459 if ((error = rt_getifa(&info)) != 0) 460 goto flush; 461 if (gate && rt_setgate(rt, rt_key(rt), gate, tableid)) { 462 error = EDQUOT; 463 goto flush; 464 } 465 if (ifpaddr && (ifa = ifa_ifwithnet(ifpaddr)) && 466 (ifp = ifa->ifa_ifp) && (ifaaddr || gate)) 467 ifa = ifaof_ifpforaddr(ifaaddr ? ifaaddr : gate, 468 ifp); 469 else if ((ifaaddr && (ifa = ifa_ifwithaddr(ifaaddr))) || 470 (gate && (ifa = ifa_ifwithroute(rt->rt_flags, 471 rt_key(rt), gate)))) 472 ifp = ifa->ifa_ifp; 473 if (ifa) { 474 struct ifaddr *oifa = rt->rt_ifa; 475 if (oifa != ifa) { 476 if (oifa && oifa->ifa_rtrequest) 477 oifa->ifa_rtrequest(RTM_DELETE, rt, 478 &info); 479 IFAFREE(rt->rt_ifa); 480 rt->rt_ifa = ifa; 481 ifa->ifa_refcnt++; 482 rt->rt_ifp = ifp; 483 } 484 } 485 486 /* XXX Hack to allow some flags to be toggled */ 487 if (rtm->rtm_fmask & RTF_FMASK) 488 rt->rt_flags = (rt->rt_flags & 489 ~rtm->rtm_fmask) | 490 (rtm->rtm_flags & rtm->rtm_fmask); 491 492 rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, 493 &rt->rt_rmx); 494 rtm->rtm_index = rt->rt_ifp->if_index; 495 if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) 496 rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, &info); 497 if (genmask) 498 rt->rt_genmask = genmask; 499 if (info.rti_info[RTAX_LABEL] != NULL) { 500 char *rtlabel = ((struct sockaddr_rtlabel *) 501 info.rti_info[RTAX_LABEL])->sr_label; 502 rtlabel_unref(rt->rt_labelid); 503 rt->rt_labelid = 504 rtlabel_name2id(rtlabel); 505 } 506 if_group_routechange(dst, netmask); 507 /* FALLTHROUGH */ 508 case RTM_LOCK: 509 rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits); 510 rt->rt_rmx.rmx_locks |= 511 (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); 512 break; 513 } 514 break; 515 516 default: 517 error = EOPNOTSUPP; 518 break; 519 } 520 521 flush: 522 if (rtm) { 523 if (error) 524 rtm->rtm_errno = error; 525 else 526 rtm->rtm_flags |= RTF_DONE; 527 } 528 if (rt) 529 rtfree(rt); 530 531 /* 532 * Check to see if we don't want our own messages. 533 */ 534 if (!(so->so_options & SO_USELOOPBACK)) { 535 if (route_cb.any_count <= 1) { 536 if (rtm) 537 Free(rtm); 538 m_freem(m); 539 return (error); 540 } 541 /* There is another listener, so construct message */ 542 rp = sotorawcb(so); 543 } 544 if (rp) 545 rp->rcb_proto.sp_family = 0; /* Avoid us */ 546 if (dst) 547 route_proto.sp_protocol = dst->sa_family; 548 if (rtm) { 549 m_copyback(m, 0, rtm->rtm_msglen, rtm); 550 if (m->m_pkthdr.len < rtm->rtm_msglen) { 551 m_freem(m); 552 m = NULL; 553 } else if (m->m_pkthdr.len > rtm->rtm_msglen) 554 m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len); 555 Free(rtm); 556 } 557 if (m) 558 raw_input(m, &route_proto, &route_src, &route_dst); 559 if (rp) 560 rp->rcb_proto.sp_family = PF_ROUTE; 561 562 return (error); 563 } 564 565 void 566 rt_setmetrics(u_long which, struct rt_metrics *in, struct rt_kmetrics *out) 567 { 568 if (which & RTV_MTU) 569 out->rmx_mtu = in->rmx_mtu; 570 if (which & RTV_EXPIRE) 571 out->rmx_expire = in->rmx_expire; 572 /* RTV_PRIORITY handled befor */ 573 } 574 575 void 576 rt_getmetrics(struct rt_kmetrics *in, struct rt_metrics *out) 577 { 578 bzero(out, sizeof(*out)); 579 out->rmx_locks = in->rmx_locks; 580 out->rmx_mtu = in->rmx_mtu; 581 out->rmx_expire = in->rmx_expire; 582 out->rmx_pksent = in->rmx_pksent; 583 } 584 585 #define ROUNDUP(a) \ 586 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 587 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 588 589 void 590 rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo) 591 { 592 struct sockaddr *sa; 593 int i; 594 595 bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info)); 596 for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) { 597 if ((rtinfo->rti_addrs & (1 << i)) == 0) 598 continue; 599 rtinfo->rti_info[i] = sa = (struct sockaddr *)cp; 600 ADVANCE(cp, sa); 601 } 602 } 603 604 struct mbuf * 605 rt_msg1(int type, struct rt_addrinfo *rtinfo) 606 { 607 struct rt_msghdr *rtm; 608 struct mbuf *m; 609 int i; 610 struct sockaddr *sa; 611 int len, dlen, hlen; 612 613 switch (type) { 614 case RTM_DELADDR: 615 case RTM_NEWADDR: 616 len = sizeof(struct ifa_msghdr); 617 break; 618 case RTM_IFINFO: 619 len = sizeof(struct if_msghdr); 620 break; 621 case RTM_IFANNOUNCE: 622 len = sizeof(struct if_announcemsghdr); 623 break; 624 default: 625 len = sizeof(struct rt_msghdr); 626 break; 627 } 628 if (len > MCLBYTES) 629 panic("rt_msg1"); 630 m = m_gethdr(M_DONTWAIT, MT_DATA); 631 if (m && len > MHLEN) { 632 MCLGET(m, M_DONTWAIT); 633 if ((m->m_flags & M_EXT) == 0) { 634 m_free(m); 635 m = NULL; 636 } 637 } 638 if (m == 0) 639 return (m); 640 m->m_pkthdr.len = m->m_len = hlen = len; 641 m->m_pkthdr.rcvif = NULL; 642 rtm = mtod(m, struct rt_msghdr *); 643 bzero(rtm, len); 644 for (i = 0; i < RTAX_MAX; i++) { 645 if ((sa = rtinfo->rti_info[i]) == NULL) 646 continue; 647 rtinfo->rti_addrs |= (1 << i); 648 dlen = ROUNDUP(sa->sa_len); 649 m_copyback(m, len, dlen, sa); 650 len += dlen; 651 } 652 if (m->m_pkthdr.len != len) { 653 m_freem(m); 654 return (NULL); 655 } 656 rtm->rtm_msglen = len; 657 rtm->rtm_hdrlen = hlen; 658 rtm->rtm_version = RTM_VERSION; 659 rtm->rtm_type = type; 660 return (m); 661 } 662 663 int 664 rt_msg2(int type, int vers, struct rt_addrinfo *rtinfo, caddr_t cp, 665 struct walkarg *w) 666 { 667 int i; 668 int len, dlen, hlen, second_time = 0; 669 caddr_t cp0; 670 671 rtinfo->rti_addrs = 0; 672 again: 673 switch (type) { 674 case RTM_DELADDR: 675 case RTM_NEWADDR: 676 #ifndef SMALL_KERNEL 677 if (vers == RTM_OVERSION) 678 len = sizeof(struct ifa_omsghdr); 679 else 680 #endif 681 len = sizeof(struct ifa_msghdr); 682 break; 683 case RTM_IFINFO: 684 #ifndef SMALL_KERNEL 685 if (vers == RTM_OVERSION) 686 len = sizeof(struct if_omsghdr); 687 else 688 #endif 689 len = sizeof(struct if_msghdr); 690 break; 691 default: 692 #ifndef SMALL_KERNEL 693 if (vers == RTM_OVERSION) 694 len = sizeof(struct rt_omsghdr); 695 else 696 #endif 697 len = sizeof(struct rt_msghdr); 698 break; 699 } 700 hlen = len; 701 if ((cp0 = cp) != NULL) 702 cp += len; 703 for (i = 0; i < RTAX_MAX; i++) { 704 struct sockaddr *sa; 705 706 if ((sa = rtinfo->rti_info[i]) == 0) 707 continue; 708 rtinfo->rti_addrs |= (1 << i); 709 dlen = ROUNDUP(sa->sa_len); 710 if (cp) { 711 bcopy(sa, cp, (size_t)dlen); 712 cp += dlen; 713 } 714 len += dlen; 715 } 716 /* align message length to the next natural boundary */ 717 len = ALIGN(len); 718 if (cp == 0 && w != NULL && !second_time) { 719 struct walkarg *rw = w; 720 721 rw->w_needed += len; 722 if (rw->w_needed <= 0 && rw->w_where) { 723 if (rw->w_tmemsize < len) { 724 if (rw->w_tmem) 725 free(rw->w_tmem, M_RTABLE); 726 rw->w_tmem = malloc(len, M_RTABLE, M_NOWAIT); 727 if (rw->w_tmem) 728 rw->w_tmemsize = len; 729 } 730 if (rw->w_tmem) { 731 cp = rw->w_tmem; 732 second_time = 1; 733 goto again; 734 } else 735 rw->w_where = 0; 736 } 737 } 738 if (cp && w) /* clear the message header */ 739 bzero(cp0, hlen); 740 741 if (cp && vers != RTM_OVERSION) { 742 struct rt_msghdr *rtm = (struct rt_msghdr *)cp0; 743 744 rtm->rtm_version = RTM_VERSION; 745 rtm->rtm_type = type; 746 rtm->rtm_msglen = len; 747 rtm->rtm_hdrlen = hlen; 748 } 749 #ifndef SMALL_KERNEL 750 if (cp && vers == RTM_OVERSION) { 751 struct rt_omsghdr *rtm = (struct rt_omsghdr *)cp0; 752 753 rtm->rtm_version = RTM_OVERSION; 754 rtm->rtm_type = type; 755 rtm->rtm_msglen = len; 756 } 757 #endif 758 return (len); 759 } 760 761 /* 762 * This routine is called to generate a message from the routing 763 * socket indicating that a redirect has occurred, a routing lookup 764 * has failed, or that a protocol has detected timeouts to a particular 765 * destination. 766 */ 767 void 768 rt_missmsg(int type, struct rt_addrinfo *rtinfo, int flags, 769 struct ifnet *ifp, int error, u_int tableid) 770 { 771 struct rt_msghdr *rtm; 772 struct mbuf *m; 773 struct sockaddr *sa = rtinfo->rti_info[RTAX_DST]; 774 775 if (route_cb.any_count == 0) 776 return; 777 m = rt_msg1(type, rtinfo); 778 if (m == 0) 779 return; 780 rtm = mtod(m, struct rt_msghdr *); 781 rtm->rtm_flags = RTF_DONE | flags; 782 rtm->rtm_errno = error; 783 rtm->rtm_tableid = tableid; 784 rtm->rtm_addrs = rtinfo->rti_addrs; 785 if (ifp != NULL) 786 rtm->rtm_index = ifp->if_index; 787 if (sa == NULL) 788 route_proto.sp_protocol = 0; 789 else 790 route_proto.sp_protocol = sa->sa_family; 791 raw_input(m, &route_proto, &route_src, &route_dst); 792 } 793 794 /* 795 * This routine is called to generate a message from the routing 796 * socket indicating that the status of a network interface has changed. 797 */ 798 void 799 rt_ifmsg(struct ifnet *ifp) 800 { 801 struct if_msghdr *ifm; 802 struct mbuf *m; 803 struct rt_addrinfo info; 804 805 if (route_cb.any_count == 0) 806 return; 807 bzero(&info, sizeof(info)); 808 m = rt_msg1(RTM_IFINFO, &info); 809 if (m == 0) 810 return; 811 ifm = mtod(m, struct if_msghdr *); 812 ifm->ifm_index = ifp->if_index; 813 ifm->ifm_flags = ifp->if_flags; 814 ifm->ifm_data = ifp->if_data; 815 ifm->ifm_addrs = 0; 816 route_proto.sp_protocol = 0; 817 raw_input(m, &route_proto, &route_src, &route_dst); 818 } 819 820 /* 821 * This is called to generate messages from the routing socket 822 * indicating a network interface has had addresses associated with it. 823 * if we ever reverse the logic and replace messages TO the routing 824 * socket indicate a request to configure interfaces, then it will 825 * be unnecessary as the routing socket will automatically generate 826 * copies of it. 827 */ 828 void 829 rt_newaddrmsg(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt) 830 { 831 struct rt_addrinfo info; 832 struct sockaddr *sa = NULL; 833 int pass; 834 struct mbuf *m = NULL; 835 struct ifnet *ifp = ifa->ifa_ifp; 836 837 if (route_cb.any_count == 0) 838 return; 839 for (pass = 1; pass < 3; pass++) { 840 bzero(&info, sizeof(info)); 841 if ((cmd == RTM_ADD && pass == 1) || 842 (cmd == RTM_DELETE && pass == 2)) { 843 struct ifa_msghdr *ifam; 844 int ncmd; 845 846 if (cmd == RTM_ADD) 847 ncmd = RTM_NEWADDR; 848 else 849 ncmd = RTM_DELADDR; 850 851 ifaaddr = sa = ifa->ifa_addr; 852 ifpaddr = TAILQ_FIRST(&ifp->if_addrlist)->ifa_addr; 853 netmask = ifa->ifa_netmask; 854 brdaddr = ifa->ifa_dstaddr; 855 if ((m = rt_msg1(ncmd, &info)) == NULL) 856 continue; 857 ifam = mtod(m, struct ifa_msghdr *); 858 ifam->ifam_index = ifp->if_index; 859 ifam->ifam_metric = ifa->ifa_metric; 860 ifam->ifam_flags = ifa->ifa_flags; 861 ifam->ifam_addrs = info.rti_addrs; 862 } 863 if ((cmd == RTM_ADD && pass == 2) || 864 (cmd == RTM_DELETE && pass == 1)) { 865 struct rt_msghdr *rtm; 866 867 if (rt == 0) 868 continue; 869 netmask = rt_mask(rt); 870 dst = sa = rt_key(rt); 871 gate = rt->rt_gateway; 872 if ((m = rt_msg1(cmd, &info)) == NULL) 873 continue; 874 rtm = mtod(m, struct rt_msghdr *); 875 rtm->rtm_index = ifp->if_index; 876 rtm->rtm_flags |= rt->rt_flags; 877 rtm->rtm_errno = error; 878 rtm->rtm_addrs = info.rti_addrs; 879 } 880 if (sa == NULL) 881 route_proto.sp_protocol = 0; 882 else 883 route_proto.sp_protocol = sa->sa_family; 884 raw_input(m, &route_proto, &route_src, &route_dst); 885 } 886 } 887 888 /* 889 * This is called to generate routing socket messages indicating 890 * network interface arrival and departure. 891 */ 892 void 893 rt_ifannouncemsg(struct ifnet *ifp, int what) 894 { 895 struct if_announcemsghdr *ifan; 896 struct mbuf *m; 897 struct rt_addrinfo info; 898 899 if (route_cb.any_count == 0) 900 return; 901 bzero(&info, sizeof(info)); 902 m = rt_msg1(RTM_IFANNOUNCE, &info); 903 if (m == 0) 904 return; 905 ifan = mtod(m, struct if_announcemsghdr *); 906 ifan->ifan_index = ifp->if_index; 907 strlcpy(ifan->ifan_name, ifp->if_xname, sizeof(ifan->ifan_name)); 908 ifan->ifan_what = what; 909 route_proto.sp_protocol = 0; 910 raw_input(m, &route_proto, &route_src, &route_dst); 911 } 912 913 /* 914 * This is used in dumping the kernel table via sysctl(). 915 */ 916 int 917 sysctl_dumpentry(struct radix_node *rn, void *v) 918 { 919 struct walkarg *w = v; 920 struct rtentry *rt = (struct rtentry *)rn; 921 int error = 0, size; 922 struct rt_addrinfo info; 923 struct sockaddr_rtlabel sa_rt; 924 const char *label; 925 926 if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg)) 927 return 0; 928 bzero(&info, sizeof(info)); 929 dst = rt_key(rt); 930 gate = rt->rt_gateway; 931 netmask = rt_mask(rt); 932 genmask = rt->rt_genmask; 933 if (rt->rt_ifp) { 934 ifpaddr = TAILQ_FIRST(&rt->rt_ifp->if_addrlist)->ifa_addr; 935 ifaaddr = rt->rt_ifa->ifa_addr; 936 if (rt->rt_ifp->if_flags & IFF_POINTOPOINT) 937 brdaddr = rt->rt_ifa->ifa_dstaddr; 938 } 939 if (rt->rt_labelid) { 940 bzero(&sa_rt, sizeof(sa_rt)); 941 sa_rt.sr_len = sizeof(sa_rt); 942 label = rtlabel_id2name(rt->rt_labelid); 943 if (label != NULL) { 944 strlcpy(sa_rt.sr_label, label, 945 sizeof(sa_rt.sr_label)); 946 info.rti_info[RTAX_LABEL] = 947 (struct sockaddr *)&sa_rt; 948 } 949 } 950 951 size = rt_msg2(RTM_GET, RTM_VERSION, &info, NULL, w); 952 if (w->w_where && w->w_tmem && w->w_needed <= 0) { 953 struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem; 954 955 rtm->rtm_flags = rt->rt_flags; 956 rtm->rtm_priority = rt->rt_priority; 957 rt_getmetrics(&rt->rt_rmx, &rtm->rtm_rmx); 958 rtm->rtm_rmx.rmx_refcnt = rt->rt_refcnt; 959 rtm->rtm_index = rt->rt_ifp->if_index; 960 rtm->rtm_addrs = info.rti_addrs; 961 if ((error = copyout(rtm, w->w_where, size)) != 0) 962 w->w_where = NULL; 963 else 964 w->w_where += size; 965 } 966 #ifndef SMALL_KERNEL 967 size = rt_msg2(RTM_GET, RTM_OVERSION, &info, NULL, w); 968 if (w->w_where && w->w_tmem && w->w_needed <= 0) { 969 struct rt_omsghdr *rtm = (struct rt_omsghdr *)w->w_tmem; 970 971 rtm->rtm_flags = rt->rt_flags; 972 rtm->rtm_rmx.rmx_locks = rt->rt_rmx.rmx_locks; 973 rtm->rtm_rmx.rmx_mtu = rt->rt_rmx.rmx_mtu; 974 rtm->rtm_index = rt->rt_ifp->if_index; 975 rtm->rtm_addrs = info.rti_addrs; 976 if ((error = copyout(rtm, w->w_where, size)) != 0) 977 w->w_where = NULL; 978 else 979 w->w_where += size; 980 } 981 #endif 982 return (error); 983 } 984 985 int 986 sysctl_iflist(int af, struct walkarg *w) 987 { 988 struct ifnet *ifp; 989 struct ifaddr *ifa; 990 struct rt_addrinfo info; 991 int len, error = 0; 992 993 bzero(&info, sizeof(info)); 994 TAILQ_FOREACH(ifp, &ifnet, if_list) { 995 if (w->w_arg && w->w_arg != ifp->if_index) 996 continue; 997 ifa = TAILQ_FIRST(&ifp->if_addrlist); 998 if (!ifa) 999 continue; 1000 ifpaddr = ifa->ifa_addr; 1001 len = rt_msg2(RTM_IFINFO, RTM_VERSION, &info, 0, w); 1002 if (w->w_where && w->w_tmem && w->w_needed <= 0) { 1003 struct if_msghdr *ifm; 1004 1005 ifm = (struct if_msghdr *)w->w_tmem; 1006 ifm->ifm_index = ifp->if_index; 1007 ifm->ifm_flags = ifp->if_flags; 1008 ifm->ifm_data = ifp->if_data; 1009 ifm->ifm_addrs = info.rti_addrs; 1010 error = copyout(ifm, w->w_where, len); 1011 if (error) 1012 return (error); 1013 w->w_where += len; 1014 } 1015 #ifndef SMALL_KERNEL 1016 len = rt_msg2(RTM_IFINFO, RTM_OVERSION, &info, 0, w); 1017 if (w->w_where && w->w_tmem && w->w_needed <= 0) { 1018 struct if_omsghdr *ifm; 1019 1020 ifm = (struct if_omsghdr *)w->w_tmem; 1021 ifm->ifm_index = ifp->if_index; 1022 ifm->ifm_flags = ifp->if_flags; 1023 /* just init the most important types of if_data */ 1024 ifm->ifm_data.ifi_type = ifp->if_data.ifi_type; 1025 ifm->ifm_data.ifi_addrlen = ifp->if_data.ifi_addrlen; 1026 ifm->ifm_data.ifi_hdrlen = ifp->if_data.ifi_hdrlen; 1027 ifm->ifm_data.ifi_link_state = 1028 ifp->if_data.ifi_link_state; 1029 ifm->ifm_data.ifi_mtu = ifp->if_data.ifi_mtu; 1030 ifm->ifm_data.ifi_metric = ifp->if_data.ifi_metric; 1031 if (ifp->if_data.ifi_baudrate > ULONG_MAX) 1032 ifm->ifm_data.ifi_baudrate = ULONG_MAX; 1033 else 1034 ifm->ifm_data.ifi_baudrate = 1035 ifp->if_data.ifi_baudrate; 1036 1037 ifm->ifm_addrs = info.rti_addrs; 1038 error = copyout(ifm, w->w_where, len); 1039 if (error) 1040 return (error); 1041 w->w_where += len; 1042 } 1043 #endif 1044 ifpaddr = 0; 1045 while ((ifa = TAILQ_NEXT(ifa, ifa_list)) != 1046 TAILQ_END(&ifp->if_addrlist)) { 1047 if (af && af != ifa->ifa_addr->sa_family) 1048 continue; 1049 ifaaddr = ifa->ifa_addr; 1050 netmask = ifa->ifa_netmask; 1051 brdaddr = ifa->ifa_dstaddr; 1052 len = rt_msg2(RTM_NEWADDR, RTM_VERSION, &info, 0, w); 1053 if (w->w_where && w->w_tmem && w->w_needed <= 0) { 1054 struct ifa_msghdr *ifam; 1055 1056 ifam = (struct ifa_msghdr *)w->w_tmem; 1057 ifam->ifam_index = ifa->ifa_ifp->if_index; 1058 ifam->ifam_flags = ifa->ifa_flags; 1059 ifam->ifam_metric = ifa->ifa_metric; 1060 ifam->ifam_addrs = info.rti_addrs; 1061 error = copyout(w->w_tmem, w->w_where, len); 1062 if (error) 1063 return (error); 1064 w->w_where += len; 1065 } 1066 #ifndef SMALL_KERNEL 1067 len = rt_msg2(RTM_NEWADDR, RTM_OVERSION, &info, 0, w); 1068 if (w->w_where && w->w_tmem && w->w_needed <= 0) { 1069 struct ifa_omsghdr *ifam; 1070 1071 ifam = (struct ifa_omsghdr *)w->w_tmem; 1072 ifam->ifam_index = ifa->ifa_ifp->if_index; 1073 ifam->ifam_flags = ifa->ifa_flags; 1074 ifam->ifam_metric = ifa->ifa_metric; 1075 ifam->ifam_addrs = info.rti_addrs; 1076 error = copyout(w->w_tmem, w->w_where, len); 1077 if (error) 1078 return (error); 1079 w->w_where += len; 1080 } 1081 #endif 1082 } 1083 ifaaddr = netmask = brdaddr = 0; 1084 } 1085 return (0); 1086 } 1087 1088 int 1089 sysctl_rtable(int *name, u_int namelen, void *where, size_t *given, void *new, 1090 size_t newlen) 1091 { 1092 struct radix_node_head *rnh; 1093 int i, s, error = EINVAL; 1094 u_char af; 1095 struct walkarg w; 1096 u_int tableid = 0; 1097 1098 if (new) 1099 return (EPERM); 1100 if (namelen < 3 || namelen > 4) 1101 return (EINVAL); 1102 af = name[0]; 1103 bzero(&w, sizeof(w)); 1104 w.w_where = where; 1105 w.w_given = *given; 1106 w.w_needed = 0 - w.w_given; 1107 w.w_op = name[1]; 1108 w.w_arg = name[2]; 1109 1110 if (namelen == 4) { 1111 tableid = name[3]; 1112 if (!rtable_exists(tableid)) 1113 return (EINVAL); 1114 } 1115 1116 s = splsoftnet(); 1117 switch (w.w_op) { 1118 1119 case NET_RT_DUMP: 1120 case NET_RT_FLAGS: 1121 for (i = 1; i <= AF_MAX; i++) 1122 if ((rnh = rt_gettable(i, tableid)) != NULL && 1123 (af == 0 || af == i) && 1124 (error = (*rnh->rnh_walktree)(rnh, 1125 sysctl_dumpentry, &w))) 1126 break; 1127 break; 1128 1129 case NET_RT_IFLIST: 1130 error = sysctl_iflist(af, &w); 1131 break; 1132 1133 case NET_RT_STATS: 1134 error = sysctl_rdstruct(where, given, new, 1135 &rtstat, sizeof(rtstat)); 1136 splx(s); 1137 return (error); 1138 } 1139 splx(s); 1140 if (w.w_tmem) 1141 free(w.w_tmem, M_RTABLE); 1142 w.w_needed += w.w_given; 1143 if (where) { 1144 *given = w.w_where - (caddr_t)where; 1145 if (*given < w.w_needed) 1146 return (ENOMEM); 1147 } else 1148 *given = (11 * w.w_needed) / 10; 1149 1150 return (error); 1151 } 1152 1153 #ifndef SMALL_KERNEL 1154 struct rt_msghdr * 1155 rtmsg_3to4(struct mbuf *m, int *len) 1156 { 1157 struct rt_msghdr *rtm; 1158 struct rt_omsghdr *ortm; 1159 int slen; 1160 1161 slen = *len - sizeof(struct rt_omsghdr); 1162 *len = sizeof(struct rt_msghdr) + slen; 1163 R_Malloc(rtm, struct rt_msghdr *, *len); 1164 if (rtm == 0) 1165 return (NULL); 1166 bzero(rtm, sizeof(struct rt_msghdr)); 1167 ortm = mtod(m, struct rt_omsghdr *); 1168 rtm->rtm_msglen = sizeof(struct rt_msghdr) + slen; 1169 rtm->rtm_version = RTM_VERSION; 1170 rtm->rtm_type = ortm->rtm_type; 1171 rtm->rtm_hdrlen = sizeof(struct rt_msghdr); 1172 rtm->rtm_index = ortm->rtm_index; 1173 rtm->rtm_tableid = 0; /* XXX we only care about the main table */ 1174 rtm->rtm_flags = ortm->rtm_flags; 1175 rtm->rtm_addrs = ortm->rtm_addrs; 1176 rtm->rtm_seq = ortm->rtm_seq; 1177 rtm->rtm_fmask = ortm->rtm_fmask; 1178 rtm->rtm_inits = ortm->rtm_inits; 1179 /* copy just the interesting stuff ignore the rest */ 1180 rtm->rtm_rmx.rmx_locks = ortm->rtm_rmx.rmx_locks; 1181 rtm->rtm_rmx.rmx_mtu = ortm->rtm_rmx.rmx_mtu; 1182 1183 m_copydata(m, sizeof(struct rt_omsghdr), slen, 1184 ((caddr_t)rtm + sizeof(struct rt_msghdr))); 1185 1186 return (rtm); 1187 } 1188 #endif 1189 1190 /* 1191 * Definitions of protocols supported in the ROUTE domain. 1192 */ 1193 1194 extern struct domain routedomain; /* or at least forward */ 1195 1196 struct protosw routesw[] = { 1197 { SOCK_RAW, &routedomain, 0, PR_ATOMIC|PR_ADDR, 1198 raw_input, route_output, raw_ctlinput, 0, 1199 route_usrreq, 1200 raw_init, 0, 0, 0, 1201 sysctl_rtable, 1202 } 1203 }; 1204 1205 struct domain routedomain = 1206 { PF_ROUTE, "route", route_init, 0, 0, 1207 routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] }; 1208