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 3758938916SGarrett Wollman #define _IP_VHL 3858938916SGarrett Wollman 39e4f4247aSEivind Eklund #include "opt_bootp.h" 4074a9466cSGary Palmer #include "opt_ipfw.h" 41b715f178SLuigi Rizzo #include "opt_ipdn.h" 42fbd1372aSJoerg Wunsch #include "opt_ipdivert.h" 431ee25934SPeter Wemm #include "opt_ipfilter.h" 4427108a15SDag-Erling Smørgrav #include "opt_ipstealth.h" 456a800098SYoshinobu Inoue #include "opt_ipsec.h" 46c4ac87eaSDarren Reed #include "opt_pfil_hooks.h" 4774a9466cSGary Palmer 48df8bae1dSRodney W. Grimes #include <sys/param.h> 49df8bae1dSRodney W. Grimes #include <sys/systm.h> 50df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 51b715f178SLuigi Rizzo #include <sys/malloc.h> 52df8bae1dSRodney W. Grimes #include <sys/domain.h> 53df8bae1dSRodney W. Grimes #include <sys/protosw.h> 54df8bae1dSRodney W. Grimes #include <sys/socket.h> 55df8bae1dSRodney W. Grimes #include <sys/time.h> 56df8bae1dSRodney W. Grimes #include <sys/kernel.h> 571025071fSGarrett Wollman #include <sys/syslog.h> 58b5e8ce9fSBruce Evans #include <sys/sysctl.h> 59df8bae1dSRodney W. Grimes 60c85540ddSAndrey A. Chernov #include <net/pfil.h> 61df8bae1dSRodney W. Grimes #include <net/if.h> 62d314ad7bSJulian Elischer #include <net/if_var.h> 6382c23ebaSBill Fenner #include <net/if_dl.h> 64df8bae1dSRodney W. Grimes #include <net/route.h> 65748e0b0aSGarrett Wollman #include <net/netisr.h> 66367d34f8SBrian Somers #include <net/intrq.h> 67df8bae1dSRodney W. Grimes 68df8bae1dSRodney W. Grimes #include <netinet/in.h> 69df8bae1dSRodney W. Grimes #include <netinet/in_systm.h> 70b5e8ce9fSBruce Evans #include <netinet/in_var.h> 71df8bae1dSRodney W. Grimes #include <netinet/ip.h> 72df8bae1dSRodney W. Grimes #include <netinet/in_pcb.h> 73df8bae1dSRodney W. Grimes #include <netinet/ip_var.h> 74df8bae1dSRodney W. Grimes #include <netinet/ip_icmp.h> 7558938916SGarrett Wollman #include <machine/in_cksum.h> 76df8bae1dSRodney W. Grimes 776a800098SYoshinobu Inoue #include <netinet/ipprotosw.h> 786a800098SYoshinobu Inoue 79f0068c4aSGarrett Wollman #include <sys/socketvar.h> 806ddbf1e2SGary Palmer 816ddbf1e2SGary Palmer #include <netinet/ip_fw.h> 826ddbf1e2SGary Palmer 836a800098SYoshinobu Inoue #ifdef IPSEC 846a800098SYoshinobu Inoue #include <netinet6/ipsec.h> 856a800098SYoshinobu Inoue #include <netkey/key.h> 866a800098SYoshinobu Inoue #endif 876a800098SYoshinobu Inoue 886a800098SYoshinobu Inoue #include "faith.h" 896a800098SYoshinobu Inoue #if defined(NFAITH) && NFAITH > 0 906a800098SYoshinobu Inoue #include <net/if_types.h> 916a800098SYoshinobu Inoue #endif 926a800098SYoshinobu Inoue 93b715f178SLuigi Rizzo #ifdef DUMMYNET 94b715f178SLuigi Rizzo #include <netinet/ip_dummynet.h> 95b715f178SLuigi Rizzo #endif 96b715f178SLuigi Rizzo 971c5de19aSGarrett Wollman int rsvp_on = 0; 98f708ef1bSPoul-Henning Kamp static int ip_rsvp_on; 99f0068c4aSGarrett Wollman struct socket *ip_rsvpd; 100f0068c4aSGarrett Wollman 1011f91d8c5SDavid Greenman int ipforwarding = 0; 1020312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_FORWARDING, forwarding, CTLFLAG_RW, 1033d177f46SBill Fumerola &ipforwarding, 0, "Enable IP forwarding between interfaces"); 1040312fbe9SPoul-Henning Kamp 105d4fb926cSGarrett Wollman static int ipsendredirects = 1; /* XXX */ 1060312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_SENDREDIRECTS, redirect, CTLFLAG_RW, 1073d177f46SBill Fumerola &ipsendredirects, 0, "Enable sending IP redirects"); 1080312fbe9SPoul-Henning Kamp 109df8bae1dSRodney W. Grimes int ip_defttl = IPDEFTTL; 1100312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_DEFTTL, ttl, CTLFLAG_RW, 1113d177f46SBill Fumerola &ip_defttl, 0, "Maximum TTL on IP packets"); 1120312fbe9SPoul-Henning Kamp 1130312fbe9SPoul-Henning Kamp static int ip_dosourceroute = 0; 1140312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_SOURCEROUTE, sourceroute, CTLFLAG_RW, 1153d177f46SBill Fumerola &ip_dosourceroute, 0, "Enable forwarding source routed IP packets"); 1164fce5804SGuido van Rooij 1174fce5804SGuido van Rooij static int ip_acceptsourceroute = 0; 1184fce5804SGuido van Rooij SYSCTL_INT(_net_inet_ip, IPCTL_ACCEPTSOURCEROUTE, accept_sourceroute, 1193d177f46SBill Fumerola CTLFLAG_RW, &ip_acceptsourceroute, 0, 1203d177f46SBill Fumerola "Enable accepting source routed IP packets"); 1216a800098SYoshinobu Inoue 1226a800098SYoshinobu Inoue static int ip_keepfaith = 0; 1236a800098SYoshinobu Inoue SYSCTL_INT(_net_inet_ip, IPCTL_KEEPFAITH, keepfaith, CTLFLAG_RW, 1246a800098SYoshinobu Inoue &ip_keepfaith, 0, 1256a800098SYoshinobu Inoue "Enable packet capture for FAITH IPv4->IPv6 translater daemon"); 1266a800098SYoshinobu Inoue 127823db0e9SDon Lewis /* 128823db0e9SDon Lewis * XXX - Setting ip_checkinterface mostly implements the receive side of 129823db0e9SDon Lewis * the Strong ES model described in RFC 1122, but since the routing table 130a8f12100SDon Lewis * and transmit implementation do not implement the Strong ES model, 131823db0e9SDon Lewis * setting this to 1 results in an odd hybrid. 1323f67c834SDon Lewis * 133a8f12100SDon Lewis * XXX - ip_checkinterface currently must be disabled if you use ipnat 134a8f12100SDon Lewis * to translate the destination address to another local interface. 1353f67c834SDon Lewis * 1363f67c834SDon Lewis * XXX - ip_checkinterface must be disabled if you add IP aliases 1373f67c834SDon Lewis * to the loopback interface instead of the interface where the 1383f67c834SDon Lewis * packets for those addresses are received. 139823db0e9SDon Lewis */ 140b3e95d4eSJonathan Lemon static int ip_checkinterface = 1; 141b3e95d4eSJonathan Lemon SYSCTL_INT(_net_inet_ip, OID_AUTO, check_interface, CTLFLAG_RW, 142b3e95d4eSJonathan Lemon &ip_checkinterface, 0, "Verify packet arrives on correct interface"); 143b3e95d4eSJonathan Lemon 144df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1450312fbe9SPoul-Henning Kamp static int ipprintfs = 0; 146df8bae1dSRodney W. Grimes #endif 147df8bae1dSRodney W. Grimes 148df8bae1dSRodney W. Grimes extern struct domain inetdomain; 1496a800098SYoshinobu Inoue extern struct ipprotosw inetsw[]; 150df8bae1dSRodney W. Grimes u_char ip_protox[IPPROTO_MAX]; 1510312fbe9SPoul-Henning Kamp static int ipqmaxlen = IFQ_MAXLEN; 15259562606SGarrett Wollman struct in_ifaddrhead in_ifaddrhead; /* first inet address */ 153afed1375SDavid Greenman SYSCTL_INT(_net_inet_ip, IPCTL_INTRQMAXLEN, intr_queue_maxlen, CTLFLAG_RW, 1543d177f46SBill Fumerola &ipintrq.ifq_maxlen, 0, "Maximum size of the IP input queue"); 1550312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_INTRQDROPS, intr_queue_drops, CTLFLAG_RD, 1563d177f46SBill Fumerola &ipintrq.ifq_drops, 0, "Number of packets dropped from the IP input queue"); 157df8bae1dSRodney W. Grimes 158f23b4c91SGarrett Wollman struct ipstat ipstat; 1596fce01c9SGarrett Wollman SYSCTL_STRUCT(_net_inet_ip, IPCTL_STATS, stats, CTLFLAG_RD, 1603d177f46SBill Fumerola &ipstat, ipstat, "IP statistics (struct ipstat, netinet/ip_var.h)"); 161194a213eSAndrey A. Chernov 162194a213eSAndrey A. Chernov /* Packet reassembly stuff */ 163194a213eSAndrey A. Chernov #define IPREASS_NHASH_LOG2 6 164194a213eSAndrey A. Chernov #define IPREASS_NHASH (1 << IPREASS_NHASH_LOG2) 165194a213eSAndrey A. Chernov #define IPREASS_HMASK (IPREASS_NHASH - 1) 166194a213eSAndrey A. Chernov #define IPREASS_HASH(x,y) \ 167831a80b0SMatthew Dillon (((((x) & 0xF) | ((((x) >> 8) & 0xF) << 4)) ^ (y)) & IPREASS_HMASK) 168194a213eSAndrey A. Chernov 169194a213eSAndrey A. Chernov static struct ipq ipq[IPREASS_NHASH]; 170194a213eSAndrey A. Chernov static int nipq = 0; /* total # of reass queues */ 171194a213eSAndrey A. Chernov static int maxnipq; 172367d34f8SBrian Somers const int ipintrq_present = 1; 173f23b4c91SGarrett Wollman 1740312fbe9SPoul-Henning Kamp #ifdef IPCTL_DEFMTU 1750312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_DEFMTU, mtu, CTLFLAG_RW, 1763d177f46SBill Fumerola &ip_mtu, 0, "Default MTU"); 1770312fbe9SPoul-Henning Kamp #endif 1780312fbe9SPoul-Henning Kamp 1791b968362SDag-Erling Smørgrav #ifdef IPSTEALTH 1801b968362SDag-Erling Smørgrav static int ipstealth = 0; 1811b968362SDag-Erling Smørgrav SYSCTL_INT(_net_inet_ip, OID_AUTO, stealth, CTLFLAG_RW, 1821b968362SDag-Erling Smørgrav &ipstealth, 0, ""); 1831b968362SDag-Erling Smørgrav #endif 1841b968362SDag-Erling Smørgrav 185cfe8b629SGarrett Wollman 18623bf9953SPoul-Henning Kamp /* Firewall hooks */ 18723bf9953SPoul-Henning Kamp ip_fw_chk_t *ip_fw_chk_ptr; 18823bf9953SPoul-Henning Kamp ip_fw_ctl_t *ip_fw_ctl_ptr; 1899fcc0795SLuigi Rizzo int fw_enable = 1 ; 190e7319babSPoul-Henning Kamp 191b715f178SLuigi Rizzo #ifdef DUMMYNET 192b715f178SLuigi Rizzo ip_dn_ctl_t *ip_dn_ctl_ptr; 193b715f178SLuigi Rizzo #endif 194b715f178SLuigi Rizzo 195afed1b49SDarren Reed 196e7319babSPoul-Henning Kamp /* 197df8bae1dSRodney W. Grimes * We need to save the IP options in case a protocol wants to respond 198df8bae1dSRodney W. Grimes * to an incoming packet over the same route if the packet got here 199df8bae1dSRodney W. Grimes * using IP source routing. This allows connection establishment and 200df8bae1dSRodney W. Grimes * maintenance when the remote end is on a network that is not known 201df8bae1dSRodney W. Grimes * to us. 202df8bae1dSRodney W. Grimes */ 2030312fbe9SPoul-Henning Kamp static int ip_nhops = 0; 204df8bae1dSRodney W. Grimes static struct ip_srcrt { 205df8bae1dSRodney W. Grimes struct in_addr dst; /* final destination */ 206df8bae1dSRodney W. Grimes char nop; /* one NOP to align */ 207df8bae1dSRodney W. Grimes char srcopt[IPOPT_OFFSET + 1]; /* OPTVAL, OLEN and OFFSET */ 208df8bae1dSRodney W. Grimes struct in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)]; 209df8bae1dSRodney W. Grimes } ip_srcrt; 210df8bae1dSRodney W. Grimes 211f9e354dfSJulian Elischer struct sockaddr_in *ip_fw_fwd_addr; 212f9e354dfSJulian Elischer 213df8bae1dSRodney W. Grimes static void save_rte __P((u_char *, struct in_addr)); 2140312fbe9SPoul-Henning Kamp static int ip_dooptions __P((struct mbuf *)); 2150312fbe9SPoul-Henning Kamp static void ip_forward __P((struct mbuf *, int)); 2160312fbe9SPoul-Henning Kamp static void ip_freef __P((struct ipq *)); 2178948e4baSArchie Cobbs #ifdef IPDIVERT 2186a800098SYoshinobu Inoue static struct mbuf *ip_reass __P((struct mbuf *, 2198948e4baSArchie Cobbs struct ipq *, struct ipq *, u_int32_t *, u_int16_t *)); 2208948e4baSArchie Cobbs #else 2216a800098SYoshinobu Inoue static struct mbuf *ip_reass __P((struct mbuf *, struct ipq *, struct ipq *)); 2228948e4baSArchie Cobbs #endif 2238948e4baSArchie Cobbs static struct in_ifaddr *ip_rtaddr __P((struct in_addr)); 2240312fbe9SPoul-Henning Kamp static void ipintr __P((void)); 2258948e4baSArchie Cobbs 226df8bae1dSRodney W. Grimes /* 227df8bae1dSRodney W. Grimes * IP initialization: fill in IP protocol switch table. 228df8bae1dSRodney W. Grimes * All protocols not implemented in kernel go to raw IP protocol handler. 229df8bae1dSRodney W. Grimes */ 230df8bae1dSRodney W. Grimes void 231df8bae1dSRodney W. Grimes ip_init() 232df8bae1dSRodney W. Grimes { 2336a800098SYoshinobu Inoue register struct ipprotosw *pr; 234df8bae1dSRodney W. Grimes register int i; 235df8bae1dSRodney W. Grimes 23659562606SGarrett Wollman TAILQ_INIT(&in_ifaddrhead); 2376a800098SYoshinobu Inoue pr = (struct ipprotosw *)pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW); 238df8bae1dSRodney W. Grimes if (pr == 0) 239df8bae1dSRodney W. Grimes panic("ip_init"); 240df8bae1dSRodney W. Grimes for (i = 0; i < IPPROTO_MAX; i++) 241df8bae1dSRodney W. Grimes ip_protox[i] = pr - inetsw; 2426a800098SYoshinobu Inoue for (pr = (struct ipprotosw *)inetdomain.dom_protosw; 2436a800098SYoshinobu Inoue pr < (struct ipprotosw *)inetdomain.dom_protoswNPROTOSW; pr++) 244df8bae1dSRodney W. Grimes if (pr->pr_domain->dom_family == PF_INET && 245df8bae1dSRodney W. Grimes pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) 246df8bae1dSRodney W. Grimes ip_protox[pr->pr_protocol] = pr - inetsw; 247194a213eSAndrey A. Chernov 248194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) 249194a213eSAndrey A. Chernov ipq[i].next = ipq[i].prev = &ipq[i]; 250194a213eSAndrey A. Chernov 251194a213eSAndrey A. Chernov maxnipq = nmbclusters/4; 252194a213eSAndrey A. Chernov 253227ee8a1SPoul-Henning Kamp ip_id = time_second & 0xffff; 254df8bae1dSRodney W. Grimes ipintrq.ifq_maxlen = ipqmaxlen; 255df5e1987SJonathan Lemon mtx_init(&ipintrq.ifq_mtx, "ip_inq", MTX_DEF); 256242c5536SPeter Wemm 257242c5536SPeter Wemm register_netisr(NETISR_IP, ipintr); 258df8bae1dSRodney W. Grimes } 259df8bae1dSRodney W. Grimes 2600312fbe9SPoul-Henning Kamp static struct sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET }; 261f708ef1bSPoul-Henning Kamp static struct route ipforward_rt; 262df8bae1dSRodney W. Grimes 263df8bae1dSRodney W. Grimes /* 264df8bae1dSRodney W. Grimes * Ip input routine. Checksum and byte swap header. If fragmented 265df8bae1dSRodney W. Grimes * try to reassemble. Process options. Pass to next level. 266df8bae1dSRodney W. Grimes */ 267c67b1d17SGarrett Wollman void 268c67b1d17SGarrett Wollman ip_input(struct mbuf *m) 269df8bae1dSRodney W. Grimes { 27023bf9953SPoul-Henning Kamp struct ip *ip; 27123bf9953SPoul-Henning Kamp struct ipq *fp; 2725da9f8faSJosef Karthauser struct in_ifaddr *ia = NULL; 273823db0e9SDon Lewis int i, hlen, checkif; 27447c861ecSBrian Somers u_short sum; 2758948e4baSArchie Cobbs u_int16_t divert_cookie; /* firewall cookie */ 2767538a9a0SJonathan Lemon struct in_addr pkt_dst; 2778948e4baSArchie Cobbs #ifdef IPDIVERT 2788948e4baSArchie Cobbs u_int32_t divert_info = 0; /* packet divert/tee info */ 279b715f178SLuigi Rizzo #endif 280b715f178SLuigi Rizzo struct ip_fw_chain *rule = NULL; 281c4ac87eaSDarren Reed #ifdef PFIL_HOOKS 282c4ac87eaSDarren Reed struct packet_filter_hook *pfh; 283c4ac87eaSDarren Reed struct mbuf *m0; 284c4ac87eaSDarren Reed int rv; 285c4ac87eaSDarren Reed #endif /* PFIL_HOOKS */ 286b715f178SLuigi Rizzo 2878948e4baSArchie Cobbs #ifdef IPDIVERT 2888948e4baSArchie Cobbs /* Get and reset firewall cookie */ 2898948e4baSArchie Cobbs divert_cookie = ip_divert_cookie; 2908948e4baSArchie Cobbs ip_divert_cookie = 0; 2918948e4baSArchie Cobbs #else 2928948e4baSArchie Cobbs divert_cookie = 0; 2938948e4baSArchie Cobbs #endif 2948948e4baSArchie Cobbs 295b715f178SLuigi Rizzo #if defined(IPFIREWALL) && defined(DUMMYNET) 296b715f178SLuigi Rizzo /* 297b715f178SLuigi Rizzo * dummynet packet are prepended a vestigial mbuf with 298b715f178SLuigi Rizzo * m_type = MT_DUMMYNET and m_data pointing to the matching 299b715f178SLuigi Rizzo * rule. 300b715f178SLuigi Rizzo */ 301b715f178SLuigi Rizzo if (m->m_type == MT_DUMMYNET) { 302b715f178SLuigi Rizzo rule = (struct ip_fw_chain *)(m->m_data) ; 303b715f178SLuigi Rizzo m = m->m_next ; 304b715f178SLuigi Rizzo ip = mtod(m, struct ip *); 305b715f178SLuigi Rizzo hlen = IP_VHL_HL(ip->ip_vhl) << 2; 306b715f178SLuigi Rizzo goto iphack ; 307b715f178SLuigi Rizzo } else 308b715f178SLuigi Rizzo rule = NULL ; 309b715f178SLuigi Rizzo #endif 310df8bae1dSRodney W. Grimes 311df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 312ed7509acSJulian Elischer if (m == NULL || (m->m_flags & M_PKTHDR) == 0) 31358938916SGarrett Wollman panic("ip_input no HDR"); 314df8bae1dSRodney W. Grimes #endif 315df8bae1dSRodney W. Grimes ipstat.ips_total++; 31658938916SGarrett Wollman 31758938916SGarrett Wollman if (m->m_pkthdr.len < sizeof(struct ip)) 31858938916SGarrett Wollman goto tooshort; 31958938916SGarrett Wollman 320df8bae1dSRodney W. Grimes if (m->m_len < sizeof (struct ip) && 321df8bae1dSRodney W. Grimes (m = m_pullup(m, sizeof (struct ip))) == 0) { 322df8bae1dSRodney W. Grimes ipstat.ips_toosmall++; 323c67b1d17SGarrett Wollman return; 324df8bae1dSRodney W. Grimes } 325df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 32658938916SGarrett Wollman 32758938916SGarrett Wollman if (IP_VHL_V(ip->ip_vhl) != IPVERSION) { 328df8bae1dSRodney W. Grimes ipstat.ips_badvers++; 329df8bae1dSRodney W. Grimes goto bad; 330df8bae1dSRodney W. Grimes } 33158938916SGarrett Wollman 33258938916SGarrett Wollman hlen = IP_VHL_HL(ip->ip_vhl) << 2; 333df8bae1dSRodney W. Grimes if (hlen < sizeof(struct ip)) { /* minimum header length */ 334df8bae1dSRodney W. Grimes ipstat.ips_badhlen++; 335df8bae1dSRodney W. Grimes goto bad; 336df8bae1dSRodney W. Grimes } 337df8bae1dSRodney W. Grimes if (hlen > m->m_len) { 338df8bae1dSRodney W. Grimes if ((m = m_pullup(m, hlen)) == 0) { 339df8bae1dSRodney W. Grimes ipstat.ips_badhlen++; 340c67b1d17SGarrett Wollman return; 341df8bae1dSRodney W. Grimes } 342df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 343df8bae1dSRodney W. Grimes } 344db4f9cc7SJonathan Lemon if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) { 345db4f9cc7SJonathan Lemon sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID); 346db4f9cc7SJonathan Lemon } else { 34758938916SGarrett Wollman if (hlen == sizeof(struct ip)) { 34847c861ecSBrian Somers sum = in_cksum_hdr(ip); 34958938916SGarrett Wollman } else { 35047c861ecSBrian Somers sum = in_cksum(m, hlen); 35158938916SGarrett Wollman } 352db4f9cc7SJonathan Lemon } 35347c861ecSBrian Somers if (sum) { 354df8bae1dSRodney W. Grimes ipstat.ips_badsum++; 355df8bae1dSRodney W. Grimes goto bad; 356df8bae1dSRodney W. Grimes } 357df8bae1dSRodney W. Grimes 358df8bae1dSRodney W. Grimes /* 359df8bae1dSRodney W. Grimes * Convert fields to host representation. 360df8bae1dSRodney W. Grimes */ 361df8bae1dSRodney W. Grimes NTOHS(ip->ip_len); 362df8bae1dSRodney W. Grimes if (ip->ip_len < hlen) { 363df8bae1dSRodney W. Grimes ipstat.ips_badlen++; 364df8bae1dSRodney W. Grimes goto bad; 365df8bae1dSRodney W. Grimes } 366df8bae1dSRodney W. Grimes NTOHS(ip->ip_off); 367df8bae1dSRodney W. Grimes 368df8bae1dSRodney W. Grimes /* 369df8bae1dSRodney W. Grimes * Check that the amount of data in the buffers 370df8bae1dSRodney W. Grimes * is as at least much as the IP header would have us expect. 371df8bae1dSRodney W. Grimes * Trim mbufs if longer than we expect. 372df8bae1dSRodney W. Grimes * Drop packet if shorter than we expect. 373df8bae1dSRodney W. Grimes */ 374df8bae1dSRodney W. Grimes if (m->m_pkthdr.len < ip->ip_len) { 37558938916SGarrett Wollman tooshort: 376df8bae1dSRodney W. Grimes ipstat.ips_tooshort++; 377df8bae1dSRodney W. Grimes goto bad; 378df8bae1dSRodney W. Grimes } 379df8bae1dSRodney W. Grimes if (m->m_pkthdr.len > ip->ip_len) { 380df8bae1dSRodney W. Grimes if (m->m_len == m->m_pkthdr.len) { 381df8bae1dSRodney W. Grimes m->m_len = ip->ip_len; 382df8bae1dSRodney W. Grimes m->m_pkthdr.len = ip->ip_len; 383df8bae1dSRodney W. Grimes } else 384df8bae1dSRodney W. Grimes m_adj(m, ip->ip_len - m->m_pkthdr.len); 385df8bae1dSRodney W. Grimes } 3863f67c834SDon Lewis 3873f67c834SDon Lewis /* 3883f67c834SDon Lewis * Don't accept packets with a loopback destination address 3893f67c834SDon Lewis * unless they arrived via the loopback interface. 3903f67c834SDon Lewis */ 3913f67c834SDon Lewis if ((ntohl(ip->ip_dst.s_addr) & IN_CLASSA_NET) == 3923f67c834SDon Lewis (IN_LOOPBACKNET << IN_CLASSA_NSHIFT) && 3933f67c834SDon Lewis (m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) { 3943f67c834SDon Lewis goto bad; 3953f67c834SDon Lewis } 3963f67c834SDon Lewis 3974dd1662bSUgen J.S. Antsilevich /* 3984dd1662bSUgen J.S. Antsilevich * IpHack's section. 3994dd1662bSUgen J.S. Antsilevich * Right now when no processing on packet has done 4004dd1662bSUgen J.S. Antsilevich * and it is still fresh out of network we do our black 4014dd1662bSUgen J.S. Antsilevich * deals with it. 40293e0e116SJulian Elischer * - Firewall: deny/allow/divert 403fed1c7e9SSøren Schmidt * - Xlate: translate packet's addr/port (NAT). 404b715f178SLuigi Rizzo * - Pipe: pass pkt through dummynet. 4054dd1662bSUgen J.S. Antsilevich * - Wrap: fake packet's addr/port <unimpl.> 4064dd1662bSUgen J.S. Antsilevich * - Encapsulate: put it in another IP and send out. <unimp.> 4074dd1662bSUgen J.S. Antsilevich */ 408b715f178SLuigi Rizzo 409dee383e0SEivind Eklund #if defined(IPFIREWALL) && defined(DUMMYNET) 410b715f178SLuigi Rizzo iphack: 411dee383e0SEivind Eklund #endif 412df8bae1dSRodney W. Grimes 413c4ac87eaSDarren Reed #ifdef PFIL_HOOKS 414c4ac87eaSDarren Reed /* 415c4ac87eaSDarren Reed * Run through list of hooks for input packets. If there are any 416c4ac87eaSDarren Reed * filters which require that additional packets in the flow are 417c4ac87eaSDarren Reed * not fast-forwarded, they must clear the M_CANFASTFWD flag. 418c4ac87eaSDarren Reed * Note that filters must _never_ set this flag, as another filter 419c4ac87eaSDarren Reed * in the list may have previously cleared it. 420c4ac87eaSDarren Reed */ 421c4ac87eaSDarren Reed m0 = m; 422c4ac87eaSDarren Reed pfh = pfil_hook_get(PFIL_IN, &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); 423fc2ffbe6SPoul-Henning Kamp for (; pfh; pfh = TAILQ_NEXT(pfh, pfil_link)) 424c4ac87eaSDarren Reed if (pfh->pfil_func) { 425c4ac87eaSDarren Reed rv = pfh->pfil_func(ip, hlen, 426c4ac87eaSDarren Reed m->m_pkthdr.rcvif, 0, &m0); 427c4ac87eaSDarren Reed if (rv) 428beec8214SDarren Reed return; 429c4ac87eaSDarren Reed m = m0; 430c4ac87eaSDarren Reed if (m == NULL) 431c4ac87eaSDarren Reed return; 432c4ac87eaSDarren Reed ip = mtod(m, struct ip *); 433beec8214SDarren Reed } 434c4ac87eaSDarren Reed #endif /* PFIL_HOOKS */ 435c4ac87eaSDarren Reed 4366bc748b0SLuigi Rizzo if (fw_enable && ip_fw_chk_ptr) { 437f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 438f9e354dfSJulian Elischer /* 439f9e354dfSJulian Elischer * If we've been forwarded from the output side, then 440f9e354dfSJulian Elischer * skip the firewall a second time 441f9e354dfSJulian Elischer */ 442f9e354dfSJulian Elischer if (ip_fw_fwd_addr) 443f9e354dfSJulian Elischer goto ours; 444f9e354dfSJulian Elischer #endif /* IPFIREWALL_FORWARD */ 445f9e354dfSJulian Elischer /* 4468948e4baSArchie Cobbs * See the comment in ip_output for the return values 447b715f178SLuigi Rizzo * produced by the firewall. 448f9e354dfSJulian Elischer */ 4498948e4baSArchie Cobbs i = (*ip_fw_chk_ptr)(&ip, 4508948e4baSArchie Cobbs hlen, NULL, &divert_cookie, &m, &rule, &ip_fw_fwd_addr); 451507b4b54SLuigi Rizzo if (i & IP_FW_PORT_DENY_FLAG) { /* XXX new interface-denied */ 452507b4b54SLuigi Rizzo if (m) 453507b4b54SLuigi Rizzo m_freem(m); 454b715f178SLuigi Rizzo return ; 455507b4b54SLuigi Rizzo } 456507b4b54SLuigi Rizzo if (m == NULL) { /* Packet discarded by firewall */ 457507b4b54SLuigi Rizzo static int __debug=10; 458507b4b54SLuigi Rizzo if (__debug >0) { 459507b4b54SLuigi Rizzo printf("firewall returns NULL, please update!\n"); 460507b4b54SLuigi Rizzo __debug-- ; 461507b4b54SLuigi Rizzo } 462507b4b54SLuigi Rizzo return; 463507b4b54SLuigi Rizzo } 464b715f178SLuigi Rizzo if (i == 0 && ip_fw_fwd_addr == NULL) /* common case */ 465b715f178SLuigi Rizzo goto pass; 466b715f178SLuigi Rizzo #ifdef DUMMYNET 4678948e4baSArchie Cobbs if ((i & IP_FW_PORT_DYNT_FLAG) != 0) { 4688948e4baSArchie Cobbs /* Send packet to the appropriate pipe */ 4696a800098SYoshinobu Inoue dummynet_io(i&0xffff,DN_TO_IP_IN,m,NULL,NULL,0, rule, 4706a800098SYoshinobu Inoue 0); 471e4676ba6SJulian Elischer return; 47293e0e116SJulian Elischer } 473b715f178SLuigi Rizzo #endif 474b715f178SLuigi Rizzo #ifdef IPDIVERT 4758948e4baSArchie Cobbs if (i != 0 && (i & IP_FW_PORT_DYNT_FLAG) == 0) { 4768948e4baSArchie Cobbs /* Divert or tee packet */ 4778948e4baSArchie Cobbs divert_info = i; 478b715f178SLuigi Rizzo goto ours; 479b715f178SLuigi Rizzo } 480b715f178SLuigi Rizzo #endif 481b715f178SLuigi Rizzo #ifdef IPFIREWALL_FORWARD 482b715f178SLuigi Rizzo if (i == 0 && ip_fw_fwd_addr != NULL) 483b715f178SLuigi Rizzo goto pass; 484b715f178SLuigi Rizzo #endif 485b715f178SLuigi Rizzo /* 486b715f178SLuigi Rizzo * if we get here, the packet must be dropped 487b715f178SLuigi Rizzo */ 488b715f178SLuigi Rizzo m_freem(m); 489b715f178SLuigi Rizzo return; 490b715f178SLuigi Rizzo } 491b715f178SLuigi Rizzo pass: 492100ba1a6SJordan K. Hubbard 493df8bae1dSRodney W. Grimes /* 494df8bae1dSRodney W. Grimes * Process options and, if not destined for us, 495df8bae1dSRodney W. Grimes * ship it on. ip_dooptions returns 1 when an 496df8bae1dSRodney W. Grimes * error was detected (causing an icmp message 497df8bae1dSRodney W. Grimes * to be sent and the original packet to be freed). 498df8bae1dSRodney W. Grimes */ 499df8bae1dSRodney W. Grimes ip_nhops = 0; /* for source routed packets */ 500ed1ff184SJulian Elischer if (hlen > sizeof (struct ip) && ip_dooptions(m)) { 501ed1ff184SJulian Elischer #ifdef IPFIREWALL_FORWARD 502ed1ff184SJulian Elischer ip_fw_fwd_addr = NULL; 503ed1ff184SJulian Elischer #endif 504c67b1d17SGarrett Wollman return; 505ed1ff184SJulian Elischer } 506df8bae1dSRodney W. Grimes 507f0068c4aSGarrett Wollman /* greedy RSVP, snatches any PATH packet of the RSVP protocol and no 508f0068c4aSGarrett Wollman * matter if it is destined to another node, or whether it is 509f0068c4aSGarrett Wollman * a multicast one, RSVP wants it! and prevents it from being forwarded 510f0068c4aSGarrett Wollman * anywhere else. Also checks if the rsvp daemon is running before 511f0068c4aSGarrett Wollman * grabbing the packet. 512f0068c4aSGarrett Wollman */ 5131c5de19aSGarrett Wollman if (rsvp_on && ip->ip_p==IPPROTO_RSVP) 514f0068c4aSGarrett Wollman goto ours; 515f0068c4aSGarrett Wollman 516df8bae1dSRodney W. Grimes /* 517df8bae1dSRodney W. Grimes * Check our list of addresses, to see if the packet is for us. 518cc766e04SGarrett Wollman * If we don't have any addresses, assume any unicast packet 519cc766e04SGarrett Wollman * we receive might be for us (and let the upper layers deal 520cc766e04SGarrett Wollman * with it). 521df8bae1dSRodney W. Grimes */ 522cc766e04SGarrett Wollman if (TAILQ_EMPTY(&in_ifaddrhead) && 523cc766e04SGarrett Wollman (m->m_flags & (M_MCAST|M_BCAST)) == 0) 524cc766e04SGarrett Wollman goto ours; 525cc766e04SGarrett Wollman 5267538a9a0SJonathan Lemon /* 5277538a9a0SJonathan Lemon * Cache the destination address of the packet; this may be 5287538a9a0SJonathan Lemon * changed by use of 'ipfw fwd'. 5297538a9a0SJonathan Lemon */ 5307538a9a0SJonathan Lemon pkt_dst = ip_fw_fwd_addr == NULL ? 5317538a9a0SJonathan Lemon ip->ip_dst : ip_fw_fwd_addr->sin_addr; 5327538a9a0SJonathan Lemon 533823db0e9SDon Lewis /* 534823db0e9SDon Lewis * Enable a consistency check between the destination address 535823db0e9SDon Lewis * and the arrival interface for a unicast packet (the RFC 1122 536823db0e9SDon Lewis * strong ES model) if IP forwarding is disabled and the packet 537e15ae1b2SDon Lewis * is not locally generated and the packet is not subject to 538e15ae1b2SDon Lewis * 'ipfw fwd'. 5393f67c834SDon Lewis * 5403f67c834SDon Lewis * XXX - Checking also should be disabled if the destination 5413f67c834SDon Lewis * address is ipnat'ed to a different interface. 5423f67c834SDon Lewis * 543a8f12100SDon Lewis * XXX - Checking is incompatible with IP aliases added 5443f67c834SDon Lewis * to the loopback interface instead of the interface where 5453f67c834SDon Lewis * the packets are received. 546823db0e9SDon Lewis */ 547823db0e9SDon Lewis checkif = ip_checkinterface && (ipforwarding == 0) && 548e15ae1b2SDon Lewis ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) && 549e15ae1b2SDon Lewis (ip_fw_fwd_addr == NULL); 550823db0e9SDon Lewis 55137d40066SPoul-Henning Kamp TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) { 552df8bae1dSRodney W. Grimes #define satosin(sa) ((struct sockaddr_in *)(sa)) 553df8bae1dSRodney W. Grimes 554432aad0eSTor Egge #ifdef BOOTP_COMPAT 555432aad0eSTor Egge if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY) 556432aad0eSTor Egge goto ours; 557432aad0eSTor Egge #endif 558f9e354dfSJulian Elischer /* 559823db0e9SDon Lewis * If the address matches, verify that the packet 560823db0e9SDon Lewis * arrived via the correct interface if checking is 561823db0e9SDon Lewis * enabled. 562f9e354dfSJulian Elischer */ 563823db0e9SDon Lewis if (IA_SIN(ia)->sin_addr.s_addr == pkt_dst.s_addr && 564823db0e9SDon Lewis (!checkif || ia->ia_ifp == m->m_pkthdr.rcvif)) 565ed1ff184SJulian Elischer goto ours; 566823db0e9SDon Lewis /* 567823db0e9SDon Lewis * Only accept broadcast packets that arrive via the 568823db0e9SDon Lewis * matching interface. Reception of forwarded directed 569823db0e9SDon Lewis * broadcasts would be handled via ip_forward() and 570823db0e9SDon Lewis * ether_output() with the loopback into the stack for 571823db0e9SDon Lewis * SIMPLEX interfaces handled by ether_output(). 572823db0e9SDon Lewis */ 573823db0e9SDon Lewis if (ia->ia_ifp == m->m_pkthdr.rcvif && 574823db0e9SDon Lewis ia->ia_ifp && ia->ia_ifp->if_flags & IFF_BROADCAST) { 575df8bae1dSRodney W. Grimes if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == 5767538a9a0SJonathan Lemon pkt_dst.s_addr) 577df8bae1dSRodney W. Grimes goto ours; 5787538a9a0SJonathan Lemon if (ia->ia_netbroadcast.s_addr == pkt_dst.s_addr) 579df8bae1dSRodney W. Grimes goto ours; 580df8bae1dSRodney W. Grimes } 581df8bae1dSRodney W. Grimes } 582df8bae1dSRodney W. Grimes if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { 583df8bae1dSRodney W. Grimes struct in_multi *inm; 584df8bae1dSRodney W. Grimes if (ip_mrouter) { 585df8bae1dSRodney W. Grimes /* 586df8bae1dSRodney W. Grimes * If we are acting as a multicast router, all 587df8bae1dSRodney W. Grimes * incoming multicast packets are passed to the 588df8bae1dSRodney W. Grimes * kernel-level multicast forwarding function. 589df8bae1dSRodney W. Grimes * The packet is returned (relatively) intact; if 590df8bae1dSRodney W. Grimes * ip_mforward() returns a non-zero value, the packet 591df8bae1dSRodney W. Grimes * must be discarded, else it may be accepted below. 592df8bae1dSRodney W. Grimes */ 593f0068c4aSGarrett Wollman if (ip_mforward(ip, m->m_pkthdr.rcvif, m, 0) != 0) { 594df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 595df8bae1dSRodney W. Grimes m_freem(m); 596c67b1d17SGarrett Wollman return; 597df8bae1dSRodney W. Grimes } 598df8bae1dSRodney W. Grimes 599df8bae1dSRodney W. Grimes /* 600df8bae1dSRodney W. Grimes * The process-level routing demon needs to receive 601df8bae1dSRodney W. Grimes * all multicast IGMP packets, whether or not this 602df8bae1dSRodney W. Grimes * host belongs to their destination groups. 603df8bae1dSRodney W. Grimes */ 604df8bae1dSRodney W. Grimes if (ip->ip_p == IPPROTO_IGMP) 605df8bae1dSRodney W. Grimes goto ours; 606df8bae1dSRodney W. Grimes ipstat.ips_forward++; 607df8bae1dSRodney W. Grimes } 608df8bae1dSRodney W. Grimes /* 609df8bae1dSRodney W. Grimes * See if we belong to the destination multicast group on the 610df8bae1dSRodney W. Grimes * arrival interface. 611df8bae1dSRodney W. Grimes */ 612df8bae1dSRodney W. Grimes IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm); 613df8bae1dSRodney W. Grimes if (inm == NULL) { 61482c39223SGarrett Wollman ipstat.ips_notmember++; 615df8bae1dSRodney W. Grimes m_freem(m); 616c67b1d17SGarrett Wollman return; 617df8bae1dSRodney W. Grimes } 618df8bae1dSRodney W. Grimes goto ours; 619df8bae1dSRodney W. Grimes } 620df8bae1dSRodney W. Grimes if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST) 621df8bae1dSRodney W. Grimes goto ours; 622df8bae1dSRodney W. Grimes if (ip->ip_dst.s_addr == INADDR_ANY) 623df8bae1dSRodney W. Grimes goto ours; 624df8bae1dSRodney W. Grimes 6256a800098SYoshinobu Inoue #if defined(NFAITH) && 0 < NFAITH 6266a800098SYoshinobu Inoue /* 6276a800098SYoshinobu Inoue * FAITH(Firewall Aided Internet Translator) 6286a800098SYoshinobu Inoue */ 6296a800098SYoshinobu Inoue if (m->m_pkthdr.rcvif && m->m_pkthdr.rcvif->if_type == IFT_FAITH) { 6306a800098SYoshinobu Inoue if (ip_keepfaith) { 6316a800098SYoshinobu Inoue if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_ICMP) 6326a800098SYoshinobu Inoue goto ours; 6336a800098SYoshinobu Inoue } 6346a800098SYoshinobu Inoue m_freem(m); 6356a800098SYoshinobu Inoue return; 6366a800098SYoshinobu Inoue } 6376a800098SYoshinobu Inoue #endif 638df8bae1dSRodney W. Grimes /* 639df8bae1dSRodney W. Grimes * Not for us; forward if possible and desirable. 640df8bae1dSRodney W. Grimes */ 641df8bae1dSRodney W. Grimes if (ipforwarding == 0) { 642df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 643df8bae1dSRodney W. Grimes m_freem(m); 644df8bae1dSRodney W. Grimes } else 645df8bae1dSRodney W. Grimes ip_forward(m, 0); 646ed1ff184SJulian Elischer #ifdef IPFIREWALL_FORWARD 647ed1ff184SJulian Elischer ip_fw_fwd_addr = NULL; 648ed1ff184SJulian Elischer #endif 649c67b1d17SGarrett Wollman return; 650df8bae1dSRodney W. Grimes 651df8bae1dSRodney W. Grimes ours: 6525da9f8faSJosef Karthauser /* Count the packet in the ip address stats */ 6535da9f8faSJosef Karthauser if (ia != NULL) { 6545da9f8faSJosef Karthauser ia->ia_ifa.if_ipackets++; 6555da9f8faSJosef Karthauser ia->ia_ifa.if_ibytes += m->m_pkthdr.len; 6565da9f8faSJosef Karthauser } 657100ba1a6SJordan K. Hubbard 65863f8d699SJordan K. Hubbard /* 659df8bae1dSRodney W. Grimes * If offset or IP_MF are set, must reassemble. 660df8bae1dSRodney W. Grimes * Otherwise, nothing need be done. 661df8bae1dSRodney W. Grimes * (We could look in the reassembly queue to see 662df8bae1dSRodney W. Grimes * if the packet was previously fragmented, 663df8bae1dSRodney W. Grimes * but it's not worth the time; just let them time out.) 664df8bae1dSRodney W. Grimes */ 665b6ea1aa5SRuslan Ermilov if (ip->ip_off & (IP_MF | IP_OFFMASK)) { 6666a800098SYoshinobu Inoue 667194a213eSAndrey A. Chernov sum = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id); 668df8bae1dSRodney W. Grimes /* 669df8bae1dSRodney W. Grimes * Look for queue of fragments 670df8bae1dSRodney W. Grimes * of this datagram. 671df8bae1dSRodney W. Grimes */ 672194a213eSAndrey A. Chernov for (fp = ipq[sum].next; fp != &ipq[sum]; fp = fp->next) 673df8bae1dSRodney W. Grimes if (ip->ip_id == fp->ipq_id && 674df8bae1dSRodney W. Grimes ip->ip_src.s_addr == fp->ipq_src.s_addr && 675df8bae1dSRodney W. Grimes ip->ip_dst.s_addr == fp->ipq_dst.s_addr && 676df8bae1dSRodney W. Grimes ip->ip_p == fp->ipq_p) 677df8bae1dSRodney W. Grimes goto found; 678df8bae1dSRodney W. Grimes 679194a213eSAndrey A. Chernov fp = 0; 680194a213eSAndrey A. Chernov 681194a213eSAndrey A. Chernov /* check if there's a place for the new queue */ 682194a213eSAndrey A. Chernov if (nipq > maxnipq) { 683194a213eSAndrey A. Chernov /* 684194a213eSAndrey A. Chernov * drop something from the tail of the current queue 685194a213eSAndrey A. Chernov * before proceeding further 686194a213eSAndrey A. Chernov */ 687194a213eSAndrey A. Chernov if (ipq[sum].prev == &ipq[sum]) { /* gak */ 688194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 689194a213eSAndrey A. Chernov if (ipq[i].prev != &ipq[i]) { 690194a213eSAndrey A. Chernov ip_freef(ipq[i].prev); 691194a213eSAndrey A. Chernov break; 692194a213eSAndrey A. Chernov } 693194a213eSAndrey A. Chernov } 694194a213eSAndrey A. Chernov } else 695194a213eSAndrey A. Chernov ip_freef(ipq[sum].prev); 696194a213eSAndrey A. Chernov } 697194a213eSAndrey A. Chernov found: 698df8bae1dSRodney W. Grimes /* 699df8bae1dSRodney W. Grimes * Adjust ip_len to not reflect header, 700df8bae1dSRodney W. Grimes * convert offset of this to bytes. 701df8bae1dSRodney W. Grimes */ 702df8bae1dSRodney W. Grimes ip->ip_len -= hlen; 703b6ea1aa5SRuslan Ermilov if (ip->ip_off & IP_MF) { 7046effc713SDoug Rabson /* 7056effc713SDoug Rabson * Make sure that fragments have a data length 7066effc713SDoug Rabson * that's a non-zero multiple of 8 bytes. 7076effc713SDoug Rabson */ 7086effc713SDoug Rabson if (ip->ip_len == 0 || (ip->ip_len & 0x7) != 0) { 7096effc713SDoug Rabson ipstat.ips_toosmall++; /* XXX */ 7106effc713SDoug Rabson goto bad; 7116effc713SDoug Rabson } 7126effc713SDoug Rabson m->m_flags |= M_FRAG; 7136effc713SDoug Rabson } 714df8bae1dSRodney W. Grimes ip->ip_off <<= 3; 715df8bae1dSRodney W. Grimes 716df8bae1dSRodney W. Grimes /* 717b6ea1aa5SRuslan Ermilov * Attempt reassembly; if it succeeds, proceed. 718df8bae1dSRodney W. Grimes */ 719df8bae1dSRodney W. Grimes ipstat.ips_fragments++; 720487bdb38SRuslan Ermilov m->m_pkthdr.header = ip; 7218948e4baSArchie Cobbs #ifdef IPDIVERT 7226a800098SYoshinobu Inoue m = ip_reass(m, 7238948e4baSArchie Cobbs fp, &ipq[sum], &divert_info, &divert_cookie); 7248948e4baSArchie Cobbs #else 7256a800098SYoshinobu Inoue m = ip_reass(m, fp, &ipq[sum]); 7268948e4baSArchie Cobbs #endif 7276a800098SYoshinobu Inoue if (m == 0) { 728f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 729f9e354dfSJulian Elischer ip_fw_fwd_addr = NULL; 730f9e354dfSJulian Elischer #endif 731c67b1d17SGarrett Wollman return; 732f9e354dfSJulian Elischer } 733df8bae1dSRodney W. Grimes ipstat.ips_reassembled++; 7346a800098SYoshinobu Inoue ip = mtod(m, struct ip *); 7357e2df452SRuslan Ermilov /* Get the header length of the reassembled packet */ 7367e2df452SRuslan Ermilov hlen = IP_VHL_HL(ip->ip_vhl) << 2; 737af782f1cSBrian Somers #ifdef IPDIVERT 7388948e4baSArchie Cobbs /* Restore original checksum before diverting packet */ 7398948e4baSArchie Cobbs if (divert_info != 0) { 740af782f1cSBrian Somers ip->ip_len += hlen; 741af782f1cSBrian Somers HTONS(ip->ip_len); 742af782f1cSBrian Somers HTONS(ip->ip_off); 743af782f1cSBrian Somers ip->ip_sum = 0; 74460123168SRuslan Ermilov if (hlen == sizeof(struct ip)) 745af782f1cSBrian Somers ip->ip_sum = in_cksum_hdr(ip); 74660123168SRuslan Ermilov else 74760123168SRuslan Ermilov ip->ip_sum = in_cksum(m, hlen); 748af782f1cSBrian Somers NTOHS(ip->ip_off); 749af782f1cSBrian Somers NTOHS(ip->ip_len); 750af782f1cSBrian Somers ip->ip_len -= hlen; 751af782f1cSBrian Somers } 752af782f1cSBrian Somers #endif 753df8bae1dSRodney W. Grimes } else 754df8bae1dSRodney W. Grimes ip->ip_len -= hlen; 755df8bae1dSRodney W. Grimes 75693e0e116SJulian Elischer #ifdef IPDIVERT 75793e0e116SJulian Elischer /* 7588948e4baSArchie Cobbs * Divert or tee packet to the divert protocol if required. 7598948e4baSArchie Cobbs * 7608948e4baSArchie Cobbs * If divert_info is zero then cookie should be too, so we shouldn't 7618948e4baSArchie Cobbs * need to clear them here. Assume divert_packet() does so also. 76293e0e116SJulian Elischer */ 7638948e4baSArchie Cobbs if (divert_info != 0) { 7648948e4baSArchie Cobbs struct mbuf *clone = NULL; 7658948e4baSArchie Cobbs 7668948e4baSArchie Cobbs /* Clone packet if we're doing a 'tee' */ 7678948e4baSArchie Cobbs if ((divert_info & IP_FW_PORT_TEE_FLAG) != 0) 7688948e4baSArchie Cobbs clone = m_dup(m, M_DONTWAIT); 7698948e4baSArchie Cobbs 7708948e4baSArchie Cobbs /* Restore packet header fields to original values */ 7718948e4baSArchie Cobbs ip->ip_len += hlen; 7728948e4baSArchie Cobbs HTONS(ip->ip_len); 7738948e4baSArchie Cobbs HTONS(ip->ip_off); 7748948e4baSArchie Cobbs 7758948e4baSArchie Cobbs /* Deliver packet to divert input routine */ 7768948e4baSArchie Cobbs ip_divert_cookie = divert_cookie; 7778948e4baSArchie Cobbs divert_packet(m, 1, divert_info & 0xffff); 778e4676ba6SJulian Elischer ipstat.ips_delivered++; 7798948e4baSArchie Cobbs 7808948e4baSArchie Cobbs /* If 'tee', continue with original packet */ 7818948e4baSArchie Cobbs if (clone == NULL) 78293e0e116SJulian Elischer return; 7838948e4baSArchie Cobbs m = clone; 7848948e4baSArchie Cobbs ip = mtod(m, struct ip *); 78593e0e116SJulian Elischer } 78693e0e116SJulian Elischer #endif 78793e0e116SJulian Elischer 788df8bae1dSRodney W. Grimes /* 789df8bae1dSRodney W. Grimes * Switch out to protocol's input routine. 790df8bae1dSRodney W. Grimes */ 791df8bae1dSRodney W. Grimes ipstat.ips_delivered++; 7926a800098SYoshinobu Inoue { 7936a800098SYoshinobu Inoue int off = hlen, nh = ip->ip_p; 7946a800098SYoshinobu Inoue 7956a800098SYoshinobu Inoue (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, off, nh); 796f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 797f9e354dfSJulian Elischer ip_fw_fwd_addr = NULL; /* tcp needed it */ 798f9e354dfSJulian Elischer #endif 799c67b1d17SGarrett Wollman return; 8006a800098SYoshinobu Inoue } 801df8bae1dSRodney W. Grimes bad: 802f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 803f9e354dfSJulian Elischer ip_fw_fwd_addr = NULL; 804f9e354dfSJulian Elischer #endif 805df8bae1dSRodney W. Grimes m_freem(m); 806c67b1d17SGarrett Wollman } 807c67b1d17SGarrett Wollman 808c67b1d17SGarrett Wollman /* 809c67b1d17SGarrett Wollman * IP software interrupt routine - to go away sometime soon 810c67b1d17SGarrett Wollman */ 811c67b1d17SGarrett Wollman static void 812c67b1d17SGarrett Wollman ipintr(void) 813c67b1d17SGarrett Wollman { 814c67b1d17SGarrett Wollman struct mbuf *m; 815c67b1d17SGarrett Wollman 816c67b1d17SGarrett Wollman while (1) { 817c67b1d17SGarrett Wollman IF_DEQUEUE(&ipintrq, m); 818c67b1d17SGarrett Wollman if (m == 0) 819c67b1d17SGarrett Wollman return; 820c67b1d17SGarrett Wollman ip_input(m); 821c67b1d17SGarrett Wollman } 822df8bae1dSRodney W. Grimes } 823df8bae1dSRodney W. Grimes 824df8bae1dSRodney W. Grimes /* 8258948e4baSArchie Cobbs * Take incoming datagram fragment and try to reassemble it into 8268948e4baSArchie Cobbs * whole datagram. If a chain for reassembly of this datagram already 8278948e4baSArchie Cobbs * exists, then it is given as fp; otherwise have to make a chain. 8288948e4baSArchie Cobbs * 8298948e4baSArchie Cobbs * When IPDIVERT enabled, keep additional state with each packet that 8308948e4baSArchie Cobbs * tells us if we need to divert or tee the packet we're building. 831df8bae1dSRodney W. Grimes */ 8328948e4baSArchie Cobbs 8336a800098SYoshinobu Inoue static struct mbuf * 8348948e4baSArchie Cobbs #ifdef IPDIVERT 8358948e4baSArchie Cobbs ip_reass(m, fp, where, divinfo, divcookie) 8368948e4baSArchie Cobbs #else 8376effc713SDoug Rabson ip_reass(m, fp, where) 8388948e4baSArchie Cobbs #endif 8396effc713SDoug Rabson register struct mbuf *m; 840df8bae1dSRodney W. Grimes register struct ipq *fp; 841194a213eSAndrey A. Chernov struct ipq *where; 8428948e4baSArchie Cobbs #ifdef IPDIVERT 8438948e4baSArchie Cobbs u_int32_t *divinfo; 8448948e4baSArchie Cobbs u_int16_t *divcookie; 8458948e4baSArchie Cobbs #endif 846df8bae1dSRodney W. Grimes { 8476effc713SDoug Rabson struct ip *ip = mtod(m, struct ip *); 848b6ea1aa5SRuslan Ermilov register struct mbuf *p, *q, *nq; 849df8bae1dSRodney W. Grimes struct mbuf *t; 8506effc713SDoug Rabson int hlen = IP_VHL_HL(ip->ip_vhl) << 2; 851df8bae1dSRodney W. Grimes int i, next; 852df8bae1dSRodney W. Grimes 853df8bae1dSRodney W. Grimes /* 854df8bae1dSRodney W. Grimes * Presence of header sizes in mbufs 855df8bae1dSRodney W. Grimes * would confuse code below. 856df8bae1dSRodney W. Grimes */ 857df8bae1dSRodney W. Grimes m->m_data += hlen; 858df8bae1dSRodney W. Grimes m->m_len -= hlen; 859df8bae1dSRodney W. Grimes 860df8bae1dSRodney W. Grimes /* 861df8bae1dSRodney W. Grimes * If first fragment to arrive, create a reassembly queue. 862df8bae1dSRodney W. Grimes */ 863df8bae1dSRodney W. Grimes if (fp == 0) { 864df8bae1dSRodney W. Grimes if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL) 865df8bae1dSRodney W. Grimes goto dropfrag; 866df8bae1dSRodney W. Grimes fp = mtod(t, struct ipq *); 867194a213eSAndrey A. Chernov insque(fp, where); 868194a213eSAndrey A. Chernov nipq++; 869df8bae1dSRodney W. Grimes fp->ipq_ttl = IPFRAGTTL; 870df8bae1dSRodney W. Grimes fp->ipq_p = ip->ip_p; 871df8bae1dSRodney W. Grimes fp->ipq_id = ip->ip_id; 8726effc713SDoug Rabson fp->ipq_src = ip->ip_src; 8736effc713SDoug Rabson fp->ipq_dst = ip->ip_dst; 874af38c68cSLuigi Rizzo fp->ipq_frags = m; 875af38c68cSLuigi Rizzo m->m_nextpkt = NULL; 87693e0e116SJulian Elischer #ifdef IPDIVERT 8778948e4baSArchie Cobbs fp->ipq_div_info = 0; 878bb60f459SJulian Elischer fp->ipq_div_cookie = 0; 87993e0e116SJulian Elischer #endif 880af38c68cSLuigi Rizzo goto inserted; 881df8bae1dSRodney W. Grimes } 882df8bae1dSRodney W. Grimes 8836effc713SDoug Rabson #define GETIP(m) ((struct ip*)((m)->m_pkthdr.header)) 8846effc713SDoug Rabson 885df8bae1dSRodney W. Grimes /* 886df8bae1dSRodney W. Grimes * Find a segment which begins after this one does. 887df8bae1dSRodney W. Grimes */ 8886effc713SDoug Rabson for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) 8896effc713SDoug Rabson if (GETIP(q)->ip_off > ip->ip_off) 890df8bae1dSRodney W. Grimes break; 891df8bae1dSRodney W. Grimes 892df8bae1dSRodney W. Grimes /* 893df8bae1dSRodney W. Grimes * If there is a preceding segment, it may provide some of 894df8bae1dSRodney W. Grimes * our data already. If so, drop the data from the incoming 895af38c68cSLuigi Rizzo * segment. If it provides all of our data, drop us, otherwise 896af38c68cSLuigi Rizzo * stick new segment in the proper place. 897db4f9cc7SJonathan Lemon * 898db4f9cc7SJonathan Lemon * If some of the data is dropped from the the preceding 899db4f9cc7SJonathan Lemon * segment, then it's checksum is invalidated. 900df8bae1dSRodney W. Grimes */ 9016effc713SDoug Rabson if (p) { 9026effc713SDoug Rabson i = GETIP(p)->ip_off + GETIP(p)->ip_len - ip->ip_off; 903df8bae1dSRodney W. Grimes if (i > 0) { 904df8bae1dSRodney W. Grimes if (i >= ip->ip_len) 905df8bae1dSRodney W. Grimes goto dropfrag; 9066a800098SYoshinobu Inoue m_adj(m, i); 907db4f9cc7SJonathan Lemon m->m_pkthdr.csum_flags = 0; 908df8bae1dSRodney W. Grimes ip->ip_off += i; 909df8bae1dSRodney W. Grimes ip->ip_len -= i; 910df8bae1dSRodney W. Grimes } 911af38c68cSLuigi Rizzo m->m_nextpkt = p->m_nextpkt; 912af38c68cSLuigi Rizzo p->m_nextpkt = m; 913af38c68cSLuigi Rizzo } else { 914af38c68cSLuigi Rizzo m->m_nextpkt = fp->ipq_frags; 915af38c68cSLuigi Rizzo fp->ipq_frags = m; 916df8bae1dSRodney W. Grimes } 917df8bae1dSRodney W. Grimes 918df8bae1dSRodney W. Grimes /* 919df8bae1dSRodney W. Grimes * While we overlap succeeding segments trim them or, 920df8bae1dSRodney W. Grimes * if they are completely covered, dequeue them. 921df8bae1dSRodney W. Grimes */ 9226effc713SDoug Rabson for (; q != NULL && ip->ip_off + ip->ip_len > GETIP(q)->ip_off; 923af38c68cSLuigi Rizzo q = nq) { 9246effc713SDoug Rabson i = (ip->ip_off + ip->ip_len) - 9256effc713SDoug Rabson GETIP(q)->ip_off; 9266effc713SDoug Rabson if (i < GETIP(q)->ip_len) { 9276effc713SDoug Rabson GETIP(q)->ip_len -= i; 9286effc713SDoug Rabson GETIP(q)->ip_off += i; 9296effc713SDoug Rabson m_adj(q, i); 930db4f9cc7SJonathan Lemon q->m_pkthdr.csum_flags = 0; 931df8bae1dSRodney W. Grimes break; 932df8bae1dSRodney W. Grimes } 9336effc713SDoug Rabson nq = q->m_nextpkt; 934af38c68cSLuigi Rizzo m->m_nextpkt = nq; 9356effc713SDoug Rabson m_freem(q); 936df8bae1dSRodney W. Grimes } 937df8bae1dSRodney W. Grimes 938af38c68cSLuigi Rizzo inserted: 93993e0e116SJulian Elischer 94093e0e116SJulian Elischer #ifdef IPDIVERT 94193e0e116SJulian Elischer /* 9428948e4baSArchie Cobbs * Transfer firewall instructions to the fragment structure. 9438948e4baSArchie Cobbs * Any fragment diverting causes the whole packet to divert. 94493e0e116SJulian Elischer */ 9458948e4baSArchie Cobbs fp->ipq_div_info = *divinfo; 9468948e4baSArchie Cobbs fp->ipq_div_cookie = *divcookie; 9478948e4baSArchie Cobbs *divinfo = 0; 9488948e4baSArchie Cobbs *divcookie = 0; 94993e0e116SJulian Elischer #endif 95093e0e116SJulian Elischer 951df8bae1dSRodney W. Grimes /* 952af38c68cSLuigi Rizzo * Check for complete reassembly. 953df8bae1dSRodney W. Grimes */ 9546effc713SDoug Rabson next = 0; 9556effc713SDoug Rabson for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) { 9566effc713SDoug Rabson if (GETIP(q)->ip_off != next) 9576effc713SDoug Rabson return (0); 9586effc713SDoug Rabson next += GETIP(q)->ip_len; 9596effc713SDoug Rabson } 9606effc713SDoug Rabson /* Make sure the last packet didn't have the IP_MF flag */ 9616effc713SDoug Rabson if (p->m_flags & M_FRAG) 962df8bae1dSRodney W. Grimes return (0); 963df8bae1dSRodney W. Grimes 964df8bae1dSRodney W. Grimes /* 965430d30d8SBill Fenner * Reassembly is complete. Make sure the packet is a sane size. 966430d30d8SBill Fenner */ 9676effc713SDoug Rabson q = fp->ipq_frags; 9686effc713SDoug Rabson ip = GETIP(q); 9696effc713SDoug Rabson if (next + (IP_VHL_HL(ip->ip_vhl) << 2) > IP_MAXPACKET) { 970430d30d8SBill Fenner ipstat.ips_toolong++; 971430d30d8SBill Fenner ip_freef(fp); 972430d30d8SBill Fenner return (0); 973430d30d8SBill Fenner } 974430d30d8SBill Fenner 975430d30d8SBill Fenner /* 976430d30d8SBill Fenner * Concatenate fragments. 977df8bae1dSRodney W. Grimes */ 9786effc713SDoug Rabson m = q; 979df8bae1dSRodney W. Grimes t = m->m_next; 980df8bae1dSRodney W. Grimes m->m_next = 0; 981df8bae1dSRodney W. Grimes m_cat(m, t); 9826effc713SDoug Rabson nq = q->m_nextpkt; 983945aa40dSDoug Rabson q->m_nextpkt = 0; 9846effc713SDoug Rabson for (q = nq; q != NULL; q = nq) { 9856effc713SDoug Rabson nq = q->m_nextpkt; 986945aa40dSDoug Rabson q->m_nextpkt = NULL; 987db4f9cc7SJonathan Lemon m->m_pkthdr.csum_flags &= q->m_pkthdr.csum_flags; 988db4f9cc7SJonathan Lemon m->m_pkthdr.csum_data += q->m_pkthdr.csum_data; 989a8db1d93SJonathan Lemon m_cat(m, q); 990df8bae1dSRodney W. Grimes } 991df8bae1dSRodney W. Grimes 99293e0e116SJulian Elischer #ifdef IPDIVERT 99393e0e116SJulian Elischer /* 9948948e4baSArchie Cobbs * Extract firewall instructions from the fragment structure. 99593e0e116SJulian Elischer */ 9968948e4baSArchie Cobbs *divinfo = fp->ipq_div_info; 9978948e4baSArchie Cobbs *divcookie = fp->ipq_div_cookie; 99893e0e116SJulian Elischer #endif 99993e0e116SJulian Elischer 1000df8bae1dSRodney W. Grimes /* 1001df8bae1dSRodney W. Grimes * Create header for new ip packet by 1002df8bae1dSRodney W. Grimes * modifying header of first packet; 1003df8bae1dSRodney W. Grimes * dequeue and discard fragment reassembly header. 1004df8bae1dSRodney W. Grimes * Make header visible. 1005df8bae1dSRodney W. Grimes */ 1006df8bae1dSRodney W. Grimes ip->ip_len = next; 10076effc713SDoug Rabson ip->ip_src = fp->ipq_src; 10086effc713SDoug Rabson ip->ip_dst = fp->ipq_dst; 1009df8bae1dSRodney W. Grimes remque(fp); 1010194a213eSAndrey A. Chernov nipq--; 1011df8bae1dSRodney W. Grimes (void) m_free(dtom(fp)); 10126effc713SDoug Rabson m->m_len += (IP_VHL_HL(ip->ip_vhl) << 2); 10136effc713SDoug Rabson m->m_data -= (IP_VHL_HL(ip->ip_vhl) << 2); 1014df8bae1dSRodney W. Grimes /* some debugging cruft by sklower, below, will go away soon */ 1015df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) { /* XXX this should be done elsewhere */ 1016df8bae1dSRodney W. Grimes register int plen = 0; 10176a800098SYoshinobu Inoue for (t = m; t; t = t->m_next) 10186a800098SYoshinobu Inoue plen += t->m_len; 10196a800098SYoshinobu Inoue m->m_pkthdr.len = plen; 1020df8bae1dSRodney W. Grimes } 10216a800098SYoshinobu Inoue return (m); 1022df8bae1dSRodney W. Grimes 1023df8bae1dSRodney W. Grimes dropfrag: 1024efe39c6aSJulian Elischer #ifdef IPDIVERT 10258948e4baSArchie Cobbs *divinfo = 0; 10268948e4baSArchie Cobbs *divcookie = 0; 1027efe39c6aSJulian Elischer #endif 1028df8bae1dSRodney W. Grimes ipstat.ips_fragdropped++; 1029df8bae1dSRodney W. Grimes m_freem(m); 1030df8bae1dSRodney W. Grimes return (0); 10316effc713SDoug Rabson 10326effc713SDoug Rabson #undef GETIP 1033df8bae1dSRodney W. Grimes } 1034df8bae1dSRodney W. Grimes 1035df8bae1dSRodney W. Grimes /* 1036df8bae1dSRodney W. Grimes * Free a fragment reassembly header and all 1037df8bae1dSRodney W. Grimes * associated datagrams. 1038df8bae1dSRodney W. Grimes */ 10390312fbe9SPoul-Henning Kamp static void 1040df8bae1dSRodney W. Grimes ip_freef(fp) 1041df8bae1dSRodney W. Grimes struct ipq *fp; 1042df8bae1dSRodney W. Grimes { 10436effc713SDoug Rabson register struct mbuf *q; 1044df8bae1dSRodney W. Grimes 10456effc713SDoug Rabson while (fp->ipq_frags) { 10466effc713SDoug Rabson q = fp->ipq_frags; 10476effc713SDoug Rabson fp->ipq_frags = q->m_nextpkt; 10486effc713SDoug Rabson m_freem(q); 1049df8bae1dSRodney W. Grimes } 1050df8bae1dSRodney W. Grimes remque(fp); 1051df8bae1dSRodney W. Grimes (void) m_free(dtom(fp)); 1052194a213eSAndrey A. Chernov nipq--; 1053df8bae1dSRodney W. Grimes } 1054df8bae1dSRodney W. Grimes 1055df8bae1dSRodney W. Grimes /* 1056df8bae1dSRodney W. Grimes * IP timer processing; 1057df8bae1dSRodney W. Grimes * if a timer expires on a reassembly 1058df8bae1dSRodney W. Grimes * queue, discard it. 1059df8bae1dSRodney W. Grimes */ 1060df8bae1dSRodney W. Grimes void 1061df8bae1dSRodney W. Grimes ip_slowtimo() 1062df8bae1dSRodney W. Grimes { 1063df8bae1dSRodney W. Grimes register struct ipq *fp; 1064df8bae1dSRodney W. Grimes int s = splnet(); 1065194a213eSAndrey A. Chernov int i; 1066df8bae1dSRodney W. Grimes 1067194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 1068194a213eSAndrey A. Chernov fp = ipq[i].next; 1069194a213eSAndrey A. Chernov if (fp == 0) 1070194a213eSAndrey A. Chernov continue; 1071194a213eSAndrey A. Chernov while (fp != &ipq[i]) { 1072df8bae1dSRodney W. Grimes --fp->ipq_ttl; 1073df8bae1dSRodney W. Grimes fp = fp->next; 1074df8bae1dSRodney W. Grimes if (fp->prev->ipq_ttl == 0) { 1075df8bae1dSRodney W. Grimes ipstat.ips_fragtimeout++; 1076df8bae1dSRodney W. Grimes ip_freef(fp->prev); 1077df8bae1dSRodney W. Grimes } 1078df8bae1dSRodney W. Grimes } 1079194a213eSAndrey A. Chernov } 10801f91d8c5SDavid Greenman ipflow_slowtimo(); 1081df8bae1dSRodney W. Grimes splx(s); 1082df8bae1dSRodney W. Grimes } 1083df8bae1dSRodney W. Grimes 1084df8bae1dSRodney W. Grimes /* 1085df8bae1dSRodney W. Grimes * Drain off all datagram fragments. 1086df8bae1dSRodney W. Grimes */ 1087df8bae1dSRodney W. Grimes void 1088df8bae1dSRodney W. Grimes ip_drain() 1089df8bae1dSRodney W. Grimes { 1090194a213eSAndrey A. Chernov int i; 1091ce29ab3aSGarrett Wollman 1092194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 1093194a213eSAndrey A. Chernov while (ipq[i].next != &ipq[i]) { 1094194a213eSAndrey A. Chernov ipstat.ips_fragdropped++; 1095194a213eSAndrey A. Chernov ip_freef(ipq[i].next); 1096194a213eSAndrey A. Chernov } 1097194a213eSAndrey A. Chernov } 1098ce29ab3aSGarrett Wollman in_rtqdrain(); 1099df8bae1dSRodney W. Grimes } 1100df8bae1dSRodney W. Grimes 1101df8bae1dSRodney W. Grimes /* 1102df8bae1dSRodney W. Grimes * Do option processing on a datagram, 1103df8bae1dSRodney W. Grimes * possibly discarding it if bad options are encountered, 1104df8bae1dSRodney W. Grimes * or forwarding it if source-routed. 1105df8bae1dSRodney W. Grimes * Returns 1 if packet has been forwarded/freed, 1106df8bae1dSRodney W. Grimes * 0 if the packet should be processed further. 1107df8bae1dSRodney W. Grimes */ 11080312fbe9SPoul-Henning Kamp static int 1109df8bae1dSRodney W. Grimes ip_dooptions(m) 1110df8bae1dSRodney W. Grimes struct mbuf *m; 1111df8bae1dSRodney W. Grimes { 1112df8bae1dSRodney W. Grimes register struct ip *ip = mtod(m, struct ip *); 1113df8bae1dSRodney W. Grimes register u_char *cp; 1114df8bae1dSRodney W. Grimes register struct ip_timestamp *ipt; 1115df8bae1dSRodney W. Grimes register struct in_ifaddr *ia; 1116df8bae1dSRodney W. Grimes int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0; 1117df8bae1dSRodney W. Grimes struct in_addr *sin, dst; 1118df8bae1dSRodney W. Grimes n_time ntime; 1119df8bae1dSRodney W. Grimes 1120df8bae1dSRodney W. Grimes dst = ip->ip_dst; 1121df8bae1dSRodney W. Grimes cp = (u_char *)(ip + 1); 112258938916SGarrett Wollman cnt = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip); 1123df8bae1dSRodney W. Grimes for (; cnt > 0; cnt -= optlen, cp += optlen) { 1124df8bae1dSRodney W. Grimes opt = cp[IPOPT_OPTVAL]; 1125df8bae1dSRodney W. Grimes if (opt == IPOPT_EOL) 1126df8bae1dSRodney W. Grimes break; 1127df8bae1dSRodney W. Grimes if (opt == IPOPT_NOP) 1128df8bae1dSRodney W. Grimes optlen = 1; 1129df8bae1dSRodney W. Grimes else { 1130fdcb8debSJun-ichiro itojun Hagino if (cnt < IPOPT_OLEN + sizeof(*cp)) { 1131fdcb8debSJun-ichiro itojun Hagino code = &cp[IPOPT_OLEN] - (u_char *)ip; 1132fdcb8debSJun-ichiro itojun Hagino goto bad; 1133fdcb8debSJun-ichiro itojun Hagino } 1134df8bae1dSRodney W. Grimes optlen = cp[IPOPT_OLEN]; 1135707d00a3SJonathan Lemon if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt) { 1136df8bae1dSRodney W. Grimes code = &cp[IPOPT_OLEN] - (u_char *)ip; 1137df8bae1dSRodney W. Grimes goto bad; 1138df8bae1dSRodney W. Grimes } 1139df8bae1dSRodney W. Grimes } 1140df8bae1dSRodney W. Grimes switch (opt) { 1141df8bae1dSRodney W. Grimes 1142df8bae1dSRodney W. Grimes default: 1143df8bae1dSRodney W. Grimes break; 1144df8bae1dSRodney W. Grimes 1145df8bae1dSRodney W. Grimes /* 1146df8bae1dSRodney W. Grimes * Source routing with record. 1147df8bae1dSRodney W. Grimes * Find interface with current destination address. 1148df8bae1dSRodney W. Grimes * If none on this machine then drop if strictly routed, 1149df8bae1dSRodney W. Grimes * or do nothing if loosely routed. 1150df8bae1dSRodney W. Grimes * Record interface address and bring up next address 1151df8bae1dSRodney W. Grimes * component. If strictly routed make sure next 1152df8bae1dSRodney W. Grimes * address is on directly accessible net. 1153df8bae1dSRodney W. Grimes */ 1154df8bae1dSRodney W. Grimes case IPOPT_LSRR: 1155df8bae1dSRodney W. Grimes case IPOPT_SSRR: 1156df8bae1dSRodney W. Grimes if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { 1157df8bae1dSRodney W. Grimes code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1158df8bae1dSRodney W. Grimes goto bad; 1159df8bae1dSRodney W. Grimes } 1160df8bae1dSRodney W. Grimes ipaddr.sin_addr = ip->ip_dst; 1161df8bae1dSRodney W. Grimes ia = (struct in_ifaddr *) 1162df8bae1dSRodney W. Grimes ifa_ifwithaddr((struct sockaddr *)&ipaddr); 1163df8bae1dSRodney W. Grimes if (ia == 0) { 1164df8bae1dSRodney W. Grimes if (opt == IPOPT_SSRR) { 1165df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1166df8bae1dSRodney W. Grimes code = ICMP_UNREACH_SRCFAIL; 1167df8bae1dSRodney W. Grimes goto bad; 1168df8bae1dSRodney W. Grimes } 1169bc189bf8SGuido van Rooij if (!ip_dosourceroute) 1170bc189bf8SGuido van Rooij goto nosourcerouting; 1171df8bae1dSRodney W. Grimes /* 1172df8bae1dSRodney W. Grimes * Loose routing, and not at next destination 1173df8bae1dSRodney W. Grimes * yet; nothing to do except forward. 1174df8bae1dSRodney W. Grimes */ 1175df8bae1dSRodney W. Grimes break; 1176df8bae1dSRodney W. Grimes } 1177df8bae1dSRodney W. Grimes off--; /* 0 origin */ 11785d5d5fc0SJonathan Lemon if (off > optlen - (int)sizeof(struct in_addr)) { 1179df8bae1dSRodney W. Grimes /* 1180df8bae1dSRodney W. Grimes * End of source route. Should be for us. 1181df8bae1dSRodney W. Grimes */ 11824fce5804SGuido van Rooij if (!ip_acceptsourceroute) 11834fce5804SGuido van Rooij goto nosourcerouting; 1184df8bae1dSRodney W. Grimes save_rte(cp, ip->ip_src); 1185df8bae1dSRodney W. Grimes break; 1186df8bae1dSRodney W. Grimes } 11871025071fSGarrett Wollman 11881025071fSGarrett Wollman if (!ip_dosourceroute) { 11890af8d3ecSDavid Greenman if (ipforwarding) { 11900af8d3ecSDavid Greenman char buf[16]; /* aaa.bbb.ccc.ddd\0 */ 11910af8d3ecSDavid Greenman /* 11920af8d3ecSDavid Greenman * Acting as a router, so generate ICMP 11930af8d3ecSDavid Greenman */ 1194efa48587SGuido van Rooij nosourcerouting: 1195bc189bf8SGuido van Rooij strcpy(buf, inet_ntoa(ip->ip_dst)); 11961025071fSGarrett Wollman log(LOG_WARNING, 11971025071fSGarrett Wollman "attempted source route from %s to %s\n", 11981025071fSGarrett Wollman inet_ntoa(ip->ip_src), buf); 11991025071fSGarrett Wollman type = ICMP_UNREACH; 12001025071fSGarrett Wollman code = ICMP_UNREACH_SRCFAIL; 12011025071fSGarrett Wollman goto bad; 12020af8d3ecSDavid Greenman } else { 12030af8d3ecSDavid Greenman /* 12040af8d3ecSDavid Greenman * Not acting as a router, so silently drop. 12050af8d3ecSDavid Greenman */ 12060af8d3ecSDavid Greenman ipstat.ips_cantforward++; 12070af8d3ecSDavid Greenman m_freem(m); 12080af8d3ecSDavid Greenman return (1); 12090af8d3ecSDavid Greenman } 12101025071fSGarrett Wollman } 12111025071fSGarrett Wollman 1212df8bae1dSRodney W. Grimes /* 1213df8bae1dSRodney W. Grimes * locate outgoing interface 1214df8bae1dSRodney W. Grimes */ 121594a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, cp + off, 1216df8bae1dSRodney W. Grimes sizeof(ipaddr.sin_addr)); 12171025071fSGarrett Wollman 1218df8bae1dSRodney W. Grimes if (opt == IPOPT_SSRR) { 1219df8bae1dSRodney W. Grimes #define INA struct in_ifaddr * 1220df8bae1dSRodney W. Grimes #define SA struct sockaddr * 1221df8bae1dSRodney W. Grimes if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0) 1222df8bae1dSRodney W. Grimes ia = (INA)ifa_ifwithnet((SA)&ipaddr); 1223df8bae1dSRodney W. Grimes } else 1224df8bae1dSRodney W. Grimes ia = ip_rtaddr(ipaddr.sin_addr); 1225df8bae1dSRodney W. Grimes if (ia == 0) { 1226df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1227df8bae1dSRodney W. Grimes code = ICMP_UNREACH_SRCFAIL; 1228df8bae1dSRodney W. Grimes goto bad; 1229df8bae1dSRodney W. Grimes } 1230df8bae1dSRodney W. Grimes ip->ip_dst = ipaddr.sin_addr; 123194a5d9b6SDavid Greenman (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr), 123294a5d9b6SDavid Greenman sizeof(struct in_addr)); 1233df8bae1dSRodney W. Grimes cp[IPOPT_OFFSET] += sizeof(struct in_addr); 1234df8bae1dSRodney W. Grimes /* 1235df8bae1dSRodney W. Grimes * Let ip_intr's mcast routing check handle mcast pkts 1236df8bae1dSRodney W. Grimes */ 1237df8bae1dSRodney W. Grimes forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr)); 1238df8bae1dSRodney W. Grimes break; 1239df8bae1dSRodney W. Grimes 1240df8bae1dSRodney W. Grimes case IPOPT_RR: 1241707d00a3SJonathan Lemon if (optlen < IPOPT_OFFSET + sizeof(*cp)) { 1242707d00a3SJonathan Lemon code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1243707d00a3SJonathan Lemon goto bad; 1244707d00a3SJonathan Lemon } 1245df8bae1dSRodney W. Grimes if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { 1246df8bae1dSRodney W. Grimes code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1247df8bae1dSRodney W. Grimes goto bad; 1248df8bae1dSRodney W. Grimes } 1249df8bae1dSRodney W. Grimes /* 1250df8bae1dSRodney W. Grimes * If no space remains, ignore. 1251df8bae1dSRodney W. Grimes */ 1252df8bae1dSRodney W. Grimes off--; /* 0 origin */ 12535d5d5fc0SJonathan Lemon if (off > optlen - (int)sizeof(struct in_addr)) 1254df8bae1dSRodney W. Grimes break; 125594a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, &ip->ip_dst, 1256df8bae1dSRodney W. Grimes sizeof(ipaddr.sin_addr)); 1257df8bae1dSRodney W. Grimes /* 1258df8bae1dSRodney W. Grimes * locate outgoing interface; if we're the destination, 1259df8bae1dSRodney W. Grimes * use the incoming interface (should be same). 1260df8bae1dSRodney W. Grimes */ 1261df8bae1dSRodney W. Grimes if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 && 1262df8bae1dSRodney W. Grimes (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) { 1263df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1264df8bae1dSRodney W. Grimes code = ICMP_UNREACH_HOST; 1265df8bae1dSRodney W. Grimes goto bad; 1266df8bae1dSRodney W. Grimes } 126794a5d9b6SDavid Greenman (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr), 126894a5d9b6SDavid Greenman sizeof(struct in_addr)); 1269df8bae1dSRodney W. Grimes cp[IPOPT_OFFSET] += sizeof(struct in_addr); 1270df8bae1dSRodney W. Grimes break; 1271df8bae1dSRodney W. Grimes 1272df8bae1dSRodney W. Grimes case IPOPT_TS: 1273df8bae1dSRodney W. Grimes code = cp - (u_char *)ip; 1274df8bae1dSRodney W. Grimes ipt = (struct ip_timestamp *)cp; 1275df8bae1dSRodney W. Grimes if (ipt->ipt_len < 5) 1276df8bae1dSRodney W. Grimes goto bad; 12775d5d5fc0SJonathan Lemon if (ipt->ipt_ptr > 12785d5d5fc0SJonathan Lemon ipt->ipt_len - (int)sizeof(int32_t)) { 1279df8bae1dSRodney W. Grimes if (++ipt->ipt_oflw == 0) 1280df8bae1dSRodney W. Grimes goto bad; 1281df8bae1dSRodney W. Grimes break; 1282df8bae1dSRodney W. Grimes } 1283df8bae1dSRodney W. Grimes sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1); 1284df8bae1dSRodney W. Grimes switch (ipt->ipt_flg) { 1285df8bae1dSRodney W. Grimes 1286df8bae1dSRodney W. Grimes case IPOPT_TS_TSONLY: 1287df8bae1dSRodney W. Grimes break; 1288df8bae1dSRodney W. Grimes 1289df8bae1dSRodney W. Grimes case IPOPT_TS_TSANDADDR: 1290b8e8c209SDavid Greenman if (ipt->ipt_ptr - 1 + sizeof(n_time) + 1291df8bae1dSRodney W. Grimes sizeof(struct in_addr) > ipt->ipt_len) 1292df8bae1dSRodney W. Grimes goto bad; 1293df8bae1dSRodney W. Grimes ipaddr.sin_addr = dst; 1294df8bae1dSRodney W. Grimes ia = (INA)ifaof_ifpforaddr((SA)&ipaddr, 1295df8bae1dSRodney W. Grimes m->m_pkthdr.rcvif); 1296df8bae1dSRodney W. Grimes if (ia == 0) 1297df8bae1dSRodney W. Grimes continue; 129894a5d9b6SDavid Greenman (void)memcpy(sin, &IA_SIN(ia)->sin_addr, 129994a5d9b6SDavid Greenman sizeof(struct in_addr)); 1300df8bae1dSRodney W. Grimes ipt->ipt_ptr += sizeof(struct in_addr); 1301df8bae1dSRodney W. Grimes break; 1302df8bae1dSRodney W. Grimes 1303df8bae1dSRodney W. Grimes case IPOPT_TS_PRESPEC: 1304b8e8c209SDavid Greenman if (ipt->ipt_ptr - 1 + sizeof(n_time) + 1305df8bae1dSRodney W. Grimes sizeof(struct in_addr) > ipt->ipt_len) 1306df8bae1dSRodney W. Grimes goto bad; 130794a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, sin, 1308df8bae1dSRodney W. Grimes sizeof(struct in_addr)); 1309df8bae1dSRodney W. Grimes if (ifa_ifwithaddr((SA)&ipaddr) == 0) 1310df8bae1dSRodney W. Grimes continue; 1311df8bae1dSRodney W. Grimes ipt->ipt_ptr += sizeof(struct in_addr); 1312df8bae1dSRodney W. Grimes break; 1313df8bae1dSRodney W. Grimes 1314df8bae1dSRodney W. Grimes default: 1315df8bae1dSRodney W. Grimes goto bad; 1316df8bae1dSRodney W. Grimes } 1317df8bae1dSRodney W. Grimes ntime = iptime(); 131894a5d9b6SDavid Greenman (void)memcpy(cp + ipt->ipt_ptr - 1, &ntime, 1319df8bae1dSRodney W. Grimes sizeof(n_time)); 1320df8bae1dSRodney W. Grimes ipt->ipt_ptr += sizeof(n_time); 1321df8bae1dSRodney W. Grimes } 1322df8bae1dSRodney W. Grimes } 132347174b49SAndrey A. Chernov if (forward && ipforwarding) { 1324df8bae1dSRodney W. Grimes ip_forward(m, 1); 1325df8bae1dSRodney W. Grimes return (1); 1326df8bae1dSRodney W. Grimes } 1327df8bae1dSRodney W. Grimes return (0); 1328df8bae1dSRodney W. Grimes bad: 1329df8bae1dSRodney W. Grimes icmp_error(m, type, code, 0, 0); 1330df8bae1dSRodney W. Grimes ipstat.ips_badoptions++; 1331df8bae1dSRodney W. Grimes return (1); 1332df8bae1dSRodney W. Grimes } 1333df8bae1dSRodney W. Grimes 1334df8bae1dSRodney W. Grimes /* 1335df8bae1dSRodney W. Grimes * Given address of next destination (final or next hop), 1336df8bae1dSRodney W. Grimes * return internet address info of interface to be used to get there. 1337df8bae1dSRodney W. Grimes */ 13380312fbe9SPoul-Henning Kamp static struct in_ifaddr * 1339df8bae1dSRodney W. Grimes ip_rtaddr(dst) 1340df8bae1dSRodney W. Grimes struct in_addr dst; 1341df8bae1dSRodney W. Grimes { 1342df8bae1dSRodney W. Grimes register struct sockaddr_in *sin; 1343df8bae1dSRodney W. Grimes 1344df8bae1dSRodney W. Grimes sin = (struct sockaddr_in *) &ipforward_rt.ro_dst; 1345df8bae1dSRodney W. Grimes 1346df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt == 0 || dst.s_addr != sin->sin_addr.s_addr) { 1347df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt) { 1348df8bae1dSRodney W. Grimes RTFREE(ipforward_rt.ro_rt); 1349df8bae1dSRodney W. Grimes ipforward_rt.ro_rt = 0; 1350df8bae1dSRodney W. Grimes } 1351df8bae1dSRodney W. Grimes sin->sin_family = AF_INET; 1352df8bae1dSRodney W. Grimes sin->sin_len = sizeof(*sin); 1353df8bae1dSRodney W. Grimes sin->sin_addr = dst; 1354df8bae1dSRodney W. Grimes 13552c17fe93SGarrett Wollman rtalloc_ign(&ipforward_rt, RTF_PRCLONING); 1356df8bae1dSRodney W. Grimes } 1357df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt == 0) 1358df8bae1dSRodney W. Grimes return ((struct in_ifaddr *)0); 1359df8bae1dSRodney W. Grimes return ((struct in_ifaddr *) ipforward_rt.ro_rt->rt_ifa); 1360df8bae1dSRodney W. Grimes } 1361df8bae1dSRodney W. Grimes 1362df8bae1dSRodney W. Grimes /* 1363df8bae1dSRodney W. Grimes * Save incoming source route for use in replies, 1364df8bae1dSRodney W. Grimes * to be picked up later by ip_srcroute if the receiver is interested. 1365df8bae1dSRodney W. Grimes */ 1366df8bae1dSRodney W. Grimes void 1367df8bae1dSRodney W. Grimes save_rte(option, dst) 1368df8bae1dSRodney W. Grimes u_char *option; 1369df8bae1dSRodney W. Grimes struct in_addr dst; 1370df8bae1dSRodney W. Grimes { 1371df8bae1dSRodney W. Grimes unsigned olen; 1372df8bae1dSRodney W. Grimes 1373df8bae1dSRodney W. Grimes olen = option[IPOPT_OLEN]; 1374df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1375df8bae1dSRodney W. Grimes if (ipprintfs) 1376df8bae1dSRodney W. Grimes printf("save_rte: olen %d\n", olen); 1377df8bae1dSRodney W. Grimes #endif 1378df8bae1dSRodney W. Grimes if (olen > sizeof(ip_srcrt) - (1 + sizeof(dst))) 1379df8bae1dSRodney W. Grimes return; 13800453d3cbSBruce Evans bcopy(option, ip_srcrt.srcopt, olen); 1381df8bae1dSRodney W. Grimes ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr); 1382df8bae1dSRodney W. Grimes ip_srcrt.dst = dst; 1383df8bae1dSRodney W. Grimes } 1384df8bae1dSRodney W. Grimes 1385df8bae1dSRodney W. Grimes /* 1386df8bae1dSRodney W. Grimes * Retrieve incoming source route for use in replies, 1387df8bae1dSRodney W. Grimes * in the same form used by setsockopt. 1388df8bae1dSRodney W. Grimes * The first hop is placed before the options, will be removed later. 1389df8bae1dSRodney W. Grimes */ 1390df8bae1dSRodney W. Grimes struct mbuf * 1391df8bae1dSRodney W. Grimes ip_srcroute() 1392df8bae1dSRodney W. Grimes { 1393df8bae1dSRodney W. Grimes register struct in_addr *p, *q; 1394df8bae1dSRodney W. Grimes register struct mbuf *m; 1395df8bae1dSRodney W. Grimes 1396df8bae1dSRodney W. Grimes if (ip_nhops == 0) 1397df8bae1dSRodney W. Grimes return ((struct mbuf *)0); 1398cfe8b629SGarrett Wollman m = m_get(M_DONTWAIT, MT_HEADER); 1399df8bae1dSRodney W. Grimes if (m == 0) 1400df8bae1dSRodney W. Grimes return ((struct mbuf *)0); 1401df8bae1dSRodney W. Grimes 1402df8bae1dSRodney W. Grimes #define OPTSIZ (sizeof(ip_srcrt.nop) + sizeof(ip_srcrt.srcopt)) 1403df8bae1dSRodney W. Grimes 1404df8bae1dSRodney W. Grimes /* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */ 1405df8bae1dSRodney W. Grimes m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) + 1406df8bae1dSRodney W. Grimes OPTSIZ; 1407df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1408df8bae1dSRodney W. Grimes if (ipprintfs) 1409df8bae1dSRodney W. Grimes printf("ip_srcroute: nhops %d mlen %d", ip_nhops, m->m_len); 1410df8bae1dSRodney W. Grimes #endif 1411df8bae1dSRodney W. Grimes 1412df8bae1dSRodney W. Grimes /* 1413df8bae1dSRodney W. Grimes * First save first hop for return route 1414df8bae1dSRodney W. Grimes */ 1415df8bae1dSRodney W. Grimes p = &ip_srcrt.route[ip_nhops - 1]; 1416df8bae1dSRodney W. Grimes *(mtod(m, struct in_addr *)) = *p--; 1417df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1418df8bae1dSRodney W. Grimes if (ipprintfs) 1419af38c68cSLuigi Rizzo printf(" hops %lx", (u_long)ntohl(mtod(m, struct in_addr *)->s_addr)); 1420df8bae1dSRodney W. Grimes #endif 1421df8bae1dSRodney W. Grimes 1422df8bae1dSRodney W. Grimes /* 1423df8bae1dSRodney W. Grimes * Copy option fields and padding (nop) to mbuf. 1424df8bae1dSRodney W. Grimes */ 1425df8bae1dSRodney W. Grimes ip_srcrt.nop = IPOPT_NOP; 1426df8bae1dSRodney W. Grimes ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF; 142794a5d9b6SDavid Greenman (void)memcpy(mtod(m, caddr_t) + sizeof(struct in_addr), 142894a5d9b6SDavid Greenman &ip_srcrt.nop, OPTSIZ); 1429df8bae1dSRodney W. Grimes q = (struct in_addr *)(mtod(m, caddr_t) + 1430df8bae1dSRodney W. Grimes sizeof(struct in_addr) + OPTSIZ); 1431df8bae1dSRodney W. Grimes #undef OPTSIZ 1432df8bae1dSRodney W. Grimes /* 1433df8bae1dSRodney W. Grimes * Record return path as an IP source route, 1434df8bae1dSRodney W. Grimes * reversing the path (pointers are now aligned). 1435df8bae1dSRodney W. Grimes */ 1436df8bae1dSRodney W. Grimes while (p >= ip_srcrt.route) { 1437df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1438df8bae1dSRodney W. Grimes if (ipprintfs) 1439af38c68cSLuigi Rizzo printf(" %lx", (u_long)ntohl(q->s_addr)); 1440df8bae1dSRodney W. Grimes #endif 1441df8bae1dSRodney W. Grimes *q++ = *p--; 1442df8bae1dSRodney W. Grimes } 1443df8bae1dSRodney W. Grimes /* 1444df8bae1dSRodney W. Grimes * Last hop goes to final destination. 1445df8bae1dSRodney W. Grimes */ 1446df8bae1dSRodney W. Grimes *q = ip_srcrt.dst; 1447df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1448df8bae1dSRodney W. Grimes if (ipprintfs) 1449af38c68cSLuigi Rizzo printf(" %lx\n", (u_long)ntohl(q->s_addr)); 1450df8bae1dSRodney W. Grimes #endif 1451df8bae1dSRodney W. Grimes return (m); 1452df8bae1dSRodney W. Grimes } 1453df8bae1dSRodney W. Grimes 1454df8bae1dSRodney W. Grimes /* 1455df8bae1dSRodney W. Grimes * Strip out IP options, at higher 1456df8bae1dSRodney W. Grimes * level protocol in the kernel. 1457df8bae1dSRodney W. Grimes * Second argument is buffer to which options 1458df8bae1dSRodney W. Grimes * will be moved, and return value is their length. 1459df8bae1dSRodney W. Grimes * XXX should be deleted; last arg currently ignored. 1460df8bae1dSRodney W. Grimes */ 1461df8bae1dSRodney W. Grimes void 1462df8bae1dSRodney W. Grimes ip_stripoptions(m, mopt) 1463df8bae1dSRodney W. Grimes register struct mbuf *m; 1464df8bae1dSRodney W. Grimes struct mbuf *mopt; 1465df8bae1dSRodney W. Grimes { 1466df8bae1dSRodney W. Grimes register int i; 1467df8bae1dSRodney W. Grimes struct ip *ip = mtod(m, struct ip *); 1468df8bae1dSRodney W. Grimes register caddr_t opts; 1469df8bae1dSRodney W. Grimes int olen; 1470df8bae1dSRodney W. Grimes 147158938916SGarrett Wollman olen = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip); 1472df8bae1dSRodney W. Grimes opts = (caddr_t)(ip + 1); 1473df8bae1dSRodney W. Grimes i = m->m_len - (sizeof (struct ip) + olen); 1474df8bae1dSRodney W. Grimes bcopy(opts + olen, opts, (unsigned)i); 1475df8bae1dSRodney W. Grimes m->m_len -= olen; 1476df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) 1477df8bae1dSRodney W. Grimes m->m_pkthdr.len -= olen; 147858938916SGarrett Wollman ip->ip_vhl = IP_MAKE_VHL(IPVERSION, sizeof(struct ip) >> 2); 1479df8bae1dSRodney W. Grimes } 1480df8bae1dSRodney W. Grimes 1481df8bae1dSRodney W. Grimes u_char inetctlerrmap[PRC_NCMDS] = { 1482df8bae1dSRodney W. Grimes 0, 0, 0, 0, 1483df8bae1dSRodney W. Grimes 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH, 1484df8bae1dSRodney W. Grimes EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, 1485df8bae1dSRodney W. Grimes EMSGSIZE, EHOSTUNREACH, 0, 0, 1486df8bae1dSRodney W. Grimes 0, 0, 0, 0, 1487e4bb5b05SJonathan Lemon ENOPROTOOPT, ENETRESET 1488df8bae1dSRodney W. Grimes }; 1489df8bae1dSRodney W. Grimes 1490df8bae1dSRodney W. Grimes /* 1491df8bae1dSRodney W. Grimes * Forward a packet. If some error occurs return the sender 1492df8bae1dSRodney W. Grimes * an icmp packet. Note we can't always generate a meaningful 1493df8bae1dSRodney W. Grimes * icmp message because icmp doesn't have a large enough repertoire 1494df8bae1dSRodney W. Grimes * of codes and types. 1495df8bae1dSRodney W. Grimes * 1496df8bae1dSRodney W. Grimes * If not forwarding, just drop the packet. This could be confusing 1497df8bae1dSRodney W. Grimes * if ipforwarding was zero but some routing protocol was advancing 1498df8bae1dSRodney W. Grimes * us as a gateway to somewhere. However, we must let the routing 1499df8bae1dSRodney W. Grimes * protocol deal with that. 1500df8bae1dSRodney W. Grimes * 1501df8bae1dSRodney W. Grimes * The srcrt parameter indicates whether the packet is being forwarded 1502df8bae1dSRodney W. Grimes * via a source route. 1503df8bae1dSRodney W. Grimes */ 15040312fbe9SPoul-Henning Kamp static void 1505df8bae1dSRodney W. Grimes ip_forward(m, srcrt) 1506df8bae1dSRodney W. Grimes struct mbuf *m; 1507df8bae1dSRodney W. Grimes int srcrt; 1508df8bae1dSRodney W. Grimes { 1509df8bae1dSRodney W. Grimes register struct ip *ip = mtod(m, struct ip *); 1510df8bae1dSRodney W. Grimes register struct sockaddr_in *sin; 1511df8bae1dSRodney W. Grimes register struct rtentry *rt; 151226f9a767SRodney W. Grimes int error, type = 0, code = 0; 1513df8bae1dSRodney W. Grimes struct mbuf *mcopy; 1514df8bae1dSRodney W. Grimes n_long dest; 1515df8bae1dSRodney W. Grimes struct ifnet *destifp; 15166a800098SYoshinobu Inoue #ifdef IPSEC 15176a800098SYoshinobu Inoue struct ifnet dummyifp; 15186a800098SYoshinobu Inoue #endif 1519df8bae1dSRodney W. Grimes 1520df8bae1dSRodney W. Grimes dest = 0; 1521df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1522df8bae1dSRodney W. Grimes if (ipprintfs) 152361ce519bSPoul-Henning Kamp printf("forward: src %lx dst %lx ttl %x\n", 1524162886e2SBruce Evans (u_long)ip->ip_src.s_addr, (u_long)ip->ip_dst.s_addr, 1525162886e2SBruce Evans ip->ip_ttl); 1526df8bae1dSRodney W. Grimes #endif 1527100ba1a6SJordan K. Hubbard 1528100ba1a6SJordan K. Hubbard 152992af003dSGarrett Wollman if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(ip->ip_dst) == 0) { 1530df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 1531df8bae1dSRodney W. Grimes m_freem(m); 1532df8bae1dSRodney W. Grimes return; 1533df8bae1dSRodney W. Grimes } 15341b968362SDag-Erling Smørgrav #ifdef IPSTEALTH 15351b968362SDag-Erling Smørgrav if (!ipstealth) { 15361b968362SDag-Erling Smørgrav #endif 1537df8bae1dSRodney W. Grimes if (ip->ip_ttl <= IPTTLDEC) { 15381b968362SDag-Erling Smørgrav icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 15391b968362SDag-Erling Smørgrav dest, 0); 1540df8bae1dSRodney W. Grimes return; 1541df8bae1dSRodney W. Grimes } 15421b968362SDag-Erling Smørgrav #ifdef IPSTEALTH 15431b968362SDag-Erling Smørgrav } 15441b968362SDag-Erling Smørgrav #endif 1545df8bae1dSRodney W. Grimes 1546df8bae1dSRodney W. Grimes sin = (struct sockaddr_in *)&ipforward_rt.ro_dst; 1547df8bae1dSRodney W. Grimes if ((rt = ipforward_rt.ro_rt) == 0 || 1548df8bae1dSRodney W. Grimes ip->ip_dst.s_addr != sin->sin_addr.s_addr) { 1549df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt) { 1550df8bae1dSRodney W. Grimes RTFREE(ipforward_rt.ro_rt); 1551df8bae1dSRodney W. Grimes ipforward_rt.ro_rt = 0; 1552df8bae1dSRodney W. Grimes } 1553df8bae1dSRodney W. Grimes sin->sin_family = AF_INET; 1554df8bae1dSRodney W. Grimes sin->sin_len = sizeof(*sin); 1555df8bae1dSRodney W. Grimes sin->sin_addr = ip->ip_dst; 1556df8bae1dSRodney W. Grimes 15572c17fe93SGarrett Wollman rtalloc_ign(&ipforward_rt, RTF_PRCLONING); 1558df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt == 0) { 1559df8bae1dSRodney W. Grimes icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0); 1560df8bae1dSRodney W. Grimes return; 1561df8bae1dSRodney W. Grimes } 1562df8bae1dSRodney W. Grimes rt = ipforward_rt.ro_rt; 1563df8bae1dSRodney W. Grimes } 1564df8bae1dSRodney W. Grimes 1565df8bae1dSRodney W. Grimes /* 1566bfef7ed4SIan Dowse * Save the IP header and at most 8 bytes of the payload, 1567bfef7ed4SIan Dowse * in case we need to generate an ICMP message to the src. 1568bfef7ed4SIan Dowse * 1569bfef7ed4SIan Dowse * We don't use m_copy() because it might return a reference 1570bfef7ed4SIan Dowse * to a shared cluster. Both this function and ip_output() 1571bfef7ed4SIan Dowse * assume exclusive access to the IP header in `m', so any 1572bfef7ed4SIan Dowse * data in a cluster may change before we reach icmp_error(). 1573df8bae1dSRodney W. Grimes */ 1574bfef7ed4SIan Dowse MGET(mcopy, M_DONTWAIT, m->m_type); 1575bfef7ed4SIan Dowse if (mcopy != NULL) { 1576bfef7ed4SIan Dowse M_COPY_PKTHDR(mcopy, m); 1577bfef7ed4SIan Dowse mcopy->m_len = imin((IP_VHL_HL(ip->ip_vhl) << 2) + 8, 1578bfef7ed4SIan Dowse (int)ip->ip_len); 1579bfef7ed4SIan Dowse m_copydata(m, 0, mcopy->m_len, mtod(mcopy, caddr_t)); 1580bfef7ed4SIan Dowse } 158104287599SRuslan Ermilov 158204287599SRuslan Ermilov #ifdef IPSTEALTH 158304287599SRuslan Ermilov if (!ipstealth) { 158404287599SRuslan Ermilov #endif 158504287599SRuslan Ermilov ip->ip_ttl -= IPTTLDEC; 158604287599SRuslan Ermilov #ifdef IPSTEALTH 158704287599SRuslan Ermilov } 158804287599SRuslan Ermilov #endif 1589df8bae1dSRodney W. Grimes 1590df8bae1dSRodney W. Grimes /* 1591df8bae1dSRodney W. Grimes * If forwarding packet using same interface that it came in on, 1592df8bae1dSRodney W. Grimes * perhaps should send a redirect to sender to shortcut a hop. 1593df8bae1dSRodney W. Grimes * Only send redirect if source is sending directly to us, 1594df8bae1dSRodney W. Grimes * and if packet was not source routed (or has any options). 1595df8bae1dSRodney W. Grimes * Also, don't send redirect if forwarding using a default route 1596df8bae1dSRodney W. Grimes * or a route modified by a redirect. 1597df8bae1dSRodney W. Grimes */ 1598df8bae1dSRodney W. Grimes #define satosin(sa) ((struct sockaddr_in *)(sa)) 1599df8bae1dSRodney W. Grimes if (rt->rt_ifp == m->m_pkthdr.rcvif && 1600df8bae1dSRodney W. Grimes (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 && 1601df8bae1dSRodney W. Grimes satosin(rt_key(rt))->sin_addr.s_addr != 0 && 1602df8bae1dSRodney W. Grimes ipsendredirects && !srcrt) { 1603df8bae1dSRodney W. Grimes #define RTA(rt) ((struct in_ifaddr *)(rt->rt_ifa)) 1604df8bae1dSRodney W. Grimes u_long src = ntohl(ip->ip_src.s_addr); 1605df8bae1dSRodney W. Grimes 1606df8bae1dSRodney W. Grimes if (RTA(rt) && 1607df8bae1dSRodney W. Grimes (src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) { 1608df8bae1dSRodney W. Grimes if (rt->rt_flags & RTF_GATEWAY) 1609df8bae1dSRodney W. Grimes dest = satosin(rt->rt_gateway)->sin_addr.s_addr; 1610df8bae1dSRodney W. Grimes else 1611df8bae1dSRodney W. Grimes dest = ip->ip_dst.s_addr; 1612df8bae1dSRodney W. Grimes /* Router requirements says to only send host redirects */ 1613df8bae1dSRodney W. Grimes type = ICMP_REDIRECT; 1614df8bae1dSRodney W. Grimes code = ICMP_REDIRECT_HOST; 1615df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1616df8bae1dSRodney W. Grimes if (ipprintfs) 1617df8bae1dSRodney W. Grimes printf("redirect (%d) to %lx\n", code, (u_long)dest); 1618df8bae1dSRodney W. Grimes #endif 1619df8bae1dSRodney W. Grimes } 1620df8bae1dSRodney W. Grimes } 1621df8bae1dSRodney W. Grimes 1622b97d15cbSGarrett Wollman error = ip_output(m, (struct mbuf *)0, &ipforward_rt, 1623b97d15cbSGarrett Wollman IP_FORWARDING, 0); 1624df8bae1dSRodney W. Grimes if (error) 1625df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 1626df8bae1dSRodney W. Grimes else { 1627df8bae1dSRodney W. Grimes ipstat.ips_forward++; 1628df8bae1dSRodney W. Grimes if (type) 1629df8bae1dSRodney W. Grimes ipstat.ips_redirectsent++; 1630df8bae1dSRodney W. Grimes else { 16311f91d8c5SDavid Greenman if (mcopy) { 16321f91d8c5SDavid Greenman ipflow_create(&ipforward_rt, mcopy); 1633df8bae1dSRodney W. Grimes m_freem(mcopy); 16341f91d8c5SDavid Greenman } 1635df8bae1dSRodney W. Grimes return; 1636df8bae1dSRodney W. Grimes } 1637df8bae1dSRodney W. Grimes } 1638df8bae1dSRodney W. Grimes if (mcopy == NULL) 1639df8bae1dSRodney W. Grimes return; 1640df8bae1dSRodney W. Grimes destifp = NULL; 1641df8bae1dSRodney W. Grimes 1642df8bae1dSRodney W. Grimes switch (error) { 1643df8bae1dSRodney W. Grimes 1644df8bae1dSRodney W. Grimes case 0: /* forwarded, but need redirect */ 1645df8bae1dSRodney W. Grimes /* type, code set above */ 1646df8bae1dSRodney W. Grimes break; 1647df8bae1dSRodney W. Grimes 1648df8bae1dSRodney W. Grimes case ENETUNREACH: /* shouldn't happen, checked above */ 1649df8bae1dSRodney W. Grimes case EHOSTUNREACH: 1650df8bae1dSRodney W. Grimes case ENETDOWN: 1651df8bae1dSRodney W. Grimes case EHOSTDOWN: 1652df8bae1dSRodney W. Grimes default: 1653df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1654df8bae1dSRodney W. Grimes code = ICMP_UNREACH_HOST; 1655df8bae1dSRodney W. Grimes break; 1656df8bae1dSRodney W. Grimes 1657df8bae1dSRodney W. Grimes case EMSGSIZE: 1658df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1659df8bae1dSRodney W. Grimes code = ICMP_UNREACH_NEEDFRAG; 16606a800098SYoshinobu Inoue #ifndef IPSEC 1661df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt) 1662df8bae1dSRodney W. Grimes destifp = ipforward_rt.ro_rt->rt_ifp; 16636a800098SYoshinobu Inoue #else 16646a800098SYoshinobu Inoue /* 16656a800098SYoshinobu Inoue * If the packet is routed over IPsec tunnel, tell the 16666a800098SYoshinobu Inoue * originator the tunnel MTU. 16676a800098SYoshinobu Inoue * tunnel MTU = if MTU - sizeof(IP) - ESP/AH hdrsiz 16686a800098SYoshinobu Inoue * XXX quickhack!!! 16696a800098SYoshinobu Inoue */ 16706a800098SYoshinobu Inoue if (ipforward_rt.ro_rt) { 16716a800098SYoshinobu Inoue struct secpolicy *sp = NULL; 16726a800098SYoshinobu Inoue int ipsecerror; 16736a800098SYoshinobu Inoue int ipsechdr; 16746a800098SYoshinobu Inoue struct route *ro; 16756a800098SYoshinobu Inoue 16766a800098SYoshinobu Inoue sp = ipsec4_getpolicybyaddr(mcopy, 16776a800098SYoshinobu Inoue IPSEC_DIR_OUTBOUND, 16786a800098SYoshinobu Inoue IP_FORWARDING, 16796a800098SYoshinobu Inoue &ipsecerror); 16806a800098SYoshinobu Inoue 16816a800098SYoshinobu Inoue if (sp == NULL) 16826a800098SYoshinobu Inoue destifp = ipforward_rt.ro_rt->rt_ifp; 16836a800098SYoshinobu Inoue else { 16846a800098SYoshinobu Inoue /* count IPsec header size */ 16856a800098SYoshinobu Inoue ipsechdr = ipsec4_hdrsiz(mcopy, 16866a800098SYoshinobu Inoue IPSEC_DIR_OUTBOUND, 16876a800098SYoshinobu Inoue NULL); 16886a800098SYoshinobu Inoue 16896a800098SYoshinobu Inoue /* 16906a800098SYoshinobu Inoue * find the correct route for outer IPv4 16916a800098SYoshinobu Inoue * header, compute tunnel MTU. 16926a800098SYoshinobu Inoue * 16936a800098SYoshinobu Inoue * XXX BUG ALERT 16946a800098SYoshinobu Inoue * The "dummyifp" code relies upon the fact 16956a800098SYoshinobu Inoue * that icmp_error() touches only ifp->if_mtu. 16966a800098SYoshinobu Inoue */ 16976a800098SYoshinobu Inoue /*XXX*/ 16986a800098SYoshinobu Inoue destifp = NULL; 16996a800098SYoshinobu Inoue if (sp->req != NULL 17006a800098SYoshinobu Inoue && sp->req->sav != NULL 17016a800098SYoshinobu Inoue && sp->req->sav->sah != NULL) { 17026a800098SYoshinobu Inoue ro = &sp->req->sav->sah->sa_route; 17036a800098SYoshinobu Inoue if (ro->ro_rt && ro->ro_rt->rt_ifp) { 17046a800098SYoshinobu Inoue dummyifp.if_mtu = 17056a800098SYoshinobu Inoue ro->ro_rt->rt_ifp->if_mtu; 17066a800098SYoshinobu Inoue dummyifp.if_mtu -= ipsechdr; 17076a800098SYoshinobu Inoue destifp = &dummyifp; 17086a800098SYoshinobu Inoue } 17096a800098SYoshinobu Inoue } 17106a800098SYoshinobu Inoue 17116a800098SYoshinobu Inoue key_freesp(sp); 17126a800098SYoshinobu Inoue } 17136a800098SYoshinobu Inoue } 17146a800098SYoshinobu Inoue #endif /*IPSEC*/ 1715df8bae1dSRodney W. Grimes ipstat.ips_cantfrag++; 1716df8bae1dSRodney W. Grimes break; 1717df8bae1dSRodney W. Grimes 1718df8bae1dSRodney W. Grimes case ENOBUFS: 1719df8bae1dSRodney W. Grimes type = ICMP_SOURCEQUENCH; 1720df8bae1dSRodney W. Grimes code = 0; 1721df8bae1dSRodney W. Grimes break; 17223a06e3e0SRuslan Ermilov 17233a06e3e0SRuslan Ermilov case EACCES: /* ipfw denied packet */ 17243a06e3e0SRuslan Ermilov m_freem(mcopy); 17253a06e3e0SRuslan Ermilov return; 1726df8bae1dSRodney W. Grimes } 1727df8bae1dSRodney W. Grimes icmp_error(mcopy, type, code, dest, destifp); 1728df8bae1dSRodney W. Grimes } 1729df8bae1dSRodney W. Grimes 173082c23ebaSBill Fenner void 173182c23ebaSBill Fenner ip_savecontrol(inp, mp, ip, m) 173282c23ebaSBill Fenner register struct inpcb *inp; 173382c23ebaSBill Fenner register struct mbuf **mp; 173482c23ebaSBill Fenner register struct ip *ip; 173582c23ebaSBill Fenner register struct mbuf *m; 173682c23ebaSBill Fenner { 173782c23ebaSBill Fenner if (inp->inp_socket->so_options & SO_TIMESTAMP) { 173882c23ebaSBill Fenner struct timeval tv; 173982c23ebaSBill Fenner 174082c23ebaSBill Fenner microtime(&tv); 174182c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv), 174282c23ebaSBill Fenner SCM_TIMESTAMP, SOL_SOCKET); 174382c23ebaSBill Fenner if (*mp) 174482c23ebaSBill Fenner mp = &(*mp)->m_next; 174582c23ebaSBill Fenner } 174682c23ebaSBill Fenner if (inp->inp_flags & INP_RECVDSTADDR) { 174782c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) &ip->ip_dst, 174882c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVDSTADDR, IPPROTO_IP); 174982c23ebaSBill Fenner if (*mp) 175082c23ebaSBill Fenner mp = &(*mp)->m_next; 175182c23ebaSBill Fenner } 175282c23ebaSBill Fenner #ifdef notyet 175382c23ebaSBill Fenner /* XXX 175482c23ebaSBill Fenner * Moving these out of udp_input() made them even more broken 175582c23ebaSBill Fenner * than they already were. 175682c23ebaSBill Fenner */ 175782c23ebaSBill Fenner /* options were tossed already */ 175882c23ebaSBill Fenner if (inp->inp_flags & INP_RECVOPTS) { 175982c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) opts_deleted_above, 176082c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVOPTS, IPPROTO_IP); 176182c23ebaSBill Fenner if (*mp) 176282c23ebaSBill Fenner mp = &(*mp)->m_next; 176382c23ebaSBill Fenner } 176482c23ebaSBill Fenner /* ip_srcroute doesn't do what we want here, need to fix */ 176582c23ebaSBill Fenner if (inp->inp_flags & INP_RECVRETOPTS) { 176682c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) ip_srcroute(), 176782c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVRETOPTS, IPPROTO_IP); 176882c23ebaSBill Fenner if (*mp) 176982c23ebaSBill Fenner mp = &(*mp)->m_next; 177082c23ebaSBill Fenner } 177182c23ebaSBill Fenner #endif 177282c23ebaSBill Fenner if (inp->inp_flags & INP_RECVIF) { 1773d314ad7bSJulian Elischer struct ifnet *ifp; 1774d314ad7bSJulian Elischer struct sdlbuf { 177582c23ebaSBill Fenner struct sockaddr_dl sdl; 1776d314ad7bSJulian Elischer u_char pad[32]; 1777d314ad7bSJulian Elischer } sdlbuf; 1778d314ad7bSJulian Elischer struct sockaddr_dl *sdp; 1779d314ad7bSJulian Elischer struct sockaddr_dl *sdl2 = &sdlbuf.sdl; 178082c23ebaSBill Fenner 1781d314ad7bSJulian Elischer if (((ifp = m->m_pkthdr.rcvif)) 1782d314ad7bSJulian Elischer && ( ifp->if_index && (ifp->if_index <= if_index))) { 1783d314ad7bSJulian Elischer sdp = (struct sockaddr_dl *)(ifnet_addrs 1784d314ad7bSJulian Elischer [ifp->if_index - 1]->ifa_addr); 1785d314ad7bSJulian Elischer /* 1786d314ad7bSJulian Elischer * Change our mind and don't try copy. 1787d314ad7bSJulian Elischer */ 1788d314ad7bSJulian Elischer if ((sdp->sdl_family != AF_LINK) 1789d314ad7bSJulian Elischer || (sdp->sdl_len > sizeof(sdlbuf))) { 1790d314ad7bSJulian Elischer goto makedummy; 1791d314ad7bSJulian Elischer } 1792d314ad7bSJulian Elischer bcopy(sdp, sdl2, sdp->sdl_len); 1793d314ad7bSJulian Elischer } else { 1794d314ad7bSJulian Elischer makedummy: 1795d314ad7bSJulian Elischer sdl2->sdl_len 1796d314ad7bSJulian Elischer = offsetof(struct sockaddr_dl, sdl_data[0]); 1797d314ad7bSJulian Elischer sdl2->sdl_family = AF_LINK; 1798d314ad7bSJulian Elischer sdl2->sdl_index = 0; 1799d314ad7bSJulian Elischer sdl2->sdl_nlen = sdl2->sdl_alen = sdl2->sdl_slen = 0; 1800d314ad7bSJulian Elischer } 1801d314ad7bSJulian Elischer *mp = sbcreatecontrol((caddr_t) sdl2, sdl2->sdl_len, 180282c23ebaSBill Fenner IP_RECVIF, IPPROTO_IP); 180382c23ebaSBill Fenner if (*mp) 180482c23ebaSBill Fenner mp = &(*mp)->m_next; 180582c23ebaSBill Fenner } 180682c23ebaSBill Fenner } 180782c23ebaSBill Fenner 1808df8bae1dSRodney W. Grimes int 1809f0068c4aSGarrett Wollman ip_rsvp_init(struct socket *so) 1810f0068c4aSGarrett Wollman { 1811f0068c4aSGarrett Wollman if (so->so_type != SOCK_RAW || 1812f0068c4aSGarrett Wollman so->so_proto->pr_protocol != IPPROTO_RSVP) 1813f0068c4aSGarrett Wollman return EOPNOTSUPP; 1814f0068c4aSGarrett Wollman 1815f0068c4aSGarrett Wollman if (ip_rsvpd != NULL) 1816f0068c4aSGarrett Wollman return EADDRINUSE; 1817f0068c4aSGarrett Wollman 1818f0068c4aSGarrett Wollman ip_rsvpd = so; 18191c5de19aSGarrett Wollman /* 18201c5de19aSGarrett Wollman * This may seem silly, but we need to be sure we don't over-increment 18211c5de19aSGarrett Wollman * the RSVP counter, in case something slips up. 18221c5de19aSGarrett Wollman */ 18231c5de19aSGarrett Wollman if (!ip_rsvp_on) { 18241c5de19aSGarrett Wollman ip_rsvp_on = 1; 18251c5de19aSGarrett Wollman rsvp_on++; 18261c5de19aSGarrett Wollman } 1827f0068c4aSGarrett Wollman 1828f0068c4aSGarrett Wollman return 0; 1829f0068c4aSGarrett Wollman } 1830f0068c4aSGarrett Wollman 1831f0068c4aSGarrett Wollman int 1832f0068c4aSGarrett Wollman ip_rsvp_done(void) 1833f0068c4aSGarrett Wollman { 1834f0068c4aSGarrett Wollman ip_rsvpd = NULL; 18351c5de19aSGarrett Wollman /* 18361c5de19aSGarrett Wollman * This may seem silly, but we need to be sure we don't over-decrement 18371c5de19aSGarrett Wollman * the RSVP counter, in case something slips up. 18381c5de19aSGarrett Wollman */ 18391c5de19aSGarrett Wollman if (ip_rsvp_on) { 18401c5de19aSGarrett Wollman ip_rsvp_on = 0; 18411c5de19aSGarrett Wollman rsvp_on--; 18421c5de19aSGarrett Wollman } 1843f0068c4aSGarrett Wollman return 0; 1844f0068c4aSGarrett Wollman } 1845