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_input.c 8.2 (Berkeley) 1/4/94 34f9e354dfSJulian Elischer * $Id: ip_input.c,v 1.91 1998/07/02 05:49:12 julian Exp $ 3558938916SGarrett Wollman * $ANA: ip_input.c,v 1.5 1996/09/18 14:34:59 wollman Exp $ 36df8bae1dSRodney W. Grimes */ 37df8bae1dSRodney W. Grimes 3858938916SGarrett Wollman #define _IP_VHL 3958938916SGarrett Wollman 40e4f4247aSEivind Eklund #include "opt_bootp.h" 4174a9466cSGary Palmer #include "opt_ipfw.h" 42fbd1372aSJoerg Wunsch #include "opt_ipdivert.h" 431ee25934SPeter Wemm #include "opt_ipfilter.h" 4474a9466cSGary Palmer 4582c23ebaSBill Fenner #include <stddef.h> 4682c23ebaSBill Fenner 47df8bae1dSRodney W. Grimes #include <sys/param.h> 48df8bae1dSRodney W. Grimes #include <sys/systm.h> 49df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 50df8bae1dSRodney W. Grimes #include <sys/domain.h> 51df8bae1dSRodney W. Grimes #include <sys/protosw.h> 52df8bae1dSRodney W. Grimes #include <sys/socket.h> 53df8bae1dSRodney W. Grimes #include <sys/time.h> 54df8bae1dSRodney W. Grimes #include <sys/kernel.h> 551025071fSGarrett Wollman #include <sys/syslog.h> 56b5e8ce9fSBruce Evans #include <sys/sysctl.h> 57df8bae1dSRodney W. Grimes 58df8bae1dSRodney W. Grimes #include <net/if.h> 59d314ad7bSJulian Elischer #include <net/if_var.h> 6082c23ebaSBill Fenner #include <net/if_dl.h> 61df8bae1dSRodney W. Grimes #include <net/route.h> 62748e0b0aSGarrett Wollman #include <net/netisr.h> 63df8bae1dSRodney W. Grimes 64df8bae1dSRodney W. Grimes #include <netinet/in.h> 65df8bae1dSRodney W. Grimes #include <netinet/in_systm.h> 66b5e8ce9fSBruce Evans #include <netinet/in_var.h> 67df8bae1dSRodney W. Grimes #include <netinet/ip.h> 68df8bae1dSRodney W. Grimes #include <netinet/in_pcb.h> 69df8bae1dSRodney W. Grimes #include <netinet/ip_var.h> 70df8bae1dSRodney W. Grimes #include <netinet/ip_icmp.h> 7158938916SGarrett Wollman #include <machine/in_cksum.h> 72df8bae1dSRodney W. Grimes 73f0068c4aSGarrett Wollman #include <sys/socketvar.h> 746ddbf1e2SGary Palmer 756ddbf1e2SGary Palmer #ifdef IPFIREWALL 766ddbf1e2SGary Palmer #include <netinet/ip_fw.h> 776ddbf1e2SGary Palmer #endif 786ddbf1e2SGary Palmer 791c5de19aSGarrett Wollman int rsvp_on = 0; 80f708ef1bSPoul-Henning Kamp static int ip_rsvp_on; 81f0068c4aSGarrett Wollman struct socket *ip_rsvpd; 82f0068c4aSGarrett Wollman 831f91d8c5SDavid Greenman int ipforwarding = 0; 840312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_FORWARDING, forwarding, CTLFLAG_RW, 850312fbe9SPoul-Henning Kamp &ipforwarding, 0, ""); 860312fbe9SPoul-Henning Kamp 87d4fb926cSGarrett Wollman static int ipsendredirects = 1; /* XXX */ 880312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_SENDREDIRECTS, redirect, CTLFLAG_RW, 890312fbe9SPoul-Henning Kamp &ipsendredirects, 0, ""); 900312fbe9SPoul-Henning Kamp 91df8bae1dSRodney W. Grimes int ip_defttl = IPDEFTTL; 920312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_DEFTTL, ttl, CTLFLAG_RW, 930312fbe9SPoul-Henning Kamp &ip_defttl, 0, ""); 940312fbe9SPoul-Henning Kamp 950312fbe9SPoul-Henning Kamp static int ip_dosourceroute = 0; 960312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_SOURCEROUTE, sourceroute, CTLFLAG_RW, 970312fbe9SPoul-Henning Kamp &ip_dosourceroute, 0, ""); 984fce5804SGuido van Rooij 994fce5804SGuido van Rooij static int ip_acceptsourceroute = 0; 1004fce5804SGuido van Rooij SYSCTL_INT(_net_inet_ip, IPCTL_ACCEPTSOURCEROUTE, accept_sourceroute, 1014fce5804SGuido van Rooij CTLFLAG_RW, &ip_acceptsourceroute, 0, ""); 102df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1030312fbe9SPoul-Henning Kamp static int ipprintfs = 0; 104df8bae1dSRodney W. Grimes #endif 105df8bae1dSRodney W. Grimes 106df8bae1dSRodney W. Grimes extern struct domain inetdomain; 107df8bae1dSRodney W. Grimes extern struct protosw inetsw[]; 108df8bae1dSRodney W. Grimes u_char ip_protox[IPPROTO_MAX]; 1090312fbe9SPoul-Henning Kamp static int ipqmaxlen = IFQ_MAXLEN; 11059562606SGarrett Wollman struct in_ifaddrhead in_ifaddrhead; /* first inet address */ 111df8bae1dSRodney W. Grimes struct ifqueue ipintrq; 1120312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_INTRQMAXLEN, intr_queue_maxlen, CTLFLAG_RD, 1130312fbe9SPoul-Henning Kamp &ipintrq.ifq_maxlen, 0, ""); 1140312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_INTRQDROPS, intr_queue_drops, CTLFLAG_RD, 1150312fbe9SPoul-Henning Kamp &ipintrq.ifq_drops, 0, ""); 116df8bae1dSRodney W. Grimes 117f23b4c91SGarrett Wollman struct ipstat ipstat; 1186fce01c9SGarrett Wollman SYSCTL_STRUCT(_net_inet_ip, IPCTL_STATS, stats, CTLFLAG_RD, 1196fce01c9SGarrett Wollman &ipstat, ipstat, ""); 120194a213eSAndrey A. Chernov 121194a213eSAndrey A. Chernov /* Packet reassembly stuff */ 122194a213eSAndrey A. Chernov #define IPREASS_NHASH_LOG2 6 123194a213eSAndrey A. Chernov #define IPREASS_NHASH (1 << IPREASS_NHASH_LOG2) 124194a213eSAndrey A. Chernov #define IPREASS_HMASK (IPREASS_NHASH - 1) 125194a213eSAndrey A. Chernov #define IPREASS_HASH(x,y) \ 126194a213eSAndrey A. Chernov ((((x) & 0xF | ((((x) >> 8) & 0xF) << 4)) ^ (y)) & IPREASS_HMASK) 127194a213eSAndrey A. Chernov 128194a213eSAndrey A. Chernov static struct ipq ipq[IPREASS_NHASH]; 129194a213eSAndrey A. Chernov static int nipq = 0; /* total # of reass queues */ 130194a213eSAndrey A. Chernov static int maxnipq; 131f23b4c91SGarrett Wollman 1320312fbe9SPoul-Henning Kamp #ifdef IPCTL_DEFMTU 1330312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_DEFMTU, mtu, CTLFLAG_RW, 1340312fbe9SPoul-Henning Kamp &ip_mtu, 0, ""); 1350312fbe9SPoul-Henning Kamp #endif 1360312fbe9SPoul-Henning Kamp 13758938916SGarrett Wollman #if !defined(COMPAT_IPFW) || COMPAT_IPFW == 1 13858938916SGarrett Wollman #undef COMPAT_IPFW 13958938916SGarrett Wollman #define COMPAT_IPFW 1 14058938916SGarrett Wollman #else 14158938916SGarrett Wollman #undef COMPAT_IPFW 14258938916SGarrett Wollman #endif 14358938916SGarrett Wollman 14458938916SGarrett Wollman #ifdef COMPAT_IPFW 14523bf9953SPoul-Henning Kamp /* Firewall hooks */ 14623bf9953SPoul-Henning Kamp ip_fw_chk_t *ip_fw_chk_ptr; 14723bf9953SPoul-Henning Kamp ip_fw_ctl_t *ip_fw_ctl_ptr; 148e7319babSPoul-Henning Kamp 149fed1c7e9SSøren Schmidt /* IP Network Address Translation (NAT) hooks */ 150fed1c7e9SSøren Schmidt ip_nat_t *ip_nat_ptr; 151fed1c7e9SSøren Schmidt ip_nat_ctl_t *ip_nat_ctl_ptr; 15258938916SGarrett Wollman #endif 153fed1c7e9SSøren Schmidt 154afed1b49SDarren Reed #if defined(IPFILTER_LKM) || defined(IPFILTER) 1551ee25934SPeter Wemm int iplattach __P((void)); 156afed1b49SDarren Reed int (*fr_checkp) __P((struct ip *, int, struct ifnet *, int, struct mbuf **)) = NULL; 157afed1b49SDarren Reed #endif 158afed1b49SDarren Reed 159afed1b49SDarren Reed 160e7319babSPoul-Henning Kamp /* 161df8bae1dSRodney W. Grimes * We need to save the IP options in case a protocol wants to respond 162df8bae1dSRodney W. Grimes * to an incoming packet over the same route if the packet got here 163df8bae1dSRodney W. Grimes * using IP source routing. This allows connection establishment and 164df8bae1dSRodney W. Grimes * maintenance when the remote end is on a network that is not known 165df8bae1dSRodney W. Grimes * to us. 166df8bae1dSRodney W. Grimes */ 1670312fbe9SPoul-Henning Kamp static int ip_nhops = 0; 168df8bae1dSRodney W. Grimes static struct ip_srcrt { 169df8bae1dSRodney W. Grimes struct in_addr dst; /* final destination */ 170df8bae1dSRodney W. Grimes char nop; /* one NOP to align */ 171df8bae1dSRodney W. Grimes char srcopt[IPOPT_OFFSET + 1]; /* OPTVAL, OLEN and OFFSET */ 172df8bae1dSRodney W. Grimes struct in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)]; 173df8bae1dSRodney W. Grimes } ip_srcrt; 174df8bae1dSRodney W. Grimes 17593e0e116SJulian Elischer #ifdef IPDIVERT 17693e0e116SJulian Elischer /* 17793e0e116SJulian Elischer * Shared variable between ip_input() and ip_reass() to communicate 17893e0e116SJulian Elischer * about which packets, once assembled from fragments, get diverted, 17993e0e116SJulian Elischer * and to which port. 18093e0e116SJulian Elischer */ 18193e0e116SJulian Elischer static u_short frag_divert_port; 18293e0e116SJulian Elischer #endif 18393e0e116SJulian Elischer 184f9e354dfSJulian Elischer struct sockaddr_in *ip_fw_fwd_addr; 185f9e354dfSJulian Elischer 186df8bae1dSRodney W. Grimes static void save_rte __P((u_char *, struct in_addr)); 1870312fbe9SPoul-Henning Kamp static void ip_deq __P((struct ipasfrag *)); 1880312fbe9SPoul-Henning Kamp static int ip_dooptions __P((struct mbuf *)); 1890312fbe9SPoul-Henning Kamp static void ip_enq __P((struct ipasfrag *, struct ipasfrag *)); 1900312fbe9SPoul-Henning Kamp static void ip_forward __P((struct mbuf *, int)); 1910312fbe9SPoul-Henning Kamp static void ip_freef __P((struct ipq *)); 1920312fbe9SPoul-Henning Kamp static struct ip * 193194a213eSAndrey A. Chernov ip_reass __P((struct ipasfrag *, struct ipq *, struct ipq *)); 1940312fbe9SPoul-Henning Kamp static struct in_ifaddr * 1950312fbe9SPoul-Henning Kamp ip_rtaddr __P((struct in_addr)); 1960312fbe9SPoul-Henning Kamp static void ipintr __P((void)); 197df8bae1dSRodney W. Grimes /* 198df8bae1dSRodney W. Grimes * IP initialization: fill in IP protocol switch table. 199df8bae1dSRodney W. Grimes * All protocols not implemented in kernel go to raw IP protocol handler. 200df8bae1dSRodney W. Grimes */ 201df8bae1dSRodney W. Grimes void 202df8bae1dSRodney W. Grimes ip_init() 203df8bae1dSRodney W. Grimes { 204df8bae1dSRodney W. Grimes register struct protosw *pr; 205df8bae1dSRodney W. Grimes register int i; 206df8bae1dSRodney W. Grimes 20759562606SGarrett Wollman TAILQ_INIT(&in_ifaddrhead); 208df8bae1dSRodney W. Grimes pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW); 209df8bae1dSRodney W. Grimes if (pr == 0) 210df8bae1dSRodney W. Grimes panic("ip_init"); 211df8bae1dSRodney W. Grimes for (i = 0; i < IPPROTO_MAX; i++) 212df8bae1dSRodney W. Grimes ip_protox[i] = pr - inetsw; 213df8bae1dSRodney W. Grimes for (pr = inetdomain.dom_protosw; 214df8bae1dSRodney W. Grimes pr < inetdomain.dom_protoswNPROTOSW; pr++) 215df8bae1dSRodney W. Grimes if (pr->pr_domain->dom_family == PF_INET && 216df8bae1dSRodney W. Grimes pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) 217df8bae1dSRodney W. Grimes ip_protox[pr->pr_protocol] = pr - inetsw; 218194a213eSAndrey A. Chernov 219194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) 220194a213eSAndrey A. Chernov ipq[i].next = ipq[i].prev = &ipq[i]; 221194a213eSAndrey A. Chernov 222194a213eSAndrey A. Chernov maxnipq = nmbclusters/4; 223194a213eSAndrey A. Chernov 224227ee8a1SPoul-Henning Kamp ip_id = time_second & 0xffff; 225df8bae1dSRodney W. Grimes ipintrq.ifq_maxlen = ipqmaxlen; 226b83e4314SPoul-Henning Kamp #ifdef IPFIREWALL 227b83e4314SPoul-Henning Kamp ip_fw_init(); 228b83e4314SPoul-Henning Kamp #endif 229fed1c7e9SSøren Schmidt #ifdef IPNAT 230fed1c7e9SSøren Schmidt ip_nat_init(); 231fed1c7e9SSøren Schmidt #endif 2321ee25934SPeter Wemm #ifdef IPFILTER 2331ee25934SPeter Wemm iplattach(); 2341ee25934SPeter Wemm #endif 235fed1c7e9SSøren Schmidt 236df8bae1dSRodney W. Grimes } 237df8bae1dSRodney W. Grimes 2380312fbe9SPoul-Henning Kamp static struct sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET }; 239f708ef1bSPoul-Henning Kamp static struct route ipforward_rt; 240df8bae1dSRodney W. Grimes 241df8bae1dSRodney W. Grimes /* 242df8bae1dSRodney W. Grimes * Ip input routine. Checksum and byte swap header. If fragmented 243df8bae1dSRodney W. Grimes * try to reassemble. Process options. Pass to next level. 244df8bae1dSRodney W. Grimes */ 245c67b1d17SGarrett Wollman void 246c67b1d17SGarrett Wollman ip_input(struct mbuf *m) 247df8bae1dSRodney W. Grimes { 24823bf9953SPoul-Henning Kamp struct ip *ip; 24923bf9953SPoul-Henning Kamp struct ipq *fp; 25023bf9953SPoul-Henning Kamp struct in_ifaddr *ia; 251194a213eSAndrey A. Chernov int i, hlen; 25247c861ecSBrian Somers u_short sum; 253df8bae1dSRodney W. Grimes 254df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 255ed7509acSJulian Elischer if (m == NULL || (m->m_flags & M_PKTHDR) == 0) 25658938916SGarrett Wollman panic("ip_input no HDR"); 257df8bae1dSRodney W. Grimes #endif 258df8bae1dSRodney W. Grimes /* 259df8bae1dSRodney W. Grimes * If no IP addresses have been set yet but the interfaces 260df8bae1dSRodney W. Grimes * are receiving, can't do anything with incoming packets yet. 26159562606SGarrett Wollman * XXX This is broken! We should be able to receive broadcasts 26259562606SGarrett Wollman * and multicasts even without any local addresses configured. 263df8bae1dSRodney W. Grimes */ 26459562606SGarrett Wollman if (TAILQ_EMPTY(&in_ifaddrhead)) 265df8bae1dSRodney W. Grimes goto bad; 266df8bae1dSRodney W. Grimes ipstat.ips_total++; 26758938916SGarrett Wollman 26858938916SGarrett Wollman if (m->m_pkthdr.len < sizeof(struct ip)) 26958938916SGarrett Wollman goto tooshort; 27058938916SGarrett Wollman 271df8bae1dSRodney W. Grimes if (m->m_len < sizeof (struct ip) && 272df8bae1dSRodney W. Grimes (m = m_pullup(m, sizeof (struct ip))) == 0) { 273df8bae1dSRodney W. Grimes ipstat.ips_toosmall++; 274c67b1d17SGarrett Wollman return; 275df8bae1dSRodney W. Grimes } 276df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 27758938916SGarrett Wollman 27858938916SGarrett Wollman if (IP_VHL_V(ip->ip_vhl) != IPVERSION) { 279df8bae1dSRodney W. Grimes ipstat.ips_badvers++; 280df8bae1dSRodney W. Grimes goto bad; 281df8bae1dSRodney W. Grimes } 28258938916SGarrett Wollman 28358938916SGarrett Wollman hlen = IP_VHL_HL(ip->ip_vhl) << 2; 284df8bae1dSRodney W. Grimes if (hlen < sizeof(struct ip)) { /* minimum header length */ 285df8bae1dSRodney W. Grimes ipstat.ips_badhlen++; 286df8bae1dSRodney W. Grimes goto bad; 287df8bae1dSRodney W. Grimes } 288df8bae1dSRodney W. Grimes if (hlen > m->m_len) { 289df8bae1dSRodney W. Grimes if ((m = m_pullup(m, hlen)) == 0) { 290df8bae1dSRodney W. Grimes ipstat.ips_badhlen++; 291c67b1d17SGarrett Wollman return; 292df8bae1dSRodney W. Grimes } 293df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 294df8bae1dSRodney W. Grimes } 29558938916SGarrett Wollman if (hlen == sizeof(struct ip)) { 29647c861ecSBrian Somers sum = in_cksum_hdr(ip); 29758938916SGarrett Wollman } else { 29847c861ecSBrian Somers sum = in_cksum(m, hlen); 29958938916SGarrett Wollman } 30047c861ecSBrian Somers if (sum) { 301df8bae1dSRodney W. Grimes ipstat.ips_badsum++; 302df8bae1dSRodney W. Grimes goto bad; 303df8bae1dSRodney W. Grimes } 304df8bae1dSRodney W. Grimes 305df8bae1dSRodney W. Grimes /* 306df8bae1dSRodney W. Grimes * Convert fields to host representation. 307df8bae1dSRodney W. Grimes */ 308df8bae1dSRodney W. Grimes NTOHS(ip->ip_len); 309df8bae1dSRodney W. Grimes if (ip->ip_len < hlen) { 310df8bae1dSRodney W. Grimes ipstat.ips_badlen++; 311df8bae1dSRodney W. Grimes goto bad; 312df8bae1dSRodney W. Grimes } 313df8bae1dSRodney W. Grimes NTOHS(ip->ip_id); 314df8bae1dSRodney W. Grimes NTOHS(ip->ip_off); 315df8bae1dSRodney W. Grimes 316df8bae1dSRodney W. Grimes /* 317df8bae1dSRodney W. Grimes * Check that the amount of data in the buffers 318df8bae1dSRodney W. Grimes * is as at least much as the IP header would have us expect. 319df8bae1dSRodney W. Grimes * Trim mbufs if longer than we expect. 320df8bae1dSRodney W. Grimes * Drop packet if shorter than we expect. 321df8bae1dSRodney W. Grimes */ 322df8bae1dSRodney W. Grimes if (m->m_pkthdr.len < ip->ip_len) { 32358938916SGarrett Wollman tooshort: 324df8bae1dSRodney W. Grimes ipstat.ips_tooshort++; 325df8bae1dSRodney W. Grimes goto bad; 326df8bae1dSRodney W. Grimes } 327df8bae1dSRodney W. Grimes if (m->m_pkthdr.len > ip->ip_len) { 328df8bae1dSRodney W. Grimes if (m->m_len == m->m_pkthdr.len) { 329df8bae1dSRodney W. Grimes m->m_len = ip->ip_len; 330df8bae1dSRodney W. Grimes m->m_pkthdr.len = ip->ip_len; 331df8bae1dSRodney W. Grimes } else 332df8bae1dSRodney W. Grimes m_adj(m, ip->ip_len - m->m_pkthdr.len); 333df8bae1dSRodney W. Grimes } 3344dd1662bSUgen J.S. Antsilevich /* 3354dd1662bSUgen J.S. Antsilevich * IpHack's section. 3364dd1662bSUgen J.S. Antsilevich * Right now when no processing on packet has done 3374dd1662bSUgen J.S. Antsilevich * and it is still fresh out of network we do our black 3384dd1662bSUgen J.S. Antsilevich * deals with it. 33993e0e116SJulian Elischer * - Firewall: deny/allow/divert 340fed1c7e9SSøren Schmidt * - Xlate: translate packet's addr/port (NAT). 3414dd1662bSUgen J.S. Antsilevich * - Wrap: fake packet's addr/port <unimpl.> 3424dd1662bSUgen J.S. Antsilevich * - Encapsulate: put it in another IP and send out. <unimp.> 3434dd1662bSUgen J.S. Antsilevich */ 344beec8214SDarren Reed #if defined(IPFILTER) || defined(IPFILTER_LKM) 345beec8214SDarren Reed /* 346beec8214SDarren Reed * Check if we want to allow this packet to be processed. 347beec8214SDarren Reed * Consider it to be bad if not. 348beec8214SDarren Reed */ 3491ee25934SPeter Wemm if (fr_checkp) { 350beec8214SDarren Reed struct mbuf *m1 = m; 351df8bae1dSRodney W. Grimes 352beec8214SDarren Reed if ((*fr_checkp)(ip, hlen, m->m_pkthdr.rcvif, 0, &m1) || !m1) 353beec8214SDarren Reed return; 354beec8214SDarren Reed ip = mtod(m = m1, struct ip *); 355beec8214SDarren Reed } 356beec8214SDarren Reed #endif 35758938916SGarrett Wollman #ifdef COMPAT_IPFW 35893e0e116SJulian Elischer if (ip_fw_chk_ptr) { 359f9e354dfSJulian Elischer u_int16_t port; 36093e0e116SJulian Elischer 361f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 362f9e354dfSJulian Elischer /* 363f9e354dfSJulian Elischer * If we've been forwarded from the output side, then 364f9e354dfSJulian Elischer * skip the firewall a second time 365f9e354dfSJulian Elischer */ 366f9e354dfSJulian Elischer if (ip_fw_fwd_addr) 367f9e354dfSJulian Elischer goto ours; 368f9e354dfSJulian Elischer #endif /* IPFIREWALL_FORWARD */ 369f9e354dfSJulian Elischer #ifdef IPDIVERT 370f9e354dfSJulian Elischer port = (*ip_fw_chk_ptr)(&ip, hlen, NULL, &ip_divert_cookie, 371f9e354dfSJulian Elischer &m, &ip_fw_fwd_addr); 372b3adeeb2SJulian Elischer if (port) { 373b3adeeb2SJulian Elischer /* Divert packet */ 374e4676ba6SJulian Elischer frag_divert_port = port; 37593e0e116SJulian Elischer goto ours; 37693e0e116SJulian Elischer } 377f9e354dfSJulian Elischer #else /* !DIVERT */ 378f9e354dfSJulian Elischer /* 379f9e354dfSJulian Elischer * If ipfw says divert, we have to just drop packet */ 380f9e354dfSJulian Elischer * Use port as a dummy argument. 381f9e354dfSJulian Elischer */ 382f9e354dfSJulian Elischer port = 0; 383f9e354dfSJulian Elischer if ((*ip_fw_chk_ptr)(&ip, hlen, NULL, &port, 384f9e354dfSJulian Elischer &m, &ip_fw_fwd_addr)) { 385e4676ba6SJulian Elischer m_freem(m); 386e4676ba6SJulian Elischer m = NULL; 387e4676ba6SJulian Elischer } 388f9e354dfSJulian Elischer #endif /* !DIVERT */ 389e4676ba6SJulian Elischer if (!m) 390e4676ba6SJulian Elischer return; 39193e0e116SJulian Elischer } 392100ba1a6SJordan K. Hubbard 3936713d4a7SSøren Schmidt if (ip_nat_ptr && !(*ip_nat_ptr)(&ip, &m, m->m_pkthdr.rcvif, IP_NAT_IN)) 394fed1c7e9SSøren Schmidt return; 395f9e354dfSJulian Elischer #endif /* !COMPAT_IPFW */ 396fed1c7e9SSøren Schmidt 397df8bae1dSRodney W. Grimes /* 398df8bae1dSRodney W. Grimes * Process options and, if not destined for us, 399df8bae1dSRodney W. Grimes * ship it on. ip_dooptions returns 1 when an 400df8bae1dSRodney W. Grimes * error was detected (causing an icmp message 401df8bae1dSRodney W. Grimes * to be sent and the original packet to be freed). 402df8bae1dSRodney W. Grimes */ 403df8bae1dSRodney W. Grimes ip_nhops = 0; /* for source routed packets */ 404df8bae1dSRodney W. Grimes if (hlen > sizeof (struct ip) && ip_dooptions(m)) 405c67b1d17SGarrett Wollman return; 406df8bae1dSRodney W. Grimes 407f0068c4aSGarrett Wollman /* greedy RSVP, snatches any PATH packet of the RSVP protocol and no 408f0068c4aSGarrett Wollman * matter if it is destined to another node, or whether it is 409f0068c4aSGarrett Wollman * a multicast one, RSVP wants it! and prevents it from being forwarded 410f0068c4aSGarrett Wollman * anywhere else. Also checks if the rsvp daemon is running before 411f0068c4aSGarrett Wollman * grabbing the packet. 412f0068c4aSGarrett Wollman */ 4131c5de19aSGarrett Wollman if (rsvp_on && ip->ip_p==IPPROTO_RSVP) 414f0068c4aSGarrett Wollman goto ours; 415f0068c4aSGarrett Wollman 416df8bae1dSRodney W. Grimes /* 417df8bae1dSRodney W. Grimes * Check our list of addresses, to see if the packet is for us. 418df8bae1dSRodney W. Grimes */ 419f9e354dfSJulian Elischer for (ia = TAILQ_FIRST(in_ifaddrhead); ia; 420f9e354dfSJulian Elischer ia = TAILQ_NEXT(ia, ia_link)) { 421df8bae1dSRodney W. Grimes #define satosin(sa) ((struct sockaddr_in *)(sa)) 422df8bae1dSRodney W. Grimes 423df8bae1dSRodney W. Grimes if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr) 424df8bae1dSRodney W. Grimes goto ours; 425432aad0eSTor Egge #ifdef BOOTP_COMPAT 426432aad0eSTor Egge if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY) 427432aad0eSTor Egge goto ours; 428432aad0eSTor Egge #endif 429f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 430f9e354dfSJulian Elischer /* 431f9e354dfSJulian Elischer * If the addr to forward to is one of ours, we pretend to 432f9e354dfSJulian Elischer * be the destination for this packet. 433f9e354dfSJulian Elischer */ 434f9e354dfSJulian Elischer if (ip_fw_fwd_addr != NULL && 435f9e354dfSJulian Elischer IA_SIN(ia)->sin_addr.s_addr == 436f9e354dfSJulian Elischer ip_fw_fwd_addr->sin_addr.s_addr) 437f9e354dfSJulian Elischer goto ours; 438f9e354dfSJulian Elischer #endif 4396ed666afSPoul-Henning Kamp if (ia->ia_ifp && ia->ia_ifp->if_flags & IFF_BROADCAST) { 440df8bae1dSRodney W. Grimes if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == 441df8bae1dSRodney W. Grimes ip->ip_dst.s_addr) 442df8bae1dSRodney W. Grimes goto ours; 443df8bae1dSRodney W. Grimes if (ip->ip_dst.s_addr == ia->ia_netbroadcast.s_addr) 444df8bae1dSRodney W. Grimes goto ours; 445df8bae1dSRodney W. Grimes } 446df8bae1dSRodney W. Grimes } 447df8bae1dSRodney W. Grimes if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { 448df8bae1dSRodney W. Grimes struct in_multi *inm; 449df8bae1dSRodney W. Grimes if (ip_mrouter) { 450df8bae1dSRodney W. Grimes /* 451df8bae1dSRodney W. Grimes * If we are acting as a multicast router, all 452df8bae1dSRodney W. Grimes * incoming multicast packets are passed to the 453df8bae1dSRodney W. Grimes * kernel-level multicast forwarding function. 454df8bae1dSRodney W. Grimes * The packet is returned (relatively) intact; if 455df8bae1dSRodney W. Grimes * ip_mforward() returns a non-zero value, the packet 456df8bae1dSRodney W. Grimes * must be discarded, else it may be accepted below. 457df8bae1dSRodney W. Grimes * 458df8bae1dSRodney W. Grimes * (The IP ident field is put in the same byte order 459df8bae1dSRodney W. Grimes * as expected when ip_mforward() is called from 460df8bae1dSRodney W. Grimes * ip_output().) 461df8bae1dSRodney W. Grimes */ 462df8bae1dSRodney W. Grimes ip->ip_id = htons(ip->ip_id); 463f0068c4aSGarrett Wollman if (ip_mforward(ip, m->m_pkthdr.rcvif, m, 0) != 0) { 464df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 465df8bae1dSRodney W. Grimes m_freem(m); 466c67b1d17SGarrett Wollman return; 467df8bae1dSRodney W. Grimes } 468df8bae1dSRodney W. Grimes ip->ip_id = ntohs(ip->ip_id); 469df8bae1dSRodney W. Grimes 470df8bae1dSRodney W. Grimes /* 471df8bae1dSRodney W. Grimes * The process-level routing demon needs to receive 472df8bae1dSRodney W. Grimes * all multicast IGMP packets, whether or not this 473df8bae1dSRodney W. Grimes * host belongs to their destination groups. 474df8bae1dSRodney W. Grimes */ 475df8bae1dSRodney W. Grimes if (ip->ip_p == IPPROTO_IGMP) 476df8bae1dSRodney W. Grimes goto ours; 477df8bae1dSRodney W. Grimes ipstat.ips_forward++; 478df8bae1dSRodney W. Grimes } 479df8bae1dSRodney W. Grimes /* 480df8bae1dSRodney W. Grimes * See if we belong to the destination multicast group on the 481df8bae1dSRodney W. Grimes * arrival interface. 482df8bae1dSRodney W. Grimes */ 483df8bae1dSRodney W. Grimes IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm); 484df8bae1dSRodney W. Grimes if (inm == NULL) { 48582c39223SGarrett Wollman ipstat.ips_notmember++; 486df8bae1dSRodney W. Grimes m_freem(m); 487c67b1d17SGarrett Wollman return; 488df8bae1dSRodney W. Grimes } 489df8bae1dSRodney W. Grimes goto ours; 490df8bae1dSRodney W. Grimes } 491df8bae1dSRodney W. Grimes if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST) 492df8bae1dSRodney W. Grimes goto ours; 493df8bae1dSRodney W. Grimes if (ip->ip_dst.s_addr == INADDR_ANY) 494df8bae1dSRodney W. Grimes goto ours; 495df8bae1dSRodney W. Grimes 496df8bae1dSRodney W. Grimes /* 497df8bae1dSRodney W. Grimes * Not for us; forward if possible and desirable. 498df8bae1dSRodney W. Grimes */ 499df8bae1dSRodney W. Grimes if (ipforwarding == 0) { 500df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 501df8bae1dSRodney W. Grimes m_freem(m); 502df8bae1dSRodney W. Grimes } else 503df8bae1dSRodney W. Grimes ip_forward(m, 0); 504c67b1d17SGarrett Wollman return; 505df8bae1dSRodney W. Grimes 506df8bae1dSRodney W. Grimes ours: 507100ba1a6SJordan K. Hubbard 50863f8d699SJordan K. Hubbard /* 509df8bae1dSRodney W. Grimes * If offset or IP_MF are set, must reassemble. 510df8bae1dSRodney W. Grimes * Otherwise, nothing need be done. 511df8bae1dSRodney W. Grimes * (We could look in the reassembly queue to see 512df8bae1dSRodney W. Grimes * if the packet was previously fragmented, 513df8bae1dSRodney W. Grimes * but it's not worth the time; just let them time out.) 514df8bae1dSRodney W. Grimes */ 515c383a33fSDima Ruban if (ip->ip_off & (IP_MF | IP_OFFMASK | IP_RF)) { 516df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT) { /* XXX */ 517df8bae1dSRodney W. Grimes if ((m = m_pullup(m, sizeof (struct ip))) == 0) { 518df8bae1dSRodney W. Grimes ipstat.ips_toosmall++; 51993e0e116SJulian Elischer #ifdef IPDIVERT 52093e0e116SJulian Elischer frag_divert_port = 0; 521c977d4c7SJulian Elischer ip_divert_cookie = 0; 52293e0e116SJulian Elischer #endif 523c67b1d17SGarrett Wollman return; 524df8bae1dSRodney W. Grimes } 525df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 526df8bae1dSRodney W. Grimes } 527194a213eSAndrey A. Chernov sum = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id); 528df8bae1dSRodney W. Grimes /* 529df8bae1dSRodney W. Grimes * Look for queue of fragments 530df8bae1dSRodney W. Grimes * of this datagram. 531df8bae1dSRodney W. Grimes */ 532194a213eSAndrey A. Chernov for (fp = ipq[sum].next; fp != &ipq[sum]; fp = fp->next) 533df8bae1dSRodney W. Grimes if (ip->ip_id == fp->ipq_id && 534df8bae1dSRodney W. Grimes ip->ip_src.s_addr == fp->ipq_src.s_addr && 535df8bae1dSRodney W. Grimes ip->ip_dst.s_addr == fp->ipq_dst.s_addr && 536df8bae1dSRodney W. Grimes ip->ip_p == fp->ipq_p) 537df8bae1dSRodney W. Grimes goto found; 538df8bae1dSRodney W. Grimes 539194a213eSAndrey A. Chernov fp = 0; 540194a213eSAndrey A. Chernov 541194a213eSAndrey A. Chernov /* check if there's a place for the new queue */ 542194a213eSAndrey A. Chernov if (nipq > maxnipq) { 543194a213eSAndrey A. Chernov /* 544194a213eSAndrey A. Chernov * drop something from the tail of the current queue 545194a213eSAndrey A. Chernov * before proceeding further 546194a213eSAndrey A. Chernov */ 547194a213eSAndrey A. Chernov if (ipq[sum].prev == &ipq[sum]) { /* gak */ 548194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 549194a213eSAndrey A. Chernov if (ipq[i].prev != &ipq[i]) { 550194a213eSAndrey A. Chernov ip_freef(ipq[i].prev); 551194a213eSAndrey A. Chernov break; 552194a213eSAndrey A. Chernov } 553194a213eSAndrey A. Chernov } 554194a213eSAndrey A. Chernov } else 555194a213eSAndrey A. Chernov ip_freef(ipq[sum].prev); 556194a213eSAndrey A. Chernov } 557194a213eSAndrey A. Chernov found: 558df8bae1dSRodney W. Grimes /* 559df8bae1dSRodney W. Grimes * Adjust ip_len to not reflect header, 560df8bae1dSRodney W. Grimes * set ip_mff if more fragments are expected, 561df8bae1dSRodney W. Grimes * convert offset of this to bytes. 562df8bae1dSRodney W. Grimes */ 563df8bae1dSRodney W. Grimes ip->ip_len -= hlen; 564df8bae1dSRodney W. Grimes ((struct ipasfrag *)ip)->ipf_mff &= ~1; 565df8bae1dSRodney W. Grimes if (ip->ip_off & IP_MF) 566df8bae1dSRodney W. Grimes ((struct ipasfrag *)ip)->ipf_mff |= 1; 567df8bae1dSRodney W. Grimes ip->ip_off <<= 3; 568df8bae1dSRodney W. Grimes 569df8bae1dSRodney W. Grimes /* 570df8bae1dSRodney W. Grimes * If datagram marked as having more fragments 571df8bae1dSRodney W. Grimes * or if this is not the first fragment, 572df8bae1dSRodney W. Grimes * attempt reassembly; if it succeeds, proceed. 573df8bae1dSRodney W. Grimes */ 574df8bae1dSRodney W. Grimes if (((struct ipasfrag *)ip)->ipf_mff & 1 || ip->ip_off) { 575df8bae1dSRodney W. Grimes ipstat.ips_fragments++; 576194a213eSAndrey A. Chernov ip = ip_reass((struct ipasfrag *)ip, fp, &ipq[sum]); 577f9e354dfSJulian Elischer if (ip == 0) { 578f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 579f9e354dfSJulian Elischer ip_fw_fwd_addr = NULL; 580f9e354dfSJulian Elischer #endif 581c67b1d17SGarrett Wollman return; 582f9e354dfSJulian Elischer } 58381aee63dSPoul-Henning Kamp /* Get the length of the reassembled packets header */ 58481aee63dSPoul-Henning Kamp hlen = IP_VHL_HL(ip->ip_vhl) << 2; 585df8bae1dSRodney W. Grimes ipstat.ips_reassembled++; 586df8bae1dSRodney W. Grimes m = dtom(ip); 587af782f1cSBrian Somers #ifdef IPDIVERT 588af782f1cSBrian Somers if (frag_divert_port) { 589af782f1cSBrian Somers ip->ip_len += hlen; 590af782f1cSBrian Somers HTONS(ip->ip_len); 591af782f1cSBrian Somers HTONS(ip->ip_off); 592af782f1cSBrian Somers HTONS(ip->ip_id); 593af782f1cSBrian Somers ip->ip_sum = 0; 594af782f1cSBrian Somers ip->ip_sum = in_cksum_hdr(ip); 595af782f1cSBrian Somers NTOHS(ip->ip_id); 596af782f1cSBrian Somers NTOHS(ip->ip_off); 597af782f1cSBrian Somers NTOHS(ip->ip_len); 598af782f1cSBrian Somers ip->ip_len -= hlen; 599af782f1cSBrian Somers } 600af782f1cSBrian Somers #endif 601df8bae1dSRodney W. Grimes } else 602df8bae1dSRodney W. Grimes if (fp) 603df8bae1dSRodney W. Grimes ip_freef(fp); 604df8bae1dSRodney W. Grimes } else 605df8bae1dSRodney W. Grimes ip->ip_len -= hlen; 606df8bae1dSRodney W. Grimes 60793e0e116SJulian Elischer #ifdef IPDIVERT 60893e0e116SJulian Elischer /* 609e4676ba6SJulian Elischer * Divert reassembled packets to the divert protocol if required 61093e0e116SJulian Elischer */ 61193e0e116SJulian Elischer if (frag_divert_port) { 612e4676ba6SJulian Elischer ipstat.ips_delivered++; 61393e0e116SJulian Elischer ip_divert_port = frag_divert_port; 61493e0e116SJulian Elischer frag_divert_port = 0; 61593e0e116SJulian Elischer (*inetsw[ip_protox[IPPROTO_DIVERT]].pr_input)(m, hlen); 61693e0e116SJulian Elischer return; 61793e0e116SJulian Elischer } 61879755dc5SJulian Elischer 61979755dc5SJulian Elischer /* Don't let packets divert themselves */ 62079755dc5SJulian Elischer if (ip->ip_p == IPPROTO_DIVERT) { 62179755dc5SJulian Elischer ipstat.ips_noproto++; 62279755dc5SJulian Elischer goto bad; 62379755dc5SJulian Elischer } 624bb60f459SJulian Elischer 62593e0e116SJulian Elischer #endif 62693e0e116SJulian Elischer 627df8bae1dSRodney W. Grimes /* 628df8bae1dSRodney W. Grimes * Switch out to protocol's input routine. 629df8bae1dSRodney W. Grimes */ 630df8bae1dSRodney W. Grimes ipstat.ips_delivered++; 631df8bae1dSRodney W. Grimes (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen); 632f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 633f9e354dfSJulian Elischer ip_fw_fwd_addr = NULL; /* tcp needed it */ 634f9e354dfSJulian Elischer #endif 635c67b1d17SGarrett Wollman return; 636df8bae1dSRodney W. Grimes bad: 637f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 638f9e354dfSJulian Elischer ip_fw_fwd_addr = NULL; 639f9e354dfSJulian Elischer #endif 640df8bae1dSRodney W. Grimes m_freem(m); 641c67b1d17SGarrett Wollman } 642c67b1d17SGarrett Wollman 643c67b1d17SGarrett Wollman /* 644c67b1d17SGarrett Wollman * IP software interrupt routine - to go away sometime soon 645c67b1d17SGarrett Wollman */ 646c67b1d17SGarrett Wollman static void 647c67b1d17SGarrett Wollman ipintr(void) 648c67b1d17SGarrett Wollman { 649c67b1d17SGarrett Wollman int s; 650c67b1d17SGarrett Wollman struct mbuf *m; 651c67b1d17SGarrett Wollman 652c67b1d17SGarrett Wollman while(1) { 653c67b1d17SGarrett Wollman s = splimp(); 654c67b1d17SGarrett Wollman IF_DEQUEUE(&ipintrq, m); 655c67b1d17SGarrett Wollman splx(s); 656c67b1d17SGarrett Wollman if (m == 0) 657c67b1d17SGarrett Wollman return; 658c67b1d17SGarrett Wollman ip_input(m); 659c67b1d17SGarrett Wollman } 660df8bae1dSRodney W. Grimes } 661df8bae1dSRodney W. Grimes 662748e0b0aSGarrett Wollman NETISR_SET(NETISR_IP, ipintr); 663748e0b0aSGarrett Wollman 664df8bae1dSRodney W. Grimes /* 665df8bae1dSRodney W. Grimes * Take incoming datagram fragment and try to 666df8bae1dSRodney W. Grimes * reassemble it into whole datagram. If a chain for 667df8bae1dSRodney W. Grimes * reassembly of this datagram already exists, then it 668df8bae1dSRodney W. Grimes * is given as fp; otherwise have to make a chain. 669df8bae1dSRodney W. Grimes */ 6700312fbe9SPoul-Henning Kamp static struct ip * 671194a213eSAndrey A. Chernov ip_reass(ip, fp, where) 672df8bae1dSRodney W. Grimes register struct ipasfrag *ip; 673df8bae1dSRodney W. Grimes register struct ipq *fp; 674194a213eSAndrey A. Chernov struct ipq *where; 675df8bae1dSRodney W. Grimes { 676df8bae1dSRodney W. Grimes register struct mbuf *m = dtom(ip); 677df8bae1dSRodney W. Grimes register struct ipasfrag *q; 678df8bae1dSRodney W. Grimes struct mbuf *t; 679df8bae1dSRodney W. Grimes int hlen = ip->ip_hl << 2; 680df8bae1dSRodney W. Grimes int i, next; 681df8bae1dSRodney W. Grimes 682df8bae1dSRodney W. Grimes /* 683df8bae1dSRodney W. Grimes * Presence of header sizes in mbufs 684df8bae1dSRodney W. Grimes * would confuse code below. 685df8bae1dSRodney W. Grimes */ 686df8bae1dSRodney W. Grimes m->m_data += hlen; 687df8bae1dSRodney W. Grimes m->m_len -= hlen; 688df8bae1dSRodney W. Grimes 689df8bae1dSRodney W. Grimes /* 690df8bae1dSRodney W. Grimes * If first fragment to arrive, create a reassembly queue. 691df8bae1dSRodney W. Grimes */ 692df8bae1dSRodney W. Grimes if (fp == 0) { 693df8bae1dSRodney W. Grimes if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL) 694df8bae1dSRodney W. Grimes goto dropfrag; 695df8bae1dSRodney W. Grimes fp = mtod(t, struct ipq *); 696194a213eSAndrey A. Chernov insque(fp, where); 697194a213eSAndrey A. Chernov nipq++; 698df8bae1dSRodney W. Grimes fp->ipq_ttl = IPFRAGTTL; 699df8bae1dSRodney W. Grimes fp->ipq_p = ip->ip_p; 700df8bae1dSRodney W. Grimes fp->ipq_id = ip->ip_id; 701df8bae1dSRodney W. Grimes fp->ipq_next = fp->ipq_prev = (struct ipasfrag *)fp; 702df8bae1dSRodney W. Grimes fp->ipq_src = ((struct ip *)ip)->ip_src; 703df8bae1dSRodney W. Grimes fp->ipq_dst = ((struct ip *)ip)->ip_dst; 70493e0e116SJulian Elischer #ifdef IPDIVERT 70593e0e116SJulian Elischer fp->ipq_divert = 0; 706bb60f459SJulian Elischer fp->ipq_div_cookie = 0; 70793e0e116SJulian Elischer #endif 708df8bae1dSRodney W. Grimes q = (struct ipasfrag *)fp; 709df8bae1dSRodney W. Grimes goto insert; 710df8bae1dSRodney W. Grimes } 711df8bae1dSRodney W. Grimes 712df8bae1dSRodney W. Grimes /* 713df8bae1dSRodney W. Grimes * Find a segment which begins after this one does. 714df8bae1dSRodney W. Grimes */ 715df8bae1dSRodney W. Grimes for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) 716df8bae1dSRodney W. Grimes if (q->ip_off > ip->ip_off) 717df8bae1dSRodney W. Grimes break; 718df8bae1dSRodney W. Grimes 719df8bae1dSRodney W. Grimes /* 720df8bae1dSRodney W. Grimes * If there is a preceding segment, it may provide some of 721df8bae1dSRodney W. Grimes * our data already. If so, drop the data from the incoming 722df8bae1dSRodney W. Grimes * segment. If it provides all of our data, drop us. 723df8bae1dSRodney W. Grimes */ 724df8bae1dSRodney W. Grimes if (q->ipf_prev != (struct ipasfrag *)fp) { 725df8bae1dSRodney W. Grimes i = q->ipf_prev->ip_off + q->ipf_prev->ip_len - ip->ip_off; 726df8bae1dSRodney W. Grimes if (i > 0) { 727df8bae1dSRodney W. Grimes if (i >= ip->ip_len) 728df8bae1dSRodney W. Grimes goto dropfrag; 729df8bae1dSRodney W. Grimes m_adj(dtom(ip), i); 730df8bae1dSRodney W. Grimes ip->ip_off += i; 731df8bae1dSRodney W. Grimes ip->ip_len -= i; 732df8bae1dSRodney W. Grimes } 733df8bae1dSRodney W. Grimes } 734df8bae1dSRodney W. Grimes 735df8bae1dSRodney W. Grimes /* 736df8bae1dSRodney W. Grimes * While we overlap succeeding segments trim them or, 737df8bae1dSRodney W. Grimes * if they are completely covered, dequeue them. 738df8bae1dSRodney W. Grimes */ 739df8bae1dSRodney W. Grimes while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) { 740e7c81944SDavid Greenman struct mbuf *m0; 741e7c81944SDavid Greenman 742df8bae1dSRodney W. Grimes i = (ip->ip_off + ip->ip_len) - q->ip_off; 743df8bae1dSRodney W. Grimes if (i < q->ip_len) { 744df8bae1dSRodney W. Grimes q->ip_len -= i; 745df8bae1dSRodney W. Grimes q->ip_off += i; 746df8bae1dSRodney W. Grimes m_adj(dtom(q), i); 747df8bae1dSRodney W. Grimes break; 748df8bae1dSRodney W. Grimes } 749e7c81944SDavid Greenman m0 = dtom(q); 750df8bae1dSRodney W. Grimes q = q->ipf_next; 751df8bae1dSRodney W. Grimes ip_deq(q->ipf_prev); 752e7c81944SDavid Greenman m_freem(m0); 753df8bae1dSRodney W. Grimes } 754df8bae1dSRodney W. Grimes 755df8bae1dSRodney W. Grimes insert: 75693e0e116SJulian Elischer 75793e0e116SJulian Elischer #ifdef IPDIVERT 75893e0e116SJulian Elischer /* 75993e0e116SJulian Elischer * Any fragment diverting causes the whole packet to divert 76093e0e116SJulian Elischer */ 761bb60f459SJulian Elischer if (frag_divert_port != 0) { 76293e0e116SJulian Elischer fp->ipq_divert = frag_divert_port; 763c977d4c7SJulian Elischer fp->ipq_div_cookie = ip_divert_cookie; 764bb60f459SJulian Elischer } 76593e0e116SJulian Elischer frag_divert_port = 0; 766c977d4c7SJulian Elischer ip_divert_cookie = 0; 76793e0e116SJulian Elischer #endif 76893e0e116SJulian Elischer 769df8bae1dSRodney W. Grimes /* 770df8bae1dSRodney W. Grimes * Stick new segment in its place; 771df8bae1dSRodney W. Grimes * check for complete reassembly. 772df8bae1dSRodney W. Grimes */ 773df8bae1dSRodney W. Grimes ip_enq(ip, q->ipf_prev); 774df8bae1dSRodney W. Grimes next = 0; 775df8bae1dSRodney W. Grimes for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) { 776df8bae1dSRodney W. Grimes if (q->ip_off != next) 777df8bae1dSRodney W. Grimes return (0); 778df8bae1dSRodney W. Grimes next += q->ip_len; 779df8bae1dSRodney W. Grimes } 780df8bae1dSRodney W. Grimes if (q->ipf_prev->ipf_mff & 1) 781df8bae1dSRodney W. Grimes return (0); 782df8bae1dSRodney W. Grimes 783df8bae1dSRodney W. Grimes /* 784430d30d8SBill Fenner * Reassembly is complete. Make sure the packet is a sane size. 785430d30d8SBill Fenner */ 786430d30d8SBill Fenner if (next + (IP_VHL_HL(((struct ip *)fp->ipq_next)->ip_vhl) << 2) 787430d30d8SBill Fenner > IP_MAXPACKET) { 788430d30d8SBill Fenner ipstat.ips_toolong++; 789430d30d8SBill Fenner ip_freef(fp); 790430d30d8SBill Fenner return (0); 791430d30d8SBill Fenner } 792430d30d8SBill Fenner 793430d30d8SBill Fenner /* 794430d30d8SBill Fenner * Concatenate fragments. 795df8bae1dSRodney W. Grimes */ 796df8bae1dSRodney W. Grimes q = fp->ipq_next; 797df8bae1dSRodney W. Grimes m = dtom(q); 798df8bae1dSRodney W. Grimes t = m->m_next; 799df8bae1dSRodney W. Grimes m->m_next = 0; 800df8bae1dSRodney W. Grimes m_cat(m, t); 801df8bae1dSRodney W. Grimes q = q->ipf_next; 802df8bae1dSRodney W. Grimes while (q != (struct ipasfrag *)fp) { 803df8bae1dSRodney W. Grimes t = dtom(q); 804df8bae1dSRodney W. Grimes q = q->ipf_next; 805df8bae1dSRodney W. Grimes m_cat(m, t); 806df8bae1dSRodney W. Grimes } 807df8bae1dSRodney W. Grimes 80893e0e116SJulian Elischer #ifdef IPDIVERT 80993e0e116SJulian Elischer /* 810c977d4c7SJulian Elischer * extract divert port for packet, if any 81193e0e116SJulian Elischer */ 81293e0e116SJulian Elischer frag_divert_port = fp->ipq_divert; 813c977d4c7SJulian Elischer ip_divert_cookie = fp->ipq_div_cookie; 81493e0e116SJulian Elischer #endif 81593e0e116SJulian Elischer 816df8bae1dSRodney W. Grimes /* 817df8bae1dSRodney W. Grimes * Create header for new ip packet by 818df8bae1dSRodney W. Grimes * modifying header of first packet; 819df8bae1dSRodney W. Grimes * dequeue and discard fragment reassembly header. 820df8bae1dSRodney W. Grimes * Make header visible. 821df8bae1dSRodney W. Grimes */ 822df8bae1dSRodney W. Grimes ip = fp->ipq_next; 823df8bae1dSRodney W. Grimes ip->ip_len = next; 824df8bae1dSRodney W. Grimes ip->ipf_mff &= ~1; 825df8bae1dSRodney W. Grimes ((struct ip *)ip)->ip_src = fp->ipq_src; 826df8bae1dSRodney W. Grimes ((struct ip *)ip)->ip_dst = fp->ipq_dst; 827df8bae1dSRodney W. Grimes remque(fp); 828194a213eSAndrey A. Chernov nipq--; 829df8bae1dSRodney W. Grimes (void) m_free(dtom(fp)); 830df8bae1dSRodney W. Grimes m = dtom(ip); 831df8bae1dSRodney W. Grimes m->m_len += (ip->ip_hl << 2); 832df8bae1dSRodney W. Grimes m->m_data -= (ip->ip_hl << 2); 833df8bae1dSRodney W. Grimes /* some debugging cruft by sklower, below, will go away soon */ 834df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) { /* XXX this should be done elsewhere */ 835df8bae1dSRodney W. Grimes register int plen = 0; 836df8bae1dSRodney W. Grimes for (t = m; m; m = m->m_next) 837df8bae1dSRodney W. Grimes plen += m->m_len; 838df8bae1dSRodney W. Grimes t->m_pkthdr.len = plen; 839df8bae1dSRodney W. Grimes } 840df8bae1dSRodney W. Grimes return ((struct ip *)ip); 841df8bae1dSRodney W. Grimes 842df8bae1dSRodney W. Grimes dropfrag: 843df8bae1dSRodney W. Grimes ipstat.ips_fragdropped++; 844df8bae1dSRodney W. Grimes m_freem(m); 845df8bae1dSRodney W. Grimes return (0); 846df8bae1dSRodney W. Grimes } 847df8bae1dSRodney W. Grimes 848df8bae1dSRodney W. Grimes /* 849df8bae1dSRodney W. Grimes * Free a fragment reassembly header and all 850df8bae1dSRodney W. Grimes * associated datagrams. 851df8bae1dSRodney W. Grimes */ 8520312fbe9SPoul-Henning Kamp static void 853df8bae1dSRodney W. Grimes ip_freef(fp) 854df8bae1dSRodney W. Grimes struct ipq *fp; 855df8bae1dSRodney W. Grimes { 856df8bae1dSRodney W. Grimes register struct ipasfrag *q, *p; 857df8bae1dSRodney W. Grimes 858df8bae1dSRodney W. Grimes for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = p) { 859df8bae1dSRodney W. Grimes p = q->ipf_next; 860df8bae1dSRodney W. Grimes ip_deq(q); 861df8bae1dSRodney W. Grimes m_freem(dtom(q)); 862df8bae1dSRodney W. Grimes } 863df8bae1dSRodney W. Grimes remque(fp); 864df8bae1dSRodney W. Grimes (void) m_free(dtom(fp)); 865194a213eSAndrey A. Chernov nipq--; 866df8bae1dSRodney W. Grimes } 867df8bae1dSRodney W. Grimes 868df8bae1dSRodney W. Grimes /* 869df8bae1dSRodney W. Grimes * Put an ip fragment on a reassembly chain. 870df8bae1dSRodney W. Grimes * Like insque, but pointers in middle of structure. 871df8bae1dSRodney W. Grimes */ 8720312fbe9SPoul-Henning Kamp static void 873df8bae1dSRodney W. Grimes ip_enq(p, prev) 874df8bae1dSRodney W. Grimes register struct ipasfrag *p, *prev; 875df8bae1dSRodney W. Grimes { 876df8bae1dSRodney W. Grimes 877df8bae1dSRodney W. Grimes p->ipf_prev = prev; 878df8bae1dSRodney W. Grimes p->ipf_next = prev->ipf_next; 879df8bae1dSRodney W. Grimes prev->ipf_next->ipf_prev = p; 880df8bae1dSRodney W. Grimes prev->ipf_next = p; 881df8bae1dSRodney W. Grimes } 882df8bae1dSRodney W. Grimes 883df8bae1dSRodney W. Grimes /* 884df8bae1dSRodney W. Grimes * To ip_enq as remque is to insque. 885df8bae1dSRodney W. Grimes */ 8860312fbe9SPoul-Henning Kamp static void 887df8bae1dSRodney W. Grimes ip_deq(p) 888df8bae1dSRodney W. Grimes register struct ipasfrag *p; 889df8bae1dSRodney W. Grimes { 890df8bae1dSRodney W. Grimes 891df8bae1dSRodney W. Grimes p->ipf_prev->ipf_next = p->ipf_next; 892df8bae1dSRodney W. Grimes p->ipf_next->ipf_prev = p->ipf_prev; 893df8bae1dSRodney W. Grimes } 894df8bae1dSRodney W. Grimes 895df8bae1dSRodney W. Grimes /* 896df8bae1dSRodney W. Grimes * IP timer processing; 897df8bae1dSRodney W. Grimes * if a timer expires on a reassembly 898df8bae1dSRodney W. Grimes * queue, discard it. 899df8bae1dSRodney W. Grimes */ 900df8bae1dSRodney W. Grimes void 901df8bae1dSRodney W. Grimes ip_slowtimo() 902df8bae1dSRodney W. Grimes { 903df8bae1dSRodney W. Grimes register struct ipq *fp; 904df8bae1dSRodney W. Grimes int s = splnet(); 905194a213eSAndrey A. Chernov int i; 906df8bae1dSRodney W. Grimes 907194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 908194a213eSAndrey A. Chernov fp = ipq[i].next; 909194a213eSAndrey A. Chernov if (fp == 0) 910194a213eSAndrey A. Chernov continue; 911194a213eSAndrey A. Chernov while (fp != &ipq[i]) { 912df8bae1dSRodney W. Grimes --fp->ipq_ttl; 913df8bae1dSRodney W. Grimes fp = fp->next; 914df8bae1dSRodney W. Grimes if (fp->prev->ipq_ttl == 0) { 915df8bae1dSRodney W. Grimes ipstat.ips_fragtimeout++; 916df8bae1dSRodney W. Grimes ip_freef(fp->prev); 917df8bae1dSRodney W. Grimes } 918df8bae1dSRodney W. Grimes } 919194a213eSAndrey A. Chernov } 9201f91d8c5SDavid Greenman ipflow_slowtimo(); 921df8bae1dSRodney W. Grimes splx(s); 922df8bae1dSRodney W. Grimes } 923df8bae1dSRodney W. Grimes 924df8bae1dSRodney W. Grimes /* 925df8bae1dSRodney W. Grimes * Drain off all datagram fragments. 926df8bae1dSRodney W. Grimes */ 927df8bae1dSRodney W. Grimes void 928df8bae1dSRodney W. Grimes ip_drain() 929df8bae1dSRodney W. Grimes { 930194a213eSAndrey A. Chernov int i; 931ce29ab3aSGarrett Wollman 932194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 933194a213eSAndrey A. Chernov while (ipq[i].next != &ipq[i]) { 934194a213eSAndrey A. Chernov ipstat.ips_fragdropped++; 935194a213eSAndrey A. Chernov ip_freef(ipq[i].next); 936194a213eSAndrey A. Chernov } 937194a213eSAndrey A. Chernov } 938ce29ab3aSGarrett Wollman in_rtqdrain(); 939df8bae1dSRodney W. Grimes } 940df8bae1dSRodney W. Grimes 941df8bae1dSRodney W. Grimes /* 942df8bae1dSRodney W. Grimes * Do option processing on a datagram, 943df8bae1dSRodney W. Grimes * possibly discarding it if bad options are encountered, 944df8bae1dSRodney W. Grimes * or forwarding it if source-routed. 945df8bae1dSRodney W. Grimes * Returns 1 if packet has been forwarded/freed, 946df8bae1dSRodney W. Grimes * 0 if the packet should be processed further. 947df8bae1dSRodney W. Grimes */ 9480312fbe9SPoul-Henning Kamp static int 949df8bae1dSRodney W. Grimes ip_dooptions(m) 950df8bae1dSRodney W. Grimes struct mbuf *m; 951df8bae1dSRodney W. Grimes { 952df8bae1dSRodney W. Grimes register struct ip *ip = mtod(m, struct ip *); 953df8bae1dSRodney W. Grimes register u_char *cp; 954df8bae1dSRodney W. Grimes register struct ip_timestamp *ipt; 955df8bae1dSRodney W. Grimes register struct in_ifaddr *ia; 956df8bae1dSRodney W. Grimes int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0; 957df8bae1dSRodney W. Grimes struct in_addr *sin, dst; 958df8bae1dSRodney W. Grimes n_time ntime; 959df8bae1dSRodney W. Grimes 960df8bae1dSRodney W. Grimes dst = ip->ip_dst; 961df8bae1dSRodney W. Grimes cp = (u_char *)(ip + 1); 96258938916SGarrett Wollman cnt = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip); 963df8bae1dSRodney W. Grimes for (; cnt > 0; cnt -= optlen, cp += optlen) { 964df8bae1dSRodney W. Grimes opt = cp[IPOPT_OPTVAL]; 965df8bae1dSRodney W. Grimes if (opt == IPOPT_EOL) 966df8bae1dSRodney W. Grimes break; 967df8bae1dSRodney W. Grimes if (opt == IPOPT_NOP) 968df8bae1dSRodney W. Grimes optlen = 1; 969df8bae1dSRodney W. Grimes else { 970df8bae1dSRodney W. Grimes optlen = cp[IPOPT_OLEN]; 971df8bae1dSRodney W. Grimes if (optlen <= 0 || optlen > cnt) { 972df8bae1dSRodney W. Grimes code = &cp[IPOPT_OLEN] - (u_char *)ip; 973df8bae1dSRodney W. Grimes goto bad; 974df8bae1dSRodney W. Grimes } 975df8bae1dSRodney W. Grimes } 976df8bae1dSRodney W. Grimes switch (opt) { 977df8bae1dSRodney W. Grimes 978df8bae1dSRodney W. Grimes default: 979df8bae1dSRodney W. Grimes break; 980df8bae1dSRodney W. Grimes 981df8bae1dSRodney W. Grimes /* 982df8bae1dSRodney W. Grimes * Source routing with record. 983df8bae1dSRodney W. Grimes * Find interface with current destination address. 984df8bae1dSRodney W. Grimes * If none on this machine then drop if strictly routed, 985df8bae1dSRodney W. Grimes * or do nothing if loosely routed. 986df8bae1dSRodney W. Grimes * Record interface address and bring up next address 987df8bae1dSRodney W. Grimes * component. If strictly routed make sure next 988df8bae1dSRodney W. Grimes * address is on directly accessible net. 989df8bae1dSRodney W. Grimes */ 990df8bae1dSRodney W. Grimes case IPOPT_LSRR: 991df8bae1dSRodney W. Grimes case IPOPT_SSRR: 992df8bae1dSRodney W. Grimes if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { 993df8bae1dSRodney W. Grimes code = &cp[IPOPT_OFFSET] - (u_char *)ip; 994df8bae1dSRodney W. Grimes goto bad; 995df8bae1dSRodney W. Grimes } 996df8bae1dSRodney W. Grimes ipaddr.sin_addr = ip->ip_dst; 997df8bae1dSRodney W. Grimes ia = (struct in_ifaddr *) 998df8bae1dSRodney W. Grimes ifa_ifwithaddr((struct sockaddr *)&ipaddr); 999df8bae1dSRodney W. Grimes if (ia == 0) { 1000df8bae1dSRodney W. Grimes if (opt == IPOPT_SSRR) { 1001df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1002df8bae1dSRodney W. Grimes code = ICMP_UNREACH_SRCFAIL; 1003df8bae1dSRodney W. Grimes goto bad; 1004df8bae1dSRodney W. Grimes } 1005bc189bf8SGuido van Rooij if (!ip_dosourceroute) 1006bc189bf8SGuido van Rooij goto nosourcerouting; 1007df8bae1dSRodney W. Grimes /* 1008df8bae1dSRodney W. Grimes * Loose routing, and not at next destination 1009df8bae1dSRodney W. Grimes * yet; nothing to do except forward. 1010df8bae1dSRodney W. Grimes */ 1011df8bae1dSRodney W. Grimes break; 1012df8bae1dSRodney W. Grimes } 1013df8bae1dSRodney W. Grimes off--; /* 0 origin */ 1014df8bae1dSRodney W. Grimes if (off > optlen - sizeof(struct in_addr)) { 1015df8bae1dSRodney W. Grimes /* 1016df8bae1dSRodney W. Grimes * End of source route. Should be for us. 1017df8bae1dSRodney W. Grimes */ 10184fce5804SGuido van Rooij if (!ip_acceptsourceroute) 10194fce5804SGuido van Rooij goto nosourcerouting; 1020df8bae1dSRodney W. Grimes save_rte(cp, ip->ip_src); 1021df8bae1dSRodney W. Grimes break; 1022df8bae1dSRodney W. Grimes } 10231025071fSGarrett Wollman 10241025071fSGarrett Wollman if (!ip_dosourceroute) { 10251025071fSGarrett Wollman char buf[4*sizeof "123"]; 10261025071fSGarrett Wollman 1027efa48587SGuido van Rooij nosourcerouting: 1028bc189bf8SGuido van Rooij strcpy(buf, inet_ntoa(ip->ip_dst)); 10291025071fSGarrett Wollman log(LOG_WARNING, 10301025071fSGarrett Wollman "attempted source route from %s to %s\n", 10311025071fSGarrett Wollman inet_ntoa(ip->ip_src), buf); 10321025071fSGarrett Wollman type = ICMP_UNREACH; 10331025071fSGarrett Wollman code = ICMP_UNREACH_SRCFAIL; 10341025071fSGarrett Wollman goto bad; 10351025071fSGarrett Wollman } 10361025071fSGarrett Wollman 1037df8bae1dSRodney W. Grimes /* 1038df8bae1dSRodney W. Grimes * locate outgoing interface 1039df8bae1dSRodney W. Grimes */ 104094a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, cp + off, 1041df8bae1dSRodney W. Grimes sizeof(ipaddr.sin_addr)); 10421025071fSGarrett Wollman 1043df8bae1dSRodney W. Grimes if (opt == IPOPT_SSRR) { 1044df8bae1dSRodney W. Grimes #define INA struct in_ifaddr * 1045df8bae1dSRodney W. Grimes #define SA struct sockaddr * 1046df8bae1dSRodney W. Grimes if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0) 1047df8bae1dSRodney W. Grimes ia = (INA)ifa_ifwithnet((SA)&ipaddr); 1048df8bae1dSRodney W. Grimes } else 1049df8bae1dSRodney W. Grimes ia = ip_rtaddr(ipaddr.sin_addr); 1050df8bae1dSRodney W. Grimes if (ia == 0) { 1051df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1052df8bae1dSRodney W. Grimes code = ICMP_UNREACH_SRCFAIL; 1053df8bae1dSRodney W. Grimes goto bad; 1054df8bae1dSRodney W. Grimes } 1055df8bae1dSRodney W. Grimes ip->ip_dst = ipaddr.sin_addr; 105694a5d9b6SDavid Greenman (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr), 105794a5d9b6SDavid Greenman sizeof(struct in_addr)); 1058df8bae1dSRodney W. Grimes cp[IPOPT_OFFSET] += sizeof(struct in_addr); 1059df8bae1dSRodney W. Grimes /* 1060df8bae1dSRodney W. Grimes * Let ip_intr's mcast routing check handle mcast pkts 1061df8bae1dSRodney W. Grimes */ 1062df8bae1dSRodney W. Grimes forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr)); 1063df8bae1dSRodney W. Grimes break; 1064df8bae1dSRodney W. Grimes 1065df8bae1dSRodney W. Grimes case IPOPT_RR: 1066df8bae1dSRodney W. Grimes if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { 1067df8bae1dSRodney W. Grimes code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1068df8bae1dSRodney W. Grimes goto bad; 1069df8bae1dSRodney W. Grimes } 1070df8bae1dSRodney W. Grimes /* 1071df8bae1dSRodney W. Grimes * If no space remains, ignore. 1072df8bae1dSRodney W. Grimes */ 1073df8bae1dSRodney W. Grimes off--; /* 0 origin */ 1074df8bae1dSRodney W. Grimes if (off > optlen - sizeof(struct in_addr)) 1075df8bae1dSRodney W. Grimes break; 107694a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, &ip->ip_dst, 1077df8bae1dSRodney W. Grimes sizeof(ipaddr.sin_addr)); 1078df8bae1dSRodney W. Grimes /* 1079df8bae1dSRodney W. Grimes * locate outgoing interface; if we're the destination, 1080df8bae1dSRodney W. Grimes * use the incoming interface (should be same). 1081df8bae1dSRodney W. Grimes */ 1082df8bae1dSRodney W. Grimes if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 && 1083df8bae1dSRodney W. Grimes (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) { 1084df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1085df8bae1dSRodney W. Grimes code = ICMP_UNREACH_HOST; 1086df8bae1dSRodney W. Grimes goto bad; 1087df8bae1dSRodney W. Grimes } 108894a5d9b6SDavid Greenman (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr), 108994a5d9b6SDavid Greenman sizeof(struct in_addr)); 1090df8bae1dSRodney W. Grimes cp[IPOPT_OFFSET] += sizeof(struct in_addr); 1091df8bae1dSRodney W. Grimes break; 1092df8bae1dSRodney W. Grimes 1093df8bae1dSRodney W. Grimes case IPOPT_TS: 1094df8bae1dSRodney W. Grimes code = cp - (u_char *)ip; 1095df8bae1dSRodney W. Grimes ipt = (struct ip_timestamp *)cp; 1096df8bae1dSRodney W. Grimes if (ipt->ipt_len < 5) 1097df8bae1dSRodney W. Grimes goto bad; 1098df8bae1dSRodney W. Grimes if (ipt->ipt_ptr > ipt->ipt_len - sizeof (long)) { 1099df8bae1dSRodney W. Grimes if (++ipt->ipt_oflw == 0) 1100df8bae1dSRodney W. Grimes goto bad; 1101df8bae1dSRodney W. Grimes break; 1102df8bae1dSRodney W. Grimes } 1103df8bae1dSRodney W. Grimes sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1); 1104df8bae1dSRodney W. Grimes switch (ipt->ipt_flg) { 1105df8bae1dSRodney W. Grimes 1106df8bae1dSRodney W. Grimes case IPOPT_TS_TSONLY: 1107df8bae1dSRodney W. Grimes break; 1108df8bae1dSRodney W. Grimes 1109df8bae1dSRodney W. Grimes case IPOPT_TS_TSANDADDR: 1110b8e8c209SDavid Greenman if (ipt->ipt_ptr - 1 + sizeof(n_time) + 1111df8bae1dSRodney W. Grimes sizeof(struct in_addr) > ipt->ipt_len) 1112df8bae1dSRodney W. Grimes goto bad; 1113df8bae1dSRodney W. Grimes ipaddr.sin_addr = dst; 1114df8bae1dSRodney W. Grimes ia = (INA)ifaof_ifpforaddr((SA)&ipaddr, 1115df8bae1dSRodney W. Grimes m->m_pkthdr.rcvif); 1116df8bae1dSRodney W. Grimes if (ia == 0) 1117df8bae1dSRodney W. Grimes continue; 111894a5d9b6SDavid Greenman (void)memcpy(sin, &IA_SIN(ia)->sin_addr, 111994a5d9b6SDavid Greenman sizeof(struct in_addr)); 1120df8bae1dSRodney W. Grimes ipt->ipt_ptr += sizeof(struct in_addr); 1121df8bae1dSRodney W. Grimes break; 1122df8bae1dSRodney W. Grimes 1123df8bae1dSRodney W. Grimes case IPOPT_TS_PRESPEC: 1124b8e8c209SDavid Greenman if (ipt->ipt_ptr - 1 + sizeof(n_time) + 1125df8bae1dSRodney W. Grimes sizeof(struct in_addr) > ipt->ipt_len) 1126df8bae1dSRodney W. Grimes goto bad; 112794a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, sin, 1128df8bae1dSRodney W. Grimes sizeof(struct in_addr)); 1129df8bae1dSRodney W. Grimes if (ifa_ifwithaddr((SA)&ipaddr) == 0) 1130df8bae1dSRodney W. Grimes continue; 1131df8bae1dSRodney W. Grimes ipt->ipt_ptr += sizeof(struct in_addr); 1132df8bae1dSRodney W. Grimes break; 1133df8bae1dSRodney W. Grimes 1134df8bae1dSRodney W. Grimes default: 1135df8bae1dSRodney W. Grimes goto bad; 1136df8bae1dSRodney W. Grimes } 1137df8bae1dSRodney W. Grimes ntime = iptime(); 113894a5d9b6SDavid Greenman (void)memcpy(cp + ipt->ipt_ptr - 1, &ntime, 1139df8bae1dSRodney W. Grimes sizeof(n_time)); 1140df8bae1dSRodney W. Grimes ipt->ipt_ptr += sizeof(n_time); 1141df8bae1dSRodney W. Grimes } 1142df8bae1dSRodney W. Grimes } 114347174b49SAndrey A. Chernov if (forward && ipforwarding) { 1144df8bae1dSRodney W. Grimes ip_forward(m, 1); 1145df8bae1dSRodney W. Grimes return (1); 1146df8bae1dSRodney W. Grimes } 1147df8bae1dSRodney W. Grimes return (0); 1148df8bae1dSRodney W. Grimes bad: 114958938916SGarrett Wollman ip->ip_len -= IP_VHL_HL(ip->ip_vhl) << 2; /* XXX icmp_error adds in hdr length */ 1150df8bae1dSRodney W. Grimes icmp_error(m, type, code, 0, 0); 1151df8bae1dSRodney W. Grimes ipstat.ips_badoptions++; 1152df8bae1dSRodney W. Grimes return (1); 1153df8bae1dSRodney W. Grimes } 1154df8bae1dSRodney W. Grimes 1155df8bae1dSRodney W. Grimes /* 1156df8bae1dSRodney W. Grimes * Given address of next destination (final or next hop), 1157df8bae1dSRodney W. Grimes * return internet address info of interface to be used to get there. 1158df8bae1dSRodney W. Grimes */ 11590312fbe9SPoul-Henning Kamp static struct in_ifaddr * 1160df8bae1dSRodney W. Grimes ip_rtaddr(dst) 1161df8bae1dSRodney W. Grimes struct in_addr dst; 1162df8bae1dSRodney W. Grimes { 1163df8bae1dSRodney W. Grimes register struct sockaddr_in *sin; 1164df8bae1dSRodney W. Grimes 1165df8bae1dSRodney W. Grimes sin = (struct sockaddr_in *) &ipforward_rt.ro_dst; 1166df8bae1dSRodney W. Grimes 1167df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt == 0 || dst.s_addr != sin->sin_addr.s_addr) { 1168df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt) { 1169df8bae1dSRodney W. Grimes RTFREE(ipforward_rt.ro_rt); 1170df8bae1dSRodney W. Grimes ipforward_rt.ro_rt = 0; 1171df8bae1dSRodney W. Grimes } 1172df8bae1dSRodney W. Grimes sin->sin_family = AF_INET; 1173df8bae1dSRodney W. Grimes sin->sin_len = sizeof(*sin); 1174df8bae1dSRodney W. Grimes sin->sin_addr = dst; 1175df8bae1dSRodney W. Grimes 11762c17fe93SGarrett Wollman rtalloc_ign(&ipforward_rt, RTF_PRCLONING); 1177df8bae1dSRodney W. Grimes } 1178df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt == 0) 1179df8bae1dSRodney W. Grimes return ((struct in_ifaddr *)0); 1180df8bae1dSRodney W. Grimes return ((struct in_ifaddr *) ipforward_rt.ro_rt->rt_ifa); 1181df8bae1dSRodney W. Grimes } 1182df8bae1dSRodney W. Grimes 1183df8bae1dSRodney W. Grimes /* 1184df8bae1dSRodney W. Grimes * Save incoming source route for use in replies, 1185df8bae1dSRodney W. Grimes * to be picked up later by ip_srcroute if the receiver is interested. 1186df8bae1dSRodney W. Grimes */ 1187df8bae1dSRodney W. Grimes void 1188df8bae1dSRodney W. Grimes save_rte(option, dst) 1189df8bae1dSRodney W. Grimes u_char *option; 1190df8bae1dSRodney W. Grimes struct in_addr dst; 1191df8bae1dSRodney W. Grimes { 1192df8bae1dSRodney W. Grimes unsigned olen; 1193df8bae1dSRodney W. Grimes 1194df8bae1dSRodney W. Grimes olen = option[IPOPT_OLEN]; 1195df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1196df8bae1dSRodney W. Grimes if (ipprintfs) 1197df8bae1dSRodney W. Grimes printf("save_rte: olen %d\n", olen); 1198df8bae1dSRodney W. Grimes #endif 1199df8bae1dSRodney W. Grimes if (olen > sizeof(ip_srcrt) - (1 + sizeof(dst))) 1200df8bae1dSRodney W. Grimes return; 12010453d3cbSBruce Evans bcopy(option, ip_srcrt.srcopt, olen); 1202df8bae1dSRodney W. Grimes ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr); 1203df8bae1dSRodney W. Grimes ip_srcrt.dst = dst; 1204df8bae1dSRodney W. Grimes } 1205df8bae1dSRodney W. Grimes 1206df8bae1dSRodney W. Grimes /* 1207df8bae1dSRodney W. Grimes * Retrieve incoming source route for use in replies, 1208df8bae1dSRodney W. Grimes * in the same form used by setsockopt. 1209df8bae1dSRodney W. Grimes * The first hop is placed before the options, will be removed later. 1210df8bae1dSRodney W. Grimes */ 1211df8bae1dSRodney W. Grimes struct mbuf * 1212df8bae1dSRodney W. Grimes ip_srcroute() 1213df8bae1dSRodney W. Grimes { 1214df8bae1dSRodney W. Grimes register struct in_addr *p, *q; 1215df8bae1dSRodney W. Grimes register struct mbuf *m; 1216df8bae1dSRodney W. Grimes 1217df8bae1dSRodney W. Grimes if (ip_nhops == 0) 1218df8bae1dSRodney W. Grimes return ((struct mbuf *)0); 1219df8bae1dSRodney W. Grimes m = m_get(M_DONTWAIT, MT_SOOPTS); 1220df8bae1dSRodney W. Grimes if (m == 0) 1221df8bae1dSRodney W. Grimes return ((struct mbuf *)0); 1222df8bae1dSRodney W. Grimes 1223df8bae1dSRodney W. Grimes #define OPTSIZ (sizeof(ip_srcrt.nop) + sizeof(ip_srcrt.srcopt)) 1224df8bae1dSRodney W. Grimes 1225df8bae1dSRodney W. Grimes /* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */ 1226df8bae1dSRodney W. Grimes m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) + 1227df8bae1dSRodney W. Grimes OPTSIZ; 1228df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1229df8bae1dSRodney W. Grimes if (ipprintfs) 1230df8bae1dSRodney W. Grimes printf("ip_srcroute: nhops %d mlen %d", ip_nhops, m->m_len); 1231df8bae1dSRodney W. Grimes #endif 1232df8bae1dSRodney W. Grimes 1233df8bae1dSRodney W. Grimes /* 1234df8bae1dSRodney W. Grimes * First save first hop for return route 1235df8bae1dSRodney W. Grimes */ 1236df8bae1dSRodney W. Grimes p = &ip_srcrt.route[ip_nhops - 1]; 1237df8bae1dSRodney W. Grimes *(mtod(m, struct in_addr *)) = *p--; 1238df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1239df8bae1dSRodney W. Grimes if (ipprintfs) 1240df8bae1dSRodney W. Grimes printf(" hops %lx", ntohl(mtod(m, struct in_addr *)->s_addr)); 1241df8bae1dSRodney W. Grimes #endif 1242df8bae1dSRodney W. Grimes 1243df8bae1dSRodney W. Grimes /* 1244df8bae1dSRodney W. Grimes * Copy option fields and padding (nop) to mbuf. 1245df8bae1dSRodney W. Grimes */ 1246df8bae1dSRodney W. Grimes ip_srcrt.nop = IPOPT_NOP; 1247df8bae1dSRodney W. Grimes ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF; 124894a5d9b6SDavid Greenman (void)memcpy(mtod(m, caddr_t) + sizeof(struct in_addr), 124994a5d9b6SDavid Greenman &ip_srcrt.nop, OPTSIZ); 1250df8bae1dSRodney W. Grimes q = (struct in_addr *)(mtod(m, caddr_t) + 1251df8bae1dSRodney W. Grimes sizeof(struct in_addr) + OPTSIZ); 1252df8bae1dSRodney W. Grimes #undef OPTSIZ 1253df8bae1dSRodney W. Grimes /* 1254df8bae1dSRodney W. Grimes * Record return path as an IP source route, 1255df8bae1dSRodney W. Grimes * reversing the path (pointers are now aligned). 1256df8bae1dSRodney W. Grimes */ 1257df8bae1dSRodney W. Grimes while (p >= ip_srcrt.route) { 1258df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1259df8bae1dSRodney W. Grimes if (ipprintfs) 1260df8bae1dSRodney W. Grimes printf(" %lx", ntohl(q->s_addr)); 1261df8bae1dSRodney W. Grimes #endif 1262df8bae1dSRodney W. Grimes *q++ = *p--; 1263df8bae1dSRodney W. Grimes } 1264df8bae1dSRodney W. Grimes /* 1265df8bae1dSRodney W. Grimes * Last hop goes to final destination. 1266df8bae1dSRodney W. Grimes */ 1267df8bae1dSRodney W. Grimes *q = ip_srcrt.dst; 1268df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1269df8bae1dSRodney W. Grimes if (ipprintfs) 1270df8bae1dSRodney W. Grimes printf(" %lx\n", ntohl(q->s_addr)); 1271df8bae1dSRodney W. Grimes #endif 1272df8bae1dSRodney W. Grimes return (m); 1273df8bae1dSRodney W. Grimes } 1274df8bae1dSRodney W. Grimes 1275df8bae1dSRodney W. Grimes /* 1276df8bae1dSRodney W. Grimes * Strip out IP options, at higher 1277df8bae1dSRodney W. Grimes * level protocol in the kernel. 1278df8bae1dSRodney W. Grimes * Second argument is buffer to which options 1279df8bae1dSRodney W. Grimes * will be moved, and return value is their length. 1280df8bae1dSRodney W. Grimes * XXX should be deleted; last arg currently ignored. 1281df8bae1dSRodney W. Grimes */ 1282df8bae1dSRodney W. Grimes void 1283df8bae1dSRodney W. Grimes ip_stripoptions(m, mopt) 1284df8bae1dSRodney W. Grimes register struct mbuf *m; 1285df8bae1dSRodney W. Grimes struct mbuf *mopt; 1286df8bae1dSRodney W. Grimes { 1287df8bae1dSRodney W. Grimes register int i; 1288df8bae1dSRodney W. Grimes struct ip *ip = mtod(m, struct ip *); 1289df8bae1dSRodney W. Grimes register caddr_t opts; 1290df8bae1dSRodney W. Grimes int olen; 1291df8bae1dSRodney W. Grimes 129258938916SGarrett Wollman olen = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip); 1293df8bae1dSRodney W. Grimes opts = (caddr_t)(ip + 1); 1294df8bae1dSRodney W. Grimes i = m->m_len - (sizeof (struct ip) + olen); 1295df8bae1dSRodney W. Grimes bcopy(opts + olen, opts, (unsigned)i); 1296df8bae1dSRodney W. Grimes m->m_len -= olen; 1297df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) 1298df8bae1dSRodney W. Grimes m->m_pkthdr.len -= olen; 129958938916SGarrett Wollman ip->ip_vhl = IP_MAKE_VHL(IPVERSION, sizeof(struct ip) >> 2); 1300df8bae1dSRodney W. Grimes } 1301df8bae1dSRodney W. Grimes 1302df8bae1dSRodney W. Grimes u_char inetctlerrmap[PRC_NCMDS] = { 1303df8bae1dSRodney W. Grimes 0, 0, 0, 0, 1304df8bae1dSRodney W. Grimes 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH, 1305df8bae1dSRodney W. Grimes EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, 1306df8bae1dSRodney W. Grimes EMSGSIZE, EHOSTUNREACH, 0, 0, 1307df8bae1dSRodney W. Grimes 0, 0, 0, 0, 1308df8bae1dSRodney W. Grimes ENOPROTOOPT 1309df8bae1dSRodney W. Grimes }; 1310df8bae1dSRodney W. Grimes 1311df8bae1dSRodney W. Grimes /* 1312df8bae1dSRodney W. Grimes * Forward a packet. If some error occurs return the sender 1313df8bae1dSRodney W. Grimes * an icmp packet. Note we can't always generate a meaningful 1314df8bae1dSRodney W. Grimes * icmp message because icmp doesn't have a large enough repertoire 1315df8bae1dSRodney W. Grimes * of codes and types. 1316df8bae1dSRodney W. Grimes * 1317df8bae1dSRodney W. Grimes * If not forwarding, just drop the packet. This could be confusing 1318df8bae1dSRodney W. Grimes * if ipforwarding was zero but some routing protocol was advancing 1319df8bae1dSRodney W. Grimes * us as a gateway to somewhere. However, we must let the routing 1320df8bae1dSRodney W. Grimes * protocol deal with that. 1321df8bae1dSRodney W. Grimes * 1322df8bae1dSRodney W. Grimes * The srcrt parameter indicates whether the packet is being forwarded 1323df8bae1dSRodney W. Grimes * via a source route. 1324df8bae1dSRodney W. Grimes */ 13250312fbe9SPoul-Henning Kamp static void 1326df8bae1dSRodney W. Grimes ip_forward(m, srcrt) 1327df8bae1dSRodney W. Grimes struct mbuf *m; 1328df8bae1dSRodney W. Grimes int srcrt; 1329df8bae1dSRodney W. Grimes { 1330df8bae1dSRodney W. Grimes register struct ip *ip = mtod(m, struct ip *); 1331df8bae1dSRodney W. Grimes register struct sockaddr_in *sin; 1332df8bae1dSRodney W. Grimes register struct rtentry *rt; 133326f9a767SRodney W. Grimes int error, type = 0, code = 0; 1334df8bae1dSRodney W. Grimes struct mbuf *mcopy; 1335df8bae1dSRodney W. Grimes n_long dest; 1336df8bae1dSRodney W. Grimes struct ifnet *destifp; 1337df8bae1dSRodney W. Grimes 1338df8bae1dSRodney W. Grimes dest = 0; 1339df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1340df8bae1dSRodney W. Grimes if (ipprintfs) 134161ce519bSPoul-Henning Kamp printf("forward: src %lx dst %lx ttl %x\n", 1342623ae52eSPoul-Henning Kamp ip->ip_src.s_addr, ip->ip_dst.s_addr, ip->ip_ttl); 1343df8bae1dSRodney W. Grimes #endif 1344100ba1a6SJordan K. Hubbard 1345100ba1a6SJordan K. Hubbard 1346df8bae1dSRodney W. Grimes if (m->m_flags & M_BCAST || in_canforward(ip->ip_dst) == 0) { 1347df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 1348df8bae1dSRodney W. Grimes m_freem(m); 1349df8bae1dSRodney W. Grimes return; 1350df8bae1dSRodney W. Grimes } 1351df8bae1dSRodney W. Grimes HTONS(ip->ip_id); 1352df8bae1dSRodney W. Grimes if (ip->ip_ttl <= IPTTLDEC) { 1353df8bae1dSRodney W. Grimes icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, dest, 0); 1354df8bae1dSRodney W. Grimes return; 1355df8bae1dSRodney W. Grimes } 1356df8bae1dSRodney W. Grimes ip->ip_ttl -= IPTTLDEC; 1357df8bae1dSRodney W. Grimes 1358df8bae1dSRodney W. Grimes sin = (struct sockaddr_in *)&ipforward_rt.ro_dst; 1359df8bae1dSRodney W. Grimes if ((rt = ipforward_rt.ro_rt) == 0 || 1360df8bae1dSRodney W. Grimes ip->ip_dst.s_addr != sin->sin_addr.s_addr) { 1361df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt) { 1362df8bae1dSRodney W. Grimes RTFREE(ipforward_rt.ro_rt); 1363df8bae1dSRodney W. Grimes ipforward_rt.ro_rt = 0; 1364df8bae1dSRodney W. Grimes } 1365df8bae1dSRodney W. Grimes sin->sin_family = AF_INET; 1366df8bae1dSRodney W. Grimes sin->sin_len = sizeof(*sin); 1367df8bae1dSRodney W. Grimes sin->sin_addr = ip->ip_dst; 1368df8bae1dSRodney W. Grimes 13692c17fe93SGarrett Wollman rtalloc_ign(&ipforward_rt, RTF_PRCLONING); 1370df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt == 0) { 1371df8bae1dSRodney W. Grimes icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0); 1372df8bae1dSRodney W. Grimes return; 1373df8bae1dSRodney W. Grimes } 1374df8bae1dSRodney W. Grimes rt = ipforward_rt.ro_rt; 1375df8bae1dSRodney W. Grimes } 1376df8bae1dSRodney W. Grimes 1377df8bae1dSRodney W. Grimes /* 1378df8bae1dSRodney W. Grimes * Save at most 64 bytes of the packet in case 1379df8bae1dSRodney W. Grimes * we need to generate an ICMP message to the src. 1380df8bae1dSRodney W. Grimes */ 1381df8bae1dSRodney W. Grimes mcopy = m_copy(m, 0, imin((int)ip->ip_len, 64)); 1382df8bae1dSRodney W. Grimes 1383df8bae1dSRodney W. Grimes /* 1384df8bae1dSRodney W. Grimes * If forwarding packet using same interface that it came in on, 1385df8bae1dSRodney W. Grimes * perhaps should send a redirect to sender to shortcut a hop. 1386df8bae1dSRodney W. Grimes * Only send redirect if source is sending directly to us, 1387df8bae1dSRodney W. Grimes * and if packet was not source routed (or has any options). 1388df8bae1dSRodney W. Grimes * Also, don't send redirect if forwarding using a default route 1389df8bae1dSRodney W. Grimes * or a route modified by a redirect. 1390df8bae1dSRodney W. Grimes */ 1391df8bae1dSRodney W. Grimes #define satosin(sa) ((struct sockaddr_in *)(sa)) 1392df8bae1dSRodney W. Grimes if (rt->rt_ifp == m->m_pkthdr.rcvif && 1393df8bae1dSRodney W. Grimes (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 && 1394df8bae1dSRodney W. Grimes satosin(rt_key(rt))->sin_addr.s_addr != 0 && 1395df8bae1dSRodney W. Grimes ipsendredirects && !srcrt) { 1396df8bae1dSRodney W. Grimes #define RTA(rt) ((struct in_ifaddr *)(rt->rt_ifa)) 1397df8bae1dSRodney W. Grimes u_long src = ntohl(ip->ip_src.s_addr); 1398df8bae1dSRodney W. Grimes 1399df8bae1dSRodney W. Grimes if (RTA(rt) && 1400df8bae1dSRodney W. Grimes (src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) { 1401df8bae1dSRodney W. Grimes if (rt->rt_flags & RTF_GATEWAY) 1402df8bae1dSRodney W. Grimes dest = satosin(rt->rt_gateway)->sin_addr.s_addr; 1403df8bae1dSRodney W. Grimes else 1404df8bae1dSRodney W. Grimes dest = ip->ip_dst.s_addr; 1405df8bae1dSRodney W. Grimes /* Router requirements says to only send host redirects */ 1406df8bae1dSRodney W. Grimes type = ICMP_REDIRECT; 1407df8bae1dSRodney W. Grimes code = ICMP_REDIRECT_HOST; 1408df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1409df8bae1dSRodney W. Grimes if (ipprintfs) 1410df8bae1dSRodney W. Grimes printf("redirect (%d) to %lx\n", code, (u_long)dest); 1411df8bae1dSRodney W. Grimes #endif 1412df8bae1dSRodney W. Grimes } 1413df8bae1dSRodney W. Grimes } 1414df8bae1dSRodney W. Grimes 1415b97d15cbSGarrett Wollman error = ip_output(m, (struct mbuf *)0, &ipforward_rt, 1416b97d15cbSGarrett Wollman IP_FORWARDING, 0); 1417df8bae1dSRodney W. Grimes if (error) 1418df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 1419df8bae1dSRodney W. Grimes else { 1420df8bae1dSRodney W. Grimes ipstat.ips_forward++; 1421df8bae1dSRodney W. Grimes if (type) 1422df8bae1dSRodney W. Grimes ipstat.ips_redirectsent++; 1423df8bae1dSRodney W. Grimes else { 14241f91d8c5SDavid Greenman if (mcopy) { 14251f91d8c5SDavid Greenman ipflow_create(&ipforward_rt, mcopy); 1426df8bae1dSRodney W. Grimes m_freem(mcopy); 14271f91d8c5SDavid Greenman } 1428df8bae1dSRodney W. Grimes return; 1429df8bae1dSRodney W. Grimes } 1430df8bae1dSRodney W. Grimes } 1431df8bae1dSRodney W. Grimes if (mcopy == NULL) 1432df8bae1dSRodney W. Grimes return; 1433df8bae1dSRodney W. Grimes destifp = NULL; 1434df8bae1dSRodney W. Grimes 1435df8bae1dSRodney W. Grimes switch (error) { 1436df8bae1dSRodney W. Grimes 1437df8bae1dSRodney W. Grimes case 0: /* forwarded, but need redirect */ 1438df8bae1dSRodney W. Grimes /* type, code set above */ 1439df8bae1dSRodney W. Grimes break; 1440df8bae1dSRodney W. Grimes 1441df8bae1dSRodney W. Grimes case ENETUNREACH: /* shouldn't happen, checked above */ 1442df8bae1dSRodney W. Grimes case EHOSTUNREACH: 1443df8bae1dSRodney W. Grimes case ENETDOWN: 1444df8bae1dSRodney W. Grimes case EHOSTDOWN: 1445df8bae1dSRodney W. Grimes default: 1446df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1447df8bae1dSRodney W. Grimes code = ICMP_UNREACH_HOST; 1448df8bae1dSRodney W. Grimes break; 1449df8bae1dSRodney W. Grimes 1450df8bae1dSRodney W. Grimes case EMSGSIZE: 1451df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1452df8bae1dSRodney W. Grimes code = ICMP_UNREACH_NEEDFRAG; 1453df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt) 1454df8bae1dSRodney W. Grimes destifp = ipforward_rt.ro_rt->rt_ifp; 1455df8bae1dSRodney W. Grimes ipstat.ips_cantfrag++; 1456df8bae1dSRodney W. Grimes break; 1457df8bae1dSRodney W. Grimes 1458df8bae1dSRodney W. Grimes case ENOBUFS: 1459df8bae1dSRodney W. Grimes type = ICMP_SOURCEQUENCH; 1460df8bae1dSRodney W. Grimes code = 0; 1461df8bae1dSRodney W. Grimes break; 1462df8bae1dSRodney W. Grimes } 1463df8bae1dSRodney W. Grimes icmp_error(mcopy, type, code, dest, destifp); 1464df8bae1dSRodney W. Grimes } 1465df8bae1dSRodney W. Grimes 146682c23ebaSBill Fenner void 146782c23ebaSBill Fenner ip_savecontrol(inp, mp, ip, m) 146882c23ebaSBill Fenner register struct inpcb *inp; 146982c23ebaSBill Fenner register struct mbuf **mp; 147082c23ebaSBill Fenner register struct ip *ip; 147182c23ebaSBill Fenner register struct mbuf *m; 147282c23ebaSBill Fenner { 147382c23ebaSBill Fenner if (inp->inp_socket->so_options & SO_TIMESTAMP) { 147482c23ebaSBill Fenner struct timeval tv; 147582c23ebaSBill Fenner 147682c23ebaSBill Fenner microtime(&tv); 147782c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv), 147882c23ebaSBill Fenner SCM_TIMESTAMP, SOL_SOCKET); 147982c23ebaSBill Fenner if (*mp) 148082c23ebaSBill Fenner mp = &(*mp)->m_next; 148182c23ebaSBill Fenner } 148282c23ebaSBill Fenner if (inp->inp_flags & INP_RECVDSTADDR) { 148382c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) &ip->ip_dst, 148482c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVDSTADDR, IPPROTO_IP); 148582c23ebaSBill Fenner if (*mp) 148682c23ebaSBill Fenner mp = &(*mp)->m_next; 148782c23ebaSBill Fenner } 148882c23ebaSBill Fenner #ifdef notyet 148982c23ebaSBill Fenner /* XXX 149082c23ebaSBill Fenner * Moving these out of udp_input() made them even more broken 149182c23ebaSBill Fenner * than they already were. 149282c23ebaSBill Fenner */ 149382c23ebaSBill Fenner /* options were tossed already */ 149482c23ebaSBill Fenner if (inp->inp_flags & INP_RECVOPTS) { 149582c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) opts_deleted_above, 149682c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVOPTS, IPPROTO_IP); 149782c23ebaSBill Fenner if (*mp) 149882c23ebaSBill Fenner mp = &(*mp)->m_next; 149982c23ebaSBill Fenner } 150082c23ebaSBill Fenner /* ip_srcroute doesn't do what we want here, need to fix */ 150182c23ebaSBill Fenner if (inp->inp_flags & INP_RECVRETOPTS) { 150282c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) ip_srcroute(), 150382c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVRETOPTS, IPPROTO_IP); 150482c23ebaSBill Fenner if (*mp) 150582c23ebaSBill Fenner mp = &(*mp)->m_next; 150682c23ebaSBill Fenner } 150782c23ebaSBill Fenner #endif 150882c23ebaSBill Fenner if (inp->inp_flags & INP_RECVIF) { 1509d314ad7bSJulian Elischer struct ifnet *ifp; 1510d314ad7bSJulian Elischer struct sdlbuf { 151182c23ebaSBill Fenner struct sockaddr_dl sdl; 1512d314ad7bSJulian Elischer u_char pad[32]; 1513d314ad7bSJulian Elischer } sdlbuf; 1514d314ad7bSJulian Elischer struct sockaddr_dl *sdp; 1515d314ad7bSJulian Elischer struct sockaddr_dl *sdl2 = &sdlbuf.sdl; 151682c23ebaSBill Fenner 1517d314ad7bSJulian Elischer if (((ifp = m->m_pkthdr.rcvif)) 1518d314ad7bSJulian Elischer && ( ifp->if_index && (ifp->if_index <= if_index))) { 1519d314ad7bSJulian Elischer sdp = (struct sockaddr_dl *)(ifnet_addrs 1520d314ad7bSJulian Elischer [ifp->if_index - 1]->ifa_addr); 1521d314ad7bSJulian Elischer /* 1522d314ad7bSJulian Elischer * Change our mind and don't try copy. 1523d314ad7bSJulian Elischer */ 1524d314ad7bSJulian Elischer if ((sdp->sdl_family != AF_LINK) 1525d314ad7bSJulian Elischer || (sdp->sdl_len > sizeof(sdlbuf))) { 1526d314ad7bSJulian Elischer goto makedummy; 1527d314ad7bSJulian Elischer } 1528d314ad7bSJulian Elischer bcopy(sdp, sdl2, sdp->sdl_len); 1529d314ad7bSJulian Elischer } else { 1530d314ad7bSJulian Elischer makedummy: 1531d314ad7bSJulian Elischer sdl2->sdl_len 1532d314ad7bSJulian Elischer = offsetof(struct sockaddr_dl, sdl_data[0]); 1533d314ad7bSJulian Elischer sdl2->sdl_family = AF_LINK; 1534d314ad7bSJulian Elischer sdl2->sdl_index = 0; 1535d314ad7bSJulian Elischer sdl2->sdl_nlen = sdl2->sdl_alen = sdl2->sdl_slen = 0; 1536d314ad7bSJulian Elischer } 1537d314ad7bSJulian Elischer *mp = sbcreatecontrol((caddr_t) sdl2, sdl2->sdl_len, 153882c23ebaSBill Fenner IP_RECVIF, IPPROTO_IP); 153982c23ebaSBill Fenner if (*mp) 154082c23ebaSBill Fenner mp = &(*mp)->m_next; 154182c23ebaSBill Fenner } 154282c23ebaSBill Fenner } 154382c23ebaSBill Fenner 1544df8bae1dSRodney W. Grimes int 1545f0068c4aSGarrett Wollman ip_rsvp_init(struct socket *so) 1546f0068c4aSGarrett Wollman { 1547f0068c4aSGarrett Wollman if (so->so_type != SOCK_RAW || 1548f0068c4aSGarrett Wollman so->so_proto->pr_protocol != IPPROTO_RSVP) 1549f0068c4aSGarrett Wollman return EOPNOTSUPP; 1550f0068c4aSGarrett Wollman 1551f0068c4aSGarrett Wollman if (ip_rsvpd != NULL) 1552f0068c4aSGarrett Wollman return EADDRINUSE; 1553f0068c4aSGarrett Wollman 1554f0068c4aSGarrett Wollman ip_rsvpd = so; 15551c5de19aSGarrett Wollman /* 15561c5de19aSGarrett Wollman * This may seem silly, but we need to be sure we don't over-increment 15571c5de19aSGarrett Wollman * the RSVP counter, in case something slips up. 15581c5de19aSGarrett Wollman */ 15591c5de19aSGarrett Wollman if (!ip_rsvp_on) { 15601c5de19aSGarrett Wollman ip_rsvp_on = 1; 15611c5de19aSGarrett Wollman rsvp_on++; 15621c5de19aSGarrett Wollman } 1563f0068c4aSGarrett Wollman 1564f0068c4aSGarrett Wollman return 0; 1565f0068c4aSGarrett Wollman } 1566f0068c4aSGarrett Wollman 1567f0068c4aSGarrett Wollman int 1568f0068c4aSGarrett Wollman ip_rsvp_done(void) 1569f0068c4aSGarrett Wollman { 1570f0068c4aSGarrett Wollman ip_rsvpd = NULL; 15711c5de19aSGarrett Wollman /* 15721c5de19aSGarrett Wollman * This may seem silly, but we need to be sure we don't over-decrement 15731c5de19aSGarrett Wollman * the RSVP counter, in case something slips up. 15741c5de19aSGarrett Wollman */ 15751c5de19aSGarrett Wollman if (ip_rsvp_on) { 15761c5de19aSGarrett Wollman ip_rsvp_on = 0; 15771c5de19aSGarrett Wollman rsvp_on--; 15781c5de19aSGarrett Wollman } 1579f0068c4aSGarrett Wollman return 0; 1580f0068c4aSGarrett Wollman } 1581