date and time created 81/11/15 14:34:06 by wnj
[unix-history] / usr / src / sys / netinet / ip_input.c
... / ...
CommitLineData
1/* ip_input.c 1.13 81/11/15 */
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
18u_char ip_protox[IPPROTO_MAX];
19
20/*
21 * Ip initialization.
22 */
23ip_init()
24{
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;
38 ipq.next = ipq.prev = &ipq;
39 ip_id = time & 0xffff;
40}
41
42u_char ipcksum = 1;
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;
56{
57 register struct ip *ip; /* known to be r11 in CKSUM below */
58 register struct mbuf *m = m0;
59 register int i;
60 register struct ipq *q;
61 register struct ipq *fp;
62 int hlen;
63
64COUNT(IP_INPUT);
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);
72 return;
73 }
74 CKSUM_IPCHK(m, ip, r11, hlen);
75 if (ip->ip_sum) {
76 printf("ip_sum %x\n", ip->ip_sum);
77 netstat.ip_badsum++;
78 if (ipcksum) {
79 m_freem(m);
80 return;
81 }
82 }
83 ip->ip_len = ntohs(ip->ip_len);
84 ip->ip_id = ntohs(ip->ip_id);
85 ip->ip_off = ntohs(ip->ip_off);
86
87 /*
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.
92 */
93 i = 0;
94 for (; m != NULL; m = m->m_next)
95 i += m->m_len;
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;
102 }
103 m_adj(m, ip->ip_len - i);
104 }
105
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;
119 }
120
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:
133
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;
140 ((struct ipasfrag *)ip)->ipf_mff = 0;
141 if (ip->ip_off & IP_MF)
142 ((struct ipasfrag *)ip)->ipf_mff = 1;
143 ip->ip_off <<= 3;
144
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 */
150 if (((struct ipasfrag *)ip)->ipf_mff || ip->ip_off) {
151 ip = ip_reass((struct ipasfrag *)ip, fp);
152 if (ip == 0)
153 return;
154 hlen = ip->ip_hl << 2;
155 m = dtom(ip);
156 } else
157 if (fp)
158 (void) ip_freef(fp);
159 (*protosw[ip_protox[ip->ip_p]].pr_input)(m);
160}
161
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)
170 register struct ipasfrag *ip;
171 register struct ipq *fp;
172{
173 register struct mbuf *m = dtom(ip);
174 register struct ipasfrag *q;
175 struct mbuf *t;
176 int hlen = ip->ip_hl << 2;
177 int i, next;
178
179 /*
180 * Presence of header sizes in mbufs
181 * would confuse code below.
182 */
183 m->m_off += hlen;
184 m->m_len -= hlen;
185
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;
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;
201 }
202
203 /*
204 * Find a segment which begins after this one does.
205 */
206 for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next)
207 if (q->ip_off > ip->ip_off)
208 break;
209
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 */
215 if (q->ipf_prev != (struct ipasfrag *)fp) {
216 i = q->ipf_prev->ip_off + q->ipf_prev->ip_len - ip->ip_off;
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;
223 }
224 }
225
226 /*
227 * While we overlap succeeding segments trim them or,
228 * if they are completely covered, dequeue them.
229 */
230 while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) {
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 }
237 q = q->ipf_next;
238 m_freem(dtom(q->ipf_prev));
239 ip_deq(q->ipf_prev);
240 }
241
242 /*
243 * Stick new segment in its place;
244 * check for complete reassembly.
245 */
246 ip_enq(ip, q->ipf_prev);
247 next = 0;
248 for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) {
249 if (q->ip_off != next)
250 return (0);
251 next += q->ip_len;
252 }
253 if (q->ipf_prev->ipf_mff)
254 return (0);
255
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);
264 while ((q = q->ipf_next) != (struct ipasfrag *)fp)
265 m_cat(m, dtom(q));
266
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;
275 ((struct ip *)ip)->ip_src = fp->ipq_src;
276 ((struct ip *)ip)->ip_dst = fp->ipq_dst;
277 remque(fp);
278 m_free(dtom(fp));
279 m = dtom(ip);
280 m->m_len += sizeof (struct ipasfrag);
281 m->m_off -= sizeof (struct ipasfrag);
282 return ((struct ip *)ip);
283
284dropfrag:
285 m_freem(m);
286 return (0);
287}
288
289/*
290 * Free a fragment reassembly header and all
291 * associated datagrams.
292 */
293struct ipq *
294ip_freef(fp)
295 struct ipq *fp;
296{
297 register struct ipasfrag *q;
298 struct mbuf *m;
299
300 for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next)
301 m_freem(dtom(q));
302 m = dtom(fp);
303 fp = fp->next;
304 remque(fp->prev);
305 m_free(m);
306 return (fp);
307}
308
309/*
310 * Put an ip fragment on a reassembly chain.
311 * Like insque, but pointers in middle of structure.
312 */
313ip_enq(p, prev)
314 register struct ipasfrag *p, *prev;
315{
316COUNT(IP_ENQ);
317
318 p->ipf_prev = prev;
319 p->ipf_next = prev->ipf_next;
320 prev->ipf_next->ipf_prev = p;
321 prev->ipf_next = p;
322}
323
324/*
325 * To ip_enq as remque is to insque.
326 */
327ip_deq(p)
328 register struct ipasfrag *p;
329{
330COUNT(IP_DEQ);
331
332 p->ipf_prev->ipf_next = p->ipf_next;
333 p->ipf_next->ipf_prev = p->ipf_prev;
334}
335
336/*
337 * IP timer processing;
338 * if a timer expires on a reassembly
339 * queue, discard it.
340 */
341ip_slowtimo()
342{
343 register struct ipq *fp;
344 int s = splnet();
345COUNT(IP_SLOWTIMO);
346
347 for (fp = ipq.next; fp != &ipq; )
348 if (--fp->ipq_ttl == 0)
349 fp = ip_freef(fp);
350 else
351 fp = fp->next;
352 splx(s);
353}
354
355ip_drain()
356{
357
358}
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;
366{
367 register u_char *cp;
368 int opt, optlen, cnt, s;
369 struct ip_addr *sp;
370 register struct ip_timestamp *ipt;
371 int x;
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) {
384
385 default:
386 break;
387
388 case IPOPT_LSRR:
389 case IPOPT_SSRR:
390 if (cp[2] < 4 || cp[2] > optlen - (sizeof (long) - 1))
391 break;
392 sp = (struct ip_addr *)(cp + cp[2]);
393 if (n_lhost.s_addr == *(u_long *)sp) {
394 if (opt == IPOPT_SSRR) {
395 /* MAKE SURE *SP DIRECTLY ACCESSIBLE */
396 }
397 ip->ip_dst = *sp;
398 *sp = n_lhost;
399 cp[2] += 4;
400 }
401 break;
402
403 case IPOPT_TS:
404 ipt = (struct ip_timestamp *)cp;
405 if (ipt->ipt_len < 5)
406 goto bad;
407 if (ipt->ipt_ptr > ipt->ipt_len - sizeof (long)) {
408 if (++ipt->ipt_oflw == 0)
409 goto bad;
410 break;
411 }
412 sp = (struct ip_addr *)(cp+cp[2]);
413 switch (ipt->ipt_flg) {
414
415 case IPOPT_TS_TSONLY:
416 break;
417
418 case IPOPT_TS_TSANDADDR:
419 if (ipt->ipt_ptr + 8 > ipt->ipt_len)
420 goto bad;
421 *(struct ip_addr *)sp++ = n_lhost;
422 break;
423
424 case IPOPT_TS_PRESPEC:
425 if (*(u_long *)sp != n_lhost.s_addr)
426 break;
427 if (ipt->ipt_ptr + 8 > ipt->ipt_len)
428 goto bad;
429 ipt->ipt_ptr += 4;
430 break;
431
432 default:
433 goto bad;
434 }
435 *(n_time *)sp = ip_time();
436 ipt->ipt_ptr += 4;
437 }
438 }
439 return (0);
440bad:
441 /* SHOULD FORCE ICMP MESSAGE */
442 return (-1);
443}
444
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;
451{
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;
464}