xref: /csrg-svn/sys/netinet/ip_input.c (revision 4543)
1*4543Swnj /* ip_input.c 1.4 81/10/18 */
24495Swnj #include "../h/param.h"
34495Swnj #include "../bbnnet/net.h"
44495Swnj #include "../bbnnet/tcp.h"
54495Swnj #include "../bbnnet/ip.h"
64495Swnj #include "../bbnnet/ucb.h"
7*4543Swnj #include "../h/systm.h"
84495Swnj 
94495Swnj int nosum = 0;
104495Swnj 
114495Swnj ip_input(mp)
124495Swnj struct mbuf *mp;
134495Swnj {
144495Swnj 	register struct ip *ip, *q;
154495Swnj 	register struct ipq *fp;
164495Swnj 	register struct mbuf *m;
174495Swnj 	register i;
184495Swnj 	struct mbuf *n;
194495Swnj 	int hlen;
204495Swnj 	struct ip *p, *savq;
214495Swnj 	struct ipq *ip_findf();
224495Swnj 
234495Swnj COUNT(IP_INPUT);
244495Swnj 	ip = (struct ip *)((int)mp + mp->m_off);        /* ->ip hdr */
254495Swnj 
264495Swnj 	/* make sure header does not overflow mbuf */
274495Swnj 
284495Swnj 	if ((hlen = ip->ip_hl << 2) > mp->m_len) {
294495Swnj 		printf("ip header overflow\n");
304495Swnj 		m_freem(mp);
314495Swnj 		return;
324495Swnj 	}
334495Swnj 
344495Swnj 	i = (unsigned short)ip->ip_sum;
354495Swnj 	ip->ip_sum = 0;
364495Swnj 
374495Swnj 	if (i != (unsigned short)cksum(mp, hlen)) {     /* verify checksum */
384495Swnj 		netstat.ip_badsum++;
394495Swnj 		if (!nosum) {
404495Swnj         	  	m_freem(mp);
414495Swnj         		return;
424495Swnj 		}
434495Swnj 	}
44*4543Swnj 	ip_bswap(ip);
45*4543Swnj 	fp = netcb.n_ip_head ? ip_findf(ip) : 0;
464495Swnj 
47*4543Swnj 	/*
48*4543Swnj 	 * adjust message length to remove any padding
49*4543Swnj 	 */
504495Swnj 	for (i=0, m=mp; m != NULL; m = m->m_next) {
514495Swnj 		i += m->m_len;
524495Swnj 		n = m;
534495Swnj 	}
544495Swnj 	i -= ip->ip_len;
554495Swnj 
56*4543Swnj 	if (i != 0)
574495Swnj         	if (i > (int)n->m_len)
584495Swnj         		m_adj(mp, -i);
594495Swnj         	else
604495Swnj         		n->m_len -= i;
614495Swnj 
624495Swnj 	ip->ip_len -= hlen;     /* length of data */
63*4543Swnj   	ip->ip_mff = ((ip->ip_off & ip_mf) ? TRUE : FALSE);
64*4543Swnj 	ip->ip_off <<= 3;
65*4543Swnj 	if (ip->ip_mff || ip->ip_off)
66*4543Swnj 		goto fragged;
67*4543Swnj 	if (fp != NULL) {
68*4543Swnj 		q = fp->iqx.ip_next;
69*4543Swnj 		while (q != (struct ip *)fp) {
70*4543Swnj 			m_freem(dtom(q));
71*4543Swnj 			q = q->ip_next;
72*4543Swnj 		}
73*4543Swnj 		ip_freef(fp);           /* free header */
74*4543Swnj 	}
75*4543Swnj 	if (hlen > sizeof (struct ip))
76*4543Swnj 		ip_opt(ip, hlen);
77*4543Swnj 	switch (ip->ip_p) {
784495Swnj 
79*4543Swnj 	case TCPROTO:
80*4543Swnj 		tcp_input(mp);
81*4543Swnj 		break;
824495Swnj 
83*4543Swnj 	default:
84*4543Swnj 		raw_input(mp, ip->ip_p, UIP);
85*4543Swnj 		break;
86*4543Swnj 	}
87*4543Swnj 	return;
884495Swnj 
89*4543Swnj fragged:
90*4543Swnj 	/* -> msg buf beyond ip hdr if not first fragment */
914495Swnj 
92*4543Swnj 	if (ip->ip_off != 0) {
93*4543Swnj 		mp->m_off += hlen;
94*4543Swnj 		mp->m_len -= hlen;
95*4543Swnj 	}
964495Swnj 
97*4543Swnj 	if (fp == NULL) {               /* first fragment of datagram in */
984495Swnj 
99*4543Swnj 	/* set up reass.q header: enq it, set up as head of frag
100*4543Swnj 	   chain, set a timer value, and move in ip header */
1014495Swnj 
102*4543Swnj 		if ((m = m_get(1)) == NULL) {   /* allocate an mbuf */
103*4543Swnj 			m_freem(mp);
104*4543Swnj 			return;
1054495Swnj 		}
1064495Swnj 
107*4543Swnj 		fp = (struct ipq *)((int)m + MHEAD);
108*4543Swnj 		fp->iqx.ip_next = fp->iqx.ip_prev = (struct ip *)fp;
109*4543Swnj 		bcopy(ip, &fp->iqh, min(MLEN-28, hlen));
110*4543Swnj 		fp->iqh.ip_ttl = MAXTTL;
111*4543Swnj 		fp->iq_next = NULL;
112*4543Swnj 		fp->iq_prev = netcb.n_ip_tail;
113*4543Swnj 		if (netcb.n_ip_head != NULL)
114*4543Swnj 			netcb.n_ip_tail->iq_next = fp;
115*4543Swnj 		else
116*4543Swnj 			netcb.n_ip_head = fp;
117*4543Swnj 		netcb.n_ip_tail = fp;
118*4543Swnj 	}
1194495Swnj 
120*4543Swnj 	/***********************************************************
121*4543Swnj 	*                                                          *
122*4543Swnj 	*              merge fragment into reass.q                 *
123*4543Swnj 	*    algorithm:   match  start  and  end  bytes  of new    *
124*4543Swnj 	*    fragment  with  fragments  on  the  queue.   if   no  *
125*4543Swnj 	*    overlaps  are  found,  add  new  frag. to the queue.  *
126*4543Swnj 	*    otherwise, adjust start and end of new frag.  so  no  *
127*4543Swnj 	*    overlap   and   add  remainder  to  queue.   if  any  *
128*4543Swnj 	*    fragments are completely covered by the new one,  or  *
129*4543Swnj 	*    if  the  new  one is completely duplicated, free the  *
130*4543Swnj 	*    fragments.                                            *
131*4543Swnj 	*                                                          *
132*4543Swnj 	***********************************************************/
1334495Swnj 
134*4543Swnj 	q = fp->iqx.ip_next;    /* -> top of reass. chain */
135*4543Swnj 	ip->ip_end = ip->ip_off + ip->ip_len - 1;
1364495Swnj 
137*4543Swnj 	/* skip frags which new doesn't overlap at end */
1384495Swnj 
139*4543Swnj 	while ((q != (struct ip *)fp) && (ip->ip_off > q->ip_end))
140*4543Swnj 		q = q->ip_next;
1414495Swnj 
142*4543Swnj 	if (q == (struct ip *)fp)               /* frag at end of chain */
143*4543Swnj 		ip_enq(ip, fp->iqx.ip_prev);
144*4543Swnj 
145*4543Swnj 	else {
146*4543Swnj 		if (ip->ip_end < q->ip_off)     /* frag doesn't overlap any on chain */
147*4543Swnj 			ip_enq(ip, q->ip_prev);
1484495Swnj 
149*4543Swnj 		/* new overlaps beginning of next frag only */
1504495Swnj 
151*4543Swnj 		else if (ip->ip_end < q->ip_end) {
152*4543Swnj 			if ((i = ip->ip_end - q->ip_off + 1) < ip->ip_len) {
153*4543Swnj 				ip->ip_len -= i;
154*4543Swnj 				ip->ip_end -= i;
155*4543Swnj 				m_adj(mp, -i);
1564495Swnj 				ip_enq(ip, q->ip_prev);
157*4543Swnj 			} else
158*4543Swnj 				m_freem(mp);
1594495Swnj 
160*4543Swnj 		/* new overlaps end of previous frag */
1614495Swnj 
162*4543Swnj 		} else {
163*4543Swnj 
164*4543Swnj 			savq = q;
165*4543Swnj 			if (ip->ip_off <= q->ip_off) {  /* complete cover */
166*4543Swnj 				savq = q->ip_prev;
167*4543Swnj 				ip_deq(q);
168*4543Swnj 				m_freem(dtom(q));
169*4543Swnj 
170*4543Swnj 			} else {                        /* overlap */
171*4543Swnj 				if ((i = q->ip_end - ip->ip_off + 1) < ip->ip_len) {
172*4543Swnj 					ip->ip_off += i;
173*4543Swnj 					ip->ip_len -= i;
174*4543Swnj 					m_adj(mp, i);
1754495Swnj 				} else
176*4543Swnj 					ip->ip_len = 0;
177*4543Swnj 			}
1784495Swnj 
179*4543Swnj 		/* new overlaps at beginning of successor frags */
1804495Swnj 
181*4543Swnj 			q = savq->ip_next;
182*4543Swnj 			while ((q != (struct ip *)fp) && (ip->ip_len != 0) &&
183*4543Swnj 				(q->ip_off < ip->ip_end))
1844495Swnj 
185*4543Swnj 				/* complete cover */
186*4543Swnj 
187*4543Swnj 				if (q->ip_end <= ip->ip_end) {
188*4543Swnj 					p = q->ip_next;
1894495Swnj 					ip_deq(q);
1904495Swnj 					m_freem(dtom(q));
191*4543Swnj 					q = p;
192*4543Swnj 
193*4543Swnj 				} else {        /* overlap */
194*4543Swnj 
195*4543Swnj 					if ((i = ip->ip_end - q->ip_off + 1) < ip->ip_len) {
196*4543Swnj 						ip->ip_len -= i;
197*4543Swnj 						ip->ip_end -= i;
198*4543Swnj 						m_adj(mp, -i);
1994495Swnj 					} else
2004495Swnj 						ip->ip_len = 0;
201*4543Swnj 					break;
2024495Swnj 				}
2034495Swnj 
204*4543Swnj 		/* enqueue whatever is left of new before successors */
2054495Swnj 
206*4543Swnj 			if (ip->ip_len != 0)
207*4543Swnj 				ip_enq(ip, savq);
208*4543Swnj 			else
209*4543Swnj 				m_freem(mp);
2104495Swnj 		}
211*4543Swnj 	}
2124495Swnj 
213*4543Swnj 	/* check for completed fragment reassembly */
2144495Swnj 
215*4543Swnj 	if ((i = ip_done(fp)) == 0)
216*4543Swnj 		return;
2174495Swnj 
218*4543Swnj 	p = fp->iqx.ip_next;            /* -> top mbuf */
219*4543Swnj 	m = dtom(p);
220*4543Swnj 	p->ip_len = i;                  /* total data length */
221*4543Swnj 	ip_opt(p, p->ip_hl << 2);       /* option processing */
222*4543Swnj 	ip_mergef(fp);                  /* cleanup frag chain */
2234495Swnj 
224*4543Swnj 	/* copy src/dst internet address to header mbuf */
2254495Swnj 
226*4543Swnj 	bcopy(&fp->iqh.ip_src, &p->ip_src, 2*sizeof(struct socket));
227*4543Swnj 	ip_freef(fp);                   /* dequeue header */
228*4543Swnj 	i = p->ip_p;
229*4543Swnj 	if (i == TCPROTO)
230*4543Swnj 		tcp_input(m);
231*4543Swnj 	else
232*4543Swnj 		raw_input(m, i, UIP);
2334495Swnj }
2344495Swnj 
235*4543Swnj ip_done(p)
236*4543Swnj 	register struct ip *p;
2374495Swnj {
2384495Swnj 	register struct ip *q;
2394495Swnj 	register next;
2404495Swnj 
2414495Swnj COUNT(IP_DONE);
242*4543Swnj 	q = p->ip_next;
2434495Swnj 
2444495Swnj 	if (q->ip_off != 0)
2454495Swnj 		return(0);
2464495Swnj 	do {
2474495Swnj 		next = q->ip_end + 1;
2484495Swnj 		q = q->ip_next;
2494495Swnj 	} while ((q != p) && (q->ip_off == next));
2504495Swnj 
2514495Swnj 	if ((q == p) && !(q->ip_prev->ip_mff))        /* all fragments in */
2524495Swnj 		return(next);                         /* total data length */
2534495Swnj 	else
2544495Swnj 		return(0);
2554495Swnj }
2564495Swnj 
2574495Swnj ip_mergef(p)    /* merge mbufs of fragments of completed datagram */
2584495Swnj register struct ip *p;
2594495Swnj {
2604495Swnj 	register struct mbuf *m, *n;
2614495Swnj 	register struct ip *q;
2624495Swnj 	int dummy;
2634495Swnj 
2644495Swnj COUNT(IP_MERGEF);
2654495Swnj 	q = p->ip_next;                         /* -> bottom of reass chain */
2664495Swnj 	n = (struct mbuf *)&dummy;              /* dummy for init assignment */
2674495Swnj 
2684495Swnj 	while (q != p) {        /* through chain */
2694495Swnj 
2704495Swnj 	        n->m_next = m = dtom(q);
271*4543Swnj 		while (m != NULL)
2724495Swnj 			if (m->m_len != 0) {
2734495Swnj 				n = m;
2744495Swnj 				m = m->m_next;
2754495Swnj 			} else                  /* free null mbufs */
2764495Swnj 				n->m_next = m = m_free(m);
2774495Swnj 		q = q->ip_next;
2784495Swnj 	}
2794495Swnj }
2804495Swnj 
2814495Swnj 
282*4543Swnj ip_freef(fp)	        /* deq and free reass.q header */
2834495Swnj register struct ipq *fp;
2844495Swnj {
2854495Swnj COUNT(IP_FREEF);
286*4543Swnj 	if (fp->iq_prev != NULL)
287*4543Swnj 		(fp->iq_prev)->iq_next = fp->iq_next;
2884495Swnj 	else
289*4543Swnj 		netcb.n_ip_head = fp->iq_next;
290*4543Swnj 	if (fp->iq_next != NULL)
291*4543Swnj 		(fp->iq_next)->iq_prev = fp->iq_prev;
292*4543Swnj 	else
2934495Swnj 		netcb.n_ip_tail = fp->iq_prev;
2944495Swnj 	m_free(dtom(fp));
2954495Swnj }
2964495Swnj 
297*4543Swnj struct ipq *
298*4543Swnj ip_findf(p)         /* does fragment reass chain w/this hdr exist? */
2994495Swnj register struct ip *p;
3004495Swnj {
3014495Swnj 	register struct ipq *fp;
3024495Swnj 
3034495Swnj COUNT(IP_FINDF);
3044495Swnj 	for (fp = netcb.n_ip_head; (fp != NULL && (
3054495Swnj 			p->ip_src.s_addr != fp->iqh.ip_src.s_addr ||
3064495Swnj 			p->ip_dst.s_addr != fp->iqh.ip_dst.s_addr ||
3074495Swnj 			p->ip_id != fp->iqh.ip_id ||
3084495Swnj 			p->ip_p != fp->iqh.ip_p)); fp = fp->iq_next);
3094495Swnj 	return(fp);
3104495Swnj }
3114495Swnj 
3124495Swnj ip_opt(ip, hlen)        /* process ip options */
3134495Swnj struct ip *ip;
3144495Swnj int hlen;
3154495Swnj {
3164495Swnj 	register char *p, *q;
3174495Swnj 	register i, len;
3184495Swnj 	register struct mbuf *m;
3194495Swnj 
3204495Swnj COUNT(IP_OPT);
3214495Swnj 	p = q = (char *)((int)ip + sizeof(struct ip));  /* -> at options */
3224495Swnj 
3234495Swnj 	if ((i = hlen - sizeof(struct ip)) > 0) {       /* any options */
3244495Swnj 
3254495Swnj /*      *** IP OPTION PROCESSING ***
3264495Swnj 
3274495Swnj 		while (i > 0)
3284495Swnj 
3294495Swnj   			switch (*q++) {
330*4543Swnj 			case 0:
331*4543Swnj 			case 1:
3324495Swnj 				i--;
3334495Swnj 				break;
3344495Swnj 
3354495Swnj 			default:
3364495Swnj 				i -= *q;
3374495Swnj 				q += *q;
3384495Swnj 			}
3394495Swnj */              q += i;
3404495Swnj 		m = dtom(q);
3414495Swnj 		len = (int)m + m->m_off + m->m_len - (int)q;
3424495Swnj 		bcopy((caddr_t)q, (caddr_t)p, len);    /* remove options */
3434495Swnj 		m->m_len -= i;
3444495Swnj 	}
3454495Swnj }
3464495Swnj 
3474495Swnj ip_enq(p, prev)
3484495Swnj register struct ip *p;
3494495Swnj register struct ip *prev;
3504495Swnj {
3514495Swnj COUNT(IP_ENQ);
3524495Swnj 	p->ip_prev = prev;
3534495Swnj 	p->ip_next = prev->ip_next;
3544495Swnj 	prev->ip_next->ip_prev = p;
3554495Swnj 	prev->ip_next = p;
3564495Swnj }
357*4543Swnj 
3584495Swnj ip_deq(p)
3594495Swnj register struct ip *p;
3604495Swnj {
3614495Swnj COUNT(IP_DEQ);
3624495Swnj 	p->ip_prev->ip_next = p->ip_next;
3634495Swnj 	p->ip_next->ip_prev = p->ip_prev;
3644495Swnj }
3654495Swnj 
3664495Swnj ip_timeo()      /* frag reass.q timeout routine */
3674495Swnj {
3684495Swnj 	register struct ip *q;
3694495Swnj 	register struct ipq *fp;
3704525Swnj 	int s = splnet();
3714495Swnj 
3724495Swnj COUNT(IP_TIMEO);
373*4543Swnj 	timeout(ip_timeo, 0, hz);       /* reschedule every second */
3744495Swnj 
3754495Swnj 	/* search through reass.q */
3764495Swnj 
377*4543Swnj 	for (fp = netcb.n_ip_head; fp != NULL; fp = fp->iq_next)
3784495Swnj 
3794495Swnj 		if (--(fp->iqx.ip_ttl) == 0) {  /* time to die */
3804495Swnj 
3814495Swnj 			q = fp->iqx.ip_next;    /* free mbufs assoc. w/chain */
382*4543Swnj 			while (q != (struct ip *)fp) {
383*4543Swnj 				m_freem(dtom(q));
384*4543Swnj 				q = q->ip_next;
385*4543Swnj 			}
386*4543Swnj 			ip_freef(fp);           /* free header */
3874495Swnj 		}
3884525Swnj 	splx(s);
3894495Swnj }
390