OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [uclinux/] [uClinux-2.0.x/] [net/] [ipv4/] [ip_options.c] - Blame information for rev 1782

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 * INET         An implementation of the TCP/IP protocol suite for the LINUX
3
 *              operating system.  INET is implemented using the  BSD Socket
4
 *              interface as the means of communication with the user level.
5
 *
6
 *              The options processing module for ip.c
7
 *
8
 * Authors:     A.N.Kuznetsov
9
 *
10
 */
11
 
12
#include <linux/types.h>
13
#include <linux/skbuff.h>
14
#include <linux/ip.h>
15
#include <linux/icmp.h>
16
#include <linux/netdevice.h>
17
#include <net/sock.h>
18
#include <net/ip.h>
19
#include <net/icmp.h>
20
 
21
/*
22
 * Write options to IP header, record destination address to
23
 * source route option, address of outgoing interface
24
 * (we should already know it, so that this  function is allowed be
25
 * called only after routing decision) and timestamp,
26
 * if we originate this datagram.
27
 */
28
 
29
void ip_options_build(struct sk_buff * skb, struct options * opt,
30
                            __u32 daddr, __u32 saddr,
31
                            int is_frag)
32
{
33
        unsigned char * iph = (unsigned char*)skb->ip_hdr;
34
 
35
        memcpy(skb->proto_priv, opt, sizeof(struct options));
36
        memcpy(iph+sizeof(struct iphdr), opt->__data, opt->optlen);
37
        opt = (struct options*)skb->proto_priv;
38
        opt->is_data = 0;
39
 
40
        if (opt->srr)
41
                memcpy(iph+opt->srr+iph[opt->srr+1]-4, &daddr, 4);
42
 
43
        if (!is_frag)
44
        {
45
                if (opt->rr_needaddr)
46
                        memcpy(iph+opt->rr+iph[opt->rr+2]-5, &saddr, 4);
47
                if (opt->ts_needaddr)
48
                        memcpy(iph+opt->ts+iph[opt->ts+2]-9, &saddr, 4);
49
                if (opt->ts_needtime)
50
                {
51
                        struct timeval tv;
52
                        __u32 midtime;
53
                        do_gettimeofday(&tv);
54
                        midtime = htonl((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000);
55
                        memcpy(iph+opt->ts+iph[opt->ts+2]-5, &midtime, 4);
56
                }
57
                return;
58
        }
59
        if (opt->rr)
60
        {
61
                memset(iph+opt->rr, IPOPT_NOP, iph[opt->rr+1]);
62
                opt->rr = 0;
63
                opt->rr_needaddr = 0;
64
        }
65
        if (opt->ts)
66
        {
67
                memset(iph+opt->ts, IPOPT_NOP, iph[opt->ts+1]);
68
                opt->ts = 0;
69
                opt->ts_needaddr = opt->ts_needtime = 0;
70
        }
71
}
72
 
73
int ip_options_echo(struct options * dopt, struct options * sopt,
74
                     __u32 daddr, __u32 saddr,
75
                     struct sk_buff * skb)
76
{
77
        unsigned char *sptr, *dptr;
78
        int soffset, doffset;
79
        int     optlen;
80
 
81
        memset(dopt, 0, sizeof(struct options));
82
 
83
        dopt->is_data = 1;
84
 
85
        if (!sopt)
86
                sopt = (struct options*)skb->proto_priv;
87
 
88
        if (sopt->optlen == 0)
89
        {
90
                dopt->optlen = 0;
91
                return 0;
92
        }
93
 
94
        sptr = (sopt->is_data ? sopt->__data - sizeof(struct iphdr) :
95
                (unsigned char *)skb->ip_hdr);
96
        dptr = dopt->__data;
97
 
98
        if (sopt->rr)
99
        {
100
                optlen  = sptr[sopt->rr+1];
101
                soffset = sptr[sopt->rr+2];
102
                dopt->rr = dopt->optlen + sizeof(struct iphdr);
103
                memcpy(dptr, sptr+sopt->rr, optlen);
104
                if (sopt->rr_needaddr && soffset <= optlen) {
105
                        if (soffset + 3 > optlen)
106
                          return -EINVAL;
107
                        dptr[2] = soffset + 4;
108
                        dopt->rr_needaddr = 1;
109
                }
110
                dptr     += optlen;
111
                dopt->optlen += optlen;
112
        }
113
        if (sopt->ts)
114
        {
115
                optlen = sptr[sopt->ts+1];
116
                soffset = sptr[sopt->ts+2];
117
                dopt->ts = dopt->optlen + sizeof(struct iphdr);
118
                memcpy(dptr, sptr+sopt->ts, optlen);
119
                if (soffset <= optlen)
120
                {
121
                        if (sopt->ts_needaddr)
122
                        {
123
                                if (soffset + 3 > optlen)
124
                                        return -EINVAL;
125
                                dopt->ts_needaddr = 1;
126
                                soffset += 4;
127
                        }
128
                        if (sopt->ts_needtime)
129
                        {
130
                                if (soffset + 3 > optlen)
131
                                        return -EINVAL;
132
                                dopt->ts_needtime = 1;
133
                                soffset += 4;
134
                        }
135
                        if (((struct timestamp*)(dptr+1))->flags == IPOPT_TS_PRESPEC)
136
                        {
137
                                __u32 addr;
138
                                memcpy(&addr, sptr+soffset-9, 4);
139
                                if (ip_chk_addr(addr) == 0)
140
                                {
141
                                        dopt->ts_needtime = 0;
142
                                        dopt->ts_needaddr = 0;
143
                                        soffset -= 8;
144
                                }
145
                        }
146
                        dptr[2] = soffset;
147
                }
148
                dptr += optlen;
149
                dopt->optlen += optlen;
150
        }
151
        if (sopt->srr)
152
        {
153
                unsigned char * start = sptr+sopt->srr;
154
                __u32 faddr;
155
 
156
                optlen  = start[1];
157
                soffset = start[2];
158
                doffset = 0;
159
                if (soffset > optlen)
160
                        soffset = optlen + 1;
161
                soffset -= 4;
162
                if (soffset > 3)
163
                {
164
                        memcpy(&faddr, &start[soffset-1], 4);
165
                        for (soffset-=4, doffset=4; soffset > 3; soffset-=4, doffset+=4)
166
                                memcpy(&dptr[doffset-1], &start[soffset-1], 4);
167
                        /*
168
                         * RFC1812 requires to fix illegal source routes.
169
                         */
170
                        if (memcmp(&saddr, &start[soffset+3], 4) == 0)
171
                                doffset -= 4;
172
                }
173
                if (doffset > 3)
174
                {
175
                        memcpy(&start[doffset-1], &daddr, 4);
176
                        dopt->faddr = faddr;
177
                        dptr[0] = start[0];
178
                        dptr[1] = doffset+3;
179
                        dptr[2] = 4;
180
                        dptr += doffset+3;
181
                        dopt->srr = dopt->optlen + sizeof(struct iphdr);
182
                        dopt->optlen += doffset+3;
183
                        dopt->is_strictroute = sopt->is_strictroute;
184
                }
185
        }
186
        while (dopt->optlen & 3)
187
        {
188
                *dptr++ = IPOPT_END;
189
                dopt->optlen++;
190
        }
191
        return 0;
192
}
193
 
194
void ip_options_fragment(struct sk_buff * skb)
195
{
196
        unsigned char * optptr = (unsigned char*)skb->ip_hdr;
197
        struct options * opt = (struct options*)skb->proto_priv;
198
        int  l = opt->optlen;
199
        int  optlen;
200
 
201
        while (l > 0)
202
        {
203
                switch (*optptr)
204
                {
205
                      case IPOPT_END:
206
                        return;
207
                      case IPOPT_NOOP:
208
                        l--;
209
                        optptr++;
210
                        continue;
211
                }
212
                optlen = optptr[1];
213
                if (optlen<2 || optlen>l)
214
                  return;
215
                if (!(*optptr & 0x80))
216
                        memset(optptr, IPOPT_NOOP, optlen);
217
                l -= optlen;
218
                optptr += optlen;
219
        }
220
        opt->ts = 0;
221
        opt->rr = 0;
222
        opt->rr_needaddr = 0;
223
        opt->ts_needaddr = 0;
224
        opt->ts_needtime = 0;
225
        return;
226
}
227
 
228
/*
229
 * Verify options and fill pointers in struct options.
230
 * Caller should clear *opt, and set opt->data.
231
 * If opt == NULL, then skb->data should point to IP header.
232
 */
233
 
234
int ip_options_compile(struct options * opt, struct sk_buff * skb)
235
{
236
        int l;
237
        unsigned char * iph;
238
        unsigned char * optptr;
239
        int optlen;
240
        unsigned char * pp_ptr = NULL;
241
 
242
        if (!opt)
243
        {
244
                opt = (struct options*)skb->proto_priv;
245
                memset(opt, 0, sizeof(struct options));
246
                iph = (unsigned char*)skb->ip_hdr;
247
                opt->optlen = ((struct iphdr *)iph)->ihl*4 - sizeof(struct iphdr);
248
                optptr = iph + sizeof(struct iphdr);
249
                opt->is_data = 0;
250
        }
251
        else
252
        {
253
                optptr = opt->is_data ? opt->__data : (unsigned char*)&skb->ip_hdr[1];
254
                iph = optptr - sizeof(struct iphdr);
255
        }
256
 
257
        for (l = opt->optlen; l > 0; )
258
        {
259
                switch (*optptr)
260
                {
261
                      case IPOPT_END:
262
                        for (optptr++, l--; l>0; l--)
263
                        {
264
                                if (*optptr != IPOPT_END)
265
                                {
266
                                        *optptr = IPOPT_END;
267
                                        opt->is_changed = 1;
268
                                }
269
                        }
270
                        goto eol;
271
                      case IPOPT_NOOP:
272
                        l--;
273
                        optptr++;
274
                        continue;
275
                }
276
                optlen = optptr[1];
277
                if (optlen<2 || optlen>l)
278
                {
279
                        pp_ptr = optptr;
280
                        goto error;
281
                }
282
                switch (*optptr)
283
                {
284
                      case IPOPT_SSRR:
285
                      case IPOPT_LSRR:
286
                        if (optlen < 3)
287
                        {
288
                                pp_ptr = optptr + 1;
289
                                goto error;
290
                        }
291
                        if (optptr[2] < 4)
292
                        {
293
                                pp_ptr = optptr + 2;
294
                                goto error;
295
                        }
296
                        /* NB: cf RFC-1812 5.2.4.1 */
297
                        if (opt->srr)
298
                        {
299
                                pp_ptr = optptr;
300
                                goto error;
301
                        }
302
                        if (!skb)
303
                        {
304
                                if (optptr[2] != 4 || optlen < 7 || ((optlen-3) & 3))
305
                                {
306
                                        pp_ptr = optptr + 1;
307
                                        goto error;
308
                                }
309
                                memcpy(&opt->faddr, &optptr[3], 4);
310
                                if (optlen > 7)
311
                                        memmove(&optptr[3], &optptr[7], optlen-7);
312
                        }
313
                        opt->is_strictroute = (optptr[0] == IPOPT_SSRR);
314
                        opt->srr = optptr - iph;
315
                        break;
316
                      case IPOPT_RR:
317
                        if (opt->rr)
318
                        {
319
                                pp_ptr = optptr;
320
                                goto error;
321
                        }
322
                        if (optlen < 3)
323
                        {
324
                                pp_ptr = optptr + 1;
325
                                goto error;
326
                        }
327
                        if (optptr[2] < 4)
328
                        {
329
                                pp_ptr = optptr + 2;
330
                                goto error;
331
                        }
332
                        if (optptr[2] <= optlen)
333
                        {
334
                                if (optptr[2]+3 > optlen)
335
                                {
336
                                        pp_ptr = optptr + 2;
337
                                        goto error;
338
                                }
339
                                if (skb)
340
                                {
341
                                        memcpy(&optptr[optptr[2]-1], &skb->dev->pa_addr, 4);
342
                                        opt->is_changed = 1;
343
                                }
344
                                optptr[2] += 4;
345
                                opt->rr_needaddr = 1;
346
                        }
347
                        opt->rr = optptr - iph;
348
                        break;
349
                      case IPOPT_TIMESTAMP:
350
                        if (opt->ts)
351
                        {
352
                                pp_ptr = optptr;
353
                                goto error;
354
                        }
355
                        if (optlen < 4)
356
                        {
357
                                pp_ptr = optptr + 1;
358
                                goto error;
359
                        }
360
                        if (optptr[2] < 5)
361
                        {
362
                                pp_ptr = optptr + 2;
363
                                goto error;
364
                        }
365
                        if (optptr[2] <= optlen)
366
                        {
367
                                struct timestamp * ts = (struct timestamp*)(optptr+1);
368
                                __u32 * timeptr = NULL;
369
                                if (ts->ptr+3 > ts->len)
370
                                {
371
                                        pp_ptr = optptr + 2;
372
                                        goto error;
373
                                }
374
                                switch (ts->flags)
375
                                {
376
                                      case IPOPT_TS_TSONLY:
377
                                        opt->ts = optptr - iph;
378
                                        if (skb)
379
                                                timeptr = (__u32*)&optptr[ts->ptr-1];
380
                                        opt->ts_needtime = 1;
381
                                        ts->ptr += 4;
382
                                        break;
383
                                      case IPOPT_TS_TSANDADDR:
384
                                        if (ts->ptr+7 > ts->len)
385
                                        {
386
                                                pp_ptr = optptr + 2;
387
                                                goto error;
388
                                        }
389
                                        opt->ts = optptr - iph;
390
                                        if (skb)
391
                                        {
392
                                                memcpy(&optptr[ts->ptr-1], &skb->dev->pa_addr, 4);
393
                                                timeptr = (__u32*)&optptr[ts->ptr+3];
394
                                        }
395
                                        opt->ts_needaddr = 1;
396
                                        opt->ts_needtime = 1;
397
                                        ts->ptr += 8;
398
                                        break;
399
                                      case IPOPT_TS_PRESPEC:
400
                                        if (ts->ptr+7 > ts->len)
401
                                        {
402
                                                pp_ptr = optptr + 2;
403
                                                goto error;
404
                                        }
405
                                        opt->ts = optptr - iph;
406
                                        {
407
                                                __u32 addr;
408
                                                memcpy(&addr, &optptr[ts->ptr-1], 4);
409
                                                if (ip_chk_addr(addr) == 0)
410
                                                        break;
411
                                                if (skb)
412
                                                        timeptr = (__u32*)&optptr[ts->ptr+3];
413
                                        }
414
                                        opt->ts_needaddr = 1;
415
                                        opt->ts_needtime = 1;
416
                                        ts->ptr += 8;
417
                                        break;
418
                                      default:
419
                                        pp_ptr = optptr + 3;
420
                                        goto error;
421
                                }
422
                                if (timeptr)
423
                                {
424
                                        struct timeval tv;
425
                                        __u32  midtime;
426
                                        do_gettimeofday(&tv);
427
                                        midtime = htonl((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000);
428
                                        memcpy(timeptr, &midtime, sizeof(__u32));
429
                                        opt->is_changed = 1;
430
                                }
431
                        }
432
                        else
433
                        {
434
                                struct timestamp * ts = (struct timestamp*)(optptr+1);
435
                                if (ts->overflow == 15)
436
                                {
437
                                        pp_ptr = optptr + 3;
438
                                        goto error;
439
                                }
440
                                opt->ts = optptr - iph;
441
                                if (skb)
442
                                {
443
                                        ts->overflow++;
444
                                        opt->is_changed = 1;
445
                                }
446
                        }
447
                        break;
448
                      case IPOPT_SEC:
449
                      case IPOPT_SID:
450
                      default:
451
                        if (!skb)
452
                        {
453
                                pp_ptr = optptr;
454
                                goto error;
455
                        }
456
                        break;
457
                }
458
                l -= optlen;
459
                optptr += optlen;
460
        }
461
 
462
eol:
463
        if (!pp_ptr)
464
                return 0;
465
 
466
error:
467
        if (skb)
468
        {
469
                icmp_send(skb, ICMP_PARAMETERPROB, 0, pp_ptr-iph, skb->dev);
470
                kfree_skb(skb, FREE_READ);
471
        }
472
        return -EINVAL;
473
}
474
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.