1c398230bSWarner Losh /*- 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 * 4. Neither the name of the University nor the names of its contributors 14df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 15df8bae1dSRodney W. Grimes * without specific prior written permission. 16df8bae1dSRodney W. Grimes * 17df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27df8bae1dSRodney W. Grimes * SUCH DAMAGE. 28df8bae1dSRodney W. Grimes * 29df8bae1dSRodney W. Grimes * @(#)ip_input.c 8.2 (Berkeley) 1/4/94 30c3aac50fSPeter Wemm * $FreeBSD$ 31df8bae1dSRodney W. Grimes */ 32df8bae1dSRodney W. Grimes 330ac40133SBrian Somers #include "opt_bootp.h" 3474a9466cSGary Palmer #include "opt_ipfw.h" 3527108a15SDag-Erling Smørgrav #include "opt_ipstealth.h" 366a800098SYoshinobu Inoue #include "opt_ipsec.h" 3736b0360bSRobert Watson #include "opt_mac.h" 3874a9466cSGary Palmer 39df8bae1dSRodney W. Grimes #include <sys/param.h> 40df8bae1dSRodney W. Grimes #include <sys/systm.h> 415f311da2SMike Silbersack #include <sys/callout.h> 4236b0360bSRobert Watson #include <sys/mac.h> 43df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 44b715f178SLuigi Rizzo #include <sys/malloc.h> 45df8bae1dSRodney W. Grimes #include <sys/domain.h> 46df8bae1dSRodney W. Grimes #include <sys/protosw.h> 47df8bae1dSRodney W. Grimes #include <sys/socket.h> 48df8bae1dSRodney W. Grimes #include <sys/time.h> 49df8bae1dSRodney W. Grimes #include <sys/kernel.h> 501025071fSGarrett Wollman #include <sys/syslog.h> 51b5e8ce9fSBruce Evans #include <sys/sysctl.h> 52df8bae1dSRodney W. Grimes 53c85540ddSAndrey A. Chernov #include <net/pfil.h> 54df8bae1dSRodney W. Grimes #include <net/if.h> 559494d596SBrooks Davis #include <net/if_types.h> 56d314ad7bSJulian Elischer #include <net/if_var.h> 5782c23ebaSBill Fenner #include <net/if_dl.h> 58df8bae1dSRodney W. Grimes #include <net/route.h> 59748e0b0aSGarrett Wollman #include <net/netisr.h> 60df8bae1dSRodney W. Grimes 61df8bae1dSRodney W. Grimes #include <netinet/in.h> 62df8bae1dSRodney W. Grimes #include <netinet/in_systm.h> 63b5e8ce9fSBruce Evans #include <netinet/in_var.h> 64df8bae1dSRodney W. Grimes #include <netinet/ip.h> 65df8bae1dSRodney W. Grimes #include <netinet/in_pcb.h> 66df8bae1dSRodney W. Grimes #include <netinet/ip_var.h> 67df8bae1dSRodney W. Grimes #include <netinet/ip_icmp.h> 6858938916SGarrett Wollman #include <machine/in_cksum.h> 69df8bae1dSRodney W. Grimes 70f0068c4aSGarrett Wollman #include <sys/socketvar.h> 716ddbf1e2SGary Palmer 729b932e9eSAndre Oppermann /* XXX: Temporary until ipfw_ether and ipfw_bridge are converted. */ 736ddbf1e2SGary Palmer #include <netinet/ip_fw.h> 74db69a05dSPaul Saab #include <netinet/ip_dummynet.h> 75db69a05dSPaul Saab 766a800098SYoshinobu Inoue #ifdef IPSEC 776a800098SYoshinobu Inoue #include <netinet6/ipsec.h> 786a800098SYoshinobu Inoue #include <netkey/key.h> 796a800098SYoshinobu Inoue #endif 806a800098SYoshinobu Inoue 81b9234fafSSam Leffler #ifdef FAST_IPSEC 82b9234fafSSam Leffler #include <netipsec/ipsec.h> 83b9234fafSSam Leffler #include <netipsec/key.h> 84b9234fafSSam Leffler #endif 85b9234fafSSam Leffler 861c5de19aSGarrett Wollman int rsvp_on = 0; 87f0068c4aSGarrett Wollman 881f91d8c5SDavid Greenman int ipforwarding = 0; 890312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_FORWARDING, forwarding, CTLFLAG_RW, 903d177f46SBill Fumerola &ipforwarding, 0, "Enable IP forwarding between interfaces"); 910312fbe9SPoul-Henning Kamp 92d4fb926cSGarrett Wollman static int ipsendredirects = 1; /* XXX */ 930312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_SENDREDIRECTS, redirect, CTLFLAG_RW, 943d177f46SBill Fumerola &ipsendredirects, 0, "Enable sending IP redirects"); 950312fbe9SPoul-Henning Kamp 96df8bae1dSRodney W. Grimes int ip_defttl = IPDEFTTL; 970312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_DEFTTL, ttl, CTLFLAG_RW, 983d177f46SBill Fumerola &ip_defttl, 0, "Maximum TTL on IP packets"); 990312fbe9SPoul-Henning Kamp 1000312fbe9SPoul-Henning Kamp static int ip_dosourceroute = 0; 1010312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_SOURCEROUTE, sourceroute, CTLFLAG_RW, 1023d177f46SBill Fumerola &ip_dosourceroute, 0, "Enable forwarding source routed IP packets"); 1034fce5804SGuido van Rooij 1044fce5804SGuido van Rooij static int ip_acceptsourceroute = 0; 1054fce5804SGuido van Rooij SYSCTL_INT(_net_inet_ip, IPCTL_ACCEPTSOURCEROUTE, accept_sourceroute, 1063d177f46SBill Fumerola CTLFLAG_RW, &ip_acceptsourceroute, 0, 1073d177f46SBill Fumerola "Enable accepting source routed IP packets"); 1086a800098SYoshinobu Inoue 1092bde81acSAndre Oppermann int ip_doopts = 1; /* 0 = ignore, 1 = process, 2 = reject */ 1102bde81acSAndre Oppermann SYSCTL_INT(_net_inet_ip, OID_AUTO, process_options, CTLFLAG_RW, 1112bde81acSAndre Oppermann &ip_doopts, 0, "Enable IP options processing ([LS]SRR, RR, TS)"); 1122bde81acSAndre Oppermann 1136a800098SYoshinobu Inoue static int ip_keepfaith = 0; 1146a800098SYoshinobu Inoue SYSCTL_INT(_net_inet_ip, IPCTL_KEEPFAITH, keepfaith, CTLFLAG_RW, 1156a800098SYoshinobu Inoue &ip_keepfaith, 0, 1166a800098SYoshinobu Inoue "Enable packet capture for FAITH IPv4->IPv6 translater daemon"); 1176a800098SYoshinobu Inoue 118402062e8SMike Silbersack static int nipq = 0; /* total # of reass queues */ 119402062e8SMike Silbersack static int maxnipq; 120690a6055SJesper Skriver SYSCTL_INT(_net_inet_ip, OID_AUTO, maxfragpackets, CTLFLAG_RW, 121402062e8SMike Silbersack &maxnipq, 0, 122690a6055SJesper Skriver "Maximum number of IPv4 fragment reassembly queue entries"); 123690a6055SJesper Skriver 124375386e2SMike Silbersack static int maxfragsperpacket; 125375386e2SMike Silbersack SYSCTL_INT(_net_inet_ip, OID_AUTO, maxfragsperpacket, CTLFLAG_RW, 126375386e2SMike Silbersack &maxfragsperpacket, 0, 127375386e2SMike Silbersack "Maximum number of IPv4 fragments allowed per packet"); 128375386e2SMike Silbersack 129df285b3dSMike Silbersack static int ip_sendsourcequench = 0; 130df285b3dSMike Silbersack SYSCTL_INT(_net_inet_ip, OID_AUTO, sendsourcequench, CTLFLAG_RW, 131df285b3dSMike Silbersack &ip_sendsourcequench, 0, 132df285b3dSMike Silbersack "Enable the transmission of source quench packets"); 133df285b3dSMike Silbersack 1341f44b0a1SDavid Malone int ip_do_randomid = 0; 1351f44b0a1SDavid Malone SYSCTL_INT(_net_inet_ip, OID_AUTO, random_id, CTLFLAG_RW, 1361f44b0a1SDavid Malone &ip_do_randomid, 0, 1371f44b0a1SDavid Malone "Assign random ip_id values"); 1381f44b0a1SDavid Malone 139823db0e9SDon Lewis /* 140823db0e9SDon Lewis * XXX - Setting ip_checkinterface mostly implements the receive side of 141823db0e9SDon Lewis * the Strong ES model described in RFC 1122, but since the routing table 142a8f12100SDon Lewis * and transmit implementation do not implement the Strong ES model, 143823db0e9SDon Lewis * setting this to 1 results in an odd hybrid. 1443f67c834SDon Lewis * 145a8f12100SDon Lewis * XXX - ip_checkinterface currently must be disabled if you use ipnat 146a8f12100SDon Lewis * to translate the destination address to another local interface. 1473f67c834SDon Lewis * 1483f67c834SDon Lewis * XXX - ip_checkinterface must be disabled if you add IP aliases 1493f67c834SDon Lewis * to the loopback interface instead of the interface where the 1503f67c834SDon Lewis * packets for those addresses are received. 151823db0e9SDon Lewis */ 1524bc37f98SMaxim Konovalov static int ip_checkinterface = 0; 153b3e95d4eSJonathan Lemon SYSCTL_INT(_net_inet_ip, OID_AUTO, check_interface, CTLFLAG_RW, 154b3e95d4eSJonathan Lemon &ip_checkinterface, 0, "Verify packet arrives on correct interface"); 155b3e95d4eSJonathan Lemon 156df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1570312fbe9SPoul-Henning Kamp static int ipprintfs = 0; 158df8bae1dSRodney W. Grimes #endif 159c21fd232SAndre Oppermann 160c21fd232SAndre Oppermann struct pfil_head inet_pfil_hook; /* Packet filter hooks */ 161df8bae1dSRodney W. Grimes 1621cafed39SJonathan Lemon static struct ifqueue ipintrq; 163ca925d9cSJonathan Lemon static int ipqmaxlen = IFQ_MAXLEN; 164ca925d9cSJonathan Lemon 165df8bae1dSRodney W. Grimes extern struct domain inetdomain; 166f0ffb944SJulian Elischer extern struct protosw inetsw[]; 167df8bae1dSRodney W. Grimes u_char ip_protox[IPPROTO_MAX]; 16859562606SGarrett Wollman struct in_ifaddrhead in_ifaddrhead; /* first inet address */ 169ca925d9cSJonathan Lemon struct in_ifaddrhashhead *in_ifaddrhashtbl; /* inet addr hash table */ 170ca925d9cSJonathan Lemon u_long in_ifaddrhmask; /* mask for hash table */ 171ca925d9cSJonathan Lemon 172afed1375SDavid Greenman SYSCTL_INT(_net_inet_ip, IPCTL_INTRQMAXLEN, intr_queue_maxlen, CTLFLAG_RW, 1733d177f46SBill Fumerola &ipintrq.ifq_maxlen, 0, "Maximum size of the IP input queue"); 1740312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_INTRQDROPS, intr_queue_drops, CTLFLAG_RD, 1753d177f46SBill Fumerola &ipintrq.ifq_drops, 0, "Number of packets dropped from the IP input queue"); 176df8bae1dSRodney W. Grimes 177f23b4c91SGarrett Wollman struct ipstat ipstat; 178c73d99b5SRuslan Ermilov SYSCTL_STRUCT(_net_inet_ip, IPCTL_STATS, stats, CTLFLAG_RW, 1793d177f46SBill Fumerola &ipstat, ipstat, "IP statistics (struct ipstat, netinet/ip_var.h)"); 180194a213eSAndrey A. Chernov 181194a213eSAndrey A. Chernov /* Packet reassembly stuff */ 182194a213eSAndrey A. Chernov #define IPREASS_NHASH_LOG2 6 183194a213eSAndrey A. Chernov #define IPREASS_NHASH (1 << IPREASS_NHASH_LOG2) 184194a213eSAndrey A. Chernov #define IPREASS_HMASK (IPREASS_NHASH - 1) 185194a213eSAndrey A. Chernov #define IPREASS_HASH(x,y) \ 186831a80b0SMatthew Dillon (((((x) & 0xF) | ((((x) >> 8) & 0xF) << 4)) ^ (y)) & IPREASS_HMASK) 187194a213eSAndrey A. Chernov 188462b86feSPoul-Henning Kamp static TAILQ_HEAD(ipqhead, ipq) ipq[IPREASS_NHASH]; 1892fad1e93SSam Leffler struct mtx ipqlock; 1905f311da2SMike Silbersack struct callout ipport_tick_callout; 1912fad1e93SSam Leffler 1922fad1e93SSam Leffler #define IPQ_LOCK() mtx_lock(&ipqlock) 1932fad1e93SSam Leffler #define IPQ_UNLOCK() mtx_unlock(&ipqlock) 194888c2a3cSSam Leffler #define IPQ_LOCK_INIT() mtx_init(&ipqlock, "ipqlock", NULL, MTX_DEF) 195888c2a3cSSam Leffler #define IPQ_LOCK_ASSERT() mtx_assert(&ipqlock, MA_OWNED) 196f23b4c91SGarrett Wollman 1970312fbe9SPoul-Henning Kamp #ifdef IPCTL_DEFMTU 1980312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_DEFMTU, mtu, CTLFLAG_RW, 1993d177f46SBill Fumerola &ip_mtu, 0, "Default MTU"); 2000312fbe9SPoul-Henning Kamp #endif 2010312fbe9SPoul-Henning Kamp 2021b968362SDag-Erling Smørgrav #ifdef IPSTEALTH 203c76ff708SAndre Oppermann int ipstealth = 0; 2041b968362SDag-Erling Smørgrav SYSCTL_INT(_net_inet_ip, OID_AUTO, stealth, CTLFLAG_RW, 2051b968362SDag-Erling Smørgrav &ipstealth, 0, ""); 2061b968362SDag-Erling Smørgrav #endif 2071b968362SDag-Erling Smørgrav 2089b932e9eSAndre Oppermann /* 2099b932e9eSAndre Oppermann * ipfw_ether and ipfw_bridge hooks. 2109b932e9eSAndre Oppermann * XXX: Temporary until those are converted to pfil_hooks as well. 2119b932e9eSAndre Oppermann */ 2129b932e9eSAndre Oppermann ip_fw_chk_t *ip_fw_chk_ptr = NULL; 2139b932e9eSAndre Oppermann ip_dn_io_t *ip_dn_io_ptr = NULL; 214e4c97effSAndre Oppermann int fw_enable = 1; 21597850a5dSLuigi Rizzo int fw_one_pass = 1; 216e7319babSPoul-Henning Kamp 217929b31ddSSam Leffler /* 218e0982661SAndre Oppermann * XXX this is ugly. IP options source routing magic. 219df8bae1dSRodney W. Grimes */ 220e0982661SAndre Oppermann struct ipoptrt { 221df8bae1dSRodney W. Grimes struct in_addr dst; /* final destination */ 222df8bae1dSRodney W. Grimes char nop; /* one NOP to align */ 223df8bae1dSRodney W. Grimes char srcopt[IPOPT_OFFSET + 1]; /* OPTVAL, OLEN and OFFSET */ 224df8bae1dSRodney W. Grimes struct in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)]; 225e0982661SAndre Oppermann }; 226df8bae1dSRodney W. Grimes 227e0982661SAndre Oppermann struct ipopt_tag { 228e0982661SAndre Oppermann struct m_tag tag; 229e0982661SAndre Oppermann int ip_nhops; 230e0982661SAndre Oppermann struct ipoptrt ip_srcrt; 231e0982661SAndre Oppermann }; 232e0982661SAndre Oppermann 233e0982661SAndre Oppermann static void save_rte(struct mbuf *, u_char *, struct in_addr); 2349b932e9eSAndre Oppermann static int ip_dooptions(struct mbuf *m, int); 2359b932e9eSAndre Oppermann static void ip_forward(struct mbuf *m, int srcrt); 2364d77a549SAlfred Perlstein static void ip_freef(struct ipqhead *, struct ipq *); 2378948e4baSArchie Cobbs 238df8bae1dSRodney W. Grimes /* 239df8bae1dSRodney W. Grimes * IP initialization: fill in IP protocol switch table. 240df8bae1dSRodney W. Grimes * All protocols not implemented in kernel go to raw IP protocol handler. 241df8bae1dSRodney W. Grimes */ 242df8bae1dSRodney W. Grimes void 243df8bae1dSRodney W. Grimes ip_init() 244df8bae1dSRodney W. Grimes { 245f0ffb944SJulian Elischer register struct protosw *pr; 246df8bae1dSRodney W. Grimes register int i; 247df8bae1dSRodney W. Grimes 24859562606SGarrett Wollman TAILQ_INIT(&in_ifaddrhead); 249ca925d9cSJonathan Lemon in_ifaddrhashtbl = hashinit(INADDR_NHASH, M_IFADDR, &in_ifaddrhmask); 250f0ffb944SJulian Elischer pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW); 251df8bae1dSRodney W. Grimes if (pr == 0) 252db09bef3SAndre Oppermann panic("ip_init: PF_INET not found"); 253db09bef3SAndre Oppermann 254db09bef3SAndre Oppermann /* Initialize the entire ip_protox[] array to IPPROTO_RAW. */ 255df8bae1dSRodney W. Grimes for (i = 0; i < IPPROTO_MAX; i++) 256df8bae1dSRodney W. Grimes ip_protox[i] = pr - inetsw; 257db09bef3SAndre Oppermann /* 258db09bef3SAndre Oppermann * Cycle through IP protocols and put them into the appropriate place 259db09bef3SAndre Oppermann * in ip_protox[]. 260db09bef3SAndre Oppermann */ 261f0ffb944SJulian Elischer for (pr = inetdomain.dom_protosw; 262f0ffb944SJulian Elischer pr < inetdomain.dom_protoswNPROTOSW; pr++) 263df8bae1dSRodney W. Grimes if (pr->pr_domain->dom_family == PF_INET && 264db09bef3SAndre Oppermann pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) { 265db09bef3SAndre Oppermann /* Be careful to only index valid IP protocols. */ 266de38924dSAndre Oppermann if (pr->pr_protocol <= IPPROTO_MAX) 267df8bae1dSRodney W. Grimes ip_protox[pr->pr_protocol] = pr - inetsw; 268db09bef3SAndre Oppermann } 269194a213eSAndrey A. Chernov 270c21fd232SAndre Oppermann /* Initialize packet filter hooks. */ 271134ea224SSam Leffler inet_pfil_hook.ph_type = PFIL_TYPE_AF; 272134ea224SSam Leffler inet_pfil_hook.ph_af = AF_INET; 273134ea224SSam Leffler if ((i = pfil_head_register(&inet_pfil_hook)) != 0) 274134ea224SSam Leffler printf("%s: WARNING: unable to register pfil hook, " 275134ea224SSam Leffler "error %d\n", __func__, i); 276134ea224SSam Leffler 277db09bef3SAndre Oppermann /* Initialize IP reassembly queue. */ 2782fad1e93SSam Leffler IPQ_LOCK_INIT(); 279194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) 280462b86feSPoul-Henning Kamp TAILQ_INIT(&ipq[i]); 281375386e2SMike Silbersack maxnipq = nmbclusters / 32; 282375386e2SMike Silbersack maxfragsperpacket = 16; 283194a213eSAndrey A. Chernov 2845f311da2SMike Silbersack /* Start ipport_tick. */ 2855f311da2SMike Silbersack callout_init(&ipport_tick_callout, CALLOUT_MPSAFE); 2865f311da2SMike Silbersack ipport_tick(NULL); 2875f311da2SMike Silbersack EVENTHANDLER_REGISTER(shutdown_pre_sync, ip_fini, NULL, 2885f311da2SMike Silbersack SHUTDOWN_PRI_DEFAULT); 2895f311da2SMike Silbersack 290db09bef3SAndre Oppermann /* Initialize various other remaining things. */ 291227ee8a1SPoul-Henning Kamp ip_id = time_second & 0xffff; 292df8bae1dSRodney W. Grimes ipintrq.ifq_maxlen = ipqmaxlen; 2936008862bSJohn Baldwin mtx_init(&ipintrq.ifq_mtx, "ip_inq", NULL, MTX_DEF); 2947902224cSSam Leffler netisr_register(NETISR_IP, ip_input, &ipintrq, NETISR_MPSAFE); 295df8bae1dSRodney W. Grimes } 296df8bae1dSRodney W. Grimes 2975f311da2SMike Silbersack void ip_fini(xtp) 2985f311da2SMike Silbersack void *xtp; 2995f311da2SMike Silbersack { 3005f311da2SMike Silbersack callout_stop(&ipport_tick_callout); 3015f311da2SMike Silbersack } 3025f311da2SMike Silbersack 3034d2e3692SLuigi Rizzo /* 304df8bae1dSRodney W. Grimes * Ip input routine. Checksum and byte swap header. If fragmented 305df8bae1dSRodney W. Grimes * try to reassemble. Process options. Pass to next level. 306df8bae1dSRodney W. Grimes */ 307c67b1d17SGarrett Wollman void 308c67b1d17SGarrett Wollman ip_input(struct mbuf *m) 309df8bae1dSRodney W. Grimes { 3109188b4a1SAndre Oppermann struct ip *ip = NULL; 3115da9f8faSJosef Karthauser struct in_ifaddr *ia = NULL; 312ca925d9cSJonathan Lemon struct ifaddr *ifa; 3139b932e9eSAndre Oppermann int checkif, hlen = 0; 31447c861ecSBrian Somers u_short sum; 31502c1c707SAndre Oppermann int dchg = 0; /* dest changed after fw */ 316f51f805fSSam Leffler struct in_addr odst; /* original dst address */ 317b9234fafSSam Leffler #ifdef FAST_IPSEC 31836e8826fSMax Laier struct m_tag *mtag; 319b9234fafSSam Leffler struct tdb_ident *tdbi; 320b9234fafSSam Leffler struct secpolicy *sp; 321b9234fafSSam Leffler int s, error; 322b9234fafSSam Leffler #endif /* FAST_IPSEC */ 323b715f178SLuigi Rizzo 324fe584538SDag-Erling Smørgrav M_ASSERTPKTHDR(m); 325db40007dSAndrew R. Reiter 326ac9d7e26SMax Laier if (m->m_flags & M_FASTFWD_OURS) { 3279b932e9eSAndre Oppermann /* 32876ff6dcfSAndre Oppermann * Firewall or NAT changed destination to local. 32976ff6dcfSAndre Oppermann * We expect ip_len and ip_off to be in host byte order. 3309b932e9eSAndre Oppermann */ 33176ff6dcfSAndre Oppermann m->m_flags &= ~M_FASTFWD_OURS; 33276ff6dcfSAndre Oppermann /* Set up some basics that will be used later. */ 3332b25acc1SLuigi Rizzo ip = mtod(m, struct ip *); 33453be11f6SPoul-Henning Kamp hlen = ip->ip_hl << 2; 3359b932e9eSAndre Oppermann goto ours; 3362b25acc1SLuigi Rizzo } 3372b25acc1SLuigi Rizzo 338df8bae1dSRodney W. Grimes ipstat.ips_total++; 33958938916SGarrett Wollman 34058938916SGarrett Wollman if (m->m_pkthdr.len < sizeof(struct ip)) 34158938916SGarrett Wollman goto tooshort; 34258938916SGarrett Wollman 343df8bae1dSRodney W. Grimes if (m->m_len < sizeof (struct ip) && 3440b17fba7SAndre Oppermann (m = m_pullup(m, sizeof (struct ip))) == NULL) { 345df8bae1dSRodney W. Grimes ipstat.ips_toosmall++; 346c67b1d17SGarrett Wollman return; 347df8bae1dSRodney W. Grimes } 348df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 34958938916SGarrett Wollman 35053be11f6SPoul-Henning Kamp if (ip->ip_v != IPVERSION) { 351df8bae1dSRodney W. Grimes ipstat.ips_badvers++; 352df8bae1dSRodney W. Grimes goto bad; 353df8bae1dSRodney W. Grimes } 35458938916SGarrett Wollman 35553be11f6SPoul-Henning Kamp hlen = ip->ip_hl << 2; 356df8bae1dSRodney W. Grimes if (hlen < sizeof(struct ip)) { /* minimum header length */ 357df8bae1dSRodney W. Grimes ipstat.ips_badhlen++; 358df8bae1dSRodney W. Grimes goto bad; 359df8bae1dSRodney W. Grimes } 360df8bae1dSRodney W. Grimes if (hlen > m->m_len) { 3610b17fba7SAndre Oppermann if ((m = m_pullup(m, hlen)) == NULL) { 362df8bae1dSRodney W. Grimes ipstat.ips_badhlen++; 363c67b1d17SGarrett Wollman return; 364df8bae1dSRodney W. Grimes } 365df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 366df8bae1dSRodney W. Grimes } 36733841545SHajimu UMEMOTO 36833841545SHajimu UMEMOTO /* 127/8 must not appear on wire - RFC1122 */ 36933841545SHajimu UMEMOTO if ((ntohl(ip->ip_dst.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET || 37033841545SHajimu UMEMOTO (ntohl(ip->ip_src.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) { 37133841545SHajimu UMEMOTO if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) { 37233841545SHajimu UMEMOTO ipstat.ips_badaddr++; 37333841545SHajimu UMEMOTO goto bad; 37433841545SHajimu UMEMOTO } 37533841545SHajimu UMEMOTO } 37633841545SHajimu UMEMOTO 377db4f9cc7SJonathan Lemon if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) { 378db4f9cc7SJonathan Lemon sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID); 379db4f9cc7SJonathan Lemon } else { 38058938916SGarrett Wollman if (hlen == sizeof(struct ip)) { 38147c861ecSBrian Somers sum = in_cksum_hdr(ip); 38258938916SGarrett Wollman } else { 38347c861ecSBrian Somers sum = in_cksum(m, hlen); 38458938916SGarrett Wollman } 385db4f9cc7SJonathan Lemon } 38647c861ecSBrian Somers if (sum) { 387df8bae1dSRodney W. Grimes ipstat.ips_badsum++; 388df8bae1dSRodney W. Grimes goto bad; 389df8bae1dSRodney W. Grimes } 390df8bae1dSRodney W. Grimes 39102b199f1SMax Laier #ifdef ALTQ 39202b199f1SMax Laier if (altq_input != NULL && (*altq_input)(m, AF_INET) == 0) 39302b199f1SMax Laier /* packet is dropped by traffic conditioner */ 39402b199f1SMax Laier return; 39502b199f1SMax Laier #endif 39602b199f1SMax Laier 397df8bae1dSRodney W. Grimes /* 398df8bae1dSRodney W. Grimes * Convert fields to host representation. 399df8bae1dSRodney W. Grimes */ 400fd8e4ebcSMike Barcroft ip->ip_len = ntohs(ip->ip_len); 401df8bae1dSRodney W. Grimes if (ip->ip_len < hlen) { 402df8bae1dSRodney W. Grimes ipstat.ips_badlen++; 403df8bae1dSRodney W. Grimes goto bad; 404df8bae1dSRodney W. Grimes } 405fd8e4ebcSMike Barcroft ip->ip_off = ntohs(ip->ip_off); 406df8bae1dSRodney W. Grimes 407df8bae1dSRodney W. Grimes /* 408df8bae1dSRodney W. Grimes * Check that the amount of data in the buffers 409df8bae1dSRodney W. Grimes * is as at least much as the IP header would have us expect. 410df8bae1dSRodney W. Grimes * Trim mbufs if longer than we expect. 411df8bae1dSRodney W. Grimes * Drop packet if shorter than we expect. 412df8bae1dSRodney W. Grimes */ 413df8bae1dSRodney W. Grimes if (m->m_pkthdr.len < ip->ip_len) { 41458938916SGarrett Wollman tooshort: 415df8bae1dSRodney W. Grimes ipstat.ips_tooshort++; 416df8bae1dSRodney W. Grimes goto bad; 417df8bae1dSRodney W. Grimes } 418df8bae1dSRodney W. Grimes if (m->m_pkthdr.len > ip->ip_len) { 419df8bae1dSRodney W. Grimes if (m->m_len == m->m_pkthdr.len) { 420df8bae1dSRodney W. Grimes m->m_len = ip->ip_len; 421df8bae1dSRodney W. Grimes m->m_pkthdr.len = ip->ip_len; 422df8bae1dSRodney W. Grimes } else 423df8bae1dSRodney W. Grimes m_adj(m, ip->ip_len - m->m_pkthdr.len); 424df8bae1dSRodney W. Grimes } 42514dd6717SSam Leffler #if defined(IPSEC) && !defined(IPSEC_FILTERGIF) 42614dd6717SSam Leffler /* 42714dd6717SSam Leffler * Bypass packet filtering for packets from a tunnel (gif). 42814dd6717SSam Leffler */ 4290f9ade71SHajimu UMEMOTO if (ipsec_getnhist(m)) 430c21fd232SAndre Oppermann goto passin; 43114dd6717SSam Leffler #endif 4321f76a5e2SSam Leffler #if defined(FAST_IPSEC) && !defined(IPSEC_FILTERGIF) 4331f76a5e2SSam Leffler /* 4341f76a5e2SSam Leffler * Bypass packet filtering for packets from a tunnel (gif). 4351f76a5e2SSam Leffler */ 4361f76a5e2SSam Leffler if (m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL) != NULL) 437c21fd232SAndre Oppermann goto passin; 4381f76a5e2SSam Leffler #endif 4393f67c834SDon Lewis 440c4ac87eaSDarren Reed /* 441134ea224SSam Leffler * Run through list of hooks for input packets. 442f51f805fSSam Leffler * 443f51f805fSSam Leffler * NB: Beware of the destination address changing (e.g. 444f51f805fSSam Leffler * by NAT rewriting). When this happens, tell 445f51f805fSSam Leffler * ip_forward to do the right thing. 446c4ac87eaSDarren Reed */ 447c21fd232SAndre Oppermann 448c21fd232SAndre Oppermann /* Jump over all PFIL processing if hooks are not active. */ 449c21fd232SAndre Oppermann if (inet_pfil_hook.ph_busy_count == -1) 450c21fd232SAndre Oppermann goto passin; 451c21fd232SAndre Oppermann 452f51f805fSSam Leffler odst = ip->ip_dst; 453134ea224SSam Leffler if (pfil_run_hooks(&inet_pfil_hook, &m, m->m_pkthdr.rcvif, 454d6a8d588SMax Laier PFIL_IN, NULL) != 0) 455beec8214SDarren Reed return; 456134ea224SSam Leffler if (m == NULL) /* consumed by filter */ 457c4ac87eaSDarren Reed return; 4589b932e9eSAndre Oppermann 459c4ac87eaSDarren Reed ip = mtod(m, struct ip *); 46002c1c707SAndre Oppermann dchg = (odst.s_addr != ip->ip_dst.s_addr); 4619b932e9eSAndre Oppermann 4629b932e9eSAndre Oppermann #ifdef IPFIREWALL_FORWARD 4639b932e9eSAndre Oppermann if (m->m_flags & M_FASTFWD_OURS) { 4649b932e9eSAndre Oppermann m->m_flags &= ~M_FASTFWD_OURS; 4659b932e9eSAndre Oppermann goto ours; 4669b932e9eSAndre Oppermann } 4679b932e9eSAndre Oppermann dchg = (m_tag_find(m, PACKET_TAG_IPFORWARD, NULL) != NULL); 4689b932e9eSAndre Oppermann #endif /* IPFIREWALL_FORWARD */ 4699b932e9eSAndre Oppermann 470c21fd232SAndre Oppermann passin: 471df8bae1dSRodney W. Grimes /* 472df8bae1dSRodney W. Grimes * Process options and, if not destined for us, 473df8bae1dSRodney W. Grimes * ship it on. ip_dooptions returns 1 when an 474df8bae1dSRodney W. Grimes * error was detected (causing an icmp message 475df8bae1dSRodney W. Grimes * to be sent and the original packet to be freed). 476df8bae1dSRodney W. Grimes */ 4779b932e9eSAndre Oppermann if (hlen > sizeof (struct ip) && ip_dooptions(m, 0)) 478c67b1d17SGarrett Wollman return; 479df8bae1dSRodney W. Grimes 480f0068c4aSGarrett Wollman /* greedy RSVP, snatches any PATH packet of the RSVP protocol and no 481f0068c4aSGarrett Wollman * matter if it is destined to another node, or whether it is 482f0068c4aSGarrett Wollman * a multicast one, RSVP wants it! and prevents it from being forwarded 483f0068c4aSGarrett Wollman * anywhere else. Also checks if the rsvp daemon is running before 484f0068c4aSGarrett Wollman * grabbing the packet. 485f0068c4aSGarrett Wollman */ 4861c5de19aSGarrett Wollman if (rsvp_on && ip->ip_p==IPPROTO_RSVP) 487f0068c4aSGarrett Wollman goto ours; 488f0068c4aSGarrett Wollman 489df8bae1dSRodney W. Grimes /* 490df8bae1dSRodney W. Grimes * Check our list of addresses, to see if the packet is for us. 491cc766e04SGarrett Wollman * If we don't have any addresses, assume any unicast packet 492cc766e04SGarrett Wollman * we receive might be for us (and let the upper layers deal 493cc766e04SGarrett Wollman * with it). 494df8bae1dSRodney W. Grimes */ 495cc766e04SGarrett Wollman if (TAILQ_EMPTY(&in_ifaddrhead) && 496cc766e04SGarrett Wollman (m->m_flags & (M_MCAST|M_BCAST)) == 0) 497cc766e04SGarrett Wollman goto ours; 498cc766e04SGarrett Wollman 4997538a9a0SJonathan Lemon /* 500823db0e9SDon Lewis * Enable a consistency check between the destination address 501823db0e9SDon Lewis * and the arrival interface for a unicast packet (the RFC 1122 502823db0e9SDon Lewis * strong ES model) if IP forwarding is disabled and the packet 503e15ae1b2SDon Lewis * is not locally generated and the packet is not subject to 504e15ae1b2SDon Lewis * 'ipfw fwd'. 5053f67c834SDon Lewis * 5063f67c834SDon Lewis * XXX - Checking also should be disabled if the destination 5073f67c834SDon Lewis * address is ipnat'ed to a different interface. 5083f67c834SDon Lewis * 509a8f12100SDon Lewis * XXX - Checking is incompatible with IP aliases added 5103f67c834SDon Lewis * to the loopback interface instead of the interface where 5113f67c834SDon Lewis * the packets are received. 512823db0e9SDon Lewis */ 513823db0e9SDon Lewis checkif = ip_checkinterface && (ipforwarding == 0) && 5149494d596SBrooks Davis m->m_pkthdr.rcvif != NULL && 515e15ae1b2SDon Lewis ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) && 5169b932e9eSAndre Oppermann (dchg == 0); 517823db0e9SDon Lewis 518ca925d9cSJonathan Lemon /* 519ca925d9cSJonathan Lemon * Check for exact addresses in the hash bucket. 520ca925d9cSJonathan Lemon */ 5219b932e9eSAndre Oppermann LIST_FOREACH(ia, INADDR_HASH(ip->ip_dst.s_addr), ia_hash) { 522f9e354dfSJulian Elischer /* 523823db0e9SDon Lewis * If the address matches, verify that the packet 524823db0e9SDon Lewis * arrived via the correct interface if checking is 525823db0e9SDon Lewis * enabled. 526f9e354dfSJulian Elischer */ 5279b932e9eSAndre Oppermann if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr && 528823db0e9SDon Lewis (!checkif || ia->ia_ifp == m->m_pkthdr.rcvif)) 529ed1ff184SJulian Elischer goto ours; 530ca925d9cSJonathan Lemon } 531823db0e9SDon Lewis /* 532ca925d9cSJonathan Lemon * Check for broadcast addresses. 533ca925d9cSJonathan Lemon * 534ca925d9cSJonathan Lemon * Only accept broadcast packets that arrive via the matching 535ca925d9cSJonathan Lemon * interface. Reception of forwarded directed broadcasts would 536ca925d9cSJonathan Lemon * be handled via ip_forward() and ether_output() with the loopback 537ca925d9cSJonathan Lemon * into the stack for SIMPLEX interfaces handled by ether_output(). 538823db0e9SDon Lewis */ 5394f450ff9SBruce M Simpson if (m->m_pkthdr.rcvif != NULL && 5404f450ff9SBruce M Simpson m->m_pkthdr.rcvif->if_flags & IFF_BROADCAST) { 541ca925d9cSJonathan Lemon TAILQ_FOREACH(ifa, &m->m_pkthdr.rcvif->if_addrhead, ifa_link) { 542ca925d9cSJonathan Lemon if (ifa->ifa_addr->sa_family != AF_INET) 543ca925d9cSJonathan Lemon continue; 544ca925d9cSJonathan Lemon ia = ifatoia(ifa); 545df8bae1dSRodney W. Grimes if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == 5469b932e9eSAndre Oppermann ip->ip_dst.s_addr) 547df8bae1dSRodney W. Grimes goto ours; 5489b932e9eSAndre Oppermann if (ia->ia_netbroadcast.s_addr == ip->ip_dst.s_addr) 549df8bae1dSRodney W. Grimes goto ours; 5500ac40133SBrian Somers #ifdef BOOTP_COMPAT 551ca925d9cSJonathan Lemon if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY) 552ca925d9cSJonathan Lemon goto ours; 5530ac40133SBrian Somers #endif 554df8bae1dSRodney W. Grimes } 555df8bae1dSRodney W. Grimes } 556df8bae1dSRodney W. Grimes if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { 557df8bae1dSRodney W. Grimes struct in_multi *inm; 558df8bae1dSRodney W. Grimes if (ip_mrouter) { 559df8bae1dSRodney W. Grimes /* 560df8bae1dSRodney W. Grimes * If we are acting as a multicast router, all 561df8bae1dSRodney W. Grimes * incoming multicast packets are passed to the 562df8bae1dSRodney W. Grimes * kernel-level multicast forwarding function. 563df8bae1dSRodney W. Grimes * The packet is returned (relatively) intact; if 564df8bae1dSRodney W. Grimes * ip_mforward() returns a non-zero value, the packet 565df8bae1dSRodney W. Grimes * must be discarded, else it may be accepted below. 566df8bae1dSRodney W. Grimes */ 567bbb4330bSLuigi Rizzo if (ip_mforward && 568bbb4330bSLuigi Rizzo ip_mforward(ip, m->m_pkthdr.rcvif, m, 0) != 0) { 569df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 570df8bae1dSRodney W. Grimes m_freem(m); 571c67b1d17SGarrett Wollman return; 572df8bae1dSRodney W. Grimes } 573df8bae1dSRodney W. Grimes 574df8bae1dSRodney W. Grimes /* 57511612afaSDima Dorfman * The process-level routing daemon needs to receive 576df8bae1dSRodney W. Grimes * all multicast IGMP packets, whether or not this 577df8bae1dSRodney W. Grimes * host belongs to their destination groups. 578df8bae1dSRodney W. Grimes */ 579df8bae1dSRodney W. Grimes if (ip->ip_p == IPPROTO_IGMP) 580df8bae1dSRodney W. Grimes goto ours; 581df8bae1dSRodney W. Grimes ipstat.ips_forward++; 582df8bae1dSRodney W. Grimes } 583df8bae1dSRodney W. Grimes /* 584df8bae1dSRodney W. Grimes * See if we belong to the destination multicast group on the 585df8bae1dSRodney W. Grimes * arrival interface. 586df8bae1dSRodney W. Grimes */ 587df8bae1dSRodney W. Grimes IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm); 588df8bae1dSRodney W. Grimes if (inm == NULL) { 58982c39223SGarrett Wollman ipstat.ips_notmember++; 590df8bae1dSRodney W. Grimes m_freem(m); 591c67b1d17SGarrett Wollman return; 592df8bae1dSRodney W. Grimes } 593df8bae1dSRodney W. Grimes goto ours; 594df8bae1dSRodney W. Grimes } 595df8bae1dSRodney W. Grimes if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST) 596df8bae1dSRodney W. Grimes goto ours; 597df8bae1dSRodney W. Grimes if (ip->ip_dst.s_addr == INADDR_ANY) 598df8bae1dSRodney W. Grimes goto ours; 599df8bae1dSRodney W. Grimes 6006a800098SYoshinobu Inoue /* 6016a800098SYoshinobu Inoue * FAITH(Firewall Aided Internet Translator) 6026a800098SYoshinobu Inoue */ 6036a800098SYoshinobu Inoue if (m->m_pkthdr.rcvif && m->m_pkthdr.rcvif->if_type == IFT_FAITH) { 6046a800098SYoshinobu Inoue if (ip_keepfaith) { 6056a800098SYoshinobu Inoue if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_ICMP) 6066a800098SYoshinobu Inoue goto ours; 6076a800098SYoshinobu Inoue } 6086a800098SYoshinobu Inoue m_freem(m); 6096a800098SYoshinobu Inoue return; 6106a800098SYoshinobu Inoue } 6119494d596SBrooks Davis 612df8bae1dSRodney W. Grimes /* 613df8bae1dSRodney W. Grimes * Not for us; forward if possible and desirable. 614df8bae1dSRodney W. Grimes */ 615df8bae1dSRodney W. Grimes if (ipforwarding == 0) { 616df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 617df8bae1dSRodney W. Grimes m_freem(m); 618546f251bSChris D. Faulhaber } else { 619546f251bSChris D. Faulhaber #ifdef IPSEC 620546f251bSChris D. Faulhaber /* 621546f251bSChris D. Faulhaber * Enforce inbound IPsec SPD. 622546f251bSChris D. Faulhaber */ 623546f251bSChris D. Faulhaber if (ipsec4_in_reject(m, NULL)) { 624546f251bSChris D. Faulhaber ipsecstat.in_polvio++; 625546f251bSChris D. Faulhaber goto bad; 626546f251bSChris D. Faulhaber } 627546f251bSChris D. Faulhaber #endif /* IPSEC */ 628b9234fafSSam Leffler #ifdef FAST_IPSEC 629b9234fafSSam Leffler mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL); 630b9234fafSSam Leffler s = splnet(); 631b9234fafSSam Leffler if (mtag != NULL) { 632b9234fafSSam Leffler tdbi = (struct tdb_ident *)(mtag + 1); 633b9234fafSSam Leffler sp = ipsec_getpolicy(tdbi, IPSEC_DIR_INBOUND); 634b9234fafSSam Leffler } else { 635b9234fafSSam Leffler sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND, 636b9234fafSSam Leffler IP_FORWARDING, &error); 637b9234fafSSam Leffler } 638b9234fafSSam Leffler if (sp == NULL) { /* NB: can happen if error */ 639b9234fafSSam Leffler splx(s); 640b9234fafSSam Leffler /*XXX error stat???*/ 641b9234fafSSam Leffler DPRINTF(("ip_input: no SP for forwarding\n")); /*XXX*/ 642b9234fafSSam Leffler goto bad; 643b9234fafSSam Leffler } 644b9234fafSSam Leffler 645b9234fafSSam Leffler /* 646b9234fafSSam Leffler * Check security policy against packet attributes. 647b9234fafSSam Leffler */ 648b9234fafSSam Leffler error = ipsec_in_reject(sp, m); 649b9234fafSSam Leffler KEY_FREESP(&sp); 650b9234fafSSam Leffler splx(s); 651b9234fafSSam Leffler if (error) { 652b9234fafSSam Leffler ipstat.ips_cantforward++; 653b9234fafSSam Leffler goto bad; 654b9234fafSSam Leffler } 655b9234fafSSam Leffler #endif /* FAST_IPSEC */ 6569b932e9eSAndre Oppermann ip_forward(m, dchg); 657546f251bSChris D. Faulhaber } 658c67b1d17SGarrett Wollman return; 659df8bae1dSRodney W. Grimes 660df8bae1dSRodney W. Grimes ours: 661d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH 662d0ebc0d2SYaroslav Tykhiy /* 663d0ebc0d2SYaroslav Tykhiy * IPSTEALTH: Process non-routing options only 664d0ebc0d2SYaroslav Tykhiy * if the packet is destined for us. 665d0ebc0d2SYaroslav Tykhiy */ 6662b25acc1SLuigi Rizzo if (ipstealth && hlen > sizeof (struct ip) && 6679b932e9eSAndre Oppermann ip_dooptions(m, 1)) 668d0ebc0d2SYaroslav Tykhiy return; 669d0ebc0d2SYaroslav Tykhiy #endif /* IPSTEALTH */ 670d0ebc0d2SYaroslav Tykhiy 6715da9f8faSJosef Karthauser /* Count the packet in the ip address stats */ 6725da9f8faSJosef Karthauser if (ia != NULL) { 6735da9f8faSJosef Karthauser ia->ia_ifa.if_ipackets++; 6745da9f8faSJosef Karthauser ia->ia_ifa.if_ibytes += m->m_pkthdr.len; 6755da9f8faSJosef Karthauser } 676100ba1a6SJordan K. Hubbard 67763f8d699SJordan K. Hubbard /* 678b6ea1aa5SRuslan Ermilov * Attempt reassembly; if it succeeds, proceed. 679ac9d7e26SMax Laier * ip_reass() will return a different mbuf. 680df8bae1dSRodney W. Grimes */ 681f0cada84SAndre Oppermann if (ip->ip_off & (IP_MF | IP_OFFMASK)) { 682f0cada84SAndre Oppermann m = ip_reass(m); 683f0cada84SAndre Oppermann if (m == NULL) 684c67b1d17SGarrett Wollman return; 6856a800098SYoshinobu Inoue ip = mtod(m, struct ip *); 6867e2df452SRuslan Ermilov /* Get the header length of the reassembled packet */ 68753be11f6SPoul-Henning Kamp hlen = ip->ip_hl << 2; 688f0cada84SAndre Oppermann } 689f0cada84SAndre Oppermann 690f0cada84SAndre Oppermann /* 691f0cada84SAndre Oppermann * Further protocols expect the packet length to be w/o the 692f0cada84SAndre Oppermann * IP header. 693f0cada84SAndre Oppermann */ 694df8bae1dSRodney W. Grimes ip->ip_len -= hlen; 695df8bae1dSRodney W. Grimes 69633841545SHajimu UMEMOTO #ifdef IPSEC 69733841545SHajimu UMEMOTO /* 69833841545SHajimu UMEMOTO * enforce IPsec policy checking if we are seeing last header. 69933841545SHajimu UMEMOTO * note that we do not visit this with protocols with pcb layer 70033841545SHajimu UMEMOTO * code - like udp/tcp/raw ip. 70133841545SHajimu UMEMOTO */ 70233841545SHajimu UMEMOTO if ((inetsw[ip_protox[ip->ip_p]].pr_flags & PR_LASTHDR) != 0 && 70333841545SHajimu UMEMOTO ipsec4_in_reject(m, NULL)) { 70433841545SHajimu UMEMOTO ipsecstat.in_polvio++; 70533841545SHajimu UMEMOTO goto bad; 70633841545SHajimu UMEMOTO } 70733841545SHajimu UMEMOTO #endif 708b9234fafSSam Leffler #if FAST_IPSEC 709b9234fafSSam Leffler /* 710b9234fafSSam Leffler * enforce IPsec policy checking if we are seeing last header. 711b9234fafSSam Leffler * note that we do not visit this with protocols with pcb layer 712b9234fafSSam Leffler * code - like udp/tcp/raw ip. 713b9234fafSSam Leffler */ 714b9234fafSSam Leffler if ((inetsw[ip_protox[ip->ip_p]].pr_flags & PR_LASTHDR) != 0) { 715b9234fafSSam Leffler /* 716b9234fafSSam Leffler * Check if the packet has already had IPsec processing 717b9234fafSSam Leffler * done. If so, then just pass it along. This tag gets 718b9234fafSSam Leffler * set during AH, ESP, etc. input handling, before the 719b9234fafSSam Leffler * packet is returned to the ip input queue for delivery. 720b9234fafSSam Leffler */ 721b9234fafSSam Leffler mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL); 722b9234fafSSam Leffler s = splnet(); 723b9234fafSSam Leffler if (mtag != NULL) { 724b9234fafSSam Leffler tdbi = (struct tdb_ident *)(mtag + 1); 725b9234fafSSam Leffler sp = ipsec_getpolicy(tdbi, IPSEC_DIR_INBOUND); 726b9234fafSSam Leffler } else { 727b9234fafSSam Leffler sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND, 728b9234fafSSam Leffler IP_FORWARDING, &error); 729b9234fafSSam Leffler } 730b9234fafSSam Leffler if (sp != NULL) { 731b9234fafSSam Leffler /* 732b9234fafSSam Leffler * Check security policy against packet attributes. 733b9234fafSSam Leffler */ 734b9234fafSSam Leffler error = ipsec_in_reject(sp, m); 735b9234fafSSam Leffler KEY_FREESP(&sp); 736b9234fafSSam Leffler } else { 737b9234fafSSam Leffler /* XXX error stat??? */ 738b9234fafSSam Leffler error = EINVAL; 739b9234fafSSam Leffler DPRINTF(("ip_input: no SP, packet discarded\n"));/*XXX*/ 740b9234fafSSam Leffler goto bad; 741b9234fafSSam Leffler } 742b9234fafSSam Leffler splx(s); 743b9234fafSSam Leffler if (error) 744b9234fafSSam Leffler goto bad; 745b9234fafSSam Leffler } 746b9234fafSSam Leffler #endif /* FAST_IPSEC */ 74733841545SHajimu UMEMOTO 748df8bae1dSRodney W. Grimes /* 749df8bae1dSRodney W. Grimes * Switch out to protocol's input routine. 750df8bae1dSRodney W. Grimes */ 751df8bae1dSRodney W. Grimes ipstat.ips_delivered++; 7529b932e9eSAndre Oppermann 7532b25acc1SLuigi Rizzo (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen); 754c67b1d17SGarrett Wollman return; 755df8bae1dSRodney W. Grimes bad: 756df8bae1dSRodney W. Grimes m_freem(m); 757c67b1d17SGarrett Wollman } 758c67b1d17SGarrett Wollman 759c67b1d17SGarrett Wollman /* 7608948e4baSArchie Cobbs * Take incoming datagram fragment and try to reassemble it into 761f0cada84SAndre Oppermann * whole datagram. If the argument is the first fragment or one 762f0cada84SAndre Oppermann * in between the function will return NULL and store the mbuf 763f0cada84SAndre Oppermann * in the fragment chain. If the argument is the last fragment 764f0cada84SAndre Oppermann * the packet will be reassembled and the pointer to the new 765f0cada84SAndre Oppermann * mbuf returned for further processing. Only m_tags attached 766f0cada84SAndre Oppermann * to the first packet/fragment are preserved. 767f0cada84SAndre Oppermann * The IP header is *NOT* adjusted out of iplen. 768df8bae1dSRodney W. Grimes */ 7698948e4baSArchie Cobbs 770f0cada84SAndre Oppermann struct mbuf * 771f0cada84SAndre Oppermann ip_reass(struct mbuf *m) 772df8bae1dSRodney W. Grimes { 773f0cada84SAndre Oppermann struct ip *ip; 774f0cada84SAndre Oppermann struct mbuf *p, *q, *nq, *t; 775f0cada84SAndre Oppermann struct ipq *fp = NULL; 776f0cada84SAndre Oppermann struct ipqhead *head; 777f0cada84SAndre Oppermann int i, hlen, next; 77859dfcba4SHajimu UMEMOTO u_int8_t ecn, ecn0; 779f0cada84SAndre Oppermann u_short hash; 780df8bae1dSRodney W. Grimes 781f0cada84SAndre Oppermann /* If maxnipq is 0, never accept fragments. */ 782f0cada84SAndre Oppermann if (maxnipq == 0) { 783f0cada84SAndre Oppermann ipstat.ips_fragments++; 784f0cada84SAndre Oppermann ipstat.ips_fragdropped++; 7859d804f81SAndre Oppermann m_freem(m); 7869d804f81SAndre Oppermann return (NULL); 787f0cada84SAndre Oppermann } 7882fad1e93SSam Leffler 789f0cada84SAndre Oppermann ip = mtod(m, struct ip *); 790f0cada84SAndre Oppermann hlen = ip->ip_hl << 2; 791f0cada84SAndre Oppermann 792f0cada84SAndre Oppermann hash = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id); 793f0cada84SAndre Oppermann head = &ipq[hash]; 794f0cada84SAndre Oppermann IPQ_LOCK(); 795f0cada84SAndre Oppermann 796f0cada84SAndre Oppermann /* 797f0cada84SAndre Oppermann * Look for queue of fragments 798f0cada84SAndre Oppermann * of this datagram. 799f0cada84SAndre Oppermann */ 800f0cada84SAndre Oppermann TAILQ_FOREACH(fp, head, ipq_list) 801f0cada84SAndre Oppermann if (ip->ip_id == fp->ipq_id && 802f0cada84SAndre Oppermann ip->ip_src.s_addr == fp->ipq_src.s_addr && 803f0cada84SAndre Oppermann ip->ip_dst.s_addr == fp->ipq_dst.s_addr && 804f0cada84SAndre Oppermann #ifdef MAC 805f0cada84SAndre Oppermann mac_fragment_match(m, fp) && 806f0cada84SAndre Oppermann #endif 807f0cada84SAndre Oppermann ip->ip_p == fp->ipq_p) 808f0cada84SAndre Oppermann goto found; 809f0cada84SAndre Oppermann 810f0cada84SAndre Oppermann fp = NULL; 811f0cada84SAndre Oppermann 812f0cada84SAndre Oppermann /* 813f0cada84SAndre Oppermann * Enforce upper bound on number of fragmented packets 814f0cada84SAndre Oppermann * for which we attempt reassembly; 815f0cada84SAndre Oppermann * If maxnipq is -1, accept all fragments without limitation. 816f0cada84SAndre Oppermann */ 817f0cada84SAndre Oppermann if ((nipq > maxnipq) && (maxnipq > 0)) { 818f0cada84SAndre Oppermann /* 819f0cada84SAndre Oppermann * drop something from the tail of the current queue 820f0cada84SAndre Oppermann * before proceeding further 821f0cada84SAndre Oppermann */ 822f0cada84SAndre Oppermann struct ipq *q = TAILQ_LAST(head, ipqhead); 823f0cada84SAndre Oppermann if (q == NULL) { /* gak */ 824f0cada84SAndre Oppermann for (i = 0; i < IPREASS_NHASH; i++) { 825f0cada84SAndre Oppermann struct ipq *r = TAILQ_LAST(&ipq[i], ipqhead); 826f0cada84SAndre Oppermann if (r) { 827f0cada84SAndre Oppermann ipstat.ips_fragtimeout += r->ipq_nfrags; 828f0cada84SAndre Oppermann ip_freef(&ipq[i], r); 829f0cada84SAndre Oppermann break; 830f0cada84SAndre Oppermann } 831f0cada84SAndre Oppermann } 832f0cada84SAndre Oppermann } else { 833f0cada84SAndre Oppermann ipstat.ips_fragtimeout += q->ipq_nfrags; 834f0cada84SAndre Oppermann ip_freef(head, q); 835f0cada84SAndre Oppermann } 836f0cada84SAndre Oppermann } 837f0cada84SAndre Oppermann 838f0cada84SAndre Oppermann found: 839f0cada84SAndre Oppermann /* 840f0cada84SAndre Oppermann * Adjust ip_len to not reflect header, 841f0cada84SAndre Oppermann * convert offset of this to bytes. 842f0cada84SAndre Oppermann */ 843f0cada84SAndre Oppermann ip->ip_len -= hlen; 844f0cada84SAndre Oppermann if (ip->ip_off & IP_MF) { 845f0cada84SAndre Oppermann /* 846f0cada84SAndre Oppermann * Make sure that fragments have a data length 847f0cada84SAndre Oppermann * that's a non-zero multiple of 8 bytes. 848f0cada84SAndre Oppermann */ 849f0cada84SAndre Oppermann if (ip->ip_len == 0 || (ip->ip_len & 0x7) != 0) { 850f0cada84SAndre Oppermann ipstat.ips_toosmall++; /* XXX */ 851f0cada84SAndre Oppermann goto dropfrag; 852f0cada84SAndre Oppermann } 853f0cada84SAndre Oppermann m->m_flags |= M_FRAG; 854f0cada84SAndre Oppermann } else 855f0cada84SAndre Oppermann m->m_flags &= ~M_FRAG; 856f0cada84SAndre Oppermann ip->ip_off <<= 3; 857f0cada84SAndre Oppermann 858f0cada84SAndre Oppermann 859f0cada84SAndre Oppermann /* 860f0cada84SAndre Oppermann * Attempt reassembly; if it succeeds, proceed. 861f0cada84SAndre Oppermann * ip_reass() will return a different mbuf. 862f0cada84SAndre Oppermann */ 863f0cada84SAndre Oppermann ipstat.ips_fragments++; 864f0cada84SAndre Oppermann m->m_pkthdr.header = ip; 865f0cada84SAndre Oppermann 866f0cada84SAndre Oppermann /* Previous ip_reass() started here. */ 867df8bae1dSRodney W. Grimes /* 868df8bae1dSRodney W. Grimes * Presence of header sizes in mbufs 869df8bae1dSRodney W. Grimes * would confuse code below. 870df8bae1dSRodney W. Grimes */ 871df8bae1dSRodney W. Grimes m->m_data += hlen; 872df8bae1dSRodney W. Grimes m->m_len -= hlen; 873df8bae1dSRodney W. Grimes 874df8bae1dSRodney W. Grimes /* 875df8bae1dSRodney W. Grimes * If first fragment to arrive, create a reassembly queue. 876df8bae1dSRodney W. Grimes */ 877042bbfa3SRobert Watson if (fp == NULL) { 878a163d034SWarner Losh if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL) 879df8bae1dSRodney W. Grimes goto dropfrag; 880df8bae1dSRodney W. Grimes fp = mtod(t, struct ipq *); 88136b0360bSRobert Watson #ifdef MAC 8825e7ce478SRobert Watson if (mac_init_ipq(fp, M_NOWAIT) != 0) { 8835e7ce478SRobert Watson m_free(t); 8845e7ce478SRobert Watson goto dropfrag; 8855e7ce478SRobert Watson } 88636b0360bSRobert Watson mac_create_ipq(m, fp); 88736b0360bSRobert Watson #endif 888462b86feSPoul-Henning Kamp TAILQ_INSERT_HEAD(head, fp, ipq_list); 889194a213eSAndrey A. Chernov nipq++; 890375386e2SMike Silbersack fp->ipq_nfrags = 1; 891df8bae1dSRodney W. Grimes fp->ipq_ttl = IPFRAGTTL; 892df8bae1dSRodney W. Grimes fp->ipq_p = ip->ip_p; 893df8bae1dSRodney W. Grimes fp->ipq_id = ip->ip_id; 8946effc713SDoug Rabson fp->ipq_src = ip->ip_src; 8956effc713SDoug Rabson fp->ipq_dst = ip->ip_dst; 896af38c68cSLuigi Rizzo fp->ipq_frags = m; 897af38c68cSLuigi Rizzo m->m_nextpkt = NULL; 898af38c68cSLuigi Rizzo goto inserted; 89936b0360bSRobert Watson } else { 900375386e2SMike Silbersack fp->ipq_nfrags++; 90136b0360bSRobert Watson #ifdef MAC 90236b0360bSRobert Watson mac_update_ipq(m, fp); 90336b0360bSRobert Watson #endif 904df8bae1dSRodney W. Grimes } 905df8bae1dSRodney W. Grimes 9066effc713SDoug Rabson #define GETIP(m) ((struct ip*)((m)->m_pkthdr.header)) 9076effc713SDoug Rabson 908df8bae1dSRodney W. Grimes /* 90959dfcba4SHajimu UMEMOTO * Handle ECN by comparing this segment with the first one; 91059dfcba4SHajimu UMEMOTO * if CE is set, do not lose CE. 91159dfcba4SHajimu UMEMOTO * drop if CE and not-ECT are mixed for the same packet. 91259dfcba4SHajimu UMEMOTO */ 91359dfcba4SHajimu UMEMOTO ecn = ip->ip_tos & IPTOS_ECN_MASK; 91459dfcba4SHajimu UMEMOTO ecn0 = GETIP(fp->ipq_frags)->ip_tos & IPTOS_ECN_MASK; 91559dfcba4SHajimu UMEMOTO if (ecn == IPTOS_ECN_CE) { 91659dfcba4SHajimu UMEMOTO if (ecn0 == IPTOS_ECN_NOTECT) 91759dfcba4SHajimu UMEMOTO goto dropfrag; 91859dfcba4SHajimu UMEMOTO if (ecn0 != IPTOS_ECN_CE) 91959dfcba4SHajimu UMEMOTO GETIP(fp->ipq_frags)->ip_tos |= IPTOS_ECN_CE; 92059dfcba4SHajimu UMEMOTO } 92159dfcba4SHajimu UMEMOTO if (ecn == IPTOS_ECN_NOTECT && ecn0 != IPTOS_ECN_NOTECT) 92259dfcba4SHajimu UMEMOTO goto dropfrag; 92359dfcba4SHajimu UMEMOTO 92459dfcba4SHajimu UMEMOTO /* 925df8bae1dSRodney W. Grimes * Find a segment which begins after this one does. 926df8bae1dSRodney W. Grimes */ 9276effc713SDoug Rabson for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) 9286effc713SDoug Rabson if (GETIP(q)->ip_off > ip->ip_off) 929df8bae1dSRodney W. Grimes break; 930df8bae1dSRodney W. Grimes 931df8bae1dSRodney W. Grimes /* 932df8bae1dSRodney W. Grimes * If there is a preceding segment, it may provide some of 933df8bae1dSRodney W. Grimes * our data already. If so, drop the data from the incoming 934af38c68cSLuigi Rizzo * segment. If it provides all of our data, drop us, otherwise 935af38c68cSLuigi Rizzo * stick new segment in the proper place. 936db4f9cc7SJonathan Lemon * 937db4f9cc7SJonathan Lemon * If some of the data is dropped from the the preceding 938db4f9cc7SJonathan Lemon * segment, then it's checksum is invalidated. 939df8bae1dSRodney W. Grimes */ 9406effc713SDoug Rabson if (p) { 9416effc713SDoug Rabson i = GETIP(p)->ip_off + GETIP(p)->ip_len - ip->ip_off; 942df8bae1dSRodney W. Grimes if (i > 0) { 943df8bae1dSRodney W. Grimes if (i >= ip->ip_len) 944df8bae1dSRodney W. Grimes goto dropfrag; 9456a800098SYoshinobu Inoue m_adj(m, i); 946db4f9cc7SJonathan Lemon m->m_pkthdr.csum_flags = 0; 947df8bae1dSRodney W. Grimes ip->ip_off += i; 948df8bae1dSRodney W. Grimes ip->ip_len -= i; 949df8bae1dSRodney W. Grimes } 950af38c68cSLuigi Rizzo m->m_nextpkt = p->m_nextpkt; 951af38c68cSLuigi Rizzo p->m_nextpkt = m; 952af38c68cSLuigi Rizzo } else { 953af38c68cSLuigi Rizzo m->m_nextpkt = fp->ipq_frags; 954af38c68cSLuigi Rizzo fp->ipq_frags = m; 955df8bae1dSRodney W. Grimes } 956df8bae1dSRodney W. Grimes 957df8bae1dSRodney W. Grimes /* 958df8bae1dSRodney W. Grimes * While we overlap succeeding segments trim them or, 959df8bae1dSRodney W. Grimes * if they are completely covered, dequeue them. 960df8bae1dSRodney W. Grimes */ 9616effc713SDoug Rabson for (; q != NULL && ip->ip_off + ip->ip_len > GETIP(q)->ip_off; 962af38c68cSLuigi Rizzo q = nq) { 963b36f5b37SMaxim Konovalov i = (ip->ip_off + ip->ip_len) - GETIP(q)->ip_off; 9646effc713SDoug Rabson if (i < GETIP(q)->ip_len) { 9656effc713SDoug Rabson GETIP(q)->ip_len -= i; 9666effc713SDoug Rabson GETIP(q)->ip_off += i; 9676effc713SDoug Rabson m_adj(q, i); 968db4f9cc7SJonathan Lemon q->m_pkthdr.csum_flags = 0; 969df8bae1dSRodney W. Grimes break; 970df8bae1dSRodney W. Grimes } 9716effc713SDoug Rabson nq = q->m_nextpkt; 972af38c68cSLuigi Rizzo m->m_nextpkt = nq; 97399e8617dSMaxim Konovalov ipstat.ips_fragdropped++; 974375386e2SMike Silbersack fp->ipq_nfrags--; 9756effc713SDoug Rabson m_freem(q); 976df8bae1dSRodney W. Grimes } 977df8bae1dSRodney W. Grimes 978af38c68cSLuigi Rizzo inserted: 97993e0e116SJulian Elischer 980df8bae1dSRodney W. Grimes /* 981375386e2SMike Silbersack * Check for complete reassembly and perform frag per packet 982375386e2SMike Silbersack * limiting. 983375386e2SMike Silbersack * 984375386e2SMike Silbersack * Frag limiting is performed here so that the nth frag has 985375386e2SMike Silbersack * a chance to complete the packet before we drop the packet. 986375386e2SMike Silbersack * As a result, n+1 frags are actually allowed per packet, but 987375386e2SMike Silbersack * only n will ever be stored. (n = maxfragsperpacket.) 988375386e2SMike Silbersack * 989df8bae1dSRodney W. Grimes */ 9906effc713SDoug Rabson next = 0; 9916effc713SDoug Rabson for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) { 992375386e2SMike Silbersack if (GETIP(q)->ip_off != next) { 99399e8617dSMaxim Konovalov if (fp->ipq_nfrags > maxfragsperpacket) { 99499e8617dSMaxim Konovalov ipstat.ips_fragdropped += fp->ipq_nfrags; 995375386e2SMike Silbersack ip_freef(head, fp); 99699e8617dSMaxim Konovalov } 997f0cada84SAndre Oppermann goto done; 998375386e2SMike Silbersack } 9996effc713SDoug Rabson next += GETIP(q)->ip_len; 10006effc713SDoug Rabson } 10016effc713SDoug Rabson /* Make sure the last packet didn't have the IP_MF flag */ 1002375386e2SMike Silbersack if (p->m_flags & M_FRAG) { 100399e8617dSMaxim Konovalov if (fp->ipq_nfrags > maxfragsperpacket) { 100499e8617dSMaxim Konovalov ipstat.ips_fragdropped += fp->ipq_nfrags; 1005375386e2SMike Silbersack ip_freef(head, fp); 100699e8617dSMaxim Konovalov } 1007f0cada84SAndre Oppermann goto done; 1008375386e2SMike Silbersack } 1009df8bae1dSRodney W. Grimes 1010df8bae1dSRodney W. Grimes /* 1011430d30d8SBill Fenner * Reassembly is complete. Make sure the packet is a sane size. 1012430d30d8SBill Fenner */ 10136effc713SDoug Rabson q = fp->ipq_frags; 10146effc713SDoug Rabson ip = GETIP(q); 101553be11f6SPoul-Henning Kamp if (next + (ip->ip_hl << 2) > IP_MAXPACKET) { 1016430d30d8SBill Fenner ipstat.ips_toolong++; 101799e8617dSMaxim Konovalov ipstat.ips_fragdropped += fp->ipq_nfrags; 1018462b86feSPoul-Henning Kamp ip_freef(head, fp); 1019f0cada84SAndre Oppermann goto done; 1020430d30d8SBill Fenner } 1021430d30d8SBill Fenner 1022430d30d8SBill Fenner /* 1023430d30d8SBill Fenner * Concatenate fragments. 1024df8bae1dSRodney W. Grimes */ 10256effc713SDoug Rabson m = q; 1026df8bae1dSRodney W. Grimes t = m->m_next; 1027df8bae1dSRodney W. Grimes m->m_next = 0; 1028df8bae1dSRodney W. Grimes m_cat(m, t); 10296effc713SDoug Rabson nq = q->m_nextpkt; 1030945aa40dSDoug Rabson q->m_nextpkt = 0; 10316effc713SDoug Rabson for (q = nq; q != NULL; q = nq) { 10326effc713SDoug Rabson nq = q->m_nextpkt; 1033945aa40dSDoug Rabson q->m_nextpkt = NULL; 1034db4f9cc7SJonathan Lemon m->m_pkthdr.csum_flags &= q->m_pkthdr.csum_flags; 1035db4f9cc7SJonathan Lemon m->m_pkthdr.csum_data += q->m_pkthdr.csum_data; 1036a8db1d93SJonathan Lemon m_cat(m, q); 1037df8bae1dSRodney W. Grimes } 103836b0360bSRobert Watson #ifdef MAC 103936b0360bSRobert Watson mac_create_datagram_from_ipq(fp, m); 104036b0360bSRobert Watson mac_destroy_ipq(fp); 104136b0360bSRobert Watson #endif 1042df8bae1dSRodney W. Grimes 1043df8bae1dSRodney W. Grimes /* 1044f0cada84SAndre Oppermann * Create header for new ip packet by modifying header of first 1045f0cada84SAndre Oppermann * packet; dequeue and discard fragment reassembly header. 1046df8bae1dSRodney W. Grimes * Make header visible. 1047df8bae1dSRodney W. Grimes */ 1048f0cada84SAndre Oppermann ip->ip_len = (ip->ip_hl << 2) + next; 10496effc713SDoug Rabson ip->ip_src = fp->ipq_src; 10506effc713SDoug Rabson ip->ip_dst = fp->ipq_dst; 1051462b86feSPoul-Henning Kamp TAILQ_REMOVE(head, fp, ipq_list); 1052194a213eSAndrey A. Chernov nipq--; 1053df8bae1dSRodney W. Grimes (void) m_free(dtom(fp)); 105453be11f6SPoul-Henning Kamp m->m_len += (ip->ip_hl << 2); 105553be11f6SPoul-Henning Kamp m->m_data -= (ip->ip_hl << 2); 1056df8bae1dSRodney W. Grimes /* some debugging cruft by sklower, below, will go away soon */ 1057a5554bf0SPoul-Henning Kamp if (m->m_flags & M_PKTHDR) /* XXX this should be done elsewhere */ 1058a5554bf0SPoul-Henning Kamp m_fixhdr(m); 1059f0cada84SAndre Oppermann ipstat.ips_reassembled++; 1060f0cada84SAndre Oppermann IPQ_UNLOCK(); 10616a800098SYoshinobu Inoue return (m); 1062df8bae1dSRodney W. Grimes 1063df8bae1dSRodney W. Grimes dropfrag: 1064df8bae1dSRodney W. Grimes ipstat.ips_fragdropped++; 1065042bbfa3SRobert Watson if (fp != NULL) 1066375386e2SMike Silbersack fp->ipq_nfrags--; 1067df8bae1dSRodney W. Grimes m_freem(m); 1068f0cada84SAndre Oppermann done: 1069f0cada84SAndre Oppermann IPQ_UNLOCK(); 1070f0cada84SAndre Oppermann return (NULL); 10716effc713SDoug Rabson 10726effc713SDoug Rabson #undef GETIP 1073df8bae1dSRodney W. Grimes } 1074df8bae1dSRodney W. Grimes 1075df8bae1dSRodney W. Grimes /* 1076df8bae1dSRodney W. Grimes * Free a fragment reassembly header and all 1077df8bae1dSRodney W. Grimes * associated datagrams. 1078df8bae1dSRodney W. Grimes */ 10790312fbe9SPoul-Henning Kamp static void 1080462b86feSPoul-Henning Kamp ip_freef(fhp, fp) 1081462b86feSPoul-Henning Kamp struct ipqhead *fhp; 1082df8bae1dSRodney W. Grimes struct ipq *fp; 1083df8bae1dSRodney W. Grimes { 10846effc713SDoug Rabson register struct mbuf *q; 1085df8bae1dSRodney W. Grimes 10862fad1e93SSam Leffler IPQ_LOCK_ASSERT(); 10872fad1e93SSam Leffler 10886effc713SDoug Rabson while (fp->ipq_frags) { 10896effc713SDoug Rabson q = fp->ipq_frags; 10906effc713SDoug Rabson fp->ipq_frags = q->m_nextpkt; 10916effc713SDoug Rabson m_freem(q); 1092df8bae1dSRodney W. Grimes } 1093462b86feSPoul-Henning Kamp TAILQ_REMOVE(fhp, fp, ipq_list); 1094df8bae1dSRodney W. Grimes (void) m_free(dtom(fp)); 1095194a213eSAndrey A. Chernov nipq--; 1096df8bae1dSRodney W. Grimes } 1097df8bae1dSRodney W. Grimes 1098df8bae1dSRodney W. Grimes /* 1099df8bae1dSRodney W. Grimes * IP timer processing; 1100df8bae1dSRodney W. Grimes * if a timer expires on a reassembly 1101df8bae1dSRodney W. Grimes * queue, discard it. 1102df8bae1dSRodney W. Grimes */ 1103df8bae1dSRodney W. Grimes void 1104df8bae1dSRodney W. Grimes ip_slowtimo() 1105df8bae1dSRodney W. Grimes { 1106df8bae1dSRodney W. Grimes register struct ipq *fp; 1107df8bae1dSRodney W. Grimes int s = splnet(); 1108194a213eSAndrey A. Chernov int i; 1109df8bae1dSRodney W. Grimes 11102fad1e93SSam Leffler IPQ_LOCK(); 1111194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 1112462b86feSPoul-Henning Kamp for(fp = TAILQ_FIRST(&ipq[i]); fp;) { 1113462b86feSPoul-Henning Kamp struct ipq *fpp; 1114462b86feSPoul-Henning Kamp 1115462b86feSPoul-Henning Kamp fpp = fp; 1116462b86feSPoul-Henning Kamp fp = TAILQ_NEXT(fp, ipq_list); 1117462b86feSPoul-Henning Kamp if(--fpp->ipq_ttl == 0) { 111899e8617dSMaxim Konovalov ipstat.ips_fragtimeout += fpp->ipq_nfrags; 1119462b86feSPoul-Henning Kamp ip_freef(&ipq[i], fpp); 1120df8bae1dSRodney W. Grimes } 1121df8bae1dSRodney W. Grimes } 1122194a213eSAndrey A. Chernov } 1123690a6055SJesper Skriver /* 1124690a6055SJesper Skriver * If we are over the maximum number of fragments 1125690a6055SJesper Skriver * (due to the limit being lowered), drain off 1126690a6055SJesper Skriver * enough to get down to the new limit. 1127690a6055SJesper Skriver */ 1128a75a485dSMike Silbersack if (maxnipq >= 0 && nipq > maxnipq) { 1129690a6055SJesper Skriver for (i = 0; i < IPREASS_NHASH; i++) { 1130b36f5b37SMaxim Konovalov while (nipq > maxnipq && !TAILQ_EMPTY(&ipq[i])) { 113199e8617dSMaxim Konovalov ipstat.ips_fragdropped += 113299e8617dSMaxim Konovalov TAILQ_FIRST(&ipq[i])->ipq_nfrags; 1133690a6055SJesper Skriver ip_freef(&ipq[i], TAILQ_FIRST(&ipq[i])); 1134690a6055SJesper Skriver } 1135690a6055SJesper Skriver } 1136690a6055SJesper Skriver } 11372fad1e93SSam Leffler IPQ_UNLOCK(); 1138df8bae1dSRodney W. Grimes splx(s); 1139df8bae1dSRodney W. Grimes } 1140df8bae1dSRodney W. Grimes 1141df8bae1dSRodney W. Grimes /* 1142df8bae1dSRodney W. Grimes * Drain off all datagram fragments. 1143df8bae1dSRodney W. Grimes */ 1144df8bae1dSRodney W. Grimes void 1145df8bae1dSRodney W. Grimes ip_drain() 1146df8bae1dSRodney W. Grimes { 1147194a213eSAndrey A. Chernov int i; 1148ce29ab3aSGarrett Wollman 11492fad1e93SSam Leffler IPQ_LOCK(); 1150194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 1151462b86feSPoul-Henning Kamp while(!TAILQ_EMPTY(&ipq[i])) { 115299e8617dSMaxim Konovalov ipstat.ips_fragdropped += 115399e8617dSMaxim Konovalov TAILQ_FIRST(&ipq[i])->ipq_nfrags; 1154462b86feSPoul-Henning Kamp ip_freef(&ipq[i], TAILQ_FIRST(&ipq[i])); 1155194a213eSAndrey A. Chernov } 1156194a213eSAndrey A. Chernov } 11572fad1e93SSam Leffler IPQ_UNLOCK(); 1158ce29ab3aSGarrett Wollman in_rtqdrain(); 1159df8bae1dSRodney W. Grimes } 1160df8bae1dSRodney W. Grimes 1161df8bae1dSRodney W. Grimes /* 1162de38924dSAndre Oppermann * The protocol to be inserted into ip_protox[] must be already registered 1163de38924dSAndre Oppermann * in inetsw[], either statically or through pf_proto_register(). 1164de38924dSAndre Oppermann */ 1165de38924dSAndre Oppermann int 1166de38924dSAndre Oppermann ipproto_register(u_char ipproto) 1167de38924dSAndre Oppermann { 1168de38924dSAndre Oppermann struct protosw *pr; 1169de38924dSAndre Oppermann 1170de38924dSAndre Oppermann /* Sanity checks. */ 1171de38924dSAndre Oppermann if (ipproto == 0) 1172de38924dSAndre Oppermann return (EPROTONOSUPPORT); 1173de38924dSAndre Oppermann 1174de38924dSAndre Oppermann /* 1175de38924dSAndre Oppermann * The protocol slot must not be occupied by another protocol 1176de38924dSAndre Oppermann * already. An index pointing to IPPROTO_RAW is unused. 1177de38924dSAndre Oppermann */ 1178de38924dSAndre Oppermann pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW); 1179de38924dSAndre Oppermann if (pr == NULL) 1180de38924dSAndre Oppermann return (EPFNOSUPPORT); 1181de38924dSAndre Oppermann if (ip_protox[ipproto] != pr - inetsw) /* IPPROTO_RAW */ 1182de38924dSAndre Oppermann return (EEXIST); 1183de38924dSAndre Oppermann 1184de38924dSAndre Oppermann /* Find the protocol position in inetsw[] and set the index. */ 1185de38924dSAndre Oppermann for (pr = inetdomain.dom_protosw; 1186de38924dSAndre Oppermann pr < inetdomain.dom_protoswNPROTOSW; pr++) { 1187de38924dSAndre Oppermann if (pr->pr_domain->dom_family == PF_INET && 1188de38924dSAndre Oppermann pr->pr_protocol && pr->pr_protocol == ipproto) { 1189de38924dSAndre Oppermann /* Be careful to only index valid IP protocols. */ 1190de38924dSAndre Oppermann if (pr->pr_protocol <= IPPROTO_MAX) { 1191de38924dSAndre Oppermann ip_protox[pr->pr_protocol] = pr - inetsw; 1192de38924dSAndre Oppermann return (0); 1193de38924dSAndre Oppermann } else 1194de38924dSAndre Oppermann return (EINVAL); 1195de38924dSAndre Oppermann } 1196de38924dSAndre Oppermann } 1197de38924dSAndre Oppermann return (EPROTONOSUPPORT); 1198de38924dSAndre Oppermann } 1199de38924dSAndre Oppermann 1200de38924dSAndre Oppermann int 1201de38924dSAndre Oppermann ipproto_unregister(u_char ipproto) 1202de38924dSAndre Oppermann { 1203de38924dSAndre Oppermann struct protosw *pr; 1204de38924dSAndre Oppermann 1205de38924dSAndre Oppermann /* Sanity checks. */ 1206de38924dSAndre Oppermann if (ipproto == 0) 1207de38924dSAndre Oppermann return (EPROTONOSUPPORT); 1208de38924dSAndre Oppermann 1209de38924dSAndre Oppermann /* Check if the protocol was indeed registered. */ 1210de38924dSAndre Oppermann pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW); 1211de38924dSAndre Oppermann if (pr == NULL) 1212de38924dSAndre Oppermann return (EPFNOSUPPORT); 1213de38924dSAndre Oppermann if (ip_protox[ipproto] == pr - inetsw) /* IPPROTO_RAW */ 1214de38924dSAndre Oppermann return (ENOENT); 1215de38924dSAndre Oppermann 1216de38924dSAndre Oppermann /* Reset the protocol slot to IPPROTO_RAW. */ 1217de38924dSAndre Oppermann ip_protox[ipproto] = pr - inetsw; 1218de38924dSAndre Oppermann return (0); 1219de38924dSAndre Oppermann } 1220de38924dSAndre Oppermann 1221de38924dSAndre Oppermann 1222de38924dSAndre Oppermann /* 1223df8bae1dSRodney W. Grimes * Do option processing on a datagram, 1224df8bae1dSRodney W. Grimes * possibly discarding it if bad options are encountered, 1225df8bae1dSRodney W. Grimes * or forwarding it if source-routed. 1226d0ebc0d2SYaroslav Tykhiy * The pass argument is used when operating in the IPSTEALTH 1227d0ebc0d2SYaroslav Tykhiy * mode to tell what options to process: 1228d0ebc0d2SYaroslav Tykhiy * [LS]SRR (pass 0) or the others (pass 1). 1229d0ebc0d2SYaroslav Tykhiy * The reason for as many as two passes is that when doing IPSTEALTH, 1230d0ebc0d2SYaroslav Tykhiy * non-routing options should be processed only if the packet is for us. 1231df8bae1dSRodney W. Grimes * Returns 1 if packet has been forwarded/freed, 1232df8bae1dSRodney W. Grimes * 0 if the packet should be processed further. 1233df8bae1dSRodney W. Grimes */ 12340312fbe9SPoul-Henning Kamp static int 12359b932e9eSAndre Oppermann ip_dooptions(struct mbuf *m, int pass) 1236df8bae1dSRodney W. Grimes { 12372b25acc1SLuigi Rizzo struct ip *ip = mtod(m, struct ip *); 12382b25acc1SLuigi Rizzo u_char *cp; 12392b25acc1SLuigi Rizzo struct in_ifaddr *ia; 1240df8bae1dSRodney W. Grimes int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0; 1241df8bae1dSRodney W. Grimes struct in_addr *sin, dst; 1242df8bae1dSRodney W. Grimes n_time ntime; 12434d2e3692SLuigi Rizzo struct sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET }; 1244df8bae1dSRodney W. Grimes 12452bde81acSAndre Oppermann /* ignore or reject packets with IP options */ 12462bde81acSAndre Oppermann if (ip_doopts == 0) 12472bde81acSAndre Oppermann return 0; 12482bde81acSAndre Oppermann else if (ip_doopts == 2) { 12492bde81acSAndre Oppermann type = ICMP_UNREACH; 12502bde81acSAndre Oppermann code = ICMP_UNREACH_FILTER_PROHIB; 12512bde81acSAndre Oppermann goto bad; 12522bde81acSAndre Oppermann } 12532bde81acSAndre Oppermann 1254df8bae1dSRodney W. Grimes dst = ip->ip_dst; 1255df8bae1dSRodney W. Grimes cp = (u_char *)(ip + 1); 125653be11f6SPoul-Henning Kamp cnt = (ip->ip_hl << 2) - sizeof (struct ip); 1257df8bae1dSRodney W. Grimes for (; cnt > 0; cnt -= optlen, cp += optlen) { 1258df8bae1dSRodney W. Grimes opt = cp[IPOPT_OPTVAL]; 1259df8bae1dSRodney W. Grimes if (opt == IPOPT_EOL) 1260df8bae1dSRodney W. Grimes break; 1261df8bae1dSRodney W. Grimes if (opt == IPOPT_NOP) 1262df8bae1dSRodney W. Grimes optlen = 1; 1263df8bae1dSRodney W. Grimes else { 1264fdcb8debSJun-ichiro itojun Hagino if (cnt < IPOPT_OLEN + sizeof(*cp)) { 1265fdcb8debSJun-ichiro itojun Hagino code = &cp[IPOPT_OLEN] - (u_char *)ip; 1266fdcb8debSJun-ichiro itojun Hagino goto bad; 1267fdcb8debSJun-ichiro itojun Hagino } 1268df8bae1dSRodney W. Grimes optlen = cp[IPOPT_OLEN]; 1269707d00a3SJonathan Lemon if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt) { 1270df8bae1dSRodney W. Grimes code = &cp[IPOPT_OLEN] - (u_char *)ip; 1271df8bae1dSRodney W. Grimes goto bad; 1272df8bae1dSRodney W. Grimes } 1273df8bae1dSRodney W. Grimes } 1274df8bae1dSRodney W. Grimes switch (opt) { 1275df8bae1dSRodney W. Grimes 1276df8bae1dSRodney W. Grimes default: 1277df8bae1dSRodney W. Grimes break; 1278df8bae1dSRodney W. Grimes 1279df8bae1dSRodney W. Grimes /* 1280df8bae1dSRodney W. Grimes * Source routing with record. 1281df8bae1dSRodney W. Grimes * Find interface with current destination address. 1282df8bae1dSRodney W. Grimes * If none on this machine then drop if strictly routed, 1283df8bae1dSRodney W. Grimes * or do nothing if loosely routed. 1284df8bae1dSRodney W. Grimes * Record interface address and bring up next address 1285df8bae1dSRodney W. Grimes * component. If strictly routed make sure next 1286df8bae1dSRodney W. Grimes * address is on directly accessible net. 1287df8bae1dSRodney W. Grimes */ 1288df8bae1dSRodney W. Grimes case IPOPT_LSRR: 1289df8bae1dSRodney W. Grimes case IPOPT_SSRR: 1290d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH 1291d0ebc0d2SYaroslav Tykhiy if (ipstealth && pass > 0) 1292d0ebc0d2SYaroslav Tykhiy break; 1293d0ebc0d2SYaroslav Tykhiy #endif 129433841545SHajimu UMEMOTO if (optlen < IPOPT_OFFSET + sizeof(*cp)) { 129533841545SHajimu UMEMOTO code = &cp[IPOPT_OLEN] - (u_char *)ip; 129633841545SHajimu UMEMOTO goto bad; 129733841545SHajimu UMEMOTO } 1298df8bae1dSRodney W. Grimes if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { 1299df8bae1dSRodney W. Grimes code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1300df8bae1dSRodney W. Grimes goto bad; 1301df8bae1dSRodney W. Grimes } 1302df8bae1dSRodney W. Grimes ipaddr.sin_addr = ip->ip_dst; 1303df8bae1dSRodney W. Grimes ia = (struct in_ifaddr *) 1304df8bae1dSRodney W. Grimes ifa_ifwithaddr((struct sockaddr *)&ipaddr); 13050b17fba7SAndre Oppermann if (ia == NULL) { 1306df8bae1dSRodney W. Grimes if (opt == IPOPT_SSRR) { 1307df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1308df8bae1dSRodney W. Grimes code = ICMP_UNREACH_SRCFAIL; 1309df8bae1dSRodney W. Grimes goto bad; 1310df8bae1dSRodney W. Grimes } 1311bc189bf8SGuido van Rooij if (!ip_dosourceroute) 1312bc189bf8SGuido van Rooij goto nosourcerouting; 1313df8bae1dSRodney W. Grimes /* 1314df8bae1dSRodney W. Grimes * Loose routing, and not at next destination 1315df8bae1dSRodney W. Grimes * yet; nothing to do except forward. 1316df8bae1dSRodney W. Grimes */ 1317df8bae1dSRodney W. Grimes break; 1318df8bae1dSRodney W. Grimes } 1319df8bae1dSRodney W. Grimes off--; /* 0 origin */ 13205d5d5fc0SJonathan Lemon if (off > optlen - (int)sizeof(struct in_addr)) { 1321df8bae1dSRodney W. Grimes /* 1322df8bae1dSRodney W. Grimes * End of source route. Should be for us. 1323df8bae1dSRodney W. Grimes */ 13244fce5804SGuido van Rooij if (!ip_acceptsourceroute) 13254fce5804SGuido van Rooij goto nosourcerouting; 1326e0982661SAndre Oppermann save_rte(m, cp, ip->ip_src); 1327df8bae1dSRodney W. Grimes break; 1328df8bae1dSRodney W. Grimes } 1329d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH 1330d0ebc0d2SYaroslav Tykhiy if (ipstealth) 1331d0ebc0d2SYaroslav Tykhiy goto dropit; 1332d0ebc0d2SYaroslav Tykhiy #endif 13331025071fSGarrett Wollman if (!ip_dosourceroute) { 13340af8d3ecSDavid Greenman if (ipforwarding) { 13350af8d3ecSDavid Greenman char buf[16]; /* aaa.bbb.ccc.ddd\0 */ 13360af8d3ecSDavid Greenman /* 13370af8d3ecSDavid Greenman * Acting as a router, so generate ICMP 13380af8d3ecSDavid Greenman */ 1339efa48587SGuido van Rooij nosourcerouting: 1340bc189bf8SGuido van Rooij strcpy(buf, inet_ntoa(ip->ip_dst)); 13411025071fSGarrett Wollman log(LOG_WARNING, 13421025071fSGarrett Wollman "attempted source route from %s to %s\n", 13431025071fSGarrett Wollman inet_ntoa(ip->ip_src), buf); 13441025071fSGarrett Wollman type = ICMP_UNREACH; 13451025071fSGarrett Wollman code = ICMP_UNREACH_SRCFAIL; 13461025071fSGarrett Wollman goto bad; 13470af8d3ecSDavid Greenman } else { 13480af8d3ecSDavid Greenman /* 13490af8d3ecSDavid Greenman * Not acting as a router, so silently drop. 13500af8d3ecSDavid Greenman */ 1351d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH 1352d0ebc0d2SYaroslav Tykhiy dropit: 1353d0ebc0d2SYaroslav Tykhiy #endif 13540af8d3ecSDavid Greenman ipstat.ips_cantforward++; 13550af8d3ecSDavid Greenman m_freem(m); 13560af8d3ecSDavid Greenman return (1); 13570af8d3ecSDavid Greenman } 13581025071fSGarrett Wollman } 13591025071fSGarrett Wollman 1360df8bae1dSRodney W. Grimes /* 1361df8bae1dSRodney W. Grimes * locate outgoing interface 1362df8bae1dSRodney W. Grimes */ 136394a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, cp + off, 1364df8bae1dSRodney W. Grimes sizeof(ipaddr.sin_addr)); 13651025071fSGarrett Wollman 1366df8bae1dSRodney W. Grimes if (opt == IPOPT_SSRR) { 1367df8bae1dSRodney W. Grimes #define INA struct in_ifaddr * 1368df8bae1dSRodney W. Grimes #define SA struct sockaddr * 13690b17fba7SAndre Oppermann if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == NULL) 1370df8bae1dSRodney W. Grimes ia = (INA)ifa_ifwithnet((SA)&ipaddr); 1371df8bae1dSRodney W. Grimes } else 137202c1c707SAndre Oppermann ia = ip_rtaddr(ipaddr.sin_addr); 13730b17fba7SAndre Oppermann if (ia == NULL) { 1374df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1375df8bae1dSRodney W. Grimes code = ICMP_UNREACH_SRCFAIL; 1376df8bae1dSRodney W. Grimes goto bad; 1377df8bae1dSRodney W. Grimes } 1378df8bae1dSRodney W. Grimes ip->ip_dst = ipaddr.sin_addr; 137994a5d9b6SDavid Greenman (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr), 138094a5d9b6SDavid Greenman sizeof(struct in_addr)); 1381df8bae1dSRodney W. Grimes cp[IPOPT_OFFSET] += sizeof(struct in_addr); 1382df8bae1dSRodney W. Grimes /* 1383df8bae1dSRodney W. Grimes * Let ip_intr's mcast routing check handle mcast pkts 1384df8bae1dSRodney W. Grimes */ 1385df8bae1dSRodney W. Grimes forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr)); 1386df8bae1dSRodney W. Grimes break; 1387df8bae1dSRodney W. Grimes 1388df8bae1dSRodney W. Grimes case IPOPT_RR: 1389d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH 1390d0ebc0d2SYaroslav Tykhiy if (ipstealth && pass == 0) 1391d0ebc0d2SYaroslav Tykhiy break; 1392d0ebc0d2SYaroslav Tykhiy #endif 1393707d00a3SJonathan Lemon if (optlen < IPOPT_OFFSET + sizeof(*cp)) { 1394707d00a3SJonathan Lemon code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1395707d00a3SJonathan Lemon goto bad; 1396707d00a3SJonathan Lemon } 1397df8bae1dSRodney W. Grimes if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { 1398df8bae1dSRodney W. Grimes code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1399df8bae1dSRodney W. Grimes goto bad; 1400df8bae1dSRodney W. Grimes } 1401df8bae1dSRodney W. Grimes /* 1402df8bae1dSRodney W. Grimes * If no space remains, ignore. 1403df8bae1dSRodney W. Grimes */ 1404df8bae1dSRodney W. Grimes off--; /* 0 origin */ 14055d5d5fc0SJonathan Lemon if (off > optlen - (int)sizeof(struct in_addr)) 1406df8bae1dSRodney W. Grimes break; 140794a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, &ip->ip_dst, 1408df8bae1dSRodney W. Grimes sizeof(ipaddr.sin_addr)); 1409df8bae1dSRodney W. Grimes /* 1410df8bae1dSRodney W. Grimes * locate outgoing interface; if we're the destination, 1411df8bae1dSRodney W. Grimes * use the incoming interface (should be same). 1412df8bae1dSRodney W. Grimes */ 14130b17fba7SAndre Oppermann if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == NULL && 14140b17fba7SAndre Oppermann (ia = ip_rtaddr(ipaddr.sin_addr)) == NULL) { 1415df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1416df8bae1dSRodney W. Grimes code = ICMP_UNREACH_HOST; 1417df8bae1dSRodney W. Grimes goto bad; 1418df8bae1dSRodney W. Grimes } 141994a5d9b6SDavid Greenman (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr), 142094a5d9b6SDavid Greenman sizeof(struct in_addr)); 1421df8bae1dSRodney W. Grimes cp[IPOPT_OFFSET] += sizeof(struct in_addr); 1422df8bae1dSRodney W. Grimes break; 1423df8bae1dSRodney W. Grimes 1424df8bae1dSRodney W. Grimes case IPOPT_TS: 1425d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH 1426d0ebc0d2SYaroslav Tykhiy if (ipstealth && pass == 0) 1427d0ebc0d2SYaroslav Tykhiy break; 1428d0ebc0d2SYaroslav Tykhiy #endif 1429df8bae1dSRodney W. Grimes code = cp - (u_char *)ip; 143007514071SJonathan Lemon if (optlen < 4 || optlen > 40) { 143107514071SJonathan Lemon code = &cp[IPOPT_OLEN] - (u_char *)ip; 1432df8bae1dSRodney W. Grimes goto bad; 143333841545SHajimu UMEMOTO } 143407514071SJonathan Lemon if ((off = cp[IPOPT_OFFSET]) < 5) { 143507514071SJonathan Lemon code = &cp[IPOPT_OLEN] - (u_char *)ip; 143633841545SHajimu UMEMOTO goto bad; 143733841545SHajimu UMEMOTO } 143807514071SJonathan Lemon if (off > optlen - (int)sizeof(int32_t)) { 143907514071SJonathan Lemon cp[IPOPT_OFFSET + 1] += (1 << 4); 144007514071SJonathan Lemon if ((cp[IPOPT_OFFSET + 1] & 0xf0) == 0) { 144107514071SJonathan Lemon code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1442df8bae1dSRodney W. Grimes goto bad; 144333841545SHajimu UMEMOTO } 1444df8bae1dSRodney W. Grimes break; 1445df8bae1dSRodney W. Grimes } 144607514071SJonathan Lemon off--; /* 0 origin */ 144707514071SJonathan Lemon sin = (struct in_addr *)(cp + off); 144807514071SJonathan Lemon switch (cp[IPOPT_OFFSET + 1] & 0x0f) { 1449df8bae1dSRodney W. Grimes 1450df8bae1dSRodney W. Grimes case IPOPT_TS_TSONLY: 1451df8bae1dSRodney W. Grimes break; 1452df8bae1dSRodney W. Grimes 1453df8bae1dSRodney W. Grimes case IPOPT_TS_TSANDADDR: 145407514071SJonathan Lemon if (off + sizeof(n_time) + 145507514071SJonathan Lemon sizeof(struct in_addr) > optlen) { 145607514071SJonathan Lemon code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1457df8bae1dSRodney W. Grimes goto bad; 145833841545SHajimu UMEMOTO } 1459df8bae1dSRodney W. Grimes ipaddr.sin_addr = dst; 1460df8bae1dSRodney W. Grimes ia = (INA)ifaof_ifpforaddr((SA)&ipaddr, 1461df8bae1dSRodney W. Grimes m->m_pkthdr.rcvif); 14620b17fba7SAndre Oppermann if (ia == NULL) 1463df8bae1dSRodney W. Grimes continue; 146494a5d9b6SDavid Greenman (void)memcpy(sin, &IA_SIN(ia)->sin_addr, 146594a5d9b6SDavid Greenman sizeof(struct in_addr)); 146607514071SJonathan Lemon cp[IPOPT_OFFSET] += sizeof(struct in_addr); 1467a5428e3aSMaxim Konovalov off += sizeof(struct in_addr); 1468df8bae1dSRodney W. Grimes break; 1469df8bae1dSRodney W. Grimes 1470df8bae1dSRodney W. Grimes case IPOPT_TS_PRESPEC: 147107514071SJonathan Lemon if (off + sizeof(n_time) + 147207514071SJonathan Lemon sizeof(struct in_addr) > optlen) { 147307514071SJonathan Lemon code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1474df8bae1dSRodney W. Grimes goto bad; 147533841545SHajimu UMEMOTO } 147694a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, sin, 1477df8bae1dSRodney W. Grimes sizeof(struct in_addr)); 14780b17fba7SAndre Oppermann if (ifa_ifwithaddr((SA)&ipaddr) == NULL) 1479df8bae1dSRodney W. Grimes continue; 148007514071SJonathan Lemon cp[IPOPT_OFFSET] += sizeof(struct in_addr); 1481a5428e3aSMaxim Konovalov off += sizeof(struct in_addr); 1482df8bae1dSRodney W. Grimes break; 1483df8bae1dSRodney W. Grimes 1484df8bae1dSRodney W. Grimes default: 148507514071SJonathan Lemon code = &cp[IPOPT_OFFSET + 1] - (u_char *)ip; 1486df8bae1dSRodney W. Grimes goto bad; 1487df8bae1dSRodney W. Grimes } 1488df8bae1dSRodney W. Grimes ntime = iptime(); 148907514071SJonathan Lemon (void)memcpy(cp + off, &ntime, sizeof(n_time)); 149007514071SJonathan Lemon cp[IPOPT_OFFSET] += sizeof(n_time); 1491df8bae1dSRodney W. Grimes } 1492df8bae1dSRodney W. Grimes } 149347174b49SAndrey A. Chernov if (forward && ipforwarding) { 14949b932e9eSAndre Oppermann ip_forward(m, 1); 1495df8bae1dSRodney W. Grimes return (1); 1496df8bae1dSRodney W. Grimes } 1497df8bae1dSRodney W. Grimes return (0); 1498df8bae1dSRodney W. Grimes bad: 1499df8bae1dSRodney W. Grimes icmp_error(m, type, code, 0, 0); 1500df8bae1dSRodney W. Grimes ipstat.ips_badoptions++; 1501df8bae1dSRodney W. Grimes return (1); 1502df8bae1dSRodney W. Grimes } 1503df8bae1dSRodney W. Grimes 1504df8bae1dSRodney W. Grimes /* 1505df8bae1dSRodney W. Grimes * Given address of next destination (final or next hop), 1506df8bae1dSRodney W. Grimes * return internet address info of interface to be used to get there. 1507df8bae1dSRodney W. Grimes */ 1508bd714208SRuslan Ermilov struct in_ifaddr * 150902c1c707SAndre Oppermann ip_rtaddr(dst) 1510df8bae1dSRodney W. Grimes struct in_addr dst; 1511df8bae1dSRodney W. Grimes { 151297d8d152SAndre Oppermann struct route sro; 151302c1c707SAndre Oppermann struct sockaddr_in *sin; 151402c1c707SAndre Oppermann struct in_ifaddr *ifa; 1515df8bae1dSRodney W. Grimes 15160cfbbe3bSAndre Oppermann bzero(&sro, sizeof(sro)); 151797d8d152SAndre Oppermann sin = (struct sockaddr_in *)&sro.ro_dst; 1518df8bae1dSRodney W. Grimes sin->sin_family = AF_INET; 1519df8bae1dSRodney W. Grimes sin->sin_len = sizeof(*sin); 1520df8bae1dSRodney W. Grimes sin->sin_addr = dst; 152197d8d152SAndre Oppermann rtalloc_ign(&sro, RTF_CLONING); 1522df8bae1dSRodney W. Grimes 152397d8d152SAndre Oppermann if (sro.ro_rt == NULL) 1524df8bae1dSRodney W. Grimes return ((struct in_ifaddr *)0); 152502c1c707SAndre Oppermann 152697d8d152SAndre Oppermann ifa = ifatoia(sro.ro_rt->rt_ifa); 152797d8d152SAndre Oppermann RTFREE(sro.ro_rt); 152802c1c707SAndre Oppermann return ifa; 1529df8bae1dSRodney W. Grimes } 1530df8bae1dSRodney W. Grimes 1531df8bae1dSRodney W. Grimes /* 1532df8bae1dSRodney W. Grimes * Save incoming source route for use in replies, 1533df8bae1dSRodney W. Grimes * to be picked up later by ip_srcroute if the receiver is interested. 1534df8bae1dSRodney W. Grimes */ 153537c84183SPoul-Henning Kamp static void 1536e0982661SAndre Oppermann save_rte(m, option, dst) 1537e0982661SAndre Oppermann struct mbuf *m; 1538df8bae1dSRodney W. Grimes u_char *option; 1539df8bae1dSRodney W. Grimes struct in_addr dst; 1540df8bae1dSRodney W. Grimes { 1541df8bae1dSRodney W. Grimes unsigned olen; 1542e0982661SAndre Oppermann struct ipopt_tag *opts; 1543e0982661SAndre Oppermann 1544e0982661SAndre Oppermann opts = (struct ipopt_tag *)m_tag_get(PACKET_TAG_IPOPTIONS, 1545e0982661SAndre Oppermann sizeof(struct ipopt_tag), M_NOWAIT); 1546e0982661SAndre Oppermann if (opts == NULL) 1547e0982661SAndre Oppermann return; 1548df8bae1dSRodney W. Grimes 1549df8bae1dSRodney W. Grimes olen = option[IPOPT_OLEN]; 1550df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1551df8bae1dSRodney W. Grimes if (ipprintfs) 1552df8bae1dSRodney W. Grimes printf("save_rte: olen %d\n", olen); 1553df8bae1dSRodney W. Grimes #endif 1554e0982661SAndre Oppermann if (olen > sizeof(opts->ip_srcrt) - (1 + sizeof(dst))) 1555df8bae1dSRodney W. Grimes return; 1556e0982661SAndre Oppermann bcopy(option, opts->ip_srcrt.srcopt, olen); 1557e0982661SAndre Oppermann opts->ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr); 1558e0982661SAndre Oppermann opts->ip_srcrt.dst = dst; 1559e0982661SAndre Oppermann m_tag_prepend(m, (struct m_tag *)opts); 1560df8bae1dSRodney W. Grimes } 1561df8bae1dSRodney W. Grimes 1562df8bae1dSRodney W. Grimes /* 1563df8bae1dSRodney W. Grimes * Retrieve incoming source route for use in replies, 1564df8bae1dSRodney W. Grimes * in the same form used by setsockopt. 1565df8bae1dSRodney W. Grimes * The first hop is placed before the options, will be removed later. 1566df8bae1dSRodney W. Grimes */ 1567df8bae1dSRodney W. Grimes struct mbuf * 1568e0982661SAndre Oppermann ip_srcroute(m0) 1569e0982661SAndre Oppermann struct mbuf *m0; 1570df8bae1dSRodney W. Grimes { 1571df8bae1dSRodney W. Grimes register struct in_addr *p, *q; 1572df8bae1dSRodney W. Grimes register struct mbuf *m; 1573e0982661SAndre Oppermann struct ipopt_tag *opts; 1574df8bae1dSRodney W. Grimes 1575e0982661SAndre Oppermann opts = (struct ipopt_tag *)m_tag_find(m0, PACKET_TAG_IPOPTIONS, NULL); 1576e0982661SAndre Oppermann if (opts == NULL) 1577e0982661SAndre Oppermann return ((struct mbuf *)0); 1578e0982661SAndre Oppermann 1579e0982661SAndre Oppermann if (opts->ip_nhops == 0) 1580df8bae1dSRodney W. Grimes return ((struct mbuf *)0); 1581a163d034SWarner Losh m = m_get(M_DONTWAIT, MT_HEADER); 15820b17fba7SAndre Oppermann if (m == NULL) 1583df8bae1dSRodney W. Grimes return ((struct mbuf *)0); 1584df8bae1dSRodney W. Grimes 1585e0982661SAndre Oppermann #define OPTSIZ (sizeof(opts->ip_srcrt.nop) + sizeof(opts->ip_srcrt.srcopt)) 1586df8bae1dSRodney W. Grimes 1587df8bae1dSRodney W. Grimes /* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */ 1588e0982661SAndre Oppermann m->m_len = opts->ip_nhops * sizeof(struct in_addr) + 1589e0982661SAndre Oppermann sizeof(struct in_addr) + OPTSIZ; 1590df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1591df8bae1dSRodney W. Grimes if (ipprintfs) 1592e0982661SAndre Oppermann printf("ip_srcroute: nhops %d mlen %d", opts->ip_nhops, m->m_len); 1593df8bae1dSRodney W. Grimes #endif 1594df8bae1dSRodney W. Grimes 1595df8bae1dSRodney W. Grimes /* 1596df8bae1dSRodney W. Grimes * First save first hop for return route 1597df8bae1dSRodney W. Grimes */ 1598e0982661SAndre Oppermann p = &(opts->ip_srcrt.route[opts->ip_nhops - 1]); 1599df8bae1dSRodney W. Grimes *(mtod(m, struct in_addr *)) = *p--; 1600df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1601df8bae1dSRodney W. Grimes if (ipprintfs) 1602af38c68cSLuigi Rizzo printf(" hops %lx", (u_long)ntohl(mtod(m, struct in_addr *)->s_addr)); 1603df8bae1dSRodney W. Grimes #endif 1604df8bae1dSRodney W. Grimes 1605df8bae1dSRodney W. Grimes /* 1606df8bae1dSRodney W. Grimes * Copy option fields and padding (nop) to mbuf. 1607df8bae1dSRodney W. Grimes */ 1608e0982661SAndre Oppermann opts->ip_srcrt.nop = IPOPT_NOP; 1609e0982661SAndre Oppermann opts->ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF; 161094a5d9b6SDavid Greenman (void)memcpy(mtod(m, caddr_t) + sizeof(struct in_addr), 1611e0982661SAndre Oppermann &(opts->ip_srcrt.nop), OPTSIZ); 1612df8bae1dSRodney W. Grimes q = (struct in_addr *)(mtod(m, caddr_t) + 1613df8bae1dSRodney W. Grimes sizeof(struct in_addr) + OPTSIZ); 1614df8bae1dSRodney W. Grimes #undef OPTSIZ 1615df8bae1dSRodney W. Grimes /* 1616df8bae1dSRodney W. Grimes * Record return path as an IP source route, 1617df8bae1dSRodney W. Grimes * reversing the path (pointers are now aligned). 1618df8bae1dSRodney W. Grimes */ 1619e0982661SAndre Oppermann while (p >= opts->ip_srcrt.route) { 1620df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1621df8bae1dSRodney W. Grimes if (ipprintfs) 1622af38c68cSLuigi Rizzo printf(" %lx", (u_long)ntohl(q->s_addr)); 1623df8bae1dSRodney W. Grimes #endif 1624df8bae1dSRodney W. Grimes *q++ = *p--; 1625df8bae1dSRodney W. Grimes } 1626df8bae1dSRodney W. Grimes /* 1627df8bae1dSRodney W. Grimes * Last hop goes to final destination. 1628df8bae1dSRodney W. Grimes */ 1629e0982661SAndre Oppermann *q = opts->ip_srcrt.dst; 1630df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1631df8bae1dSRodney W. Grimes if (ipprintfs) 1632af38c68cSLuigi Rizzo printf(" %lx\n", (u_long)ntohl(q->s_addr)); 1633df8bae1dSRodney W. Grimes #endif 1634e0982661SAndre Oppermann m_tag_delete(m0, (struct m_tag *)opts); 1635df8bae1dSRodney W. Grimes return (m); 1636df8bae1dSRodney W. Grimes } 1637df8bae1dSRodney W. Grimes 1638df8bae1dSRodney W. Grimes /* 1639df8bae1dSRodney W. Grimes * Strip out IP options, at higher 1640df8bae1dSRodney W. Grimes * level protocol in the kernel. 1641df8bae1dSRodney W. Grimes * Second argument is buffer to which options 1642df8bae1dSRodney W. Grimes * will be moved, and return value is their length. 1643df8bae1dSRodney W. Grimes * XXX should be deleted; last arg currently ignored. 1644df8bae1dSRodney W. Grimes */ 1645df8bae1dSRodney W. Grimes void 1646df8bae1dSRodney W. Grimes ip_stripoptions(m, mopt) 1647df8bae1dSRodney W. Grimes register struct mbuf *m; 1648df8bae1dSRodney W. Grimes struct mbuf *mopt; 1649df8bae1dSRodney W. Grimes { 1650df8bae1dSRodney W. Grimes register int i; 1651df8bae1dSRodney W. Grimes struct ip *ip = mtod(m, struct ip *); 1652df8bae1dSRodney W. Grimes register caddr_t opts; 1653df8bae1dSRodney W. Grimes int olen; 1654df8bae1dSRodney W. Grimes 165553be11f6SPoul-Henning Kamp olen = (ip->ip_hl << 2) - sizeof (struct ip); 1656df8bae1dSRodney W. Grimes opts = (caddr_t)(ip + 1); 1657df8bae1dSRodney W. Grimes i = m->m_len - (sizeof (struct ip) + olen); 1658df8bae1dSRodney W. Grimes bcopy(opts + olen, opts, (unsigned)i); 1659df8bae1dSRodney W. Grimes m->m_len -= olen; 1660df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) 1661df8bae1dSRodney W. Grimes m->m_pkthdr.len -= olen; 166253be11f6SPoul-Henning Kamp ip->ip_v = IPVERSION; 166353be11f6SPoul-Henning Kamp ip->ip_hl = sizeof(struct ip) >> 2; 1664df8bae1dSRodney W. Grimes } 1665df8bae1dSRodney W. Grimes 1666df8bae1dSRodney W. Grimes u_char inetctlerrmap[PRC_NCMDS] = { 1667df8bae1dSRodney W. Grimes 0, 0, 0, 0, 1668df8bae1dSRodney W. Grimes 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH, 1669df8bae1dSRodney W. Grimes EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, 1670df8bae1dSRodney W. Grimes EMSGSIZE, EHOSTUNREACH, 0, 0, 1671fcaf9f91SMike Silbersack 0, 0, EHOSTUNREACH, 0, 16723b8123b7SJesper Skriver ENOPROTOOPT, ECONNREFUSED 1673df8bae1dSRodney W. Grimes }; 1674df8bae1dSRodney W. Grimes 1675df8bae1dSRodney W. Grimes /* 1676df8bae1dSRodney W. Grimes * Forward a packet. If some error occurs return the sender 1677df8bae1dSRodney W. Grimes * an icmp packet. Note we can't always generate a meaningful 1678df8bae1dSRodney W. Grimes * icmp message because icmp doesn't have a large enough repertoire 1679df8bae1dSRodney W. Grimes * of codes and types. 1680df8bae1dSRodney W. Grimes * 1681df8bae1dSRodney W. Grimes * If not forwarding, just drop the packet. This could be confusing 1682df8bae1dSRodney W. Grimes * if ipforwarding was zero but some routing protocol was advancing 1683df8bae1dSRodney W. Grimes * us as a gateway to somewhere. However, we must let the routing 1684df8bae1dSRodney W. Grimes * protocol deal with that. 1685df8bae1dSRodney W. Grimes * 1686df8bae1dSRodney W. Grimes * The srcrt parameter indicates whether the packet is being forwarded 1687df8bae1dSRodney W. Grimes * via a source route. 1688df8bae1dSRodney W. Grimes */ 16899b932e9eSAndre Oppermann void 16909b932e9eSAndre Oppermann ip_forward(struct mbuf *m, int srcrt) 1691df8bae1dSRodney W. Grimes { 16922b25acc1SLuigi Rizzo struct ip *ip = mtod(m, struct ip *); 16939b932e9eSAndre Oppermann struct in_ifaddr *ia = NULL; 169426f9a767SRodney W. Grimes int error, type = 0, code = 0; 1695df8bae1dSRodney W. Grimes struct mbuf *mcopy; 16969b932e9eSAndre Oppermann struct in_addr dest; 16979b932e9eSAndre Oppermann struct ifnet *destifp, dummyifp; 16983efc3014SJulian Elischer 1699df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1700df8bae1dSRodney W. Grimes if (ipprintfs) 170161ce519bSPoul-Henning Kamp printf("forward: src %lx dst %lx ttl %x\n", 17029b932e9eSAndre Oppermann (u_long)ip->ip_src.s_addr, (u_long)ip->ip_dst.s_addr, 1703162886e2SBruce Evans ip->ip_ttl); 1704df8bae1dSRodney W. Grimes #endif 1705100ba1a6SJordan K. Hubbard 1706100ba1a6SJordan K. Hubbard 17079b932e9eSAndre Oppermann if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(ip->ip_dst) == 0) { 1708df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 1709df8bae1dSRodney W. Grimes m_freem(m); 1710df8bae1dSRodney W. Grimes return; 1711df8bae1dSRodney W. Grimes } 17121b968362SDag-Erling Smørgrav #ifdef IPSTEALTH 17131b968362SDag-Erling Smørgrav if (!ipstealth) { 17141b968362SDag-Erling Smørgrav #endif 1715df8bae1dSRodney W. Grimes if (ip->ip_ttl <= IPTTLDEC) { 17161b968362SDag-Erling Smørgrav icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 171702c1c707SAndre Oppermann 0, 0); 1718df8bae1dSRodney W. Grimes return; 1719df8bae1dSRodney W. Grimes } 17201b968362SDag-Erling Smørgrav #ifdef IPSTEALTH 17211b968362SDag-Erling Smørgrav } 17221b968362SDag-Erling Smørgrav #endif 1723df8bae1dSRodney W. Grimes 17249b932e9eSAndre Oppermann if (!srcrt && (ia = ip_rtaddr(ip->ip_dst)) == NULL) { 172502c1c707SAndre Oppermann icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0); 1726df8bae1dSRodney W. Grimes return; 172702c1c707SAndre Oppermann } 1728df8bae1dSRodney W. Grimes 1729df8bae1dSRodney W. Grimes /* 1730bfef7ed4SIan Dowse * Save the IP header and at most 8 bytes of the payload, 1731bfef7ed4SIan Dowse * in case we need to generate an ICMP message to the src. 1732bfef7ed4SIan Dowse * 17334d2e3692SLuigi Rizzo * XXX this can be optimized a lot by saving the data in a local 17344d2e3692SLuigi Rizzo * buffer on the stack (72 bytes at most), and only allocating the 17354d2e3692SLuigi Rizzo * mbuf if really necessary. The vast majority of the packets 17364d2e3692SLuigi Rizzo * are forwarded without having to send an ICMP back (either 17374d2e3692SLuigi Rizzo * because unnecessary, or because rate limited), so we are 17384d2e3692SLuigi Rizzo * really we are wasting a lot of work here. 17394d2e3692SLuigi Rizzo * 1740bfef7ed4SIan Dowse * We don't use m_copy() because it might return a reference 1741bfef7ed4SIan Dowse * to a shared cluster. Both this function and ip_output() 1742bfef7ed4SIan Dowse * assume exclusive access to the IP header in `m', so any 1743bfef7ed4SIan Dowse * data in a cluster may change before we reach icmp_error(). 1744df8bae1dSRodney W. Grimes */ 1745a163d034SWarner Losh MGET(mcopy, M_DONTWAIT, m->m_type); 1746a163d034SWarner Losh if (mcopy != NULL && !m_dup_pkthdr(mcopy, m, M_DONTWAIT)) { 17479967cafcSSam Leffler /* 17489967cafcSSam Leffler * It's probably ok if the pkthdr dup fails (because 17499967cafcSSam Leffler * the deep copy of the tag chain failed), but for now 17509967cafcSSam Leffler * be conservative and just discard the copy since 17519967cafcSSam Leffler * code below may some day want the tags. 17529967cafcSSam Leffler */ 17539967cafcSSam Leffler m_free(mcopy); 17549967cafcSSam Leffler mcopy = NULL; 17559967cafcSSam Leffler } 1756bfef7ed4SIan Dowse if (mcopy != NULL) { 175753be11f6SPoul-Henning Kamp mcopy->m_len = imin((ip->ip_hl << 2) + 8, 1758bfef7ed4SIan Dowse (int)ip->ip_len); 1759e6b0a570SBruce M Simpson mcopy->m_pkthdr.len = mcopy->m_len; 1760bfef7ed4SIan Dowse m_copydata(m, 0, mcopy->m_len, mtod(mcopy, caddr_t)); 1761bfef7ed4SIan Dowse } 176204287599SRuslan Ermilov 176304287599SRuslan Ermilov #ifdef IPSTEALTH 176404287599SRuslan Ermilov if (!ipstealth) { 176504287599SRuslan Ermilov #endif 176604287599SRuslan Ermilov ip->ip_ttl -= IPTTLDEC; 176704287599SRuslan Ermilov #ifdef IPSTEALTH 176804287599SRuslan Ermilov } 176904287599SRuslan Ermilov #endif 1770df8bae1dSRodney W. Grimes 1771df8bae1dSRodney W. Grimes /* 1772df8bae1dSRodney W. Grimes * If forwarding packet using same interface that it came in on, 1773df8bae1dSRodney W. Grimes * perhaps should send a redirect to sender to shortcut a hop. 1774df8bae1dSRodney W. Grimes * Only send redirect if source is sending directly to us, 1775df8bae1dSRodney W. Grimes * and if packet was not source routed (or has any options). 1776df8bae1dSRodney W. Grimes * Also, don't send redirect if forwarding using a default route 1777df8bae1dSRodney W. Grimes * or a route modified by a redirect. 1778df8bae1dSRodney W. Grimes */ 17799b932e9eSAndre Oppermann dest.s_addr = 0; 17809b932e9eSAndre Oppermann if (!srcrt && ipsendredirects && ia->ia_ifp == m->m_pkthdr.rcvif) { 178102c1c707SAndre Oppermann struct sockaddr_in *sin; 178202c1c707SAndre Oppermann struct route ro; 178302c1c707SAndre Oppermann struct rtentry *rt; 178402c1c707SAndre Oppermann 17850cfbbe3bSAndre Oppermann bzero(&ro, sizeof(ro)); 178602c1c707SAndre Oppermann sin = (struct sockaddr_in *)&ro.ro_dst; 178702c1c707SAndre Oppermann sin->sin_family = AF_INET; 178802c1c707SAndre Oppermann sin->sin_len = sizeof(*sin); 17899b932e9eSAndre Oppermann sin->sin_addr = ip->ip_dst; 179026d02ca7SAndre Oppermann rtalloc_ign(&ro, RTF_CLONING); 179102c1c707SAndre Oppermann 179202c1c707SAndre Oppermann rt = ro.ro_rt; 179302c1c707SAndre Oppermann 179402c1c707SAndre Oppermann if (rt && (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 && 17959b932e9eSAndre Oppermann satosin(rt_key(rt))->sin_addr.s_addr != 0) { 1796df8bae1dSRodney W. Grimes #define RTA(rt) ((struct in_ifaddr *)(rt->rt_ifa)) 1797df8bae1dSRodney W. Grimes u_long src = ntohl(ip->ip_src.s_addr); 1798df8bae1dSRodney W. Grimes 1799df8bae1dSRodney W. Grimes if (RTA(rt) && 1800df8bae1dSRodney W. Grimes (src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) { 1801df8bae1dSRodney W. Grimes if (rt->rt_flags & RTF_GATEWAY) 18029b932e9eSAndre Oppermann dest.s_addr = satosin(rt->rt_gateway)->sin_addr.s_addr; 1803df8bae1dSRodney W. Grimes else 18049b932e9eSAndre Oppermann dest.s_addr = ip->ip_dst.s_addr; 1805df8bae1dSRodney W. Grimes /* Router requirements says to only send host redirects */ 1806df8bae1dSRodney W. Grimes type = ICMP_REDIRECT; 1807df8bae1dSRodney W. Grimes code = ICMP_REDIRECT_HOST; 1808df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1809df8bae1dSRodney W. Grimes if (ipprintfs) 18109b932e9eSAndre Oppermann printf("redirect (%d) to %lx\n", code, (u_long)dest.s_addr); 1811df8bae1dSRodney W. Grimes #endif 1812df8bae1dSRodney W. Grimes } 1813df8bae1dSRodney W. Grimes } 181402c1c707SAndre Oppermann if (rt) 181502c1c707SAndre Oppermann RTFREE(rt); 181602c1c707SAndre Oppermann } 1817df8bae1dSRodney W. Grimes 181802c1c707SAndre Oppermann error = ip_output(m, (struct mbuf *)0, NULL, IP_FORWARDING, 0, NULL); 1819df8bae1dSRodney W. Grimes if (error) 1820df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 1821df8bae1dSRodney W. Grimes else { 1822df8bae1dSRodney W. Grimes ipstat.ips_forward++; 1823df8bae1dSRodney W. Grimes if (type) 1824df8bae1dSRodney W. Grimes ipstat.ips_redirectsent++; 1825df8bae1dSRodney W. Grimes else { 18269188b4a1SAndre Oppermann if (mcopy) 1827df8bae1dSRodney W. Grimes m_freem(mcopy); 1828df8bae1dSRodney W. Grimes return; 1829df8bae1dSRodney W. Grimes } 1830df8bae1dSRodney W. Grimes } 1831df8bae1dSRodney W. Grimes if (mcopy == NULL) 1832df8bae1dSRodney W. Grimes return; 1833df8bae1dSRodney W. Grimes destifp = NULL; 1834df8bae1dSRodney W. Grimes 1835df8bae1dSRodney W. Grimes switch (error) { 1836df8bae1dSRodney W. Grimes 1837df8bae1dSRodney W. Grimes case 0: /* forwarded, but need redirect */ 1838df8bae1dSRodney W. Grimes /* type, code set above */ 1839df8bae1dSRodney W. Grimes break; 1840df8bae1dSRodney W. Grimes 1841df8bae1dSRodney W. Grimes case ENETUNREACH: /* shouldn't happen, checked above */ 1842df8bae1dSRodney W. Grimes case EHOSTUNREACH: 1843df8bae1dSRodney W. Grimes case ENETDOWN: 1844df8bae1dSRodney W. Grimes case EHOSTDOWN: 1845df8bae1dSRodney W. Grimes default: 1846df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1847df8bae1dSRodney W. Grimes code = ICMP_UNREACH_HOST; 1848df8bae1dSRodney W. Grimes break; 1849df8bae1dSRodney W. Grimes 1850df8bae1dSRodney W. Grimes case EMSGSIZE: 1851df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1852df8bae1dSRodney W. Grimes code = ICMP_UNREACH_NEEDFRAG; 185302c1c707SAndre Oppermann #if defined(IPSEC) || defined(FAST_IPSEC) 18546a800098SYoshinobu Inoue /* 18556a800098SYoshinobu Inoue * If the packet is routed over IPsec tunnel, tell the 18566a800098SYoshinobu Inoue * originator the tunnel MTU. 18576a800098SYoshinobu Inoue * tunnel MTU = if MTU - sizeof(IP) - ESP/AH hdrsiz 18586a800098SYoshinobu Inoue * XXX quickhack!!! 18596a800098SYoshinobu Inoue */ 186002c1c707SAndre Oppermann { 18616a800098SYoshinobu Inoue struct secpolicy *sp = NULL; 18626a800098SYoshinobu Inoue int ipsecerror; 18636a800098SYoshinobu Inoue int ipsechdr; 186402c1c707SAndre Oppermann struct route *ro; 18656a800098SYoshinobu Inoue 186602c1c707SAndre Oppermann #ifdef IPSEC 18676a800098SYoshinobu Inoue sp = ipsec4_getpolicybyaddr(mcopy, 18686a800098SYoshinobu Inoue IPSEC_DIR_OUTBOUND, 18696a800098SYoshinobu Inoue IP_FORWARDING, 18706a800098SYoshinobu Inoue &ipsecerror); 187102c1c707SAndre Oppermann #else /* FAST_IPSEC */ 1872b9234fafSSam Leffler sp = ipsec_getpolicybyaddr(mcopy, 1873b9234fafSSam Leffler IPSEC_DIR_OUTBOUND, 1874b9234fafSSam Leffler IP_FORWARDING, 1875b9234fafSSam Leffler &ipsecerror); 187602c1c707SAndre Oppermann #endif 187702c1c707SAndre Oppermann if (sp != NULL) { 1878b9234fafSSam Leffler /* count IPsec header size */ 1879b9234fafSSam Leffler ipsechdr = ipsec4_hdrsiz(mcopy, 1880b9234fafSSam Leffler IPSEC_DIR_OUTBOUND, 1881b9234fafSSam Leffler NULL); 1882b9234fafSSam Leffler 1883b9234fafSSam Leffler /* 1884b9234fafSSam Leffler * find the correct route for outer IPv4 1885b9234fafSSam Leffler * header, compute tunnel MTU. 1886b9234fafSSam Leffler * 1887b9234fafSSam Leffler * XXX BUG ALERT 1888b9234fafSSam Leffler * The "dummyifp" code relies upon the fact 1889b9234fafSSam Leffler * that icmp_error() touches only ifp->if_mtu. 1890b9234fafSSam Leffler */ 1891b9234fafSSam Leffler /*XXX*/ 1892b9234fafSSam Leffler destifp = NULL; 1893b9234fafSSam Leffler if (sp->req != NULL 1894b9234fafSSam Leffler && sp->req->sav != NULL 1895b9234fafSSam Leffler && sp->req->sav->sah != NULL) { 189602c1c707SAndre Oppermann ro = &sp->req->sav->sah->sa_route; 189702c1c707SAndre Oppermann if (ro->ro_rt && ro->ro_rt->rt_ifp) { 1898b9234fafSSam Leffler dummyifp.if_mtu = 189957ab3660SBruce M Simpson ro->ro_rt->rt_rmx.rmx_mtu ? 190057ab3660SBruce M Simpson ro->ro_rt->rt_rmx.rmx_mtu : 190102c1c707SAndre Oppermann ro->ro_rt->rt_ifp->if_mtu; 1902b9234fafSSam Leffler dummyifp.if_mtu -= ipsechdr; 1903b9234fafSSam Leffler destifp = &dummyifp; 1904b9234fafSSam Leffler } 1905b9234fafSSam Leffler } 1906b9234fafSSam Leffler 190702c1c707SAndre Oppermann #ifdef IPSEC 190802c1c707SAndre Oppermann key_freesp(sp); 190902c1c707SAndre Oppermann #else /* FAST_IPSEC */ 1910b9234fafSSam Leffler KEY_FREESP(&sp); 191102c1c707SAndre Oppermann #endif 191202c1c707SAndre Oppermann ipstat.ips_cantfrag++; 191302c1c707SAndre Oppermann break; 191402c1c707SAndre Oppermann } else 191502c1c707SAndre Oppermann #endif /*IPSEC || FAST_IPSEC*/ 19169b932e9eSAndre Oppermann /* 19179b932e9eSAndre Oppermann * When doing source routing 'ia' can be NULL. Fall back 19189b932e9eSAndre Oppermann * to the minimum guaranteed routeable packet size and use 19199b932e9eSAndre Oppermann * the same hack as IPSEC to setup a dummyifp for icmp. 19209b932e9eSAndre Oppermann */ 19219b932e9eSAndre Oppermann if (ia == NULL) { 19229b932e9eSAndre Oppermann dummyifp.if_mtu = IP_MSS; 19239b932e9eSAndre Oppermann destifp = &dummyifp; 19249b932e9eSAndre Oppermann } else 192502c1c707SAndre Oppermann destifp = ia->ia_ifp; 192602c1c707SAndre Oppermann #if defined(IPSEC) || defined(FAST_IPSEC) 1927b9234fafSSam Leffler } 192802c1c707SAndre Oppermann #endif /*IPSEC || FAST_IPSEC*/ 1929df8bae1dSRodney W. Grimes ipstat.ips_cantfrag++; 1930df8bae1dSRodney W. Grimes break; 1931df8bae1dSRodney W. Grimes 1932df8bae1dSRodney W. Grimes case ENOBUFS: 1933df285b3dSMike Silbersack /* 1934df285b3dSMike Silbersack * A router should not generate ICMP_SOURCEQUENCH as 1935df285b3dSMike Silbersack * required in RFC1812 Requirements for IP Version 4 Routers. 1936df285b3dSMike Silbersack * Source quench could be a big problem under DoS attacks, 1937df285b3dSMike Silbersack * or if the underlying interface is rate-limited. 1938df285b3dSMike Silbersack * Those who need source quench packets may re-enable them 1939df285b3dSMike Silbersack * via the net.inet.ip.sendsourcequench sysctl. 1940df285b3dSMike Silbersack */ 1941df285b3dSMike Silbersack if (ip_sendsourcequench == 0) { 1942df285b3dSMike Silbersack m_freem(mcopy); 1943df285b3dSMike Silbersack return; 1944df285b3dSMike Silbersack } else { 1945df8bae1dSRodney W. Grimes type = ICMP_SOURCEQUENCH; 1946df8bae1dSRodney W. Grimes code = 0; 1947df285b3dSMike Silbersack } 1948df8bae1dSRodney W. Grimes break; 19493a06e3e0SRuslan Ermilov 19503a06e3e0SRuslan Ermilov case EACCES: /* ipfw denied packet */ 19513a06e3e0SRuslan Ermilov m_freem(mcopy); 19523a06e3e0SRuslan Ermilov return; 1953df8bae1dSRodney W. Grimes } 19549b932e9eSAndre Oppermann icmp_error(mcopy, type, code, dest.s_addr, destifp); 1955df8bae1dSRodney W. Grimes } 1956df8bae1dSRodney W. Grimes 195782c23ebaSBill Fenner void 195882c23ebaSBill Fenner ip_savecontrol(inp, mp, ip, m) 195982c23ebaSBill Fenner register struct inpcb *inp; 196082c23ebaSBill Fenner register struct mbuf **mp; 196182c23ebaSBill Fenner register struct ip *ip; 196282c23ebaSBill Fenner register struct mbuf *m; 196382c23ebaSBill Fenner { 1964be8a62e8SPoul-Henning Kamp if (inp->inp_socket->so_options & (SO_BINTIME | SO_TIMESTAMP)) { 1965be8a62e8SPoul-Henning Kamp struct bintime bt; 1966be8a62e8SPoul-Henning Kamp 1967be8a62e8SPoul-Henning Kamp bintime(&bt); 1968be8a62e8SPoul-Henning Kamp if (inp->inp_socket->so_options & SO_BINTIME) { 1969be8a62e8SPoul-Henning Kamp *mp = sbcreatecontrol((caddr_t) &bt, sizeof(bt), 1970be8a62e8SPoul-Henning Kamp SCM_BINTIME, SOL_SOCKET); 1971be8a62e8SPoul-Henning Kamp if (*mp) 1972be8a62e8SPoul-Henning Kamp mp = &(*mp)->m_next; 1973be8a62e8SPoul-Henning Kamp } 197482c23ebaSBill Fenner if (inp->inp_socket->so_options & SO_TIMESTAMP) { 197582c23ebaSBill Fenner struct timeval tv; 197682c23ebaSBill Fenner 1977be8a62e8SPoul-Henning Kamp bintime2timeval(&bt, &tv); 197882c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv), 197982c23ebaSBill Fenner SCM_TIMESTAMP, SOL_SOCKET); 198082c23ebaSBill Fenner if (*mp) 198182c23ebaSBill Fenner mp = &(*mp)->m_next; 19824cc20ab1SSeigo Tanimura } 1983be8a62e8SPoul-Henning Kamp } 198482c23ebaSBill Fenner if (inp->inp_flags & INP_RECVDSTADDR) { 198582c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) &ip->ip_dst, 198682c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVDSTADDR, IPPROTO_IP); 198782c23ebaSBill Fenner if (*mp) 198882c23ebaSBill Fenner mp = &(*mp)->m_next; 198982c23ebaSBill Fenner } 19904957466bSMatthew N. Dodd if (inp->inp_flags & INP_RECVTTL) { 19914957466bSMatthew N. Dodd *mp = sbcreatecontrol((caddr_t) &ip->ip_ttl, 19924957466bSMatthew N. Dodd sizeof(u_char), IP_RECVTTL, IPPROTO_IP); 19934957466bSMatthew N. Dodd if (*mp) 19944957466bSMatthew N. Dodd mp = &(*mp)->m_next; 19954957466bSMatthew N. Dodd } 199682c23ebaSBill Fenner #ifdef notyet 199782c23ebaSBill Fenner /* XXX 199882c23ebaSBill Fenner * Moving these out of udp_input() made them even more broken 199982c23ebaSBill Fenner * than they already were. 200082c23ebaSBill Fenner */ 200182c23ebaSBill Fenner /* options were tossed already */ 200282c23ebaSBill Fenner if (inp->inp_flags & INP_RECVOPTS) { 200382c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) opts_deleted_above, 200482c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVOPTS, IPPROTO_IP); 200582c23ebaSBill Fenner if (*mp) 200682c23ebaSBill Fenner mp = &(*mp)->m_next; 200782c23ebaSBill Fenner } 200882c23ebaSBill Fenner /* ip_srcroute doesn't do what we want here, need to fix */ 200982c23ebaSBill Fenner if (inp->inp_flags & INP_RECVRETOPTS) { 2010e0982661SAndre Oppermann *mp = sbcreatecontrol((caddr_t) ip_srcroute(m), 201182c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVRETOPTS, IPPROTO_IP); 201282c23ebaSBill Fenner if (*mp) 201382c23ebaSBill Fenner mp = &(*mp)->m_next; 201482c23ebaSBill Fenner } 201582c23ebaSBill Fenner #endif 201682c23ebaSBill Fenner if (inp->inp_flags & INP_RECVIF) { 2017d314ad7bSJulian Elischer struct ifnet *ifp; 2018d314ad7bSJulian Elischer struct sdlbuf { 201982c23ebaSBill Fenner struct sockaddr_dl sdl; 2020d314ad7bSJulian Elischer u_char pad[32]; 2021d314ad7bSJulian Elischer } sdlbuf; 2022d314ad7bSJulian Elischer struct sockaddr_dl *sdp; 2023d314ad7bSJulian Elischer struct sockaddr_dl *sdl2 = &sdlbuf.sdl; 202482c23ebaSBill Fenner 2025d314ad7bSJulian Elischer if (((ifp = m->m_pkthdr.rcvif)) 2026d314ad7bSJulian Elischer && ( ifp->if_index && (ifp->if_index <= if_index))) { 2027f9132cebSJonathan Lemon sdp = (struct sockaddr_dl *) 2028f9132cebSJonathan Lemon (ifaddr_byindex(ifp->if_index)->ifa_addr); 2029d314ad7bSJulian Elischer /* 2030d314ad7bSJulian Elischer * Change our mind and don't try copy. 2031d314ad7bSJulian Elischer */ 2032d314ad7bSJulian Elischer if ((sdp->sdl_family != AF_LINK) 2033d314ad7bSJulian Elischer || (sdp->sdl_len > sizeof(sdlbuf))) { 2034d314ad7bSJulian Elischer goto makedummy; 2035d314ad7bSJulian Elischer } 2036d314ad7bSJulian Elischer bcopy(sdp, sdl2, sdp->sdl_len); 2037d314ad7bSJulian Elischer } else { 2038d314ad7bSJulian Elischer makedummy: 2039d314ad7bSJulian Elischer sdl2->sdl_len 2040d314ad7bSJulian Elischer = offsetof(struct sockaddr_dl, sdl_data[0]); 2041d314ad7bSJulian Elischer sdl2->sdl_family = AF_LINK; 2042d314ad7bSJulian Elischer sdl2->sdl_index = 0; 2043d314ad7bSJulian Elischer sdl2->sdl_nlen = sdl2->sdl_alen = sdl2->sdl_slen = 0; 2044d314ad7bSJulian Elischer } 2045d314ad7bSJulian Elischer *mp = sbcreatecontrol((caddr_t) sdl2, sdl2->sdl_len, 204682c23ebaSBill Fenner IP_RECVIF, IPPROTO_IP); 204782c23ebaSBill Fenner if (*mp) 204882c23ebaSBill Fenner mp = &(*mp)->m_next; 204982c23ebaSBill Fenner } 205082c23ebaSBill Fenner } 205182c23ebaSBill Fenner 20524d2e3692SLuigi Rizzo /* 20534d2e3692SLuigi Rizzo * XXX these routines are called from the upper part of the kernel. 20544d2e3692SLuigi Rizzo * They need to be locked when we remove Giant. 20554d2e3692SLuigi Rizzo * 20564d2e3692SLuigi Rizzo * They could also be moved to ip_mroute.c, since all the RSVP 20574d2e3692SLuigi Rizzo * handling is done there already. 20584d2e3692SLuigi Rizzo */ 20594d2e3692SLuigi Rizzo static int ip_rsvp_on; 20604d2e3692SLuigi Rizzo struct socket *ip_rsvpd; 2061df8bae1dSRodney W. Grimes int 2062f0068c4aSGarrett Wollman ip_rsvp_init(struct socket *so) 2063f0068c4aSGarrett Wollman { 2064f0068c4aSGarrett Wollman if (so->so_type != SOCK_RAW || 2065f0068c4aSGarrett Wollman so->so_proto->pr_protocol != IPPROTO_RSVP) 2066f0068c4aSGarrett Wollman return EOPNOTSUPP; 2067f0068c4aSGarrett Wollman 2068f0068c4aSGarrett Wollman if (ip_rsvpd != NULL) 2069f0068c4aSGarrett Wollman return EADDRINUSE; 2070f0068c4aSGarrett Wollman 2071f0068c4aSGarrett Wollman ip_rsvpd = so; 20721c5de19aSGarrett Wollman /* 20731c5de19aSGarrett Wollman * This may seem silly, but we need to be sure we don't over-increment 20741c5de19aSGarrett Wollman * the RSVP counter, in case something slips up. 20751c5de19aSGarrett Wollman */ 20761c5de19aSGarrett Wollman if (!ip_rsvp_on) { 20771c5de19aSGarrett Wollman ip_rsvp_on = 1; 20781c5de19aSGarrett Wollman rsvp_on++; 20791c5de19aSGarrett Wollman } 2080f0068c4aSGarrett Wollman 2081f0068c4aSGarrett Wollman return 0; 2082f0068c4aSGarrett Wollman } 2083f0068c4aSGarrett Wollman 2084f0068c4aSGarrett Wollman int 2085f0068c4aSGarrett Wollman ip_rsvp_done(void) 2086f0068c4aSGarrett Wollman { 2087f0068c4aSGarrett Wollman ip_rsvpd = NULL; 20881c5de19aSGarrett Wollman /* 20891c5de19aSGarrett Wollman * This may seem silly, but we need to be sure we don't over-decrement 20901c5de19aSGarrett Wollman * the RSVP counter, in case something slips up. 20911c5de19aSGarrett Wollman */ 20921c5de19aSGarrett Wollman if (ip_rsvp_on) { 20931c5de19aSGarrett Wollman ip_rsvp_on = 0; 20941c5de19aSGarrett Wollman rsvp_on--; 20951c5de19aSGarrett Wollman } 2096f0068c4aSGarrett Wollman return 0; 2097f0068c4aSGarrett Wollman } 2098bbb4330bSLuigi Rizzo 2099bbb4330bSLuigi Rizzo void 2100bbb4330bSLuigi Rizzo rsvp_input(struct mbuf *m, int off) /* XXX must fixup manually */ 2101bbb4330bSLuigi Rizzo { 2102bbb4330bSLuigi Rizzo if (rsvp_input_p) { /* call the real one if loaded */ 2103bbb4330bSLuigi Rizzo rsvp_input_p(m, off); 2104bbb4330bSLuigi Rizzo return; 2105bbb4330bSLuigi Rizzo } 2106bbb4330bSLuigi Rizzo 2107bbb4330bSLuigi Rizzo /* Can still get packets with rsvp_on = 0 if there is a local member 2108bbb4330bSLuigi Rizzo * of the group to which the RSVP packet is addressed. But in this 2109bbb4330bSLuigi Rizzo * case we want to throw the packet away. 2110bbb4330bSLuigi Rizzo */ 2111bbb4330bSLuigi Rizzo 2112bbb4330bSLuigi Rizzo if (!rsvp_on) { 2113bbb4330bSLuigi Rizzo m_freem(m); 2114bbb4330bSLuigi Rizzo return; 2115bbb4330bSLuigi Rizzo } 2116bbb4330bSLuigi Rizzo 2117bbb4330bSLuigi Rizzo if (ip_rsvpd != NULL) { 2118bbb4330bSLuigi Rizzo rip_input(m, off); 2119bbb4330bSLuigi Rizzo return; 2120bbb4330bSLuigi Rizzo } 2121bbb4330bSLuigi Rizzo /* Drop the packet */ 2122bbb4330bSLuigi Rizzo m_freem(m); 2123bbb4330bSLuigi Rizzo } 2124