125202Skarels #ifdef RCSIDENT
225202Skarels static char rcsident[] = "$Header: ip_input.c,v 1.39 85/07/31 09:31:26 walsh Exp $";
325202Skarels #endif
425202Skarels
525202Skarels #include "../h/param.h"
625202Skarels #include "../h/mbuf.h"
725202Skarels #include "../h/socket.h"
825202Skarels #include "../h/socketvar.h"
925202Skarels #include "../h/errno.h"
1025202Skarels #include "../h/protosw.h"
1125202Skarels #include "../h/domain.h"
1225202Skarels #include "../h/syslog.h"
1325202Skarels
1425202Skarels #include "../net/if.h"
1525202Skarels #include "../net/route.h"
1625202Skarels #include "../net/raw_cb.h"
1725202Skarels
1825202Skarels #include "../bbnnet/in.h"
1925202Skarels #include "../bbnnet/net.h"
2025202Skarels #include "../bbnnet/in_pcb.h"
2125202Skarels #include "../bbnnet/in_var.h"
2225202Skarels #include "../bbnnet/ip.h"
2325202Skarels #include "../bbnnet/icmp.h"
2425202Skarels #ifdef HMP
2525202Skarels #include "../bbnnet/hmp_traps.h"
2625202Skarels #endif
2725202Skarels
2825202Skarels #ifdef RCSIDENT
2925202Skarels static char rcsiphdr[] = RCSIPHDR;
3025202Skarels #endif
3125202Skarels
3225202Skarels #define rawreaders(r) ((r)->rcb_next != (r))
3325202Skarels #define any_rawreaders() rawreaders(&rawcb)
3425202Skarels
3525202Skarels #define FIELD_OFF(fld, type) (((char *) (&(((type *) 0)->fld))) - ((char *) 0))
3625202Skarels
3725202Skarels struct in_stat otherstat;
3825202Skarels struct ip_stat ipstat;
3925202Skarels struct {
4025202Skarels struct ipq *n_ip_head; /* -> top of ip reass. queue */
4125202Skarels struct ipq *n_ip_tail; /* -> end of ip reass. queue */
4225202Skarels } ipfrags;
4325202Skarels
4425202Skarels
4525202Skarels /*
4625202Skarels * The protocol layers above IP assume the IP header and the protocol
4725202Skarels * header are contiguous. However, need to save the options in case
4825202Skarels * a connection oriented protocol (RDP/TCP) wants to respond to an
4925202Skarels * incoming packet (SYN) over the same route if the packet got here
5025202Skarels * using IP source routing. This allows connection establishment and
5125202Skarels * maintenance when the remote end is on a network that is not known
5225202Skarels * to our gateways. Only applicable options are Loose/Strict source
5325202Skarels * routing, so rather than saving them in ip_stripopt() and reinterpreting
5425202Skarels * them, we'll set up something specific and appropriate here.
5525202Skarels */
5625202Skarels
5725202Skarels int nosum = 0;
5825202Skarels int ip_nhops = 0;
5925202Skarels struct in_addr ip_hops[MAX_IPOPTLEN / sizeof(struct in_addr)];
6025202Skarels
6125202Skarels /* use a dispatch table for protocol dispatching */
6225202Skarels struct ipswitch ipsw[IPPROTO_MAX];
6325202Skarels
6425202Skarels extern struct ip *ip_reass();
6525202Skarels
6625202Skarels
ip_init()6725202Skarels ip_init()
6825202Skarels {
6925202Skarels register struct protosw *pr;
7025202Skarels register int i;
7125202Skarels
7225202Skarels pr = pffindproto(PF_INET, IPPROTO_IP, SOCK_RAW);
7325202Skarels
7425202Skarels /* build our internal switch table */
7525202Skarels for(i=0; i < IPPROTO_MAX; i++)
7625202Skarels {
7725202Skarels ipsw[i].ipsw_raw = pr;
7825202Skarels ipsw[i].ipsw_user = 0;
7925202Skarels ipsw[i].ipsw_hlen = sizeof(struct ip);
8025202Skarels }
8125202Skarels
8225202Skarels for(pr = inetdomain.dom_protosw; pr < inetdomain.dom_protoswNPROTOSW; pr++)
8325202Skarels {
8425202Skarels if (pr->pr_protocol >= IPPROTO_MAX)
8525202Skarels panic("ip_init");
8625202Skarels
8725202Skarels if (pr->pr_type == SOCK_RAW)
8825202Skarels ipsw[pr->pr_protocol].ipsw_raw = pr;
8925202Skarels else
9025202Skarels ipsw[pr->pr_protocol].ipsw_user = pr;
9125202Skarels }
9225202Skarels
9325202Skarels ipintrq.ifq_maxlen = IFQ_MAXLEN; /* got a better number? */
9425202Skarels }
9525202Skarels
9625202Skarels /*
9725202Skarels * Being global might be a little gross, but we just got the interface pointer
9825202Skarels * passed up the week before 4.3 release.
9925202Skarels */
10025202Skarels struct ifnet *inetifp;
10125202Skarels
10225202Skarels /*
10325202Skarels * IP network software interrupt service routine. Dequeue a message from the
10425202Skarels * ip input queue, and pass to internal ip input processor (ip_input).
10525202Skarels */
ipintr()10625202Skarels ipintr()
10725202Skarels {
10825202Skarels extern char *panicstr;
10925202Skarels register struct mbuf *m;
11025202Skarels register int s;
11125202Skarels
11225202Skarels /*
11325202Skarels * Half-hearted attempt to prevent recursive panics due to network
11425202Skarels * bugs since panic calls boot, which lowers spl. Note that the
11525202Skarels * drivers will still store packets in mbufs and that some processing
11625202Skarels * (ARP, Chaosnet) that occurs at splimp() will still proceed. At
11725202Skarels * least this should preserve state information for post-mortem.
11825202Skarels */
11925202Skarels if (panicstr == NULL)
12025202Skarels {
12125202Skarels for (;;)
12225202Skarels {
12325202Skarels /* for 4.3, Berkeley finally changed imp code to queue up messages
12425202Skarels * for ctlinput path, so don't need to check for them here with our
12525202Skarels * old queueing mechanism
12625202Skarels */
12725202Skarels
12825202Skarels s = splimp();
12925202Skarels IF_DEQUEUEIF (&ipintrq, m, inetifp);
13025202Skarels splx(s);
13125202Skarels if (m == NULL)
13225202Skarels return;
13325202Skarels
13425202Skarels ip_input(m);
13525202Skarels }
13625202Skarels }
13725202Skarels }
13825202Skarels
13925202Skarels /*
14025202Skarels * IP level input routine
14125202Skarels *
14225202Skarels * Called from local net level upon recpt of an internet datagram or fragment.
14325202Skarels * This routine does fragment reassembly, if necessary, and passes completed
14425202Skarels * datagrams to higher level protocol processing routines on the basis of the
14525202Skarels * ip header protocol field. It is passed a pointer to an mbuf chain
14625202Skarels * containing the datagram/fragment. The mbuf offset+length are set to point
14725202Skarels * at the ip header.
14825202Skarels */
ip_input(mp)14925202Skarels ip_input(mp)
15025202Skarels register struct mbuf *mp;
15125202Skarels {
15225202Skarels register struct ip *ip;
15325202Skarels register int hlen;
15425202Skarels register int i;
15525202Skarels register struct mbuf *m;
15625202Skarels register struct ipq *fp;
15725202Skarels int fragsize = 0;
15825202Skarels struct in_ifaddr *ia;
15925202Skarels int j;
16025202Skarels struct inpcb fwdinp;
16125202Skarels
16225202Skarels ipstat.ip_total ++;
16325202Skarels /*
16425202Skarels * make sure dtom() macro works by getting header out of mbufs using
16525202Skarels * pages, also make sure header contiguous in first mbuf.
16625202Skarels */
16725202Skarels if ((mp->m_off > MMAXOFF) || (mp->m_len < sizeof(struct ip)))
16825202Skarels {
16925202Skarels /*
17025202Skarels * Might as well avoid doing m_pullup twice.
17125202Skarels * Common case is using cluster for large chunk of data.
17225202Skarels */
17325202Skarels if (mp->m_len < FIELD_OFF(ip_p, struct ip) + sizeof(ip->ip_p))
17425202Skarels i = sizeof(struct ip);
17525202Skarels else
17625202Skarels {
17725202Skarels ip = mtod(mp, struct ip *);
17825202Skarels i = ipsw[ip->ip_p].ipsw_hlen;
17925202Skarels }
18025202Skarels
18125202Skarels if ((mp = m_pullup(mp, i)) == NULL)
18225202Skarels {
18325202Skarels ipstat.ip_tooshort ++;
18425202Skarels return;
18525202Skarels }
18625202Skarels }
18725202Skarels
18825202Skarels ip = mtod(mp, struct ip *);
18925202Skarels
19025202Skarels /*
19125202Skarels * make sure header does not overflow mbuf (is contiguous)
19225202Skarels */
19325202Skarels hlen = ip->ip_hl << IP_HLSHIFT;
19425202Skarels if (hlen > mp->m_len)
19525202Skarels {
19625202Skarels if ((mp = m_pullup(mp, hlen)) == NULL)
19725202Skarels {
19825202Skarels ip_log(ip, "ip header overflow");
19925202Skarels #ifdef HMPTRAPS
20025202Skarels /* hmp_trap(T_IP_OVFLO, (caddr_t)0,0); */
20125202Skarels #else
20225202Skarels /* netlog(mp); no longer have mbuf list */
20325202Skarels #endif
20425202Skarels return;
20525202Skarels }
20625202Skarels ip = mtod(mp, struct ip *);
20725202Skarels }
20825202Skarels
20925202Skarels /*
21025202Skarels * Adjust msg length to remove any driver padding. Make sure that
21125202Skarels * message length matches ip length.
21225202Skarels */
21325202Skarels for (i = 0, m = mp; m->m_next != NULL; m = m->m_next)
21425202Skarels i += m->m_len;
21525202Skarels i -= ntohs((u_short)ip->ip_len) - m->m_len;
21625202Skarels if (i != 0)
21725202Skarels {
21825202Skarels if (i > (int)m->m_len)
21925202Skarels m_adj(mp, -i);
22025202Skarels else if (i < 0)
22125202Skarels {
22225202Skarels ip_log(ip, "truncated ip packet");
22325202Skarels #ifdef HMPTRAPS
22425202Skarels /* hmp_trap(T_IP_TRUNC, (caddr_t)0, 0); */
22525202Skarels #else
22625202Skarels netlog(mp);
22725202Skarels #endif
22825202Skarels return;
22925202Skarels }
23025202Skarels else
23125202Skarels m->m_len -= i;
23225202Skarels }
23325202Skarels
23425202Skarels i = (u_short)ip->ip_sum;
23525202Skarels ip->ip_sum = 0;
23625202Skarels
23725202Skarels /* used to do inline cksum here via sed */
23825202Skarels if (i != (j = (u_short)in_cksum(dtom(ip), hlen)))
23925202Skarels {
24025202Skarels ipstat.ip_badsum++;
24125202Skarels if (!nosum)
24225202Skarels {
24325202Skarels #ifdef HMPTRAPS
24425202Skarels /* hmp_trap(T_IP_CKSUM, (caddr_t)0,0); */
24525202Skarels #endif
24625202Skarels inet_cksum_err ("ip", ip, (u_long) i, (u_long) j);
24725202Skarels
24825202Skarels ip->ip_sum = i;
24925202Skarels ic_errmsg (icmp_addr(ip), ip->ip_src,
25025202Skarels ICMP_PARM, 0, FIELD_OFF(ip_sum, struct ip),
25125202Skarels hlen + ICMP_ERRLEN, (char *) ip);
25225202Skarels
25325202Skarels netlog(mp);
25425202Skarels return;
25525202Skarels }
25625202Skarels }
25725202Skarels
25825202Skarels /*
25925202Skarels * Make sure this packet is addressed to us before we put fields
26025202Skarels * in host order and do reassembly (fragments may reach destination
26125202Skarels * by separate routes.)
26225202Skarels * Remember that IP source routing option can change ip_dst, so have
26325202Skarels * to do option processing for all incoming packets with options.
26425202Skarels * Even if the packet turns out to be for us and we strip them.
26525202Skarels */
26625202Skarels fwdinp.inp_route.ro_rt = NULL; /* in case fwd, but no options */
26725202Skarels ip_nhops = 0; /* for source routed TCP/RDP... connections */
26825202Skarels if (hlen > sizeof(struct ip))
26925202Skarels /*
27025202Skarels * Any route allocated by ip_opt() 1. will be used by
27125202Skarels * ip_forward(), and 2. will only be needed by ip_forward()
27225202Skarels */
27325202Skarels if (! ip_opt (ip, hlen, &fwdinp))
27425202Skarels {
27525202Skarels ip_log (ip, "ip option error");
27625202Skarels netlog (mp);
27725202Skarels return;
27825202Skarels }
27925202Skarels
28025202Skarels /*
28125202Skarels * if packet is not for us then forward
28225202Skarels */
28325202Skarels if ((ia = in_iawithaddr(ip->ip_dst, TRUE)) == NULL)
28425202Skarels {
28525202Skarels ip_forward (&fwdinp, ip, mp, hlen);
28625202Skarels return;
28725202Skarels }
28825202Skarels
28925202Skarels ip->ip_len = ntohs((u_short)ip->ip_len);
29025202Skarels if ((int)(ip->ip_len -= hlen) < 0)
29125202Skarels { /* length of data */
29225202Skarels ip_log(ip, "ip header length error");
29325202Skarels #ifdef HMPTRAPS
29425202Skarels /* hmp_trap(T_IP_HLEN, (caddr_t)0,0); */
29525202Skarels #else
29625202Skarels netlog(mp);
29725202Skarels #endif
29825202Skarels return;
29925202Skarels }
30025202Skarels ip->ip_off = ntohs((u_short)ip->ip_off);
30125202Skarels ip->ip_mff = ((ip->ip_off & ip_mf) ? TRUE : FALSE);
30225202Skarels ip->ip_off <<= IP_OFFSHIFT;
30325202Skarels
30425202Skarels /* look for chain on reassembly queue with this header */
30525202Skarels
30625202Skarels for (fp = ipfrags.n_ip_head; (fp != NULL && (
30725202Skarels ip->ip_src.s_addr != fp->iqh.ip_src.s_addr ||
30825202Skarels ip->ip_dst.s_addr != fp->iqh.ip_dst.s_addr ||
30925202Skarels ip->ip_id != fp->iqh.ip_id ||
31025202Skarels ip->ip_p != fp->iqh.ip_p)); fp = fp->iq_next);
31125202Skarels
31225202Skarels if (!ip->ip_mff && ip->ip_off == 0)
31325202Skarels { /* not fragmented */
31425202Skarels
31525202Skarels if (fp != NULL)
31625202Skarels { /* free existing reass chain */
31725202Skarels struct ip *q;
31825202Skarels struct ip *p;
31925202Skarels
32025202Skarels q = fp->iqx.ip_next; /* free mbufs assoc. w/chain */
32125202Skarels while (q != (struct ip *)fp)
32225202Skarels {
32325202Skarels p = q->ip_next;
32425202Skarels m_freem(dtom(q));
32525202Skarels q = p;
32625202Skarels }
32725202Skarels ip_freef(fp); /* free header */
32825202Skarels }
32925202Skarels
33025202Skarels /*
33125202Skarels * The options aren't of any use to higher level
33225202Skarels * protocols or of any concern to the user process.
33325202Skarels */
33425202Skarels if (hlen > sizeof(struct ip))
33525202Skarels ip_stripopt (ip, hlen);
33625202Skarels
33725202Skarels }
33825202Skarels else
33925202Skarels {
34025202Skarels ip = ip_reass(ip, fp, &fragsize);
34125202Skarels if (ip == NULL)
34225202Skarels return;
34325202Skarels mp = dtom(ip);
34425202Skarels }
34525202Skarels
34625202Skarels /* call next level with completed datagram */
34725202Skarels
34825202Skarels /* any raw readers?? */
34925202Skarels /* if (rawreaders((struct rawcb *)ipsw[ip->ip_p].ipsw_raw->pr_ppcbq)) */
35025202Skarels if (any_rawreaders())
35125202Skarels {
35225202Skarels otherstat.in_total++;
35325202Skarels if (m = m_copy(mp, 0, M_COPYALL))
35425202Skarels ipsw[ip->ip_p].ipsw_raw->pr_input(m);
35525202Skarels }
35625202Skarels
35725202Skarels if (ip->ip_p == IPPROTO_TCP)
35825202Skarels /* wish I didn't need this special case for fragsize */
35925202Skarels tcp_input(mp, fragsize);
36025202Skarels else if (ipsw[ip->ip_p].ipsw_user != 0)
36125202Skarels /* There's a protocol implementation for these packets */
36225202Skarels ipsw[ip->ip_p].ipsw_user->pr_input(mp);
36325202Skarels else if (ip->ip_p == IPPROTO_ICMP)
36425202Skarels /*
36525202Skarels * Since don't want user to get a non-raw ICMP socket, did not make
36625202Skarels * an entry in the protocol jump table; also wanted to be able to
36725202Skarels * make raw ICMP socket.
36825202Skarels */
36925202Skarels icmp (mp);
37025202Skarels else
37125202Skarels {
37225202Skarels /*
37325202Skarels * Don't bother everyone on the net, and remember some other
37425202Skarels * host may support the protocol.
37525202Skarels */
37625202Skarels if ((!in_broadcast(ip->ip_src)) && (!in_broadcast(ip->ip_dst)))
37725202Skarels ic_errmsg (icmp_addr(ip), ip->ip_src,
37825202Skarels ICMP_UNRCH, ICMP_UNRCH_PR, FIELD_OFF(ip_p, struct ip),
37925202Skarels sizeof(struct ip) + ICMP_ERRLEN, (char *) ip);
38025202Skarels
38125202Skarels /* get rid of the packet */
38225202Skarels ipstat.ip_drops++;
38325202Skarels m_freem(mp);
38425202Skarels }
38525202Skarels }
38625202Skarels
38725202Skarels
38825202Skarels /*
38925202Skarels * We've received an IP fragment. Try to perform IP reassembly.
39025202Skarels */
ip_reass(ip,fp,fragsize)39125202Skarels struct ip *ip_reass(ip, fp, fragsize)
39225202Skarels register struct ip *ip;
39325202Skarels register struct ipq *fp;
39425202Skarels int *fragsize;
39525202Skarels {
39625202Skarels register struct ip *q, *savq;
39725202Skarels register struct mbuf *mp;
39825202Skarels int hlen;
39925202Skarels int i;
40025202Skarels
40125202Skarels mp = dtom(ip);
40225202Skarels hlen = ip->ip_hl << IP_HLSHIFT;
40325202Skarels
40425202Skarels if (ip->ip_off != 0)
40525202Skarels {
40625202Skarels /*
40725202Skarels * Only the first fragment retains the IP header.
40825202Skarels */
40925202Skarels mp->m_off += hlen;
41025202Skarels mp->m_len -= hlen;
41125202Skarels }
41225202Skarels
41325202Skarels if (fp == NULL)
41425202Skarels {
41525202Skarels /*
41625202Skarels * This is the first fragment of the IP datagram that we've
41725202Skarels * received. Set up reassembly q header.
41825202Skarels */
41925202Skarels struct mbuf *m;
42025202Skarels
42125202Skarels if ((m = m_get(M_WAIT, MT_FTABLE)) == NULL)
42225202Skarels {
42325202Skarels m_freem(mp);
42425202Skarels return(NULL);
42525202Skarels }
42625202Skarels
42725202Skarels fp = mtod(m, struct ipq *);
42825202Skarels fp->iqx.ip_next = fp->iqx.ip_prev = (struct ip *)fp;
42925202Skarels bcopy((caddr_t)ip, (caddr_t)&fp->iqh, sizeof(struct ip));
43025202Skarels fp->iqx.ip_ttl = MAXTTL;
43125202Skarels fp->iq_size = 0;
43225202Skarels /*
43325202Skarels * and enter this into the list of fragmented IP datagrams
43425202Skarels */
43525202Skarels fp->iq_next = NULL;
43625202Skarels fp->iq_prev = ipfrags.n_ip_tail;
43725202Skarels if (ipfrags.n_ip_head != NULL)
43825202Skarels ipfrags.n_ip_tail->iq_next = fp;
43925202Skarels else
44025202Skarels ipfrags.n_ip_head = fp;
44125202Skarels ipfrags.n_ip_tail = fp;
44225202Skarels }
44325202Skarels
44425202Skarels /*
44525202Skarels * Merge fragment into reass.q
44625202Skarels *
44725202Skarels * Algorithm: Match start and end bytes of new
44825202Skarels * fragment with fragments on the queue. If no
44925202Skarels * overlaps are found, add new frag. to the queue.
45025202Skarels * Otherwise, adjust start and end of new frag. so no
45125202Skarels * overlap and add remainder to queue. If any
45225202Skarels * fragments are completely covered by the new one, or
45325202Skarels * if the new one is completely duplicated, free the
45425202Skarels * fragments.
45525202Skarels */
45625202Skarels q = fp->iqx.ip_next; /* -> top of reass. chain */
45725202Skarels ip->ip_end = ip->ip_off + ip->ip_len - 1;
45825202Skarels
45925202Skarels /* record the maximum fragment size for TCP */
46025202Skarels
46125202Skarels fp->iq_size = MAX(ip->ip_len, fp->iq_size);
46225202Skarels
46325202Skarels /* skip frags which new doesn't overlap at end */
46425202Skarels
46525202Skarels while ((q != (struct ip *)fp) && (ip->ip_off > q->ip_end))
46625202Skarels q = q->ip_next;
46725202Skarels
46825202Skarels if (q == (struct ip *)fp)
46925202Skarels { /* frag at end of chain */
47025202Skarels ip_enq(ip, fp->iqx.ip_prev);
47125202Skarels }
47225202Skarels else
47325202Skarels { /* frag doesn't overlap any */
47425202Skarels if (ip->ip_end < q->ip_off)
47525202Skarels {
47625202Skarels ip_enq(ip, q->ip_prev);
47725202Skarels
47825202Skarels /* new overlaps beginning of next frag only */
47925202Skarels
48025202Skarels }
48125202Skarels else if (ip->ip_end < q->ip_end)
48225202Skarels {
48325202Skarels if ((i = ip->ip_end-q->ip_off+1) < ip->ip_len)
48425202Skarels {
48525202Skarels ip->ip_len -= i;
48625202Skarels ip->ip_end -= i;
48725202Skarels m_adj(mp, -i);
48825202Skarels ip_enq(ip, q->ip_prev);
48925202Skarels }
49025202Skarels else
49125202Skarels m_freem(mp);
49225202Skarels
49325202Skarels /* new overlaps end of previous frag */
49425202Skarels
49525202Skarels }
49625202Skarels else
49725202Skarels {
49825202Skarels savq = q;
49925202Skarels if (ip->ip_off <= q->ip_off)
50025202Skarels {
50125202Skarels
50225202Skarels /* complete cover */
50325202Skarels
50425202Skarels savq = q->ip_prev;
50525202Skarels ip_deq(q);
50625202Skarels m_freem(dtom(q));
50725202Skarels
50825202Skarels }
50925202Skarels else
51025202Skarels { /* overlap */
51125202Skarels if ((i = q->ip_end-ip->ip_off+1)
51225202Skarels < ip->ip_len)
51325202Skarels {
51425202Skarels ip->ip_off += i;
51525202Skarels ip->ip_len -= i;
51625202Skarels m_adj(mp, i);
51725202Skarels }
51825202Skarels else
51925202Skarels ip->ip_len = 0;
52025202Skarels }
52125202Skarels
52225202Skarels /* new overlaps at beginning of successor frags */
52325202Skarels
52425202Skarels q = savq->ip_next;
52525202Skarels while ((q != (struct ip *)fp) &&
52625202Skarels (ip->ip_len != 0) &&
52725202Skarels (q->ip_off <= ip->ip_end))
52825202Skarels
52925202Skarels /* complete cover */
53025202Skarels
53125202Skarels if (q->ip_end <= ip->ip_end)
53225202Skarels {
53325202Skarels struct ip *next;
53425202Skarels
53525202Skarels next = q->ip_next;
53625202Skarels ip_deq(q);
53725202Skarels m_freem(dtom(q));
53825202Skarels q = next;
53925202Skarels }
54025202Skarels else
54125202Skarels { /* overlap */
54225202Skarels if ((i = ip->ip_end-q->ip_off+1) < ip->ip_len)
54325202Skarels {
54425202Skarels ip->ip_len -= i;
54525202Skarels ip->ip_end -= i;
54625202Skarels m_adj(mp, -i);
54725202Skarels }
54825202Skarels else
54925202Skarels ip->ip_len = 0;
55025202Skarels break;
55125202Skarels }
55225202Skarels
55325202Skarels /* enqueue whatever is left of new before successors */
55425202Skarels
55525202Skarels if (ip->ip_len != 0)
55625202Skarels {
55725202Skarels ip_enq(ip, savq);
55825202Skarels }
55925202Skarels else
56025202Skarels m_freem(mp);
56125202Skarels }
56225202Skarels }
56325202Skarels
56425202Skarels /* check for completed fragment reassembly */
56525202Skarels
56625202Skarels if ((i = ip_done(&fp->iqx)) == 0)
56725202Skarels return(NULL);
56825202Skarels
56925202Skarels ip = fp->iqx.ip_next; /* -> top mbuf */
57025202Skarels ip->ip_len = i; /* total data length */
57125202Skarels *fragsize = fp->iq_size; /* remember for TCP */
57225202Skarels /* option processing */
57325202Skarels
57425202Skarels if ((hlen = ip->ip_hl<<IP_HLSHIFT) > sizeof(struct ip))
57525202Skarels ip_stripopt (ip, hlen);
57625202Skarels
57725202Skarels ip_mergef(&fp->iqx); /* clean frag chain */
57825202Skarels
57925202Skarels /* copy src/dst internet address to header mbuf */
58025202Skarels
58125202Skarels ip->ip_src = fp->iqh.ip_src;
58225202Skarels ip->ip_dst = fp->iqh.ip_dst;
58325202Skarels
58425202Skarels ip_freef(fp); /* dequeue header */
58525202Skarels return(ip);
58625202Skarels }
58725202Skarels
58825202Skarels /*
58925202Skarels * Let people control gateway action by patching this:
59025202Skarels */
59125202Skarels int ip_forwarding = FALSE;
59225202Skarels
59325202Skarels /*
59425202Skarels * Try to forward the packet. Act like a gateway.
59525202Skarels */
59625202Skarels ip_forward (fwdinp, ip, mp, hlen)
59725202Skarels struct inpcb *fwdinp;
59825202Skarels register struct ip *ip;
59925202Skarels struct mbuf *mp;
60025202Skarels int hlen;
60125202Skarels {
60225202Skarels register int type, code;
60325202Skarels register u_short len;
60425202Skarels register struct mbuf *mcopy;
60525202Skarels register unsigned icmplen;
60625202Skarels int error;
60725202Skarels
60825202Skarels /*
60925202Skarels * Also copy forwarded packets, just like copy TCP/UDP/RDP...
61025202Skarels * packets sent to us so that can debug gateway action problems.
61125202Skarels * It's easy enough for the user-level program to filter these
61225202Skarels * out.
61325202Skarels */
61425202Skarels if (any_rawreaders())
61525202Skarels if (mcopy = m_copy(mp, 0, M_COPYALL))
61625202Skarels raw_ip_input (mcopy);
61725202Skarels
61825202Skarels if (ip->ip_ttl)
61925202Skarels ip->ip_ttl --;
62025202Skarels
62125202Skarels len = ntohs(ip->ip_len);
62225202Skarels icmplen = MIN(len, hlen + ICMP_ERRLEN);
62325202Skarels
62425202Skarels if (ip_forwarding && ip->ip_ttl)
62525202Skarels {
62625202Skarels /*
62725202Skarels * Save chunk of ip packet in case there is an error
62825202Skarels */
62925202Skarels mcopy = m_copy (mp, 0, (int)icmplen);
63025202Skarels
63125202Skarels /*
63225202Skarels * The packet is not sourced by the local machine, so
63325202Skarels * save ourselves a useless call to ip_route in ip_send().
63425202Skarels * Also, don't want ip_send to work if sending from
63525202Skarels * 8.7.0.2 to 192.1.11.1 via 8.0.0.16, and 8.0.0.16
63625202Skarels * knows about a default gateway on net 8. This can
63725202Skarels * cause an ENETUNREACH if 192.1.11 is not a network
63825202Skarels * that default gateway knows about. [8.0.0.16 is on
63925202Skarels * 192.1.11 and ip_route uses default gateway on net 8
64025202Skarels * while rtalloc uses local interface]
64125202Skarels *
64225202Skarels * This route should be found by rtalloc, so let's do
64325202Skarels * it here.
64425202Skarels */
64525202Skarels if (fwdinp->inp_route.ro_rt == NULL)
64625202Skarels {
64725202Skarels /* Isn't a source routed packet */
64825202Skarels struct rtentry *rt;
64925202Skarels struct sockaddr_in *sin;
65025202Skarels
65125202Skarels bzero ((caddr_t) fwdinp, sizeof(*fwdinp));
65225202Skarels sin = (struct sockaddr_in *) &fwdinp->inp_route.ro_dst;
65325202Skarels sin->sin_family = AF_INET;
65425202Skarels sin->sin_addr = ip->ip_dst;
65525202Skarels rtalloc (&fwdinp->inp_route);
65625202Skarels
65725202Skarels /*
65825202Skarels * Check to see if should send ICMP redirect. Don't
65925202Skarels * send redirect if source routing was used.
66025202Skarels */
66125202Skarels if ((rt = fwdinp->inp_route.ro_rt) != NULL)
66225202Skarels {
66325202Skarels sin = (struct sockaddr_in *) &rt->rt_gateway;
66425202Skarels if (! (rt->rt_flags & (RTF_GATEWAY|RTF_HOST)))
66525202Skarels send_redirect (ip, ip->ip_dst, ICMP_REDIR_HOST, icmplen);
66625202Skarels else if (iptonet(ip->ip_src) == iptonet(sin->sin_addr))
66725202Skarels send_redirect (ip, sin->sin_addr, ICMP_REDIR_NET, icmplen);
66825202Skarels }
66925202Skarels }
67025202Skarels
67125202Skarels if (fwdinp->inp_route.ro_rt == NULL)
67225202Skarels {
67325202Skarels /* no way to get there from here */
67425202Skarels m_freem(mp);
67525202Skarels type = ICMP_UNRCH;
67625202Skarels code = ICMP_UNRCH_NET;
67725202Skarels }
67825202Skarels else
67925202Skarels {
68025202Skarels error = ip_send (fwdinp, mp, (int)len, TRUE);
68125202Skarels rtfree(fwdinp->inp_route.ro_rt);
68225202Skarels fwdinp->inp_route.ro_rt = NULL;
68325202Skarels
68425202Skarels if (! error)
68525202Skarels {
68625202Skarels ipstat.ip_forwarded ++;
68725202Skarels if (mcopy)
68825202Skarels m_freem(mcopy);
68925202Skarels return;
69025202Skarels }
69125202Skarels
69225202Skarels type = ICMP_UNRCH;
69325202Skarels switch (error)
69425202Skarels {
69525202Skarels case ENETUNREACH:
69625202Skarels case ENETDOWN:
69725202Skarels code = ICMP_UNRCH_NET;
69825202Skarels break;
69925202Skarels case EMSGSIZE:
70025202Skarels code = ICMP_UNRCH_FRAG;
70125202Skarels break;
70225202Skarels case EHOSTDOWN:
70325202Skarels case EHOSTUNREACH:
70425202Skarels code = ICMP_UNRCH_HOST;
70525202Skarels break;
70625202Skarels
70725202Skarels case ENOBUFS:
70825202Skarels type = ICMP_SRCQ;
70925202Skarels break;
71025202Skarels
71125202Skarels default:
712*25206Skarels log(LOG_INFO, "ip_forward: error %d\n", error);
71325202Skarels }
71425202Skarels }
71525202Skarels }
71625202Skarels else
71725202Skarels {
71825202Skarels if (ip->ip_ttl == 0)
71925202Skarels {
72025202Skarels type = ICMP_TIMEX;
72125202Skarels code = ICMP_TIMEX_XMT;
72225202Skarels }
72325202Skarels else
72425202Skarels {
72525202Skarels type = ICMP_UNRCH;
72625202Skarels code = ICMP_UNRCH_NET;
72725202Skarels }
72825202Skarels mcopy = mp;
72925202Skarels if (fwdinp->inp_route.ro_rt)
73025202Skarels {
73125202Skarels /* was source routed by IP option */
73225202Skarels rtfree (fwdinp->inp_route.ro_rt);
73325202Skarels fwdinp->inp_route.ro_rt = NULL;
73425202Skarels }
73525202Skarels }
73625202Skarels
73725202Skarels if (mcopy)
73825202Skarels {
73925202Skarels ip = mtod(mcopy, struct ip *);
74025202Skarels ic_errmsg (redir_addr(ip), ip->ip_src, type, code, 0, icmplen, (char *) ip);
74125202Skarels #ifdef HMPTRAPS
74225202Skarels /* hmp_trap(T_IP_ADDRS, (caddr_t) 0, 0); */
74325202Skarels #else
74425202Skarels if (ip_forwarding)
74525202Skarels /*
74625202Skarels * If not acting as a gateway, don't want some one else's
74725202Skarels * misconception to flood our console or logfile. This error
74825202Skarels * can be found through netstat an ip_drops.
74925202Skarels */
75025202Skarels ip_log(ip, "ip forwarding error");
75125202Skarels netlog(mcopy);
75225202Skarels #endif
75325202Skarels }
75425202Skarels
75525202Skarels ipstat.ip_drops++;
75625202Skarels }
75725202Skarels
75825202Skarels
75925202Skarels /*
76025202Skarels * Check to see if fragment reassembly is complete
76125202Skarels */
ip_done(p)76225202Skarels ip_done(p)
76325202Skarels register struct ip *p;
76425202Skarels {
76525202Skarels register struct ip *q;
76625202Skarels register next;
76725202Skarels
76825202Skarels q = p->ip_next;
76925202Skarels
77025202Skarels if (q->ip_off != 0)
77125202Skarels return(0);
77225202Skarels do
77325202Skarels {
77425202Skarels next = q->ip_end + 1;
77525202Skarels q = q->ip_next;
77625202Skarels }
77725202Skarels while ((q != p) && (q->ip_off == next));
77825202Skarels
77925202Skarels if ((q == p) && !(q->ip_prev->ip_mff)) /* all fragments in */
78025202Skarels return(next); /* total data length */
78125202Skarels else
78225202Skarels return(0);
78325202Skarels }
78425202Skarels
78525202Skarels /*
78625202Skarels * Merge mbufs of fragments of completed datagram
78725202Skarels */
ip_mergef(p)78825202Skarels ip_mergef(p)
78925202Skarels register struct ip *p;
79025202Skarels {
79125202Skarels register struct mbuf *m, *n;
79225202Skarels register struct ip *q;
79325202Skarels int dummy;
79425202Skarels
79525202Skarels q = p->ip_next; /* -> bottom of reass chain */
79625202Skarels n = (struct mbuf *)&dummy; /* dummy for init assignment */
79725202Skarels
79825202Skarels while (q != p)
79925202Skarels { /* through chain */
80025202Skarels /*
80125202Skarels * If free mbuf holding q, cannot access q->ip_next in case
80225202Skarels * that mbuf is used by device code for an incoming packet.
80325202Skarels */
80425202Skarels register struct ip *next;
80525202Skarels
80625202Skarels next = q->ip_next;
80725202Skarels n->m_next = m = dtom(q);
80825202Skarels while (m != NULL)
80925202Skarels {
81025202Skarels if (m->m_len != 0)
81125202Skarels {
81225202Skarels n = m;
81325202Skarels m = m->m_next;
81425202Skarels }
81525202Skarels else /* free null mbufs */
81625202Skarels n->m_next = m = m_free(m);
81725202Skarels }
81825202Skarels q = next;
81925202Skarels }
82025202Skarels }
82125202Skarels
82225202Skarels /*
82325202Skarels * Dequeue and free reass.q header
82425202Skarels */
ip_freef(fp)82525202Skarels ip_freef(fp)
82625202Skarels register struct ipq *fp;
82725202Skarels {
82825202Skarels if (fp->iq_prev != NULL)
82925202Skarels (fp->iq_prev)->iq_next = fp->iq_next;
83025202Skarels else
83125202Skarels ipfrags.n_ip_head = fp->iq_next;
83225202Skarels
83325202Skarels if (fp->iq_next != NULL)
83425202Skarels (fp->iq_next)->iq_prev = fp->iq_prev;
83525202Skarels else
83625202Skarels ipfrags.n_ip_tail = fp->iq_prev;
83725202Skarels
83825202Skarels m_free(dtom(fp));
83925202Skarels }
84025202Skarels
84125202Skarels ip_stripopt (ip, hlen)
84225202Skarels struct ip *ip;
84325202Skarels int hlen;
84425202Skarels {
84525202Skarels int optlen;
84625202Skarels
84725202Skarels if ((optlen = (hlen - sizeof(struct ip))) > 0)
84825202Skarels {
84925202Skarels struct mbuf *m;
85025202Skarels caddr_t end_of_ip, end_of_opt;
85125202Skarels unsigned len;
85225202Skarels
85325202Skarels m = dtom(ip);
85425202Skarels end_of_ip = (char *) (ip +1);
85525202Skarels end_of_opt = end_of_ip + optlen;
85625202Skarels len = m->m_len - hlen;
85725202Skarels bcopy (end_of_opt, end_of_ip, len);
85825202Skarels m->m_len -= optlen;
85925202Skarels }
86025202Skarels }
86125202Skarels
86225202Skarels /*
86325202Skarels * Process ip options
86425202Skarels * FALSE -> options were in error, and an icmp message has been sent
86525202Skarels */
86625202Skarels #define OFF_OLEN 1
86725202Skarels #define OFF_OFFSET 2
86825202Skarels #define MIN_OFF 4 /* since option is a 1, not 0, based array */
86925202Skarels
87025202Skarels /*
87125202Skarels * Record route in same form as ip_setopt()
87225202Skarels */
save_rte(option,dst)87325202Skarels save_rte (option, dst)
87425202Skarels u_char *option;
87525202Skarels struct in_addr dst;
87625202Skarels {
87725202Skarels int olen;
87825202Skarels int off;
87925202Skarels u_char *x;
88025202Skarels struct in_addr *p, *q;
88125202Skarels
88225202Skarels if (ip_nhops != 0)
88325202Skarels {
88425202Skarels /* Use both loose and strict source routing? */
885*25206Skarels log(LOG_INFO, "ip_nhops %d\n", ip_nhops);
88625202Skarels ip_nhops = 0;
88725202Skarels return;
88825202Skarels }
88925202Skarels olen = option[OFF_OLEN];
89025202Skarels if (olen > sizeof(ip_hops))
89125202Skarels {
892*25206Skarels log(LOG_INFO, "save_rte: olen %d\n", olen);
89325202Skarels return;
89425202Skarels }
89525202Skarels off = option[OFF_OFFSET];
89625202Skarels p = (struct in_addr *) (&option[off - 1]);
89725202Skarels q = (struct in_addr *) (&option[MIN_OFF -1]);
89825202Skarels
89925202Skarels x = (u_char *) ip_hops;
90025202Skarels x[0] = IP_NOP_OPT;
90125202Skarels x[1] = option[0]; /* loose/strict source routing */
90225202Skarels x[2] = (p - q) * sizeof(struct in_addr) + 3;
90325202Skarels x[3] = MIN_OFF;
90425202Skarels ip_nhops ++; /* = 1 (1 long for opt hdr) */
90525202Skarels p--; /* p points at first hop for return route */
90625202Skarels
90725202Skarels ip_hops[p-q+2] = (*p); /* save first hop after return route option */
90825202Skarels p--; /* it is in what will be ip_hops[ip_nhops] */
90925202Skarels
91025202Skarels /* record return path as an IP source route */
91125202Skarels while (p >= q)
91225202Skarels {
91325202Skarels ip_hops[ip_nhops] = (*p);
91425202Skarels p--;
91525202Skarels ip_nhops ++;
91625202Skarels }
91725202Skarels /* remember eventual destination is in the option field */
91825202Skarels ip_hops[ip_nhops] = dst;
91925202Skarels ip_nhops ++;
92025202Skarels }
92125202Skarels
ip_opt(ip,hlen,fwdinp)92225202Skarels ip_opt (ip, hlen, fwdinp)
92325202Skarels register struct ip *ip;
92425202Skarels struct inpcb *fwdinp;
92525202Skarels {
92625202Skarels register u_char *endopt;
92725202Skarels register u_char *option;
92825202Skarels register int olen;
92925202Skarels register int off;
93025202Skarels int type;
93125202Skarels int code;
93225202Skarels struct in_addr nexthop;
93325202Skarels struct in_ifaddr *ia;
93425202Skarels
93525202Skarels endopt = ((u_char *) ip) + hlen;
93625202Skarels option = (u_char *) (ip +1);
93725202Skarels
93825202Skarels while (option < endopt)
93925202Skarels {
94025202Skarels switch (*option)
94125202Skarels {
94225202Skarels case IP_END_OPT:
94325202Skarels return (TRUE);
94425202Skarels
94525202Skarels case IP_NOP_OPT:
94625202Skarels olen = sizeof(u_char);
94725202Skarels break;
94825202Skarels
94925202Skarels case IP_SEC_OPT:
95025202Skarels olen = option[OFF_OLEN];
95125202Skarels /* so much for security */
95225202Skarels break;
95325202Skarels
95425202Skarels case IP_LRTE_OPT:
95525202Skarels olen = option[OFF_OLEN];
95625202Skarels off = option[OFF_OFFSET];
95725202Skarels if (off < MIN_OFF)
95825202Skarels {
95925202Skarels type = ICMP_PARM;
96025202Skarels code = &option[OFF_OFFSET] - ((u_char *) ip);
96125202Skarels goto err;
96225202Skarels }
96325202Skarels off--; /* adjust for use by C */
96425202Skarels if (in_iawithaddr(ip->ip_dst, TRUE) == NULL)
96525202Skarels /*
96625202Skarels * With loose routing, may take a few hops
96725202Skarels * to get to current nexthop.
96825202Skarels */
96925202Skarels break;
97025202Skarels
97125202Skarels if (off > (olen - sizeof(struct in_addr)))
97225202Skarels {
97325202Skarels /* hints all used up. pkt for us */
97425202Skarels save_rte (option, ip->ip_src);
97525202Skarels break;
97625202Skarels }
97725202Skarels
97825202Skarels nexthop = *((struct in_addr *) (option + off));
97925202Skarels
98025202Skarels /*
98125202Skarels * record outgoing interface
98225202Skarels */
98325202Skarels if (! ip_opt_route(fwdinp, nexthop))
98425202Skarels {
98525202Skarels type = ICMP_UNRCH;
98625202Skarels /* net? frag? host? */
98725202Skarels code = ICMP_UNRCH_SRC;
98825202Skarels goto err;
98925202Skarels }
99025202Skarels ip->ip_dst = nexthop;
99125202Skarels option[OFF_OFFSET] += sizeof(struct in_addr);
99225202Skarels if (fwdinp->inp_route.ro_rt == NULL)
99325202Skarels /*
99425202Skarels * Destined for ourselves, and we're
99525202Skarels * just going to strip the options off
99625202Skarels */
99725202Skarels break;
99825202Skarels *((struct in_addr *) (option + off)) =
99925202Skarels IA_INADDR(in_iafromif (fwdinp->inp_route.ro_rt->rt_ifp));
100025202Skarels break;
100125202Skarels
100225202Skarels case IP_SRTE_OPT:
100325202Skarels olen = option[OFF_OLEN];
100425202Skarels off = option[OFF_OFFSET];
100525202Skarels if (off < MIN_OFF)
100625202Skarels {
100725202Skarels type = ICMP_PARM;
100825202Skarels code = &option[OFF_OFFSET] - ((u_char *) ip);
100925202Skarels goto err;
101025202Skarels }
101125202Skarels off--; /* adjust for use by C */
101225202Skarels if (in_iawithaddr(ip->ip_dst, TRUE) == NULL)
101325202Skarels {
101425202Skarels /* strict path -> someone goofed */
101525202Skarels /* should have come in on us for us */
101625202Skarels type = ICMP_UNRCH;
101725202Skarels code = ICMP_UNRCH_SRC;
101825202Skarels goto err;
101925202Skarels }
102025202Skarels
102125202Skarels if (off > (olen - sizeof(struct in_addr)))
102225202Skarels {
102325202Skarels /* hints all used up */
102425202Skarels save_rte (option, ip->ip_src);
102525202Skarels break;
102625202Skarels }
102725202Skarels
102825202Skarels nexthop = *((struct in_addr *) (option + off));
102925202Skarels
103025202Skarels if ((ia = in_iawithnet(nexthop)) == NULL)
103125202Skarels {
103225202Skarels /* strict path -> someone goofed
103325202Skarels * we should be directly connected to
103425202Skarels * next hop
103525202Skarels */
103625202Skarels type = ICMP_UNRCH;
103725202Skarels code = ICMP_UNRCH_SRC;
103825202Skarels goto err;
103925202Skarels }
104025202Skarels *((struct in_addr *) (option + off)) = IA_INADDR(ia);
104125202Skarels
104225202Skarels ip->ip_dst = nexthop;
104325202Skarels
104425202Skarels option[OFF_OFFSET] += sizeof(struct in_addr);
104525202Skarels break;
104625202Skarels
104725202Skarels case IP_TIME_OPT:
104825202Skarels olen = option[OFF_OLEN];
104925202Skarels off = option[OFF_OFFSET];
105025202Skarels if (off < MIN_OFF)
105125202Skarels {
105225202Skarels type = ICMP_PARM;
105325202Skarels code = &option[OFF_OFFSET] - ((u_char *) ip);
105425202Skarels goto err;
105525202Skarels }
105625202Skarels off--; /* adjust for use by C */
105725202Skarels if (off > (olen - sizeof(u_long)))
105825202Skarels {
105925202Skarels /* increment overflow count */
106025202Skarels if ((option[3] & 0xf0) == 0xf0)
106125202Skarels {
106225202Skarels /* overflow overflowed */
106325202Skarels type = ICMP_PARM;
106425202Skarels code = &option[OFF_OLEN] - ((u_char *) ip);
106525202Skarels goto err;
106625202Skarels }
106725202Skarels option[3] += 0x10;
106825202Skarels break;
106925202Skarels }
107025202Skarels
107125202Skarels if (option[3] & 2)
107225202Skarels {
107325202Skarels /* want specific host to stamp */
107425202Skarels ia = in_iawithaddr(*((struct in_addr *) (option + off)), FALSE);
107525202Skarels if (ia == NULL)
107625202Skarels break;
107725202Skarels }
107825202Skarels else
107925202Skarels ia = in_ifaddr;
108025202Skarels
108125202Skarels if (option[3] & 1)
108225202Skarels {
108325202Skarels /* record stamping host */
108425202Skarels *((struct in_addr *) (option + off)) = IA_INADDR (ia);
108525202Skarels off += sizeof(struct in_addr);
108625202Skarels option[OFF_OFFSET] += sizeof(struct in_addr);
108725202Skarels }
108825202Skarels if (off > (olen - sizeof(u_long)))
108925202Skarels {
109025202Skarels option[3] += 0x10;
109125202Skarels break;
109225202Skarels }
109325202Skarels *((u_long *) (option + off)) = iptime();
109425202Skarels option[OFF_OFFSET] += sizeof(u_long);
109525202Skarels break;
109625202Skarels
109725202Skarels case IP_STRID_OPT:
109825202Skarels olen = option[OFF_OLEN];
109925202Skarels break;
110025202Skarels
110125202Skarels case IP_RRTE_OPT:
110225202Skarels olen = option[OFF_OLEN];
110325202Skarels off = option[OFF_OFFSET];
110425202Skarels if (off < MIN_OFF)
110525202Skarels {
110625202Skarels type = ICMP_PARM;
110725202Skarels code = &option[OFF_OFFSET] - ((u_char *) ip);
110825202Skarels goto err;
110925202Skarels }
111025202Skarels off--; /* adjust for use by C */
111125202Skarels if (off > (olen - sizeof(u_long)))
111225202Skarels /* no space left for recording route */
111325202Skarels break;
111425202Skarels
111525202Skarels /* record outgoing interface */
111625202Skarels if (! ip_opt_route(fwdinp, ip->ip_dst))
111725202Skarels {
111825202Skarels type = ICMP_UNRCH;
111925202Skarels code = ICMP_UNRCH_NET;
112025202Skarels goto err;
112125202Skarels }
112225202Skarels option[OFF_OFFSET] += sizeof(struct in_addr);
112325202Skarels if (fwdinp->inp_route.ro_rt == NULL)
112425202Skarels /*
112525202Skarels * Destined for us, and we're just
112625202Skarels * going to strip options off
112725202Skarels */
112825202Skarels break;
112925202Skarels *((struct in_addr *) (option + off)) =
113025202Skarels IA_INADDR(in_iafromif (fwdinp->inp_route.ro_rt->rt_ifp));
113125202Skarels break;
113225202Skarels }
113325202Skarels
113425202Skarels option += olen;
113525202Skarels }
113625202Skarels return (TRUE);
113725202Skarels
113825202Skarels err :
113925202Skarels ic_errmsg (icmp_addr(ip), ip->ip_src,
114025202Skarels type, code, option - ((u_char *) ip), hlen, (char *) ip);
114125202Skarels return (FALSE);
114225202Skarels }
114325202Skarels #undef OFF_OLEN
114425202Skarels #undef OFF_OFFSET
114525202Skarels #undef MIN_OFF
114625202Skarels
114725202Skarels
ip_opt_route(fwdinp,dst)114825202Skarels ip_opt_route (fwdinp, dst)
114925202Skarels register struct inpcb *fwdinp;
115025202Skarels struct in_addr dst;
115125202Skarels {
115225202Skarels register struct sockaddr_in *sin;
115325202Skarels
115425202Skarels /* in case they use several options involving routing */
115525202Skarels if (fwdinp->inp_route.ro_rt)
115625202Skarels return (TRUE);
115725202Skarels
115825202Skarels bzero ((caddr_t) fwdinp, sizeof(*fwdinp));
115925202Skarels
116025202Skarels sin = (struct sockaddr_in *) &fwdinp->inp_route.ro_dst;
116125202Skarels
116225202Skarels /* not sure ip_send cares about this stuff ... */
116325202Skarels sin->sin_family = AF_INET;
116425202Skarels sin->sin_addr = dst;
116525202Skarels
116625202Skarels /* Don't allocate route if not forwarding packet.
116725202Skarels * This saves us from doing a check in ip_input() to see
116825202Skarels * if we should do a rtfree() for an uncommon occurrence.
116925202Skarels */
117025202Skarels
117125202Skarels if (in_iawithaddr(dst, TRUE) != NULL)
117225202Skarels return (TRUE);
117325202Skarels
117425202Skarels rtalloc (&fwdinp->inp_route);
117525202Skarels return (fwdinp->inp_route.ro_rt != NULL);
117625202Skarels }
117725202Skarels
117825202Skarels
117925202Skarels /*
118025202Skarels * IP fragment reassembly timeout routine.
118125202Skarels */
ip_timeo()118225202Skarels ip_timeo()
118325202Skarels {
118425202Skarels register struct ip *p, *q;
118525202Skarels register struct ipq *fp, *next;
118625202Skarels register int s;
118725202Skarels
118825202Skarels static int timflag;
118925202Skarels
119025202Skarels /* check once per sec */
119125202Skarels
119225202Skarels if (timflag = !timflag) /* looks strange, doesn't it? */
119325202Skarels return;
119425202Skarels
119525202Skarels
119625202Skarels /* search through reass.q */
119725202Skarels s = splnet();
119825202Skarels for (fp = ipfrags.n_ip_head; fp != NULL; fp = next)
119925202Skarels {
120025202Skarels /*
120125202Skarels * If fragment times out, mbufs are freed, and can't
120225202Skarels * use next pointer since mbuf may be grabbed by
120325202Skarels * an interface at splimp
120425202Skarels */
120525202Skarels next = fp->iq_next;
120625202Skarels
120725202Skarels if (--(fp->iqx.ip_ttl) == 0)
120825202Skarels { /* time to die */
120925202Skarels
121025202Skarels q = fp->iqx.ip_next; /* free mbufs assoc. w/chain */
121125202Skarels while (q != (struct ip *)fp)
121225202Skarels {
121325202Skarels p = q->ip_next;
121425202Skarels /* ### generate timed out in reassembly msg */
121525202Skarels #ifdef HMPTRAPS
121625202Skarels /* hmp_trap(T_IP_FDROP, (caddr_t)0,0); */
121725202Skarels #else
121825202Skarels m_freem(dtom(q));
121925202Skarels #endif
122025202Skarels q = p;
122125202Skarels }
122225202Skarels ip_freef(fp); /* free header */
122325202Skarels }
122425202Skarels }
122525202Skarels splx(s);
122625202Skarels }
122725202Skarels
122825202Skarels /*
122925202Skarels * Called at splimp from uipc_mbuf.c
123025202Skarels * Network code needs to free up space! IP fragments dropped.
123125202Skarels */
ip_drain()123225202Skarels ip_drain()
123325202Skarels {
123425202Skarels register struct ip *p, *q;
123525202Skarels register struct ipq *fp;
123625202Skarels
123725202Skarels while (fp = ipfrags.n_ip_head)
123825202Skarels {
123925202Skarels q = fp->iqx.ip_next; /* free mbufs assoc w/chain */
124025202Skarels while (q != (struct ip *)fp)
124125202Skarels {
124225202Skarels p = q->ip_next;
124325202Skarels m_freem(dtom(q));
124425202Skarels q = p;
124525202Skarels }
124625202Skarels ip_freef(fp); /* free header */
124725202Skarels }
124825202Skarels }
124925202Skarels
125025202Skarels #include "../h/syslog.h"
125125202Skarels
inet_cksum_err(protoname,ip,was,should_be)125225202Skarels inet_cksum_err (protoname, ip, was, should_be)
125325202Skarels char *protoname;
125425202Skarels struct ip *ip;
125525202Skarels u_long was;
125625202Skarels u_long should_be;
125725202Skarels {
125825202Skarels union { u_long ul; u_char c[4]; } s, d;
125925202Skarels
126025202Skarels s.ul = ip->ip_src.s_addr;
126125202Skarels d.ul = ip->ip_dst.s_addr;
1262*25206Skarels log (LOG_INFO,
126325202Skarels "%s checksum was 0x%x not 0x%x src %d.%d.%d.%d dst %d.%d.%d.%d\n",
126425202Skarels protoname, was, should_be,
126525202Skarels s.c[0], s.c[1], s.c[2], s.c[3],
126625202Skarels d.c[0], d.c[1], d.c[2], d.c[3]);
126725202Skarels }
126825202Skarels
126925202Skarels ip_log(ip, emsg)
127025202Skarels struct ip *ip;
127125202Skarels char *emsg;
127225202Skarels {
127325202Skarels union { u_long ul; u_char c[4]; } s, d;
127425202Skarels
127525202Skarels s.ul = ip->ip_src.s_addr;
127625202Skarels d.ul = ip->ip_dst.s_addr;
1277*25206Skarels log(LOG_INFO, "%s: src %d.%d.%d.%d dst %d.%d.%d.%d\n",
127825202Skarels emsg,
127925202Skarels s.c[0], s.c[1], s.c[2], s.c[3],
128025202Skarels d.c[0], d.c[1], d.c[2], d.c[3]);
128125202Skarels }
128225202Skarels
no_route(msg,from,to)128325202Skarels no_route (msg, from, to)
128425202Skarels char *msg;
128525202Skarels struct in_addr from;
128625202Skarels struct in_addr to;
128725202Skarels {
128825202Skarels union { u_long ul; u_char c[4]; } f, t;
128925202Skarels
129025202Skarels f.ul = from.s_addr;
129125202Skarels t.ul = to.s_addr;
1292*25206Skarels log(LOG_INFO, "%s: no route %d.%d.%d.%d -> %d.%d.%d.%d\n",
129325202Skarels msg,
129425202Skarels f.c[0], f.c[1], f.c[2], f.c[3],
129525202Skarels t.c[0], t.c[1], t.c[2], t.c[3]);
129625202Skarels }
1297