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 127b3e95d4eSJonathan Lemon static int ip_checkinterface = 1; 128b3e95d4eSJonathan Lemon SYSCTL_INT(_net_inet_ip, OID_AUTO, check_interface, CTLFLAG_RW, 129b3e95d4eSJonathan Lemon &ip_checkinterface, 0, "Verify packet arrives on correct interface"); 130b3e95d4eSJonathan Lemon 131df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1320312fbe9SPoul-Henning Kamp static int ipprintfs = 0; 133df8bae1dSRodney W. Grimes #endif 134df8bae1dSRodney W. Grimes 135df8bae1dSRodney W. Grimes extern struct domain inetdomain; 1366a800098SYoshinobu Inoue extern struct ipprotosw inetsw[]; 137df8bae1dSRodney W. Grimes u_char ip_protox[IPPROTO_MAX]; 1380312fbe9SPoul-Henning Kamp static int ipqmaxlen = IFQ_MAXLEN; 13959562606SGarrett Wollman struct in_ifaddrhead in_ifaddrhead; /* first inet address */ 140afed1375SDavid Greenman SYSCTL_INT(_net_inet_ip, IPCTL_INTRQMAXLEN, intr_queue_maxlen, CTLFLAG_RW, 1413d177f46SBill Fumerola &ipintrq.ifq_maxlen, 0, "Maximum size of the IP input queue"); 1420312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_INTRQDROPS, intr_queue_drops, CTLFLAG_RD, 1433d177f46SBill Fumerola &ipintrq.ifq_drops, 0, "Number of packets dropped from the IP input queue"); 144df8bae1dSRodney W. Grimes 145f23b4c91SGarrett Wollman struct ipstat ipstat; 1466fce01c9SGarrett Wollman SYSCTL_STRUCT(_net_inet_ip, IPCTL_STATS, stats, CTLFLAG_RD, 1473d177f46SBill Fumerola &ipstat, ipstat, "IP statistics (struct ipstat, netinet/ip_var.h)"); 148194a213eSAndrey A. Chernov 149194a213eSAndrey A. Chernov /* Packet reassembly stuff */ 150194a213eSAndrey A. Chernov #define IPREASS_NHASH_LOG2 6 151194a213eSAndrey A. Chernov #define IPREASS_NHASH (1 << IPREASS_NHASH_LOG2) 152194a213eSAndrey A. Chernov #define IPREASS_HMASK (IPREASS_NHASH - 1) 153194a213eSAndrey A. Chernov #define IPREASS_HASH(x,y) \ 154831a80b0SMatthew Dillon (((((x) & 0xF) | ((((x) >> 8) & 0xF) << 4)) ^ (y)) & IPREASS_HMASK) 155194a213eSAndrey A. Chernov 156194a213eSAndrey A. Chernov static struct ipq ipq[IPREASS_NHASH]; 157194a213eSAndrey A. Chernov static int nipq = 0; /* total # of reass queues */ 158194a213eSAndrey A. Chernov static int maxnipq; 159367d34f8SBrian Somers const int ipintrq_present = 1; 160f23b4c91SGarrett Wollman 1610312fbe9SPoul-Henning Kamp #ifdef IPCTL_DEFMTU 1620312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_DEFMTU, mtu, CTLFLAG_RW, 1633d177f46SBill Fumerola &ip_mtu, 0, "Default MTU"); 1640312fbe9SPoul-Henning Kamp #endif 1650312fbe9SPoul-Henning Kamp 1661b968362SDag-Erling Smørgrav #ifdef IPSTEALTH 1671b968362SDag-Erling Smørgrav static int ipstealth = 0; 1681b968362SDag-Erling Smørgrav SYSCTL_INT(_net_inet_ip, OID_AUTO, stealth, CTLFLAG_RW, 1691b968362SDag-Erling Smørgrav &ipstealth, 0, ""); 1701b968362SDag-Erling Smørgrav #endif 1711b968362SDag-Erling Smørgrav 172cfe8b629SGarrett Wollman 17323bf9953SPoul-Henning Kamp /* Firewall hooks */ 17423bf9953SPoul-Henning Kamp ip_fw_chk_t *ip_fw_chk_ptr; 17523bf9953SPoul-Henning Kamp ip_fw_ctl_t *ip_fw_ctl_ptr; 1769fcc0795SLuigi Rizzo int fw_enable = 1 ; 177e7319babSPoul-Henning Kamp 178b715f178SLuigi Rizzo #ifdef DUMMYNET 179b715f178SLuigi Rizzo ip_dn_ctl_t *ip_dn_ctl_ptr; 180b715f178SLuigi Rizzo #endif 181b715f178SLuigi Rizzo 182afed1b49SDarren Reed 183e7319babSPoul-Henning Kamp /* 184df8bae1dSRodney W. Grimes * We need to save the IP options in case a protocol wants to respond 185df8bae1dSRodney W. Grimes * to an incoming packet over the same route if the packet got here 186df8bae1dSRodney W. Grimes * using IP source routing. This allows connection establishment and 187df8bae1dSRodney W. Grimes * maintenance when the remote end is on a network that is not known 188df8bae1dSRodney W. Grimes * to us. 189df8bae1dSRodney W. Grimes */ 1900312fbe9SPoul-Henning Kamp static int ip_nhops = 0; 191df8bae1dSRodney W. Grimes static struct ip_srcrt { 192df8bae1dSRodney W. Grimes struct in_addr dst; /* final destination */ 193df8bae1dSRodney W. Grimes char nop; /* one NOP to align */ 194df8bae1dSRodney W. Grimes char srcopt[IPOPT_OFFSET + 1]; /* OPTVAL, OLEN and OFFSET */ 195df8bae1dSRodney W. Grimes struct in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)]; 196df8bae1dSRodney W. Grimes } ip_srcrt; 197df8bae1dSRodney W. Grimes 198f9e354dfSJulian Elischer struct sockaddr_in *ip_fw_fwd_addr; 199f9e354dfSJulian Elischer 200df8bae1dSRodney W. Grimes static void save_rte __P((u_char *, struct in_addr)); 2010312fbe9SPoul-Henning Kamp static int ip_dooptions __P((struct mbuf *)); 2020312fbe9SPoul-Henning Kamp static void ip_forward __P((struct mbuf *, int)); 2030312fbe9SPoul-Henning Kamp static void ip_freef __P((struct ipq *)); 2048948e4baSArchie Cobbs #ifdef IPDIVERT 2056a800098SYoshinobu Inoue static struct mbuf *ip_reass __P((struct mbuf *, 2068948e4baSArchie Cobbs struct ipq *, struct ipq *, u_int32_t *, u_int16_t *)); 2078948e4baSArchie Cobbs #else 2086a800098SYoshinobu Inoue static struct mbuf *ip_reass __P((struct mbuf *, struct ipq *, struct ipq *)); 2098948e4baSArchie Cobbs #endif 2108948e4baSArchie Cobbs static struct in_ifaddr *ip_rtaddr __P((struct in_addr)); 2110312fbe9SPoul-Henning Kamp static void ipintr __P((void)); 2128948e4baSArchie Cobbs 213df8bae1dSRodney W. Grimes /* 214df8bae1dSRodney W. Grimes * IP initialization: fill in IP protocol switch table. 215df8bae1dSRodney W. Grimes * All protocols not implemented in kernel go to raw IP protocol handler. 216df8bae1dSRodney W. Grimes */ 217df8bae1dSRodney W. Grimes void 218df8bae1dSRodney W. Grimes ip_init() 219df8bae1dSRodney W. Grimes { 2206a800098SYoshinobu Inoue register struct ipprotosw *pr; 221df8bae1dSRodney W. Grimes register int i; 222df8bae1dSRodney W. Grimes 22359562606SGarrett Wollman TAILQ_INIT(&in_ifaddrhead); 2246a800098SYoshinobu Inoue pr = (struct ipprotosw *)pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW); 225df8bae1dSRodney W. Grimes if (pr == 0) 226df8bae1dSRodney W. Grimes panic("ip_init"); 227df8bae1dSRodney W. Grimes for (i = 0; i < IPPROTO_MAX; i++) 228df8bae1dSRodney W. Grimes ip_protox[i] = pr - inetsw; 2296a800098SYoshinobu Inoue for (pr = (struct ipprotosw *)inetdomain.dom_protosw; 2306a800098SYoshinobu Inoue pr < (struct ipprotosw *)inetdomain.dom_protoswNPROTOSW; pr++) 231df8bae1dSRodney W. Grimes if (pr->pr_domain->dom_family == PF_INET && 232df8bae1dSRodney W. Grimes pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) 233df8bae1dSRodney W. Grimes ip_protox[pr->pr_protocol] = pr - inetsw; 234194a213eSAndrey A. Chernov 235194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) 236194a213eSAndrey A. Chernov ipq[i].next = ipq[i].prev = &ipq[i]; 237194a213eSAndrey A. Chernov 238194a213eSAndrey A. Chernov maxnipq = nmbclusters/4; 239194a213eSAndrey A. Chernov 240227ee8a1SPoul-Henning Kamp ip_id = time_second & 0xffff; 241df8bae1dSRodney W. Grimes ipintrq.ifq_maxlen = ipqmaxlen; 242df5e1987SJonathan Lemon mtx_init(&ipintrq.ifq_mtx, "ip_inq", MTX_DEF); 243242c5536SPeter Wemm 244242c5536SPeter Wemm register_netisr(NETISR_IP, ipintr); 245df8bae1dSRodney W. Grimes } 246df8bae1dSRodney W. Grimes 2470312fbe9SPoul-Henning Kamp static struct sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET }; 248f708ef1bSPoul-Henning Kamp static struct route ipforward_rt; 249df8bae1dSRodney W. Grimes 250df8bae1dSRodney W. Grimes /* 251df8bae1dSRodney W. Grimes * Ip input routine. Checksum and byte swap header. If fragmented 252df8bae1dSRodney W. Grimes * try to reassemble. Process options. Pass to next level. 253df8bae1dSRodney W. Grimes */ 254c67b1d17SGarrett Wollman void 255c67b1d17SGarrett Wollman ip_input(struct mbuf *m) 256df8bae1dSRodney W. Grimes { 25723bf9953SPoul-Henning Kamp struct ip *ip; 25823bf9953SPoul-Henning Kamp struct ipq *fp; 2595da9f8faSJosef Karthauser struct in_ifaddr *ia = NULL; 260b6ea1aa5SRuslan Ermilov int i, hlen; 26147c861ecSBrian Somers u_short sum; 2628948e4baSArchie Cobbs u_int16_t divert_cookie; /* firewall cookie */ 2637538a9a0SJonathan Lemon struct in_addr pkt_dst; 2648948e4baSArchie Cobbs #ifdef IPDIVERT 2658948e4baSArchie Cobbs u_int32_t divert_info = 0; /* packet divert/tee info */ 266b715f178SLuigi Rizzo #endif 267b715f178SLuigi Rizzo struct ip_fw_chain *rule = NULL; 268c4ac87eaSDarren Reed #ifdef PFIL_HOOKS 269c4ac87eaSDarren Reed struct packet_filter_hook *pfh; 270c4ac87eaSDarren Reed struct mbuf *m0; 271c4ac87eaSDarren Reed int rv; 272c4ac87eaSDarren Reed #endif /* PFIL_HOOKS */ 273b715f178SLuigi Rizzo 2748948e4baSArchie Cobbs #ifdef IPDIVERT 2758948e4baSArchie Cobbs /* Get and reset firewall cookie */ 2768948e4baSArchie Cobbs divert_cookie = ip_divert_cookie; 2778948e4baSArchie Cobbs ip_divert_cookie = 0; 2788948e4baSArchie Cobbs #else 2798948e4baSArchie Cobbs divert_cookie = 0; 2808948e4baSArchie Cobbs #endif 2818948e4baSArchie Cobbs 282b715f178SLuigi Rizzo #if defined(IPFIREWALL) && defined(DUMMYNET) 283b715f178SLuigi Rizzo /* 284b715f178SLuigi Rizzo * dummynet packet are prepended a vestigial mbuf with 285b715f178SLuigi Rizzo * m_type = MT_DUMMYNET and m_data pointing to the matching 286b715f178SLuigi Rizzo * rule. 287b715f178SLuigi Rizzo */ 288b715f178SLuigi Rizzo if (m->m_type == MT_DUMMYNET) { 289b715f178SLuigi Rizzo rule = (struct ip_fw_chain *)(m->m_data) ; 290b715f178SLuigi Rizzo m = m->m_next ; 291b715f178SLuigi Rizzo ip = mtod(m, struct ip *); 292b715f178SLuigi Rizzo hlen = IP_VHL_HL(ip->ip_vhl) << 2; 293b715f178SLuigi Rizzo goto iphack ; 294b715f178SLuigi Rizzo } else 295b715f178SLuigi Rizzo rule = NULL ; 296b715f178SLuigi Rizzo #endif 297df8bae1dSRodney W. Grimes 298df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 299ed7509acSJulian Elischer if (m == NULL || (m->m_flags & M_PKTHDR) == 0) 30058938916SGarrett Wollman panic("ip_input no HDR"); 301df8bae1dSRodney W. Grimes #endif 302df8bae1dSRodney W. Grimes ipstat.ips_total++; 30358938916SGarrett Wollman 30458938916SGarrett Wollman if (m->m_pkthdr.len < sizeof(struct ip)) 30558938916SGarrett Wollman goto tooshort; 30658938916SGarrett Wollman 307df8bae1dSRodney W. Grimes if (m->m_len < sizeof (struct ip) && 308df8bae1dSRodney W. Grimes (m = m_pullup(m, sizeof (struct ip))) == 0) { 309df8bae1dSRodney W. Grimes ipstat.ips_toosmall++; 310c67b1d17SGarrett Wollman return; 311df8bae1dSRodney W. Grimes } 312df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 31358938916SGarrett Wollman 31458938916SGarrett Wollman if (IP_VHL_V(ip->ip_vhl) != IPVERSION) { 315df8bae1dSRodney W. Grimes ipstat.ips_badvers++; 316df8bae1dSRodney W. Grimes goto bad; 317df8bae1dSRodney W. Grimes } 31858938916SGarrett Wollman 31958938916SGarrett Wollman hlen = IP_VHL_HL(ip->ip_vhl) << 2; 320df8bae1dSRodney W. Grimes if (hlen < sizeof(struct ip)) { /* minimum header length */ 321df8bae1dSRodney W. Grimes ipstat.ips_badhlen++; 322df8bae1dSRodney W. Grimes goto bad; 323df8bae1dSRodney W. Grimes } 324df8bae1dSRodney W. Grimes if (hlen > m->m_len) { 325df8bae1dSRodney W. Grimes if ((m = m_pullup(m, hlen)) == 0) { 326df8bae1dSRodney W. Grimes ipstat.ips_badhlen++; 327c67b1d17SGarrett Wollman return; 328df8bae1dSRodney W. Grimes } 329df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 330df8bae1dSRodney W. Grimes } 331db4f9cc7SJonathan Lemon if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) { 332db4f9cc7SJonathan Lemon sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID); 333db4f9cc7SJonathan Lemon } else { 33458938916SGarrett Wollman if (hlen == sizeof(struct ip)) { 33547c861ecSBrian Somers sum = in_cksum_hdr(ip); 33658938916SGarrett Wollman } else { 33747c861ecSBrian Somers sum = in_cksum(m, hlen); 33858938916SGarrett Wollman } 339db4f9cc7SJonathan Lemon } 34047c861ecSBrian Somers if (sum) { 341df8bae1dSRodney W. Grimes ipstat.ips_badsum++; 342df8bae1dSRodney W. Grimes goto bad; 343df8bae1dSRodney W. Grimes } 344df8bae1dSRodney W. Grimes 345df8bae1dSRodney W. Grimes /* 346df8bae1dSRodney W. Grimes * Convert fields to host representation. 347df8bae1dSRodney W. Grimes */ 348df8bae1dSRodney W. Grimes NTOHS(ip->ip_len); 349df8bae1dSRodney W. Grimes if (ip->ip_len < hlen) { 350df8bae1dSRodney W. Grimes ipstat.ips_badlen++; 351df8bae1dSRodney W. Grimes goto bad; 352df8bae1dSRodney W. Grimes } 353df8bae1dSRodney W. Grimes NTOHS(ip->ip_off); 354df8bae1dSRodney W. Grimes 355df8bae1dSRodney W. Grimes /* 356df8bae1dSRodney W. Grimes * Check that the amount of data in the buffers 357df8bae1dSRodney W. Grimes * is as at least much as the IP header would have us expect. 358df8bae1dSRodney W. Grimes * Trim mbufs if longer than we expect. 359df8bae1dSRodney W. Grimes * Drop packet if shorter than we expect. 360df8bae1dSRodney W. Grimes */ 361df8bae1dSRodney W. Grimes if (m->m_pkthdr.len < ip->ip_len) { 36258938916SGarrett Wollman tooshort: 363df8bae1dSRodney W. Grimes ipstat.ips_tooshort++; 364df8bae1dSRodney W. Grimes goto bad; 365df8bae1dSRodney W. Grimes } 366df8bae1dSRodney W. Grimes if (m->m_pkthdr.len > ip->ip_len) { 367df8bae1dSRodney W. Grimes if (m->m_len == m->m_pkthdr.len) { 368df8bae1dSRodney W. Grimes m->m_len = ip->ip_len; 369df8bae1dSRodney W. Grimes m->m_pkthdr.len = ip->ip_len; 370df8bae1dSRodney W. Grimes } else 371df8bae1dSRodney W. Grimes m_adj(m, ip->ip_len - m->m_pkthdr.len); 372df8bae1dSRodney W. Grimes } 3734dd1662bSUgen J.S. Antsilevich /* 3744dd1662bSUgen J.S. Antsilevich * IpHack's section. 3754dd1662bSUgen J.S. Antsilevich * Right now when no processing on packet has done 3764dd1662bSUgen J.S. Antsilevich * and it is still fresh out of network we do our black 3774dd1662bSUgen J.S. Antsilevich * deals with it. 37893e0e116SJulian Elischer * - Firewall: deny/allow/divert 379fed1c7e9SSøren Schmidt * - Xlate: translate packet's addr/port (NAT). 380b715f178SLuigi Rizzo * - Pipe: pass pkt through dummynet. 3814dd1662bSUgen J.S. Antsilevich * - Wrap: fake packet's addr/port <unimpl.> 3824dd1662bSUgen J.S. Antsilevich * - Encapsulate: put it in another IP and send out. <unimp.> 3834dd1662bSUgen J.S. Antsilevich */ 384b715f178SLuigi Rizzo 385dee383e0SEivind Eklund #if defined(IPFIREWALL) && defined(DUMMYNET) 386b715f178SLuigi Rizzo iphack: 387dee383e0SEivind Eklund #endif 388df8bae1dSRodney W. Grimes 389c4ac87eaSDarren Reed #ifdef PFIL_HOOKS 390c4ac87eaSDarren Reed /* 391c4ac87eaSDarren Reed * Run through list of hooks for input packets. If there are any 392c4ac87eaSDarren Reed * filters which require that additional packets in the flow are 393c4ac87eaSDarren Reed * not fast-forwarded, they must clear the M_CANFASTFWD flag. 394c4ac87eaSDarren Reed * Note that filters must _never_ set this flag, as another filter 395c4ac87eaSDarren Reed * in the list may have previously cleared it. 396c4ac87eaSDarren Reed */ 397c4ac87eaSDarren Reed m0 = m; 398c4ac87eaSDarren Reed pfh = pfil_hook_get(PFIL_IN, &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); 399fc2ffbe6SPoul-Henning Kamp for (; pfh; pfh = TAILQ_NEXT(pfh, pfil_link)) 400c4ac87eaSDarren Reed if (pfh->pfil_func) { 401c4ac87eaSDarren Reed rv = pfh->pfil_func(ip, hlen, 402c4ac87eaSDarren Reed m->m_pkthdr.rcvif, 0, &m0); 403c4ac87eaSDarren Reed if (rv) 404beec8214SDarren Reed return; 405c4ac87eaSDarren Reed m = m0; 406c4ac87eaSDarren Reed if (m == NULL) 407c4ac87eaSDarren Reed return; 408c4ac87eaSDarren Reed ip = mtod(m, struct ip *); 409beec8214SDarren Reed } 410c4ac87eaSDarren Reed #endif /* PFIL_HOOKS */ 411c4ac87eaSDarren Reed 4126bc748b0SLuigi Rizzo if (fw_enable && ip_fw_chk_ptr) { 413f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 414f9e354dfSJulian Elischer /* 415f9e354dfSJulian Elischer * If we've been forwarded from the output side, then 416f9e354dfSJulian Elischer * skip the firewall a second time 417f9e354dfSJulian Elischer */ 418f9e354dfSJulian Elischer if (ip_fw_fwd_addr) 419f9e354dfSJulian Elischer goto ours; 420f9e354dfSJulian Elischer #endif /* IPFIREWALL_FORWARD */ 421f9e354dfSJulian Elischer /* 4228948e4baSArchie Cobbs * See the comment in ip_output for the return values 423b715f178SLuigi Rizzo * produced by the firewall. 424f9e354dfSJulian Elischer */ 4258948e4baSArchie Cobbs i = (*ip_fw_chk_ptr)(&ip, 4268948e4baSArchie Cobbs hlen, NULL, &divert_cookie, &m, &rule, &ip_fw_fwd_addr); 427507b4b54SLuigi Rizzo if (i & IP_FW_PORT_DENY_FLAG) { /* XXX new interface-denied */ 428507b4b54SLuigi Rizzo if (m) 429507b4b54SLuigi Rizzo m_freem(m); 430b715f178SLuigi Rizzo return ; 431507b4b54SLuigi Rizzo } 432507b4b54SLuigi Rizzo if (m == NULL) { /* Packet discarded by firewall */ 433507b4b54SLuigi Rizzo static int __debug=10; 434507b4b54SLuigi Rizzo if (__debug >0) { 435507b4b54SLuigi Rizzo printf("firewall returns NULL, please update!\n"); 436507b4b54SLuigi Rizzo __debug-- ; 437507b4b54SLuigi Rizzo } 438507b4b54SLuigi Rizzo return; 439507b4b54SLuigi Rizzo } 440b715f178SLuigi Rizzo if (i == 0 && ip_fw_fwd_addr == NULL) /* common case */ 441b715f178SLuigi Rizzo goto pass; 442b715f178SLuigi Rizzo #ifdef DUMMYNET 4438948e4baSArchie Cobbs if ((i & IP_FW_PORT_DYNT_FLAG) != 0) { 4448948e4baSArchie Cobbs /* Send packet to the appropriate pipe */ 4456a800098SYoshinobu Inoue dummynet_io(i&0xffff,DN_TO_IP_IN,m,NULL,NULL,0, rule, 4466a800098SYoshinobu Inoue 0); 447e4676ba6SJulian Elischer return; 44893e0e116SJulian Elischer } 449b715f178SLuigi Rizzo #endif 450b715f178SLuigi Rizzo #ifdef IPDIVERT 4518948e4baSArchie Cobbs if (i != 0 && (i & IP_FW_PORT_DYNT_FLAG) == 0) { 4528948e4baSArchie Cobbs /* Divert or tee packet */ 4538948e4baSArchie Cobbs divert_info = i; 454b715f178SLuigi Rizzo goto ours; 455b715f178SLuigi Rizzo } 456b715f178SLuigi Rizzo #endif 457b715f178SLuigi Rizzo #ifdef IPFIREWALL_FORWARD 458b715f178SLuigi Rizzo if (i == 0 && ip_fw_fwd_addr != NULL) 459b715f178SLuigi Rizzo goto pass; 460b715f178SLuigi Rizzo #endif 461b715f178SLuigi Rizzo /* 462b715f178SLuigi Rizzo * if we get here, the packet must be dropped 463b715f178SLuigi Rizzo */ 464b715f178SLuigi Rizzo m_freem(m); 465b715f178SLuigi Rizzo return; 466b715f178SLuigi Rizzo } 467b715f178SLuigi Rizzo pass: 468100ba1a6SJordan K. Hubbard 469df8bae1dSRodney W. Grimes /* 470df8bae1dSRodney W. Grimes * Process options and, if not destined for us, 471df8bae1dSRodney W. Grimes * ship it on. ip_dooptions returns 1 when an 472df8bae1dSRodney W. Grimes * error was detected (causing an icmp message 473df8bae1dSRodney W. Grimes * to be sent and the original packet to be freed). 474df8bae1dSRodney W. Grimes */ 475df8bae1dSRodney W. Grimes ip_nhops = 0; /* for source routed packets */ 476ed1ff184SJulian Elischer if (hlen > sizeof (struct ip) && ip_dooptions(m)) { 477ed1ff184SJulian Elischer #ifdef IPFIREWALL_FORWARD 478ed1ff184SJulian Elischer ip_fw_fwd_addr = NULL; 479ed1ff184SJulian Elischer #endif 480c67b1d17SGarrett Wollman return; 481ed1ff184SJulian Elischer } 482df8bae1dSRodney W. Grimes 483f0068c4aSGarrett Wollman /* greedy RSVP, snatches any PATH packet of the RSVP protocol and no 484f0068c4aSGarrett Wollman * matter if it is destined to another node, or whether it is 485f0068c4aSGarrett Wollman * a multicast one, RSVP wants it! and prevents it from being forwarded 486f0068c4aSGarrett Wollman * anywhere else. Also checks if the rsvp daemon is running before 487f0068c4aSGarrett Wollman * grabbing the packet. 488f0068c4aSGarrett Wollman */ 4891c5de19aSGarrett Wollman if (rsvp_on && ip->ip_p==IPPROTO_RSVP) 490f0068c4aSGarrett Wollman goto ours; 491f0068c4aSGarrett Wollman 492df8bae1dSRodney W. Grimes /* 493df8bae1dSRodney W. Grimes * Check our list of addresses, to see if the packet is for us. 494cc766e04SGarrett Wollman * If we don't have any addresses, assume any unicast packet 495cc766e04SGarrett Wollman * we receive might be for us (and let the upper layers deal 496cc766e04SGarrett Wollman * with it). 497df8bae1dSRodney W. Grimes */ 498cc766e04SGarrett Wollman if (TAILQ_EMPTY(&in_ifaddrhead) && 499cc766e04SGarrett Wollman (m->m_flags & (M_MCAST|M_BCAST)) == 0) 500cc766e04SGarrett Wollman goto ours; 501cc766e04SGarrett Wollman 5027538a9a0SJonathan Lemon /* 5037538a9a0SJonathan Lemon * Cache the destination address of the packet; this may be 5047538a9a0SJonathan Lemon * changed by use of 'ipfw fwd'. 5057538a9a0SJonathan Lemon */ 5067538a9a0SJonathan Lemon pkt_dst = ip_fw_fwd_addr == NULL ? 5077538a9a0SJonathan Lemon ip->ip_dst : ip_fw_fwd_addr->sin_addr; 5087538a9a0SJonathan Lemon 50937d40066SPoul-Henning Kamp TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) { 510df8bae1dSRodney W. Grimes #define satosin(sa) ((struct sockaddr_in *)(sa)) 511df8bae1dSRodney W. Grimes 512432aad0eSTor Egge #ifdef BOOTP_COMPAT 513432aad0eSTor Egge if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY) 514432aad0eSTor Egge goto ours; 515432aad0eSTor Egge #endif 516f9e354dfSJulian Elischer /* 5177538a9a0SJonathan Lemon * check that the packet is either arriving from the 5187538a9a0SJonathan Lemon * correct interface or is locally generated. 519f9e354dfSJulian Elischer */ 520b3e95d4eSJonathan Lemon if (ia->ia_ifp != m->m_pkthdr.rcvif && ip_checkinterface && 5217538a9a0SJonathan Lemon (m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) 5227538a9a0SJonathan Lemon continue; 5237538a9a0SJonathan Lemon 5247538a9a0SJonathan Lemon if (IA_SIN(ia)->sin_addr.s_addr == pkt_dst.s_addr) 525ed1ff184SJulian Elischer goto ours; 5267538a9a0SJonathan Lemon 5276ed666afSPoul-Henning Kamp if (ia->ia_ifp && ia->ia_ifp->if_flags & IFF_BROADCAST) { 528df8bae1dSRodney W. Grimes if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == 5297538a9a0SJonathan Lemon pkt_dst.s_addr) 530df8bae1dSRodney W. Grimes goto ours; 5317538a9a0SJonathan Lemon if (ia->ia_netbroadcast.s_addr == pkt_dst.s_addr) 532df8bae1dSRodney W. Grimes goto ours; 533df8bae1dSRodney W. Grimes } 534df8bae1dSRodney W. Grimes } 535df8bae1dSRodney W. Grimes if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { 536df8bae1dSRodney W. Grimes struct in_multi *inm; 537df8bae1dSRodney W. Grimes if (ip_mrouter) { 538df8bae1dSRodney W. Grimes /* 539df8bae1dSRodney W. Grimes * If we are acting as a multicast router, all 540df8bae1dSRodney W. Grimes * incoming multicast packets are passed to the 541df8bae1dSRodney W. Grimes * kernel-level multicast forwarding function. 542df8bae1dSRodney W. Grimes * The packet is returned (relatively) intact; if 543df8bae1dSRodney W. Grimes * ip_mforward() returns a non-zero value, the packet 544df8bae1dSRodney W. Grimes * must be discarded, else it may be accepted below. 545df8bae1dSRodney W. Grimes */ 546f0068c4aSGarrett Wollman if (ip_mforward(ip, m->m_pkthdr.rcvif, m, 0) != 0) { 547df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 548df8bae1dSRodney W. Grimes m_freem(m); 549c67b1d17SGarrett Wollman return; 550df8bae1dSRodney W. Grimes } 551df8bae1dSRodney W. Grimes 552df8bae1dSRodney W. Grimes /* 553df8bae1dSRodney W. Grimes * The process-level routing demon needs to receive 554df8bae1dSRodney W. Grimes * all multicast IGMP packets, whether or not this 555df8bae1dSRodney W. Grimes * host belongs to their destination groups. 556df8bae1dSRodney W. Grimes */ 557df8bae1dSRodney W. Grimes if (ip->ip_p == IPPROTO_IGMP) 558df8bae1dSRodney W. Grimes goto ours; 559df8bae1dSRodney W. Grimes ipstat.ips_forward++; 560df8bae1dSRodney W. Grimes } 561df8bae1dSRodney W. Grimes /* 562df8bae1dSRodney W. Grimes * See if we belong to the destination multicast group on the 563df8bae1dSRodney W. Grimes * arrival interface. 564df8bae1dSRodney W. Grimes */ 565df8bae1dSRodney W. Grimes IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm); 566df8bae1dSRodney W. Grimes if (inm == NULL) { 56782c39223SGarrett Wollman ipstat.ips_notmember++; 568df8bae1dSRodney W. Grimes m_freem(m); 569c67b1d17SGarrett Wollman return; 570df8bae1dSRodney W. Grimes } 571df8bae1dSRodney W. Grimes goto ours; 572df8bae1dSRodney W. Grimes } 573df8bae1dSRodney W. Grimes if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST) 574df8bae1dSRodney W. Grimes goto ours; 575df8bae1dSRodney W. Grimes if (ip->ip_dst.s_addr == INADDR_ANY) 576df8bae1dSRodney W. Grimes goto ours; 577df8bae1dSRodney W. Grimes 5786a800098SYoshinobu Inoue #if defined(NFAITH) && 0 < NFAITH 5796a800098SYoshinobu Inoue /* 5806a800098SYoshinobu Inoue * FAITH(Firewall Aided Internet Translator) 5816a800098SYoshinobu Inoue */ 5826a800098SYoshinobu Inoue if (m->m_pkthdr.rcvif && m->m_pkthdr.rcvif->if_type == IFT_FAITH) { 5836a800098SYoshinobu Inoue if (ip_keepfaith) { 5846a800098SYoshinobu Inoue if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_ICMP) 5856a800098SYoshinobu Inoue goto ours; 5866a800098SYoshinobu Inoue } 5876a800098SYoshinobu Inoue m_freem(m); 5886a800098SYoshinobu Inoue return; 5896a800098SYoshinobu Inoue } 5906a800098SYoshinobu Inoue #endif 591df8bae1dSRodney W. Grimes /* 592df8bae1dSRodney W. Grimes * Not for us; forward if possible and desirable. 593df8bae1dSRodney W. Grimes */ 594df8bae1dSRodney W. Grimes if (ipforwarding == 0) { 595df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 596df8bae1dSRodney W. Grimes m_freem(m); 597df8bae1dSRodney W. Grimes } else 598df8bae1dSRodney W. Grimes ip_forward(m, 0); 599ed1ff184SJulian Elischer #ifdef IPFIREWALL_FORWARD 600ed1ff184SJulian Elischer ip_fw_fwd_addr = NULL; 601ed1ff184SJulian Elischer #endif 602c67b1d17SGarrett Wollman return; 603df8bae1dSRodney W. Grimes 604df8bae1dSRodney W. Grimes ours: 6055da9f8faSJosef Karthauser /* Count the packet in the ip address stats */ 6065da9f8faSJosef Karthauser if (ia != NULL) { 6075da9f8faSJosef Karthauser ia->ia_ifa.if_ipackets++; 6085da9f8faSJosef Karthauser ia->ia_ifa.if_ibytes += m->m_pkthdr.len; 6095da9f8faSJosef Karthauser } 610100ba1a6SJordan K. Hubbard 61163f8d699SJordan K. Hubbard /* 612df8bae1dSRodney W. Grimes * If offset or IP_MF are set, must reassemble. 613df8bae1dSRodney W. Grimes * Otherwise, nothing need be done. 614df8bae1dSRodney W. Grimes * (We could look in the reassembly queue to see 615df8bae1dSRodney W. Grimes * if the packet was previously fragmented, 616df8bae1dSRodney W. Grimes * but it's not worth the time; just let them time out.) 617df8bae1dSRodney W. Grimes */ 618b6ea1aa5SRuslan Ermilov if (ip->ip_off & (IP_MF | IP_OFFMASK)) { 6196a800098SYoshinobu Inoue 620194a213eSAndrey A. Chernov sum = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id); 621df8bae1dSRodney W. Grimes /* 622df8bae1dSRodney W. Grimes * Look for queue of fragments 623df8bae1dSRodney W. Grimes * of this datagram. 624df8bae1dSRodney W. Grimes */ 625194a213eSAndrey A. Chernov for (fp = ipq[sum].next; fp != &ipq[sum]; fp = fp->next) 626df8bae1dSRodney W. Grimes if (ip->ip_id == fp->ipq_id && 627df8bae1dSRodney W. Grimes ip->ip_src.s_addr == fp->ipq_src.s_addr && 628df8bae1dSRodney W. Grimes ip->ip_dst.s_addr == fp->ipq_dst.s_addr && 629df8bae1dSRodney W. Grimes ip->ip_p == fp->ipq_p) 630df8bae1dSRodney W. Grimes goto found; 631df8bae1dSRodney W. Grimes 632194a213eSAndrey A. Chernov fp = 0; 633194a213eSAndrey A. Chernov 634194a213eSAndrey A. Chernov /* check if there's a place for the new queue */ 635194a213eSAndrey A. Chernov if (nipq > maxnipq) { 636194a213eSAndrey A. Chernov /* 637194a213eSAndrey A. Chernov * drop something from the tail of the current queue 638194a213eSAndrey A. Chernov * before proceeding further 639194a213eSAndrey A. Chernov */ 640194a213eSAndrey A. Chernov if (ipq[sum].prev == &ipq[sum]) { /* gak */ 641194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 642194a213eSAndrey A. Chernov if (ipq[i].prev != &ipq[i]) { 643194a213eSAndrey A. Chernov ip_freef(ipq[i].prev); 644194a213eSAndrey A. Chernov break; 645194a213eSAndrey A. Chernov } 646194a213eSAndrey A. Chernov } 647194a213eSAndrey A. Chernov } else 648194a213eSAndrey A. Chernov ip_freef(ipq[sum].prev); 649194a213eSAndrey A. Chernov } 650194a213eSAndrey A. Chernov found: 651df8bae1dSRodney W. Grimes /* 652df8bae1dSRodney W. Grimes * Adjust ip_len to not reflect header, 653df8bae1dSRodney W. Grimes * convert offset of this to bytes. 654df8bae1dSRodney W. Grimes */ 655df8bae1dSRodney W. Grimes ip->ip_len -= hlen; 656b6ea1aa5SRuslan Ermilov if (ip->ip_off & IP_MF) { 6576effc713SDoug Rabson /* 6586effc713SDoug Rabson * Make sure that fragments have a data length 6596effc713SDoug Rabson * that's a non-zero multiple of 8 bytes. 6606effc713SDoug Rabson */ 6616effc713SDoug Rabson if (ip->ip_len == 0 || (ip->ip_len & 0x7) != 0) { 6626effc713SDoug Rabson ipstat.ips_toosmall++; /* XXX */ 6636effc713SDoug Rabson goto bad; 6646effc713SDoug Rabson } 6656effc713SDoug Rabson m->m_flags |= M_FRAG; 6666effc713SDoug Rabson } 667df8bae1dSRodney W. Grimes ip->ip_off <<= 3; 668df8bae1dSRodney W. Grimes 669df8bae1dSRodney W. Grimes /* 670b6ea1aa5SRuslan Ermilov * Attempt reassembly; if it succeeds, proceed. 671df8bae1dSRodney W. Grimes */ 672df8bae1dSRodney W. Grimes ipstat.ips_fragments++; 673487bdb38SRuslan Ermilov m->m_pkthdr.header = ip; 6748948e4baSArchie Cobbs #ifdef IPDIVERT 6756a800098SYoshinobu Inoue m = ip_reass(m, 6768948e4baSArchie Cobbs fp, &ipq[sum], &divert_info, &divert_cookie); 6778948e4baSArchie Cobbs #else 6786a800098SYoshinobu Inoue m = ip_reass(m, fp, &ipq[sum]); 6798948e4baSArchie Cobbs #endif 6806a800098SYoshinobu Inoue if (m == 0) { 681f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 682f9e354dfSJulian Elischer ip_fw_fwd_addr = NULL; 683f9e354dfSJulian Elischer #endif 684c67b1d17SGarrett Wollman return; 685f9e354dfSJulian Elischer } 686df8bae1dSRodney W. Grimes ipstat.ips_reassembled++; 6876a800098SYoshinobu Inoue ip = mtod(m, struct ip *); 6887e2df452SRuslan Ermilov /* Get the header length of the reassembled packet */ 6897e2df452SRuslan Ermilov hlen = IP_VHL_HL(ip->ip_vhl) << 2; 690af782f1cSBrian Somers #ifdef IPDIVERT 6918948e4baSArchie Cobbs /* Restore original checksum before diverting packet */ 6928948e4baSArchie Cobbs if (divert_info != 0) { 693af782f1cSBrian Somers ip->ip_len += hlen; 694af782f1cSBrian Somers HTONS(ip->ip_len); 695af782f1cSBrian Somers HTONS(ip->ip_off); 696af782f1cSBrian Somers ip->ip_sum = 0; 69760123168SRuslan Ermilov if (hlen == sizeof(struct ip)) 698af782f1cSBrian Somers ip->ip_sum = in_cksum_hdr(ip); 69960123168SRuslan Ermilov else 70060123168SRuslan Ermilov ip->ip_sum = in_cksum(m, hlen); 701af782f1cSBrian Somers NTOHS(ip->ip_off); 702af782f1cSBrian Somers NTOHS(ip->ip_len); 703af782f1cSBrian Somers ip->ip_len -= hlen; 704af782f1cSBrian Somers } 705af782f1cSBrian Somers #endif 706df8bae1dSRodney W. Grimes } else 707df8bae1dSRodney W. Grimes ip->ip_len -= hlen; 708df8bae1dSRodney W. Grimes 70993e0e116SJulian Elischer #ifdef IPDIVERT 71093e0e116SJulian Elischer /* 7118948e4baSArchie Cobbs * Divert or tee packet to the divert protocol if required. 7128948e4baSArchie Cobbs * 7138948e4baSArchie Cobbs * If divert_info is zero then cookie should be too, so we shouldn't 7148948e4baSArchie Cobbs * need to clear them here. Assume divert_packet() does so also. 71593e0e116SJulian Elischer */ 7168948e4baSArchie Cobbs if (divert_info != 0) { 7178948e4baSArchie Cobbs struct mbuf *clone = NULL; 7188948e4baSArchie Cobbs 7198948e4baSArchie Cobbs /* Clone packet if we're doing a 'tee' */ 7208948e4baSArchie Cobbs if ((divert_info & IP_FW_PORT_TEE_FLAG) != 0) 7218948e4baSArchie Cobbs clone = m_dup(m, M_DONTWAIT); 7228948e4baSArchie Cobbs 7238948e4baSArchie Cobbs /* Restore packet header fields to original values */ 7248948e4baSArchie Cobbs ip->ip_len += hlen; 7258948e4baSArchie Cobbs HTONS(ip->ip_len); 7268948e4baSArchie Cobbs HTONS(ip->ip_off); 7278948e4baSArchie Cobbs 7288948e4baSArchie Cobbs /* Deliver packet to divert input routine */ 7298948e4baSArchie Cobbs ip_divert_cookie = divert_cookie; 7308948e4baSArchie Cobbs divert_packet(m, 1, divert_info & 0xffff); 731e4676ba6SJulian Elischer ipstat.ips_delivered++; 7328948e4baSArchie Cobbs 7338948e4baSArchie Cobbs /* If 'tee', continue with original packet */ 7348948e4baSArchie Cobbs if (clone == NULL) 73593e0e116SJulian Elischer return; 7368948e4baSArchie Cobbs m = clone; 7378948e4baSArchie Cobbs ip = mtod(m, struct ip *); 73893e0e116SJulian Elischer } 73993e0e116SJulian Elischer #endif 74093e0e116SJulian Elischer 741df8bae1dSRodney W. Grimes /* 742df8bae1dSRodney W. Grimes * Switch out to protocol's input routine. 743df8bae1dSRodney W. Grimes */ 744df8bae1dSRodney W. Grimes ipstat.ips_delivered++; 7456a800098SYoshinobu Inoue { 7466a800098SYoshinobu Inoue int off = hlen, nh = ip->ip_p; 7476a800098SYoshinobu Inoue 7486a800098SYoshinobu Inoue (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, off, nh); 749f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 750f9e354dfSJulian Elischer ip_fw_fwd_addr = NULL; /* tcp needed it */ 751f9e354dfSJulian Elischer #endif 752c67b1d17SGarrett Wollman return; 7536a800098SYoshinobu Inoue } 754df8bae1dSRodney W. Grimes bad: 755f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 756f9e354dfSJulian Elischer ip_fw_fwd_addr = NULL; 757f9e354dfSJulian Elischer #endif 758df8bae1dSRodney W. Grimes m_freem(m); 759c67b1d17SGarrett Wollman } 760c67b1d17SGarrett Wollman 761c67b1d17SGarrett Wollman /* 762c67b1d17SGarrett Wollman * IP software interrupt routine - to go away sometime soon 763c67b1d17SGarrett Wollman */ 764c67b1d17SGarrett Wollman static void 765c67b1d17SGarrett Wollman ipintr(void) 766c67b1d17SGarrett Wollman { 767c67b1d17SGarrett Wollman struct mbuf *m; 768c67b1d17SGarrett Wollman 769c67b1d17SGarrett Wollman while (1) { 770c67b1d17SGarrett Wollman IF_DEQUEUE(&ipintrq, m); 771c67b1d17SGarrett Wollman if (m == 0) 772c67b1d17SGarrett Wollman return; 773c67b1d17SGarrett Wollman ip_input(m); 774c67b1d17SGarrett Wollman } 775df8bae1dSRodney W. Grimes } 776df8bae1dSRodney W. Grimes 777df8bae1dSRodney W. Grimes /* 7788948e4baSArchie Cobbs * Take incoming datagram fragment and try to reassemble it into 7798948e4baSArchie Cobbs * whole datagram. If a chain for reassembly of this datagram already 7808948e4baSArchie Cobbs * exists, then it is given as fp; otherwise have to make a chain. 7818948e4baSArchie Cobbs * 7828948e4baSArchie Cobbs * When IPDIVERT enabled, keep additional state with each packet that 7838948e4baSArchie Cobbs * tells us if we need to divert or tee the packet we're building. 784df8bae1dSRodney W. Grimes */ 7858948e4baSArchie Cobbs 7866a800098SYoshinobu Inoue static struct mbuf * 7878948e4baSArchie Cobbs #ifdef IPDIVERT 7888948e4baSArchie Cobbs ip_reass(m, fp, where, divinfo, divcookie) 7898948e4baSArchie Cobbs #else 7906effc713SDoug Rabson ip_reass(m, fp, where) 7918948e4baSArchie Cobbs #endif 7926effc713SDoug Rabson register struct mbuf *m; 793df8bae1dSRodney W. Grimes register struct ipq *fp; 794194a213eSAndrey A. Chernov struct ipq *where; 7958948e4baSArchie Cobbs #ifdef IPDIVERT 7968948e4baSArchie Cobbs u_int32_t *divinfo; 7978948e4baSArchie Cobbs u_int16_t *divcookie; 7988948e4baSArchie Cobbs #endif 799df8bae1dSRodney W. Grimes { 8006effc713SDoug Rabson struct ip *ip = mtod(m, struct ip *); 801b6ea1aa5SRuslan Ermilov register struct mbuf *p, *q, *nq; 802df8bae1dSRodney W. Grimes struct mbuf *t; 8036effc713SDoug Rabson int hlen = IP_VHL_HL(ip->ip_vhl) << 2; 804df8bae1dSRodney W. Grimes int i, next; 805df8bae1dSRodney W. Grimes 806df8bae1dSRodney W. Grimes /* 807df8bae1dSRodney W. Grimes * Presence of header sizes in mbufs 808df8bae1dSRodney W. Grimes * would confuse code below. 809df8bae1dSRodney W. Grimes */ 810df8bae1dSRodney W. Grimes m->m_data += hlen; 811df8bae1dSRodney W. Grimes m->m_len -= hlen; 812df8bae1dSRodney W. Grimes 813df8bae1dSRodney W. Grimes /* 814df8bae1dSRodney W. Grimes * If first fragment to arrive, create a reassembly queue. 815df8bae1dSRodney W. Grimes */ 816df8bae1dSRodney W. Grimes if (fp == 0) { 817df8bae1dSRodney W. Grimes if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL) 818df8bae1dSRodney W. Grimes goto dropfrag; 819df8bae1dSRodney W. Grimes fp = mtod(t, struct ipq *); 820194a213eSAndrey A. Chernov insque(fp, where); 821194a213eSAndrey A. Chernov nipq++; 822df8bae1dSRodney W. Grimes fp->ipq_ttl = IPFRAGTTL; 823df8bae1dSRodney W. Grimes fp->ipq_p = ip->ip_p; 824df8bae1dSRodney W. Grimes fp->ipq_id = ip->ip_id; 8256effc713SDoug Rabson fp->ipq_src = ip->ip_src; 8266effc713SDoug Rabson fp->ipq_dst = ip->ip_dst; 827af38c68cSLuigi Rizzo fp->ipq_frags = m; 828af38c68cSLuigi Rizzo m->m_nextpkt = NULL; 82993e0e116SJulian Elischer #ifdef IPDIVERT 8308948e4baSArchie Cobbs fp->ipq_div_info = 0; 831bb60f459SJulian Elischer fp->ipq_div_cookie = 0; 83293e0e116SJulian Elischer #endif 833af38c68cSLuigi Rizzo goto inserted; 834df8bae1dSRodney W. Grimes } 835df8bae1dSRodney W. Grimes 8366effc713SDoug Rabson #define GETIP(m) ((struct ip*)((m)->m_pkthdr.header)) 8376effc713SDoug Rabson 838df8bae1dSRodney W. Grimes /* 839df8bae1dSRodney W. Grimes * Find a segment which begins after this one does. 840df8bae1dSRodney W. Grimes */ 8416effc713SDoug Rabson for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) 8426effc713SDoug Rabson if (GETIP(q)->ip_off > ip->ip_off) 843df8bae1dSRodney W. Grimes break; 844df8bae1dSRodney W. Grimes 845df8bae1dSRodney W. Grimes /* 846df8bae1dSRodney W. Grimes * If there is a preceding segment, it may provide some of 847df8bae1dSRodney W. Grimes * our data already. If so, drop the data from the incoming 848af38c68cSLuigi Rizzo * segment. If it provides all of our data, drop us, otherwise 849af38c68cSLuigi Rizzo * stick new segment in the proper place. 850db4f9cc7SJonathan Lemon * 851db4f9cc7SJonathan Lemon * If some of the data is dropped from the the preceding 852db4f9cc7SJonathan Lemon * segment, then it's checksum is invalidated. 853df8bae1dSRodney W. Grimes */ 8546effc713SDoug Rabson if (p) { 8556effc713SDoug Rabson i = GETIP(p)->ip_off + GETIP(p)->ip_len - ip->ip_off; 856df8bae1dSRodney W. Grimes if (i > 0) { 857df8bae1dSRodney W. Grimes if (i >= ip->ip_len) 858df8bae1dSRodney W. Grimes goto dropfrag; 8596a800098SYoshinobu Inoue m_adj(m, i); 860db4f9cc7SJonathan Lemon m->m_pkthdr.csum_flags = 0; 861df8bae1dSRodney W. Grimes ip->ip_off += i; 862df8bae1dSRodney W. Grimes ip->ip_len -= i; 863df8bae1dSRodney W. Grimes } 864af38c68cSLuigi Rizzo m->m_nextpkt = p->m_nextpkt; 865af38c68cSLuigi Rizzo p->m_nextpkt = m; 866af38c68cSLuigi Rizzo } else { 867af38c68cSLuigi Rizzo m->m_nextpkt = fp->ipq_frags; 868af38c68cSLuigi Rizzo fp->ipq_frags = m; 869df8bae1dSRodney W. Grimes } 870df8bae1dSRodney W. Grimes 871df8bae1dSRodney W. Grimes /* 872df8bae1dSRodney W. Grimes * While we overlap succeeding segments trim them or, 873df8bae1dSRodney W. Grimes * if they are completely covered, dequeue them. 874df8bae1dSRodney W. Grimes */ 8756effc713SDoug Rabson for (; q != NULL && ip->ip_off + ip->ip_len > GETIP(q)->ip_off; 876af38c68cSLuigi Rizzo q = nq) { 8776effc713SDoug Rabson i = (ip->ip_off + ip->ip_len) - 8786effc713SDoug Rabson GETIP(q)->ip_off; 8796effc713SDoug Rabson if (i < GETIP(q)->ip_len) { 8806effc713SDoug Rabson GETIP(q)->ip_len -= i; 8816effc713SDoug Rabson GETIP(q)->ip_off += i; 8826effc713SDoug Rabson m_adj(q, i); 883db4f9cc7SJonathan Lemon q->m_pkthdr.csum_flags = 0; 884df8bae1dSRodney W. Grimes break; 885df8bae1dSRodney W. Grimes } 8866effc713SDoug Rabson nq = q->m_nextpkt; 887af38c68cSLuigi Rizzo m->m_nextpkt = nq; 8886effc713SDoug Rabson m_freem(q); 889df8bae1dSRodney W. Grimes } 890df8bae1dSRodney W. Grimes 891af38c68cSLuigi Rizzo inserted: 89293e0e116SJulian Elischer 89393e0e116SJulian Elischer #ifdef IPDIVERT 89493e0e116SJulian Elischer /* 8958948e4baSArchie Cobbs * Transfer firewall instructions to the fragment structure. 8968948e4baSArchie Cobbs * Any fragment diverting causes the whole packet to divert. 89793e0e116SJulian Elischer */ 8988948e4baSArchie Cobbs fp->ipq_div_info = *divinfo; 8998948e4baSArchie Cobbs fp->ipq_div_cookie = *divcookie; 9008948e4baSArchie Cobbs *divinfo = 0; 9018948e4baSArchie Cobbs *divcookie = 0; 90293e0e116SJulian Elischer #endif 90393e0e116SJulian Elischer 904df8bae1dSRodney W. Grimes /* 905af38c68cSLuigi Rizzo * Check for complete reassembly. 906df8bae1dSRodney W. Grimes */ 9076effc713SDoug Rabson next = 0; 9086effc713SDoug Rabson for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) { 9096effc713SDoug Rabson if (GETIP(q)->ip_off != next) 9106effc713SDoug Rabson return (0); 9116effc713SDoug Rabson next += GETIP(q)->ip_len; 9126effc713SDoug Rabson } 9136effc713SDoug Rabson /* Make sure the last packet didn't have the IP_MF flag */ 9146effc713SDoug Rabson if (p->m_flags & M_FRAG) 915df8bae1dSRodney W. Grimes return (0); 916df8bae1dSRodney W. Grimes 917df8bae1dSRodney W. Grimes /* 918430d30d8SBill Fenner * Reassembly is complete. Make sure the packet is a sane size. 919430d30d8SBill Fenner */ 9206effc713SDoug Rabson q = fp->ipq_frags; 9216effc713SDoug Rabson ip = GETIP(q); 9226effc713SDoug Rabson if (next + (IP_VHL_HL(ip->ip_vhl) << 2) > IP_MAXPACKET) { 923430d30d8SBill Fenner ipstat.ips_toolong++; 924430d30d8SBill Fenner ip_freef(fp); 925430d30d8SBill Fenner return (0); 926430d30d8SBill Fenner } 927430d30d8SBill Fenner 928430d30d8SBill Fenner /* 929430d30d8SBill Fenner * Concatenate fragments. 930df8bae1dSRodney W. Grimes */ 9316effc713SDoug Rabson m = q; 932df8bae1dSRodney W. Grimes t = m->m_next; 933df8bae1dSRodney W. Grimes m->m_next = 0; 934df8bae1dSRodney W. Grimes m_cat(m, t); 9356effc713SDoug Rabson nq = q->m_nextpkt; 936945aa40dSDoug Rabson q->m_nextpkt = 0; 9376effc713SDoug Rabson for (q = nq; q != NULL; q = nq) { 9386effc713SDoug Rabson nq = q->m_nextpkt; 939945aa40dSDoug Rabson q->m_nextpkt = NULL; 940db4f9cc7SJonathan Lemon m->m_pkthdr.csum_flags &= q->m_pkthdr.csum_flags; 941db4f9cc7SJonathan Lemon m->m_pkthdr.csum_data += q->m_pkthdr.csum_data; 942a8db1d93SJonathan Lemon m_cat(m, q); 943df8bae1dSRodney W. Grimes } 944df8bae1dSRodney W. Grimes 94593e0e116SJulian Elischer #ifdef IPDIVERT 94693e0e116SJulian Elischer /* 9478948e4baSArchie Cobbs * Extract firewall instructions from the fragment structure. 94893e0e116SJulian Elischer */ 9498948e4baSArchie Cobbs *divinfo = fp->ipq_div_info; 9508948e4baSArchie Cobbs *divcookie = fp->ipq_div_cookie; 95193e0e116SJulian Elischer #endif 95293e0e116SJulian Elischer 953df8bae1dSRodney W. Grimes /* 954df8bae1dSRodney W. Grimes * Create header for new ip packet by 955df8bae1dSRodney W. Grimes * modifying header of first packet; 956df8bae1dSRodney W. Grimes * dequeue and discard fragment reassembly header. 957df8bae1dSRodney W. Grimes * Make header visible. 958df8bae1dSRodney W. Grimes */ 959df8bae1dSRodney W. Grimes ip->ip_len = next; 9606effc713SDoug Rabson ip->ip_src = fp->ipq_src; 9616effc713SDoug Rabson ip->ip_dst = fp->ipq_dst; 962df8bae1dSRodney W. Grimes remque(fp); 963194a213eSAndrey A. Chernov nipq--; 964df8bae1dSRodney W. Grimes (void) m_free(dtom(fp)); 9656effc713SDoug Rabson m->m_len += (IP_VHL_HL(ip->ip_vhl) << 2); 9666effc713SDoug Rabson m->m_data -= (IP_VHL_HL(ip->ip_vhl) << 2); 967df8bae1dSRodney W. Grimes /* some debugging cruft by sklower, below, will go away soon */ 968df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) { /* XXX this should be done elsewhere */ 969df8bae1dSRodney W. Grimes register int plen = 0; 9706a800098SYoshinobu Inoue for (t = m; t; t = t->m_next) 9716a800098SYoshinobu Inoue plen += t->m_len; 9726a800098SYoshinobu Inoue m->m_pkthdr.len = plen; 973df8bae1dSRodney W. Grimes } 9746a800098SYoshinobu Inoue return (m); 975df8bae1dSRodney W. Grimes 976df8bae1dSRodney W. Grimes dropfrag: 977efe39c6aSJulian Elischer #ifdef IPDIVERT 9788948e4baSArchie Cobbs *divinfo = 0; 9798948e4baSArchie Cobbs *divcookie = 0; 980efe39c6aSJulian Elischer #endif 981df8bae1dSRodney W. Grimes ipstat.ips_fragdropped++; 982df8bae1dSRodney W. Grimes m_freem(m); 983df8bae1dSRodney W. Grimes return (0); 9846effc713SDoug Rabson 9856effc713SDoug Rabson #undef GETIP 986df8bae1dSRodney W. Grimes } 987df8bae1dSRodney W. Grimes 988df8bae1dSRodney W. Grimes /* 989df8bae1dSRodney W. Grimes * Free a fragment reassembly header and all 990df8bae1dSRodney W. Grimes * associated datagrams. 991df8bae1dSRodney W. Grimes */ 9920312fbe9SPoul-Henning Kamp static void 993df8bae1dSRodney W. Grimes ip_freef(fp) 994df8bae1dSRodney W. Grimes struct ipq *fp; 995df8bae1dSRodney W. Grimes { 9966effc713SDoug Rabson register struct mbuf *q; 997df8bae1dSRodney W. Grimes 9986effc713SDoug Rabson while (fp->ipq_frags) { 9996effc713SDoug Rabson q = fp->ipq_frags; 10006effc713SDoug Rabson fp->ipq_frags = q->m_nextpkt; 10016effc713SDoug Rabson m_freem(q); 1002df8bae1dSRodney W. Grimes } 1003df8bae1dSRodney W. Grimes remque(fp); 1004df8bae1dSRodney W. Grimes (void) m_free(dtom(fp)); 1005194a213eSAndrey A. Chernov nipq--; 1006df8bae1dSRodney W. Grimes } 1007df8bae1dSRodney W. Grimes 1008df8bae1dSRodney W. Grimes /* 1009df8bae1dSRodney W. Grimes * IP timer processing; 1010df8bae1dSRodney W. Grimes * if a timer expires on a reassembly 1011df8bae1dSRodney W. Grimes * queue, discard it. 1012df8bae1dSRodney W. Grimes */ 1013df8bae1dSRodney W. Grimes void 1014df8bae1dSRodney W. Grimes ip_slowtimo() 1015df8bae1dSRodney W. Grimes { 1016df8bae1dSRodney W. Grimes register struct ipq *fp; 1017df8bae1dSRodney W. Grimes int s = splnet(); 1018194a213eSAndrey A. Chernov int i; 1019df8bae1dSRodney W. Grimes 1020194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 1021194a213eSAndrey A. Chernov fp = ipq[i].next; 1022194a213eSAndrey A. Chernov if (fp == 0) 1023194a213eSAndrey A. Chernov continue; 1024194a213eSAndrey A. Chernov while (fp != &ipq[i]) { 1025df8bae1dSRodney W. Grimes --fp->ipq_ttl; 1026df8bae1dSRodney W. Grimes fp = fp->next; 1027df8bae1dSRodney W. Grimes if (fp->prev->ipq_ttl == 0) { 1028df8bae1dSRodney W. Grimes ipstat.ips_fragtimeout++; 1029df8bae1dSRodney W. Grimes ip_freef(fp->prev); 1030df8bae1dSRodney W. Grimes } 1031df8bae1dSRodney W. Grimes } 1032194a213eSAndrey A. Chernov } 10331f91d8c5SDavid Greenman ipflow_slowtimo(); 1034df8bae1dSRodney W. Grimes splx(s); 1035df8bae1dSRodney W. Grimes } 1036df8bae1dSRodney W. Grimes 1037df8bae1dSRodney W. Grimes /* 1038df8bae1dSRodney W. Grimes * Drain off all datagram fragments. 1039df8bae1dSRodney W. Grimes */ 1040df8bae1dSRodney W. Grimes void 1041df8bae1dSRodney W. Grimes ip_drain() 1042df8bae1dSRodney W. Grimes { 1043194a213eSAndrey A. Chernov int i; 1044ce29ab3aSGarrett Wollman 1045194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 1046194a213eSAndrey A. Chernov while (ipq[i].next != &ipq[i]) { 1047194a213eSAndrey A. Chernov ipstat.ips_fragdropped++; 1048194a213eSAndrey A. Chernov ip_freef(ipq[i].next); 1049194a213eSAndrey A. Chernov } 1050194a213eSAndrey A. Chernov } 1051ce29ab3aSGarrett Wollman in_rtqdrain(); 1052df8bae1dSRodney W. Grimes } 1053df8bae1dSRodney W. Grimes 1054df8bae1dSRodney W. Grimes /* 1055df8bae1dSRodney W. Grimes * Do option processing on a datagram, 1056df8bae1dSRodney W. Grimes * possibly discarding it if bad options are encountered, 1057df8bae1dSRodney W. Grimes * or forwarding it if source-routed. 1058df8bae1dSRodney W. Grimes * Returns 1 if packet has been forwarded/freed, 1059df8bae1dSRodney W. Grimes * 0 if the packet should be processed further. 1060df8bae1dSRodney W. Grimes */ 10610312fbe9SPoul-Henning Kamp static int 1062df8bae1dSRodney W. Grimes ip_dooptions(m) 1063df8bae1dSRodney W. Grimes struct mbuf *m; 1064df8bae1dSRodney W. Grimes { 1065df8bae1dSRodney W. Grimes register struct ip *ip = mtod(m, struct ip *); 1066df8bae1dSRodney W. Grimes register u_char *cp; 1067df8bae1dSRodney W. Grimes register struct ip_timestamp *ipt; 1068df8bae1dSRodney W. Grimes register struct in_ifaddr *ia; 1069df8bae1dSRodney W. Grimes int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0; 1070df8bae1dSRodney W. Grimes struct in_addr *sin, dst; 1071df8bae1dSRodney W. Grimes n_time ntime; 1072df8bae1dSRodney W. Grimes 1073df8bae1dSRodney W. Grimes dst = ip->ip_dst; 1074df8bae1dSRodney W. Grimes cp = (u_char *)(ip + 1); 107558938916SGarrett Wollman cnt = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip); 1076df8bae1dSRodney W. Grimes for (; cnt > 0; cnt -= optlen, cp += optlen) { 1077df8bae1dSRodney W. Grimes opt = cp[IPOPT_OPTVAL]; 1078df8bae1dSRodney W. Grimes if (opt == IPOPT_EOL) 1079df8bae1dSRodney W. Grimes break; 1080df8bae1dSRodney W. Grimes if (opt == IPOPT_NOP) 1081df8bae1dSRodney W. Grimes optlen = 1; 1082df8bae1dSRodney W. Grimes else { 1083fdcb8debSJun-ichiro itojun Hagino if (cnt < IPOPT_OLEN + sizeof(*cp)) { 1084fdcb8debSJun-ichiro itojun Hagino code = &cp[IPOPT_OLEN] - (u_char *)ip; 1085fdcb8debSJun-ichiro itojun Hagino goto bad; 1086fdcb8debSJun-ichiro itojun Hagino } 1087df8bae1dSRodney W. Grimes optlen = cp[IPOPT_OLEN]; 1088707d00a3SJonathan Lemon if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt) { 1089df8bae1dSRodney W. Grimes code = &cp[IPOPT_OLEN] - (u_char *)ip; 1090df8bae1dSRodney W. Grimes goto bad; 1091df8bae1dSRodney W. Grimes } 1092df8bae1dSRodney W. Grimes } 1093df8bae1dSRodney W. Grimes switch (opt) { 1094df8bae1dSRodney W. Grimes 1095df8bae1dSRodney W. Grimes default: 1096df8bae1dSRodney W. Grimes break; 1097df8bae1dSRodney W. Grimes 1098df8bae1dSRodney W. Grimes /* 1099df8bae1dSRodney W. Grimes * Source routing with record. 1100df8bae1dSRodney W. Grimes * Find interface with current destination address. 1101df8bae1dSRodney W. Grimes * If none on this machine then drop if strictly routed, 1102df8bae1dSRodney W. Grimes * or do nothing if loosely routed. 1103df8bae1dSRodney W. Grimes * Record interface address and bring up next address 1104df8bae1dSRodney W. Grimes * component. If strictly routed make sure next 1105df8bae1dSRodney W. Grimes * address is on directly accessible net. 1106df8bae1dSRodney W. Grimes */ 1107df8bae1dSRodney W. Grimes case IPOPT_LSRR: 1108df8bae1dSRodney W. Grimes case IPOPT_SSRR: 1109df8bae1dSRodney W. Grimes if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { 1110df8bae1dSRodney W. Grimes code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1111df8bae1dSRodney W. Grimes goto bad; 1112df8bae1dSRodney W. Grimes } 1113df8bae1dSRodney W. Grimes ipaddr.sin_addr = ip->ip_dst; 1114df8bae1dSRodney W. Grimes ia = (struct in_ifaddr *) 1115df8bae1dSRodney W. Grimes ifa_ifwithaddr((struct sockaddr *)&ipaddr); 1116df8bae1dSRodney W. Grimes if (ia == 0) { 1117df8bae1dSRodney W. Grimes if (opt == IPOPT_SSRR) { 1118df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1119df8bae1dSRodney W. Grimes code = ICMP_UNREACH_SRCFAIL; 1120df8bae1dSRodney W. Grimes goto bad; 1121df8bae1dSRodney W. Grimes } 1122bc189bf8SGuido van Rooij if (!ip_dosourceroute) 1123bc189bf8SGuido van Rooij goto nosourcerouting; 1124df8bae1dSRodney W. Grimes /* 1125df8bae1dSRodney W. Grimes * Loose routing, and not at next destination 1126df8bae1dSRodney W. Grimes * yet; nothing to do except forward. 1127df8bae1dSRodney W. Grimes */ 1128df8bae1dSRodney W. Grimes break; 1129df8bae1dSRodney W. Grimes } 1130df8bae1dSRodney W. Grimes off--; /* 0 origin */ 11315d5d5fc0SJonathan Lemon if (off > optlen - (int)sizeof(struct in_addr)) { 1132df8bae1dSRodney W. Grimes /* 1133df8bae1dSRodney W. Grimes * End of source route. Should be for us. 1134df8bae1dSRodney W. Grimes */ 11354fce5804SGuido van Rooij if (!ip_acceptsourceroute) 11364fce5804SGuido van Rooij goto nosourcerouting; 1137df8bae1dSRodney W. Grimes save_rte(cp, ip->ip_src); 1138df8bae1dSRodney W. Grimes break; 1139df8bae1dSRodney W. Grimes } 11401025071fSGarrett Wollman 11411025071fSGarrett Wollman if (!ip_dosourceroute) { 11420af8d3ecSDavid Greenman if (ipforwarding) { 11430af8d3ecSDavid Greenman char buf[16]; /* aaa.bbb.ccc.ddd\0 */ 11440af8d3ecSDavid Greenman /* 11450af8d3ecSDavid Greenman * Acting as a router, so generate ICMP 11460af8d3ecSDavid Greenman */ 1147efa48587SGuido van Rooij nosourcerouting: 1148bc189bf8SGuido van Rooij strcpy(buf, inet_ntoa(ip->ip_dst)); 11491025071fSGarrett Wollman log(LOG_WARNING, 11501025071fSGarrett Wollman "attempted source route from %s to %s\n", 11511025071fSGarrett Wollman inet_ntoa(ip->ip_src), buf); 11521025071fSGarrett Wollman type = ICMP_UNREACH; 11531025071fSGarrett Wollman code = ICMP_UNREACH_SRCFAIL; 11541025071fSGarrett Wollman goto bad; 11550af8d3ecSDavid Greenman } else { 11560af8d3ecSDavid Greenman /* 11570af8d3ecSDavid Greenman * Not acting as a router, so silently drop. 11580af8d3ecSDavid Greenman */ 11590af8d3ecSDavid Greenman ipstat.ips_cantforward++; 11600af8d3ecSDavid Greenman m_freem(m); 11610af8d3ecSDavid Greenman return (1); 11620af8d3ecSDavid Greenman } 11631025071fSGarrett Wollman } 11641025071fSGarrett Wollman 1165df8bae1dSRodney W. Grimes /* 1166df8bae1dSRodney W. Grimes * locate outgoing interface 1167df8bae1dSRodney W. Grimes */ 116894a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, cp + off, 1169df8bae1dSRodney W. Grimes sizeof(ipaddr.sin_addr)); 11701025071fSGarrett Wollman 1171df8bae1dSRodney W. Grimes if (opt == IPOPT_SSRR) { 1172df8bae1dSRodney W. Grimes #define INA struct in_ifaddr * 1173df8bae1dSRodney W. Grimes #define SA struct sockaddr * 1174df8bae1dSRodney W. Grimes if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0) 1175df8bae1dSRodney W. Grimes ia = (INA)ifa_ifwithnet((SA)&ipaddr); 1176df8bae1dSRodney W. Grimes } else 1177df8bae1dSRodney W. Grimes ia = ip_rtaddr(ipaddr.sin_addr); 1178df8bae1dSRodney W. Grimes if (ia == 0) { 1179df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1180df8bae1dSRodney W. Grimes code = ICMP_UNREACH_SRCFAIL; 1181df8bae1dSRodney W. Grimes goto bad; 1182df8bae1dSRodney W. Grimes } 1183df8bae1dSRodney W. Grimes ip->ip_dst = ipaddr.sin_addr; 118494a5d9b6SDavid Greenman (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr), 118594a5d9b6SDavid Greenman sizeof(struct in_addr)); 1186df8bae1dSRodney W. Grimes cp[IPOPT_OFFSET] += sizeof(struct in_addr); 1187df8bae1dSRodney W. Grimes /* 1188df8bae1dSRodney W. Grimes * Let ip_intr's mcast routing check handle mcast pkts 1189df8bae1dSRodney W. Grimes */ 1190df8bae1dSRodney W. Grimes forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr)); 1191df8bae1dSRodney W. Grimes break; 1192df8bae1dSRodney W. Grimes 1193df8bae1dSRodney W. Grimes case IPOPT_RR: 1194707d00a3SJonathan Lemon if (optlen < IPOPT_OFFSET + sizeof(*cp)) { 1195707d00a3SJonathan Lemon code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1196707d00a3SJonathan Lemon goto bad; 1197707d00a3SJonathan Lemon } 1198df8bae1dSRodney W. Grimes if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { 1199df8bae1dSRodney W. Grimes code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1200df8bae1dSRodney W. Grimes goto bad; 1201df8bae1dSRodney W. Grimes } 1202df8bae1dSRodney W. Grimes /* 1203df8bae1dSRodney W. Grimes * If no space remains, ignore. 1204df8bae1dSRodney W. Grimes */ 1205df8bae1dSRodney W. Grimes off--; /* 0 origin */ 12065d5d5fc0SJonathan Lemon if (off > optlen - (int)sizeof(struct in_addr)) 1207df8bae1dSRodney W. Grimes break; 120894a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, &ip->ip_dst, 1209df8bae1dSRodney W. Grimes sizeof(ipaddr.sin_addr)); 1210df8bae1dSRodney W. Grimes /* 1211df8bae1dSRodney W. Grimes * locate outgoing interface; if we're the destination, 1212df8bae1dSRodney W. Grimes * use the incoming interface (should be same). 1213df8bae1dSRodney W. Grimes */ 1214df8bae1dSRodney W. Grimes if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 && 1215df8bae1dSRodney W. Grimes (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) { 1216df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1217df8bae1dSRodney W. Grimes code = ICMP_UNREACH_HOST; 1218df8bae1dSRodney W. Grimes goto bad; 1219df8bae1dSRodney W. Grimes } 122094a5d9b6SDavid Greenman (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr), 122194a5d9b6SDavid Greenman sizeof(struct in_addr)); 1222df8bae1dSRodney W. Grimes cp[IPOPT_OFFSET] += sizeof(struct in_addr); 1223df8bae1dSRodney W. Grimes break; 1224df8bae1dSRodney W. Grimes 1225df8bae1dSRodney W. Grimes case IPOPT_TS: 1226df8bae1dSRodney W. Grimes code = cp - (u_char *)ip; 1227df8bae1dSRodney W. Grimes ipt = (struct ip_timestamp *)cp; 1228df8bae1dSRodney W. Grimes if (ipt->ipt_len < 5) 1229df8bae1dSRodney W. Grimes goto bad; 12305d5d5fc0SJonathan Lemon if (ipt->ipt_ptr > 12315d5d5fc0SJonathan Lemon ipt->ipt_len - (int)sizeof(int32_t)) { 1232df8bae1dSRodney W. Grimes if (++ipt->ipt_oflw == 0) 1233df8bae1dSRodney W. Grimes goto bad; 1234df8bae1dSRodney W. Grimes break; 1235df8bae1dSRodney W. Grimes } 1236df8bae1dSRodney W. Grimes sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1); 1237df8bae1dSRodney W. Grimes switch (ipt->ipt_flg) { 1238df8bae1dSRodney W. Grimes 1239df8bae1dSRodney W. Grimes case IPOPT_TS_TSONLY: 1240df8bae1dSRodney W. Grimes break; 1241df8bae1dSRodney W. Grimes 1242df8bae1dSRodney W. Grimes case IPOPT_TS_TSANDADDR: 1243b8e8c209SDavid Greenman if (ipt->ipt_ptr - 1 + sizeof(n_time) + 1244df8bae1dSRodney W. Grimes sizeof(struct in_addr) > ipt->ipt_len) 1245df8bae1dSRodney W. Grimes goto bad; 1246df8bae1dSRodney W. Grimes ipaddr.sin_addr = dst; 1247df8bae1dSRodney W. Grimes ia = (INA)ifaof_ifpforaddr((SA)&ipaddr, 1248df8bae1dSRodney W. Grimes m->m_pkthdr.rcvif); 1249df8bae1dSRodney W. Grimes if (ia == 0) 1250df8bae1dSRodney W. Grimes continue; 125194a5d9b6SDavid Greenman (void)memcpy(sin, &IA_SIN(ia)->sin_addr, 125294a5d9b6SDavid Greenman sizeof(struct in_addr)); 1253df8bae1dSRodney W. Grimes ipt->ipt_ptr += sizeof(struct in_addr); 1254df8bae1dSRodney W. Grimes break; 1255df8bae1dSRodney W. Grimes 1256df8bae1dSRodney W. Grimes case IPOPT_TS_PRESPEC: 1257b8e8c209SDavid Greenman if (ipt->ipt_ptr - 1 + sizeof(n_time) + 1258df8bae1dSRodney W. Grimes sizeof(struct in_addr) > ipt->ipt_len) 1259df8bae1dSRodney W. Grimes goto bad; 126094a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, sin, 1261df8bae1dSRodney W. Grimes sizeof(struct in_addr)); 1262df8bae1dSRodney W. Grimes if (ifa_ifwithaddr((SA)&ipaddr) == 0) 1263df8bae1dSRodney W. Grimes continue; 1264df8bae1dSRodney W. Grimes ipt->ipt_ptr += sizeof(struct in_addr); 1265df8bae1dSRodney W. Grimes break; 1266df8bae1dSRodney W. Grimes 1267df8bae1dSRodney W. Grimes default: 1268df8bae1dSRodney W. Grimes goto bad; 1269df8bae1dSRodney W. Grimes } 1270df8bae1dSRodney W. Grimes ntime = iptime(); 127194a5d9b6SDavid Greenman (void)memcpy(cp + ipt->ipt_ptr - 1, &ntime, 1272df8bae1dSRodney W. Grimes sizeof(n_time)); 1273df8bae1dSRodney W. Grimes ipt->ipt_ptr += sizeof(n_time); 1274df8bae1dSRodney W. Grimes } 1275df8bae1dSRodney W. Grimes } 127647174b49SAndrey A. Chernov if (forward && ipforwarding) { 1277df8bae1dSRodney W. Grimes ip_forward(m, 1); 1278df8bae1dSRodney W. Grimes return (1); 1279df8bae1dSRodney W. Grimes } 1280df8bae1dSRodney W. Grimes return (0); 1281df8bae1dSRodney W. Grimes bad: 1282df8bae1dSRodney W. Grimes icmp_error(m, type, code, 0, 0); 1283df8bae1dSRodney W. Grimes ipstat.ips_badoptions++; 1284df8bae1dSRodney W. Grimes return (1); 1285df8bae1dSRodney W. Grimes } 1286df8bae1dSRodney W. Grimes 1287df8bae1dSRodney W. Grimes /* 1288df8bae1dSRodney W. Grimes * Given address of next destination (final or next hop), 1289df8bae1dSRodney W. Grimes * return internet address info of interface to be used to get there. 1290df8bae1dSRodney W. Grimes */ 12910312fbe9SPoul-Henning Kamp static struct in_ifaddr * 1292df8bae1dSRodney W. Grimes ip_rtaddr(dst) 1293df8bae1dSRodney W. Grimes struct in_addr dst; 1294df8bae1dSRodney W. Grimes { 1295df8bae1dSRodney W. Grimes register struct sockaddr_in *sin; 1296df8bae1dSRodney W. Grimes 1297df8bae1dSRodney W. Grimes sin = (struct sockaddr_in *) &ipforward_rt.ro_dst; 1298df8bae1dSRodney W. Grimes 1299df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt == 0 || dst.s_addr != sin->sin_addr.s_addr) { 1300df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt) { 1301df8bae1dSRodney W. Grimes RTFREE(ipforward_rt.ro_rt); 1302df8bae1dSRodney W. Grimes ipforward_rt.ro_rt = 0; 1303df8bae1dSRodney W. Grimes } 1304df8bae1dSRodney W. Grimes sin->sin_family = AF_INET; 1305df8bae1dSRodney W. Grimes sin->sin_len = sizeof(*sin); 1306df8bae1dSRodney W. Grimes sin->sin_addr = dst; 1307df8bae1dSRodney W. Grimes 13082c17fe93SGarrett Wollman rtalloc_ign(&ipforward_rt, RTF_PRCLONING); 1309df8bae1dSRodney W. Grimes } 1310df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt == 0) 1311df8bae1dSRodney W. Grimes return ((struct in_ifaddr *)0); 1312df8bae1dSRodney W. Grimes return ((struct in_ifaddr *) ipforward_rt.ro_rt->rt_ifa); 1313df8bae1dSRodney W. Grimes } 1314df8bae1dSRodney W. Grimes 1315df8bae1dSRodney W. Grimes /* 1316df8bae1dSRodney W. Grimes * Save incoming source route for use in replies, 1317df8bae1dSRodney W. Grimes * to be picked up later by ip_srcroute if the receiver is interested. 1318df8bae1dSRodney W. Grimes */ 1319df8bae1dSRodney W. Grimes void 1320df8bae1dSRodney W. Grimes save_rte(option, dst) 1321df8bae1dSRodney W. Grimes u_char *option; 1322df8bae1dSRodney W. Grimes struct in_addr dst; 1323df8bae1dSRodney W. Grimes { 1324df8bae1dSRodney W. Grimes unsigned olen; 1325df8bae1dSRodney W. Grimes 1326df8bae1dSRodney W. Grimes olen = option[IPOPT_OLEN]; 1327df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1328df8bae1dSRodney W. Grimes if (ipprintfs) 1329df8bae1dSRodney W. Grimes printf("save_rte: olen %d\n", olen); 1330df8bae1dSRodney W. Grimes #endif 1331df8bae1dSRodney W. Grimes if (olen > sizeof(ip_srcrt) - (1 + sizeof(dst))) 1332df8bae1dSRodney W. Grimes return; 13330453d3cbSBruce Evans bcopy(option, ip_srcrt.srcopt, olen); 1334df8bae1dSRodney W. Grimes ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr); 1335df8bae1dSRodney W. Grimes ip_srcrt.dst = dst; 1336df8bae1dSRodney W. Grimes } 1337df8bae1dSRodney W. Grimes 1338df8bae1dSRodney W. Grimes /* 1339df8bae1dSRodney W. Grimes * Retrieve incoming source route for use in replies, 1340df8bae1dSRodney W. Grimes * in the same form used by setsockopt. 1341df8bae1dSRodney W. Grimes * The first hop is placed before the options, will be removed later. 1342df8bae1dSRodney W. Grimes */ 1343df8bae1dSRodney W. Grimes struct mbuf * 1344df8bae1dSRodney W. Grimes ip_srcroute() 1345df8bae1dSRodney W. Grimes { 1346df8bae1dSRodney W. Grimes register struct in_addr *p, *q; 1347df8bae1dSRodney W. Grimes register struct mbuf *m; 1348df8bae1dSRodney W. Grimes 1349df8bae1dSRodney W. Grimes if (ip_nhops == 0) 1350df8bae1dSRodney W. Grimes return ((struct mbuf *)0); 1351cfe8b629SGarrett Wollman m = m_get(M_DONTWAIT, MT_HEADER); 1352df8bae1dSRodney W. Grimes if (m == 0) 1353df8bae1dSRodney W. Grimes return ((struct mbuf *)0); 1354df8bae1dSRodney W. Grimes 1355df8bae1dSRodney W. Grimes #define OPTSIZ (sizeof(ip_srcrt.nop) + sizeof(ip_srcrt.srcopt)) 1356df8bae1dSRodney W. Grimes 1357df8bae1dSRodney W. Grimes /* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */ 1358df8bae1dSRodney W. Grimes m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) + 1359df8bae1dSRodney W. Grimes OPTSIZ; 1360df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1361df8bae1dSRodney W. Grimes if (ipprintfs) 1362df8bae1dSRodney W. Grimes printf("ip_srcroute: nhops %d mlen %d", ip_nhops, m->m_len); 1363df8bae1dSRodney W. Grimes #endif 1364df8bae1dSRodney W. Grimes 1365df8bae1dSRodney W. Grimes /* 1366df8bae1dSRodney W. Grimes * First save first hop for return route 1367df8bae1dSRodney W. Grimes */ 1368df8bae1dSRodney W. Grimes p = &ip_srcrt.route[ip_nhops - 1]; 1369df8bae1dSRodney W. Grimes *(mtod(m, struct in_addr *)) = *p--; 1370df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1371df8bae1dSRodney W. Grimes if (ipprintfs) 1372af38c68cSLuigi Rizzo printf(" hops %lx", (u_long)ntohl(mtod(m, struct in_addr *)->s_addr)); 1373df8bae1dSRodney W. Grimes #endif 1374df8bae1dSRodney W. Grimes 1375df8bae1dSRodney W. Grimes /* 1376df8bae1dSRodney W. Grimes * Copy option fields and padding (nop) to mbuf. 1377df8bae1dSRodney W. Grimes */ 1378df8bae1dSRodney W. Grimes ip_srcrt.nop = IPOPT_NOP; 1379df8bae1dSRodney W. Grimes ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF; 138094a5d9b6SDavid Greenman (void)memcpy(mtod(m, caddr_t) + sizeof(struct in_addr), 138194a5d9b6SDavid Greenman &ip_srcrt.nop, OPTSIZ); 1382df8bae1dSRodney W. Grimes q = (struct in_addr *)(mtod(m, caddr_t) + 1383df8bae1dSRodney W. Grimes sizeof(struct in_addr) + OPTSIZ); 1384df8bae1dSRodney W. Grimes #undef OPTSIZ 1385df8bae1dSRodney W. Grimes /* 1386df8bae1dSRodney W. Grimes * Record return path as an IP source route, 1387df8bae1dSRodney W. Grimes * reversing the path (pointers are now aligned). 1388df8bae1dSRodney W. Grimes */ 1389df8bae1dSRodney W. Grimes while (p >= ip_srcrt.route) { 1390df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1391df8bae1dSRodney W. Grimes if (ipprintfs) 1392af38c68cSLuigi Rizzo printf(" %lx", (u_long)ntohl(q->s_addr)); 1393df8bae1dSRodney W. Grimes #endif 1394df8bae1dSRodney W. Grimes *q++ = *p--; 1395df8bae1dSRodney W. Grimes } 1396df8bae1dSRodney W. Grimes /* 1397df8bae1dSRodney W. Grimes * Last hop goes to final destination. 1398df8bae1dSRodney W. Grimes */ 1399df8bae1dSRodney W. Grimes *q = ip_srcrt.dst; 1400df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1401df8bae1dSRodney W. Grimes if (ipprintfs) 1402af38c68cSLuigi Rizzo printf(" %lx\n", (u_long)ntohl(q->s_addr)); 1403df8bae1dSRodney W. Grimes #endif 1404df8bae1dSRodney W. Grimes return (m); 1405df8bae1dSRodney W. Grimes } 1406df8bae1dSRodney W. Grimes 1407df8bae1dSRodney W. Grimes /* 1408df8bae1dSRodney W. Grimes * Strip out IP options, at higher 1409df8bae1dSRodney W. Grimes * level protocol in the kernel. 1410df8bae1dSRodney W. Grimes * Second argument is buffer to which options 1411df8bae1dSRodney W. Grimes * will be moved, and return value is their length. 1412df8bae1dSRodney W. Grimes * XXX should be deleted; last arg currently ignored. 1413df8bae1dSRodney W. Grimes */ 1414df8bae1dSRodney W. Grimes void 1415df8bae1dSRodney W. Grimes ip_stripoptions(m, mopt) 1416df8bae1dSRodney W. Grimes register struct mbuf *m; 1417df8bae1dSRodney W. Grimes struct mbuf *mopt; 1418df8bae1dSRodney W. Grimes { 1419df8bae1dSRodney W. Grimes register int i; 1420df8bae1dSRodney W. Grimes struct ip *ip = mtod(m, struct ip *); 1421df8bae1dSRodney W. Grimes register caddr_t opts; 1422df8bae1dSRodney W. Grimes int olen; 1423df8bae1dSRodney W. Grimes 142458938916SGarrett Wollman olen = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip); 1425df8bae1dSRodney W. Grimes opts = (caddr_t)(ip + 1); 1426df8bae1dSRodney W. Grimes i = m->m_len - (sizeof (struct ip) + olen); 1427df8bae1dSRodney W. Grimes bcopy(opts + olen, opts, (unsigned)i); 1428df8bae1dSRodney W. Grimes m->m_len -= olen; 1429df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) 1430df8bae1dSRodney W. Grimes m->m_pkthdr.len -= olen; 143158938916SGarrett Wollman ip->ip_vhl = IP_MAKE_VHL(IPVERSION, sizeof(struct ip) >> 2); 1432df8bae1dSRodney W. Grimes } 1433df8bae1dSRodney W. Grimes 1434df8bae1dSRodney W. Grimes u_char inetctlerrmap[PRC_NCMDS] = { 1435df8bae1dSRodney W. Grimes 0, 0, 0, 0, 1436df8bae1dSRodney W. Grimes 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH, 1437df8bae1dSRodney W. Grimes EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, 1438df8bae1dSRodney W. Grimes EMSGSIZE, EHOSTUNREACH, 0, 0, 1439df8bae1dSRodney W. Grimes 0, 0, 0, 0, 1440e4bb5b05SJonathan Lemon ENOPROTOOPT, ENETRESET 1441df8bae1dSRodney W. Grimes }; 1442df8bae1dSRodney W. Grimes 1443df8bae1dSRodney W. Grimes /* 1444df8bae1dSRodney W. Grimes * Forward a packet. If some error occurs return the sender 1445df8bae1dSRodney W. Grimes * an icmp packet. Note we can't always generate a meaningful 1446df8bae1dSRodney W. Grimes * icmp message because icmp doesn't have a large enough repertoire 1447df8bae1dSRodney W. Grimes * of codes and types. 1448df8bae1dSRodney W. Grimes * 1449df8bae1dSRodney W. Grimes * If not forwarding, just drop the packet. This could be confusing 1450df8bae1dSRodney W. Grimes * if ipforwarding was zero but some routing protocol was advancing 1451df8bae1dSRodney W. Grimes * us as a gateway to somewhere. However, we must let the routing 1452df8bae1dSRodney W. Grimes * protocol deal with that. 1453df8bae1dSRodney W. Grimes * 1454df8bae1dSRodney W. Grimes * The srcrt parameter indicates whether the packet is being forwarded 1455df8bae1dSRodney W. Grimes * via a source route. 1456df8bae1dSRodney W. Grimes */ 14570312fbe9SPoul-Henning Kamp static void 1458df8bae1dSRodney W. Grimes ip_forward(m, srcrt) 1459df8bae1dSRodney W. Grimes struct mbuf *m; 1460df8bae1dSRodney W. Grimes int srcrt; 1461df8bae1dSRodney W. Grimes { 1462df8bae1dSRodney W. Grimes register struct ip *ip = mtod(m, struct ip *); 1463df8bae1dSRodney W. Grimes register struct sockaddr_in *sin; 1464df8bae1dSRodney W. Grimes register struct rtentry *rt; 146526f9a767SRodney W. Grimes int error, type = 0, code = 0; 1466df8bae1dSRodney W. Grimes struct mbuf *mcopy; 1467df8bae1dSRodney W. Grimes n_long dest; 1468df8bae1dSRodney W. Grimes struct ifnet *destifp; 14696a800098SYoshinobu Inoue #ifdef IPSEC 14706a800098SYoshinobu Inoue struct ifnet dummyifp; 14716a800098SYoshinobu Inoue #endif 1472df8bae1dSRodney W. Grimes 1473df8bae1dSRodney W. Grimes dest = 0; 1474df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1475df8bae1dSRodney W. Grimes if (ipprintfs) 147661ce519bSPoul-Henning Kamp printf("forward: src %lx dst %lx ttl %x\n", 1477162886e2SBruce Evans (u_long)ip->ip_src.s_addr, (u_long)ip->ip_dst.s_addr, 1478162886e2SBruce Evans ip->ip_ttl); 1479df8bae1dSRodney W. Grimes #endif 1480100ba1a6SJordan K. Hubbard 1481100ba1a6SJordan K. Hubbard 148292af003dSGarrett Wollman if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(ip->ip_dst) == 0) { 1483df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 1484df8bae1dSRodney W. Grimes m_freem(m); 1485df8bae1dSRodney W. Grimes return; 1486df8bae1dSRodney W. Grimes } 14871b968362SDag-Erling Smørgrav #ifdef IPSTEALTH 14881b968362SDag-Erling Smørgrav if (!ipstealth) { 14891b968362SDag-Erling Smørgrav #endif 1490df8bae1dSRodney W. Grimes if (ip->ip_ttl <= IPTTLDEC) { 14911b968362SDag-Erling Smørgrav icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 14921b968362SDag-Erling Smørgrav dest, 0); 1493df8bae1dSRodney W. Grimes return; 1494df8bae1dSRodney W. Grimes } 14951b968362SDag-Erling Smørgrav #ifdef IPSTEALTH 14961b968362SDag-Erling Smørgrav } 14971b968362SDag-Erling Smørgrav #endif 1498df8bae1dSRodney W. Grimes 1499df8bae1dSRodney W. Grimes sin = (struct sockaddr_in *)&ipforward_rt.ro_dst; 1500df8bae1dSRodney W. Grimes if ((rt = ipforward_rt.ro_rt) == 0 || 1501df8bae1dSRodney W. Grimes ip->ip_dst.s_addr != sin->sin_addr.s_addr) { 1502df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt) { 1503df8bae1dSRodney W. Grimes RTFREE(ipforward_rt.ro_rt); 1504df8bae1dSRodney W. Grimes ipforward_rt.ro_rt = 0; 1505df8bae1dSRodney W. Grimes } 1506df8bae1dSRodney W. Grimes sin->sin_family = AF_INET; 1507df8bae1dSRodney W. Grimes sin->sin_len = sizeof(*sin); 1508df8bae1dSRodney W. Grimes sin->sin_addr = ip->ip_dst; 1509df8bae1dSRodney W. Grimes 15102c17fe93SGarrett Wollman rtalloc_ign(&ipforward_rt, RTF_PRCLONING); 1511df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt == 0) { 1512df8bae1dSRodney W. Grimes icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0); 1513df8bae1dSRodney W. Grimes return; 1514df8bae1dSRodney W. Grimes } 1515df8bae1dSRodney W. Grimes rt = ipforward_rt.ro_rt; 1516df8bae1dSRodney W. Grimes } 1517df8bae1dSRodney W. Grimes 1518df8bae1dSRodney W. Grimes /* 1519df8bae1dSRodney W. Grimes * Save at most 64 bytes of the packet in case 1520df8bae1dSRodney W. Grimes * we need to generate an ICMP message to the src. 1521df8bae1dSRodney W. Grimes */ 1522df8bae1dSRodney W. Grimes mcopy = m_copy(m, 0, imin((int)ip->ip_len, 64)); 152304287599SRuslan Ermilov if (mcopy && (mcopy->m_flags & M_EXT)) 152404287599SRuslan Ermilov m_copydata(mcopy, 0, sizeof(struct ip), mtod(mcopy, caddr_t)); 152504287599SRuslan Ermilov 152604287599SRuslan Ermilov #ifdef IPSTEALTH 152704287599SRuslan Ermilov if (!ipstealth) { 152804287599SRuslan Ermilov #endif 152904287599SRuslan Ermilov ip->ip_ttl -= IPTTLDEC; 153004287599SRuslan Ermilov #ifdef IPSTEALTH 153104287599SRuslan Ermilov } 153204287599SRuslan Ermilov #endif 1533df8bae1dSRodney W. Grimes 1534df8bae1dSRodney W. Grimes /* 1535df8bae1dSRodney W. Grimes * If forwarding packet using same interface that it came in on, 1536df8bae1dSRodney W. Grimes * perhaps should send a redirect to sender to shortcut a hop. 1537df8bae1dSRodney W. Grimes * Only send redirect if source is sending directly to us, 1538df8bae1dSRodney W. Grimes * and if packet was not source routed (or has any options). 1539df8bae1dSRodney W. Grimes * Also, don't send redirect if forwarding using a default route 1540df8bae1dSRodney W. Grimes * or a route modified by a redirect. 1541df8bae1dSRodney W. Grimes */ 1542df8bae1dSRodney W. Grimes #define satosin(sa) ((struct sockaddr_in *)(sa)) 1543df8bae1dSRodney W. Grimes if (rt->rt_ifp == m->m_pkthdr.rcvif && 1544df8bae1dSRodney W. Grimes (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 && 1545df8bae1dSRodney W. Grimes satosin(rt_key(rt))->sin_addr.s_addr != 0 && 1546df8bae1dSRodney W. Grimes ipsendredirects && !srcrt) { 1547df8bae1dSRodney W. Grimes #define RTA(rt) ((struct in_ifaddr *)(rt->rt_ifa)) 1548df8bae1dSRodney W. Grimes u_long src = ntohl(ip->ip_src.s_addr); 1549df8bae1dSRodney W. Grimes 1550df8bae1dSRodney W. Grimes if (RTA(rt) && 1551df8bae1dSRodney W. Grimes (src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) { 1552df8bae1dSRodney W. Grimes if (rt->rt_flags & RTF_GATEWAY) 1553df8bae1dSRodney W. Grimes dest = satosin(rt->rt_gateway)->sin_addr.s_addr; 1554df8bae1dSRodney W. Grimes else 1555df8bae1dSRodney W. Grimes dest = ip->ip_dst.s_addr; 1556df8bae1dSRodney W. Grimes /* Router requirements says to only send host redirects */ 1557df8bae1dSRodney W. Grimes type = ICMP_REDIRECT; 1558df8bae1dSRodney W. Grimes code = ICMP_REDIRECT_HOST; 1559df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1560df8bae1dSRodney W. Grimes if (ipprintfs) 1561df8bae1dSRodney W. Grimes printf("redirect (%d) to %lx\n", code, (u_long)dest); 1562df8bae1dSRodney W. Grimes #endif 1563df8bae1dSRodney W. Grimes } 1564df8bae1dSRodney W. Grimes } 1565df8bae1dSRodney W. Grimes 1566b97d15cbSGarrett Wollman error = ip_output(m, (struct mbuf *)0, &ipforward_rt, 1567b97d15cbSGarrett Wollman IP_FORWARDING, 0); 1568df8bae1dSRodney W. Grimes if (error) 1569df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 1570df8bae1dSRodney W. Grimes else { 1571df8bae1dSRodney W. Grimes ipstat.ips_forward++; 1572df8bae1dSRodney W. Grimes if (type) 1573df8bae1dSRodney W. Grimes ipstat.ips_redirectsent++; 1574df8bae1dSRodney W. Grimes else { 15751f91d8c5SDavid Greenman if (mcopy) { 15761f91d8c5SDavid Greenman ipflow_create(&ipforward_rt, mcopy); 1577df8bae1dSRodney W. Grimes m_freem(mcopy); 15781f91d8c5SDavid Greenman } 1579df8bae1dSRodney W. Grimes return; 1580df8bae1dSRodney W. Grimes } 1581df8bae1dSRodney W. Grimes } 1582df8bae1dSRodney W. Grimes if (mcopy == NULL) 1583df8bae1dSRodney W. Grimes return; 1584df8bae1dSRodney W. Grimes destifp = NULL; 1585df8bae1dSRodney W. Grimes 1586df8bae1dSRodney W. Grimes switch (error) { 1587df8bae1dSRodney W. Grimes 1588df8bae1dSRodney W. Grimes case 0: /* forwarded, but need redirect */ 1589df8bae1dSRodney W. Grimes /* type, code set above */ 1590df8bae1dSRodney W. Grimes break; 1591df8bae1dSRodney W. Grimes 1592df8bae1dSRodney W. Grimes case ENETUNREACH: /* shouldn't happen, checked above */ 1593df8bae1dSRodney W. Grimes case EHOSTUNREACH: 1594df8bae1dSRodney W. Grimes case ENETDOWN: 1595df8bae1dSRodney W. Grimes case EHOSTDOWN: 1596df8bae1dSRodney W. Grimes default: 1597df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1598df8bae1dSRodney W. Grimes code = ICMP_UNREACH_HOST; 1599df8bae1dSRodney W. Grimes break; 1600df8bae1dSRodney W. Grimes 1601df8bae1dSRodney W. Grimes case EMSGSIZE: 1602df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1603df8bae1dSRodney W. Grimes code = ICMP_UNREACH_NEEDFRAG; 16046a800098SYoshinobu Inoue #ifndef IPSEC 1605df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt) 1606df8bae1dSRodney W. Grimes destifp = ipforward_rt.ro_rt->rt_ifp; 16076a800098SYoshinobu Inoue #else 16086a800098SYoshinobu Inoue /* 16096a800098SYoshinobu Inoue * If the packet is routed over IPsec tunnel, tell the 16106a800098SYoshinobu Inoue * originator the tunnel MTU. 16116a800098SYoshinobu Inoue * tunnel MTU = if MTU - sizeof(IP) - ESP/AH hdrsiz 16126a800098SYoshinobu Inoue * XXX quickhack!!! 16136a800098SYoshinobu Inoue */ 16146a800098SYoshinobu Inoue if (ipforward_rt.ro_rt) { 16156a800098SYoshinobu Inoue struct secpolicy *sp = NULL; 16166a800098SYoshinobu Inoue int ipsecerror; 16176a800098SYoshinobu Inoue int ipsechdr; 16186a800098SYoshinobu Inoue struct route *ro; 16196a800098SYoshinobu Inoue 16206a800098SYoshinobu Inoue sp = ipsec4_getpolicybyaddr(mcopy, 16216a800098SYoshinobu Inoue IPSEC_DIR_OUTBOUND, 16226a800098SYoshinobu Inoue IP_FORWARDING, 16236a800098SYoshinobu Inoue &ipsecerror); 16246a800098SYoshinobu Inoue 16256a800098SYoshinobu Inoue if (sp == NULL) 16266a800098SYoshinobu Inoue destifp = ipforward_rt.ro_rt->rt_ifp; 16276a800098SYoshinobu Inoue else { 16286a800098SYoshinobu Inoue /* count IPsec header size */ 16296a800098SYoshinobu Inoue ipsechdr = ipsec4_hdrsiz(mcopy, 16306a800098SYoshinobu Inoue IPSEC_DIR_OUTBOUND, 16316a800098SYoshinobu Inoue NULL); 16326a800098SYoshinobu Inoue 16336a800098SYoshinobu Inoue /* 16346a800098SYoshinobu Inoue * find the correct route for outer IPv4 16356a800098SYoshinobu Inoue * header, compute tunnel MTU. 16366a800098SYoshinobu Inoue * 16376a800098SYoshinobu Inoue * XXX BUG ALERT 16386a800098SYoshinobu Inoue * The "dummyifp" code relies upon the fact 16396a800098SYoshinobu Inoue * that icmp_error() touches only ifp->if_mtu. 16406a800098SYoshinobu Inoue */ 16416a800098SYoshinobu Inoue /*XXX*/ 16426a800098SYoshinobu Inoue destifp = NULL; 16436a800098SYoshinobu Inoue if (sp->req != NULL 16446a800098SYoshinobu Inoue && sp->req->sav != NULL 16456a800098SYoshinobu Inoue && sp->req->sav->sah != NULL) { 16466a800098SYoshinobu Inoue ro = &sp->req->sav->sah->sa_route; 16476a800098SYoshinobu Inoue if (ro->ro_rt && ro->ro_rt->rt_ifp) { 16486a800098SYoshinobu Inoue dummyifp.if_mtu = 16496a800098SYoshinobu Inoue ro->ro_rt->rt_ifp->if_mtu; 16506a800098SYoshinobu Inoue dummyifp.if_mtu -= ipsechdr; 16516a800098SYoshinobu Inoue destifp = &dummyifp; 16526a800098SYoshinobu Inoue } 16536a800098SYoshinobu Inoue } 16546a800098SYoshinobu Inoue 16556a800098SYoshinobu Inoue key_freesp(sp); 16566a800098SYoshinobu Inoue } 16576a800098SYoshinobu Inoue } 16586a800098SYoshinobu Inoue #endif /*IPSEC*/ 1659df8bae1dSRodney W. Grimes ipstat.ips_cantfrag++; 1660df8bae1dSRodney W. Grimes break; 1661df8bae1dSRodney W. Grimes 1662df8bae1dSRodney W. Grimes case ENOBUFS: 1663df8bae1dSRodney W. Grimes type = ICMP_SOURCEQUENCH; 1664df8bae1dSRodney W. Grimes code = 0; 1665df8bae1dSRodney W. Grimes break; 16663a06e3e0SRuslan Ermilov 16673a06e3e0SRuslan Ermilov case EACCES: /* ipfw denied packet */ 16683a06e3e0SRuslan Ermilov m_freem(mcopy); 16693a06e3e0SRuslan Ermilov return; 1670df8bae1dSRodney W. Grimes } 167104287599SRuslan Ermilov if (mcopy->m_flags & M_EXT) 167204287599SRuslan Ermilov m_copyback(mcopy, 0, sizeof(struct ip), mtod(mcopy, caddr_t)); 1673df8bae1dSRodney W. Grimes icmp_error(mcopy, type, code, dest, destifp); 1674df8bae1dSRodney W. Grimes } 1675df8bae1dSRodney W. Grimes 167682c23ebaSBill Fenner void 167782c23ebaSBill Fenner ip_savecontrol(inp, mp, ip, m) 167882c23ebaSBill Fenner register struct inpcb *inp; 167982c23ebaSBill Fenner register struct mbuf **mp; 168082c23ebaSBill Fenner register struct ip *ip; 168182c23ebaSBill Fenner register struct mbuf *m; 168282c23ebaSBill Fenner { 168382c23ebaSBill Fenner if (inp->inp_socket->so_options & SO_TIMESTAMP) { 168482c23ebaSBill Fenner struct timeval tv; 168582c23ebaSBill Fenner 168682c23ebaSBill Fenner microtime(&tv); 168782c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv), 168882c23ebaSBill Fenner SCM_TIMESTAMP, SOL_SOCKET); 168982c23ebaSBill Fenner if (*mp) 169082c23ebaSBill Fenner mp = &(*mp)->m_next; 169182c23ebaSBill Fenner } 169282c23ebaSBill Fenner if (inp->inp_flags & INP_RECVDSTADDR) { 169382c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) &ip->ip_dst, 169482c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVDSTADDR, IPPROTO_IP); 169582c23ebaSBill Fenner if (*mp) 169682c23ebaSBill Fenner mp = &(*mp)->m_next; 169782c23ebaSBill Fenner } 169882c23ebaSBill Fenner #ifdef notyet 169982c23ebaSBill Fenner /* XXX 170082c23ebaSBill Fenner * Moving these out of udp_input() made them even more broken 170182c23ebaSBill Fenner * than they already were. 170282c23ebaSBill Fenner */ 170382c23ebaSBill Fenner /* options were tossed already */ 170482c23ebaSBill Fenner if (inp->inp_flags & INP_RECVOPTS) { 170582c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) opts_deleted_above, 170682c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVOPTS, IPPROTO_IP); 170782c23ebaSBill Fenner if (*mp) 170882c23ebaSBill Fenner mp = &(*mp)->m_next; 170982c23ebaSBill Fenner } 171082c23ebaSBill Fenner /* ip_srcroute doesn't do what we want here, need to fix */ 171182c23ebaSBill Fenner if (inp->inp_flags & INP_RECVRETOPTS) { 171282c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) ip_srcroute(), 171382c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVRETOPTS, IPPROTO_IP); 171482c23ebaSBill Fenner if (*mp) 171582c23ebaSBill Fenner mp = &(*mp)->m_next; 171682c23ebaSBill Fenner } 171782c23ebaSBill Fenner #endif 171882c23ebaSBill Fenner if (inp->inp_flags & INP_RECVIF) { 1719d314ad7bSJulian Elischer struct ifnet *ifp; 1720d314ad7bSJulian Elischer struct sdlbuf { 172182c23ebaSBill Fenner struct sockaddr_dl sdl; 1722d314ad7bSJulian Elischer u_char pad[32]; 1723d314ad7bSJulian Elischer } sdlbuf; 1724d314ad7bSJulian Elischer struct sockaddr_dl *sdp; 1725d314ad7bSJulian Elischer struct sockaddr_dl *sdl2 = &sdlbuf.sdl; 172682c23ebaSBill Fenner 1727d314ad7bSJulian Elischer if (((ifp = m->m_pkthdr.rcvif)) 1728d314ad7bSJulian Elischer && ( ifp->if_index && (ifp->if_index <= if_index))) { 1729d314ad7bSJulian Elischer sdp = (struct sockaddr_dl *)(ifnet_addrs 1730d314ad7bSJulian Elischer [ifp->if_index - 1]->ifa_addr); 1731d314ad7bSJulian Elischer /* 1732d314ad7bSJulian Elischer * Change our mind and don't try copy. 1733d314ad7bSJulian Elischer */ 1734d314ad7bSJulian Elischer if ((sdp->sdl_family != AF_LINK) 1735d314ad7bSJulian Elischer || (sdp->sdl_len > sizeof(sdlbuf))) { 1736d314ad7bSJulian Elischer goto makedummy; 1737d314ad7bSJulian Elischer } 1738d314ad7bSJulian Elischer bcopy(sdp, sdl2, sdp->sdl_len); 1739d314ad7bSJulian Elischer } else { 1740d314ad7bSJulian Elischer makedummy: 1741d314ad7bSJulian Elischer sdl2->sdl_len 1742d314ad7bSJulian Elischer = offsetof(struct sockaddr_dl, sdl_data[0]); 1743d314ad7bSJulian Elischer sdl2->sdl_family = AF_LINK; 1744d314ad7bSJulian Elischer sdl2->sdl_index = 0; 1745d314ad7bSJulian Elischer sdl2->sdl_nlen = sdl2->sdl_alen = sdl2->sdl_slen = 0; 1746d314ad7bSJulian Elischer } 1747d314ad7bSJulian Elischer *mp = sbcreatecontrol((caddr_t) sdl2, sdl2->sdl_len, 174882c23ebaSBill Fenner IP_RECVIF, IPPROTO_IP); 174982c23ebaSBill Fenner if (*mp) 175082c23ebaSBill Fenner mp = &(*mp)->m_next; 175182c23ebaSBill Fenner } 175282c23ebaSBill Fenner } 175382c23ebaSBill Fenner 1754df8bae1dSRodney W. Grimes int 1755f0068c4aSGarrett Wollman ip_rsvp_init(struct socket *so) 1756f0068c4aSGarrett Wollman { 1757f0068c4aSGarrett Wollman if (so->so_type != SOCK_RAW || 1758f0068c4aSGarrett Wollman so->so_proto->pr_protocol != IPPROTO_RSVP) 1759f0068c4aSGarrett Wollman return EOPNOTSUPP; 1760f0068c4aSGarrett Wollman 1761f0068c4aSGarrett Wollman if (ip_rsvpd != NULL) 1762f0068c4aSGarrett Wollman return EADDRINUSE; 1763f0068c4aSGarrett Wollman 1764f0068c4aSGarrett Wollman ip_rsvpd = so; 17651c5de19aSGarrett Wollman /* 17661c5de19aSGarrett Wollman * This may seem silly, but we need to be sure we don't over-increment 17671c5de19aSGarrett Wollman * the RSVP counter, in case something slips up. 17681c5de19aSGarrett Wollman */ 17691c5de19aSGarrett Wollman if (!ip_rsvp_on) { 17701c5de19aSGarrett Wollman ip_rsvp_on = 1; 17711c5de19aSGarrett Wollman rsvp_on++; 17721c5de19aSGarrett Wollman } 1773f0068c4aSGarrett Wollman 1774f0068c4aSGarrett Wollman return 0; 1775f0068c4aSGarrett Wollman } 1776f0068c4aSGarrett Wollman 1777f0068c4aSGarrett Wollman int 1778f0068c4aSGarrett Wollman ip_rsvp_done(void) 1779f0068c4aSGarrett Wollman { 1780f0068c4aSGarrett Wollman ip_rsvpd = NULL; 17811c5de19aSGarrett Wollman /* 17821c5de19aSGarrett Wollman * This may seem silly, but we need to be sure we don't over-decrement 17831c5de19aSGarrett Wollman * the RSVP counter, in case something slips up. 17841c5de19aSGarrett Wollman */ 17851c5de19aSGarrett Wollman if (ip_rsvp_on) { 17861c5de19aSGarrett Wollman ip_rsvp_on = 0; 17871c5de19aSGarrett Wollman rsvp_on--; 17881c5de19aSGarrett Wollman } 1789f0068c4aSGarrett Wollman return 0; 1790f0068c4aSGarrett Wollman } 1791