xref: /csrg-svn/sys/netinet/ip_input.c (revision 4525)
1*4525Swnj /* ip_input.c 1.3 81/10/16 */
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"
74495Swnj 
84495Swnj /*****************************************************************************
94495Swnj *                                                                            *
104495Swnj *         ip level input routine: called from 1822 level upon receipt        *
114495Swnj *         of an internet datagram or fragment.  this routine does            *
124495Swnj *         fragment reassembly, if necessary, and passes completed            *
134495Swnj *         datagrams to higher level protocol processing routines on          *
144495Swnj *         the basis of the ip header protocol field.  it is passed a         *
154495Swnj *         pointer to an mbuf chain containing the datagram/fragment.         *
164495Swnj *         the mbuf offset/length are set to point at the ip header.          *
174495Swnj *                                                                            *
184495Swnj *****************************************************************************/
194495Swnj 
204495Swnj int nosum = 0;
214495Swnj 
224495Swnj ip_input(mp)
234495Swnj struct mbuf *mp;
244495Swnj {
254495Swnj 	register struct ip *ip, *q;
264495Swnj 	register struct ipq *fp;
274495Swnj 	register struct mbuf *m;
284495Swnj 	register i;
294495Swnj 	struct mbuf *n;
304495Swnj 	int hlen;
314495Swnj 	struct ip *p, *savq;
324495Swnj 	struct ipq *ip_findf();
334495Swnj 
344495Swnj COUNT(IP_INPUT);
354495Swnj 	ip = (struct ip *)((int)mp + mp->m_off);        /* ->ip hdr */
364495Swnj 
374495Swnj 	/* make sure header does not overflow mbuf */
384495Swnj 
394495Swnj 	if ((hlen = ip->ip_hl << 2) > mp->m_len) {
404495Swnj 		printf("ip header overflow\n");
414495Swnj 		m_freem(mp);
424495Swnj 		return;
434495Swnj 	}
444495Swnj 
454495Swnj 	i = (unsigned short)ip->ip_sum;
464495Swnj 	ip->ip_sum = 0;
474495Swnj 
484495Swnj 	if (i != (unsigned short)cksum(mp, hlen)) {     /* verify checksum */
494495Swnj 		netstat.ip_badsum++;
504495Swnj 		if (!nosum) {
514495Swnj         	  	m_freem(mp);
524495Swnj         		return;
534495Swnj 		}
544495Swnj 	}
554495Swnj 
564495Swnj 	ip_bswap(ip);                   /* byte-swap header */
574495Swnj 
584495Swnj 	netcb.n_ip_lock++;      /* lock frag reass.q */
594495Swnj 	fp = ip_findf(ip);      /* look for chain on reass.q with this hdr */
604495Swnj 
614495Swnj 	/* adjust message length to remove any padding */
624495Swnj 
634495Swnj 	for (i=0, m=mp; m != NULL; m = m->m_next) {
644495Swnj 		i += m->m_len;
654495Swnj 		n = m;
664495Swnj 	}
674495Swnj 	i -= ip->ip_len;
684495Swnj 
694495Swnj 	if (i != 0)
704495Swnj         	if (i > (int)n->m_len)
714495Swnj         		m_adj(mp, -i);
724495Swnj         	else
734495Swnj         		n->m_len -= i;
744495Swnj 
754495Swnj 	ip->ip_len -= hlen;     /* length of data */
764495Swnj   	ip->ip_mff = ((ip->ip_off & ip_mf) ? TRUE : FALSE);
774495Swnj 	ip->ip_off <<= 3;
784495Swnj 	if (!ip->ip_mff && ip->ip_off == 0) {    /* not fragmented */
794495Swnj 
804495Swnj 		if (fp != NULL) {               /* free existing reass.q chain */
814495Swnj 
824495Swnj 			q = fp->iqx.ip_next;    /* free mbufs assoc. w/chain */
834495Swnj 			while (q != (struct ip *)fp) {
844495Swnj 				m_freem(dtom(q));
854495Swnj 				q = q->ip_next;
864495Swnj 			}
874495Swnj 			ip_freef(fp);           /* free header */
884495Swnj 		}
894495Swnj 		netcb.n_ip_lock = 0;
904495Swnj 
914495Swnj 		ip_opt(ip, hlen);               /* option processing */
924495Swnj 		i = ip->ip_p;
934495Swnj 
944495Swnj 		/* pass to next level */
954495Swnj 
964495Swnj 		if (i == TCPROTO)
974495Swnj 			tcp_input(mp);
984495Swnj 		else
994495Swnj 			raw_input(mp, i, UIP);
1004495Swnj 
1014495Swnj 	} else {                                /* fragmented */
1024495Swnj 
1034495Swnj         	/* -> msg buf beyond ip hdr if not first fragment */
1044495Swnj 
1054495Swnj 		if (ip->ip_off != 0) {
1064495Swnj                 	mp->m_off += hlen;
1074495Swnj                 	mp->m_len -= hlen;
1084495Swnj 		}
1094495Swnj 
1104495Swnj 		if (fp == NULL) {               /* first fragment of datagram in */
1114495Swnj 
1124495Swnj 		/* set up reass.q header: enq it, set up as head of frag
1134495Swnj 		   chain, set a timer value, and move in ip header */
1144495Swnj 
1154495Swnj 			if ((m = m_get(1)) == NULL) {   /* allocate an mbuf */
1164495Swnj 				m_freem(mp);
1174495Swnj 				return;
1184495Swnj 			}
1194495Swnj 
1204495Swnj 			fp = (struct ipq *)((int)m + MHEAD);
1214495Swnj 			fp->iqx.ip_next = fp->iqx.ip_prev = (struct ip *)fp;
1224495Swnj 			bcopy(ip, &fp->iqh, min(MLEN-28, hlen));
1234495Swnj 			fp->iqh.ip_ttl = MAXTTL;
1244495Swnj 			fp->iq_next = NULL;
1254495Swnj 			fp->iq_prev = netcb.n_ip_tail;
1264495Swnj 			if (netcb.n_ip_head != NULL)
1274495Swnj 				netcb.n_ip_tail->iq_next = fp;
1284495Swnj 			else
1294495Swnj 				netcb.n_ip_head = fp;
1304495Swnj 			netcb.n_ip_tail = fp;
1314495Swnj 		}
1324495Swnj 
1334495Swnj                 /***********************************************************
1344495Swnj                 *                                                          *
1354495Swnj                 *              merge fragment into reass.q                 *
1364495Swnj                 *    algorithm:   match  start  and  end  bytes  of new    *
1374495Swnj                 *    fragment  with  fragments  on  the  queue.   if   no  *
1384495Swnj                 *    overlaps  are  found,  add  new  frag. to the queue.  *
1394495Swnj                 *    otherwise, adjust start and end of new frag.  so  no  *
1404495Swnj                 *    overlap   and   add  remainder  to  queue.   if  any  *
1414495Swnj                 *    fragments are completely covered by the new one,  or  *
1424495Swnj                 *    if  the  new  one is completely duplicated, free the  *
1434495Swnj                 *    fragments.                                            *
1444495Swnj                 *                                                          *
1454495Swnj                 ***********************************************************/
1464495Swnj 
1474495Swnj 	        q = fp->iqx.ip_next;    /* -> top of reass. chain */
1484495Swnj 		ip->ip_end = ip->ip_off + ip->ip_len - 1;
1494495Swnj 
1504495Swnj 		/* skip frags which new doesn't overlap at end */
1514495Swnj 
1524495Swnj 		while ((q != (struct ip *)fp) && (ip->ip_off > q->ip_end))
1534495Swnj 			q = q->ip_next;
1544495Swnj 
1554495Swnj 		if (q == (struct ip *)fp)               /* frag at end of chain */
1564495Swnj 			ip_enq(ip, fp->iqx.ip_prev);
1574495Swnj 
1584495Swnj 		else {
1594495Swnj 			if (ip->ip_end < q->ip_off)     /* frag doesn't overlap any on chain */
1604495Swnj 				ip_enq(ip, q->ip_prev);
1614495Swnj 
1624495Swnj 			/* new overlaps beginning of next frag only */
1634495Swnj 
1644495Swnj 			else if (ip->ip_end < q->ip_end) {
1654495Swnj 				if ((i = ip->ip_end - q->ip_off + 1) < ip->ip_len) {
1664495Swnj         				ip->ip_len -= i;
1674495Swnj         				ip->ip_end -= i;
1684495Swnj 					m_adj(mp, -i);
1694495Swnj 					ip_enq(ip, q->ip_prev);
1704495Swnj 				} else
1714495Swnj 					m_freem(mp);
1724495Swnj 
1734495Swnj 			/* new overlaps end of previous frag */
1744495Swnj 
1754495Swnj 			} else {
1764495Swnj 
1774495Swnj 				savq = q;
1784495Swnj 				if (ip->ip_off <= q->ip_off) {  /* complete cover */
1794495Swnj 					savq = q->ip_prev;
1804495Swnj 					ip_deq(q);
1814495Swnj 					m_freem(dtom(q));
1824495Swnj 
1834495Swnj 				} else {                        /* overlap */
1844495Swnj 					if ((i = q->ip_end - ip->ip_off + 1) < ip->ip_len) {
1854495Swnj         					ip->ip_off += i;
1864495Swnj         					ip->ip_len -= i;
1874495Swnj         					m_adj(mp, i);
1884495Swnj 					} else
1894495Swnj 						ip->ip_len = 0;
1904495Swnj 				}
1914495Swnj 
1924495Swnj 			/* new overlaps at beginning of successor frags */
1934495Swnj 
1944495Swnj 				q = savq->ip_next;
1954495Swnj 				while ((q != (struct ip *)fp) && (ip->ip_len != 0) &&
1964495Swnj 					(q->ip_off < ip->ip_end))
1974495Swnj 
1984495Swnj 					/* complete cover */
1994495Swnj 
2004495Swnj 					if (q->ip_end <= ip->ip_end) {
2014495Swnj 						p = q->ip_next;
2024495Swnj 						ip_deq(q);
2034495Swnj 						m_freem(dtom(q));
2044495Swnj 						q = p;
2054495Swnj 
2064495Swnj 					} else {        /* overlap */
2074495Swnj 
2084495Swnj 						if ((i = ip->ip_end - q->ip_off + 1) < ip->ip_len) {
2094495Swnj         						ip->ip_len -= i;
2104495Swnj         						ip->ip_end -= i;
2114495Swnj         						m_adj(mp, -i);
2124495Swnj 						} else
2134495Swnj 							ip->ip_len = 0;
2144495Swnj 						break;
2154495Swnj 					}
2164495Swnj 
2174495Swnj 			/* enqueue whatever is left of new before successors */
2184495Swnj 
2194495Swnj 				if (ip->ip_len != 0)
2204495Swnj 					ip_enq(ip, savq);
2214495Swnj 				else
2224495Swnj 					m_freem(mp);
2234495Swnj 			}
2244495Swnj 		}
2254495Swnj 
2264495Swnj 		/* check for completed fragment reassembly */
2274495Swnj 
2284495Swnj 		if ((i = ip_done(fp)) > 0) {
2294495Swnj 
2304495Swnj 			p = fp->iqx.ip_next;            /* -> top mbuf */
2314495Swnj 			m = dtom(p);
2324495Swnj 			p->ip_len = i;                  /* total data length */
2334495Swnj 			ip_opt(p, p->ip_hl << 2);       /* option processing */
2344495Swnj 			ip_mergef(fp);                  /* cleanup frag chain */
2354495Swnj 
2364495Swnj 			/* copy src/dst internet address to header mbuf */
2374495Swnj 
2384495Swnj 			bcopy(&fp->iqh.ip_src, &p->ip_src, 2*sizeof(struct socket));
2394495Swnj 			ip_freef(fp);                   /* dequeue header */
2404495Swnj 			netcb.n_ip_lock = 0;
2414495Swnj 
2424495Swnj 			/* call next level with completed datagram */
2434495Swnj 
2444495Swnj 			i = p->ip_p;
2454495Swnj 			if (i == TCPROTO)
2464495Swnj 				tcp_input(m);
2474495Swnj         		else
2484495Swnj 				raw_input(m, i, UIP);
2494495Swnj 		} else
2504495Swnj 			netcb.n_ip_lock = 0;
2514495Swnj 	}
2524495Swnj }
2534495Swnj 
2544495Swnj 
2554495Swnj ip_done(p)      /* check to see if fragment reassembly is complete */
2564495Swnj register struct ip *p;
2574495Swnj {
2584495Swnj 	register struct ip *q;
2594495Swnj 	register next;
2604495Swnj 
2614495Swnj COUNT(IP_DONE);
2624495Swnj 	q = p->ip_next;
2634495Swnj 
2644495Swnj 	if (q->ip_off != 0)
2654495Swnj 		return(0);
2664495Swnj 	do {
2674495Swnj 		next = q->ip_end + 1;
2684495Swnj 		q = q->ip_next;
2694495Swnj 	} while ((q != p) && (q->ip_off == next));
2704495Swnj 
2714495Swnj 	if ((q == p) && !(q->ip_prev->ip_mff))        /* all fragments in */
2724495Swnj 		return(next);                         /* total data length */
2734495Swnj 	else
2744495Swnj 		return(0);
2754495Swnj }
2764495Swnj 
2774495Swnj ip_mergef(p)    /* merge mbufs of fragments of completed datagram */
2784495Swnj register struct ip *p;
2794495Swnj {
2804495Swnj 	register struct mbuf *m, *n;
2814495Swnj 	register struct ip *q;
2824495Swnj 	int dummy;
2834495Swnj 
2844495Swnj COUNT(IP_MERGEF);
2854495Swnj 	q = p->ip_next;                         /* -> bottom of reass chain */
2864495Swnj 	n = (struct mbuf *)&dummy;              /* dummy for init assignment */
2874495Swnj 
2884495Swnj 	while (q != p) {        /* through chain */
2894495Swnj 
2904495Swnj 	        n->m_next = m = dtom(q);
2914495Swnj 		while (m != NULL)
2924495Swnj 			if (m->m_len != 0) {
2934495Swnj 				n = m;
2944495Swnj 				m = m->m_next;
2954495Swnj 			} else                  /* free null mbufs */
2964495Swnj 				n->m_next = m = m_free(m);
2974495Swnj 		q = q->ip_next;
2984495Swnj 	}
2994495Swnj }
3004495Swnj 
3014495Swnj 
3024495Swnj ip_freef(fp)	        /* deq and free reass.q header */
3034495Swnj register struct ipq *fp;
3044495Swnj {
3054495Swnj COUNT(IP_FREEF);
3064495Swnj 	if (fp->iq_prev != NULL)
3074495Swnj 		(fp->iq_prev)->iq_next = fp->iq_next;
3084495Swnj 	else
3094495Swnj 		netcb.n_ip_head = fp->iq_next;
3104495Swnj 	if (fp->iq_next != NULL)
3114495Swnj 		(fp->iq_next)->iq_prev = fp->iq_prev;
3124495Swnj 	else
3134495Swnj 		netcb.n_ip_tail = fp->iq_prev;
3144495Swnj 	m_free(dtom(fp));
3154495Swnj }
3164495Swnj 
3174495Swnj struct ipq *ip_findf(p)         /* does fragment reass chain w/this hdr exist? */
3184495Swnj register struct ip *p;
3194495Swnj {
3204495Swnj 	register struct ipq *fp;
3214495Swnj 
3224495Swnj COUNT(IP_FINDF);
3234495Swnj 	for (fp = netcb.n_ip_head; (fp != NULL && (
3244495Swnj 			p->ip_src.s_addr != fp->iqh.ip_src.s_addr ||
3254495Swnj 			p->ip_dst.s_addr != fp->iqh.ip_dst.s_addr ||
3264495Swnj 			p->ip_id != fp->iqh.ip_id ||
3274495Swnj 			p->ip_p != fp->iqh.ip_p)); fp = fp->iq_next);
3284495Swnj 	return(fp);
3294495Swnj }
3304495Swnj 
3314495Swnj ip_opt(ip, hlen)        /* process ip options */
3324495Swnj struct ip *ip;
3334495Swnj int hlen;
3344495Swnj {
3354495Swnj 	register char *p, *q;
3364495Swnj 	register i, len;
3374495Swnj 	register struct mbuf *m;
3384495Swnj 
3394495Swnj COUNT(IP_OPT);
3404495Swnj 	p = q = (char *)((int)ip + sizeof(struct ip));  /* -> at options */
3414495Swnj 
3424495Swnj 	if ((i = hlen - sizeof(struct ip)) > 0) {       /* any options */
3434495Swnj 
3444495Swnj /*      *** IP OPTION PROCESSING ***
3454495Swnj 
3464495Swnj 		while (i > 0)
3474495Swnj 
3484495Swnj   			switch (*q++) {
3494495Swnj 			case 0:
3504495Swnj 			case 1:
3514495Swnj 				i--;
3524495Swnj 				break;
3534495Swnj 
3544495Swnj 			default:
3554495Swnj 				i -= *q;
3564495Swnj 				q += *q;
3574495Swnj 			}
3584495Swnj */              q += i;
3594495Swnj 		m = dtom(q);
3604495Swnj 		len = (int)m + m->m_off + m->m_len - (int)q;
3614495Swnj 		bcopy((caddr_t)q, (caddr_t)p, len);    /* remove options */
3624495Swnj 		m->m_len -= i;
3634495Swnj 	}
3644495Swnj }
3654495Swnj 
3664495Swnj ip_enq(p, prev)
3674495Swnj register struct ip *p;
3684495Swnj register struct ip *prev;
3694495Swnj {
3704495Swnj COUNT(IP_ENQ);
3714495Swnj 	p->ip_prev = prev;
3724495Swnj 	p->ip_next = prev->ip_next;
3734495Swnj 	prev->ip_next->ip_prev = p;
3744495Swnj 	prev->ip_next = p;
3754495Swnj }
3764495Swnj 
3774495Swnj ip_deq(p)
3784495Swnj register struct ip *p;
3794495Swnj {
3804495Swnj COUNT(IP_DEQ);
3814495Swnj 	p->ip_prev->ip_next = p->ip_next;
3824495Swnj 	p->ip_next->ip_prev = p->ip_prev;
3834495Swnj }
3844495Swnj 
3854495Swnj ip_timeo()      /* frag reass.q timeout routine */
3864495Swnj {
3874495Swnj 	register struct ip *q;
3884495Swnj 	register struct ipq *fp;
389*4525Swnj 	int s = splnet();
3904495Swnj 
3914495Swnj COUNT(IP_TIMEO);
3924495Swnj 	timeout(ip_timeo, 0, 60);       /* reschedule every second */
3934495Swnj 
394*4525Swnj 	if (netcb.n_ip_lock) {    /* reass.q must not be in use */
395*4525Swnj 		splx(s);
3964495Swnj 		return;
397*4525Swnj 	}
3984495Swnj 
3994495Swnj 	/* search through reass.q */
4004495Swnj 
4014495Swnj 	for (fp = netcb.n_ip_head; fp != NULL; fp = fp->iq_next)
4024495Swnj 
4034495Swnj 		if (--(fp->iqx.ip_ttl) == 0) {  /* time to die */
4044495Swnj 
4054495Swnj 			q = fp->iqx.ip_next;    /* free mbufs assoc. w/chain */
4064495Swnj 			while (q != (struct ip *)fp) {
4074495Swnj 				m_freem(dtom(q));
4084495Swnj 				q = q->ip_next;
4094495Swnj 			}
4104495Swnj 			ip_freef(fp);           /* free header */
4114495Swnj 		}
412*4525Swnj 	splx(s);
4134495Swnj }
414