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