1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1982, 1986, 1988, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 6df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 7df8bae1dSRodney W. Grimes * are met: 8df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 9df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 10df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 12df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 13df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 14df8bae1dSRodney W. Grimes * must display the following acknowledgement: 15df8bae1dSRodney W. Grimes * This product includes software developed by the University of 16df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 17df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 18df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 19df8bae1dSRodney W. Grimes * without specific prior written permission. 20df8bae1dSRodney W. Grimes * 21df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31df8bae1dSRodney W. Grimes * SUCH DAMAGE. 32df8bae1dSRodney W. Grimes * 33df8bae1dSRodney W. Grimes * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94 347022ea0aSGarrett Wollman * $Id: ip_icmp.c,v 1.27 1997/08/02 14:32:53 bde Exp $ 35df8bae1dSRodney W. Grimes */ 36df8bae1dSRodney W. Grimes 37df8bae1dSRodney W. Grimes #include <sys/param.h> 38df8bae1dSRodney W. Grimes #include <sys/systm.h> 39df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 40df8bae1dSRodney W. Grimes #include <sys/protosw.h> 41df8bae1dSRodney W. Grimes #include <sys/socket.h> 42df8bae1dSRodney W. Grimes #include <sys/time.h> 43df8bae1dSRodney W. Grimes #include <sys/kernel.h> 44b5e8ce9fSBruce Evans #include <sys/sysctl.h> 45df8bae1dSRodney W. Grimes 46df8bae1dSRodney W. Grimes #include <net/if.h> 47df8bae1dSRodney W. Grimes #include <net/route.h> 48df8bae1dSRodney W. Grimes 495e2d0696SGarrett Wollman #define _IP_VHL 50df8bae1dSRodney W. Grimes #include <netinet/in.h> 51df8bae1dSRodney W. Grimes #include <netinet/in_systm.h> 52df8bae1dSRodney W. Grimes #include <netinet/in_var.h> 53df8bae1dSRodney W. Grimes #include <netinet/ip.h> 54df8bae1dSRodney W. Grimes #include <netinet/ip_icmp.h> 55b5e8ce9fSBruce Evans #include <netinet/ip_var.h> 56df8bae1dSRodney W. Grimes #include <netinet/icmp_var.h> 57df8bae1dSRodney W. Grimes 58df8bae1dSRodney W. Grimes /* 59df8bae1dSRodney W. Grimes * ICMP routines: error generation, receive packet processing, and 60df8bae1dSRodney W. Grimes * routines to turnaround packets back to the originator, and 61df8bae1dSRodney W. Grimes * host table maintenance routines. 62df8bae1dSRodney W. Grimes */ 63df8bae1dSRodney W. Grimes 64f708ef1bSPoul-Henning Kamp static struct icmpstat icmpstat; 650312fbe9SPoul-Henning Kamp SYSCTL_STRUCT(_net_inet_icmp, ICMPCTL_STATS, stats, CTLFLAG_RD, 660312fbe9SPoul-Henning Kamp &icmpstat, icmpstat, ""); 670312fbe9SPoul-Henning Kamp 680312fbe9SPoul-Henning Kamp static int icmpmaskrepl = 0; 690312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_icmp, ICMPCTL_MASKREPL, maskrepl, CTLFLAG_RW, 700312fbe9SPoul-Henning Kamp &icmpmaskrepl, 0, ""); 710312fbe9SPoul-Henning Kamp 727022ea0aSGarrett Wollman static int icmpbmcastecho = 1; 737022ea0aSGarrett Wollman SYSCTL_INT(_net_inet_icmp, OID_AUTO, bmcastecho, CTLFLAG_RW, &icmpbmcastecho, 747022ea0aSGarrett Wollman 0, ""); 757022ea0aSGarrett Wollman 76df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS 77df8bae1dSRodney W. Grimes int icmpprintfs = 0; 78df8bae1dSRodney W. Grimes #endif 79df8bae1dSRodney W. Grimes 800312fbe9SPoul-Henning Kamp static void icmp_reflect __P((struct mbuf *)); 810312fbe9SPoul-Henning Kamp static void icmp_send __P((struct mbuf *, struct mbuf *)); 82f708ef1bSPoul-Henning Kamp static int ip_next_mtu __P((int, int)); 830312fbe9SPoul-Henning Kamp 84df8bae1dSRodney W. Grimes extern struct protosw inetsw[]; 85df8bae1dSRodney W. Grimes 86df8bae1dSRodney W. Grimes /* 87df8bae1dSRodney W. Grimes * Generate an error packet of type error 88df8bae1dSRodney W. Grimes * in response to bad packet ip. 89df8bae1dSRodney W. Grimes */ 90df8bae1dSRodney W. Grimes void 91df8bae1dSRodney W. Grimes icmp_error(n, type, code, dest, destifp) 92df8bae1dSRodney W. Grimes struct mbuf *n; 93df8bae1dSRodney W. Grimes int type, code; 94df8bae1dSRodney W. Grimes n_long dest; 95df8bae1dSRodney W. Grimes struct ifnet *destifp; 96df8bae1dSRodney W. Grimes { 97df8bae1dSRodney W. Grimes register struct ip *oip = mtod(n, struct ip *), *nip; 985e2d0696SGarrett Wollman register unsigned oiplen = IP_VHL_HL(oip->ip_vhl) << 2; 99df8bae1dSRodney W. Grimes register struct icmp *icp; 100df8bae1dSRodney W. Grimes register struct mbuf *m; 101df8bae1dSRodney W. Grimes unsigned icmplen; 102df8bae1dSRodney W. Grimes 103df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS 104df8bae1dSRodney W. Grimes if (icmpprintfs) 105623ae52eSPoul-Henning Kamp printf("icmp_error(%p, %x, %d)\n", oip, type, code); 106df8bae1dSRodney W. Grimes #endif 107df8bae1dSRodney W. Grimes if (type != ICMP_REDIRECT) 108df8bae1dSRodney W. Grimes icmpstat.icps_error++; 109df8bae1dSRodney W. Grimes /* 110df8bae1dSRodney W. Grimes * Don't send error if not the first fragment of message. 111df8bae1dSRodney W. Grimes * Don't error if the old packet protocol was ICMP 112df8bae1dSRodney W. Grimes * error message, only known informational types. 113df8bae1dSRodney W. Grimes */ 114df8bae1dSRodney W. Grimes if (oip->ip_off &~ (IP_MF|IP_DF)) 115df8bae1dSRodney W. Grimes goto freeit; 116df8bae1dSRodney W. Grimes if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT && 117df8bae1dSRodney W. Grimes n->m_len >= oiplen + ICMP_MINLEN && 118df8bae1dSRodney W. Grimes !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) { 119df8bae1dSRodney W. Grimes icmpstat.icps_oldicmp++; 120df8bae1dSRodney W. Grimes goto freeit; 121df8bae1dSRodney W. Grimes } 122df8bae1dSRodney W. Grimes /* Don't send error in response to a multicast or broadcast packet */ 123df8bae1dSRodney W. Grimes if (n->m_flags & (M_BCAST|M_MCAST)) 124df8bae1dSRodney W. Grimes goto freeit; 125df8bae1dSRodney W. Grimes /* 126df8bae1dSRodney W. Grimes * First, formulate icmp message 127df8bae1dSRodney W. Grimes */ 128df8bae1dSRodney W. Grimes m = m_gethdr(M_DONTWAIT, MT_HEADER); 129df8bae1dSRodney W. Grimes if (m == NULL) 130df8bae1dSRodney W. Grimes goto freeit; 131df8bae1dSRodney W. Grimes icmplen = oiplen + min(8, oip->ip_len); 132df8bae1dSRodney W. Grimes m->m_len = icmplen + ICMP_MINLEN; 133df8bae1dSRodney W. Grimes MH_ALIGN(m, m->m_len); 134df8bae1dSRodney W. Grimes icp = mtod(m, struct icmp *); 135df8bae1dSRodney W. Grimes if ((u_int)type > ICMP_MAXTYPE) 136df8bae1dSRodney W. Grimes panic("icmp_error"); 137df8bae1dSRodney W. Grimes icmpstat.icps_outhist[type]++; 138df8bae1dSRodney W. Grimes icp->icmp_type = type; 139df8bae1dSRodney W. Grimes if (type == ICMP_REDIRECT) 140df8bae1dSRodney W. Grimes icp->icmp_gwaddr.s_addr = dest; 141df8bae1dSRodney W. Grimes else { 142df8bae1dSRodney W. Grimes icp->icmp_void = 0; 143df8bae1dSRodney W. Grimes /* 144df8bae1dSRodney W. Grimes * The following assignments assume an overlay with the 145df8bae1dSRodney W. Grimes * zeroed icmp_void field. 146df8bae1dSRodney W. Grimes */ 147df8bae1dSRodney W. Grimes if (type == ICMP_PARAMPROB) { 148df8bae1dSRodney W. Grimes icp->icmp_pptr = code; 149df8bae1dSRodney W. Grimes code = 0; 150df8bae1dSRodney W. Grimes } else if (type == ICMP_UNREACH && 151df8bae1dSRodney W. Grimes code == ICMP_UNREACH_NEEDFRAG && destifp) { 152df8bae1dSRodney W. Grimes icp->icmp_nextmtu = htons(destifp->if_mtu); 153df8bae1dSRodney W. Grimes } 154df8bae1dSRodney W. Grimes } 155df8bae1dSRodney W. Grimes 156df8bae1dSRodney W. Grimes icp->icmp_code = code; 157df8bae1dSRodney W. Grimes bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen); 158df8bae1dSRodney W. Grimes nip = &icp->icmp_ip; 159df8bae1dSRodney W. Grimes nip->ip_len = htons((u_short)(nip->ip_len + oiplen)); 160df8bae1dSRodney W. Grimes 161df8bae1dSRodney W. Grimes /* 162df8bae1dSRodney W. Grimes * Now, copy old ip header (without options) 163df8bae1dSRodney W. Grimes * in front of icmp message. 164df8bae1dSRodney W. Grimes */ 165df8bae1dSRodney W. Grimes if (m->m_data - sizeof(struct ip) < m->m_pktdat) 166df8bae1dSRodney W. Grimes panic("icmp len"); 167df8bae1dSRodney W. Grimes m->m_data -= sizeof(struct ip); 168df8bae1dSRodney W. Grimes m->m_len += sizeof(struct ip); 169df8bae1dSRodney W. Grimes m->m_pkthdr.len = m->m_len; 170df8bae1dSRodney W. Grimes m->m_pkthdr.rcvif = n->m_pkthdr.rcvif; 171df8bae1dSRodney W. Grimes nip = mtod(m, struct ip *); 172df8bae1dSRodney W. Grimes bcopy((caddr_t)oip, (caddr_t)nip, sizeof(struct ip)); 173df8bae1dSRodney W. Grimes nip->ip_len = m->m_len; 1745e2d0696SGarrett Wollman nip->ip_vhl = IP_VHL_BORING; 175df8bae1dSRodney W. Grimes nip->ip_p = IPPROTO_ICMP; 176df8bae1dSRodney W. Grimes nip->ip_tos = 0; 177df8bae1dSRodney W. Grimes icmp_reflect(m); 178df8bae1dSRodney W. Grimes 179df8bae1dSRodney W. Grimes freeit: 180df8bae1dSRodney W. Grimes m_freem(n); 181df8bae1dSRodney W. Grimes } 182df8bae1dSRodney W. Grimes 183df8bae1dSRodney W. Grimes static struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET }; 184df8bae1dSRodney W. Grimes static struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET }; 185df8bae1dSRodney W. Grimes static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET }; 186df8bae1dSRodney W. Grimes 187df8bae1dSRodney W. Grimes /* 188df8bae1dSRodney W. Grimes * Process a received ICMP message. 189df8bae1dSRodney W. Grimes */ 190df8bae1dSRodney W. Grimes void 191df8bae1dSRodney W. Grimes icmp_input(m, hlen) 192df8bae1dSRodney W. Grimes register struct mbuf *m; 193df8bae1dSRodney W. Grimes int hlen; 194df8bae1dSRodney W. Grimes { 195df8bae1dSRodney W. Grimes register struct icmp *icp; 196df8bae1dSRodney W. Grimes register struct ip *ip = mtod(m, struct ip *); 197df8bae1dSRodney W. Grimes int icmplen = ip->ip_len; 198df8bae1dSRodney W. Grimes register int i; 199df8bae1dSRodney W. Grimes struct in_ifaddr *ia; 200b62d102cSBruce Evans void (*ctlfunc) __P((int, struct sockaddr *, void *)); 201df8bae1dSRodney W. Grimes int code; 202df8bae1dSRodney W. Grimes 203df8bae1dSRodney W. Grimes /* 204df8bae1dSRodney W. Grimes * Locate icmp structure in mbuf, and check 205df8bae1dSRodney W. Grimes * that not corrupted and of at least minimum length. 206df8bae1dSRodney W. Grimes */ 207df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS 2082b758395SGarrett Wollman if (icmpprintfs) { 2092b758395SGarrett Wollman char buf[4 * sizeof "123"]; 2102b758395SGarrett Wollman strcpy(buf, inet_ntoa(ip->ip_src)); 2112b758395SGarrett Wollman printf("icmp_input from %s to %s, len %d\n", 2122b758395SGarrett Wollman buf, inet_ntoa(ip->ip_dst), icmplen); 2132b758395SGarrett Wollman } 214df8bae1dSRodney W. Grimes #endif 215df8bae1dSRodney W. Grimes if (icmplen < ICMP_MINLEN) { 216df8bae1dSRodney W. Grimes icmpstat.icps_tooshort++; 217df8bae1dSRodney W. Grimes goto freeit; 218df8bae1dSRodney W. Grimes } 219df8bae1dSRodney W. Grimes i = hlen + min(icmplen, ICMP_ADVLENMIN); 220df8bae1dSRodney W. Grimes if (m->m_len < i && (m = m_pullup(m, i)) == 0) { 221df8bae1dSRodney W. Grimes icmpstat.icps_tooshort++; 222df8bae1dSRodney W. Grimes return; 223df8bae1dSRodney W. Grimes } 224df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 225df8bae1dSRodney W. Grimes m->m_len -= hlen; 226df8bae1dSRodney W. Grimes m->m_data += hlen; 227df8bae1dSRodney W. Grimes icp = mtod(m, struct icmp *); 228df8bae1dSRodney W. Grimes if (in_cksum(m, icmplen)) { 229df8bae1dSRodney W. Grimes icmpstat.icps_checksum++; 230df8bae1dSRodney W. Grimes goto freeit; 231df8bae1dSRodney W. Grimes } 232df8bae1dSRodney W. Grimes m->m_len += hlen; 233df8bae1dSRodney W. Grimes m->m_data -= hlen; 234df8bae1dSRodney W. Grimes 235df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS 236df8bae1dSRodney W. Grimes if (icmpprintfs) 237df8bae1dSRodney W. Grimes printf("icmp_input, type %d code %d\n", icp->icmp_type, 238df8bae1dSRodney W. Grimes icp->icmp_code); 239df8bae1dSRodney W. Grimes #endif 2405b7ee6edSGarrett Wollman 2415b7ee6edSGarrett Wollman /* 2425b7ee6edSGarrett Wollman * Message type specific processing. 2435b7ee6edSGarrett Wollman */ 244df8bae1dSRodney W. Grimes if (icp->icmp_type > ICMP_MAXTYPE) 245df8bae1dSRodney W. Grimes goto raw; 246df8bae1dSRodney W. Grimes icmpstat.icps_inhist[icp->icmp_type]++; 247df8bae1dSRodney W. Grimes code = icp->icmp_code; 248df8bae1dSRodney W. Grimes switch (icp->icmp_type) { 249df8bae1dSRodney W. Grimes 250df8bae1dSRodney W. Grimes case ICMP_UNREACH: 251df8bae1dSRodney W. Grimes switch (code) { 252df8bae1dSRodney W. Grimes case ICMP_UNREACH_NET: 253df8bae1dSRodney W. Grimes case ICMP_UNREACH_HOST: 254df8bae1dSRodney W. Grimes case ICMP_UNREACH_PROTOCOL: 255df8bae1dSRodney W. Grimes case ICMP_UNREACH_PORT: 256df8bae1dSRodney W. Grimes case ICMP_UNREACH_SRCFAIL: 257df8bae1dSRodney W. Grimes code += PRC_UNREACH_NET; 258df8bae1dSRodney W. Grimes break; 259df8bae1dSRodney W. Grimes 260df8bae1dSRodney W. Grimes case ICMP_UNREACH_NEEDFRAG: 261df8bae1dSRodney W. Grimes code = PRC_MSGSIZE; 262df8bae1dSRodney W. Grimes break; 263df8bae1dSRodney W. Grimes 264df8bae1dSRodney W. Grimes case ICMP_UNREACH_NET_UNKNOWN: 265df8bae1dSRodney W. Grimes case ICMP_UNREACH_NET_PROHIB: 266df8bae1dSRodney W. Grimes case ICMP_UNREACH_TOSNET: 267df8bae1dSRodney W. Grimes code = PRC_UNREACH_NET; 268df8bae1dSRodney W. Grimes break; 269df8bae1dSRodney W. Grimes 270df8bae1dSRodney W. Grimes case ICMP_UNREACH_HOST_UNKNOWN: 271df8bae1dSRodney W. Grimes case ICMP_UNREACH_ISOLATED: 272df8bae1dSRodney W. Grimes case ICMP_UNREACH_HOST_PROHIB: 273df8bae1dSRodney W. Grimes case ICMP_UNREACH_TOSHOST: 274df8bae1dSRodney W. Grimes code = PRC_UNREACH_HOST; 275df8bae1dSRodney W. Grimes break; 276df8bae1dSRodney W. Grimes 2779c4b2574SPaul Traina case ICMP_UNREACH_FILTER_PROHIB: 2789c4b2574SPaul Traina case ICMP_UNREACH_HOST_PRECEDENCE: 2799c4b2574SPaul Traina case ICMP_UNREACH_PRECEDENCE_CUTOFF: 2809c4b2574SPaul Traina code = PRC_UNREACH_PORT; 2819c4b2574SPaul Traina break; 2829c4b2574SPaul Traina 283df8bae1dSRodney W. Grimes default: 284df8bae1dSRodney W. Grimes goto badcode; 285df8bae1dSRodney W. Grimes } 286df8bae1dSRodney W. Grimes goto deliver; 287df8bae1dSRodney W. Grimes 288df8bae1dSRodney W. Grimes case ICMP_TIMXCEED: 289df8bae1dSRodney W. Grimes if (code > 1) 290df8bae1dSRodney W. Grimes goto badcode; 291df8bae1dSRodney W. Grimes code += PRC_TIMXCEED_INTRANS; 292df8bae1dSRodney W. Grimes goto deliver; 293df8bae1dSRodney W. Grimes 294df8bae1dSRodney W. Grimes case ICMP_PARAMPROB: 295df8bae1dSRodney W. Grimes if (code > 1) 296df8bae1dSRodney W. Grimes goto badcode; 297df8bae1dSRodney W. Grimes code = PRC_PARAMPROB; 298df8bae1dSRodney W. Grimes goto deliver; 299df8bae1dSRodney W. Grimes 300df8bae1dSRodney W. Grimes case ICMP_SOURCEQUENCH: 301df8bae1dSRodney W. Grimes if (code) 302df8bae1dSRodney W. Grimes goto badcode; 303df8bae1dSRodney W. Grimes code = PRC_QUENCH; 304df8bae1dSRodney W. Grimes deliver: 305df8bae1dSRodney W. Grimes /* 306df8bae1dSRodney W. Grimes * Problem with datagram; advise higher level routines. 307df8bae1dSRodney W. Grimes */ 308df8bae1dSRodney W. Grimes if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) || 3095e2d0696SGarrett Wollman IP_VHL_HL(icp->icmp_ip.ip_vhl) < (sizeof(struct ip) >> 2)) { 310df8bae1dSRodney W. Grimes icmpstat.icps_badlen++; 311df8bae1dSRodney W. Grimes goto freeit; 312df8bae1dSRodney W. Grimes } 313df8bae1dSRodney W. Grimes NTOHS(icp->icmp_ip.ip_len); 3145b7ee6edSGarrett Wollman /* Discard ICMP's in response to multicast packets */ 3155b7ee6edSGarrett Wollman if (IN_MULTICAST(ntohl(icp->icmp_ip.ip_dst.s_addr))) 3165b7ee6edSGarrett Wollman goto badcode; 317df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS 318df8bae1dSRodney W. Grimes if (icmpprintfs) 319df8bae1dSRodney W. Grimes printf("deliver to protocol %d\n", icp->icmp_ip.ip_p); 320df8bae1dSRodney W. Grimes #endif 321df8bae1dSRodney W. Grimes icmpsrc.sin_addr = icp->icmp_ip.ip_dst; 322b7a44e34SGarrett Wollman #if 1 3235cbf3e08SGarrett Wollman /* 3245cbf3e08SGarrett Wollman * MTU discovery: 3255cbf3e08SGarrett Wollman * If we got a needfrag and there is a host route to the 3265cbf3e08SGarrett Wollman * original destination, and the MTU is not locked, then 3275cbf3e08SGarrett Wollman * set the MTU in the route to the suggested new value 3285cbf3e08SGarrett Wollman * (if given) and then notify as usual. The ULPs will 3295cbf3e08SGarrett Wollman * notice that the MTU has changed and adapt accordingly. 3305cbf3e08SGarrett Wollman * If no new MTU was suggested, then we guess a new one 3315cbf3e08SGarrett Wollman * less than the current value. If the new MTU is 3325cbf3e08SGarrett Wollman * unreasonably small (arbitrarily set at 296), then 3335cbf3e08SGarrett Wollman * we reset the MTU to the interface value and enable the 3345cbf3e08SGarrett Wollman * lock bit, indicating that we are no longer doing MTU 3355cbf3e08SGarrett Wollman * discovery. 3365cbf3e08SGarrett Wollman */ 3375cbf3e08SGarrett Wollman if (code == PRC_MSGSIZE) { 3385cbf3e08SGarrett Wollman struct rtentry *rt; 3395cbf3e08SGarrett Wollman int mtu; 3405cbf3e08SGarrett Wollman 3415cbf3e08SGarrett Wollman rt = rtalloc1((struct sockaddr *)&icmpsrc, 0, 3425cbf3e08SGarrett Wollman RTF_CLONING | RTF_PRCLONING); 3435cbf3e08SGarrett Wollman if (rt && (rt->rt_flags & RTF_HOST) 3445cbf3e08SGarrett Wollman && !(rt->rt_rmx.rmx_locks & RTV_MTU)) { 3455cbf3e08SGarrett Wollman mtu = ntohs(icp->icmp_nextmtu); 3465cbf3e08SGarrett Wollman if (!mtu) 3475cbf3e08SGarrett Wollman mtu = ip_next_mtu(rt->rt_rmx.rmx_mtu, 3485cbf3e08SGarrett Wollman 1); 349be070f43SGarrett Wollman #ifdef DEBUG_MTUDISC 350be070f43SGarrett Wollman printf("MTU for %s reduced to %d\n", 351be070f43SGarrett Wollman inet_ntoa(icmpsrc.sin_addr), mtu); 352be070f43SGarrett Wollman #endif 353be070f43SGarrett Wollman if (mtu < 296) { 354b7a44e34SGarrett Wollman /* rt->rt_rmx.rmx_mtu = 355b7a44e34SGarrett Wollman rt->rt_ifp->if_mtu; */ 3565cbf3e08SGarrett Wollman rt->rt_rmx.rmx_locks |= RTV_MTU; 3575cbf3e08SGarrett Wollman } else if (rt->rt_rmx.rmx_mtu > mtu) { 3585cbf3e08SGarrett Wollman rt->rt_rmx.rmx_mtu = mtu; 3595cbf3e08SGarrett Wollman } 3605cbf3e08SGarrett Wollman } 3615cbf3e08SGarrett Wollman if (rt) 3625cbf3e08SGarrett Wollman RTFREE(rt); 3635cbf3e08SGarrett Wollman } 3645cbf3e08SGarrett Wollman 365b7a44e34SGarrett Wollman #endif 366623ae52eSPoul-Henning Kamp ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput; 367623ae52eSPoul-Henning Kamp if (ctlfunc) 368df8bae1dSRodney W. Grimes (*ctlfunc)(code, (struct sockaddr *)&icmpsrc, 369b62d102cSBruce Evans (void *)&icp->icmp_ip); 370df8bae1dSRodney W. Grimes break; 371df8bae1dSRodney W. Grimes 372df8bae1dSRodney W. Grimes badcode: 373df8bae1dSRodney W. Grimes icmpstat.icps_badcode++; 374df8bae1dSRodney W. Grimes break; 375df8bae1dSRodney W. Grimes 376df8bae1dSRodney W. Grimes case ICMP_ECHO: 3777022ea0aSGarrett Wollman if (!icmpbmcastecho 3787022ea0aSGarrett Wollman && (m->m_flags & (M_MCAST | M_BCAST)) != 0 3797022ea0aSGarrett Wollman && IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { 3807022ea0aSGarrett Wollman icmpstat.icps_bmcastecho++; 3817022ea0aSGarrett Wollman break; 3827022ea0aSGarrett Wollman } 383df8bae1dSRodney W. Grimes icp->icmp_type = ICMP_ECHOREPLY; 384df8bae1dSRodney W. Grimes goto reflect; 385df8bae1dSRodney W. Grimes 386df8bae1dSRodney W. Grimes case ICMP_TSTAMP: 387df8bae1dSRodney W. Grimes if (icmplen < ICMP_TSLEN) { 388df8bae1dSRodney W. Grimes icmpstat.icps_badlen++; 389df8bae1dSRodney W. Grimes break; 390df8bae1dSRodney W. Grimes } 391df8bae1dSRodney W. Grimes icp->icmp_type = ICMP_TSTAMPREPLY; 392df8bae1dSRodney W. Grimes icp->icmp_rtime = iptime(); 393df8bae1dSRodney W. Grimes icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */ 394df8bae1dSRodney W. Grimes goto reflect; 395df8bae1dSRodney W. Grimes 396df8bae1dSRodney W. Grimes case ICMP_MASKREQ: 397df8bae1dSRodney W. Grimes #define satosin(sa) ((struct sockaddr_in *)(sa)) 398df8bae1dSRodney W. Grimes if (icmpmaskrepl == 0) 399df8bae1dSRodney W. Grimes break; 400df8bae1dSRodney W. Grimes /* 401df8bae1dSRodney W. Grimes * We are not able to respond with all ones broadcast 402df8bae1dSRodney W. Grimes * unless we receive it over a point-to-point interface. 403df8bae1dSRodney W. Grimes */ 404df8bae1dSRodney W. Grimes if (icmplen < ICMP_MASKLEN) 405df8bae1dSRodney W. Grimes break; 406df8bae1dSRodney W. Grimes switch (ip->ip_dst.s_addr) { 407df8bae1dSRodney W. Grimes 408df8bae1dSRodney W. Grimes case INADDR_BROADCAST: 409df8bae1dSRodney W. Grimes case INADDR_ANY: 410df8bae1dSRodney W. Grimes icmpdst.sin_addr = ip->ip_src; 411df8bae1dSRodney W. Grimes break; 412df8bae1dSRodney W. Grimes 413df8bae1dSRodney W. Grimes default: 414df8bae1dSRodney W. Grimes icmpdst.sin_addr = ip->ip_dst; 415df8bae1dSRodney W. Grimes } 416df8bae1dSRodney W. Grimes ia = (struct in_ifaddr *)ifaof_ifpforaddr( 417df8bae1dSRodney W. Grimes (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif); 418df8bae1dSRodney W. Grimes if (ia == 0) 419df8bae1dSRodney W. Grimes break; 4207e6f7714SPoul-Henning Kamp if (ia->ia_ifp == 0) 4217e6f7714SPoul-Henning Kamp break; 422df8bae1dSRodney W. Grimes icp->icmp_type = ICMP_MASKREPLY; 423df8bae1dSRodney W. Grimes icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr; 424df8bae1dSRodney W. Grimes if (ip->ip_src.s_addr == 0) { 425df8bae1dSRodney W. Grimes if (ia->ia_ifp->if_flags & IFF_BROADCAST) 426df8bae1dSRodney W. Grimes ip->ip_src = satosin(&ia->ia_broadaddr)->sin_addr; 427df8bae1dSRodney W. Grimes else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT) 428df8bae1dSRodney W. Grimes ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr; 429df8bae1dSRodney W. Grimes } 430df8bae1dSRodney W. Grimes reflect: 431df8bae1dSRodney W. Grimes ip->ip_len += hlen; /* since ip_input deducts this */ 432df8bae1dSRodney W. Grimes icmpstat.icps_reflect++; 433df8bae1dSRodney W. Grimes icmpstat.icps_outhist[icp->icmp_type]++; 434df8bae1dSRodney W. Grimes icmp_reflect(m); 435df8bae1dSRodney W. Grimes return; 436df8bae1dSRodney W. Grimes 437df8bae1dSRodney W. Grimes case ICMP_REDIRECT: 438df8bae1dSRodney W. Grimes if (code > 3) 439df8bae1dSRodney W. Grimes goto badcode; 440df8bae1dSRodney W. Grimes if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) || 4415e2d0696SGarrett Wollman IP_VHL_HL(icp->icmp_ip.ip_vhl) < (sizeof(struct ip) >> 2)) { 442df8bae1dSRodney W. Grimes icmpstat.icps_badlen++; 443df8bae1dSRodney W. Grimes break; 444df8bae1dSRodney W. Grimes } 445df8bae1dSRodney W. Grimes /* 446df8bae1dSRodney W. Grimes * Short circuit routing redirects to force 447df8bae1dSRodney W. Grimes * immediate change in the kernel's routing 448df8bae1dSRodney W. Grimes * tables. The message is also handed to anyone 449df8bae1dSRodney W. Grimes * listening on a raw socket (e.g. the routing 450df8bae1dSRodney W. Grimes * daemon for use in updating its tables). 451df8bae1dSRodney W. Grimes */ 452df8bae1dSRodney W. Grimes icmpgw.sin_addr = ip->ip_src; 453df8bae1dSRodney W. Grimes icmpdst.sin_addr = icp->icmp_gwaddr; 454df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS 4552b758395SGarrett Wollman if (icmpprintfs) { 4562b758395SGarrett Wollman char buf[4 * sizeof "123"]; 4572b758395SGarrett Wollman strcpy(buf, inet_ntoa(icp->icmp_ip.ip_dst)); 4582b758395SGarrett Wollman 4592b758395SGarrett Wollman printf("redirect dst %s to %s\n", 4602b758395SGarrett Wollman buf, inet_ntoa(icp->icmp_gwaddr)); 4612b758395SGarrett Wollman } 462df8bae1dSRodney W. Grimes #endif 463df8bae1dSRodney W. Grimes icmpsrc.sin_addr = icp->icmp_ip.ip_dst; 464df8bae1dSRodney W. Grimes rtredirect((struct sockaddr *)&icmpsrc, 465df8bae1dSRodney W. Grimes (struct sockaddr *)&icmpdst, 466df8bae1dSRodney W. Grimes (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST, 467df8bae1dSRodney W. Grimes (struct sockaddr *)&icmpgw, (struct rtentry **)0); 468df8bae1dSRodney W. Grimes pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&icmpsrc); 469df8bae1dSRodney W. Grimes break; 470df8bae1dSRodney W. Grimes 471df8bae1dSRodney W. Grimes /* 472df8bae1dSRodney W. Grimes * No kernel processing for the following; 473df8bae1dSRodney W. Grimes * just fall through to send to raw listener. 474df8bae1dSRodney W. Grimes */ 475df8bae1dSRodney W. Grimes case ICMP_ECHOREPLY: 476df8bae1dSRodney W. Grimes case ICMP_ROUTERADVERT: 477df8bae1dSRodney W. Grimes case ICMP_ROUTERSOLICIT: 478df8bae1dSRodney W. Grimes case ICMP_TSTAMPREPLY: 479df8bae1dSRodney W. Grimes case ICMP_IREQREPLY: 480df8bae1dSRodney W. Grimes case ICMP_MASKREPLY: 481df8bae1dSRodney W. Grimes default: 482df8bae1dSRodney W. Grimes break; 483df8bae1dSRodney W. Grimes } 484df8bae1dSRodney W. Grimes 485df8bae1dSRodney W. Grimes raw: 486e62b8c49SBill Fenner rip_input(m, hlen); 487df8bae1dSRodney W. Grimes return; 488df8bae1dSRodney W. Grimes 489df8bae1dSRodney W. Grimes freeit: 490df8bae1dSRodney W. Grimes m_freem(m); 491df8bae1dSRodney W. Grimes } 492df8bae1dSRodney W. Grimes 493df8bae1dSRodney W. Grimes /* 494df8bae1dSRodney W. Grimes * Reflect the ip packet back to the source 495df8bae1dSRodney W. Grimes */ 4960312fbe9SPoul-Henning Kamp static void 497df8bae1dSRodney W. Grimes icmp_reflect(m) 498df8bae1dSRodney W. Grimes struct mbuf *m; 499df8bae1dSRodney W. Grimes { 500df8bae1dSRodney W. Grimes register struct ip *ip = mtod(m, struct ip *); 501df8bae1dSRodney W. Grimes register struct in_ifaddr *ia; 502df8bae1dSRodney W. Grimes struct in_addr t; 503b5e8ce9fSBruce Evans struct mbuf *opts = 0; 5045e2d0696SGarrett Wollman int optlen = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof(struct ip); 505df8bae1dSRodney W. Grimes 506df8bae1dSRodney W. Grimes if (!in_canforward(ip->ip_src) && 507df8bae1dSRodney W. Grimes ((ntohl(ip->ip_src.s_addr) & IN_CLASSA_NET) != 508df8bae1dSRodney W. Grimes (IN_LOOPBACKNET << IN_CLASSA_NSHIFT))) { 509df8bae1dSRodney W. Grimes m_freem(m); /* Bad return address */ 510df8bae1dSRodney W. Grimes goto done; /* Ip_output() will check for broadcast */ 511df8bae1dSRodney W. Grimes } 512df8bae1dSRodney W. Grimes t = ip->ip_dst; 513df8bae1dSRodney W. Grimes ip->ip_dst = ip->ip_src; 514df8bae1dSRodney W. Grimes /* 515df8bae1dSRodney W. Grimes * If the incoming packet was addressed directly to us, 516df8bae1dSRodney W. Grimes * use dst as the src for the reply. Otherwise (broadcast 517df8bae1dSRodney W. Grimes * or anonymous), use the address which corresponds 518df8bae1dSRodney W. Grimes * to the incoming interface. 519df8bae1dSRodney W. Grimes */ 52059562606SGarrett Wollman for (ia = in_ifaddrhead.tqh_first; ia; ia = ia->ia_link.tqe_next) { 521df8bae1dSRodney W. Grimes if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr) 522df8bae1dSRodney W. Grimes break; 5237e6f7714SPoul-Henning Kamp if (ia->ia_ifp && (ia->ia_ifp->if_flags & IFF_BROADCAST) && 524df8bae1dSRodney W. Grimes t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr) 525df8bae1dSRodney W. Grimes break; 526df8bae1dSRodney W. Grimes } 527df8bae1dSRodney W. Grimes icmpdst.sin_addr = t; 52841fbdc96SJulian Elischer if ((ia == (struct in_ifaddr *)0) && m->m_pkthdr.rcvif) 529df8bae1dSRodney W. Grimes ia = (struct in_ifaddr *)ifaof_ifpforaddr( 530df8bae1dSRodney W. Grimes (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif); 531df8bae1dSRodney W. Grimes /* 532df8bae1dSRodney W. Grimes * The following happens if the packet was not addressed to us, 533df8bae1dSRodney W. Grimes * and was received on an interface with no IP address. 534df8bae1dSRodney W. Grimes */ 535df8bae1dSRodney W. Grimes if (ia == (struct in_ifaddr *)0) 53659562606SGarrett Wollman ia = in_ifaddrhead.tqh_first; 537df8bae1dSRodney W. Grimes t = IA_SIN(ia)->sin_addr; 538df8bae1dSRodney W. Grimes ip->ip_src = t; 539df8bae1dSRodney W. Grimes ip->ip_ttl = MAXTTL; 540df8bae1dSRodney W. Grimes 541df8bae1dSRodney W. Grimes if (optlen > 0) { 542df8bae1dSRodney W. Grimes register u_char *cp; 543df8bae1dSRodney W. Grimes int opt, cnt; 544df8bae1dSRodney W. Grimes u_int len; 545df8bae1dSRodney W. Grimes 546df8bae1dSRodney W. Grimes /* 547df8bae1dSRodney W. Grimes * Retrieve any source routing from the incoming packet; 548df8bae1dSRodney W. Grimes * add on any record-route or timestamp options. 549df8bae1dSRodney W. Grimes */ 550df8bae1dSRodney W. Grimes cp = (u_char *) (ip + 1); 551df8bae1dSRodney W. Grimes if ((opts = ip_srcroute()) == 0 && 552df8bae1dSRodney W. Grimes (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) { 553df8bae1dSRodney W. Grimes opts->m_len = sizeof(struct in_addr); 554df8bae1dSRodney W. Grimes mtod(opts, struct in_addr *)->s_addr = 0; 555df8bae1dSRodney W. Grimes } 556df8bae1dSRodney W. Grimes if (opts) { 557df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS 558df8bae1dSRodney W. Grimes if (icmpprintfs) 559df8bae1dSRodney W. Grimes printf("icmp_reflect optlen %d rt %d => ", 560df8bae1dSRodney W. Grimes optlen, opts->m_len); 561df8bae1dSRodney W. Grimes #endif 562df8bae1dSRodney W. Grimes for (cnt = optlen; cnt > 0; cnt -= len, cp += len) { 563df8bae1dSRodney W. Grimes opt = cp[IPOPT_OPTVAL]; 564df8bae1dSRodney W. Grimes if (opt == IPOPT_EOL) 565df8bae1dSRodney W. Grimes break; 566df8bae1dSRodney W. Grimes if (opt == IPOPT_NOP) 567df8bae1dSRodney W. Grimes len = 1; 568df8bae1dSRodney W. Grimes else { 569df8bae1dSRodney W. Grimes len = cp[IPOPT_OLEN]; 570df8bae1dSRodney W. Grimes if (len <= 0 || len > cnt) 571df8bae1dSRodney W. Grimes break; 572df8bae1dSRodney W. Grimes } 573df8bae1dSRodney W. Grimes /* 574df8bae1dSRodney W. Grimes * Should check for overflow, but it "can't happen" 575df8bae1dSRodney W. Grimes */ 576df8bae1dSRodney W. Grimes if (opt == IPOPT_RR || opt == IPOPT_TS || 577df8bae1dSRodney W. Grimes opt == IPOPT_SECURITY) { 578df8bae1dSRodney W. Grimes bcopy((caddr_t)cp, 579df8bae1dSRodney W. Grimes mtod(opts, caddr_t) + opts->m_len, len); 580df8bae1dSRodney W. Grimes opts->m_len += len; 581df8bae1dSRodney W. Grimes } 582df8bae1dSRodney W. Grimes } 583df8bae1dSRodney W. Grimes /* Terminate & pad, if necessary */ 584623ae52eSPoul-Henning Kamp cnt = opts->m_len % 4; 585623ae52eSPoul-Henning Kamp if (cnt) { 586df8bae1dSRodney W. Grimes for (; cnt < 4; cnt++) { 587df8bae1dSRodney W. Grimes *(mtod(opts, caddr_t) + opts->m_len) = 588df8bae1dSRodney W. Grimes IPOPT_EOL; 589df8bae1dSRodney W. Grimes opts->m_len++; 590df8bae1dSRodney W. Grimes } 591df8bae1dSRodney W. Grimes } 592df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS 593df8bae1dSRodney W. Grimes if (icmpprintfs) 594df8bae1dSRodney W. Grimes printf("%d\n", opts->m_len); 595df8bae1dSRodney W. Grimes #endif 596df8bae1dSRodney W. Grimes } 597df8bae1dSRodney W. Grimes /* 598df8bae1dSRodney W. Grimes * Now strip out original options by copying rest of first 599df8bae1dSRodney W. Grimes * mbuf's data back, and adjust the IP length. 600df8bae1dSRodney W. Grimes */ 601df8bae1dSRodney W. Grimes ip->ip_len -= optlen; 6025e2d0696SGarrett Wollman ip->ip_vhl = IP_VHL_BORING; 603df8bae1dSRodney W. Grimes m->m_len -= optlen; 604df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) 605df8bae1dSRodney W. Grimes m->m_pkthdr.len -= optlen; 606df8bae1dSRodney W. Grimes optlen += sizeof(struct ip); 607df8bae1dSRodney W. Grimes bcopy((caddr_t)ip + optlen, (caddr_t)(ip + 1), 608df8bae1dSRodney W. Grimes (unsigned)(m->m_len - sizeof(struct ip))); 609df8bae1dSRodney W. Grimes } 610df8bae1dSRodney W. Grimes m->m_flags &= ~(M_BCAST|M_MCAST); 611df8bae1dSRodney W. Grimes icmp_send(m, opts); 612df8bae1dSRodney W. Grimes done: 613df8bae1dSRodney W. Grimes if (opts) 614df8bae1dSRodney W. Grimes (void)m_free(opts); 615df8bae1dSRodney W. Grimes } 616df8bae1dSRodney W. Grimes 617df8bae1dSRodney W. Grimes /* 618df8bae1dSRodney W. Grimes * Send an icmp packet back to the ip level, 619df8bae1dSRodney W. Grimes * after supplying a checksum. 620df8bae1dSRodney W. Grimes */ 6210312fbe9SPoul-Henning Kamp static void 622df8bae1dSRodney W. Grimes icmp_send(m, opts) 623df8bae1dSRodney W. Grimes register struct mbuf *m; 624df8bae1dSRodney W. Grimes struct mbuf *opts; 625df8bae1dSRodney W. Grimes { 626df8bae1dSRodney W. Grimes register struct ip *ip = mtod(m, struct ip *); 627df8bae1dSRodney W. Grimes register int hlen; 628df8bae1dSRodney W. Grimes register struct icmp *icp; 629d3d20ad1SGarrett Wollman struct route ro; 630df8bae1dSRodney W. Grimes 6315e2d0696SGarrett Wollman hlen = IP_VHL_HL(ip->ip_vhl) << 2; 632df8bae1dSRodney W. Grimes m->m_data += hlen; 633df8bae1dSRodney W. Grimes m->m_len -= hlen; 634df8bae1dSRodney W. Grimes icp = mtod(m, struct icmp *); 635df8bae1dSRodney W. Grimes icp->icmp_cksum = 0; 636df8bae1dSRodney W. Grimes icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen); 637df8bae1dSRodney W. Grimes m->m_data -= hlen; 638df8bae1dSRodney W. Grimes m->m_len += hlen; 639df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS 6402b758395SGarrett Wollman if (icmpprintfs) { 6412b758395SGarrett Wollman char buf[4 * sizeof "123"]; 6422b758395SGarrett Wollman strcpy(buf, inet_ntoa(ip->ip_dst)); 6432b758395SGarrett Wollman printf("icmp_send dst %s src %s\n", 6442b758395SGarrett Wollman buf, inet_ntoa(ip->ip_src)); 6452b758395SGarrett Wollman } 646df8bae1dSRodney W. Grimes #endif 647d3d20ad1SGarrett Wollman bzero(&ro, sizeof ro); 648d3d20ad1SGarrett Wollman (void) ip_output(m, opts, &ro, 0, NULL); 649d3d20ad1SGarrett Wollman if (ro.ro_rt) 650d3d20ad1SGarrett Wollman RTFREE(ro.ro_rt); 651df8bae1dSRodney W. Grimes } 652df8bae1dSRodney W. Grimes 653df8bae1dSRodney W. Grimes n_time 654df8bae1dSRodney W. Grimes iptime() 655df8bae1dSRodney W. Grimes { 656df8bae1dSRodney W. Grimes struct timeval atv; 657df8bae1dSRodney W. Grimes u_long t; 658df8bae1dSRodney W. Grimes 659df8bae1dSRodney W. Grimes microtime(&atv); 660df8bae1dSRodney W. Grimes t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000; 661df8bae1dSRodney W. Grimes return (htonl(t)); 662df8bae1dSRodney W. Grimes } 663df8bae1dSRodney W. Grimes 664b7a44e34SGarrett Wollman #if 1 6655cbf3e08SGarrett Wollman /* 6665cbf3e08SGarrett Wollman * Return the next larger or smaller MTU plateau (table from RFC 1191) 6675cbf3e08SGarrett Wollman * given current value MTU. If DIR is less than zero, a larger plateau 6685cbf3e08SGarrett Wollman * is returned; otherwise, a smaller value is returned. 6695cbf3e08SGarrett Wollman */ 670f708ef1bSPoul-Henning Kamp static int 6715cbf3e08SGarrett Wollman ip_next_mtu(mtu, dir) 6725cbf3e08SGarrett Wollman int mtu; 6735cbf3e08SGarrett Wollman int dir; 6745cbf3e08SGarrett Wollman { 6755cbf3e08SGarrett Wollman static int mtutab[] = { 6765cbf3e08SGarrett Wollman 65535, 32000, 17914, 8166, 4352, 2002, 1492, 1006, 508, 296, 6775cbf3e08SGarrett Wollman 68, 0 6785cbf3e08SGarrett Wollman }; 6795cbf3e08SGarrett Wollman int i; 6805cbf3e08SGarrett Wollman 6815cbf3e08SGarrett Wollman for (i = 0; i < (sizeof mtutab) / (sizeof mtutab[0]); i++) { 6825cbf3e08SGarrett Wollman if (mtu >= mtutab[i]) 6835cbf3e08SGarrett Wollman break; 6845cbf3e08SGarrett Wollman } 6855cbf3e08SGarrett Wollman 6865cbf3e08SGarrett Wollman if (dir < 0) { 6875cbf3e08SGarrett Wollman if (i == 0) { 6885cbf3e08SGarrett Wollman return 0; 6895cbf3e08SGarrett Wollman } else { 6905cbf3e08SGarrett Wollman return mtutab[i - 1]; 6915cbf3e08SGarrett Wollman } 6925cbf3e08SGarrett Wollman } else { 6935cbf3e08SGarrett Wollman if (mtutab[i] == 0) { 6945cbf3e08SGarrett Wollman return 0; 6955cbf3e08SGarrett Wollman } else if(mtu > mtutab[i]) { 6965cbf3e08SGarrett Wollman return mtutab[i]; 6975cbf3e08SGarrett Wollman } else { 6985cbf3e08SGarrett Wollman return mtutab[i + 1]; 6995cbf3e08SGarrett Wollman } 7005cbf3e08SGarrett Wollman } 7015cbf3e08SGarrett Wollman } 702b7a44e34SGarrett Wollman #endif 703