1 /* $NetBSD: ip_icmp.c,v 1.26 1997/10/29 05:28:44 kml Exp $ */ 2 3 /* 4 * Copyright (c) 1982, 1986, 1988, 1993 5 * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94 36 */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/malloc.h> 41 #include <sys/mbuf.h> 42 #include <sys/protosw.h> 43 #include <sys/socket.h> 44 #include <sys/time.h> 45 #include <sys/kernel.h> 46 #include <sys/proc.h> 47 48 #include <vm/vm.h> 49 #include <sys/sysctl.h> 50 51 #include <net/if.h> 52 #include <net/route.h> 53 54 #include <netinet/in.h> 55 #include <netinet/in_systm.h> 56 #include <netinet/in_var.h> 57 #include <netinet/ip.h> 58 #include <netinet/ip_icmp.h> 59 #include <netinet/ip_var.h> 60 #include <netinet/icmp_var.h> 61 62 #include <machine/stdarg.h> 63 64 /* 65 * ICMP routines: error generation, receive packet processing, and 66 * routines to turnaround packets back to the originator, and 67 * host table maintenance routines. 68 */ 69 70 int icmpmaskrepl = 0; 71 #ifdef ICMPPRINTFS 72 int icmpprintfs = 0; 73 #endif 74 75 extern struct protosw inetsw[]; 76 77 static void icmp_mtudisc __P((struct icmp *)); 78 79 /* 80 * Generate an error packet of type error 81 * in response to bad packet ip. 82 */ 83 void 84 icmp_error(n, type, code, dest, destifp) 85 struct mbuf *n; 86 int type, code; 87 n_long dest; 88 struct ifnet *destifp; 89 { 90 register struct ip *oip = mtod(n, struct ip *), *nip; 91 register unsigned oiplen = oip->ip_hl << 2; 92 register struct icmp *icp; 93 register struct mbuf *m; 94 unsigned icmplen; 95 96 #ifdef ICMPPRINTFS 97 if (icmpprintfs) 98 printf("icmp_error(%x, %d, %d)\n", oip, type, code); 99 #endif 100 if (type != ICMP_REDIRECT) 101 icmpstat.icps_error++; 102 /* 103 * Don't send error if not the first fragment of message. 104 * Don't error if the old packet protocol was ICMP 105 * error message, only known informational types. 106 */ 107 if (oip->ip_off &~ (IP_MF|IP_DF)) 108 goto freeit; 109 if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT && 110 n->m_len >= oiplen + ICMP_MINLEN && 111 !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) { 112 icmpstat.icps_oldicmp++; 113 goto freeit; 114 } 115 /* Don't send error in response to a multicast or broadcast packet */ 116 if (n->m_flags & (M_BCAST|M_MCAST)) 117 goto freeit; 118 /* 119 * First, formulate icmp message 120 */ 121 m = m_gethdr(M_DONTWAIT, MT_HEADER); 122 if (m == NULL) 123 goto freeit; 124 icmplen = oiplen + min(8, oip->ip_len); 125 m->m_len = icmplen + ICMP_MINLEN; 126 MH_ALIGN(m, m->m_len); 127 icp = mtod(m, struct icmp *); 128 if ((u_int)type > ICMP_MAXTYPE) 129 panic("icmp_error"); 130 icmpstat.icps_outhist[type]++; 131 icp->icmp_type = type; 132 if (type == ICMP_REDIRECT) 133 icp->icmp_gwaddr.s_addr = dest; 134 else { 135 icp->icmp_void = 0; 136 /* 137 * The following assignments assume an overlay with the 138 * zeroed icmp_void field. 139 */ 140 if (type == ICMP_PARAMPROB) { 141 icp->icmp_pptr = code; 142 code = 0; 143 } else if (type == ICMP_UNREACH && 144 code == ICMP_UNREACH_NEEDFRAG && destifp) 145 icp->icmp_nextmtu = htons(destifp->if_mtu); 146 } 147 148 icp->icmp_code = code; 149 bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen); 150 nip = &icp->icmp_ip; 151 nip->ip_len = htons((u_int16_t)(nip->ip_len + oiplen)); 152 153 /* 154 * Now, copy old ip header (without options) 155 * in front of icmp message. 156 */ 157 if (m->m_data - sizeof(struct ip) < m->m_pktdat) 158 panic("icmp len"); 159 m->m_data -= sizeof(struct ip); 160 m->m_len += sizeof(struct ip); 161 m->m_pkthdr.len = m->m_len; 162 m->m_pkthdr.rcvif = n->m_pkthdr.rcvif; 163 nip = mtod(m, struct ip *); 164 bcopy((caddr_t)oip, (caddr_t)nip, sizeof(struct ip)); 165 nip->ip_len = m->m_len; 166 nip->ip_hl = sizeof(struct ip) >> 2; 167 nip->ip_p = IPPROTO_ICMP; 168 nip->ip_tos = 0; 169 icmp_reflect(m); 170 171 freeit: 172 m_freem(n); 173 } 174 175 static struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET }; 176 static struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET }; 177 static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET }; 178 struct sockaddr_in icmpmask = { 8, 0 }; 179 180 /* 181 * Process a received ICMP message. 182 */ 183 void 184 #if __STDC__ 185 icmp_input(struct mbuf *m, ...) 186 #else 187 icmp_input(m, va_alist) 188 struct mbuf *m; 189 va_dcl 190 #endif 191 { 192 register struct icmp *icp; 193 register struct ip *ip = mtod(m, struct ip *); 194 int icmplen = ip->ip_len; 195 register int i; 196 struct in_ifaddr *ia; 197 void *(*ctlfunc) __P((int, struct sockaddr *, void *)); 198 int code; 199 extern u_char ip_protox[]; 200 int hlen; 201 va_list ap; 202 203 va_start(ap, m); 204 hlen = va_arg(ap, int); 205 va_end(ap); 206 207 /* 208 * Locate icmp structure in mbuf, and check 209 * that not corrupted and of at least minimum length. 210 */ 211 #ifdef ICMPPRINTFS 212 if (icmpprintfs) 213 printf("icmp_input from %x to %x, len %d\n", 214 ntohl(ip->ip_src.s_addr), ntohl(ip->ip_dst.s_addr), 215 icmplen); 216 #endif 217 if (icmplen < ICMP_MINLEN) { 218 icmpstat.icps_tooshort++; 219 goto freeit; 220 } 221 i = hlen + min(icmplen, ICMP_ADVLENMIN); 222 if (m->m_len < i && (m = m_pullup(m, i)) == 0) { 223 icmpstat.icps_tooshort++; 224 return; 225 } 226 ip = mtod(m, struct ip *); 227 m->m_len -= hlen; 228 m->m_data += hlen; 229 icp = mtod(m, struct icmp *); 230 if (in_cksum(m, icmplen)) { 231 icmpstat.icps_checksum++; 232 goto freeit; 233 } 234 m->m_len += hlen; 235 m->m_data -= hlen; 236 237 #ifdef ICMPPRINTFS 238 /* 239 * Message type specific processing. 240 */ 241 if (icmpprintfs) 242 printf("icmp_input, type %d code %d\n", icp->icmp_type, 243 icp->icmp_code); 244 #endif 245 if (icp->icmp_type > ICMP_MAXTYPE) 246 goto raw; 247 icmpstat.icps_inhist[icp->icmp_type]++; 248 code = icp->icmp_code; 249 switch (icp->icmp_type) { 250 251 case ICMP_UNREACH: 252 switch (code) { 253 case ICMP_UNREACH_NET: 254 case ICMP_UNREACH_HOST: 255 case ICMP_UNREACH_PROTOCOL: 256 case ICMP_UNREACH_PORT: 257 case ICMP_UNREACH_SRCFAIL: 258 code += PRC_UNREACH_NET; 259 break; 260 261 case ICMP_UNREACH_NEEDFRAG: 262 code = PRC_MSGSIZE; 263 break; 264 265 case ICMP_UNREACH_NET_UNKNOWN: 266 case ICMP_UNREACH_NET_PROHIB: 267 case ICMP_UNREACH_TOSNET: 268 code = PRC_UNREACH_NET; 269 break; 270 271 case ICMP_UNREACH_HOST_UNKNOWN: 272 case ICMP_UNREACH_ISOLATED: 273 case ICMP_UNREACH_HOST_PROHIB: 274 case ICMP_UNREACH_TOSHOST: 275 code = PRC_UNREACH_HOST; 276 break; 277 278 default: 279 goto badcode; 280 } 281 goto deliver; 282 283 case ICMP_TIMXCEED: 284 if (code > 1) 285 goto badcode; 286 code += PRC_TIMXCEED_INTRANS; 287 goto deliver; 288 289 case ICMP_PARAMPROB: 290 if (code > 1) 291 goto badcode; 292 code = PRC_PARAMPROB; 293 goto deliver; 294 295 case ICMP_SOURCEQUENCH: 296 if (code) 297 goto badcode; 298 code = PRC_QUENCH; 299 goto deliver; 300 301 deliver: 302 /* 303 * Problem with datagram; advise higher level routines. 304 */ 305 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) || 306 icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) { 307 icmpstat.icps_badlen++; 308 goto freeit; 309 } 310 if (IN_MULTICAST(icp->icmp_ip.ip_dst.s_addr)) 311 goto badcode; 312 NTOHS(icp->icmp_ip.ip_len); 313 #ifdef ICMPPRINTFS 314 if (icmpprintfs) 315 printf("deliver to protocol %d\n", icp->icmp_ip.ip_p); 316 #endif 317 icmpsrc.sin_addr = icp->icmp_ip.ip_dst; 318 if (code == PRC_MSGSIZE && ip_mtudisc) 319 icmp_mtudisc(icp); 320 ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput; 321 if (ctlfunc) 322 (*ctlfunc)(code, sintosa(&icmpsrc), &icp->icmp_ip); 323 break; 324 325 badcode: 326 icmpstat.icps_badcode++; 327 break; 328 329 case ICMP_ECHO: 330 icp->icmp_type = ICMP_ECHOREPLY; 331 goto reflect; 332 333 case ICMP_TSTAMP: 334 if (icmplen < ICMP_TSLEN) { 335 icmpstat.icps_badlen++; 336 break; 337 } 338 icp->icmp_type = ICMP_TSTAMPREPLY; 339 icp->icmp_rtime = iptime(); 340 icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */ 341 goto reflect; 342 343 case ICMP_MASKREQ: 344 if (icmpmaskrepl == 0) 345 break; 346 /* 347 * We are not able to respond with all ones broadcast 348 * unless we receive it over a point-to-point interface. 349 */ 350 if (icmplen < ICMP_MASKLEN) { 351 icmpstat.icps_badlen++; 352 break; 353 } 354 if (ip->ip_dst.s_addr == INADDR_BROADCAST || 355 in_nullhost(ip->ip_dst)) 356 icmpdst.sin_addr = ip->ip_src; 357 else 358 icmpdst.sin_addr = ip->ip_dst; 359 ia = ifatoia(ifaof_ifpforaddr(sintosa(&icmpdst), 360 m->m_pkthdr.rcvif)); 361 if (ia == 0) 362 break; 363 icp->icmp_type = ICMP_MASKREPLY; 364 icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr; 365 if (in_nullhost(ip->ip_src)) { 366 if (ia->ia_ifp->if_flags & IFF_BROADCAST) 367 ip->ip_src = ia->ia_broadaddr.sin_addr; 368 else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT) 369 ip->ip_src = ia->ia_dstaddr.sin_addr; 370 } 371 reflect: 372 ip->ip_len += hlen; /* since ip_input deducts this */ 373 icmpstat.icps_reflect++; 374 icmpstat.icps_outhist[icp->icmp_type]++; 375 icmp_reflect(m); 376 return; 377 378 case ICMP_REDIRECT: 379 if (code > 3) 380 goto badcode; 381 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) || 382 icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) { 383 icmpstat.icps_badlen++; 384 break; 385 } 386 /* 387 * Short circuit routing redirects to force 388 * immediate change in the kernel's routing 389 * tables. The message is also handed to anyone 390 * listening on a raw socket (e.g. the routing 391 * daemon for use in updating its tables). 392 */ 393 icmpgw.sin_addr = ip->ip_src; 394 icmpdst.sin_addr = icp->icmp_gwaddr; 395 #ifdef ICMPPRINTFS 396 if (icmpprintfs) 397 printf("redirect dst %x to %x\n", icp->icmp_ip.ip_dst, 398 icp->icmp_gwaddr); 399 #endif 400 icmpsrc.sin_addr = icp->icmp_ip.ip_dst; 401 rtredirect(sintosa(&icmpsrc), sintosa(&icmpdst), 402 (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST, 403 sintosa(&icmpgw), (struct rtentry **)0); 404 pfctlinput(PRC_REDIRECT_HOST, sintosa(&icmpsrc)); 405 break; 406 407 /* 408 * No kernel processing for the following; 409 * just fall through to send to raw listener. 410 */ 411 case ICMP_ECHOREPLY: 412 case ICMP_ROUTERADVERT: 413 case ICMP_ROUTERSOLICIT: 414 case ICMP_TSTAMPREPLY: 415 case ICMP_IREQREPLY: 416 case ICMP_MASKREPLY: 417 default: 418 break; 419 } 420 421 raw: 422 rip_input(m); 423 return; 424 425 freeit: 426 m_freem(m); 427 } 428 429 /* 430 * Reflect the ip packet back to the source 431 */ 432 void 433 icmp_reflect(m) 434 struct mbuf *m; 435 { 436 register struct ip *ip = mtod(m, struct ip *); 437 register struct in_ifaddr *ia; 438 struct in_addr t; 439 struct mbuf *opts = 0; 440 int optlen = (ip->ip_hl << 2) - sizeof(struct ip); 441 442 if (!in_canforward(ip->ip_src) && 443 ((ip->ip_src.s_addr & IN_CLASSA_NET) != 444 htonl(IN_LOOPBACKNET << IN_CLASSA_NSHIFT))) { 445 m_freem(m); /* Bad return address */ 446 goto done; /* ip_output() will check for broadcast */ 447 } 448 t = ip->ip_dst; 449 ip->ip_dst = ip->ip_src; 450 /* 451 * If the incoming packet was addressed directly to us, 452 * use dst as the src for the reply. Otherwise (broadcast 453 * or anonymous), use the address which corresponds 454 * to the incoming interface. 455 */ 456 for (ia = in_ifaddr.tqh_first; ia; ia = ia->ia_list.tqe_next) { 457 if (in_hosteq(t, ia->ia_addr.sin_addr)) 458 break; 459 if ((ia->ia_ifp->if_flags & IFF_BROADCAST) && 460 in_hosteq(t, ia->ia_broadaddr.sin_addr)) 461 break; 462 } 463 icmpdst.sin_addr = t; 464 if (ia == (struct in_ifaddr *)0) 465 ia = ifatoia(ifaof_ifpforaddr(sintosa(&icmpdst), 466 m->m_pkthdr.rcvif)); 467 /* 468 * The following happens if the packet was not addressed to us, 469 * and was received on an interface with no IP address. 470 */ 471 if (ia == (struct in_ifaddr *)0) 472 ia = in_ifaddr.tqh_first; 473 t = ia->ia_addr.sin_addr; 474 ip->ip_src = t; 475 ip->ip_ttl = MAXTTL; 476 477 if (optlen > 0) { 478 register u_char *cp; 479 int opt, cnt; 480 u_int len; 481 482 /* 483 * Retrieve any source routing from the incoming packet; 484 * add on any record-route or timestamp options. 485 */ 486 cp = (u_char *) (ip + 1); 487 if ((opts = ip_srcroute()) == 0 && 488 (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) { 489 opts->m_len = sizeof(struct in_addr); 490 *mtod(opts, struct in_addr *) = zeroin_addr; 491 } 492 if (opts) { 493 #ifdef ICMPPRINTFS 494 if (icmpprintfs) 495 printf("icmp_reflect optlen %d rt %d => ", 496 optlen, opts->m_len); 497 #endif 498 for (cnt = optlen; cnt > 0; cnt -= len, cp += len) { 499 opt = cp[IPOPT_OPTVAL]; 500 if (opt == IPOPT_EOL) 501 break; 502 if (opt == IPOPT_NOP) 503 len = 1; 504 else { 505 len = cp[IPOPT_OLEN]; 506 if (len <= 0 || len > cnt) 507 break; 508 } 509 /* 510 * Should check for overflow, but it "can't happen" 511 */ 512 if (opt == IPOPT_RR || opt == IPOPT_TS || 513 opt == IPOPT_SECURITY) { 514 bcopy((caddr_t)cp, 515 mtod(opts, caddr_t) + opts->m_len, len); 516 opts->m_len += len; 517 } 518 } 519 /* Terminate & pad, if necessary */ 520 if ((cnt = opts->m_len % 4) != 0) { 521 for (; cnt < 4; cnt++) { 522 *(mtod(opts, caddr_t) + opts->m_len) = 523 IPOPT_EOL; 524 opts->m_len++; 525 } 526 } 527 #ifdef ICMPPRINTFS 528 if (icmpprintfs) 529 printf("%d\n", opts->m_len); 530 #endif 531 } 532 /* 533 * Now strip out original options by copying rest of first 534 * mbuf's data back, and adjust the IP length. 535 */ 536 ip->ip_len -= optlen; 537 ip->ip_hl = sizeof(struct ip) >> 2; 538 m->m_len -= optlen; 539 if (m->m_flags & M_PKTHDR) 540 m->m_pkthdr.len -= optlen; 541 optlen += sizeof(struct ip); 542 bcopy((caddr_t)ip + optlen, (caddr_t)(ip + 1), 543 (unsigned)(m->m_len - sizeof(struct ip))); 544 } 545 m->m_flags &= ~(M_BCAST|M_MCAST); 546 icmp_send(m, opts); 547 done: 548 if (opts) 549 (void)m_free(opts); 550 } 551 552 /* 553 * Send an icmp packet back to the ip level, 554 * after supplying a checksum. 555 */ 556 void 557 icmp_send(m, opts) 558 register struct mbuf *m; 559 struct mbuf *opts; 560 { 561 register struct ip *ip = mtod(m, struct ip *); 562 register int hlen; 563 register struct icmp *icp; 564 565 hlen = ip->ip_hl << 2; 566 m->m_data += hlen; 567 m->m_len -= hlen; 568 icp = mtod(m, struct icmp *); 569 icp->icmp_cksum = 0; 570 icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen); 571 m->m_data -= hlen; 572 m->m_len += hlen; 573 #ifdef ICMPPRINTFS 574 if (icmpprintfs) 575 printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src); 576 #endif 577 (void) ip_output(m, opts, NULL, 0, NULL); 578 } 579 580 n_time 581 iptime() 582 { 583 struct timeval atv; 584 u_long t; 585 586 microtime(&atv); 587 t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000; 588 return (htonl(t)); 589 } 590 591 int 592 icmp_sysctl(name, namelen, oldp, oldlenp, newp, newlen) 593 int *name; 594 u_int namelen; 595 void *oldp; 596 size_t *oldlenp; 597 void *newp; 598 size_t newlen; 599 { 600 601 /* All sysctl names at this level are terminal. */ 602 if (namelen != 1) 603 return (ENOTDIR); 604 605 switch (name[0]) { 606 case ICMPCTL_MASKREPL: 607 return (sysctl_int(oldp, oldlenp, newp, newlen, &icmpmaskrepl)); 608 default: 609 return (ENOPROTOOPT); 610 } 611 /* NOTREACHED */ 612 } 613 614 static void 615 icmp_mtudisc(icp) 616 struct icmp *icp; 617 { 618 struct rtentry *rt; 619 struct sockaddr *dst = sintosa(&icmpsrc); 620 u_long mtu = ntohs(icp->icmp_nextmtu); /* Why a long? IPv6 */ 621 622 /* Table of common MTUs: */ 623 624 static u_long mtu_table[] = {65535, 65280, 32000, 17914, 9180, 8166, 625 4352, 2002, 1492, 1006, 508, 296, 68, 0}; 626 627 rt = rtalloc1(dst, 1); 628 if (rt == 0) 629 return; 630 631 /* If we didn't get a host route, allocate one */ 632 633 if ((rt->rt_flags & RTF_HOST) == 0) { 634 struct rtentry *nrt; 635 int error; 636 637 error = rtrequest((int) RTM_ADD, dst, 638 (struct sockaddr *) rt->rt_gateway, 639 (struct sockaddr *) 0, 640 RTF_GATEWAY | RTF_HOST | RTF_DYNAMIC, &nrt); 641 if (error) { 642 rtfree(rt); 643 rtfree(nrt); 644 return; 645 } 646 nrt->rt_rmx = rt->rt_rmx; 647 rtfree(rt); 648 rt = nrt; 649 } 650 651 if (mtu == 0) { 652 int i = 0; 653 654 mtu = icp->icmp_ip.ip_len; /* NTOHS happened in deliver: */ 655 /* Some 4.2BSD-based routers incorrectly adjust the ip_len */ 656 if (mtu > rt->rt_rmx.rmx_mtu && rt->rt_rmx.rmx_mtu != 0) 657 mtu -= (icp->icmp_ip.ip_hl << 2); 658 659 /* If we still can't guess a value, try the route */ 660 661 if (mtu == 0) { 662 mtu = rt->rt_rmx.rmx_mtu; 663 664 /* If no route mtu, default to the interface mtu */ 665 666 if (mtu == 0) 667 mtu = rt->rt_ifp->if_mtu; 668 } 669 670 for (i = 0; i < sizeof(mtu_table) / sizeof(mtu_table[0]); i++) 671 if (mtu > mtu_table[i]) { 672 mtu = mtu_table[i]; 673 break; 674 } 675 } 676 677 if ((rt->rt_rmx.rmx_locks & RTV_MTU) == 0) { 678 if (mtu < 296 || mtu > rt->rt_ifp->if_mtu) 679 rt->rt_rmx.rmx_locks |= RTV_MTU; 680 else if (rt->rt_rmx.rmx_mtu > mtu || 681 rt->rt_rmx.rmx_mtu == 0) 682 rt->rt_rmx.rmx_mtu = mtu; 683 } 684 685 if (rt) 686 rtfree(rt); 687 } 688