first version test with _tcp_seq
[unix-history] / usr / src / sys / netinet / ip_input.c
CommitLineData
905758fb 1/* ip_input.c 1.8 81/10/28 */
6e8b2eca 2
e1d82856 3#include "../h/param.h"
d10bd5b7 4#include "../h/systm.h"
e6dd2097
BJ
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
14int nosum = 0;
15
16struct 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 */
27ip_input(m0)
28 struct mbuf *m0;
e1d82856 29{
e6dd2097 30 register int i;
e1d82856
BJ
31 register struct ip *ip, *q;
32 register struct ipq *fp;
e6dd2097 33 register struct mbuf *m = m0;
e1d82856 34 int hlen;
e1d82856
BJ
35
36COUNT(IP_INPUT);
e6dd2097
BJ
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);
e1d82856
BJ
44 return;
45 }
e6dd2097 46 i = ip->ip_sum;
e1d82856 47 ip->ip_sum = 0;
e6dd2097
BJ
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) {
e1d82856
BJ
59 netstat.ip_badsum++;
60 if (!nosum) {
e6dd2097
BJ
61 m_freem(m);
62 return;
e1d82856
BJ
63 }
64 }
e6dd2097
BJ
65 ip->ip_len = ntohs(ip->ip_len);
66 ip->ip_id = ntohs(ip->ip_id);
67 ip->ip_off = ntohs(ip->ip_off);
e1d82856 68
d10bd5b7 69 /*
e6dd2097
BJ
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.
d10bd5b7 74 */
e6dd2097
BJ
75 i = 0;
76 for (; m != NULL; m = m->m_next)
e1d82856 77 i += m->m_len;
e6dd2097
BJ
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;
d10bd5b7 84 }
e6dd2097 85 m_adj(m, ip->ip_len - i);
d10bd5b7 86 }
e1d82856 87
e6dd2097
BJ
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;
d10bd5b7 101 }
e1d82856 102
e6dd2097
BJ
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;
114found:
e1d82856 115
e6dd2097
BJ
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;
e1d82856 126
e6dd2097
BJ
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)
d10bd5b7 135 return;
e6dd2097
BJ
136 hlen = ip->ip_hl << 2;
137 m = dtom(ip);
138 } else
139 if (fp)
140 (void) ip_freef(fp);
e1d82856 141
e6dd2097
BJ
142 /*
143 * Switch out to protocol specific routine.
144 * SHOULD GO THROUGH PROTOCOL SWITCH TABLE
145 */
146 switch (ip->ip_p) {
e1d82856 147
e6dd2097
BJ
148 case IPPROTO_ICMP:
149 icmp_input(m);
150 break;
d10bd5b7 151
e6dd2097
BJ
152 case IPPROTO_TCP:
153 if (hlen > sizeof (struct ip))
154 ip_stripoptions(ip, hlen);
155 tcp_input(m);
156 break;
e1d82856 157
e6dd2097
BJ
158 case IPPROTO_UDP:
159 if (hlen > sizeof (struct ip))
160 ip_stripoptions(ip, hlen);
161 udp_input(m);
162 break;
e1d82856 163
e6dd2097
BJ
164 default:
165 raw_input(m);
166 break;
167 }
168}
e1d82856 169
e6dd2097
BJ
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 */
176struct ip *
177ip_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;
d10bd5b7 186
e6dd2097
BJ
187 /*
188 * Presence of header sizes in mbufs
189 * would confuse code below.
190 */
191 m->m_off += hlen;
192 m->m_len -= hlen;
d10bd5b7 193
e6dd2097
BJ
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 }
e1d82856 210
e6dd2097
BJ
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;
e1d82856 217
e6dd2097
BJ
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;
e1d82856 231 }
d10bd5b7 232 }
e1d82856 233
e6dd2097
BJ
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 }
e1d82856 249
e6dd2097
BJ
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);
e1d82856 263
e6dd2097
BJ
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));
e1d82856 274
e6dd2097
BJ
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
292dropfrag:
293 m_freem(m);
294 return (0);
e1d82856
BJ
295}
296
e6dd2097
BJ
297/*
298 * Free a fragment reassembly header and all
299 * associated datagrams.
300 */
301struct ipq *
302ip_freef(fp)
303 struct ipq *fp;
e1d82856
BJ
304{
305 register struct ip *q;
e6dd2097
BJ
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);
e1d82856
BJ
315}
316
e6dd2097
BJ
317/*
318 * Put an ip fragment on a reassembly chain.
319 * Like insque, but pointers in middle of structure.
320 */
321ip_enq(p, prev)
322 register struct ip *p;
323 register struct ip *prev;
e1d82856 324{
e6dd2097 325COUNT(IP_ENQ);
e1d82856 326
e6dd2097
BJ
327 p->ip_prev = prev;
328 p->ip_next = prev->ip_next;
329 prev->ip_next->ip_prev = p;
330 prev->ip_next = p;
e1d82856
BJ
331}
332
e6dd2097
BJ
333/*
334 * To ip_enq as remque is to insque.
335 */
336ip_deq(p)
337 register struct ip *p;
e1d82856 338{
e6dd2097
BJ
339COUNT(IP_DEQ);
340
341 p->ip_prev->ip_next = p->ip_next;
342 p->ip_next->ip_prev = p->ip_prev;
e1d82856
BJ
343}
344
e6dd2097
BJ
345/*
346 * IP timer processing;
347 * if a timer expires on a reassembly
348 * queue, discard it.
349 */
350ip_timeo()
e1d82856 351{
e6dd2097 352 register struct ip *q;
e1d82856 353 register struct ipq *fp;
e6dd2097
BJ
354 int s = splnet();
355COUNT(IP_TIMEO);
e1d82856 356
905758fb 357 for (fp = ipq.next; fp != &ipq; )
e6dd2097
BJ
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);
e1d82856
BJ
364}
365
e6dd2097
BJ
366/*
367 * Do option processing on a datagram,
368 * possibly discarding it if bad options
369 * are encountered.
370 */
371ip_dooptions(ip)
372 struct ip *ip;
e1d82856 373{
e6dd2097
BJ
374 register u_char *cp;
375 int opt, optlen, cnt, s;
376 struct inet_addr *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) {
e1d82856 389
e6dd2097
BJ
390 default:
391 break;
e1d82856 392
e6dd2097
BJ
393 case IPOPT_LSRR:
394 case IPOPT_SSRR:
395 if (cp[2] < 4 || cp[2] > optlen - 3)
396 break;
397 sp = (struct inet_addr *)(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 inet_addr *)(cp+cp[2]);
418 switch (cp[3] & 0xf) {
e1d82856 419
e6dd2097
BJ
420 case IPOPT_TS_TSONLY:
421 break;
e1d82856 422
e6dd2097
BJ
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;
e1d82856
BJ
434 break;
435
436 default:
e6dd2097 437 goto bad;
e1d82856 438 }
e6dd2097
BJ
439 s = spl6();
440 *(int *)sp = (time % SECDAY) * 1000 + (lbolt*1000/hz);
441 splx(s);
442 cp[1] += 4;
443 }
e1d82856 444 }
e6dd2097
BJ
445 return (0);
446bad:
447 /* SHOULD FORCE ICMP MESSAGE */
448 return (-1);
e1d82856
BJ
449}
450
e6dd2097
BJ
451/*
452 * Strip out IP options, e.g. before passing
453 * to higher level protocol in the kernel.
454 */
455ip_stripoptions(ip)
456 struct ip *ip;
e1d82856 457{
e6dd2097
BJ
458 register int i;
459 register struct mbuf *m;
460 char *op;
461 int olen;
462COUNT(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;
e1d82856 470}
d10bd5b7 471
e6dd2097
BJ
472/* stubs */
473
474icmp_error(ip, error)
e1d82856 475{
e6dd2097
BJ
476
477 m_freem(dtom(ip));
e1d82856
BJ
478}
479
e6dd2097
BJ
480icmp_input(m)
481 struct mbuf *m;
e1d82856 482{
e1d82856 483
e6dd2097
BJ
484 printf("icmp_input %x\n", m);
485}
e1d82856 486
e6dd2097
BJ
487udp_input(m)
488 struct mbuf *m;
489{
e1d82856 490
e6dd2097
BJ
491 printf("udp_input %x\n", m);
492}
e1d82856 493
e6dd2097
BJ
494raw_input(m)
495 struct mbuf *m;
496{
e1d82856 497
e6dd2097 498 printf("raw_input %x\n", m);
e1d82856 499}