1 /* ip_input.c 1.12 81/11/08 */ 2 3 #include "../h/param.h" 4 #include "../h/systm.h" 5 #include "../h/clock.h" 6 #include "../h/mbuf.h" 7 #include "../net/inet_cksum.h" 8 #include "../net/inet.h" 9 #include "../net/inet_systm.h" 10 #include "../net/imp.h" 11 #include "../net/ip.h" /* belongs before inet.h */ 12 #include "../net/ip_icmp.h" 13 #include "../net/tcp.h" 14 15 /* 16 * Ip initialization. 17 */ 18 ip_init() 19 { 20 21 ipq.next = ipq.prev = &ipq; 22 ip_id = time & 0xffff; 23 } 24 25 int ipcksum = 1; 26 27 struct ip *ip_reass(); 28 29 /* 30 * Ip input routines. 31 */ 32 33 /* 34 * Ip input routine. Checksum and byte swap header. If fragmented 35 * try to reassamble. If complete and fragment queue exists, discard. 36 * Process options. Pass to next level. 37 */ 38 ip_input(m0) 39 struct mbuf *m0; 40 { 41 register struct ip *ip; /* known to be r11 in CKSUM below */ 42 register struct mbuf *m = m0; 43 register int i; 44 register struct ipq *q; 45 register struct ipq *fp; 46 int hlen; 47 48 COUNT(IP_INPUT); 49 /* 50 * Check header and byteswap. 51 */ 52 ip = mtod(m, struct ip *); 53 if ((hlen = ip->ip_hl << 2) > m->m_len) { 54 printf("ip hdr ovflo\n"); 55 m_freem(m); 56 return; 57 } 58 CKSUM_IPCHK(m, ip, r11, hlen); 59 if (ip->ip_sum) { 60 printf("ip_sum %x\n", ip->ip_sum); 61 netstat.ip_badsum++; 62 if (ipcksum) { 63 m_freem(m); 64 return; 65 } 66 } 67 ip->ip_len = ntohs(ip->ip_len); 68 ip->ip_id = ntohs(ip->ip_id); 69 ip->ip_off = ntohs(ip->ip_off); 70 71 /* 72 * Check that the amount of data in the buffers 73 * is as at least much as the IP header would have us expect. 74 * Trim mbufs if longer than we expect. 75 * Drop packet if shorter than we expect. 76 */ 77 i = 0; 78 for (; m != NULL; m = m->m_next) 79 i += m->m_len; 80 m = m0; 81 if (i != ip->ip_len) { 82 if (i < ip->ip_len) { 83 printf("ip_input: short packet\n"); 84 m_freem(m); 85 return; 86 } 87 m_adj(m, ip->ip_len - i); 88 } 89 90 /* 91 * Process options and, if not destined for us, 92 * ship it on. 93 */ 94 if (hlen > sizeof (struct ip)) 95 ip_dooptions(ip, hlen); 96 if (ip->ip_dst.s_addr != n_lhost.s_addr) { 97 if (--ip->ip_ttl == 0) { 98 icmp_error(ip, ICMP_TIMXCEED); 99 return; 100 } 101 ip_output(dtom(ip)); 102 return; 103 } 104 105 /* 106 * Look for queue of fragments 107 * of this datagram. 108 */ 109 for (fp = ipq.next; fp != &ipq; fp = fp->next) 110 if (ip->ip_id == fp->ipq_id && 111 ip->ip_src.s_addr == fp->ipq_src.s_addr && 112 ip->ip_dst.s_addr == fp->ipq_dst.s_addr && 113 ip->ip_p == fp->ipq_p) 114 goto found; 115 fp = 0; 116 found: 117 118 /* 119 * Adjust ip_len to not reflect header, 120 * set ip_mff if more fragments are expected, 121 * convert offset of this to bytes. 122 */ 123 ip->ip_len -= hlen; 124 ip->ip_mff = 0; 125 if (ip->ip_off & IP_MF) 126 ip->ip_mff = 1; 127 ip->ip_off <<= 3; 128 129 /* 130 * If datagram marked as having more fragments 131 * or if this is not the first fragment, 132 * attempt reassembly; if it succeeds, proceed. 133 */ 134 if (ip->ip_mff || ip->ip_off) { 135 ip = ip_reass(ip, fp); 136 if (ip == 0) 137 return; 138 hlen = ip->ip_hl << 2; 139 m = dtom(ip); 140 } else 141 if (fp) 142 (void) ip_freef(fp); 143 144 /* 145 * Switch out to protocol specific routine. 146 * SHOULD GO THROUGH PROTOCOL SWITCH TABLE 147 */ 148 switch (ip->ip_p) { 149 150 case IPPROTO_ICMP: 151 icmp_input(m); 152 break; 153 154 case IPPROTO_TCP: 155 if (hlen > sizeof (struct ip)) 156 ip_stripoptions(ip, hlen); 157 tcp_input(m); 158 break; 159 160 case IPPROTO_UDP: 161 if (hlen > sizeof (struct ip)) 162 ip_stripoptions(ip, hlen); 163 udp_input(m); 164 break; 165 166 default: 167 ri_input(m); 168 break; 169 } 170 } 171 172 /* 173 * Take incoming datagram fragment and try to 174 * reassamble it into whole datagram. If a chain for 175 * reassembly of this datagram already exists, then it 176 * is given as fp; otherwise have to make a chain. 177 */ 178 struct ip * 179 ip_reass(ip, fp) 180 register struct ip *ip; 181 register struct ipq *fp; 182 { 183 register struct mbuf *m = dtom(ip); 184 register struct ip *q; 185 struct mbuf *t; 186 int hlen = ip->ip_hl << 2; 187 int i, next; 188 189 /* 190 * Presence of header sizes in mbufs 191 * would confuse code below. 192 */ 193 m->m_off += hlen; 194 m->m_len -= hlen; 195 196 /* 197 * If first fragment to arrive, create a reassembly queue. 198 */ 199 if (fp == 0) { 200 if ((t = m_get(1)) == NULL) 201 goto dropfrag; 202 t->m_off = MMINOFF; 203 fp = mtod(t, struct ipq *); 204 insque(fp, &ipq); 205 fp->ipq_ttl = IPFRAGTTL; 206 fp->ipq_p = ip->ip_p; 207 fp->ipq_id = ip->ip_id; 208 fp->ipq_next = fp->ipq_prev = (struct ip *)fp; 209 fp->ipq_src = ip->ip_src; 210 fp->ipq_dst = ip->ip_dst; 211 } 212 213 /* 214 * Find a segment which begins after this one does. 215 */ 216 for (q = fp->ipq_next; q != (struct ip *)fp; q = q->ip_next) 217 if (q->ip_off > ip->ip_off) 218 break; 219 220 /* 221 * If there is a preceding segment, it may provide some of 222 * our data already. If so, drop the data from the incoming 223 * segment. If it provides all of our data, drop us. 224 */ 225 if (q->ip_prev != (struct ip *)fp) { 226 i = q->ip_prev->ip_off + q->ip_prev->ip_len - ip->ip_off; 227 if (i > 0) { 228 if (i >= ip->ip_len) 229 goto dropfrag; 230 m_adj(dtom(ip), i); 231 ip->ip_off += i; 232 ip->ip_len -= i; 233 } 234 } 235 236 /* 237 * While we overlap succeeding segments trim them or, 238 * if they are completely covered, dequeue them. 239 */ 240 while (q != (struct ip *)fp && ip->ip_off + ip->ip_len > q->ip_off) { 241 i = (ip->ip_off + ip->ip_len) - q->ip_off; 242 if (i < q->ip_len) { 243 q->ip_len -= i; 244 m_adj(dtom(q), i); 245 break; 246 } 247 q = q->ip_next; 248 m_freem(dtom(q->ip_prev)); 249 ip_deq(q->ip_prev); 250 } 251 252 /* 253 * Stick new segment in its place; 254 * check for complete reassembly. 255 */ 256 ip_enq(ip, q->ip_prev); 257 next = 0; 258 for (q = fp->ipq_next; q != (struct ip *)fp; q = q->ip_next) { 259 if (q->ip_off != next) 260 return (0); 261 next += q->ip_len; 262 } 263 if (q->ip_prev->ip_mff) 264 return (0); 265 266 /* 267 * Reassembly is complete; concatenate fragments. 268 */ 269 q = fp->ipq_next; 270 m = dtom(q); 271 t = m->m_next; 272 m->m_next = 0; 273 m_cat(m, t); 274 while ((q = q->ip_next) != (struct ip *)fp) 275 m_cat(m, dtom(q)); 276 277 /* 278 * Create header for new ip packet by 279 * modifying header of first packet; 280 * dequeue and discard fragment reassembly header. 281 * Make header visible. 282 */ 283 ip = fp->ipq_next; 284 ip->ip_len = next; 285 ip->ip_src = fp->ipq_src; 286 ip->ip_dst = fp->ipq_dst; 287 remque(fp); 288 m_free(dtom(fp)); 289 m = dtom(ip); 290 m->m_len += sizeof (struct ip); 291 m->m_off -= sizeof (struct ip); 292 return (ip); 293 294 dropfrag: 295 m_freem(m); 296 return (0); 297 } 298 299 /* 300 * Free a fragment reassembly header and all 301 * associated datagrams. 302 */ 303 struct ipq * 304 ip_freef(fp) 305 struct ipq *fp; 306 { 307 register struct ip *q; 308 struct mbuf *m; 309 310 for (q = fp->ipq_next; q != (struct ip *)fp; q = q->ip_next) 311 m_freem(dtom(q)); 312 m = dtom(fp); 313 fp = fp->next; 314 remque(fp->prev); 315 m_free(m); 316 return (fp); 317 } 318 319 /* 320 * Put an ip fragment on a reassembly chain. 321 * Like insque, but pointers in middle of structure. 322 */ 323 ip_enq(p, prev) 324 register struct ip *p; 325 register struct ip *prev; 326 { 327 COUNT(IP_ENQ); 328 329 p->ip_prev = prev; 330 p->ip_next = prev->ip_next; 331 prev->ip_next->ip_prev = p; 332 prev->ip_next = p; 333 } 334 335 /* 336 * To ip_enq as remque is to insque. 337 */ 338 ip_deq(p) 339 register struct ip *p; 340 { 341 COUNT(IP_DEQ); 342 343 p->ip_prev->ip_next = p->ip_next; 344 p->ip_next->ip_prev = p->ip_prev; 345 } 346 347 /* 348 * IP timer processing; 349 * if a timer expires on a reassembly 350 * queue, discard it. 351 */ 352 ip_slowtimo() 353 { 354 register struct ip *q; 355 register struct ipq *fp; 356 int s = splnet(); 357 COUNT(IP_SLOWTIMO); 358 359 for (fp = ipq.next; fp != &ipq; ) 360 if (--fp->ipq_ttl == 0) 361 fp = ip_freef(fp); 362 else 363 fp = fp->next; 364 splx(s); 365 } 366 367 ip_drain() 368 { 369 370 } 371 /* 372 * Do option processing on a datagram, 373 * possibly discarding it if bad options 374 * are encountered. 375 */ 376 ip_dooptions(ip) 377 struct ip *ip; 378 { 379 register u_char *cp; 380 int opt, optlen, cnt, s; 381 struct ip_addr *sp; 382 register struct ip_timestamp *ipt; 383 int x; 384 385 cp = (u_char *)(ip + 1); 386 cnt = (ip->ip_hl << 2) - sizeof (struct ip); 387 for (; cnt > 0; cnt -= optlen, cp += optlen) { 388 opt = cp[0]; 389 if (opt == IPOPT_EOL) 390 break; 391 if (opt == IPOPT_NOP) 392 optlen = 1; 393 else 394 optlen = cp[1]; 395 switch (opt) { 396 397 default: 398 break; 399 400 case IPOPT_LSRR: 401 case IPOPT_SSRR: 402 if (cp[2] < 4 || cp[2] > optlen - (sizeof (long) - 1)) 403 break; 404 sp = (struct ip_addr *)(cp + cp[2]); 405 if (n_lhost.s_addr == *(u_long *)sp) { 406 if (opt == IPOPT_SSRR) { 407 /* MAKE SURE *SP DIRECTLY ACCESSIBLE */ 408 } 409 ip->ip_dst = *sp; 410 *sp = n_lhost; 411 cp[2] += 4; 412 } 413 break; 414 415 case IPOPT_TS: 416 ipt = (struct ip_timestamp *)cp; 417 if (ipt->ipt_len < 5) 418 goto bad; 419 if (ipt->ipt_ptr > ipt->ipt_len - sizeof (long)) { 420 if (++ipt->ipt_oflw == 0) 421 goto bad; 422 break; 423 } 424 sp = (struct ip_addr *)(cp+cp[2]); 425 switch (ipt->ipt_flg) { 426 427 case IPOPT_TS_TSONLY: 428 break; 429 430 case IPOPT_TS_TSANDADDR: 431 if (ipt->ipt_ptr + 8 > ipt->ipt_len) 432 goto bad; 433 *(struct ip_addr *)sp++ = n_lhost; 434 break; 435 436 case IPOPT_TS_PRESPEC: 437 if (*(u_long *)sp != n_lhost.s_addr) 438 break; 439 if (ipt->ipt_ptr + 8 > ipt->ipt_len) 440 goto bad; 441 ipt->ipt_ptr += 4; 442 break; 443 444 default: 445 goto bad; 446 } 447 *(n_time *)sp = ip_time(); 448 ipt->ipt_ptr += 4; 449 } 450 } 451 return (0); 452 bad: 453 /* SHOULD FORCE ICMP MESSAGE */ 454 return (-1); 455 } 456 457 /* 458 * Strip out IP options, e.g. before passing 459 * to higher level protocol in the kernel. 460 */ 461 ip_stripoptions(ip) 462 struct ip *ip; 463 { 464 register int i; 465 register struct mbuf *m; 466 char *op; 467 int olen; 468 COUNT(IP_OPT); 469 470 olen = (ip->ip_hl<<2) - sizeof (struct ip); 471 op = (caddr_t)ip + olen; 472 m = dtom(++ip); 473 i = m->m_len - (sizeof (struct ip) + olen); 474 bcopy((caddr_t)ip+olen, (caddr_t)ip, i); 475 m->m_len -= i; 476 } 477