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