1*4644Swnj /* ip_input.c 1.8 81/10/28 */ 24571Swnj 34495Swnj #include "../h/param.h" 44543Swnj #include "../h/systm.h" 54640Swnj #include "../h/clock.h" 64640Swnj #include "../h/mbuf.h" 74640Swnj #include "../inet/inet.h" 84640Swnj #include "../inet/inet_systm.h" 94640Swnj #include "../inet/imp.h" 104640Swnj #include "../inet/ip.h" /* belongs before inet.h */ 114640Swnj #include "../inet/ip_icmp.h" 124640Swnj #include "../inet/tcp.h" 134495Swnj 144640Swnj int nosum = 0; 154495Swnj 164640Swnj struct ip *ip_reass(); 174640Swnj 184640Swnj /* 194640Swnj * Ip input routines. 204640Swnj */ 214640Swnj 224640Swnj /* 234640Swnj * Ip input routine. Checksum and byte swap header. If fragmented 244640Swnj * try to reassamble. If complete and fragment queue exists, discard. 254640Swnj * Process options. Pass to next level. 264640Swnj */ 274640Swnj ip_input(m0) 284640Swnj struct mbuf *m0; 294495Swnj { 304640Swnj register int i; 314495Swnj register struct ip *ip, *q; 324495Swnj register struct ipq *fp; 334640Swnj register struct mbuf *m = m0; 344495Swnj int hlen; 354495Swnj 364495Swnj COUNT(IP_INPUT); 374640Swnj /* 384640Swnj * Check header and byteswap. 394640Swnj */ 404640Swnj ip = mtod(m, struct ip *); 414640Swnj if ((hlen = ip->ip_hl << 2) > m->m_len) { 424640Swnj printf("ip hdr ovflo\n"); 434640Swnj m_freem(m); 444495Swnj return; 454495Swnj } 464640Swnj i = ip->ip_sum; 474495Swnj ip->ip_sum = 0; 484640Swnj #ifdef vax 494640Swnj if (hlen == sizeof (struct ip)) { 504640Swnj asm("movl r10,r0; movl (r0)+,r1; addl2 (r0)+,r1"); 514640Swnj asm("adwc (r0)+,r1; adwc (r0)+,r1; adwc (r0)+,r1"); 524640Swnj asm("adwc $0,r1; ashl $-16,r1,r0; addw2 r0,r1"); 534640Swnj asm("adwc $0,r1"); /* ### */ 544640Swnj asm("mcoml r1,r1; movzwl r1,r1; subl2 r1,r11"); 554640Swnj } else 564640Swnj #endif 574640Swnj i -= cksum(m, hlen); 584640Swnj if (i) { 594495Swnj netstat.ip_badsum++; 604495Swnj if (!nosum) { 614640Swnj m_freem(m); 624640Swnj return; 634495Swnj } 644495Swnj } 654640Swnj ip->ip_len = ntohs(ip->ip_len); 664640Swnj ip->ip_id = ntohs(ip->ip_id); 674640Swnj ip->ip_off = ntohs(ip->ip_off); 684495Swnj 694543Swnj /* 704640Swnj * Check that the amount of data in the buffers 714640Swnj * is as at least much as the IP header would have us expect. 724640Swnj * Trim mbufs if longer than we expect. 734640Swnj * Drop packet if shorter than we expect. 744543Swnj */ 754640Swnj i = 0; 764640Swnj for (; m != NULL; m = m->m_next) 774495Swnj i += m->m_len; 784640Swnj m = m0; 794640Swnj if (i != ip->ip_len) { 804640Swnj if (i < ip->ip_len) { 814640Swnj printf("ip_input: short packet\n"); 824640Swnj m_freem(m); 834640Swnj return; 844640Swnj } 854640Swnj m_adj(m, ip->ip_len - i); 864495Swnj } 874495Swnj 884640Swnj /* 894640Swnj * Process options and, if not destined for us, 904640Swnj * ship it on. 914640Swnj */ 924543Swnj if (hlen > sizeof (struct ip)) 934640Swnj ip_dooptions(ip, hlen); 944640Swnj if (ip->ip_dst.s_addr != n_lhost.s_addr) { 954640Swnj if (--ip->ip_ttl == 0) { 964640Swnj icmp_error(ip, ICMP_TIMXCEED); 974543Swnj return; 984495Swnj } 994640Swnj ip_output(dtom(ip)); 1004640Swnj return; 1014543Swnj } 1024495Swnj 1034640Swnj /* 1044640Swnj * Look for queue of fragments 1054640Swnj * of this datagram. 1064640Swnj */ 1074640Swnj for (fp = ipq.next; fp != &ipq; fp = fp->next) 1084640Swnj if (ip->ip_id == fp->ipq_id && 1094640Swnj ip->ip_src.s_addr == fp->ipq_src.s_addr && 1104640Swnj ip->ip_dst.s_addr == fp->ipq_dst.s_addr && 1114640Swnj ip->ip_p == fp->ipq_p) 1124640Swnj goto found; 1134640Swnj fp = 0; 1144640Swnj found: 1154495Swnj 1164640Swnj /* 1174640Swnj * Adjust ip_len to not reflect header, 1184640Swnj * set ip_mff if more fragments are expected, 1194640Swnj * convert offset of this to bytes. 1204640Swnj */ 1214640Swnj ip->ip_len -= hlen; 1224640Swnj ip->ip_mff = 0; 1234640Swnj if (ip->ip_off & IP_MF) 1244640Swnj ip->ip_mff = 1; 1254640Swnj ip->ip_off <<= 3; 1264495Swnj 1274640Swnj /* 1284640Swnj * If datagram marked as having more fragments 1294640Swnj * or if this is not the first fragment, 1304640Swnj * attempt reassembly; if it succeeds, proceed. 1314640Swnj */ 1324640Swnj if (ip->ip_mff || ip->ip_off) { 1334640Swnj ip = ip_reass(ip, fp); 1344640Swnj if (ip == 0) 1354640Swnj return; 1364640Swnj hlen = ip->ip_hl << 2; 1374640Swnj m = dtom(ip); 1384640Swnj } else 1394640Swnj if (fp) 1404640Swnj (void) ip_freef(fp); 1414495Swnj 1424640Swnj /* 1434640Swnj * Switch out to protocol specific routine. 1444640Swnj * SHOULD GO THROUGH PROTOCOL SWITCH TABLE 1454640Swnj */ 1464640Swnj switch (ip->ip_p) { 1474495Swnj 1484640Swnj case IPPROTO_ICMP: 1494640Swnj icmp_input(m); 1504640Swnj break; 1514495Swnj 1524640Swnj case IPPROTO_TCP: 1534640Swnj if (hlen > sizeof (struct ip)) 1544640Swnj ip_stripoptions(ip, hlen); 1554640Swnj tcp_input(m); 1564640Swnj break; 1574495Swnj 1584640Swnj case IPPROTO_UDP: 1594640Swnj if (hlen > sizeof (struct ip)) 1604640Swnj ip_stripoptions(ip, hlen); 1614640Swnj udp_input(m); 1624640Swnj break; 1634495Swnj 1644640Swnj default: 1654640Swnj raw_input(m); 1664640Swnj break; 1674640Swnj } 1684640Swnj } 1694495Swnj 1704640Swnj /* 1714640Swnj * Take incoming datagram fragment and try to 1724640Swnj * reassamble it into whole datagram. If a chain for 1734640Swnj * reassembly of this datagram already exists, then it 1744640Swnj * is given as fp; otherwise have to make a chain. 1754640Swnj */ 1764640Swnj struct ip * 1774640Swnj ip_reass(ip, fp) 1784640Swnj register struct ip *ip; 1794640Swnj register struct ipq *fp; 1804640Swnj { 1814640Swnj register struct mbuf *m = dtom(ip); 1824640Swnj register struct ip *q; 1834640Swnj struct mbuf *t; 1844640Swnj int hlen = ip->ip_hl << 2; 1854640Swnj int i, next; 1864543Swnj 1874640Swnj /* 1884640Swnj * Presence of header sizes in mbufs 1894640Swnj * would confuse code below. 1904640Swnj */ 1914640Swnj m->m_off += hlen; 1924640Swnj m->m_len -= hlen; 1934495Swnj 1944640Swnj /* 1954640Swnj * If first fragment to arrive, create a reassembly queue. 1964640Swnj */ 1974640Swnj if (fp == 0) { 1984640Swnj if ((t = m_get(1)) == NULL) 1994640Swnj goto dropfrag; 2004640Swnj t->m_off = MMINOFF; 2014640Swnj fp = mtod(t, struct ipq *); 2024640Swnj insque(fp, &ipq); 2034640Swnj fp->ipq_ttl = IPFRAGTTL; 2044640Swnj fp->ipq_p = ip->ip_p; 2054640Swnj fp->ipq_id = ip->ip_id; 2064640Swnj fp->ipq_next = fp->ipq_prev = (struct ip *)fp; 2074640Swnj fp->ipq_src = ip->ip_src; 2084640Swnj fp->ipq_dst = ip->ip_dst; 2094640Swnj } 2104495Swnj 2114640Swnj /* 2124640Swnj * Find a segment which begins after this one does. 2134640Swnj */ 2144640Swnj for (q = fp->ipq_next; q != (struct ip *)fp; q = q->ip_next) 2154640Swnj if (q->ip_off > ip->ip_off) 2164640Swnj break; 2174495Swnj 2184640Swnj /* 2194640Swnj * If there is a preceding segment, it may provide some of 2204640Swnj * our data already. If so, drop the data from the incoming 2214640Swnj * segment. If it provides all of our data, drop us. 2224640Swnj */ 2234640Swnj if (q->ip_prev != (struct ip *)fp) { 2244640Swnj i = q->ip_prev->ip_off + q->ip_prev->ip_len - ip->ip_off; 2254640Swnj if (i > 0) { 2264640Swnj if (i >= ip->ip_len) 2274640Swnj goto dropfrag; 2284640Swnj m_adj(dtom(ip), i); 2294640Swnj ip->ip_off += i; 2304640Swnj ip->ip_len -= i; 2314640Swnj } 2324640Swnj } 2334543Swnj 2344640Swnj /* 2354640Swnj * While we overlap succeeding segments trim them or, 2364640Swnj * if they are completely covered, dequeue them. 2374640Swnj */ 2384640Swnj while (q != (struct ip *)fp && ip->ip_off + ip->ip_len > q->ip_off) { 2394640Swnj i = (ip->ip_off + ip->ip_len) - q->ip_off; 2404640Swnj if (i < q->ip_len) { 2414640Swnj q->ip_len -= i; 2424640Swnj m_adj(dtom(q), i); 2434640Swnj break; 2444495Swnj } 2454640Swnj q = q->ip_next; 2464640Swnj m_freem(dtom(q->ip_prev)); 2474640Swnj ip_deq(q->ip_prev); 2484543Swnj } 2494495Swnj 2504640Swnj /* 2514640Swnj * Stick new segment in its place; 2524640Swnj * check for complete reassembly. 2534640Swnj */ 2544640Swnj ip_enq(ip, q->ip_prev); 2554640Swnj next = 0; 2564640Swnj for (q = fp->ipq_next; q != (struct ip *)fp; q = q->ip_next) { 2574640Swnj if (q->ip_off != next) 2584640Swnj return (0); 2594640Swnj next += q->ip_len; 2604640Swnj } 2614640Swnj if (q->ip_prev->ip_mff) 2624640Swnj return (0); 2634495Swnj 2644640Swnj /* 2654640Swnj * Reassembly is complete; concatenate fragments. 2664640Swnj */ 2674640Swnj q = fp->ipq_next; 2684640Swnj m = dtom(q); 2694640Swnj t = m->m_next; 2704640Swnj m->m_next = 0; 2714640Swnj m_cat(m, t); 2724640Swnj while ((q = q->ip_next) != (struct ip *)fp) 2734640Swnj m_cat(m, dtom(q)); 2744495Swnj 2754640Swnj /* 2764640Swnj * Create header for new ip packet by 2774640Swnj * modifying header of first packet; 2784640Swnj * dequeue and discard fragment reassembly header. 2794640Swnj * Make header visible. 2804640Swnj */ 2814640Swnj ip = fp->ipq_next; 2824640Swnj ip->ip_len = next; 2834640Swnj ip->ip_src = fp->ipq_src; 2844640Swnj ip->ip_dst = fp->ipq_dst; 2854640Swnj remque(fp); 2864640Swnj m_free(dtom(fp)); 2874640Swnj m = dtom(ip); 2884640Swnj m->m_len += sizeof (struct ip); 2894640Swnj m->m_off -= sizeof (struct ip); 2904640Swnj return (ip); 2914495Swnj 2924640Swnj dropfrag: 2934640Swnj m_freem(m); 2944640Swnj return (0); 2954495Swnj } 2964495Swnj 2974640Swnj /* 2984640Swnj * Free a fragment reassembly header and all 2994640Swnj * associated datagrams. 3004640Swnj */ 3014640Swnj struct ipq * 3024640Swnj ip_freef(fp) 3034640Swnj struct ipq *fp; 3044495Swnj { 3054495Swnj register struct ip *q; 3064640Swnj struct mbuf *m; 3074495Swnj 3084640Swnj for (q = fp->ipq_next; q != (struct ip *)fp; q = q->ip_next) 3094640Swnj m_freem(dtom(q)); 3104640Swnj m = dtom(fp); 3114640Swnj fp = fp->next; 3124640Swnj remque(fp->prev); 3134640Swnj m_free(m); 3144640Swnj return (fp); 3154495Swnj } 3164495Swnj 3174640Swnj /* 3184640Swnj * Put an ip fragment on a reassembly chain. 3194640Swnj * Like insque, but pointers in middle of structure. 3204640Swnj */ 3214640Swnj ip_enq(p, prev) 3224640Swnj register struct ip *p; 3234640Swnj register struct ip *prev; 3244495Swnj { 3254640Swnj COUNT(IP_ENQ); 3264495Swnj 3274640Swnj p->ip_prev = prev; 3284640Swnj p->ip_next = prev->ip_next; 3294640Swnj prev->ip_next->ip_prev = p; 3304640Swnj prev->ip_next = p; 3314495Swnj } 3324495Swnj 3334640Swnj /* 3344640Swnj * To ip_enq as remque is to insque. 3354640Swnj */ 3364640Swnj ip_deq(p) 3374640Swnj register struct ip *p; 3384640Swnj { 3394640Swnj COUNT(IP_DEQ); 3404495Swnj 3414640Swnj p->ip_prev->ip_next = p->ip_next; 3424640Swnj p->ip_next->ip_prev = p->ip_prev; 3434495Swnj } 3444495Swnj 3454640Swnj /* 3464640Swnj * IP timer processing; 3474640Swnj * if a timer expires on a reassembly 3484640Swnj * queue, discard it. 3494640Swnj */ 3504640Swnj ip_timeo() 3514495Swnj { 3524640Swnj register struct ip *q; 3534495Swnj register struct ipq *fp; 3544640Swnj int s = splnet(); 3554640Swnj COUNT(IP_TIMEO); 3564495Swnj 357*4644Swnj for (fp = ipq.next; fp != &ipq; ) 3584640Swnj if (--fp->ipq_ttl == 0) 3594640Swnj fp = ip_freef(fp); 3604640Swnj else 3614640Swnj fp = fp->next; 3624640Swnj timeout(ip_timeo, 0, hz); 3634640Swnj splx(s); 3644495Swnj } 3654495Swnj 3664640Swnj /* 3674640Swnj * Do option processing on a datagram, 3684640Swnj * possibly discarding it if bad options 3694640Swnj * are encountered. 3704640Swnj */ 3714640Swnj ip_dooptions(ip) 3724640Swnj struct ip *ip; 3734495Swnj { 3744640Swnj register u_char *cp; 3754640Swnj int opt, optlen, cnt, s; 3764640Swnj struct inet_addr *sp; 3774495Swnj 3784640Swnj cp = (u_char *)(ip + 1); 3794640Swnj cnt = (ip->ip_hl << 2) - sizeof (struct ip); 3804640Swnj for (; cnt > 0; cnt -= optlen, cp += optlen) { 3814640Swnj opt = cp[0]; 3824640Swnj if (opt == IPOPT_EOL) 3834640Swnj break; 3844640Swnj if (opt == IPOPT_NOP) 3854640Swnj optlen = 1; 3864640Swnj else 3874640Swnj optlen = cp[1]; 3884640Swnj switch (opt) { 3894495Swnj 3904640Swnj default: 3914640Swnj break; 3924495Swnj 3934640Swnj case IPOPT_LSRR: 3944640Swnj case IPOPT_SSRR: 3954640Swnj if (cp[2] < 4 || cp[2] > optlen - 3) 3964640Swnj break; 3974640Swnj sp = (struct inet_addr *)(cp+cp[2]); 3984640Swnj if (n_lhost.s_addr == *(u_long *)sp) { 3994640Swnj if (opt == IPOPT_SSRR) { 4004640Swnj /* make sure *sp directly accessible*/ 4014640Swnj } 4024640Swnj ip->ip_dst = *sp; 4034640Swnj *sp = n_lhost; 4044640Swnj cp[2] += 4; 4054640Swnj } 4064640Swnj break; 4074495Swnj 4084640Swnj case IPOPT_TS: 4094640Swnj if (cp[2] < 5) 4104640Swnj goto bad; 4114640Swnj if (cp[2] > cp[1] - 3) { 4124640Swnj if ((cp[3] & 0xf0) == 0xf0) 4134640Swnj goto bad; 4144640Swnj cp[3] += 0x10; 4154495Swnj break; 4164640Swnj } 4174640Swnj sp = (struct inet_addr *)(cp+cp[2]); 4184640Swnj switch (cp[3] & 0xf) { 4194495Swnj 4204640Swnj case IPOPT_TS_TSONLY: 4214640Swnj break; 4224640Swnj 4234640Swnj case IPOPT_TS_TSANDADDR: 4244640Swnj if (cp[2] > cp[1] - 7) 4254640Swnj goto bad; 4264640Swnj break; 4274640Swnj 4284640Swnj case IPOPT_TS_PRESPEC: 4294640Swnj if (*(u_long *)sp != n_lhost.s_addr) 4304640Swnj break; 4314640Swnj if (cp[2] > cp[1] - 7) 4324640Swnj goto bad; 4334640Swnj cp[1] += 4; 4344640Swnj break; 4354640Swnj 4364495Swnj default: 4374640Swnj goto bad; 4384495Swnj } 4394640Swnj s = spl6(); 4404640Swnj *(int *)sp = (time % SECDAY) * 1000 + (lbolt*1000/hz); 4414640Swnj splx(s); 4424640Swnj cp[1] += 4; 4434640Swnj } 4444495Swnj } 4454640Swnj return (0); 4464640Swnj bad: 4474640Swnj /* SHOULD FORCE ICMP MESSAGE */ 4484640Swnj return (-1); 4494495Swnj } 4504495Swnj 4514640Swnj /* 4524640Swnj * Strip out IP options, e.g. before passing 4534640Swnj * to higher level protocol in the kernel. 4544640Swnj */ 4554640Swnj ip_stripoptions(ip) 4564640Swnj struct ip *ip; 4574495Swnj { 4584640Swnj register int i; 4594640Swnj register struct mbuf *m; 4604640Swnj char *op; 4614640Swnj int olen; 4624640Swnj COUNT(IP_OPT); 4634640Swnj 4644640Swnj olen = (ip->ip_hl<<2) - sizeof (struct ip); 4654640Swnj op = (caddr_t)ip + olen; 4664640Swnj m = dtom(++ip); 4674640Swnj i = m->m_len - (sizeof (struct ip) + olen); 4684640Swnj bcopy((caddr_t)ip+olen, (caddr_t)ip, i); 4694640Swnj m->m_len -= i; 4704495Swnj } 4714543Swnj 4724640Swnj /* stubs */ 4734640Swnj 4744640Swnj icmp_error(ip, error) 4754495Swnj { 4764640Swnj 4774640Swnj m_freem(dtom(ip)); 4784495Swnj } 4794495Swnj 4804640Swnj icmp_input(m) 4814640Swnj struct mbuf *m; 4824495Swnj { 4834495Swnj 4844640Swnj printf("icmp_input %x\n", m); 4854640Swnj } 4864495Swnj 4874640Swnj udp_input(m) 4884640Swnj struct mbuf *m; 4894640Swnj { 4904495Swnj 4914640Swnj printf("udp_input %x\n", m); 4924640Swnj } 4934495Swnj 4944640Swnj raw_input(m) 4954640Swnj struct mbuf *m; 4964640Swnj { 4974495Swnj 4984640Swnj printf("raw_input %x\n", m); 4994495Swnj } 500