1 /* ip_input.c 1.15 81/11/18 */ 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/inet.h" 10 #include "../net/inet_systm.h" 11 #include "../net/imp.h" 12 #include "../net/ip.h" /* belongs before inet.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. 21 */ 22 ip_init() 23 { 24 register struct protosw *pr; 25 register int i; 26 27 pr = pffindproto(PF_INET, IPPROTO_RAW); 28 if (pr == 0) 29 panic("ip_init"); 30 for (i = 0; i < IPPROTO_MAX; i++) 31 ip_protox[i] = pr - protosw; 32 for (pr = protosw; pr <= protoswLAST; pr++) 33 if (pr->pr_family == PF_INET && 34 pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) 35 ip_protox[pr->pr_protocol] = pr - protosw; 36 ipq.next = ipq.prev = &ipq; 37 ip_id = time & 0xffff; 38 } 39 40 u_char ipcksum = 1; 41 struct ip *ip_reass(); 42 43 /* 44 * Ip input routines. 45 */ 46 47 /* 48 * Ip input routine. Checksum and byte swap header. If fragmented 49 * try to reassamble. If complete and fragment queue exists, discard. 50 * Process options. Pass to next level. 51 */ 52 ip_input(m0) 53 struct mbuf *m0; 54 { 55 register struct ip *ip; 56 register struct mbuf *m = m0; 57 register int i; 58 register struct ipq *fp; 59 int hlen; 60 61 COUNT(IP_INPUT); 62 /* 63 * Check header and byteswap. 64 */ 65 ip = mtod(m, struct ip *); 66 if ((hlen = ip->ip_hl << 2) > m->m_len) { 67 printf("ip hdr ovflo\n"); 68 m_freem(m); 69 return; 70 } 71 ip->ip_sum = inet_cksum(m, hlen); 72 if (ip->ip_sum) { 73 printf("ip_sum %x\n", ip->ip_sum); 74 ipstat.ips_badsum++; 75 if (ipcksum) { 76 m_freem(m); 77 return; 78 } 79 } 80 ip->ip_len = ntohs((u_short)ip->ip_len); 81 ip->ip_id = ntohs(ip->ip_id); 82 ip->ip_off = ntohs(ip->ip_off); 83 84 /* 85 * Check that the amount of data in the buffers 86 * is as at least much as the IP header would have us expect. 87 * Trim mbufs if longer than we expect. 88 * Drop packet if shorter than we expect. 89 */ 90 i = 0; 91 for (; m != NULL; m = m->m_next) 92 i += m->m_len; 93 m = m0; 94 if (i != ip->ip_len) { 95 if (i < ip->ip_len) { 96 printf("ip_input: short packet\n"); 97 m_freem(m); 98 return; 99 } 100 m_adj(m, ip->ip_len - i); 101 } 102 103 /* 104 * Process options and, if not destined for us, 105 * ship it on. 106 */ 107 if (hlen > sizeof (struct ip)) 108 ip_dooptions(ip); 109 if (ip->ip_dst.s_addr != n_lhost.s_addr) { 110 if (--ip->ip_ttl == 0) { 111 icmp_error(ip, ICMP_TIMXCEED, 0); 112 return; 113 } 114 ip_output(dtom(ip)); 115 return; 116 } 117 118 /* 119 * Look for queue of fragments 120 * of this datagram. 121 */ 122 for (fp = ipq.next; fp != &ipq; fp = fp->next) 123 if (ip->ip_id == fp->ipq_id && 124 ip->ip_src.s_addr == fp->ipq_src.s_addr && 125 ip->ip_dst.s_addr == fp->ipq_dst.s_addr && 126 ip->ip_p == fp->ipq_p) 127 goto found; 128 fp = 0; 129 found: 130 131 /* 132 * Adjust ip_len to not reflect header, 133 * set ip_mff if more fragments are expected, 134 * convert offset of this to bytes. 135 */ 136 ip->ip_len -= hlen; 137 ((struct ipasfrag *)ip)->ipf_mff = 0; 138 if (ip->ip_off & IP_MF) 139 ((struct ipasfrag *)ip)->ipf_mff = 1; 140 ip->ip_off <<= 3; 141 142 /* 143 * If datagram marked as having more fragments 144 * or if this is not the first fragment, 145 * attempt reassembly; if it succeeds, proceed. 146 */ 147 if (((struct ipasfrag *)ip)->ipf_mff || ip->ip_off) { 148 ip = ip_reass((struct ipasfrag *)ip, fp); 149 if (ip == 0) 150 return; 151 hlen = ip->ip_hl << 2; 152 m = dtom(ip); 153 } else 154 if (fp) 155 (void) ip_freef(fp); 156 (*protosw[ip_protox[ip->ip_p]].pr_input)(m); 157 } 158 159 /* 160 * Take incoming datagram fragment and try to 161 * reassamble it into whole datagram. If a chain for 162 * reassembly of this datagram already exists, then it 163 * is given as fp; otherwise have to make a chain. 164 */ 165 struct ip * 166 ip_reass(ip, fp) 167 register struct ipasfrag *ip; 168 register struct ipq *fp; 169 { 170 register struct mbuf *m = dtom(ip); 171 register struct ipasfrag *q; 172 struct mbuf *t; 173 int hlen = ip->ip_hl << 2; 174 int i, next; 175 176 /* 177 * Presence of header sizes in mbufs 178 * would confuse code below. 179 */ 180 m->m_off += hlen; 181 m->m_len -= hlen; 182 183 /* 184 * If first fragment to arrive, create a reassembly queue. 185 */ 186 if (fp == 0) { 187 if ((t = m_get(1)) == NULL) 188 goto dropfrag; 189 t->m_off = MMINOFF; 190 fp = mtod(t, struct ipq *); 191 insque(fp, &ipq); 192 fp->ipq_ttl = IPFRAGTTL; 193 fp->ipq_p = ip->ip_p; 194 fp->ipq_id = ip->ip_id; 195 fp->ipq_next = fp->ipq_prev = (struct ipasfrag *)fp; 196 fp->ipq_src = ((struct ip *)ip)->ip_src; 197 fp->ipq_dst = ((struct ip *)ip)->ip_dst; 198 } 199 200 /* 201 * Find a segment which begins after this one does. 202 */ 203 for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) 204 if (q->ip_off > ip->ip_off) 205 break; 206 207 /* 208 * If there is a preceding segment, it may provide some of 209 * our data already. If so, drop the data from the incoming 210 * segment. If it provides all of our data, drop us. 211 */ 212 if (q->ipf_prev != (struct ipasfrag *)fp) { 213 i = q->ipf_prev->ip_off + q->ipf_prev->ip_len - ip->ip_off; 214 if (i > 0) { 215 if (i >= ip->ip_len) 216 goto dropfrag; 217 m_adj(dtom(ip), i); 218 ip->ip_off += i; 219 ip->ip_len -= i; 220 } 221 } 222 223 /* 224 * While we overlap succeeding segments trim them or, 225 * if they are completely covered, dequeue them. 226 */ 227 while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) { 228 i = (ip->ip_off + ip->ip_len) - q->ip_off; 229 if (i < q->ip_len) { 230 q->ip_len -= i; 231 m_adj(dtom(q), i); 232 break; 233 } 234 q = q->ipf_next; 235 m_freem(dtom(q->ipf_prev)); 236 ip_deq(q->ipf_prev); 237 } 238 239 /* 240 * Stick new segment in its place; 241 * check for complete reassembly. 242 */ 243 ip_enq(ip, q->ipf_prev); 244 next = 0; 245 for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) { 246 if (q->ip_off != next) 247 return (0); 248 next += q->ip_len; 249 } 250 if (q->ipf_prev->ipf_mff) 251 return (0); 252 253 /* 254 * Reassembly is complete; concatenate fragments. 255 */ 256 q = fp->ipq_next; 257 m = dtom(q); 258 t = m->m_next; 259 m->m_next = 0; 260 m_cat(m, t); 261 while ((q = q->ipf_next) != (struct ipasfrag *)fp) 262 m_cat(m, dtom(q)); 263 264 /* 265 * Create header for new ip packet by 266 * modifying header of first packet; 267 * dequeue and discard fragment reassembly header. 268 * Make header visible. 269 */ 270 ip = fp->ipq_next; 271 ip->ip_len = next; 272 ((struct ip *)ip)->ip_src = fp->ipq_src; 273 ((struct ip *)ip)->ip_dst = fp->ipq_dst; 274 remque(fp); 275 (void) m_free(dtom(fp)); 276 m = dtom(ip); 277 m->m_len += sizeof (struct ipasfrag); 278 m->m_off -= sizeof (struct ipasfrag); 279 return ((struct ip *)ip); 280 281 dropfrag: 282 m_freem(m); 283 return (0); 284 } 285 286 /* 287 * Free a fragment reassembly header and all 288 * associated datagrams. 289 */ 290 struct ipq * 291 ip_freef(fp) 292 struct ipq *fp; 293 { 294 register struct ipasfrag *q; 295 struct mbuf *m; 296 297 for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) 298 m_freem(dtom(q)); 299 m = dtom(fp); 300 fp = fp->next; 301 remque(fp->prev); 302 (void) m_free(m); 303 return (fp); 304 } 305 306 /* 307 * Put an ip fragment on a reassembly chain. 308 * Like insque, but pointers in middle of structure. 309 */ 310 ip_enq(p, prev) 311 register struct ipasfrag *p, *prev; 312 { 313 COUNT(IP_ENQ); 314 315 p->ipf_prev = prev; 316 p->ipf_next = prev->ipf_next; 317 prev->ipf_next->ipf_prev = p; 318 prev->ipf_next = p; 319 } 320 321 /* 322 * To ip_enq as remque is to insque. 323 */ 324 ip_deq(p) 325 register struct ipasfrag *p; 326 { 327 COUNT(IP_DEQ); 328 329 p->ipf_prev->ipf_next = p->ipf_next; 330 p->ipf_next->ipf_prev = p->ipf_prev; 331 } 332 333 /* 334 * IP timer processing; 335 * if a timer expires on a reassembly 336 * queue, discard it. 337 */ 338 ip_slowtimo() 339 { 340 register struct ipq *fp; 341 int s = splnet(); 342 COUNT(IP_SLOWTIMO); 343 344 for (fp = ipq.next; fp != &ipq; ) 345 if (--fp->ipq_ttl == 0) 346 fp = ip_freef(fp); 347 else 348 fp = fp->next; 349 splx(s); 350 } 351 352 ip_drain() 353 { 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 in_addr *sin; 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 sin = (struct in_addr *)(cp + cp[2]); 390 if (n_lhost.s_addr == *(u_long *)sin) { 391 if (opt == IPOPT_SSRR) { 392 /* MAKE SURE *SP DIRECTLY ACCESSIBLE */ 393 } 394 ip->ip_dst = *sin; 395 *sin = 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 sin = (struct in_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 in_addr *)sin++ = n_lhost; 419 break; 420 421 case IPOPT_TS_PRESPEC: 422 if (*(u_long *)sin != 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 *)sin = iptime(); 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