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 34b5e8ce9fSBruce Evans * $Id: ip_input.c,v 1.17 1995/02/14 23:04:52 wollman Exp $ 35df8bae1dSRodney W. Grimes */ 36df8bae1dSRodney W. Grimes 37df8bae1dSRodney W. Grimes #include <sys/param.h> 38df8bae1dSRodney W. Grimes #include <sys/systm.h> 39df8bae1dSRodney W. Grimes #include <sys/malloc.h> 40df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 41df8bae1dSRodney W. Grimes #include <sys/domain.h> 42df8bae1dSRodney W. Grimes #include <sys/protosw.h> 43df8bae1dSRodney W. Grimes #include <sys/socket.h> 44df8bae1dSRodney W. Grimes #include <sys/errno.h> 45df8bae1dSRodney W. Grimes #include <sys/time.h> 46df8bae1dSRodney W. Grimes #include <sys/kernel.h> 47b5e8ce9fSBruce Evans #include <vm/vm.h> 48b5e8ce9fSBruce Evans #include <sys/sysctl.h> 49df8bae1dSRodney W. Grimes 50df8bae1dSRodney W. Grimes #include <net/if.h> 51df8bae1dSRodney W. Grimes #include <net/route.h> 52df8bae1dSRodney W. Grimes 53df8bae1dSRodney W. Grimes #include <netinet/in.h> 54df8bae1dSRodney W. Grimes #include <netinet/in_systm.h> 55b5e8ce9fSBruce Evans #include <netinet/in_var.h> 56df8bae1dSRodney W. Grimes #include <netinet/ip.h> 57df8bae1dSRodney W. Grimes #include <netinet/in_pcb.h> 58df8bae1dSRodney W. Grimes #include <netinet/in_var.h> 59df8bae1dSRodney W. Grimes #include <netinet/ip_var.h> 60df8bae1dSRodney W. Grimes #include <netinet/ip_icmp.h> 61df8bae1dSRodney W. Grimes 62100ba1a6SJordan K. Hubbard #include <netinet/ip_fw.h> 63100ba1a6SJordan K. Hubbard 64f0068c4aSGarrett Wollman #include <sys/socketvar.h> 65f0068c4aSGarrett Wollman struct socket *ip_rsvpd; 66f0068c4aSGarrett Wollman 67df8bae1dSRodney W. Grimes #ifndef IPFORWARDING 68df8bae1dSRodney W. Grimes #ifdef GATEWAY 69df8bae1dSRodney W. Grimes #define IPFORWARDING 1 /* forward IP packets not for us */ 70df8bae1dSRodney W. Grimes #else /* GATEWAY */ 71df8bae1dSRodney W. Grimes #define IPFORWARDING 0 /* don't forward IP packets not for us */ 72df8bae1dSRodney W. Grimes #endif /* GATEWAY */ 73df8bae1dSRodney W. Grimes #endif /* IPFORWARDING */ 74df8bae1dSRodney W. Grimes #ifndef IPSENDREDIRECTS 75df8bae1dSRodney W. Grimes #define IPSENDREDIRECTS 1 76df8bae1dSRodney W. Grimes #endif 77df8bae1dSRodney W. Grimes int ipforwarding = IPFORWARDING; 78df8bae1dSRodney W. Grimes int ipsendredirects = IPSENDREDIRECTS; 79df8bae1dSRodney W. Grimes int ip_defttl = IPDEFTTL; 80df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 81df8bae1dSRodney W. Grimes int ipprintfs = 0; 82df8bae1dSRodney W. Grimes #endif 83df8bae1dSRodney W. Grimes 84df8bae1dSRodney W. Grimes extern struct domain inetdomain; 85df8bae1dSRodney W. Grimes extern struct protosw inetsw[]; 86df8bae1dSRodney W. Grimes u_char ip_protox[IPPROTO_MAX]; 87df8bae1dSRodney W. Grimes int ipqmaxlen = IFQ_MAXLEN; 88df8bae1dSRodney W. Grimes struct in_ifaddr *in_ifaddr; /* first inet address */ 89df8bae1dSRodney W. Grimes struct ifqueue ipintrq; 90df8bae1dSRodney W. Grimes 91f23b4c91SGarrett Wollman struct ipstat ipstat; 92f23b4c91SGarrett Wollman struct ipq ipq; 93f23b4c91SGarrett Wollman 94df8bae1dSRodney W. Grimes /* 95df8bae1dSRodney W. Grimes * We need to save the IP options in case a protocol wants to respond 96df8bae1dSRodney W. Grimes * to an incoming packet over the same route if the packet got here 97df8bae1dSRodney W. Grimes * using IP source routing. This allows connection establishment and 98df8bae1dSRodney W. Grimes * maintenance when the remote end is on a network that is not known 99df8bae1dSRodney W. Grimes * to us. 100df8bae1dSRodney W. Grimes */ 101df8bae1dSRodney W. Grimes int ip_nhops = 0; 102df8bae1dSRodney W. Grimes static struct ip_srcrt { 103df8bae1dSRodney W. Grimes struct in_addr dst; /* final destination */ 104df8bae1dSRodney W. Grimes char nop; /* one NOP to align */ 105df8bae1dSRodney W. Grimes char srcopt[IPOPT_OFFSET + 1]; /* OPTVAL, OLEN and OFFSET */ 106df8bae1dSRodney W. Grimes struct in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)]; 107df8bae1dSRodney W. Grimes } ip_srcrt; 108df8bae1dSRodney W. Grimes 109df8bae1dSRodney W. Grimes #ifdef GATEWAY 110df8bae1dSRodney W. Grimes extern int if_index; 111df8bae1dSRodney W. Grimes u_long *ip_ifmatrix; 112df8bae1dSRodney W. Grimes #endif 113df8bae1dSRodney W. Grimes 114df8bae1dSRodney W. Grimes static void save_rte __P((u_char *, struct in_addr)); 115df8bae1dSRodney W. Grimes /* 116df8bae1dSRodney W. Grimes * IP initialization: fill in IP protocol switch table. 117df8bae1dSRodney W. Grimes * All protocols not implemented in kernel go to raw IP protocol handler. 118df8bae1dSRodney W. Grimes */ 119df8bae1dSRodney W. Grimes void 120df8bae1dSRodney W. Grimes ip_init() 121df8bae1dSRodney W. Grimes { 122df8bae1dSRodney W. Grimes register struct protosw *pr; 123df8bae1dSRodney W. Grimes register int i; 124df8bae1dSRodney W. Grimes 125df8bae1dSRodney W. Grimes pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW); 126df8bae1dSRodney W. Grimes if (pr == 0) 127df8bae1dSRodney W. Grimes panic("ip_init"); 128df8bae1dSRodney W. Grimes for (i = 0; i < IPPROTO_MAX; i++) 129df8bae1dSRodney W. Grimes ip_protox[i] = pr - inetsw; 130df8bae1dSRodney W. Grimes for (pr = inetdomain.dom_protosw; 131df8bae1dSRodney W. Grimes pr < inetdomain.dom_protoswNPROTOSW; pr++) 132df8bae1dSRodney W. Grimes if (pr->pr_domain->dom_family == PF_INET && 133df8bae1dSRodney W. Grimes pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) 134df8bae1dSRodney W. Grimes ip_protox[pr->pr_protocol] = pr - inetsw; 135df8bae1dSRodney W. Grimes ipq.next = ipq.prev = &ipq; 136df8bae1dSRodney W. Grimes ip_id = time.tv_sec & 0xffff; 137df8bae1dSRodney W. Grimes ipintrq.ifq_maxlen = ipqmaxlen; 138df8bae1dSRodney W. Grimes #ifdef GATEWAY 139df8bae1dSRodney W. Grimes i = (if_index + 1) * (if_index + 1) * sizeof (u_long); 140df8bae1dSRodney W. Grimes ip_ifmatrix = (u_long *) malloc(i, M_RTABLE, M_WAITOK); 141df8bae1dSRodney W. Grimes bzero((char *)ip_ifmatrix, i); 142df8bae1dSRodney W. Grimes #endif 143df8bae1dSRodney W. Grimes } 144df8bae1dSRodney W. Grimes 145df8bae1dSRodney W. Grimes struct sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET }; 146df8bae1dSRodney W. Grimes struct route ipforward_rt; 147df8bae1dSRodney W. Grimes 148df8bae1dSRodney W. Grimes /* 149df8bae1dSRodney W. Grimes * Ip input routine. Checksum and byte swap header. If fragmented 150df8bae1dSRodney W. Grimes * try to reassemble. Process options. Pass to next level. 151df8bae1dSRodney W. Grimes */ 152df8bae1dSRodney W. Grimes void 153df8bae1dSRodney W. Grimes ipintr() 154df8bae1dSRodney W. Grimes { 155df8bae1dSRodney W. Grimes register struct ip *ip; 156df8bae1dSRodney W. Grimes register struct mbuf *m; 157df8bae1dSRodney W. Grimes register struct ipq *fp; 158df8bae1dSRodney W. Grimes register struct in_ifaddr *ia; 159df8bae1dSRodney W. Grimes int hlen, s; 160df8bae1dSRodney W. Grimes 161df8bae1dSRodney W. Grimes next: 162df8bae1dSRodney W. Grimes /* 163df8bae1dSRodney W. Grimes * Get next datagram off input queue and get IP header 164df8bae1dSRodney W. Grimes * in first mbuf. 165df8bae1dSRodney W. Grimes */ 166df8bae1dSRodney W. Grimes s = splimp(); 167df8bae1dSRodney W. Grimes IF_DEQUEUE(&ipintrq, m); 168df8bae1dSRodney W. Grimes splx(s); 169df8bae1dSRodney W. Grimes if (m == 0) 170df8bae1dSRodney W. Grimes return; 171df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 172df8bae1dSRodney W. Grimes if ((m->m_flags & M_PKTHDR) == 0) 173df8bae1dSRodney W. Grimes panic("ipintr no HDR"); 174df8bae1dSRodney W. Grimes #endif 175df8bae1dSRodney W. Grimes /* 176df8bae1dSRodney W. Grimes * If no IP addresses have been set yet but the interfaces 177df8bae1dSRodney W. Grimes * are receiving, can't do anything with incoming packets yet. 178df8bae1dSRodney W. Grimes */ 179df8bae1dSRodney W. Grimes if (in_ifaddr == NULL) 180df8bae1dSRodney W. Grimes goto bad; 181df8bae1dSRodney W. Grimes ipstat.ips_total++; 182df8bae1dSRodney W. Grimes if (m->m_len < sizeof (struct ip) && 183df8bae1dSRodney W. Grimes (m = m_pullup(m, sizeof (struct ip))) == 0) { 184df8bae1dSRodney W. Grimes ipstat.ips_toosmall++; 185df8bae1dSRodney W. Grimes goto next; 186df8bae1dSRodney W. Grimes } 187df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 188df8bae1dSRodney W. Grimes if (ip->ip_v != IPVERSION) { 189df8bae1dSRodney W. Grimes ipstat.ips_badvers++; 190df8bae1dSRodney W. Grimes goto bad; 191df8bae1dSRodney W. Grimes } 192df8bae1dSRodney W. Grimes hlen = ip->ip_hl << 2; 193df8bae1dSRodney W. Grimes if (hlen < sizeof(struct ip)) { /* minimum header length */ 194df8bae1dSRodney W. Grimes ipstat.ips_badhlen++; 195df8bae1dSRodney W. Grimes goto bad; 196df8bae1dSRodney W. Grimes } 197df8bae1dSRodney W. Grimes if (hlen > m->m_len) { 198df8bae1dSRodney W. Grimes if ((m = m_pullup(m, hlen)) == 0) { 199df8bae1dSRodney W. Grimes ipstat.ips_badhlen++; 200df8bae1dSRodney W. Grimes goto next; 201df8bae1dSRodney W. Grimes } 202df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 203df8bae1dSRodney W. Grimes } 204623ae52eSPoul-Henning Kamp ip->ip_sum = in_cksum(m, hlen); 205623ae52eSPoul-Henning Kamp if (ip->ip_sum) { 206df8bae1dSRodney W. Grimes ipstat.ips_badsum++; 207df8bae1dSRodney W. Grimes goto bad; 208df8bae1dSRodney W. Grimes } 209df8bae1dSRodney W. Grimes 210df8bae1dSRodney W. Grimes /* 211df8bae1dSRodney W. Grimes * Convert fields to host representation. 212df8bae1dSRodney W. Grimes */ 213df8bae1dSRodney W. Grimes NTOHS(ip->ip_len); 214df8bae1dSRodney W. Grimes if (ip->ip_len < hlen) { 215df8bae1dSRodney W. Grimes ipstat.ips_badlen++; 216df8bae1dSRodney W. Grimes goto bad; 217df8bae1dSRodney W. Grimes } 218df8bae1dSRodney W. Grimes NTOHS(ip->ip_id); 219df8bae1dSRodney W. Grimes NTOHS(ip->ip_off); 220df8bae1dSRodney W. Grimes 221df8bae1dSRodney W. Grimes /* 222df8bae1dSRodney W. Grimes * Check that the amount of data in the buffers 223df8bae1dSRodney W. Grimes * is as at least much as the IP header would have us expect. 224df8bae1dSRodney W. Grimes * Trim mbufs if longer than we expect. 225df8bae1dSRodney W. Grimes * Drop packet if shorter than we expect. 226df8bae1dSRodney W. Grimes */ 227df8bae1dSRodney W. Grimes if (m->m_pkthdr.len < ip->ip_len) { 228df8bae1dSRodney W. Grimes ipstat.ips_tooshort++; 229df8bae1dSRodney W. Grimes goto bad; 230df8bae1dSRodney W. Grimes } 231df8bae1dSRodney W. Grimes if (m->m_pkthdr.len > ip->ip_len) { 232df8bae1dSRodney W. Grimes if (m->m_len == m->m_pkthdr.len) { 233df8bae1dSRodney W. Grimes m->m_len = ip->ip_len; 234df8bae1dSRodney W. Grimes m->m_pkthdr.len = ip->ip_len; 235df8bae1dSRodney W. Grimes } else 236df8bae1dSRodney W. Grimes m_adj(m, ip->ip_len - m->m_pkthdr.len); 237df8bae1dSRodney W. Grimes } 2384dd1662bSUgen J.S. Antsilevich /* 2394dd1662bSUgen J.S. Antsilevich * IpHack's section. 2404dd1662bSUgen J.S. Antsilevich * Right now when no processing on packet has done 2414dd1662bSUgen J.S. Antsilevich * and it is still fresh out of network we do our black 2424dd1662bSUgen J.S. Antsilevich * deals with it. 2434dd1662bSUgen J.S. Antsilevich * - Firewall: deny/allow 2444dd1662bSUgen J.S. Antsilevich * - Wrap: fake packet's addr/port <unimpl.> 2454dd1662bSUgen J.S. Antsilevich * - Encapsulate: put it in another IP and send out. <unimp.> 2464dd1662bSUgen J.S. Antsilevich */ 247df8bae1dSRodney W. Grimes 2484dd1662bSUgen J.S. Antsilevich if (ip_fw_chk_ptr!=NULL) 2496db216a6SGary Palmer if (!(*ip_fw_chk_ptr)(ip,m->m_pkthdr.rcvif,ip_fw_chain) ) { 250100ba1a6SJordan K. Hubbard goto bad; 251100ba1a6SJordan K. Hubbard } 252100ba1a6SJordan K. Hubbard 253df8bae1dSRodney W. Grimes /* 254df8bae1dSRodney W. Grimes * Process options and, if not destined for us, 255df8bae1dSRodney W. Grimes * ship it on. ip_dooptions returns 1 when an 256df8bae1dSRodney W. Grimes * error was detected (causing an icmp message 257df8bae1dSRodney W. Grimes * to be sent and the original packet to be freed). 258df8bae1dSRodney W. Grimes */ 259df8bae1dSRodney W. Grimes ip_nhops = 0; /* for source routed packets */ 260df8bae1dSRodney W. Grimes if (hlen > sizeof (struct ip) && ip_dooptions(m)) 261df8bae1dSRodney W. Grimes goto next; 262df8bae1dSRodney W. Grimes 263f0068c4aSGarrett Wollman /* greedy RSVP, snatches any PATH packet of the RSVP protocol and no 264f0068c4aSGarrett Wollman * matter if it is destined to another node, or whether it is 265f0068c4aSGarrett Wollman * a multicast one, RSVP wants it! and prevents it from being forwarded 266f0068c4aSGarrett Wollman * anywhere else. Also checks if the rsvp daemon is running before 267f0068c4aSGarrett Wollman * grabbing the packet. 268f0068c4aSGarrett Wollman */ 269f0068c4aSGarrett Wollman if (ip_rsvpd != NULL && ip->ip_p==IPPROTO_RSVP) 270f0068c4aSGarrett Wollman goto ours; 271f0068c4aSGarrett Wollman 272df8bae1dSRodney W. Grimes /* 273df8bae1dSRodney W. Grimes * Check our list of addresses, to see if the packet is for us. 274df8bae1dSRodney W. Grimes */ 275df8bae1dSRodney W. Grimes for (ia = in_ifaddr; ia; ia = ia->ia_next) { 276df8bae1dSRodney W. Grimes #define satosin(sa) ((struct sockaddr_in *)(sa)) 277df8bae1dSRodney W. Grimes 278df8bae1dSRodney W. Grimes if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr) 279df8bae1dSRodney W. Grimes goto ours; 280df8bae1dSRodney W. Grimes if ( 281df8bae1dSRodney W. Grimes #ifdef DIRECTED_BROADCAST 282df8bae1dSRodney W. Grimes ia->ia_ifp == m->m_pkthdr.rcvif && 283df8bae1dSRodney W. Grimes #endif 284df8bae1dSRodney W. Grimes (ia->ia_ifp->if_flags & IFF_BROADCAST)) { 285df8bae1dSRodney W. Grimes u_long t; 286df8bae1dSRodney W. Grimes 287df8bae1dSRodney W. Grimes if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == 288df8bae1dSRodney W. Grimes ip->ip_dst.s_addr) 289df8bae1dSRodney W. Grimes goto ours; 290df8bae1dSRodney W. Grimes if (ip->ip_dst.s_addr == ia->ia_netbroadcast.s_addr) 291df8bae1dSRodney W. Grimes goto ours; 292df8bae1dSRodney W. Grimes /* 293df8bae1dSRodney W. Grimes * Look for all-0's host part (old broadcast addr), 294df8bae1dSRodney W. Grimes * either for subnet or net. 295df8bae1dSRodney W. Grimes */ 296df8bae1dSRodney W. Grimes t = ntohl(ip->ip_dst.s_addr); 297df8bae1dSRodney W. Grimes if (t == ia->ia_subnet) 298df8bae1dSRodney W. Grimes goto ours; 299df8bae1dSRodney W. Grimes if (t == ia->ia_net) 300df8bae1dSRodney W. Grimes goto ours; 301df8bae1dSRodney W. Grimes } 302df8bae1dSRodney W. Grimes } 303df8bae1dSRodney W. Grimes if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { 304df8bae1dSRodney W. Grimes struct in_multi *inm; 305df8bae1dSRodney W. Grimes if (ip_mrouter) { 306df8bae1dSRodney W. Grimes /* 307df8bae1dSRodney W. Grimes * If we are acting as a multicast router, all 308df8bae1dSRodney W. Grimes * incoming multicast packets are passed to the 309df8bae1dSRodney W. Grimes * kernel-level multicast forwarding function. 310df8bae1dSRodney W. Grimes * The packet is returned (relatively) intact; if 311df8bae1dSRodney W. Grimes * ip_mforward() returns a non-zero value, the packet 312df8bae1dSRodney W. Grimes * must be discarded, else it may be accepted below. 313df8bae1dSRodney W. Grimes * 314df8bae1dSRodney W. Grimes * (The IP ident field is put in the same byte order 315df8bae1dSRodney W. Grimes * as expected when ip_mforward() is called from 316df8bae1dSRodney W. Grimes * ip_output().) 317df8bae1dSRodney W. Grimes */ 318df8bae1dSRodney W. Grimes ip->ip_id = htons(ip->ip_id); 319f0068c4aSGarrett Wollman if (ip_mforward(ip, m->m_pkthdr.rcvif, m, 0) != 0) { 320df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 321df8bae1dSRodney W. Grimes m_freem(m); 322df8bae1dSRodney W. Grimes goto next; 323df8bae1dSRodney W. Grimes } 324df8bae1dSRodney W. Grimes ip->ip_id = ntohs(ip->ip_id); 325df8bae1dSRodney W. Grimes 326df8bae1dSRodney W. Grimes /* 327df8bae1dSRodney W. Grimes * The process-level routing demon needs to receive 328df8bae1dSRodney W. Grimes * all multicast IGMP packets, whether or not this 329df8bae1dSRodney W. Grimes * host belongs to their destination groups. 330df8bae1dSRodney W. Grimes */ 331df8bae1dSRodney W. Grimes if (ip->ip_p == IPPROTO_IGMP) 332df8bae1dSRodney W. Grimes goto ours; 333df8bae1dSRodney W. Grimes ipstat.ips_forward++; 334df8bae1dSRodney W. Grimes } 335df8bae1dSRodney W. Grimes /* 336df8bae1dSRodney W. Grimes * See if we belong to the destination multicast group on the 337df8bae1dSRodney W. Grimes * arrival interface. 338df8bae1dSRodney W. Grimes */ 339df8bae1dSRodney W. Grimes IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm); 340df8bae1dSRodney W. Grimes if (inm == NULL) { 341df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 342df8bae1dSRodney W. Grimes m_freem(m); 343df8bae1dSRodney W. Grimes goto next; 344df8bae1dSRodney W. Grimes } 345df8bae1dSRodney W. Grimes goto ours; 346df8bae1dSRodney W. Grimes } 347df8bae1dSRodney W. Grimes if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST) 348df8bae1dSRodney W. Grimes goto ours; 349df8bae1dSRodney W. Grimes if (ip->ip_dst.s_addr == INADDR_ANY) 350df8bae1dSRodney W. Grimes goto ours; 351df8bae1dSRodney W. Grimes 352df8bae1dSRodney W. Grimes /* 353df8bae1dSRodney W. Grimes * Not for us; forward if possible and desirable. 354df8bae1dSRodney W. Grimes */ 355df8bae1dSRodney W. Grimes if (ipforwarding == 0) { 356df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 357df8bae1dSRodney W. Grimes m_freem(m); 358df8bae1dSRodney W. Grimes } else 359df8bae1dSRodney W. Grimes ip_forward(m, 0); 360df8bae1dSRodney W. Grimes goto next; 361df8bae1dSRodney W. Grimes 362df8bae1dSRodney W. Grimes ours: 363100ba1a6SJordan K. Hubbard 36463f8d699SJordan K. Hubbard /* 36563f8d699SJordan K. Hubbard * If packet came to us we count it... 36663f8d699SJordan K. Hubbard * This way we count all incoming packets which has 36763f8d699SJordan K. Hubbard * not been forwarded... 36863f8d699SJordan K. Hubbard * Do not convert ip_len to host byte order when 36963f8d699SJordan K. Hubbard * counting,ppl already made it for us before.. 37063f8d699SJordan K. Hubbard */ 3714dd1662bSUgen J.S. Antsilevich if (ip_acct_cnt_ptr!=NULL) 3724dd1662bSUgen J.S. Antsilevich (*ip_acct_cnt_ptr)(ip,m->m_pkthdr.rcvif,ip_acct_chain,0); 37363f8d699SJordan K. Hubbard 374df8bae1dSRodney W. Grimes /* 375df8bae1dSRodney W. Grimes * If offset or IP_MF are set, must reassemble. 376df8bae1dSRodney W. Grimes * Otherwise, nothing need be done. 377df8bae1dSRodney W. Grimes * (We could look in the reassembly queue to see 378df8bae1dSRodney W. Grimes * if the packet was previously fragmented, 379df8bae1dSRodney W. Grimes * but it's not worth the time; just let them time out.) 380df8bae1dSRodney W. Grimes */ 381df8bae1dSRodney W. Grimes if (ip->ip_off &~ IP_DF) { 382df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT) { /* XXX */ 383df8bae1dSRodney W. Grimes if ((m = m_pullup(m, sizeof (struct ip))) == 0) { 384df8bae1dSRodney W. Grimes ipstat.ips_toosmall++; 385df8bae1dSRodney W. Grimes goto next; 386df8bae1dSRodney W. Grimes } 387df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 388df8bae1dSRodney W. Grimes } 389df8bae1dSRodney W. Grimes /* 390df8bae1dSRodney W. Grimes * Look for queue of fragments 391df8bae1dSRodney W. Grimes * of this datagram. 392df8bae1dSRodney W. Grimes */ 393df8bae1dSRodney W. Grimes for (fp = ipq.next; fp != &ipq; fp = fp->next) 394df8bae1dSRodney W. Grimes if (ip->ip_id == fp->ipq_id && 395df8bae1dSRodney W. Grimes ip->ip_src.s_addr == fp->ipq_src.s_addr && 396df8bae1dSRodney W. Grimes ip->ip_dst.s_addr == fp->ipq_dst.s_addr && 397df8bae1dSRodney W. Grimes ip->ip_p == fp->ipq_p) 398df8bae1dSRodney W. Grimes goto found; 399df8bae1dSRodney W. Grimes fp = 0; 400df8bae1dSRodney W. Grimes found: 401df8bae1dSRodney W. Grimes 402df8bae1dSRodney W. Grimes /* 403df8bae1dSRodney W. Grimes * Adjust ip_len to not reflect header, 404df8bae1dSRodney W. Grimes * set ip_mff if more fragments are expected, 405df8bae1dSRodney W. Grimes * convert offset of this to bytes. 406df8bae1dSRodney W. Grimes */ 407df8bae1dSRodney W. Grimes ip->ip_len -= hlen; 408df8bae1dSRodney W. Grimes ((struct ipasfrag *)ip)->ipf_mff &= ~1; 409df8bae1dSRodney W. Grimes if (ip->ip_off & IP_MF) 410df8bae1dSRodney W. Grimes ((struct ipasfrag *)ip)->ipf_mff |= 1; 411df8bae1dSRodney W. Grimes ip->ip_off <<= 3; 412df8bae1dSRodney W. Grimes 413df8bae1dSRodney W. Grimes /* 414df8bae1dSRodney W. Grimes * If datagram marked as having more fragments 415df8bae1dSRodney W. Grimes * or if this is not the first fragment, 416df8bae1dSRodney W. Grimes * attempt reassembly; if it succeeds, proceed. 417df8bae1dSRodney W. Grimes */ 418df8bae1dSRodney W. Grimes if (((struct ipasfrag *)ip)->ipf_mff & 1 || ip->ip_off) { 419df8bae1dSRodney W. Grimes ipstat.ips_fragments++; 420df8bae1dSRodney W. Grimes ip = ip_reass((struct ipasfrag *)ip, fp); 421df8bae1dSRodney W. Grimes if (ip == 0) 422df8bae1dSRodney W. Grimes goto next; 423df8bae1dSRodney W. Grimes ipstat.ips_reassembled++; 424df8bae1dSRodney W. Grimes m = dtom(ip); 425df8bae1dSRodney W. Grimes } else 426df8bae1dSRodney W. Grimes if (fp) 427df8bae1dSRodney W. Grimes ip_freef(fp); 428df8bae1dSRodney W. Grimes } else 429df8bae1dSRodney W. Grimes ip->ip_len -= hlen; 430df8bae1dSRodney W. Grimes 431df8bae1dSRodney W. Grimes /* 432df8bae1dSRodney W. Grimes * Switch out to protocol's input routine. 433df8bae1dSRodney W. Grimes */ 434df8bae1dSRodney W. Grimes ipstat.ips_delivered++; 435df8bae1dSRodney W. Grimes (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen); 436df8bae1dSRodney W. Grimes goto next; 437df8bae1dSRodney W. Grimes bad: 438df8bae1dSRodney W. Grimes m_freem(m); 439df8bae1dSRodney W. Grimes goto next; 440df8bae1dSRodney W. Grimes } 441df8bae1dSRodney W. Grimes 442df8bae1dSRodney W. Grimes /* 443df8bae1dSRodney W. Grimes * Take incoming datagram fragment and try to 444df8bae1dSRodney W. Grimes * reassemble it into whole datagram. If a chain for 445df8bae1dSRodney W. Grimes * reassembly of this datagram already exists, then it 446df8bae1dSRodney W. Grimes * is given as fp; otherwise have to make a chain. 447df8bae1dSRodney W. Grimes */ 448df8bae1dSRodney W. Grimes struct ip * 449df8bae1dSRodney W. Grimes ip_reass(ip, fp) 450df8bae1dSRodney W. Grimes register struct ipasfrag *ip; 451df8bae1dSRodney W. Grimes register struct ipq *fp; 452df8bae1dSRodney W. Grimes { 453df8bae1dSRodney W. Grimes register struct mbuf *m = dtom(ip); 454df8bae1dSRodney W. Grimes register struct ipasfrag *q; 455df8bae1dSRodney W. Grimes struct mbuf *t; 456df8bae1dSRodney W. Grimes int hlen = ip->ip_hl << 2; 457df8bae1dSRodney W. Grimes int i, next; 458df8bae1dSRodney W. Grimes 459df8bae1dSRodney W. Grimes /* 460df8bae1dSRodney W. Grimes * Presence of header sizes in mbufs 461df8bae1dSRodney W. Grimes * would confuse code below. 462df8bae1dSRodney W. Grimes */ 463df8bae1dSRodney W. Grimes m->m_data += hlen; 464df8bae1dSRodney W. Grimes m->m_len -= hlen; 465df8bae1dSRodney W. Grimes 466df8bae1dSRodney W. Grimes /* 467df8bae1dSRodney W. Grimes * If first fragment to arrive, create a reassembly queue. 468df8bae1dSRodney W. Grimes */ 469df8bae1dSRodney W. Grimes if (fp == 0) { 470df8bae1dSRodney W. Grimes if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL) 471df8bae1dSRodney W. Grimes goto dropfrag; 472df8bae1dSRodney W. Grimes fp = mtod(t, struct ipq *); 473df8bae1dSRodney W. Grimes insque(fp, &ipq); 474df8bae1dSRodney W. Grimes fp->ipq_ttl = IPFRAGTTL; 475df8bae1dSRodney W. Grimes fp->ipq_p = ip->ip_p; 476df8bae1dSRodney W. Grimes fp->ipq_id = ip->ip_id; 477df8bae1dSRodney W. Grimes fp->ipq_next = fp->ipq_prev = (struct ipasfrag *)fp; 478df8bae1dSRodney W. Grimes fp->ipq_src = ((struct ip *)ip)->ip_src; 479df8bae1dSRodney W. Grimes fp->ipq_dst = ((struct ip *)ip)->ip_dst; 480df8bae1dSRodney W. Grimes q = (struct ipasfrag *)fp; 481df8bae1dSRodney W. Grimes goto insert; 482df8bae1dSRodney W. Grimes } 483df8bae1dSRodney W. Grimes 484df8bae1dSRodney W. Grimes /* 485df8bae1dSRodney W. Grimes * Find a segment which begins after this one does. 486df8bae1dSRodney W. Grimes */ 487df8bae1dSRodney W. Grimes for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) 488df8bae1dSRodney W. Grimes if (q->ip_off > ip->ip_off) 489df8bae1dSRodney W. Grimes break; 490df8bae1dSRodney W. Grimes 491df8bae1dSRodney W. Grimes /* 492df8bae1dSRodney W. Grimes * If there is a preceding segment, it may provide some of 493df8bae1dSRodney W. Grimes * our data already. If so, drop the data from the incoming 494df8bae1dSRodney W. Grimes * segment. If it provides all of our data, drop us. 495df8bae1dSRodney W. Grimes */ 496df8bae1dSRodney W. Grimes if (q->ipf_prev != (struct ipasfrag *)fp) { 497df8bae1dSRodney W. Grimes i = q->ipf_prev->ip_off + q->ipf_prev->ip_len - ip->ip_off; 498df8bae1dSRodney W. Grimes if (i > 0) { 499df8bae1dSRodney W. Grimes if (i >= ip->ip_len) 500df8bae1dSRodney W. Grimes goto dropfrag; 501df8bae1dSRodney W. Grimes m_adj(dtom(ip), i); 502df8bae1dSRodney W. Grimes ip->ip_off += i; 503df8bae1dSRodney W. Grimes ip->ip_len -= i; 504df8bae1dSRodney W. Grimes } 505df8bae1dSRodney W. Grimes } 506df8bae1dSRodney W. Grimes 507df8bae1dSRodney W. Grimes /* 508df8bae1dSRodney W. Grimes * While we overlap succeeding segments trim them or, 509df8bae1dSRodney W. Grimes * if they are completely covered, dequeue them. 510df8bae1dSRodney W. Grimes */ 511df8bae1dSRodney W. Grimes while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) { 512df8bae1dSRodney W. Grimes i = (ip->ip_off + ip->ip_len) - q->ip_off; 513df8bae1dSRodney W. Grimes if (i < q->ip_len) { 514df8bae1dSRodney W. Grimes q->ip_len -= i; 515df8bae1dSRodney W. Grimes q->ip_off += i; 516df8bae1dSRodney W. Grimes m_adj(dtom(q), i); 517df8bae1dSRodney W. Grimes break; 518df8bae1dSRodney W. Grimes } 519df8bae1dSRodney W. Grimes q = q->ipf_next; 520df8bae1dSRodney W. Grimes m_freem(dtom(q->ipf_prev)); 521df8bae1dSRodney W. Grimes ip_deq(q->ipf_prev); 522df8bae1dSRodney W. Grimes } 523df8bae1dSRodney W. Grimes 524df8bae1dSRodney W. Grimes insert: 525df8bae1dSRodney W. Grimes /* 526df8bae1dSRodney W. Grimes * Stick new segment in its place; 527df8bae1dSRodney W. Grimes * check for complete reassembly. 528df8bae1dSRodney W. Grimes */ 529df8bae1dSRodney W. Grimes ip_enq(ip, q->ipf_prev); 530df8bae1dSRodney W. Grimes next = 0; 531df8bae1dSRodney W. Grimes for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) { 532df8bae1dSRodney W. Grimes if (q->ip_off != next) 533df8bae1dSRodney W. Grimes return (0); 534df8bae1dSRodney W. Grimes next += q->ip_len; 535df8bae1dSRodney W. Grimes } 536df8bae1dSRodney W. Grimes if (q->ipf_prev->ipf_mff & 1) 537df8bae1dSRodney W. Grimes return (0); 538df8bae1dSRodney W. Grimes 539df8bae1dSRodney W. Grimes /* 540df8bae1dSRodney W. Grimes * Reassembly is complete; concatenate fragments. 541df8bae1dSRodney W. Grimes */ 542df8bae1dSRodney W. Grimes q = fp->ipq_next; 543df8bae1dSRodney W. Grimes m = dtom(q); 544df8bae1dSRodney W. Grimes t = m->m_next; 545df8bae1dSRodney W. Grimes m->m_next = 0; 546df8bae1dSRodney W. Grimes m_cat(m, t); 547df8bae1dSRodney W. Grimes q = q->ipf_next; 548df8bae1dSRodney W. Grimes while (q != (struct ipasfrag *)fp) { 549df8bae1dSRodney W. Grimes t = dtom(q); 550df8bae1dSRodney W. Grimes q = q->ipf_next; 551df8bae1dSRodney W. Grimes m_cat(m, t); 552df8bae1dSRodney W. Grimes } 553df8bae1dSRodney W. Grimes 554df8bae1dSRodney W. Grimes /* 555df8bae1dSRodney W. Grimes * Create header for new ip packet by 556df8bae1dSRodney W. Grimes * modifying header of first packet; 557df8bae1dSRodney W. Grimes * dequeue and discard fragment reassembly header. 558df8bae1dSRodney W. Grimes * Make header visible. 559df8bae1dSRodney W. Grimes */ 560df8bae1dSRodney W. Grimes ip = fp->ipq_next; 561df8bae1dSRodney W. Grimes ip->ip_len = next; 562df8bae1dSRodney W. Grimes ip->ipf_mff &= ~1; 563df8bae1dSRodney W. Grimes ((struct ip *)ip)->ip_src = fp->ipq_src; 564df8bae1dSRodney W. Grimes ((struct ip *)ip)->ip_dst = fp->ipq_dst; 565df8bae1dSRodney W. Grimes remque(fp); 566df8bae1dSRodney W. Grimes (void) m_free(dtom(fp)); 567df8bae1dSRodney W. Grimes m = dtom(ip); 568df8bae1dSRodney W. Grimes m->m_len += (ip->ip_hl << 2); 569df8bae1dSRodney W. Grimes m->m_data -= (ip->ip_hl << 2); 570df8bae1dSRodney W. Grimes /* some debugging cruft by sklower, below, will go away soon */ 571df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) { /* XXX this should be done elsewhere */ 572df8bae1dSRodney W. Grimes register int plen = 0; 573df8bae1dSRodney W. Grimes for (t = m; m; m = m->m_next) 574df8bae1dSRodney W. Grimes plen += m->m_len; 575df8bae1dSRodney W. Grimes t->m_pkthdr.len = plen; 576df8bae1dSRodney W. Grimes } 577df8bae1dSRodney W. Grimes return ((struct ip *)ip); 578df8bae1dSRodney W. Grimes 579df8bae1dSRodney W. Grimes dropfrag: 580df8bae1dSRodney W. Grimes ipstat.ips_fragdropped++; 581df8bae1dSRodney W. Grimes m_freem(m); 582df8bae1dSRodney W. Grimes return (0); 583df8bae1dSRodney W. Grimes } 584df8bae1dSRodney W. Grimes 585df8bae1dSRodney W. Grimes /* 586df8bae1dSRodney W. Grimes * Free a fragment reassembly header and all 587df8bae1dSRodney W. Grimes * associated datagrams. 588df8bae1dSRodney W. Grimes */ 589df8bae1dSRodney W. Grimes void 590df8bae1dSRodney W. Grimes ip_freef(fp) 591df8bae1dSRodney W. Grimes struct ipq *fp; 592df8bae1dSRodney W. Grimes { 593df8bae1dSRodney W. Grimes register struct ipasfrag *q, *p; 594df8bae1dSRodney W. Grimes 595df8bae1dSRodney W. Grimes for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = p) { 596df8bae1dSRodney W. Grimes p = q->ipf_next; 597df8bae1dSRodney W. Grimes ip_deq(q); 598df8bae1dSRodney W. Grimes m_freem(dtom(q)); 599df8bae1dSRodney W. Grimes } 600df8bae1dSRodney W. Grimes remque(fp); 601df8bae1dSRodney W. Grimes (void) m_free(dtom(fp)); 602df8bae1dSRodney W. Grimes } 603df8bae1dSRodney W. Grimes 604df8bae1dSRodney W. Grimes /* 605df8bae1dSRodney W. Grimes * Put an ip fragment on a reassembly chain. 606df8bae1dSRodney W. Grimes * Like insque, but pointers in middle of structure. 607df8bae1dSRodney W. Grimes */ 608df8bae1dSRodney W. Grimes void 609df8bae1dSRodney W. Grimes ip_enq(p, prev) 610df8bae1dSRodney W. Grimes register struct ipasfrag *p, *prev; 611df8bae1dSRodney W. Grimes { 612df8bae1dSRodney W. Grimes 613df8bae1dSRodney W. Grimes p->ipf_prev = prev; 614df8bae1dSRodney W. Grimes p->ipf_next = prev->ipf_next; 615df8bae1dSRodney W. Grimes prev->ipf_next->ipf_prev = p; 616df8bae1dSRodney W. Grimes prev->ipf_next = p; 617df8bae1dSRodney W. Grimes } 618df8bae1dSRodney W. Grimes 619df8bae1dSRodney W. Grimes /* 620df8bae1dSRodney W. Grimes * To ip_enq as remque is to insque. 621df8bae1dSRodney W. Grimes */ 622df8bae1dSRodney W. Grimes void 623df8bae1dSRodney W. Grimes ip_deq(p) 624df8bae1dSRodney W. Grimes register struct ipasfrag *p; 625df8bae1dSRodney W. Grimes { 626df8bae1dSRodney W. Grimes 627df8bae1dSRodney W. Grimes p->ipf_prev->ipf_next = p->ipf_next; 628df8bae1dSRodney W. Grimes p->ipf_next->ipf_prev = p->ipf_prev; 629df8bae1dSRodney W. Grimes } 630df8bae1dSRodney W. Grimes 631df8bae1dSRodney W. Grimes /* 632df8bae1dSRodney W. Grimes * IP timer processing; 633df8bae1dSRodney W. Grimes * if a timer expires on a reassembly 634df8bae1dSRodney W. Grimes * queue, discard it. 635df8bae1dSRodney W. Grimes */ 636df8bae1dSRodney W. Grimes void 637df8bae1dSRodney W. Grimes ip_slowtimo() 638df8bae1dSRodney W. Grimes { 639df8bae1dSRodney W. Grimes register struct ipq *fp; 640df8bae1dSRodney W. Grimes int s = splnet(); 641df8bae1dSRodney W. Grimes 642df8bae1dSRodney W. Grimes fp = ipq.next; 643df8bae1dSRodney W. Grimes if (fp == 0) { 644df8bae1dSRodney W. Grimes splx(s); 645df8bae1dSRodney W. Grimes return; 646df8bae1dSRodney W. Grimes } 647df8bae1dSRodney W. Grimes while (fp != &ipq) { 648df8bae1dSRodney W. Grimes --fp->ipq_ttl; 649df8bae1dSRodney W. Grimes fp = fp->next; 650df8bae1dSRodney W. Grimes if (fp->prev->ipq_ttl == 0) { 651df8bae1dSRodney W. Grimes ipstat.ips_fragtimeout++; 652df8bae1dSRodney W. Grimes ip_freef(fp->prev); 653df8bae1dSRodney W. Grimes } 654df8bae1dSRodney W. Grimes } 655df8bae1dSRodney W. Grimes splx(s); 656df8bae1dSRodney W. Grimes } 657df8bae1dSRodney W. Grimes 658df8bae1dSRodney W. Grimes /* 659df8bae1dSRodney W. Grimes * Drain off all datagram fragments. 660df8bae1dSRodney W. Grimes */ 661df8bae1dSRodney W. Grimes void 662df8bae1dSRodney W. Grimes ip_drain() 663df8bae1dSRodney W. Grimes { 664df8bae1dSRodney W. Grimes 665df8bae1dSRodney W. Grimes while (ipq.next != &ipq) { 666df8bae1dSRodney W. Grimes ipstat.ips_fragdropped++; 667df8bae1dSRodney W. Grimes ip_freef(ipq.next); 668df8bae1dSRodney W. Grimes } 669df8bae1dSRodney W. Grimes } 670df8bae1dSRodney W. Grimes 671df8bae1dSRodney W. Grimes /* 672df8bae1dSRodney W. Grimes * Do option processing on a datagram, 673df8bae1dSRodney W. Grimes * possibly discarding it if bad options are encountered, 674df8bae1dSRodney W. Grimes * or forwarding it if source-routed. 675df8bae1dSRodney W. Grimes * Returns 1 if packet has been forwarded/freed, 676df8bae1dSRodney W. Grimes * 0 if the packet should be processed further. 677df8bae1dSRodney W. Grimes */ 678df8bae1dSRodney W. Grimes int 679df8bae1dSRodney W. Grimes ip_dooptions(m) 680df8bae1dSRodney W. Grimes struct mbuf *m; 681df8bae1dSRodney W. Grimes { 682df8bae1dSRodney W. Grimes register struct ip *ip = mtod(m, struct ip *); 683df8bae1dSRodney W. Grimes register u_char *cp; 684df8bae1dSRodney W. Grimes register struct ip_timestamp *ipt; 685df8bae1dSRodney W. Grimes register struct in_ifaddr *ia; 686df8bae1dSRodney W. Grimes int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0; 687df8bae1dSRodney W. Grimes struct in_addr *sin, dst; 688df8bae1dSRodney W. Grimes n_time ntime; 689df8bae1dSRodney W. Grimes 690df8bae1dSRodney W. Grimes dst = ip->ip_dst; 691df8bae1dSRodney W. Grimes cp = (u_char *)(ip + 1); 692df8bae1dSRodney W. Grimes cnt = (ip->ip_hl << 2) - sizeof (struct ip); 693df8bae1dSRodney W. Grimes for (; cnt > 0; cnt -= optlen, cp += optlen) { 694df8bae1dSRodney W. Grimes opt = cp[IPOPT_OPTVAL]; 695df8bae1dSRodney W. Grimes if (opt == IPOPT_EOL) 696df8bae1dSRodney W. Grimes break; 697df8bae1dSRodney W. Grimes if (opt == IPOPT_NOP) 698df8bae1dSRodney W. Grimes optlen = 1; 699df8bae1dSRodney W. Grimes else { 700df8bae1dSRodney W. Grimes optlen = cp[IPOPT_OLEN]; 701df8bae1dSRodney W. Grimes if (optlen <= 0 || optlen > cnt) { 702df8bae1dSRodney W. Grimes code = &cp[IPOPT_OLEN] - (u_char *)ip; 703df8bae1dSRodney W. Grimes goto bad; 704df8bae1dSRodney W. Grimes } 705df8bae1dSRodney W. Grimes } 706df8bae1dSRodney W. Grimes switch (opt) { 707df8bae1dSRodney W. Grimes 708df8bae1dSRodney W. Grimes default: 709df8bae1dSRodney W. Grimes break; 710df8bae1dSRodney W. Grimes 711df8bae1dSRodney W. Grimes /* 712df8bae1dSRodney W. Grimes * Source routing with record. 713df8bae1dSRodney W. Grimes * Find interface with current destination address. 714df8bae1dSRodney W. Grimes * If none on this machine then drop if strictly routed, 715df8bae1dSRodney W. Grimes * or do nothing if loosely routed. 716df8bae1dSRodney W. Grimes * Record interface address and bring up next address 717df8bae1dSRodney W. Grimes * component. If strictly routed make sure next 718df8bae1dSRodney W. Grimes * address is on directly accessible net. 719df8bae1dSRodney W. Grimes */ 720df8bae1dSRodney W. Grimes case IPOPT_LSRR: 721df8bae1dSRodney W. Grimes case IPOPT_SSRR: 722df8bae1dSRodney W. Grimes if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { 723df8bae1dSRodney W. Grimes code = &cp[IPOPT_OFFSET] - (u_char *)ip; 724df8bae1dSRodney W. Grimes goto bad; 725df8bae1dSRodney W. Grimes } 726df8bae1dSRodney W. Grimes ipaddr.sin_addr = ip->ip_dst; 727df8bae1dSRodney W. Grimes ia = (struct in_ifaddr *) 728df8bae1dSRodney W. Grimes ifa_ifwithaddr((struct sockaddr *)&ipaddr); 729df8bae1dSRodney W. Grimes if (ia == 0) { 730df8bae1dSRodney W. Grimes if (opt == IPOPT_SSRR) { 731df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 732df8bae1dSRodney W. Grimes code = ICMP_UNREACH_SRCFAIL; 733df8bae1dSRodney W. Grimes goto bad; 734df8bae1dSRodney W. Grimes } 735df8bae1dSRodney W. Grimes /* 736df8bae1dSRodney W. Grimes * Loose routing, and not at next destination 737df8bae1dSRodney W. Grimes * yet; nothing to do except forward. 738df8bae1dSRodney W. Grimes */ 739df8bae1dSRodney W. Grimes break; 740df8bae1dSRodney W. Grimes } 741df8bae1dSRodney W. Grimes off--; /* 0 origin */ 742df8bae1dSRodney W. Grimes if (off > optlen - sizeof(struct in_addr)) { 743df8bae1dSRodney W. Grimes /* 744df8bae1dSRodney W. Grimes * End of source route. Should be for us. 745df8bae1dSRodney W. Grimes */ 746df8bae1dSRodney W. Grimes save_rte(cp, ip->ip_src); 747df8bae1dSRodney W. Grimes break; 748df8bae1dSRodney W. Grimes } 749df8bae1dSRodney W. Grimes /* 750df8bae1dSRodney W. Grimes * locate outgoing interface 751df8bae1dSRodney W. Grimes */ 752df8bae1dSRodney W. Grimes bcopy((caddr_t)(cp + off), (caddr_t)&ipaddr.sin_addr, 753df8bae1dSRodney W. Grimes sizeof(ipaddr.sin_addr)); 754df8bae1dSRodney W. Grimes if (opt == IPOPT_SSRR) { 755df8bae1dSRodney W. Grimes #define INA struct in_ifaddr * 756df8bae1dSRodney W. Grimes #define SA struct sockaddr * 757df8bae1dSRodney W. Grimes if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0) 758df8bae1dSRodney W. Grimes ia = (INA)ifa_ifwithnet((SA)&ipaddr); 759df8bae1dSRodney W. Grimes } else 760df8bae1dSRodney W. Grimes ia = ip_rtaddr(ipaddr.sin_addr); 761df8bae1dSRodney W. Grimes if (ia == 0) { 762df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 763df8bae1dSRodney W. Grimes code = ICMP_UNREACH_SRCFAIL; 764df8bae1dSRodney W. Grimes goto bad; 765df8bae1dSRodney W. Grimes } 766df8bae1dSRodney W. Grimes ip->ip_dst = ipaddr.sin_addr; 767df8bae1dSRodney W. Grimes bcopy((caddr_t)&(IA_SIN(ia)->sin_addr), 768df8bae1dSRodney W. Grimes (caddr_t)(cp + off), sizeof(struct in_addr)); 769df8bae1dSRodney W. Grimes cp[IPOPT_OFFSET] += sizeof(struct in_addr); 770df8bae1dSRodney W. Grimes /* 771df8bae1dSRodney W. Grimes * Let ip_intr's mcast routing check handle mcast pkts 772df8bae1dSRodney W. Grimes */ 773df8bae1dSRodney W. Grimes forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr)); 774df8bae1dSRodney W. Grimes break; 775df8bae1dSRodney W. Grimes 776df8bae1dSRodney W. Grimes case IPOPT_RR: 777df8bae1dSRodney W. Grimes if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { 778df8bae1dSRodney W. Grimes code = &cp[IPOPT_OFFSET] - (u_char *)ip; 779df8bae1dSRodney W. Grimes goto bad; 780df8bae1dSRodney W. Grimes } 781df8bae1dSRodney W. Grimes /* 782df8bae1dSRodney W. Grimes * If no space remains, ignore. 783df8bae1dSRodney W. Grimes */ 784df8bae1dSRodney W. Grimes off--; /* 0 origin */ 785df8bae1dSRodney W. Grimes if (off > optlen - sizeof(struct in_addr)) 786df8bae1dSRodney W. Grimes break; 787df8bae1dSRodney W. Grimes bcopy((caddr_t)(&ip->ip_dst), (caddr_t)&ipaddr.sin_addr, 788df8bae1dSRodney W. Grimes sizeof(ipaddr.sin_addr)); 789df8bae1dSRodney W. Grimes /* 790df8bae1dSRodney W. Grimes * locate outgoing interface; if we're the destination, 791df8bae1dSRodney W. Grimes * use the incoming interface (should be same). 792df8bae1dSRodney W. Grimes */ 793df8bae1dSRodney W. Grimes if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 && 794df8bae1dSRodney W. Grimes (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) { 795df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 796df8bae1dSRodney W. Grimes code = ICMP_UNREACH_HOST; 797df8bae1dSRodney W. Grimes goto bad; 798df8bae1dSRodney W. Grimes } 799df8bae1dSRodney W. Grimes bcopy((caddr_t)&(IA_SIN(ia)->sin_addr), 800df8bae1dSRodney W. Grimes (caddr_t)(cp + off), sizeof(struct in_addr)); 801df8bae1dSRodney W. Grimes cp[IPOPT_OFFSET] += sizeof(struct in_addr); 802df8bae1dSRodney W. Grimes break; 803df8bae1dSRodney W. Grimes 804df8bae1dSRodney W. Grimes case IPOPT_TS: 805df8bae1dSRodney W. Grimes code = cp - (u_char *)ip; 806df8bae1dSRodney W. Grimes ipt = (struct ip_timestamp *)cp; 807df8bae1dSRodney W. Grimes if (ipt->ipt_len < 5) 808df8bae1dSRodney W. Grimes goto bad; 809df8bae1dSRodney W. Grimes if (ipt->ipt_ptr > ipt->ipt_len - sizeof (long)) { 810df8bae1dSRodney W. Grimes if (++ipt->ipt_oflw == 0) 811df8bae1dSRodney W. Grimes goto bad; 812df8bae1dSRodney W. Grimes break; 813df8bae1dSRodney W. Grimes } 814df8bae1dSRodney W. Grimes sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1); 815df8bae1dSRodney W. Grimes switch (ipt->ipt_flg) { 816df8bae1dSRodney W. Grimes 817df8bae1dSRodney W. Grimes case IPOPT_TS_TSONLY: 818df8bae1dSRodney W. Grimes break; 819df8bae1dSRodney W. Grimes 820df8bae1dSRodney W. Grimes case IPOPT_TS_TSANDADDR: 821df8bae1dSRodney W. Grimes if (ipt->ipt_ptr + sizeof(n_time) + 822df8bae1dSRodney W. Grimes sizeof(struct in_addr) > ipt->ipt_len) 823df8bae1dSRodney W. Grimes goto bad; 824df8bae1dSRodney W. Grimes ipaddr.sin_addr = dst; 825df8bae1dSRodney W. Grimes ia = (INA)ifaof_ifpforaddr((SA)&ipaddr, 826df8bae1dSRodney W. Grimes m->m_pkthdr.rcvif); 827df8bae1dSRodney W. Grimes if (ia == 0) 828df8bae1dSRodney W. Grimes continue; 829df8bae1dSRodney W. Grimes bcopy((caddr_t)&IA_SIN(ia)->sin_addr, 830df8bae1dSRodney W. Grimes (caddr_t)sin, sizeof(struct in_addr)); 831df8bae1dSRodney W. Grimes ipt->ipt_ptr += sizeof(struct in_addr); 832df8bae1dSRodney W. Grimes break; 833df8bae1dSRodney W. Grimes 834df8bae1dSRodney W. Grimes case IPOPT_TS_PRESPEC: 835df8bae1dSRodney W. Grimes if (ipt->ipt_ptr + sizeof(n_time) + 836df8bae1dSRodney W. Grimes sizeof(struct in_addr) > ipt->ipt_len) 837df8bae1dSRodney W. Grimes goto bad; 838df8bae1dSRodney W. Grimes bcopy((caddr_t)sin, (caddr_t)&ipaddr.sin_addr, 839df8bae1dSRodney W. Grimes sizeof(struct in_addr)); 840df8bae1dSRodney W. Grimes if (ifa_ifwithaddr((SA)&ipaddr) == 0) 841df8bae1dSRodney W. Grimes continue; 842df8bae1dSRodney W. Grimes ipt->ipt_ptr += sizeof(struct in_addr); 843df8bae1dSRodney W. Grimes break; 844df8bae1dSRodney W. Grimes 845df8bae1dSRodney W. Grimes default: 846df8bae1dSRodney W. Grimes goto bad; 847df8bae1dSRodney W. Grimes } 848df8bae1dSRodney W. Grimes ntime = iptime(); 849df8bae1dSRodney W. Grimes bcopy((caddr_t)&ntime, (caddr_t)cp + ipt->ipt_ptr - 1, 850df8bae1dSRodney W. Grimes sizeof(n_time)); 851df8bae1dSRodney W. Grimes ipt->ipt_ptr += sizeof(n_time); 852df8bae1dSRodney W. Grimes } 853df8bae1dSRodney W. Grimes } 854df8bae1dSRodney W. Grimes if (forward) { 855df8bae1dSRodney W. Grimes ip_forward(m, 1); 856df8bae1dSRodney W. Grimes return (1); 857df8bae1dSRodney W. Grimes } 858df8bae1dSRodney W. Grimes return (0); 859df8bae1dSRodney W. Grimes bad: 860df8bae1dSRodney W. Grimes ip->ip_len -= ip->ip_hl << 2; /* XXX icmp_error adds in hdr length */ 861df8bae1dSRodney W. Grimes icmp_error(m, type, code, 0, 0); 862df8bae1dSRodney W. Grimes ipstat.ips_badoptions++; 863df8bae1dSRodney W. Grimes return (1); 864df8bae1dSRodney W. Grimes } 865df8bae1dSRodney W. Grimes 866df8bae1dSRodney W. Grimes /* 867df8bae1dSRodney W. Grimes * Given address of next destination (final or next hop), 868df8bae1dSRodney W. Grimes * return internet address info of interface to be used to get there. 869df8bae1dSRodney W. Grimes */ 870df8bae1dSRodney W. Grimes struct in_ifaddr * 871df8bae1dSRodney W. Grimes ip_rtaddr(dst) 872df8bae1dSRodney W. Grimes struct in_addr dst; 873df8bae1dSRodney W. Grimes { 874df8bae1dSRodney W. Grimes register struct sockaddr_in *sin; 875df8bae1dSRodney W. Grimes 876df8bae1dSRodney W. Grimes sin = (struct sockaddr_in *) &ipforward_rt.ro_dst; 877df8bae1dSRodney W. Grimes 878df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt == 0 || dst.s_addr != sin->sin_addr.s_addr) { 879df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt) { 880df8bae1dSRodney W. Grimes RTFREE(ipforward_rt.ro_rt); 881df8bae1dSRodney W. Grimes ipforward_rt.ro_rt = 0; 882df8bae1dSRodney W. Grimes } 883df8bae1dSRodney W. Grimes sin->sin_family = AF_INET; 884df8bae1dSRodney W. Grimes sin->sin_len = sizeof(*sin); 885df8bae1dSRodney W. Grimes sin->sin_addr = dst; 886df8bae1dSRodney W. Grimes 8872c17fe93SGarrett Wollman rtalloc_ign(&ipforward_rt, RTF_PRCLONING); 888df8bae1dSRodney W. Grimes } 889df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt == 0) 890df8bae1dSRodney W. Grimes return ((struct in_ifaddr *)0); 891df8bae1dSRodney W. Grimes return ((struct in_ifaddr *) ipforward_rt.ro_rt->rt_ifa); 892df8bae1dSRodney W. Grimes } 893df8bae1dSRodney W. Grimes 894df8bae1dSRodney W. Grimes /* 895df8bae1dSRodney W. Grimes * Save incoming source route for use in replies, 896df8bae1dSRodney W. Grimes * to be picked up later by ip_srcroute if the receiver is interested. 897df8bae1dSRodney W. Grimes */ 898df8bae1dSRodney W. Grimes void 899df8bae1dSRodney W. Grimes save_rte(option, dst) 900df8bae1dSRodney W. Grimes u_char *option; 901df8bae1dSRodney W. Grimes struct in_addr dst; 902df8bae1dSRodney W. Grimes { 903df8bae1dSRodney W. Grimes unsigned olen; 904df8bae1dSRodney W. Grimes 905df8bae1dSRodney W. Grimes olen = option[IPOPT_OLEN]; 906df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 907df8bae1dSRodney W. Grimes if (ipprintfs) 908df8bae1dSRodney W. Grimes printf("save_rte: olen %d\n", olen); 909df8bae1dSRodney W. Grimes #endif 910df8bae1dSRodney W. Grimes if (olen > sizeof(ip_srcrt) - (1 + sizeof(dst))) 911df8bae1dSRodney W. Grimes return; 912df8bae1dSRodney W. Grimes bcopy((caddr_t)option, (caddr_t)ip_srcrt.srcopt, olen); 913df8bae1dSRodney W. Grimes ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr); 914df8bae1dSRodney W. Grimes ip_srcrt.dst = dst; 915df8bae1dSRodney W. Grimes } 916df8bae1dSRodney W. Grimes 917df8bae1dSRodney W. Grimes /* 918df8bae1dSRodney W. Grimes * Retrieve incoming source route for use in replies, 919df8bae1dSRodney W. Grimes * in the same form used by setsockopt. 920df8bae1dSRodney W. Grimes * The first hop is placed before the options, will be removed later. 921df8bae1dSRodney W. Grimes */ 922df8bae1dSRodney W. Grimes struct mbuf * 923df8bae1dSRodney W. Grimes ip_srcroute() 924df8bae1dSRodney W. Grimes { 925df8bae1dSRodney W. Grimes register struct in_addr *p, *q; 926df8bae1dSRodney W. Grimes register struct mbuf *m; 927df8bae1dSRodney W. Grimes 928df8bae1dSRodney W. Grimes if (ip_nhops == 0) 929df8bae1dSRodney W. Grimes return ((struct mbuf *)0); 930df8bae1dSRodney W. Grimes m = m_get(M_DONTWAIT, MT_SOOPTS); 931df8bae1dSRodney W. Grimes if (m == 0) 932df8bae1dSRodney W. Grimes return ((struct mbuf *)0); 933df8bae1dSRodney W. Grimes 934df8bae1dSRodney W. Grimes #define OPTSIZ (sizeof(ip_srcrt.nop) + sizeof(ip_srcrt.srcopt)) 935df8bae1dSRodney W. Grimes 936df8bae1dSRodney W. Grimes /* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */ 937df8bae1dSRodney W. Grimes m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) + 938df8bae1dSRodney W. Grimes OPTSIZ; 939df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 940df8bae1dSRodney W. Grimes if (ipprintfs) 941df8bae1dSRodney W. Grimes printf("ip_srcroute: nhops %d mlen %d", ip_nhops, m->m_len); 942df8bae1dSRodney W. Grimes #endif 943df8bae1dSRodney W. Grimes 944df8bae1dSRodney W. Grimes /* 945df8bae1dSRodney W. Grimes * First save first hop for return route 946df8bae1dSRodney W. Grimes */ 947df8bae1dSRodney W. Grimes p = &ip_srcrt.route[ip_nhops - 1]; 948df8bae1dSRodney W. Grimes *(mtod(m, struct in_addr *)) = *p--; 949df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 950df8bae1dSRodney W. Grimes if (ipprintfs) 951df8bae1dSRodney W. Grimes printf(" hops %lx", ntohl(mtod(m, struct in_addr *)->s_addr)); 952df8bae1dSRodney W. Grimes #endif 953df8bae1dSRodney W. Grimes 954df8bae1dSRodney W. Grimes /* 955df8bae1dSRodney W. Grimes * Copy option fields and padding (nop) to mbuf. 956df8bae1dSRodney W. Grimes */ 957df8bae1dSRodney W. Grimes ip_srcrt.nop = IPOPT_NOP; 958df8bae1dSRodney W. Grimes ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF; 959df8bae1dSRodney W. Grimes bcopy((caddr_t)&ip_srcrt.nop, 960df8bae1dSRodney W. Grimes mtod(m, caddr_t) + sizeof(struct in_addr), OPTSIZ); 961df8bae1dSRodney W. Grimes q = (struct in_addr *)(mtod(m, caddr_t) + 962df8bae1dSRodney W. Grimes sizeof(struct in_addr) + OPTSIZ); 963df8bae1dSRodney W. Grimes #undef OPTSIZ 964df8bae1dSRodney W. Grimes /* 965df8bae1dSRodney W. Grimes * Record return path as an IP source route, 966df8bae1dSRodney W. Grimes * reversing the path (pointers are now aligned). 967df8bae1dSRodney W. Grimes */ 968df8bae1dSRodney W. Grimes while (p >= ip_srcrt.route) { 969df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 970df8bae1dSRodney W. Grimes if (ipprintfs) 971df8bae1dSRodney W. Grimes printf(" %lx", ntohl(q->s_addr)); 972df8bae1dSRodney W. Grimes #endif 973df8bae1dSRodney W. Grimes *q++ = *p--; 974df8bae1dSRodney W. Grimes } 975df8bae1dSRodney W. Grimes /* 976df8bae1dSRodney W. Grimes * Last hop goes to final destination. 977df8bae1dSRodney W. Grimes */ 978df8bae1dSRodney W. Grimes *q = ip_srcrt.dst; 979df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 980df8bae1dSRodney W. Grimes if (ipprintfs) 981df8bae1dSRodney W. Grimes printf(" %lx\n", ntohl(q->s_addr)); 982df8bae1dSRodney W. Grimes #endif 983df8bae1dSRodney W. Grimes return (m); 984df8bae1dSRodney W. Grimes } 985df8bae1dSRodney W. Grimes 986df8bae1dSRodney W. Grimes /* 987df8bae1dSRodney W. Grimes * Strip out IP options, at higher 988df8bae1dSRodney W. Grimes * level protocol in the kernel. 989df8bae1dSRodney W. Grimes * Second argument is buffer to which options 990df8bae1dSRodney W. Grimes * will be moved, and return value is their length. 991df8bae1dSRodney W. Grimes * XXX should be deleted; last arg currently ignored. 992df8bae1dSRodney W. Grimes */ 993df8bae1dSRodney W. Grimes void 994df8bae1dSRodney W. Grimes ip_stripoptions(m, mopt) 995df8bae1dSRodney W. Grimes register struct mbuf *m; 996df8bae1dSRodney W. Grimes struct mbuf *mopt; 997df8bae1dSRodney W. Grimes { 998df8bae1dSRodney W. Grimes register int i; 999df8bae1dSRodney W. Grimes struct ip *ip = mtod(m, struct ip *); 1000df8bae1dSRodney W. Grimes register caddr_t opts; 1001df8bae1dSRodney W. Grimes int olen; 1002df8bae1dSRodney W. Grimes 1003df8bae1dSRodney W. Grimes olen = (ip->ip_hl<<2) - sizeof (struct ip); 1004df8bae1dSRodney W. Grimes opts = (caddr_t)(ip + 1); 1005df8bae1dSRodney W. Grimes i = m->m_len - (sizeof (struct ip) + olen); 1006df8bae1dSRodney W. Grimes bcopy(opts + olen, opts, (unsigned)i); 1007df8bae1dSRodney W. Grimes m->m_len -= olen; 1008df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) 1009df8bae1dSRodney W. Grimes m->m_pkthdr.len -= olen; 1010df8bae1dSRodney W. Grimes ip->ip_hl = sizeof(struct ip) >> 2; 1011df8bae1dSRodney W. Grimes } 1012df8bae1dSRodney W. Grimes 1013df8bae1dSRodney W. Grimes u_char inetctlerrmap[PRC_NCMDS] = { 1014df8bae1dSRodney W. Grimes 0, 0, 0, 0, 1015df8bae1dSRodney W. Grimes 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH, 1016df8bae1dSRodney W. Grimes EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, 1017df8bae1dSRodney W. Grimes EMSGSIZE, EHOSTUNREACH, 0, 0, 1018df8bae1dSRodney W. Grimes 0, 0, 0, 0, 1019df8bae1dSRodney W. Grimes ENOPROTOOPT 1020df8bae1dSRodney W. Grimes }; 1021df8bae1dSRodney W. Grimes 1022df8bae1dSRodney W. Grimes /* 1023df8bae1dSRodney W. Grimes * Forward a packet. If some error occurs return the sender 1024df8bae1dSRodney W. Grimes * an icmp packet. Note we can't always generate a meaningful 1025df8bae1dSRodney W. Grimes * icmp message because icmp doesn't have a large enough repertoire 1026df8bae1dSRodney W. Grimes * of codes and types. 1027df8bae1dSRodney W. Grimes * 1028df8bae1dSRodney W. Grimes * If not forwarding, just drop the packet. This could be confusing 1029df8bae1dSRodney W. Grimes * if ipforwarding was zero but some routing protocol was advancing 1030df8bae1dSRodney W. Grimes * us as a gateway to somewhere. However, we must let the routing 1031df8bae1dSRodney W. Grimes * protocol deal with that. 1032df8bae1dSRodney W. Grimes * 1033df8bae1dSRodney W. Grimes * The srcrt parameter indicates whether the packet is being forwarded 1034df8bae1dSRodney W. Grimes * via a source route. 1035df8bae1dSRodney W. Grimes */ 1036df8bae1dSRodney W. Grimes void 1037df8bae1dSRodney W. Grimes ip_forward(m, srcrt) 1038df8bae1dSRodney W. Grimes struct mbuf *m; 1039df8bae1dSRodney W. Grimes int srcrt; 1040df8bae1dSRodney W. Grimes { 1041df8bae1dSRodney W. Grimes register struct ip *ip = mtod(m, struct ip *); 1042df8bae1dSRodney W. Grimes register struct sockaddr_in *sin; 1043df8bae1dSRodney W. Grimes register struct rtentry *rt; 104426f9a767SRodney W. Grimes int error, type = 0, code = 0; 1045df8bae1dSRodney W. Grimes struct mbuf *mcopy; 1046df8bae1dSRodney W. Grimes n_long dest; 1047df8bae1dSRodney W. Grimes struct ifnet *destifp; 1048df8bae1dSRodney W. Grimes 1049df8bae1dSRodney W. Grimes dest = 0; 1050df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1051df8bae1dSRodney W. Grimes if (ipprintfs) 105261ce519bSPoul-Henning Kamp printf("forward: src %lx dst %lx ttl %x\n", 1053623ae52eSPoul-Henning Kamp ip->ip_src.s_addr, ip->ip_dst.s_addr, ip->ip_ttl); 1054df8bae1dSRodney W. Grimes #endif 1055100ba1a6SJordan K. Hubbard 1056100ba1a6SJordan K. Hubbard 1057df8bae1dSRodney W. Grimes if (m->m_flags & M_BCAST || in_canforward(ip->ip_dst) == 0) { 1058df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 1059df8bae1dSRodney W. Grimes m_freem(m); 1060df8bae1dSRodney W. Grimes return; 1061df8bae1dSRodney W. Grimes } 1062df8bae1dSRodney W. Grimes HTONS(ip->ip_id); 1063df8bae1dSRodney W. Grimes if (ip->ip_ttl <= IPTTLDEC) { 1064df8bae1dSRodney W. Grimes icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, dest, 0); 1065df8bae1dSRodney W. Grimes return; 1066df8bae1dSRodney W. Grimes } 1067df8bae1dSRodney W. Grimes ip->ip_ttl -= IPTTLDEC; 1068df8bae1dSRodney W. Grimes 1069df8bae1dSRodney W. Grimes sin = (struct sockaddr_in *)&ipforward_rt.ro_dst; 1070df8bae1dSRodney W. Grimes if ((rt = ipforward_rt.ro_rt) == 0 || 1071df8bae1dSRodney W. Grimes ip->ip_dst.s_addr != sin->sin_addr.s_addr) { 1072df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt) { 1073df8bae1dSRodney W. Grimes RTFREE(ipforward_rt.ro_rt); 1074df8bae1dSRodney W. Grimes ipforward_rt.ro_rt = 0; 1075df8bae1dSRodney W. Grimes } 1076df8bae1dSRodney W. Grimes sin->sin_family = AF_INET; 1077df8bae1dSRodney W. Grimes sin->sin_len = sizeof(*sin); 1078df8bae1dSRodney W. Grimes sin->sin_addr = ip->ip_dst; 1079df8bae1dSRodney W. Grimes 10802c17fe93SGarrett Wollman rtalloc_ign(&ipforward_rt, RTF_PRCLONING); 1081df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt == 0) { 1082df8bae1dSRodney W. Grimes icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0); 1083df8bae1dSRodney W. Grimes return; 1084df8bae1dSRodney W. Grimes } 1085df8bae1dSRodney W. Grimes rt = ipforward_rt.ro_rt; 1086df8bae1dSRodney W. Grimes } 1087df8bae1dSRodney W. Grimes 1088df8bae1dSRodney W. Grimes /* 1089df8bae1dSRodney W. Grimes * Save at most 64 bytes of the packet in case 1090df8bae1dSRodney W. Grimes * we need to generate an ICMP message to the src. 1091df8bae1dSRodney W. Grimes */ 1092df8bae1dSRodney W. Grimes mcopy = m_copy(m, 0, imin((int)ip->ip_len, 64)); 1093df8bae1dSRodney W. Grimes 10942c17fe93SGarrett Wollman #ifdef bogus 1095df8bae1dSRodney W. Grimes #ifdef GATEWAY 1096df8bae1dSRodney W. Grimes ip_ifmatrix[rt->rt_ifp->if_index + 1097df8bae1dSRodney W. Grimes if_index * m->m_pkthdr.rcvif->if_index]++; 1098df8bae1dSRodney W. Grimes #endif 10992c17fe93SGarrett Wollman #endif 1100df8bae1dSRodney W. Grimes /* 1101df8bae1dSRodney W. Grimes * If forwarding packet using same interface that it came in on, 1102df8bae1dSRodney W. Grimes * perhaps should send a redirect to sender to shortcut a hop. 1103df8bae1dSRodney W. Grimes * Only send redirect if source is sending directly to us, 1104df8bae1dSRodney W. Grimes * and if packet was not source routed (or has any options). 1105df8bae1dSRodney W. Grimes * Also, don't send redirect if forwarding using a default route 1106df8bae1dSRodney W. Grimes * or a route modified by a redirect. 1107df8bae1dSRodney W. Grimes */ 1108df8bae1dSRodney W. Grimes #define satosin(sa) ((struct sockaddr_in *)(sa)) 1109df8bae1dSRodney W. Grimes if (rt->rt_ifp == m->m_pkthdr.rcvif && 1110df8bae1dSRodney W. Grimes (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 && 1111df8bae1dSRodney W. Grimes satosin(rt_key(rt))->sin_addr.s_addr != 0 && 1112df8bae1dSRodney W. Grimes ipsendredirects && !srcrt) { 1113df8bae1dSRodney W. Grimes #define RTA(rt) ((struct in_ifaddr *)(rt->rt_ifa)) 1114df8bae1dSRodney W. Grimes u_long src = ntohl(ip->ip_src.s_addr); 1115df8bae1dSRodney W. Grimes 1116df8bae1dSRodney W. Grimes if (RTA(rt) && 1117df8bae1dSRodney W. Grimes (src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) { 1118df8bae1dSRodney W. Grimes if (rt->rt_flags & RTF_GATEWAY) 1119df8bae1dSRodney W. Grimes dest = satosin(rt->rt_gateway)->sin_addr.s_addr; 1120df8bae1dSRodney W. Grimes else 1121df8bae1dSRodney W. Grimes dest = ip->ip_dst.s_addr; 1122df8bae1dSRodney W. Grimes /* Router requirements says to only send host redirects */ 1123df8bae1dSRodney W. Grimes type = ICMP_REDIRECT; 1124df8bae1dSRodney W. Grimes code = ICMP_REDIRECT_HOST; 1125df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1126df8bae1dSRodney W. Grimes if (ipprintfs) 1127df8bae1dSRodney W. Grimes printf("redirect (%d) to %lx\n", code, (u_long)dest); 1128df8bae1dSRodney W. Grimes #endif 1129df8bae1dSRodney W. Grimes } 1130df8bae1dSRodney W. Grimes } 1131df8bae1dSRodney W. Grimes 1132df8bae1dSRodney W. Grimes error = ip_output(m, (struct mbuf *)0, &ipforward_rt, IP_FORWARDING 1133df8bae1dSRodney W. Grimes #ifdef DIRECTED_BROADCAST 1134df8bae1dSRodney W. Grimes | IP_ALLOWBROADCAST 1135df8bae1dSRodney W. Grimes #endif 1136df8bae1dSRodney W. Grimes , 0); 1137df8bae1dSRodney W. Grimes if (error) 1138df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 1139df8bae1dSRodney W. Grimes else { 1140df8bae1dSRodney W. Grimes ipstat.ips_forward++; 1141df8bae1dSRodney W. Grimes if (type) 1142df8bae1dSRodney W. Grimes ipstat.ips_redirectsent++; 1143df8bae1dSRodney W. Grimes else { 1144df8bae1dSRodney W. Grimes if (mcopy) 1145df8bae1dSRodney W. Grimes m_freem(mcopy); 1146df8bae1dSRodney W. Grimes return; 1147df8bae1dSRodney W. Grimes } 1148df8bae1dSRodney W. Grimes } 1149df8bae1dSRodney W. Grimes if (mcopy == NULL) 1150df8bae1dSRodney W. Grimes return; 1151df8bae1dSRodney W. Grimes destifp = NULL; 1152df8bae1dSRodney W. Grimes 1153df8bae1dSRodney W. Grimes switch (error) { 1154df8bae1dSRodney W. Grimes 1155df8bae1dSRodney W. Grimes case 0: /* forwarded, but need redirect */ 1156df8bae1dSRodney W. Grimes /* type, code set above */ 1157df8bae1dSRodney W. Grimes break; 1158df8bae1dSRodney W. Grimes 1159df8bae1dSRodney W. Grimes case ENETUNREACH: /* shouldn't happen, checked above */ 1160df8bae1dSRodney W. Grimes case EHOSTUNREACH: 1161df8bae1dSRodney W. Grimes case ENETDOWN: 1162df8bae1dSRodney W. Grimes case EHOSTDOWN: 1163df8bae1dSRodney W. Grimes default: 1164df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1165df8bae1dSRodney W. Grimes code = ICMP_UNREACH_HOST; 1166df8bae1dSRodney W. Grimes break; 1167df8bae1dSRodney W. Grimes 1168df8bae1dSRodney W. Grimes case EMSGSIZE: 1169df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1170df8bae1dSRodney W. Grimes code = ICMP_UNREACH_NEEDFRAG; 1171df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt) 1172df8bae1dSRodney W. Grimes destifp = ipforward_rt.ro_rt->rt_ifp; 1173df8bae1dSRodney W. Grimes ipstat.ips_cantfrag++; 1174df8bae1dSRodney W. Grimes break; 1175df8bae1dSRodney W. Grimes 1176df8bae1dSRodney W. Grimes case ENOBUFS: 1177df8bae1dSRodney W. Grimes type = ICMP_SOURCEQUENCH; 1178df8bae1dSRodney W. Grimes code = 0; 1179df8bae1dSRodney W. Grimes break; 1180df8bae1dSRodney W. Grimes } 1181df8bae1dSRodney W. Grimes icmp_error(mcopy, type, code, dest, destifp); 1182df8bae1dSRodney W. Grimes } 1183df8bae1dSRodney W. Grimes 1184df8bae1dSRodney W. Grimes int 1185df8bae1dSRodney W. Grimes ip_sysctl(name, namelen, oldp, oldlenp, newp, newlen) 1186df8bae1dSRodney W. Grimes int *name; 1187df8bae1dSRodney W. Grimes u_int namelen; 1188df8bae1dSRodney W. Grimes void *oldp; 1189df8bae1dSRodney W. Grimes size_t *oldlenp; 1190df8bae1dSRodney W. Grimes void *newp; 1191df8bae1dSRodney W. Grimes size_t newlen; 1192df8bae1dSRodney W. Grimes { 1193df8bae1dSRodney W. Grimes /* All sysctl names at this level are terminal. */ 1194df8bae1dSRodney W. Grimes if (namelen != 1) 1195df8bae1dSRodney W. Grimes return (ENOTDIR); 1196df8bae1dSRodney W. Grimes 1197df8bae1dSRodney W. Grimes switch (name[0]) { 1198df8bae1dSRodney W. Grimes case IPCTL_FORWARDING: 1199df8bae1dSRodney W. Grimes return (sysctl_int(oldp, oldlenp, newp, newlen, &ipforwarding)); 1200df8bae1dSRodney W. Grimes case IPCTL_SENDREDIRECTS: 1201df8bae1dSRodney W. Grimes return (sysctl_int(oldp, oldlenp, newp, newlen, 1202df8bae1dSRodney W. Grimes &ipsendredirects)); 1203df8bae1dSRodney W. Grimes case IPCTL_DEFTTL: 1204df8bae1dSRodney W. Grimes return (sysctl_int(oldp, oldlenp, newp, newlen, &ip_defttl)); 1205df8bae1dSRodney W. Grimes #ifdef notyet 1206df8bae1dSRodney W. Grimes case IPCTL_DEFMTU: 1207df8bae1dSRodney W. Grimes return (sysctl_int(oldp, oldlenp, newp, newlen, &ip_mtu)); 1208df8bae1dSRodney W. Grimes #endif 12095be2baf8SGarrett Wollman case IPCTL_RTEXPIRE: 1210ea80aed1SGarrett Wollman return (sysctl_int(oldp, oldlenp, newp, newlen, 1211ea80aed1SGarrett Wollman &rtq_reallyold)); 1212ea80aed1SGarrett Wollman case IPCTL_RTMINEXPIRE: 1213ea80aed1SGarrett Wollman return (sysctl_int(oldp, oldlenp, newp, newlen, 1214ea80aed1SGarrett Wollman &rtq_minreallyold)); 1215ea80aed1SGarrett Wollman case IPCTL_RTMAXCACHE: 1216ea80aed1SGarrett Wollman return (sysctl_int(oldp, oldlenp, newp, newlen, 1217ea80aed1SGarrett Wollman &rtq_toomany)); 1218df8bae1dSRodney W. Grimes default: 1219df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 1220df8bae1dSRodney W. Grimes } 1221df8bae1dSRodney W. Grimes /* NOTREACHED */ 1222df8bae1dSRodney W. Grimes } 1223f0068c4aSGarrett Wollman 1224f0068c4aSGarrett Wollman int 1225f0068c4aSGarrett Wollman ip_rsvp_init(struct socket *so) 1226f0068c4aSGarrett Wollman { 1227f0068c4aSGarrett Wollman if (so->so_type != SOCK_RAW || 1228f0068c4aSGarrett Wollman so->so_proto->pr_protocol != IPPROTO_RSVP) 1229f0068c4aSGarrett Wollman return EOPNOTSUPP; 1230f0068c4aSGarrett Wollman 1231f0068c4aSGarrett Wollman if (ip_rsvpd != NULL) 1232f0068c4aSGarrett Wollman return EADDRINUSE; 1233f0068c4aSGarrett Wollman 1234f0068c4aSGarrett Wollman ip_rsvpd = so; 1235f0068c4aSGarrett Wollman 1236f0068c4aSGarrett Wollman return 0; 1237f0068c4aSGarrett Wollman } 1238f0068c4aSGarrett Wollman 1239f0068c4aSGarrett Wollman int 1240f0068c4aSGarrett Wollman ip_rsvp_done(void) 1241f0068c4aSGarrett Wollman { 1242f0068c4aSGarrett Wollman ip_rsvpd = NULL; 1243f0068c4aSGarrett Wollman return 0; 1244f0068c4aSGarrett Wollman } 1245