1*4640Swnj /* ip_input.c 1.7 81/10/28 */ 24571Swnj 34495Swnj #include "../h/param.h" 44543Swnj #include "../h/systm.h" 5*4640Swnj #include "../h/clock.h" 6*4640Swnj #include "../h/mbuf.h" 7*4640Swnj #include "../inet/inet.h" 8*4640Swnj #include "../inet/inet_systm.h" 9*4640Swnj #include "../inet/imp.h" 10*4640Swnj #include "../inet/ip.h" /* belongs before inet.h */ 11*4640Swnj #include "../inet/ip_icmp.h" 12*4640Swnj #include "../inet/tcp.h" 134495Swnj 14*4640Swnj int nosum = 0; 154495Swnj 16*4640Swnj struct ip *ip_reass(); 17*4640Swnj 18*4640Swnj /* 19*4640Swnj * Ip input routines. 20*4640Swnj */ 21*4640Swnj 22*4640Swnj /* 23*4640Swnj * Ip input routine. Checksum and byte swap header. If fragmented 24*4640Swnj * try to reassamble. If complete and fragment queue exists, discard. 25*4640Swnj * Process options. Pass to next level. 26*4640Swnj */ 27*4640Swnj ip_input(m0) 28*4640Swnj struct mbuf *m0; 294495Swnj { 30*4640Swnj register int i; 314495Swnj register struct ip *ip, *q; 324495Swnj register struct ipq *fp; 33*4640Swnj register struct mbuf *m = m0; 344495Swnj int hlen; 354495Swnj 364495Swnj COUNT(IP_INPUT); 37*4640Swnj /* 38*4640Swnj * Check header and byteswap. 39*4640Swnj */ 40*4640Swnj ip = mtod(m, struct ip *); 41*4640Swnj if ((hlen = ip->ip_hl << 2) > m->m_len) { 42*4640Swnj printf("ip hdr ovflo\n"); 43*4640Swnj m_freem(m); 444495Swnj return; 454495Swnj } 46*4640Swnj i = ip->ip_sum; 474495Swnj ip->ip_sum = 0; 48*4640Swnj #ifdef vax 49*4640Swnj if (hlen == sizeof (struct ip)) { 50*4640Swnj asm("movl r10,r0; movl (r0)+,r1; addl2 (r0)+,r1"); 51*4640Swnj asm("adwc (r0)+,r1; adwc (r0)+,r1; adwc (r0)+,r1"); 52*4640Swnj asm("adwc $0,r1; ashl $-16,r1,r0; addw2 r0,r1"); 53*4640Swnj asm("adwc $0,r1"); /* ### */ 54*4640Swnj asm("mcoml r1,r1; movzwl r1,r1; subl2 r1,r11"); 55*4640Swnj } else 56*4640Swnj #endif 57*4640Swnj i -= cksum(m, hlen); 58*4640Swnj if (i) { 594495Swnj netstat.ip_badsum++; 604495Swnj if (!nosum) { 61*4640Swnj m_freem(m); 62*4640Swnj return; 634495Swnj } 644495Swnj } 65*4640Swnj ip->ip_len = ntohs(ip->ip_len); 66*4640Swnj ip->ip_id = ntohs(ip->ip_id); 67*4640Swnj ip->ip_off = ntohs(ip->ip_off); 684495Swnj 694543Swnj /* 70*4640Swnj * Check that the amount of data in the buffers 71*4640Swnj * is as at least much as the IP header would have us expect. 72*4640Swnj * Trim mbufs if longer than we expect. 73*4640Swnj * Drop packet if shorter than we expect. 744543Swnj */ 75*4640Swnj i = 0; 76*4640Swnj for (; m != NULL; m = m->m_next) 774495Swnj i += m->m_len; 78*4640Swnj m = m0; 79*4640Swnj if (i != ip->ip_len) { 80*4640Swnj if (i < ip->ip_len) { 81*4640Swnj printf("ip_input: short packet\n"); 82*4640Swnj m_freem(m); 83*4640Swnj return; 84*4640Swnj } 85*4640Swnj m_adj(m, ip->ip_len - i); 864495Swnj } 874495Swnj 88*4640Swnj /* 89*4640Swnj * Process options and, if not destined for us, 90*4640Swnj * ship it on. 91*4640Swnj */ 924543Swnj if (hlen > sizeof (struct ip)) 93*4640Swnj ip_dooptions(ip, hlen); 94*4640Swnj if (ip->ip_dst.s_addr != n_lhost.s_addr) { 95*4640Swnj if (--ip->ip_ttl == 0) { 96*4640Swnj icmp_error(ip, ICMP_TIMXCEED); 974543Swnj return; 984495Swnj } 99*4640Swnj ip_output(dtom(ip)); 100*4640Swnj return; 1014543Swnj } 1024495Swnj 103*4640Swnj /* 104*4640Swnj * Look for queue of fragments 105*4640Swnj * of this datagram. 106*4640Swnj */ 107*4640Swnj for (fp = ipq.next; fp != &ipq; fp = fp->next) 108*4640Swnj if (ip->ip_id == fp->ipq_id && 109*4640Swnj ip->ip_src.s_addr == fp->ipq_src.s_addr && 110*4640Swnj ip->ip_dst.s_addr == fp->ipq_dst.s_addr && 111*4640Swnj ip->ip_p == fp->ipq_p) 112*4640Swnj goto found; 113*4640Swnj fp = 0; 114*4640Swnj found: 1154495Swnj 116*4640Swnj /* 117*4640Swnj * Adjust ip_len to not reflect header, 118*4640Swnj * set ip_mff if more fragments are expected, 119*4640Swnj * convert offset of this to bytes. 120*4640Swnj */ 121*4640Swnj ip->ip_len -= hlen; 122*4640Swnj ip->ip_mff = 0; 123*4640Swnj if (ip->ip_off & IP_MF) 124*4640Swnj ip->ip_mff = 1; 125*4640Swnj ip->ip_off <<= 3; 1264495Swnj 127*4640Swnj /* 128*4640Swnj * If datagram marked as having more fragments 129*4640Swnj * or if this is not the first fragment, 130*4640Swnj * attempt reassembly; if it succeeds, proceed. 131*4640Swnj */ 132*4640Swnj if (ip->ip_mff || ip->ip_off) { 133*4640Swnj ip = ip_reass(ip, fp); 134*4640Swnj if (ip == 0) 135*4640Swnj return; 136*4640Swnj hlen = ip->ip_hl << 2; 137*4640Swnj m = dtom(ip); 138*4640Swnj } else 139*4640Swnj if (fp) 140*4640Swnj (void) ip_freef(fp); 1414495Swnj 142*4640Swnj /* 143*4640Swnj * Switch out to protocol specific routine. 144*4640Swnj * SHOULD GO THROUGH PROTOCOL SWITCH TABLE 145*4640Swnj */ 146*4640Swnj switch (ip->ip_p) { 1474495Swnj 148*4640Swnj case IPPROTO_ICMP: 149*4640Swnj icmp_input(m); 150*4640Swnj break; 1514495Swnj 152*4640Swnj case IPPROTO_TCP: 153*4640Swnj if (hlen > sizeof (struct ip)) 154*4640Swnj ip_stripoptions(ip, hlen); 155*4640Swnj tcp_input(m); 156*4640Swnj break; 1574495Swnj 158*4640Swnj case IPPROTO_UDP: 159*4640Swnj if (hlen > sizeof (struct ip)) 160*4640Swnj ip_stripoptions(ip, hlen); 161*4640Swnj udp_input(m); 162*4640Swnj break; 1634495Swnj 164*4640Swnj default: 165*4640Swnj raw_input(m); 166*4640Swnj break; 167*4640Swnj } 168*4640Swnj } 1694495Swnj 170*4640Swnj /* 171*4640Swnj * Take incoming datagram fragment and try to 172*4640Swnj * reassamble it into whole datagram. If a chain for 173*4640Swnj * reassembly of this datagram already exists, then it 174*4640Swnj * is given as fp; otherwise have to make a chain. 175*4640Swnj */ 176*4640Swnj struct ip * 177*4640Swnj ip_reass(ip, fp) 178*4640Swnj register struct ip *ip; 179*4640Swnj register struct ipq *fp; 180*4640Swnj { 181*4640Swnj register struct mbuf *m = dtom(ip); 182*4640Swnj register struct ip *q; 183*4640Swnj struct mbuf *t; 184*4640Swnj int hlen = ip->ip_hl << 2; 185*4640Swnj int i, next; 1864543Swnj 187*4640Swnj /* 188*4640Swnj * Presence of header sizes in mbufs 189*4640Swnj * would confuse code below. 190*4640Swnj */ 191*4640Swnj m->m_off += hlen; 192*4640Swnj m->m_len -= hlen; 1934495Swnj 194*4640Swnj /* 195*4640Swnj * If first fragment to arrive, create a reassembly queue. 196*4640Swnj */ 197*4640Swnj if (fp == 0) { 198*4640Swnj if ((t = m_get(1)) == NULL) 199*4640Swnj goto dropfrag; 200*4640Swnj t->m_off = MMINOFF; 201*4640Swnj fp = mtod(t, struct ipq *); 202*4640Swnj insque(fp, &ipq); 203*4640Swnj fp->ipq_ttl = IPFRAGTTL; 204*4640Swnj fp->ipq_p = ip->ip_p; 205*4640Swnj fp->ipq_id = ip->ip_id; 206*4640Swnj fp->ipq_next = fp->ipq_prev = (struct ip *)fp; 207*4640Swnj fp->ipq_src = ip->ip_src; 208*4640Swnj fp->ipq_dst = ip->ip_dst; 209*4640Swnj } 2104495Swnj 211*4640Swnj /* 212*4640Swnj * Find a segment which begins after this one does. 213*4640Swnj */ 214*4640Swnj for (q = fp->ipq_next; q != (struct ip *)fp; q = q->ip_next) 215*4640Swnj if (q->ip_off > ip->ip_off) 216*4640Swnj break; 2174495Swnj 218*4640Swnj /* 219*4640Swnj * If there is a preceding segment, it may provide some of 220*4640Swnj * our data already. If so, drop the data from the incoming 221*4640Swnj * segment. If it provides all of our data, drop us. 222*4640Swnj */ 223*4640Swnj if (q->ip_prev != (struct ip *)fp) { 224*4640Swnj i = q->ip_prev->ip_off + q->ip_prev->ip_len - ip->ip_off; 225*4640Swnj if (i > 0) { 226*4640Swnj if (i >= ip->ip_len) 227*4640Swnj goto dropfrag; 228*4640Swnj m_adj(dtom(ip), i); 229*4640Swnj ip->ip_off += i; 230*4640Swnj ip->ip_len -= i; 231*4640Swnj } 232*4640Swnj } 2334543Swnj 234*4640Swnj /* 235*4640Swnj * While we overlap succeeding segments trim them or, 236*4640Swnj * if they are completely covered, dequeue them. 237*4640Swnj */ 238*4640Swnj while (q != (struct ip *)fp && ip->ip_off + ip->ip_len > q->ip_off) { 239*4640Swnj i = (ip->ip_off + ip->ip_len) - q->ip_off; 240*4640Swnj if (i < q->ip_len) { 241*4640Swnj q->ip_len -= i; 242*4640Swnj m_adj(dtom(q), i); 243*4640Swnj break; 2444495Swnj } 245*4640Swnj q = q->ip_next; 246*4640Swnj m_freem(dtom(q->ip_prev)); 247*4640Swnj ip_deq(q->ip_prev); 2484543Swnj } 2494495Swnj 250*4640Swnj /* 251*4640Swnj * Stick new segment in its place; 252*4640Swnj * check for complete reassembly. 253*4640Swnj */ 254*4640Swnj ip_enq(ip, q->ip_prev); 255*4640Swnj next = 0; 256*4640Swnj for (q = fp->ipq_next; q != (struct ip *)fp; q = q->ip_next) { 257*4640Swnj if (q->ip_off != next) 258*4640Swnj return (0); 259*4640Swnj next += q->ip_len; 260*4640Swnj } 261*4640Swnj if (q->ip_prev->ip_mff) 262*4640Swnj return (0); 2634495Swnj 264*4640Swnj /* 265*4640Swnj * Reassembly is complete; concatenate fragments. 266*4640Swnj */ 267*4640Swnj q = fp->ipq_next; 268*4640Swnj m = dtom(q); 269*4640Swnj t = m->m_next; 270*4640Swnj m->m_next = 0; 271*4640Swnj m_cat(m, t); 272*4640Swnj while ((q = q->ip_next) != (struct ip *)fp) 273*4640Swnj m_cat(m, dtom(q)); 2744495Swnj 275*4640Swnj /* 276*4640Swnj * Create header for new ip packet by 277*4640Swnj * modifying header of first packet; 278*4640Swnj * dequeue and discard fragment reassembly header. 279*4640Swnj * Make header visible. 280*4640Swnj */ 281*4640Swnj ip = fp->ipq_next; 282*4640Swnj ip->ip_len = next; 283*4640Swnj ip->ip_src = fp->ipq_src; 284*4640Swnj ip->ip_dst = fp->ipq_dst; 285*4640Swnj remque(fp); 286*4640Swnj m_free(dtom(fp)); 287*4640Swnj m = dtom(ip); 288*4640Swnj m->m_len += sizeof (struct ip); 289*4640Swnj m->m_off -= sizeof (struct ip); 290*4640Swnj return (ip); 2914495Swnj 292*4640Swnj dropfrag: 293*4640Swnj m_freem(m); 294*4640Swnj return (0); 2954495Swnj } 2964495Swnj 297*4640Swnj /* 298*4640Swnj * Free a fragment reassembly header and all 299*4640Swnj * associated datagrams. 300*4640Swnj */ 301*4640Swnj struct ipq * 302*4640Swnj ip_freef(fp) 303*4640Swnj struct ipq *fp; 3044495Swnj { 3054495Swnj register struct ip *q; 306*4640Swnj struct mbuf *m; 3074495Swnj 308*4640Swnj for (q = fp->ipq_next; q != (struct ip *)fp; q = q->ip_next) 309*4640Swnj m_freem(dtom(q)); 310*4640Swnj m = dtom(fp); 311*4640Swnj fp = fp->next; 312*4640Swnj remque(fp->prev); 313*4640Swnj m_free(m); 314*4640Swnj return (fp); 3154495Swnj } 3164495Swnj 317*4640Swnj /* 318*4640Swnj * Put an ip fragment on a reassembly chain. 319*4640Swnj * Like insque, but pointers in middle of structure. 320*4640Swnj */ 321*4640Swnj ip_enq(p, prev) 322*4640Swnj register struct ip *p; 323*4640Swnj register struct ip *prev; 3244495Swnj { 325*4640Swnj COUNT(IP_ENQ); 3264495Swnj 327*4640Swnj p->ip_prev = prev; 328*4640Swnj p->ip_next = prev->ip_next; 329*4640Swnj prev->ip_next->ip_prev = p; 330*4640Swnj prev->ip_next = p; 3314495Swnj } 3324495Swnj 333*4640Swnj /* 334*4640Swnj * To ip_enq as remque is to insque. 335*4640Swnj */ 336*4640Swnj ip_deq(p) 337*4640Swnj register struct ip *p; 338*4640Swnj { 339*4640Swnj COUNT(IP_DEQ); 3404495Swnj 341*4640Swnj p->ip_prev->ip_next = p->ip_next; 342*4640Swnj p->ip_next->ip_prev = p->ip_prev; 3434495Swnj } 3444495Swnj 345*4640Swnj /* 346*4640Swnj * IP timer processing; 347*4640Swnj * if a timer expires on a reassembly 348*4640Swnj * queue, discard it. 349*4640Swnj */ 350*4640Swnj ip_timeo() 3514495Swnj { 352*4640Swnj register struct ip *q; 3534495Swnj register struct ipq *fp; 354*4640Swnj int s = splnet(); 355*4640Swnj COUNT(IP_TIMEO); 3564495Swnj 357*4640Swnj for (fp = &ipq; fp; ) 358*4640Swnj if (--fp->ipq_ttl == 0) 359*4640Swnj fp = ip_freef(fp); 360*4640Swnj else 361*4640Swnj fp = fp->next; 362*4640Swnj timeout(ip_timeo, 0, hz); 363*4640Swnj splx(s); 3644495Swnj } 3654495Swnj 366*4640Swnj /* 367*4640Swnj * Do option processing on a datagram, 368*4640Swnj * possibly discarding it if bad options 369*4640Swnj * are encountered. 370*4640Swnj */ 371*4640Swnj ip_dooptions(ip) 372*4640Swnj struct ip *ip; 3734495Swnj { 374*4640Swnj register u_char *cp; 375*4640Swnj int opt, optlen, cnt, s; 376*4640Swnj struct inet_addr *sp; 3774495Swnj 378*4640Swnj cp = (u_char *)(ip + 1); 379*4640Swnj cnt = (ip->ip_hl << 2) - sizeof (struct ip); 380*4640Swnj for (; cnt > 0; cnt -= optlen, cp += optlen) { 381*4640Swnj opt = cp[0]; 382*4640Swnj if (opt == IPOPT_EOL) 383*4640Swnj break; 384*4640Swnj if (opt == IPOPT_NOP) 385*4640Swnj optlen = 1; 386*4640Swnj else 387*4640Swnj optlen = cp[1]; 388*4640Swnj switch (opt) { 3894495Swnj 390*4640Swnj default: 391*4640Swnj break; 3924495Swnj 393*4640Swnj case IPOPT_LSRR: 394*4640Swnj case IPOPT_SSRR: 395*4640Swnj if (cp[2] < 4 || cp[2] > optlen - 3) 396*4640Swnj break; 397*4640Swnj sp = (struct inet_addr *)(cp+cp[2]); 398*4640Swnj if (n_lhost.s_addr == *(u_long *)sp) { 399*4640Swnj if (opt == IPOPT_SSRR) { 400*4640Swnj /* make sure *sp directly accessible*/ 401*4640Swnj } 402*4640Swnj ip->ip_dst = *sp; 403*4640Swnj *sp = n_lhost; 404*4640Swnj cp[2] += 4; 405*4640Swnj } 406*4640Swnj break; 4074495Swnj 408*4640Swnj case IPOPT_TS: 409*4640Swnj if (cp[2] < 5) 410*4640Swnj goto bad; 411*4640Swnj if (cp[2] > cp[1] - 3) { 412*4640Swnj if ((cp[3] & 0xf0) == 0xf0) 413*4640Swnj goto bad; 414*4640Swnj cp[3] += 0x10; 4154495Swnj break; 416*4640Swnj } 417*4640Swnj sp = (struct inet_addr *)(cp+cp[2]); 418*4640Swnj switch (cp[3] & 0xf) { 4194495Swnj 420*4640Swnj case IPOPT_TS_TSONLY: 421*4640Swnj break; 422*4640Swnj 423*4640Swnj case IPOPT_TS_TSANDADDR: 424*4640Swnj if (cp[2] > cp[1] - 7) 425*4640Swnj goto bad; 426*4640Swnj break; 427*4640Swnj 428*4640Swnj case IPOPT_TS_PRESPEC: 429*4640Swnj if (*(u_long *)sp != n_lhost.s_addr) 430*4640Swnj break; 431*4640Swnj if (cp[2] > cp[1] - 7) 432*4640Swnj goto bad; 433*4640Swnj cp[1] += 4; 434*4640Swnj break; 435*4640Swnj 4364495Swnj default: 437*4640Swnj goto bad; 4384495Swnj } 439*4640Swnj s = spl6(); 440*4640Swnj *(int *)sp = (time % SECDAY) * 1000 + (lbolt*1000/hz); 441*4640Swnj splx(s); 442*4640Swnj cp[1] += 4; 443*4640Swnj } 4444495Swnj } 445*4640Swnj return (0); 446*4640Swnj bad: 447*4640Swnj /* SHOULD FORCE ICMP MESSAGE */ 448*4640Swnj return (-1); 4494495Swnj } 4504495Swnj 451*4640Swnj /* 452*4640Swnj * Strip out IP options, e.g. before passing 453*4640Swnj * to higher level protocol in the kernel. 454*4640Swnj */ 455*4640Swnj ip_stripoptions(ip) 456*4640Swnj struct ip *ip; 4574495Swnj { 458*4640Swnj register int i; 459*4640Swnj register struct mbuf *m; 460*4640Swnj char *op; 461*4640Swnj int olen; 462*4640Swnj COUNT(IP_OPT); 463*4640Swnj 464*4640Swnj olen = (ip->ip_hl<<2) - sizeof (struct ip); 465*4640Swnj op = (caddr_t)ip + olen; 466*4640Swnj m = dtom(++ip); 467*4640Swnj i = m->m_len - (sizeof (struct ip) + olen); 468*4640Swnj bcopy((caddr_t)ip+olen, (caddr_t)ip, i); 469*4640Swnj m->m_len -= i; 4704495Swnj } 4714543Swnj 472*4640Swnj /* stubs */ 473*4640Swnj 474*4640Swnj icmp_error(ip, error) 4754495Swnj { 476*4640Swnj 477*4640Swnj m_freem(dtom(ip)); 4784495Swnj } 4794495Swnj 480*4640Swnj icmp_input(m) 481*4640Swnj struct mbuf *m; 4824495Swnj { 4834495Swnj 484*4640Swnj printf("icmp_input %x\n", m); 485*4640Swnj } 4864495Swnj 487*4640Swnj udp_input(m) 488*4640Swnj struct mbuf *m; 489*4640Swnj { 4904495Swnj 491*4640Swnj printf("udp_input %x\n", m); 492*4640Swnj } 4934495Swnj 494*4640Swnj raw_input(m) 495*4640Swnj struct mbuf *m; 496*4640Swnj { 4974495Swnj 498*4640Swnj printf("raw_input %x\n", m); 4994495Swnj } 500