1 /* 2 * net/dccp/feat.c 3 * 4 * An implementation of the DCCP protocol 5 * Andrea Bittau <a.bittau@cs.ucl.ac.uk> 6 * 7 * ASSUMPTIONS 8 * ----------- 9 * o Feature negotiation is coordinated with connection setup (as in TCP), wild 10 * changes of parameters of an established connection are not supported. 11 * o All currently known SP features have 1-byte quantities. If in the future 12 * extensions of RFCs 4340..42 define features with item lengths larger than 13 * one byte, a feature-specific extension of the code will be required. 14 * 15 * This program is free software; you can redistribute it and/or 16 * modify it under the terms of the GNU General Public License 17 * as published by the Free Software Foundation; either version 18 * 2 of the License, or (at your option) any later version. 19 */ 20 21 #include <linux/module.h> 22 23 #include "ccid.h" 24 #include "feat.h" 25 26 #define DCCP_FEAT_SP_NOAGREE (-123) 27 28 static const struct { 29 u8 feat_num; /* DCCPF_xxx */ 30 enum dccp_feat_type rxtx; /* RX or TX */ 31 enum dccp_feat_type reconciliation; /* SP or NN */ 32 u8 default_value; /* as in 6.4 */ 33 /* 34 * Lookup table for location and type of features (from RFC 4340/4342) 35 * +--------------------------+----+-----+----+----+---------+-----------+ 36 * | Feature | Location | Reconc. | Initial | Section | 37 * | | RX | TX | SP | NN | Value | Reference | 38 * +--------------------------+----+-----+----+----+---------+-----------+ 39 * | DCCPF_CCID | | X | X | | 2 | 10 | 40 * | DCCPF_SHORT_SEQNOS | | X | X | | 0 | 7.6.1 | 41 * | DCCPF_SEQUENCE_WINDOW | | X | | X | 100 | 7.5.2 | 42 * | DCCPF_ECN_INCAPABLE | X | | X | | 0 | 12.1 | 43 * | DCCPF_ACK_RATIO | | X | | X | 2 | 11.3 | 44 * | DCCPF_SEND_ACK_VECTOR | X | | X | | 0 | 11.5 | 45 * | DCCPF_SEND_NDP_COUNT | | X | X | | 0 | 7.7.2 | 46 * | DCCPF_MIN_CSUM_COVER | X | | X | | 0 | 9.2.1 | 47 * | DCCPF_DATA_CHECKSUM | X | | X | | 0 | 9.3.1 | 48 * | DCCPF_SEND_LEV_RATE | X | | X | | 0 | 4342/8.4 | 49 * +--------------------------+----+-----+----+----+---------+-----------+ 50 */ 51 } dccp_feat_table[] = { 52 { DCCPF_CCID, FEAT_AT_TX, FEAT_SP, 2 }, 53 { DCCPF_SHORT_SEQNOS, FEAT_AT_TX, FEAT_SP, 0 }, 54 { DCCPF_SEQUENCE_WINDOW, FEAT_AT_TX, FEAT_NN, 100 }, 55 { DCCPF_ECN_INCAPABLE, FEAT_AT_RX, FEAT_SP, 0 }, 56 { DCCPF_ACK_RATIO, FEAT_AT_TX, FEAT_NN, 2 }, 57 { DCCPF_SEND_ACK_VECTOR, FEAT_AT_RX, FEAT_SP, 0 }, 58 { DCCPF_SEND_NDP_COUNT, FEAT_AT_TX, FEAT_SP, 0 }, 59 { DCCPF_MIN_CSUM_COVER, FEAT_AT_RX, FEAT_SP, 0 }, 60 { DCCPF_DATA_CHECKSUM, FEAT_AT_RX, FEAT_SP, 0 }, 61 { DCCPF_SEND_LEV_RATE, FEAT_AT_RX, FEAT_SP, 0 }, 62 }; 63 #define DCCP_FEAT_SUPPORTED_MAX ARRAY_SIZE(dccp_feat_table) 64 65 /** 66 * dccp_feat_index - Hash function to map feature number into array position 67 * Returns consecutive array index or -1 if the feature is not understood. 68 */ 69 static int dccp_feat_index(u8 feat_num) 70 { 71 /* The first 9 entries are occupied by the types from RFC 4340, 6.4 */ 72 if (feat_num > DCCPF_RESERVED && feat_num <= DCCPF_DATA_CHECKSUM) 73 return feat_num - 1; 74 75 /* 76 * Other features: add cases for new feature types here after adding 77 * them to the above table. 78 */ 79 switch (feat_num) { 80 case DCCPF_SEND_LEV_RATE: 81 return DCCP_FEAT_SUPPORTED_MAX - 1; 82 } 83 return -1; 84 } 85 86 static u8 dccp_feat_type(u8 feat_num) 87 { 88 int idx = dccp_feat_index(feat_num); 89 90 if (idx < 0) 91 return FEAT_UNKNOWN; 92 return dccp_feat_table[idx].reconciliation; 93 } 94 95 /* copy constructor, fval must not already contain allocated memory */ 96 static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len) 97 { 98 fval->sp.len = len; 99 if (fval->sp.len > 0) { 100 fval->sp.vec = kmemdup(val, len, gfp_any()); 101 if (fval->sp.vec == NULL) { 102 fval->sp.len = 0; 103 return -ENOBUFS; 104 } 105 } 106 return 0; 107 } 108 109 static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val) 110 { 111 if (unlikely(val == NULL)) 112 return; 113 if (dccp_feat_type(feat_num) == FEAT_SP) 114 kfree(val->sp.vec); 115 memset(val, 0, sizeof(*val)); 116 } 117 118 static struct dccp_feat_entry * 119 dccp_feat_clone_entry(struct dccp_feat_entry const *original) 120 { 121 struct dccp_feat_entry *new; 122 u8 type = dccp_feat_type(original->feat_num); 123 124 if (type == FEAT_UNKNOWN) 125 return NULL; 126 127 new = kmemdup(original, sizeof(struct dccp_feat_entry), gfp_any()); 128 if (new == NULL) 129 return NULL; 130 131 if (type == FEAT_SP && dccp_feat_clone_sp_val(&new->val, 132 original->val.sp.vec, 133 original->val.sp.len)) { 134 kfree(new); 135 return NULL; 136 } 137 return new; 138 } 139 140 static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry) 141 { 142 if (entry != NULL) { 143 dccp_feat_val_destructor(entry->feat_num, &entry->val); 144 kfree(entry); 145 } 146 } 147 148 /* 149 * List management functions 150 * 151 * Feature negotiation lists rely on and maintain the following invariants: 152 * - each feat_num in the list is known, i.e. we know its type and default value 153 * - each feat_num/is_local combination is unique (old entries are overwritten) 154 * - SP values are always freshly allocated 155 * - list is sorted in increasing order of feature number (faster lookup) 156 */ 157 158 static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry) 159 { 160 list_del(&entry->node); 161 dccp_feat_entry_destructor(entry); 162 } 163 164 void dccp_feat_list_purge(struct list_head *fn_list) 165 { 166 struct dccp_feat_entry *entry, *next; 167 168 list_for_each_entry_safe(entry, next, fn_list, node) 169 dccp_feat_entry_destructor(entry); 170 INIT_LIST_HEAD(fn_list); 171 } 172 EXPORT_SYMBOL_GPL(dccp_feat_list_purge); 173 174 /* generate @to as full clone of @from - @to must not contain any nodes */ 175 int dccp_feat_clone_list(struct list_head const *from, struct list_head *to) 176 { 177 struct dccp_feat_entry *entry, *new; 178 179 INIT_LIST_HEAD(to); 180 list_for_each_entry(entry, from, node) { 181 new = dccp_feat_clone_entry(entry); 182 if (new == NULL) 183 goto cloning_failed; 184 list_add_tail(&new->node, to); 185 } 186 return 0; 187 188 cloning_failed: 189 dccp_feat_list_purge(to); 190 return -ENOMEM; 191 } 192 193 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature, 194 u8 *val, u8 len, gfp_t gfp) 195 { 196 struct dccp_opt_pend *opt; 197 198 dccp_feat_debug(type, feature, *val); 199 200 if (len > 3) { 201 DCCP_WARN("invalid length %d\n", len); 202 return -EINVAL; 203 } 204 /* XXX add further sanity checks */ 205 206 /* check if that feature is already being negotiated */ 207 list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { 208 /* ok we found a negotiation for this option already */ 209 if (opt->dccpop_feat == feature && opt->dccpop_type == type) { 210 dccp_pr_debug("Replacing old\n"); 211 /* replace */ 212 BUG_ON(opt->dccpop_val == NULL); 213 kfree(opt->dccpop_val); 214 opt->dccpop_val = val; 215 opt->dccpop_len = len; 216 opt->dccpop_conf = 0; 217 return 0; 218 } 219 } 220 221 /* negotiation for a new feature */ 222 opt = kmalloc(sizeof(*opt), gfp); 223 if (opt == NULL) 224 return -ENOMEM; 225 226 opt->dccpop_type = type; 227 opt->dccpop_feat = feature; 228 opt->dccpop_len = len; 229 opt->dccpop_val = val; 230 opt->dccpop_conf = 0; 231 opt->dccpop_sc = NULL; 232 233 BUG_ON(opt->dccpop_val == NULL); 234 235 list_add_tail(&opt->dccpop_node, &dmsk->dccpms_pending); 236 return 0; 237 } 238 239 EXPORT_SYMBOL_GPL(dccp_feat_change); 240 241 static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr) 242 { 243 struct dccp_sock *dp = dccp_sk(sk); 244 struct dccp_minisock *dmsk = dccp_msk(sk); 245 /* figure out if we are changing our CCID or the peer's */ 246 const int rx = type == DCCPO_CHANGE_R; 247 const u8 ccid_nr = rx ? dmsk->dccpms_rx_ccid : dmsk->dccpms_tx_ccid; 248 struct ccid *new_ccid; 249 250 /* Check if nothing is being changed. */ 251 if (ccid_nr == new_ccid_nr) 252 return 0; 253 254 new_ccid = ccid_new(new_ccid_nr, sk, rx, GFP_ATOMIC); 255 if (new_ccid == NULL) 256 return -ENOMEM; 257 258 if (rx) { 259 ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk); 260 dp->dccps_hc_rx_ccid = new_ccid; 261 dmsk->dccpms_rx_ccid = new_ccid_nr; 262 } else { 263 ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk); 264 dp->dccps_hc_tx_ccid = new_ccid; 265 dmsk->dccpms_tx_ccid = new_ccid_nr; 266 } 267 268 return 0; 269 } 270 271 static int dccp_feat_update(struct sock *sk, u8 type, u8 feat, u8 val) 272 { 273 dccp_feat_debug(type, feat, val); 274 275 switch (feat) { 276 case DCCPF_CCID: 277 return dccp_feat_update_ccid(sk, type, val); 278 default: 279 dccp_pr_debug("UNIMPLEMENTED: %s(%d, ...)\n", 280 dccp_feat_typename(type), feat); 281 break; 282 } 283 return 0; 284 } 285 286 static int dccp_feat_reconcile(struct sock *sk, struct dccp_opt_pend *opt, 287 u8 *rpref, u8 rlen) 288 { 289 struct dccp_sock *dp = dccp_sk(sk); 290 u8 *spref, slen, *res = NULL; 291 int i, j, rc, agree = 1; 292 293 BUG_ON(rpref == NULL); 294 295 /* check if we are the black sheep */ 296 if (dp->dccps_role == DCCP_ROLE_CLIENT) { 297 spref = rpref; 298 slen = rlen; 299 rpref = opt->dccpop_val; 300 rlen = opt->dccpop_len; 301 } else { 302 spref = opt->dccpop_val; 303 slen = opt->dccpop_len; 304 } 305 /* 306 * Now we have server preference list in spref and client preference in 307 * rpref 308 */ 309 BUG_ON(spref == NULL); 310 BUG_ON(rpref == NULL); 311 312 /* FIXME sanity check vals */ 313 314 /* Are values in any order? XXX Lame "algorithm" here */ 315 for (i = 0; i < slen; i++) { 316 for (j = 0; j < rlen; j++) { 317 if (spref[i] == rpref[j]) { 318 res = &spref[i]; 319 break; 320 } 321 } 322 if (res) 323 break; 324 } 325 326 /* we didn't agree on anything */ 327 if (res == NULL) { 328 /* confirm previous value */ 329 switch (opt->dccpop_feat) { 330 case DCCPF_CCID: 331 /* XXX did i get this right? =P */ 332 if (opt->dccpop_type == DCCPO_CHANGE_L) 333 res = &dccp_msk(sk)->dccpms_tx_ccid; 334 else 335 res = &dccp_msk(sk)->dccpms_rx_ccid; 336 break; 337 338 default: 339 DCCP_BUG("Fell through, feat=%d", opt->dccpop_feat); 340 /* XXX implement res */ 341 return -EFAULT; 342 } 343 344 dccp_pr_debug("Don't agree... reconfirming %d\n", *res); 345 agree = 0; /* this is used for mandatory options... */ 346 } 347 348 /* need to put result and our preference list */ 349 rlen = 1 + opt->dccpop_len; 350 rpref = kmalloc(rlen, GFP_ATOMIC); 351 if (rpref == NULL) 352 return -ENOMEM; 353 354 *rpref = *res; 355 memcpy(&rpref[1], opt->dccpop_val, opt->dccpop_len); 356 357 /* put it in the "confirm queue" */ 358 if (opt->dccpop_sc == NULL) { 359 opt->dccpop_sc = kmalloc(sizeof(*opt->dccpop_sc), GFP_ATOMIC); 360 if (opt->dccpop_sc == NULL) { 361 kfree(rpref); 362 return -ENOMEM; 363 } 364 } else { 365 /* recycle the confirm slot */ 366 BUG_ON(opt->dccpop_sc->dccpoc_val == NULL); 367 kfree(opt->dccpop_sc->dccpoc_val); 368 dccp_pr_debug("recycling confirm slot\n"); 369 } 370 memset(opt->dccpop_sc, 0, sizeof(*opt->dccpop_sc)); 371 372 opt->dccpop_sc->dccpoc_val = rpref; 373 opt->dccpop_sc->dccpoc_len = rlen; 374 375 /* update the option on our side [we are about to send the confirm] */ 376 rc = dccp_feat_update(sk, opt->dccpop_type, opt->dccpop_feat, *res); 377 if (rc) { 378 kfree(opt->dccpop_sc->dccpoc_val); 379 kfree(opt->dccpop_sc); 380 opt->dccpop_sc = NULL; 381 return rc; 382 } 383 384 dccp_pr_debug("Will confirm %d\n", *rpref); 385 386 /* say we want to change to X but we just got a confirm X, suppress our 387 * change 388 */ 389 if (!opt->dccpop_conf) { 390 if (*opt->dccpop_val == *res) 391 opt->dccpop_conf = 1; 392 dccp_pr_debug("won't ask for change of same feature\n"); 393 } 394 395 return agree ? 0 : DCCP_FEAT_SP_NOAGREE; /* used for mandatory opts */ 396 } 397 398 static int dccp_feat_sp(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) 399 { 400 struct dccp_minisock *dmsk = dccp_msk(sk); 401 struct dccp_opt_pend *opt; 402 int rc = 1; 403 u8 t; 404 405 /* 406 * We received a CHANGE. We gotta match it against our own preference 407 * list. If we got a CHANGE_R it means it's a change for us, so we need 408 * to compare our CHANGE_L list. 409 */ 410 if (type == DCCPO_CHANGE_L) 411 t = DCCPO_CHANGE_R; 412 else 413 t = DCCPO_CHANGE_L; 414 415 /* find our preference list for this feature */ 416 list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { 417 if (opt->dccpop_type != t || opt->dccpop_feat != feature) 418 continue; 419 420 /* find the winner from the two preference lists */ 421 rc = dccp_feat_reconcile(sk, opt, val, len); 422 break; 423 } 424 425 /* We didn't deal with the change. This can happen if we have no 426 * preference list for the feature. In fact, it just shouldn't 427 * happen---if we understand a feature, we should have a preference list 428 * with at least the default value. 429 */ 430 BUG_ON(rc == 1); 431 432 return rc; 433 } 434 435 static int dccp_feat_nn(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) 436 { 437 struct dccp_opt_pend *opt; 438 struct dccp_minisock *dmsk = dccp_msk(sk); 439 u8 *copy; 440 int rc; 441 442 /* NN features must be Change L (sec. 6.3.2) */ 443 if (type != DCCPO_CHANGE_L) { 444 dccp_pr_debug("received %s for NN feature %d\n", 445 dccp_feat_typename(type), feature); 446 return -EFAULT; 447 } 448 449 /* XXX sanity check opt val */ 450 451 /* copy option so we can confirm it */ 452 opt = kzalloc(sizeof(*opt), GFP_ATOMIC); 453 if (opt == NULL) 454 return -ENOMEM; 455 456 copy = kmemdup(val, len, GFP_ATOMIC); 457 if (copy == NULL) { 458 kfree(opt); 459 return -ENOMEM; 460 } 461 462 opt->dccpop_type = DCCPO_CONFIRM_R; /* NN can only confirm R */ 463 opt->dccpop_feat = feature; 464 opt->dccpop_val = copy; 465 opt->dccpop_len = len; 466 467 /* change feature */ 468 rc = dccp_feat_update(sk, type, feature, *val); 469 if (rc) { 470 kfree(opt->dccpop_val); 471 kfree(opt); 472 return rc; 473 } 474 475 dccp_feat_debug(type, feature, *copy); 476 477 list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf); 478 479 return 0; 480 } 481 482 static void dccp_feat_empty_confirm(struct dccp_minisock *dmsk, 483 u8 type, u8 feature) 484 { 485 /* XXX check if other confirms for that are queued and recycle slot */ 486 struct dccp_opt_pend *opt = kzalloc(sizeof(*opt), GFP_ATOMIC); 487 488 if (opt == NULL) { 489 /* XXX what do we do? Ignoring should be fine. It's a change 490 * after all =P 491 */ 492 return; 493 } 494 495 switch (type) { 496 case DCCPO_CHANGE_L: 497 opt->dccpop_type = DCCPO_CONFIRM_R; 498 break; 499 case DCCPO_CHANGE_R: 500 opt->dccpop_type = DCCPO_CONFIRM_L; 501 break; 502 default: 503 DCCP_WARN("invalid type %d\n", type); 504 kfree(opt); 505 return; 506 } 507 opt->dccpop_feat = feature; 508 opt->dccpop_val = NULL; 509 opt->dccpop_len = 0; 510 511 /* change feature */ 512 dccp_pr_debug("Empty %s(%d)\n", dccp_feat_typename(type), feature); 513 514 list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf); 515 } 516 517 static void dccp_feat_flush_confirm(struct sock *sk) 518 { 519 struct dccp_minisock *dmsk = dccp_msk(sk); 520 /* Check if there is anything to confirm in the first place */ 521 int yes = !list_empty(&dmsk->dccpms_conf); 522 523 if (!yes) { 524 struct dccp_opt_pend *opt; 525 526 list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { 527 if (opt->dccpop_conf) { 528 yes = 1; 529 break; 530 } 531 } 532 } 533 534 if (!yes) 535 return; 536 537 /* OK there is something to confirm... */ 538 /* XXX check if packet is in flight? Send delayed ack?? */ 539 if (sk->sk_state == DCCP_OPEN) 540 dccp_send_ack(sk); 541 } 542 543 int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) 544 { 545 int rc; 546 547 /* Ignore Change requests other than during connection setup */ 548 if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING) 549 return 0; 550 dccp_feat_debug(type, feature, *val); 551 552 /* figure out if it's SP or NN feature */ 553 switch (feature) { 554 /* deal with SP features */ 555 case DCCPF_CCID: 556 rc = dccp_feat_sp(sk, type, feature, val, len); 557 break; 558 559 /* deal with NN features */ 560 case DCCPF_ACK_RATIO: 561 rc = dccp_feat_nn(sk, type, feature, val, len); 562 break; 563 564 /* XXX implement other features */ 565 default: 566 dccp_pr_debug("UNIMPLEMENTED: not handling %s(%d, ...)\n", 567 dccp_feat_typename(type), feature); 568 rc = -EFAULT; 569 break; 570 } 571 572 /* check if there were problems changing features */ 573 if (rc) { 574 /* If we don't agree on SP, we sent a confirm for old value. 575 * However we propagate rc to caller in case option was 576 * mandatory 577 */ 578 if (rc != DCCP_FEAT_SP_NOAGREE) 579 dccp_feat_empty_confirm(dccp_msk(sk), type, feature); 580 } 581 582 /* generate the confirm [if required] */ 583 dccp_feat_flush_confirm(sk); 584 585 return rc; 586 } 587 588 EXPORT_SYMBOL_GPL(dccp_feat_change_recv); 589 590 int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, 591 u8 *val, u8 len) 592 { 593 u8 t; 594 struct dccp_opt_pend *opt; 595 struct dccp_minisock *dmsk = dccp_msk(sk); 596 int found = 0; 597 int all_confirmed = 1; 598 599 /* Ignore Confirm options other than during connection setup */ 600 if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING) 601 return 0; 602 dccp_feat_debug(type, feature, *val); 603 604 /* locate our change request */ 605 switch (type) { 606 case DCCPO_CONFIRM_L: t = DCCPO_CHANGE_R; break; 607 case DCCPO_CONFIRM_R: t = DCCPO_CHANGE_L; break; 608 default: DCCP_WARN("invalid type %d\n", type); 609 return 1; 610 611 } 612 /* XXX sanity check feature value */ 613 614 list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { 615 if (!opt->dccpop_conf && opt->dccpop_type == t && 616 opt->dccpop_feat == feature) { 617 found = 1; 618 dccp_pr_debug("feature %d found\n", opt->dccpop_feat); 619 620 /* XXX do sanity check */ 621 622 opt->dccpop_conf = 1; 623 624 /* We got a confirmation---change the option */ 625 dccp_feat_update(sk, opt->dccpop_type, 626 opt->dccpop_feat, *val); 627 628 /* XXX check the return value of dccp_feat_update */ 629 break; 630 } 631 632 if (!opt->dccpop_conf) 633 all_confirmed = 0; 634 } 635 636 if (!found) 637 dccp_pr_debug("%s(%d, ...) never requested\n", 638 dccp_feat_typename(type), feature); 639 return 0; 640 } 641 642 EXPORT_SYMBOL_GPL(dccp_feat_confirm_recv); 643 644 void dccp_feat_clean(struct dccp_minisock *dmsk) 645 { 646 struct dccp_opt_pend *opt, *next; 647 648 list_for_each_entry_safe(opt, next, &dmsk->dccpms_pending, 649 dccpop_node) { 650 BUG_ON(opt->dccpop_val == NULL); 651 kfree(opt->dccpop_val); 652 653 if (opt->dccpop_sc != NULL) { 654 BUG_ON(opt->dccpop_sc->dccpoc_val == NULL); 655 kfree(opt->dccpop_sc->dccpoc_val); 656 kfree(opt->dccpop_sc); 657 } 658 659 kfree(opt); 660 } 661 INIT_LIST_HEAD(&dmsk->dccpms_pending); 662 663 list_for_each_entry_safe(opt, next, &dmsk->dccpms_conf, dccpop_node) { 664 BUG_ON(opt == NULL); 665 if (opt->dccpop_val != NULL) 666 kfree(opt->dccpop_val); 667 kfree(opt); 668 } 669 INIT_LIST_HEAD(&dmsk->dccpms_conf); 670 } 671 672 EXPORT_SYMBOL_GPL(dccp_feat_clean); 673 674 /* this is to be called only when a listening sock creates its child. It is 675 * assumed by the function---the confirm is not duplicated, but rather it is 676 * "passed on". 677 */ 678 int dccp_feat_clone(struct sock *oldsk, struct sock *newsk) 679 { 680 struct dccp_minisock *olddmsk = dccp_msk(oldsk); 681 struct dccp_minisock *newdmsk = dccp_msk(newsk); 682 struct dccp_opt_pend *opt; 683 int rc = 0; 684 685 INIT_LIST_HEAD(&newdmsk->dccpms_pending); 686 INIT_LIST_HEAD(&newdmsk->dccpms_conf); 687 688 list_for_each_entry(opt, &olddmsk->dccpms_pending, dccpop_node) { 689 struct dccp_opt_pend *newopt; 690 /* copy the value of the option */ 691 u8 *val = kmemdup(opt->dccpop_val, opt->dccpop_len, GFP_ATOMIC); 692 693 if (val == NULL) 694 goto out_clean; 695 696 newopt = kmemdup(opt, sizeof(*newopt), GFP_ATOMIC); 697 if (newopt == NULL) { 698 kfree(val); 699 goto out_clean; 700 } 701 702 /* insert the option */ 703 newopt->dccpop_val = val; 704 list_add_tail(&newopt->dccpop_node, &newdmsk->dccpms_pending); 705 706 /* XXX what happens with backlogs and multiple connections at 707 * once... 708 */ 709 /* the master socket no longer needs to worry about confirms */ 710 opt->dccpop_sc = NULL; /* it's not a memleak---new socket has it */ 711 712 /* reset state for a new socket */ 713 opt->dccpop_conf = 0; 714 } 715 716 /* XXX not doing anything about the conf queue */ 717 718 out: 719 return rc; 720 721 out_clean: 722 dccp_feat_clean(newdmsk); 723 rc = -ENOMEM; 724 goto out; 725 } 726 727 EXPORT_SYMBOL_GPL(dccp_feat_clone); 728 729 static int __dccp_feat_init(struct dccp_minisock *dmsk, u8 type, u8 feat, 730 u8 *val, u8 len) 731 { 732 int rc = -ENOMEM; 733 u8 *copy = kmemdup(val, len, GFP_KERNEL); 734 735 if (copy != NULL) { 736 rc = dccp_feat_change(dmsk, type, feat, copy, len, GFP_KERNEL); 737 if (rc) 738 kfree(copy); 739 } 740 return rc; 741 } 742 743 int dccp_feat_init(struct dccp_minisock *dmsk) 744 { 745 int rc; 746 747 INIT_LIST_HEAD(&dmsk->dccpms_pending); 748 INIT_LIST_HEAD(&dmsk->dccpms_conf); 749 750 /* CCID L */ 751 rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_CCID, 752 &dmsk->dccpms_tx_ccid, 1); 753 if (rc) 754 goto out; 755 756 /* CCID R */ 757 rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_R, DCCPF_CCID, 758 &dmsk->dccpms_rx_ccid, 1); 759 if (rc) 760 goto out; 761 762 /* Ack ratio */ 763 rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_ACK_RATIO, 764 &dmsk->dccpms_ack_ratio, 1); 765 out: 766 return rc; 767 } 768 769 EXPORT_SYMBOL_GPL(dccp_feat_init); 770 771 #ifdef CONFIG_IP_DCCP_DEBUG 772 const char *dccp_feat_typename(const u8 type) 773 { 774 switch(type) { 775 case DCCPO_CHANGE_L: return("ChangeL"); 776 case DCCPO_CONFIRM_L: return("ConfirmL"); 777 case DCCPO_CHANGE_R: return("ChangeR"); 778 case DCCPO_CONFIRM_R: return("ConfirmR"); 779 /* the following case must not appear in feature negotation */ 780 default: dccp_pr_debug("unknown type %d [BUG!]\n", type); 781 } 782 return NULL; 783 } 784 785 EXPORT_SYMBOL_GPL(dccp_feat_typename); 786 787 const char *dccp_feat_name(const u8 feat) 788 { 789 static const char *feature_names[] = { 790 [DCCPF_RESERVED] = "Reserved", 791 [DCCPF_CCID] = "CCID", 792 [DCCPF_SHORT_SEQNOS] = "Allow Short Seqnos", 793 [DCCPF_SEQUENCE_WINDOW] = "Sequence Window", 794 [DCCPF_ECN_INCAPABLE] = "ECN Incapable", 795 [DCCPF_ACK_RATIO] = "Ack Ratio", 796 [DCCPF_SEND_ACK_VECTOR] = "Send ACK Vector", 797 [DCCPF_SEND_NDP_COUNT] = "Send NDP Count", 798 [DCCPF_MIN_CSUM_COVER] = "Min. Csum Coverage", 799 [DCCPF_DATA_CHECKSUM] = "Send Data Checksum", 800 }; 801 if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC) 802 return feature_names[DCCPF_RESERVED]; 803 804 if (feat == DCCPF_SEND_LEV_RATE) 805 return "Send Loss Event Rate"; 806 if (feat >= DCCPF_MIN_CCID_SPECIFIC) 807 return "CCID-specific"; 808 809 return feature_names[feat]; 810 } 811 812 EXPORT_SYMBOL_GPL(dccp_feat_name); 813 #endif /* CONFIG_IP_DCCP_DEBUG */ 814