1*4543Swnj /* ip_input.c 1.4 81/10/18 */ 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" 7*4543Swnj #include "../h/systm.h" 84495Swnj 94495Swnj int nosum = 0; 104495Swnj 114495Swnj ip_input(mp) 124495Swnj struct mbuf *mp; 134495Swnj { 144495Swnj register struct ip *ip, *q; 154495Swnj register struct ipq *fp; 164495Swnj register struct mbuf *m; 174495Swnj register i; 184495Swnj struct mbuf *n; 194495Swnj int hlen; 204495Swnj struct ip *p, *savq; 214495Swnj struct ipq *ip_findf(); 224495Swnj 234495Swnj COUNT(IP_INPUT); 244495Swnj ip = (struct ip *)((int)mp + mp->m_off); /* ->ip hdr */ 254495Swnj 264495Swnj /* make sure header does not overflow mbuf */ 274495Swnj 284495Swnj if ((hlen = ip->ip_hl << 2) > mp->m_len) { 294495Swnj printf("ip header overflow\n"); 304495Swnj m_freem(mp); 314495Swnj return; 324495Swnj } 334495Swnj 344495Swnj i = (unsigned short)ip->ip_sum; 354495Swnj ip->ip_sum = 0; 364495Swnj 374495Swnj if (i != (unsigned short)cksum(mp, hlen)) { /* verify checksum */ 384495Swnj netstat.ip_badsum++; 394495Swnj if (!nosum) { 404495Swnj m_freem(mp); 414495Swnj return; 424495Swnj } 434495Swnj } 44*4543Swnj ip_bswap(ip); 45*4543Swnj fp = netcb.n_ip_head ? ip_findf(ip) : 0; 464495Swnj 47*4543Swnj /* 48*4543Swnj * adjust message length to remove any padding 49*4543Swnj */ 504495Swnj for (i=0, m=mp; m != NULL; m = m->m_next) { 514495Swnj i += m->m_len; 524495Swnj n = m; 534495Swnj } 544495Swnj i -= ip->ip_len; 554495Swnj 56*4543Swnj if (i != 0) 574495Swnj if (i > (int)n->m_len) 584495Swnj m_adj(mp, -i); 594495Swnj else 604495Swnj n->m_len -= i; 614495Swnj 624495Swnj ip->ip_len -= hlen; /* length of data */ 63*4543Swnj ip->ip_mff = ((ip->ip_off & ip_mf) ? TRUE : FALSE); 64*4543Swnj ip->ip_off <<= 3; 65*4543Swnj if (ip->ip_mff || ip->ip_off) 66*4543Swnj goto fragged; 67*4543Swnj if (fp != NULL) { 68*4543Swnj q = fp->iqx.ip_next; 69*4543Swnj while (q != (struct ip *)fp) { 70*4543Swnj m_freem(dtom(q)); 71*4543Swnj q = q->ip_next; 72*4543Swnj } 73*4543Swnj ip_freef(fp); /* free header */ 74*4543Swnj } 75*4543Swnj if (hlen > sizeof (struct ip)) 76*4543Swnj ip_opt(ip, hlen); 77*4543Swnj switch (ip->ip_p) { 784495Swnj 79*4543Swnj case TCPROTO: 80*4543Swnj tcp_input(mp); 81*4543Swnj break; 824495Swnj 83*4543Swnj default: 84*4543Swnj raw_input(mp, ip->ip_p, UIP); 85*4543Swnj break; 86*4543Swnj } 87*4543Swnj return; 884495Swnj 89*4543Swnj fragged: 90*4543Swnj /* -> msg buf beyond ip hdr if not first fragment */ 914495Swnj 92*4543Swnj if (ip->ip_off != 0) { 93*4543Swnj mp->m_off += hlen; 94*4543Swnj mp->m_len -= hlen; 95*4543Swnj } 964495Swnj 97*4543Swnj if (fp == NULL) { /* first fragment of datagram in */ 984495Swnj 99*4543Swnj /* set up reass.q header: enq it, set up as head of frag 100*4543Swnj chain, set a timer value, and move in ip header */ 1014495Swnj 102*4543Swnj if ((m = m_get(1)) == NULL) { /* allocate an mbuf */ 103*4543Swnj m_freem(mp); 104*4543Swnj return; 1054495Swnj } 1064495Swnj 107*4543Swnj fp = (struct ipq *)((int)m + MHEAD); 108*4543Swnj fp->iqx.ip_next = fp->iqx.ip_prev = (struct ip *)fp; 109*4543Swnj bcopy(ip, &fp->iqh, min(MLEN-28, hlen)); 110*4543Swnj fp->iqh.ip_ttl = MAXTTL; 111*4543Swnj fp->iq_next = NULL; 112*4543Swnj fp->iq_prev = netcb.n_ip_tail; 113*4543Swnj if (netcb.n_ip_head != NULL) 114*4543Swnj netcb.n_ip_tail->iq_next = fp; 115*4543Swnj else 116*4543Swnj netcb.n_ip_head = fp; 117*4543Swnj netcb.n_ip_tail = fp; 118*4543Swnj } 1194495Swnj 120*4543Swnj /*********************************************************** 121*4543Swnj * * 122*4543Swnj * merge fragment into reass.q * 123*4543Swnj * algorithm: match start and end bytes of new * 124*4543Swnj * fragment with fragments on the queue. if no * 125*4543Swnj * overlaps are found, add new frag. to the queue. * 126*4543Swnj * otherwise, adjust start and end of new frag. so no * 127*4543Swnj * overlap and add remainder to queue. if any * 128*4543Swnj * fragments are completely covered by the new one, or * 129*4543Swnj * if the new one is completely duplicated, free the * 130*4543Swnj * fragments. * 131*4543Swnj * * 132*4543Swnj ***********************************************************/ 1334495Swnj 134*4543Swnj q = fp->iqx.ip_next; /* -> top of reass. chain */ 135*4543Swnj ip->ip_end = ip->ip_off + ip->ip_len - 1; 1364495Swnj 137*4543Swnj /* skip frags which new doesn't overlap at end */ 1384495Swnj 139*4543Swnj while ((q != (struct ip *)fp) && (ip->ip_off > q->ip_end)) 140*4543Swnj q = q->ip_next; 1414495Swnj 142*4543Swnj if (q == (struct ip *)fp) /* frag at end of chain */ 143*4543Swnj ip_enq(ip, fp->iqx.ip_prev); 144*4543Swnj 145*4543Swnj else { 146*4543Swnj if (ip->ip_end < q->ip_off) /* frag doesn't overlap any on chain */ 147*4543Swnj ip_enq(ip, q->ip_prev); 1484495Swnj 149*4543Swnj /* new overlaps beginning of next frag only */ 1504495Swnj 151*4543Swnj else if (ip->ip_end < q->ip_end) { 152*4543Swnj if ((i = ip->ip_end - q->ip_off + 1) < ip->ip_len) { 153*4543Swnj ip->ip_len -= i; 154*4543Swnj ip->ip_end -= i; 155*4543Swnj m_adj(mp, -i); 1564495Swnj ip_enq(ip, q->ip_prev); 157*4543Swnj } else 158*4543Swnj m_freem(mp); 1594495Swnj 160*4543Swnj /* new overlaps end of previous frag */ 1614495Swnj 162*4543Swnj } else { 163*4543Swnj 164*4543Swnj savq = q; 165*4543Swnj if (ip->ip_off <= q->ip_off) { /* complete cover */ 166*4543Swnj savq = q->ip_prev; 167*4543Swnj ip_deq(q); 168*4543Swnj m_freem(dtom(q)); 169*4543Swnj 170*4543Swnj } else { /* overlap */ 171*4543Swnj if ((i = q->ip_end - ip->ip_off + 1) < ip->ip_len) { 172*4543Swnj ip->ip_off += i; 173*4543Swnj ip->ip_len -= i; 174*4543Swnj m_adj(mp, i); 1754495Swnj } else 176*4543Swnj ip->ip_len = 0; 177*4543Swnj } 1784495Swnj 179*4543Swnj /* new overlaps at beginning of successor frags */ 1804495Swnj 181*4543Swnj q = savq->ip_next; 182*4543Swnj while ((q != (struct ip *)fp) && (ip->ip_len != 0) && 183*4543Swnj (q->ip_off < ip->ip_end)) 1844495Swnj 185*4543Swnj /* complete cover */ 186*4543Swnj 187*4543Swnj if (q->ip_end <= ip->ip_end) { 188*4543Swnj p = q->ip_next; 1894495Swnj ip_deq(q); 1904495Swnj m_freem(dtom(q)); 191*4543Swnj q = p; 192*4543Swnj 193*4543Swnj } else { /* overlap */ 194*4543Swnj 195*4543Swnj if ((i = ip->ip_end - q->ip_off + 1) < ip->ip_len) { 196*4543Swnj ip->ip_len -= i; 197*4543Swnj ip->ip_end -= i; 198*4543Swnj m_adj(mp, -i); 1994495Swnj } else 2004495Swnj ip->ip_len = 0; 201*4543Swnj break; 2024495Swnj } 2034495Swnj 204*4543Swnj /* enqueue whatever is left of new before successors */ 2054495Swnj 206*4543Swnj if (ip->ip_len != 0) 207*4543Swnj ip_enq(ip, savq); 208*4543Swnj else 209*4543Swnj m_freem(mp); 2104495Swnj } 211*4543Swnj } 2124495Swnj 213*4543Swnj /* check for completed fragment reassembly */ 2144495Swnj 215*4543Swnj if ((i = ip_done(fp)) == 0) 216*4543Swnj return; 2174495Swnj 218*4543Swnj p = fp->iqx.ip_next; /* -> top mbuf */ 219*4543Swnj m = dtom(p); 220*4543Swnj p->ip_len = i; /* total data length */ 221*4543Swnj ip_opt(p, p->ip_hl << 2); /* option processing */ 222*4543Swnj ip_mergef(fp); /* cleanup frag chain */ 2234495Swnj 224*4543Swnj /* copy src/dst internet address to header mbuf */ 2254495Swnj 226*4543Swnj bcopy(&fp->iqh.ip_src, &p->ip_src, 2*sizeof(struct socket)); 227*4543Swnj ip_freef(fp); /* dequeue header */ 228*4543Swnj i = p->ip_p; 229*4543Swnj if (i == TCPROTO) 230*4543Swnj tcp_input(m); 231*4543Swnj else 232*4543Swnj raw_input(m, i, UIP); 2334495Swnj } 2344495Swnj 235*4543Swnj ip_done(p) 236*4543Swnj register struct ip *p; 2374495Swnj { 2384495Swnj register struct ip *q; 2394495Swnj register next; 2404495Swnj 2414495Swnj COUNT(IP_DONE); 242*4543Swnj q = p->ip_next; 2434495Swnj 2444495Swnj if (q->ip_off != 0) 2454495Swnj return(0); 2464495Swnj do { 2474495Swnj next = q->ip_end + 1; 2484495Swnj q = q->ip_next; 2494495Swnj } while ((q != p) && (q->ip_off == next)); 2504495Swnj 2514495Swnj if ((q == p) && !(q->ip_prev->ip_mff)) /* all fragments in */ 2524495Swnj return(next); /* total data length */ 2534495Swnj else 2544495Swnj return(0); 2554495Swnj } 2564495Swnj 2574495Swnj ip_mergef(p) /* merge mbufs of fragments of completed datagram */ 2584495Swnj register struct ip *p; 2594495Swnj { 2604495Swnj register struct mbuf *m, *n; 2614495Swnj register struct ip *q; 2624495Swnj int dummy; 2634495Swnj 2644495Swnj COUNT(IP_MERGEF); 2654495Swnj q = p->ip_next; /* -> bottom of reass chain */ 2664495Swnj n = (struct mbuf *)&dummy; /* dummy for init assignment */ 2674495Swnj 2684495Swnj while (q != p) { /* through chain */ 2694495Swnj 2704495Swnj n->m_next = m = dtom(q); 271*4543Swnj while (m != NULL) 2724495Swnj if (m->m_len != 0) { 2734495Swnj n = m; 2744495Swnj m = m->m_next; 2754495Swnj } else /* free null mbufs */ 2764495Swnj n->m_next = m = m_free(m); 2774495Swnj q = q->ip_next; 2784495Swnj } 2794495Swnj } 2804495Swnj 2814495Swnj 282*4543Swnj ip_freef(fp) /* deq and free reass.q header */ 2834495Swnj register struct ipq *fp; 2844495Swnj { 2854495Swnj COUNT(IP_FREEF); 286*4543Swnj if (fp->iq_prev != NULL) 287*4543Swnj (fp->iq_prev)->iq_next = fp->iq_next; 2884495Swnj else 289*4543Swnj netcb.n_ip_head = fp->iq_next; 290*4543Swnj if (fp->iq_next != NULL) 291*4543Swnj (fp->iq_next)->iq_prev = fp->iq_prev; 292*4543Swnj else 2934495Swnj netcb.n_ip_tail = fp->iq_prev; 2944495Swnj m_free(dtom(fp)); 2954495Swnj } 2964495Swnj 297*4543Swnj struct ipq * 298*4543Swnj ip_findf(p) /* does fragment reass chain w/this hdr exist? */ 2994495Swnj register struct ip *p; 3004495Swnj { 3014495Swnj register struct ipq *fp; 3024495Swnj 3034495Swnj COUNT(IP_FINDF); 3044495Swnj for (fp = netcb.n_ip_head; (fp != NULL && ( 3054495Swnj p->ip_src.s_addr != fp->iqh.ip_src.s_addr || 3064495Swnj p->ip_dst.s_addr != fp->iqh.ip_dst.s_addr || 3074495Swnj p->ip_id != fp->iqh.ip_id || 3084495Swnj p->ip_p != fp->iqh.ip_p)); fp = fp->iq_next); 3094495Swnj return(fp); 3104495Swnj } 3114495Swnj 3124495Swnj ip_opt(ip, hlen) /* process ip options */ 3134495Swnj struct ip *ip; 3144495Swnj int hlen; 3154495Swnj { 3164495Swnj register char *p, *q; 3174495Swnj register i, len; 3184495Swnj register struct mbuf *m; 3194495Swnj 3204495Swnj COUNT(IP_OPT); 3214495Swnj p = q = (char *)((int)ip + sizeof(struct ip)); /* -> at options */ 3224495Swnj 3234495Swnj if ((i = hlen - sizeof(struct ip)) > 0) { /* any options */ 3244495Swnj 3254495Swnj /* *** IP OPTION PROCESSING *** 3264495Swnj 3274495Swnj while (i > 0) 3284495Swnj 3294495Swnj switch (*q++) { 330*4543Swnj case 0: 331*4543Swnj case 1: 3324495Swnj i--; 3334495Swnj break; 3344495Swnj 3354495Swnj default: 3364495Swnj i -= *q; 3374495Swnj q += *q; 3384495Swnj } 3394495Swnj */ q += i; 3404495Swnj m = dtom(q); 3414495Swnj len = (int)m + m->m_off + m->m_len - (int)q; 3424495Swnj bcopy((caddr_t)q, (caddr_t)p, len); /* remove options */ 3434495Swnj m->m_len -= i; 3444495Swnj } 3454495Swnj } 3464495Swnj 3474495Swnj ip_enq(p, prev) 3484495Swnj register struct ip *p; 3494495Swnj register struct ip *prev; 3504495Swnj { 3514495Swnj COUNT(IP_ENQ); 3524495Swnj p->ip_prev = prev; 3534495Swnj p->ip_next = prev->ip_next; 3544495Swnj prev->ip_next->ip_prev = p; 3554495Swnj prev->ip_next = p; 3564495Swnj } 357*4543Swnj 3584495Swnj ip_deq(p) 3594495Swnj register struct ip *p; 3604495Swnj { 3614495Swnj COUNT(IP_DEQ); 3624495Swnj p->ip_prev->ip_next = p->ip_next; 3634495Swnj p->ip_next->ip_prev = p->ip_prev; 3644495Swnj } 3654495Swnj 3664495Swnj ip_timeo() /* frag reass.q timeout routine */ 3674495Swnj { 3684495Swnj register struct ip *q; 3694495Swnj register struct ipq *fp; 3704525Swnj int s = splnet(); 3714495Swnj 3724495Swnj COUNT(IP_TIMEO); 373*4543Swnj timeout(ip_timeo, 0, hz); /* reschedule every second */ 3744495Swnj 3754495Swnj /* search through reass.q */ 3764495Swnj 377*4543Swnj for (fp = netcb.n_ip_head; fp != NULL; fp = fp->iq_next) 3784495Swnj 3794495Swnj if (--(fp->iqx.ip_ttl) == 0) { /* time to die */ 3804495Swnj 3814495Swnj q = fp->iqx.ip_next; /* free mbufs assoc. w/chain */ 382*4543Swnj while (q != (struct ip *)fp) { 383*4543Swnj m_freem(dtom(q)); 384*4543Swnj q = q->ip_next; 385*4543Swnj } 386*4543Swnj ip_freef(fp); /* free header */ 3874495Swnj } 3884525Swnj splx(s); 3894495Swnj } 390