1afe00251SAndrea Bittau /* 2afe00251SAndrea Bittau * net/dccp/feat.c 3afe00251SAndrea Bittau * 4afe00251SAndrea Bittau * An implementation of the DCCP protocol 5afe00251SAndrea Bittau * Andrea Bittau <a.bittau@cs.ucl.ac.uk> 6afe00251SAndrea Bittau * 7afe00251SAndrea Bittau * This program is free software; you can redistribute it and/or 8afe00251SAndrea Bittau * modify it under the terms of the GNU General Public License 9afe00251SAndrea Bittau * as published by the Free Software Foundation; either version 10afe00251SAndrea Bittau * 2 of the License, or (at your option) any later version. 11afe00251SAndrea Bittau */ 12afe00251SAndrea Bittau 13afe00251SAndrea Bittau #include <linux/config.h> 14afe00251SAndrea Bittau #include <linux/module.h> 15afe00251SAndrea Bittau 16afe00251SAndrea Bittau #include "dccp.h" 176ffd30fbSAndrea Bittau #include "ccid.h" 18afe00251SAndrea Bittau #include "feat.h" 19afe00251SAndrea Bittau 20afe00251SAndrea Bittau #define DCCP_FEAT_SP_NOAGREE (-123) 21afe00251SAndrea Bittau 22afe00251SAndrea Bittau int dccp_feat_change(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len, 23afe00251SAndrea Bittau gfp_t gfp) 24afe00251SAndrea Bittau { 25*a4bf3902SArnaldo Carvalho de Melo struct dccp_minisock *dmsk = dccp_msk(sk); 26afe00251SAndrea Bittau struct dccp_opt_pend *opt; 27afe00251SAndrea Bittau 28afe00251SAndrea Bittau dccp_pr_debug("feat change type=%d feat=%d\n", type, feature); 29afe00251SAndrea Bittau 306ffd30fbSAndrea Bittau /* XXX sanity check feat change request */ 316ffd30fbSAndrea Bittau 32afe00251SAndrea Bittau /* check if that feature is already being negotiated */ 33*a4bf3902SArnaldo Carvalho de Melo list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { 34afe00251SAndrea Bittau /* ok we found a negotiation for this option already */ 35afe00251SAndrea Bittau if (opt->dccpop_feat == feature && opt->dccpop_type == type) { 36afe00251SAndrea Bittau dccp_pr_debug("Replacing old\n"); 37afe00251SAndrea Bittau /* replace */ 38afe00251SAndrea Bittau BUG_ON(opt->dccpop_val == NULL); 39afe00251SAndrea Bittau kfree(opt->dccpop_val); 40afe00251SAndrea Bittau opt->dccpop_val = val; 41afe00251SAndrea Bittau opt->dccpop_len = len; 42afe00251SAndrea Bittau opt->dccpop_conf = 0; 43afe00251SAndrea Bittau return 0; 44afe00251SAndrea Bittau } 45afe00251SAndrea Bittau } 46afe00251SAndrea Bittau 47afe00251SAndrea Bittau /* negotiation for a new feature */ 48afe00251SAndrea Bittau opt = kmalloc(sizeof(*opt), gfp); 49afe00251SAndrea Bittau if (opt == NULL) 50afe00251SAndrea Bittau return -ENOMEM; 51afe00251SAndrea Bittau 52afe00251SAndrea Bittau opt->dccpop_type = type; 53afe00251SAndrea Bittau opt->dccpop_feat = feature; 54afe00251SAndrea Bittau opt->dccpop_len = len; 55afe00251SAndrea Bittau opt->dccpop_val = val; 56afe00251SAndrea Bittau opt->dccpop_conf = 0; 57afe00251SAndrea Bittau opt->dccpop_sc = NULL; 58afe00251SAndrea Bittau 59afe00251SAndrea Bittau BUG_ON(opt->dccpop_val == NULL); 60afe00251SAndrea Bittau 61*a4bf3902SArnaldo Carvalho de Melo list_add_tail(&opt->dccpop_node, &dmsk->dccpms_pending); 62afe00251SAndrea Bittau return 0; 63afe00251SAndrea Bittau } 64afe00251SAndrea Bittau 65afe00251SAndrea Bittau EXPORT_SYMBOL_GPL(dccp_feat_change); 66afe00251SAndrea Bittau 676ffd30fbSAndrea Bittau static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr) 686ffd30fbSAndrea Bittau { 696ffd30fbSAndrea Bittau struct dccp_sock *dp = dccp_sk(sk); 70*a4bf3902SArnaldo Carvalho de Melo struct dccp_minisock *dmsk = dccp_msk(sk); 716ffd30fbSAndrea Bittau /* figure out if we are changing our CCID or the peer's */ 726ffd30fbSAndrea Bittau const int rx = type == DCCPO_CHANGE_R; 73*a4bf3902SArnaldo Carvalho de Melo const u8 ccid_nr = rx ? dmsk->dccpms_rx_ccid : dmsk->dccpms_tx_ccid; 746ffd30fbSAndrea Bittau struct ccid *new_ccid; 756ffd30fbSAndrea Bittau 766ffd30fbSAndrea Bittau /* Check if nothing is being changed. */ 776ffd30fbSAndrea Bittau if (ccid_nr == new_ccid_nr) 786ffd30fbSAndrea Bittau return 0; 796ffd30fbSAndrea Bittau 806ffd30fbSAndrea Bittau new_ccid = ccid_new(new_ccid_nr, sk, rx, GFP_ATOMIC); 816ffd30fbSAndrea Bittau if (new_ccid == NULL) 826ffd30fbSAndrea Bittau return -ENOMEM; 836ffd30fbSAndrea Bittau 846ffd30fbSAndrea Bittau if (rx) { 856ffd30fbSAndrea Bittau ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk); 866ffd30fbSAndrea Bittau dp->dccps_hc_rx_ccid = new_ccid; 87*a4bf3902SArnaldo Carvalho de Melo dmsk->dccpms_rx_ccid = new_ccid_nr; 886ffd30fbSAndrea Bittau } else { 896ffd30fbSAndrea Bittau ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk); 906ffd30fbSAndrea Bittau dp->dccps_hc_tx_ccid = new_ccid; 91*a4bf3902SArnaldo Carvalho de Melo dmsk->dccpms_tx_ccid = new_ccid_nr; 926ffd30fbSAndrea Bittau } 936ffd30fbSAndrea Bittau 946ffd30fbSAndrea Bittau return 0; 956ffd30fbSAndrea Bittau } 966ffd30fbSAndrea Bittau 97afe00251SAndrea Bittau /* XXX taking only u8 vals */ 98afe00251SAndrea Bittau static int dccp_feat_update(struct sock *sk, u8 type, u8 feat, u8 val) 99afe00251SAndrea Bittau { 100afe00251SAndrea Bittau dccp_pr_debug("changing [%d] feat %d to %d\n", type, feat, val); 1016ffd30fbSAndrea Bittau 1026ffd30fbSAndrea Bittau switch (feat) { 1036ffd30fbSAndrea Bittau case DCCPF_CCID: 1046ffd30fbSAndrea Bittau return dccp_feat_update_ccid(sk, type, val); 1056ffd30fbSAndrea Bittau default: 1066ffd30fbSAndrea Bittau dccp_pr_debug("IMPLEMENT changing [%d] feat %d to %d\n", 1076ffd30fbSAndrea Bittau type, feat, val); 1086ffd30fbSAndrea Bittau break; 1096ffd30fbSAndrea Bittau } 110afe00251SAndrea Bittau return 0; 111afe00251SAndrea Bittau } 112afe00251SAndrea Bittau 113afe00251SAndrea Bittau static int dccp_feat_reconcile(struct sock *sk, struct dccp_opt_pend *opt, 114afe00251SAndrea Bittau u8 *rpref, u8 rlen) 115afe00251SAndrea Bittau { 116afe00251SAndrea Bittau struct dccp_sock *dp = dccp_sk(sk); 117afe00251SAndrea Bittau u8 *spref, slen, *res = NULL; 118afe00251SAndrea Bittau int i, j, rc, agree = 1; 119afe00251SAndrea Bittau 120afe00251SAndrea Bittau BUG_ON(rpref == NULL); 121afe00251SAndrea Bittau 122afe00251SAndrea Bittau /* check if we are the black sheep */ 123afe00251SAndrea Bittau if (dp->dccps_role == DCCP_ROLE_CLIENT) { 124afe00251SAndrea Bittau spref = rpref; 125afe00251SAndrea Bittau slen = rlen; 126afe00251SAndrea Bittau rpref = opt->dccpop_val; 127afe00251SAndrea Bittau rlen = opt->dccpop_len; 128afe00251SAndrea Bittau } else { 129afe00251SAndrea Bittau spref = opt->dccpop_val; 130afe00251SAndrea Bittau slen = opt->dccpop_len; 131afe00251SAndrea Bittau } 132afe00251SAndrea Bittau /* 133afe00251SAndrea Bittau * Now we have server preference list in spref and client preference in 134afe00251SAndrea Bittau * rpref 135afe00251SAndrea Bittau */ 136afe00251SAndrea Bittau BUG_ON(spref == NULL); 137afe00251SAndrea Bittau BUG_ON(rpref == NULL); 138afe00251SAndrea Bittau 139afe00251SAndrea Bittau /* FIXME sanity check vals */ 140afe00251SAndrea Bittau 141afe00251SAndrea Bittau /* Are values in any order? XXX Lame "algorithm" here */ 142afe00251SAndrea Bittau /* XXX assume values are 1 byte */ 143afe00251SAndrea Bittau for (i = 0; i < slen; i++) { 144afe00251SAndrea Bittau for (j = 0; j < rlen; j++) { 145afe00251SAndrea Bittau if (spref[i] == rpref[j]) { 146afe00251SAndrea Bittau res = &spref[i]; 147afe00251SAndrea Bittau break; 148afe00251SAndrea Bittau } 149afe00251SAndrea Bittau } 150afe00251SAndrea Bittau if (res) 151afe00251SAndrea Bittau break; 152afe00251SAndrea Bittau } 153afe00251SAndrea Bittau 154afe00251SAndrea Bittau /* we didn't agree on anything */ 155afe00251SAndrea Bittau if (res == NULL) { 156afe00251SAndrea Bittau /* confirm previous value */ 157afe00251SAndrea Bittau switch (opt->dccpop_feat) { 158afe00251SAndrea Bittau case DCCPF_CCID: 159afe00251SAndrea Bittau /* XXX did i get this right? =P */ 160afe00251SAndrea Bittau if (opt->dccpop_type == DCCPO_CHANGE_L) 161*a4bf3902SArnaldo Carvalho de Melo res = &dccp_msk(sk)->dccpms_tx_ccid; 162afe00251SAndrea Bittau else 163*a4bf3902SArnaldo Carvalho de Melo res = &dccp_msk(sk)->dccpms_rx_ccid; 164afe00251SAndrea Bittau break; 165afe00251SAndrea Bittau 166afe00251SAndrea Bittau default: 167afe00251SAndrea Bittau WARN_ON(1); /* XXX implement res */ 168afe00251SAndrea Bittau return -EFAULT; 169afe00251SAndrea Bittau } 170afe00251SAndrea Bittau 171afe00251SAndrea Bittau dccp_pr_debug("Don't agree... reconfirming %d\n", *res); 172afe00251SAndrea Bittau agree = 0; /* this is used for mandatory options... */ 173afe00251SAndrea Bittau } 174afe00251SAndrea Bittau 175afe00251SAndrea Bittau /* need to put result and our preference list */ 176afe00251SAndrea Bittau /* XXX assume 1 byte vals */ 177afe00251SAndrea Bittau rlen = 1 + opt->dccpop_len; 178afe00251SAndrea Bittau rpref = kmalloc(rlen, GFP_ATOMIC); 179afe00251SAndrea Bittau if (rpref == NULL) 180afe00251SAndrea Bittau return -ENOMEM; 181afe00251SAndrea Bittau 182afe00251SAndrea Bittau *rpref = *res; 183afe00251SAndrea Bittau memcpy(&rpref[1], opt->dccpop_val, opt->dccpop_len); 184afe00251SAndrea Bittau 185afe00251SAndrea Bittau /* put it in the "confirm queue" */ 186afe00251SAndrea Bittau if (opt->dccpop_sc == NULL) { 187afe00251SAndrea Bittau opt->dccpop_sc = kmalloc(sizeof(*opt->dccpop_sc), GFP_ATOMIC); 188afe00251SAndrea Bittau if (opt->dccpop_sc == NULL) { 189afe00251SAndrea Bittau kfree(rpref); 190afe00251SAndrea Bittau return -ENOMEM; 191afe00251SAndrea Bittau } 192afe00251SAndrea Bittau } else { 193afe00251SAndrea Bittau /* recycle the confirm slot */ 194afe00251SAndrea Bittau BUG_ON(opt->dccpop_sc->dccpoc_val == NULL); 195afe00251SAndrea Bittau kfree(opt->dccpop_sc->dccpoc_val); 196afe00251SAndrea Bittau dccp_pr_debug("recycling confirm slot\n"); 197afe00251SAndrea Bittau } 198afe00251SAndrea Bittau memset(opt->dccpop_sc, 0, sizeof(*opt->dccpop_sc)); 199afe00251SAndrea Bittau 200afe00251SAndrea Bittau opt->dccpop_sc->dccpoc_val = rpref; 201afe00251SAndrea Bittau opt->dccpop_sc->dccpoc_len = rlen; 202afe00251SAndrea Bittau 203afe00251SAndrea Bittau /* update the option on our side [we are about to send the confirm] */ 204afe00251SAndrea Bittau rc = dccp_feat_update(sk, opt->dccpop_type, opt->dccpop_feat, *res); 205afe00251SAndrea Bittau if (rc) { 206afe00251SAndrea Bittau kfree(opt->dccpop_sc->dccpoc_val); 207afe00251SAndrea Bittau kfree(opt->dccpop_sc); 208afe00251SAndrea Bittau opt->dccpop_sc = 0; 209afe00251SAndrea Bittau return rc; 210afe00251SAndrea Bittau } 211afe00251SAndrea Bittau 212afe00251SAndrea Bittau dccp_pr_debug("Will confirm %d\n", *rpref); 213afe00251SAndrea Bittau 214afe00251SAndrea Bittau /* say we want to change to X but we just got a confirm X, suppress our 215afe00251SAndrea Bittau * change 216afe00251SAndrea Bittau */ 217afe00251SAndrea Bittau if (!opt->dccpop_conf) { 218afe00251SAndrea Bittau if (*opt->dccpop_val == *res) 219afe00251SAndrea Bittau opt->dccpop_conf = 1; 220afe00251SAndrea Bittau dccp_pr_debug("won't ask for change of same feature\n"); 221afe00251SAndrea Bittau } 222afe00251SAndrea Bittau 223afe00251SAndrea Bittau return agree ? 0 : DCCP_FEAT_SP_NOAGREE; /* used for mandatory opts */ 224afe00251SAndrea Bittau } 225afe00251SAndrea Bittau 226afe00251SAndrea Bittau static int dccp_feat_sp(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) 227afe00251SAndrea Bittau { 228*a4bf3902SArnaldo Carvalho de Melo struct dccp_minisock *dmsk = dccp_msk(sk); 229afe00251SAndrea Bittau struct dccp_opt_pend *opt; 230afe00251SAndrea Bittau int rc = 1; 231afe00251SAndrea Bittau u8 t; 232afe00251SAndrea Bittau 233afe00251SAndrea Bittau /* 234afe00251SAndrea Bittau * We received a CHANGE. We gotta match it against our own preference 235afe00251SAndrea Bittau * list. If we got a CHANGE_R it means it's a change for us, so we need 236afe00251SAndrea Bittau * to compare our CHANGE_L list. 237afe00251SAndrea Bittau */ 238afe00251SAndrea Bittau if (type == DCCPO_CHANGE_L) 239afe00251SAndrea Bittau t = DCCPO_CHANGE_R; 240afe00251SAndrea Bittau else 241afe00251SAndrea Bittau t = DCCPO_CHANGE_L; 242afe00251SAndrea Bittau 243afe00251SAndrea Bittau /* find our preference list for this feature */ 244*a4bf3902SArnaldo Carvalho de Melo list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { 245afe00251SAndrea Bittau if (opt->dccpop_type != t || opt->dccpop_feat != feature) 246afe00251SAndrea Bittau continue; 247afe00251SAndrea Bittau 248afe00251SAndrea Bittau /* find the winner from the two preference lists */ 249afe00251SAndrea Bittau rc = dccp_feat_reconcile(sk, opt, val, len); 250afe00251SAndrea Bittau break; 251afe00251SAndrea Bittau } 252afe00251SAndrea Bittau 253afe00251SAndrea Bittau /* We didn't deal with the change. This can happen if we have no 254afe00251SAndrea Bittau * preference list for the feature. In fact, it just shouldn't 255afe00251SAndrea Bittau * happen---if we understand a feature, we should have a preference list 256afe00251SAndrea Bittau * with at least the default value. 257afe00251SAndrea Bittau */ 258afe00251SAndrea Bittau BUG_ON(rc == 1); 259afe00251SAndrea Bittau 260afe00251SAndrea Bittau return rc; 261afe00251SAndrea Bittau } 262afe00251SAndrea Bittau 263afe00251SAndrea Bittau static int dccp_feat_nn(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) 264afe00251SAndrea Bittau { 265afe00251SAndrea Bittau struct dccp_opt_pend *opt; 266*a4bf3902SArnaldo Carvalho de Melo struct dccp_minisock *dmsk = dccp_msk(sk); 267afe00251SAndrea Bittau u8 *copy; 268afe00251SAndrea Bittau int rc; 269afe00251SAndrea Bittau 270afe00251SAndrea Bittau /* NN features must be change L */ 271afe00251SAndrea Bittau if (type == DCCPO_CHANGE_R) { 272afe00251SAndrea Bittau dccp_pr_debug("received CHANGE_R %d for NN feat %d\n", 273afe00251SAndrea Bittau type, feature); 274afe00251SAndrea Bittau return -EFAULT; 275afe00251SAndrea Bittau } 276afe00251SAndrea Bittau 277afe00251SAndrea Bittau /* XXX sanity check opt val */ 278afe00251SAndrea Bittau 279afe00251SAndrea Bittau /* copy option so we can confirm it */ 280afe00251SAndrea Bittau opt = kzalloc(sizeof(*opt), GFP_ATOMIC); 281afe00251SAndrea Bittau if (opt == NULL) 282afe00251SAndrea Bittau return -ENOMEM; 283afe00251SAndrea Bittau 284afe00251SAndrea Bittau copy = kmalloc(len, GFP_ATOMIC); 285afe00251SAndrea Bittau if (copy == NULL) { 286afe00251SAndrea Bittau kfree(opt); 287afe00251SAndrea Bittau return -ENOMEM; 288afe00251SAndrea Bittau } 289afe00251SAndrea Bittau memcpy(copy, val, len); 290afe00251SAndrea Bittau 291afe00251SAndrea Bittau opt->dccpop_type = DCCPO_CONFIRM_R; /* NN can only confirm R */ 292afe00251SAndrea Bittau opt->dccpop_feat = feature; 293afe00251SAndrea Bittau opt->dccpop_val = copy; 294afe00251SAndrea Bittau opt->dccpop_len = len; 295afe00251SAndrea Bittau 296afe00251SAndrea Bittau /* change feature */ 297afe00251SAndrea Bittau rc = dccp_feat_update(sk, type, feature, *val); 298afe00251SAndrea Bittau if (rc) { 299afe00251SAndrea Bittau kfree(opt->dccpop_val); 300afe00251SAndrea Bittau kfree(opt); 301afe00251SAndrea Bittau return rc; 302afe00251SAndrea Bittau } 303afe00251SAndrea Bittau 304afe00251SAndrea Bittau dccp_pr_debug("Confirming NN feature %d (val=%d)\n", feature, *copy); 305*a4bf3902SArnaldo Carvalho de Melo list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf); 306afe00251SAndrea Bittau 307afe00251SAndrea Bittau return 0; 308afe00251SAndrea Bittau } 309afe00251SAndrea Bittau 310afe00251SAndrea Bittau static void dccp_feat_empty_confirm(struct sock *sk, u8 type, u8 feature) 311afe00251SAndrea Bittau { 312*a4bf3902SArnaldo Carvalho de Melo struct dccp_minisock *dmsk = dccp_msk(sk); 313afe00251SAndrea Bittau /* XXX check if other confirms for that are queued and recycle slot */ 314afe00251SAndrea Bittau struct dccp_opt_pend *opt = kzalloc(sizeof(*opt), GFP_ATOMIC); 315afe00251SAndrea Bittau 316afe00251SAndrea Bittau if (opt == NULL) { 317afe00251SAndrea Bittau /* XXX what do we do? Ignoring should be fine. It's a change 318afe00251SAndrea Bittau * after all =P 319afe00251SAndrea Bittau */ 320afe00251SAndrea Bittau return; 321afe00251SAndrea Bittau } 322afe00251SAndrea Bittau 323afe00251SAndrea Bittau opt->dccpop_type = type == DCCPO_CHANGE_L ? DCCPO_CONFIRM_R : 324afe00251SAndrea Bittau DCCPO_CONFIRM_L; 325afe00251SAndrea Bittau opt->dccpop_feat = feature; 326afe00251SAndrea Bittau opt->dccpop_val = 0; 327afe00251SAndrea Bittau opt->dccpop_len = 0; 328afe00251SAndrea Bittau 329afe00251SAndrea Bittau /* change feature */ 330afe00251SAndrea Bittau dccp_pr_debug("Empty confirm feature %d type %d\n", feature, type); 331*a4bf3902SArnaldo Carvalho de Melo list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf); 332afe00251SAndrea Bittau } 333afe00251SAndrea Bittau 334afe00251SAndrea Bittau static void dccp_feat_flush_confirm(struct sock *sk) 335afe00251SAndrea Bittau { 336*a4bf3902SArnaldo Carvalho de Melo struct dccp_minisock *dmsk = dccp_msk(sk); 337afe00251SAndrea Bittau /* Check if there is anything to confirm in the first place */ 338*a4bf3902SArnaldo Carvalho de Melo int yes = !list_empty(&dmsk->dccpms_conf); 339afe00251SAndrea Bittau 340afe00251SAndrea Bittau if (!yes) { 341afe00251SAndrea Bittau struct dccp_opt_pend *opt; 342afe00251SAndrea Bittau 343*a4bf3902SArnaldo Carvalho de Melo list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { 344afe00251SAndrea Bittau if (opt->dccpop_conf) { 345afe00251SAndrea Bittau yes = 1; 346afe00251SAndrea Bittau break; 347afe00251SAndrea Bittau } 348afe00251SAndrea Bittau } 349afe00251SAndrea Bittau } 350afe00251SAndrea Bittau 351afe00251SAndrea Bittau if (!yes) 352afe00251SAndrea Bittau return; 353afe00251SAndrea Bittau 354afe00251SAndrea Bittau /* OK there is something to confirm... */ 355afe00251SAndrea Bittau /* XXX check if packet is in flight? Send delayed ack?? */ 356afe00251SAndrea Bittau if (sk->sk_state == DCCP_OPEN) 357afe00251SAndrea Bittau dccp_send_ack(sk); 358afe00251SAndrea Bittau } 359afe00251SAndrea Bittau 360afe00251SAndrea Bittau int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) 361afe00251SAndrea Bittau { 362afe00251SAndrea Bittau int rc; 363afe00251SAndrea Bittau 364afe00251SAndrea Bittau dccp_pr_debug("got feat change type=%d feat=%d\n", type, feature); 365afe00251SAndrea Bittau 366afe00251SAndrea Bittau /* figure out if it's SP or NN feature */ 367afe00251SAndrea Bittau switch (feature) { 368afe00251SAndrea Bittau /* deal with SP features */ 369afe00251SAndrea Bittau case DCCPF_CCID: 370afe00251SAndrea Bittau rc = dccp_feat_sp(sk, type, feature, val, len); 371afe00251SAndrea Bittau break; 372afe00251SAndrea Bittau 373afe00251SAndrea Bittau /* deal with NN features */ 374afe00251SAndrea Bittau case DCCPF_ACK_RATIO: 375afe00251SAndrea Bittau rc = dccp_feat_nn(sk, type, feature, val, len); 376afe00251SAndrea Bittau break; 377afe00251SAndrea Bittau 378afe00251SAndrea Bittau /* XXX implement other features */ 379afe00251SAndrea Bittau default: 380afe00251SAndrea Bittau rc = -EFAULT; 381afe00251SAndrea Bittau break; 382afe00251SAndrea Bittau } 383afe00251SAndrea Bittau 384afe00251SAndrea Bittau /* check if there were problems changing features */ 385afe00251SAndrea Bittau if (rc) { 386afe00251SAndrea Bittau /* If we don't agree on SP, we sent a confirm for old value. 387afe00251SAndrea Bittau * However we propagate rc to caller in case option was 388afe00251SAndrea Bittau * mandatory 389afe00251SAndrea Bittau */ 390afe00251SAndrea Bittau if (rc != DCCP_FEAT_SP_NOAGREE) 391afe00251SAndrea Bittau dccp_feat_empty_confirm(sk, type, feature); 392afe00251SAndrea Bittau } 393afe00251SAndrea Bittau 394afe00251SAndrea Bittau /* generate the confirm [if required] */ 395afe00251SAndrea Bittau dccp_feat_flush_confirm(sk); 396afe00251SAndrea Bittau 397afe00251SAndrea Bittau return rc; 398afe00251SAndrea Bittau } 399afe00251SAndrea Bittau 400afe00251SAndrea Bittau EXPORT_SYMBOL_GPL(dccp_feat_change_recv); 401afe00251SAndrea Bittau 402afe00251SAndrea Bittau int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, 403afe00251SAndrea Bittau u8 *val, u8 len) 404afe00251SAndrea Bittau { 405afe00251SAndrea Bittau u8 t; 406afe00251SAndrea Bittau struct dccp_opt_pend *opt; 407*a4bf3902SArnaldo Carvalho de Melo struct dccp_minisock *dmsk = dccp_msk(sk); 408afe00251SAndrea Bittau int rc = 1; 409afe00251SAndrea Bittau int all_confirmed = 1; 410afe00251SAndrea Bittau 411afe00251SAndrea Bittau dccp_pr_debug("got feat confirm type=%d feat=%d\n", type, feature); 412afe00251SAndrea Bittau 413afe00251SAndrea Bittau /* XXX sanity check type & feat */ 414afe00251SAndrea Bittau 415afe00251SAndrea Bittau /* locate our change request */ 416afe00251SAndrea Bittau t = type == DCCPO_CONFIRM_L ? DCCPO_CHANGE_R : DCCPO_CHANGE_L; 417afe00251SAndrea Bittau 418*a4bf3902SArnaldo Carvalho de Melo list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { 419afe00251SAndrea Bittau if (!opt->dccpop_conf && opt->dccpop_type == t && 420afe00251SAndrea Bittau opt->dccpop_feat == feature) { 421afe00251SAndrea Bittau /* we found it */ 422afe00251SAndrea Bittau /* XXX do sanity check */ 423afe00251SAndrea Bittau 424afe00251SAndrea Bittau opt->dccpop_conf = 1; 425afe00251SAndrea Bittau 426afe00251SAndrea Bittau /* We got a confirmation---change the option */ 427afe00251SAndrea Bittau dccp_feat_update(sk, opt->dccpop_type, 428afe00251SAndrea Bittau opt->dccpop_feat, *val); 429afe00251SAndrea Bittau 430afe00251SAndrea Bittau dccp_pr_debug("feat %d type %d confirmed %d\n", 431afe00251SAndrea Bittau feature, type, *val); 432afe00251SAndrea Bittau rc = 0; 433afe00251SAndrea Bittau break; 434afe00251SAndrea Bittau } 435afe00251SAndrea Bittau 436afe00251SAndrea Bittau if (!opt->dccpop_conf) 437afe00251SAndrea Bittau all_confirmed = 0; 438afe00251SAndrea Bittau } 439afe00251SAndrea Bittau 440afe00251SAndrea Bittau /* fix re-transmit timer */ 441afe00251SAndrea Bittau /* XXX gotta make sure that no option negotiation occurs during 442afe00251SAndrea Bittau * connection shutdown. Consider that the CLOSEREQ is sent and timer is 443afe00251SAndrea Bittau * on. if all options are confirmed it might kill timer which should 444afe00251SAndrea Bittau * remain alive until close is received. 445afe00251SAndrea Bittau */ 446afe00251SAndrea Bittau if (all_confirmed) { 447afe00251SAndrea Bittau dccp_pr_debug("clear feat negotiation timer %p\n", sk); 448afe00251SAndrea Bittau inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS); 449afe00251SAndrea Bittau } 450afe00251SAndrea Bittau 451afe00251SAndrea Bittau if (rc) 452afe00251SAndrea Bittau dccp_pr_debug("feat %d type %d never requested\n", 453afe00251SAndrea Bittau feature, type); 454afe00251SAndrea Bittau return 0; 455afe00251SAndrea Bittau } 456afe00251SAndrea Bittau 457afe00251SAndrea Bittau EXPORT_SYMBOL_GPL(dccp_feat_confirm_recv); 458afe00251SAndrea Bittau 459afe00251SAndrea Bittau void dccp_feat_clean(struct sock *sk) 460afe00251SAndrea Bittau { 461*a4bf3902SArnaldo Carvalho de Melo struct dccp_minisock *dmsk = dccp_msk(sk); 462afe00251SAndrea Bittau struct dccp_opt_pend *opt, *next; 463afe00251SAndrea Bittau 464*a4bf3902SArnaldo Carvalho de Melo list_for_each_entry_safe(opt, next, &dmsk->dccpms_pending, 465afe00251SAndrea Bittau dccpop_node) { 466afe00251SAndrea Bittau BUG_ON(opt->dccpop_val == NULL); 467afe00251SAndrea Bittau kfree(opt->dccpop_val); 468afe00251SAndrea Bittau 469afe00251SAndrea Bittau if (opt->dccpop_sc != NULL) { 470afe00251SAndrea Bittau BUG_ON(opt->dccpop_sc->dccpoc_val == NULL); 471afe00251SAndrea Bittau kfree(opt->dccpop_sc->dccpoc_val); 472afe00251SAndrea Bittau kfree(opt->dccpop_sc); 473afe00251SAndrea Bittau } 474afe00251SAndrea Bittau 475afe00251SAndrea Bittau kfree(opt); 476afe00251SAndrea Bittau } 477*a4bf3902SArnaldo Carvalho de Melo INIT_LIST_HEAD(&dmsk->dccpms_pending); 478afe00251SAndrea Bittau 479*a4bf3902SArnaldo Carvalho de Melo list_for_each_entry_safe(opt, next, &dmsk->dccpms_conf, dccpop_node) { 480afe00251SAndrea Bittau BUG_ON(opt == NULL); 481afe00251SAndrea Bittau if (opt->dccpop_val != NULL) 482afe00251SAndrea Bittau kfree(opt->dccpop_val); 483afe00251SAndrea Bittau kfree(opt); 484afe00251SAndrea Bittau } 485*a4bf3902SArnaldo Carvalho de Melo INIT_LIST_HEAD(&dmsk->dccpms_conf); 486afe00251SAndrea Bittau } 487afe00251SAndrea Bittau 488afe00251SAndrea Bittau EXPORT_SYMBOL_GPL(dccp_feat_clean); 489afe00251SAndrea Bittau 490afe00251SAndrea Bittau /* this is to be called only when a listening sock creates its child. It is 491afe00251SAndrea Bittau * assumed by the function---the confirm is not duplicated, but rather it is 492afe00251SAndrea Bittau * "passed on". 493afe00251SAndrea Bittau */ 494afe00251SAndrea Bittau int dccp_feat_clone(struct sock *oldsk, struct sock *newsk) 495afe00251SAndrea Bittau { 496*a4bf3902SArnaldo Carvalho de Melo struct dccp_minisock *olddmsk = dccp_msk(oldsk); 497*a4bf3902SArnaldo Carvalho de Melo struct dccp_minisock *newdmsk = dccp_msk(newsk); 498afe00251SAndrea Bittau struct dccp_opt_pend *opt; 499afe00251SAndrea Bittau int rc = 0; 500afe00251SAndrea Bittau 501*a4bf3902SArnaldo Carvalho de Melo INIT_LIST_HEAD(&newdmsk->dccpms_pending); 502*a4bf3902SArnaldo Carvalho de Melo INIT_LIST_HEAD(&newdmsk->dccpms_conf); 503afe00251SAndrea Bittau 504*a4bf3902SArnaldo Carvalho de Melo list_for_each_entry(opt, &olddmsk->dccpms_pending, dccpop_node) { 505afe00251SAndrea Bittau struct dccp_opt_pend *newopt; 506afe00251SAndrea Bittau /* copy the value of the option */ 507afe00251SAndrea Bittau u8 *val = kmalloc(opt->dccpop_len, GFP_ATOMIC); 508afe00251SAndrea Bittau 509afe00251SAndrea Bittau if (val == NULL) 510afe00251SAndrea Bittau goto out_clean; 511afe00251SAndrea Bittau memcpy(val, opt->dccpop_val, opt->dccpop_len); 512afe00251SAndrea Bittau 513afe00251SAndrea Bittau newopt = kmalloc(sizeof(*newopt), GFP_ATOMIC); 514afe00251SAndrea Bittau if (newopt == NULL) { 515afe00251SAndrea Bittau kfree(val); 516afe00251SAndrea Bittau goto out_clean; 517afe00251SAndrea Bittau } 518afe00251SAndrea Bittau 519afe00251SAndrea Bittau /* insert the option */ 520afe00251SAndrea Bittau memcpy(newopt, opt, sizeof(*newopt)); 521afe00251SAndrea Bittau newopt->dccpop_val = val; 522*a4bf3902SArnaldo Carvalho de Melo list_add_tail(&newopt->dccpop_node, &newdmsk->dccpms_pending); 523afe00251SAndrea Bittau 524afe00251SAndrea Bittau /* XXX what happens with backlogs and multiple connections at 525afe00251SAndrea Bittau * once... 526afe00251SAndrea Bittau */ 527afe00251SAndrea Bittau /* the master socket no longer needs to worry about confirms */ 528afe00251SAndrea Bittau opt->dccpop_sc = 0; /* it's not a memleak---new socket has it */ 529afe00251SAndrea Bittau 530afe00251SAndrea Bittau /* reset state for a new socket */ 531afe00251SAndrea Bittau opt->dccpop_conf = 0; 532afe00251SAndrea Bittau } 533afe00251SAndrea Bittau 534afe00251SAndrea Bittau /* XXX not doing anything about the conf queue */ 535afe00251SAndrea Bittau 536afe00251SAndrea Bittau out: 537afe00251SAndrea Bittau return rc; 538afe00251SAndrea Bittau 539afe00251SAndrea Bittau out_clean: 540afe00251SAndrea Bittau dccp_feat_clean(newsk); 541afe00251SAndrea Bittau rc = -ENOMEM; 542afe00251SAndrea Bittau goto out; 543afe00251SAndrea Bittau } 544afe00251SAndrea Bittau 545afe00251SAndrea Bittau EXPORT_SYMBOL_GPL(dccp_feat_clone); 546afe00251SAndrea Bittau 547afe00251SAndrea Bittau static int __dccp_feat_init(struct sock *sk, u8 type, u8 feat, u8 *val, u8 len) 548afe00251SAndrea Bittau { 549afe00251SAndrea Bittau int rc = -ENOMEM; 550afe00251SAndrea Bittau u8 *copy = kmalloc(len, GFP_KERNEL); 551afe00251SAndrea Bittau 552afe00251SAndrea Bittau if (copy != NULL) { 553afe00251SAndrea Bittau memcpy(copy, val, len); 554afe00251SAndrea Bittau rc = dccp_feat_change(sk, type, feat, copy, len, GFP_KERNEL); 555afe00251SAndrea Bittau if (rc) 556afe00251SAndrea Bittau kfree(copy); 557afe00251SAndrea Bittau } 558afe00251SAndrea Bittau return rc; 559afe00251SAndrea Bittau } 560afe00251SAndrea Bittau 561afe00251SAndrea Bittau int dccp_feat_init(struct sock *sk) 562afe00251SAndrea Bittau { 563*a4bf3902SArnaldo Carvalho de Melo struct dccp_minisock *dmsk = dccp_msk(sk); 564afe00251SAndrea Bittau int rc; 565afe00251SAndrea Bittau 566*a4bf3902SArnaldo Carvalho de Melo INIT_LIST_HEAD(&dmsk->dccpms_pending); 567*a4bf3902SArnaldo Carvalho de Melo INIT_LIST_HEAD(&dmsk->dccpms_conf); 568afe00251SAndrea Bittau 569afe00251SAndrea Bittau /* CCID L */ 570afe00251SAndrea Bittau rc = __dccp_feat_init(sk, DCCPO_CHANGE_L, DCCPF_CCID, 571*a4bf3902SArnaldo Carvalho de Melo &dmsk->dccpms_tx_ccid, 1); 572afe00251SAndrea Bittau if (rc) 573afe00251SAndrea Bittau goto out; 574afe00251SAndrea Bittau 575afe00251SAndrea Bittau /* CCID R */ 576afe00251SAndrea Bittau rc = __dccp_feat_init(sk, DCCPO_CHANGE_R, DCCPF_CCID, 577*a4bf3902SArnaldo Carvalho de Melo &dmsk->dccpms_rx_ccid, 1); 578afe00251SAndrea Bittau if (rc) 579afe00251SAndrea Bittau goto out; 580afe00251SAndrea Bittau 581afe00251SAndrea Bittau /* Ack ratio */ 582afe00251SAndrea Bittau rc = __dccp_feat_init(sk, DCCPO_CHANGE_L, DCCPF_ACK_RATIO, 583*a4bf3902SArnaldo Carvalho de Melo &dmsk->dccpms_ack_ratio, 1); 584afe00251SAndrea Bittau out: 585afe00251SAndrea Bittau return rc; 586afe00251SAndrea Bittau } 587afe00251SAndrea Bittau 588afe00251SAndrea Bittau EXPORT_SYMBOL_GPL(dccp_feat_init); 589