ip_reass.c revision 6399
1224006Shrs/* 2224006Shrs * Copyright (c) 1982, 1986, 1988, 1993 3224006Shrs * The Regents of the University of California. All rights reserved. 4224006Shrs * 5224006Shrs * Redistribution and use in source and binary forms, with or without 6224006Shrs * modification, are permitted provided that the following conditions 7224006Shrs * are met: 8224006Shrs * 1. Redistributions of source code must retain the above copyright 9224006Shrs * notice, this list of conditions and the following disclaimer. 10224006Shrs * 2. Redistributions in binary form must reproduce the above copyright 11224006Shrs * notice, this list of conditions and the following disclaimer in the 12224006Shrs * documentation and/or other materials provided with the distribution. 13224006Shrs * 3. All advertising materials mentioning features or use of this software 14224006Shrs * must display the following acknowledgement: 15224006Shrs * This product includes software developed by the University of 16224006Shrs * California, Berkeley and its contributors. 17224006Shrs * 4. Neither the name of the University nor the names of its contributors 18224006Shrs * may be used to endorse or promote products derived from this software 19224006Shrs * without specific prior written permission. 20224006Shrs * 21224006Shrs * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22224006Shrs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23224006Shrs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24224006Shrs * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25224006Shrs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26224006Shrs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27224006Shrs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28224006Shrs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29224006Shrs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30224006Shrs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31224006Shrs * SUCH DAMAGE. 32224006Shrs * 33224006Shrs * @(#)ip_input.c 8.2 (Berkeley) 1/4/94 34224006Shrs * $Id: ip_input.c,v 1.16 1995/02/07 20:30:42 gpalmer Exp $ 35224006Shrs */ 36224006Shrs 37224006Shrs#include <sys/param.h> 38224006Shrs#include <sys/systm.h> 39224006Shrs#include <sys/malloc.h> 40224006Shrs#include <sys/mbuf.h> 41224006Shrs#include <sys/domain.h> 42224006Shrs#include <sys/protosw.h> 43224006Shrs#include <sys/socket.h> 44224006Shrs#include <sys/errno.h> 45224006Shrs#include <sys/time.h> 46224006Shrs#include <sys/kernel.h> 47224006Shrs 48224006Shrs#include <net/if.h> 49224144Shrs#include <net/route.h> 50224006Shrs 51224006Shrs#include <netinet/in.h> 52224006Shrs#include <netinet/in_systm.h> 53224006Shrs#include <netinet/ip.h> 54224006Shrs#include <netinet/in_pcb.h> 55224006Shrs#include <netinet/in_var.h> 56224006Shrs#include <netinet/ip_var.h> 57224006Shrs#include <netinet/ip_icmp.h> 58253970Shrs 59224006Shrs#include <netinet/ip_fw.h> 60224006Shrs 61224006Shrs#include <sys/socketvar.h> 62224006Shrsstruct socket *ip_rsvpd; 63224006Shrs 64224006Shrs#ifndef IPFORWARDING 65224144Shrs#ifdef GATEWAY 66224006Shrs#define IPFORWARDING 1 /* forward IP packets not for us */ 67224006Shrs#else /* GATEWAY */ 68224006Shrs#define IPFORWARDING 0 /* don't forward IP packets not for us */ 69224006Shrs#endif /* GATEWAY */ 70224006Shrs#endif /* IPFORWARDING */ 71224006Shrs#ifndef IPSENDREDIRECTS 72224006Shrs#define IPSENDREDIRECTS 1 73224006Shrs#endif 74224006Shrsint ipforwarding = IPFORWARDING; 75224006Shrsint ipsendredirects = IPSENDREDIRECTS; 76224006Shrsint ip_defttl = IPDEFTTL; 77224006Shrs#ifdef DIAGNOSTIC 78224006Shrsint ipprintfs = 0; 79224006Shrs#endif 80224006Shrs 81224006Shrsextern struct domain inetdomain; 82224006Shrsextern struct protosw inetsw[]; 83224006Shrsu_char ip_protox[IPPROTO_MAX]; 84224006Shrsint ipqmaxlen = IFQ_MAXLEN; 85224006Shrsstruct in_ifaddr *in_ifaddr; /* first inet address */ 86224006Shrsstruct ifqueue ipintrq; 87224006Shrs 88224006Shrsstruct ipstat ipstat; 89224006Shrsstruct ipq ipq; 90224006Shrs 91224006Shrs/* 92224006Shrs * We need to save the IP options in case a protocol wants to respond 93224006Shrs * to an incoming packet over the same route if the packet got here 94224006Shrs * using IP source routing. This allows connection establishment and 95224006Shrs * maintenance when the remote end is on a network that is not known 96224006Shrs * to us. 97224006Shrs */ 98224006Shrsint ip_nhops = 0; 99224006Shrsstatic struct ip_srcrt { 100224006Shrs struct in_addr dst; /* final destination */ 101224006Shrs char nop; /* one NOP to align */ 102224006Shrs char srcopt[IPOPT_OFFSET + 1]; /* OPTVAL, OLEN and OFFSET */ 103224006Shrs struct in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)]; 104224006Shrs} ip_srcrt; 105224006Shrs 106224006Shrs#ifdef GATEWAY 107224006Shrsextern int if_index; 108224006Shrsu_long *ip_ifmatrix; 109224006Shrs#endif 110224006Shrs 111224006Shrsstatic void save_rte __P((u_char *, struct in_addr)); 112224006Shrs/* 113224006Shrs * IP initialization: fill in IP protocol switch table. 114224144Shrs * All protocols not implemented in kernel go to raw IP protocol handler. 115224006Shrs */ 116224006Shrsvoid 117224006Shrsip_init() 118224006Shrs{ 119224006Shrs register struct protosw *pr; 120224144Shrs register int i; 121224144Shrs 122224144Shrs pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW); 123224006Shrs if (pr == 0) 124224006Shrs panic("ip_init"); 125224006Shrs for (i = 0; i < IPPROTO_MAX; i++) 126224006Shrs ip_protox[i] = pr - inetsw; 127224006Shrs for (pr = inetdomain.dom_protosw; 128224006Shrs pr < inetdomain.dom_protoswNPROTOSW; pr++) 129224006Shrs if (pr->pr_domain->dom_family == PF_INET && 130224006Shrs pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) 131224006Shrs ip_protox[pr->pr_protocol] = pr - inetsw; 132224006Shrs ipq.next = ipq.prev = &ipq; 133224006Shrs ip_id = time.tv_sec & 0xffff; 134224006Shrs ipintrq.ifq_maxlen = ipqmaxlen; 135224006Shrs#ifdef GATEWAY 136224006Shrs i = (if_index + 1) * (if_index + 1) * sizeof (u_long); 137224006Shrs ip_ifmatrix = (u_long *) malloc(i, M_RTABLE, M_WAITOK); 138224006Shrs bzero((char *)ip_ifmatrix, i); 139224006Shrs#endif 140224006Shrs} 141224006Shrs 142224006Shrsstruct sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET }; 143224006Shrsstruct route ipforward_rt; 144224006Shrs 145224006Shrs/* 146224006Shrs * Ip input routine. Checksum and byte swap header. If fragmented 147224006Shrs * try to reassemble. Process options. Pass to next level. 148224006Shrs */ 149224006Shrsvoid 150224006Shrsipintr() 151224006Shrs{ 152224006Shrs register struct ip *ip; 153224006Shrs register struct mbuf *m; 154224006Shrs register struct ipq *fp; 155224006Shrs register struct in_ifaddr *ia; 156224006Shrs int hlen, s; 157224006Shrs 158224006Shrsnext: 159224006Shrs /* 160224006Shrs * Get next datagram off input queue and get IP header 161224006Shrs * in first mbuf. 162224006Shrs */ 163224006Shrs s = splimp(); 164224006Shrs IF_DEQUEUE(&ipintrq, m); 165224006Shrs splx(s); 166224006Shrs if (m == 0) 167224006Shrs return; 168224006Shrs#ifdef DIAGNOSTIC 169224006Shrs if ((m->m_flags & M_PKTHDR) == 0) 170224006Shrs panic("ipintr no HDR"); 171224006Shrs#endif 172224006Shrs /* 173224006Shrs * If no IP addresses have been set yet but the interfaces 174224006Shrs * are receiving, can't do anything with incoming packets yet. 175224006Shrs */ 176224006Shrs if (in_ifaddr == NULL) 177224006Shrs goto bad; 178224006Shrs ipstat.ips_total++; 179224006Shrs if (m->m_len < sizeof (struct ip) && 180224006Shrs (m = m_pullup(m, sizeof (struct ip))) == 0) { 181224006Shrs ipstat.ips_toosmall++; 182224006Shrs goto next; 183224006Shrs } 184224144Shrs ip = mtod(m, struct ip *); 185224006Shrs if (ip->ip_v != IPVERSION) { 186224006Shrs ipstat.ips_badvers++; 187224144Shrs goto bad; 188224144Shrs } 189224144Shrs hlen = ip->ip_hl << 2; 190224144Shrs if (hlen < sizeof(struct ip)) { /* minimum header length */ 191224144Shrs ipstat.ips_badhlen++; 192224144Shrs goto bad; 193224144Shrs } 194224144Shrs if (hlen > m->m_len) { 195224006Shrs if ((m = m_pullup(m, hlen)) == 0) { 196224006Shrs ipstat.ips_badhlen++; 197224006Shrs goto next; 198224006Shrs } 199224006Shrs ip = mtod(m, struct ip *); 200224006Shrs } 201224006Shrs ip->ip_sum = in_cksum(m, hlen); 202224006Shrs if (ip->ip_sum) { 203224006Shrs ipstat.ips_badsum++; 204224006Shrs goto bad; 205224006Shrs } 206224006Shrs 207224006Shrs /* 208224006Shrs * Convert fields to host representation. 209224006Shrs */ 210224006Shrs NTOHS(ip->ip_len); 211224006Shrs if (ip->ip_len < hlen) { 212224006Shrs ipstat.ips_badlen++; 213224006Shrs goto bad; 214224006Shrs } 215224006Shrs NTOHS(ip->ip_id); 216224006Shrs NTOHS(ip->ip_off); 217224006Shrs 218224006Shrs /* 219224006Shrs * Check that the amount of data in the buffers 220224006Shrs * is as at least much as the IP header would have us expect. 221224006Shrs * Trim mbufs if longer than we expect. 222224006Shrs * Drop packet if shorter than we expect. 223224006Shrs */ 224224006Shrs if (m->m_pkthdr.len < ip->ip_len) { 225224006Shrs ipstat.ips_tooshort++; 226224006Shrs goto bad; 227224006Shrs } 228224006Shrs if (m->m_pkthdr.len > ip->ip_len) { 229224006Shrs if (m->m_len == m->m_pkthdr.len) { 230224006Shrs m->m_len = ip->ip_len; 231224006Shrs m->m_pkthdr.len = ip->ip_len; 232224006Shrs } else 233224006Shrs m_adj(m, ip->ip_len - m->m_pkthdr.len); 234224006Shrs } 235224006Shrs /* 236224006Shrs * IpHack's section. 237224006Shrs * Right now when no processing on packet has done 238224006Shrs * and it is still fresh out of network we do our black 239224006Shrs * deals with it. 240224006Shrs * - Firewall: deny/allow 241224006Shrs * - Wrap: fake packet's addr/port <unimpl.> 242224006Shrs * - Encapsulate: put it in another IP and send out. <unimp.> 243224006Shrs */ 244224006Shrs 245224006Shrs if (ip_fw_chk_ptr!=NULL) 246224006Shrs if (!(*ip_fw_chk_ptr)(ip,m->m_pkthdr.rcvif,ip_fw_chain) ) { 247224006Shrs goto bad; 248224006Shrs } 249224006Shrs 250224006Shrs /* 251224006Shrs * Process options and, if not destined for us, 252224006Shrs * ship it on. ip_dooptions returns 1 when an 253224006Shrs * error was detected (causing an icmp message 254224006Shrs * to be sent and the original packet to be freed). 255224006Shrs */ 256224006Shrs ip_nhops = 0; /* for source routed packets */ 257224006Shrs if (hlen > sizeof (struct ip) && ip_dooptions(m)) 258224006Shrs goto next; 259224006Shrs 260224006Shrs /* greedy RSVP, snatches any PATH packet of the RSVP protocol and no 261224006Shrs * matter if it is destined to another node, or whether it is 262224006Shrs * a multicast one, RSVP wants it! and prevents it from being forwarded 263224006Shrs * anywhere else. Also checks if the rsvp daemon is running before 264225519Shrs * grabbing the packet. 265224006Shrs */ 266224006Shrs if (ip_rsvpd != NULL && ip->ip_p==IPPROTO_RSVP) 267224006Shrs goto ours; 268224006Shrs 269224006Shrs /* 270225519Shrs * Check our list of addresses, to see if the packet is for us. 271224006Shrs */ 272224006Shrs for (ia = in_ifaddr; ia; ia = ia->ia_next) { 273224006Shrs#define satosin(sa) ((struct sockaddr_in *)(sa)) 274224006Shrs 275224006Shrs if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr) 276224006Shrs goto ours; 277224006Shrs if ( 278224006Shrs#ifdef DIRECTED_BROADCAST 279224006Shrs ia->ia_ifp == m->m_pkthdr.rcvif && 280224006Shrs#endif 281224006Shrs (ia->ia_ifp->if_flags & IFF_BROADCAST)) { 282224006Shrs u_long t; 283224006Shrs 284224006Shrs if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == 285224006Shrs ip->ip_dst.s_addr) 286224006Shrs goto ours; 287224006Shrs if (ip->ip_dst.s_addr == ia->ia_netbroadcast.s_addr) 288224006Shrs goto ours; 289225519Shrs /* 290224006Shrs * Look for all-0's host part (old broadcast addr), 291224006Shrs * either for subnet or net. 292224006Shrs */ 293224006Shrs t = ntohl(ip->ip_dst.s_addr); 294224006Shrs if (t == ia->ia_subnet) 295224006Shrs goto ours; 296224006Shrs if (t == ia->ia_net) 297224006Shrs goto ours; 298224006Shrs } 299224006Shrs } 300224006Shrs if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { 301224006Shrs struct in_multi *inm; 302224006Shrs if (ip_mrouter) { 303224006Shrs /* 304224006Shrs * If we are acting as a multicast router, all 305224006Shrs * incoming multicast packets are passed to the 306224006Shrs * kernel-level multicast forwarding function. 307224144Shrs * The packet is returned (relatively) intact; if 308224006Shrs * ip_mforward() returns a non-zero value, the packet 309224144Shrs * must be discarded, else it may be accepted below. 310224144Shrs * 311224144Shrs * (The IP ident field is put in the same byte order 312224144Shrs * as expected when ip_mforward() is called from 313224006Shrs * ip_output().) 314224144Shrs */ 315224144Shrs ip->ip_id = htons(ip->ip_id); 316224144Shrs if (ip_mforward(ip, m->m_pkthdr.rcvif, m, 0) != 0) { 317224144Shrs ipstat.ips_cantforward++; 318224144Shrs m_freem(m); 319224144Shrs goto next; 320224144Shrs } 321224144Shrs ip->ip_id = ntohs(ip->ip_id); 322224144Shrs 323224144Shrs /* 324224144Shrs * The process-level routing demon needs to receive 325224006Shrs * all multicast IGMP packets, whether or not this 326224006Shrs * host belongs to their destination groups. 327224006Shrs */ 328224144Shrs if (ip->ip_p == IPPROTO_IGMP) 329224006Shrs goto ours; 330224144Shrs ipstat.ips_forward++; 331224144Shrs } 332224144Shrs /* 333224144Shrs * See if we belong to the destination multicast group on the 334224006Shrs * arrival interface. 335224144Shrs */ 336224144Shrs IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm); 337224144Shrs if (inm == NULL) { 338224144Shrs ipstat.ips_cantforward++; 339224144Shrs m_freem(m); 340224144Shrs goto next; 341224144Shrs } 342224144Shrs goto ours; 343224144Shrs } 344224144Shrs if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST) 345224144Shrs goto ours; 346224006Shrs if (ip->ip_dst.s_addr == INADDR_ANY) 347224006Shrs goto ours; 348224006Shrs 349224144Shrs /* 350224006Shrs * Not for us; forward if possible and desirable. 351224006Shrs */ 352224144Shrs if (ipforwarding == 0) { 353224144Shrs ipstat.ips_cantforward++; 354224144Shrs m_freem(m); 355224006Shrs } else 356224144Shrs ip_forward(m, 0); 357224144Shrs goto next; 358224144Shrs 359224144Shrsours: 360224144Shrs 361224144Shrs /* 362224144Shrs * If packet came to us we count it... 363224144Shrs * This way we count all incoming packets which has 364224144Shrs * not been forwarded... 365224144Shrs * Do not convert ip_len to host byte order when 366224144Shrs * counting,ppl already made it for us before.. 367224144Shrs */ 368224144Shrs if (ip_acct_cnt_ptr!=NULL) 369224006Shrs (*ip_acct_cnt_ptr)(ip,m->m_pkthdr.rcvif,ip_acct_chain,0); 370224006Shrs 371224006Shrs /* 372224006Shrs * If offset or IP_MF are set, must reassemble. 373224006Shrs * Otherwise, nothing need be done. 374224006Shrs * (We could look in the reassembly queue to see 375224006Shrs * if the packet was previously fragmented, 376224006Shrs * but it's not worth the time; just let them time out.) 377224144Shrs */ 378224006Shrs if (ip->ip_off &~ IP_DF) { 379224006Shrs if (m->m_flags & M_EXT) { /* XXX */ 380224006Shrs if ((m = m_pullup(m, sizeof (struct ip))) == 0) { 381224006Shrs ipstat.ips_toosmall++; 382224006Shrs goto next; 383224006Shrs } 384224006Shrs ip = mtod(m, struct ip *); 385224006Shrs } 386224144Shrs /* 387224006Shrs * Look for queue of fragments 388224006Shrs * of this datagram. 389224006Shrs */ 390224006Shrs for (fp = ipq.next; fp != &ipq; fp = fp->next) 391224006Shrs if (ip->ip_id == fp->ipq_id && 392224006Shrs ip->ip_src.s_addr == fp->ipq_src.s_addr && 393224006Shrs ip->ip_dst.s_addr == fp->ipq_dst.s_addr && 394224006Shrs ip->ip_p == fp->ipq_p) 395224006Shrs goto found; 396224006Shrs fp = 0; 397224006Shrsfound: 398224006Shrs 399224006Shrs /* 400224006Shrs * Adjust ip_len to not reflect header, 401224006Shrs * set ip_mff if more fragments are expected, 402224006Shrs * convert offset of this to bytes. 403224006Shrs */ 404224006Shrs ip->ip_len -= hlen; 405224006Shrs ((struct ipasfrag *)ip)->ipf_mff &= ~1; 406224006Shrs if (ip->ip_off & IP_MF) 407224006Shrs ((struct ipasfrag *)ip)->ipf_mff |= 1; 408224006Shrs ip->ip_off <<= 3; 409224006Shrs 410224006Shrs /* 411224006Shrs * If datagram marked as having more fragments 412224006Shrs * or if this is not the first fragment, 413224006Shrs * attempt reassembly; if it succeeds, proceed. 414224006Shrs */ 415224144Shrs if (((struct ipasfrag *)ip)->ipf_mff & 1 || ip->ip_off) { 416224006Shrs ipstat.ips_fragments++; 417224006Shrs ip = ip_reass((struct ipasfrag *)ip, fp); 418224006Shrs if (ip == 0) 419224006Shrs goto next; 420253970Shrs ipstat.ips_reassembled++; 421224006Shrs m = dtom(ip); 422224006Shrs } else 423224006Shrs if (fp) 424224006Shrs ip_freef(fp); 425224006Shrs } else 426224006Shrs ip->ip_len -= hlen; 427224006Shrs 428224006Shrs /* 429224006Shrs * Switch out to protocol's input routine. 430224006Shrs */ 431224006Shrs ipstat.ips_delivered++; 432224006Shrs (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen); 433224006Shrs goto next; 434224006Shrsbad: 435224006Shrs m_freem(m); 436224006Shrs goto next; 437224006Shrs} 438224006Shrs 439224006Shrs/* 440224006Shrs * Take incoming datagram fragment and try to 441224144Shrs * reassemble it into whole datagram. If a chain for 442224006Shrs * reassembly of this datagram already exists, then it 443224006Shrs * is given as fp; otherwise have to make a chain. 444224006Shrs */ 445224006Shrsstruct ip * 446224006Shrsip_reass(ip, fp) 447224006Shrs register struct ipasfrag *ip; 448224006Shrs register struct ipq *fp; 449224006Shrs{ 450224006Shrs register struct mbuf *m = dtom(ip); 451224006Shrs register struct ipasfrag *q; 452224006Shrs struct mbuf *t; 453224144Shrs int hlen = ip->ip_hl << 2; 454224006Shrs int i, next; 455224006Shrs 456224006Shrs /* 457224006Shrs * Presence of header sizes in mbufs 458224144Shrs * would confuse code below. 459224144Shrs */ 460224144Shrs m->m_data += hlen; 461224144Shrs m->m_len -= hlen; 462224144Shrs 463224144Shrs /* 464224144Shrs * If first fragment to arrive, create a reassembly queue. 465224006Shrs */ 466224006Shrs if (fp == 0) { 467224006Shrs if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL) 468224006Shrs goto dropfrag; 469253970Shrs fp = mtod(t, struct ipq *); 470253970Shrs insque(fp, &ipq); 471253970Shrs fp->ipq_ttl = IPFRAGTTL; 472253970Shrs fp->ipq_p = ip->ip_p; 473224006Shrs fp->ipq_id = ip->ip_id; 474224006Shrs fp->ipq_next = fp->ipq_prev = (struct ipasfrag *)fp; 475224144Shrs fp->ipq_src = ((struct ip *)ip)->ip_src; 476224006Shrs fp->ipq_dst = ((struct ip *)ip)->ip_dst; 477224006Shrs q = (struct ipasfrag *)fp; 478224006Shrs goto insert; 479224006Shrs } 480224006Shrs 481224006Shrs /* 482224006Shrs * Find a segment which begins after this one does. 483224006Shrs */ 484224006Shrs for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) 485224006Shrs if (q->ip_off > ip->ip_off) 486224006Shrs break; 487224006Shrs 488224006Shrs /* 489224006Shrs * If there is a preceding segment, it may provide some of 490224006Shrs * our data already. If so, drop the data from the incoming 491224006Shrs * segment. If it provides all of our data, drop us. 492224006Shrs */ 493224006Shrs if (q->ipf_prev != (struct ipasfrag *)fp) { 494224006Shrs i = q->ipf_prev->ip_off + q->ipf_prev->ip_len - ip->ip_off; 495224006Shrs if (i > 0) { 496224006Shrs if (i >= ip->ip_len) 497224006Shrs goto dropfrag; 498224006Shrs m_adj(dtom(ip), i); 499224006Shrs ip->ip_off += i; 500224144Shrs ip->ip_len -= i; 501224144Shrs } 502224006Shrs } 503224144Shrs 504224144Shrs /* 505224144Shrs * While we overlap succeeding segments trim them or, 506224144Shrs * if they are completely covered, dequeue them. 507224144Shrs */ 508224006Shrs while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) { 509224006Shrs i = (ip->ip_off + ip->ip_len) - q->ip_off; 510224006Shrs if (i < q->ip_len) { 511224006Shrs q->ip_len -= i; 512224006Shrs q->ip_off += i; 513224006Shrs m_adj(dtom(q), i); 514224144Shrs break; 515224144Shrs } 516224144Shrs q = q->ipf_next; 517224144Shrs m_freem(dtom(q->ipf_prev)); 518224144Shrs ip_deq(q->ipf_prev); 519224144Shrs } 520224144Shrs 521224144Shrsinsert: 522224144Shrs /* 523224144Shrs * Stick new segment in its place; 524224144Shrs * check for complete reassembly. 525224144Shrs */ 526224144Shrs ip_enq(ip, q->ipf_prev); 527224144Shrs next = 0; 528224144Shrs for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) { 529224144Shrs if (q->ip_off != next) 530224144Shrs return (0); 531224144Shrs next += q->ip_len; 532224144Shrs } 533224006Shrs if (q->ipf_prev->ipf_mff & 1) 534224006Shrs return (0); 535224006Shrs 536224006Shrs /* 537224006Shrs * Reassembly is complete; concatenate fragments. 538224006Shrs */ 539224144Shrs q = fp->ipq_next; 540224006Shrs m = dtom(q); 541224006Shrs t = m->m_next; 542224006Shrs m->m_next = 0; 543224006Shrs m_cat(m, t); 544224006Shrs q = q->ipf_next; 545224006Shrs while (q != (struct ipasfrag *)fp) { 546224006Shrs t = dtom(q); 547224006Shrs q = q->ipf_next; 548224006Shrs m_cat(m, t); 549224006Shrs } 550224006Shrs 551224006Shrs /* 552224144Shrs * Create header for new ip packet by 553224144Shrs * modifying header of first packet; 554224144Shrs * dequeue and discard fragment reassembly header. 555224144Shrs * Make header visible. 556224144Shrs */ 557224006Shrs ip = fp->ipq_next; 558224006Shrs ip->ip_len = next; 559224006Shrs ip->ipf_mff &= ~1; 560224006Shrs ((struct ip *)ip)->ip_src = fp->ipq_src; 561224006Shrs ((struct ip *)ip)->ip_dst = fp->ipq_dst; 562224006Shrs remque(fp); 563224006Shrs (void) m_free(dtom(fp)); 564224006Shrs m = dtom(ip); 565224006Shrs m->m_len += (ip->ip_hl << 2); 566224006Shrs m->m_data -= (ip->ip_hl << 2); 567224006Shrs /* some debugging cruft by sklower, below, will go away soon */ 568224006Shrs if (m->m_flags & M_PKTHDR) { /* XXX this should be done elsewhere */ 569224006Shrs register int plen = 0; 570224006Shrs for (t = m; m; m = m->m_next) 571224006Shrs plen += m->m_len; 572224006Shrs t->m_pkthdr.len = plen; 573224006Shrs } 574224006Shrs return ((struct ip *)ip); 575224006Shrs 576224006Shrsdropfrag: 577224006Shrs ipstat.ips_fragdropped++; 578224006Shrs m_freem(m); 579224006Shrs return (0); 580225519Shrs} 581225519Shrs 582225519Shrs/* 583224006Shrs * Free a fragment reassembly header and all 584224006Shrs * associated datagrams. 585224006Shrs */ 586224006Shrsvoid 587224006Shrsip_freef(fp) 588224006Shrs struct ipq *fp; 589224006Shrs{ 590224006Shrs register struct ipasfrag *q, *p; 591224006Shrs 592224006Shrs for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = p) { 593224006Shrs p = q->ipf_next; 594224006Shrs ip_deq(q); 595224006Shrs m_freem(dtom(q)); 596224006Shrs } 597224006Shrs remque(fp); 598224006Shrs (void) m_free(dtom(fp)); 599224006Shrs} 600224006Shrs 601224006Shrs/* 602225519Shrs * Put an ip fragment on a reassembly chain. 603225519Shrs * Like insque, but pointers in middle of structure. 604225519Shrs */ 605224006Shrsvoid 606224006Shrsip_enq(p, prev) 607224006Shrs register struct ipasfrag *p, *prev; 608224006Shrs{ 609224006Shrs 610224144Shrs p->ipf_prev = prev; 611224144Shrs p->ipf_next = prev->ipf_next; 612224144Shrs prev->ipf_next->ipf_prev = p; 613224144Shrs prev->ipf_next = p; 614224144Shrs} 615224144Shrs 616224144Shrs/* 617224144Shrs * To ip_enq as remque is to insque. 618224144Shrs */ 619224144Shrsvoid 620224144Shrsip_deq(p) 621224144Shrs register struct ipasfrag *p; 622224144Shrs{ 623224144Shrs 624253970Shrs p->ipf_prev->ipf_next = p->ipf_next; 625253970Shrs p->ipf_next->ipf_prev = p->ipf_prev; 626253970Shrs} 627253970Shrs 628253970Shrs/* 629253970Shrs * IP timer processing; 630253970Shrs * if a timer expires on a reassembly 631253970Shrs * queue, discard it. 632253970Shrs */ 633253970Shrsvoid 634253970Shrsip_slowtimo() 635253970Shrs{ 636253970Shrs register struct ipq *fp; 637253970Shrs int s = splnet(); 638224006Shrs 639224144Shrs fp = ipq.next; 640224006Shrs if (fp == 0) { 641224006Shrs splx(s); 642224006Shrs return; 643224006Shrs } 644224006Shrs while (fp != &ipq) { 645224006Shrs --fp->ipq_ttl; 646224006Shrs fp = fp->next; 647224006Shrs if (fp->prev->ipq_ttl == 0) { 648224006Shrs ipstat.ips_fragtimeout++; 649224006Shrs ip_freef(fp->prev); 650224006Shrs } 651224006Shrs } 652224006Shrs splx(s); 653224006Shrs} 654224006Shrs 655224006Shrs/* 656224006Shrs * Drain off all datagram fragments. 657224006Shrs */ 658224006Shrsvoid 659224006Shrsip_drain() 660224144Shrs{ 661224006Shrs 662224006Shrs while (ipq.next != &ipq) { 663224006Shrs ipstat.ips_fragdropped++; 664224006Shrs ip_freef(ipq.next); 665224006Shrs } 666224006Shrs} 667224006Shrs 668224006Shrs/* 669224006Shrs * Do option processing on a datagram, 670224006Shrs * possibly discarding it if bad options are encountered, 671224006Shrs * or forwarding it if source-routed. 672224006Shrs * Returns 1 if packet has been forwarded/freed, 673224006Shrs * 0 if the packet should be processed further. 674224006Shrs */ 675224006Shrsint 676224006Shrsip_dooptions(m) 677224006Shrs struct mbuf *m; 678224006Shrs{ 679224006Shrs register struct ip *ip = mtod(m, struct ip *); 680224006Shrs register u_char *cp; 681224006Shrs register struct ip_timestamp *ipt; 682224006Shrs register struct in_ifaddr *ia; 683224006Shrs int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0; 684224006Shrs struct in_addr *sin, dst; 685224006Shrs n_time ntime; 686224006Shrs 687224144Shrs dst = ip->ip_dst; 688224006Shrs cp = (u_char *)(ip + 1); 689224006Shrs cnt = (ip->ip_hl << 2) - sizeof (struct ip); 690224006Shrs for (; cnt > 0; cnt -= optlen, cp += optlen) { 691224006Shrs opt = cp[IPOPT_OPTVAL]; 692224006Shrs if (opt == IPOPT_EOL) 693224006Shrs break; 694224006Shrs if (opt == IPOPT_NOP) 695224006Shrs optlen = 1; 696224006Shrs else { 697224006Shrs optlen = cp[IPOPT_OLEN]; 698224006Shrs if (optlen <= 0 || optlen > cnt) { 699224006Shrs code = &cp[IPOPT_OLEN] - (u_char *)ip; 700224006Shrs goto bad; 701224006Shrs } 702224144Shrs } 703224006Shrs switch (opt) { 704224006Shrs 705224006Shrs default: 706224006Shrs break; 707224006Shrs 708224006Shrs /* 709224006Shrs * Source routing with record. 710224006Shrs * Find interface with current destination address. 711224006Shrs * If none on this machine then drop if strictly routed, 712224006Shrs * or do nothing if loosely routed. 713224006Shrs * Record interface address and bring up next address 714224144Shrs * component. If strictly routed make sure next 715224144Shrs * address is on directly accessible net. 716224144Shrs */ 717224144Shrs case IPOPT_LSRR: 718224144Shrs case IPOPT_SSRR: 719224144Shrs if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { 720224144Shrs code = &cp[IPOPT_OFFSET] - (u_char *)ip; 721224144Shrs goto bad; 722224144Shrs } 723224144Shrs ipaddr.sin_addr = ip->ip_dst; 724224144Shrs ia = (struct in_ifaddr *) 725224144Shrs ifa_ifwithaddr((struct sockaddr *)&ipaddr); 726224144Shrs if (ia == 0) { 727224144Shrs if (opt == IPOPT_SSRR) { 728224006Shrs type = ICMP_UNREACH; 729224144Shrs code = ICMP_UNREACH_SRCFAIL; 730224006Shrs goto bad; 731224006Shrs } 732224006Shrs /* 733224006Shrs * Loose routing, and not at next destination 734224144Shrs * yet; nothing to do except forward. 735224006Shrs */ 736224144Shrs break; 737224006Shrs } 738224006Shrs off--; /* 0 origin */ 739224006Shrs if (off > optlen - sizeof(struct in_addr)) { 740224006Shrs /* 741224006Shrs * End of source route. Should be for us. 742224006Shrs */ 743224006Shrs save_rte(cp, ip->ip_src); 744224006Shrs break; 745224006Shrs } 746224006Shrs /* 747224006Shrs * locate outgoing interface 748224006Shrs */ 749224006Shrs bcopy((caddr_t)(cp + off), (caddr_t)&ipaddr.sin_addr, 750224006Shrs sizeof(ipaddr.sin_addr)); 751224006Shrs if (opt == IPOPT_SSRR) { 752224006Shrs#define INA struct in_ifaddr * 753224006Shrs#define SA struct sockaddr * 754224006Shrs if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0) 755224006Shrs ia = (INA)ifa_ifwithnet((SA)&ipaddr); 756224006Shrs } else 757224006Shrs ia = ip_rtaddr(ipaddr.sin_addr); 758224006Shrs if (ia == 0) { 759224006Shrs type = ICMP_UNREACH; 760224006Shrs code = ICMP_UNREACH_SRCFAIL; 761224006Shrs goto bad; 762224006Shrs } 763224006Shrs ip->ip_dst = ipaddr.sin_addr; 764253970Shrs bcopy((caddr_t)&(IA_SIN(ia)->sin_addr), 765224006Shrs (caddr_t)(cp + off), sizeof(struct in_addr)); 766253970Shrs cp[IPOPT_OFFSET] += sizeof(struct in_addr); 767224006Shrs /* 768224006Shrs * Let ip_intr's mcast routing check handle mcast pkts 769224006Shrs */ 770224006Shrs forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr)); 771224006Shrs break; 772224006Shrs 773224006Shrs case IPOPT_RR: 774224006Shrs if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { 775224006Shrs code = &cp[IPOPT_OFFSET] - (u_char *)ip; 776224006Shrs goto bad; 777224006Shrs } 778224006Shrs /* 779224006Shrs * If no space remains, ignore. 780224006Shrs */ 781224006Shrs off--; /* 0 origin */ 782224006Shrs if (off > optlen - sizeof(struct in_addr)) 783224006Shrs break; 784224006Shrs bcopy((caddr_t)(&ip->ip_dst), (caddr_t)&ipaddr.sin_addr, 785224006Shrs sizeof(ipaddr.sin_addr)); 786224006Shrs /* 787224006Shrs * locate outgoing interface; if we're the destination, 788224006Shrs * use the incoming interface (should be same). 789224006Shrs */ 790224006Shrs if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 && 791224006Shrs (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) { 792224006Shrs type = ICMP_UNREACH; 793224006Shrs code = ICMP_UNREACH_HOST; 794224006Shrs goto bad; 795224006Shrs } 796224006Shrs bcopy((caddr_t)&(IA_SIN(ia)->sin_addr), 797224006Shrs (caddr_t)(cp + off), sizeof(struct in_addr)); 798224006Shrs cp[IPOPT_OFFSET] += sizeof(struct in_addr); 799224006Shrs break; 800224006Shrs 801224006Shrs case IPOPT_TS: 802224006Shrs code = cp - (u_char *)ip; 803224006Shrs ipt = (struct ip_timestamp *)cp; 804224006Shrs if (ipt->ipt_len < 5) 805224006Shrs goto bad; 806224006Shrs if (ipt->ipt_ptr > ipt->ipt_len - sizeof (long)) { 807224006Shrs if (++ipt->ipt_oflw == 0) 808224006Shrs goto bad; 809224006Shrs break; 810224006Shrs } 811224006Shrs sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1); 812224006Shrs switch (ipt->ipt_flg) { 813224006Shrs 814224006Shrs case IPOPT_TS_TSONLY: 815224006Shrs break; 816224006Shrs 817253970Shrs case IPOPT_TS_TSANDADDR: 818224006Shrs if (ipt->ipt_ptr + sizeof(n_time) + 819224006Shrs sizeof(struct in_addr) > ipt->ipt_len) 820224006Shrs goto bad; 821224006Shrs ipaddr.sin_addr = dst; 822224006Shrs ia = (INA)ifaof_ifpforaddr((SA)&ipaddr, 823224006Shrs m->m_pkthdr.rcvif); 824224006Shrs if (ia == 0) 825224006Shrs continue; 826224006Shrs bcopy((caddr_t)&IA_SIN(ia)->sin_addr, 827224006Shrs (caddr_t)sin, sizeof(struct in_addr)); 828224006Shrs ipt->ipt_ptr += sizeof(struct in_addr); 829224006Shrs break; 830224006Shrs 831224006Shrs case IPOPT_TS_PRESPEC: 832224006Shrs if (ipt->ipt_ptr + sizeof(n_time) + 833224006Shrs sizeof(struct in_addr) > ipt->ipt_len) 834224006Shrs goto bad; 835224144Shrs bcopy((caddr_t)sin, (caddr_t)&ipaddr.sin_addr, 836224144Shrs sizeof(struct in_addr)); 837224006Shrs if (ifa_ifwithaddr((SA)&ipaddr) == 0) 838224006Shrs continue; 839224006Shrs ipt->ipt_ptr += sizeof(struct in_addr); 840224144Shrs break; 841224006Shrs 842224006Shrs default: 843224006Shrs goto bad; 844224006Shrs } 845224144Shrs ntime = iptime(); 846224006Shrs bcopy((caddr_t)&ntime, (caddr_t)cp + ipt->ipt_ptr - 1, 847224006Shrs sizeof(n_time)); 848224006Shrs ipt->ipt_ptr += sizeof(n_time); 849224006Shrs } 850224006Shrs } 851224006Shrs if (forward) { 852224006Shrs ip_forward(m, 1); 853224006Shrs return (1); 854224144Shrs } 855224006Shrs return (0); 856224006Shrsbad: 857224006Shrs ip->ip_len -= ip->ip_hl << 2; /* XXX icmp_error adds in hdr length */ 858224006Shrs icmp_error(m, type, code, 0, 0); 859224006Shrs ipstat.ips_badoptions++; 860224006Shrs return (1); 861224006Shrs} 862224006Shrs 863224006Shrs/* 864224006Shrs * Given address of next destination (final or next hop), 865224006Shrs * return internet address info of interface to be used to get there. 866224006Shrs */ 867224006Shrsstruct in_ifaddr * 868224006Shrsip_rtaddr(dst) 869224006Shrs struct in_addr dst; 870224006Shrs{ 871224006Shrs register struct sockaddr_in *sin; 872224006Shrs 873224006Shrs sin = (struct sockaddr_in *) &ipforward_rt.ro_dst; 874224006Shrs 875224006Shrs if (ipforward_rt.ro_rt == 0 || dst.s_addr != sin->sin_addr.s_addr) { 876224006Shrs if (ipforward_rt.ro_rt) { 877224006Shrs RTFREE(ipforward_rt.ro_rt); 878224144Shrs ipforward_rt.ro_rt = 0; 879224144Shrs } 880224006Shrs sin->sin_family = AF_INET; 881224006Shrs sin->sin_len = sizeof(*sin); 882224006Shrs sin->sin_addr = dst; 883224144Shrs 884224006Shrs rtalloc_ign(&ipforward_rt, RTF_PRCLONING); 885224006Shrs } 886224006Shrs if (ipforward_rt.ro_rt == 0) 887224006Shrs return ((struct in_ifaddr *)0); 888224144Shrs return ((struct in_ifaddr *) ipforward_rt.ro_rt->rt_ifa); 889224006Shrs} 890224006Shrs 891224006Shrs/* 892224006Shrs * Save incoming source route for use in replies, 893224006Shrs * to be picked up later by ip_srcroute if the receiver is interested. 894224006Shrs */ 895224006Shrsvoid 896224006Shrssave_rte(option, dst) 897224144Shrs u_char *option; 898224006Shrs struct in_addr dst; 899224006Shrs{ 900224006Shrs unsigned olen; 901224006Shrs 902224006Shrs olen = option[IPOPT_OLEN]; 903224006Shrs#ifdef DIAGNOSTIC 904224006Shrs if (ipprintfs) 905224006Shrs printf("save_rte: olen %d\n", olen); 906224006Shrs#endif 907224006Shrs if (olen > sizeof(ip_srcrt) - (1 + sizeof(dst))) 908224006Shrs return; 909224006Shrs bcopy((caddr_t)option, (caddr_t)ip_srcrt.srcopt, olen); 910224006Shrs ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr); 911224006Shrs ip_srcrt.dst = dst; 912224006Shrs} 913224006Shrs 914224006Shrs/* 915224006Shrs * Retrieve incoming source route for use in replies, 916224006Shrs * in the same form used by setsockopt. 917224006Shrs * The first hop is placed before the options, will be removed later. 918224006Shrs */ 919224006Shrsstruct mbuf * 920224006Shrsip_srcroute() 921224006Shrs{ 922224006Shrs register struct in_addr *p, *q; 923224006Shrs register struct mbuf *m; 924224006Shrs 925224006Shrs if (ip_nhops == 0) 926224006Shrs return ((struct mbuf *)0); 927224006Shrs m = m_get(M_DONTWAIT, MT_SOOPTS); 928224006Shrs if (m == 0) 929224006Shrs return ((struct mbuf *)0); 930224006Shrs 931224006Shrs#define OPTSIZ (sizeof(ip_srcrt.nop) + sizeof(ip_srcrt.srcopt)) 932224006Shrs 933224006Shrs /* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */ 934224006Shrs m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) + 935224006Shrs OPTSIZ; 936224006Shrs#ifdef DIAGNOSTIC 937224006Shrs if (ipprintfs) 938224006Shrs printf("ip_srcroute: nhops %d mlen %d", ip_nhops, m->m_len); 939224006Shrs#endif 940 941 /* 942 * First save first hop for return route 943 */ 944 p = &ip_srcrt.route[ip_nhops - 1]; 945 *(mtod(m, struct in_addr *)) = *p--; 946#ifdef DIAGNOSTIC 947 if (ipprintfs) 948 printf(" hops %lx", ntohl(mtod(m, struct in_addr *)->s_addr)); 949#endif 950 951 /* 952 * Copy option fields and padding (nop) to mbuf. 953 */ 954 ip_srcrt.nop = IPOPT_NOP; 955 ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF; 956 bcopy((caddr_t)&ip_srcrt.nop, 957 mtod(m, caddr_t) + sizeof(struct in_addr), OPTSIZ); 958 q = (struct in_addr *)(mtod(m, caddr_t) + 959 sizeof(struct in_addr) + OPTSIZ); 960#undef OPTSIZ 961 /* 962 * Record return path as an IP source route, 963 * reversing the path (pointers are now aligned). 964 */ 965 while (p >= ip_srcrt.route) { 966#ifdef DIAGNOSTIC 967 if (ipprintfs) 968 printf(" %lx", ntohl(q->s_addr)); 969#endif 970 *q++ = *p--; 971 } 972 /* 973 * Last hop goes to final destination. 974 */ 975 *q = ip_srcrt.dst; 976#ifdef DIAGNOSTIC 977 if (ipprintfs) 978 printf(" %lx\n", ntohl(q->s_addr)); 979#endif 980 return (m); 981} 982 983/* 984 * Strip out IP options, at higher 985 * level protocol in the kernel. 986 * Second argument is buffer to which options 987 * will be moved, and return value is their length. 988 * XXX should be deleted; last arg currently ignored. 989 */ 990void 991ip_stripoptions(m, mopt) 992 register struct mbuf *m; 993 struct mbuf *mopt; 994{ 995 register int i; 996 struct ip *ip = mtod(m, struct ip *); 997 register caddr_t opts; 998 int olen; 999 1000 olen = (ip->ip_hl<<2) - sizeof (struct ip); 1001 opts = (caddr_t)(ip + 1); 1002 i = m->m_len - (sizeof (struct ip) + olen); 1003 bcopy(opts + olen, opts, (unsigned)i); 1004 m->m_len -= olen; 1005 if (m->m_flags & M_PKTHDR) 1006 m->m_pkthdr.len -= olen; 1007 ip->ip_hl = sizeof(struct ip) >> 2; 1008} 1009 1010u_char inetctlerrmap[PRC_NCMDS] = { 1011 0, 0, 0, 0, 1012 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH, 1013 EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, 1014 EMSGSIZE, EHOSTUNREACH, 0, 0, 1015 0, 0, 0, 0, 1016 ENOPROTOOPT 1017}; 1018 1019/* 1020 * Forward a packet. If some error occurs return the sender 1021 * an icmp packet. Note we can't always generate a meaningful 1022 * icmp message because icmp doesn't have a large enough repertoire 1023 * of codes and types. 1024 * 1025 * If not forwarding, just drop the packet. This could be confusing 1026 * if ipforwarding was zero but some routing protocol was advancing 1027 * us as a gateway to somewhere. However, we must let the routing 1028 * protocol deal with that. 1029 * 1030 * The srcrt parameter indicates whether the packet is being forwarded 1031 * via a source route. 1032 */ 1033void 1034ip_forward(m, srcrt) 1035 struct mbuf *m; 1036 int srcrt; 1037{ 1038 register struct ip *ip = mtod(m, struct ip *); 1039 register struct sockaddr_in *sin; 1040 register struct rtentry *rt; 1041 int error, type = 0, code = 0; 1042 struct mbuf *mcopy; 1043 n_long dest; 1044 struct ifnet *destifp; 1045 1046 dest = 0; 1047#ifdef DIAGNOSTIC 1048 if (ipprintfs) 1049 printf("forward: src %lx dst %lx ttl %x\n", 1050 ip->ip_src.s_addr, ip->ip_dst.s_addr, ip->ip_ttl); 1051#endif 1052 1053 1054 if (m->m_flags & M_BCAST || in_canforward(ip->ip_dst) == 0) { 1055 ipstat.ips_cantforward++; 1056 m_freem(m); 1057 return; 1058 } 1059 HTONS(ip->ip_id); 1060 if (ip->ip_ttl <= IPTTLDEC) { 1061 icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, dest, 0); 1062 return; 1063 } 1064 ip->ip_ttl -= IPTTLDEC; 1065 1066 sin = (struct sockaddr_in *)&ipforward_rt.ro_dst; 1067 if ((rt = ipforward_rt.ro_rt) == 0 || 1068 ip->ip_dst.s_addr != sin->sin_addr.s_addr) { 1069 if (ipforward_rt.ro_rt) { 1070 RTFREE(ipforward_rt.ro_rt); 1071 ipforward_rt.ro_rt = 0; 1072 } 1073 sin->sin_family = AF_INET; 1074 sin->sin_len = sizeof(*sin); 1075 sin->sin_addr = ip->ip_dst; 1076 1077 rtalloc_ign(&ipforward_rt, RTF_PRCLONING); 1078 if (ipforward_rt.ro_rt == 0) { 1079 icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0); 1080 return; 1081 } 1082 rt = ipforward_rt.ro_rt; 1083 } 1084 1085 /* 1086 * Save at most 64 bytes of the packet in case 1087 * we need to generate an ICMP message to the src. 1088 */ 1089 mcopy = m_copy(m, 0, imin((int)ip->ip_len, 64)); 1090 1091#ifdef bogus 1092#ifdef GATEWAY 1093 ip_ifmatrix[rt->rt_ifp->if_index + 1094 if_index * m->m_pkthdr.rcvif->if_index]++; 1095#endif 1096#endif 1097 /* 1098 * If forwarding packet using same interface that it came in on, 1099 * perhaps should send a redirect to sender to shortcut a hop. 1100 * Only send redirect if source is sending directly to us, 1101 * and if packet was not source routed (or has any options). 1102 * Also, don't send redirect if forwarding using a default route 1103 * or a route modified by a redirect. 1104 */ 1105#define satosin(sa) ((struct sockaddr_in *)(sa)) 1106 if (rt->rt_ifp == m->m_pkthdr.rcvif && 1107 (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 && 1108 satosin(rt_key(rt))->sin_addr.s_addr != 0 && 1109 ipsendredirects && !srcrt) { 1110#define RTA(rt) ((struct in_ifaddr *)(rt->rt_ifa)) 1111 u_long src = ntohl(ip->ip_src.s_addr); 1112 1113 if (RTA(rt) && 1114 (src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) { 1115 if (rt->rt_flags & RTF_GATEWAY) 1116 dest = satosin(rt->rt_gateway)->sin_addr.s_addr; 1117 else 1118 dest = ip->ip_dst.s_addr; 1119 /* Router requirements says to only send host redirects */ 1120 type = ICMP_REDIRECT; 1121 code = ICMP_REDIRECT_HOST; 1122#ifdef DIAGNOSTIC 1123 if (ipprintfs) 1124 printf("redirect (%d) to %lx\n", code, (u_long)dest); 1125#endif 1126 } 1127 } 1128 1129 error = ip_output(m, (struct mbuf *)0, &ipforward_rt, IP_FORWARDING 1130#ifdef DIRECTED_BROADCAST 1131 | IP_ALLOWBROADCAST 1132#endif 1133 , 0); 1134 if (error) 1135 ipstat.ips_cantforward++; 1136 else { 1137 ipstat.ips_forward++; 1138 if (type) 1139 ipstat.ips_redirectsent++; 1140 else { 1141 if (mcopy) 1142 m_freem(mcopy); 1143 return; 1144 } 1145 } 1146 if (mcopy == NULL) 1147 return; 1148 destifp = NULL; 1149 1150 switch (error) { 1151 1152 case 0: /* forwarded, but need redirect */ 1153 /* type, code set above */ 1154 break; 1155 1156 case ENETUNREACH: /* shouldn't happen, checked above */ 1157 case EHOSTUNREACH: 1158 case ENETDOWN: 1159 case EHOSTDOWN: 1160 default: 1161 type = ICMP_UNREACH; 1162 code = ICMP_UNREACH_HOST; 1163 break; 1164 1165 case EMSGSIZE: 1166 type = ICMP_UNREACH; 1167 code = ICMP_UNREACH_NEEDFRAG; 1168 if (ipforward_rt.ro_rt) 1169 destifp = ipforward_rt.ro_rt->rt_ifp; 1170 ipstat.ips_cantfrag++; 1171 break; 1172 1173 case ENOBUFS: 1174 type = ICMP_SOURCEQUENCH; 1175 code = 0; 1176 break; 1177 } 1178 icmp_error(mcopy, type, code, dest, destifp); 1179} 1180 1181int 1182ip_sysctl(name, namelen, oldp, oldlenp, newp, newlen) 1183 int *name; 1184 u_int namelen; 1185 void *oldp; 1186 size_t *oldlenp; 1187 void *newp; 1188 size_t newlen; 1189{ 1190 extern int rtq_reallyold; /* XXX */ 1191 extern int rtq_minreallyold; /* XXX */ 1192 extern int rtq_toomany; /* XXX */ 1193 1194 /* All sysctl names at this level are terminal. */ 1195 if (namelen != 1) 1196 return (ENOTDIR); 1197 1198 switch (name[0]) { 1199 case IPCTL_FORWARDING: 1200 return (sysctl_int(oldp, oldlenp, newp, newlen, &ipforwarding)); 1201 case IPCTL_SENDREDIRECTS: 1202 return (sysctl_int(oldp, oldlenp, newp, newlen, 1203 &ipsendredirects)); 1204 case IPCTL_DEFTTL: 1205 return (sysctl_int(oldp, oldlenp, newp, newlen, &ip_defttl)); 1206#ifdef notyet 1207 case IPCTL_DEFMTU: 1208 return (sysctl_int(oldp, oldlenp, newp, newlen, &ip_mtu)); 1209#endif 1210 case IPCTL_RTEXPIRE: 1211 return (sysctl_int(oldp, oldlenp, newp, newlen, 1212 &rtq_reallyold)); 1213 case IPCTL_RTMINEXPIRE: 1214 return (sysctl_int(oldp, oldlenp, newp, newlen, 1215 &rtq_minreallyold)); 1216 case IPCTL_RTMAXCACHE: 1217 return (sysctl_int(oldp, oldlenp, newp, newlen, 1218 &rtq_toomany)); 1219 default: 1220 return (EOPNOTSUPP); 1221 } 1222 /* NOTREACHED */ 1223} 1224 1225int 1226ip_rsvp_init(struct socket *so) 1227{ 1228 if (so->so_type != SOCK_RAW || 1229 so->so_proto->pr_protocol != IPPROTO_RSVP) 1230 return EOPNOTSUPP; 1231 1232 if (ip_rsvpd != NULL) 1233 return EADDRINUSE; 1234 1235 ip_rsvpd = so; 1236 1237 return 0; 1238} 1239 1240int 1241ip_rsvp_done(void) 1242{ 1243 ip_rsvpd = NULL; 1244 return 0; 1245} 1246