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 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 10 * 2 of the License, or (at your option) any later version. 11 */ 12 13#include <linux/module.h> 14 15#include "ccid.h" 16#include "feat.h" 17 18#define DCCP_FEAT_SP_NOAGREE (-123) 19 20int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature, 21 u8 *val, u8 len, gfp_t gfp) 22{ 23 struct dccp_opt_pend *opt; 24 25 dccp_feat_debug(type, feature, *val); 26 27 if (!dccp_feat_is_valid_type(type)) { 28 DCCP_WARN("option type %d invalid in negotiation\n", type); 29 return 1; 30 } 31 if (!dccp_feat_is_valid_length(type, feature, len)) { 32 DCCP_WARN("invalid length %d\n", len); 33 return 1; 34 } 35 36 /* check if that feature is already being negotiated */ 37 list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { 38 /* ok we found a negotiation for this option already */ 39 if (opt->dccpop_feat == feature && opt->dccpop_type == type) { 40 dccp_pr_debug("Replacing old\n"); 41 /* replace */ 42 BUG_ON(opt->dccpop_val == NULL); 43 kfree(opt->dccpop_val); 44 opt->dccpop_val = val; 45 opt->dccpop_len = len; 46 opt->dccpop_conf = 0; 47 return 0; 48 } 49 } 50 51 /* negotiation for a new feature */ 52 opt = kmalloc(sizeof(*opt), gfp); 53 if (opt == NULL) 54 return -ENOMEM; 55 56 opt->dccpop_type = type; 57 opt->dccpop_feat = feature; 58 opt->dccpop_len = len; 59 opt->dccpop_val = val; 60 opt->dccpop_conf = 0; 61 opt->dccpop_sc = NULL; 62 63 BUG_ON(opt->dccpop_val == NULL); 64 65 list_add_tail(&opt->dccpop_node, &dmsk->dccpms_pending); 66 return 0; 67} 68 69EXPORT_SYMBOL_GPL(dccp_feat_change); 70 71static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr) 72{ 73 struct dccp_sock *dp = dccp_sk(sk); 74 struct dccp_minisock *dmsk = dccp_msk(sk); 75 /* figure out if we are changing our CCID or the peer's */ 76 const int rx = type == DCCPO_CHANGE_R; 77 const u8 ccid_nr = rx ? dmsk->dccpms_rx_ccid : dmsk->dccpms_tx_ccid; 78 struct ccid *new_ccid; 79 80 /* Check if nothing is being changed. */ 81 if (ccid_nr == new_ccid_nr) 82 return 0; 83 84 new_ccid = ccid_new(new_ccid_nr, sk, rx, GFP_ATOMIC); 85 if (new_ccid == NULL) 86 return -ENOMEM; 87 88 if (rx) { 89 ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk); 90 dp->dccps_hc_rx_ccid = new_ccid; 91 dmsk->dccpms_rx_ccid = new_ccid_nr; 92 } else { 93 ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk); 94 dp->dccps_hc_tx_ccid = new_ccid; 95 dmsk->dccpms_tx_ccid = new_ccid_nr; 96 } 97 98 return 0; 99} 100 101static int dccp_feat_update(struct sock *sk, u8 type, u8 feat, u8 val) 102{ 103 dccp_feat_debug(type, feat, val); 104 105 switch (feat) { 106 case DCCPF_CCID: 107 return dccp_feat_update_ccid(sk, type, val); 108 default: 109 dccp_pr_debug("UNIMPLEMENTED: %s(%d, ...)\n", 110 dccp_feat_typename(type), feat); 111 break; 112 } 113 return 0; 114} 115 116static int dccp_feat_reconcile(struct sock *sk, struct dccp_opt_pend *opt, 117 u8 *rpref, u8 rlen) 118{ 119 struct dccp_sock *dp = dccp_sk(sk); 120 u8 *spref, slen, *res = NULL; 121 int i, j, rc, agree = 1; 122 123 BUG_ON(rpref == NULL); 124 125 /* check if we are the black sheep */ 126 if (dp->dccps_role == DCCP_ROLE_CLIENT) { 127 spref = rpref; 128 slen = rlen; 129 rpref = opt->dccpop_val; 130 rlen = opt->dccpop_len; 131 } else { 132 spref = opt->dccpop_val; 133 slen = opt->dccpop_len; 134 } 135 /* 136 * Now we have server preference list in spref and client preference in 137 * rpref 138 */ 139 BUG_ON(spref == NULL); 140 BUG_ON(rpref == NULL); 141 142 143 for (i = 0; i < slen; i++) { 144 for (j = 0; j < rlen; j++) { 145 if (spref[i] == rpref[j]) { 146 res = &spref[i]; 147 break; 148 } 149 } 150 if (res) 151 break; 152 } 153 154 /* we didn't agree on anything */ 155 if (res == NULL) { 156 /* confirm previous value */ 157 switch (opt->dccpop_feat) { 158 case DCCPF_CCID: 159 if (opt->dccpop_type == DCCPO_CHANGE_L) 160 res = &dccp_msk(sk)->dccpms_tx_ccid; 161 else 162 res = &dccp_msk(sk)->dccpms_rx_ccid; 163 break; 164 165 default: 166 DCCP_BUG("Fell through, feat=%d", opt->dccpop_feat); 167 return -EFAULT; 168 } 169 170 dccp_pr_debug("Don't agree... reconfirming %d\n", *res); 171 agree = 0; /* this is used for mandatory options... */ 172 } 173 174 /* need to put result and our preference list */ 175 rlen = 1 + opt->dccpop_len; 176 rpref = kmalloc(rlen, GFP_ATOMIC); 177 if (rpref == NULL) 178 return -ENOMEM; 179 180 *rpref = *res; 181 memcpy(&rpref[1], opt->dccpop_val, opt->dccpop_len); 182 183 /* put it in the "confirm queue" */ 184 if (opt->dccpop_sc == NULL) { 185 opt->dccpop_sc = kmalloc(sizeof(*opt->dccpop_sc), GFP_ATOMIC); 186 if (opt->dccpop_sc == NULL) { 187 kfree(rpref); 188 return -ENOMEM; 189 } 190 } else { 191 /* recycle the confirm slot */ 192 BUG_ON(opt->dccpop_sc->dccpoc_val == NULL); 193 kfree(opt->dccpop_sc->dccpoc_val); 194 dccp_pr_debug("recycling confirm slot\n"); 195 } 196 memset(opt->dccpop_sc, 0, sizeof(*opt->dccpop_sc)); 197 198 opt->dccpop_sc->dccpoc_val = rpref; 199 opt->dccpop_sc->dccpoc_len = rlen; 200 201 /* update the option on our side [we are about to send the confirm] */ 202 rc = dccp_feat_update(sk, opt->dccpop_type, opt->dccpop_feat, *res); 203 if (rc) { 204 kfree(opt->dccpop_sc->dccpoc_val); 205 kfree(opt->dccpop_sc); 206 opt->dccpop_sc = NULL; 207 return rc; 208 } 209 210 dccp_pr_debug("Will confirm %d\n", *rpref); 211 212 /* say we want to change to X but we just got a confirm X, suppress our 213 * change 214 */ 215 if (!opt->dccpop_conf) { 216 if (*opt->dccpop_val == *res) 217 opt->dccpop_conf = 1; 218 dccp_pr_debug("won't ask for change of same feature\n"); 219 } 220 221 return agree ? 0 : DCCP_FEAT_SP_NOAGREE; /* used for mandatory opts */ 222} 223 224static int dccp_feat_sp(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) 225{ 226 struct dccp_minisock *dmsk = dccp_msk(sk); 227 struct dccp_opt_pend *opt; 228 int rc = 1; 229 u8 t; 230 231 /* 232 * We received a CHANGE. We gotta match it against our own preference 233 * list. If we got a CHANGE_R it means it's a change for us, so we need 234 * to compare our CHANGE_L list. 235 */ 236 if (type == DCCPO_CHANGE_L) 237 t = DCCPO_CHANGE_R; 238 else 239 t = DCCPO_CHANGE_L; 240 241 /* find our preference list for this feature */ 242 list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { 243 if (opt->dccpop_type != t || opt->dccpop_feat != feature) 244 continue; 245 246 /* find the winner from the two preference lists */ 247 rc = dccp_feat_reconcile(sk, opt, val, len); 248 break; 249 } 250 251 /* We didn't deal with the change. This can happen if we have no 252 * preference list for the feature. In fact, it just shouldn't 253 * happen---if we understand a feature, we should have a preference list 254 * with at least the default value. 255 */ 256 BUG_ON(rc == 1); 257 258 return rc; 259} 260 261static int dccp_feat_nn(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) 262{ 263 struct dccp_opt_pend *opt; 264 struct dccp_minisock *dmsk = dccp_msk(sk); 265 u8 *copy; 266 int rc; 267 268 /* NN features must be Change L (sec. 6.3.2) */ 269 if (type != DCCPO_CHANGE_L) { 270 dccp_pr_debug("received %s for NN feature %d\n", 271 dccp_feat_typename(type), feature); 272 return -EFAULT; 273 } 274 275 276 /* copy option so we can confirm it */ 277 opt = kzalloc(sizeof(*opt), GFP_ATOMIC); 278 if (opt == NULL) 279 return -ENOMEM; 280 281 copy = kmemdup(val, len, GFP_ATOMIC); 282 if (copy == NULL) { 283 kfree(opt); 284 return -ENOMEM; 285 } 286 287 opt->dccpop_type = DCCPO_CONFIRM_R; /* NN can only confirm R */ 288 opt->dccpop_feat = feature; 289 opt->dccpop_val = copy; 290 opt->dccpop_len = len; 291 292 /* change feature */ 293 rc = dccp_feat_update(sk, type, feature, *val); 294 if (rc) { 295 kfree(opt->dccpop_val); 296 kfree(opt); 297 return rc; 298 } 299 300 dccp_feat_debug(type, feature, *copy); 301 302 list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf); 303 304 return 0; 305} 306 307static void dccp_feat_empty_confirm(struct dccp_minisock *dmsk, 308 u8 type, u8 feature) 309{ 310 struct dccp_opt_pend *opt = kzalloc(sizeof(*opt), GFP_ATOMIC); 311 312 if (opt == NULL) { 313 return; 314 } 315 316 switch (type) { 317 case DCCPO_CHANGE_L: opt->dccpop_type = DCCPO_CONFIRM_R; break; 318 case DCCPO_CHANGE_R: opt->dccpop_type = DCCPO_CONFIRM_L; break; 319 default: DCCP_WARN("invalid type %d\n", type); return; 320 321 } 322 opt->dccpop_feat = feature; 323 opt->dccpop_val = NULL; 324 opt->dccpop_len = 0; 325 326 /* change feature */ 327 dccp_pr_debug("Empty %s(%d)\n", dccp_feat_typename(type), feature); 328 329 list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf); 330} 331 332static void dccp_feat_flush_confirm(struct sock *sk) 333{ 334 struct dccp_minisock *dmsk = dccp_msk(sk); 335 /* Check if there is anything to confirm in the first place */ 336 int yes = !list_empty(&dmsk->dccpms_conf); 337 338 if (!yes) { 339 struct dccp_opt_pend *opt; 340 341 list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { 342 if (opt->dccpop_conf) { 343 yes = 1; 344 break; 345 } 346 } 347 } 348 349 if (!yes) 350 return; 351 352 /* OK there is something to confirm... */ 353 if (sk->sk_state == DCCP_OPEN) 354 dccp_send_ack(sk); 355} 356 357int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) 358{ 359 int rc; 360 361 dccp_feat_debug(type, feature, *val); 362 363 /* figure out if it's SP or NN feature */ 364 switch (feature) { 365 /* deal with SP features */ 366 case DCCPF_CCID: 367 rc = dccp_feat_sp(sk, type, feature, val, len); 368 break; 369 370 /* deal with NN features */ 371 case DCCPF_ACK_RATIO: 372 rc = dccp_feat_nn(sk, type, feature, val, len); 373 break; 374 375 default: 376 dccp_pr_debug("UNIMPLEMENTED: not handling %s(%d, ...)\n", 377 dccp_feat_typename(type), feature); 378 rc = -EFAULT; 379 break; 380 } 381 382 /* check if there were problems changing features */ 383 if (rc) { 384 /* If we don't agree on SP, we sent a confirm for old value. 385 * However we propagate rc to caller in case option was 386 * mandatory 387 */ 388 if (rc != DCCP_FEAT_SP_NOAGREE) 389 dccp_feat_empty_confirm(dccp_msk(sk), type, feature); 390 } 391 392 /* generate the confirm [if required] */ 393 dccp_feat_flush_confirm(sk); 394 395 return rc; 396} 397 398EXPORT_SYMBOL_GPL(dccp_feat_change_recv); 399 400int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, 401 u8 *val, u8 len) 402{ 403 u8 t; 404 struct dccp_opt_pend *opt; 405 struct dccp_minisock *dmsk = dccp_msk(sk); 406 int found = 0; 407 int all_confirmed = 1; 408 409 dccp_feat_debug(type, feature, *val); 410 411 /* locate our change request */ 412 switch (type) { 413 case DCCPO_CONFIRM_L: t = DCCPO_CHANGE_R; break; 414 case DCCPO_CONFIRM_R: t = DCCPO_CHANGE_L; break; 415 default: DCCP_WARN("invalid type %d\n", type); 416 return 1; 417 418 } 419 420 list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { 421 if (!opt->dccpop_conf && opt->dccpop_type == t && 422 opt->dccpop_feat == feature) { 423 found = 1; 424 dccp_pr_debug("feature %d found\n", opt->dccpop_feat); 425 426 427 opt->dccpop_conf = 1; 428 429 /* We got a confirmation---change the option */ 430 dccp_feat_update(sk, opt->dccpop_type, 431 opt->dccpop_feat, *val); 432 433 break; 434 } 435 436 if (!opt->dccpop_conf) 437 all_confirmed = 0; 438 } 439 440 /* fix re-transmit timer */ 441 if (all_confirmed) { 442 dccp_pr_debug("clear feat negotiation timer %p\n", sk); 443 inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS); 444 } 445 446 if (!found) 447 dccp_pr_debug("%s(%d, ...) never requested\n", 448 dccp_feat_typename(type), feature); 449 return 0; 450} 451 452EXPORT_SYMBOL_GPL(dccp_feat_confirm_recv); 453 454void dccp_feat_clean(struct dccp_minisock *dmsk) 455{ 456 struct dccp_opt_pend *opt, *next; 457 458 list_for_each_entry_safe(opt, next, &dmsk->dccpms_pending, 459 dccpop_node) { 460 BUG_ON(opt->dccpop_val == NULL); 461 kfree(opt->dccpop_val); 462 463 if (opt->dccpop_sc != NULL) { 464 BUG_ON(opt->dccpop_sc->dccpoc_val == NULL); 465 kfree(opt->dccpop_sc->dccpoc_val); 466 kfree(opt->dccpop_sc); 467 } 468 469 kfree(opt); 470 } 471 INIT_LIST_HEAD(&dmsk->dccpms_pending); 472 473 list_for_each_entry_safe(opt, next, &dmsk->dccpms_conf, dccpop_node) { 474 BUG_ON(opt == NULL); 475 if (opt->dccpop_val != NULL) 476 kfree(opt->dccpop_val); 477 kfree(opt); 478 } 479 INIT_LIST_HEAD(&dmsk->dccpms_conf); 480} 481 482EXPORT_SYMBOL_GPL(dccp_feat_clean); 483 484/* this is to be called only when a listening sock creates its child. It is 485 * assumed by the function---the confirm is not duplicated, but rather it is 486 * "passed on". 487 */ 488int dccp_feat_clone(struct sock *oldsk, struct sock *newsk) 489{ 490 struct dccp_minisock *olddmsk = dccp_msk(oldsk); 491 struct dccp_minisock *newdmsk = dccp_msk(newsk); 492 struct dccp_opt_pend *opt; 493 int rc = 0; 494 495 INIT_LIST_HEAD(&newdmsk->dccpms_pending); 496 INIT_LIST_HEAD(&newdmsk->dccpms_conf); 497 498 list_for_each_entry(opt, &olddmsk->dccpms_pending, dccpop_node) { 499 struct dccp_opt_pend *newopt; 500 /* copy the value of the option */ 501 u8 *val = kmemdup(opt->dccpop_val, opt->dccpop_len, GFP_ATOMIC); 502 503 if (val == NULL) 504 goto out_clean; 505 506 newopt = kmemdup(opt, sizeof(*newopt), GFP_ATOMIC); 507 if (newopt == NULL) { 508 kfree(val); 509 goto out_clean; 510 } 511 512 /* insert the option */ 513 newopt->dccpop_val = val; 514 list_add_tail(&newopt->dccpop_node, &newdmsk->dccpms_pending); 515 516 /* the master socket no longer needs to worry about confirms */ 517 opt->dccpop_sc = NULL; /* it's not a memleak---new socket has it */ 518 519 /* reset state for a new socket */ 520 opt->dccpop_conf = 0; 521 } 522 523 524out: 525 return rc; 526 527out_clean: 528 dccp_feat_clean(newdmsk); 529 rc = -ENOMEM; 530 goto out; 531} 532 533EXPORT_SYMBOL_GPL(dccp_feat_clone); 534 535static int __dccp_feat_init(struct dccp_minisock *dmsk, u8 type, u8 feat, 536 u8 *val, u8 len) 537{ 538 int rc = -ENOMEM; 539 u8 *copy = kmemdup(val, len, GFP_KERNEL); 540 541 if (copy != NULL) { 542 rc = dccp_feat_change(dmsk, type, feat, copy, len, GFP_KERNEL); 543 if (rc) 544 kfree(copy); 545 } 546 return rc; 547} 548 549int dccp_feat_init(struct dccp_minisock *dmsk) 550{ 551 int rc; 552 553 INIT_LIST_HEAD(&dmsk->dccpms_pending); 554 INIT_LIST_HEAD(&dmsk->dccpms_conf); 555 556 /* CCID L */ 557 rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_CCID, 558 &dmsk->dccpms_tx_ccid, 1); 559 if (rc) 560 goto out; 561 562 /* CCID R */ 563 rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_R, DCCPF_CCID, 564 &dmsk->dccpms_rx_ccid, 1); 565 if (rc) 566 goto out; 567 568 /* Ack ratio */ 569 rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_ACK_RATIO, 570 &dmsk->dccpms_ack_ratio, 1); 571out: 572 return rc; 573} 574 575EXPORT_SYMBOL_GPL(dccp_feat_init); 576 577#ifdef CONFIG_IP_DCCP_DEBUG 578const char *dccp_feat_typename(const u8 type) 579{ 580 switch(type) { 581 case DCCPO_CHANGE_L: return("ChangeL"); 582 case DCCPO_CONFIRM_L: return("ConfirmL"); 583 case DCCPO_CHANGE_R: return("ChangeR"); 584 case DCCPO_CONFIRM_R: return("ConfirmR"); 585 /* the following case must not appear in feature negotation */ 586 default: dccp_pr_debug("unknown type %d [BUG!]\n", type); 587 } 588 return NULL; 589} 590 591EXPORT_SYMBOL_GPL(dccp_feat_typename); 592 593const char *dccp_feat_name(const u8 feat) 594{ 595 static const char *feature_names[] = { 596 [DCCPF_RESERVED] = "Reserved", 597 [DCCPF_CCID] = "CCID", 598 [DCCPF_SHORT_SEQNOS] = "Allow Short Seqnos", 599 [DCCPF_SEQUENCE_WINDOW] = "Sequence Window", 600 [DCCPF_ECN_INCAPABLE] = "ECN Incapable", 601 [DCCPF_ACK_RATIO] = "Ack Ratio", 602 [DCCPF_SEND_ACK_VECTOR] = "Send ACK Vector", 603 [DCCPF_SEND_NDP_COUNT] = "Send NDP Count", 604 [DCCPF_MIN_CSUM_COVER] = "Min. Csum Coverage", 605 [DCCPF_DATA_CHECKSUM] = "Send Data Checksum", 606 }; 607 if (feat >= DCCPF_MIN_CCID_SPECIFIC) 608 return "CCID-specific"; 609 610 if (dccp_feat_is_reserved(feat)) 611 return feature_names[DCCPF_RESERVED]; 612 613 return feature_names[feat]; 614} 615 616EXPORT_SYMBOL_GPL(dccp_feat_name); 617#endif /* CONFIG_IP_DCCP_DEBUG */ 618