1 /* ip_input.c 1.27 81/12/12 */ 2 3 #include "../h/param.h" 4 #include "../h/systm.h" 5 #include "../h/clock.h" 6 #include "../h/mbuf.h" 7 #include "../h/protosw.h" 8 #include "../h/socket.h" 9 #include "../net/in.h" 10 #include "../net/in_systm.h" 11 #include "../net/if.h" 12 #include "../net/ip.h" /* belongs before in.h */ 13 #include "../net/ip_var.h" 14 #include "../net/ip_icmp.h" 15 #include "../net/tcp.h" 16 17 u_char ip_protox[IPPROTO_MAX]; 18 19 /* 20 * IP initialization: fill in IP protocol switch table. 21 * All protocols not implemented in kernel go to raw IP protocol handler. 22 */ 23 ip_init() 24 { 25 register struct protosw *pr; 26 register int i; 27 28 COUNT(IP_INIT); 29 pr = pffindproto(PF_INET, IPPROTO_RAW); 30 if (pr == 0) 31 panic("ip_init"); 32 for (i = 0; i < IPPROTO_MAX; i++) 33 ip_protox[i] = pr - protosw; 34 for (pr = protosw; pr <= protoswLAST; pr++) 35 if (pr->pr_family == PF_INET && 36 pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) 37 ip_protox[pr->pr_protocol] = pr - protosw; 38 ipq.next = ipq.prev = &ipq; 39 ip_id = time & 0xffff; 40 } 41 42 u_char ipcksum = 1; 43 struct ip *ip_reass(); 44 45 /* 46 * Ip input routine. Checksum and byte swap header. If fragmented 47 * try to reassamble. If complete and fragment queue exists, discard. 48 * Process options. Pass to next level. 49 */ 50 ipintr() 51 { 52 register struct ip *ip; 53 register struct mbuf *m; 54 struct mbuf *m0, *mopt; 55 register int i; 56 register struct ipq *fp; 57 int hlen, s; 58 59 COUNT(IPINTR); 60 next: 61 /* 62 * Get next datagram off input queue and get IP header 63 * in first mbuf. 64 */ 65 s = splimp(); 66 IF_DEQUEUE(&ipintrq, m); 67 splx(s); 68 if (m == 0) 69 return; 70 if (m->m_len < sizeof (struct ip) && 71 m_pullup(m, sizeof (struct ip)) == 0) 72 goto bad; 73 ip = mtod(m, struct ip *); 74 if ((hlen = ip->ip_hl << 2) > m->m_len) { 75 if (m_pullup(m, hlen) == 0) 76 goto bad; 77 ip = mtod(m, struct ip *); 78 } 79 if (ipcksum) 80 if (ip->ip_sum = in_cksum(m, hlen)) { 81 printf("ip_sum %x\n", ip->ip_sum); /* XXX */ 82 ipstat.ips_badsum++; 83 goto bad; 84 } 85 86 #if vax 87 /* 88 * Convert fields to host representation. 89 */ 90 ip->ip_len = ntohs((u_short)ip->ip_len); 91 ip->ip_id = ntohs(ip->ip_id); 92 ip->ip_off = ntohs((u_short)ip->ip_off); 93 #endif 94 95 /* 96 * Check that the amount of data in the buffers 97 * is as at least much as the IP header would have us expect. 98 * Trim mbufs if longer than we expect. 99 * Drop packet if shorter than we expect. 100 */ 101 i = 0; 102 m0 = m; 103 for (; m != NULL; m = m->m_next) 104 i += m->m_len; 105 m = m0; 106 if (i != ip->ip_len) { 107 if (i < ip->ip_len) { 108 ipstat.ips_tooshort++; 109 goto bad; 110 } 111 m_adj(m, ip->ip_len - i); 112 } 113 114 /* 115 * Process options and, if not destined for us, 116 * ship it on. 117 */ 118 if (hlen > sizeof (struct ip)) 119 ip_dooptions(ip); 120 if (ifnet && ip->ip_dst.s_addr != ifnet->if_addr.s_addr && 121 if_ifwithaddr(ip->ip_dst) == 0) { 122 if (--ip->ip_ttl == 0) { 123 icmp_error(ip, ICMP_TIMXCEED, 0); 124 goto next; 125 } 126 mopt = m_get(M_DONTWAIT); 127 if (mopt == 0) 128 goto bad; 129 ip_stripoptions(ip, mopt); 130 (void) ip_output(m0, mopt); 131 goto next; 132 } 133 134 /* 135 * Look for queue of fragments 136 * of this datagram. 137 */ 138 for (fp = ipq.next; fp != &ipq; fp = fp->next) 139 if (ip->ip_id == fp->ipq_id && 140 ip->ip_src.s_addr == fp->ipq_src.s_addr && 141 ip->ip_dst.s_addr == fp->ipq_dst.s_addr && 142 ip->ip_p == fp->ipq_p) 143 goto found; 144 fp = 0; 145 found: 146 147 /* 148 * Adjust ip_len to not reflect header, 149 * set ip_mff if more fragments are expected, 150 * convert offset of this to bytes. 151 */ 152 ip->ip_len -= hlen; 153 ((struct ipasfrag *)ip)->ipf_mff = 0; 154 if (ip->ip_off & IP_MF) 155 ((struct ipasfrag *)ip)->ipf_mff = 1; 156 ip->ip_off <<= 3; 157 158 /* 159 * If datagram marked as having more fragments 160 * or if this is not the first fragment, 161 * attempt reassembly; if it succeeds, proceed. 162 */ 163 if (((struct ipasfrag *)ip)->ipf_mff || ip->ip_off) { 164 ip = ip_reass((struct ipasfrag *)ip, fp); 165 if (ip == 0) 166 goto next; 167 hlen = ip->ip_hl << 2; 168 m = dtom(ip); 169 } else 170 if (fp) 171 (void) ip_freef(fp); 172 173 /* 174 * Switch out to protocol's input routine. 175 */ 176 (*protosw[ip_protox[ip->ip_p]].pr_input)(m); 177 goto next; 178 bad: 179 m_freem(m); 180 goto next; 181 } 182 183 /* 184 * Take incoming datagram fragment and try to 185 * reassemble it into whole datagram. If a chain for 186 * reassembly of this datagram already exists, then it 187 * is given as fp; otherwise have to make a chain. 188 */ 189 struct ip * 190 ip_reass(ip, fp) 191 register struct ipasfrag *ip; 192 register struct ipq *fp; 193 { 194 register struct mbuf *m = dtom(ip); 195 register struct ipasfrag *q; 196 struct mbuf *t; 197 int hlen = ip->ip_hl << 2; 198 int i, next; 199 COUNT(IP_REASS); 200 201 /* 202 * Presence of header sizes in mbufs 203 * would confuse code below. 204 */ 205 m->m_off += hlen; 206 m->m_len -= hlen; 207 208 /* 209 * If first fragment to arrive, create a reassembly queue. 210 */ 211 if (fp == 0) { 212 if ((t = m_get(1)) == NULL) 213 goto dropfrag; 214 t->m_off = MMINOFF; 215 fp = mtod(t, struct ipq *); 216 insque(fp, &ipq); 217 fp->ipq_ttl = IPFRAGTTL; 218 fp->ipq_p = ip->ip_p; 219 fp->ipq_id = ip->ip_id; 220 fp->ipq_next = fp->ipq_prev = (struct ipasfrag *)fp; 221 fp->ipq_src = ((struct ip *)ip)->ip_src; 222 fp->ipq_dst = ((struct ip *)ip)->ip_dst; 223 q = (struct ipasfrag *)fp; 224 goto insert; 225 } 226 227 /* 228 * Find a segment which begins after this one does. 229 */ 230 for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) 231 if (q->ip_off > ip->ip_off) 232 break; 233 234 /* 235 * If there is a preceding segment, it may provide some of 236 * our data already. If so, drop the data from the incoming 237 * segment. If it provides all of our data, drop us. 238 */ 239 if (q->ipf_prev != (struct ipasfrag *)fp) { 240 i = q->ipf_prev->ip_off + q->ipf_prev->ip_len - ip->ip_off; 241 if (i > 0) { 242 if (i >= ip->ip_len) 243 goto dropfrag; 244 m_adj(dtom(ip), i); 245 ip->ip_off += i; 246 ip->ip_len -= i; 247 } 248 } 249 250 /* 251 * While we overlap succeeding segments trim them or, 252 * if they are completely covered, dequeue them. 253 */ 254 while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) { 255 i = (ip->ip_off + ip->ip_len) - q->ip_off; 256 if (i < q->ip_len) { 257 q->ip_len -= i; 258 m_adj(dtom(q), i); 259 break; 260 } 261 q = q->ipf_next; 262 m_freem(dtom(q->ipf_prev)); 263 ip_deq(q->ipf_prev); 264 } 265 266 insert: 267 /* 268 * Stick new segment in its place; 269 * check for complete reassembly. 270 */ 271 ip_enq(ip, q->ipf_prev); 272 next = 0; 273 for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) { 274 if (q->ip_off != next) 275 return (0); 276 next += q->ip_len; 277 } 278 if (q->ipf_prev->ipf_mff) 279 return (0); 280 281 /* 282 * Reassembly is complete; concatenate fragments. 283 */ 284 q = fp->ipq_next; 285 m = dtom(q); 286 t = m->m_next; 287 m->m_next = 0; 288 m_cat(m, t); 289 while ((q = q->ipf_next) != (struct ipasfrag *)fp) 290 m_cat(m, dtom(q)); 291 292 /* 293 * Create header for new ip packet by 294 * modifying header of first packet; 295 * dequeue and discard fragment reassembly header. 296 * Make header visible. 297 */ 298 ip = fp->ipq_next; 299 ip->ip_len = next; 300 ((struct ip *)ip)->ip_src = fp->ipq_src; 301 ((struct ip *)ip)->ip_dst = fp->ipq_dst; 302 remque(fp); 303 (void) m_free(dtom(fp)); 304 m = dtom(ip); 305 m->m_len += sizeof (struct ipasfrag); 306 m->m_off -= sizeof (struct ipasfrag); 307 return ((struct ip *)ip); 308 309 dropfrag: 310 m_freem(m); 311 return (0); 312 } 313 314 /* 315 * Free a fragment reassembly header and all 316 * associated datagrams. 317 */ 318 struct ipq * 319 ip_freef(fp) 320 struct ipq *fp; 321 { 322 register struct ipasfrag *q; 323 struct mbuf *m; 324 COUNT(IP_FREEF); 325 326 for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) 327 m_freem(dtom(q)); 328 m = dtom(fp); 329 fp = fp->next; 330 remque(fp->prev); 331 (void) m_free(m); 332 return (fp); 333 } 334 335 /* 336 * Put an ip fragment on a reassembly chain. 337 * Like insque, but pointers in middle of structure. 338 */ 339 ip_enq(p, prev) 340 register struct ipasfrag *p, *prev; 341 { 342 343 COUNT(IP_ENQ); 344 p->ipf_prev = prev; 345 p->ipf_next = prev->ipf_next; 346 prev->ipf_next->ipf_prev = p; 347 prev->ipf_next = p; 348 } 349 350 /* 351 * To ip_enq as remque is to insque. 352 */ 353 ip_deq(p) 354 register struct ipasfrag *p; 355 { 356 357 COUNT(IP_DEQ); 358 p->ipf_prev->ipf_next = p->ipf_next; 359 p->ipf_next->ipf_prev = p->ipf_prev; 360 } 361 362 /* 363 * IP timer processing; 364 * if a timer expires on a reassembly 365 * queue, discard it. 366 */ 367 ip_slowtimo() 368 { 369 register struct ipq *fp; 370 int s = splnet(); 371 372 COUNT(IP_SLOWTIMO); 373 fp = ipq.next; 374 if (fp == 0) { 375 splx(s); 376 return; 377 } 378 while (fp != &ipq) 379 if (--fp->ipq_ttl == 0) 380 fp = ip_freef(fp); 381 else 382 fp = fp->next; 383 splx(s); 384 } 385 386 /* 387 * Drain off all datagram fragments. 388 */ 389 ip_drain() 390 { 391 392 COUNT(IP_DRAIN); 393 while (ipq.next != &ipq) 394 (void) ip_freef(ipq.next); 395 } 396 397 /* 398 * Do option processing on a datagram, 399 * possibly discarding it if bad options 400 * are encountered. 401 */ 402 ip_dooptions(ip) 403 struct ip *ip; 404 { 405 register u_char *cp; 406 int opt, optlen, cnt; 407 struct in_addr *sin; 408 register struct ip_timestamp *ipt; 409 register struct ifnet *ifp; 410 struct in_addr t; 411 412 COUNT(IP_DOOPTIONS); 413 cp = (u_char *)(ip + 1); 414 cnt = (ip->ip_hl << 2) - sizeof (struct ip); 415 for (; cnt > 0; cnt -= optlen, cp += optlen) { 416 opt = cp[0]; 417 if (opt == IPOPT_EOL) 418 break; 419 if (opt == IPOPT_NOP) 420 optlen = 1; 421 else 422 optlen = cp[1]; 423 switch (opt) { 424 425 default: 426 break; 427 428 /* 429 * Source routing with record. 430 * Find interface with current destination address. 431 * If none on this machine then drop if strictly routed, 432 * or do nothing if loosely routed. 433 * Record interface address and bring up next address 434 * component. If strictly routed make sure next 435 * address on directly accessible net. 436 */ 437 case IPOPT_LSRR: 438 if (cp[2] < 4 || cp[2] > optlen - (sizeof (long) - 1)) 439 break; 440 sin = (struct in_addr *)(cp + cp[2]); 441 ifp = if_ifwithaddr(*sin); 442 if (ifp == 0) { 443 if (opt == IPOPT_SSRR) 444 goto bad; 445 break; 446 } 447 t = ip->ip_dst; ip->ip_dst = *sin; *sin = t; 448 cp[2] += 4; 449 if (cp[2] > optlen - (sizeof (long) - 1)) 450 break; 451 ip->ip_dst = sin[1]; 452 if (opt == IPOPT_SSRR && if_ifonnetof(ip->ip_dst)==0) 453 goto bad; 454 break; 455 456 case IPOPT_TS: 457 ipt = (struct ip_timestamp *)cp; 458 if (ipt->ipt_len < 5) 459 goto bad; 460 if (ipt->ipt_ptr > ipt->ipt_len - sizeof (long)) { 461 if (++ipt->ipt_oflw == 0) 462 goto bad; 463 break; 464 } 465 sin = (struct in_addr *)(cp+cp[2]); 466 switch (ipt->ipt_flg) { 467 468 case IPOPT_TS_TSONLY: 469 break; 470 471 case IPOPT_TS_TSANDADDR: 472 if (ipt->ipt_ptr + 8 > ipt->ipt_len) 473 goto bad; 474 /* stamp with ``first'' interface address */ 475 *sin++ = ifnet->if_addr; 476 break; 477 478 case IPOPT_TS_PRESPEC: 479 if (if_ifwithaddr(*sin) == 0) 480 continue; 481 if (ipt->ipt_ptr + 8 > ipt->ipt_len) 482 goto bad; 483 ipt->ipt_ptr += 4; 484 break; 485 486 default: 487 goto bad; 488 } 489 *(n_time *)sin = iptime(); 490 ipt->ipt_ptr += 4; 491 } 492 } 493 return; 494 bad: 495 /* SHOULD FORCE ICMP MESSAGE */ 496 return; 497 } 498 499 /* 500 * Strip out IP options, at higher 501 * level protocol in the kernel. 502 * Second argument is buffer to which options 503 * will be moved, and return value is their length. 504 */ 505 ip_stripoptions(ip, mopt) 506 struct ip *ip; 507 struct mbuf *mopt; 508 { 509 register int i; 510 register struct mbuf *m; 511 int olen; 512 COUNT(IP_STRIPOPTIONS); 513 514 olen = (ip->ip_hl<<2) - sizeof (struct ip); 515 m = dtom(ip); 516 ip++; 517 if (mopt) { 518 mopt->m_len = olen; 519 mopt->m_off = MMINOFF; 520 bcopy((caddr_t)ip, mtod(m, caddr_t), (unsigned)olen); 521 } 522 i = m->m_len - (sizeof (struct ip) + olen); 523 bcopy((caddr_t)ip+olen, (caddr_t)ip, (unsigned)i); 524 m->m_len -= olen; 525 } 526