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