xref: /csrg-svn/sys/netinet/ip_input.c (revision 4571)
1*4571Swnj /* ip_input.c 1.5 81/10/21 */
2*4571Swnj 
34495Swnj #include "../h/param.h"
44495Swnj #include "../bbnnet/net.h"
5*4571Swnj #include "../bbnnet/mbuf.h"
64495Swnj #include "../bbnnet/tcp.h"
74495Swnj #include "../bbnnet/ip.h"
84495Swnj #include "../bbnnet/ucb.h"
94543Swnj #include "../h/systm.h"
104495Swnj 
114495Swnj int nosum = 0;
124495Swnj 
134495Swnj ip_input(mp)
144495Swnj struct mbuf *mp;
154495Swnj {
164495Swnj 	register struct ip *ip, *q;
174495Swnj 	register struct ipq *fp;
184495Swnj 	register struct mbuf *m;
194495Swnj 	register i;
204495Swnj 	struct mbuf *n;
214495Swnj 	int hlen;
224495Swnj 	struct ip *p, *savq;
234495Swnj 	struct ipq *ip_findf();
244495Swnj 
254495Swnj COUNT(IP_INPUT);
264495Swnj 	ip = (struct ip *)((int)mp + mp->m_off);        /* ->ip hdr */
274495Swnj 
284495Swnj 	/* make sure header does not overflow mbuf */
294495Swnj 
304495Swnj 	if ((hlen = ip->ip_hl << 2) > mp->m_len) {
314495Swnj 		printf("ip header overflow\n");
324495Swnj 		m_freem(mp);
334495Swnj 		return;
344495Swnj 	}
354495Swnj 
364495Swnj 	i = (unsigned short)ip->ip_sum;
374495Swnj 	ip->ip_sum = 0;
384495Swnj 
394495Swnj 	if (i != (unsigned short)cksum(mp, hlen)) {     /* verify checksum */
404495Swnj 		netstat.ip_badsum++;
414495Swnj 		if (!nosum) {
424495Swnj         	  	m_freem(mp);
434495Swnj         		return;
444495Swnj 		}
454495Swnj 	}
464543Swnj 	ip_bswap(ip);
474543Swnj 	fp = netcb.n_ip_head ? ip_findf(ip) : 0;
484495Swnj 
494543Swnj 	/*
504543Swnj 	 * adjust message length to remove any padding
514543Swnj 	 */
524495Swnj 	for (i=0, m=mp; m != NULL; m = m->m_next) {
534495Swnj 		i += m->m_len;
544495Swnj 		n = m;
554495Swnj 	}
564495Swnj 	i -= ip->ip_len;
574495Swnj 
584543Swnj 	if (i != 0)
594495Swnj         	if (i > (int)n->m_len)
604495Swnj         		m_adj(mp, -i);
614495Swnj         	else
624495Swnj         		n->m_len -= i;
634495Swnj 
644495Swnj 	ip->ip_len -= hlen;     /* length of data */
654543Swnj   	ip->ip_mff = ((ip->ip_off & ip_mf) ? TRUE : FALSE);
664543Swnj 	ip->ip_off <<= 3;
674543Swnj 	if (ip->ip_mff || ip->ip_off)
684543Swnj 		goto fragged;
694543Swnj 	if (fp != NULL) {
704543Swnj 		q = fp->iqx.ip_next;
714543Swnj 		while (q != (struct ip *)fp) {
724543Swnj 			m_freem(dtom(q));
734543Swnj 			q = q->ip_next;
744543Swnj 		}
754543Swnj 		ip_freef(fp);           /* free header */
764543Swnj 	}
774543Swnj 	if (hlen > sizeof (struct ip))
784543Swnj 		ip_opt(ip, hlen);
794543Swnj 	switch (ip->ip_p) {
804495Swnj 
814543Swnj 	case TCPROTO:
824543Swnj 		tcp_input(mp);
834543Swnj 		break;
844495Swnj 
854543Swnj 	default:
864543Swnj 		raw_input(mp, ip->ip_p, UIP);
874543Swnj 		break;
884543Swnj 	}
894543Swnj 	return;
904495Swnj 
914543Swnj fragged:
924543Swnj 	/* -> msg buf beyond ip hdr if not first fragment */
934495Swnj 
944543Swnj 	if (ip->ip_off != 0) {
954543Swnj 		mp->m_off += hlen;
964543Swnj 		mp->m_len -= hlen;
974543Swnj 	}
984495Swnj 
994543Swnj 	if (fp == NULL) {               /* first fragment of datagram in */
1004495Swnj 
1014543Swnj 	/* set up reass.q header: enq it, set up as head of frag
1024543Swnj 	   chain, set a timer value, and move in ip header */
1034495Swnj 
1044543Swnj 		if ((m = m_get(1)) == NULL) {   /* allocate an mbuf */
1054543Swnj 			m_freem(mp);
1064543Swnj 			return;
1074495Swnj 		}
1084495Swnj 
1094543Swnj 		fp = (struct ipq *)((int)m + MHEAD);
1104543Swnj 		fp->iqx.ip_next = fp->iqx.ip_prev = (struct ip *)fp;
1114543Swnj 		bcopy(ip, &fp->iqh, min(MLEN-28, hlen));
1124543Swnj 		fp->iqh.ip_ttl = MAXTTL;
1134543Swnj 		fp->iq_next = NULL;
1144543Swnj 		fp->iq_prev = netcb.n_ip_tail;
1154543Swnj 		if (netcb.n_ip_head != NULL)
1164543Swnj 			netcb.n_ip_tail->iq_next = fp;
1174543Swnj 		else
1184543Swnj 			netcb.n_ip_head = fp;
1194543Swnj 		netcb.n_ip_tail = fp;
1204543Swnj 	}
1214495Swnj 
1224543Swnj 	/***********************************************************
1234543Swnj 	*                                                          *
1244543Swnj 	*              merge fragment into reass.q                 *
1254543Swnj 	*    algorithm:   match  start  and  end  bytes  of new    *
1264543Swnj 	*    fragment  with  fragments  on  the  queue.   if   no  *
1274543Swnj 	*    overlaps  are  found,  add  new  frag. to the queue.  *
1284543Swnj 	*    otherwise, adjust start and end of new frag.  so  no  *
1294543Swnj 	*    overlap   and   add  remainder  to  queue.   if  any  *
1304543Swnj 	*    fragments are completely covered by the new one,  or  *
1314543Swnj 	*    if  the  new  one is completely duplicated, free the  *
1324543Swnj 	*    fragments.                                            *
1334543Swnj 	*                                                          *
1344543Swnj 	***********************************************************/
1354495Swnj 
1364543Swnj 	q = fp->iqx.ip_next;    /* -> top of reass. chain */
1374543Swnj 	ip->ip_end = ip->ip_off + ip->ip_len - 1;
1384495Swnj 
1394543Swnj 	/* skip frags which new doesn't overlap at end */
1404495Swnj 
1414543Swnj 	while ((q != (struct ip *)fp) && (ip->ip_off > q->ip_end))
1424543Swnj 		q = q->ip_next;
1434495Swnj 
1444543Swnj 	if (q == (struct ip *)fp)               /* frag at end of chain */
1454543Swnj 		ip_enq(ip, fp->iqx.ip_prev);
1464543Swnj 
1474543Swnj 	else {
1484543Swnj 		if (ip->ip_end < q->ip_off)     /* frag doesn't overlap any on chain */
1494543Swnj 			ip_enq(ip, q->ip_prev);
1504495Swnj 
1514543Swnj 		/* new overlaps beginning of next frag only */
1524495Swnj 
1534543Swnj 		else if (ip->ip_end < q->ip_end) {
1544543Swnj 			if ((i = ip->ip_end - q->ip_off + 1) < ip->ip_len) {
1554543Swnj 				ip->ip_len -= i;
1564543Swnj 				ip->ip_end -= i;
1574543Swnj 				m_adj(mp, -i);
1584495Swnj 				ip_enq(ip, q->ip_prev);
1594543Swnj 			} else
1604543Swnj 				m_freem(mp);
1614495Swnj 
1624543Swnj 		/* new overlaps end of previous frag */
1634495Swnj 
1644543Swnj 		} else {
1654543Swnj 
1664543Swnj 			savq = q;
1674543Swnj 			if (ip->ip_off <= q->ip_off) {  /* complete cover */
1684543Swnj 				savq = q->ip_prev;
1694543Swnj 				ip_deq(q);
1704543Swnj 				m_freem(dtom(q));
1714543Swnj 
1724543Swnj 			} else {                        /* overlap */
1734543Swnj 				if ((i = q->ip_end - ip->ip_off + 1) < ip->ip_len) {
1744543Swnj 					ip->ip_off += i;
1754543Swnj 					ip->ip_len -= i;
1764543Swnj 					m_adj(mp, i);
1774495Swnj 				} else
1784543Swnj 					ip->ip_len = 0;
1794543Swnj 			}
1804495Swnj 
1814543Swnj 		/* new overlaps at beginning of successor frags */
1824495Swnj 
1834543Swnj 			q = savq->ip_next;
1844543Swnj 			while ((q != (struct ip *)fp) && (ip->ip_len != 0) &&
1854543Swnj 				(q->ip_off < ip->ip_end))
1864495Swnj 
1874543Swnj 				/* complete cover */
1884543Swnj 
1894543Swnj 				if (q->ip_end <= ip->ip_end) {
1904543Swnj 					p = q->ip_next;
1914495Swnj 					ip_deq(q);
1924495Swnj 					m_freem(dtom(q));
1934543Swnj 					q = p;
1944543Swnj 
1954543Swnj 				} else {        /* overlap */
1964543Swnj 
1974543Swnj 					if ((i = ip->ip_end - q->ip_off + 1) < ip->ip_len) {
1984543Swnj 						ip->ip_len -= i;
1994543Swnj 						ip->ip_end -= i;
2004543Swnj 						m_adj(mp, -i);
2014495Swnj 					} else
2024495Swnj 						ip->ip_len = 0;
2034543Swnj 					break;
2044495Swnj 				}
2054495Swnj 
2064543Swnj 		/* enqueue whatever is left of new before successors */
2074495Swnj 
2084543Swnj 			if (ip->ip_len != 0)
2094543Swnj 				ip_enq(ip, savq);
2104543Swnj 			else
2114543Swnj 				m_freem(mp);
2124495Swnj 		}
2134543Swnj 	}
2144495Swnj 
2154543Swnj 	/* check for completed fragment reassembly */
2164495Swnj 
2174543Swnj 	if ((i = ip_done(fp)) == 0)
2184543Swnj 		return;
2194495Swnj 
2204543Swnj 	p = fp->iqx.ip_next;            /* -> top mbuf */
2214543Swnj 	m = dtom(p);
2224543Swnj 	p->ip_len = i;                  /* total data length */
2234543Swnj 	ip_opt(p, p->ip_hl << 2);       /* option processing */
2244543Swnj 	ip_mergef(fp);                  /* cleanup frag chain */
2254495Swnj 
2264543Swnj 	/* copy src/dst internet address to header mbuf */
2274495Swnj 
2284543Swnj 	bcopy(&fp->iqh.ip_src, &p->ip_src, 2*sizeof(struct socket));
2294543Swnj 	ip_freef(fp);                   /* dequeue header */
2304543Swnj 	i = p->ip_p;
2314543Swnj 	if (i == TCPROTO)
2324543Swnj 		tcp_input(m);
2334543Swnj 	else
2344543Swnj 		raw_input(m, i, UIP);
2354495Swnj }
2364495Swnj 
2374543Swnj ip_done(p)
2384543Swnj 	register struct ip *p;
2394495Swnj {
2404495Swnj 	register struct ip *q;
2414495Swnj 	register next;
2424495Swnj 
2434495Swnj COUNT(IP_DONE);
2444543Swnj 	q = p->ip_next;
2454495Swnj 
2464495Swnj 	if (q->ip_off != 0)
2474495Swnj 		return(0);
2484495Swnj 	do {
2494495Swnj 		next = q->ip_end + 1;
2504495Swnj 		q = q->ip_next;
2514495Swnj 	} while ((q != p) && (q->ip_off == next));
2524495Swnj 
2534495Swnj 	if ((q == p) && !(q->ip_prev->ip_mff))        /* all fragments in */
2544495Swnj 		return(next);                         /* total data length */
2554495Swnj 	else
2564495Swnj 		return(0);
2574495Swnj }
2584495Swnj 
2594495Swnj ip_mergef(p)    /* merge mbufs of fragments of completed datagram */
2604495Swnj register struct ip *p;
2614495Swnj {
2624495Swnj 	register struct mbuf *m, *n;
2634495Swnj 	register struct ip *q;
2644495Swnj 	int dummy;
2654495Swnj 
2664495Swnj COUNT(IP_MERGEF);
2674495Swnj 	q = p->ip_next;                         /* -> bottom of reass chain */
2684495Swnj 	n = (struct mbuf *)&dummy;              /* dummy for init assignment */
2694495Swnj 
2704495Swnj 	while (q != p) {        /* through chain */
2714495Swnj 
2724495Swnj 	        n->m_next = m = dtom(q);
2734543Swnj 		while (m != NULL)
2744495Swnj 			if (m->m_len != 0) {
2754495Swnj 				n = m;
2764495Swnj 				m = m->m_next;
2774495Swnj 			} else                  /* free null mbufs */
2784495Swnj 				n->m_next = m = m_free(m);
2794495Swnj 		q = q->ip_next;
2804495Swnj 	}
2814495Swnj }
2824495Swnj 
2834495Swnj 
2844543Swnj ip_freef(fp)	        /* deq and free reass.q header */
2854495Swnj register struct ipq *fp;
2864495Swnj {
2874495Swnj COUNT(IP_FREEF);
2884543Swnj 	if (fp->iq_prev != NULL)
2894543Swnj 		(fp->iq_prev)->iq_next = fp->iq_next;
2904495Swnj 	else
2914543Swnj 		netcb.n_ip_head = fp->iq_next;
2924543Swnj 	if (fp->iq_next != NULL)
2934543Swnj 		(fp->iq_next)->iq_prev = fp->iq_prev;
2944543Swnj 	else
2954495Swnj 		netcb.n_ip_tail = fp->iq_prev;
2964495Swnj 	m_free(dtom(fp));
2974495Swnj }
2984495Swnj 
2994543Swnj struct ipq *
3004543Swnj ip_findf(p)         /* does fragment reass chain w/this hdr exist? */
3014495Swnj register struct ip *p;
3024495Swnj {
3034495Swnj 	register struct ipq *fp;
3044495Swnj 
3054495Swnj COUNT(IP_FINDF);
3064495Swnj 	for (fp = netcb.n_ip_head; (fp != NULL && (
3074495Swnj 			p->ip_src.s_addr != fp->iqh.ip_src.s_addr ||
3084495Swnj 			p->ip_dst.s_addr != fp->iqh.ip_dst.s_addr ||
3094495Swnj 			p->ip_id != fp->iqh.ip_id ||
3104495Swnj 			p->ip_p != fp->iqh.ip_p)); fp = fp->iq_next);
3114495Swnj 	return(fp);
3124495Swnj }
3134495Swnj 
3144495Swnj ip_opt(ip, hlen)        /* process ip options */
3154495Swnj struct ip *ip;
3164495Swnj int hlen;
3174495Swnj {
3184495Swnj 	register char *p, *q;
3194495Swnj 	register i, len;
3204495Swnj 	register struct mbuf *m;
3214495Swnj 
3224495Swnj COUNT(IP_OPT);
3234495Swnj 	p = q = (char *)((int)ip + sizeof(struct ip));  /* -> at options */
3244495Swnj 
3254495Swnj 	if ((i = hlen - sizeof(struct ip)) > 0) {       /* any options */
3264495Swnj 
3274495Swnj /*      *** IP OPTION PROCESSING ***
3284495Swnj 
3294495Swnj 		while (i > 0)
3304495Swnj 
3314495Swnj   			switch (*q++) {
3324543Swnj 			case 0:
3334543Swnj 			case 1:
3344495Swnj 				i--;
3354495Swnj 				break;
3364495Swnj 
3374495Swnj 			default:
3384495Swnj 				i -= *q;
3394495Swnj 				q += *q;
3404495Swnj 			}
3414495Swnj */              q += i;
3424495Swnj 		m = dtom(q);
3434495Swnj 		len = (int)m + m->m_off + m->m_len - (int)q;
3444495Swnj 		bcopy((caddr_t)q, (caddr_t)p, len);    /* remove options */
3454495Swnj 		m->m_len -= i;
3464495Swnj 	}
3474495Swnj }
3484495Swnj 
3494495Swnj ip_enq(p, prev)
3504495Swnj register struct ip *p;
3514495Swnj register struct ip *prev;
3524495Swnj {
3534495Swnj COUNT(IP_ENQ);
3544495Swnj 	p->ip_prev = prev;
3554495Swnj 	p->ip_next = prev->ip_next;
3564495Swnj 	prev->ip_next->ip_prev = p;
3574495Swnj 	prev->ip_next = p;
3584495Swnj }
3594543Swnj 
3604495Swnj ip_deq(p)
3614495Swnj register struct ip *p;
3624495Swnj {
3634495Swnj COUNT(IP_DEQ);
3644495Swnj 	p->ip_prev->ip_next = p->ip_next;
3654495Swnj 	p->ip_next->ip_prev = p->ip_prev;
3664495Swnj }
3674495Swnj 
3684495Swnj ip_timeo()      /* frag reass.q timeout routine */
3694495Swnj {
3704495Swnj 	register struct ip *q;
3714495Swnj 	register struct ipq *fp;
3724525Swnj 	int s = splnet();
3734495Swnj 
3744495Swnj COUNT(IP_TIMEO);
3754543Swnj 	timeout(ip_timeo, 0, hz);       /* reschedule every second */
3764495Swnj 
3774495Swnj 	/* search through reass.q */
3784495Swnj 
3794543Swnj 	for (fp = netcb.n_ip_head; fp != NULL; fp = fp->iq_next)
3804495Swnj 
3814495Swnj 		if (--(fp->iqx.ip_ttl) == 0) {  /* time to die */
3824495Swnj 
3834495Swnj 			q = fp->iqx.ip_next;    /* free mbufs assoc. w/chain */
3844543Swnj 			while (q != (struct ip *)fp) {
3854543Swnj 				m_freem(dtom(q));
3864543Swnj 				q = q->ip_next;
3874543Swnj 			}
3884543Swnj 			ip_freef(fp);           /* free header */
3894495Swnj 		}
3904525Swnj 	splx(s);
3914495Swnj }
392