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

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [net/] [dccp/] [options.c] - Blame information for rev 17

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
/*
2
 *  net/dccp/options.c
3
 *
4
 *  An implementation of the DCCP protocol
5
 *  Copyright (c) 2005 Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
6
 *  Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
7
 *  Copyright (c) 2005 Ian McDonald <ian.mcdonald@jandi.co.nz>
8
 *
9
 *      This program is free software; you can redistribute it and/or
10
 *      modify it under the terms of the GNU General Public License
11
 *      as published by the Free Software Foundation; either version
12
 *      2 of the License, or (at your option) any later version.
13
 */
14
#include <linux/dccp.h>
15
#include <linux/module.h>
16
#include <linux/types.h>
17
#include <asm/unaligned.h>
18
#include <linux/kernel.h>
19
#include <linux/skbuff.h>
20
 
21
#include "ackvec.h"
22
#include "ccid.h"
23
#include "dccp.h"
24
#include "feat.h"
25
 
26
int sysctl_dccp_feat_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW;
27
int sysctl_dccp_feat_rx_ccid          = DCCPF_INITIAL_CCID;
28
int sysctl_dccp_feat_tx_ccid          = DCCPF_INITIAL_CCID;
29
int sysctl_dccp_feat_ack_ratio        = DCCPF_INITIAL_ACK_RATIO;
30
int sysctl_dccp_feat_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR;
31
int sysctl_dccp_feat_send_ndp_count  = DCCPF_INITIAL_SEND_NDP_COUNT;
32
 
33
static u32 dccp_decode_value_var(const unsigned char *bf, const u8 len)
34
{
35
        u32 value = 0;
36
 
37
        if (len > 3)
38
                value += *bf++ << 24;
39
        if (len > 2)
40
                value += *bf++ << 16;
41
        if (len > 1)
42
                value += *bf++ << 8;
43
        if (len > 0)
44
                value += *bf;
45
 
46
        return value;
47
}
48
 
49
int dccp_parse_options(struct sock *sk, struct sk_buff *skb)
50
{
51
        struct dccp_sock *dp = dccp_sk(sk);
52
        const struct dccp_hdr *dh = dccp_hdr(skb);
53
        const u8 pkt_type = DCCP_SKB_CB(skb)->dccpd_type;
54
        u64 ackno = DCCP_SKB_CB(skb)->dccpd_ack_seq;
55
        unsigned char *options = (unsigned char *)dh + dccp_hdr_len(skb);
56
        unsigned char *opt_ptr = options;
57
        const unsigned char *opt_end = (unsigned char *)dh +
58
                                        (dh->dccph_doff * 4);
59
        struct dccp_options_received *opt_recv = &dp->dccps_options_received;
60
        unsigned char opt, len;
61
        unsigned char *value;
62
        u32 elapsed_time;
63
        __be32 opt_val;
64
        int rc;
65
        int mandatory = 0;
66
 
67
        memset(opt_recv, 0, sizeof(*opt_recv));
68
 
69
        opt = len = 0;
70
        while (opt_ptr != opt_end) {
71
                opt   = *opt_ptr++;
72
                len   = 0;
73
                value = NULL;
74
 
75
                /* Check if this isn't a single byte option */
76
                if (opt > DCCPO_MAX_RESERVED) {
77
                        if (opt_ptr == opt_end)
78
                                goto out_invalid_option;
79
 
80
                        len = *opt_ptr++;
81
                        if (len < 3)
82
                                goto out_invalid_option;
83
                        /*
84
                         * Remove the type and len fields, leaving
85
                         * just the value size
86
                         */
87
                        len     -= 2;
88
                        value   = opt_ptr;
89
                        opt_ptr += len;
90
 
91
                        if (opt_ptr > opt_end)
92
                                goto out_invalid_option;
93
                }
94
 
95
                switch (opt) {
96
                case DCCPO_PADDING:
97
                        break;
98
                case DCCPO_MANDATORY:
99
                        if (mandatory)
100
                                goto out_invalid_option;
101
                        if (pkt_type != DCCP_PKT_DATA)
102
                                mandatory = 1;
103
                        break;
104
                case DCCPO_NDP_COUNT:
105
                        if (len > 3)
106
                                goto out_invalid_option;
107
 
108
                        opt_recv->dccpor_ndp = dccp_decode_value_var(value, len);
109
                        dccp_pr_debug("%s rx opt: NDP count=%d\n", dccp_role(sk),
110
                                      opt_recv->dccpor_ndp);
111
                        break;
112
                case DCCPO_CHANGE_L:
113
                        /* fall through */
114
                case DCCPO_CHANGE_R:
115
                        if (len < 2)
116
                                goto out_invalid_option;
117
                        rc = dccp_feat_change_recv(sk, opt, *value, value + 1,
118
                                                   len - 1);
119
                        /*
120
                         * When there is a change error, change_recv is
121
                         * responsible for dealing with it.  i.e. reply with an
122
                         * empty confirm.
123
                         * If the change was mandatory, then we need to die.
124
                         */
125
                        if (rc && mandatory)
126
                                goto out_invalid_option;
127
                        break;
128
                case DCCPO_CONFIRM_L:
129
                        /* fall through */
130
                case DCCPO_CONFIRM_R:
131
                        if (len < 2)
132
                                goto out_invalid_option;
133
                        if (dccp_feat_confirm_recv(sk, opt, *value,
134
                                                   value + 1, len - 1))
135
                                goto out_invalid_option;
136
                        break;
137
                case DCCPO_ACK_VECTOR_0:
138
                case DCCPO_ACK_VECTOR_1:
139
                        if (pkt_type == DCCP_PKT_DATA)
140
                                break;
141
 
142
                        if (dccp_msk(sk)->dccpms_send_ack_vector &&
143
                            dccp_ackvec_parse(sk, skb, &ackno, opt, value, len))
144
                                goto out_invalid_option;
145
                        break;
146
                case DCCPO_TIMESTAMP:
147
                        if (len != 4)
148
                                goto out_invalid_option;
149
 
150
                        opt_val = get_unaligned((__be32 *)value);
151
                        opt_recv->dccpor_timestamp = ntohl(opt_val);
152
 
153
                        dp->dccps_timestamp_echo = opt_recv->dccpor_timestamp;
154
                        dp->dccps_timestamp_time = ktime_get_real();
155
 
156
                        dccp_pr_debug("%s rx opt: TIMESTAMP=%u, ackno=%llu\n",
157
                                      dccp_role(sk), opt_recv->dccpor_timestamp,
158
                                      (unsigned long long)
159
                                      DCCP_SKB_CB(skb)->dccpd_ack_seq);
160
                        break;
161
                case DCCPO_TIMESTAMP_ECHO:
162
                        if (len != 4 && len != 6 && len != 8)
163
                                goto out_invalid_option;
164
 
165
                        opt_val = get_unaligned((__be32 *)value);
166
                        opt_recv->dccpor_timestamp_echo = ntohl(opt_val);
167
 
168
                        dccp_pr_debug("%s rx opt: TIMESTAMP_ECHO=%u, len=%d, "
169
                                      "ackno=%llu", dccp_role(sk),
170
                                      opt_recv->dccpor_timestamp_echo,
171
                                      len + 2,
172
                                      (unsigned long long)
173
                                      DCCP_SKB_CB(skb)->dccpd_ack_seq);
174
 
175
                        value += 4;
176
 
177
                        if (len == 4) {         /* no elapsed time included */
178
                                dccp_pr_debug_cat("\n");
179
                                break;
180
                        }
181
 
182
                        if (len == 6) {         /* 2-byte elapsed time */
183
                                __be16 opt_val2 = get_unaligned((__be16 *)value);
184
                                elapsed_time = ntohs(opt_val2);
185
                        } else {                /* 4-byte elapsed time */
186
                                opt_val = get_unaligned((__be32 *)value);
187
                                elapsed_time = ntohl(opt_val);
188
                        }
189
 
190
                        dccp_pr_debug_cat(", ELAPSED_TIME=%u\n", elapsed_time);
191
 
192
                        /* Give precedence to the biggest ELAPSED_TIME */
193
                        if (elapsed_time > opt_recv->dccpor_elapsed_time)
194
                                opt_recv->dccpor_elapsed_time = elapsed_time;
195
                        break;
196
                case DCCPO_ELAPSED_TIME:
197
                        if (len != 2 && len != 4)
198
                                goto out_invalid_option;
199
 
200
                        if (pkt_type == DCCP_PKT_DATA)
201
                                continue;
202
 
203
                        if (len == 2) {
204
                                __be16 opt_val2 = get_unaligned((__be16 *)value);
205
                                elapsed_time = ntohs(opt_val2);
206
                        } else {
207
                                opt_val = get_unaligned((__be32 *)value);
208
                                elapsed_time = ntohl(opt_val);
209
                        }
210
 
211
                        if (elapsed_time > opt_recv->dccpor_elapsed_time)
212
                                opt_recv->dccpor_elapsed_time = elapsed_time;
213
 
214
                        dccp_pr_debug("%s rx opt: ELAPSED_TIME=%d\n",
215
                                      dccp_role(sk), elapsed_time);
216
                        break;
217
                        /*
218
                         * From RFC 4340, sec. 10.3:
219
                         *
220
                         *      Option numbers 128 through 191 are for
221
                         *      options sent from the HC-Sender to the
222
                         *      HC-Receiver; option numbers 192 through 255
223
                         *      are for options sent from the HC-Receiver to
224
                         *      the HC-Sender.
225
                         */
226
                case 128 ... 191: {
227
                        const u16 idx = value - options;
228
 
229
                        if (ccid_hc_rx_parse_options(dp->dccps_hc_rx_ccid, sk,
230
                                                     opt, len, idx,
231
                                                     value) != 0)
232
                                goto out_invalid_option;
233
                }
234
                        break;
235
                case 192 ... 255: {
236
                        const u16 idx = value - options;
237
 
238
                        if (ccid_hc_tx_parse_options(dp->dccps_hc_tx_ccid, sk,
239
                                                     opt, len, idx,
240
                                                     value) != 0)
241
                                goto out_invalid_option;
242
                }
243
                        break;
244
                default:
245
                        DCCP_CRIT("DCCP(%p): option %d(len=%d) not "
246
                                  "implemented, ignoring", sk, opt, len);
247
                        break;
248
                }
249
 
250
                if (opt != DCCPO_MANDATORY)
251
                        mandatory = 0;
252
        }
253
 
254
        /* mandatory was the last byte in option list -> reset connection */
255
        if (mandatory)
256
                goto out_invalid_option;
257
 
258
        return 0;
259
 
260
out_invalid_option:
261
        DCCP_INC_STATS_BH(DCCP_MIB_INVALIDOPT);
262
        DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_OPTION_ERROR;
263
        DCCP_WARN("DCCP(%p): invalid option %d, len=%d", sk, opt, len);
264
        return -1;
265
}
266
 
267
EXPORT_SYMBOL_GPL(dccp_parse_options);
268
 
269
static void dccp_encode_value_var(const u32 value, unsigned char *to,
270
                                  const unsigned int len)
271
{
272
        if (len > 3)
273
                *to++ = (value & 0xFF000000) >> 24;
274
        if (len > 2)
275
                *to++ = (value & 0xFF0000) >> 16;
276
        if (len > 1)
277
                *to++ = (value & 0xFF00) >> 8;
278
        if (len > 0)
279
                *to++ = (value & 0xFF);
280
}
281
 
282
static inline int dccp_ndp_len(const int ndp)
283
{
284
        return likely(ndp <= 0xFF) ? 1 : ndp <= 0xFFFF ? 2 : 3;
285
}
286
 
287
int dccp_insert_option(struct sock *sk, struct sk_buff *skb,
288
                        const unsigned char option,
289
                        const void *value, const unsigned char len)
290
{
291
        unsigned char *to;
292
 
293
        if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 2 > DCCP_MAX_OPT_LEN)
294
                return -1;
295
 
296
        DCCP_SKB_CB(skb)->dccpd_opt_len += len + 2;
297
 
298
        to    = skb_push(skb, len + 2);
299
        *to++ = option;
300
        *to++ = len + 2;
301
 
302
        memcpy(to, value, len);
303
        return 0;
304
}
305
 
306
EXPORT_SYMBOL_GPL(dccp_insert_option);
307
 
308
static int dccp_insert_option_ndp(struct sock *sk, struct sk_buff *skb)
309
{
310
        struct dccp_sock *dp = dccp_sk(sk);
311
        int ndp = dp->dccps_ndp_count;
312
 
313
        if (dccp_non_data_packet(skb))
314
                ++dp->dccps_ndp_count;
315
        else
316
                dp->dccps_ndp_count = 0;
317
 
318
        if (ndp > 0) {
319
                unsigned char *ptr;
320
                const int ndp_len = dccp_ndp_len(ndp);
321
                const int len = ndp_len + 2;
322
 
323
                if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN)
324
                        return -1;
325
 
326
                DCCP_SKB_CB(skb)->dccpd_opt_len += len;
327
 
328
                ptr = skb_push(skb, len);
329
                *ptr++ = DCCPO_NDP_COUNT;
330
                *ptr++ = len;
331
                dccp_encode_value_var(ndp, ptr, ndp_len);
332
        }
333
 
334
        return 0;
335
}
336
 
337
static inline int dccp_elapsed_time_len(const u32 elapsed_time)
338
{
339
        return elapsed_time == 0 ? 0 : elapsed_time <= 0xFFFF ? 2 : 4;
340
}
341
 
342
int dccp_insert_option_elapsed_time(struct sock *sk, struct sk_buff *skb,
343
                                    u32 elapsed_time)
344
{
345
        const int elapsed_time_len = dccp_elapsed_time_len(elapsed_time);
346
        const int len = 2 + elapsed_time_len;
347
        unsigned char *to;
348
 
349
        if (elapsed_time_len == 0)
350
                return 0;
351
 
352
        if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN)
353
                return -1;
354
 
355
        DCCP_SKB_CB(skb)->dccpd_opt_len += len;
356
 
357
        to    = skb_push(skb, len);
358
        *to++ = DCCPO_ELAPSED_TIME;
359
        *to++ = len;
360
 
361
        if (elapsed_time_len == 2) {
362
                const __be16 var16 = htons((u16)elapsed_time);
363
                memcpy(to, &var16, 2);
364
        } else {
365
                const __be32 var32 = htonl(elapsed_time);
366
                memcpy(to, &var32, 4);
367
        }
368
 
369
        return 0;
370
}
371
 
372
EXPORT_SYMBOL_GPL(dccp_insert_option_elapsed_time);
373
 
374
int dccp_insert_option_timestamp(struct sock *sk, struct sk_buff *skb)
375
{
376
        __be32 now = htonl(dccp_timestamp());
377
        /* yes this will overflow but that is the point as we want a
378
         * 10 usec 32 bit timer which mean it wraps every 11.9 hours */
379
 
380
        return dccp_insert_option(sk, skb, DCCPO_TIMESTAMP, &now, sizeof(now));
381
}
382
 
383
EXPORT_SYMBOL_GPL(dccp_insert_option_timestamp);
384
 
385
static int dccp_insert_option_timestamp_echo(struct sock *sk,
386
                                             struct sk_buff *skb)
387
{
388
        struct dccp_sock *dp = dccp_sk(sk);
389
        __be32 tstamp_echo;
390
        int len, elapsed_time_len;
391
        unsigned char *to;
392
        const suseconds_t delta = ktime_us_delta(ktime_get_real(),
393
                                                 dp->dccps_timestamp_time);
394
        u32 elapsed_time = delta / 10;
395
        elapsed_time_len = dccp_elapsed_time_len(elapsed_time);
396
        len = 6 + elapsed_time_len;
397
 
398
        if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN)
399
                return -1;
400
 
401
        DCCP_SKB_CB(skb)->dccpd_opt_len += len;
402
 
403
        to    = skb_push(skb, len);
404
        *to++ = DCCPO_TIMESTAMP_ECHO;
405
        *to++ = len;
406
 
407
        tstamp_echo = htonl(dp->dccps_timestamp_echo);
408
        memcpy(to, &tstamp_echo, 4);
409
        to += 4;
410
 
411
        if (elapsed_time_len == 2) {
412
                const __be16 var16 = htons((u16)elapsed_time);
413
                memcpy(to, &var16, 2);
414
        } else if (elapsed_time_len == 4) {
415
                const __be32 var32 = htonl(elapsed_time);
416
                memcpy(to, &var32, 4);
417
        }
418
 
419
        dp->dccps_timestamp_echo = 0;
420
        dp->dccps_timestamp_time = ktime_set(0, 0);
421
        return 0;
422
}
423
 
424
static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat,
425
                                u8 *val, u8 len)
426
{
427
        u8 *to;
428
 
429
        if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 3 > DCCP_MAX_OPT_LEN) {
430
                DCCP_WARN("packet too small for feature %d option!\n", feat);
431
                return -1;
432
        }
433
 
434
        DCCP_SKB_CB(skb)->dccpd_opt_len += len + 3;
435
 
436
        to    = skb_push(skb, len + 3);
437
        *to++ = type;
438
        *to++ = len + 3;
439
        *to++ = feat;
440
 
441
        if (len)
442
                memcpy(to, val, len);
443
 
444
        dccp_pr_debug("%s(%s (%d), ...), length %d\n",
445
                      dccp_feat_typename(type),
446
                      dccp_feat_name(feat), feat, len);
447
        return 0;
448
}
449
 
450
static int dccp_insert_options_feat(struct sock *sk, struct sk_buff *skb)
451
{
452
        struct dccp_sock *dp = dccp_sk(sk);
453
        struct dccp_minisock *dmsk = dccp_msk(sk);
454
        struct dccp_opt_pend *opt, *next;
455
        int change = 0;
456
 
457
        /* confirm any options [NN opts] */
458
        list_for_each_entry_safe(opt, next, &dmsk->dccpms_conf, dccpop_node) {
459
                dccp_insert_feat_opt(skb, opt->dccpop_type,
460
                                     opt->dccpop_feat, opt->dccpop_val,
461
                                     opt->dccpop_len);
462
                /* fear empty confirms */
463
                if (opt->dccpop_val)
464
                        kfree(opt->dccpop_val);
465
                kfree(opt);
466
        }
467
        INIT_LIST_HEAD(&dmsk->dccpms_conf);
468
 
469
        /* see which features we need to send */
470
        list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
471
                /* see if we need to send any confirm */
472
                if (opt->dccpop_sc) {
473
                        dccp_insert_feat_opt(skb, opt->dccpop_type + 1,
474
                                             opt->dccpop_feat,
475
                                             opt->dccpop_sc->dccpoc_val,
476
                                             opt->dccpop_sc->dccpoc_len);
477
 
478
                        BUG_ON(!opt->dccpop_sc->dccpoc_val);
479
                        kfree(opt->dccpop_sc->dccpoc_val);
480
                        kfree(opt->dccpop_sc);
481
                        opt->dccpop_sc = NULL;
482
                }
483
 
484
                /* any option not confirmed, re-send it */
485
                if (!opt->dccpop_conf) {
486
                        dccp_insert_feat_opt(skb, opt->dccpop_type,
487
                                             opt->dccpop_feat, opt->dccpop_val,
488
                                             opt->dccpop_len);
489
                        change++;
490
                }
491
        }
492
 
493
        /* Retransmit timer.
494
         * If this is the master listening sock, we don't set a timer on it.  It
495
         * should be fine because if the dude doesn't receive our RESPONSE
496
         * [which will contain the CHANGE] he will send another REQUEST which
497
         * will "retrnasmit" the change.
498
         */
499
        if (change && dp->dccps_role != DCCP_ROLE_LISTEN) {
500
                dccp_pr_debug("reset feat negotiation timer %p\n", sk);
501
 
502
                /* XXX don't reset the timer on re-transmissions.  I.e. reset it
503
                 * only when sending new stuff i guess.  Currently the timer
504
                 * never backs off because on re-transmission it just resets it!
505
                 */
506
                inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
507
                                          inet_csk(sk)->icsk_rto, DCCP_RTO_MAX);
508
        }
509
 
510
        return 0;
511
}
512
 
513
int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
514
{
515
        struct dccp_sock *dp = dccp_sk(sk);
516
        struct dccp_minisock *dmsk = dccp_msk(sk);
517
 
518
        DCCP_SKB_CB(skb)->dccpd_opt_len = 0;
519
 
520
        if (dmsk->dccpms_send_ndp_count &&
521
            dccp_insert_option_ndp(sk, skb))
522
                return -1;
523
 
524
        if (!dccp_packet_without_ack(skb)) {
525
                if (dmsk->dccpms_send_ack_vector &&
526
                    dccp_ackvec_pending(dp->dccps_hc_rx_ackvec) &&
527
                    dccp_insert_option_ackvec(sk, skb))
528
                        return -1;
529
 
530
                if (dp->dccps_timestamp_echo != 0 &&
531
                    dccp_insert_option_timestamp_echo(sk, skb))
532
                        return -1;
533
        }
534
 
535
        if (dp->dccps_hc_rx_insert_options) {
536
                if (ccid_hc_rx_insert_options(dp->dccps_hc_rx_ccid, sk, skb))
537
                        return -1;
538
                dp->dccps_hc_rx_insert_options = 0;
539
        }
540
 
541
        /* Feature negotiation */
542
        /* Data packets can't do feat negotiation */
543
        if (DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATA &&
544
            DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATAACK &&
545
            dccp_insert_options_feat(sk, skb))
546
                return -1;
547
 
548
        /*
549
         * Obtain RTT sample from Request/Response exchange.
550
         * This is currently used in CCID 3 initialisation.
551
         */
552
        if (DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_REQUEST &&
553
            dccp_insert_option_timestamp(sk, skb))
554
                return -1;
555
 
556
        /* XXX: insert other options when appropriate */
557
 
558
        if (DCCP_SKB_CB(skb)->dccpd_opt_len != 0) {
559
                /* The length of all options has to be a multiple of 4 */
560
                int padding = DCCP_SKB_CB(skb)->dccpd_opt_len % 4;
561
 
562
                if (padding != 0) {
563
                        padding = 4 - padding;
564
                        memset(skb_push(skb, padding), 0, padding);
565
                        DCCP_SKB_CB(skb)->dccpd_opt_len += padding;
566
                }
567
        }
568
 
569
        return 0;
570
}

powered by: WebSVN 2.1.0

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