diff options
Diffstat (limited to 'net/dccp/ackvec.c')
| -rw-r--r-- | net/dccp/ackvec.c | 296 |
1 files changed, 194 insertions, 102 deletions
diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c index 2c77dafbd091..b5981e5f6b00 100644 --- a/net/dccp/ackvec.c +++ b/net/dccp/ackvec.c | |||
| @@ -13,36 +13,83 @@ | |||
| 13 | #include "dccp.h" | 13 | #include "dccp.h" |
| 14 | 14 | ||
| 15 | #include <linux/dccp.h> | 15 | #include <linux/dccp.h> |
| 16 | #include <linux/init.h> | ||
| 17 | #include <linux/errno.h> | ||
| 18 | #include <linux/kernel.h> | ||
| 16 | #include <linux/skbuff.h> | 19 | #include <linux/skbuff.h> |
| 20 | #include <linux/slab.h> | ||
| 17 | 21 | ||
| 18 | #include <net/sock.h> | 22 | #include <net/sock.h> |
| 19 | 23 | ||
| 24 | static kmem_cache_t *dccp_ackvec_slab; | ||
| 25 | static kmem_cache_t *dccp_ackvec_record_slab; | ||
| 26 | |||
| 27 | static struct dccp_ackvec_record *dccp_ackvec_record_new(void) | ||
| 28 | { | ||
| 29 | struct dccp_ackvec_record *avr = | ||
| 30 | kmem_cache_alloc(dccp_ackvec_record_slab, GFP_ATOMIC); | ||
| 31 | |||
| 32 | if (avr != NULL) | ||
| 33 | INIT_LIST_HEAD(&avr->dccpavr_node); | ||
| 34 | |||
| 35 | return avr; | ||
| 36 | } | ||
| 37 | |||
| 38 | static void dccp_ackvec_record_delete(struct dccp_ackvec_record *avr) | ||
| 39 | { | ||
| 40 | if (unlikely(avr == NULL)) | ||
| 41 | return; | ||
| 42 | /* Check if deleting a linked record */ | ||
| 43 | WARN_ON(!list_empty(&avr->dccpavr_node)); | ||
| 44 | kmem_cache_free(dccp_ackvec_record_slab, avr); | ||
| 45 | } | ||
| 46 | |||
| 47 | static void dccp_ackvec_insert_avr(struct dccp_ackvec *av, | ||
| 48 | struct dccp_ackvec_record *avr) | ||
| 49 | { | ||
| 50 | /* | ||
| 51 | * AVRs are sorted by seqno. Since we are sending them in order, we | ||
| 52 | * just add the AVR at the head of the list. | ||
| 53 | * -sorbo. | ||
| 54 | */ | ||
| 55 | if (!list_empty(&av->dccpav_records)) { | ||
| 56 | const struct dccp_ackvec_record *head = | ||
| 57 | list_entry(av->dccpav_records.next, | ||
| 58 | struct dccp_ackvec_record, | ||
| 59 | dccpavr_node); | ||
| 60 | BUG_ON(before48(avr->dccpavr_ack_seqno, | ||
| 61 | head->dccpavr_ack_seqno)); | ||
| 62 | } | ||
| 63 | |||
| 64 | list_add(&avr->dccpavr_node, &av->dccpav_records); | ||
| 65 | } | ||
| 66 | |||
| 20 | int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) | 67 | int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) |
| 21 | { | 68 | { |
| 22 | struct dccp_sock *dp = dccp_sk(sk); | 69 | struct dccp_sock *dp = dccp_sk(sk); |
| 70 | #ifdef CONFIG_IP_DCCP_DEBUG | ||
| 71 | const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? | ||
| 72 | "CLIENT tx: " : "server tx: "; | ||
| 73 | #endif | ||
| 23 | struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec; | 74 | struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec; |
| 24 | int len = av->dccpav_vec_len + 2; | 75 | int len = av->dccpav_vec_len + 2; |
| 25 | struct timeval now; | 76 | struct timeval now; |
| 26 | u32 elapsed_time; | 77 | u32 elapsed_time; |
| 27 | unsigned char *to, *from; | 78 | unsigned char *to, *from; |
| 79 | struct dccp_ackvec_record *avr; | ||
| 80 | |||
| 81 | if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) | ||
| 82 | return -1; | ||
| 28 | 83 | ||
| 29 | dccp_timestamp(sk, &now); | 84 | dccp_timestamp(sk, &now); |
| 30 | elapsed_time = timeval_delta(&now, &av->dccpav_time) / 10; | 85 | elapsed_time = timeval_delta(&now, &av->dccpav_time) / 10; |
| 31 | 86 | ||
| 32 | if (elapsed_time != 0) | 87 | if (elapsed_time != 0 && |
| 33 | dccp_insert_option_elapsed_time(sk, skb, elapsed_time); | 88 | dccp_insert_option_elapsed_time(sk, skb, elapsed_time)) |
| 34 | |||
| 35 | if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) | ||
| 36 | return -1; | 89 | return -1; |
| 37 | 90 | ||
| 38 | /* | 91 | avr = dccp_ackvec_record_new(); |
| 39 | * XXX: now we have just one ack vector sent record, so | 92 | if (avr == NULL) |
| 40 | * we have to wait for it to be cleared. | ||
| 41 | * | ||
| 42 | * Of course this is not acceptable, but this is just for | ||
| 43 | * basic testing now. | ||
| 44 | */ | ||
| 45 | if (av->dccpav_ack_seqno != DCCP_MAX_SEQNO + 1) | ||
| 46 | return -1; | 93 | return -1; |
| 47 | 94 | ||
| 48 | DCCP_SKB_CB(skb)->dccpd_opt_len += len; | 95 | DCCP_SKB_CB(skb)->dccpd_opt_len += len; |
| @@ -55,8 +102,8 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) | |||
| 55 | from = av->dccpav_buf + av->dccpav_buf_head; | 102 | from = av->dccpav_buf + av->dccpav_buf_head; |
| 56 | 103 | ||
| 57 | /* Check if buf_head wraps */ | 104 | /* Check if buf_head wraps */ |
| 58 | if ((int)av->dccpav_buf_head + len > av->dccpav_vec_len) { | 105 | if ((int)av->dccpav_buf_head + len > DCCP_MAX_ACKVEC_LEN) { |
| 59 | const u32 tailsize = av->dccpav_vec_len - av->dccpav_buf_head; | 106 | const u32 tailsize = DCCP_MAX_ACKVEC_LEN - av->dccpav_buf_head; |
| 60 | 107 | ||
| 61 | memcpy(to, from, tailsize); | 108 | memcpy(to, from, tailsize); |
| 62 | to += tailsize; | 109 | to += tailsize; |
| @@ -73,45 +120,37 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) | |||
| 73 | * sequence number it used for the ack packet; ack_ptr will equal | 120 | * sequence number it used for the ack packet; ack_ptr will equal |
| 74 | * buf_head; ack_ackno will equal buf_ackno; and ack_nonce will | 121 | * buf_head; ack_ackno will equal buf_ackno; and ack_nonce will |
| 75 | * equal buf_nonce. | 122 | * equal buf_nonce. |
| 76 | * | ||
| 77 | * This implemention uses just one ack record for now. | ||
| 78 | */ | 123 | */ |
| 79 | av->dccpav_ack_seqno = DCCP_SKB_CB(skb)->dccpd_seq; | 124 | avr->dccpavr_ack_seqno = DCCP_SKB_CB(skb)->dccpd_seq; |
| 80 | av->dccpav_ack_ptr = av->dccpav_buf_head; | 125 | avr->dccpavr_ack_ptr = av->dccpav_buf_head; |
| 81 | av->dccpav_ack_ackno = av->dccpav_buf_ackno; | 126 | avr->dccpavr_ack_ackno = av->dccpav_buf_ackno; |
| 82 | av->dccpav_ack_nonce = av->dccpav_buf_nonce; | 127 | avr->dccpavr_ack_nonce = av->dccpav_buf_nonce; |
| 83 | av->dccpav_sent_len = av->dccpav_vec_len; | 128 | avr->dccpavr_sent_len = av->dccpav_vec_len; |
| 129 | |||
| 130 | dccp_ackvec_insert_avr(av, avr); | ||
| 84 | 131 | ||
| 85 | dccp_pr_debug("%sACK Vector 0, len=%d, ack_seqno=%llu, " | 132 | dccp_pr_debug("%sACK Vector 0, len=%d, ack_seqno=%llu, " |
| 86 | "ack_ackno=%llu\n", | 133 | "ack_ackno=%llu\n", |
| 87 | debug_prefix, av->dccpav_sent_len, | 134 | debug_prefix, avr->dccpavr_sent_len, |
| 88 | (unsigned long long)av->dccpav_ack_seqno, | 135 | (unsigned long long)avr->dccpavr_ack_seqno, |
| 89 | (unsigned long long)av->dccpav_ack_ackno); | 136 | (unsigned long long)avr->dccpavr_ack_ackno); |
| 90 | return -1; | 137 | return 0; |
| 91 | } | 138 | } |
| 92 | 139 | ||
| 93 | struct dccp_ackvec *dccp_ackvec_alloc(const unsigned int len, | 140 | struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority) |
| 94 | const gfp_t priority) | ||
| 95 | { | 141 | { |
| 96 | struct dccp_ackvec *av; | 142 | struct dccp_ackvec *av = kmem_cache_alloc(dccp_ackvec_slab, priority); |
| 97 | |||
| 98 | BUG_ON(len == 0); | ||
| 99 | 143 | ||
| 100 | if (len > DCCP_MAX_ACKVEC_LEN) | ||
| 101 | return NULL; | ||
| 102 | |||
| 103 | av = kmalloc(sizeof(*av) + len, priority); | ||
| 104 | if (av != NULL) { | 144 | if (av != NULL) { |
| 105 | av->dccpav_buf_len = len; | ||
| 106 | av->dccpav_buf_head = | 145 | av->dccpav_buf_head = |
| 107 | av->dccpav_buf_tail = av->dccpav_buf_len - 1; | 146 | av->dccpav_buf_tail = DCCP_MAX_ACKVEC_LEN - 1; |
| 108 | av->dccpav_buf_ackno = | 147 | av->dccpav_buf_ackno = DCCP_MAX_SEQNO + 1; |
| 109 | av->dccpav_ack_ackno = av->dccpav_ack_seqno = ~0LLU; | ||
| 110 | av->dccpav_buf_nonce = av->dccpav_buf_nonce = 0; | 148 | av->dccpav_buf_nonce = av->dccpav_buf_nonce = 0; |
| 111 | av->dccpav_ack_ptr = 0; | 149 | av->dccpav_ack_ptr = 0; |
| 112 | av->dccpav_time.tv_sec = 0; | 150 | av->dccpav_time.tv_sec = 0; |
| 113 | av->dccpav_time.tv_usec = 0; | 151 | av->dccpav_time.tv_usec = 0; |
| 114 | av->dccpav_sent_len = av->dccpav_vec_len = 0; | 152 | av->dccpav_sent_len = av->dccpav_vec_len = 0; |
| 153 | INIT_LIST_HEAD(&av->dccpav_records); | ||
| 115 | } | 154 | } |
| 116 | 155 | ||
| 117 | return av; | 156 | return av; |
| @@ -119,7 +158,20 @@ struct dccp_ackvec *dccp_ackvec_alloc(const unsigned int len, | |||
| 119 | 158 | ||
| 120 | void dccp_ackvec_free(struct dccp_ackvec *av) | 159 | void dccp_ackvec_free(struct dccp_ackvec *av) |
| 121 | { | 160 | { |
| 122 | kfree(av); | 161 | if (unlikely(av == NULL)) |
| 162 | return; | ||
| 163 | |||
| 164 | if (!list_empty(&av->dccpav_records)) { | ||
| 165 | struct dccp_ackvec_record *avr, *next; | ||
| 166 | |||
| 167 | list_for_each_entry_safe(avr, next, &av->dccpav_records, | ||
| 168 | dccpavr_node) { | ||
| 169 | list_del_init(&avr->dccpavr_node); | ||
| 170 | dccp_ackvec_record_delete(avr); | ||
| 171 | } | ||
| 172 | } | ||
| 173 | |||
| 174 | kmem_cache_free(dccp_ackvec_slab, av); | ||
| 123 | } | 175 | } |
| 124 | 176 | ||
| 125 | static inline u8 dccp_ackvec_state(const struct dccp_ackvec *av, | 177 | static inline u8 dccp_ackvec_state(const struct dccp_ackvec *av, |
| @@ -146,7 +198,7 @@ static inline int dccp_ackvec_set_buf_head_state(struct dccp_ackvec *av, | |||
| 146 | unsigned int gap; | 198 | unsigned int gap; |
| 147 | long new_head; | 199 | long new_head; |
| 148 | 200 | ||
| 149 | if (av->dccpav_vec_len + packets > av->dccpav_buf_len) | 201 | if (av->dccpav_vec_len + packets > DCCP_MAX_ACKVEC_LEN) |
| 150 | return -ENOBUFS; | 202 | return -ENOBUFS; |
| 151 | 203 | ||
| 152 | gap = packets - 1; | 204 | gap = packets - 1; |
| @@ -158,7 +210,7 @@ static inline int dccp_ackvec_set_buf_head_state(struct dccp_ackvec *av, | |||
| 158 | gap + new_head + 1); | 210 | gap + new_head + 1); |
| 159 | gap = -new_head; | 211 | gap = -new_head; |
| 160 | } | 212 | } |
| 161 | new_head += av->dccpav_buf_len; | 213 | new_head += DCCP_MAX_ACKVEC_LEN; |
| 162 | } | 214 | } |
| 163 | 215 | ||
| 164 | av->dccpav_buf_head = new_head; | 216 | av->dccpav_buf_head = new_head; |
| @@ -251,7 +303,7 @@ int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk, | |||
| 251 | goto out_duplicate; | 303 | goto out_duplicate; |
| 252 | 304 | ||
| 253 | delta -= len + 1; | 305 | delta -= len + 1; |
| 254 | if (++index == av->dccpav_buf_len) | 306 | if (++index == DCCP_MAX_ACKVEC_LEN) |
| 255 | index = 0; | 307 | index = 0; |
| 256 | } | 308 | } |
| 257 | } | 309 | } |
| @@ -259,7 +311,6 @@ int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk, | |||
| 259 | av->dccpav_buf_ackno = ackno; | 311 | av->dccpav_buf_ackno = ackno; |
| 260 | dccp_timestamp(sk, &av->dccpav_time); | 312 | dccp_timestamp(sk, &av->dccpav_time); |
| 261 | out: | 313 | out: |
| 262 | dccp_pr_debug(""); | ||
| 263 | return 0; | 314 | return 0; |
| 264 | 315 | ||
| 265 | out_duplicate: | 316 | out_duplicate: |
| @@ -297,44 +348,50 @@ void dccp_ackvec_print(const struct dccp_ackvec *av) | |||
| 297 | } | 348 | } |
| 298 | #endif | 349 | #endif |
| 299 | 350 | ||
| 300 | static void dccp_ackvec_throw_away_ack_record(struct dccp_ackvec *av) | 351 | static void dccp_ackvec_throw_record(struct dccp_ackvec *av, |
| 352 | struct dccp_ackvec_record *avr) | ||
| 301 | { | 353 | { |
| 302 | /* | 354 | struct dccp_ackvec_record *next; |
| 303 | * As we're keeping track of the ack vector size (dccpav_vec_len) and | 355 | |
| 304 | * the sent ack vector size (dccpav_sent_len) we don't need | 356 | av->dccpav_buf_tail = avr->dccpavr_ack_ptr - 1; |
| 305 | * dccpav_buf_tail at all, but keep this code here as in the future | 357 | if (av->dccpav_buf_tail == 0) |
| 306 | * we'll implement a vector of ack records, as suggested in | 358 | av->dccpav_buf_tail = DCCP_MAX_ACKVEC_LEN - 1; |
| 307 | * draft-ietf-dccp-spec-11.txt Appendix A. -acme | 359 | |
| 308 | */ | 360 | av->dccpav_vec_len -= avr->dccpavr_sent_len; |
| 309 | #if 0 | 361 | |
| 310 | u32 new_buf_tail = av->dccpav_ack_ptr + 1; | 362 | /* free records */ |
| 311 | if (new_buf_tail >= av->dccpav_vec_len) | 363 | list_for_each_entry_safe_from(avr, next, &av->dccpav_records, |
| 312 | new_buf_tail -= av->dccpav_vec_len; | 364 | dccpavr_node) { |
| 313 | av->dccpav_buf_tail = new_buf_tail; | 365 | list_del_init(&avr->dccpavr_node); |
| 314 | #endif | 366 | dccp_ackvec_record_delete(avr); |
| 315 | av->dccpav_vec_len -= av->dccpav_sent_len; | 367 | } |
| 316 | } | 368 | } |
| 317 | 369 | ||
| 318 | void dccp_ackvec_check_rcv_ackno(struct dccp_ackvec *av, struct sock *sk, | 370 | void dccp_ackvec_check_rcv_ackno(struct dccp_ackvec *av, struct sock *sk, |
| 319 | const u64 ackno) | 371 | const u64 ackno) |
| 320 | { | 372 | { |
| 321 | /* Check if we actually sent an ACK vector */ | 373 | struct dccp_ackvec_record *avr; |
| 322 | if (av->dccpav_ack_seqno == DCCP_MAX_SEQNO + 1) | ||
| 323 | return; | ||
| 324 | 374 | ||
| 325 | if (ackno == av->dccpav_ack_seqno) { | 375 | /* |
| 376 | * If we traverse backwards, it should be faster when we have large | ||
| 377 | * windows. We will be receiving ACKs for stuff we sent a while back | ||
| 378 | * -sorbo. | ||
| 379 | */ | ||
| 380 | list_for_each_entry_reverse(avr, &av->dccpav_records, dccpavr_node) { | ||
| 381 | if (ackno == avr->dccpavr_ack_seqno) { | ||
| 326 | #ifdef CONFIG_IP_DCCP_DEBUG | 382 | #ifdef CONFIG_IP_DCCP_DEBUG |
| 327 | struct dccp_sock *dp = dccp_sk(sk); | 383 | struct dccp_sock *dp = dccp_sk(sk); |
| 328 | const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? | 384 | const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? |
| 329 | "CLIENT rx ack: " : "server rx ack: "; | 385 | "CLIENT rx ack: " : "server rx ack: "; |
| 330 | #endif | 386 | #endif |
| 331 | dccp_pr_debug("%sACK packet 0, len=%d, ack_seqno=%llu, " | 387 | dccp_pr_debug("%sACK packet 0, len=%d, ack_seqno=%llu, " |
| 332 | "ack_ackno=%llu, ACKED!\n", | 388 | "ack_ackno=%llu, ACKED!\n", |
| 333 | debug_prefix, 1, | 389 | debug_prefix, 1, |
| 334 | (unsigned long long)av->dccpav_ack_seqno, | 390 | (unsigned long long)avr->dccpavr_ack_seqno, |
| 335 | (unsigned long long)av->dccpav_ack_ackno); | 391 | (unsigned long long)avr->dccpavr_ack_ackno); |
| 336 | dccp_ackvec_throw_away_ack_record(av); | 392 | dccp_ackvec_throw_record(av, avr); |
| 337 | av->dccpav_ack_seqno = DCCP_MAX_SEQNO + 1; | 393 | break; |
| 394 | } | ||
| 338 | } | 395 | } |
| 339 | } | 396 | } |
| 340 | 397 | ||
| @@ -344,28 +401,20 @@ static void dccp_ackvec_check_rcv_ackvector(struct dccp_ackvec *av, | |||
| 344 | const unsigned char *vector) | 401 | const unsigned char *vector) |
| 345 | { | 402 | { |
| 346 | unsigned char i; | 403 | unsigned char i; |
| 404 | struct dccp_ackvec_record *avr; | ||
| 347 | 405 | ||
| 348 | /* Check if we actually sent an ACK vector */ | 406 | /* Check if we actually sent an ACK vector */ |
| 349 | if (av->dccpav_ack_seqno == DCCP_MAX_SEQNO + 1) | 407 | if (list_empty(&av->dccpav_records)) |
| 350 | return; | ||
| 351 | /* | ||
| 352 | * We're in the receiver half connection, so if the received an ACK | ||
| 353 | * vector ackno (e.g. 50) before dccpav_ack_seqno (e.g. 52), we're | ||
| 354 | * not interested. | ||
| 355 | * | ||
| 356 | * Extra explanation with example: | ||
| 357 | * | ||
| 358 | * if we received an ACK vector with ackno 50, it can only be acking | ||
| 359 | * 50, 49, 48, etc, not 52 (the seqno for the ACK vector we sent). | ||
| 360 | */ | ||
| 361 | /* dccp_pr_debug("is %llu < %llu? ", ackno, av->dccpav_ack_seqno); */ | ||
| 362 | if (before48(ackno, av->dccpav_ack_seqno)) { | ||
| 363 | /* dccp_pr_debug_cat("yes\n"); */ | ||
| 364 | return; | 408 | return; |
| 365 | } | ||
| 366 | /* dccp_pr_debug_cat("no\n"); */ | ||
| 367 | 409 | ||
| 368 | i = len; | 410 | i = len; |
| 411 | /* | ||
| 412 | * XXX | ||
| 413 | * I think it might be more efficient to work backwards. See comment on | ||
| 414 | * rcv_ackno. -sorbo. | ||
| 415 | */ | ||
| 416 | avr = list_entry(av->dccpav_records.next, struct dccp_ackvec_record, | ||
| 417 | dccpavr_node); | ||
| 369 | while (i--) { | 418 | while (i--) { |
| 370 | const u8 rl = *vector & DCCP_ACKVEC_LEN_MASK; | 419 | const u8 rl = *vector & DCCP_ACKVEC_LEN_MASK; |
| 371 | u64 ackno_end_rl; | 420 | u64 ackno_end_rl; |
| @@ -373,14 +422,20 @@ static void dccp_ackvec_check_rcv_ackvector(struct dccp_ackvec *av, | |||
| 373 | dccp_set_seqno(&ackno_end_rl, ackno - rl); | 422 | dccp_set_seqno(&ackno_end_rl, ackno - rl); |
| 374 | 423 | ||
| 375 | /* | 424 | /* |
| 376 | * dccp_pr_debug("is %llu <= %llu <= %llu? ", ackno_end_rl, | 425 | * If our AVR sequence number is greater than the ack, go |
| 377 | * av->dccpav_ack_seqno, ackno); | 426 | * forward in the AVR list until it is not so. |
| 378 | */ | 427 | */ |
| 379 | if (between48(av->dccpav_ack_seqno, ackno_end_rl, ackno)) { | 428 | list_for_each_entry_from(avr, &av->dccpav_records, |
| 429 | dccpavr_node) { | ||
| 430 | if (!after48(avr->dccpavr_ack_seqno, ackno)) | ||
| 431 | goto found; | ||
| 432 | } | ||
| 433 | /* End of the dccpav_records list, not found, exit */ | ||
| 434 | break; | ||
| 435 | found: | ||
| 436 | if (between48(avr->dccpavr_ack_seqno, ackno_end_rl, ackno)) { | ||
| 380 | const u8 state = (*vector & | 437 | const u8 state = (*vector & |
| 381 | DCCP_ACKVEC_STATE_MASK) >> 6; | 438 | DCCP_ACKVEC_STATE_MASK) >> 6; |
| 382 | /* dccp_pr_debug_cat("yes\n"); */ | ||
| 383 | |||
| 384 | if (state != DCCP_ACKVEC_STATE_NOT_RECEIVED) { | 439 | if (state != DCCP_ACKVEC_STATE_NOT_RECEIVED) { |
| 385 | #ifdef CONFIG_IP_DCCP_DEBUG | 440 | #ifdef CONFIG_IP_DCCP_DEBUG |
| 386 | struct dccp_sock *dp = dccp_sk(sk); | 441 | struct dccp_sock *dp = dccp_sk(sk); |
| @@ -393,19 +448,16 @@ static void dccp_ackvec_check_rcv_ackvector(struct dccp_ackvec *av, | |||
| 393 | "ACKED!\n", | 448 | "ACKED!\n", |
| 394 | debug_prefix, len, | 449 | debug_prefix, len, |
| 395 | (unsigned long long) | 450 | (unsigned long long) |
| 396 | av->dccpav_ack_seqno, | 451 | avr->dccpavr_ack_seqno, |
| 397 | (unsigned long long) | 452 | (unsigned long long) |
| 398 | av->dccpav_ack_ackno); | 453 | avr->dccpavr_ack_ackno); |
| 399 | dccp_ackvec_throw_away_ack_record(av); | 454 | dccp_ackvec_throw_record(av, avr); |
| 400 | } | 455 | } |
| 401 | /* | 456 | /* |
| 402 | * If dccpav_ack_seqno was not received, no problem | 457 | * If it wasn't received, continue scanning... we might |
| 403 | * we'll send another ACK vector. | 458 | * find another one. |
| 404 | */ | 459 | */ |
| 405 | av->dccpav_ack_seqno = DCCP_MAX_SEQNO + 1; | ||
| 406 | break; | ||
| 407 | } | 460 | } |
| 408 | /* dccp_pr_debug_cat("no\n"); */ | ||
| 409 | 461 | ||
| 410 | dccp_set_seqno(&ackno, ackno_end_rl - 1); | 462 | dccp_set_seqno(&ackno, ackno_end_rl - 1); |
| 411 | ++vector; | 463 | ++vector; |
| @@ -424,3 +476,43 @@ int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb, | |||
| 424 | len, value); | 476 | len, value); |
| 425 | return 0; | 477 | return 0; |
| 426 | } | 478 | } |
| 479 | |||
| 480 | static char dccp_ackvec_slab_msg[] __initdata = | ||
| 481 | KERN_CRIT "DCCP: Unable to create ack vectors slab caches\n"; | ||
| 482 | |||
| 483 | int __init dccp_ackvec_init(void) | ||
| 484 | { | ||
| 485 | dccp_ackvec_slab = kmem_cache_create("dccp_ackvec", | ||
| 486 | sizeof(struct dccp_ackvec), 0, | ||
| 487 | SLAB_HWCACHE_ALIGN, NULL, NULL); | ||
| 488 | if (dccp_ackvec_slab == NULL) | ||
| 489 | goto out_err; | ||
| 490 | |||
| 491 | dccp_ackvec_record_slab = | ||
| 492 | kmem_cache_create("dccp_ackvec_record", | ||
| 493 | sizeof(struct dccp_ackvec_record), | ||
| 494 | 0, SLAB_HWCACHE_ALIGN, NULL, NULL); | ||
| 495 | if (dccp_ackvec_record_slab == NULL) | ||
| 496 | goto out_destroy_slab; | ||
| 497 | |||
| 498 | return 0; | ||
| 499 | |||
| 500 | out_destroy_slab: | ||
| 501 | kmem_cache_destroy(dccp_ackvec_slab); | ||
| 502 | dccp_ackvec_slab = NULL; | ||
| 503 | out_err: | ||
| 504 | printk(dccp_ackvec_slab_msg); | ||
| 505 | return -ENOBUFS; | ||
| 506 | } | ||
| 507 | |||
| 508 | void dccp_ackvec_exit(void) | ||
| 509 | { | ||
| 510 | if (dccp_ackvec_slab != NULL) { | ||
| 511 | kmem_cache_destroy(dccp_ackvec_slab); | ||
| 512 | dccp_ackvec_slab = NULL; | ||
| 513 | } | ||
| 514 | if (dccp_ackvec_record_slab != NULL) { | ||
| 515 | kmem_cache_destroy(dccp_ackvec_record_slab); | ||
| 516 | dccp_ackvec_record_slab = NULL; | ||
| 517 | } | ||
| 518 | } | ||
