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