diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/dccp/ackvec.c | 100 | ||||
-rw-r--r-- | net/dccp/ackvec.h | 2 | ||||
-rw-r--r-- | net/dccp/options.c | 60 |
3 files changed, 79 insertions, 83 deletions
diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c index 17bf10f96057..af976fca407a 100644 --- a/net/dccp/ackvec.c +++ b/net/dccp/ackvec.c | |||
@@ -52,99 +52,35 @@ void dccp_ackvec_free(struct dccp_ackvec *av) | |||
52 | } | 52 | } |
53 | } | 53 | } |
54 | 54 | ||
55 | static void dccp_ackvec_insert_avr(struct dccp_ackvec *av, | 55 | /** |
56 | struct dccp_ackvec_record *avr) | 56 | * dccp_ackvec_update_records - Record information about sent Ack Vectors |
57 | { | 57 | * @av: Ack Vector records to update |
58 | /* | 58 | * @seqno: Sequence number of the packet carrying the Ack Vector just sent |
59 | * AVRs are sorted by seqno. Since we are sending them in order, we | 59 | * @nonce_sum: The sum of all buffer nonces contained in the Ack Vector |
60 | * just add the AVR at the head of the list. | 60 | */ |
61 | * -sorbo. | 61 | int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seqno, u8 nonce_sum) |
62 | */ | ||
63 | if (!list_empty(&av->av_records)) { | ||
64 | const struct dccp_ackvec_record *head = | ||
65 | list_entry(av->av_records.next, | ||
66 | struct dccp_ackvec_record, | ||
67 | avr_node); | ||
68 | BUG_ON(before48(avr->avr_ack_seqno, head->avr_ack_seqno)); | ||
69 | } | ||
70 | |||
71 | list_add(&avr->avr_node, &av->av_records); | ||
72 | } | ||
73 | |||
74 | int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) | ||
75 | { | 62 | { |
76 | struct dccp_sock *dp = dccp_sk(sk); | ||
77 | struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec; | ||
78 | /* Figure out how many options do we need to represent the ackvec */ | ||
79 | const u8 nr_opts = DIV_ROUND_UP(av->av_vec_len, DCCP_SINGLE_OPT_MAXLEN); | ||
80 | u16 len = av->av_vec_len + 2 * nr_opts; | ||
81 | u8 i, nonce = 0; | ||
82 | const unsigned char *tail, *from; | ||
83 | unsigned char *to; | ||
84 | struct dccp_ackvec_record *avr; | 63 | struct dccp_ackvec_record *avr; |
85 | 64 | ||
86 | if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) | ||
87 | return -1; | ||
88 | |||
89 | avr = kmem_cache_alloc(dccp_ackvec_record_slab, GFP_ATOMIC); | 65 | avr = kmem_cache_alloc(dccp_ackvec_record_slab, GFP_ATOMIC); |
90 | if (avr == NULL) | 66 | if (avr == NULL) |
91 | return -1; | 67 | return -ENOBUFS; |
92 | |||
93 | DCCP_SKB_CB(skb)->dccpd_opt_len += len; | ||
94 | |||
95 | to = skb_push(skb, len); | ||
96 | len = av->av_vec_len; | ||
97 | from = av->av_buf + av->av_buf_head; | ||
98 | tail = av->av_buf + DCCPAV_MAX_ACKVEC_LEN; | ||
99 | |||
100 | for (i = 0; i < nr_opts; ++i) { | ||
101 | int copylen = len; | ||
102 | |||
103 | if (len > DCCP_SINGLE_OPT_MAXLEN) | ||
104 | copylen = DCCP_SINGLE_OPT_MAXLEN; | ||
105 | |||
106 | /* | ||
107 | * RFC 4340, 12.2: Encode the Nonce Echo for this Ack Vector via | ||
108 | * its type; ack_nonce is the sum of all individual buf_nonce's. | ||
109 | */ | ||
110 | nonce ^= av->av_buf_nonce[i]; | ||
111 | |||
112 | *to++ = DCCPO_ACK_VECTOR_0 + av->av_buf_nonce[i]; | ||
113 | *to++ = copylen + 2; | ||
114 | |||
115 | /* Check if buf_head wraps */ | ||
116 | if (from + copylen > tail) { | ||
117 | const u16 tailsize = tail - from; | ||
118 | |||
119 | memcpy(to, from, tailsize); | ||
120 | to += tailsize; | ||
121 | len -= tailsize; | ||
122 | copylen -= tailsize; | ||
123 | from = av->av_buf; | ||
124 | } | ||
125 | |||
126 | memcpy(to, from, copylen); | ||
127 | from += copylen; | ||
128 | to += copylen; | ||
129 | len -= copylen; | ||
130 | } | ||
131 | 68 | ||
132 | /* | 69 | avr->avr_ack_seqno = seqno; |
133 | * Each sent Ack Vector is recorded in the list, as per A.2 of RFC 4340. | ||
134 | */ | ||
135 | avr->avr_ack_seqno = DCCP_SKB_CB(skb)->dccpd_seq; | ||
136 | avr->avr_ack_ptr = av->av_buf_head; | 70 | avr->avr_ack_ptr = av->av_buf_head; |
137 | avr->avr_ack_ackno = av->av_buf_ackno; | 71 | avr->avr_ack_ackno = av->av_buf_ackno; |
138 | avr->avr_ack_nonce = nonce; | 72 | avr->avr_ack_nonce = nonce_sum; |
139 | avr->avr_ack_runlen = dccp_ackvec_runlen(av->av_buf + av->av_buf_head); | 73 | avr->avr_ack_runlen = dccp_ackvec_runlen(av->av_buf + av->av_buf_head); |
74 | /* | ||
75 | * Since GSS is incremented for each packet, the list is automatically | ||
76 | * arranged in descending order of @ack_seqno. | ||
77 | */ | ||
78 | list_add(&avr->avr_node, &av->av_records); | ||
140 | 79 | ||
141 | dccp_ackvec_insert_avr(av, avr); | 80 | dccp_pr_debug("Added Vector, ack_seqno=%llu, ack_ackno=%llu (rl=%u)\n", |
142 | |||
143 | dccp_pr_debug("%s ACK Vector 0, len=%d, ack_seqno=%llu, " | ||
144 | "ack_ackno=%llu\n", | ||
145 | dccp_role(sk), avr->avr_ack_runlen, | ||
146 | (unsigned long long)avr->avr_ack_seqno, | 81 | (unsigned long long)avr->avr_ack_seqno, |
147 | (unsigned long long)avr->avr_ack_ackno); | 82 | (unsigned long long)avr->avr_ack_ackno, |
83 | avr->avr_ack_runlen); | ||
148 | return 0; | 84 | return 0; |
149 | } | 85 | } |
150 | 86 | ||
diff --git a/net/dccp/ackvec.h b/net/dccp/ackvec.h index ebcbbc726cff..3e894a0173a7 100644 --- a/net/dccp/ackvec.h +++ b/net/dccp/ackvec.h | |||
@@ -111,7 +111,7 @@ extern int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb, | |||
111 | u64 *ackno, const u8 opt, | 111 | u64 *ackno, const u8 opt, |
112 | const u8 *value, const u8 len); | 112 | const u8 *value, const u8 len); |
113 | 113 | ||
114 | extern int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb); | 114 | extern int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seq, u8 sum); |
115 | 115 | ||
116 | static inline int dccp_ackvec_pending(const struct dccp_ackvec *av) | 116 | static inline int dccp_ackvec_pending(const struct dccp_ackvec *av) |
117 | { | 117 | { |
diff --git a/net/dccp/options.c b/net/dccp/options.c index 799c6f4547cd..f4ff0a308269 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c | |||
@@ -425,6 +425,66 @@ static int dccp_insert_option_timestamp_echo(struct dccp_sock *dp, | |||
425 | return 0; | 425 | return 0; |
426 | } | 426 | } |
427 | 427 | ||
428 | static int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) | ||
429 | { | ||
430 | struct dccp_sock *dp = dccp_sk(sk); | ||
431 | struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec; | ||
432 | /* Figure out how many options do we need to represent the ackvec */ | ||
433 | const u8 nr_opts = DIV_ROUND_UP(av->av_vec_len, DCCP_SINGLE_OPT_MAXLEN); | ||
434 | u16 len = av->av_vec_len + 2 * nr_opts; | ||
435 | u8 i, nonce = 0; | ||
436 | const unsigned char *tail, *from; | ||
437 | unsigned char *to; | ||
438 | |||
439 | if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) | ||
440 | return -1; | ||
441 | |||
442 | DCCP_SKB_CB(skb)->dccpd_opt_len += len; | ||
443 | |||
444 | to = skb_push(skb, len); | ||
445 | len = av->av_vec_len; | ||
446 | from = av->av_buf + av->av_buf_head; | ||
447 | tail = av->av_buf + DCCPAV_MAX_ACKVEC_LEN; | ||
448 | |||
449 | for (i = 0; i < nr_opts; ++i) { | ||
450 | int copylen = len; | ||
451 | |||
452 | if (len > DCCP_SINGLE_OPT_MAXLEN) | ||
453 | copylen = DCCP_SINGLE_OPT_MAXLEN; | ||
454 | |||
455 | /* | ||
456 | * RFC 4340, 12.2: Encode the Nonce Echo for this Ack Vector via | ||
457 | * its type; ack_nonce is the sum of all individual buf_nonce's. | ||
458 | */ | ||
459 | nonce ^= av->av_buf_nonce[i]; | ||
460 | |||
461 | *to++ = DCCPO_ACK_VECTOR_0 + av->av_buf_nonce[i]; | ||
462 | *to++ = copylen + 2; | ||
463 | |||
464 | /* Check if buf_head wraps */ | ||
465 | if (from + copylen > tail) { | ||
466 | const u16 tailsize = tail - from; | ||
467 | |||
468 | memcpy(to, from, tailsize); | ||
469 | to += tailsize; | ||
470 | len -= tailsize; | ||
471 | copylen -= tailsize; | ||
472 | from = av->av_buf; | ||
473 | } | ||
474 | |||
475 | memcpy(to, from, copylen); | ||
476 | from += copylen; | ||
477 | to += copylen; | ||
478 | len -= copylen; | ||
479 | } | ||
480 | /* | ||
481 | * Each sent Ack Vector is recorded in the list, as per A.2 of RFC 4340. | ||
482 | */ | ||
483 | if (dccp_ackvec_update_records(av, DCCP_SKB_CB(skb)->dccpd_seq, nonce)) | ||
484 | return -ENOBUFS; | ||
485 | return 0; | ||
486 | } | ||
487 | |||
428 | /** | 488 | /** |
429 | * dccp_insert_option_mandatory - Mandatory option (5.8.2) | 489 | * dccp_insert_option_mandatory - Mandatory option (5.8.2) |
430 | * Note that since we are using skb_push, this function needs to be called | 490 | * Note that since we are using skb_push, this function needs to be called |