1 /* 2 * Copyright (c) 1988, 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * Copyright (C) 2017 THL A29 Limited, a Tencent company. 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 * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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 * Copied part from FreeBSD rtsock.c. 32 * 33 */ 34 35 #include <sys/param.h> 36 #include <sys/proc.h> 37 #include <sys/jail.h> 38 #include <sys/kernel.h> 39 #include <sys/domain.h> 40 #include <sys/lock.h> 41 #include <sys/malloc.h> 42 #include <sys/socket.h> 43 #include <sys/socketvar.h> 44 45 #include <net/if.h> 46 #include <net/if_var.h> 47 #include <net/if_dl.h> 48 #include <net/if_llatbl.h> 49 #include <net/if_types.h> 50 #include <net/route.h> 51 #include <net/route_var.h> 52 #include <netinet/if_ether.h> 53 54 #include "ff_api.h" 55 #include "ff_host_interface.h" 56 57 #ifndef _SOCKADDR_UNION_DEFINED 58 #define _SOCKADDR_UNION_DEFINED 59 /* 60 * The union of all possible address formats we handle. 61 */ 62 union sockaddr_union { 63 struct sockaddr sa; 64 struct sockaddr_in sin; 65 struct sockaddr_in6 sin6; 66 }; 67 #endif /* _SOCKADDR_UNION_DEFINED */ 68 69 static struct sockaddr sa_zero = { sizeof(sa_zero), AF_INET, }; 70 71 struct walkarg { 72 int w_tmemsize; 73 int w_op, w_arg; 74 caddr_t w_tmem; 75 struct sysctl_req *w_req; 76 }; 77 78 static int 79 rtm_get_jailed(struct rt_addrinfo *info, struct ifnet *ifp, 80 struct rtentry *rt, union sockaddr_union *saun, struct ucred *cred) 81 { 82 83 /* First, see if the returned address is part of the jail. */ 84 if (prison_if(cred, rt->rt_ifa->ifa_addr) == 0) { 85 info->rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; 86 return (0); 87 } 88 89 switch (info->rti_info[RTAX_DST]->sa_family) { 90 #ifdef INET 91 case AF_INET: 92 { 93 struct in_addr ia; 94 struct ifaddr *ifa; 95 int found; 96 97 found = 0; 98 /* 99 * Try to find an address on the given outgoing interface 100 * that belongs to the jail. 101 */ 102 IF_ADDR_RLOCK(ifp); 103 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 104 struct sockaddr *sa; 105 sa = ifa->ifa_addr; 106 if (sa->sa_family != AF_INET) 107 continue; 108 ia = ((struct sockaddr_in *)sa)->sin_addr; 109 if (prison_check_ip4(cred, &ia) == 0) { 110 found = 1; 111 break; 112 } 113 } 114 IF_ADDR_RUNLOCK(ifp); 115 if (!found) { 116 /* 117 * As a last resort return the 'default' jail address. 118 */ 119 ia = ((struct sockaddr_in *)rt->rt_ifa->ifa_addr)-> 120 sin_addr; 121 if (prison_get_ip4(cred, &ia) != 0) 122 return (ESRCH); 123 } 124 bzero(&saun->sin, sizeof(struct sockaddr_in)); 125 saun->sin.sin_len = sizeof(struct sockaddr_in); 126 saun->sin.sin_family = AF_INET; 127 saun->sin.sin_addr.s_addr = ia.s_addr; 128 info->rti_info[RTAX_IFA] = (struct sockaddr *)&saun->sin; 129 break; 130 } 131 #endif 132 #ifdef INET6 133 case AF_INET6: 134 { 135 struct in6_addr ia6; 136 struct ifaddr *ifa; 137 int found; 138 139 found = 0; 140 /* 141 * Try to find an address on the given outgoing interface 142 * that belongs to the jail. 143 */ 144 IF_ADDR_RLOCK(ifp); 145 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 146 struct sockaddr *sa; 147 sa = ifa->ifa_addr; 148 if (sa->sa_family != AF_INET6) 149 continue; 150 bcopy(&((struct sockaddr_in6 *)sa)->sin6_addr, 151 &ia6, sizeof(struct in6_addr)); 152 if (prison_check_ip6(cred, &ia6) == 0) { 153 found = 1; 154 break; 155 } 156 } 157 IF_ADDR_RUNLOCK(ifp); 158 if (!found) { 159 /* 160 * As a last resort return the 'default' jail address. 161 */ 162 ia6 = ((struct sockaddr_in6 *)rt->rt_ifa->ifa_addr)-> 163 sin6_addr; 164 if (prison_get_ip6(cred, &ia6) != 0) 165 return (ESRCH); 166 } 167 bzero(&saun->sin6, sizeof(struct sockaddr_in6)); 168 saun->sin6.sin6_len = sizeof(struct sockaddr_in6); 169 saun->sin6.sin6_family = AF_INET6; 170 bcopy(&ia6, &saun->sin6.sin6_addr, sizeof(struct in6_addr)); 171 if (sa6_recoverscope(&saun->sin6) != 0) 172 return (ESRCH); 173 info->rti_info[RTAX_IFA] = (struct sockaddr *)&saun->sin6; 174 break; 175 } 176 #endif 177 default: 178 return (ESRCH); 179 } 180 return (0); 181 } 182 183 /* 184 * Extract the addresses of the passed sockaddrs. 185 * Do a little sanity checking so as to avoid bad memory references. 186 * This data is derived straight from userland. 187 */ 188 static int 189 rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo) 190 { 191 struct sockaddr *sa; 192 int i; 193 194 for (i = 0; i < RTAX_MAX && cp < cplim; i++) { 195 if ((rtinfo->rti_addrs & (1 << i)) == 0) 196 continue; 197 sa = (struct sockaddr *)cp; 198 /* 199 * It won't fit. 200 */ 201 if (cp + sa->sa_len > cplim) 202 return (EINVAL); 203 /* 204 * there are no more.. quit now 205 * If there are more bits, they are in error. 206 * I've seen this. route(1) can evidently generate these. 207 * This causes kernel to core dump. 208 * for compatibility, If we see this, point to a safe address. 209 */ 210 if (sa->sa_len == 0) { 211 rtinfo->rti_info[i] = &sa_zero; 212 return (0); /* should be EINVAL but for compat */ 213 } 214 /* accept it */ 215 #ifdef INET6 216 if (sa->sa_family == AF_INET6) 217 sa6_embedscope((struct sockaddr_in6 *)sa, 218 V_ip6_use_defzone); 219 #endif 220 rtinfo->rti_info[i] = sa; 221 cp += SA_SIZE(sa); 222 } 223 return (0); 224 } 225 226 /* 227 * Writes information related to @rtinfo object to preallocated buffer. 228 * Stores needed size in @plen. If @w is NULL, calculates size without 229 * writing. 230 * Used for sysctl dumps and rtsock answers (RTM_DEL/RTM_GET) generation. 231 * 232 * Returns 0 on success. 233 * 234 */ 235 static int 236 rtsock_msg_buffer(int type, struct rt_addrinfo *rtinfo, struct walkarg *w, int *plen) 237 { 238 int i; 239 int len, buflen = 0, dlen; 240 caddr_t cp = NULL; 241 struct rt_msghdr *rtm = NULL; 242 #ifdef INET6 243 struct sockaddr_storage ss; 244 struct sockaddr_in6 *sin6; 245 #endif 246 247 switch (type) { 248 249 case RTM_DELADDR: 250 case RTM_NEWADDR: 251 if (w != NULL && w->w_op == NET_RT_IFLISTL) { 252 #ifdef COMPAT_FREEBSD32 253 if (w->w_req->flags & SCTL_MASK32) 254 len = sizeof(struct ifa_msghdrl32); 255 else 256 #endif 257 len = sizeof(struct ifa_msghdrl); 258 } else 259 len = sizeof(struct ifa_msghdr); 260 break; 261 262 case RTM_IFINFO: 263 #ifdef COMPAT_FREEBSD32 264 if (w != NULL && w->w_req->flags & SCTL_MASK32) { 265 if (w->w_op == NET_RT_IFLISTL) 266 len = sizeof(struct if_msghdrl32); 267 else 268 len = sizeof(struct if_msghdr32); 269 break; 270 } 271 #endif 272 if (w != NULL && w->w_op == NET_RT_IFLISTL) 273 len = sizeof(struct if_msghdrl); 274 else 275 len = sizeof(struct if_msghdr); 276 break; 277 278 case RTM_NEWMADDR: 279 len = sizeof(struct ifma_msghdr); 280 break; 281 282 default: 283 len = sizeof(struct rt_msghdr); 284 } 285 286 if (w != NULL) { 287 rtm = (struct rt_msghdr *)w->w_tmem; 288 buflen = w->w_tmemsize - len; 289 cp = (caddr_t)w->w_tmem + len; 290 } 291 292 rtinfo->rti_addrs = 0; 293 for (i = 0; i < RTAX_MAX; i++) { 294 struct sockaddr *sa; 295 296 if ((sa = rtinfo->rti_info[i]) == NULL) 297 continue; 298 rtinfo->rti_addrs |= (1 << i); 299 dlen = SA_SIZE(sa); 300 if (cp != NULL && buflen >= dlen) { 301 #ifdef INET6 302 if (V_deembed_scopeid && sa->sa_family == AF_INET6) { 303 sin6 = (struct sockaddr_in6 *)&ss; 304 bcopy(sa, sin6, sizeof(*sin6)); 305 if (sa6_recoverscope(sin6) == 0) 306 sa = (struct sockaddr *)sin6; 307 } 308 #endif 309 bcopy((caddr_t)sa, cp, (unsigned)dlen); 310 cp += dlen; 311 buflen -= dlen; 312 } else if (cp != NULL) { 313 /* 314 * Buffer too small. Count needed size 315 * and return with error. 316 */ 317 cp = NULL; 318 } 319 320 len += dlen; 321 } 322 323 if (cp != NULL) { 324 dlen = ALIGN(len) - len; 325 if (buflen < dlen) 326 cp = NULL; 327 else 328 buflen -= dlen; 329 } 330 len = ALIGN(len); 331 332 if (cp != NULL) { 333 /* fill header iff buffer is large enough */ 334 rtm->rtm_version = RTM_VERSION; 335 rtm->rtm_type = type; 336 rtm->rtm_msglen = len; 337 } 338 339 *plen = len; 340 341 if (w != NULL && cp == NULL) 342 return (ENOBUFS); 343 344 return (0); 345 } 346 347 /* 348 * Fill in @dmask with valid netmask leaving original @smask 349 * intact. Mostly used with radix netmasks. 350 */ 351 static struct sockaddr * 352 rtsock_fix_netmask(struct sockaddr *dst, struct sockaddr *smask, 353 struct sockaddr_storage *dmask) 354 { 355 if (dst == NULL || smask == NULL) 356 return (NULL); 357 358 memset(dmask, 0, dst->sa_len); 359 memcpy(dmask, smask, smask->sa_len); 360 dmask->ss_len = dst->sa_len; 361 dmask->ss_family = dst->sa_family; 362 363 return ((struct sockaddr *)dmask); 364 } 365 366 static void 367 rt_getmetrics(const struct rtentry *rt, struct rt_metrics *out) 368 { 369 370 bzero(out, sizeof(*out)); 371 out->rmx_mtu = rt->rt_mtu; 372 out->rmx_weight = rt->rt_weight; 373 out->rmx_pksent = counter_u64_fetch(rt->rt_pksent); 374 /* Kernel -> userland timebase conversion. */ 375 out->rmx_expire = rt->rt_expire ? 376 rt->rt_expire - time_uptime + time_second : 0; 377 } 378 379 int 380 ff_rtioctl(int fibnum, void *data, unsigned *plen, unsigned maxlen) 381 { 382 struct rt_msghdr *rtm = NULL; 383 struct rtentry *rt = NULL; 384 struct rib_head *rnh; 385 struct rt_addrinfo info; 386 union sockaddr_union saun; 387 sa_family_t saf = AF_UNSPEC; 388 struct sockaddr_storage ss; 389 struct walkarg w; 390 int error = 0, alloc_len = 0, len; 391 struct ifnet *ifp = NULL; 392 393 #ifdef INET6 394 struct sockaddr_in6 *sin6; 395 int i, rti_need_deembed = 0; 396 #endif 397 398 #define senderr(e) { error = e; goto flush;} 399 400 len = *plen; 401 /* 402 * Most of current messages are in range 200-240 bytes, 403 * minimize possible re-allocation on reply using larger size 404 * buffer aligned on 1k boundaty. 405 */ 406 alloc_len = roundup2(len, 1024); 407 if ((rtm = malloc(alloc_len, M_TEMP, M_NOWAIT)) == NULL) 408 senderr(ENOBUFS); 409 bcopy(data, (caddr_t)rtm, len); 410 411 if (len < sizeof(*rtm) || len != rtm->rtm_msglen) 412 senderr(EINVAL); 413 414 bzero(&info, sizeof(info)); 415 bzero(&w, sizeof(w)); 416 417 if (rtm->rtm_version != RTM_VERSION) 418 senderr(EPROTONOSUPPORT); 419 420 /* 421 * Starting from here, it is possible 422 * to alter original message and insert 423 * caller PID and error value. 424 */ 425 426 rtm->rtm_pid = curproc->p_pid; 427 info.rti_addrs = rtm->rtm_addrs; 428 429 info.rti_mflags = rtm->rtm_inits; 430 info.rti_rmx = &rtm->rtm_rmx; 431 432 /* 433 * rt_xaddrs() performs s6_addr[2] := sin6_scope_id for AF_INET6 434 * link-local address because rtrequest requires addresses with 435 * embedded scope id. 436 */ 437 if (rt_xaddrs((caddr_t)(rtm + 1), len + (caddr_t)rtm, &info)) 438 senderr(EINVAL); 439 440 info.rti_flags = rtm->rtm_flags; 441 if (info.rti_info[RTAX_DST] == NULL || 442 info.rti_info[RTAX_DST]->sa_family >= AF_MAX || 443 (info.rti_info[RTAX_GATEWAY] != NULL && 444 info.rti_info[RTAX_GATEWAY]->sa_family >= AF_MAX)) 445 senderr(EINVAL); 446 saf = info.rti_info[RTAX_DST]->sa_family; 447 448 /* 449 * The given gateway address may be an interface address. 450 * For example, issuing a "route change" command on a route 451 * entry that was created from a tunnel, and the gateway 452 * address given is the local end point. In this case the 453 * RTF_GATEWAY flag must be cleared or the destination will 454 * not be reachable even though there is no error message. 455 */ 456 if (info.rti_info[RTAX_GATEWAY] != NULL && 457 info.rti_info[RTAX_GATEWAY]->sa_family != AF_LINK) { 458 struct rt_addrinfo ginfo; 459 struct sockaddr *gdst; 460 461 bzero(&ginfo, sizeof(ginfo)); 462 bzero(&ss, sizeof(ss)); 463 ss.ss_len = sizeof(ss); 464 465 ginfo.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&ss; 466 gdst = info.rti_info[RTAX_GATEWAY]; 467 468 /* 469 * A host route through the loopback interface is 470 * installed for each interface adddress. In pre 8.0 471 * releases the interface address of a PPP link type 472 * is not reachable locally. This behavior is fixed as 473 * part of the new L2/L3 redesign and rewrite work. The 474 * signature of this interface address route is the 475 * AF_LINK sa_family type of the rt_gateway, and the 476 * rt_ifp has the IFF_LOOPBACK flag set. 477 */ 478 if (rib_lookup_info(fibnum, gdst, NHR_REF, 0, &ginfo) == 0) { 479 if (ss.ss_family == AF_LINK && 480 ginfo.rti_ifp->if_flags & IFF_LOOPBACK) { 481 info.rti_flags &= ~RTF_GATEWAY; 482 info.rti_flags |= RTF_GWFLAG_COMPAT; 483 } 484 rib_free_info(&ginfo); 485 } 486 } 487 488 switch (rtm->rtm_type) { 489 struct rtentry *saved_nrt; 490 491 case RTM_ADD: 492 case RTM_CHANGE: 493 if (info.rti_info[RTAX_GATEWAY] == NULL) 494 senderr(EINVAL); 495 saved_nrt = NULL; 496 497 /* support for new ARP code */ 498 if (info.rti_info[RTAX_GATEWAY]->sa_family == AF_LINK && 499 (rtm->rtm_flags & RTF_LLDATA) != 0) { 500 error = lla_rt_output(rtm, &info); 501 #ifdef INET6 502 if (error == 0) 503 rti_need_deembed = (V_deembed_scopeid) ? 1 : 0; 504 #endif 505 break; 506 } 507 error = rtrequest1_fib(rtm->rtm_type, &info, &saved_nrt, 508 fibnum); 509 if (error == 0 && saved_nrt != NULL) { 510 #ifdef INET6 511 rti_need_deembed = (V_deembed_scopeid) ? 1 : 0; 512 #endif 513 RT_LOCK(saved_nrt); 514 rtm->rtm_index = saved_nrt->rt_ifp->if_index; 515 RT_REMREF(saved_nrt); 516 RT_UNLOCK(saved_nrt); 517 } 518 break; 519 520 case RTM_DELETE: 521 saved_nrt = NULL; 522 /* support for new ARP code */ 523 if (info.rti_info[RTAX_GATEWAY] && 524 (info.rti_info[RTAX_GATEWAY]->sa_family == AF_LINK) && 525 (rtm->rtm_flags & RTF_LLDATA) != 0) { 526 error = lla_rt_output(rtm, &info); 527 #ifdef INET6 528 if (error == 0) 529 rti_need_deembed = (V_deembed_scopeid) ? 1 : 0; 530 #endif 531 break; 532 } 533 error = rtrequest1_fib(RTM_DELETE, &info, &saved_nrt, fibnum); 534 if (error == 0) { 535 RT_LOCK(saved_nrt); 536 rt = saved_nrt; 537 goto report; 538 } 539 #ifdef INET6 540 /* rt_msg2() will not be used when RTM_DELETE fails. */ 541 rti_need_deembed = (V_deembed_scopeid) ? 1 : 0; 542 #endif 543 break; 544 545 case RTM_GET: 546 rnh = rt_tables_get_rnh(fibnum, saf); 547 if (rnh == NULL) 548 senderr(EAFNOSUPPORT); 549 550 RIB_RLOCK(rnh); 551 552 if (info.rti_info[RTAX_NETMASK] == NULL && 553 rtm->rtm_type == RTM_GET) { 554 /* 555 * Provide logest prefix match for 556 * address lookup (no mask). 557 * 'route -n get addr' 558 */ 559 rt = (struct rtentry *) rnh->rnh_matchaddr( 560 info.rti_info[RTAX_DST], &rnh->head); 561 } else 562 rt = (struct rtentry *) rnh->rnh_lookup( 563 info.rti_info[RTAX_DST], 564 info.rti_info[RTAX_NETMASK], &rnh->head); 565 566 if (rt == NULL) { 567 RIB_RUNLOCK(rnh); 568 senderr(ESRCH); 569 } 570 #ifdef RADIX_MPATH 571 /* 572 * for RTM_CHANGE/LOCK, if we got multipath routes, 573 * we require users to specify a matching RTAX_GATEWAY. 574 * 575 * for RTM_GET, gate is optional even with multipath. 576 * if gate == NULL the first match is returned. 577 * (no need to call rt_mpath_matchgate if gate == NULL) 578 */ 579 if (rt_mpath_capable(rnh) && 580 (rtm->rtm_type != RTM_GET || info.rti_info[RTAX_GATEWAY])) { 581 rt = rt_mpath_matchgate(rt, info.rti_info[RTAX_GATEWAY]); 582 if (!rt) { 583 RIB_RUNLOCK(rnh); 584 senderr(ESRCH); 585 } 586 } 587 #endif 588 /* 589 * If performing proxied L2 entry insertion, and 590 * the actual PPP host entry is found, perform 591 * another search to retrieve the prefix route of 592 * the local end point of the PPP link. 593 */ 594 if (rtm->rtm_flags & RTF_ANNOUNCE) { 595 struct sockaddr laddr; 596 597 if (rt->rt_ifp != NULL && 598 rt->rt_ifp->if_type == IFT_PROPVIRTUAL) { 599 struct ifaddr *ifa; 600 601 ifa = ifa_ifwithnet(info.rti_info[RTAX_DST], 1, 602 RT_ALL_FIBS); 603 if (ifa != NULL) 604 rt_maskedcopy(ifa->ifa_addr, 605 &laddr, 606 ifa->ifa_netmask); 607 } else 608 rt_maskedcopy(rt->rt_ifa->ifa_addr, 609 &laddr, 610 rt->rt_ifa->ifa_netmask); 611 /* 612 * refactor rt and no lock operation necessary 613 */ 614 rt = (struct rtentry *)rnh->rnh_matchaddr(&laddr, 615 &rnh->head); 616 if (rt == NULL) { 617 RIB_RUNLOCK(rnh); 618 senderr(ESRCH); 619 } 620 } 621 RT_LOCK(rt); 622 RT_ADDREF(rt); 623 RIB_RUNLOCK(rnh); 624 625 report: 626 RT_LOCK_ASSERT(rt); 627 if ((rt->rt_flags & RTF_HOST) == 0 628 ? jailed_without_vnet(curthread->td_ucred) 629 : prison_if(curthread->td_ucred, 630 rt_key(rt)) != 0) { 631 RT_UNLOCK(rt); 632 senderr(ESRCH); 633 } 634 info.rti_info[RTAX_DST] = rt_key(rt); 635 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 636 info.rti_info[RTAX_NETMASK] = rtsock_fix_netmask(rt_key(rt), 637 rt_mask(rt), &ss); 638 info.rti_info[RTAX_GENMASK] = 0; 639 if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) { 640 ifp = rt->rt_ifp; 641 if (ifp) { 642 info.rti_info[RTAX_IFP] = 643 ifp->if_addr->ifa_addr; 644 error = rtm_get_jailed(&info, ifp, rt, 645 &saun, curthread->td_ucred); 646 if (error != 0) { 647 RT_UNLOCK(rt); 648 senderr(error); 649 } 650 if (ifp->if_flags & IFF_POINTOPOINT) 651 info.rti_info[RTAX_BRD] = 652 rt->rt_ifa->ifa_dstaddr; 653 rtm->rtm_index = ifp->if_index; 654 } else { 655 info.rti_info[RTAX_IFP] = NULL; 656 info.rti_info[RTAX_IFA] = NULL; 657 } 658 } else if ((ifp = rt->rt_ifp) != NULL) { 659 rtm->rtm_index = ifp->if_index; 660 } 661 662 /* Check if we need to realloc storage */ 663 rtsock_msg_buffer(rtm->rtm_type, &info, NULL, &len); 664 if (len > maxlen) { 665 RT_UNLOCK(rt); 666 senderr(ENOBUFS); 667 } 668 669 if (len > alloc_len) { 670 struct rt_msghdr *new_rtm; 671 new_rtm = malloc(len, M_TEMP, M_NOWAIT); 672 if (new_rtm == NULL) { 673 RT_UNLOCK(rt); 674 senderr(ENOBUFS); 675 } 676 bcopy(rtm, new_rtm, rtm->rtm_msglen); 677 free(rtm, M_TEMP); 678 rtm = new_rtm; 679 alloc_len = len; 680 } 681 682 w.w_tmem = (caddr_t)rtm; 683 w.w_tmemsize = alloc_len; 684 rtsock_msg_buffer(rtm->rtm_type, &info, &w, &len); 685 686 if (rt->rt_flags & RTF_GWFLAG_COMPAT) 687 rtm->rtm_flags = RTF_GATEWAY | 688 (rt->rt_flags & ~RTF_GWFLAG_COMPAT); 689 else 690 rtm->rtm_flags = rt->rt_flags; 691 rt_getmetrics(rt, &rtm->rtm_rmx); 692 rtm->rtm_addrs = info.rti_addrs; 693 694 RT_UNLOCK(rt); 695 break; 696 697 default: 698 senderr(EOPNOTSUPP); 699 } 700 701 flush: 702 if (rt != NULL) 703 RTFREE(rt); 704 705 if (rtm != NULL) { 706 #ifdef INET6 707 if (rti_need_deembed) { 708 /* sin6_scope_id is recovered before sending rtm. */ 709 sin6 = (struct sockaddr_in6 *)&ss; 710 for (i = 0; i < RTAX_MAX; i++) { 711 if (info.rti_info[i] == NULL) 712 continue; 713 if (info.rti_info[i]->sa_family != AF_INET6) 714 continue; 715 bcopy(info.rti_info[i], sin6, sizeof(*sin6)); 716 if (sa6_recoverscope(sin6) == 0) 717 bcopy(sin6, info.rti_info[i], 718 sizeof(*sin6)); 719 } 720 } 721 #endif 722 if (error != 0) 723 rtm->rtm_errno = error; 724 else 725 rtm->rtm_flags |= RTF_DONE; 726 727 bcopy((caddr_t)rtm, data, rtm->rtm_msglen); 728 *plen = rtm->rtm_msglen; 729 free(rtm, M_TEMP); 730 } 731 732 return (error); 733 } 734