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