1*4495Swnj /* ip_input.c 1.1 81/10/14 */ 2*4495Swnj #include "../h/param.h" 3*4495Swnj #include "../bbnnet/net.h" 4*4495Swnj #include "../bbnnet/tcp.h" 5*4495Swnj #include "../bbnnet/ip.h" 6*4495Swnj #include "../bbnnet/ucb.h" 7*4495Swnj 8*4495Swnj /***************************************************************************** 9*4495Swnj * * 10*4495Swnj * ip level input routine: called from 1822 level upon receipt * 11*4495Swnj * of an internet datagram or fragment. this routine does * 12*4495Swnj * fragment reassembly, if necessary, and passes completed * 13*4495Swnj * datagrams to higher level protocol processing routines on * 14*4495Swnj * the basis of the ip header protocol field. it is passed a * 15*4495Swnj * pointer to an mbuf chain containing the datagram/fragment. * 16*4495Swnj * the mbuf offset/length are set to point at the ip header. * 17*4495Swnj * * 18*4495Swnj *****************************************************************************/ 19*4495Swnj 20*4495Swnj int nosum = 0; 21*4495Swnj 22*4495Swnj ip_input(mp) 23*4495Swnj struct mbuf *mp; 24*4495Swnj { 25*4495Swnj register struct ip *ip, *q; 26*4495Swnj register struct ipq *fp; 27*4495Swnj register struct mbuf *m; 28*4495Swnj register i; 29*4495Swnj struct mbuf *n; 30*4495Swnj int hlen; 31*4495Swnj struct ip *p, *savq; 32*4495Swnj struct ipq *ip_findf(); 33*4495Swnj 34*4495Swnj COUNT(IP_INPUT); 35*4495Swnj ip = (struct ip *)((int)mp + mp->m_off); /* ->ip hdr */ 36*4495Swnj 37*4495Swnj /* make sure header does not overflow mbuf */ 38*4495Swnj 39*4495Swnj if ((hlen = ip->ip_hl << 2) > mp->m_len) { 40*4495Swnj printf("ip header overflow\n"); 41*4495Swnj m_freem(mp); 42*4495Swnj return; 43*4495Swnj } 44*4495Swnj 45*4495Swnj i = (unsigned short)ip->ip_sum; 46*4495Swnj ip->ip_sum = 0; 47*4495Swnj 48*4495Swnj if (i != (unsigned short)cksum(mp, hlen)) { /* verify checksum */ 49*4495Swnj netstat.ip_badsum++; 50*4495Swnj if (!nosum) { 51*4495Swnj m_freem(mp); 52*4495Swnj return; 53*4495Swnj } 54*4495Swnj } 55*4495Swnj 56*4495Swnj ip_bswap(ip); /* byte-swap header */ 57*4495Swnj 58*4495Swnj netcb.n_ip_lock++; /* lock frag reass.q */ 59*4495Swnj fp = ip_findf(ip); /* look for chain on reass.q with this hdr */ 60*4495Swnj 61*4495Swnj /* adjust message length to remove any padding */ 62*4495Swnj 63*4495Swnj for (i=0, m=mp; m != NULL; m = m->m_next) { 64*4495Swnj i += m->m_len; 65*4495Swnj n = m; 66*4495Swnj } 67*4495Swnj i -= ip->ip_len; 68*4495Swnj 69*4495Swnj if (i != 0) 70*4495Swnj if (i > (int)n->m_len) 71*4495Swnj m_adj(mp, -i); 72*4495Swnj else 73*4495Swnj n->m_len -= i; 74*4495Swnj 75*4495Swnj ip->ip_len -= hlen; /* length of data */ 76*4495Swnj ip->ip_mff = ((ip->ip_off & ip_mf) ? TRUE : FALSE); 77*4495Swnj ip->ip_off <<= 3; 78*4495Swnj if (!ip->ip_mff && ip->ip_off == 0) { /* not fragmented */ 79*4495Swnj 80*4495Swnj if (fp != NULL) { /* free existing reass.q chain */ 81*4495Swnj 82*4495Swnj q = fp->iqx.ip_next; /* free mbufs assoc. w/chain */ 83*4495Swnj while (q != (struct ip *)fp) { 84*4495Swnj m_freem(dtom(q)); 85*4495Swnj q = q->ip_next; 86*4495Swnj } 87*4495Swnj ip_freef(fp); /* free header */ 88*4495Swnj } 89*4495Swnj netcb.n_ip_lock = 0; 90*4495Swnj 91*4495Swnj ip_opt(ip, hlen); /* option processing */ 92*4495Swnj i = ip->ip_p; 93*4495Swnj 94*4495Swnj /* pass to next level */ 95*4495Swnj 96*4495Swnj if (i == TCPROTO) 97*4495Swnj tcp_input(mp); 98*4495Swnj else 99*4495Swnj raw_input(mp, i, UIP); 100*4495Swnj 101*4495Swnj } else { /* fragmented */ 102*4495Swnj 103*4495Swnj /* -> msg buf beyond ip hdr if not first fragment */ 104*4495Swnj 105*4495Swnj if (ip->ip_off != 0) { 106*4495Swnj mp->m_off += hlen; 107*4495Swnj mp->m_len -= hlen; 108*4495Swnj } 109*4495Swnj 110*4495Swnj if (fp == NULL) { /* first fragment of datagram in */ 111*4495Swnj 112*4495Swnj /* set up reass.q header: enq it, set up as head of frag 113*4495Swnj chain, set a timer value, and move in ip header */ 114*4495Swnj 115*4495Swnj if ((m = m_get(1)) == NULL) { /* allocate an mbuf */ 116*4495Swnj m_freem(mp); 117*4495Swnj return; 118*4495Swnj } 119*4495Swnj 120*4495Swnj fp = (struct ipq *)((int)m + MHEAD); 121*4495Swnj fp->iqx.ip_next = fp->iqx.ip_prev = (struct ip *)fp; 122*4495Swnj bcopy(ip, &fp->iqh, min(MLEN-28, hlen)); 123*4495Swnj fp->iqh.ip_ttl = MAXTTL; 124*4495Swnj fp->iq_next = NULL; 125*4495Swnj fp->iq_prev = netcb.n_ip_tail; 126*4495Swnj if (netcb.n_ip_head != NULL) 127*4495Swnj netcb.n_ip_tail->iq_next = fp; 128*4495Swnj else 129*4495Swnj netcb.n_ip_head = fp; 130*4495Swnj netcb.n_ip_tail = fp; 131*4495Swnj } 132*4495Swnj 133*4495Swnj /*********************************************************** 134*4495Swnj * * 135*4495Swnj * merge fragment into reass.q * 136*4495Swnj * algorithm: match start and end bytes of new * 137*4495Swnj * fragment with fragments on the queue. if no * 138*4495Swnj * overlaps are found, add new frag. to the queue. * 139*4495Swnj * otherwise, adjust start and end of new frag. so no * 140*4495Swnj * overlap and add remainder to queue. if any * 141*4495Swnj * fragments are completely covered by the new one, or * 142*4495Swnj * if the new one is completely duplicated, free the * 143*4495Swnj * fragments. * 144*4495Swnj * * 145*4495Swnj ***********************************************************/ 146*4495Swnj 147*4495Swnj q = fp->iqx.ip_next; /* -> top of reass. chain */ 148*4495Swnj ip->ip_end = ip->ip_off + ip->ip_len - 1; 149*4495Swnj 150*4495Swnj /* skip frags which new doesn't overlap at end */ 151*4495Swnj 152*4495Swnj while ((q != (struct ip *)fp) && (ip->ip_off > q->ip_end)) 153*4495Swnj q = q->ip_next; 154*4495Swnj 155*4495Swnj if (q == (struct ip *)fp) /* frag at end of chain */ 156*4495Swnj ip_enq(ip, fp->iqx.ip_prev); 157*4495Swnj 158*4495Swnj else { 159*4495Swnj if (ip->ip_end < q->ip_off) /* frag doesn't overlap any on chain */ 160*4495Swnj ip_enq(ip, q->ip_prev); 161*4495Swnj 162*4495Swnj /* new overlaps beginning of next frag only */ 163*4495Swnj 164*4495Swnj else if (ip->ip_end < q->ip_end) { 165*4495Swnj if ((i = ip->ip_end - q->ip_off + 1) < ip->ip_len) { 166*4495Swnj ip->ip_len -= i; 167*4495Swnj ip->ip_end -= i; 168*4495Swnj m_adj(mp, -i); 169*4495Swnj ip_enq(ip, q->ip_prev); 170*4495Swnj } else 171*4495Swnj m_freem(mp); 172*4495Swnj 173*4495Swnj /* new overlaps end of previous frag */ 174*4495Swnj 175*4495Swnj } else { 176*4495Swnj 177*4495Swnj savq = q; 178*4495Swnj if (ip->ip_off <= q->ip_off) { /* complete cover */ 179*4495Swnj savq = q->ip_prev; 180*4495Swnj ip_deq(q); 181*4495Swnj m_freem(dtom(q)); 182*4495Swnj 183*4495Swnj } else { /* overlap */ 184*4495Swnj if ((i = q->ip_end - ip->ip_off + 1) < ip->ip_len) { 185*4495Swnj ip->ip_off += i; 186*4495Swnj ip->ip_len -= i; 187*4495Swnj m_adj(mp, i); 188*4495Swnj } else 189*4495Swnj ip->ip_len = 0; 190*4495Swnj } 191*4495Swnj 192*4495Swnj /* new overlaps at beginning of successor frags */ 193*4495Swnj 194*4495Swnj q = savq->ip_next; 195*4495Swnj while ((q != (struct ip *)fp) && (ip->ip_len != 0) && 196*4495Swnj (q->ip_off < ip->ip_end)) 197*4495Swnj 198*4495Swnj /* complete cover */ 199*4495Swnj 200*4495Swnj if (q->ip_end <= ip->ip_end) { 201*4495Swnj p = q->ip_next; 202*4495Swnj ip_deq(q); 203*4495Swnj m_freem(dtom(q)); 204*4495Swnj q = p; 205*4495Swnj 206*4495Swnj } else { /* overlap */ 207*4495Swnj 208*4495Swnj if ((i = ip->ip_end - q->ip_off + 1) < ip->ip_len) { 209*4495Swnj ip->ip_len -= i; 210*4495Swnj ip->ip_end -= i; 211*4495Swnj m_adj(mp, -i); 212*4495Swnj } else 213*4495Swnj ip->ip_len = 0; 214*4495Swnj break; 215*4495Swnj } 216*4495Swnj 217*4495Swnj /* enqueue whatever is left of new before successors */ 218*4495Swnj 219*4495Swnj if (ip->ip_len != 0) 220*4495Swnj ip_enq(ip, savq); 221*4495Swnj else 222*4495Swnj m_freem(mp); 223*4495Swnj } 224*4495Swnj } 225*4495Swnj 226*4495Swnj /* check for completed fragment reassembly */ 227*4495Swnj 228*4495Swnj if ((i = ip_done(fp)) > 0) { 229*4495Swnj 230*4495Swnj p = fp->iqx.ip_next; /* -> top mbuf */ 231*4495Swnj m = dtom(p); 232*4495Swnj p->ip_len = i; /* total data length */ 233*4495Swnj ip_opt(p, p->ip_hl << 2); /* option processing */ 234*4495Swnj ip_mergef(fp); /* cleanup frag chain */ 235*4495Swnj 236*4495Swnj /* copy src/dst internet address to header mbuf */ 237*4495Swnj 238*4495Swnj bcopy(&fp->iqh.ip_src, &p->ip_src, 2*sizeof(struct socket)); 239*4495Swnj ip_freef(fp); /* dequeue header */ 240*4495Swnj netcb.n_ip_lock = 0; 241*4495Swnj 242*4495Swnj /* call next level with completed datagram */ 243*4495Swnj 244*4495Swnj i = p->ip_p; 245*4495Swnj if (i == TCPROTO) 246*4495Swnj tcp_input(m); 247*4495Swnj else 248*4495Swnj raw_input(m, i, UIP); 249*4495Swnj } else 250*4495Swnj netcb.n_ip_lock = 0; 251*4495Swnj } 252*4495Swnj } 253*4495Swnj 254*4495Swnj 255*4495Swnj ip_done(p) /* check to see if fragment reassembly is complete */ 256*4495Swnj register struct ip *p; 257*4495Swnj { 258*4495Swnj register struct ip *q; 259*4495Swnj register next; 260*4495Swnj 261*4495Swnj COUNT(IP_DONE); 262*4495Swnj q = p->ip_next; 263*4495Swnj 264*4495Swnj if (q->ip_off != 0) 265*4495Swnj return(0); 266*4495Swnj do { 267*4495Swnj next = q->ip_end + 1; 268*4495Swnj q = q->ip_next; 269*4495Swnj } while ((q != p) && (q->ip_off == next)); 270*4495Swnj 271*4495Swnj if ((q == p) && !(q->ip_prev->ip_mff)) /* all fragments in */ 272*4495Swnj return(next); /* total data length */ 273*4495Swnj else 274*4495Swnj return(0); 275*4495Swnj } 276*4495Swnj 277*4495Swnj ip_mergef(p) /* merge mbufs of fragments of completed datagram */ 278*4495Swnj register struct ip *p; 279*4495Swnj { 280*4495Swnj register struct mbuf *m, *n; 281*4495Swnj register struct ip *q; 282*4495Swnj int dummy; 283*4495Swnj 284*4495Swnj COUNT(IP_MERGEF); 285*4495Swnj q = p->ip_next; /* -> bottom of reass chain */ 286*4495Swnj n = (struct mbuf *)&dummy; /* dummy for init assignment */ 287*4495Swnj 288*4495Swnj while (q != p) { /* through chain */ 289*4495Swnj 290*4495Swnj n->m_next = m = dtom(q); 291*4495Swnj while (m != NULL) 292*4495Swnj if (m->m_len != 0) { 293*4495Swnj n = m; 294*4495Swnj m = m->m_next; 295*4495Swnj } else /* free null mbufs */ 296*4495Swnj n->m_next = m = m_free(m); 297*4495Swnj q = q->ip_next; 298*4495Swnj } 299*4495Swnj } 300*4495Swnj 301*4495Swnj 302*4495Swnj ip_freef(fp) /* deq and free reass.q header */ 303*4495Swnj register struct ipq *fp; 304*4495Swnj { 305*4495Swnj COUNT(IP_FREEF); 306*4495Swnj if (fp->iq_prev != NULL) 307*4495Swnj (fp->iq_prev)->iq_next = fp->iq_next; 308*4495Swnj else 309*4495Swnj netcb.n_ip_head = fp->iq_next; 310*4495Swnj if (fp->iq_next != NULL) 311*4495Swnj (fp->iq_next)->iq_prev = fp->iq_prev; 312*4495Swnj else 313*4495Swnj netcb.n_ip_tail = fp->iq_prev; 314*4495Swnj m_free(dtom(fp)); 315*4495Swnj } 316*4495Swnj 317*4495Swnj struct ipq *ip_findf(p) /* does fragment reass chain w/this hdr exist? */ 318*4495Swnj register struct ip *p; 319*4495Swnj { 320*4495Swnj register struct ipq *fp; 321*4495Swnj 322*4495Swnj COUNT(IP_FINDF); 323*4495Swnj for (fp = netcb.n_ip_head; (fp != NULL && ( 324*4495Swnj p->ip_src.s_addr != fp->iqh.ip_src.s_addr || 325*4495Swnj p->ip_dst.s_addr != fp->iqh.ip_dst.s_addr || 326*4495Swnj p->ip_id != fp->iqh.ip_id || 327*4495Swnj p->ip_p != fp->iqh.ip_p)); fp = fp->iq_next); 328*4495Swnj return(fp); 329*4495Swnj } 330*4495Swnj 331*4495Swnj ip_opt(ip, hlen) /* process ip options */ 332*4495Swnj struct ip *ip; 333*4495Swnj int hlen; 334*4495Swnj { 335*4495Swnj register char *p, *q; 336*4495Swnj register i, len; 337*4495Swnj register struct mbuf *m; 338*4495Swnj 339*4495Swnj COUNT(IP_OPT); 340*4495Swnj p = q = (char *)((int)ip + sizeof(struct ip)); /* -> at options */ 341*4495Swnj 342*4495Swnj if ((i = hlen - sizeof(struct ip)) > 0) { /* any options */ 343*4495Swnj 344*4495Swnj /* *** IP OPTION PROCESSING *** 345*4495Swnj 346*4495Swnj while (i > 0) 347*4495Swnj 348*4495Swnj switch (*q++) { 349*4495Swnj case 0: 350*4495Swnj case 1: 351*4495Swnj i--; 352*4495Swnj break; 353*4495Swnj 354*4495Swnj default: 355*4495Swnj i -= *q; 356*4495Swnj q += *q; 357*4495Swnj } 358*4495Swnj */ q += i; 359*4495Swnj m = dtom(q); 360*4495Swnj len = (int)m + m->m_off + m->m_len - (int)q; 361*4495Swnj bcopy((caddr_t)q, (caddr_t)p, len); /* remove options */ 362*4495Swnj m->m_len -= i; 363*4495Swnj } 364*4495Swnj } 365*4495Swnj 366*4495Swnj ip_enq(p, prev) 367*4495Swnj register struct ip *p; 368*4495Swnj register struct ip *prev; 369*4495Swnj { 370*4495Swnj COUNT(IP_ENQ); 371*4495Swnj p->ip_prev = prev; 372*4495Swnj p->ip_next = prev->ip_next; 373*4495Swnj prev->ip_next->ip_prev = p; 374*4495Swnj prev->ip_next = p; 375*4495Swnj } 376*4495Swnj 377*4495Swnj ip_deq(p) 378*4495Swnj register struct ip *p; 379*4495Swnj { 380*4495Swnj COUNT(IP_DEQ); 381*4495Swnj p->ip_prev->ip_next = p->ip_next; 382*4495Swnj p->ip_next->ip_prev = p->ip_prev; 383*4495Swnj } 384*4495Swnj 385*4495Swnj ip_bswap(p) /* byte swap ip header */ 386*4495Swnj register struct ip *p; 387*4495Swnj { 388*4495Swnj COUNT(IP_BSWAP); 389*4495Swnj p->ip_len = ntohs(p->ip_len); 390*4495Swnj p->ip_id = ntohs(p->ip_id); 391*4495Swnj p->ip_off = ntohs(p->ip_off); 392*4495Swnj } 393*4495Swnj 394*4495Swnj ip_timeo() /* frag reass.q timeout routine */ 395*4495Swnj { 396*4495Swnj register struct ip *q; 397*4495Swnj register struct ipq *fp; 398*4495Swnj 399*4495Swnj COUNT(IP_TIMEO); 400*4495Swnj timeout(ip_timeo, 0, 60); /* reschedule every second */ 401*4495Swnj 402*4495Swnj if (netcb.n_ip_lock) /* reass.q must not be in use */ 403*4495Swnj return; 404*4495Swnj 405*4495Swnj /* search through reass.q */ 406*4495Swnj 407*4495Swnj for (fp = netcb.n_ip_head; fp != NULL; fp = fp->iq_next) 408*4495Swnj 409*4495Swnj if (--(fp->iqx.ip_ttl) == 0) { /* time to die */ 410*4495Swnj 411*4495Swnj q = fp->iqx.ip_next; /* free mbufs assoc. w/chain */ 412*4495Swnj while (q != (struct ip *)fp) { 413*4495Swnj m_freem(dtom(q)); 414*4495Swnj q = q->ip_next; 415*4495Swnj } 416*4495Swnj ip_freef(fp); /* free header */ 417*4495Swnj } 418*4495Swnj } 419