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 127df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1280312fbe9SPoul-Henning Kamp static int ipprintfs = 0; 129df8bae1dSRodney W. Grimes #endif 130df8bae1dSRodney W. Grimes 131df8bae1dSRodney W. Grimes extern struct domain inetdomain; 1326a800098SYoshinobu Inoue extern struct ipprotosw inetsw[]; 133df8bae1dSRodney W. Grimes u_char ip_protox[IPPROTO_MAX]; 1340312fbe9SPoul-Henning Kamp static int ipqmaxlen = IFQ_MAXLEN; 13559562606SGarrett Wollman struct in_ifaddrhead in_ifaddrhead; /* first inet address */ 136afed1375SDavid Greenman SYSCTL_INT(_net_inet_ip, IPCTL_INTRQMAXLEN, intr_queue_maxlen, CTLFLAG_RW, 1373d177f46SBill Fumerola &ipintrq.ifq_maxlen, 0, "Maximum size of the IP input queue"); 1380312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_INTRQDROPS, intr_queue_drops, CTLFLAG_RD, 1393d177f46SBill Fumerola &ipintrq.ifq_drops, 0, "Number of packets dropped from the IP input queue"); 140df8bae1dSRodney W. Grimes 141f23b4c91SGarrett Wollman struct ipstat ipstat; 1426fce01c9SGarrett Wollman SYSCTL_STRUCT(_net_inet_ip, IPCTL_STATS, stats, CTLFLAG_RD, 1433d177f46SBill Fumerola &ipstat, ipstat, "IP statistics (struct ipstat, netinet/ip_var.h)"); 144194a213eSAndrey A. Chernov 145194a213eSAndrey A. Chernov /* Packet reassembly stuff */ 146194a213eSAndrey A. Chernov #define IPREASS_NHASH_LOG2 6 147194a213eSAndrey A. Chernov #define IPREASS_NHASH (1 << IPREASS_NHASH_LOG2) 148194a213eSAndrey A. Chernov #define IPREASS_HMASK (IPREASS_NHASH - 1) 149194a213eSAndrey A. Chernov #define IPREASS_HASH(x,y) \ 150831a80b0SMatthew Dillon (((((x) & 0xF) | ((((x) >> 8) & 0xF) << 4)) ^ (y)) & IPREASS_HMASK) 151194a213eSAndrey A. Chernov 152194a213eSAndrey A. Chernov static struct ipq ipq[IPREASS_NHASH]; 153194a213eSAndrey A. Chernov static int nipq = 0; /* total # of reass queues */ 154194a213eSAndrey A. Chernov static int maxnipq; 155367d34f8SBrian Somers const int ipintrq_present = 1; 156f23b4c91SGarrett Wollman 1570312fbe9SPoul-Henning Kamp #ifdef IPCTL_DEFMTU 1580312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_DEFMTU, mtu, CTLFLAG_RW, 1593d177f46SBill Fumerola &ip_mtu, 0, "Default MTU"); 1600312fbe9SPoul-Henning Kamp #endif 1610312fbe9SPoul-Henning Kamp 1621b968362SDag-Erling Smørgrav #ifdef IPSTEALTH 1631b968362SDag-Erling Smørgrav static int ipstealth = 0; 1641b968362SDag-Erling Smørgrav SYSCTL_INT(_net_inet_ip, OID_AUTO, stealth, CTLFLAG_RW, 1651b968362SDag-Erling Smørgrav &ipstealth, 0, ""); 1661b968362SDag-Erling Smørgrav #endif 1671b968362SDag-Erling Smørgrav 168cfe8b629SGarrett Wollman 16923bf9953SPoul-Henning Kamp /* Firewall hooks */ 17023bf9953SPoul-Henning Kamp ip_fw_chk_t *ip_fw_chk_ptr; 17123bf9953SPoul-Henning Kamp ip_fw_ctl_t *ip_fw_ctl_ptr; 1729fcc0795SLuigi Rizzo int fw_enable = 1 ; 173e7319babSPoul-Henning Kamp 174b715f178SLuigi Rizzo #ifdef DUMMYNET 175b715f178SLuigi Rizzo ip_dn_ctl_t *ip_dn_ctl_ptr; 176b715f178SLuigi Rizzo #endif 177b715f178SLuigi Rizzo 178afed1b49SDarren Reed 179e7319babSPoul-Henning Kamp /* 180df8bae1dSRodney W. Grimes * We need to save the IP options in case a protocol wants to respond 181df8bae1dSRodney W. Grimes * to an incoming packet over the same route if the packet got here 182df8bae1dSRodney W. Grimes * using IP source routing. This allows connection establishment and 183df8bae1dSRodney W. Grimes * maintenance when the remote end is on a network that is not known 184df8bae1dSRodney W. Grimes * to us. 185df8bae1dSRodney W. Grimes */ 1860312fbe9SPoul-Henning Kamp static int ip_nhops = 0; 187df8bae1dSRodney W. Grimes static struct ip_srcrt { 188df8bae1dSRodney W. Grimes struct in_addr dst; /* final destination */ 189df8bae1dSRodney W. Grimes char nop; /* one NOP to align */ 190df8bae1dSRodney W. Grimes char srcopt[IPOPT_OFFSET + 1]; /* OPTVAL, OLEN and OFFSET */ 191df8bae1dSRodney W. Grimes struct in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)]; 192df8bae1dSRodney W. Grimes } ip_srcrt; 193df8bae1dSRodney W. Grimes 194f9e354dfSJulian Elischer struct sockaddr_in *ip_fw_fwd_addr; 195f9e354dfSJulian Elischer 196df8bae1dSRodney W. Grimes static void save_rte __P((u_char *, struct in_addr)); 1970312fbe9SPoul-Henning Kamp static int ip_dooptions __P((struct mbuf *)); 1980312fbe9SPoul-Henning Kamp static void ip_forward __P((struct mbuf *, int)); 1990312fbe9SPoul-Henning Kamp static void ip_freef __P((struct ipq *)); 2008948e4baSArchie Cobbs #ifdef IPDIVERT 2016a800098SYoshinobu Inoue static struct mbuf *ip_reass __P((struct mbuf *, 2028948e4baSArchie Cobbs struct ipq *, struct ipq *, u_int32_t *, u_int16_t *)); 2038948e4baSArchie Cobbs #else 2046a800098SYoshinobu Inoue static struct mbuf *ip_reass __P((struct mbuf *, struct ipq *, struct ipq *)); 2058948e4baSArchie Cobbs #endif 2068948e4baSArchie Cobbs static struct in_ifaddr *ip_rtaddr __P((struct in_addr)); 2070312fbe9SPoul-Henning Kamp static void ipintr __P((void)); 2088948e4baSArchie Cobbs 209df8bae1dSRodney W. Grimes /* 210df8bae1dSRodney W. Grimes * IP initialization: fill in IP protocol switch table. 211df8bae1dSRodney W. Grimes * All protocols not implemented in kernel go to raw IP protocol handler. 212df8bae1dSRodney W. Grimes */ 213df8bae1dSRodney W. Grimes void 214df8bae1dSRodney W. Grimes ip_init() 215df8bae1dSRodney W. Grimes { 2166a800098SYoshinobu Inoue register struct ipprotosw *pr; 217df8bae1dSRodney W. Grimes register int i; 218df8bae1dSRodney W. Grimes 21959562606SGarrett Wollman TAILQ_INIT(&in_ifaddrhead); 2206a800098SYoshinobu Inoue pr = (struct ipprotosw *)pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW); 221df8bae1dSRodney W. Grimes if (pr == 0) 222df8bae1dSRodney W. Grimes panic("ip_init"); 223df8bae1dSRodney W. Grimes for (i = 0; i < IPPROTO_MAX; i++) 224df8bae1dSRodney W. Grimes ip_protox[i] = pr - inetsw; 2256a800098SYoshinobu Inoue for (pr = (struct ipprotosw *)inetdomain.dom_protosw; 2266a800098SYoshinobu Inoue pr < (struct ipprotosw *)inetdomain.dom_protoswNPROTOSW; pr++) 227df8bae1dSRodney W. Grimes if (pr->pr_domain->dom_family == PF_INET && 228df8bae1dSRodney W. Grimes pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) 229df8bae1dSRodney W. Grimes ip_protox[pr->pr_protocol] = pr - inetsw; 230194a213eSAndrey A. Chernov 231194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) 232194a213eSAndrey A. Chernov ipq[i].next = ipq[i].prev = &ipq[i]; 233194a213eSAndrey A. Chernov 234194a213eSAndrey A. Chernov maxnipq = nmbclusters/4; 235194a213eSAndrey A. Chernov 236227ee8a1SPoul-Henning Kamp ip_id = time_second & 0xffff; 237df8bae1dSRodney W. Grimes ipintrq.ifq_maxlen = ipqmaxlen; 238df5e1987SJonathan Lemon mtx_init(&ipintrq.ifq_mtx, "ip_inq", MTX_DEF); 239242c5536SPeter Wemm 240242c5536SPeter Wemm register_netisr(NETISR_IP, ipintr); 241df8bae1dSRodney W. Grimes } 242df8bae1dSRodney W. Grimes 2430312fbe9SPoul-Henning Kamp static struct sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET }; 244f708ef1bSPoul-Henning Kamp static struct route ipforward_rt; 245df8bae1dSRodney W. Grimes 246df8bae1dSRodney W. Grimes /* 247df8bae1dSRodney W. Grimes * Ip input routine. Checksum and byte swap header. If fragmented 248df8bae1dSRodney W. Grimes * try to reassemble. Process options. Pass to next level. 249df8bae1dSRodney W. Grimes */ 250c67b1d17SGarrett Wollman void 251c67b1d17SGarrett Wollman ip_input(struct mbuf *m) 252df8bae1dSRodney W. Grimes { 25323bf9953SPoul-Henning Kamp struct ip *ip; 25423bf9953SPoul-Henning Kamp struct ipq *fp; 2555da9f8faSJosef Karthauser struct in_ifaddr *ia = NULL; 256b6ea1aa5SRuslan Ermilov int i, hlen; 25747c861ecSBrian Somers u_short sum; 2588948e4baSArchie Cobbs u_int16_t divert_cookie; /* firewall cookie */ 2597538a9a0SJonathan Lemon struct in_addr pkt_dst; 2608948e4baSArchie Cobbs #ifdef IPDIVERT 2618948e4baSArchie Cobbs u_int32_t divert_info = 0; /* packet divert/tee info */ 262b715f178SLuigi Rizzo #endif 263b715f178SLuigi Rizzo struct ip_fw_chain *rule = NULL; 264c4ac87eaSDarren Reed #ifdef PFIL_HOOKS 265c4ac87eaSDarren Reed struct packet_filter_hook *pfh; 266c4ac87eaSDarren Reed struct mbuf *m0; 267c4ac87eaSDarren Reed int rv; 268c4ac87eaSDarren Reed #endif /* PFIL_HOOKS */ 269b715f178SLuigi Rizzo 2708948e4baSArchie Cobbs #ifdef IPDIVERT 2718948e4baSArchie Cobbs /* Get and reset firewall cookie */ 2728948e4baSArchie Cobbs divert_cookie = ip_divert_cookie; 2738948e4baSArchie Cobbs ip_divert_cookie = 0; 2748948e4baSArchie Cobbs #else 2758948e4baSArchie Cobbs divert_cookie = 0; 2768948e4baSArchie Cobbs #endif 2778948e4baSArchie Cobbs 278b715f178SLuigi Rizzo #if defined(IPFIREWALL) && defined(DUMMYNET) 279b715f178SLuigi Rizzo /* 280b715f178SLuigi Rizzo * dummynet packet are prepended a vestigial mbuf with 281b715f178SLuigi Rizzo * m_type = MT_DUMMYNET and m_data pointing to the matching 282b715f178SLuigi Rizzo * rule. 283b715f178SLuigi Rizzo */ 284b715f178SLuigi Rizzo if (m->m_type == MT_DUMMYNET) { 285b715f178SLuigi Rizzo rule = (struct ip_fw_chain *)(m->m_data) ; 286b715f178SLuigi Rizzo m = m->m_next ; 287b715f178SLuigi Rizzo ip = mtod(m, struct ip *); 288b715f178SLuigi Rizzo hlen = IP_VHL_HL(ip->ip_vhl) << 2; 289b715f178SLuigi Rizzo goto iphack ; 290b715f178SLuigi Rizzo } else 291b715f178SLuigi Rizzo rule = NULL ; 292b715f178SLuigi Rizzo #endif 293df8bae1dSRodney W. Grimes 294df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 295ed7509acSJulian Elischer if (m == NULL || (m->m_flags & M_PKTHDR) == 0) 29658938916SGarrett Wollman panic("ip_input no HDR"); 297df8bae1dSRodney W. Grimes #endif 298df8bae1dSRodney W. Grimes ipstat.ips_total++; 29958938916SGarrett Wollman 30058938916SGarrett Wollman if (m->m_pkthdr.len < sizeof(struct ip)) 30158938916SGarrett Wollman goto tooshort; 30258938916SGarrett Wollman 303df8bae1dSRodney W. Grimes if (m->m_len < sizeof (struct ip) && 304df8bae1dSRodney W. Grimes (m = m_pullup(m, sizeof (struct ip))) == 0) { 305df8bae1dSRodney W. Grimes ipstat.ips_toosmall++; 306c67b1d17SGarrett Wollman return; 307df8bae1dSRodney W. Grimes } 308df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 30958938916SGarrett Wollman 31058938916SGarrett Wollman if (IP_VHL_V(ip->ip_vhl) != IPVERSION) { 311df8bae1dSRodney W. Grimes ipstat.ips_badvers++; 312df8bae1dSRodney W. Grimes goto bad; 313df8bae1dSRodney W. Grimes } 31458938916SGarrett Wollman 31558938916SGarrett Wollman hlen = IP_VHL_HL(ip->ip_vhl) << 2; 316df8bae1dSRodney W. Grimes if (hlen < sizeof(struct ip)) { /* minimum header length */ 317df8bae1dSRodney W. Grimes ipstat.ips_badhlen++; 318df8bae1dSRodney W. Grimes goto bad; 319df8bae1dSRodney W. Grimes } 320df8bae1dSRodney W. Grimes if (hlen > m->m_len) { 321df8bae1dSRodney W. Grimes if ((m = m_pullup(m, hlen)) == 0) { 322df8bae1dSRodney W. Grimes ipstat.ips_badhlen++; 323c67b1d17SGarrett Wollman return; 324df8bae1dSRodney W. Grimes } 325df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 326df8bae1dSRodney W. Grimes } 327db4f9cc7SJonathan Lemon if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) { 328db4f9cc7SJonathan Lemon sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID); 329db4f9cc7SJonathan Lemon } else { 33058938916SGarrett Wollman if (hlen == sizeof(struct ip)) { 33147c861ecSBrian Somers sum = in_cksum_hdr(ip); 33258938916SGarrett Wollman } else { 33347c861ecSBrian Somers sum = in_cksum(m, hlen); 33458938916SGarrett Wollman } 335db4f9cc7SJonathan Lemon } 33647c861ecSBrian Somers if (sum) { 337df8bae1dSRodney W. Grimes ipstat.ips_badsum++; 338df8bae1dSRodney W. Grimes goto bad; 339df8bae1dSRodney W. Grimes } 340df8bae1dSRodney W. Grimes 341df8bae1dSRodney W. Grimes /* 342df8bae1dSRodney W. Grimes * Convert fields to host representation. 343df8bae1dSRodney W. Grimes */ 344df8bae1dSRodney W. Grimes NTOHS(ip->ip_len); 345df8bae1dSRodney W. Grimes if (ip->ip_len < hlen) { 346df8bae1dSRodney W. Grimes ipstat.ips_badlen++; 347df8bae1dSRodney W. Grimes goto bad; 348df8bae1dSRodney W. Grimes } 349df8bae1dSRodney W. Grimes NTOHS(ip->ip_off); 350df8bae1dSRodney W. Grimes 351df8bae1dSRodney W. Grimes /* 352df8bae1dSRodney W. Grimes * Check that the amount of data in the buffers 353df8bae1dSRodney W. Grimes * is as at least much as the IP header would have us expect. 354df8bae1dSRodney W. Grimes * Trim mbufs if longer than we expect. 355df8bae1dSRodney W. Grimes * Drop packet if shorter than we expect. 356df8bae1dSRodney W. Grimes */ 357df8bae1dSRodney W. Grimes if (m->m_pkthdr.len < ip->ip_len) { 35858938916SGarrett Wollman tooshort: 359df8bae1dSRodney W. Grimes ipstat.ips_tooshort++; 360df8bae1dSRodney W. Grimes goto bad; 361df8bae1dSRodney W. Grimes } 362df8bae1dSRodney W. Grimes if (m->m_pkthdr.len > ip->ip_len) { 363df8bae1dSRodney W. Grimes if (m->m_len == m->m_pkthdr.len) { 364df8bae1dSRodney W. Grimes m->m_len = ip->ip_len; 365df8bae1dSRodney W. Grimes m->m_pkthdr.len = ip->ip_len; 366df8bae1dSRodney W. Grimes } else 367df8bae1dSRodney W. Grimes m_adj(m, ip->ip_len - m->m_pkthdr.len); 368df8bae1dSRodney W. Grimes } 3694dd1662bSUgen J.S. Antsilevich /* 3704dd1662bSUgen J.S. Antsilevich * IpHack's section. 3714dd1662bSUgen J.S. Antsilevich * Right now when no processing on packet has done 3724dd1662bSUgen J.S. Antsilevich * and it is still fresh out of network we do our black 3734dd1662bSUgen J.S. Antsilevich * deals with it. 37493e0e116SJulian Elischer * - Firewall: deny/allow/divert 375fed1c7e9SSøren Schmidt * - Xlate: translate packet's addr/port (NAT). 376b715f178SLuigi Rizzo * - Pipe: pass pkt through dummynet. 3774dd1662bSUgen J.S. Antsilevich * - Wrap: fake packet's addr/port <unimpl.> 3784dd1662bSUgen J.S. Antsilevich * - Encapsulate: put it in another IP and send out. <unimp.> 3794dd1662bSUgen J.S. Antsilevich */ 380b715f178SLuigi Rizzo 381dee383e0SEivind Eklund #if defined(IPFIREWALL) && defined(DUMMYNET) 382b715f178SLuigi Rizzo iphack: 383dee383e0SEivind Eklund #endif 384df8bae1dSRodney W. Grimes 385c4ac87eaSDarren Reed #ifdef PFIL_HOOKS 386c4ac87eaSDarren Reed /* 387c4ac87eaSDarren Reed * Run through list of hooks for input packets. If there are any 388c4ac87eaSDarren Reed * filters which require that additional packets in the flow are 389c4ac87eaSDarren Reed * not fast-forwarded, they must clear the M_CANFASTFWD flag. 390c4ac87eaSDarren Reed * Note that filters must _never_ set this flag, as another filter 391c4ac87eaSDarren Reed * in the list may have previously cleared it. 392c4ac87eaSDarren Reed */ 393c4ac87eaSDarren Reed m0 = m; 394c4ac87eaSDarren Reed pfh = pfil_hook_get(PFIL_IN, &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); 395fc2ffbe6SPoul-Henning Kamp for (; pfh; pfh = TAILQ_NEXT(pfh, pfil_link)) 396c4ac87eaSDarren Reed if (pfh->pfil_func) { 397c4ac87eaSDarren Reed rv = pfh->pfil_func(ip, hlen, 398c4ac87eaSDarren Reed m->m_pkthdr.rcvif, 0, &m0); 399c4ac87eaSDarren Reed if (rv) 400beec8214SDarren Reed return; 401c4ac87eaSDarren Reed m = m0; 402c4ac87eaSDarren Reed if (m == NULL) 403c4ac87eaSDarren Reed return; 404c4ac87eaSDarren Reed ip = mtod(m, struct ip *); 405beec8214SDarren Reed } 406c4ac87eaSDarren Reed #endif /* PFIL_HOOKS */ 407c4ac87eaSDarren Reed 4086bc748b0SLuigi Rizzo if (fw_enable && ip_fw_chk_ptr) { 409f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 410f9e354dfSJulian Elischer /* 411f9e354dfSJulian Elischer * If we've been forwarded from the output side, then 412f9e354dfSJulian Elischer * skip the firewall a second time 413f9e354dfSJulian Elischer */ 414f9e354dfSJulian Elischer if (ip_fw_fwd_addr) 415f9e354dfSJulian Elischer goto ours; 416f9e354dfSJulian Elischer #endif /* IPFIREWALL_FORWARD */ 417f9e354dfSJulian Elischer /* 4188948e4baSArchie Cobbs * See the comment in ip_output for the return values 419b715f178SLuigi Rizzo * produced by the firewall. 420f9e354dfSJulian Elischer */ 4218948e4baSArchie Cobbs i = (*ip_fw_chk_ptr)(&ip, 4228948e4baSArchie Cobbs hlen, NULL, &divert_cookie, &m, &rule, &ip_fw_fwd_addr); 423507b4b54SLuigi Rizzo if (i & IP_FW_PORT_DENY_FLAG) { /* XXX new interface-denied */ 424507b4b54SLuigi Rizzo if (m) 425507b4b54SLuigi Rizzo m_freem(m); 426b715f178SLuigi Rizzo return ; 427507b4b54SLuigi Rizzo } 428507b4b54SLuigi Rizzo if (m == NULL) { /* Packet discarded by firewall */ 429507b4b54SLuigi Rizzo static int __debug=10; 430507b4b54SLuigi Rizzo if (__debug >0) { 431507b4b54SLuigi Rizzo printf("firewall returns NULL, please update!\n"); 432507b4b54SLuigi Rizzo __debug-- ; 433507b4b54SLuigi Rizzo } 434507b4b54SLuigi Rizzo return; 435507b4b54SLuigi Rizzo } 436b715f178SLuigi Rizzo if (i == 0 && ip_fw_fwd_addr == NULL) /* common case */ 437b715f178SLuigi Rizzo goto pass; 438b715f178SLuigi Rizzo #ifdef DUMMYNET 4398948e4baSArchie Cobbs if ((i & IP_FW_PORT_DYNT_FLAG) != 0) { 4408948e4baSArchie Cobbs /* Send packet to the appropriate pipe */ 4416a800098SYoshinobu Inoue dummynet_io(i&0xffff,DN_TO_IP_IN,m,NULL,NULL,0, rule, 4426a800098SYoshinobu Inoue 0); 443e4676ba6SJulian Elischer return; 44493e0e116SJulian Elischer } 445b715f178SLuigi Rizzo #endif 446b715f178SLuigi Rizzo #ifdef IPDIVERT 4478948e4baSArchie Cobbs if (i != 0 && (i & IP_FW_PORT_DYNT_FLAG) == 0) { 4488948e4baSArchie Cobbs /* Divert or tee packet */ 4498948e4baSArchie Cobbs divert_info = i; 450b715f178SLuigi Rizzo goto ours; 451b715f178SLuigi Rizzo } 452b715f178SLuigi Rizzo #endif 453b715f178SLuigi Rizzo #ifdef IPFIREWALL_FORWARD 454b715f178SLuigi Rizzo if (i == 0 && ip_fw_fwd_addr != NULL) 455b715f178SLuigi Rizzo goto pass; 456b715f178SLuigi Rizzo #endif 457b715f178SLuigi Rizzo /* 458b715f178SLuigi Rizzo * if we get here, the packet must be dropped 459b715f178SLuigi Rizzo */ 460b715f178SLuigi Rizzo m_freem(m); 461b715f178SLuigi Rizzo return; 462b715f178SLuigi Rizzo } 463b715f178SLuigi Rizzo pass: 464100ba1a6SJordan K. Hubbard 465df8bae1dSRodney W. Grimes /* 466df8bae1dSRodney W. Grimes * Process options and, if not destined for us, 467df8bae1dSRodney W. Grimes * ship it on. ip_dooptions returns 1 when an 468df8bae1dSRodney W. Grimes * error was detected (causing an icmp message 469df8bae1dSRodney W. Grimes * to be sent and the original packet to be freed). 470df8bae1dSRodney W. Grimes */ 471df8bae1dSRodney W. Grimes ip_nhops = 0; /* for source routed packets */ 472ed1ff184SJulian Elischer if (hlen > sizeof (struct ip) && ip_dooptions(m)) { 473ed1ff184SJulian Elischer #ifdef IPFIREWALL_FORWARD 474ed1ff184SJulian Elischer ip_fw_fwd_addr = NULL; 475ed1ff184SJulian Elischer #endif 476c67b1d17SGarrett Wollman return; 477ed1ff184SJulian Elischer } 478df8bae1dSRodney W. Grimes 479f0068c4aSGarrett Wollman /* greedy RSVP, snatches any PATH packet of the RSVP protocol and no 480f0068c4aSGarrett Wollman * matter if it is destined to another node, or whether it is 481f0068c4aSGarrett Wollman * a multicast one, RSVP wants it! and prevents it from being forwarded 482f0068c4aSGarrett Wollman * anywhere else. Also checks if the rsvp daemon is running before 483f0068c4aSGarrett Wollman * grabbing the packet. 484f0068c4aSGarrett Wollman */ 4851c5de19aSGarrett Wollman if (rsvp_on && ip->ip_p==IPPROTO_RSVP) 486f0068c4aSGarrett Wollman goto ours; 487f0068c4aSGarrett Wollman 488df8bae1dSRodney W. Grimes /* 489df8bae1dSRodney W. Grimes * Check our list of addresses, to see if the packet is for us. 490cc766e04SGarrett Wollman * If we don't have any addresses, assume any unicast packet 491cc766e04SGarrett Wollman * we receive might be for us (and let the upper layers deal 492cc766e04SGarrett Wollman * with it). 493df8bae1dSRodney W. Grimes */ 494cc766e04SGarrett Wollman if (TAILQ_EMPTY(&in_ifaddrhead) && 495cc766e04SGarrett Wollman (m->m_flags & (M_MCAST|M_BCAST)) == 0) 496cc766e04SGarrett Wollman goto ours; 497cc766e04SGarrett Wollman 4987538a9a0SJonathan Lemon /* 4997538a9a0SJonathan Lemon * Cache the destination address of the packet; this may be 5007538a9a0SJonathan Lemon * changed by use of 'ipfw fwd'. 5017538a9a0SJonathan Lemon */ 5027538a9a0SJonathan Lemon pkt_dst = ip_fw_fwd_addr == NULL ? 5037538a9a0SJonathan Lemon ip->ip_dst : ip_fw_fwd_addr->sin_addr; 5047538a9a0SJonathan Lemon 50537d40066SPoul-Henning Kamp TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) { 506df8bae1dSRodney W. Grimes #define satosin(sa) ((struct sockaddr_in *)(sa)) 507df8bae1dSRodney W. Grimes 508432aad0eSTor Egge #ifdef BOOTP_COMPAT 509432aad0eSTor Egge if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY) 510432aad0eSTor Egge goto ours; 511432aad0eSTor Egge #endif 512f9e354dfSJulian Elischer /* 5137538a9a0SJonathan Lemon * check that the packet is either arriving from the 5147538a9a0SJonathan Lemon * correct interface or is locally generated. 515f9e354dfSJulian Elischer */ 5167538a9a0SJonathan Lemon if (ia->ia_ifp != m->m_pkthdr.rcvif && 5177538a9a0SJonathan Lemon (m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) 5187538a9a0SJonathan Lemon continue; 5197538a9a0SJonathan Lemon 5207538a9a0SJonathan Lemon if (IA_SIN(ia)->sin_addr.s_addr == pkt_dst.s_addr) 521ed1ff184SJulian Elischer goto ours; 5227538a9a0SJonathan Lemon 5236ed666afSPoul-Henning Kamp if (ia->ia_ifp && ia->ia_ifp->if_flags & IFF_BROADCAST) { 524df8bae1dSRodney W. Grimes if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == 5257538a9a0SJonathan Lemon pkt_dst.s_addr) 526df8bae1dSRodney W. Grimes goto ours; 5277538a9a0SJonathan Lemon if (ia->ia_netbroadcast.s_addr == pkt_dst.s_addr) 528df8bae1dSRodney W. Grimes goto ours; 529df8bae1dSRodney W. Grimes } 530df8bae1dSRodney W. Grimes } 531df8bae1dSRodney W. Grimes if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { 532df8bae1dSRodney W. Grimes struct in_multi *inm; 533df8bae1dSRodney W. Grimes if (ip_mrouter) { 534df8bae1dSRodney W. Grimes /* 535df8bae1dSRodney W. Grimes * If we are acting as a multicast router, all 536df8bae1dSRodney W. Grimes * incoming multicast packets are passed to the 537df8bae1dSRodney W. Grimes * kernel-level multicast forwarding function. 538df8bae1dSRodney W. Grimes * The packet is returned (relatively) intact; if 539df8bae1dSRodney W. Grimes * ip_mforward() returns a non-zero value, the packet 540df8bae1dSRodney W. Grimes * must be discarded, else it may be accepted below. 541df8bae1dSRodney W. Grimes */ 542f0068c4aSGarrett Wollman if (ip_mforward(ip, m->m_pkthdr.rcvif, m, 0) != 0) { 543df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 544df8bae1dSRodney W. Grimes m_freem(m); 545c67b1d17SGarrett Wollman return; 546df8bae1dSRodney W. Grimes } 547df8bae1dSRodney W. Grimes 548df8bae1dSRodney W. Grimes /* 549df8bae1dSRodney W. Grimes * The process-level routing demon needs to receive 550df8bae1dSRodney W. Grimes * all multicast IGMP packets, whether or not this 551df8bae1dSRodney W. Grimes * host belongs to their destination groups. 552df8bae1dSRodney W. Grimes */ 553df8bae1dSRodney W. Grimes if (ip->ip_p == IPPROTO_IGMP) 554df8bae1dSRodney W. Grimes goto ours; 555df8bae1dSRodney W. Grimes ipstat.ips_forward++; 556df8bae1dSRodney W. Grimes } 557df8bae1dSRodney W. Grimes /* 558df8bae1dSRodney W. Grimes * See if we belong to the destination multicast group on the 559df8bae1dSRodney W. Grimes * arrival interface. 560df8bae1dSRodney W. Grimes */ 561df8bae1dSRodney W. Grimes IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm); 562df8bae1dSRodney W. Grimes if (inm == NULL) { 56382c39223SGarrett Wollman ipstat.ips_notmember++; 564df8bae1dSRodney W. Grimes m_freem(m); 565c67b1d17SGarrett Wollman return; 566df8bae1dSRodney W. Grimes } 567df8bae1dSRodney W. Grimes goto ours; 568df8bae1dSRodney W. Grimes } 569df8bae1dSRodney W. Grimes if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST) 570df8bae1dSRodney W. Grimes goto ours; 571df8bae1dSRodney W. Grimes if (ip->ip_dst.s_addr == INADDR_ANY) 572df8bae1dSRodney W. Grimes goto ours; 573df8bae1dSRodney W. Grimes 5746a800098SYoshinobu Inoue #if defined(NFAITH) && 0 < NFAITH 5756a800098SYoshinobu Inoue /* 5766a800098SYoshinobu Inoue * FAITH(Firewall Aided Internet Translator) 5776a800098SYoshinobu Inoue */ 5786a800098SYoshinobu Inoue if (m->m_pkthdr.rcvif && m->m_pkthdr.rcvif->if_type == IFT_FAITH) { 5796a800098SYoshinobu Inoue if (ip_keepfaith) { 5806a800098SYoshinobu Inoue if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_ICMP) 5816a800098SYoshinobu Inoue goto ours; 5826a800098SYoshinobu Inoue } 5836a800098SYoshinobu Inoue m_freem(m); 5846a800098SYoshinobu Inoue return; 5856a800098SYoshinobu Inoue } 5866a800098SYoshinobu Inoue #endif 587df8bae1dSRodney W. Grimes /* 588df8bae1dSRodney W. Grimes * Not for us; forward if possible and desirable. 589df8bae1dSRodney W. Grimes */ 590df8bae1dSRodney W. Grimes if (ipforwarding == 0) { 591df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 592df8bae1dSRodney W. Grimes m_freem(m); 593df8bae1dSRodney W. Grimes } else 594df8bae1dSRodney W. Grimes ip_forward(m, 0); 595ed1ff184SJulian Elischer #ifdef IPFIREWALL_FORWARD 596ed1ff184SJulian Elischer ip_fw_fwd_addr = NULL; 597ed1ff184SJulian Elischer #endif 598c67b1d17SGarrett Wollman return; 599df8bae1dSRodney W. Grimes 600df8bae1dSRodney W. Grimes ours: 6015da9f8faSJosef Karthauser /* Count the packet in the ip address stats */ 6025da9f8faSJosef Karthauser if (ia != NULL) { 6035da9f8faSJosef Karthauser ia->ia_ifa.if_ipackets++; 6045da9f8faSJosef Karthauser ia->ia_ifa.if_ibytes += m->m_pkthdr.len; 6055da9f8faSJosef Karthauser } 606100ba1a6SJordan K. Hubbard 60763f8d699SJordan K. Hubbard /* 608df8bae1dSRodney W. Grimes * If offset or IP_MF are set, must reassemble. 609df8bae1dSRodney W. Grimes * Otherwise, nothing need be done. 610df8bae1dSRodney W. Grimes * (We could look in the reassembly queue to see 611df8bae1dSRodney W. Grimes * if the packet was previously fragmented, 612df8bae1dSRodney W. Grimes * but it's not worth the time; just let them time out.) 613df8bae1dSRodney W. Grimes */ 614b6ea1aa5SRuslan Ermilov if (ip->ip_off & (IP_MF | IP_OFFMASK)) { 6156a800098SYoshinobu Inoue 616194a213eSAndrey A. Chernov sum = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id); 617df8bae1dSRodney W. Grimes /* 618df8bae1dSRodney W. Grimes * Look for queue of fragments 619df8bae1dSRodney W. Grimes * of this datagram. 620df8bae1dSRodney W. Grimes */ 621194a213eSAndrey A. Chernov for (fp = ipq[sum].next; fp != &ipq[sum]; fp = fp->next) 622df8bae1dSRodney W. Grimes if (ip->ip_id == fp->ipq_id && 623df8bae1dSRodney W. Grimes ip->ip_src.s_addr == fp->ipq_src.s_addr && 624df8bae1dSRodney W. Grimes ip->ip_dst.s_addr == fp->ipq_dst.s_addr && 625df8bae1dSRodney W. Grimes ip->ip_p == fp->ipq_p) 626df8bae1dSRodney W. Grimes goto found; 627df8bae1dSRodney W. Grimes 628194a213eSAndrey A. Chernov fp = 0; 629194a213eSAndrey A. Chernov 630194a213eSAndrey A. Chernov /* check if there's a place for the new queue */ 631194a213eSAndrey A. Chernov if (nipq > maxnipq) { 632194a213eSAndrey A. Chernov /* 633194a213eSAndrey A. Chernov * drop something from the tail of the current queue 634194a213eSAndrey A. Chernov * before proceeding further 635194a213eSAndrey A. Chernov */ 636194a213eSAndrey A. Chernov if (ipq[sum].prev == &ipq[sum]) { /* gak */ 637194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 638194a213eSAndrey A. Chernov if (ipq[i].prev != &ipq[i]) { 639194a213eSAndrey A. Chernov ip_freef(ipq[i].prev); 640194a213eSAndrey A. Chernov break; 641194a213eSAndrey A. Chernov } 642194a213eSAndrey A. Chernov } 643194a213eSAndrey A. Chernov } else 644194a213eSAndrey A. Chernov ip_freef(ipq[sum].prev); 645194a213eSAndrey A. Chernov } 646194a213eSAndrey A. Chernov found: 647df8bae1dSRodney W. Grimes /* 648df8bae1dSRodney W. Grimes * Adjust ip_len to not reflect header, 649df8bae1dSRodney W. Grimes * convert offset of this to bytes. 650df8bae1dSRodney W. Grimes */ 651df8bae1dSRodney W. Grimes ip->ip_len -= hlen; 652b6ea1aa5SRuslan Ermilov if (ip->ip_off & IP_MF) { 6536effc713SDoug Rabson /* 6546effc713SDoug Rabson * Make sure that fragments have a data length 6556effc713SDoug Rabson * that's a non-zero multiple of 8 bytes. 6566effc713SDoug Rabson */ 6576effc713SDoug Rabson if (ip->ip_len == 0 || (ip->ip_len & 0x7) != 0) { 6586effc713SDoug Rabson ipstat.ips_toosmall++; /* XXX */ 6596effc713SDoug Rabson goto bad; 6606effc713SDoug Rabson } 6616effc713SDoug Rabson m->m_flags |= M_FRAG; 6626effc713SDoug Rabson } 663df8bae1dSRodney W. Grimes ip->ip_off <<= 3; 664df8bae1dSRodney W. Grimes 665df8bae1dSRodney W. Grimes /* 666b6ea1aa5SRuslan Ermilov * Attempt reassembly; if it succeeds, proceed. 667df8bae1dSRodney W. Grimes */ 668df8bae1dSRodney W. Grimes ipstat.ips_fragments++; 669487bdb38SRuslan Ermilov m->m_pkthdr.header = ip; 6708948e4baSArchie Cobbs #ifdef IPDIVERT 6716a800098SYoshinobu Inoue m = ip_reass(m, 6728948e4baSArchie Cobbs fp, &ipq[sum], &divert_info, &divert_cookie); 6738948e4baSArchie Cobbs #else 6746a800098SYoshinobu Inoue m = ip_reass(m, fp, &ipq[sum]); 6758948e4baSArchie Cobbs #endif 6766a800098SYoshinobu Inoue if (m == 0) { 677f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 678f9e354dfSJulian Elischer ip_fw_fwd_addr = NULL; 679f9e354dfSJulian Elischer #endif 680c67b1d17SGarrett Wollman return; 681f9e354dfSJulian Elischer } 682df8bae1dSRodney W. Grimes ipstat.ips_reassembled++; 6836a800098SYoshinobu Inoue ip = mtod(m, struct ip *); 6847e2df452SRuslan Ermilov /* Get the header length of the reassembled packet */ 6857e2df452SRuslan Ermilov hlen = IP_VHL_HL(ip->ip_vhl) << 2; 686af782f1cSBrian Somers #ifdef IPDIVERT 6878948e4baSArchie Cobbs /* Restore original checksum before diverting packet */ 6888948e4baSArchie Cobbs if (divert_info != 0) { 689af782f1cSBrian Somers ip->ip_len += hlen; 690af782f1cSBrian Somers HTONS(ip->ip_len); 691af782f1cSBrian Somers HTONS(ip->ip_off); 692af782f1cSBrian Somers ip->ip_sum = 0; 69360123168SRuslan Ermilov if (hlen == sizeof(struct ip)) 694af782f1cSBrian Somers ip->ip_sum = in_cksum_hdr(ip); 69560123168SRuslan Ermilov else 69660123168SRuslan Ermilov ip->ip_sum = in_cksum(m, hlen); 697af782f1cSBrian Somers NTOHS(ip->ip_off); 698af782f1cSBrian Somers NTOHS(ip->ip_len); 699af782f1cSBrian Somers ip->ip_len -= hlen; 700af782f1cSBrian Somers } 701af782f1cSBrian Somers #endif 702df8bae1dSRodney W. Grimes } else 703df8bae1dSRodney W. Grimes ip->ip_len -= hlen; 704df8bae1dSRodney W. Grimes 70593e0e116SJulian Elischer #ifdef IPDIVERT 70693e0e116SJulian Elischer /* 7078948e4baSArchie Cobbs * Divert or tee packet to the divert protocol if required. 7088948e4baSArchie Cobbs * 7098948e4baSArchie Cobbs * If divert_info is zero then cookie should be too, so we shouldn't 7108948e4baSArchie Cobbs * need to clear them here. Assume divert_packet() does so also. 71193e0e116SJulian Elischer */ 7128948e4baSArchie Cobbs if (divert_info != 0) { 7138948e4baSArchie Cobbs struct mbuf *clone = NULL; 7148948e4baSArchie Cobbs 7158948e4baSArchie Cobbs /* Clone packet if we're doing a 'tee' */ 7168948e4baSArchie Cobbs if ((divert_info & IP_FW_PORT_TEE_FLAG) != 0) 7178948e4baSArchie Cobbs clone = m_dup(m, M_DONTWAIT); 7188948e4baSArchie Cobbs 7198948e4baSArchie Cobbs /* Restore packet header fields to original values */ 7208948e4baSArchie Cobbs ip->ip_len += hlen; 7218948e4baSArchie Cobbs HTONS(ip->ip_len); 7228948e4baSArchie Cobbs HTONS(ip->ip_off); 7238948e4baSArchie Cobbs 7248948e4baSArchie Cobbs /* Deliver packet to divert input routine */ 7258948e4baSArchie Cobbs ip_divert_cookie = divert_cookie; 7268948e4baSArchie Cobbs divert_packet(m, 1, divert_info & 0xffff); 727e4676ba6SJulian Elischer ipstat.ips_delivered++; 7288948e4baSArchie Cobbs 7298948e4baSArchie Cobbs /* If 'tee', continue with original packet */ 7308948e4baSArchie Cobbs if (clone == NULL) 73193e0e116SJulian Elischer return; 7328948e4baSArchie Cobbs m = clone; 7338948e4baSArchie Cobbs ip = mtod(m, struct ip *); 73493e0e116SJulian Elischer } 73593e0e116SJulian Elischer #endif 73693e0e116SJulian Elischer 737df8bae1dSRodney W. Grimes /* 738df8bae1dSRodney W. Grimes * Switch out to protocol's input routine. 739df8bae1dSRodney W. Grimes */ 740df8bae1dSRodney W. Grimes ipstat.ips_delivered++; 7416a800098SYoshinobu Inoue { 7426a800098SYoshinobu Inoue int off = hlen, nh = ip->ip_p; 7436a800098SYoshinobu Inoue 7446a800098SYoshinobu Inoue (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, off, nh); 745f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 746f9e354dfSJulian Elischer ip_fw_fwd_addr = NULL; /* tcp needed it */ 747f9e354dfSJulian Elischer #endif 748c67b1d17SGarrett Wollman return; 7496a800098SYoshinobu Inoue } 750df8bae1dSRodney W. Grimes bad: 751f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 752f9e354dfSJulian Elischer ip_fw_fwd_addr = NULL; 753f9e354dfSJulian Elischer #endif 754df8bae1dSRodney W. Grimes m_freem(m); 755c67b1d17SGarrett Wollman } 756c67b1d17SGarrett Wollman 757c67b1d17SGarrett Wollman /* 758c67b1d17SGarrett Wollman * IP software interrupt routine - to go away sometime soon 759c67b1d17SGarrett Wollman */ 760c67b1d17SGarrett Wollman static void 761c67b1d17SGarrett Wollman ipintr(void) 762c67b1d17SGarrett Wollman { 763c67b1d17SGarrett Wollman struct mbuf *m; 764c67b1d17SGarrett Wollman 765c67b1d17SGarrett Wollman while (1) { 766c67b1d17SGarrett Wollman IF_DEQUEUE(&ipintrq, m); 767c67b1d17SGarrett Wollman if (m == 0) 768c67b1d17SGarrett Wollman return; 769c67b1d17SGarrett Wollman ip_input(m); 770c67b1d17SGarrett Wollman } 771df8bae1dSRodney W. Grimes } 772df8bae1dSRodney W. Grimes 773df8bae1dSRodney W. Grimes /* 7748948e4baSArchie Cobbs * Take incoming datagram fragment and try to reassemble it into 7758948e4baSArchie Cobbs * whole datagram. If a chain for reassembly of this datagram already 7768948e4baSArchie Cobbs * exists, then it is given as fp; otherwise have to make a chain. 7778948e4baSArchie Cobbs * 7788948e4baSArchie Cobbs * When IPDIVERT enabled, keep additional state with each packet that 7798948e4baSArchie Cobbs * tells us if we need to divert or tee the packet we're building. 780df8bae1dSRodney W. Grimes */ 7818948e4baSArchie Cobbs 7826a800098SYoshinobu Inoue static struct mbuf * 7838948e4baSArchie Cobbs #ifdef IPDIVERT 7848948e4baSArchie Cobbs ip_reass(m, fp, where, divinfo, divcookie) 7858948e4baSArchie Cobbs #else 7866effc713SDoug Rabson ip_reass(m, fp, where) 7878948e4baSArchie Cobbs #endif 7886effc713SDoug Rabson register struct mbuf *m; 789df8bae1dSRodney W. Grimes register struct ipq *fp; 790194a213eSAndrey A. Chernov struct ipq *where; 7918948e4baSArchie Cobbs #ifdef IPDIVERT 7928948e4baSArchie Cobbs u_int32_t *divinfo; 7938948e4baSArchie Cobbs u_int16_t *divcookie; 7948948e4baSArchie Cobbs #endif 795df8bae1dSRodney W. Grimes { 7966effc713SDoug Rabson struct ip *ip = mtod(m, struct ip *); 797b6ea1aa5SRuslan Ermilov register struct mbuf *p, *q, *nq; 798df8bae1dSRodney W. Grimes struct mbuf *t; 7996effc713SDoug Rabson int hlen = IP_VHL_HL(ip->ip_vhl) << 2; 800df8bae1dSRodney W. Grimes int i, next; 801df8bae1dSRodney W. Grimes 802df8bae1dSRodney W. Grimes /* 803df8bae1dSRodney W. Grimes * Presence of header sizes in mbufs 804df8bae1dSRodney W. Grimes * would confuse code below. 805df8bae1dSRodney W. Grimes */ 806df8bae1dSRodney W. Grimes m->m_data += hlen; 807df8bae1dSRodney W. Grimes m->m_len -= hlen; 808df8bae1dSRodney W. Grimes 809df8bae1dSRodney W. Grimes /* 810df8bae1dSRodney W. Grimes * If first fragment to arrive, create a reassembly queue. 811df8bae1dSRodney W. Grimes */ 812df8bae1dSRodney W. Grimes if (fp == 0) { 813df8bae1dSRodney W. Grimes if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL) 814df8bae1dSRodney W. Grimes goto dropfrag; 815df8bae1dSRodney W. Grimes fp = mtod(t, struct ipq *); 816194a213eSAndrey A. Chernov insque(fp, where); 817194a213eSAndrey A. Chernov nipq++; 818df8bae1dSRodney W. Grimes fp->ipq_ttl = IPFRAGTTL; 819df8bae1dSRodney W. Grimes fp->ipq_p = ip->ip_p; 820df8bae1dSRodney W. Grimes fp->ipq_id = ip->ip_id; 8216effc713SDoug Rabson fp->ipq_src = ip->ip_src; 8226effc713SDoug Rabson fp->ipq_dst = ip->ip_dst; 823af38c68cSLuigi Rizzo fp->ipq_frags = m; 824af38c68cSLuigi Rizzo m->m_nextpkt = NULL; 82593e0e116SJulian Elischer #ifdef IPDIVERT 8268948e4baSArchie Cobbs fp->ipq_div_info = 0; 827bb60f459SJulian Elischer fp->ipq_div_cookie = 0; 82893e0e116SJulian Elischer #endif 829af38c68cSLuigi Rizzo goto inserted; 830df8bae1dSRodney W. Grimes } 831df8bae1dSRodney W. Grimes 8326effc713SDoug Rabson #define GETIP(m) ((struct ip*)((m)->m_pkthdr.header)) 8336effc713SDoug Rabson 834df8bae1dSRodney W. Grimes /* 835df8bae1dSRodney W. Grimes * Find a segment which begins after this one does. 836df8bae1dSRodney W. Grimes */ 8376effc713SDoug Rabson for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) 8386effc713SDoug Rabson if (GETIP(q)->ip_off > ip->ip_off) 839df8bae1dSRodney W. Grimes break; 840df8bae1dSRodney W. Grimes 841df8bae1dSRodney W. Grimes /* 842df8bae1dSRodney W. Grimes * If there is a preceding segment, it may provide some of 843df8bae1dSRodney W. Grimes * our data already. If so, drop the data from the incoming 844af38c68cSLuigi Rizzo * segment. If it provides all of our data, drop us, otherwise 845af38c68cSLuigi Rizzo * stick new segment in the proper place. 846db4f9cc7SJonathan Lemon * 847db4f9cc7SJonathan Lemon * If some of the data is dropped from the the preceding 848db4f9cc7SJonathan Lemon * segment, then it's checksum is invalidated. 849df8bae1dSRodney W. Grimes */ 8506effc713SDoug Rabson if (p) { 8516effc713SDoug Rabson i = GETIP(p)->ip_off + GETIP(p)->ip_len - ip->ip_off; 852df8bae1dSRodney W. Grimes if (i > 0) { 853df8bae1dSRodney W. Grimes if (i >= ip->ip_len) 854df8bae1dSRodney W. Grimes goto dropfrag; 8556a800098SYoshinobu Inoue m_adj(m, i); 856db4f9cc7SJonathan Lemon m->m_pkthdr.csum_flags = 0; 857df8bae1dSRodney W. Grimes ip->ip_off += i; 858df8bae1dSRodney W. Grimes ip->ip_len -= i; 859df8bae1dSRodney W. Grimes } 860af38c68cSLuigi Rizzo m->m_nextpkt = p->m_nextpkt; 861af38c68cSLuigi Rizzo p->m_nextpkt = m; 862af38c68cSLuigi Rizzo } else { 863af38c68cSLuigi Rizzo m->m_nextpkt = fp->ipq_frags; 864af38c68cSLuigi Rizzo fp->ipq_frags = m; 865df8bae1dSRodney W. Grimes } 866df8bae1dSRodney W. Grimes 867df8bae1dSRodney W. Grimes /* 868df8bae1dSRodney W. Grimes * While we overlap succeeding segments trim them or, 869df8bae1dSRodney W. Grimes * if they are completely covered, dequeue them. 870df8bae1dSRodney W. Grimes */ 8716effc713SDoug Rabson for (; q != NULL && ip->ip_off + ip->ip_len > GETIP(q)->ip_off; 872af38c68cSLuigi Rizzo q = nq) { 8736effc713SDoug Rabson i = (ip->ip_off + ip->ip_len) - 8746effc713SDoug Rabson GETIP(q)->ip_off; 8756effc713SDoug Rabson if (i < GETIP(q)->ip_len) { 8766effc713SDoug Rabson GETIP(q)->ip_len -= i; 8776effc713SDoug Rabson GETIP(q)->ip_off += i; 8786effc713SDoug Rabson m_adj(q, i); 879db4f9cc7SJonathan Lemon q->m_pkthdr.csum_flags = 0; 880df8bae1dSRodney W. Grimes break; 881df8bae1dSRodney W. Grimes } 8826effc713SDoug Rabson nq = q->m_nextpkt; 883af38c68cSLuigi Rizzo m->m_nextpkt = nq; 8846effc713SDoug Rabson m_freem(q); 885df8bae1dSRodney W. Grimes } 886df8bae1dSRodney W. Grimes 887af38c68cSLuigi Rizzo inserted: 88893e0e116SJulian Elischer 88993e0e116SJulian Elischer #ifdef IPDIVERT 89093e0e116SJulian Elischer /* 8918948e4baSArchie Cobbs * Transfer firewall instructions to the fragment structure. 8928948e4baSArchie Cobbs * Any fragment diverting causes the whole packet to divert. 89393e0e116SJulian Elischer */ 8948948e4baSArchie Cobbs fp->ipq_div_info = *divinfo; 8958948e4baSArchie Cobbs fp->ipq_div_cookie = *divcookie; 8968948e4baSArchie Cobbs *divinfo = 0; 8978948e4baSArchie Cobbs *divcookie = 0; 89893e0e116SJulian Elischer #endif 89993e0e116SJulian Elischer 900df8bae1dSRodney W. Grimes /* 901af38c68cSLuigi Rizzo * Check for complete reassembly. 902df8bae1dSRodney W. Grimes */ 9036effc713SDoug Rabson next = 0; 9046effc713SDoug Rabson for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) { 9056effc713SDoug Rabson if (GETIP(q)->ip_off != next) 9066effc713SDoug Rabson return (0); 9076effc713SDoug Rabson next += GETIP(q)->ip_len; 9086effc713SDoug Rabson } 9096effc713SDoug Rabson /* Make sure the last packet didn't have the IP_MF flag */ 9106effc713SDoug Rabson if (p->m_flags & M_FRAG) 911df8bae1dSRodney W. Grimes return (0); 912df8bae1dSRodney W. Grimes 913df8bae1dSRodney W. Grimes /* 914430d30d8SBill Fenner * Reassembly is complete. Make sure the packet is a sane size. 915430d30d8SBill Fenner */ 9166effc713SDoug Rabson q = fp->ipq_frags; 9176effc713SDoug Rabson ip = GETIP(q); 9186effc713SDoug Rabson if (next + (IP_VHL_HL(ip->ip_vhl) << 2) > IP_MAXPACKET) { 919430d30d8SBill Fenner ipstat.ips_toolong++; 920430d30d8SBill Fenner ip_freef(fp); 921430d30d8SBill Fenner return (0); 922430d30d8SBill Fenner } 923430d30d8SBill Fenner 924430d30d8SBill Fenner /* 925430d30d8SBill Fenner * Concatenate fragments. 926df8bae1dSRodney W. Grimes */ 9276effc713SDoug Rabson m = q; 928df8bae1dSRodney W. Grimes t = m->m_next; 929df8bae1dSRodney W. Grimes m->m_next = 0; 930df8bae1dSRodney W. Grimes m_cat(m, t); 9316effc713SDoug Rabson nq = q->m_nextpkt; 932945aa40dSDoug Rabson q->m_nextpkt = 0; 9336effc713SDoug Rabson for (q = nq; q != NULL; q = nq) { 9346effc713SDoug Rabson nq = q->m_nextpkt; 935945aa40dSDoug Rabson q->m_nextpkt = NULL; 936db4f9cc7SJonathan Lemon m->m_pkthdr.csum_flags &= q->m_pkthdr.csum_flags; 937db4f9cc7SJonathan Lemon m->m_pkthdr.csum_data += q->m_pkthdr.csum_data; 938a8db1d93SJonathan Lemon m_cat(m, q); 939df8bae1dSRodney W. Grimes } 940df8bae1dSRodney W. Grimes 94193e0e116SJulian Elischer #ifdef IPDIVERT 94293e0e116SJulian Elischer /* 9438948e4baSArchie Cobbs * Extract firewall instructions from the fragment structure. 94493e0e116SJulian Elischer */ 9458948e4baSArchie Cobbs *divinfo = fp->ipq_div_info; 9468948e4baSArchie Cobbs *divcookie = fp->ipq_div_cookie; 94793e0e116SJulian Elischer #endif 94893e0e116SJulian Elischer 949df8bae1dSRodney W. Grimes /* 950df8bae1dSRodney W. Grimes * Create header for new ip packet by 951df8bae1dSRodney W. Grimes * modifying header of first packet; 952df8bae1dSRodney W. Grimes * dequeue and discard fragment reassembly header. 953df8bae1dSRodney W. Grimes * Make header visible. 954df8bae1dSRodney W. Grimes */ 955df8bae1dSRodney W. Grimes ip->ip_len = next; 9566effc713SDoug Rabson ip->ip_src = fp->ipq_src; 9576effc713SDoug Rabson ip->ip_dst = fp->ipq_dst; 958df8bae1dSRodney W. Grimes remque(fp); 959194a213eSAndrey A. Chernov nipq--; 960df8bae1dSRodney W. Grimes (void) m_free(dtom(fp)); 9616effc713SDoug Rabson m->m_len += (IP_VHL_HL(ip->ip_vhl) << 2); 9626effc713SDoug Rabson m->m_data -= (IP_VHL_HL(ip->ip_vhl) << 2); 963df8bae1dSRodney W. Grimes /* some debugging cruft by sklower, below, will go away soon */ 964df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) { /* XXX this should be done elsewhere */ 965df8bae1dSRodney W. Grimes register int plen = 0; 9666a800098SYoshinobu Inoue for (t = m; t; t = t->m_next) 9676a800098SYoshinobu Inoue plen += t->m_len; 9686a800098SYoshinobu Inoue m->m_pkthdr.len = plen; 969df8bae1dSRodney W. Grimes } 9706a800098SYoshinobu Inoue return (m); 971df8bae1dSRodney W. Grimes 972df8bae1dSRodney W. Grimes dropfrag: 973efe39c6aSJulian Elischer #ifdef IPDIVERT 9748948e4baSArchie Cobbs *divinfo = 0; 9758948e4baSArchie Cobbs *divcookie = 0; 976efe39c6aSJulian Elischer #endif 977df8bae1dSRodney W. Grimes ipstat.ips_fragdropped++; 978df8bae1dSRodney W. Grimes m_freem(m); 979df8bae1dSRodney W. Grimes return (0); 9806effc713SDoug Rabson 9816effc713SDoug Rabson #undef GETIP 982df8bae1dSRodney W. Grimes } 983df8bae1dSRodney W. Grimes 984df8bae1dSRodney W. Grimes /* 985df8bae1dSRodney W. Grimes * Free a fragment reassembly header and all 986df8bae1dSRodney W. Grimes * associated datagrams. 987df8bae1dSRodney W. Grimes */ 9880312fbe9SPoul-Henning Kamp static void 989df8bae1dSRodney W. Grimes ip_freef(fp) 990df8bae1dSRodney W. Grimes struct ipq *fp; 991df8bae1dSRodney W. Grimes { 9926effc713SDoug Rabson register struct mbuf *q; 993df8bae1dSRodney W. Grimes 9946effc713SDoug Rabson while (fp->ipq_frags) { 9956effc713SDoug Rabson q = fp->ipq_frags; 9966effc713SDoug Rabson fp->ipq_frags = q->m_nextpkt; 9976effc713SDoug Rabson m_freem(q); 998df8bae1dSRodney W. Grimes } 999df8bae1dSRodney W. Grimes remque(fp); 1000df8bae1dSRodney W. Grimes (void) m_free(dtom(fp)); 1001194a213eSAndrey A. Chernov nipq--; 1002df8bae1dSRodney W. Grimes } 1003df8bae1dSRodney W. Grimes 1004df8bae1dSRodney W. Grimes /* 1005df8bae1dSRodney W. Grimes * IP timer processing; 1006df8bae1dSRodney W. Grimes * if a timer expires on a reassembly 1007df8bae1dSRodney W. Grimes * queue, discard it. 1008df8bae1dSRodney W. Grimes */ 1009df8bae1dSRodney W. Grimes void 1010df8bae1dSRodney W. Grimes ip_slowtimo() 1011df8bae1dSRodney W. Grimes { 1012df8bae1dSRodney W. Grimes register struct ipq *fp; 1013df8bae1dSRodney W. Grimes int s = splnet(); 1014194a213eSAndrey A. Chernov int i; 1015df8bae1dSRodney W. Grimes 1016194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 1017194a213eSAndrey A. Chernov fp = ipq[i].next; 1018194a213eSAndrey A. Chernov if (fp == 0) 1019194a213eSAndrey A. Chernov continue; 1020194a213eSAndrey A. Chernov while (fp != &ipq[i]) { 1021df8bae1dSRodney W. Grimes --fp->ipq_ttl; 1022df8bae1dSRodney W. Grimes fp = fp->next; 1023df8bae1dSRodney W. Grimes if (fp->prev->ipq_ttl == 0) { 1024df8bae1dSRodney W. Grimes ipstat.ips_fragtimeout++; 1025df8bae1dSRodney W. Grimes ip_freef(fp->prev); 1026df8bae1dSRodney W. Grimes } 1027df8bae1dSRodney W. Grimes } 1028194a213eSAndrey A. Chernov } 10291f91d8c5SDavid Greenman ipflow_slowtimo(); 1030df8bae1dSRodney W. Grimes splx(s); 1031df8bae1dSRodney W. Grimes } 1032df8bae1dSRodney W. Grimes 1033df8bae1dSRodney W. Grimes /* 1034df8bae1dSRodney W. Grimes * Drain off all datagram fragments. 1035df8bae1dSRodney W. Grimes */ 1036df8bae1dSRodney W. Grimes void 1037df8bae1dSRodney W. Grimes ip_drain() 1038df8bae1dSRodney W. Grimes { 1039194a213eSAndrey A. Chernov int i; 1040ce29ab3aSGarrett Wollman 1041194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 1042194a213eSAndrey A. Chernov while (ipq[i].next != &ipq[i]) { 1043194a213eSAndrey A. Chernov ipstat.ips_fragdropped++; 1044194a213eSAndrey A. Chernov ip_freef(ipq[i].next); 1045194a213eSAndrey A. Chernov } 1046194a213eSAndrey A. Chernov } 1047ce29ab3aSGarrett Wollman in_rtqdrain(); 1048df8bae1dSRodney W. Grimes } 1049df8bae1dSRodney W. Grimes 1050df8bae1dSRodney W. Grimes /* 1051df8bae1dSRodney W. Grimes * Do option processing on a datagram, 1052df8bae1dSRodney W. Grimes * possibly discarding it if bad options are encountered, 1053df8bae1dSRodney W. Grimes * or forwarding it if source-routed. 1054df8bae1dSRodney W. Grimes * Returns 1 if packet has been forwarded/freed, 1055df8bae1dSRodney W. Grimes * 0 if the packet should be processed further. 1056df8bae1dSRodney W. Grimes */ 10570312fbe9SPoul-Henning Kamp static int 1058df8bae1dSRodney W. Grimes ip_dooptions(m) 1059df8bae1dSRodney W. Grimes struct mbuf *m; 1060df8bae1dSRodney W. Grimes { 1061df8bae1dSRodney W. Grimes register struct ip *ip = mtod(m, struct ip *); 1062df8bae1dSRodney W. Grimes register u_char *cp; 1063df8bae1dSRodney W. Grimes register struct ip_timestamp *ipt; 1064df8bae1dSRodney W. Grimes register struct in_ifaddr *ia; 1065df8bae1dSRodney W. Grimes int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0; 1066df8bae1dSRodney W. Grimes struct in_addr *sin, dst; 1067df8bae1dSRodney W. Grimes n_time ntime; 1068df8bae1dSRodney W. Grimes 1069df8bae1dSRodney W. Grimes dst = ip->ip_dst; 1070df8bae1dSRodney W. Grimes cp = (u_char *)(ip + 1); 107158938916SGarrett Wollman cnt = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip); 1072df8bae1dSRodney W. Grimes for (; cnt > 0; cnt -= optlen, cp += optlen) { 1073df8bae1dSRodney W. Grimes opt = cp[IPOPT_OPTVAL]; 1074df8bae1dSRodney W. Grimes if (opt == IPOPT_EOL) 1075df8bae1dSRodney W. Grimes break; 1076df8bae1dSRodney W. Grimes if (opt == IPOPT_NOP) 1077df8bae1dSRodney W. Grimes optlen = 1; 1078df8bae1dSRodney W. Grimes else { 1079fdcb8debSJun-ichiro itojun Hagino if (cnt < IPOPT_OLEN + sizeof(*cp)) { 1080fdcb8debSJun-ichiro itojun Hagino code = &cp[IPOPT_OLEN] - (u_char *)ip; 1081fdcb8debSJun-ichiro itojun Hagino goto bad; 1082fdcb8debSJun-ichiro itojun Hagino } 1083df8bae1dSRodney W. Grimes optlen = cp[IPOPT_OLEN]; 1084707d00a3SJonathan Lemon if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt) { 1085df8bae1dSRodney W. Grimes code = &cp[IPOPT_OLEN] - (u_char *)ip; 1086df8bae1dSRodney W. Grimes goto bad; 1087df8bae1dSRodney W. Grimes } 1088df8bae1dSRodney W. Grimes } 1089df8bae1dSRodney W. Grimes switch (opt) { 1090df8bae1dSRodney W. Grimes 1091df8bae1dSRodney W. Grimes default: 1092df8bae1dSRodney W. Grimes break; 1093df8bae1dSRodney W. Grimes 1094df8bae1dSRodney W. Grimes /* 1095df8bae1dSRodney W. Grimes * Source routing with record. 1096df8bae1dSRodney W. Grimes * Find interface with current destination address. 1097df8bae1dSRodney W. Grimes * If none on this machine then drop if strictly routed, 1098df8bae1dSRodney W. Grimes * or do nothing if loosely routed. 1099df8bae1dSRodney W. Grimes * Record interface address and bring up next address 1100df8bae1dSRodney W. Grimes * component. If strictly routed make sure next 1101df8bae1dSRodney W. Grimes * address is on directly accessible net. 1102df8bae1dSRodney W. Grimes */ 1103df8bae1dSRodney W. Grimes case IPOPT_LSRR: 1104df8bae1dSRodney W. Grimes case IPOPT_SSRR: 1105df8bae1dSRodney W. Grimes if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { 1106df8bae1dSRodney W. Grimes code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1107df8bae1dSRodney W. Grimes goto bad; 1108df8bae1dSRodney W. Grimes } 1109df8bae1dSRodney W. Grimes ipaddr.sin_addr = ip->ip_dst; 1110df8bae1dSRodney W. Grimes ia = (struct in_ifaddr *) 1111df8bae1dSRodney W. Grimes ifa_ifwithaddr((struct sockaddr *)&ipaddr); 1112df8bae1dSRodney W. Grimes if (ia == 0) { 1113df8bae1dSRodney W. Grimes if (opt == IPOPT_SSRR) { 1114df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1115df8bae1dSRodney W. Grimes code = ICMP_UNREACH_SRCFAIL; 1116df8bae1dSRodney W. Grimes goto bad; 1117df8bae1dSRodney W. Grimes } 1118bc189bf8SGuido van Rooij if (!ip_dosourceroute) 1119bc189bf8SGuido van Rooij goto nosourcerouting; 1120df8bae1dSRodney W. Grimes /* 1121df8bae1dSRodney W. Grimes * Loose routing, and not at next destination 1122df8bae1dSRodney W. Grimes * yet; nothing to do except forward. 1123df8bae1dSRodney W. Grimes */ 1124df8bae1dSRodney W. Grimes break; 1125df8bae1dSRodney W. Grimes } 1126df8bae1dSRodney W. Grimes off--; /* 0 origin */ 11275d5d5fc0SJonathan Lemon if (off > optlen - (int)sizeof(struct in_addr)) { 1128df8bae1dSRodney W. Grimes /* 1129df8bae1dSRodney W. Grimes * End of source route. Should be for us. 1130df8bae1dSRodney W. Grimes */ 11314fce5804SGuido van Rooij if (!ip_acceptsourceroute) 11324fce5804SGuido van Rooij goto nosourcerouting; 1133df8bae1dSRodney W. Grimes save_rte(cp, ip->ip_src); 1134df8bae1dSRodney W. Grimes break; 1135df8bae1dSRodney W. Grimes } 11361025071fSGarrett Wollman 11371025071fSGarrett Wollman if (!ip_dosourceroute) { 11380af8d3ecSDavid Greenman if (ipforwarding) { 11390af8d3ecSDavid Greenman char buf[16]; /* aaa.bbb.ccc.ddd\0 */ 11400af8d3ecSDavid Greenman /* 11410af8d3ecSDavid Greenman * Acting as a router, so generate ICMP 11420af8d3ecSDavid Greenman */ 1143efa48587SGuido van Rooij nosourcerouting: 1144bc189bf8SGuido van Rooij strcpy(buf, inet_ntoa(ip->ip_dst)); 11451025071fSGarrett Wollman log(LOG_WARNING, 11461025071fSGarrett Wollman "attempted source route from %s to %s\n", 11471025071fSGarrett Wollman inet_ntoa(ip->ip_src), buf); 11481025071fSGarrett Wollman type = ICMP_UNREACH; 11491025071fSGarrett Wollman code = ICMP_UNREACH_SRCFAIL; 11501025071fSGarrett Wollman goto bad; 11510af8d3ecSDavid Greenman } else { 11520af8d3ecSDavid Greenman /* 11530af8d3ecSDavid Greenman * Not acting as a router, so silently drop. 11540af8d3ecSDavid Greenman */ 11550af8d3ecSDavid Greenman ipstat.ips_cantforward++; 11560af8d3ecSDavid Greenman m_freem(m); 11570af8d3ecSDavid Greenman return (1); 11580af8d3ecSDavid Greenman } 11591025071fSGarrett Wollman } 11601025071fSGarrett Wollman 1161df8bae1dSRodney W. Grimes /* 1162df8bae1dSRodney W. Grimes * locate outgoing interface 1163df8bae1dSRodney W. Grimes */ 116494a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, cp + off, 1165df8bae1dSRodney W. Grimes sizeof(ipaddr.sin_addr)); 11661025071fSGarrett Wollman 1167df8bae1dSRodney W. Grimes if (opt == IPOPT_SSRR) { 1168df8bae1dSRodney W. Grimes #define INA struct in_ifaddr * 1169df8bae1dSRodney W. Grimes #define SA struct sockaddr * 1170df8bae1dSRodney W. Grimes if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0) 1171df8bae1dSRodney W. Grimes ia = (INA)ifa_ifwithnet((SA)&ipaddr); 1172df8bae1dSRodney W. Grimes } else 1173df8bae1dSRodney W. Grimes ia = ip_rtaddr(ipaddr.sin_addr); 1174df8bae1dSRodney W. Grimes if (ia == 0) { 1175df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1176df8bae1dSRodney W. Grimes code = ICMP_UNREACH_SRCFAIL; 1177df8bae1dSRodney W. Grimes goto bad; 1178df8bae1dSRodney W. Grimes } 1179df8bae1dSRodney W. Grimes ip->ip_dst = ipaddr.sin_addr; 118094a5d9b6SDavid Greenman (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr), 118194a5d9b6SDavid Greenman sizeof(struct in_addr)); 1182df8bae1dSRodney W. Grimes cp[IPOPT_OFFSET] += sizeof(struct in_addr); 1183df8bae1dSRodney W. Grimes /* 1184df8bae1dSRodney W. Grimes * Let ip_intr's mcast routing check handle mcast pkts 1185df8bae1dSRodney W. Grimes */ 1186df8bae1dSRodney W. Grimes forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr)); 1187df8bae1dSRodney W. Grimes break; 1188df8bae1dSRodney W. Grimes 1189df8bae1dSRodney W. Grimes case IPOPT_RR: 1190707d00a3SJonathan Lemon if (optlen < IPOPT_OFFSET + sizeof(*cp)) { 1191707d00a3SJonathan Lemon code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1192707d00a3SJonathan Lemon goto bad; 1193707d00a3SJonathan Lemon } 1194df8bae1dSRodney W. Grimes if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { 1195df8bae1dSRodney W. Grimes code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1196df8bae1dSRodney W. Grimes goto bad; 1197df8bae1dSRodney W. Grimes } 1198df8bae1dSRodney W. Grimes /* 1199df8bae1dSRodney W. Grimes * If no space remains, ignore. 1200df8bae1dSRodney W. Grimes */ 1201df8bae1dSRodney W. Grimes off--; /* 0 origin */ 12025d5d5fc0SJonathan Lemon if (off > optlen - (int)sizeof(struct in_addr)) 1203df8bae1dSRodney W. Grimes break; 120494a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, &ip->ip_dst, 1205df8bae1dSRodney W. Grimes sizeof(ipaddr.sin_addr)); 1206df8bae1dSRodney W. Grimes /* 1207df8bae1dSRodney W. Grimes * locate outgoing interface; if we're the destination, 1208df8bae1dSRodney W. Grimes * use the incoming interface (should be same). 1209df8bae1dSRodney W. Grimes */ 1210df8bae1dSRodney W. Grimes if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 && 1211df8bae1dSRodney W. Grimes (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) { 1212df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1213df8bae1dSRodney W. Grimes code = ICMP_UNREACH_HOST; 1214df8bae1dSRodney W. Grimes goto bad; 1215df8bae1dSRodney W. Grimes } 121694a5d9b6SDavid Greenman (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr), 121794a5d9b6SDavid Greenman sizeof(struct in_addr)); 1218df8bae1dSRodney W. Grimes cp[IPOPT_OFFSET] += sizeof(struct in_addr); 1219df8bae1dSRodney W. Grimes break; 1220df8bae1dSRodney W. Grimes 1221df8bae1dSRodney W. Grimes case IPOPT_TS: 1222df8bae1dSRodney W. Grimes code = cp - (u_char *)ip; 1223df8bae1dSRodney W. Grimes ipt = (struct ip_timestamp *)cp; 1224df8bae1dSRodney W. Grimes if (ipt->ipt_len < 5) 1225df8bae1dSRodney W. Grimes goto bad; 12265d5d5fc0SJonathan Lemon if (ipt->ipt_ptr > 12275d5d5fc0SJonathan Lemon ipt->ipt_len - (int)sizeof(int32_t)) { 1228df8bae1dSRodney W. Grimes if (++ipt->ipt_oflw == 0) 1229df8bae1dSRodney W. Grimes goto bad; 1230df8bae1dSRodney W. Grimes break; 1231df8bae1dSRodney W. Grimes } 1232df8bae1dSRodney W. Grimes sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1); 1233df8bae1dSRodney W. Grimes switch (ipt->ipt_flg) { 1234df8bae1dSRodney W. Grimes 1235df8bae1dSRodney W. Grimes case IPOPT_TS_TSONLY: 1236df8bae1dSRodney W. Grimes break; 1237df8bae1dSRodney W. Grimes 1238df8bae1dSRodney W. Grimes case IPOPT_TS_TSANDADDR: 1239b8e8c209SDavid Greenman if (ipt->ipt_ptr - 1 + sizeof(n_time) + 1240df8bae1dSRodney W. Grimes sizeof(struct in_addr) > ipt->ipt_len) 1241df8bae1dSRodney W. Grimes goto bad; 1242df8bae1dSRodney W. Grimes ipaddr.sin_addr = dst; 1243df8bae1dSRodney W. Grimes ia = (INA)ifaof_ifpforaddr((SA)&ipaddr, 1244df8bae1dSRodney W. Grimes m->m_pkthdr.rcvif); 1245df8bae1dSRodney W. Grimes if (ia == 0) 1246df8bae1dSRodney W. Grimes continue; 124794a5d9b6SDavid Greenman (void)memcpy(sin, &IA_SIN(ia)->sin_addr, 124894a5d9b6SDavid Greenman sizeof(struct in_addr)); 1249df8bae1dSRodney W. Grimes ipt->ipt_ptr += sizeof(struct in_addr); 1250df8bae1dSRodney W. Grimes break; 1251df8bae1dSRodney W. Grimes 1252df8bae1dSRodney W. Grimes case IPOPT_TS_PRESPEC: 1253b8e8c209SDavid Greenman if (ipt->ipt_ptr - 1 + sizeof(n_time) + 1254df8bae1dSRodney W. Grimes sizeof(struct in_addr) > ipt->ipt_len) 1255df8bae1dSRodney W. Grimes goto bad; 125694a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, sin, 1257df8bae1dSRodney W. Grimes sizeof(struct in_addr)); 1258df8bae1dSRodney W. Grimes if (ifa_ifwithaddr((SA)&ipaddr) == 0) 1259df8bae1dSRodney W. Grimes continue; 1260df8bae1dSRodney W. Grimes ipt->ipt_ptr += sizeof(struct in_addr); 1261df8bae1dSRodney W. Grimes break; 1262df8bae1dSRodney W. Grimes 1263df8bae1dSRodney W. Grimes default: 1264df8bae1dSRodney W. Grimes goto bad; 1265df8bae1dSRodney W. Grimes } 1266df8bae1dSRodney W. Grimes ntime = iptime(); 126794a5d9b6SDavid Greenman (void)memcpy(cp + ipt->ipt_ptr - 1, &ntime, 1268df8bae1dSRodney W. Grimes sizeof(n_time)); 1269df8bae1dSRodney W. Grimes ipt->ipt_ptr += sizeof(n_time); 1270df8bae1dSRodney W. Grimes } 1271df8bae1dSRodney W. Grimes } 127247174b49SAndrey A. Chernov if (forward && ipforwarding) { 1273df8bae1dSRodney W. Grimes ip_forward(m, 1); 1274df8bae1dSRodney W. Grimes return (1); 1275df8bae1dSRodney W. Grimes } 1276df8bae1dSRodney W. Grimes return (0); 1277df8bae1dSRodney W. Grimes bad: 1278df8bae1dSRodney W. Grimes icmp_error(m, type, code, 0, 0); 1279df8bae1dSRodney W. Grimes ipstat.ips_badoptions++; 1280df8bae1dSRodney W. Grimes return (1); 1281df8bae1dSRodney W. Grimes } 1282df8bae1dSRodney W. Grimes 1283df8bae1dSRodney W. Grimes /* 1284df8bae1dSRodney W. Grimes * Given address of next destination (final or next hop), 1285df8bae1dSRodney W. Grimes * return internet address info of interface to be used to get there. 1286df8bae1dSRodney W. Grimes */ 12870312fbe9SPoul-Henning Kamp static struct in_ifaddr * 1288df8bae1dSRodney W. Grimes ip_rtaddr(dst) 1289df8bae1dSRodney W. Grimes struct in_addr dst; 1290df8bae1dSRodney W. Grimes { 1291df8bae1dSRodney W. Grimes register struct sockaddr_in *sin; 1292df8bae1dSRodney W. Grimes 1293df8bae1dSRodney W. Grimes sin = (struct sockaddr_in *) &ipforward_rt.ro_dst; 1294df8bae1dSRodney W. Grimes 1295df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt == 0 || dst.s_addr != sin->sin_addr.s_addr) { 1296df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt) { 1297df8bae1dSRodney W. Grimes RTFREE(ipforward_rt.ro_rt); 1298df8bae1dSRodney W. Grimes ipforward_rt.ro_rt = 0; 1299df8bae1dSRodney W. Grimes } 1300df8bae1dSRodney W. Grimes sin->sin_family = AF_INET; 1301df8bae1dSRodney W. Grimes sin->sin_len = sizeof(*sin); 1302df8bae1dSRodney W. Grimes sin->sin_addr = dst; 1303df8bae1dSRodney W. Grimes 13042c17fe93SGarrett Wollman rtalloc_ign(&ipforward_rt, RTF_PRCLONING); 1305df8bae1dSRodney W. Grimes } 1306df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt == 0) 1307df8bae1dSRodney W. Grimes return ((struct in_ifaddr *)0); 1308df8bae1dSRodney W. Grimes return ((struct in_ifaddr *) ipforward_rt.ro_rt->rt_ifa); 1309df8bae1dSRodney W. Grimes } 1310df8bae1dSRodney W. Grimes 1311df8bae1dSRodney W. Grimes /* 1312df8bae1dSRodney W. Grimes * Save incoming source route for use in replies, 1313df8bae1dSRodney W. Grimes * to be picked up later by ip_srcroute if the receiver is interested. 1314df8bae1dSRodney W. Grimes */ 1315df8bae1dSRodney W. Grimes void 1316df8bae1dSRodney W. Grimes save_rte(option, dst) 1317df8bae1dSRodney W. Grimes u_char *option; 1318df8bae1dSRodney W. Grimes struct in_addr dst; 1319df8bae1dSRodney W. Grimes { 1320df8bae1dSRodney W. Grimes unsigned olen; 1321df8bae1dSRodney W. Grimes 1322df8bae1dSRodney W. Grimes olen = option[IPOPT_OLEN]; 1323df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1324df8bae1dSRodney W. Grimes if (ipprintfs) 1325df8bae1dSRodney W. Grimes printf("save_rte: olen %d\n", olen); 1326df8bae1dSRodney W. Grimes #endif 1327df8bae1dSRodney W. Grimes if (olen > sizeof(ip_srcrt) - (1 + sizeof(dst))) 1328df8bae1dSRodney W. Grimes return; 13290453d3cbSBruce Evans bcopy(option, ip_srcrt.srcopt, olen); 1330df8bae1dSRodney W. Grimes ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr); 1331df8bae1dSRodney W. Grimes ip_srcrt.dst = dst; 1332df8bae1dSRodney W. Grimes } 1333df8bae1dSRodney W. Grimes 1334df8bae1dSRodney W. Grimes /* 1335df8bae1dSRodney W. Grimes * Retrieve incoming source route for use in replies, 1336df8bae1dSRodney W. Grimes * in the same form used by setsockopt. 1337df8bae1dSRodney W. Grimes * The first hop is placed before the options, will be removed later. 1338df8bae1dSRodney W. Grimes */ 1339df8bae1dSRodney W. Grimes struct mbuf * 1340df8bae1dSRodney W. Grimes ip_srcroute() 1341df8bae1dSRodney W. Grimes { 1342df8bae1dSRodney W. Grimes register struct in_addr *p, *q; 1343df8bae1dSRodney W. Grimes register struct mbuf *m; 1344df8bae1dSRodney W. Grimes 1345df8bae1dSRodney W. Grimes if (ip_nhops == 0) 1346df8bae1dSRodney W. Grimes return ((struct mbuf *)0); 1347cfe8b629SGarrett Wollman m = m_get(M_DONTWAIT, MT_HEADER); 1348df8bae1dSRodney W. Grimes if (m == 0) 1349df8bae1dSRodney W. Grimes return ((struct mbuf *)0); 1350df8bae1dSRodney W. Grimes 1351df8bae1dSRodney W. Grimes #define OPTSIZ (sizeof(ip_srcrt.nop) + sizeof(ip_srcrt.srcopt)) 1352df8bae1dSRodney W. Grimes 1353df8bae1dSRodney W. Grimes /* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */ 1354df8bae1dSRodney W. Grimes m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) + 1355df8bae1dSRodney W. Grimes OPTSIZ; 1356df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1357df8bae1dSRodney W. Grimes if (ipprintfs) 1358df8bae1dSRodney W. Grimes printf("ip_srcroute: nhops %d mlen %d", ip_nhops, m->m_len); 1359df8bae1dSRodney W. Grimes #endif 1360df8bae1dSRodney W. Grimes 1361df8bae1dSRodney W. Grimes /* 1362df8bae1dSRodney W. Grimes * First save first hop for return route 1363df8bae1dSRodney W. Grimes */ 1364df8bae1dSRodney W. Grimes p = &ip_srcrt.route[ip_nhops - 1]; 1365df8bae1dSRodney W. Grimes *(mtod(m, struct in_addr *)) = *p--; 1366df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1367df8bae1dSRodney W. Grimes if (ipprintfs) 1368af38c68cSLuigi Rizzo printf(" hops %lx", (u_long)ntohl(mtod(m, struct in_addr *)->s_addr)); 1369df8bae1dSRodney W. Grimes #endif 1370df8bae1dSRodney W. Grimes 1371df8bae1dSRodney W. Grimes /* 1372df8bae1dSRodney W. Grimes * Copy option fields and padding (nop) to mbuf. 1373df8bae1dSRodney W. Grimes */ 1374df8bae1dSRodney W. Grimes ip_srcrt.nop = IPOPT_NOP; 1375df8bae1dSRodney W. Grimes ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF; 137694a5d9b6SDavid Greenman (void)memcpy(mtod(m, caddr_t) + sizeof(struct in_addr), 137794a5d9b6SDavid Greenman &ip_srcrt.nop, OPTSIZ); 1378df8bae1dSRodney W. Grimes q = (struct in_addr *)(mtod(m, caddr_t) + 1379df8bae1dSRodney W. Grimes sizeof(struct in_addr) + OPTSIZ); 1380df8bae1dSRodney W. Grimes #undef OPTSIZ 1381df8bae1dSRodney W. Grimes /* 1382df8bae1dSRodney W. Grimes * Record return path as an IP source route, 1383df8bae1dSRodney W. Grimes * reversing the path (pointers are now aligned). 1384df8bae1dSRodney W. Grimes */ 1385df8bae1dSRodney W. Grimes while (p >= ip_srcrt.route) { 1386df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1387df8bae1dSRodney W. Grimes if (ipprintfs) 1388af38c68cSLuigi Rizzo printf(" %lx", (u_long)ntohl(q->s_addr)); 1389df8bae1dSRodney W. Grimes #endif 1390df8bae1dSRodney W. Grimes *q++ = *p--; 1391df8bae1dSRodney W. Grimes } 1392df8bae1dSRodney W. Grimes /* 1393df8bae1dSRodney W. Grimes * Last hop goes to final destination. 1394df8bae1dSRodney W. Grimes */ 1395df8bae1dSRodney W. Grimes *q = ip_srcrt.dst; 1396df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1397df8bae1dSRodney W. Grimes if (ipprintfs) 1398af38c68cSLuigi Rizzo printf(" %lx\n", (u_long)ntohl(q->s_addr)); 1399df8bae1dSRodney W. Grimes #endif 1400df8bae1dSRodney W. Grimes return (m); 1401df8bae1dSRodney W. Grimes } 1402df8bae1dSRodney W. Grimes 1403df8bae1dSRodney W. Grimes /* 1404df8bae1dSRodney W. Grimes * Strip out IP options, at higher 1405df8bae1dSRodney W. Grimes * level protocol in the kernel. 1406df8bae1dSRodney W. Grimes * Second argument is buffer to which options 1407df8bae1dSRodney W. Grimes * will be moved, and return value is their length. 1408df8bae1dSRodney W. Grimes * XXX should be deleted; last arg currently ignored. 1409df8bae1dSRodney W. Grimes */ 1410df8bae1dSRodney W. Grimes void 1411df8bae1dSRodney W. Grimes ip_stripoptions(m, mopt) 1412df8bae1dSRodney W. Grimes register struct mbuf *m; 1413df8bae1dSRodney W. Grimes struct mbuf *mopt; 1414df8bae1dSRodney W. Grimes { 1415df8bae1dSRodney W. Grimes register int i; 1416df8bae1dSRodney W. Grimes struct ip *ip = mtod(m, struct ip *); 1417df8bae1dSRodney W. Grimes register caddr_t opts; 1418df8bae1dSRodney W. Grimes int olen; 1419df8bae1dSRodney W. Grimes 142058938916SGarrett Wollman olen = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip); 1421df8bae1dSRodney W. Grimes opts = (caddr_t)(ip + 1); 1422df8bae1dSRodney W. Grimes i = m->m_len - (sizeof (struct ip) + olen); 1423df8bae1dSRodney W. Grimes bcopy(opts + olen, opts, (unsigned)i); 1424df8bae1dSRodney W. Grimes m->m_len -= olen; 1425df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) 1426df8bae1dSRodney W. Grimes m->m_pkthdr.len -= olen; 142758938916SGarrett Wollman ip->ip_vhl = IP_MAKE_VHL(IPVERSION, sizeof(struct ip) >> 2); 1428df8bae1dSRodney W. Grimes } 1429df8bae1dSRodney W. Grimes 1430df8bae1dSRodney W. Grimes u_char inetctlerrmap[PRC_NCMDS] = { 1431df8bae1dSRodney W. Grimes 0, 0, 0, 0, 1432df8bae1dSRodney W. Grimes 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH, 1433df8bae1dSRodney W. Grimes EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, 1434df8bae1dSRodney W. Grimes EMSGSIZE, EHOSTUNREACH, 0, 0, 1435df8bae1dSRodney W. Grimes 0, 0, 0, 0, 1436e4bb5b05SJonathan Lemon ENOPROTOOPT, ENETRESET 1437df8bae1dSRodney W. Grimes }; 1438df8bae1dSRodney W. Grimes 1439df8bae1dSRodney W. Grimes /* 1440df8bae1dSRodney W. Grimes * Forward a packet. If some error occurs return the sender 1441df8bae1dSRodney W. Grimes * an icmp packet. Note we can't always generate a meaningful 1442df8bae1dSRodney W. Grimes * icmp message because icmp doesn't have a large enough repertoire 1443df8bae1dSRodney W. Grimes * of codes and types. 1444df8bae1dSRodney W. Grimes * 1445df8bae1dSRodney W. Grimes * If not forwarding, just drop the packet. This could be confusing 1446df8bae1dSRodney W. Grimes * if ipforwarding was zero but some routing protocol was advancing 1447df8bae1dSRodney W. Grimes * us as a gateway to somewhere. However, we must let the routing 1448df8bae1dSRodney W. Grimes * protocol deal with that. 1449df8bae1dSRodney W. Grimes * 1450df8bae1dSRodney W. Grimes * The srcrt parameter indicates whether the packet is being forwarded 1451df8bae1dSRodney W. Grimes * via a source route. 1452df8bae1dSRodney W. Grimes */ 14530312fbe9SPoul-Henning Kamp static void 1454df8bae1dSRodney W. Grimes ip_forward(m, srcrt) 1455df8bae1dSRodney W. Grimes struct mbuf *m; 1456df8bae1dSRodney W. Grimes int srcrt; 1457df8bae1dSRodney W. Grimes { 1458df8bae1dSRodney W. Grimes register struct ip *ip = mtod(m, struct ip *); 1459df8bae1dSRodney W. Grimes register struct sockaddr_in *sin; 1460df8bae1dSRodney W. Grimes register struct rtentry *rt; 146126f9a767SRodney W. Grimes int error, type = 0, code = 0; 1462df8bae1dSRodney W. Grimes struct mbuf *mcopy; 1463df8bae1dSRodney W. Grimes n_long dest; 1464df8bae1dSRodney W. Grimes struct ifnet *destifp; 14656a800098SYoshinobu Inoue #ifdef IPSEC 14666a800098SYoshinobu Inoue struct ifnet dummyifp; 14676a800098SYoshinobu Inoue #endif 1468df8bae1dSRodney W. Grimes 1469df8bae1dSRodney W. Grimes dest = 0; 1470df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1471df8bae1dSRodney W. Grimes if (ipprintfs) 147261ce519bSPoul-Henning Kamp printf("forward: src %lx dst %lx ttl %x\n", 1473162886e2SBruce Evans (u_long)ip->ip_src.s_addr, (u_long)ip->ip_dst.s_addr, 1474162886e2SBruce Evans ip->ip_ttl); 1475df8bae1dSRodney W. Grimes #endif 1476100ba1a6SJordan K. Hubbard 1477100ba1a6SJordan K. Hubbard 147892af003dSGarrett Wollman if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(ip->ip_dst) == 0) { 1479df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 1480df8bae1dSRodney W. Grimes m_freem(m); 1481df8bae1dSRodney W. Grimes return; 1482df8bae1dSRodney W. Grimes } 14831b968362SDag-Erling Smørgrav #ifdef IPSTEALTH 14841b968362SDag-Erling Smørgrav if (!ipstealth) { 14851b968362SDag-Erling Smørgrav #endif 1486df8bae1dSRodney W. Grimes if (ip->ip_ttl <= IPTTLDEC) { 14871b968362SDag-Erling Smørgrav icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 14881b968362SDag-Erling Smørgrav dest, 0); 1489df8bae1dSRodney W. Grimes return; 1490df8bae1dSRodney W. Grimes } 14911b968362SDag-Erling Smørgrav #ifdef IPSTEALTH 14921b968362SDag-Erling Smørgrav } 14931b968362SDag-Erling Smørgrav #endif 1494df8bae1dSRodney W. Grimes 1495df8bae1dSRodney W. Grimes sin = (struct sockaddr_in *)&ipforward_rt.ro_dst; 1496df8bae1dSRodney W. Grimes if ((rt = ipforward_rt.ro_rt) == 0 || 1497df8bae1dSRodney W. Grimes ip->ip_dst.s_addr != sin->sin_addr.s_addr) { 1498df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt) { 1499df8bae1dSRodney W. Grimes RTFREE(ipforward_rt.ro_rt); 1500df8bae1dSRodney W. Grimes ipforward_rt.ro_rt = 0; 1501df8bae1dSRodney W. Grimes } 1502df8bae1dSRodney W. Grimes sin->sin_family = AF_INET; 1503df8bae1dSRodney W. Grimes sin->sin_len = sizeof(*sin); 1504df8bae1dSRodney W. Grimes sin->sin_addr = ip->ip_dst; 1505df8bae1dSRodney W. Grimes 15062c17fe93SGarrett Wollman rtalloc_ign(&ipforward_rt, RTF_PRCLONING); 1507df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt == 0) { 1508df8bae1dSRodney W. Grimes icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0); 1509df8bae1dSRodney W. Grimes return; 1510df8bae1dSRodney W. Grimes } 1511df8bae1dSRodney W. Grimes rt = ipforward_rt.ro_rt; 1512df8bae1dSRodney W. Grimes } 1513df8bae1dSRodney W. Grimes 1514df8bae1dSRodney W. Grimes /* 1515df8bae1dSRodney W. Grimes * Save at most 64 bytes of the packet in case 1516df8bae1dSRodney W. Grimes * we need to generate an ICMP message to the src. 1517df8bae1dSRodney W. Grimes */ 1518df8bae1dSRodney W. Grimes mcopy = m_copy(m, 0, imin((int)ip->ip_len, 64)); 151904287599SRuslan Ermilov if (mcopy && (mcopy->m_flags & M_EXT)) 152004287599SRuslan Ermilov m_copydata(mcopy, 0, sizeof(struct ip), mtod(mcopy, caddr_t)); 152104287599SRuslan Ermilov 152204287599SRuslan Ermilov #ifdef IPSTEALTH 152304287599SRuslan Ermilov if (!ipstealth) { 152404287599SRuslan Ermilov #endif 152504287599SRuslan Ermilov ip->ip_ttl -= IPTTLDEC; 152604287599SRuslan Ermilov #ifdef IPSTEALTH 152704287599SRuslan Ermilov } 152804287599SRuslan Ermilov #endif 1529df8bae1dSRodney W. Grimes 1530df8bae1dSRodney W. Grimes /* 1531df8bae1dSRodney W. Grimes * If forwarding packet using same interface that it came in on, 1532df8bae1dSRodney W. Grimes * perhaps should send a redirect to sender to shortcut a hop. 1533df8bae1dSRodney W. Grimes * Only send redirect if source is sending directly to us, 1534df8bae1dSRodney W. Grimes * and if packet was not source routed (or has any options). 1535df8bae1dSRodney W. Grimes * Also, don't send redirect if forwarding using a default route 1536df8bae1dSRodney W. Grimes * or a route modified by a redirect. 1537df8bae1dSRodney W. Grimes */ 1538df8bae1dSRodney W. Grimes #define satosin(sa) ((struct sockaddr_in *)(sa)) 1539df8bae1dSRodney W. Grimes if (rt->rt_ifp == m->m_pkthdr.rcvif && 1540df8bae1dSRodney W. Grimes (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 && 1541df8bae1dSRodney W. Grimes satosin(rt_key(rt))->sin_addr.s_addr != 0 && 1542df8bae1dSRodney W. Grimes ipsendredirects && !srcrt) { 1543df8bae1dSRodney W. Grimes #define RTA(rt) ((struct in_ifaddr *)(rt->rt_ifa)) 1544df8bae1dSRodney W. Grimes u_long src = ntohl(ip->ip_src.s_addr); 1545df8bae1dSRodney W. Grimes 1546df8bae1dSRodney W. Grimes if (RTA(rt) && 1547df8bae1dSRodney W. Grimes (src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) { 1548df8bae1dSRodney W. Grimes if (rt->rt_flags & RTF_GATEWAY) 1549df8bae1dSRodney W. Grimes dest = satosin(rt->rt_gateway)->sin_addr.s_addr; 1550df8bae1dSRodney W. Grimes else 1551df8bae1dSRodney W. Grimes dest = ip->ip_dst.s_addr; 1552df8bae1dSRodney W. Grimes /* Router requirements says to only send host redirects */ 1553df8bae1dSRodney W. Grimes type = ICMP_REDIRECT; 1554df8bae1dSRodney W. Grimes code = ICMP_REDIRECT_HOST; 1555df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1556df8bae1dSRodney W. Grimes if (ipprintfs) 1557df8bae1dSRodney W. Grimes printf("redirect (%d) to %lx\n", code, (u_long)dest); 1558df8bae1dSRodney W. Grimes #endif 1559df8bae1dSRodney W. Grimes } 1560df8bae1dSRodney W. Grimes } 1561df8bae1dSRodney W. Grimes 1562b97d15cbSGarrett Wollman error = ip_output(m, (struct mbuf *)0, &ipforward_rt, 1563b97d15cbSGarrett Wollman IP_FORWARDING, 0); 1564df8bae1dSRodney W. Grimes if (error) 1565df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 1566df8bae1dSRodney W. Grimes else { 1567df8bae1dSRodney W. Grimes ipstat.ips_forward++; 1568df8bae1dSRodney W. Grimes if (type) 1569df8bae1dSRodney W. Grimes ipstat.ips_redirectsent++; 1570df8bae1dSRodney W. Grimes else { 15711f91d8c5SDavid Greenman if (mcopy) { 15721f91d8c5SDavid Greenman ipflow_create(&ipforward_rt, mcopy); 1573df8bae1dSRodney W. Grimes m_freem(mcopy); 15741f91d8c5SDavid Greenman } 1575df8bae1dSRodney W. Grimes return; 1576df8bae1dSRodney W. Grimes } 1577df8bae1dSRodney W. Grimes } 1578df8bae1dSRodney W. Grimes if (mcopy == NULL) 1579df8bae1dSRodney W. Grimes return; 1580df8bae1dSRodney W. Grimes destifp = NULL; 1581df8bae1dSRodney W. Grimes 1582df8bae1dSRodney W. Grimes switch (error) { 1583df8bae1dSRodney W. Grimes 1584df8bae1dSRodney W. Grimes case 0: /* forwarded, but need redirect */ 1585df8bae1dSRodney W. Grimes /* type, code set above */ 1586df8bae1dSRodney W. Grimes break; 1587df8bae1dSRodney W. Grimes 1588df8bae1dSRodney W. Grimes case ENETUNREACH: /* shouldn't happen, checked above */ 1589df8bae1dSRodney W. Grimes case EHOSTUNREACH: 1590df8bae1dSRodney W. Grimes case ENETDOWN: 1591df8bae1dSRodney W. Grimes case EHOSTDOWN: 1592df8bae1dSRodney W. Grimes default: 1593df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1594df8bae1dSRodney W. Grimes code = ICMP_UNREACH_HOST; 1595df8bae1dSRodney W. Grimes break; 1596df8bae1dSRodney W. Grimes 1597df8bae1dSRodney W. Grimes case EMSGSIZE: 1598df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1599df8bae1dSRodney W. Grimes code = ICMP_UNREACH_NEEDFRAG; 16006a800098SYoshinobu Inoue #ifndef IPSEC 1601df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt) 1602df8bae1dSRodney W. Grimes destifp = ipforward_rt.ro_rt->rt_ifp; 16036a800098SYoshinobu Inoue #else 16046a800098SYoshinobu Inoue /* 16056a800098SYoshinobu Inoue * If the packet is routed over IPsec tunnel, tell the 16066a800098SYoshinobu Inoue * originator the tunnel MTU. 16076a800098SYoshinobu Inoue * tunnel MTU = if MTU - sizeof(IP) - ESP/AH hdrsiz 16086a800098SYoshinobu Inoue * XXX quickhack!!! 16096a800098SYoshinobu Inoue */ 16106a800098SYoshinobu Inoue if (ipforward_rt.ro_rt) { 16116a800098SYoshinobu Inoue struct secpolicy *sp = NULL; 16126a800098SYoshinobu Inoue int ipsecerror; 16136a800098SYoshinobu Inoue int ipsechdr; 16146a800098SYoshinobu Inoue struct route *ro; 16156a800098SYoshinobu Inoue 16166a800098SYoshinobu Inoue sp = ipsec4_getpolicybyaddr(mcopy, 16176a800098SYoshinobu Inoue IPSEC_DIR_OUTBOUND, 16186a800098SYoshinobu Inoue IP_FORWARDING, 16196a800098SYoshinobu Inoue &ipsecerror); 16206a800098SYoshinobu Inoue 16216a800098SYoshinobu Inoue if (sp == NULL) 16226a800098SYoshinobu Inoue destifp = ipforward_rt.ro_rt->rt_ifp; 16236a800098SYoshinobu Inoue else { 16246a800098SYoshinobu Inoue /* count IPsec header size */ 16256a800098SYoshinobu Inoue ipsechdr = ipsec4_hdrsiz(mcopy, 16266a800098SYoshinobu Inoue IPSEC_DIR_OUTBOUND, 16276a800098SYoshinobu Inoue NULL); 16286a800098SYoshinobu Inoue 16296a800098SYoshinobu Inoue /* 16306a800098SYoshinobu Inoue * find the correct route for outer IPv4 16316a800098SYoshinobu Inoue * header, compute tunnel MTU. 16326a800098SYoshinobu Inoue * 16336a800098SYoshinobu Inoue * XXX BUG ALERT 16346a800098SYoshinobu Inoue * The "dummyifp" code relies upon the fact 16356a800098SYoshinobu Inoue * that icmp_error() touches only ifp->if_mtu. 16366a800098SYoshinobu Inoue */ 16376a800098SYoshinobu Inoue /*XXX*/ 16386a800098SYoshinobu Inoue destifp = NULL; 16396a800098SYoshinobu Inoue if (sp->req != NULL 16406a800098SYoshinobu Inoue && sp->req->sav != NULL 16416a800098SYoshinobu Inoue && sp->req->sav->sah != NULL) { 16426a800098SYoshinobu Inoue ro = &sp->req->sav->sah->sa_route; 16436a800098SYoshinobu Inoue if (ro->ro_rt && ro->ro_rt->rt_ifp) { 16446a800098SYoshinobu Inoue dummyifp.if_mtu = 16456a800098SYoshinobu Inoue ro->ro_rt->rt_ifp->if_mtu; 16466a800098SYoshinobu Inoue dummyifp.if_mtu -= ipsechdr; 16476a800098SYoshinobu Inoue destifp = &dummyifp; 16486a800098SYoshinobu Inoue } 16496a800098SYoshinobu Inoue } 16506a800098SYoshinobu Inoue 16516a800098SYoshinobu Inoue key_freesp(sp); 16526a800098SYoshinobu Inoue } 16536a800098SYoshinobu Inoue } 16546a800098SYoshinobu Inoue #endif /*IPSEC*/ 1655df8bae1dSRodney W. Grimes ipstat.ips_cantfrag++; 1656df8bae1dSRodney W. Grimes break; 1657df8bae1dSRodney W. Grimes 1658df8bae1dSRodney W. Grimes case ENOBUFS: 1659df8bae1dSRodney W. Grimes type = ICMP_SOURCEQUENCH; 1660df8bae1dSRodney W. Grimes code = 0; 1661df8bae1dSRodney W. Grimes break; 16623a06e3e0SRuslan Ermilov 16633a06e3e0SRuslan Ermilov case EACCES: /* ipfw denied packet */ 16643a06e3e0SRuslan Ermilov m_freem(mcopy); 16653a06e3e0SRuslan Ermilov return; 1666df8bae1dSRodney W. Grimes } 166704287599SRuslan Ermilov if (mcopy->m_flags & M_EXT) 166804287599SRuslan Ermilov m_copyback(mcopy, 0, sizeof(struct ip), mtod(mcopy, caddr_t)); 1669df8bae1dSRodney W. Grimes icmp_error(mcopy, type, code, dest, destifp); 1670df8bae1dSRodney W. Grimes } 1671df8bae1dSRodney W. Grimes 167282c23ebaSBill Fenner void 167382c23ebaSBill Fenner ip_savecontrol(inp, mp, ip, m) 167482c23ebaSBill Fenner register struct inpcb *inp; 167582c23ebaSBill Fenner register struct mbuf **mp; 167682c23ebaSBill Fenner register struct ip *ip; 167782c23ebaSBill Fenner register struct mbuf *m; 167882c23ebaSBill Fenner { 167982c23ebaSBill Fenner if (inp->inp_socket->so_options & SO_TIMESTAMP) { 168082c23ebaSBill Fenner struct timeval tv; 168182c23ebaSBill Fenner 168282c23ebaSBill Fenner microtime(&tv); 168382c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv), 168482c23ebaSBill Fenner SCM_TIMESTAMP, SOL_SOCKET); 168582c23ebaSBill Fenner if (*mp) 168682c23ebaSBill Fenner mp = &(*mp)->m_next; 168782c23ebaSBill Fenner } 168882c23ebaSBill Fenner if (inp->inp_flags & INP_RECVDSTADDR) { 168982c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) &ip->ip_dst, 169082c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVDSTADDR, IPPROTO_IP); 169182c23ebaSBill Fenner if (*mp) 169282c23ebaSBill Fenner mp = &(*mp)->m_next; 169382c23ebaSBill Fenner } 169482c23ebaSBill Fenner #ifdef notyet 169582c23ebaSBill Fenner /* XXX 169682c23ebaSBill Fenner * Moving these out of udp_input() made them even more broken 169782c23ebaSBill Fenner * than they already were. 169882c23ebaSBill Fenner */ 169982c23ebaSBill Fenner /* options were tossed already */ 170082c23ebaSBill Fenner if (inp->inp_flags & INP_RECVOPTS) { 170182c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) opts_deleted_above, 170282c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVOPTS, IPPROTO_IP); 170382c23ebaSBill Fenner if (*mp) 170482c23ebaSBill Fenner mp = &(*mp)->m_next; 170582c23ebaSBill Fenner } 170682c23ebaSBill Fenner /* ip_srcroute doesn't do what we want here, need to fix */ 170782c23ebaSBill Fenner if (inp->inp_flags & INP_RECVRETOPTS) { 170882c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) ip_srcroute(), 170982c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVRETOPTS, IPPROTO_IP); 171082c23ebaSBill Fenner if (*mp) 171182c23ebaSBill Fenner mp = &(*mp)->m_next; 171282c23ebaSBill Fenner } 171382c23ebaSBill Fenner #endif 171482c23ebaSBill Fenner if (inp->inp_flags & INP_RECVIF) { 1715d314ad7bSJulian Elischer struct ifnet *ifp; 1716d314ad7bSJulian Elischer struct sdlbuf { 171782c23ebaSBill Fenner struct sockaddr_dl sdl; 1718d314ad7bSJulian Elischer u_char pad[32]; 1719d314ad7bSJulian Elischer } sdlbuf; 1720d314ad7bSJulian Elischer struct sockaddr_dl *sdp; 1721d314ad7bSJulian Elischer struct sockaddr_dl *sdl2 = &sdlbuf.sdl; 172282c23ebaSBill Fenner 1723d314ad7bSJulian Elischer if (((ifp = m->m_pkthdr.rcvif)) 1724d314ad7bSJulian Elischer && ( ifp->if_index && (ifp->if_index <= if_index))) { 1725d314ad7bSJulian Elischer sdp = (struct sockaddr_dl *)(ifnet_addrs 1726d314ad7bSJulian Elischer [ifp->if_index - 1]->ifa_addr); 1727d314ad7bSJulian Elischer /* 1728d314ad7bSJulian Elischer * Change our mind and don't try copy. 1729d314ad7bSJulian Elischer */ 1730d314ad7bSJulian Elischer if ((sdp->sdl_family != AF_LINK) 1731d314ad7bSJulian Elischer || (sdp->sdl_len > sizeof(sdlbuf))) { 1732d314ad7bSJulian Elischer goto makedummy; 1733d314ad7bSJulian Elischer } 1734d314ad7bSJulian Elischer bcopy(sdp, sdl2, sdp->sdl_len); 1735d314ad7bSJulian Elischer } else { 1736d314ad7bSJulian Elischer makedummy: 1737d314ad7bSJulian Elischer sdl2->sdl_len 1738d314ad7bSJulian Elischer = offsetof(struct sockaddr_dl, sdl_data[0]); 1739d314ad7bSJulian Elischer sdl2->sdl_family = AF_LINK; 1740d314ad7bSJulian Elischer sdl2->sdl_index = 0; 1741d314ad7bSJulian Elischer sdl2->sdl_nlen = sdl2->sdl_alen = sdl2->sdl_slen = 0; 1742d314ad7bSJulian Elischer } 1743d314ad7bSJulian Elischer *mp = sbcreatecontrol((caddr_t) sdl2, sdl2->sdl_len, 174482c23ebaSBill Fenner IP_RECVIF, IPPROTO_IP); 174582c23ebaSBill Fenner if (*mp) 174682c23ebaSBill Fenner mp = &(*mp)->m_next; 174782c23ebaSBill Fenner } 174882c23ebaSBill Fenner } 174982c23ebaSBill Fenner 1750df8bae1dSRodney W. Grimes int 1751f0068c4aSGarrett Wollman ip_rsvp_init(struct socket *so) 1752f0068c4aSGarrett Wollman { 1753f0068c4aSGarrett Wollman if (so->so_type != SOCK_RAW || 1754f0068c4aSGarrett Wollman so->so_proto->pr_protocol != IPPROTO_RSVP) 1755f0068c4aSGarrett Wollman return EOPNOTSUPP; 1756f0068c4aSGarrett Wollman 1757f0068c4aSGarrett Wollman if (ip_rsvpd != NULL) 1758f0068c4aSGarrett Wollman return EADDRINUSE; 1759f0068c4aSGarrett Wollman 1760f0068c4aSGarrett Wollman ip_rsvpd = so; 17611c5de19aSGarrett Wollman /* 17621c5de19aSGarrett Wollman * This may seem silly, but we need to be sure we don't over-increment 17631c5de19aSGarrett Wollman * the RSVP counter, in case something slips up. 17641c5de19aSGarrett Wollman */ 17651c5de19aSGarrett Wollman if (!ip_rsvp_on) { 17661c5de19aSGarrett Wollman ip_rsvp_on = 1; 17671c5de19aSGarrett Wollman rsvp_on++; 17681c5de19aSGarrett Wollman } 1769f0068c4aSGarrett Wollman 1770f0068c4aSGarrett Wollman return 0; 1771f0068c4aSGarrett Wollman } 1772f0068c4aSGarrett Wollman 1773f0068c4aSGarrett Wollman int 1774f0068c4aSGarrett Wollman ip_rsvp_done(void) 1775f0068c4aSGarrett Wollman { 1776f0068c4aSGarrett Wollman ip_rsvpd = NULL; 17771c5de19aSGarrett Wollman /* 17781c5de19aSGarrett Wollman * This may seem silly, but we need to be sure we don't over-decrement 17791c5de19aSGarrett Wollman * the RSVP counter, in case something slips up. 17801c5de19aSGarrett Wollman */ 17811c5de19aSGarrett Wollman if (ip_rsvp_on) { 17821c5de19aSGarrett Wollman ip_rsvp_on = 0; 17831c5de19aSGarrett Wollman rsvp_on--; 17841c5de19aSGarrett Wollman } 1785f0068c4aSGarrett Wollman return 0; 1786f0068c4aSGarrett Wollman } 1787