1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1982, 1986, 1988, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 6df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 7df8bae1dSRodney W. Grimes * are met: 8df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 9df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 10df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 12df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 13df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 14df8bae1dSRodney W. Grimes * must display the following acknowledgement: 15df8bae1dSRodney W. Grimes * This product includes software developed by the University of 16df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 17df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 18df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 19df8bae1dSRodney W. Grimes * without specific prior written permission. 20df8bae1dSRodney W. Grimes * 21df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31df8bae1dSRodney W. Grimes * SUCH DAMAGE. 32df8bae1dSRodney W. Grimes * 33df8bae1dSRodney W. Grimes * @(#)ip_input.c 8.2 (Berkeley) 1/4/94 34c3aac50fSPeter Wemm * $FreeBSD$ 35df8bae1dSRodney W. Grimes */ 36df8bae1dSRodney W. Grimes 37e4f4247aSEivind Eklund #include "opt_bootp.h" 3874a9466cSGary Palmer #include "opt_ipfw.h" 39b715f178SLuigi Rizzo #include "opt_ipdn.h" 40fbd1372aSJoerg Wunsch #include "opt_ipdivert.h" 411ee25934SPeter Wemm #include "opt_ipfilter.h" 4227108a15SDag-Erling Smørgrav #include "opt_ipstealth.h" 436a800098SYoshinobu Inoue #include "opt_ipsec.h" 4436b0360bSRobert Watson #include "opt_mac.h" 45c4ac87eaSDarren Reed #include "opt_pfil_hooks.h" 4664dddc18SKris Kennaway #include "opt_random_ip_id.h" 4774a9466cSGary Palmer 48df8bae1dSRodney W. Grimes #include <sys/param.h> 49df8bae1dSRodney W. Grimes #include <sys/systm.h> 5036b0360bSRobert Watson #include <sys/mac.h> 51df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 52b715f178SLuigi Rizzo #include <sys/malloc.h> 53df8bae1dSRodney W. Grimes #include <sys/domain.h> 54df8bae1dSRodney W. Grimes #include <sys/protosw.h> 55df8bae1dSRodney W. Grimes #include <sys/socket.h> 56df8bae1dSRodney W. Grimes #include <sys/time.h> 57df8bae1dSRodney W. Grimes #include <sys/kernel.h> 581025071fSGarrett Wollman #include <sys/syslog.h> 59b5e8ce9fSBruce Evans #include <sys/sysctl.h> 60df8bae1dSRodney W. Grimes 61c85540ddSAndrey A. Chernov #include <net/pfil.h> 62df8bae1dSRodney W. Grimes #include <net/if.h> 639494d596SBrooks Davis #include <net/if_types.h> 64d314ad7bSJulian Elischer #include <net/if_var.h> 6582c23ebaSBill Fenner #include <net/if_dl.h> 66df8bae1dSRodney W. Grimes #include <net/route.h> 67748e0b0aSGarrett Wollman #include <net/netisr.h> 68367d34f8SBrian Somers #include <net/intrq.h> 69df8bae1dSRodney W. Grimes 70df8bae1dSRodney W. Grimes #include <netinet/in.h> 71df8bae1dSRodney W. Grimes #include <netinet/in_systm.h> 72b5e8ce9fSBruce Evans #include <netinet/in_var.h> 73df8bae1dSRodney W. Grimes #include <netinet/ip.h> 74df8bae1dSRodney W. Grimes #include <netinet/in_pcb.h> 75df8bae1dSRodney W. Grimes #include <netinet/ip_var.h> 76df8bae1dSRodney W. Grimes #include <netinet/ip_icmp.h> 7758938916SGarrett Wollman #include <machine/in_cksum.h> 78df8bae1dSRodney W. Grimes 79f0068c4aSGarrett Wollman #include <sys/socketvar.h> 806ddbf1e2SGary Palmer 816ddbf1e2SGary Palmer #include <netinet/ip_fw.h> 82db69a05dSPaul Saab #include <netinet/ip_dummynet.h> 83db69a05dSPaul Saab 846a800098SYoshinobu Inoue #ifdef IPSEC 856a800098SYoshinobu Inoue #include <netinet6/ipsec.h> 866a800098SYoshinobu Inoue #include <netkey/key.h> 876a800098SYoshinobu Inoue #endif 886a800098SYoshinobu Inoue 89b9234fafSSam Leffler #ifdef FAST_IPSEC 90b9234fafSSam Leffler #include <netipsec/ipsec.h> 91b9234fafSSam Leffler #include <netipsec/key.h> 92b9234fafSSam Leffler #endif 93b9234fafSSam Leffler 941c5de19aSGarrett Wollman int rsvp_on = 0; 95f0068c4aSGarrett Wollman 961f91d8c5SDavid Greenman int ipforwarding = 0; 970312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_FORWARDING, forwarding, CTLFLAG_RW, 983d177f46SBill Fumerola &ipforwarding, 0, "Enable IP forwarding between interfaces"); 990312fbe9SPoul-Henning Kamp 100d4fb926cSGarrett Wollman static int ipsendredirects = 1; /* XXX */ 1010312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_SENDREDIRECTS, redirect, CTLFLAG_RW, 1023d177f46SBill Fumerola &ipsendredirects, 0, "Enable sending IP redirects"); 1030312fbe9SPoul-Henning Kamp 104df8bae1dSRodney W. Grimes int ip_defttl = IPDEFTTL; 1050312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_DEFTTL, ttl, CTLFLAG_RW, 1063d177f46SBill Fumerola &ip_defttl, 0, "Maximum TTL on IP packets"); 1070312fbe9SPoul-Henning Kamp 1080312fbe9SPoul-Henning Kamp static int ip_dosourceroute = 0; 1090312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_SOURCEROUTE, sourceroute, CTLFLAG_RW, 1103d177f46SBill Fumerola &ip_dosourceroute, 0, "Enable forwarding source routed IP packets"); 1114fce5804SGuido van Rooij 1124fce5804SGuido van Rooij static int ip_acceptsourceroute = 0; 1134fce5804SGuido van Rooij SYSCTL_INT(_net_inet_ip, IPCTL_ACCEPTSOURCEROUTE, accept_sourceroute, 1143d177f46SBill Fumerola CTLFLAG_RW, &ip_acceptsourceroute, 0, 1153d177f46SBill Fumerola "Enable accepting source routed IP packets"); 1166a800098SYoshinobu Inoue 1176a800098SYoshinobu Inoue static int ip_keepfaith = 0; 1186a800098SYoshinobu Inoue SYSCTL_INT(_net_inet_ip, IPCTL_KEEPFAITH, keepfaith, CTLFLAG_RW, 1196a800098SYoshinobu Inoue &ip_keepfaith, 0, 1206a800098SYoshinobu Inoue "Enable packet capture for FAITH IPv4->IPv6 translater daemon"); 1216a800098SYoshinobu Inoue 122690a6055SJesper Skriver static int ip_nfragpackets = 0; 12396c2b042SJesper Skriver static int ip_maxfragpackets; /* initialized in ip_init() */ 124690a6055SJesper Skriver SYSCTL_INT(_net_inet_ip, OID_AUTO, maxfragpackets, CTLFLAG_RW, 125690a6055SJesper Skriver &ip_maxfragpackets, 0, 126690a6055SJesper Skriver "Maximum number of IPv4 fragment reassembly queue entries"); 127690a6055SJesper Skriver 128823db0e9SDon Lewis /* 129823db0e9SDon Lewis * XXX - Setting ip_checkinterface mostly implements the receive side of 130823db0e9SDon Lewis * the Strong ES model described in RFC 1122, but since the routing table 131a8f12100SDon Lewis * and transmit implementation do not implement the Strong ES model, 132823db0e9SDon Lewis * setting this to 1 results in an odd hybrid. 1333f67c834SDon Lewis * 134a8f12100SDon Lewis * XXX - ip_checkinterface currently must be disabled if you use ipnat 135a8f12100SDon Lewis * to translate the destination address to another local interface. 1363f67c834SDon Lewis * 1373f67c834SDon Lewis * XXX - ip_checkinterface must be disabled if you add IP aliases 1383f67c834SDon Lewis * to the loopback interface instead of the interface where the 1393f67c834SDon Lewis * packets for those addresses are received. 140823db0e9SDon Lewis */ 141b3e95d4eSJonathan Lemon static int ip_checkinterface = 1; 142b3e95d4eSJonathan Lemon SYSCTL_INT(_net_inet_ip, OID_AUTO, check_interface, CTLFLAG_RW, 143b3e95d4eSJonathan Lemon &ip_checkinterface, 0, "Verify packet arrives on correct interface"); 144b3e95d4eSJonathan Lemon 145df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1460312fbe9SPoul-Henning Kamp static int ipprintfs = 0; 147df8bae1dSRodney W. Grimes #endif 148df8bae1dSRodney W. Grimes 149ca925d9cSJonathan Lemon static int ipqmaxlen = IFQ_MAXLEN; 150ca925d9cSJonathan Lemon 151df8bae1dSRodney W. Grimes extern struct domain inetdomain; 152f0ffb944SJulian Elischer extern struct protosw inetsw[]; 153df8bae1dSRodney W. Grimes u_char ip_protox[IPPROTO_MAX]; 15459562606SGarrett Wollman struct in_ifaddrhead in_ifaddrhead; /* first inet address */ 155ca925d9cSJonathan Lemon struct in_ifaddrhashhead *in_ifaddrhashtbl; /* inet addr hash table */ 156ca925d9cSJonathan Lemon u_long in_ifaddrhmask; /* mask for hash table */ 157ca925d9cSJonathan Lemon 158afed1375SDavid Greenman SYSCTL_INT(_net_inet_ip, IPCTL_INTRQMAXLEN, intr_queue_maxlen, CTLFLAG_RW, 1593d177f46SBill Fumerola &ipintrq.ifq_maxlen, 0, "Maximum size of the IP input queue"); 1600312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_INTRQDROPS, intr_queue_drops, CTLFLAG_RD, 1613d177f46SBill Fumerola &ipintrq.ifq_drops, 0, "Number of packets dropped from the IP input queue"); 162df8bae1dSRodney W. Grimes 163f23b4c91SGarrett Wollman struct ipstat ipstat; 164c73d99b5SRuslan Ermilov SYSCTL_STRUCT(_net_inet_ip, IPCTL_STATS, stats, CTLFLAG_RW, 1653d177f46SBill Fumerola &ipstat, ipstat, "IP statistics (struct ipstat, netinet/ip_var.h)"); 166194a213eSAndrey A. Chernov 167194a213eSAndrey A. Chernov /* Packet reassembly stuff */ 168194a213eSAndrey A. Chernov #define IPREASS_NHASH_LOG2 6 169194a213eSAndrey A. Chernov #define IPREASS_NHASH (1 << IPREASS_NHASH_LOG2) 170194a213eSAndrey A. Chernov #define IPREASS_HMASK (IPREASS_NHASH - 1) 171194a213eSAndrey A. Chernov #define IPREASS_HASH(x,y) \ 172831a80b0SMatthew Dillon (((((x) & 0xF) | ((((x) >> 8) & 0xF) << 4)) ^ (y)) & IPREASS_HMASK) 173194a213eSAndrey A. Chernov 174462b86feSPoul-Henning Kamp static TAILQ_HEAD(ipqhead, ipq) ipq[IPREASS_NHASH]; 175194a213eSAndrey A. Chernov static int nipq = 0; /* total # of reass queues */ 176194a213eSAndrey A. Chernov static int maxnipq; 177f23b4c91SGarrett Wollman 1780312fbe9SPoul-Henning Kamp #ifdef IPCTL_DEFMTU 1790312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_DEFMTU, mtu, CTLFLAG_RW, 1803d177f46SBill Fumerola &ip_mtu, 0, "Default MTU"); 1810312fbe9SPoul-Henning Kamp #endif 1820312fbe9SPoul-Henning Kamp 1831b968362SDag-Erling Smørgrav #ifdef IPSTEALTH 1841b968362SDag-Erling Smørgrav static int ipstealth = 0; 1851b968362SDag-Erling Smørgrav SYSCTL_INT(_net_inet_ip, OID_AUTO, stealth, CTLFLAG_RW, 1861b968362SDag-Erling Smørgrav &ipstealth, 0, ""); 1871b968362SDag-Erling Smørgrav #endif 1881b968362SDag-Erling Smørgrav 189cfe8b629SGarrett Wollman 19023bf9953SPoul-Henning Kamp /* Firewall hooks */ 19123bf9953SPoul-Henning Kamp ip_fw_chk_t *ip_fw_chk_ptr; 1929fcc0795SLuigi Rizzo int fw_enable = 1 ; 193e7319babSPoul-Henning Kamp 194db69a05dSPaul Saab /* Dummynet hooks */ 195db69a05dSPaul Saab ip_dn_io_t *ip_dn_io_ptr; 196b715f178SLuigi Rizzo 197afed1b49SDarren Reed 198e7319babSPoul-Henning Kamp /* 1994d2e3692SLuigi Rizzo * XXX this is ugly -- the following two global variables are 2004d2e3692SLuigi Rizzo * used to store packet state while it travels through the stack. 2014d2e3692SLuigi Rizzo * Note that the code even makes assumptions on the size and 2024d2e3692SLuigi Rizzo * alignment of fields inside struct ip_srcrt so e.g. adding some 2034d2e3692SLuigi Rizzo * fields will break the code. This needs to be fixed. 2044d2e3692SLuigi Rizzo * 205df8bae1dSRodney W. Grimes * We need to save the IP options in case a protocol wants to respond 206df8bae1dSRodney W. Grimes * to an incoming packet over the same route if the packet got here 207df8bae1dSRodney W. Grimes * using IP source routing. This allows connection establishment and 208df8bae1dSRodney W. Grimes * maintenance when the remote end is on a network that is not known 209df8bae1dSRodney W. Grimes * to us. 210df8bae1dSRodney W. Grimes */ 2110312fbe9SPoul-Henning Kamp static int ip_nhops = 0; 212df8bae1dSRodney W. Grimes static struct ip_srcrt { 213df8bae1dSRodney W. Grimes struct in_addr dst; /* final destination */ 214df8bae1dSRodney W. Grimes char nop; /* one NOP to align */ 215df8bae1dSRodney W. Grimes char srcopt[IPOPT_OFFSET + 1]; /* OPTVAL, OLEN and OFFSET */ 216df8bae1dSRodney W. Grimes struct in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)]; 217df8bae1dSRodney W. Grimes } ip_srcrt; 218df8bae1dSRodney W. Grimes 2194d77a549SAlfred Perlstein static void save_rte(u_char *, struct in_addr); 2202b25acc1SLuigi Rizzo static int ip_dooptions(struct mbuf *m, int, 2212b25acc1SLuigi Rizzo struct sockaddr_in *next_hop); 2222b25acc1SLuigi Rizzo static void ip_forward(struct mbuf *m, int srcrt, 2232b25acc1SLuigi Rizzo struct sockaddr_in *next_hop); 2244d77a549SAlfred Perlstein static void ip_freef(struct ipqhead *, struct ipq *); 2252b25acc1SLuigi Rizzo static struct mbuf *ip_reass(struct mbuf *, struct ipqhead *, 2262b25acc1SLuigi Rizzo struct ipq *, u_int32_t *, u_int16_t *); 2274d77a549SAlfred Perlstein static void ipintr(void); 2288948e4baSArchie Cobbs 229df8bae1dSRodney W. Grimes /* 230df8bae1dSRodney W. Grimes * IP initialization: fill in IP protocol switch table. 231df8bae1dSRodney W. Grimes * All protocols not implemented in kernel go to raw IP protocol handler. 232df8bae1dSRodney W. Grimes */ 233df8bae1dSRodney W. Grimes void 234df8bae1dSRodney W. Grimes ip_init() 235df8bae1dSRodney W. Grimes { 236f0ffb944SJulian Elischer register struct protosw *pr; 237df8bae1dSRodney W. Grimes register int i; 238df8bae1dSRodney W. Grimes 23959562606SGarrett Wollman TAILQ_INIT(&in_ifaddrhead); 240ca925d9cSJonathan Lemon in_ifaddrhashtbl = hashinit(INADDR_NHASH, M_IFADDR, &in_ifaddrhmask); 241f0ffb944SJulian Elischer pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW); 242df8bae1dSRodney W. Grimes if (pr == 0) 243df8bae1dSRodney W. Grimes panic("ip_init"); 244df8bae1dSRodney W. Grimes for (i = 0; i < IPPROTO_MAX; i++) 245df8bae1dSRodney W. Grimes ip_protox[i] = pr - inetsw; 246f0ffb944SJulian Elischer for (pr = inetdomain.dom_protosw; 247f0ffb944SJulian Elischer pr < inetdomain.dom_protoswNPROTOSW; pr++) 248df8bae1dSRodney W. Grimes if (pr->pr_domain->dom_family == PF_INET && 249df8bae1dSRodney W. Grimes pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) 250df8bae1dSRodney W. Grimes ip_protox[pr->pr_protocol] = pr - inetsw; 251194a213eSAndrey A. Chernov 252194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) 253462b86feSPoul-Henning Kamp TAILQ_INIT(&ipq[i]); 254194a213eSAndrey A. Chernov 255194a213eSAndrey A. Chernov maxnipq = nmbclusters / 4; 25696c2b042SJesper Skriver ip_maxfragpackets = nmbclusters / 4; 257194a213eSAndrey A. Chernov 25864dddc18SKris Kennaway #ifndef RANDOM_IP_ID 259227ee8a1SPoul-Henning Kamp ip_id = time_second & 0xffff; 26064dddc18SKris Kennaway #endif 261df8bae1dSRodney W. Grimes ipintrq.ifq_maxlen = ipqmaxlen; 2626008862bSJohn Baldwin mtx_init(&ipintrq.ifq_mtx, "ip_inq", NULL, MTX_DEF); 263bedbd47eSMike Smith ipintrq_present = 1; 264242c5536SPeter Wemm 265242c5536SPeter Wemm register_netisr(NETISR_IP, ipintr); 266df8bae1dSRodney W. Grimes } 267df8bae1dSRodney W. Grimes 2684d2e3692SLuigi Rizzo /* 2694d2e3692SLuigi Rizzo * XXX watch out this one. It is perhaps used as a cache for 2704d2e3692SLuigi Rizzo * the most recently used route ? it is cleared in in_addroute() 2714d2e3692SLuigi Rizzo * when a new route is successfully created. 2724d2e3692SLuigi Rizzo */ 2731e3d5af0SRuslan Ermilov struct route ipforward_rt; 274df8bae1dSRodney W. Grimes 275df8bae1dSRodney W. Grimes /* 276df8bae1dSRodney W. Grimes * Ip input routine. Checksum and byte swap header. If fragmented 277df8bae1dSRodney W. Grimes * try to reassemble. Process options. Pass to next level. 278df8bae1dSRodney W. Grimes */ 279c67b1d17SGarrett Wollman void 280c67b1d17SGarrett Wollman ip_input(struct mbuf *m) 281df8bae1dSRodney W. Grimes { 28223bf9953SPoul-Henning Kamp struct ip *ip; 28323bf9953SPoul-Henning Kamp struct ipq *fp; 2845da9f8faSJosef Karthauser struct in_ifaddr *ia = NULL; 285ca925d9cSJonathan Lemon struct ifaddr *ifa; 286823db0e9SDon Lewis int i, hlen, checkif; 28747c861ecSBrian Somers u_short sum; 2887538a9a0SJonathan Lemon struct in_addr pkt_dst; 2898948e4baSArchie Cobbs u_int32_t divert_info = 0; /* packet divert/tee info */ 2902b25acc1SLuigi Rizzo struct ip_fw_args args; 291c4ac87eaSDarren Reed #ifdef PFIL_HOOKS 292c4ac87eaSDarren Reed struct packet_filter_hook *pfh; 293c4ac87eaSDarren Reed struct mbuf *m0; 294c4ac87eaSDarren Reed int rv; 295c4ac87eaSDarren Reed #endif /* PFIL_HOOKS */ 296b9234fafSSam Leffler #ifdef FAST_IPSEC 297b9234fafSSam Leffler struct m_tag *mtag; 298b9234fafSSam Leffler struct tdb_ident *tdbi; 299b9234fafSSam Leffler struct secpolicy *sp; 300b9234fafSSam Leffler int s, error; 301b9234fafSSam Leffler #endif /* FAST_IPSEC */ 302b715f178SLuigi Rizzo 3032b25acc1SLuigi Rizzo args.eh = NULL; 3042b25acc1SLuigi Rizzo args.oif = NULL; 3052b25acc1SLuigi Rizzo args.rule = NULL; 3062b25acc1SLuigi Rizzo args.divert_rule = 0; /* divert cookie */ 3072b25acc1SLuigi Rizzo args.next_hop = NULL; 3088948e4baSArchie Cobbs 3092b25acc1SLuigi Rizzo /* Grab info from MT_TAG mbufs prepended to the chain. */ 3102b25acc1SLuigi Rizzo for (; m && m->m_type == MT_TAG; m = m->m_next) { 3115d846453SSam Leffler switch(m->_m_tag_id) { 3122b25acc1SLuigi Rizzo default: 3132b25acc1SLuigi Rizzo printf("ip_input: unrecognised MT_TAG tag %d\n", 3145d846453SSam Leffler m->_m_tag_id); 3152b25acc1SLuigi Rizzo break; 3162b25acc1SLuigi Rizzo 3172b25acc1SLuigi Rizzo case PACKET_TAG_DUMMYNET: 3182b25acc1SLuigi Rizzo args.rule = ((struct dn_pkt *)m)->rule; 3192b25acc1SLuigi Rizzo break; 3202b25acc1SLuigi Rizzo 3212b25acc1SLuigi Rizzo case PACKET_TAG_DIVERT: 3227627c6cbSMaxime Henrion args.divert_rule = (intptr_t)m->m_hdr.mh_data & 0xffff; 3232b25acc1SLuigi Rizzo break; 3242b25acc1SLuigi Rizzo 3252b25acc1SLuigi Rizzo case PACKET_TAG_IPFORWARD: 3262b25acc1SLuigi Rizzo args.next_hop = (struct sockaddr_in *)m->m_hdr.mh_data; 3272b25acc1SLuigi Rizzo break; 3282b25acc1SLuigi Rizzo } 3292b25acc1SLuigi Rizzo } 330df8bae1dSRodney W. Grimes 331db40007dSAndrew R. Reiter KASSERT(m != NULL && (m->m_flags & M_PKTHDR) != 0, 332db40007dSAndrew R. Reiter ("ip_input: no HDR")); 333db40007dSAndrew R. Reiter 3342b25acc1SLuigi Rizzo if (args.rule) { /* dummynet already filtered us */ 3352b25acc1SLuigi Rizzo ip = mtod(m, struct ip *); 33653be11f6SPoul-Henning Kamp hlen = ip->ip_hl << 2; 3372b25acc1SLuigi Rizzo goto iphack ; 3382b25acc1SLuigi Rizzo } 3392b25acc1SLuigi Rizzo 340df8bae1dSRodney W. Grimes ipstat.ips_total++; 34158938916SGarrett Wollman 34258938916SGarrett Wollman if (m->m_pkthdr.len < sizeof(struct ip)) 34358938916SGarrett Wollman goto tooshort; 34458938916SGarrett Wollman 345df8bae1dSRodney W. Grimes if (m->m_len < sizeof (struct ip) && 346df8bae1dSRodney W. Grimes (m = m_pullup(m, sizeof (struct ip))) == 0) { 347df8bae1dSRodney W. Grimes ipstat.ips_toosmall++; 348c67b1d17SGarrett Wollman return; 349df8bae1dSRodney W. Grimes } 350df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 35158938916SGarrett Wollman 35253be11f6SPoul-Henning Kamp if (ip->ip_v != IPVERSION) { 353df8bae1dSRodney W. Grimes ipstat.ips_badvers++; 354df8bae1dSRodney W. Grimes goto bad; 355df8bae1dSRodney W. Grimes } 35658938916SGarrett Wollman 35753be11f6SPoul-Henning Kamp hlen = ip->ip_hl << 2; 358df8bae1dSRodney W. Grimes if (hlen < sizeof(struct ip)) { /* minimum header length */ 359df8bae1dSRodney W. Grimes ipstat.ips_badhlen++; 360df8bae1dSRodney W. Grimes goto bad; 361df8bae1dSRodney W. Grimes } 362df8bae1dSRodney W. Grimes if (hlen > m->m_len) { 363df8bae1dSRodney W. Grimes if ((m = m_pullup(m, hlen)) == 0) { 364df8bae1dSRodney W. Grimes ipstat.ips_badhlen++; 365c67b1d17SGarrett Wollman return; 366df8bae1dSRodney W. Grimes } 367df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 368df8bae1dSRodney W. Grimes } 36933841545SHajimu UMEMOTO 37033841545SHajimu UMEMOTO /* 127/8 must not appear on wire - RFC1122 */ 37133841545SHajimu UMEMOTO if ((ntohl(ip->ip_dst.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET || 37233841545SHajimu UMEMOTO (ntohl(ip->ip_src.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) { 37333841545SHajimu UMEMOTO if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) { 37433841545SHajimu UMEMOTO ipstat.ips_badaddr++; 37533841545SHajimu UMEMOTO goto bad; 37633841545SHajimu UMEMOTO } 37733841545SHajimu UMEMOTO } 37833841545SHajimu UMEMOTO 379db4f9cc7SJonathan Lemon if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) { 380db4f9cc7SJonathan Lemon sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID); 381db4f9cc7SJonathan Lemon } else { 38258938916SGarrett Wollman if (hlen == sizeof(struct ip)) { 38347c861ecSBrian Somers sum = in_cksum_hdr(ip); 38458938916SGarrett Wollman } else { 38547c861ecSBrian Somers sum = in_cksum(m, hlen); 38658938916SGarrett Wollman } 387db4f9cc7SJonathan Lemon } 38847c861ecSBrian Somers if (sum) { 389df8bae1dSRodney W. Grimes ipstat.ips_badsum++; 390df8bae1dSRodney W. Grimes goto bad; 391df8bae1dSRodney W. Grimes } 392df8bae1dSRodney W. Grimes 393df8bae1dSRodney W. Grimes /* 394df8bae1dSRodney W. Grimes * Convert fields to host representation. 395df8bae1dSRodney W. Grimes */ 396fd8e4ebcSMike Barcroft ip->ip_len = ntohs(ip->ip_len); 397df8bae1dSRodney W. Grimes if (ip->ip_len < hlen) { 398df8bae1dSRodney W. Grimes ipstat.ips_badlen++; 399df8bae1dSRodney W. Grimes goto bad; 400df8bae1dSRodney W. Grimes } 401fd8e4ebcSMike Barcroft ip->ip_off = ntohs(ip->ip_off); 402df8bae1dSRodney W. Grimes 403df8bae1dSRodney W. Grimes /* 404df8bae1dSRodney W. Grimes * Check that the amount of data in the buffers 405df8bae1dSRodney W. Grimes * is as at least much as the IP header would have us expect. 406df8bae1dSRodney W. Grimes * Trim mbufs if longer than we expect. 407df8bae1dSRodney W. Grimes * Drop packet if shorter than we expect. 408df8bae1dSRodney W. Grimes */ 409df8bae1dSRodney W. Grimes if (m->m_pkthdr.len < ip->ip_len) { 41058938916SGarrett Wollman tooshort: 411df8bae1dSRodney W. Grimes ipstat.ips_tooshort++; 412df8bae1dSRodney W. Grimes goto bad; 413df8bae1dSRodney W. Grimes } 414df8bae1dSRodney W. Grimes if (m->m_pkthdr.len > ip->ip_len) { 415df8bae1dSRodney W. Grimes if (m->m_len == m->m_pkthdr.len) { 416df8bae1dSRodney W. Grimes m->m_len = ip->ip_len; 417df8bae1dSRodney W. Grimes m->m_pkthdr.len = ip->ip_len; 418df8bae1dSRodney W. Grimes } else 419df8bae1dSRodney W. Grimes m_adj(m, ip->ip_len - m->m_pkthdr.len); 420df8bae1dSRodney W. Grimes } 4213f67c834SDon Lewis 4224dd1662bSUgen J.S. Antsilevich /* 4234dd1662bSUgen J.S. Antsilevich * IpHack's section. 4244dd1662bSUgen J.S. Antsilevich * Right now when no processing on packet has done 4254dd1662bSUgen J.S. Antsilevich * and it is still fresh out of network we do our black 4264dd1662bSUgen J.S. Antsilevich * deals with it. 42793e0e116SJulian Elischer * - Firewall: deny/allow/divert 428fed1c7e9SSøren Schmidt * - Xlate: translate packet's addr/port (NAT). 429b715f178SLuigi Rizzo * - Pipe: pass pkt through dummynet. 4304dd1662bSUgen J.S. Antsilevich * - Wrap: fake packet's addr/port <unimpl.> 4314dd1662bSUgen J.S. Antsilevich * - Encapsulate: put it in another IP and send out. <unimp.> 4324dd1662bSUgen J.S. Antsilevich */ 433b715f178SLuigi Rizzo 434b715f178SLuigi Rizzo iphack: 435df8bae1dSRodney W. Grimes 436c4ac87eaSDarren Reed #ifdef PFIL_HOOKS 437c4ac87eaSDarren Reed /* 438c4ac87eaSDarren Reed * Run through list of hooks for input packets. If there are any 439c4ac87eaSDarren Reed * filters which require that additional packets in the flow are 440c4ac87eaSDarren Reed * not fast-forwarded, they must clear the M_CANFASTFWD flag. 441c4ac87eaSDarren Reed * Note that filters must _never_ set this flag, as another filter 442c4ac87eaSDarren Reed * in the list may have previously cleared it. 443c4ac87eaSDarren Reed */ 444c4ac87eaSDarren Reed m0 = m; 445c4ac87eaSDarren Reed pfh = pfil_hook_get(PFIL_IN, &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); 446fc2ffbe6SPoul-Henning Kamp for (; pfh; pfh = TAILQ_NEXT(pfh, pfil_link)) 447c4ac87eaSDarren Reed if (pfh->pfil_func) { 448c4ac87eaSDarren Reed rv = pfh->pfil_func(ip, hlen, 449c4ac87eaSDarren Reed m->m_pkthdr.rcvif, 0, &m0); 450c4ac87eaSDarren Reed if (rv) 451beec8214SDarren Reed return; 452c4ac87eaSDarren Reed m = m0; 453c4ac87eaSDarren Reed if (m == NULL) 454c4ac87eaSDarren Reed return; 455c4ac87eaSDarren Reed ip = mtod(m, struct ip *); 456beec8214SDarren Reed } 457c4ac87eaSDarren Reed #endif /* PFIL_HOOKS */ 458c4ac87eaSDarren Reed 4597b109fa4SLuigi Rizzo if (fw_enable && IPFW_LOADED) { 460f9e354dfSJulian Elischer /* 461f9e354dfSJulian Elischer * If we've been forwarded from the output side, then 462f9e354dfSJulian Elischer * skip the firewall a second time 463f9e354dfSJulian Elischer */ 4642b25acc1SLuigi Rizzo if (args.next_hop) 465f9e354dfSJulian Elischer goto ours; 4662b25acc1SLuigi Rizzo 4672b25acc1SLuigi Rizzo args.m = m; 4682b25acc1SLuigi Rizzo i = ip_fw_chk_ptr(&args); 4692b25acc1SLuigi Rizzo m = args.m; 4702b25acc1SLuigi Rizzo 471d60315beSLuigi Rizzo if ( (i & IP_FW_PORT_DENY_FLAG) || m == NULL) { /* drop */ 472507b4b54SLuigi Rizzo if (m) 473507b4b54SLuigi Rizzo m_freem(m); 474b715f178SLuigi Rizzo return; 475507b4b54SLuigi Rizzo } 476d60315beSLuigi Rizzo ip = mtod(m, struct ip *); /* just in case m changed */ 4772b25acc1SLuigi Rizzo if (i == 0 && args.next_hop == NULL) /* common case */ 478b715f178SLuigi Rizzo goto pass; 4797b109fa4SLuigi Rizzo if (DUMMYNET_LOADED && (i & IP_FW_PORT_DYNT_FLAG) != 0) { 4808948e4baSArchie Cobbs /* Send packet to the appropriate pipe */ 4812b25acc1SLuigi Rizzo ip_dn_io_ptr(m, i&0xffff, DN_TO_IP_IN, &args); 482e4676ba6SJulian Elischer return; 48393e0e116SJulian Elischer } 484b715f178SLuigi Rizzo #ifdef IPDIVERT 4858948e4baSArchie Cobbs if (i != 0 && (i & IP_FW_PORT_DYNT_FLAG) == 0) { 4868948e4baSArchie Cobbs /* Divert or tee packet */ 4878948e4baSArchie Cobbs divert_info = i; 488b715f178SLuigi Rizzo goto ours; 489b715f178SLuigi Rizzo } 490b715f178SLuigi Rizzo #endif 4912b25acc1SLuigi Rizzo if (i == 0 && args.next_hop != NULL) 492b715f178SLuigi Rizzo goto pass; 493b715f178SLuigi Rizzo /* 494b715f178SLuigi Rizzo * if we get here, the packet must be dropped 495b715f178SLuigi Rizzo */ 496b715f178SLuigi Rizzo m_freem(m); 497b715f178SLuigi Rizzo return; 498b715f178SLuigi Rizzo } 499b715f178SLuigi Rizzo pass: 500100ba1a6SJordan K. Hubbard 501df8bae1dSRodney W. Grimes /* 502df8bae1dSRodney W. Grimes * Process options and, if not destined for us, 503df8bae1dSRodney W. Grimes * ship it on. ip_dooptions returns 1 when an 504df8bae1dSRodney W. Grimes * error was detected (causing an icmp message 505df8bae1dSRodney W. Grimes * to be sent and the original packet to be freed). 506df8bae1dSRodney W. Grimes */ 507df8bae1dSRodney W. Grimes ip_nhops = 0; /* for source routed packets */ 5082b25acc1SLuigi Rizzo if (hlen > sizeof (struct ip) && ip_dooptions(m, 0, args.next_hop)) 509c67b1d17SGarrett Wollman return; 510df8bae1dSRodney W. Grimes 511f0068c4aSGarrett Wollman /* greedy RSVP, snatches any PATH packet of the RSVP protocol and no 512f0068c4aSGarrett Wollman * matter if it is destined to another node, or whether it is 513f0068c4aSGarrett Wollman * a multicast one, RSVP wants it! and prevents it from being forwarded 514f0068c4aSGarrett Wollman * anywhere else. Also checks if the rsvp daemon is running before 515f0068c4aSGarrett Wollman * grabbing the packet. 516f0068c4aSGarrett Wollman */ 5171c5de19aSGarrett Wollman if (rsvp_on && ip->ip_p==IPPROTO_RSVP) 518f0068c4aSGarrett Wollman goto ours; 519f0068c4aSGarrett Wollman 520df8bae1dSRodney W. Grimes /* 521df8bae1dSRodney W. Grimes * Check our list of addresses, to see if the packet is for us. 522cc766e04SGarrett Wollman * If we don't have any addresses, assume any unicast packet 523cc766e04SGarrett Wollman * we receive might be for us (and let the upper layers deal 524cc766e04SGarrett Wollman * with it). 525df8bae1dSRodney W. Grimes */ 526cc766e04SGarrett Wollman if (TAILQ_EMPTY(&in_ifaddrhead) && 527cc766e04SGarrett Wollman (m->m_flags & (M_MCAST|M_BCAST)) == 0) 528cc766e04SGarrett Wollman goto ours; 529cc766e04SGarrett Wollman 5307538a9a0SJonathan Lemon /* 5317538a9a0SJonathan Lemon * Cache the destination address of the packet; this may be 5327538a9a0SJonathan Lemon * changed by use of 'ipfw fwd'. 5337538a9a0SJonathan Lemon */ 5342b25acc1SLuigi Rizzo pkt_dst = args.next_hop ? args.next_hop->sin_addr : ip->ip_dst; 5357538a9a0SJonathan Lemon 536823db0e9SDon Lewis /* 537823db0e9SDon Lewis * Enable a consistency check between the destination address 538823db0e9SDon Lewis * and the arrival interface for a unicast packet (the RFC 1122 539823db0e9SDon Lewis * strong ES model) if IP forwarding is disabled and the packet 540e15ae1b2SDon Lewis * is not locally generated and the packet is not subject to 541e15ae1b2SDon Lewis * 'ipfw fwd'. 5423f67c834SDon Lewis * 5433f67c834SDon Lewis * XXX - Checking also should be disabled if the destination 5443f67c834SDon Lewis * address is ipnat'ed to a different interface. 5453f67c834SDon Lewis * 546a8f12100SDon Lewis * XXX - Checking is incompatible with IP aliases added 5473f67c834SDon Lewis * to the loopback interface instead of the interface where 5483f67c834SDon Lewis * the packets are received. 549823db0e9SDon Lewis */ 550823db0e9SDon Lewis checkif = ip_checkinterface && (ipforwarding == 0) && 5519494d596SBrooks Davis m->m_pkthdr.rcvif != NULL && 552e15ae1b2SDon Lewis ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) && 5532b25acc1SLuigi Rizzo (args.next_hop == NULL); 554823db0e9SDon Lewis 555ca925d9cSJonathan Lemon /* 556ca925d9cSJonathan Lemon * Check for exact addresses in the hash bucket. 557ca925d9cSJonathan Lemon */ 558ca925d9cSJonathan Lemon LIST_FOREACH(ia, INADDR_HASH(pkt_dst.s_addr), ia_hash) { 559f9e354dfSJulian Elischer /* 560823db0e9SDon Lewis * If the address matches, verify that the packet 561823db0e9SDon Lewis * arrived via the correct interface if checking is 562823db0e9SDon Lewis * enabled. 563f9e354dfSJulian Elischer */ 564823db0e9SDon Lewis if (IA_SIN(ia)->sin_addr.s_addr == pkt_dst.s_addr && 565823db0e9SDon Lewis (!checkif || ia->ia_ifp == m->m_pkthdr.rcvif)) 566ed1ff184SJulian Elischer goto ours; 567ca925d9cSJonathan Lemon } 568823db0e9SDon Lewis /* 569ca925d9cSJonathan Lemon * Check for broadcast addresses. 570ca925d9cSJonathan Lemon * 571ca925d9cSJonathan Lemon * Only accept broadcast packets that arrive via the matching 572ca925d9cSJonathan Lemon * interface. Reception of forwarded directed broadcasts would 573ca925d9cSJonathan Lemon * be handled via ip_forward() and ether_output() with the loopback 574ca925d9cSJonathan Lemon * into the stack for SIMPLEX interfaces handled by ether_output(). 575823db0e9SDon Lewis */ 576ca925d9cSJonathan Lemon if (m->m_pkthdr.rcvif->if_flags & IFF_BROADCAST) { 577ca925d9cSJonathan Lemon TAILQ_FOREACH(ifa, &m->m_pkthdr.rcvif->if_addrhead, ifa_link) { 578ca925d9cSJonathan Lemon if (ifa->ifa_addr->sa_family != AF_INET) 579ca925d9cSJonathan Lemon continue; 580ca925d9cSJonathan Lemon ia = ifatoia(ifa); 581df8bae1dSRodney W. Grimes if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == 5827538a9a0SJonathan Lemon pkt_dst.s_addr) 583df8bae1dSRodney W. Grimes goto ours; 5847538a9a0SJonathan Lemon if (ia->ia_netbroadcast.s_addr == pkt_dst.s_addr) 585df8bae1dSRodney W. Grimes goto ours; 586ca925d9cSJonathan Lemon #ifdef BOOTP_COMPAT 587ca925d9cSJonathan Lemon if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY) 588ca925d9cSJonathan Lemon goto ours; 589ca925d9cSJonathan Lemon #endif 590df8bae1dSRodney W. Grimes } 591df8bae1dSRodney W. Grimes } 592df8bae1dSRodney W. Grimes if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { 593df8bae1dSRodney W. Grimes struct in_multi *inm; 594df8bae1dSRodney W. Grimes if (ip_mrouter) { 595df8bae1dSRodney W. Grimes /* 596df8bae1dSRodney W. Grimes * If we are acting as a multicast router, all 597df8bae1dSRodney W. Grimes * incoming multicast packets are passed to the 598df8bae1dSRodney W. Grimes * kernel-level multicast forwarding function. 599df8bae1dSRodney W. Grimes * The packet is returned (relatively) intact; if 600df8bae1dSRodney W. Grimes * ip_mforward() returns a non-zero value, the packet 601df8bae1dSRodney W. Grimes * must be discarded, else it may be accepted below. 602df8bae1dSRodney W. Grimes */ 603bbb4330bSLuigi Rizzo if (ip_mforward && 604bbb4330bSLuigi Rizzo ip_mforward(ip, m->m_pkthdr.rcvif, m, 0) != 0) { 605df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 606df8bae1dSRodney W. Grimes m_freem(m); 607c67b1d17SGarrett Wollman return; 608df8bae1dSRodney W. Grimes } 609df8bae1dSRodney W. Grimes 610df8bae1dSRodney W. Grimes /* 61111612afaSDima Dorfman * The process-level routing daemon needs to receive 612df8bae1dSRodney W. Grimes * all multicast IGMP packets, whether or not this 613df8bae1dSRodney W. Grimes * host belongs to their destination groups. 614df8bae1dSRodney W. Grimes */ 615df8bae1dSRodney W. Grimes if (ip->ip_p == IPPROTO_IGMP) 616df8bae1dSRodney W. Grimes goto ours; 617df8bae1dSRodney W. Grimes ipstat.ips_forward++; 618df8bae1dSRodney W. Grimes } 619df8bae1dSRodney W. Grimes /* 620df8bae1dSRodney W. Grimes * See if we belong to the destination multicast group on the 621df8bae1dSRodney W. Grimes * arrival interface. 622df8bae1dSRodney W. Grimes */ 623df8bae1dSRodney W. Grimes IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm); 624df8bae1dSRodney W. Grimes if (inm == NULL) { 62582c39223SGarrett Wollman ipstat.ips_notmember++; 626df8bae1dSRodney W. Grimes m_freem(m); 627c67b1d17SGarrett Wollman return; 628df8bae1dSRodney W. Grimes } 629df8bae1dSRodney W. Grimes goto ours; 630df8bae1dSRodney W. Grimes } 631df8bae1dSRodney W. Grimes if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST) 632df8bae1dSRodney W. Grimes goto ours; 633df8bae1dSRodney W. Grimes if (ip->ip_dst.s_addr == INADDR_ANY) 634df8bae1dSRodney W. Grimes goto ours; 635df8bae1dSRodney W. Grimes 6366a800098SYoshinobu Inoue /* 6376a800098SYoshinobu Inoue * FAITH(Firewall Aided Internet Translator) 6386a800098SYoshinobu Inoue */ 6396a800098SYoshinobu Inoue if (m->m_pkthdr.rcvif && m->m_pkthdr.rcvif->if_type == IFT_FAITH) { 6406a800098SYoshinobu Inoue if (ip_keepfaith) { 6416a800098SYoshinobu Inoue if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_ICMP) 6426a800098SYoshinobu Inoue goto ours; 6436a800098SYoshinobu Inoue } 6446a800098SYoshinobu Inoue m_freem(m); 6456a800098SYoshinobu Inoue return; 6466a800098SYoshinobu Inoue } 6479494d596SBrooks Davis 648df8bae1dSRodney W. Grimes /* 649df8bae1dSRodney W. Grimes * Not for us; forward if possible and desirable. 650df8bae1dSRodney W. Grimes */ 651df8bae1dSRodney W. Grimes if (ipforwarding == 0) { 652df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 653df8bae1dSRodney W. Grimes m_freem(m); 654546f251bSChris D. Faulhaber } else { 655546f251bSChris D. Faulhaber #ifdef IPSEC 656546f251bSChris D. Faulhaber /* 657546f251bSChris D. Faulhaber * Enforce inbound IPsec SPD. 658546f251bSChris D. Faulhaber */ 659546f251bSChris D. Faulhaber if (ipsec4_in_reject(m, NULL)) { 660546f251bSChris D. Faulhaber ipsecstat.in_polvio++; 661546f251bSChris D. Faulhaber goto bad; 662546f251bSChris D. Faulhaber } 663546f251bSChris D. Faulhaber #endif /* IPSEC */ 664b9234fafSSam Leffler #ifdef FAST_IPSEC 665b9234fafSSam Leffler mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL); 666b9234fafSSam Leffler s = splnet(); 667b9234fafSSam Leffler if (mtag != NULL) { 668b9234fafSSam Leffler tdbi = (struct tdb_ident *)(mtag + 1); 669b9234fafSSam Leffler sp = ipsec_getpolicy(tdbi, IPSEC_DIR_INBOUND); 670b9234fafSSam Leffler } else { 671b9234fafSSam Leffler sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND, 672b9234fafSSam Leffler IP_FORWARDING, &error); 673b9234fafSSam Leffler } 674b9234fafSSam Leffler if (sp == NULL) { /* NB: can happen if error */ 675b9234fafSSam Leffler splx(s); 676b9234fafSSam Leffler /*XXX error stat???*/ 677b9234fafSSam Leffler DPRINTF(("ip_input: no SP for forwarding\n")); /*XXX*/ 678b9234fafSSam Leffler goto bad; 679b9234fafSSam Leffler } 680b9234fafSSam Leffler 681b9234fafSSam Leffler /* 682b9234fafSSam Leffler * Check security policy against packet attributes. 683b9234fafSSam Leffler */ 684b9234fafSSam Leffler error = ipsec_in_reject(sp, m); 685b9234fafSSam Leffler KEY_FREESP(&sp); 686b9234fafSSam Leffler splx(s); 687b9234fafSSam Leffler if (error) { 688b9234fafSSam Leffler ipstat.ips_cantforward++; 689b9234fafSSam Leffler goto bad; 690b9234fafSSam Leffler } 691b9234fafSSam Leffler #endif /* FAST_IPSEC */ 6922b25acc1SLuigi Rizzo ip_forward(m, 0, args.next_hop); 693546f251bSChris D. Faulhaber } 694c67b1d17SGarrett Wollman return; 695df8bae1dSRodney W. Grimes 696df8bae1dSRodney W. Grimes ours: 697d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH 698d0ebc0d2SYaroslav Tykhiy /* 699d0ebc0d2SYaroslav Tykhiy * IPSTEALTH: Process non-routing options only 700d0ebc0d2SYaroslav Tykhiy * if the packet is destined for us. 701d0ebc0d2SYaroslav Tykhiy */ 7022b25acc1SLuigi Rizzo if (ipstealth && hlen > sizeof (struct ip) && 7032b25acc1SLuigi Rizzo ip_dooptions(m, 1, args.next_hop)) 704d0ebc0d2SYaroslav Tykhiy return; 705d0ebc0d2SYaroslav Tykhiy #endif /* IPSTEALTH */ 706d0ebc0d2SYaroslav Tykhiy 7075da9f8faSJosef Karthauser /* Count the packet in the ip address stats */ 7085da9f8faSJosef Karthauser if (ia != NULL) { 7095da9f8faSJosef Karthauser ia->ia_ifa.if_ipackets++; 7105da9f8faSJosef Karthauser ia->ia_ifa.if_ibytes += m->m_pkthdr.len; 7115da9f8faSJosef Karthauser } 712100ba1a6SJordan K. Hubbard 71363f8d699SJordan K. Hubbard /* 714df8bae1dSRodney W. Grimes * If offset or IP_MF are set, must reassemble. 715df8bae1dSRodney W. Grimes * Otherwise, nothing need be done. 716df8bae1dSRodney W. Grimes * (We could look in the reassembly queue to see 717df8bae1dSRodney W. Grimes * if the packet was previously fragmented, 718df8bae1dSRodney W. Grimes * but it's not worth the time; just let them time out.) 719df8bae1dSRodney W. Grimes */ 720b6ea1aa5SRuslan Ermilov if (ip->ip_off & (IP_MF | IP_OFFMASK)) { 7216a800098SYoshinobu Inoue 722194a213eSAndrey A. Chernov sum = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id); 723df8bae1dSRodney W. Grimes /* 724df8bae1dSRodney W. Grimes * Look for queue of fragments 725df8bae1dSRodney W. Grimes * of this datagram. 726df8bae1dSRodney W. Grimes */ 727462b86feSPoul-Henning Kamp TAILQ_FOREACH(fp, &ipq[sum], ipq_list) 728df8bae1dSRodney W. Grimes if (ip->ip_id == fp->ipq_id && 729df8bae1dSRodney W. Grimes ip->ip_src.s_addr == fp->ipq_src.s_addr && 730df8bae1dSRodney W. Grimes ip->ip_dst.s_addr == fp->ipq_dst.s_addr && 73136b0360bSRobert Watson #ifdef MAC 73236b0360bSRobert Watson mac_fragment_match(m, fp) && 73336b0360bSRobert Watson #endif 734df8bae1dSRodney W. Grimes ip->ip_p == fp->ipq_p) 735df8bae1dSRodney W. Grimes goto found; 736df8bae1dSRodney W. Grimes 737194a213eSAndrey A. Chernov fp = 0; 738194a213eSAndrey A. Chernov 739194a213eSAndrey A. Chernov /* check if there's a place for the new queue */ 740194a213eSAndrey A. Chernov if (nipq > maxnipq) { 741194a213eSAndrey A. Chernov /* 742194a213eSAndrey A. Chernov * drop something from the tail of the current queue 743194a213eSAndrey A. Chernov * before proceeding further 744194a213eSAndrey A. Chernov */ 745462b86feSPoul-Henning Kamp struct ipq *q = TAILQ_LAST(&ipq[sum], ipqhead); 746462b86feSPoul-Henning Kamp if (q == NULL) { /* gak */ 747194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 748462b86feSPoul-Henning Kamp struct ipq *r = TAILQ_LAST(&ipq[i], ipqhead); 749462b86feSPoul-Henning Kamp if (r) { 750462b86feSPoul-Henning Kamp ip_freef(&ipq[i], r); 751194a213eSAndrey A. Chernov break; 752194a213eSAndrey A. Chernov } 753194a213eSAndrey A. Chernov } 754194a213eSAndrey A. Chernov } else 755462b86feSPoul-Henning Kamp ip_freef(&ipq[sum], q); 756194a213eSAndrey A. Chernov } 757194a213eSAndrey A. Chernov found: 758df8bae1dSRodney W. Grimes /* 759df8bae1dSRodney W. Grimes * Adjust ip_len to not reflect header, 760df8bae1dSRodney W. Grimes * convert offset of this to bytes. 761df8bae1dSRodney W. Grimes */ 762df8bae1dSRodney W. Grimes ip->ip_len -= hlen; 763b6ea1aa5SRuslan Ermilov if (ip->ip_off & IP_MF) { 7646effc713SDoug Rabson /* 7656effc713SDoug Rabson * Make sure that fragments have a data length 7666effc713SDoug Rabson * that's a non-zero multiple of 8 bytes. 7676effc713SDoug Rabson */ 7686effc713SDoug Rabson if (ip->ip_len == 0 || (ip->ip_len & 0x7) != 0) { 7696effc713SDoug Rabson ipstat.ips_toosmall++; /* XXX */ 7706effc713SDoug Rabson goto bad; 7716effc713SDoug Rabson } 7726effc713SDoug Rabson m->m_flags |= M_FRAG; 7731cf43499SMaxim Konovalov } else 7741cf43499SMaxim Konovalov m->m_flags &= ~M_FRAG; 775df8bae1dSRodney W. Grimes ip->ip_off <<= 3; 776df8bae1dSRodney W. Grimes 777df8bae1dSRodney W. Grimes /* 778b6ea1aa5SRuslan Ermilov * Attempt reassembly; if it succeeds, proceed. 7792b25acc1SLuigi Rizzo * ip_reass() will return a different mbuf, and update 7802b25acc1SLuigi Rizzo * the divert info in divert_info and args.divert_rule. 781df8bae1dSRodney W. Grimes */ 782df8bae1dSRodney W. Grimes ipstat.ips_fragments++; 783487bdb38SRuslan Ermilov m->m_pkthdr.header = ip; 7846a800098SYoshinobu Inoue m = ip_reass(m, 7852b25acc1SLuigi Rizzo &ipq[sum], fp, &divert_info, &args.divert_rule); 7862b25acc1SLuigi Rizzo if (m == 0) 787c67b1d17SGarrett Wollman return; 788df8bae1dSRodney W. Grimes ipstat.ips_reassembled++; 7896a800098SYoshinobu Inoue ip = mtod(m, struct ip *); 7907e2df452SRuslan Ermilov /* Get the header length of the reassembled packet */ 79153be11f6SPoul-Henning Kamp hlen = ip->ip_hl << 2; 792af782f1cSBrian Somers #ifdef IPDIVERT 7938948e4baSArchie Cobbs /* Restore original checksum before diverting packet */ 7948948e4baSArchie Cobbs if (divert_info != 0) { 795af782f1cSBrian Somers ip->ip_len += hlen; 796fd8e4ebcSMike Barcroft ip->ip_len = htons(ip->ip_len); 797fd8e4ebcSMike Barcroft ip->ip_off = htons(ip->ip_off); 798af782f1cSBrian Somers ip->ip_sum = 0; 79960123168SRuslan Ermilov if (hlen == sizeof(struct ip)) 800af782f1cSBrian Somers ip->ip_sum = in_cksum_hdr(ip); 80160123168SRuslan Ermilov else 80260123168SRuslan Ermilov ip->ip_sum = in_cksum(m, hlen); 803fd8e4ebcSMike Barcroft ip->ip_off = ntohs(ip->ip_off); 804fd8e4ebcSMike Barcroft ip->ip_len = ntohs(ip->ip_len); 805af782f1cSBrian Somers ip->ip_len -= hlen; 806af782f1cSBrian Somers } 807af782f1cSBrian Somers #endif 808df8bae1dSRodney W. Grimes } else 809df8bae1dSRodney W. Grimes ip->ip_len -= hlen; 810df8bae1dSRodney W. Grimes 81193e0e116SJulian Elischer #ifdef IPDIVERT 81293e0e116SJulian Elischer /* 8138948e4baSArchie Cobbs * Divert or tee packet to the divert protocol if required. 81493e0e116SJulian Elischer */ 8158948e4baSArchie Cobbs if (divert_info != 0) { 8168948e4baSArchie Cobbs struct mbuf *clone = NULL; 8178948e4baSArchie Cobbs 8188948e4baSArchie Cobbs /* Clone packet if we're doing a 'tee' */ 8198948e4baSArchie Cobbs if ((divert_info & IP_FW_PORT_TEE_FLAG) != 0) 8208948e4baSArchie Cobbs clone = m_dup(m, M_DONTWAIT); 8218948e4baSArchie Cobbs 8228948e4baSArchie Cobbs /* Restore packet header fields to original values */ 8238948e4baSArchie Cobbs ip->ip_len += hlen; 824fd8e4ebcSMike Barcroft ip->ip_len = htons(ip->ip_len); 825fd8e4ebcSMike Barcroft ip->ip_off = htons(ip->ip_off); 8268948e4baSArchie Cobbs 8278948e4baSArchie Cobbs /* Deliver packet to divert input routine */ 8282b25acc1SLuigi Rizzo divert_packet(m, 1, divert_info & 0xffff, args.divert_rule); 829e4676ba6SJulian Elischer ipstat.ips_delivered++; 8308948e4baSArchie Cobbs 8318948e4baSArchie Cobbs /* If 'tee', continue with original packet */ 8328948e4baSArchie Cobbs if (clone == NULL) 83393e0e116SJulian Elischer return; 8348948e4baSArchie Cobbs m = clone; 8358948e4baSArchie Cobbs ip = mtod(m, struct ip *); 83656962689SCrist J. Clark ip->ip_len += hlen; 8372b25acc1SLuigi Rizzo /* 8382b25acc1SLuigi Rizzo * Jump backwards to complete processing of the 8392b25acc1SLuigi Rizzo * packet. But first clear divert_info to avoid 8402b25acc1SLuigi Rizzo * entering this block again. 8412b25acc1SLuigi Rizzo * We do not need to clear args.divert_rule 8422b25acc1SLuigi Rizzo * or args.next_hop as they will not be used. 8432b25acc1SLuigi Rizzo */ 84456962689SCrist J. Clark divert_info = 0; 84556962689SCrist J. Clark goto pass; 84693e0e116SJulian Elischer } 84793e0e116SJulian Elischer #endif 84893e0e116SJulian Elischer 84933841545SHajimu UMEMOTO #ifdef IPSEC 85033841545SHajimu UMEMOTO /* 85133841545SHajimu UMEMOTO * enforce IPsec policy checking if we are seeing last header. 85233841545SHajimu UMEMOTO * note that we do not visit this with protocols with pcb layer 85333841545SHajimu UMEMOTO * code - like udp/tcp/raw ip. 85433841545SHajimu UMEMOTO */ 85533841545SHajimu UMEMOTO if ((inetsw[ip_protox[ip->ip_p]].pr_flags & PR_LASTHDR) != 0 && 85633841545SHajimu UMEMOTO ipsec4_in_reject(m, NULL)) { 85733841545SHajimu UMEMOTO ipsecstat.in_polvio++; 85833841545SHajimu UMEMOTO goto bad; 85933841545SHajimu UMEMOTO } 86033841545SHajimu UMEMOTO #endif 861b9234fafSSam Leffler #if FAST_IPSEC 862b9234fafSSam Leffler /* 863b9234fafSSam Leffler * enforce IPsec policy checking if we are seeing last header. 864b9234fafSSam Leffler * note that we do not visit this with protocols with pcb layer 865b9234fafSSam Leffler * code - like udp/tcp/raw ip. 866b9234fafSSam Leffler */ 867b9234fafSSam Leffler if ((inetsw[ip_protox[ip->ip_p]].pr_flags & PR_LASTHDR) != 0) { 868b9234fafSSam Leffler /* 869b9234fafSSam Leffler * Check if the packet has already had IPsec processing 870b9234fafSSam Leffler * done. If so, then just pass it along. This tag gets 871b9234fafSSam Leffler * set during AH, ESP, etc. input handling, before the 872b9234fafSSam Leffler * packet is returned to the ip input queue for delivery. 873b9234fafSSam Leffler */ 874b9234fafSSam Leffler mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL); 875b9234fafSSam Leffler s = splnet(); 876b9234fafSSam Leffler if (mtag != NULL) { 877b9234fafSSam Leffler tdbi = (struct tdb_ident *)(mtag + 1); 878b9234fafSSam Leffler sp = ipsec_getpolicy(tdbi, IPSEC_DIR_INBOUND); 879b9234fafSSam Leffler } else { 880b9234fafSSam Leffler sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND, 881b9234fafSSam Leffler IP_FORWARDING, &error); 882b9234fafSSam Leffler } 883b9234fafSSam Leffler if (sp != NULL) { 884b9234fafSSam Leffler /* 885b9234fafSSam Leffler * Check security policy against packet attributes. 886b9234fafSSam Leffler */ 887b9234fafSSam Leffler error = ipsec_in_reject(sp, m); 888b9234fafSSam Leffler KEY_FREESP(&sp); 889b9234fafSSam Leffler } else { 890b9234fafSSam Leffler /* XXX error stat??? */ 891b9234fafSSam Leffler error = EINVAL; 892b9234fafSSam Leffler DPRINTF(("ip_input: no SP, packet discarded\n"));/*XXX*/ 893b9234fafSSam Leffler goto bad; 894b9234fafSSam Leffler } 895b9234fafSSam Leffler splx(s); 896b9234fafSSam Leffler if (error) 897b9234fafSSam Leffler goto bad; 898b9234fafSSam Leffler } 899b9234fafSSam Leffler #endif /* FAST_IPSEC */ 90033841545SHajimu UMEMOTO 901df8bae1dSRodney W. Grimes /* 902df8bae1dSRodney W. Grimes * Switch out to protocol's input routine. 903df8bae1dSRodney W. Grimes */ 904df8bae1dSRodney W. Grimes ipstat.ips_delivered++; 9052b25acc1SLuigi Rizzo if (args.next_hop && ip->ip_p == IPPROTO_TCP) { 9062b25acc1SLuigi Rizzo /* TCP needs IPFORWARD info if available */ 9072b25acc1SLuigi Rizzo struct m_hdr tag; 9086a800098SYoshinobu Inoue 9092b25acc1SLuigi Rizzo tag.mh_type = MT_TAG; 9102b25acc1SLuigi Rizzo tag.mh_flags = PACKET_TAG_IPFORWARD; 9112b25acc1SLuigi Rizzo tag.mh_data = (caddr_t)args.next_hop; 9122b25acc1SLuigi Rizzo tag.mh_next = m; 9132b25acc1SLuigi Rizzo 9142b25acc1SLuigi Rizzo (*inetsw[ip_protox[ip->ip_p]].pr_input)( 9152b25acc1SLuigi Rizzo (struct mbuf *)&tag, hlen); 9162b25acc1SLuigi Rizzo } else 9172b25acc1SLuigi Rizzo (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen); 918c67b1d17SGarrett Wollman return; 919df8bae1dSRodney W. Grimes bad: 920df8bae1dSRodney W. Grimes m_freem(m); 921c67b1d17SGarrett Wollman } 922c67b1d17SGarrett Wollman 923c67b1d17SGarrett Wollman /* 924c67b1d17SGarrett Wollman * IP software interrupt routine - to go away sometime soon 925c67b1d17SGarrett Wollman */ 926c67b1d17SGarrett Wollman static void 927c67b1d17SGarrett Wollman ipintr(void) 928c67b1d17SGarrett Wollman { 929c67b1d17SGarrett Wollman struct mbuf *m; 930c67b1d17SGarrett Wollman 931c67b1d17SGarrett Wollman while (1) { 932c67b1d17SGarrett Wollman IF_DEQUEUE(&ipintrq, m); 933c67b1d17SGarrett Wollman if (m == 0) 934c67b1d17SGarrett Wollman return; 935c67b1d17SGarrett Wollman ip_input(m); 936c67b1d17SGarrett Wollman } 937df8bae1dSRodney W. Grimes } 938df8bae1dSRodney W. Grimes 939df8bae1dSRodney W. Grimes /* 9408948e4baSArchie Cobbs * Take incoming datagram fragment and try to reassemble it into 9418948e4baSArchie Cobbs * whole datagram. If a chain for reassembly of this datagram already 9428948e4baSArchie Cobbs * exists, then it is given as fp; otherwise have to make a chain. 9438948e4baSArchie Cobbs * 9448948e4baSArchie Cobbs * When IPDIVERT enabled, keep additional state with each packet that 9458948e4baSArchie Cobbs * tells us if we need to divert or tee the packet we're building. 9462b25acc1SLuigi Rizzo * In particular, *divinfo includes the port and TEE flag, 9472b25acc1SLuigi Rizzo * *divert_rule is the number of the matching rule. 948df8bae1dSRodney W. Grimes */ 9498948e4baSArchie Cobbs 9506a800098SYoshinobu Inoue static struct mbuf * 9512b25acc1SLuigi Rizzo ip_reass(struct mbuf *m, struct ipqhead *head, struct ipq *fp, 9522b25acc1SLuigi Rizzo u_int32_t *divinfo, u_int16_t *divert_rule) 953df8bae1dSRodney W. Grimes { 9546effc713SDoug Rabson struct ip *ip = mtod(m, struct ip *); 955b6ea1aa5SRuslan Ermilov register struct mbuf *p, *q, *nq; 956df8bae1dSRodney W. Grimes struct mbuf *t; 95753be11f6SPoul-Henning Kamp int hlen = ip->ip_hl << 2; 958df8bae1dSRodney W. Grimes int i, next; 959df8bae1dSRodney W. Grimes 960df8bae1dSRodney W. Grimes /* 961df8bae1dSRodney W. Grimes * Presence of header sizes in mbufs 962df8bae1dSRodney W. Grimes * would confuse code below. 963df8bae1dSRodney W. Grimes */ 964df8bae1dSRodney W. Grimes m->m_data += hlen; 965df8bae1dSRodney W. Grimes m->m_len -= hlen; 966df8bae1dSRodney W. Grimes 967df8bae1dSRodney W. Grimes /* 968df8bae1dSRodney W. Grimes * If first fragment to arrive, create a reassembly queue. 969df8bae1dSRodney W. Grimes */ 970df8bae1dSRodney W. Grimes if (fp == 0) { 971690a6055SJesper Skriver /* 972690a6055SJesper Skriver * Enforce upper bound on number of fragmented packets 973690a6055SJesper Skriver * for which we attempt reassembly; 974690a6055SJesper Skriver * If maxfrag is 0, never accept fragments. 975690a6055SJesper Skriver * If maxfrag is -1, accept all fragments without limitation. 976690a6055SJesper Skriver */ 977690a6055SJesper Skriver if ((ip_maxfragpackets >= 0) && (ip_nfragpackets >= ip_maxfragpackets)) 978690a6055SJesper Skriver goto dropfrag; 979690a6055SJesper Skriver ip_nfragpackets++; 980df8bae1dSRodney W. Grimes if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL) 981df8bae1dSRodney W. Grimes goto dropfrag; 982df8bae1dSRodney W. Grimes fp = mtod(t, struct ipq *); 98336b0360bSRobert Watson #ifdef MAC 98436b0360bSRobert Watson mac_init_ipq(fp); 98536b0360bSRobert Watson mac_create_ipq(m, fp); 98636b0360bSRobert Watson #endif 987462b86feSPoul-Henning Kamp TAILQ_INSERT_HEAD(head, fp, ipq_list); 988194a213eSAndrey A. Chernov nipq++; 989df8bae1dSRodney W. Grimes fp->ipq_ttl = IPFRAGTTL; 990df8bae1dSRodney W. Grimes fp->ipq_p = ip->ip_p; 991df8bae1dSRodney W. Grimes fp->ipq_id = ip->ip_id; 9926effc713SDoug Rabson fp->ipq_src = ip->ip_src; 9936effc713SDoug Rabson fp->ipq_dst = ip->ip_dst; 994af38c68cSLuigi Rizzo fp->ipq_frags = m; 995af38c68cSLuigi Rizzo m->m_nextpkt = NULL; 99693e0e116SJulian Elischer #ifdef IPDIVERT 9978948e4baSArchie Cobbs fp->ipq_div_info = 0; 998bb60f459SJulian Elischer fp->ipq_div_cookie = 0; 99993e0e116SJulian Elischer #endif 1000af38c68cSLuigi Rizzo goto inserted; 100136b0360bSRobert Watson } else { 100236b0360bSRobert Watson #ifdef MAC 100336b0360bSRobert Watson mac_update_ipq(m, fp); 100436b0360bSRobert Watson #endif 1005df8bae1dSRodney W. Grimes } 1006df8bae1dSRodney W. Grimes 10076effc713SDoug Rabson #define GETIP(m) ((struct ip*)((m)->m_pkthdr.header)) 10086effc713SDoug Rabson 1009df8bae1dSRodney W. Grimes /* 1010df8bae1dSRodney W. Grimes * Find a segment which begins after this one does. 1011df8bae1dSRodney W. Grimes */ 10126effc713SDoug Rabson for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) 10136effc713SDoug Rabson if (GETIP(q)->ip_off > ip->ip_off) 1014df8bae1dSRodney W. Grimes break; 1015df8bae1dSRodney W. Grimes 1016df8bae1dSRodney W. Grimes /* 1017df8bae1dSRodney W. Grimes * If there is a preceding segment, it may provide some of 1018df8bae1dSRodney W. Grimes * our data already. If so, drop the data from the incoming 1019af38c68cSLuigi Rizzo * segment. If it provides all of our data, drop us, otherwise 1020af38c68cSLuigi Rizzo * stick new segment in the proper place. 1021db4f9cc7SJonathan Lemon * 1022db4f9cc7SJonathan Lemon * If some of the data is dropped from the the preceding 1023db4f9cc7SJonathan Lemon * segment, then it's checksum is invalidated. 1024df8bae1dSRodney W. Grimes */ 10256effc713SDoug Rabson if (p) { 10266effc713SDoug Rabson i = GETIP(p)->ip_off + GETIP(p)->ip_len - ip->ip_off; 1027df8bae1dSRodney W. Grimes if (i > 0) { 1028df8bae1dSRodney W. Grimes if (i >= ip->ip_len) 1029df8bae1dSRodney W. Grimes goto dropfrag; 10306a800098SYoshinobu Inoue m_adj(m, i); 1031db4f9cc7SJonathan Lemon m->m_pkthdr.csum_flags = 0; 1032df8bae1dSRodney W. Grimes ip->ip_off += i; 1033df8bae1dSRodney W. Grimes ip->ip_len -= i; 1034df8bae1dSRodney W. Grimes } 1035af38c68cSLuigi Rizzo m->m_nextpkt = p->m_nextpkt; 1036af38c68cSLuigi Rizzo p->m_nextpkt = m; 1037af38c68cSLuigi Rizzo } else { 1038af38c68cSLuigi Rizzo m->m_nextpkt = fp->ipq_frags; 1039af38c68cSLuigi Rizzo fp->ipq_frags = m; 1040df8bae1dSRodney W. Grimes } 1041df8bae1dSRodney W. Grimes 1042df8bae1dSRodney W. Grimes /* 1043df8bae1dSRodney W. Grimes * While we overlap succeeding segments trim them or, 1044df8bae1dSRodney W. Grimes * if they are completely covered, dequeue them. 1045df8bae1dSRodney W. Grimes */ 10466effc713SDoug Rabson for (; q != NULL && ip->ip_off + ip->ip_len > GETIP(q)->ip_off; 1047af38c68cSLuigi Rizzo q = nq) { 10486effc713SDoug Rabson i = (ip->ip_off + ip->ip_len) - 10496effc713SDoug Rabson GETIP(q)->ip_off; 10506effc713SDoug Rabson if (i < GETIP(q)->ip_len) { 10516effc713SDoug Rabson GETIP(q)->ip_len -= i; 10526effc713SDoug Rabson GETIP(q)->ip_off += i; 10536effc713SDoug Rabson m_adj(q, i); 1054db4f9cc7SJonathan Lemon q->m_pkthdr.csum_flags = 0; 1055df8bae1dSRodney W. Grimes break; 1056df8bae1dSRodney W. Grimes } 10576effc713SDoug Rabson nq = q->m_nextpkt; 1058af38c68cSLuigi Rizzo m->m_nextpkt = nq; 10596effc713SDoug Rabson m_freem(q); 1060df8bae1dSRodney W. Grimes } 1061df8bae1dSRodney W. Grimes 1062af38c68cSLuigi Rizzo inserted: 106393e0e116SJulian Elischer 106493e0e116SJulian Elischer #ifdef IPDIVERT 106593e0e116SJulian Elischer /* 10668948e4baSArchie Cobbs * Transfer firewall instructions to the fragment structure. 10672b25acc1SLuigi Rizzo * Only trust info in the fragment at offset 0. 106893e0e116SJulian Elischer */ 10692b25acc1SLuigi Rizzo if (ip->ip_off == 0) { 10708948e4baSArchie Cobbs fp->ipq_div_info = *divinfo; 10712b25acc1SLuigi Rizzo fp->ipq_div_cookie = *divert_rule; 10722b25acc1SLuigi Rizzo } 10738948e4baSArchie Cobbs *divinfo = 0; 10742b25acc1SLuigi Rizzo *divert_rule = 0; 107593e0e116SJulian Elischer #endif 107693e0e116SJulian Elischer 1077df8bae1dSRodney W. Grimes /* 1078af38c68cSLuigi Rizzo * Check for complete reassembly. 1079df8bae1dSRodney W. Grimes */ 10806effc713SDoug Rabson next = 0; 10816effc713SDoug Rabson for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) { 10826effc713SDoug Rabson if (GETIP(q)->ip_off != next) 10836effc713SDoug Rabson return (0); 10846effc713SDoug Rabson next += GETIP(q)->ip_len; 10856effc713SDoug Rabson } 10866effc713SDoug Rabson /* Make sure the last packet didn't have the IP_MF flag */ 10876effc713SDoug Rabson if (p->m_flags & M_FRAG) 1088df8bae1dSRodney W. Grimes return (0); 1089df8bae1dSRodney W. Grimes 1090df8bae1dSRodney W. Grimes /* 1091430d30d8SBill Fenner * Reassembly is complete. Make sure the packet is a sane size. 1092430d30d8SBill Fenner */ 10936effc713SDoug Rabson q = fp->ipq_frags; 10946effc713SDoug Rabson ip = GETIP(q); 109553be11f6SPoul-Henning Kamp if (next + (ip->ip_hl << 2) > IP_MAXPACKET) { 1096430d30d8SBill Fenner ipstat.ips_toolong++; 1097462b86feSPoul-Henning Kamp ip_freef(head, fp); 1098430d30d8SBill Fenner return (0); 1099430d30d8SBill Fenner } 1100430d30d8SBill Fenner 1101430d30d8SBill Fenner /* 1102430d30d8SBill Fenner * Concatenate fragments. 1103df8bae1dSRodney W. Grimes */ 11046effc713SDoug Rabson m = q; 1105df8bae1dSRodney W. Grimes t = m->m_next; 1106df8bae1dSRodney W. Grimes m->m_next = 0; 1107df8bae1dSRodney W. Grimes m_cat(m, t); 11086effc713SDoug Rabson nq = q->m_nextpkt; 1109945aa40dSDoug Rabson q->m_nextpkt = 0; 11106effc713SDoug Rabson for (q = nq; q != NULL; q = nq) { 11116effc713SDoug Rabson nq = q->m_nextpkt; 1112945aa40dSDoug Rabson q->m_nextpkt = NULL; 1113db4f9cc7SJonathan Lemon m->m_pkthdr.csum_flags &= q->m_pkthdr.csum_flags; 1114db4f9cc7SJonathan Lemon m->m_pkthdr.csum_data += q->m_pkthdr.csum_data; 1115a8db1d93SJonathan Lemon m_cat(m, q); 1116df8bae1dSRodney W. Grimes } 111736b0360bSRobert Watson #ifdef MAC 111836b0360bSRobert Watson mac_create_datagram_from_ipq(fp, m); 111936b0360bSRobert Watson mac_destroy_ipq(fp); 112036b0360bSRobert Watson #endif 1121df8bae1dSRodney W. Grimes 112293e0e116SJulian Elischer #ifdef IPDIVERT 112393e0e116SJulian Elischer /* 11248948e4baSArchie Cobbs * Extract firewall instructions from the fragment structure. 112593e0e116SJulian Elischer */ 11268948e4baSArchie Cobbs *divinfo = fp->ipq_div_info; 11272b25acc1SLuigi Rizzo *divert_rule = fp->ipq_div_cookie; 112893e0e116SJulian Elischer #endif 112993e0e116SJulian Elischer 1130df8bae1dSRodney W. Grimes /* 1131df8bae1dSRodney W. Grimes * Create header for new ip packet by 1132df8bae1dSRodney W. Grimes * modifying header of first packet; 1133df8bae1dSRodney W. Grimes * dequeue and discard fragment reassembly header. 1134df8bae1dSRodney W. Grimes * Make header visible. 1135df8bae1dSRodney W. Grimes */ 1136df8bae1dSRodney W. Grimes ip->ip_len = next; 11376effc713SDoug Rabson ip->ip_src = fp->ipq_src; 11386effc713SDoug Rabson ip->ip_dst = fp->ipq_dst; 1139462b86feSPoul-Henning Kamp TAILQ_REMOVE(head, fp, ipq_list); 1140194a213eSAndrey A. Chernov nipq--; 1141df8bae1dSRodney W. Grimes (void) m_free(dtom(fp)); 1142690a6055SJesper Skriver ip_nfragpackets--; 114353be11f6SPoul-Henning Kamp m->m_len += (ip->ip_hl << 2); 114453be11f6SPoul-Henning Kamp m->m_data -= (ip->ip_hl << 2); 1145df8bae1dSRodney W. Grimes /* some debugging cruft by sklower, below, will go away soon */ 1146a5554bf0SPoul-Henning Kamp if (m->m_flags & M_PKTHDR) /* XXX this should be done elsewhere */ 1147a5554bf0SPoul-Henning Kamp m_fixhdr(m); 11486a800098SYoshinobu Inoue return (m); 1149df8bae1dSRodney W. Grimes 1150df8bae1dSRodney W. Grimes dropfrag: 1151efe39c6aSJulian Elischer #ifdef IPDIVERT 11528948e4baSArchie Cobbs *divinfo = 0; 11532b25acc1SLuigi Rizzo *divert_rule = 0; 1154efe39c6aSJulian Elischer #endif 1155df8bae1dSRodney W. Grimes ipstat.ips_fragdropped++; 1156df8bae1dSRodney W. Grimes m_freem(m); 1157df8bae1dSRodney W. Grimes return (0); 11586effc713SDoug Rabson 11596effc713SDoug Rabson #undef GETIP 1160df8bae1dSRodney W. Grimes } 1161df8bae1dSRodney W. Grimes 1162df8bae1dSRodney W. Grimes /* 1163df8bae1dSRodney W. Grimes * Free a fragment reassembly header and all 1164df8bae1dSRodney W. Grimes * associated datagrams. 1165df8bae1dSRodney W. Grimes */ 11660312fbe9SPoul-Henning Kamp static void 1167462b86feSPoul-Henning Kamp ip_freef(fhp, fp) 1168462b86feSPoul-Henning Kamp struct ipqhead *fhp; 1169df8bae1dSRodney W. Grimes struct ipq *fp; 1170df8bae1dSRodney W. Grimes { 11716effc713SDoug Rabson register struct mbuf *q; 1172df8bae1dSRodney W. Grimes 11736effc713SDoug Rabson while (fp->ipq_frags) { 11746effc713SDoug Rabson q = fp->ipq_frags; 11756effc713SDoug Rabson fp->ipq_frags = q->m_nextpkt; 11766effc713SDoug Rabson m_freem(q); 1177df8bae1dSRodney W. Grimes } 1178462b86feSPoul-Henning Kamp TAILQ_REMOVE(fhp, fp, ipq_list); 1179df8bae1dSRodney W. Grimes (void) m_free(dtom(fp)); 1180690a6055SJesper Skriver ip_nfragpackets--; 1181194a213eSAndrey A. Chernov nipq--; 1182df8bae1dSRodney W. Grimes } 1183df8bae1dSRodney W. Grimes 1184df8bae1dSRodney W. Grimes /* 1185df8bae1dSRodney W. Grimes * IP timer processing; 1186df8bae1dSRodney W. Grimes * if a timer expires on a reassembly 1187df8bae1dSRodney W. Grimes * queue, discard it. 1188df8bae1dSRodney W. Grimes */ 1189df8bae1dSRodney W. Grimes void 1190df8bae1dSRodney W. Grimes ip_slowtimo() 1191df8bae1dSRodney W. Grimes { 1192df8bae1dSRodney W. Grimes register struct ipq *fp; 1193df8bae1dSRodney W. Grimes int s = splnet(); 1194194a213eSAndrey A. Chernov int i; 1195df8bae1dSRodney W. Grimes 1196194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 1197462b86feSPoul-Henning Kamp for(fp = TAILQ_FIRST(&ipq[i]); fp;) { 1198462b86feSPoul-Henning Kamp struct ipq *fpp; 1199462b86feSPoul-Henning Kamp 1200462b86feSPoul-Henning Kamp fpp = fp; 1201462b86feSPoul-Henning Kamp fp = TAILQ_NEXT(fp, ipq_list); 1202462b86feSPoul-Henning Kamp if(--fpp->ipq_ttl == 0) { 1203df8bae1dSRodney W. Grimes ipstat.ips_fragtimeout++; 1204462b86feSPoul-Henning Kamp ip_freef(&ipq[i], fpp); 1205df8bae1dSRodney W. Grimes } 1206df8bae1dSRodney W. Grimes } 1207194a213eSAndrey A. Chernov } 1208690a6055SJesper Skriver /* 1209690a6055SJesper Skriver * If we are over the maximum number of fragments 1210690a6055SJesper Skriver * (due to the limit being lowered), drain off 1211690a6055SJesper Skriver * enough to get down to the new limit. 1212690a6055SJesper Skriver */ 1213690a6055SJesper Skriver for (i = 0; i < IPREASS_NHASH; i++) { 1214690a6055SJesper Skriver if (ip_maxfragpackets >= 0) { 1215690a6055SJesper Skriver while (ip_nfragpackets > ip_maxfragpackets && 1216690a6055SJesper Skriver !TAILQ_EMPTY(&ipq[i])) { 1217690a6055SJesper Skriver ipstat.ips_fragdropped++; 1218690a6055SJesper Skriver ip_freef(&ipq[i], TAILQ_FIRST(&ipq[i])); 1219690a6055SJesper Skriver } 1220690a6055SJesper Skriver } 1221690a6055SJesper Skriver } 12221f91d8c5SDavid Greenman ipflow_slowtimo(); 1223df8bae1dSRodney W. Grimes splx(s); 1224df8bae1dSRodney W. Grimes } 1225df8bae1dSRodney W. Grimes 1226df8bae1dSRodney W. Grimes /* 1227df8bae1dSRodney W. Grimes * Drain off all datagram fragments. 1228df8bae1dSRodney W. Grimes */ 1229df8bae1dSRodney W. Grimes void 1230df8bae1dSRodney W. Grimes ip_drain() 1231df8bae1dSRodney W. Grimes { 1232194a213eSAndrey A. Chernov int i; 1233ce29ab3aSGarrett Wollman 1234194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 1235462b86feSPoul-Henning Kamp while(!TAILQ_EMPTY(&ipq[i])) { 1236194a213eSAndrey A. Chernov ipstat.ips_fragdropped++; 1237462b86feSPoul-Henning Kamp ip_freef(&ipq[i], TAILQ_FIRST(&ipq[i])); 1238194a213eSAndrey A. Chernov } 1239194a213eSAndrey A. Chernov } 1240ce29ab3aSGarrett Wollman in_rtqdrain(); 1241df8bae1dSRodney W. Grimes } 1242df8bae1dSRodney W. Grimes 1243df8bae1dSRodney W. Grimes /* 1244df8bae1dSRodney W. Grimes * Do option processing on a datagram, 1245df8bae1dSRodney W. Grimes * possibly discarding it if bad options are encountered, 1246df8bae1dSRodney W. Grimes * or forwarding it if source-routed. 1247d0ebc0d2SYaroslav Tykhiy * The pass argument is used when operating in the IPSTEALTH 1248d0ebc0d2SYaroslav Tykhiy * mode to tell what options to process: 1249d0ebc0d2SYaroslav Tykhiy * [LS]SRR (pass 0) or the others (pass 1). 1250d0ebc0d2SYaroslav Tykhiy * The reason for as many as two passes is that when doing IPSTEALTH, 1251d0ebc0d2SYaroslav Tykhiy * non-routing options should be processed only if the packet is for us. 1252df8bae1dSRodney W. Grimes * Returns 1 if packet has been forwarded/freed, 1253df8bae1dSRodney W. Grimes * 0 if the packet should be processed further. 1254df8bae1dSRodney W. Grimes */ 12550312fbe9SPoul-Henning Kamp static int 12562b25acc1SLuigi Rizzo ip_dooptions(struct mbuf *m, int pass, struct sockaddr_in *next_hop) 1257df8bae1dSRodney W. Grimes { 12582b25acc1SLuigi Rizzo struct ip *ip = mtod(m, struct ip *); 12592b25acc1SLuigi Rizzo u_char *cp; 12602b25acc1SLuigi Rizzo struct in_ifaddr *ia; 1261df8bae1dSRodney W. Grimes int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0; 1262df8bae1dSRodney W. Grimes struct in_addr *sin, dst; 1263df8bae1dSRodney W. Grimes n_time ntime; 12644d2e3692SLuigi Rizzo struct sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET }; 1265df8bae1dSRodney W. Grimes 1266df8bae1dSRodney W. Grimes dst = ip->ip_dst; 1267df8bae1dSRodney W. Grimes cp = (u_char *)(ip + 1); 126853be11f6SPoul-Henning Kamp cnt = (ip->ip_hl << 2) - sizeof (struct ip); 1269df8bae1dSRodney W. Grimes for (; cnt > 0; cnt -= optlen, cp += optlen) { 1270df8bae1dSRodney W. Grimes opt = cp[IPOPT_OPTVAL]; 1271df8bae1dSRodney W. Grimes if (opt == IPOPT_EOL) 1272df8bae1dSRodney W. Grimes break; 1273df8bae1dSRodney W. Grimes if (opt == IPOPT_NOP) 1274df8bae1dSRodney W. Grimes optlen = 1; 1275df8bae1dSRodney W. Grimes else { 1276fdcb8debSJun-ichiro itojun Hagino if (cnt < IPOPT_OLEN + sizeof(*cp)) { 1277fdcb8debSJun-ichiro itojun Hagino code = &cp[IPOPT_OLEN] - (u_char *)ip; 1278fdcb8debSJun-ichiro itojun Hagino goto bad; 1279fdcb8debSJun-ichiro itojun Hagino } 1280df8bae1dSRodney W. Grimes optlen = cp[IPOPT_OLEN]; 1281707d00a3SJonathan Lemon if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt) { 1282df8bae1dSRodney W. Grimes code = &cp[IPOPT_OLEN] - (u_char *)ip; 1283df8bae1dSRodney W. Grimes goto bad; 1284df8bae1dSRodney W. Grimes } 1285df8bae1dSRodney W. Grimes } 1286df8bae1dSRodney W. Grimes switch (opt) { 1287df8bae1dSRodney W. Grimes 1288df8bae1dSRodney W. Grimes default: 1289df8bae1dSRodney W. Grimes break; 1290df8bae1dSRodney W. Grimes 1291df8bae1dSRodney W. Grimes /* 1292df8bae1dSRodney W. Grimes * Source routing with record. 1293df8bae1dSRodney W. Grimes * Find interface with current destination address. 1294df8bae1dSRodney W. Grimes * If none on this machine then drop if strictly routed, 1295df8bae1dSRodney W. Grimes * or do nothing if loosely routed. 1296df8bae1dSRodney W. Grimes * Record interface address and bring up next address 1297df8bae1dSRodney W. Grimes * component. If strictly routed make sure next 1298df8bae1dSRodney W. Grimes * address is on directly accessible net. 1299df8bae1dSRodney W. Grimes */ 1300df8bae1dSRodney W. Grimes case IPOPT_LSRR: 1301df8bae1dSRodney W. Grimes case IPOPT_SSRR: 1302d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH 1303d0ebc0d2SYaroslav Tykhiy if (ipstealth && pass > 0) 1304d0ebc0d2SYaroslav Tykhiy break; 1305d0ebc0d2SYaroslav Tykhiy #endif 130633841545SHajimu UMEMOTO if (optlen < IPOPT_OFFSET + sizeof(*cp)) { 130733841545SHajimu UMEMOTO code = &cp[IPOPT_OLEN] - (u_char *)ip; 130833841545SHajimu UMEMOTO goto bad; 130933841545SHajimu UMEMOTO } 1310df8bae1dSRodney W. Grimes if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { 1311df8bae1dSRodney W. Grimes code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1312df8bae1dSRodney W. Grimes goto bad; 1313df8bae1dSRodney W. Grimes } 1314df8bae1dSRodney W. Grimes ipaddr.sin_addr = ip->ip_dst; 1315df8bae1dSRodney W. Grimes ia = (struct in_ifaddr *) 1316df8bae1dSRodney W. Grimes ifa_ifwithaddr((struct sockaddr *)&ipaddr); 1317df8bae1dSRodney W. Grimes if (ia == 0) { 1318df8bae1dSRodney W. Grimes if (opt == IPOPT_SSRR) { 1319df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1320df8bae1dSRodney W. Grimes code = ICMP_UNREACH_SRCFAIL; 1321df8bae1dSRodney W. Grimes goto bad; 1322df8bae1dSRodney W. Grimes } 1323bc189bf8SGuido van Rooij if (!ip_dosourceroute) 1324bc189bf8SGuido van Rooij goto nosourcerouting; 1325df8bae1dSRodney W. Grimes /* 1326df8bae1dSRodney W. Grimes * Loose routing, and not at next destination 1327df8bae1dSRodney W. Grimes * yet; nothing to do except forward. 1328df8bae1dSRodney W. Grimes */ 1329df8bae1dSRodney W. Grimes break; 1330df8bae1dSRodney W. Grimes } 1331df8bae1dSRodney W. Grimes off--; /* 0 origin */ 13325d5d5fc0SJonathan Lemon if (off > optlen - (int)sizeof(struct in_addr)) { 1333df8bae1dSRodney W. Grimes /* 1334df8bae1dSRodney W. Grimes * End of source route. Should be for us. 1335df8bae1dSRodney W. Grimes */ 13364fce5804SGuido van Rooij if (!ip_acceptsourceroute) 13374fce5804SGuido van Rooij goto nosourcerouting; 1338df8bae1dSRodney W. Grimes save_rte(cp, ip->ip_src); 1339df8bae1dSRodney W. Grimes break; 1340df8bae1dSRodney W. Grimes } 1341d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH 1342d0ebc0d2SYaroslav Tykhiy if (ipstealth) 1343d0ebc0d2SYaroslav Tykhiy goto dropit; 1344d0ebc0d2SYaroslav Tykhiy #endif 13451025071fSGarrett Wollman if (!ip_dosourceroute) { 13460af8d3ecSDavid Greenman if (ipforwarding) { 13470af8d3ecSDavid Greenman char buf[16]; /* aaa.bbb.ccc.ddd\0 */ 13480af8d3ecSDavid Greenman /* 13490af8d3ecSDavid Greenman * Acting as a router, so generate ICMP 13500af8d3ecSDavid Greenman */ 1351efa48587SGuido van Rooij nosourcerouting: 1352bc189bf8SGuido van Rooij strcpy(buf, inet_ntoa(ip->ip_dst)); 13531025071fSGarrett Wollman log(LOG_WARNING, 13541025071fSGarrett Wollman "attempted source route from %s to %s\n", 13551025071fSGarrett Wollman inet_ntoa(ip->ip_src), buf); 13561025071fSGarrett Wollman type = ICMP_UNREACH; 13571025071fSGarrett Wollman code = ICMP_UNREACH_SRCFAIL; 13581025071fSGarrett Wollman goto bad; 13590af8d3ecSDavid Greenman } else { 13600af8d3ecSDavid Greenman /* 13610af8d3ecSDavid Greenman * Not acting as a router, so silently drop. 13620af8d3ecSDavid Greenman */ 1363d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH 1364d0ebc0d2SYaroslav Tykhiy dropit: 1365d0ebc0d2SYaroslav Tykhiy #endif 13660af8d3ecSDavid Greenman ipstat.ips_cantforward++; 13670af8d3ecSDavid Greenman m_freem(m); 13680af8d3ecSDavid Greenman return (1); 13690af8d3ecSDavid Greenman } 13701025071fSGarrett Wollman } 13711025071fSGarrett Wollman 1372df8bae1dSRodney W. Grimes /* 1373df8bae1dSRodney W. Grimes * locate outgoing interface 1374df8bae1dSRodney W. Grimes */ 137594a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, cp + off, 1376df8bae1dSRodney W. Grimes sizeof(ipaddr.sin_addr)); 13771025071fSGarrett Wollman 1378df8bae1dSRodney W. Grimes if (opt == IPOPT_SSRR) { 1379df8bae1dSRodney W. Grimes #define INA struct in_ifaddr * 1380df8bae1dSRodney W. Grimes #define SA struct sockaddr * 1381df8bae1dSRodney W. Grimes if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0) 1382df8bae1dSRodney W. Grimes ia = (INA)ifa_ifwithnet((SA)&ipaddr); 1383df8bae1dSRodney W. Grimes } else 1384bd714208SRuslan Ermilov ia = ip_rtaddr(ipaddr.sin_addr, &ipforward_rt); 1385df8bae1dSRodney W. Grimes if (ia == 0) { 1386df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1387df8bae1dSRodney W. Grimes code = ICMP_UNREACH_SRCFAIL; 1388df8bae1dSRodney W. Grimes goto bad; 1389df8bae1dSRodney W. Grimes } 1390df8bae1dSRodney W. Grimes ip->ip_dst = ipaddr.sin_addr; 139194a5d9b6SDavid Greenman (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr), 139294a5d9b6SDavid Greenman sizeof(struct in_addr)); 1393df8bae1dSRodney W. Grimes cp[IPOPT_OFFSET] += sizeof(struct in_addr); 1394df8bae1dSRodney W. Grimes /* 1395df8bae1dSRodney W. Grimes * Let ip_intr's mcast routing check handle mcast pkts 1396df8bae1dSRodney W. Grimes */ 1397df8bae1dSRodney W. Grimes forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr)); 1398df8bae1dSRodney W. Grimes break; 1399df8bae1dSRodney W. Grimes 1400df8bae1dSRodney W. Grimes case IPOPT_RR: 1401d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH 1402d0ebc0d2SYaroslav Tykhiy if (ipstealth && pass == 0) 1403d0ebc0d2SYaroslav Tykhiy break; 1404d0ebc0d2SYaroslav Tykhiy #endif 1405707d00a3SJonathan Lemon if (optlen < IPOPT_OFFSET + sizeof(*cp)) { 1406707d00a3SJonathan Lemon code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1407707d00a3SJonathan Lemon goto bad; 1408707d00a3SJonathan Lemon } 1409df8bae1dSRodney W. Grimes if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { 1410df8bae1dSRodney W. Grimes code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1411df8bae1dSRodney W. Grimes goto bad; 1412df8bae1dSRodney W. Grimes } 1413df8bae1dSRodney W. Grimes /* 1414df8bae1dSRodney W. Grimes * If no space remains, ignore. 1415df8bae1dSRodney W. Grimes */ 1416df8bae1dSRodney W. Grimes off--; /* 0 origin */ 14175d5d5fc0SJonathan Lemon if (off > optlen - (int)sizeof(struct in_addr)) 1418df8bae1dSRodney W. Grimes break; 141994a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, &ip->ip_dst, 1420df8bae1dSRodney W. Grimes sizeof(ipaddr.sin_addr)); 1421df8bae1dSRodney W. Grimes /* 1422df8bae1dSRodney W. Grimes * locate outgoing interface; if we're the destination, 1423df8bae1dSRodney W. Grimes * use the incoming interface (should be same). 1424df8bae1dSRodney W. Grimes */ 1425df8bae1dSRodney W. Grimes if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 && 1426bd714208SRuslan Ermilov (ia = ip_rtaddr(ipaddr.sin_addr, 1427bd714208SRuslan Ermilov &ipforward_rt)) == 0) { 1428df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1429df8bae1dSRodney W. Grimes code = ICMP_UNREACH_HOST; 1430df8bae1dSRodney W. Grimes goto bad; 1431df8bae1dSRodney W. Grimes } 143294a5d9b6SDavid Greenman (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr), 143394a5d9b6SDavid Greenman sizeof(struct in_addr)); 1434df8bae1dSRodney W. Grimes cp[IPOPT_OFFSET] += sizeof(struct in_addr); 1435df8bae1dSRodney W. Grimes break; 1436df8bae1dSRodney W. Grimes 1437df8bae1dSRodney W. Grimes case IPOPT_TS: 1438d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH 1439d0ebc0d2SYaroslav Tykhiy if (ipstealth && pass == 0) 1440d0ebc0d2SYaroslav Tykhiy break; 1441d0ebc0d2SYaroslav Tykhiy #endif 1442df8bae1dSRodney W. Grimes code = cp - (u_char *)ip; 144307514071SJonathan Lemon if (optlen < 4 || optlen > 40) { 144407514071SJonathan Lemon code = &cp[IPOPT_OLEN] - (u_char *)ip; 1445df8bae1dSRodney W. Grimes goto bad; 144633841545SHajimu UMEMOTO } 144707514071SJonathan Lemon if ((off = cp[IPOPT_OFFSET]) < 5) { 144807514071SJonathan Lemon code = &cp[IPOPT_OLEN] - (u_char *)ip; 144933841545SHajimu UMEMOTO goto bad; 145033841545SHajimu UMEMOTO } 145107514071SJonathan Lemon if (off > optlen - (int)sizeof(int32_t)) { 145207514071SJonathan Lemon cp[IPOPT_OFFSET + 1] += (1 << 4); 145307514071SJonathan Lemon if ((cp[IPOPT_OFFSET + 1] & 0xf0) == 0) { 145407514071SJonathan Lemon code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1455df8bae1dSRodney W. Grimes goto bad; 145633841545SHajimu UMEMOTO } 1457df8bae1dSRodney W. Grimes break; 1458df8bae1dSRodney W. Grimes } 145907514071SJonathan Lemon off--; /* 0 origin */ 146007514071SJonathan Lemon sin = (struct in_addr *)(cp + off); 146107514071SJonathan Lemon switch (cp[IPOPT_OFFSET + 1] & 0x0f) { 1462df8bae1dSRodney W. Grimes 1463df8bae1dSRodney W. Grimes case IPOPT_TS_TSONLY: 1464df8bae1dSRodney W. Grimes break; 1465df8bae1dSRodney W. Grimes 1466df8bae1dSRodney W. Grimes case IPOPT_TS_TSANDADDR: 146707514071SJonathan Lemon if (off + sizeof(n_time) + 146807514071SJonathan Lemon sizeof(struct in_addr) > optlen) { 146907514071SJonathan Lemon code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1470df8bae1dSRodney W. Grimes goto bad; 147133841545SHajimu UMEMOTO } 1472df8bae1dSRodney W. Grimes ipaddr.sin_addr = dst; 1473df8bae1dSRodney W. Grimes ia = (INA)ifaof_ifpforaddr((SA)&ipaddr, 1474df8bae1dSRodney W. Grimes m->m_pkthdr.rcvif); 1475df8bae1dSRodney W. Grimes if (ia == 0) 1476df8bae1dSRodney W. Grimes continue; 147794a5d9b6SDavid Greenman (void)memcpy(sin, &IA_SIN(ia)->sin_addr, 147894a5d9b6SDavid Greenman sizeof(struct in_addr)); 147907514071SJonathan Lemon cp[IPOPT_OFFSET] += sizeof(struct in_addr); 1480a5428e3aSMaxim Konovalov off += sizeof(struct in_addr); 1481df8bae1dSRodney W. Grimes break; 1482df8bae1dSRodney W. Grimes 1483df8bae1dSRodney W. Grimes case IPOPT_TS_PRESPEC: 148407514071SJonathan Lemon if (off + sizeof(n_time) + 148507514071SJonathan Lemon sizeof(struct in_addr) > optlen) { 148607514071SJonathan Lemon code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1487df8bae1dSRodney W. Grimes goto bad; 148833841545SHajimu UMEMOTO } 148994a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, sin, 1490df8bae1dSRodney W. Grimes sizeof(struct in_addr)); 1491df8bae1dSRodney W. Grimes if (ifa_ifwithaddr((SA)&ipaddr) == 0) 1492df8bae1dSRodney W. Grimes continue; 149307514071SJonathan Lemon cp[IPOPT_OFFSET] += sizeof(struct in_addr); 1494a5428e3aSMaxim Konovalov off += sizeof(struct in_addr); 1495df8bae1dSRodney W. Grimes break; 1496df8bae1dSRodney W. Grimes 1497df8bae1dSRodney W. Grimes default: 149807514071SJonathan Lemon code = &cp[IPOPT_OFFSET + 1] - (u_char *)ip; 1499df8bae1dSRodney W. Grimes goto bad; 1500df8bae1dSRodney W. Grimes } 1501df8bae1dSRodney W. Grimes ntime = iptime(); 150207514071SJonathan Lemon (void)memcpy(cp + off, &ntime, sizeof(n_time)); 150307514071SJonathan Lemon cp[IPOPT_OFFSET] += sizeof(n_time); 1504df8bae1dSRodney W. Grimes } 1505df8bae1dSRodney W. Grimes } 150647174b49SAndrey A. Chernov if (forward && ipforwarding) { 15072b25acc1SLuigi Rizzo ip_forward(m, 1, next_hop); 1508df8bae1dSRodney W. Grimes return (1); 1509df8bae1dSRodney W. Grimes } 1510df8bae1dSRodney W. Grimes return (0); 1511df8bae1dSRodney W. Grimes bad: 1512df8bae1dSRodney W. Grimes icmp_error(m, type, code, 0, 0); 1513df8bae1dSRodney W. Grimes ipstat.ips_badoptions++; 1514df8bae1dSRodney W. Grimes return (1); 1515df8bae1dSRodney W. Grimes } 1516df8bae1dSRodney W. Grimes 1517df8bae1dSRodney W. Grimes /* 1518df8bae1dSRodney W. Grimes * Given address of next destination (final or next hop), 1519df8bae1dSRodney W. Grimes * return internet address info of interface to be used to get there. 1520df8bae1dSRodney W. Grimes */ 1521bd714208SRuslan Ermilov struct in_ifaddr * 1522bd714208SRuslan Ermilov ip_rtaddr(dst, rt) 1523df8bae1dSRodney W. Grimes struct in_addr dst; 1524bd714208SRuslan Ermilov struct route *rt; 1525df8bae1dSRodney W. Grimes { 1526df8bae1dSRodney W. Grimes register struct sockaddr_in *sin; 1527df8bae1dSRodney W. Grimes 1528bd714208SRuslan Ermilov sin = (struct sockaddr_in *)&rt->ro_dst; 1529df8bae1dSRodney W. Grimes 1530bd714208SRuslan Ermilov if (rt->ro_rt == 0 || 1531bd714208SRuslan Ermilov !(rt->ro_rt->rt_flags & RTF_UP) || 15324078ffb1SRuslan Ermilov dst.s_addr != sin->sin_addr.s_addr) { 1533bd714208SRuslan Ermilov if (rt->ro_rt) { 1534bd714208SRuslan Ermilov RTFREE(rt->ro_rt); 1535bd714208SRuslan Ermilov rt->ro_rt = 0; 1536df8bae1dSRodney W. Grimes } 1537df8bae1dSRodney W. Grimes sin->sin_family = AF_INET; 1538df8bae1dSRodney W. Grimes sin->sin_len = sizeof(*sin); 1539df8bae1dSRodney W. Grimes sin->sin_addr = dst; 1540df8bae1dSRodney W. Grimes 1541bd714208SRuslan Ermilov rtalloc_ign(rt, RTF_PRCLONING); 1542df8bae1dSRodney W. Grimes } 1543bd714208SRuslan Ermilov if (rt->ro_rt == 0) 1544df8bae1dSRodney W. Grimes return ((struct in_ifaddr *)0); 1545bd714208SRuslan Ermilov return (ifatoia(rt->ro_rt->rt_ifa)); 1546df8bae1dSRodney W. Grimes } 1547df8bae1dSRodney W. Grimes 1548df8bae1dSRodney W. Grimes /* 1549df8bae1dSRodney W. Grimes * Save incoming source route for use in replies, 1550df8bae1dSRodney W. Grimes * to be picked up later by ip_srcroute if the receiver is interested. 1551df8bae1dSRodney W. Grimes */ 155237c84183SPoul-Henning Kamp static void 1553df8bae1dSRodney W. Grimes save_rte(option, dst) 1554df8bae1dSRodney W. Grimes u_char *option; 1555df8bae1dSRodney W. Grimes struct in_addr dst; 1556df8bae1dSRodney W. Grimes { 1557df8bae1dSRodney W. Grimes unsigned olen; 1558df8bae1dSRodney W. Grimes 1559df8bae1dSRodney W. Grimes olen = option[IPOPT_OLEN]; 1560df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1561df8bae1dSRodney W. Grimes if (ipprintfs) 1562df8bae1dSRodney W. Grimes printf("save_rte: olen %d\n", olen); 1563df8bae1dSRodney W. Grimes #endif 1564df8bae1dSRodney W. Grimes if (olen > sizeof(ip_srcrt) - (1 + sizeof(dst))) 1565df8bae1dSRodney W. Grimes return; 15660453d3cbSBruce Evans bcopy(option, ip_srcrt.srcopt, olen); 1567df8bae1dSRodney W. Grimes ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr); 1568df8bae1dSRodney W. Grimes ip_srcrt.dst = dst; 1569df8bae1dSRodney W. Grimes } 1570df8bae1dSRodney W. Grimes 1571df8bae1dSRodney W. Grimes /* 1572df8bae1dSRodney W. Grimes * Retrieve incoming source route for use in replies, 1573df8bae1dSRodney W. Grimes * in the same form used by setsockopt. 1574df8bae1dSRodney W. Grimes * The first hop is placed before the options, will be removed later. 1575df8bae1dSRodney W. Grimes */ 1576df8bae1dSRodney W. Grimes struct mbuf * 1577df8bae1dSRodney W. Grimes ip_srcroute() 1578df8bae1dSRodney W. Grimes { 1579df8bae1dSRodney W. Grimes register struct in_addr *p, *q; 1580df8bae1dSRodney W. Grimes register struct mbuf *m; 1581df8bae1dSRodney W. Grimes 1582df8bae1dSRodney W. Grimes if (ip_nhops == 0) 1583df8bae1dSRodney W. Grimes return ((struct mbuf *)0); 1584cfe8b629SGarrett Wollman m = m_get(M_DONTWAIT, MT_HEADER); 1585df8bae1dSRodney W. Grimes if (m == 0) 1586df8bae1dSRodney W. Grimes return ((struct mbuf *)0); 1587df8bae1dSRodney W. Grimes 1588df8bae1dSRodney W. Grimes #define OPTSIZ (sizeof(ip_srcrt.nop) + sizeof(ip_srcrt.srcopt)) 1589df8bae1dSRodney W. Grimes 1590df8bae1dSRodney W. Grimes /* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */ 1591df8bae1dSRodney W. Grimes m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) + 1592df8bae1dSRodney W. Grimes OPTSIZ; 1593df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1594df8bae1dSRodney W. Grimes if (ipprintfs) 1595df8bae1dSRodney W. Grimes printf("ip_srcroute: nhops %d mlen %d", ip_nhops, m->m_len); 1596df8bae1dSRodney W. Grimes #endif 1597df8bae1dSRodney W. Grimes 1598df8bae1dSRodney W. Grimes /* 1599df8bae1dSRodney W. Grimes * First save first hop for return route 1600df8bae1dSRodney W. Grimes */ 1601df8bae1dSRodney W. Grimes p = &ip_srcrt.route[ip_nhops - 1]; 1602df8bae1dSRodney W. Grimes *(mtod(m, struct in_addr *)) = *p--; 1603df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1604df8bae1dSRodney W. Grimes if (ipprintfs) 1605af38c68cSLuigi Rizzo printf(" hops %lx", (u_long)ntohl(mtod(m, struct in_addr *)->s_addr)); 1606df8bae1dSRodney W. Grimes #endif 1607df8bae1dSRodney W. Grimes 1608df8bae1dSRodney W. Grimes /* 1609df8bae1dSRodney W. Grimes * Copy option fields and padding (nop) to mbuf. 1610df8bae1dSRodney W. Grimes */ 1611df8bae1dSRodney W. Grimes ip_srcrt.nop = IPOPT_NOP; 1612df8bae1dSRodney W. Grimes ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF; 161394a5d9b6SDavid Greenman (void)memcpy(mtod(m, caddr_t) + sizeof(struct in_addr), 161494a5d9b6SDavid Greenman &ip_srcrt.nop, OPTSIZ); 1615df8bae1dSRodney W. Grimes q = (struct in_addr *)(mtod(m, caddr_t) + 1616df8bae1dSRodney W. Grimes sizeof(struct in_addr) + OPTSIZ); 1617df8bae1dSRodney W. Grimes #undef OPTSIZ 1618df8bae1dSRodney W. Grimes /* 1619df8bae1dSRodney W. Grimes * Record return path as an IP source route, 1620df8bae1dSRodney W. Grimes * reversing the path (pointers are now aligned). 1621df8bae1dSRodney W. Grimes */ 1622df8bae1dSRodney W. Grimes while (p >= ip_srcrt.route) { 1623df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1624df8bae1dSRodney W. Grimes if (ipprintfs) 1625af38c68cSLuigi Rizzo printf(" %lx", (u_long)ntohl(q->s_addr)); 1626df8bae1dSRodney W. Grimes #endif 1627df8bae1dSRodney W. Grimes *q++ = *p--; 1628df8bae1dSRodney W. Grimes } 1629df8bae1dSRodney W. Grimes /* 1630df8bae1dSRodney W. Grimes * Last hop goes to final destination. 1631df8bae1dSRodney W. Grimes */ 1632df8bae1dSRodney W. Grimes *q = ip_srcrt.dst; 1633df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1634df8bae1dSRodney W. Grimes if (ipprintfs) 1635af38c68cSLuigi Rizzo printf(" %lx\n", (u_long)ntohl(q->s_addr)); 1636df8bae1dSRodney W. Grimes #endif 1637df8bae1dSRodney W. Grimes return (m); 1638df8bae1dSRodney W. Grimes } 1639df8bae1dSRodney W. Grimes 1640df8bae1dSRodney W. Grimes /* 1641df8bae1dSRodney W. Grimes * Strip out IP options, at higher 1642df8bae1dSRodney W. Grimes * level protocol in the kernel. 1643df8bae1dSRodney W. Grimes * Second argument is buffer to which options 1644df8bae1dSRodney W. Grimes * will be moved, and return value is their length. 1645df8bae1dSRodney W. Grimes * XXX should be deleted; last arg currently ignored. 1646df8bae1dSRodney W. Grimes */ 1647df8bae1dSRodney W. Grimes void 1648df8bae1dSRodney W. Grimes ip_stripoptions(m, mopt) 1649df8bae1dSRodney W. Grimes register struct mbuf *m; 1650df8bae1dSRodney W. Grimes struct mbuf *mopt; 1651df8bae1dSRodney W. Grimes { 1652df8bae1dSRodney W. Grimes register int i; 1653df8bae1dSRodney W. Grimes struct ip *ip = mtod(m, struct ip *); 1654df8bae1dSRodney W. Grimes register caddr_t opts; 1655df8bae1dSRodney W. Grimes int olen; 1656df8bae1dSRodney W. Grimes 165753be11f6SPoul-Henning Kamp olen = (ip->ip_hl << 2) - sizeof (struct ip); 1658df8bae1dSRodney W. Grimes opts = (caddr_t)(ip + 1); 1659df8bae1dSRodney W. Grimes i = m->m_len - (sizeof (struct ip) + olen); 1660df8bae1dSRodney W. Grimes bcopy(opts + olen, opts, (unsigned)i); 1661df8bae1dSRodney W. Grimes m->m_len -= olen; 1662df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) 1663df8bae1dSRodney W. Grimes m->m_pkthdr.len -= olen; 166453be11f6SPoul-Henning Kamp ip->ip_v = IPVERSION; 166553be11f6SPoul-Henning Kamp ip->ip_hl = sizeof(struct ip) >> 2; 1666df8bae1dSRodney W. Grimes } 1667df8bae1dSRodney W. Grimes 1668df8bae1dSRodney W. Grimes u_char inetctlerrmap[PRC_NCMDS] = { 1669df8bae1dSRodney W. Grimes 0, 0, 0, 0, 1670df8bae1dSRodney W. Grimes 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH, 1671df8bae1dSRodney W. Grimes EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, 1672df8bae1dSRodney W. Grimes EMSGSIZE, EHOSTUNREACH, 0, 0, 1673df8bae1dSRodney W. Grimes 0, 0, 0, 0, 16743b8123b7SJesper Skriver ENOPROTOOPT, ECONNREFUSED 1675df8bae1dSRodney W. Grimes }; 1676df8bae1dSRodney W. Grimes 1677df8bae1dSRodney W. Grimes /* 1678df8bae1dSRodney W. Grimes * Forward a packet. If some error occurs return the sender 1679df8bae1dSRodney W. Grimes * an icmp packet. Note we can't always generate a meaningful 1680df8bae1dSRodney W. Grimes * icmp message because icmp doesn't have a large enough repertoire 1681df8bae1dSRodney W. Grimes * of codes and types. 1682df8bae1dSRodney W. Grimes * 1683df8bae1dSRodney W. Grimes * If not forwarding, just drop the packet. This could be confusing 1684df8bae1dSRodney W. Grimes * if ipforwarding was zero but some routing protocol was advancing 1685df8bae1dSRodney W. Grimes * us as a gateway to somewhere. However, we must let the routing 1686df8bae1dSRodney W. Grimes * protocol deal with that. 1687df8bae1dSRodney W. Grimes * 1688df8bae1dSRodney W. Grimes * The srcrt parameter indicates whether the packet is being forwarded 1689df8bae1dSRodney W. Grimes * via a source route. 1690df8bae1dSRodney W. Grimes */ 16910312fbe9SPoul-Henning Kamp static void 16922b25acc1SLuigi Rizzo ip_forward(struct mbuf *m, int srcrt, struct sockaddr_in *next_hop) 1693df8bae1dSRodney W. Grimes { 16942b25acc1SLuigi Rizzo struct ip *ip = mtod(m, struct ip *); 16952b25acc1SLuigi Rizzo struct rtentry *rt; 169626f9a767SRodney W. Grimes int error, type = 0, code = 0; 1697df8bae1dSRodney W. Grimes struct mbuf *mcopy; 1698df8bae1dSRodney W. Grimes n_long dest; 16993efc3014SJulian Elischer struct in_addr pkt_dst; 1700df8bae1dSRodney W. Grimes struct ifnet *destifp; 1701b9234fafSSam Leffler #if defined(IPSEC) || defined(FAST_IPSEC) 17026a800098SYoshinobu Inoue struct ifnet dummyifp; 17036a800098SYoshinobu Inoue #endif 1704df8bae1dSRodney W. Grimes 1705df8bae1dSRodney W. Grimes dest = 0; 17063efc3014SJulian Elischer /* 17073efc3014SJulian Elischer * Cache the destination address of the packet; this may be 17083efc3014SJulian Elischer * changed by use of 'ipfw fwd'. 17093efc3014SJulian Elischer */ 17102b25acc1SLuigi Rizzo pkt_dst = next_hop ? next_hop->sin_addr : ip->ip_dst; 17113efc3014SJulian Elischer 1712df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1713df8bae1dSRodney W. Grimes if (ipprintfs) 171461ce519bSPoul-Henning Kamp printf("forward: src %lx dst %lx ttl %x\n", 17153efc3014SJulian Elischer (u_long)ip->ip_src.s_addr, (u_long)pkt_dst.s_addr, 1716162886e2SBruce Evans ip->ip_ttl); 1717df8bae1dSRodney W. Grimes #endif 1718100ba1a6SJordan K. Hubbard 1719100ba1a6SJordan K. Hubbard 17203efc3014SJulian Elischer if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(pkt_dst) == 0) { 1721df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 1722df8bae1dSRodney W. Grimes m_freem(m); 1723df8bae1dSRodney W. Grimes return; 1724df8bae1dSRodney W. Grimes } 17251b968362SDag-Erling Smørgrav #ifdef IPSTEALTH 17261b968362SDag-Erling Smørgrav if (!ipstealth) { 17271b968362SDag-Erling Smørgrav #endif 1728df8bae1dSRodney W. Grimes if (ip->ip_ttl <= IPTTLDEC) { 17291b968362SDag-Erling Smørgrav icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 17301b968362SDag-Erling Smørgrav dest, 0); 1731df8bae1dSRodney W. Grimes return; 1732df8bae1dSRodney W. Grimes } 17331b968362SDag-Erling Smørgrav #ifdef IPSTEALTH 17341b968362SDag-Erling Smørgrav } 17351b968362SDag-Erling Smørgrav #endif 1736df8bae1dSRodney W. Grimes 17373efc3014SJulian Elischer if (ip_rtaddr(pkt_dst, &ipforward_rt) == 0) { 1738df8bae1dSRodney W. Grimes icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0); 1739df8bae1dSRodney W. Grimes return; 17404078ffb1SRuslan Ermilov } else 1741df8bae1dSRodney W. Grimes rt = ipforward_rt.ro_rt; 1742df8bae1dSRodney W. Grimes 1743df8bae1dSRodney W. Grimes /* 1744bfef7ed4SIan Dowse * Save the IP header and at most 8 bytes of the payload, 1745bfef7ed4SIan Dowse * in case we need to generate an ICMP message to the src. 1746bfef7ed4SIan Dowse * 17474d2e3692SLuigi Rizzo * XXX this can be optimized a lot by saving the data in a local 17484d2e3692SLuigi Rizzo * buffer on the stack (72 bytes at most), and only allocating the 17494d2e3692SLuigi Rizzo * mbuf if really necessary. The vast majority of the packets 17504d2e3692SLuigi Rizzo * are forwarded without having to send an ICMP back (either 17514d2e3692SLuigi Rizzo * because unnecessary, or because rate limited), so we are 17524d2e3692SLuigi Rizzo * really we are wasting a lot of work here. 17534d2e3692SLuigi Rizzo * 1754bfef7ed4SIan Dowse * We don't use m_copy() because it might return a reference 1755bfef7ed4SIan Dowse * to a shared cluster. Both this function and ip_output() 1756bfef7ed4SIan Dowse * assume exclusive access to the IP header in `m', so any 1757bfef7ed4SIan Dowse * data in a cluster may change before we reach icmp_error(). 1758df8bae1dSRodney W. Grimes */ 1759bfef7ed4SIan Dowse MGET(mcopy, M_DONTWAIT, m->m_type); 1760bfef7ed4SIan Dowse if (mcopy != NULL) { 1761bfef7ed4SIan Dowse M_COPY_PKTHDR(mcopy, m); 176253be11f6SPoul-Henning Kamp mcopy->m_len = imin((ip->ip_hl << 2) + 8, 1763bfef7ed4SIan Dowse (int)ip->ip_len); 1764bfef7ed4SIan Dowse m_copydata(m, 0, mcopy->m_len, mtod(mcopy, caddr_t)); 1765e316463aSRobert Watson #ifdef MAC 1766e316463aSRobert Watson /* 1767e316463aSRobert Watson * XXXMAC: This will eventually become an explicit 1768e316463aSRobert Watson * labeling point. 1769e316463aSRobert Watson */ 1770e316463aSRobert Watson mac_create_mbuf_from_mbuf(m, mcopy); 1771e316463aSRobert Watson #endif 1772bfef7ed4SIan Dowse } 177304287599SRuslan Ermilov 177404287599SRuslan Ermilov #ifdef IPSTEALTH 177504287599SRuslan Ermilov if (!ipstealth) { 177604287599SRuslan Ermilov #endif 177704287599SRuslan Ermilov ip->ip_ttl -= IPTTLDEC; 177804287599SRuslan Ermilov #ifdef IPSTEALTH 177904287599SRuslan Ermilov } 178004287599SRuslan Ermilov #endif 1781df8bae1dSRodney W. Grimes 1782df8bae1dSRodney W. Grimes /* 1783df8bae1dSRodney W. Grimes * If forwarding packet using same interface that it came in on, 1784df8bae1dSRodney W. Grimes * perhaps should send a redirect to sender to shortcut a hop. 1785df8bae1dSRodney W. Grimes * Only send redirect if source is sending directly to us, 1786df8bae1dSRodney W. Grimes * and if packet was not source routed (or has any options). 1787df8bae1dSRodney W. Grimes * Also, don't send redirect if forwarding using a default route 1788df8bae1dSRodney W. Grimes * or a route modified by a redirect. 1789df8bae1dSRodney W. Grimes */ 1790df8bae1dSRodney W. Grimes if (rt->rt_ifp == m->m_pkthdr.rcvif && 1791df8bae1dSRodney W. Grimes (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 && 1792df8bae1dSRodney W. Grimes satosin(rt_key(rt))->sin_addr.s_addr != 0 && 17932b25acc1SLuigi Rizzo ipsendredirects && !srcrt && !next_hop) { 1794df8bae1dSRodney W. Grimes #define RTA(rt) ((struct in_ifaddr *)(rt->rt_ifa)) 1795df8bae1dSRodney W. Grimes u_long src = ntohl(ip->ip_src.s_addr); 1796df8bae1dSRodney W. Grimes 1797df8bae1dSRodney W. Grimes if (RTA(rt) && 1798df8bae1dSRodney W. Grimes (src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) { 1799df8bae1dSRodney W. Grimes if (rt->rt_flags & RTF_GATEWAY) 1800df8bae1dSRodney W. Grimes dest = satosin(rt->rt_gateway)->sin_addr.s_addr; 1801df8bae1dSRodney W. Grimes else 18023efc3014SJulian Elischer dest = pkt_dst.s_addr; 1803df8bae1dSRodney W. Grimes /* Router requirements says to only send host redirects */ 1804df8bae1dSRodney W. Grimes type = ICMP_REDIRECT; 1805df8bae1dSRodney W. Grimes code = ICMP_REDIRECT_HOST; 1806df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1807df8bae1dSRodney W. Grimes if (ipprintfs) 1808df8bae1dSRodney W. Grimes printf("redirect (%d) to %lx\n", code, (u_long)dest); 1809df8bae1dSRodney W. Grimes #endif 1810df8bae1dSRodney W. Grimes } 1811df8bae1dSRodney W. Grimes } 1812df8bae1dSRodney W. Grimes 1813ea779ff3SLuigi Rizzo { 1814ea779ff3SLuigi Rizzo struct m_hdr tag; 1815ea779ff3SLuigi Rizzo 1816ea779ff3SLuigi Rizzo if (next_hop) { 1817ea779ff3SLuigi Rizzo /* Pass IPFORWARD info if available */ 1818ea779ff3SLuigi Rizzo 1819ea779ff3SLuigi Rizzo tag.mh_type = MT_TAG; 1820ea779ff3SLuigi Rizzo tag.mh_flags = PACKET_TAG_IPFORWARD; 1821ea779ff3SLuigi Rizzo tag.mh_data = (caddr_t)next_hop; 1822ea779ff3SLuigi Rizzo tag.mh_next = m; 1823ea779ff3SLuigi Rizzo m = (struct mbuf *)&tag; 1824ea779ff3SLuigi Rizzo } 1825b97d15cbSGarrett Wollman error = ip_output(m, (struct mbuf *)0, &ipforward_rt, 18265d846453SSam Leffler IP_FORWARDING, 0, NULL); 1827ea779ff3SLuigi Rizzo } 1828df8bae1dSRodney W. Grimes if (error) 1829df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 1830df8bae1dSRodney W. Grimes else { 1831df8bae1dSRodney W. Grimes ipstat.ips_forward++; 1832df8bae1dSRodney W. Grimes if (type) 1833df8bae1dSRodney W. Grimes ipstat.ips_redirectsent++; 1834df8bae1dSRodney W. Grimes else { 18351f91d8c5SDavid Greenman if (mcopy) { 18361f91d8c5SDavid Greenman ipflow_create(&ipforward_rt, mcopy); 1837df8bae1dSRodney W. Grimes m_freem(mcopy); 18381f91d8c5SDavid Greenman } 1839df8bae1dSRodney W. Grimes return; 1840df8bae1dSRodney W. Grimes } 1841df8bae1dSRodney W. Grimes } 1842df8bae1dSRodney W. Grimes if (mcopy == NULL) 1843df8bae1dSRodney W. Grimes return; 1844df8bae1dSRodney W. Grimes destifp = NULL; 1845df8bae1dSRodney W. Grimes 1846df8bae1dSRodney W. Grimes switch (error) { 1847df8bae1dSRodney W. Grimes 1848df8bae1dSRodney W. Grimes case 0: /* forwarded, but need redirect */ 1849df8bae1dSRodney W. Grimes /* type, code set above */ 1850df8bae1dSRodney W. Grimes break; 1851df8bae1dSRodney W. Grimes 1852df8bae1dSRodney W. Grimes case ENETUNREACH: /* shouldn't happen, checked above */ 1853df8bae1dSRodney W. Grimes case EHOSTUNREACH: 1854df8bae1dSRodney W. Grimes case ENETDOWN: 1855df8bae1dSRodney W. Grimes case EHOSTDOWN: 1856df8bae1dSRodney W. Grimes default: 1857df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1858df8bae1dSRodney W. Grimes code = ICMP_UNREACH_HOST; 1859df8bae1dSRodney W. Grimes break; 1860df8bae1dSRodney W. Grimes 1861df8bae1dSRodney W. Grimes case EMSGSIZE: 1862df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1863df8bae1dSRodney W. Grimes code = ICMP_UNREACH_NEEDFRAG; 18645d846453SSam Leffler #ifdef IPSEC 18656a800098SYoshinobu Inoue /* 18666a800098SYoshinobu Inoue * If the packet is routed over IPsec tunnel, tell the 18676a800098SYoshinobu Inoue * originator the tunnel MTU. 18686a800098SYoshinobu Inoue * tunnel MTU = if MTU - sizeof(IP) - ESP/AH hdrsiz 18696a800098SYoshinobu Inoue * XXX quickhack!!! 18706a800098SYoshinobu Inoue */ 18716a800098SYoshinobu Inoue if (ipforward_rt.ro_rt) { 18726a800098SYoshinobu Inoue struct secpolicy *sp = NULL; 18736a800098SYoshinobu Inoue int ipsecerror; 18746a800098SYoshinobu Inoue int ipsechdr; 18756a800098SYoshinobu Inoue struct route *ro; 18766a800098SYoshinobu Inoue 18776a800098SYoshinobu Inoue sp = ipsec4_getpolicybyaddr(mcopy, 18786a800098SYoshinobu Inoue IPSEC_DIR_OUTBOUND, 18796a800098SYoshinobu Inoue IP_FORWARDING, 18806a800098SYoshinobu Inoue &ipsecerror); 18816a800098SYoshinobu Inoue 18826a800098SYoshinobu Inoue if (sp == NULL) 18836a800098SYoshinobu Inoue destifp = ipforward_rt.ro_rt->rt_ifp; 18846a800098SYoshinobu Inoue else { 18856a800098SYoshinobu Inoue /* count IPsec header size */ 18866a800098SYoshinobu Inoue ipsechdr = ipsec4_hdrsiz(mcopy, 18876a800098SYoshinobu Inoue IPSEC_DIR_OUTBOUND, 18886a800098SYoshinobu Inoue NULL); 18896a800098SYoshinobu Inoue 18906a800098SYoshinobu Inoue /* 18916a800098SYoshinobu Inoue * find the correct route for outer IPv4 18926a800098SYoshinobu Inoue * header, compute tunnel MTU. 18936a800098SYoshinobu Inoue * 18946a800098SYoshinobu Inoue * XXX BUG ALERT 18956a800098SYoshinobu Inoue * The "dummyifp" code relies upon the fact 18966a800098SYoshinobu Inoue * that icmp_error() touches only ifp->if_mtu. 18976a800098SYoshinobu Inoue */ 18986a800098SYoshinobu Inoue /*XXX*/ 18996a800098SYoshinobu Inoue destifp = NULL; 19006a800098SYoshinobu Inoue if (sp->req != NULL 19016a800098SYoshinobu Inoue && sp->req->sav != NULL 19026a800098SYoshinobu Inoue && sp->req->sav->sah != NULL) { 19036a800098SYoshinobu Inoue ro = &sp->req->sav->sah->sa_route; 19046a800098SYoshinobu Inoue if (ro->ro_rt && ro->ro_rt->rt_ifp) { 19056a800098SYoshinobu Inoue dummyifp.if_mtu = 19066a800098SYoshinobu Inoue ro->ro_rt->rt_ifp->if_mtu; 19076a800098SYoshinobu Inoue dummyifp.if_mtu -= ipsechdr; 19086a800098SYoshinobu Inoue destifp = &dummyifp; 19096a800098SYoshinobu Inoue } 19106a800098SYoshinobu Inoue } 19116a800098SYoshinobu Inoue 19126a800098SYoshinobu Inoue key_freesp(sp); 19136a800098SYoshinobu Inoue } 19146a800098SYoshinobu Inoue } 1915b9234fafSSam Leffler #elif FAST_IPSEC 1916b9234fafSSam Leffler /* 1917b9234fafSSam Leffler * If the packet is routed over IPsec tunnel, tell the 1918b9234fafSSam Leffler * originator the tunnel MTU. 1919b9234fafSSam Leffler * tunnel MTU = if MTU - sizeof(IP) - ESP/AH hdrsiz 1920b9234fafSSam Leffler * XXX quickhack!!! 1921b9234fafSSam Leffler */ 1922b9234fafSSam Leffler if (ipforward_rt.ro_rt) { 1923b9234fafSSam Leffler struct secpolicy *sp = NULL; 1924b9234fafSSam Leffler int ipsecerror; 1925b9234fafSSam Leffler int ipsechdr; 1926b9234fafSSam Leffler struct route *ro; 1927b9234fafSSam Leffler 1928b9234fafSSam Leffler sp = ipsec_getpolicybyaddr(mcopy, 1929b9234fafSSam Leffler IPSEC_DIR_OUTBOUND, 1930b9234fafSSam Leffler IP_FORWARDING, 1931b9234fafSSam Leffler &ipsecerror); 1932b9234fafSSam Leffler 1933b9234fafSSam Leffler if (sp == NULL) 1934b9234fafSSam Leffler destifp = ipforward_rt.ro_rt->rt_ifp; 1935b9234fafSSam Leffler else { 1936b9234fafSSam Leffler /* count IPsec header size */ 1937b9234fafSSam Leffler ipsechdr = ipsec4_hdrsiz(mcopy, 1938b9234fafSSam Leffler IPSEC_DIR_OUTBOUND, 1939b9234fafSSam Leffler NULL); 1940b9234fafSSam Leffler 1941b9234fafSSam Leffler /* 1942b9234fafSSam Leffler * find the correct route for outer IPv4 1943b9234fafSSam Leffler * header, compute tunnel MTU. 1944b9234fafSSam Leffler * 1945b9234fafSSam Leffler * XXX BUG ALERT 1946b9234fafSSam Leffler * The "dummyifp" code relies upon the fact 1947b9234fafSSam Leffler * that icmp_error() touches only ifp->if_mtu. 1948b9234fafSSam Leffler */ 1949b9234fafSSam Leffler /*XXX*/ 1950b9234fafSSam Leffler destifp = NULL; 1951b9234fafSSam Leffler if (sp->req != NULL 1952b9234fafSSam Leffler && sp->req->sav != NULL 1953b9234fafSSam Leffler && sp->req->sav->sah != NULL) { 1954b9234fafSSam Leffler ro = &sp->req->sav->sah->sa_route; 1955b9234fafSSam Leffler if (ro->ro_rt && ro->ro_rt->rt_ifp) { 1956b9234fafSSam Leffler dummyifp.if_mtu = 1957b9234fafSSam Leffler ro->ro_rt->rt_ifp->if_mtu; 1958b9234fafSSam Leffler dummyifp.if_mtu -= ipsechdr; 1959b9234fafSSam Leffler destifp = &dummyifp; 1960b9234fafSSam Leffler } 1961b9234fafSSam Leffler } 1962b9234fafSSam Leffler 1963b9234fafSSam Leffler KEY_FREESP(&sp); 1964b9234fafSSam Leffler } 1965b9234fafSSam Leffler } 1966b9234fafSSam Leffler #else /* !IPSEC && !FAST_IPSEC */ 19675d846453SSam Leffler if (ipforward_rt.ro_rt) 19685d846453SSam Leffler destifp = ipforward_rt.ro_rt->rt_ifp; 19696a800098SYoshinobu Inoue #endif /*IPSEC*/ 1970df8bae1dSRodney W. Grimes ipstat.ips_cantfrag++; 1971df8bae1dSRodney W. Grimes break; 1972df8bae1dSRodney W. Grimes 1973df8bae1dSRodney W. Grimes case ENOBUFS: 1974df8bae1dSRodney W. Grimes type = ICMP_SOURCEQUENCH; 1975df8bae1dSRodney W. Grimes code = 0; 1976df8bae1dSRodney W. Grimes break; 19773a06e3e0SRuslan Ermilov 19783a06e3e0SRuslan Ermilov case EACCES: /* ipfw denied packet */ 19793a06e3e0SRuslan Ermilov m_freem(mcopy); 19803a06e3e0SRuslan Ermilov return; 1981df8bae1dSRodney W. Grimes } 1982df8bae1dSRodney W. Grimes icmp_error(mcopy, type, code, dest, destifp); 1983df8bae1dSRodney W. Grimes } 1984df8bae1dSRodney W. Grimes 198582c23ebaSBill Fenner void 198682c23ebaSBill Fenner ip_savecontrol(inp, mp, ip, m) 198782c23ebaSBill Fenner register struct inpcb *inp; 198882c23ebaSBill Fenner register struct mbuf **mp; 198982c23ebaSBill Fenner register struct ip *ip; 199082c23ebaSBill Fenner register struct mbuf *m; 199182c23ebaSBill Fenner { 199282c23ebaSBill Fenner if (inp->inp_socket->so_options & SO_TIMESTAMP) { 199382c23ebaSBill Fenner struct timeval tv; 199482c23ebaSBill Fenner 199582c23ebaSBill Fenner microtime(&tv); 199682c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv), 199782c23ebaSBill Fenner SCM_TIMESTAMP, SOL_SOCKET); 199882c23ebaSBill Fenner if (*mp) 199982c23ebaSBill Fenner mp = &(*mp)->m_next; 20004cc20ab1SSeigo Tanimura } 200182c23ebaSBill Fenner if (inp->inp_flags & INP_RECVDSTADDR) { 200282c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) &ip->ip_dst, 200382c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVDSTADDR, IPPROTO_IP); 200482c23ebaSBill Fenner if (*mp) 200582c23ebaSBill Fenner mp = &(*mp)->m_next; 200682c23ebaSBill Fenner } 200782c23ebaSBill Fenner #ifdef notyet 200882c23ebaSBill Fenner /* XXX 200982c23ebaSBill Fenner * Moving these out of udp_input() made them even more broken 201082c23ebaSBill Fenner * than they already were. 201182c23ebaSBill Fenner */ 201282c23ebaSBill Fenner /* options were tossed already */ 201382c23ebaSBill Fenner if (inp->inp_flags & INP_RECVOPTS) { 201482c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) opts_deleted_above, 201582c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVOPTS, IPPROTO_IP); 201682c23ebaSBill Fenner if (*mp) 201782c23ebaSBill Fenner mp = &(*mp)->m_next; 201882c23ebaSBill Fenner } 201982c23ebaSBill Fenner /* ip_srcroute doesn't do what we want here, need to fix */ 202082c23ebaSBill Fenner if (inp->inp_flags & INP_RECVRETOPTS) { 202182c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) ip_srcroute(), 202282c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVRETOPTS, IPPROTO_IP); 202382c23ebaSBill Fenner if (*mp) 202482c23ebaSBill Fenner mp = &(*mp)->m_next; 202582c23ebaSBill Fenner } 202682c23ebaSBill Fenner #endif 202782c23ebaSBill Fenner if (inp->inp_flags & INP_RECVIF) { 2028d314ad7bSJulian Elischer struct ifnet *ifp; 2029d314ad7bSJulian Elischer struct sdlbuf { 203082c23ebaSBill Fenner struct sockaddr_dl sdl; 2031d314ad7bSJulian Elischer u_char pad[32]; 2032d314ad7bSJulian Elischer } sdlbuf; 2033d314ad7bSJulian Elischer struct sockaddr_dl *sdp; 2034d314ad7bSJulian Elischer struct sockaddr_dl *sdl2 = &sdlbuf.sdl; 203582c23ebaSBill Fenner 2036d314ad7bSJulian Elischer if (((ifp = m->m_pkthdr.rcvif)) 2037d314ad7bSJulian Elischer && ( ifp->if_index && (ifp->if_index <= if_index))) { 2038f9132cebSJonathan Lemon sdp = (struct sockaddr_dl *) 2039f9132cebSJonathan Lemon (ifaddr_byindex(ifp->if_index)->ifa_addr); 2040d314ad7bSJulian Elischer /* 2041d314ad7bSJulian Elischer * Change our mind and don't try copy. 2042d314ad7bSJulian Elischer */ 2043d314ad7bSJulian Elischer if ((sdp->sdl_family != AF_LINK) 2044d314ad7bSJulian Elischer || (sdp->sdl_len > sizeof(sdlbuf))) { 2045d314ad7bSJulian Elischer goto makedummy; 2046d314ad7bSJulian Elischer } 2047d314ad7bSJulian Elischer bcopy(sdp, sdl2, sdp->sdl_len); 2048d314ad7bSJulian Elischer } else { 2049d314ad7bSJulian Elischer makedummy: 2050d314ad7bSJulian Elischer sdl2->sdl_len 2051d314ad7bSJulian Elischer = offsetof(struct sockaddr_dl, sdl_data[0]); 2052d314ad7bSJulian Elischer sdl2->sdl_family = AF_LINK; 2053d314ad7bSJulian Elischer sdl2->sdl_index = 0; 2054d314ad7bSJulian Elischer sdl2->sdl_nlen = sdl2->sdl_alen = sdl2->sdl_slen = 0; 2055d314ad7bSJulian Elischer } 2056d314ad7bSJulian Elischer *mp = sbcreatecontrol((caddr_t) sdl2, sdl2->sdl_len, 205782c23ebaSBill Fenner IP_RECVIF, IPPROTO_IP); 205882c23ebaSBill Fenner if (*mp) 205982c23ebaSBill Fenner mp = &(*mp)->m_next; 206082c23ebaSBill Fenner } 206182c23ebaSBill Fenner } 206282c23ebaSBill Fenner 20634d2e3692SLuigi Rizzo /* 20644d2e3692SLuigi Rizzo * XXX these routines are called from the upper part of the kernel. 20654d2e3692SLuigi Rizzo * They need to be locked when we remove Giant. 20664d2e3692SLuigi Rizzo * 20674d2e3692SLuigi Rizzo * They could also be moved to ip_mroute.c, since all the RSVP 20684d2e3692SLuigi Rizzo * handling is done there already. 20694d2e3692SLuigi Rizzo */ 20704d2e3692SLuigi Rizzo static int ip_rsvp_on; 20714d2e3692SLuigi Rizzo struct socket *ip_rsvpd; 2072df8bae1dSRodney W. Grimes int 2073f0068c4aSGarrett Wollman ip_rsvp_init(struct socket *so) 2074f0068c4aSGarrett Wollman { 2075f0068c4aSGarrett Wollman if (so->so_type != SOCK_RAW || 2076f0068c4aSGarrett Wollman so->so_proto->pr_protocol != IPPROTO_RSVP) 2077f0068c4aSGarrett Wollman return EOPNOTSUPP; 2078f0068c4aSGarrett Wollman 2079f0068c4aSGarrett Wollman if (ip_rsvpd != NULL) 2080f0068c4aSGarrett Wollman return EADDRINUSE; 2081f0068c4aSGarrett Wollman 2082f0068c4aSGarrett Wollman ip_rsvpd = so; 20831c5de19aSGarrett Wollman /* 20841c5de19aSGarrett Wollman * This may seem silly, but we need to be sure we don't over-increment 20851c5de19aSGarrett Wollman * the RSVP counter, in case something slips up. 20861c5de19aSGarrett Wollman */ 20871c5de19aSGarrett Wollman if (!ip_rsvp_on) { 20881c5de19aSGarrett Wollman ip_rsvp_on = 1; 20891c5de19aSGarrett Wollman rsvp_on++; 20901c5de19aSGarrett Wollman } 2091f0068c4aSGarrett Wollman 2092f0068c4aSGarrett Wollman return 0; 2093f0068c4aSGarrett Wollman } 2094f0068c4aSGarrett Wollman 2095f0068c4aSGarrett Wollman int 2096f0068c4aSGarrett Wollman ip_rsvp_done(void) 2097f0068c4aSGarrett Wollman { 2098f0068c4aSGarrett Wollman ip_rsvpd = NULL; 20991c5de19aSGarrett Wollman /* 21001c5de19aSGarrett Wollman * This may seem silly, but we need to be sure we don't over-decrement 21011c5de19aSGarrett Wollman * the RSVP counter, in case something slips up. 21021c5de19aSGarrett Wollman */ 21031c5de19aSGarrett Wollman if (ip_rsvp_on) { 21041c5de19aSGarrett Wollman ip_rsvp_on = 0; 21051c5de19aSGarrett Wollman rsvp_on--; 21061c5de19aSGarrett Wollman } 2107f0068c4aSGarrett Wollman return 0; 2108f0068c4aSGarrett Wollman } 2109bbb4330bSLuigi Rizzo 2110bbb4330bSLuigi Rizzo void 2111bbb4330bSLuigi Rizzo rsvp_input(struct mbuf *m, int off) /* XXX must fixup manually */ 2112bbb4330bSLuigi Rizzo { 2113bbb4330bSLuigi Rizzo if (rsvp_input_p) { /* call the real one if loaded */ 2114bbb4330bSLuigi Rizzo rsvp_input_p(m, off); 2115bbb4330bSLuigi Rizzo return; 2116bbb4330bSLuigi Rizzo } 2117bbb4330bSLuigi Rizzo 2118bbb4330bSLuigi Rizzo /* Can still get packets with rsvp_on = 0 if there is a local member 2119bbb4330bSLuigi Rizzo * of the group to which the RSVP packet is addressed. But in this 2120bbb4330bSLuigi Rizzo * case we want to throw the packet away. 2121bbb4330bSLuigi Rizzo */ 2122bbb4330bSLuigi Rizzo 2123bbb4330bSLuigi Rizzo if (!rsvp_on) { 2124bbb4330bSLuigi Rizzo m_freem(m); 2125bbb4330bSLuigi Rizzo return; 2126bbb4330bSLuigi Rizzo } 2127bbb4330bSLuigi Rizzo 2128bbb4330bSLuigi Rizzo if (ip_rsvpd != NULL) { 2129bbb4330bSLuigi Rizzo rip_input(m, off); 2130bbb4330bSLuigi Rizzo return; 2131bbb4330bSLuigi Rizzo } 2132bbb4330bSLuigi Rizzo /* Drop the packet */ 2133bbb4330bSLuigi Rizzo m_freem(m); 2134bbb4330bSLuigi Rizzo } 2135