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 34194a213eSAndrey A. Chernov * $Id: ip_input.c,v 1.64 1997/07/25 03:58:21 brian 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 4074a9466cSGary Palmer #include "opt_ipfw.h" 4174a9466cSGary Palmer 4282c23ebaSBill Fenner #include <stddef.h> 4382c23ebaSBill Fenner 44df8bae1dSRodney W. Grimes #include <sys/param.h> 45df8bae1dSRodney W. Grimes #include <sys/systm.h> 46df8bae1dSRodney W. Grimes #include <sys/malloc.h> 47df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 48df8bae1dSRodney W. Grimes #include <sys/domain.h> 49df8bae1dSRodney W. Grimes #include <sys/protosw.h> 50df8bae1dSRodney W. Grimes #include <sys/socket.h> 51df8bae1dSRodney W. Grimes #include <sys/errno.h> 52df8bae1dSRodney W. Grimes #include <sys/time.h> 53df8bae1dSRodney W. Grimes #include <sys/kernel.h> 541025071fSGarrett Wollman #include <sys/syslog.h> 55b5e8ce9fSBruce Evans #include <sys/sysctl.h> 56df8bae1dSRodney W. Grimes 57df8bae1dSRodney W. Grimes #include <net/if.h> 5882c23ebaSBill Fenner #include <net/if_dl.h> 59df8bae1dSRodney W. Grimes #include <net/route.h> 60748e0b0aSGarrett Wollman #include <net/netisr.h> 61df8bae1dSRodney W. Grimes 62df8bae1dSRodney W. Grimes #include <netinet/in.h> 63df8bae1dSRodney W. Grimes #include <netinet/in_systm.h> 64b5e8ce9fSBruce Evans #include <netinet/in_var.h> 65df8bae1dSRodney W. Grimes #include <netinet/ip.h> 66df8bae1dSRodney W. Grimes #include <netinet/in_pcb.h> 67df8bae1dSRodney W. Grimes #include <netinet/in_var.h> 68df8bae1dSRodney W. Grimes #include <netinet/ip_var.h> 69df8bae1dSRodney W. Grimes #include <netinet/ip_icmp.h> 7058938916SGarrett Wollman #include <machine/in_cksum.h> 71df8bae1dSRodney W. Grimes 72f0068c4aSGarrett Wollman #include <sys/socketvar.h> 736ddbf1e2SGary Palmer 746ddbf1e2SGary Palmer #ifdef IPFIREWALL 756ddbf1e2SGary Palmer #include <netinet/ip_fw.h> 766ddbf1e2SGary Palmer #endif 776ddbf1e2SGary Palmer 781c5de19aSGarrett Wollman int rsvp_on = 0; 79f708ef1bSPoul-Henning Kamp static int ip_rsvp_on; 80f0068c4aSGarrett Wollman struct socket *ip_rsvpd; 81f0068c4aSGarrett Wollman 82d4fb926cSGarrett Wollman static int ipforwarding = 0; 830312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_FORWARDING, forwarding, CTLFLAG_RW, 840312fbe9SPoul-Henning Kamp &ipforwarding, 0, ""); 850312fbe9SPoul-Henning Kamp 86d4fb926cSGarrett Wollman static int ipsendredirects = 1; /* XXX */ 870312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_SENDREDIRECTS, redirect, CTLFLAG_RW, 880312fbe9SPoul-Henning Kamp &ipsendredirects, 0, ""); 890312fbe9SPoul-Henning Kamp 90df8bae1dSRodney W. Grimes int ip_defttl = IPDEFTTL; 910312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_DEFTTL, ttl, CTLFLAG_RW, 920312fbe9SPoul-Henning Kamp &ip_defttl, 0, ""); 930312fbe9SPoul-Henning Kamp 940312fbe9SPoul-Henning Kamp static int ip_dosourceroute = 0; 950312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_SOURCEROUTE, sourceroute, CTLFLAG_RW, 960312fbe9SPoul-Henning Kamp &ip_dosourceroute, 0, ""); 97df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 980312fbe9SPoul-Henning Kamp static int ipprintfs = 0; 99df8bae1dSRodney W. Grimes #endif 100df8bae1dSRodney W. Grimes 101df8bae1dSRodney W. Grimes extern struct domain inetdomain; 102df8bae1dSRodney W. Grimes extern struct protosw inetsw[]; 103df8bae1dSRodney W. Grimes u_char ip_protox[IPPROTO_MAX]; 1040312fbe9SPoul-Henning Kamp static int ipqmaxlen = IFQ_MAXLEN; 10559562606SGarrett Wollman struct in_ifaddrhead in_ifaddrhead; /* first inet address */ 106df8bae1dSRodney W. Grimes struct ifqueue ipintrq; 1070312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_INTRQMAXLEN, intr_queue_maxlen, CTLFLAG_RD, 1080312fbe9SPoul-Henning Kamp &ipintrq.ifq_maxlen, 0, ""); 1090312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_INTRQDROPS, intr_queue_drops, CTLFLAG_RD, 1100312fbe9SPoul-Henning Kamp &ipintrq.ifq_drops, 0, ""); 111df8bae1dSRodney W. Grimes 112f23b4c91SGarrett Wollman struct ipstat ipstat; 113194a213eSAndrey A. Chernov 114194a213eSAndrey A. Chernov /* Packet reassembly stuff */ 115194a213eSAndrey A. Chernov #define IPREASS_NHASH_LOG2 6 116194a213eSAndrey A. Chernov #define IPREASS_NHASH (1 << IPREASS_NHASH_LOG2) 117194a213eSAndrey A. Chernov #define IPREASS_HMASK (IPREASS_NHASH - 1) 118194a213eSAndrey A. Chernov #define IPREASS_HASH(x,y) \ 119194a213eSAndrey A. Chernov ((((x) & 0xF | ((((x) >> 8) & 0xF) << 4)) ^ (y)) & IPREASS_HMASK) 120194a213eSAndrey A. Chernov 121194a213eSAndrey A. Chernov static struct ipq ipq[IPREASS_NHASH]; 122194a213eSAndrey A. Chernov static int nipq = 0; /* total # of reass queues */ 123194a213eSAndrey A. Chernov static int maxnipq; 124f23b4c91SGarrett Wollman 1250312fbe9SPoul-Henning Kamp #ifdef IPCTL_DEFMTU 1260312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_DEFMTU, mtu, CTLFLAG_RW, 1270312fbe9SPoul-Henning Kamp &ip_mtu, 0, ""); 1280312fbe9SPoul-Henning Kamp #endif 1290312fbe9SPoul-Henning Kamp 13058938916SGarrett Wollman #if !defined(COMPAT_IPFW) || COMPAT_IPFW == 1 13158938916SGarrett Wollman #undef COMPAT_IPFW 13258938916SGarrett Wollman #define COMPAT_IPFW 1 13358938916SGarrett Wollman #else 13458938916SGarrett Wollman #undef COMPAT_IPFW 13558938916SGarrett Wollman #endif 13658938916SGarrett Wollman 13758938916SGarrett Wollman #ifdef COMPAT_IPFW 13823bf9953SPoul-Henning Kamp /* Firewall hooks */ 13923bf9953SPoul-Henning Kamp ip_fw_chk_t *ip_fw_chk_ptr; 14023bf9953SPoul-Henning Kamp ip_fw_ctl_t *ip_fw_ctl_ptr; 141e7319babSPoul-Henning Kamp 142fed1c7e9SSøren Schmidt /* IP Network Address Translation (NAT) hooks */ 143fed1c7e9SSøren Schmidt ip_nat_t *ip_nat_ptr; 144fed1c7e9SSøren Schmidt ip_nat_ctl_t *ip_nat_ctl_ptr; 14558938916SGarrett Wollman #endif 146fed1c7e9SSøren Schmidt 147afed1b49SDarren Reed #if defined(IPFILTER_LKM) || defined(IPFILTER) 148afed1b49SDarren Reed int fr_check __P((struct ip *, int, struct ifnet *, int, struct mbuf **)); 149afed1b49SDarren Reed int (*fr_checkp) __P((struct ip *, int, struct ifnet *, int, struct mbuf **)) = NULL; 150afed1b49SDarren Reed #endif 151afed1b49SDarren Reed 152afed1b49SDarren Reed 153e7319babSPoul-Henning Kamp /* 154df8bae1dSRodney W. Grimes * We need to save the IP options in case a protocol wants to respond 155df8bae1dSRodney W. Grimes * to an incoming packet over the same route if the packet got here 156df8bae1dSRodney W. Grimes * using IP source routing. This allows connection establishment and 157df8bae1dSRodney W. Grimes * maintenance when the remote end is on a network that is not known 158df8bae1dSRodney W. Grimes * to us. 159df8bae1dSRodney W. Grimes */ 1600312fbe9SPoul-Henning Kamp static int ip_nhops = 0; 161df8bae1dSRodney W. Grimes static struct ip_srcrt { 162df8bae1dSRodney W. Grimes struct in_addr dst; /* final destination */ 163df8bae1dSRodney W. Grimes char nop; /* one NOP to align */ 164df8bae1dSRodney W. Grimes char srcopt[IPOPT_OFFSET + 1]; /* OPTVAL, OLEN and OFFSET */ 165df8bae1dSRodney W. Grimes struct in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)]; 166df8bae1dSRodney W. Grimes } ip_srcrt; 167df8bae1dSRodney W. Grimes 16893e0e116SJulian Elischer #ifdef IPDIVERT 16993e0e116SJulian Elischer /* 17093e0e116SJulian Elischer * Shared variable between ip_input() and ip_reass() to communicate 17193e0e116SJulian Elischer * about which packets, once assembled from fragments, get diverted, 17293e0e116SJulian Elischer * and to which port. 17393e0e116SJulian Elischer */ 17493e0e116SJulian Elischer static u_short frag_divert_port; 17593e0e116SJulian Elischer #endif 17693e0e116SJulian Elischer 177df8bae1dSRodney W. Grimes static void save_rte __P((u_char *, struct in_addr)); 1780312fbe9SPoul-Henning Kamp static void ip_deq __P((struct ipasfrag *)); 1790312fbe9SPoul-Henning Kamp static int ip_dooptions __P((struct mbuf *)); 1800312fbe9SPoul-Henning Kamp static void ip_enq __P((struct ipasfrag *, struct ipasfrag *)); 1810312fbe9SPoul-Henning Kamp static void ip_forward __P((struct mbuf *, int)); 1820312fbe9SPoul-Henning Kamp static void ip_freef __P((struct ipq *)); 1830312fbe9SPoul-Henning Kamp static struct ip * 184194a213eSAndrey A. Chernov ip_reass __P((struct ipasfrag *, struct ipq *, struct ipq *)); 1850312fbe9SPoul-Henning Kamp static struct in_ifaddr * 1860312fbe9SPoul-Henning Kamp ip_rtaddr __P((struct in_addr)); 1870312fbe9SPoul-Henning Kamp static void ipintr __P((void)); 188df8bae1dSRodney W. Grimes /* 189df8bae1dSRodney W. Grimes * IP initialization: fill in IP protocol switch table. 190df8bae1dSRodney W. Grimes * All protocols not implemented in kernel go to raw IP protocol handler. 191df8bae1dSRodney W. Grimes */ 192df8bae1dSRodney W. Grimes void 193df8bae1dSRodney W. Grimes ip_init() 194df8bae1dSRodney W. Grimes { 195df8bae1dSRodney W. Grimes register struct protosw *pr; 196df8bae1dSRodney W. Grimes register int i; 197df8bae1dSRodney W. Grimes 19859562606SGarrett Wollman TAILQ_INIT(&in_ifaddrhead); 199df8bae1dSRodney W. Grimes pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW); 200df8bae1dSRodney W. Grimes if (pr == 0) 201df8bae1dSRodney W. Grimes panic("ip_init"); 202df8bae1dSRodney W. Grimes for (i = 0; i < IPPROTO_MAX; i++) 203df8bae1dSRodney W. Grimes ip_protox[i] = pr - inetsw; 204df8bae1dSRodney W. Grimes for (pr = inetdomain.dom_protosw; 205df8bae1dSRodney W. Grimes pr < inetdomain.dom_protoswNPROTOSW; pr++) 206df8bae1dSRodney W. Grimes if (pr->pr_domain->dom_family == PF_INET && 207df8bae1dSRodney W. Grimes pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) 208df8bae1dSRodney W. Grimes ip_protox[pr->pr_protocol] = pr - inetsw; 209194a213eSAndrey A. Chernov 210194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) 211194a213eSAndrey A. Chernov ipq[i].next = ipq[i].prev = &ipq[i]; 212194a213eSAndrey A. Chernov 213194a213eSAndrey A. Chernov maxnipq = nmbclusters/4; 214194a213eSAndrey A. Chernov 215df8bae1dSRodney W. Grimes ip_id = time.tv_sec & 0xffff; 216df8bae1dSRodney W. Grimes ipintrq.ifq_maxlen = ipqmaxlen; 217b83e4314SPoul-Henning Kamp #ifdef IPFIREWALL 218b83e4314SPoul-Henning Kamp ip_fw_init(); 219b83e4314SPoul-Henning Kamp #endif 220fed1c7e9SSøren Schmidt #ifdef IPNAT 221fed1c7e9SSøren Schmidt ip_nat_init(); 222fed1c7e9SSøren Schmidt #endif 223fed1c7e9SSøren Schmidt 224df8bae1dSRodney W. Grimes } 225df8bae1dSRodney W. Grimes 2260312fbe9SPoul-Henning Kamp static struct sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET }; 227f708ef1bSPoul-Henning Kamp static struct route ipforward_rt; 228df8bae1dSRodney W. Grimes 229df8bae1dSRodney W. Grimes /* 230df8bae1dSRodney W. Grimes * Ip input routine. Checksum and byte swap header. If fragmented 231df8bae1dSRodney W. Grimes * try to reassemble. Process options. Pass to next level. 232df8bae1dSRodney W. Grimes */ 233c67b1d17SGarrett Wollman void 234c67b1d17SGarrett Wollman ip_input(struct mbuf *m) 235df8bae1dSRodney W. Grimes { 23623bf9953SPoul-Henning Kamp struct ip *ip; 23723bf9953SPoul-Henning Kamp struct ipq *fp; 23823bf9953SPoul-Henning Kamp struct in_ifaddr *ia; 239194a213eSAndrey A. Chernov int i, hlen; 24047c861ecSBrian Somers u_short sum; 241df8bae1dSRodney W. Grimes 242df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 243df8bae1dSRodney W. Grimes if ((m->m_flags & M_PKTHDR) == 0) 24458938916SGarrett Wollman panic("ip_input no HDR"); 245df8bae1dSRodney W. Grimes #endif 246df8bae1dSRodney W. Grimes /* 247df8bae1dSRodney W. Grimes * If no IP addresses have been set yet but the interfaces 248df8bae1dSRodney W. Grimes * are receiving, can't do anything with incoming packets yet. 24959562606SGarrett Wollman * XXX This is broken! We should be able to receive broadcasts 25059562606SGarrett Wollman * and multicasts even without any local addresses configured. 251df8bae1dSRodney W. Grimes */ 25259562606SGarrett Wollman if (TAILQ_EMPTY(&in_ifaddrhead)) 253df8bae1dSRodney W. Grimes goto bad; 254df8bae1dSRodney W. Grimes ipstat.ips_total++; 25558938916SGarrett Wollman 25658938916SGarrett Wollman if (m->m_pkthdr.len < sizeof(struct ip)) 25758938916SGarrett Wollman goto tooshort; 25858938916SGarrett Wollman 25958938916SGarrett Wollman #ifdef DIAGNOSTIC 26058938916SGarrett Wollman if (m->m_len < sizeof(struct ip)) 26158938916SGarrett Wollman panic("ipintr mbuf too short"); 26258938916SGarrett Wollman #endif 26358938916SGarrett Wollman 264df8bae1dSRodney W. Grimes if (m->m_len < sizeof (struct ip) && 265df8bae1dSRodney W. Grimes (m = m_pullup(m, sizeof (struct ip))) == 0) { 266df8bae1dSRodney W. Grimes ipstat.ips_toosmall++; 267c67b1d17SGarrett Wollman return; 268df8bae1dSRodney W. Grimes } 269df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 27058938916SGarrett Wollman 27158938916SGarrett Wollman if (IP_VHL_V(ip->ip_vhl) != IPVERSION) { 272df8bae1dSRodney W. Grimes ipstat.ips_badvers++; 273df8bae1dSRodney W. Grimes goto bad; 274df8bae1dSRodney W. Grimes } 27558938916SGarrett Wollman 27658938916SGarrett Wollman hlen = IP_VHL_HL(ip->ip_vhl) << 2; 277df8bae1dSRodney W. Grimes if (hlen < sizeof(struct ip)) { /* minimum header length */ 278df8bae1dSRodney W. Grimes ipstat.ips_badhlen++; 279df8bae1dSRodney W. Grimes goto bad; 280df8bae1dSRodney W. Grimes } 281df8bae1dSRodney W. Grimes if (hlen > m->m_len) { 282df8bae1dSRodney W. Grimes if ((m = m_pullup(m, hlen)) == 0) { 283df8bae1dSRodney W. Grimes ipstat.ips_badhlen++; 284c67b1d17SGarrett Wollman return; 285df8bae1dSRodney W. Grimes } 286df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 287df8bae1dSRodney W. Grimes } 28858938916SGarrett Wollman if (hlen == sizeof(struct ip)) { 28947c861ecSBrian Somers sum = in_cksum_hdr(ip); 29058938916SGarrett Wollman } else { 29147c861ecSBrian Somers sum = in_cksum(m, hlen); 29258938916SGarrett Wollman } 29347c861ecSBrian Somers if (sum) { 294df8bae1dSRodney W. Grimes ipstat.ips_badsum++; 295df8bae1dSRodney W. Grimes goto bad; 296df8bae1dSRodney W. Grimes } 297df8bae1dSRodney W. Grimes 298df8bae1dSRodney W. Grimes /* 299df8bae1dSRodney W. Grimes * Convert fields to host representation. 300df8bae1dSRodney W. Grimes */ 301df8bae1dSRodney W. Grimes NTOHS(ip->ip_len); 302df8bae1dSRodney W. Grimes if (ip->ip_len < hlen) { 303df8bae1dSRodney W. Grimes ipstat.ips_badlen++; 304df8bae1dSRodney W. Grimes goto bad; 305df8bae1dSRodney W. Grimes } 306df8bae1dSRodney W. Grimes NTOHS(ip->ip_id); 307df8bae1dSRodney W. Grimes NTOHS(ip->ip_off); 308df8bae1dSRodney W. Grimes 309df8bae1dSRodney W. Grimes /* 310df8bae1dSRodney W. Grimes * Check that the amount of data in the buffers 311df8bae1dSRodney W. Grimes * is as at least much as the IP header would have us expect. 312df8bae1dSRodney W. Grimes * Trim mbufs if longer than we expect. 313df8bae1dSRodney W. Grimes * Drop packet if shorter than we expect. 314df8bae1dSRodney W. Grimes */ 315df8bae1dSRodney W. Grimes if (m->m_pkthdr.len < ip->ip_len) { 31658938916SGarrett Wollman tooshort: 317df8bae1dSRodney W. Grimes ipstat.ips_tooshort++; 318df8bae1dSRodney W. Grimes goto bad; 319df8bae1dSRodney W. Grimes } 320df8bae1dSRodney W. Grimes if (m->m_pkthdr.len > ip->ip_len) { 321df8bae1dSRodney W. Grimes if (m->m_len == m->m_pkthdr.len) { 322df8bae1dSRodney W. Grimes m->m_len = ip->ip_len; 323df8bae1dSRodney W. Grimes m->m_pkthdr.len = ip->ip_len; 324df8bae1dSRodney W. Grimes } else 325df8bae1dSRodney W. Grimes m_adj(m, ip->ip_len - m->m_pkthdr.len); 326df8bae1dSRodney W. Grimes } 3274dd1662bSUgen J.S. Antsilevich /* 3284dd1662bSUgen J.S. Antsilevich * IpHack's section. 3294dd1662bSUgen J.S. Antsilevich * Right now when no processing on packet has done 3304dd1662bSUgen J.S. Antsilevich * and it is still fresh out of network we do our black 3314dd1662bSUgen J.S. Antsilevich * deals with it. 33293e0e116SJulian Elischer * - Firewall: deny/allow/divert 333fed1c7e9SSøren Schmidt * - Xlate: translate packet's addr/port (NAT). 3344dd1662bSUgen J.S. Antsilevich * - Wrap: fake packet's addr/port <unimpl.> 3354dd1662bSUgen J.S. Antsilevich * - Encapsulate: put it in another IP and send out. <unimp.> 3364dd1662bSUgen J.S. Antsilevich */ 337beec8214SDarren Reed #if defined(IPFILTER) || defined(IPFILTER_LKM) 338beec8214SDarren Reed /* 339beec8214SDarren Reed * Check if we want to allow this packet to be processed. 340beec8214SDarren Reed * Consider it to be bad if not. 341beec8214SDarren Reed */ 342beec8214SDarren Reed if (fr_check) { 343beec8214SDarren Reed struct mbuf *m1 = m; 344df8bae1dSRodney W. Grimes 345beec8214SDarren Reed if ((*fr_checkp)(ip, hlen, m->m_pkthdr.rcvif, 0, &m1) || !m1) 346beec8214SDarren Reed return; 347beec8214SDarren Reed ip = mtod(m = m1, struct ip *); 348beec8214SDarren Reed } 349beec8214SDarren Reed #endif 35058938916SGarrett Wollman #ifdef COMPAT_IPFW 35193e0e116SJulian Elischer if (ip_fw_chk_ptr) { 352e4676ba6SJulian Elischer #ifdef IPDIVERT 353e4676ba6SJulian Elischer u_short port; 35493e0e116SJulian Elischer 355e4676ba6SJulian Elischer port = (*ip_fw_chk_ptr)(&ip, hlen, NULL, ip_divert_ignore, &m); 356d81e4043SBrian Somers ip_divert_ignore = 0; 357e4676ba6SJulian Elischer if (port) { /* Divert packet */ 358e4676ba6SJulian Elischer frag_divert_port = port; 35993e0e116SJulian Elischer goto ours; 36093e0e116SJulian Elischer } 361e4676ba6SJulian Elischer #else 362e4676ba6SJulian Elischer /* If ipfw says divert, we have to just drop packet */ 363e4676ba6SJulian Elischer if ((*ip_fw_chk_ptr)(&ip, hlen, NULL, 0, &m)) { 364e4676ba6SJulian Elischer m_freem(m); 365e4676ba6SJulian Elischer m = NULL; 366e4676ba6SJulian Elischer } 367e4676ba6SJulian Elischer #endif 368e4676ba6SJulian Elischer if (!m) 369e4676ba6SJulian Elischer return; 37093e0e116SJulian Elischer } 371100ba1a6SJordan K. Hubbard 3726713d4a7SSøren Schmidt if (ip_nat_ptr && !(*ip_nat_ptr)(&ip, &m, m->m_pkthdr.rcvif, IP_NAT_IN)) 373fed1c7e9SSøren Schmidt return; 37458938916SGarrett Wollman #endif 375fed1c7e9SSøren Schmidt 376df8bae1dSRodney W. Grimes /* 377df8bae1dSRodney W. Grimes * Process options and, if not destined for us, 378df8bae1dSRodney W. Grimes * ship it on. ip_dooptions returns 1 when an 379df8bae1dSRodney W. Grimes * error was detected (causing an icmp message 380df8bae1dSRodney W. Grimes * to be sent and the original packet to be freed). 381df8bae1dSRodney W. Grimes */ 382df8bae1dSRodney W. Grimes ip_nhops = 0; /* for source routed packets */ 383df8bae1dSRodney W. Grimes if (hlen > sizeof (struct ip) && ip_dooptions(m)) 384c67b1d17SGarrett Wollman return; 385df8bae1dSRodney W. Grimes 386f0068c4aSGarrett Wollman /* greedy RSVP, snatches any PATH packet of the RSVP protocol and no 387f0068c4aSGarrett Wollman * matter if it is destined to another node, or whether it is 388f0068c4aSGarrett Wollman * a multicast one, RSVP wants it! and prevents it from being forwarded 389f0068c4aSGarrett Wollman * anywhere else. Also checks if the rsvp daemon is running before 390f0068c4aSGarrett Wollman * grabbing the packet. 391f0068c4aSGarrett Wollman */ 3921c5de19aSGarrett Wollman if (rsvp_on && ip->ip_p==IPPROTO_RSVP) 393f0068c4aSGarrett Wollman goto ours; 394f0068c4aSGarrett Wollman 395df8bae1dSRodney W. Grimes /* 396df8bae1dSRodney W. Grimes * Check our list of addresses, to see if the packet is for us. 397df8bae1dSRodney W. Grimes */ 39859562606SGarrett Wollman for (ia = in_ifaddrhead.tqh_first; ia; ia = ia->ia_link.tqe_next) { 399df8bae1dSRodney W. Grimes #define satosin(sa) ((struct sockaddr_in *)(sa)) 400df8bae1dSRodney W. Grimes 401df8bae1dSRodney W. Grimes if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr) 402df8bae1dSRodney W. Grimes goto ours; 403432aad0eSTor Egge #ifdef BOOTP_COMPAT 404432aad0eSTor Egge if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY) 405432aad0eSTor Egge goto ours; 406432aad0eSTor Egge #endif 4076ed666afSPoul-Henning Kamp if (ia->ia_ifp && ia->ia_ifp->if_flags & IFF_BROADCAST) { 408df8bae1dSRodney W. Grimes if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == 409df8bae1dSRodney W. Grimes ip->ip_dst.s_addr) 410df8bae1dSRodney W. Grimes goto ours; 411df8bae1dSRodney W. Grimes if (ip->ip_dst.s_addr == ia->ia_netbroadcast.s_addr) 412df8bae1dSRodney W. Grimes goto ours; 413df8bae1dSRodney W. Grimes } 414df8bae1dSRodney W. Grimes } 415df8bae1dSRodney W. Grimes if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { 416df8bae1dSRodney W. Grimes struct in_multi *inm; 417df8bae1dSRodney W. Grimes if (ip_mrouter) { 418df8bae1dSRodney W. Grimes /* 419df8bae1dSRodney W. Grimes * If we are acting as a multicast router, all 420df8bae1dSRodney W. Grimes * incoming multicast packets are passed to the 421df8bae1dSRodney W. Grimes * kernel-level multicast forwarding function. 422df8bae1dSRodney W. Grimes * The packet is returned (relatively) intact; if 423df8bae1dSRodney W. Grimes * ip_mforward() returns a non-zero value, the packet 424df8bae1dSRodney W. Grimes * must be discarded, else it may be accepted below. 425df8bae1dSRodney W. Grimes * 426df8bae1dSRodney W. Grimes * (The IP ident field is put in the same byte order 427df8bae1dSRodney W. Grimes * as expected when ip_mforward() is called from 428df8bae1dSRodney W. Grimes * ip_output().) 429df8bae1dSRodney W. Grimes */ 430df8bae1dSRodney W. Grimes ip->ip_id = htons(ip->ip_id); 431f0068c4aSGarrett Wollman if (ip_mforward(ip, m->m_pkthdr.rcvif, m, 0) != 0) { 432df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 433df8bae1dSRodney W. Grimes m_freem(m); 434c67b1d17SGarrett Wollman return; 435df8bae1dSRodney W. Grimes } 436df8bae1dSRodney W. Grimes ip->ip_id = ntohs(ip->ip_id); 437df8bae1dSRodney W. Grimes 438df8bae1dSRodney W. Grimes /* 439df8bae1dSRodney W. Grimes * The process-level routing demon needs to receive 440df8bae1dSRodney W. Grimes * all multicast IGMP packets, whether or not this 441df8bae1dSRodney W. Grimes * host belongs to their destination groups. 442df8bae1dSRodney W. Grimes */ 443df8bae1dSRodney W. Grimes if (ip->ip_p == IPPROTO_IGMP) 444df8bae1dSRodney W. Grimes goto ours; 445df8bae1dSRodney W. Grimes ipstat.ips_forward++; 446df8bae1dSRodney W. Grimes } 447df8bae1dSRodney W. Grimes /* 448df8bae1dSRodney W. Grimes * See if we belong to the destination multicast group on the 449df8bae1dSRodney W. Grimes * arrival interface. 450df8bae1dSRodney W. Grimes */ 451df8bae1dSRodney W. Grimes IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm); 452df8bae1dSRodney W. Grimes if (inm == NULL) { 45382c39223SGarrett Wollman ipstat.ips_notmember++; 454df8bae1dSRodney W. Grimes m_freem(m); 455c67b1d17SGarrett Wollman return; 456df8bae1dSRodney W. Grimes } 457df8bae1dSRodney W. Grimes goto ours; 458df8bae1dSRodney W. Grimes } 459df8bae1dSRodney W. Grimes if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST) 460df8bae1dSRodney W. Grimes goto ours; 461df8bae1dSRodney W. Grimes if (ip->ip_dst.s_addr == INADDR_ANY) 462df8bae1dSRodney W. Grimes goto ours; 463df8bae1dSRodney W. Grimes 464df8bae1dSRodney W. Grimes /* 465df8bae1dSRodney W. Grimes * Not for us; forward if possible and desirable. 466df8bae1dSRodney W. Grimes */ 467df8bae1dSRodney W. Grimes if (ipforwarding == 0) { 468df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 469df8bae1dSRodney W. Grimes m_freem(m); 470df8bae1dSRodney W. Grimes } else 471df8bae1dSRodney W. Grimes ip_forward(m, 0); 472c67b1d17SGarrett Wollman return; 473df8bae1dSRodney W. Grimes 474df8bae1dSRodney W. Grimes ours: 475100ba1a6SJordan K. Hubbard 47663f8d699SJordan K. Hubbard /* 477df8bae1dSRodney W. Grimes * If offset or IP_MF are set, must reassemble. 478df8bae1dSRodney W. Grimes * Otherwise, nothing need be done. 479df8bae1dSRodney W. Grimes * (We could look in the reassembly queue to see 480df8bae1dSRodney W. Grimes * if the packet was previously fragmented, 481df8bae1dSRodney W. Grimes * but it's not worth the time; just let them time out.) 482df8bae1dSRodney W. Grimes */ 483c7a6ccb3SDavid Greenman if (ip->ip_off & (IP_MF | IP_OFFMASK)) { 484df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT) { /* XXX */ 485df8bae1dSRodney W. Grimes if ((m = m_pullup(m, sizeof (struct ip))) == 0) { 486df8bae1dSRodney W. Grimes ipstat.ips_toosmall++; 48793e0e116SJulian Elischer #ifdef IPDIVERT 48893e0e116SJulian Elischer frag_divert_port = 0; 48993e0e116SJulian Elischer #endif 490c67b1d17SGarrett Wollman return; 491df8bae1dSRodney W. Grimes } 492df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 493df8bae1dSRodney W. Grimes } 494194a213eSAndrey A. Chernov sum = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id); 495df8bae1dSRodney W. Grimes /* 496df8bae1dSRodney W. Grimes * Look for queue of fragments 497df8bae1dSRodney W. Grimes * of this datagram. 498df8bae1dSRodney W. Grimes */ 499194a213eSAndrey A. Chernov for (fp = ipq[sum].next; fp != &ipq[sum]; fp = fp->next) 500df8bae1dSRodney W. Grimes if (ip->ip_id == fp->ipq_id && 501df8bae1dSRodney W. Grimes ip->ip_src.s_addr == fp->ipq_src.s_addr && 502df8bae1dSRodney W. Grimes ip->ip_dst.s_addr == fp->ipq_dst.s_addr && 503df8bae1dSRodney W. Grimes ip->ip_p == fp->ipq_p) 504df8bae1dSRodney W. Grimes goto found; 505df8bae1dSRodney W. Grimes 506194a213eSAndrey A. Chernov fp = 0; 507194a213eSAndrey A. Chernov 508194a213eSAndrey A. Chernov /* check if there's a place for the new queue */ 509194a213eSAndrey A. Chernov if (nipq > maxnipq) { 510194a213eSAndrey A. Chernov /* 511194a213eSAndrey A. Chernov * drop something from the tail of the current queue 512194a213eSAndrey A. Chernov * before proceeding further 513194a213eSAndrey A. Chernov */ 514194a213eSAndrey A. Chernov if (ipq[sum].prev == &ipq[sum]) { /* gak */ 515194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 516194a213eSAndrey A. Chernov if (ipq[i].prev != &ipq[i]) { 517194a213eSAndrey A. Chernov ip_freef(ipq[i].prev); 518194a213eSAndrey A. Chernov break; 519194a213eSAndrey A. Chernov } 520194a213eSAndrey A. Chernov } 521194a213eSAndrey A. Chernov } else 522194a213eSAndrey A. Chernov ip_freef(ipq[sum].prev); 523194a213eSAndrey A. Chernov } 524194a213eSAndrey A. Chernov found: 525df8bae1dSRodney W. Grimes /* 526df8bae1dSRodney W. Grimes * Adjust ip_len to not reflect header, 527df8bae1dSRodney W. Grimes * set ip_mff if more fragments are expected, 528df8bae1dSRodney W. Grimes * convert offset of this to bytes. 529df8bae1dSRodney W. Grimes */ 530df8bae1dSRodney W. Grimes ip->ip_len -= hlen; 531df8bae1dSRodney W. Grimes ((struct ipasfrag *)ip)->ipf_mff &= ~1; 532df8bae1dSRodney W. Grimes if (ip->ip_off & IP_MF) 533df8bae1dSRodney W. Grimes ((struct ipasfrag *)ip)->ipf_mff |= 1; 534df8bae1dSRodney W. Grimes ip->ip_off <<= 3; 535df8bae1dSRodney W. Grimes 536df8bae1dSRodney W. Grimes /* 537df8bae1dSRodney W. Grimes * If datagram marked as having more fragments 538df8bae1dSRodney W. Grimes * or if this is not the first fragment, 539df8bae1dSRodney W. Grimes * attempt reassembly; if it succeeds, proceed. 540df8bae1dSRodney W. Grimes */ 541df8bae1dSRodney W. Grimes if (((struct ipasfrag *)ip)->ipf_mff & 1 || ip->ip_off) { 542df8bae1dSRodney W. Grimes ipstat.ips_fragments++; 543194a213eSAndrey A. Chernov ip = ip_reass((struct ipasfrag *)ip, fp, &ipq[sum]); 544df8bae1dSRodney W. Grimes if (ip == 0) 545c67b1d17SGarrett Wollman return; 546df8bae1dSRodney W. Grimes ipstat.ips_reassembled++; 547df8bae1dSRodney W. Grimes m = dtom(ip); 548af782f1cSBrian Somers #ifdef IPDIVERT 549af782f1cSBrian Somers if (frag_divert_port) { 550af782f1cSBrian Somers ip->ip_len += hlen; 551af782f1cSBrian Somers HTONS(ip->ip_len); 552af782f1cSBrian Somers HTONS(ip->ip_off); 553af782f1cSBrian Somers HTONS(ip->ip_id); 554af782f1cSBrian Somers ip->ip_sum = 0; 555af782f1cSBrian Somers ip->ip_sum = in_cksum_hdr(ip); 556af782f1cSBrian Somers NTOHS(ip->ip_id); 557af782f1cSBrian Somers NTOHS(ip->ip_off); 558af782f1cSBrian Somers NTOHS(ip->ip_len); 559af782f1cSBrian Somers ip->ip_len -= hlen; 560af782f1cSBrian Somers } 561af782f1cSBrian Somers #endif 562df8bae1dSRodney W. Grimes } else 563df8bae1dSRodney W. Grimes if (fp) 564df8bae1dSRodney W. Grimes ip_freef(fp); 565df8bae1dSRodney W. Grimes } else 566df8bae1dSRodney W. Grimes ip->ip_len -= hlen; 567df8bae1dSRodney W. Grimes 56893e0e116SJulian Elischer #ifdef IPDIVERT 56993e0e116SJulian Elischer /* 570e4676ba6SJulian Elischer * Divert reassembled packets to the divert protocol if required 57193e0e116SJulian Elischer */ 57293e0e116SJulian Elischer if (frag_divert_port) { 573e4676ba6SJulian Elischer ipstat.ips_delivered++; 57493e0e116SJulian Elischer ip_divert_port = frag_divert_port; 57593e0e116SJulian Elischer frag_divert_port = 0; 57693e0e116SJulian Elischer (*inetsw[ip_protox[IPPROTO_DIVERT]].pr_input)(m, hlen); 57793e0e116SJulian Elischer return; 57893e0e116SJulian Elischer } 57993e0e116SJulian Elischer #endif 58093e0e116SJulian Elischer 581df8bae1dSRodney W. Grimes /* 582df8bae1dSRodney W. Grimes * Switch out to protocol's input routine. 583df8bae1dSRodney W. Grimes */ 584df8bae1dSRodney W. Grimes ipstat.ips_delivered++; 585df8bae1dSRodney W. Grimes (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen); 586c67b1d17SGarrett Wollman return; 587df8bae1dSRodney W. Grimes bad: 588df8bae1dSRodney W. Grimes m_freem(m); 589c67b1d17SGarrett Wollman } 590c67b1d17SGarrett Wollman 591c67b1d17SGarrett Wollman /* 592c67b1d17SGarrett Wollman * IP software interrupt routine - to go away sometime soon 593c67b1d17SGarrett Wollman */ 594c67b1d17SGarrett Wollman static void 595c67b1d17SGarrett Wollman ipintr(void) 596c67b1d17SGarrett Wollman { 597c67b1d17SGarrett Wollman int s; 598c67b1d17SGarrett Wollman struct mbuf *m; 599c67b1d17SGarrett Wollman 600c67b1d17SGarrett Wollman while(1) { 601c67b1d17SGarrett Wollman s = splimp(); 602c67b1d17SGarrett Wollman IF_DEQUEUE(&ipintrq, m); 603c67b1d17SGarrett Wollman splx(s); 604c67b1d17SGarrett Wollman if (m == 0) 605c67b1d17SGarrett Wollman return; 606c67b1d17SGarrett Wollman ip_input(m); 607c67b1d17SGarrett Wollman } 608df8bae1dSRodney W. Grimes } 609df8bae1dSRodney W. Grimes 610748e0b0aSGarrett Wollman NETISR_SET(NETISR_IP, ipintr); 611748e0b0aSGarrett Wollman 612df8bae1dSRodney W. Grimes /* 613df8bae1dSRodney W. Grimes * Take incoming datagram fragment and try to 614df8bae1dSRodney W. Grimes * reassemble it into whole datagram. If a chain for 615df8bae1dSRodney W. Grimes * reassembly of this datagram already exists, then it 616df8bae1dSRodney W. Grimes * is given as fp; otherwise have to make a chain. 617df8bae1dSRodney W. Grimes */ 6180312fbe9SPoul-Henning Kamp static struct ip * 619194a213eSAndrey A. Chernov ip_reass(ip, fp, where) 620df8bae1dSRodney W. Grimes register struct ipasfrag *ip; 621df8bae1dSRodney W. Grimes register struct ipq *fp; 622194a213eSAndrey A. Chernov struct ipq *where; 623df8bae1dSRodney W. Grimes { 624df8bae1dSRodney W. Grimes register struct mbuf *m = dtom(ip); 625df8bae1dSRodney W. Grimes register struct ipasfrag *q; 626df8bae1dSRodney W. Grimes struct mbuf *t; 627df8bae1dSRodney W. Grimes int hlen = ip->ip_hl << 2; 628df8bae1dSRodney W. Grimes int i, next; 629df8bae1dSRodney W. Grimes 630df8bae1dSRodney W. Grimes /* 631df8bae1dSRodney W. Grimes * Presence of header sizes in mbufs 632df8bae1dSRodney W. Grimes * would confuse code below. 633df8bae1dSRodney W. Grimes */ 634df8bae1dSRodney W. Grimes m->m_data += hlen; 635df8bae1dSRodney W. Grimes m->m_len -= hlen; 636df8bae1dSRodney W. Grimes 637df8bae1dSRodney W. Grimes /* 638df8bae1dSRodney W. Grimes * If first fragment to arrive, create a reassembly queue. 639df8bae1dSRodney W. Grimes */ 640df8bae1dSRodney W. Grimes if (fp == 0) { 641df8bae1dSRodney W. Grimes if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL) 642df8bae1dSRodney W. Grimes goto dropfrag; 643df8bae1dSRodney W. Grimes fp = mtod(t, struct ipq *); 644194a213eSAndrey A. Chernov insque(fp, where); 645194a213eSAndrey A. Chernov nipq++; 646df8bae1dSRodney W. Grimes fp->ipq_ttl = IPFRAGTTL; 647df8bae1dSRodney W. Grimes fp->ipq_p = ip->ip_p; 648df8bae1dSRodney W. Grimes fp->ipq_id = ip->ip_id; 649df8bae1dSRodney W. Grimes fp->ipq_next = fp->ipq_prev = (struct ipasfrag *)fp; 650df8bae1dSRodney W. Grimes fp->ipq_src = ((struct ip *)ip)->ip_src; 651df8bae1dSRodney W. Grimes fp->ipq_dst = ((struct ip *)ip)->ip_dst; 65293e0e116SJulian Elischer #ifdef IPDIVERT 65393e0e116SJulian Elischer fp->ipq_divert = 0; 65493e0e116SJulian Elischer #endif 655df8bae1dSRodney W. Grimes q = (struct ipasfrag *)fp; 656df8bae1dSRodney W. Grimes goto insert; 657df8bae1dSRodney W. Grimes } 658df8bae1dSRodney W. Grimes 659df8bae1dSRodney W. Grimes /* 660df8bae1dSRodney W. Grimes * Find a segment which begins after this one does. 661df8bae1dSRodney W. Grimes */ 662df8bae1dSRodney W. Grimes for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) 663df8bae1dSRodney W. Grimes if (q->ip_off > ip->ip_off) 664df8bae1dSRodney W. Grimes break; 665df8bae1dSRodney W. Grimes 666df8bae1dSRodney W. Grimes /* 667df8bae1dSRodney W. Grimes * If there is a preceding segment, it may provide some of 668df8bae1dSRodney W. Grimes * our data already. If so, drop the data from the incoming 669df8bae1dSRodney W. Grimes * segment. If it provides all of our data, drop us. 670df8bae1dSRodney W. Grimes */ 671df8bae1dSRodney W. Grimes if (q->ipf_prev != (struct ipasfrag *)fp) { 672df8bae1dSRodney W. Grimes i = q->ipf_prev->ip_off + q->ipf_prev->ip_len - ip->ip_off; 673df8bae1dSRodney W. Grimes if (i > 0) { 674df8bae1dSRodney W. Grimes if (i >= ip->ip_len) 675df8bae1dSRodney W. Grimes goto dropfrag; 676df8bae1dSRodney W. Grimes m_adj(dtom(ip), i); 677df8bae1dSRodney W. Grimes ip->ip_off += i; 678df8bae1dSRodney W. Grimes ip->ip_len -= i; 679df8bae1dSRodney W. Grimes } 680df8bae1dSRodney W. Grimes } 681df8bae1dSRodney W. Grimes 682df8bae1dSRodney W. Grimes /* 683df8bae1dSRodney W. Grimes * While we overlap succeeding segments trim them or, 684df8bae1dSRodney W. Grimes * if they are completely covered, dequeue them. 685df8bae1dSRodney W. Grimes */ 686df8bae1dSRodney W. Grimes while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) { 687e7c81944SDavid Greenman struct mbuf *m0; 688e7c81944SDavid Greenman 689df8bae1dSRodney W. Grimes i = (ip->ip_off + ip->ip_len) - q->ip_off; 690df8bae1dSRodney W. Grimes if (i < q->ip_len) { 691df8bae1dSRodney W. Grimes q->ip_len -= i; 692df8bae1dSRodney W. Grimes q->ip_off += i; 693df8bae1dSRodney W. Grimes m_adj(dtom(q), i); 694df8bae1dSRodney W. Grimes break; 695df8bae1dSRodney W. Grimes } 696e7c81944SDavid Greenman m0 = dtom(q); 697df8bae1dSRodney W. Grimes q = q->ipf_next; 698df8bae1dSRodney W. Grimes ip_deq(q->ipf_prev); 699e7c81944SDavid Greenman m_freem(m0); 700df8bae1dSRodney W. Grimes } 701df8bae1dSRodney W. Grimes 702df8bae1dSRodney W. Grimes insert: 70393e0e116SJulian Elischer 70493e0e116SJulian Elischer #ifdef IPDIVERT 70593e0e116SJulian Elischer /* 70693e0e116SJulian Elischer * Any fragment diverting causes the whole packet to divert 70793e0e116SJulian Elischer */ 70893e0e116SJulian Elischer if (frag_divert_port != 0) 70993e0e116SJulian Elischer fp->ipq_divert = frag_divert_port; 71093e0e116SJulian Elischer frag_divert_port = 0; 71193e0e116SJulian Elischer #endif 71293e0e116SJulian Elischer 713df8bae1dSRodney W. Grimes /* 714df8bae1dSRodney W. Grimes * Stick new segment in its place; 715df8bae1dSRodney W. Grimes * check for complete reassembly. 716df8bae1dSRodney W. Grimes */ 717df8bae1dSRodney W. Grimes ip_enq(ip, q->ipf_prev); 718df8bae1dSRodney W. Grimes next = 0; 719df8bae1dSRodney W. Grimes for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) { 720df8bae1dSRodney W. Grimes if (q->ip_off != next) 721df8bae1dSRodney W. Grimes return (0); 722df8bae1dSRodney W. Grimes next += q->ip_len; 723df8bae1dSRodney W. Grimes } 724df8bae1dSRodney W. Grimes if (q->ipf_prev->ipf_mff & 1) 725df8bae1dSRodney W. Grimes return (0); 726df8bae1dSRodney W. Grimes 727df8bae1dSRodney W. Grimes /* 728430d30d8SBill Fenner * Reassembly is complete. Make sure the packet is a sane size. 729430d30d8SBill Fenner */ 730430d30d8SBill Fenner if (next + (IP_VHL_HL(((struct ip *)fp->ipq_next)->ip_vhl) << 2) 731430d30d8SBill Fenner > IP_MAXPACKET) { 732430d30d8SBill Fenner ipstat.ips_toolong++; 733430d30d8SBill Fenner ip_freef(fp); 734430d30d8SBill Fenner return (0); 735430d30d8SBill Fenner } 736430d30d8SBill Fenner 737430d30d8SBill Fenner /* 738430d30d8SBill Fenner * Concatenate fragments. 739df8bae1dSRodney W. Grimes */ 740df8bae1dSRodney W. Grimes q = fp->ipq_next; 741df8bae1dSRodney W. Grimes m = dtom(q); 742df8bae1dSRodney W. Grimes t = m->m_next; 743df8bae1dSRodney W. Grimes m->m_next = 0; 744df8bae1dSRodney W. Grimes m_cat(m, t); 745df8bae1dSRodney W. Grimes q = q->ipf_next; 746df8bae1dSRodney W. Grimes while (q != (struct ipasfrag *)fp) { 747df8bae1dSRodney W. Grimes t = dtom(q); 748df8bae1dSRodney W. Grimes q = q->ipf_next; 749df8bae1dSRodney W. Grimes m_cat(m, t); 750df8bae1dSRodney W. Grimes } 751df8bae1dSRodney W. Grimes 75293e0e116SJulian Elischer #ifdef IPDIVERT 75393e0e116SJulian Elischer /* 75493e0e116SJulian Elischer * Record divert port for packet, if any 75593e0e116SJulian Elischer */ 75693e0e116SJulian Elischer frag_divert_port = fp->ipq_divert; 75793e0e116SJulian Elischer #endif 75893e0e116SJulian Elischer 759df8bae1dSRodney W. Grimes /* 760df8bae1dSRodney W. Grimes * Create header for new ip packet by 761df8bae1dSRodney W. Grimes * modifying header of first packet; 762df8bae1dSRodney W. Grimes * dequeue and discard fragment reassembly header. 763df8bae1dSRodney W. Grimes * Make header visible. 764df8bae1dSRodney W. Grimes */ 765df8bae1dSRodney W. Grimes ip = fp->ipq_next; 766df8bae1dSRodney W. Grimes ip->ip_len = next; 767df8bae1dSRodney W. Grimes ip->ipf_mff &= ~1; 768df8bae1dSRodney W. Grimes ((struct ip *)ip)->ip_src = fp->ipq_src; 769df8bae1dSRodney W. Grimes ((struct ip *)ip)->ip_dst = fp->ipq_dst; 770df8bae1dSRodney W. Grimes remque(fp); 771194a213eSAndrey A. Chernov nipq--; 772df8bae1dSRodney W. Grimes (void) m_free(dtom(fp)); 773df8bae1dSRodney W. Grimes m = dtom(ip); 774df8bae1dSRodney W. Grimes m->m_len += (ip->ip_hl << 2); 775df8bae1dSRodney W. Grimes m->m_data -= (ip->ip_hl << 2); 776df8bae1dSRodney W. Grimes /* some debugging cruft by sklower, below, will go away soon */ 777df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) { /* XXX this should be done elsewhere */ 778df8bae1dSRodney W. Grimes register int plen = 0; 779df8bae1dSRodney W. Grimes for (t = m; m; m = m->m_next) 780df8bae1dSRodney W. Grimes plen += m->m_len; 781df8bae1dSRodney W. Grimes t->m_pkthdr.len = plen; 782df8bae1dSRodney W. Grimes } 783df8bae1dSRodney W. Grimes return ((struct ip *)ip); 784df8bae1dSRodney W. Grimes 785df8bae1dSRodney W. Grimes dropfrag: 786df8bae1dSRodney W. Grimes ipstat.ips_fragdropped++; 787df8bae1dSRodney W. Grimes m_freem(m); 788df8bae1dSRodney W. Grimes return (0); 789df8bae1dSRodney W. Grimes } 790df8bae1dSRodney W. Grimes 791df8bae1dSRodney W. Grimes /* 792df8bae1dSRodney W. Grimes * Free a fragment reassembly header and all 793df8bae1dSRodney W. Grimes * associated datagrams. 794df8bae1dSRodney W. Grimes */ 7950312fbe9SPoul-Henning Kamp static void 796df8bae1dSRodney W. Grimes ip_freef(fp) 797df8bae1dSRodney W. Grimes struct ipq *fp; 798df8bae1dSRodney W. Grimes { 799df8bae1dSRodney W. Grimes register struct ipasfrag *q, *p; 800df8bae1dSRodney W. Grimes 801df8bae1dSRodney W. Grimes for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = p) { 802df8bae1dSRodney W. Grimes p = q->ipf_next; 803df8bae1dSRodney W. Grimes ip_deq(q); 804df8bae1dSRodney W. Grimes m_freem(dtom(q)); 805df8bae1dSRodney W. Grimes } 806df8bae1dSRodney W. Grimes remque(fp); 807df8bae1dSRodney W. Grimes (void) m_free(dtom(fp)); 808194a213eSAndrey A. Chernov nipq--; 809df8bae1dSRodney W. Grimes } 810df8bae1dSRodney W. Grimes 811df8bae1dSRodney W. Grimes /* 812df8bae1dSRodney W. Grimes * Put an ip fragment on a reassembly chain. 813df8bae1dSRodney W. Grimes * Like insque, but pointers in middle of structure. 814df8bae1dSRodney W. Grimes */ 8150312fbe9SPoul-Henning Kamp static void 816df8bae1dSRodney W. Grimes ip_enq(p, prev) 817df8bae1dSRodney W. Grimes register struct ipasfrag *p, *prev; 818df8bae1dSRodney W. Grimes { 819df8bae1dSRodney W. Grimes 820df8bae1dSRodney W. Grimes p->ipf_prev = prev; 821df8bae1dSRodney W. Grimes p->ipf_next = prev->ipf_next; 822df8bae1dSRodney W. Grimes prev->ipf_next->ipf_prev = p; 823df8bae1dSRodney W. Grimes prev->ipf_next = p; 824df8bae1dSRodney W. Grimes } 825df8bae1dSRodney W. Grimes 826df8bae1dSRodney W. Grimes /* 827df8bae1dSRodney W. Grimes * To ip_enq as remque is to insque. 828df8bae1dSRodney W. Grimes */ 8290312fbe9SPoul-Henning Kamp static void 830df8bae1dSRodney W. Grimes ip_deq(p) 831df8bae1dSRodney W. Grimes register struct ipasfrag *p; 832df8bae1dSRodney W. Grimes { 833df8bae1dSRodney W. Grimes 834df8bae1dSRodney W. Grimes p->ipf_prev->ipf_next = p->ipf_next; 835df8bae1dSRodney W. Grimes p->ipf_next->ipf_prev = p->ipf_prev; 836df8bae1dSRodney W. Grimes } 837df8bae1dSRodney W. Grimes 838df8bae1dSRodney W. Grimes /* 839df8bae1dSRodney W. Grimes * IP timer processing; 840df8bae1dSRodney W. Grimes * if a timer expires on a reassembly 841df8bae1dSRodney W. Grimes * queue, discard it. 842df8bae1dSRodney W. Grimes */ 843df8bae1dSRodney W. Grimes void 844df8bae1dSRodney W. Grimes ip_slowtimo() 845df8bae1dSRodney W. Grimes { 846df8bae1dSRodney W. Grimes register struct ipq *fp; 847df8bae1dSRodney W. Grimes int s = splnet(); 848194a213eSAndrey A. Chernov int i; 849df8bae1dSRodney W. Grimes 850194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 851194a213eSAndrey A. Chernov fp = ipq[i].next; 852194a213eSAndrey A. Chernov if (fp == 0) 853194a213eSAndrey A. Chernov continue; 854194a213eSAndrey A. Chernov while (fp != &ipq[i]) { 855df8bae1dSRodney W. Grimes --fp->ipq_ttl; 856df8bae1dSRodney W. Grimes fp = fp->next; 857df8bae1dSRodney W. Grimes if (fp->prev->ipq_ttl == 0) { 858df8bae1dSRodney W. Grimes ipstat.ips_fragtimeout++; 859df8bae1dSRodney W. Grimes ip_freef(fp->prev); 860df8bae1dSRodney W. Grimes } 861df8bae1dSRodney W. Grimes } 862194a213eSAndrey A. Chernov } 863df8bae1dSRodney W. Grimes splx(s); 864df8bae1dSRodney W. Grimes } 865df8bae1dSRodney W. Grimes 866df8bae1dSRodney W. Grimes /* 867df8bae1dSRodney W. Grimes * Drain off all datagram fragments. 868df8bae1dSRodney W. Grimes */ 869df8bae1dSRodney W. Grimes void 870df8bae1dSRodney W. Grimes ip_drain() 871df8bae1dSRodney W. Grimes { 872194a213eSAndrey A. Chernov int i; 873ce29ab3aSGarrett Wollman 874194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 875194a213eSAndrey A. Chernov while (ipq[i].next != &ipq[i]) { 876194a213eSAndrey A. Chernov ipstat.ips_fragdropped++; 877194a213eSAndrey A. Chernov ip_freef(ipq[i].next); 878194a213eSAndrey A. Chernov } 879194a213eSAndrey A. Chernov } 880ce29ab3aSGarrett Wollman in_rtqdrain(); 881df8bae1dSRodney W. Grimes } 882df8bae1dSRodney W. Grimes 883df8bae1dSRodney W. Grimes /* 884df8bae1dSRodney W. Grimes * Do option processing on a datagram, 885df8bae1dSRodney W. Grimes * possibly discarding it if bad options are encountered, 886df8bae1dSRodney W. Grimes * or forwarding it if source-routed. 887df8bae1dSRodney W. Grimes * Returns 1 if packet has been forwarded/freed, 888df8bae1dSRodney W. Grimes * 0 if the packet should be processed further. 889df8bae1dSRodney W. Grimes */ 8900312fbe9SPoul-Henning Kamp static int 891df8bae1dSRodney W. Grimes ip_dooptions(m) 892df8bae1dSRodney W. Grimes struct mbuf *m; 893df8bae1dSRodney W. Grimes { 894df8bae1dSRodney W. Grimes register struct ip *ip = mtod(m, struct ip *); 895df8bae1dSRodney W. Grimes register u_char *cp; 896df8bae1dSRodney W. Grimes register struct ip_timestamp *ipt; 897df8bae1dSRodney W. Grimes register struct in_ifaddr *ia; 898df8bae1dSRodney W. Grimes int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0; 899df8bae1dSRodney W. Grimes struct in_addr *sin, dst; 900df8bae1dSRodney W. Grimes n_time ntime; 901df8bae1dSRodney W. Grimes 902df8bae1dSRodney W. Grimes dst = ip->ip_dst; 903df8bae1dSRodney W. Grimes cp = (u_char *)(ip + 1); 90458938916SGarrett Wollman cnt = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip); 905df8bae1dSRodney W. Grimes for (; cnt > 0; cnt -= optlen, cp += optlen) { 906df8bae1dSRodney W. Grimes opt = cp[IPOPT_OPTVAL]; 907df8bae1dSRodney W. Grimes if (opt == IPOPT_EOL) 908df8bae1dSRodney W. Grimes break; 909df8bae1dSRodney W. Grimes if (opt == IPOPT_NOP) 910df8bae1dSRodney W. Grimes optlen = 1; 911df8bae1dSRodney W. Grimes else { 912df8bae1dSRodney W. Grimes optlen = cp[IPOPT_OLEN]; 913df8bae1dSRodney W. Grimes if (optlen <= 0 || optlen > cnt) { 914df8bae1dSRodney W. Grimes code = &cp[IPOPT_OLEN] - (u_char *)ip; 915df8bae1dSRodney W. Grimes goto bad; 916df8bae1dSRodney W. Grimes } 917df8bae1dSRodney W. Grimes } 918df8bae1dSRodney W. Grimes switch (opt) { 919df8bae1dSRodney W. Grimes 920df8bae1dSRodney W. Grimes default: 921df8bae1dSRodney W. Grimes break; 922df8bae1dSRodney W. Grimes 923df8bae1dSRodney W. Grimes /* 924df8bae1dSRodney W. Grimes * Source routing with record. 925df8bae1dSRodney W. Grimes * Find interface with current destination address. 926df8bae1dSRodney W. Grimes * If none on this machine then drop if strictly routed, 927df8bae1dSRodney W. Grimes * or do nothing if loosely routed. 928df8bae1dSRodney W. Grimes * Record interface address and bring up next address 929df8bae1dSRodney W. Grimes * component. If strictly routed make sure next 930df8bae1dSRodney W. Grimes * address is on directly accessible net. 931df8bae1dSRodney W. Grimes */ 932df8bae1dSRodney W. Grimes case IPOPT_LSRR: 933df8bae1dSRodney W. Grimes case IPOPT_SSRR: 934df8bae1dSRodney W. Grimes if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { 935df8bae1dSRodney W. Grimes code = &cp[IPOPT_OFFSET] - (u_char *)ip; 936df8bae1dSRodney W. Grimes goto bad; 937df8bae1dSRodney W. Grimes } 938df8bae1dSRodney W. Grimes ipaddr.sin_addr = ip->ip_dst; 939df8bae1dSRodney W. Grimes ia = (struct in_ifaddr *) 940df8bae1dSRodney W. Grimes ifa_ifwithaddr((struct sockaddr *)&ipaddr); 941df8bae1dSRodney W. Grimes if (ia == 0) { 942df8bae1dSRodney W. Grimes if (opt == IPOPT_SSRR) { 943df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 944df8bae1dSRodney W. Grimes code = ICMP_UNREACH_SRCFAIL; 945df8bae1dSRodney W. Grimes goto bad; 946df8bae1dSRodney W. Grimes } 947df8bae1dSRodney W. Grimes /* 948df8bae1dSRodney W. Grimes * Loose routing, and not at next destination 949df8bae1dSRodney W. Grimes * yet; nothing to do except forward. 950df8bae1dSRodney W. Grimes */ 951df8bae1dSRodney W. Grimes break; 952df8bae1dSRodney W. Grimes } 953df8bae1dSRodney W. Grimes off--; /* 0 origin */ 954df8bae1dSRodney W. Grimes if (off > optlen - sizeof(struct in_addr)) { 955df8bae1dSRodney W. Grimes /* 956df8bae1dSRodney W. Grimes * End of source route. Should be for us. 957df8bae1dSRodney W. Grimes */ 958df8bae1dSRodney W. Grimes save_rte(cp, ip->ip_src); 959df8bae1dSRodney W. Grimes break; 960df8bae1dSRodney W. Grimes } 9611025071fSGarrett Wollman 9621025071fSGarrett Wollman if (!ip_dosourceroute) { 9631025071fSGarrett Wollman char buf[4*sizeof "123"]; 9641025071fSGarrett Wollman strcpy(buf, inet_ntoa(ip->ip_dst)); 9651025071fSGarrett Wollman 9661025071fSGarrett Wollman log(LOG_WARNING, 9671025071fSGarrett Wollman "attempted source route from %s to %s\n", 9681025071fSGarrett Wollman inet_ntoa(ip->ip_src), buf); 9691025071fSGarrett Wollman type = ICMP_UNREACH; 9701025071fSGarrett Wollman code = ICMP_UNREACH_SRCFAIL; 9711025071fSGarrett Wollman goto bad; 9721025071fSGarrett Wollman } 9731025071fSGarrett Wollman 974df8bae1dSRodney W. Grimes /* 975df8bae1dSRodney W. Grimes * locate outgoing interface 976df8bae1dSRodney W. Grimes */ 97794a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, cp + off, 978df8bae1dSRodney W. Grimes sizeof(ipaddr.sin_addr)); 9791025071fSGarrett Wollman 980df8bae1dSRodney W. Grimes if (opt == IPOPT_SSRR) { 981df8bae1dSRodney W. Grimes #define INA struct in_ifaddr * 982df8bae1dSRodney W. Grimes #define SA struct sockaddr * 983df8bae1dSRodney W. Grimes if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0) 984df8bae1dSRodney W. Grimes ia = (INA)ifa_ifwithnet((SA)&ipaddr); 985df8bae1dSRodney W. Grimes } else 986df8bae1dSRodney W. Grimes ia = ip_rtaddr(ipaddr.sin_addr); 987df8bae1dSRodney W. Grimes if (ia == 0) { 988df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 989df8bae1dSRodney W. Grimes code = ICMP_UNREACH_SRCFAIL; 990df8bae1dSRodney W. Grimes goto bad; 991df8bae1dSRodney W. Grimes } 992df8bae1dSRodney W. Grimes ip->ip_dst = ipaddr.sin_addr; 99394a5d9b6SDavid Greenman (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr), 99494a5d9b6SDavid Greenman sizeof(struct in_addr)); 995df8bae1dSRodney W. Grimes cp[IPOPT_OFFSET] += sizeof(struct in_addr); 996df8bae1dSRodney W. Grimes /* 997df8bae1dSRodney W. Grimes * Let ip_intr's mcast routing check handle mcast pkts 998df8bae1dSRodney W. Grimes */ 999df8bae1dSRodney W. Grimes forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr)); 1000df8bae1dSRodney W. Grimes break; 1001df8bae1dSRodney W. Grimes 1002df8bae1dSRodney W. Grimes case IPOPT_RR: 1003df8bae1dSRodney W. Grimes if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { 1004df8bae1dSRodney W. Grimes code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1005df8bae1dSRodney W. Grimes goto bad; 1006df8bae1dSRodney W. Grimes } 1007df8bae1dSRodney W. Grimes /* 1008df8bae1dSRodney W. Grimes * If no space remains, ignore. 1009df8bae1dSRodney W. Grimes */ 1010df8bae1dSRodney W. Grimes off--; /* 0 origin */ 1011df8bae1dSRodney W. Grimes if (off > optlen - sizeof(struct in_addr)) 1012df8bae1dSRodney W. Grimes break; 101394a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, &ip->ip_dst, 1014df8bae1dSRodney W. Grimes sizeof(ipaddr.sin_addr)); 1015df8bae1dSRodney W. Grimes /* 1016df8bae1dSRodney W. Grimes * locate outgoing interface; if we're the destination, 1017df8bae1dSRodney W. Grimes * use the incoming interface (should be same). 1018df8bae1dSRodney W. Grimes */ 1019df8bae1dSRodney W. Grimes if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 && 1020df8bae1dSRodney W. Grimes (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) { 1021df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1022df8bae1dSRodney W. Grimes code = ICMP_UNREACH_HOST; 1023df8bae1dSRodney W. Grimes goto bad; 1024df8bae1dSRodney W. Grimes } 102594a5d9b6SDavid Greenman (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr), 102694a5d9b6SDavid Greenman sizeof(struct in_addr)); 1027df8bae1dSRodney W. Grimes cp[IPOPT_OFFSET] += sizeof(struct in_addr); 1028df8bae1dSRodney W. Grimes break; 1029df8bae1dSRodney W. Grimes 1030df8bae1dSRodney W. Grimes case IPOPT_TS: 1031df8bae1dSRodney W. Grimes code = cp - (u_char *)ip; 1032df8bae1dSRodney W. Grimes ipt = (struct ip_timestamp *)cp; 1033df8bae1dSRodney W. Grimes if (ipt->ipt_len < 5) 1034df8bae1dSRodney W. Grimes goto bad; 1035df8bae1dSRodney W. Grimes if (ipt->ipt_ptr > ipt->ipt_len - sizeof (long)) { 1036df8bae1dSRodney W. Grimes if (++ipt->ipt_oflw == 0) 1037df8bae1dSRodney W. Grimes goto bad; 1038df8bae1dSRodney W. Grimes break; 1039df8bae1dSRodney W. Grimes } 1040df8bae1dSRodney W. Grimes sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1); 1041df8bae1dSRodney W. Grimes switch (ipt->ipt_flg) { 1042df8bae1dSRodney W. Grimes 1043df8bae1dSRodney W. Grimes case IPOPT_TS_TSONLY: 1044df8bae1dSRodney W. Grimes break; 1045df8bae1dSRodney W. Grimes 1046df8bae1dSRodney W. Grimes case IPOPT_TS_TSANDADDR: 1047df8bae1dSRodney W. Grimes if (ipt->ipt_ptr + sizeof(n_time) + 1048df8bae1dSRodney W. Grimes sizeof(struct in_addr) > ipt->ipt_len) 1049df8bae1dSRodney W. Grimes goto bad; 1050df8bae1dSRodney W. Grimes ipaddr.sin_addr = dst; 1051df8bae1dSRodney W. Grimes ia = (INA)ifaof_ifpforaddr((SA)&ipaddr, 1052df8bae1dSRodney W. Grimes m->m_pkthdr.rcvif); 1053df8bae1dSRodney W. Grimes if (ia == 0) 1054df8bae1dSRodney W. Grimes continue; 105594a5d9b6SDavid Greenman (void)memcpy(sin, &IA_SIN(ia)->sin_addr, 105694a5d9b6SDavid Greenman sizeof(struct in_addr)); 1057df8bae1dSRodney W. Grimes ipt->ipt_ptr += sizeof(struct in_addr); 1058df8bae1dSRodney W. Grimes break; 1059df8bae1dSRodney W. Grimes 1060df8bae1dSRodney W. Grimes case IPOPT_TS_PRESPEC: 1061df8bae1dSRodney W. Grimes if (ipt->ipt_ptr + sizeof(n_time) + 1062df8bae1dSRodney W. Grimes sizeof(struct in_addr) > ipt->ipt_len) 1063df8bae1dSRodney W. Grimes goto bad; 106494a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, sin, 1065df8bae1dSRodney W. Grimes sizeof(struct in_addr)); 1066df8bae1dSRodney W. Grimes if (ifa_ifwithaddr((SA)&ipaddr) == 0) 1067df8bae1dSRodney W. Grimes continue; 1068df8bae1dSRodney W. Grimes ipt->ipt_ptr += sizeof(struct in_addr); 1069df8bae1dSRodney W. Grimes break; 1070df8bae1dSRodney W. Grimes 1071df8bae1dSRodney W. Grimes default: 1072df8bae1dSRodney W. Grimes goto bad; 1073df8bae1dSRodney W. Grimes } 1074df8bae1dSRodney W. Grimes ntime = iptime(); 107594a5d9b6SDavid Greenman (void)memcpy(cp + ipt->ipt_ptr - 1, &ntime, 1076df8bae1dSRodney W. Grimes sizeof(n_time)); 1077df8bae1dSRodney W. Grimes ipt->ipt_ptr += sizeof(n_time); 1078df8bae1dSRodney W. Grimes } 1079df8bae1dSRodney W. Grimes } 1080df8bae1dSRodney W. Grimes if (forward) { 1081df8bae1dSRodney W. Grimes ip_forward(m, 1); 1082df8bae1dSRodney W. Grimes return (1); 1083df8bae1dSRodney W. Grimes } 1084df8bae1dSRodney W. Grimes return (0); 1085df8bae1dSRodney W. Grimes bad: 108658938916SGarrett Wollman ip->ip_len -= IP_VHL_HL(ip->ip_vhl) << 2; /* XXX icmp_error adds in hdr length */ 1087df8bae1dSRodney W. Grimes icmp_error(m, type, code, 0, 0); 1088df8bae1dSRodney W. Grimes ipstat.ips_badoptions++; 1089df8bae1dSRodney W. Grimes return (1); 1090df8bae1dSRodney W. Grimes } 1091df8bae1dSRodney W. Grimes 1092df8bae1dSRodney W. Grimes /* 1093df8bae1dSRodney W. Grimes * Given address of next destination (final or next hop), 1094df8bae1dSRodney W. Grimes * return internet address info of interface to be used to get there. 1095df8bae1dSRodney W. Grimes */ 10960312fbe9SPoul-Henning Kamp static struct in_ifaddr * 1097df8bae1dSRodney W. Grimes ip_rtaddr(dst) 1098df8bae1dSRodney W. Grimes struct in_addr dst; 1099df8bae1dSRodney W. Grimes { 1100df8bae1dSRodney W. Grimes register struct sockaddr_in *sin; 1101df8bae1dSRodney W. Grimes 1102df8bae1dSRodney W. Grimes sin = (struct sockaddr_in *) &ipforward_rt.ro_dst; 1103df8bae1dSRodney W. Grimes 1104df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt == 0 || dst.s_addr != sin->sin_addr.s_addr) { 1105df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt) { 1106df8bae1dSRodney W. Grimes RTFREE(ipforward_rt.ro_rt); 1107df8bae1dSRodney W. Grimes ipforward_rt.ro_rt = 0; 1108df8bae1dSRodney W. Grimes } 1109df8bae1dSRodney W. Grimes sin->sin_family = AF_INET; 1110df8bae1dSRodney W. Grimes sin->sin_len = sizeof(*sin); 1111df8bae1dSRodney W. Grimes sin->sin_addr = dst; 1112df8bae1dSRodney W. Grimes 11132c17fe93SGarrett Wollman rtalloc_ign(&ipforward_rt, RTF_PRCLONING); 1114df8bae1dSRodney W. Grimes } 1115df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt == 0) 1116df8bae1dSRodney W. Grimes return ((struct in_ifaddr *)0); 1117df8bae1dSRodney W. Grimes return ((struct in_ifaddr *) ipforward_rt.ro_rt->rt_ifa); 1118df8bae1dSRodney W. Grimes } 1119df8bae1dSRodney W. Grimes 1120df8bae1dSRodney W. Grimes /* 1121df8bae1dSRodney W. Grimes * Save incoming source route for use in replies, 1122df8bae1dSRodney W. Grimes * to be picked up later by ip_srcroute if the receiver is interested. 1123df8bae1dSRodney W. Grimes */ 1124df8bae1dSRodney W. Grimes void 1125df8bae1dSRodney W. Grimes save_rte(option, dst) 1126df8bae1dSRodney W. Grimes u_char *option; 1127df8bae1dSRodney W. Grimes struct in_addr dst; 1128df8bae1dSRodney W. Grimes { 1129df8bae1dSRodney W. Grimes unsigned olen; 1130df8bae1dSRodney W. Grimes 1131df8bae1dSRodney W. Grimes olen = option[IPOPT_OLEN]; 1132df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1133df8bae1dSRodney W. Grimes if (ipprintfs) 1134df8bae1dSRodney W. Grimes printf("save_rte: olen %d\n", olen); 1135df8bae1dSRodney W. Grimes #endif 1136df8bae1dSRodney W. Grimes if (olen > sizeof(ip_srcrt) - (1 + sizeof(dst))) 1137df8bae1dSRodney W. Grimes return; 11380453d3cbSBruce Evans bcopy(option, ip_srcrt.srcopt, olen); 1139df8bae1dSRodney W. Grimes ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr); 1140df8bae1dSRodney W. Grimes ip_srcrt.dst = dst; 1141df8bae1dSRodney W. Grimes } 1142df8bae1dSRodney W. Grimes 1143df8bae1dSRodney W. Grimes /* 1144df8bae1dSRodney W. Grimes * Retrieve incoming source route for use in replies, 1145df8bae1dSRodney W. Grimes * in the same form used by setsockopt. 1146df8bae1dSRodney W. Grimes * The first hop is placed before the options, will be removed later. 1147df8bae1dSRodney W. Grimes */ 1148df8bae1dSRodney W. Grimes struct mbuf * 1149df8bae1dSRodney W. Grimes ip_srcroute() 1150df8bae1dSRodney W. Grimes { 1151df8bae1dSRodney W. Grimes register struct in_addr *p, *q; 1152df8bae1dSRodney W. Grimes register struct mbuf *m; 1153df8bae1dSRodney W. Grimes 1154df8bae1dSRodney W. Grimes if (ip_nhops == 0) 1155df8bae1dSRodney W. Grimes return ((struct mbuf *)0); 1156df8bae1dSRodney W. Grimes m = m_get(M_DONTWAIT, MT_SOOPTS); 1157df8bae1dSRodney W. Grimes if (m == 0) 1158df8bae1dSRodney W. Grimes return ((struct mbuf *)0); 1159df8bae1dSRodney W. Grimes 1160df8bae1dSRodney W. Grimes #define OPTSIZ (sizeof(ip_srcrt.nop) + sizeof(ip_srcrt.srcopt)) 1161df8bae1dSRodney W. Grimes 1162df8bae1dSRodney W. Grimes /* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */ 1163df8bae1dSRodney W. Grimes m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) + 1164df8bae1dSRodney W. Grimes OPTSIZ; 1165df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1166df8bae1dSRodney W. Grimes if (ipprintfs) 1167df8bae1dSRodney W. Grimes printf("ip_srcroute: nhops %d mlen %d", ip_nhops, m->m_len); 1168df8bae1dSRodney W. Grimes #endif 1169df8bae1dSRodney W. Grimes 1170df8bae1dSRodney W. Grimes /* 1171df8bae1dSRodney W. Grimes * First save first hop for return route 1172df8bae1dSRodney W. Grimes */ 1173df8bae1dSRodney W. Grimes p = &ip_srcrt.route[ip_nhops - 1]; 1174df8bae1dSRodney W. Grimes *(mtod(m, struct in_addr *)) = *p--; 1175df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1176df8bae1dSRodney W. Grimes if (ipprintfs) 1177df8bae1dSRodney W. Grimes printf(" hops %lx", ntohl(mtod(m, struct in_addr *)->s_addr)); 1178df8bae1dSRodney W. Grimes #endif 1179df8bae1dSRodney W. Grimes 1180df8bae1dSRodney W. Grimes /* 1181df8bae1dSRodney W. Grimes * Copy option fields and padding (nop) to mbuf. 1182df8bae1dSRodney W. Grimes */ 1183df8bae1dSRodney W. Grimes ip_srcrt.nop = IPOPT_NOP; 1184df8bae1dSRodney W. Grimes ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF; 118594a5d9b6SDavid Greenman (void)memcpy(mtod(m, caddr_t) + sizeof(struct in_addr), 118694a5d9b6SDavid Greenman &ip_srcrt.nop, OPTSIZ); 1187df8bae1dSRodney W. Grimes q = (struct in_addr *)(mtod(m, caddr_t) + 1188df8bae1dSRodney W. Grimes sizeof(struct in_addr) + OPTSIZ); 1189df8bae1dSRodney W. Grimes #undef OPTSIZ 1190df8bae1dSRodney W. Grimes /* 1191df8bae1dSRodney W. Grimes * Record return path as an IP source route, 1192df8bae1dSRodney W. Grimes * reversing the path (pointers are now aligned). 1193df8bae1dSRodney W. Grimes */ 1194df8bae1dSRodney W. Grimes while (p >= ip_srcrt.route) { 1195df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1196df8bae1dSRodney W. Grimes if (ipprintfs) 1197df8bae1dSRodney W. Grimes printf(" %lx", ntohl(q->s_addr)); 1198df8bae1dSRodney W. Grimes #endif 1199df8bae1dSRodney W. Grimes *q++ = *p--; 1200df8bae1dSRodney W. Grimes } 1201df8bae1dSRodney W. Grimes /* 1202df8bae1dSRodney W. Grimes * Last hop goes to final destination. 1203df8bae1dSRodney W. Grimes */ 1204df8bae1dSRodney W. Grimes *q = ip_srcrt.dst; 1205df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1206df8bae1dSRodney W. Grimes if (ipprintfs) 1207df8bae1dSRodney W. Grimes printf(" %lx\n", ntohl(q->s_addr)); 1208df8bae1dSRodney W. Grimes #endif 1209df8bae1dSRodney W. Grimes return (m); 1210df8bae1dSRodney W. Grimes } 1211df8bae1dSRodney W. Grimes 1212df8bae1dSRodney W. Grimes /* 1213df8bae1dSRodney W. Grimes * Strip out IP options, at higher 1214df8bae1dSRodney W. Grimes * level protocol in the kernel. 1215df8bae1dSRodney W. Grimes * Second argument is buffer to which options 1216df8bae1dSRodney W. Grimes * will be moved, and return value is their length. 1217df8bae1dSRodney W. Grimes * XXX should be deleted; last arg currently ignored. 1218df8bae1dSRodney W. Grimes */ 1219df8bae1dSRodney W. Grimes void 1220df8bae1dSRodney W. Grimes ip_stripoptions(m, mopt) 1221df8bae1dSRodney W. Grimes register struct mbuf *m; 1222df8bae1dSRodney W. Grimes struct mbuf *mopt; 1223df8bae1dSRodney W. Grimes { 1224df8bae1dSRodney W. Grimes register int i; 1225df8bae1dSRodney W. Grimes struct ip *ip = mtod(m, struct ip *); 1226df8bae1dSRodney W. Grimes register caddr_t opts; 1227df8bae1dSRodney W. Grimes int olen; 1228df8bae1dSRodney W. Grimes 122958938916SGarrett Wollman olen = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip); 1230df8bae1dSRodney W. Grimes opts = (caddr_t)(ip + 1); 1231df8bae1dSRodney W. Grimes i = m->m_len - (sizeof (struct ip) + olen); 1232df8bae1dSRodney W. Grimes bcopy(opts + olen, opts, (unsigned)i); 1233df8bae1dSRodney W. Grimes m->m_len -= olen; 1234df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) 1235df8bae1dSRodney W. Grimes m->m_pkthdr.len -= olen; 123658938916SGarrett Wollman ip->ip_vhl = IP_MAKE_VHL(IPVERSION, sizeof(struct ip) >> 2); 1237df8bae1dSRodney W. Grimes } 1238df8bae1dSRodney W. Grimes 1239df8bae1dSRodney W. Grimes u_char inetctlerrmap[PRC_NCMDS] = { 1240df8bae1dSRodney W. Grimes 0, 0, 0, 0, 1241df8bae1dSRodney W. Grimes 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH, 1242df8bae1dSRodney W. Grimes EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, 1243df8bae1dSRodney W. Grimes EMSGSIZE, EHOSTUNREACH, 0, 0, 1244df8bae1dSRodney W. Grimes 0, 0, 0, 0, 1245df8bae1dSRodney W. Grimes ENOPROTOOPT 1246df8bae1dSRodney W. Grimes }; 1247df8bae1dSRodney W. Grimes 1248df8bae1dSRodney W. Grimes /* 1249df8bae1dSRodney W. Grimes * Forward a packet. If some error occurs return the sender 1250df8bae1dSRodney W. Grimes * an icmp packet. Note we can't always generate a meaningful 1251df8bae1dSRodney W. Grimes * icmp message because icmp doesn't have a large enough repertoire 1252df8bae1dSRodney W. Grimes * of codes and types. 1253df8bae1dSRodney W. Grimes * 1254df8bae1dSRodney W. Grimes * If not forwarding, just drop the packet. This could be confusing 1255df8bae1dSRodney W. Grimes * if ipforwarding was zero but some routing protocol was advancing 1256df8bae1dSRodney W. Grimes * us as a gateway to somewhere. However, we must let the routing 1257df8bae1dSRodney W. Grimes * protocol deal with that. 1258df8bae1dSRodney W. Grimes * 1259df8bae1dSRodney W. Grimes * The srcrt parameter indicates whether the packet is being forwarded 1260df8bae1dSRodney W. Grimes * via a source route. 1261df8bae1dSRodney W. Grimes */ 12620312fbe9SPoul-Henning Kamp static void 1263df8bae1dSRodney W. Grimes ip_forward(m, srcrt) 1264df8bae1dSRodney W. Grimes struct mbuf *m; 1265df8bae1dSRodney W. Grimes int srcrt; 1266df8bae1dSRodney W. Grimes { 1267df8bae1dSRodney W. Grimes register struct ip *ip = mtod(m, struct ip *); 1268df8bae1dSRodney W. Grimes register struct sockaddr_in *sin; 1269df8bae1dSRodney W. Grimes register struct rtentry *rt; 127026f9a767SRodney W. Grimes int error, type = 0, code = 0; 1271df8bae1dSRodney W. Grimes struct mbuf *mcopy; 1272df8bae1dSRodney W. Grimes n_long dest; 1273df8bae1dSRodney W. Grimes struct ifnet *destifp; 1274df8bae1dSRodney W. Grimes 1275df8bae1dSRodney W. Grimes dest = 0; 1276df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1277df8bae1dSRodney W. Grimes if (ipprintfs) 127861ce519bSPoul-Henning Kamp printf("forward: src %lx dst %lx ttl %x\n", 1279623ae52eSPoul-Henning Kamp ip->ip_src.s_addr, ip->ip_dst.s_addr, ip->ip_ttl); 1280df8bae1dSRodney W. Grimes #endif 1281100ba1a6SJordan K. Hubbard 1282100ba1a6SJordan K. Hubbard 1283df8bae1dSRodney W. Grimes if (m->m_flags & M_BCAST || in_canforward(ip->ip_dst) == 0) { 1284df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 1285df8bae1dSRodney W. Grimes m_freem(m); 1286df8bae1dSRodney W. Grimes return; 1287df8bae1dSRodney W. Grimes } 1288df8bae1dSRodney W. Grimes HTONS(ip->ip_id); 1289df8bae1dSRodney W. Grimes if (ip->ip_ttl <= IPTTLDEC) { 1290df8bae1dSRodney W. Grimes icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, dest, 0); 1291df8bae1dSRodney W. Grimes return; 1292df8bae1dSRodney W. Grimes } 1293df8bae1dSRodney W. Grimes ip->ip_ttl -= IPTTLDEC; 1294df8bae1dSRodney W. Grimes 1295df8bae1dSRodney W. Grimes sin = (struct sockaddr_in *)&ipforward_rt.ro_dst; 1296df8bae1dSRodney W. Grimes if ((rt = ipforward_rt.ro_rt) == 0 || 1297df8bae1dSRodney W. Grimes ip->ip_dst.s_addr != sin->sin_addr.s_addr) { 1298df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt) { 1299df8bae1dSRodney W. Grimes RTFREE(ipforward_rt.ro_rt); 1300df8bae1dSRodney W. Grimes ipforward_rt.ro_rt = 0; 1301df8bae1dSRodney W. Grimes } 1302df8bae1dSRodney W. Grimes sin->sin_family = AF_INET; 1303df8bae1dSRodney W. Grimes sin->sin_len = sizeof(*sin); 1304df8bae1dSRodney W. Grimes sin->sin_addr = ip->ip_dst; 1305df8bae1dSRodney W. Grimes 13062c17fe93SGarrett Wollman rtalloc_ign(&ipforward_rt, RTF_PRCLONING); 1307df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt == 0) { 1308df8bae1dSRodney W. Grimes icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0); 1309df8bae1dSRodney W. Grimes return; 1310df8bae1dSRodney W. Grimes } 1311df8bae1dSRodney W. Grimes rt = ipforward_rt.ro_rt; 1312df8bae1dSRodney W. Grimes } 1313df8bae1dSRodney W. Grimes 1314df8bae1dSRodney W. Grimes /* 1315df8bae1dSRodney W. Grimes * Save at most 64 bytes of the packet in case 1316df8bae1dSRodney W. Grimes * we need to generate an ICMP message to the src. 1317df8bae1dSRodney W. Grimes */ 1318df8bae1dSRodney W. Grimes mcopy = m_copy(m, 0, imin((int)ip->ip_len, 64)); 1319df8bae1dSRodney W. Grimes 1320df8bae1dSRodney W. Grimes /* 1321df8bae1dSRodney W. Grimes * If forwarding packet using same interface that it came in on, 1322df8bae1dSRodney W. Grimes * perhaps should send a redirect to sender to shortcut a hop. 1323df8bae1dSRodney W. Grimes * Only send redirect if source is sending directly to us, 1324df8bae1dSRodney W. Grimes * and if packet was not source routed (or has any options). 1325df8bae1dSRodney W. Grimes * Also, don't send redirect if forwarding using a default route 1326df8bae1dSRodney W. Grimes * or a route modified by a redirect. 1327df8bae1dSRodney W. Grimes */ 1328df8bae1dSRodney W. Grimes #define satosin(sa) ((struct sockaddr_in *)(sa)) 1329df8bae1dSRodney W. Grimes if (rt->rt_ifp == m->m_pkthdr.rcvif && 1330df8bae1dSRodney W. Grimes (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 && 1331df8bae1dSRodney W. Grimes satosin(rt_key(rt))->sin_addr.s_addr != 0 && 1332df8bae1dSRodney W. Grimes ipsendredirects && !srcrt) { 1333df8bae1dSRodney W. Grimes #define RTA(rt) ((struct in_ifaddr *)(rt->rt_ifa)) 1334df8bae1dSRodney W. Grimes u_long src = ntohl(ip->ip_src.s_addr); 1335df8bae1dSRodney W. Grimes 1336df8bae1dSRodney W. Grimes if (RTA(rt) && 1337df8bae1dSRodney W. Grimes (src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) { 1338df8bae1dSRodney W. Grimes if (rt->rt_flags & RTF_GATEWAY) 1339df8bae1dSRodney W. Grimes dest = satosin(rt->rt_gateway)->sin_addr.s_addr; 1340df8bae1dSRodney W. Grimes else 1341df8bae1dSRodney W. Grimes dest = ip->ip_dst.s_addr; 1342df8bae1dSRodney W. Grimes /* Router requirements says to only send host redirects */ 1343df8bae1dSRodney W. Grimes type = ICMP_REDIRECT; 1344df8bae1dSRodney W. Grimes code = ICMP_REDIRECT_HOST; 1345df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1346df8bae1dSRodney W. Grimes if (ipprintfs) 1347df8bae1dSRodney W. Grimes printf("redirect (%d) to %lx\n", code, (u_long)dest); 1348df8bae1dSRodney W. Grimes #endif 1349df8bae1dSRodney W. Grimes } 1350df8bae1dSRodney W. Grimes } 1351df8bae1dSRodney W. Grimes 1352b97d15cbSGarrett Wollman error = ip_output(m, (struct mbuf *)0, &ipforward_rt, 1353b97d15cbSGarrett Wollman IP_FORWARDING, 0); 1354df8bae1dSRodney W. Grimes if (error) 1355df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 1356df8bae1dSRodney W. Grimes else { 1357df8bae1dSRodney W. Grimes ipstat.ips_forward++; 1358df8bae1dSRodney W. Grimes if (type) 1359df8bae1dSRodney W. Grimes ipstat.ips_redirectsent++; 1360df8bae1dSRodney W. Grimes else { 1361df8bae1dSRodney W. Grimes if (mcopy) 1362df8bae1dSRodney W. Grimes m_freem(mcopy); 1363df8bae1dSRodney W. Grimes return; 1364df8bae1dSRodney W. Grimes } 1365df8bae1dSRodney W. Grimes } 1366df8bae1dSRodney W. Grimes if (mcopy == NULL) 1367df8bae1dSRodney W. Grimes return; 1368df8bae1dSRodney W. Grimes destifp = NULL; 1369df8bae1dSRodney W. Grimes 1370df8bae1dSRodney W. Grimes switch (error) { 1371df8bae1dSRodney W. Grimes 1372df8bae1dSRodney W. Grimes case 0: /* forwarded, but need redirect */ 1373df8bae1dSRodney W. Grimes /* type, code set above */ 1374df8bae1dSRodney W. Grimes break; 1375df8bae1dSRodney W. Grimes 1376df8bae1dSRodney W. Grimes case ENETUNREACH: /* shouldn't happen, checked above */ 1377df8bae1dSRodney W. Grimes case EHOSTUNREACH: 1378df8bae1dSRodney W. Grimes case ENETDOWN: 1379df8bae1dSRodney W. Grimes case EHOSTDOWN: 1380df8bae1dSRodney W. Grimes default: 1381df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1382df8bae1dSRodney W. Grimes code = ICMP_UNREACH_HOST; 1383df8bae1dSRodney W. Grimes break; 1384df8bae1dSRodney W. Grimes 1385df8bae1dSRodney W. Grimes case EMSGSIZE: 1386df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1387df8bae1dSRodney W. Grimes code = ICMP_UNREACH_NEEDFRAG; 1388df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt) 1389df8bae1dSRodney W. Grimes destifp = ipforward_rt.ro_rt->rt_ifp; 1390df8bae1dSRodney W. Grimes ipstat.ips_cantfrag++; 1391df8bae1dSRodney W. Grimes break; 1392df8bae1dSRodney W. Grimes 1393df8bae1dSRodney W. Grimes case ENOBUFS: 1394df8bae1dSRodney W. Grimes type = ICMP_SOURCEQUENCH; 1395df8bae1dSRodney W. Grimes code = 0; 1396df8bae1dSRodney W. Grimes break; 1397df8bae1dSRodney W. Grimes } 1398df8bae1dSRodney W. Grimes icmp_error(mcopy, type, code, dest, destifp); 1399df8bae1dSRodney W. Grimes } 1400df8bae1dSRodney W. Grimes 140182c23ebaSBill Fenner void 140282c23ebaSBill Fenner ip_savecontrol(inp, mp, ip, m) 140382c23ebaSBill Fenner register struct inpcb *inp; 140482c23ebaSBill Fenner register struct mbuf **mp; 140582c23ebaSBill Fenner register struct ip *ip; 140682c23ebaSBill Fenner register struct mbuf *m; 140782c23ebaSBill Fenner { 140882c23ebaSBill Fenner if (inp->inp_socket->so_options & SO_TIMESTAMP) { 140982c23ebaSBill Fenner struct timeval tv; 141082c23ebaSBill Fenner 141182c23ebaSBill Fenner microtime(&tv); 141282c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv), 141382c23ebaSBill Fenner SCM_TIMESTAMP, SOL_SOCKET); 141482c23ebaSBill Fenner if (*mp) 141582c23ebaSBill Fenner mp = &(*mp)->m_next; 141682c23ebaSBill Fenner } 141782c23ebaSBill Fenner if (inp->inp_flags & INP_RECVDSTADDR) { 141882c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) &ip->ip_dst, 141982c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVDSTADDR, IPPROTO_IP); 142082c23ebaSBill Fenner if (*mp) 142182c23ebaSBill Fenner mp = &(*mp)->m_next; 142282c23ebaSBill Fenner } 142382c23ebaSBill Fenner #ifdef notyet 142482c23ebaSBill Fenner /* XXX 142582c23ebaSBill Fenner * Moving these out of udp_input() made them even more broken 142682c23ebaSBill Fenner * than they already were. 142782c23ebaSBill Fenner */ 142882c23ebaSBill Fenner /* options were tossed already */ 142982c23ebaSBill Fenner if (inp->inp_flags & INP_RECVOPTS) { 143082c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) opts_deleted_above, 143182c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVOPTS, IPPROTO_IP); 143282c23ebaSBill Fenner if (*mp) 143382c23ebaSBill Fenner mp = &(*mp)->m_next; 143482c23ebaSBill Fenner } 143582c23ebaSBill Fenner /* ip_srcroute doesn't do what we want here, need to fix */ 143682c23ebaSBill Fenner if (inp->inp_flags & INP_RECVRETOPTS) { 143782c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) ip_srcroute(), 143882c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVRETOPTS, IPPROTO_IP); 143982c23ebaSBill Fenner if (*mp) 144082c23ebaSBill Fenner mp = &(*mp)->m_next; 144182c23ebaSBill Fenner } 144282c23ebaSBill Fenner #endif 144382c23ebaSBill Fenner if (inp->inp_flags & INP_RECVIF) { 144482c23ebaSBill Fenner struct sockaddr_dl sdl; 144582c23ebaSBill Fenner 144682c23ebaSBill Fenner sdl.sdl_len = offsetof(struct sockaddr_dl, sdl_data[0]); 144782c23ebaSBill Fenner sdl.sdl_family = AF_LINK; 144882c23ebaSBill Fenner sdl.sdl_index = m->m_pkthdr.rcvif ? 144982c23ebaSBill Fenner m->m_pkthdr.rcvif->if_index : 0; 145082c23ebaSBill Fenner sdl.sdl_nlen = sdl.sdl_alen = sdl.sdl_slen = 0; 145182c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) &sdl, sdl.sdl_len, 145282c23ebaSBill Fenner IP_RECVIF, IPPROTO_IP); 145382c23ebaSBill Fenner if (*mp) 145482c23ebaSBill Fenner mp = &(*mp)->m_next; 145582c23ebaSBill Fenner } 145682c23ebaSBill Fenner } 145782c23ebaSBill Fenner 1458df8bae1dSRodney W. Grimes int 1459f0068c4aSGarrett Wollman ip_rsvp_init(struct socket *so) 1460f0068c4aSGarrett Wollman { 1461f0068c4aSGarrett Wollman if (so->so_type != SOCK_RAW || 1462f0068c4aSGarrett Wollman so->so_proto->pr_protocol != IPPROTO_RSVP) 1463f0068c4aSGarrett Wollman return EOPNOTSUPP; 1464f0068c4aSGarrett Wollman 1465f0068c4aSGarrett Wollman if (ip_rsvpd != NULL) 1466f0068c4aSGarrett Wollman return EADDRINUSE; 1467f0068c4aSGarrett Wollman 1468f0068c4aSGarrett Wollman ip_rsvpd = so; 14691c5de19aSGarrett Wollman /* 14701c5de19aSGarrett Wollman * This may seem silly, but we need to be sure we don't over-increment 14711c5de19aSGarrett Wollman * the RSVP counter, in case something slips up. 14721c5de19aSGarrett Wollman */ 14731c5de19aSGarrett Wollman if (!ip_rsvp_on) { 14741c5de19aSGarrett Wollman ip_rsvp_on = 1; 14751c5de19aSGarrett Wollman rsvp_on++; 14761c5de19aSGarrett Wollman } 1477f0068c4aSGarrett Wollman 1478f0068c4aSGarrett Wollman return 0; 1479f0068c4aSGarrett Wollman } 1480f0068c4aSGarrett Wollman 1481f0068c4aSGarrett Wollman int 1482f0068c4aSGarrett Wollman ip_rsvp_done(void) 1483f0068c4aSGarrett Wollman { 1484f0068c4aSGarrett Wollman ip_rsvpd = NULL; 14851c5de19aSGarrett Wollman /* 14861c5de19aSGarrett Wollman * This may seem silly, but we need to be sure we don't over-decrement 14871c5de19aSGarrett Wollman * the RSVP counter, in case something slips up. 14881c5de19aSGarrett Wollman */ 14891c5de19aSGarrett Wollman if (ip_rsvp_on) { 14901c5de19aSGarrett Wollman ip_rsvp_on = 0; 14911c5de19aSGarrett Wollman rsvp_on--; 14921c5de19aSGarrett Wollman } 1493f0068c4aSGarrett Wollman return 0; 1494f0068c4aSGarrett Wollman } 1495