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