1*4689Swnj /* ip_input.c 1.10 81/10/31 */ 24571Swnj 34495Swnj #include "../h/param.h" 44543Swnj #include "../h/systm.h" 54640Swnj #include "../h/clock.h" 64640Swnj #include "../h/mbuf.h" 7*4689Swnj #include "../inet/cksum.h" 84640Swnj #include "../inet/inet.h" 94640Swnj #include "../inet/inet_systm.h" 104640Swnj #include "../inet/imp.h" 114640Swnj #include "../inet/ip.h" /* belongs before inet.h */ 124640Swnj #include "../inet/ip_icmp.h" 134640Swnj #include "../inet/tcp.h" 144495Swnj 154640Swnj int nosum = 0; 164495Swnj 174640Swnj struct ip *ip_reass(); 184640Swnj 194640Swnj /* 204640Swnj * Ip input routines. 214640Swnj */ 224640Swnj 234640Swnj /* 244640Swnj * Ip input routine. Checksum and byte swap header. If fragmented 254640Swnj * try to reassamble. If complete and fragment queue exists, discard. 264640Swnj * Process options. Pass to next level. 274640Swnj */ 284640Swnj ip_input(m0) 294640Swnj struct mbuf *m0; 304495Swnj { 31*4689Swnj register struct ip *ip; /* known to be r11 in CKSUM below */ 32*4689Swnj register struct mbuf *m = m0; 334640Swnj register int i; 34*4689Swnj register struct ipq *q; 354495Swnj register struct ipq *fp; 364495Swnj int hlen; 374495Swnj 384495Swnj COUNT(IP_INPUT); 394640Swnj /* 404640Swnj * Check header and byteswap. 414640Swnj */ 424640Swnj ip = mtod(m, struct ip *); 434640Swnj if ((hlen = ip->ip_hl << 2) > m->m_len) { 444640Swnj printf("ip hdr ovflo\n"); 454640Swnj m_freem(m); 464495Swnj return; 474495Swnj } 48*4689Swnj CKSUM_IPCHK(m, ip, r11, hlen); 49*4689Swnj if (ip->ip_sum) { 50*4689Swnj printf("ip_sum %x\n", ip->ip_sum); 514495Swnj netstat.ip_badsum++; 524495Swnj if (!nosum) { 534640Swnj m_freem(m); 544640Swnj return; 554495Swnj } 564495Swnj } 574640Swnj ip->ip_len = ntohs(ip->ip_len); 584640Swnj ip->ip_id = ntohs(ip->ip_id); 594640Swnj ip->ip_off = ntohs(ip->ip_off); 604495Swnj 614543Swnj /* 624640Swnj * Check that the amount of data in the buffers 634640Swnj * is as at least much as the IP header would have us expect. 644640Swnj * Trim mbufs if longer than we expect. 654640Swnj * Drop packet if shorter than we expect. 664543Swnj */ 674640Swnj i = 0; 684640Swnj for (; m != NULL; m = m->m_next) 694495Swnj i += m->m_len; 704640Swnj m = m0; 714640Swnj if (i != ip->ip_len) { 724640Swnj if (i < ip->ip_len) { 734640Swnj printf("ip_input: short packet\n"); 744640Swnj m_freem(m); 754640Swnj return; 764640Swnj } 774640Swnj m_adj(m, ip->ip_len - i); 784495Swnj } 794495Swnj 804640Swnj /* 814640Swnj * Process options and, if not destined for us, 824640Swnj * ship it on. 834640Swnj */ 844543Swnj if (hlen > sizeof (struct ip)) 854640Swnj ip_dooptions(ip, hlen); 864640Swnj if (ip->ip_dst.s_addr != n_lhost.s_addr) { 874640Swnj if (--ip->ip_ttl == 0) { 884640Swnj icmp_error(ip, ICMP_TIMXCEED); 894543Swnj return; 904495Swnj } 914640Swnj ip_output(dtom(ip)); 924640Swnj return; 934543Swnj } 944495Swnj 954640Swnj /* 964640Swnj * Look for queue of fragments 974640Swnj * of this datagram. 984640Swnj */ 994640Swnj for (fp = ipq.next; fp != &ipq; fp = fp->next) 1004640Swnj if (ip->ip_id == fp->ipq_id && 1014640Swnj ip->ip_src.s_addr == fp->ipq_src.s_addr && 1024640Swnj ip->ip_dst.s_addr == fp->ipq_dst.s_addr && 1034640Swnj ip->ip_p == fp->ipq_p) 1044640Swnj goto found; 1054640Swnj fp = 0; 1064640Swnj found: 1074495Swnj 1084640Swnj /* 1094640Swnj * Adjust ip_len to not reflect header, 1104640Swnj * set ip_mff if more fragments are expected, 1114640Swnj * convert offset of this to bytes. 1124640Swnj */ 1134640Swnj ip->ip_len -= hlen; 1144640Swnj ip->ip_mff = 0; 1154640Swnj if (ip->ip_off & IP_MF) 1164640Swnj ip->ip_mff = 1; 1174640Swnj ip->ip_off <<= 3; 1184495Swnj 1194640Swnj /* 1204640Swnj * If datagram marked as having more fragments 1214640Swnj * or if this is not the first fragment, 1224640Swnj * attempt reassembly; if it succeeds, proceed. 1234640Swnj */ 1244640Swnj if (ip->ip_mff || ip->ip_off) { 1254640Swnj ip = ip_reass(ip, fp); 1264640Swnj if (ip == 0) 1274640Swnj return; 1284640Swnj hlen = ip->ip_hl << 2; 1294640Swnj m = dtom(ip); 1304640Swnj } else 1314640Swnj if (fp) 1324640Swnj (void) ip_freef(fp); 1334495Swnj 1344640Swnj /* 1354640Swnj * Switch out to protocol specific routine. 1364640Swnj * SHOULD GO THROUGH PROTOCOL SWITCH TABLE 1374640Swnj */ 1384640Swnj switch (ip->ip_p) { 1394495Swnj 1404640Swnj case IPPROTO_ICMP: 1414640Swnj icmp_input(m); 1424640Swnj break; 1434495Swnj 1444640Swnj case IPPROTO_TCP: 1454640Swnj if (hlen > sizeof (struct ip)) 1464640Swnj ip_stripoptions(ip, hlen); 1474640Swnj tcp_input(m); 1484640Swnj break; 1494495Swnj 1504640Swnj case IPPROTO_UDP: 1514640Swnj if (hlen > sizeof (struct ip)) 1524640Swnj ip_stripoptions(ip, hlen); 1534640Swnj udp_input(m); 1544640Swnj break; 1554495Swnj 1564640Swnj default: 1574640Swnj raw_input(m); 1584640Swnj break; 1594640Swnj } 1604640Swnj } 1614495Swnj 1624640Swnj /* 1634640Swnj * Take incoming datagram fragment and try to 1644640Swnj * reassamble it into whole datagram. If a chain for 1654640Swnj * reassembly of this datagram already exists, then it 1664640Swnj * is given as fp; otherwise have to make a chain. 1674640Swnj */ 1684640Swnj struct ip * 1694640Swnj ip_reass(ip, fp) 1704640Swnj register struct ip *ip; 1714640Swnj register struct ipq *fp; 1724640Swnj { 1734640Swnj register struct mbuf *m = dtom(ip); 1744640Swnj register struct ip *q; 1754640Swnj struct mbuf *t; 1764640Swnj int hlen = ip->ip_hl << 2; 1774640Swnj int i, next; 1784543Swnj 1794640Swnj /* 1804640Swnj * Presence of header sizes in mbufs 1814640Swnj * would confuse code below. 1824640Swnj */ 1834640Swnj m->m_off += hlen; 1844640Swnj m->m_len -= hlen; 1854495Swnj 1864640Swnj /* 1874640Swnj * If first fragment to arrive, create a reassembly queue. 1884640Swnj */ 1894640Swnj if (fp == 0) { 1904640Swnj if ((t = m_get(1)) == NULL) 1914640Swnj goto dropfrag; 1924640Swnj t->m_off = MMINOFF; 1934640Swnj fp = mtod(t, struct ipq *); 1944640Swnj insque(fp, &ipq); 1954640Swnj fp->ipq_ttl = IPFRAGTTL; 1964640Swnj fp->ipq_p = ip->ip_p; 1974640Swnj fp->ipq_id = ip->ip_id; 1984640Swnj fp->ipq_next = fp->ipq_prev = (struct ip *)fp; 1994640Swnj fp->ipq_src = ip->ip_src; 2004640Swnj fp->ipq_dst = ip->ip_dst; 2014640Swnj } 2024495Swnj 2034640Swnj /* 2044640Swnj * Find a segment which begins after this one does. 2054640Swnj */ 2064640Swnj for (q = fp->ipq_next; q != (struct ip *)fp; q = q->ip_next) 2074640Swnj if (q->ip_off > ip->ip_off) 2084640Swnj break; 2094495Swnj 2104640Swnj /* 2114640Swnj * If there is a preceding segment, it may provide some of 2124640Swnj * our data already. If so, drop the data from the incoming 2134640Swnj * segment. If it provides all of our data, drop us. 2144640Swnj */ 2154640Swnj if (q->ip_prev != (struct ip *)fp) { 2164640Swnj i = q->ip_prev->ip_off + q->ip_prev->ip_len - ip->ip_off; 2174640Swnj if (i > 0) { 2184640Swnj if (i >= ip->ip_len) 2194640Swnj goto dropfrag; 2204640Swnj m_adj(dtom(ip), i); 2214640Swnj ip->ip_off += i; 2224640Swnj ip->ip_len -= i; 2234640Swnj } 2244640Swnj } 2254543Swnj 2264640Swnj /* 2274640Swnj * While we overlap succeeding segments trim them or, 2284640Swnj * if they are completely covered, dequeue them. 2294640Swnj */ 2304640Swnj while (q != (struct ip *)fp && ip->ip_off + ip->ip_len > q->ip_off) { 2314640Swnj i = (ip->ip_off + ip->ip_len) - q->ip_off; 2324640Swnj if (i < q->ip_len) { 2334640Swnj q->ip_len -= i; 2344640Swnj m_adj(dtom(q), i); 2354640Swnj break; 2364495Swnj } 2374640Swnj q = q->ip_next; 2384640Swnj m_freem(dtom(q->ip_prev)); 2394640Swnj ip_deq(q->ip_prev); 2404543Swnj } 2414495Swnj 2424640Swnj /* 2434640Swnj * Stick new segment in its place; 2444640Swnj * check for complete reassembly. 2454640Swnj */ 2464640Swnj ip_enq(ip, q->ip_prev); 2474640Swnj next = 0; 2484640Swnj for (q = fp->ipq_next; q != (struct ip *)fp; q = q->ip_next) { 2494640Swnj if (q->ip_off != next) 2504640Swnj return (0); 2514640Swnj next += q->ip_len; 2524640Swnj } 2534640Swnj if (q->ip_prev->ip_mff) 2544640Swnj return (0); 2554495Swnj 2564640Swnj /* 2574640Swnj * Reassembly is complete; concatenate fragments. 2584640Swnj */ 2594640Swnj q = fp->ipq_next; 2604640Swnj m = dtom(q); 2614640Swnj t = m->m_next; 2624640Swnj m->m_next = 0; 2634640Swnj m_cat(m, t); 2644640Swnj while ((q = q->ip_next) != (struct ip *)fp) 2654640Swnj m_cat(m, dtom(q)); 2664495Swnj 2674640Swnj /* 2684640Swnj * Create header for new ip packet by 2694640Swnj * modifying header of first packet; 2704640Swnj * dequeue and discard fragment reassembly header. 2714640Swnj * Make header visible. 2724640Swnj */ 2734640Swnj ip = fp->ipq_next; 2744640Swnj ip->ip_len = next; 2754640Swnj ip->ip_src = fp->ipq_src; 2764640Swnj ip->ip_dst = fp->ipq_dst; 2774640Swnj remque(fp); 2784640Swnj m_free(dtom(fp)); 2794640Swnj m = dtom(ip); 2804640Swnj m->m_len += sizeof (struct ip); 2814640Swnj m->m_off -= sizeof (struct ip); 2824640Swnj return (ip); 2834495Swnj 2844640Swnj dropfrag: 2854640Swnj m_freem(m); 2864640Swnj return (0); 2874495Swnj } 2884495Swnj 2894640Swnj /* 2904640Swnj * Free a fragment reassembly header and all 2914640Swnj * associated datagrams. 2924640Swnj */ 2934640Swnj struct ipq * 2944640Swnj ip_freef(fp) 2954640Swnj struct ipq *fp; 2964495Swnj { 2974495Swnj register struct ip *q; 2984640Swnj struct mbuf *m; 2994495Swnj 3004640Swnj for (q = fp->ipq_next; q != (struct ip *)fp; q = q->ip_next) 3014640Swnj m_freem(dtom(q)); 3024640Swnj m = dtom(fp); 3034640Swnj fp = fp->next; 3044640Swnj remque(fp->prev); 3054640Swnj m_free(m); 3064640Swnj return (fp); 3074495Swnj } 3084495Swnj 3094640Swnj /* 3104640Swnj * Put an ip fragment on a reassembly chain. 3114640Swnj * Like insque, but pointers in middle of structure. 3124640Swnj */ 3134640Swnj ip_enq(p, prev) 3144640Swnj register struct ip *p; 3154640Swnj register struct ip *prev; 3164495Swnj { 3174640Swnj COUNT(IP_ENQ); 3184495Swnj 3194640Swnj p->ip_prev = prev; 3204640Swnj p->ip_next = prev->ip_next; 3214640Swnj prev->ip_next->ip_prev = p; 3224640Swnj prev->ip_next = p; 3234495Swnj } 3244495Swnj 3254640Swnj /* 3264640Swnj * To ip_enq as remque is to insque. 3274640Swnj */ 3284640Swnj ip_deq(p) 3294640Swnj register struct ip *p; 3304640Swnj { 3314640Swnj COUNT(IP_DEQ); 3324495Swnj 3334640Swnj p->ip_prev->ip_next = p->ip_next; 3344640Swnj p->ip_next->ip_prev = p->ip_prev; 3354495Swnj } 3364495Swnj 3374640Swnj /* 3384640Swnj * IP timer processing; 3394640Swnj * if a timer expires on a reassembly 3404640Swnj * queue, discard it. 3414640Swnj */ 3424640Swnj ip_timeo() 3434495Swnj { 3444640Swnj register struct ip *q; 3454495Swnj register struct ipq *fp; 3464640Swnj int s = splnet(); 3474640Swnj COUNT(IP_TIMEO); 3484495Swnj 3494644Swnj for (fp = ipq.next; fp != &ipq; ) 3504640Swnj if (--fp->ipq_ttl == 0) 3514640Swnj fp = ip_freef(fp); 3524640Swnj else 3534640Swnj fp = fp->next; 3544640Swnj timeout(ip_timeo, 0, hz); 3554640Swnj splx(s); 3564495Swnj } 3574495Swnj 3584640Swnj /* 3594640Swnj * Do option processing on a datagram, 3604640Swnj * possibly discarding it if bad options 3614640Swnj * are encountered. 3624640Swnj */ 3634640Swnj ip_dooptions(ip) 3644640Swnj struct ip *ip; 3654495Swnj { 3664640Swnj register u_char *cp; 3674640Swnj int opt, optlen, cnt, s; 3684662Swnj struct socket *sp; 3694495Swnj 3704640Swnj cp = (u_char *)(ip + 1); 3714640Swnj cnt = (ip->ip_hl << 2) - sizeof (struct ip); 3724640Swnj for (; cnt > 0; cnt -= optlen, cp += optlen) { 3734640Swnj opt = cp[0]; 3744640Swnj if (opt == IPOPT_EOL) 3754640Swnj break; 3764640Swnj if (opt == IPOPT_NOP) 3774640Swnj optlen = 1; 3784640Swnj else 3794640Swnj optlen = cp[1]; 3804640Swnj switch (opt) { 3814495Swnj 3824640Swnj default: 3834640Swnj break; 3844495Swnj 3854640Swnj case IPOPT_LSRR: 3864640Swnj case IPOPT_SSRR: 3874640Swnj if (cp[2] < 4 || cp[2] > optlen - 3) 3884640Swnj break; 3894662Swnj sp = (struct socket *)(cp+cp[2]); 3904640Swnj if (n_lhost.s_addr == *(u_long *)sp) { 3914640Swnj if (opt == IPOPT_SSRR) { 3924640Swnj /* make sure *sp directly accessible*/ 3934640Swnj } 3944640Swnj ip->ip_dst = *sp; 3954640Swnj *sp = n_lhost; 3964640Swnj cp[2] += 4; 3974640Swnj } 3984640Swnj break; 3994495Swnj 4004640Swnj case IPOPT_TS: 4014640Swnj if (cp[2] < 5) 4024640Swnj goto bad; 4034640Swnj if (cp[2] > cp[1] - 3) { 4044640Swnj if ((cp[3] & 0xf0) == 0xf0) 4054640Swnj goto bad; 4064640Swnj cp[3] += 0x10; 4074495Swnj break; 4084640Swnj } 4094662Swnj sp = (struct socket *)(cp+cp[2]); 4104640Swnj switch (cp[3] & 0xf) { 4114495Swnj 4124640Swnj case IPOPT_TS_TSONLY: 4134640Swnj break; 4144640Swnj 4154640Swnj case IPOPT_TS_TSANDADDR: 4164640Swnj if (cp[2] > cp[1] - 7) 4174640Swnj goto bad; 4184640Swnj break; 4194640Swnj 4204640Swnj case IPOPT_TS_PRESPEC: 4214640Swnj if (*(u_long *)sp != n_lhost.s_addr) 4224640Swnj break; 4234640Swnj if (cp[2] > cp[1] - 7) 4244640Swnj goto bad; 4254640Swnj cp[1] += 4; 4264640Swnj break; 4274640Swnj 4284495Swnj default: 4294640Swnj goto bad; 4304495Swnj } 4314640Swnj s = spl6(); 4324640Swnj *(int *)sp = (time % SECDAY) * 1000 + (lbolt*1000/hz); 4334640Swnj splx(s); 4344640Swnj cp[1] += 4; 4354640Swnj } 4364495Swnj } 4374640Swnj return (0); 4384640Swnj bad: 4394640Swnj /* SHOULD FORCE ICMP MESSAGE */ 4404640Swnj return (-1); 4414495Swnj } 4424495Swnj 4434640Swnj /* 4444640Swnj * Strip out IP options, e.g. before passing 4454640Swnj * to higher level protocol in the kernel. 4464640Swnj */ 4474640Swnj ip_stripoptions(ip) 4484640Swnj struct ip *ip; 4494495Swnj { 4504640Swnj register int i; 4514640Swnj register struct mbuf *m; 4524640Swnj char *op; 4534640Swnj int olen; 4544640Swnj COUNT(IP_OPT); 4554640Swnj 4564640Swnj olen = (ip->ip_hl<<2) - sizeof (struct ip); 4574640Swnj op = (caddr_t)ip + olen; 4584640Swnj m = dtom(++ip); 4594640Swnj i = m->m_len - (sizeof (struct ip) + olen); 4604640Swnj bcopy((caddr_t)ip+olen, (caddr_t)ip, i); 4614640Swnj m->m_len -= i; 4624495Swnj } 4634543Swnj 4644640Swnj /* stubs */ 4654640Swnj 4664640Swnj icmp_error(ip, error) 4674495Swnj { 4684640Swnj 4694640Swnj m_freem(dtom(ip)); 4704495Swnj } 4714495Swnj 4724640Swnj icmp_input(m) 4734640Swnj struct mbuf *m; 4744495Swnj { 4754495Swnj 4764640Swnj printf("icmp_input %x\n", m); 4774640Swnj } 4784495Swnj 4794640Swnj udp_input(m) 4804640Swnj struct mbuf *m; 4814640Swnj { 4824495Swnj 4834640Swnj printf("udp_input %x\n", m); 4844640Swnj } 4854495Swnj 4864640Swnj raw_input(m) 4874640Swnj struct mbuf *m; 4884640Swnj { 4894495Swnj 4904640Swnj printf("raw_input %x\n", m); 4914495Swnj } 492