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