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 * 75cdae198SGerrit Renker * ASSUMPTIONS 85cdae198SGerrit Renker * ----------- 9f74e91b6SGerrit Renker * o Feature negotiation is coordinated with connection setup (as in TCP), wild 10f74e91b6SGerrit Renker * changes of parameters of an established connection are not supported. 115cdae198SGerrit Renker * o All currently known SP features have 1-byte quantities. If in the future 125cdae198SGerrit Renker * extensions of RFCs 4340..42 define features with item lengths larger than 135cdae198SGerrit Renker * one byte, a feature-specific extension of the code will be required. 145cdae198SGerrit Renker * 15afe00251SAndrea Bittau * This program is free software; you can redistribute it and/or 16afe00251SAndrea Bittau * modify it under the terms of the GNU General Public License 17afe00251SAndrea Bittau * as published by the Free Software Foundation; either version 18afe00251SAndrea Bittau * 2 of the License, or (at your option) any later version. 19afe00251SAndrea Bittau */ 20afe00251SAndrea Bittau 21afe00251SAndrea Bittau #include <linux/module.h> 22afe00251SAndrea Bittau 236ffd30fbSAndrea Bittau #include "ccid.h" 24afe00251SAndrea Bittau #include "feat.h" 25afe00251SAndrea Bittau 26afe00251SAndrea Bittau #define DCCP_FEAT_SP_NOAGREE (-123) 27afe00251SAndrea Bittau 287d43d1a0SGerrit Renker static const struct { 297d43d1a0SGerrit Renker u8 feat_num; /* DCCPF_xxx */ 307d43d1a0SGerrit Renker enum dccp_feat_type rxtx; /* RX or TX */ 317d43d1a0SGerrit Renker enum dccp_feat_type reconciliation; /* SP or NN */ 327d43d1a0SGerrit Renker u8 default_value; /* as in 6.4 */ 337d43d1a0SGerrit Renker /* 347d43d1a0SGerrit Renker * Lookup table for location and type of features (from RFC 4340/4342) 357d43d1a0SGerrit Renker * +--------------------------+----+-----+----+----+---------+-----------+ 367d43d1a0SGerrit Renker * | Feature | Location | Reconc. | Initial | Section | 377d43d1a0SGerrit Renker * | | RX | TX | SP | NN | Value | Reference | 387d43d1a0SGerrit Renker * +--------------------------+----+-----+----+----+---------+-----------+ 397d43d1a0SGerrit Renker * | DCCPF_CCID | | X | X | | 2 | 10 | 407d43d1a0SGerrit Renker * | DCCPF_SHORT_SEQNOS | | X | X | | 0 | 7.6.1 | 417d43d1a0SGerrit Renker * | DCCPF_SEQUENCE_WINDOW | | X | | X | 100 | 7.5.2 | 427d43d1a0SGerrit Renker * | DCCPF_ECN_INCAPABLE | X | | X | | 0 | 12.1 | 437d43d1a0SGerrit Renker * | DCCPF_ACK_RATIO | | X | | X | 2 | 11.3 | 447d43d1a0SGerrit Renker * | DCCPF_SEND_ACK_VECTOR | X | | X | | 0 | 11.5 | 457d43d1a0SGerrit Renker * | DCCPF_SEND_NDP_COUNT | | X | X | | 0 | 7.7.2 | 467d43d1a0SGerrit Renker * | DCCPF_MIN_CSUM_COVER | X | | X | | 0 | 9.2.1 | 477d43d1a0SGerrit Renker * | DCCPF_DATA_CHECKSUM | X | | X | | 0 | 9.3.1 | 487d43d1a0SGerrit Renker * | DCCPF_SEND_LEV_RATE | X | | X | | 0 | 4342/8.4 | 497d43d1a0SGerrit Renker * +--------------------------+----+-----+----+----+---------+-----------+ 507d43d1a0SGerrit Renker */ 517d43d1a0SGerrit Renker } dccp_feat_table[] = { 527d43d1a0SGerrit Renker { DCCPF_CCID, FEAT_AT_TX, FEAT_SP, 2 }, 537d43d1a0SGerrit Renker { DCCPF_SHORT_SEQNOS, FEAT_AT_TX, FEAT_SP, 0 }, 547d43d1a0SGerrit Renker { DCCPF_SEQUENCE_WINDOW, FEAT_AT_TX, FEAT_NN, 100 }, 557d43d1a0SGerrit Renker { DCCPF_ECN_INCAPABLE, FEAT_AT_RX, FEAT_SP, 0 }, 567d43d1a0SGerrit Renker { DCCPF_ACK_RATIO, FEAT_AT_TX, FEAT_NN, 2 }, 577d43d1a0SGerrit Renker { DCCPF_SEND_ACK_VECTOR, FEAT_AT_RX, FEAT_SP, 0 }, 587d43d1a0SGerrit Renker { DCCPF_SEND_NDP_COUNT, FEAT_AT_TX, FEAT_SP, 0 }, 597d43d1a0SGerrit Renker { DCCPF_MIN_CSUM_COVER, FEAT_AT_RX, FEAT_SP, 0 }, 607d43d1a0SGerrit Renker { DCCPF_DATA_CHECKSUM, FEAT_AT_RX, FEAT_SP, 0 }, 617d43d1a0SGerrit Renker { DCCPF_SEND_LEV_RATE, FEAT_AT_RX, FEAT_SP, 0 }, 627d43d1a0SGerrit Renker }; 637d43d1a0SGerrit Renker #define DCCP_FEAT_SUPPORTED_MAX ARRAY_SIZE(dccp_feat_table) 647d43d1a0SGerrit Renker 6561e6473eSGerrit Renker /** 6661e6473eSGerrit Renker * dccp_feat_index - Hash function to map feature number into array position 6761e6473eSGerrit Renker * Returns consecutive array index or -1 if the feature is not understood. 6861e6473eSGerrit Renker */ 6961e6473eSGerrit Renker static int dccp_feat_index(u8 feat_num) 7061e6473eSGerrit Renker { 7161e6473eSGerrit Renker /* The first 9 entries are occupied by the types from RFC 4340, 6.4 */ 7261e6473eSGerrit Renker if (feat_num > DCCPF_RESERVED && feat_num <= DCCPF_DATA_CHECKSUM) 7361e6473eSGerrit Renker return feat_num - 1; 7461e6473eSGerrit Renker 7561e6473eSGerrit Renker /* 7661e6473eSGerrit Renker * Other features: add cases for new feature types here after adding 7761e6473eSGerrit Renker * them to the above table. 7861e6473eSGerrit Renker */ 7961e6473eSGerrit Renker switch (feat_num) { 8061e6473eSGerrit Renker case DCCPF_SEND_LEV_RATE: 8161e6473eSGerrit Renker return DCCP_FEAT_SUPPORTED_MAX - 1; 8261e6473eSGerrit Renker } 8361e6473eSGerrit Renker return -1; 8461e6473eSGerrit Renker } 8561e6473eSGerrit Renker 8661e6473eSGerrit Renker static u8 dccp_feat_type(u8 feat_num) 8761e6473eSGerrit Renker { 8861e6473eSGerrit Renker int idx = dccp_feat_index(feat_num); 8961e6473eSGerrit Renker 9061e6473eSGerrit Renker if (idx < 0) 9161e6473eSGerrit Renker return FEAT_UNKNOWN; 9261e6473eSGerrit Renker return dccp_feat_table[idx].reconciliation; 9361e6473eSGerrit Renker } 9461e6473eSGerrit Renker 95*e8ef967aSGerrit Renker static int dccp_feat_default_value(u8 feat_num) 96*e8ef967aSGerrit Renker { 97*e8ef967aSGerrit Renker int idx = dccp_feat_index(feat_num); 98*e8ef967aSGerrit Renker /* 99*e8ef967aSGerrit Renker * There are no default values for unknown features, so encountering a 100*e8ef967aSGerrit Renker * negative index here indicates a serious problem somewhere else. 101*e8ef967aSGerrit Renker */ 102*e8ef967aSGerrit Renker DCCP_BUG_ON(idx < 0); 103*e8ef967aSGerrit Renker 104*e8ef967aSGerrit Renker return idx < 0 ? 0 : dccp_feat_table[idx].default_value; 105*e8ef967aSGerrit Renker } 106*e8ef967aSGerrit Renker 107ac75773cSGerrit Renker /* copy constructor, fval must not already contain allocated memory */ 108ac75773cSGerrit Renker static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len) 109ac75773cSGerrit Renker { 110ac75773cSGerrit Renker fval->sp.len = len; 111ac75773cSGerrit Renker if (fval->sp.len > 0) { 112ac75773cSGerrit Renker fval->sp.vec = kmemdup(val, len, gfp_any()); 113ac75773cSGerrit Renker if (fval->sp.vec == NULL) { 114ac75773cSGerrit Renker fval->sp.len = 0; 115ac75773cSGerrit Renker return -ENOBUFS; 116ac75773cSGerrit Renker } 117ac75773cSGerrit Renker } 118ac75773cSGerrit Renker return 0; 119ac75773cSGerrit Renker } 120ac75773cSGerrit Renker 12161e6473eSGerrit Renker static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val) 12261e6473eSGerrit Renker { 12361e6473eSGerrit Renker if (unlikely(val == NULL)) 12461e6473eSGerrit Renker return; 12561e6473eSGerrit Renker if (dccp_feat_type(feat_num) == FEAT_SP) 12661e6473eSGerrit Renker kfree(val->sp.vec); 12761e6473eSGerrit Renker memset(val, 0, sizeof(*val)); 12861e6473eSGerrit Renker } 12961e6473eSGerrit Renker 130ac75773cSGerrit Renker static struct dccp_feat_entry * 131ac75773cSGerrit Renker dccp_feat_clone_entry(struct dccp_feat_entry const *original) 132ac75773cSGerrit Renker { 133ac75773cSGerrit Renker struct dccp_feat_entry *new; 134ac75773cSGerrit Renker u8 type = dccp_feat_type(original->feat_num); 135ac75773cSGerrit Renker 136ac75773cSGerrit Renker if (type == FEAT_UNKNOWN) 137ac75773cSGerrit Renker return NULL; 138ac75773cSGerrit Renker 139ac75773cSGerrit Renker new = kmemdup(original, sizeof(struct dccp_feat_entry), gfp_any()); 140ac75773cSGerrit Renker if (new == NULL) 141ac75773cSGerrit Renker return NULL; 142ac75773cSGerrit Renker 143ac75773cSGerrit Renker if (type == FEAT_SP && dccp_feat_clone_sp_val(&new->val, 144ac75773cSGerrit Renker original->val.sp.vec, 145ac75773cSGerrit Renker original->val.sp.len)) { 146ac75773cSGerrit Renker kfree(new); 147ac75773cSGerrit Renker return NULL; 148ac75773cSGerrit Renker } 149ac75773cSGerrit Renker return new; 150ac75773cSGerrit Renker } 151ac75773cSGerrit Renker 15261e6473eSGerrit Renker static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry) 15361e6473eSGerrit Renker { 15461e6473eSGerrit Renker if (entry != NULL) { 15561e6473eSGerrit Renker dccp_feat_val_destructor(entry->feat_num, &entry->val); 15661e6473eSGerrit Renker kfree(entry); 15761e6473eSGerrit Renker } 15861e6473eSGerrit Renker } 15961e6473eSGerrit Renker 16061e6473eSGerrit Renker /* 16161e6473eSGerrit Renker * List management functions 16261e6473eSGerrit Renker * 16361e6473eSGerrit Renker * Feature negotiation lists rely on and maintain the following invariants: 16461e6473eSGerrit Renker * - each feat_num in the list is known, i.e. we know its type and default value 16561e6473eSGerrit Renker * - each feat_num/is_local combination is unique (old entries are overwritten) 16661e6473eSGerrit Renker * - SP values are always freshly allocated 16761e6473eSGerrit Renker * - list is sorted in increasing order of feature number (faster lookup) 16861e6473eSGerrit Renker */ 16961e6473eSGerrit Renker 170*e8ef967aSGerrit Renker /** 171*e8ef967aSGerrit Renker * dccp_feat_entry_new - Central list update routine (called by all others) 172*e8ef967aSGerrit Renker * @head: list to add to 173*e8ef967aSGerrit Renker * @feat: feature number 174*e8ef967aSGerrit Renker * @local: whether the local (1) or remote feature with number @feat is meant 175*e8ef967aSGerrit Renker * This is the only constructor and serves to ensure the above invariants. 176*e8ef967aSGerrit Renker */ 177*e8ef967aSGerrit Renker static struct dccp_feat_entry * 178*e8ef967aSGerrit Renker dccp_feat_entry_new(struct list_head *head, u8 feat, bool local) 179*e8ef967aSGerrit Renker { 180*e8ef967aSGerrit Renker struct dccp_feat_entry *entry; 181*e8ef967aSGerrit Renker 182*e8ef967aSGerrit Renker list_for_each_entry(entry, head, node) 183*e8ef967aSGerrit Renker if (entry->feat_num == feat && entry->is_local == local) { 184*e8ef967aSGerrit Renker dccp_feat_val_destructor(entry->feat_num, &entry->val); 185*e8ef967aSGerrit Renker return entry; 186*e8ef967aSGerrit Renker } else if (entry->feat_num > feat) { 187*e8ef967aSGerrit Renker head = &entry->node; 188*e8ef967aSGerrit Renker break; 189*e8ef967aSGerrit Renker } 190*e8ef967aSGerrit Renker 191*e8ef967aSGerrit Renker entry = kmalloc(sizeof(*entry), gfp_any()); 192*e8ef967aSGerrit Renker if (entry != NULL) { 193*e8ef967aSGerrit Renker entry->feat_num = feat; 194*e8ef967aSGerrit Renker entry->is_local = local; 195*e8ef967aSGerrit Renker list_add_tail(&entry->node, head); 196*e8ef967aSGerrit Renker } 197*e8ef967aSGerrit Renker return entry; 198*e8ef967aSGerrit Renker } 199*e8ef967aSGerrit Renker 200*e8ef967aSGerrit Renker /** 201*e8ef967aSGerrit Renker * dccp_feat_push_change - Add/overwrite a Change option in the list 202*e8ef967aSGerrit Renker * @fn_list: feature-negotiation list to update 203*e8ef967aSGerrit Renker * @feat: one of %dccp_feature_numbers 204*e8ef967aSGerrit Renker * @local: whether local (1) or remote (0) @feat_num is meant 205*e8ef967aSGerrit Renker * @needs_mandatory: whether to use Mandatory feature negotiation options 206*e8ef967aSGerrit Renker * @fval: pointer to NN/SP value to be inserted (will be copied) 207*e8ef967aSGerrit Renker */ 208*e8ef967aSGerrit Renker static int dccp_feat_push_change(struct list_head *fn_list, u8 feat, u8 local, 209*e8ef967aSGerrit Renker u8 mandatory, dccp_feat_val *fval) 210*e8ef967aSGerrit Renker { 211*e8ef967aSGerrit Renker struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local); 212*e8ef967aSGerrit Renker 213*e8ef967aSGerrit Renker if (new == NULL) 214*e8ef967aSGerrit Renker return -ENOMEM; 215*e8ef967aSGerrit Renker 216*e8ef967aSGerrit Renker new->feat_num = feat; 217*e8ef967aSGerrit Renker new->is_local = local; 218*e8ef967aSGerrit Renker new->state = FEAT_INITIALISING; 219*e8ef967aSGerrit Renker new->needs_confirm = 0; 220*e8ef967aSGerrit Renker new->empty_confirm = 0; 221*e8ef967aSGerrit Renker new->val = *fval; 222*e8ef967aSGerrit Renker new->needs_mandatory = mandatory; 223*e8ef967aSGerrit Renker 224*e8ef967aSGerrit Renker return 0; 225*e8ef967aSGerrit Renker } 226*e8ef967aSGerrit Renker 22761e6473eSGerrit Renker static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry) 22861e6473eSGerrit Renker { 22961e6473eSGerrit Renker list_del(&entry->node); 23061e6473eSGerrit Renker dccp_feat_entry_destructor(entry); 23161e6473eSGerrit Renker } 23261e6473eSGerrit Renker 23361e6473eSGerrit Renker void dccp_feat_list_purge(struct list_head *fn_list) 23461e6473eSGerrit Renker { 23561e6473eSGerrit Renker struct dccp_feat_entry *entry, *next; 23661e6473eSGerrit Renker 23761e6473eSGerrit Renker list_for_each_entry_safe(entry, next, fn_list, node) 23861e6473eSGerrit Renker dccp_feat_entry_destructor(entry); 23961e6473eSGerrit Renker INIT_LIST_HEAD(fn_list); 24061e6473eSGerrit Renker } 24161e6473eSGerrit Renker EXPORT_SYMBOL_GPL(dccp_feat_list_purge); 24261e6473eSGerrit Renker 243ac75773cSGerrit Renker /* generate @to as full clone of @from - @to must not contain any nodes */ 244ac75773cSGerrit Renker int dccp_feat_clone_list(struct list_head const *from, struct list_head *to) 245ac75773cSGerrit Renker { 246ac75773cSGerrit Renker struct dccp_feat_entry *entry, *new; 247ac75773cSGerrit Renker 248ac75773cSGerrit Renker INIT_LIST_HEAD(to); 249ac75773cSGerrit Renker list_for_each_entry(entry, from, node) { 250ac75773cSGerrit Renker new = dccp_feat_clone_entry(entry); 251ac75773cSGerrit Renker if (new == NULL) 252ac75773cSGerrit Renker goto cloning_failed; 253ac75773cSGerrit Renker list_add_tail(&new->node, to); 254ac75773cSGerrit Renker } 255ac75773cSGerrit Renker return 0; 256ac75773cSGerrit Renker 257ac75773cSGerrit Renker cloning_failed: 258ac75773cSGerrit Renker dccp_feat_list_purge(to); 259ac75773cSGerrit Renker return -ENOMEM; 260ac75773cSGerrit Renker } 261ac75773cSGerrit Renker 262*e8ef967aSGerrit Renker static u8 dccp_feat_is_valid_nn_val(u8 feat_num, u64 val) 263*e8ef967aSGerrit Renker { 264*e8ef967aSGerrit Renker switch (feat_num) { 265*e8ef967aSGerrit Renker case DCCPF_ACK_RATIO: 266*e8ef967aSGerrit Renker return val <= DCCPF_ACK_RATIO_MAX; 267*e8ef967aSGerrit Renker case DCCPF_SEQUENCE_WINDOW: 268*e8ef967aSGerrit Renker return val >= DCCPF_SEQ_WMIN && val <= DCCPF_SEQ_WMAX; 269*e8ef967aSGerrit Renker } 270*e8ef967aSGerrit Renker return 0; /* feature unknown - so we can't tell */ 271*e8ef967aSGerrit Renker } 272*e8ef967aSGerrit Renker 273*e8ef967aSGerrit Renker /* check that SP values are within the ranges defined in RFC 4340 */ 274*e8ef967aSGerrit Renker static u8 dccp_feat_is_valid_sp_val(u8 feat_num, u8 val) 275*e8ef967aSGerrit Renker { 276*e8ef967aSGerrit Renker switch (feat_num) { 277*e8ef967aSGerrit Renker case DCCPF_CCID: 278*e8ef967aSGerrit Renker return val == DCCPC_CCID2 || val == DCCPC_CCID3; 279*e8ef967aSGerrit Renker /* Type-check Boolean feature values: */ 280*e8ef967aSGerrit Renker case DCCPF_SHORT_SEQNOS: 281*e8ef967aSGerrit Renker case DCCPF_ECN_INCAPABLE: 282*e8ef967aSGerrit Renker case DCCPF_SEND_ACK_VECTOR: 283*e8ef967aSGerrit Renker case DCCPF_SEND_NDP_COUNT: 284*e8ef967aSGerrit Renker case DCCPF_DATA_CHECKSUM: 285*e8ef967aSGerrit Renker case DCCPF_SEND_LEV_RATE: 286*e8ef967aSGerrit Renker return val < 2; 287*e8ef967aSGerrit Renker case DCCPF_MIN_CSUM_COVER: 288*e8ef967aSGerrit Renker return val < 16; 289*e8ef967aSGerrit Renker } 290*e8ef967aSGerrit Renker return 0; /* feature unknown */ 291*e8ef967aSGerrit Renker } 292*e8ef967aSGerrit Renker 293*e8ef967aSGerrit Renker static u8 dccp_feat_sp_list_ok(u8 feat_num, u8 const *sp_list, u8 sp_len) 294*e8ef967aSGerrit Renker { 295*e8ef967aSGerrit Renker if (sp_list == NULL || sp_len < 1) 296*e8ef967aSGerrit Renker return 0; 297*e8ef967aSGerrit Renker while (sp_len--) 298*e8ef967aSGerrit Renker if (!dccp_feat_is_valid_sp_val(feat_num, *sp_list++)) 299*e8ef967aSGerrit Renker return 0; 300*e8ef967aSGerrit Renker return 1; 301*e8ef967aSGerrit Renker } 302*e8ef967aSGerrit Renker 303*e8ef967aSGerrit Renker /** 304*e8ef967aSGerrit Renker * __feat_register_nn - Register new NN value on socket 305*e8ef967aSGerrit Renker * @fn: feature-negotiation list to register with 306*e8ef967aSGerrit Renker * @feat: an NN feature from %dccp_feature_numbers 307*e8ef967aSGerrit Renker * @mandatory: use Mandatory option if 1 308*e8ef967aSGerrit Renker * @nn_val: value to register (restricted to 4 bytes) 309*e8ef967aSGerrit Renker * Note that NN features are local by definition (RFC 4340, 6.3.2). 310*e8ef967aSGerrit Renker */ 311*e8ef967aSGerrit Renker static int __feat_register_nn(struct list_head *fn, u8 feat, 312*e8ef967aSGerrit Renker u8 mandatory, u64 nn_val) 313*e8ef967aSGerrit Renker { 314*e8ef967aSGerrit Renker dccp_feat_val fval = { .nn = nn_val }; 315*e8ef967aSGerrit Renker 316*e8ef967aSGerrit Renker if (dccp_feat_type(feat) != FEAT_NN || 317*e8ef967aSGerrit Renker !dccp_feat_is_valid_nn_val(feat, nn_val)) 318*e8ef967aSGerrit Renker return -EINVAL; 319*e8ef967aSGerrit Renker 320*e8ef967aSGerrit Renker /* Don't bother with default values, they will be activated anyway. */ 321*e8ef967aSGerrit Renker if (nn_val - (u64)dccp_feat_default_value(feat) == 0) 322*e8ef967aSGerrit Renker return 0; 323*e8ef967aSGerrit Renker 324*e8ef967aSGerrit Renker return dccp_feat_push_change(fn, feat, 1, mandatory, &fval); 325*e8ef967aSGerrit Renker } 326*e8ef967aSGerrit Renker 327*e8ef967aSGerrit Renker /** 328*e8ef967aSGerrit Renker * __feat_register_sp - Register new SP value/list on socket 329*e8ef967aSGerrit Renker * @fn: feature-negotiation list to register with 330*e8ef967aSGerrit Renker * @feat: an SP feature from %dccp_feature_numbers 331*e8ef967aSGerrit Renker * @is_local: whether the local (1) or the remote (0) @feat is meant 332*e8ef967aSGerrit Renker * @mandatory: use Mandatory option if 1 333*e8ef967aSGerrit Renker * @sp_val: SP value followed by optional preference list 334*e8ef967aSGerrit Renker * @sp_len: length of @sp_val in bytes 335*e8ef967aSGerrit Renker */ 336*e8ef967aSGerrit Renker static int __feat_register_sp(struct list_head *fn, u8 feat, u8 is_local, 337*e8ef967aSGerrit Renker u8 mandatory, u8 const *sp_val, u8 sp_len) 338*e8ef967aSGerrit Renker { 339*e8ef967aSGerrit Renker dccp_feat_val fval; 340*e8ef967aSGerrit Renker 341*e8ef967aSGerrit Renker if (dccp_feat_type(feat) != FEAT_SP || 342*e8ef967aSGerrit Renker !dccp_feat_sp_list_ok(feat, sp_val, sp_len)) 343*e8ef967aSGerrit Renker return -EINVAL; 344*e8ef967aSGerrit Renker 345*e8ef967aSGerrit Renker if (dccp_feat_clone_sp_val(&fval, sp_val, sp_len)) 346*e8ef967aSGerrit Renker return -ENOMEM; 347*e8ef967aSGerrit Renker 348*e8ef967aSGerrit Renker return dccp_feat_push_change(fn, feat, is_local, mandatory, &fval); 349*e8ef967aSGerrit Renker } 350*e8ef967aSGerrit Renker 3518ca0d17bSArnaldo Carvalho de Melo int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature, 3528ca0d17bSArnaldo Carvalho de Melo u8 *val, u8 len, gfp_t gfp) 353afe00251SAndrea Bittau { 354afe00251SAndrea Bittau struct dccp_opt_pend *opt; 355afe00251SAndrea Bittau 356c02fdc0eSGerrit Renker dccp_feat_debug(type, feature, *val); 357afe00251SAndrea Bittau 358dd6303dfSGerrit Renker if (len > 3) { 35959348b19SGerrit Renker DCCP_WARN("invalid length %d\n", len); 36019443178SChris Wright return -EINVAL; 361c02fdc0eSGerrit Renker } 362c02fdc0eSGerrit Renker /* XXX add further sanity checks */ 3636ffd30fbSAndrea Bittau 364afe00251SAndrea Bittau /* check if that feature is already being negotiated */ 365a4bf3902SArnaldo Carvalho de Melo list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { 366afe00251SAndrea Bittau /* ok we found a negotiation for this option already */ 367afe00251SAndrea Bittau if (opt->dccpop_feat == feature && opt->dccpop_type == type) { 368afe00251SAndrea Bittau dccp_pr_debug("Replacing old\n"); 369afe00251SAndrea Bittau /* replace */ 370afe00251SAndrea Bittau BUG_ON(opt->dccpop_val == NULL); 371afe00251SAndrea Bittau kfree(opt->dccpop_val); 372afe00251SAndrea Bittau opt->dccpop_val = val; 373afe00251SAndrea Bittau opt->dccpop_len = len; 374afe00251SAndrea Bittau opt->dccpop_conf = 0; 375afe00251SAndrea Bittau return 0; 376afe00251SAndrea Bittau } 377afe00251SAndrea Bittau } 378afe00251SAndrea Bittau 379afe00251SAndrea Bittau /* negotiation for a new feature */ 380afe00251SAndrea Bittau opt = kmalloc(sizeof(*opt), gfp); 381afe00251SAndrea Bittau if (opt == NULL) 382afe00251SAndrea Bittau return -ENOMEM; 383afe00251SAndrea Bittau 384afe00251SAndrea Bittau opt->dccpop_type = type; 385afe00251SAndrea Bittau opt->dccpop_feat = feature; 386afe00251SAndrea Bittau opt->dccpop_len = len; 387afe00251SAndrea Bittau opt->dccpop_val = val; 388afe00251SAndrea Bittau opt->dccpop_conf = 0; 389afe00251SAndrea Bittau opt->dccpop_sc = NULL; 390afe00251SAndrea Bittau 391afe00251SAndrea Bittau BUG_ON(opt->dccpop_val == NULL); 392afe00251SAndrea Bittau 393a4bf3902SArnaldo Carvalho de Melo list_add_tail(&opt->dccpop_node, &dmsk->dccpms_pending); 394afe00251SAndrea Bittau return 0; 395afe00251SAndrea Bittau } 396afe00251SAndrea Bittau 397afe00251SAndrea Bittau EXPORT_SYMBOL_GPL(dccp_feat_change); 398afe00251SAndrea Bittau 3996ffd30fbSAndrea Bittau static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr) 4006ffd30fbSAndrea Bittau { 4016ffd30fbSAndrea Bittau struct dccp_sock *dp = dccp_sk(sk); 402a4bf3902SArnaldo Carvalho de Melo struct dccp_minisock *dmsk = dccp_msk(sk); 4036ffd30fbSAndrea Bittau /* figure out if we are changing our CCID or the peer's */ 4046ffd30fbSAndrea Bittau const int rx = type == DCCPO_CHANGE_R; 405a4bf3902SArnaldo Carvalho de Melo const u8 ccid_nr = rx ? dmsk->dccpms_rx_ccid : dmsk->dccpms_tx_ccid; 4066ffd30fbSAndrea Bittau struct ccid *new_ccid; 4076ffd30fbSAndrea Bittau 4086ffd30fbSAndrea Bittau /* Check if nothing is being changed. */ 4096ffd30fbSAndrea Bittau if (ccid_nr == new_ccid_nr) 4106ffd30fbSAndrea Bittau return 0; 4116ffd30fbSAndrea Bittau 4126ffd30fbSAndrea Bittau new_ccid = ccid_new(new_ccid_nr, sk, rx, GFP_ATOMIC); 4136ffd30fbSAndrea Bittau if (new_ccid == NULL) 4146ffd30fbSAndrea Bittau return -ENOMEM; 4156ffd30fbSAndrea Bittau 4166ffd30fbSAndrea Bittau if (rx) { 4176ffd30fbSAndrea Bittau ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk); 4186ffd30fbSAndrea Bittau dp->dccps_hc_rx_ccid = new_ccid; 419a4bf3902SArnaldo Carvalho de Melo dmsk->dccpms_rx_ccid = new_ccid_nr; 4206ffd30fbSAndrea Bittau } else { 4216ffd30fbSAndrea Bittau ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk); 4226ffd30fbSAndrea Bittau dp->dccps_hc_tx_ccid = new_ccid; 423a4bf3902SArnaldo Carvalho de Melo dmsk->dccpms_tx_ccid = new_ccid_nr; 4246ffd30fbSAndrea Bittau } 4256ffd30fbSAndrea Bittau 4266ffd30fbSAndrea Bittau return 0; 4276ffd30fbSAndrea Bittau } 4286ffd30fbSAndrea Bittau 429afe00251SAndrea Bittau static int dccp_feat_update(struct sock *sk, u8 type, u8 feat, u8 val) 430afe00251SAndrea Bittau { 431c02fdc0eSGerrit Renker dccp_feat_debug(type, feat, val); 4326ffd30fbSAndrea Bittau 4336ffd30fbSAndrea Bittau switch (feat) { 4346ffd30fbSAndrea Bittau case DCCPF_CCID: 4356ffd30fbSAndrea Bittau return dccp_feat_update_ccid(sk, type, val); 4366ffd30fbSAndrea Bittau default: 437c02fdc0eSGerrit Renker dccp_pr_debug("UNIMPLEMENTED: %s(%d, ...)\n", 438c02fdc0eSGerrit Renker dccp_feat_typename(type), feat); 4396ffd30fbSAndrea Bittau break; 4406ffd30fbSAndrea Bittau } 441afe00251SAndrea Bittau return 0; 442afe00251SAndrea Bittau } 443afe00251SAndrea Bittau 444afe00251SAndrea Bittau static int dccp_feat_reconcile(struct sock *sk, struct dccp_opt_pend *opt, 445afe00251SAndrea Bittau u8 *rpref, u8 rlen) 446afe00251SAndrea Bittau { 447afe00251SAndrea Bittau struct dccp_sock *dp = dccp_sk(sk); 448afe00251SAndrea Bittau u8 *spref, slen, *res = NULL; 449afe00251SAndrea Bittau int i, j, rc, agree = 1; 450afe00251SAndrea Bittau 451afe00251SAndrea Bittau BUG_ON(rpref == NULL); 452afe00251SAndrea Bittau 453afe00251SAndrea Bittau /* check if we are the black sheep */ 454afe00251SAndrea Bittau if (dp->dccps_role == DCCP_ROLE_CLIENT) { 455afe00251SAndrea Bittau spref = rpref; 456afe00251SAndrea Bittau slen = rlen; 457afe00251SAndrea Bittau rpref = opt->dccpop_val; 458afe00251SAndrea Bittau rlen = opt->dccpop_len; 459afe00251SAndrea Bittau } else { 460afe00251SAndrea Bittau spref = opt->dccpop_val; 461afe00251SAndrea Bittau slen = opt->dccpop_len; 462afe00251SAndrea Bittau } 463afe00251SAndrea Bittau /* 464afe00251SAndrea Bittau * Now we have server preference list in spref and client preference in 465afe00251SAndrea Bittau * rpref 466afe00251SAndrea Bittau */ 467afe00251SAndrea Bittau BUG_ON(spref == NULL); 468afe00251SAndrea Bittau BUG_ON(rpref == NULL); 469afe00251SAndrea Bittau 470afe00251SAndrea Bittau /* FIXME sanity check vals */ 471afe00251SAndrea Bittau 472afe00251SAndrea Bittau /* Are values in any order? XXX Lame "algorithm" here */ 473afe00251SAndrea Bittau for (i = 0; i < slen; i++) { 474afe00251SAndrea Bittau for (j = 0; j < rlen; j++) { 475afe00251SAndrea Bittau if (spref[i] == rpref[j]) { 476afe00251SAndrea Bittau res = &spref[i]; 477afe00251SAndrea Bittau break; 478afe00251SAndrea Bittau } 479afe00251SAndrea Bittau } 480afe00251SAndrea Bittau if (res) 481afe00251SAndrea Bittau break; 482afe00251SAndrea Bittau } 483afe00251SAndrea Bittau 484afe00251SAndrea Bittau /* we didn't agree on anything */ 485afe00251SAndrea Bittau if (res == NULL) { 486afe00251SAndrea Bittau /* confirm previous value */ 487afe00251SAndrea Bittau switch (opt->dccpop_feat) { 488afe00251SAndrea Bittau case DCCPF_CCID: 489afe00251SAndrea Bittau /* XXX did i get this right? =P */ 490afe00251SAndrea Bittau if (opt->dccpop_type == DCCPO_CHANGE_L) 491a4bf3902SArnaldo Carvalho de Melo res = &dccp_msk(sk)->dccpms_tx_ccid; 492afe00251SAndrea Bittau else 493a4bf3902SArnaldo Carvalho de Melo res = &dccp_msk(sk)->dccpms_rx_ccid; 494afe00251SAndrea Bittau break; 495afe00251SAndrea Bittau 496afe00251SAndrea Bittau default: 49759348b19SGerrit Renker DCCP_BUG("Fell through, feat=%d", opt->dccpop_feat); 49859348b19SGerrit Renker /* XXX implement res */ 499afe00251SAndrea Bittau return -EFAULT; 500afe00251SAndrea Bittau } 501afe00251SAndrea Bittau 502afe00251SAndrea Bittau dccp_pr_debug("Don't agree... reconfirming %d\n", *res); 503afe00251SAndrea Bittau agree = 0; /* this is used for mandatory options... */ 504afe00251SAndrea Bittau } 505afe00251SAndrea Bittau 506afe00251SAndrea Bittau /* need to put result and our preference list */ 507afe00251SAndrea Bittau rlen = 1 + opt->dccpop_len; 508afe00251SAndrea Bittau rpref = kmalloc(rlen, GFP_ATOMIC); 509afe00251SAndrea Bittau if (rpref == NULL) 510afe00251SAndrea Bittau return -ENOMEM; 511afe00251SAndrea Bittau 512afe00251SAndrea Bittau *rpref = *res; 513afe00251SAndrea Bittau memcpy(&rpref[1], opt->dccpop_val, opt->dccpop_len); 514afe00251SAndrea Bittau 515afe00251SAndrea Bittau /* put it in the "confirm queue" */ 516afe00251SAndrea Bittau if (opt->dccpop_sc == NULL) { 517afe00251SAndrea Bittau opt->dccpop_sc = kmalloc(sizeof(*opt->dccpop_sc), GFP_ATOMIC); 518afe00251SAndrea Bittau if (opt->dccpop_sc == NULL) { 519afe00251SAndrea Bittau kfree(rpref); 520afe00251SAndrea Bittau return -ENOMEM; 521afe00251SAndrea Bittau } 522afe00251SAndrea Bittau } else { 523afe00251SAndrea Bittau /* recycle the confirm slot */ 524afe00251SAndrea Bittau BUG_ON(opt->dccpop_sc->dccpoc_val == NULL); 525afe00251SAndrea Bittau kfree(opt->dccpop_sc->dccpoc_val); 526afe00251SAndrea Bittau dccp_pr_debug("recycling confirm slot\n"); 527afe00251SAndrea Bittau } 528afe00251SAndrea Bittau memset(opt->dccpop_sc, 0, sizeof(*opt->dccpop_sc)); 529afe00251SAndrea Bittau 530afe00251SAndrea Bittau opt->dccpop_sc->dccpoc_val = rpref; 531afe00251SAndrea Bittau opt->dccpop_sc->dccpoc_len = rlen; 532afe00251SAndrea Bittau 533afe00251SAndrea Bittau /* update the option on our side [we are about to send the confirm] */ 534afe00251SAndrea Bittau rc = dccp_feat_update(sk, opt->dccpop_type, opt->dccpop_feat, *res); 535afe00251SAndrea Bittau if (rc) { 536afe00251SAndrea Bittau kfree(opt->dccpop_sc->dccpoc_val); 537afe00251SAndrea Bittau kfree(opt->dccpop_sc); 53868907dadSRandy Dunlap opt->dccpop_sc = NULL; 539afe00251SAndrea Bittau return rc; 540afe00251SAndrea Bittau } 541afe00251SAndrea Bittau 542afe00251SAndrea Bittau dccp_pr_debug("Will confirm %d\n", *rpref); 543afe00251SAndrea Bittau 544afe00251SAndrea Bittau /* say we want to change to X but we just got a confirm X, suppress our 545afe00251SAndrea Bittau * change 546afe00251SAndrea Bittau */ 547afe00251SAndrea Bittau if (!opt->dccpop_conf) { 548afe00251SAndrea Bittau if (*opt->dccpop_val == *res) 549afe00251SAndrea Bittau opt->dccpop_conf = 1; 550afe00251SAndrea Bittau dccp_pr_debug("won't ask for change of same feature\n"); 551afe00251SAndrea Bittau } 552afe00251SAndrea Bittau 553afe00251SAndrea Bittau return agree ? 0 : DCCP_FEAT_SP_NOAGREE; /* used for mandatory opts */ 554afe00251SAndrea Bittau } 555afe00251SAndrea Bittau 556afe00251SAndrea Bittau static int dccp_feat_sp(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) 557afe00251SAndrea Bittau { 558a4bf3902SArnaldo Carvalho de Melo struct dccp_minisock *dmsk = dccp_msk(sk); 559afe00251SAndrea Bittau struct dccp_opt_pend *opt; 560afe00251SAndrea Bittau int rc = 1; 561afe00251SAndrea Bittau u8 t; 562afe00251SAndrea Bittau 563afe00251SAndrea Bittau /* 564afe00251SAndrea Bittau * We received a CHANGE. We gotta match it against our own preference 565afe00251SAndrea Bittau * list. If we got a CHANGE_R it means it's a change for us, so we need 566afe00251SAndrea Bittau * to compare our CHANGE_L list. 567afe00251SAndrea Bittau */ 568afe00251SAndrea Bittau if (type == DCCPO_CHANGE_L) 569afe00251SAndrea Bittau t = DCCPO_CHANGE_R; 570afe00251SAndrea Bittau else 571afe00251SAndrea Bittau t = DCCPO_CHANGE_L; 572afe00251SAndrea Bittau 573afe00251SAndrea Bittau /* find our preference list for this feature */ 574a4bf3902SArnaldo Carvalho de Melo list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { 575afe00251SAndrea Bittau if (opt->dccpop_type != t || opt->dccpop_feat != feature) 576afe00251SAndrea Bittau continue; 577afe00251SAndrea Bittau 578afe00251SAndrea Bittau /* find the winner from the two preference lists */ 579afe00251SAndrea Bittau rc = dccp_feat_reconcile(sk, opt, val, len); 580afe00251SAndrea Bittau break; 581afe00251SAndrea Bittau } 582afe00251SAndrea Bittau 583afe00251SAndrea Bittau /* We didn't deal with the change. This can happen if we have no 584afe00251SAndrea Bittau * preference list for the feature. In fact, it just shouldn't 585afe00251SAndrea Bittau * happen---if we understand a feature, we should have a preference list 586afe00251SAndrea Bittau * with at least the default value. 587afe00251SAndrea Bittau */ 588afe00251SAndrea Bittau BUG_ON(rc == 1); 589afe00251SAndrea Bittau 590afe00251SAndrea Bittau return rc; 591afe00251SAndrea Bittau } 592afe00251SAndrea Bittau 593afe00251SAndrea Bittau static int dccp_feat_nn(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) 594afe00251SAndrea Bittau { 595afe00251SAndrea Bittau struct dccp_opt_pend *opt; 596a4bf3902SArnaldo Carvalho de Melo struct dccp_minisock *dmsk = dccp_msk(sk); 597afe00251SAndrea Bittau u8 *copy; 598afe00251SAndrea Bittau int rc; 599afe00251SAndrea Bittau 600c02fdc0eSGerrit Renker /* NN features must be Change L (sec. 6.3.2) */ 601c02fdc0eSGerrit Renker if (type != DCCPO_CHANGE_L) { 602c02fdc0eSGerrit Renker dccp_pr_debug("received %s for NN feature %d\n", 603c02fdc0eSGerrit Renker dccp_feat_typename(type), feature); 604afe00251SAndrea Bittau return -EFAULT; 605afe00251SAndrea Bittau } 606afe00251SAndrea Bittau 607afe00251SAndrea Bittau /* XXX sanity check opt val */ 608afe00251SAndrea Bittau 609afe00251SAndrea Bittau /* copy option so we can confirm it */ 610afe00251SAndrea Bittau opt = kzalloc(sizeof(*opt), GFP_ATOMIC); 611afe00251SAndrea Bittau if (opt == NULL) 612afe00251SAndrea Bittau return -ENOMEM; 613afe00251SAndrea Bittau 614eed73417SArnaldo Carvalho de Melo copy = kmemdup(val, len, GFP_ATOMIC); 615afe00251SAndrea Bittau if (copy == NULL) { 616afe00251SAndrea Bittau kfree(opt); 617afe00251SAndrea Bittau return -ENOMEM; 618afe00251SAndrea Bittau } 619afe00251SAndrea Bittau 620afe00251SAndrea Bittau opt->dccpop_type = DCCPO_CONFIRM_R; /* NN can only confirm R */ 621afe00251SAndrea Bittau opt->dccpop_feat = feature; 622afe00251SAndrea Bittau opt->dccpop_val = copy; 623afe00251SAndrea Bittau opt->dccpop_len = len; 624afe00251SAndrea Bittau 625afe00251SAndrea Bittau /* change feature */ 626afe00251SAndrea Bittau rc = dccp_feat_update(sk, type, feature, *val); 627afe00251SAndrea Bittau if (rc) { 628afe00251SAndrea Bittau kfree(opt->dccpop_val); 629afe00251SAndrea Bittau kfree(opt); 630afe00251SAndrea Bittau return rc; 631afe00251SAndrea Bittau } 632afe00251SAndrea Bittau 633c02fdc0eSGerrit Renker dccp_feat_debug(type, feature, *copy); 634c02fdc0eSGerrit Renker 635a4bf3902SArnaldo Carvalho de Melo list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf); 636afe00251SAndrea Bittau 637afe00251SAndrea Bittau return 0; 638afe00251SAndrea Bittau } 639afe00251SAndrea Bittau 6408ca0d17bSArnaldo Carvalho de Melo static void dccp_feat_empty_confirm(struct dccp_minisock *dmsk, 6418ca0d17bSArnaldo Carvalho de Melo u8 type, u8 feature) 642afe00251SAndrea Bittau { 643afe00251SAndrea Bittau /* XXX check if other confirms for that are queued and recycle slot */ 644afe00251SAndrea Bittau struct dccp_opt_pend *opt = kzalloc(sizeof(*opt), GFP_ATOMIC); 645afe00251SAndrea Bittau 646afe00251SAndrea Bittau if (opt == NULL) { 647afe00251SAndrea Bittau /* XXX what do we do? Ignoring should be fine. It's a change 648afe00251SAndrea Bittau * after all =P 649afe00251SAndrea Bittau */ 650afe00251SAndrea Bittau return; 651afe00251SAndrea Bittau } 652afe00251SAndrea Bittau 653c02fdc0eSGerrit Renker switch (type) { 654e576de82SJesper Juhl case DCCPO_CHANGE_L: 655e576de82SJesper Juhl opt->dccpop_type = DCCPO_CONFIRM_R; 656e576de82SJesper Juhl break; 657e576de82SJesper Juhl case DCCPO_CHANGE_R: 658e576de82SJesper Juhl opt->dccpop_type = DCCPO_CONFIRM_L; 659e576de82SJesper Juhl break; 660e576de82SJesper Juhl default: 661e576de82SJesper Juhl DCCP_WARN("invalid type %d\n", type); 662e576de82SJesper Juhl kfree(opt); 663e576de82SJesper Juhl return; 664c02fdc0eSGerrit Renker } 665afe00251SAndrea Bittau opt->dccpop_feat = feature; 66668907dadSRandy Dunlap opt->dccpop_val = NULL; 667afe00251SAndrea Bittau opt->dccpop_len = 0; 668afe00251SAndrea Bittau 669afe00251SAndrea Bittau /* change feature */ 670c02fdc0eSGerrit Renker dccp_pr_debug("Empty %s(%d)\n", dccp_feat_typename(type), feature); 671c02fdc0eSGerrit Renker 672a4bf3902SArnaldo Carvalho de Melo list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf); 673afe00251SAndrea Bittau } 674afe00251SAndrea Bittau 675afe00251SAndrea Bittau static void dccp_feat_flush_confirm(struct sock *sk) 676afe00251SAndrea Bittau { 677a4bf3902SArnaldo Carvalho de Melo struct dccp_minisock *dmsk = dccp_msk(sk); 678afe00251SAndrea Bittau /* Check if there is anything to confirm in the first place */ 679a4bf3902SArnaldo Carvalho de Melo int yes = !list_empty(&dmsk->dccpms_conf); 680afe00251SAndrea Bittau 681afe00251SAndrea Bittau if (!yes) { 682afe00251SAndrea Bittau struct dccp_opt_pend *opt; 683afe00251SAndrea Bittau 684a4bf3902SArnaldo Carvalho de Melo list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { 685afe00251SAndrea Bittau if (opt->dccpop_conf) { 686afe00251SAndrea Bittau yes = 1; 687afe00251SAndrea Bittau break; 688afe00251SAndrea Bittau } 689afe00251SAndrea Bittau } 690afe00251SAndrea Bittau } 691afe00251SAndrea Bittau 692afe00251SAndrea Bittau if (!yes) 693afe00251SAndrea Bittau return; 694afe00251SAndrea Bittau 695afe00251SAndrea Bittau /* OK there is something to confirm... */ 696afe00251SAndrea Bittau /* XXX check if packet is in flight? Send delayed ack?? */ 697afe00251SAndrea Bittau if (sk->sk_state == DCCP_OPEN) 698afe00251SAndrea Bittau dccp_send_ack(sk); 699afe00251SAndrea Bittau } 700afe00251SAndrea Bittau 701afe00251SAndrea Bittau int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) 702afe00251SAndrea Bittau { 703afe00251SAndrea Bittau int rc; 704afe00251SAndrea Bittau 705f74e91b6SGerrit Renker /* Ignore Change requests other than during connection setup */ 706f74e91b6SGerrit Renker if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING) 707f74e91b6SGerrit Renker return 0; 708c02fdc0eSGerrit Renker dccp_feat_debug(type, feature, *val); 709afe00251SAndrea Bittau 710afe00251SAndrea Bittau /* figure out if it's SP or NN feature */ 711afe00251SAndrea Bittau switch (feature) { 712afe00251SAndrea Bittau /* deal with SP features */ 713afe00251SAndrea Bittau case DCCPF_CCID: 714afe00251SAndrea Bittau rc = dccp_feat_sp(sk, type, feature, val, len); 715afe00251SAndrea Bittau break; 716afe00251SAndrea Bittau 717afe00251SAndrea Bittau /* deal with NN features */ 718afe00251SAndrea Bittau case DCCPF_ACK_RATIO: 719afe00251SAndrea Bittau rc = dccp_feat_nn(sk, type, feature, val, len); 720afe00251SAndrea Bittau break; 721afe00251SAndrea Bittau 722afe00251SAndrea Bittau /* XXX implement other features */ 723afe00251SAndrea Bittau default: 724c02fdc0eSGerrit Renker dccp_pr_debug("UNIMPLEMENTED: not handling %s(%d, ...)\n", 725c02fdc0eSGerrit Renker dccp_feat_typename(type), feature); 726afe00251SAndrea Bittau rc = -EFAULT; 727afe00251SAndrea Bittau break; 728afe00251SAndrea Bittau } 729afe00251SAndrea Bittau 730afe00251SAndrea Bittau /* check if there were problems changing features */ 731afe00251SAndrea Bittau if (rc) { 732afe00251SAndrea Bittau /* If we don't agree on SP, we sent a confirm for old value. 733afe00251SAndrea Bittau * However we propagate rc to caller in case option was 734afe00251SAndrea Bittau * mandatory 735afe00251SAndrea Bittau */ 736afe00251SAndrea Bittau if (rc != DCCP_FEAT_SP_NOAGREE) 7378ca0d17bSArnaldo Carvalho de Melo dccp_feat_empty_confirm(dccp_msk(sk), type, feature); 738afe00251SAndrea Bittau } 739afe00251SAndrea Bittau 740afe00251SAndrea Bittau /* generate the confirm [if required] */ 741afe00251SAndrea Bittau dccp_feat_flush_confirm(sk); 742afe00251SAndrea Bittau 743afe00251SAndrea Bittau return rc; 744afe00251SAndrea Bittau } 745afe00251SAndrea Bittau 746afe00251SAndrea Bittau EXPORT_SYMBOL_GPL(dccp_feat_change_recv); 747afe00251SAndrea Bittau 748afe00251SAndrea Bittau int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, 749afe00251SAndrea Bittau u8 *val, u8 len) 750afe00251SAndrea Bittau { 751afe00251SAndrea Bittau u8 t; 752afe00251SAndrea Bittau struct dccp_opt_pend *opt; 753a4bf3902SArnaldo Carvalho de Melo struct dccp_minisock *dmsk = dccp_msk(sk); 754c02fdc0eSGerrit Renker int found = 0; 755afe00251SAndrea Bittau int all_confirmed = 1; 756afe00251SAndrea Bittau 757f74e91b6SGerrit Renker /* Ignore Confirm options other than during connection setup */ 758f74e91b6SGerrit Renker if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING) 759f74e91b6SGerrit Renker return 0; 760c02fdc0eSGerrit Renker dccp_feat_debug(type, feature, *val); 761afe00251SAndrea Bittau 762afe00251SAndrea Bittau /* locate our change request */ 763c02fdc0eSGerrit Renker switch (type) { 764c02fdc0eSGerrit Renker case DCCPO_CONFIRM_L: t = DCCPO_CHANGE_R; break; 765c02fdc0eSGerrit Renker case DCCPO_CONFIRM_R: t = DCCPO_CHANGE_L; break; 76659348b19SGerrit Renker default: DCCP_WARN("invalid type %d\n", type); 767c02fdc0eSGerrit Renker return 1; 768c02fdc0eSGerrit Renker 769c02fdc0eSGerrit Renker } 770c02fdc0eSGerrit Renker /* XXX sanity check feature value */ 771afe00251SAndrea Bittau 772a4bf3902SArnaldo Carvalho de Melo list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { 773afe00251SAndrea Bittau if (!opt->dccpop_conf && opt->dccpop_type == t && 774afe00251SAndrea Bittau opt->dccpop_feat == feature) { 775c02fdc0eSGerrit Renker found = 1; 776c02fdc0eSGerrit Renker dccp_pr_debug("feature %d found\n", opt->dccpop_feat); 777c02fdc0eSGerrit Renker 778afe00251SAndrea Bittau /* XXX do sanity check */ 779afe00251SAndrea Bittau 780afe00251SAndrea Bittau opt->dccpop_conf = 1; 781afe00251SAndrea Bittau 782afe00251SAndrea Bittau /* We got a confirmation---change the option */ 783afe00251SAndrea Bittau dccp_feat_update(sk, opt->dccpop_type, 784afe00251SAndrea Bittau opt->dccpop_feat, *val); 785afe00251SAndrea Bittau 786c02fdc0eSGerrit Renker /* XXX check the return value of dccp_feat_update */ 787afe00251SAndrea Bittau break; 788afe00251SAndrea Bittau } 789afe00251SAndrea Bittau 790afe00251SAndrea Bittau if (!opt->dccpop_conf) 791afe00251SAndrea Bittau all_confirmed = 0; 792afe00251SAndrea Bittau } 793afe00251SAndrea Bittau 794c02fdc0eSGerrit Renker if (!found) 795c02fdc0eSGerrit Renker dccp_pr_debug("%s(%d, ...) never requested\n", 796c02fdc0eSGerrit Renker dccp_feat_typename(type), feature); 797afe00251SAndrea Bittau return 0; 798afe00251SAndrea Bittau } 799afe00251SAndrea Bittau 800afe00251SAndrea Bittau EXPORT_SYMBOL_GPL(dccp_feat_confirm_recv); 801afe00251SAndrea Bittau 8028ca0d17bSArnaldo Carvalho de Melo void dccp_feat_clean(struct dccp_minisock *dmsk) 803afe00251SAndrea Bittau { 804afe00251SAndrea Bittau struct dccp_opt_pend *opt, *next; 805afe00251SAndrea Bittau 806a4bf3902SArnaldo Carvalho de Melo list_for_each_entry_safe(opt, next, &dmsk->dccpms_pending, 807afe00251SAndrea Bittau dccpop_node) { 808afe00251SAndrea Bittau BUG_ON(opt->dccpop_val == NULL); 809afe00251SAndrea Bittau kfree(opt->dccpop_val); 810afe00251SAndrea Bittau 811afe00251SAndrea Bittau if (opt->dccpop_sc != NULL) { 812afe00251SAndrea Bittau BUG_ON(opt->dccpop_sc->dccpoc_val == NULL); 813afe00251SAndrea Bittau kfree(opt->dccpop_sc->dccpoc_val); 814afe00251SAndrea Bittau kfree(opt->dccpop_sc); 815afe00251SAndrea Bittau } 816afe00251SAndrea Bittau 817afe00251SAndrea Bittau kfree(opt); 818afe00251SAndrea Bittau } 819a4bf3902SArnaldo Carvalho de Melo INIT_LIST_HEAD(&dmsk->dccpms_pending); 820afe00251SAndrea Bittau 821a4bf3902SArnaldo Carvalho de Melo list_for_each_entry_safe(opt, next, &dmsk->dccpms_conf, dccpop_node) { 822afe00251SAndrea Bittau BUG_ON(opt == NULL); 823afe00251SAndrea Bittau if (opt->dccpop_val != NULL) 824afe00251SAndrea Bittau kfree(opt->dccpop_val); 825afe00251SAndrea Bittau kfree(opt); 826afe00251SAndrea Bittau } 827a4bf3902SArnaldo Carvalho de Melo INIT_LIST_HEAD(&dmsk->dccpms_conf); 828afe00251SAndrea Bittau } 829afe00251SAndrea Bittau 830afe00251SAndrea Bittau EXPORT_SYMBOL_GPL(dccp_feat_clean); 831afe00251SAndrea Bittau 832afe00251SAndrea Bittau /* this is to be called only when a listening sock creates its child. It is 833afe00251SAndrea Bittau * assumed by the function---the confirm is not duplicated, but rather it is 834afe00251SAndrea Bittau * "passed on". 835afe00251SAndrea Bittau */ 836afe00251SAndrea Bittau int dccp_feat_clone(struct sock *oldsk, struct sock *newsk) 837afe00251SAndrea Bittau { 838a4bf3902SArnaldo Carvalho de Melo struct dccp_minisock *olddmsk = dccp_msk(oldsk); 839a4bf3902SArnaldo Carvalho de Melo struct dccp_minisock *newdmsk = dccp_msk(newsk); 840afe00251SAndrea Bittau struct dccp_opt_pend *opt; 841afe00251SAndrea Bittau int rc = 0; 842afe00251SAndrea Bittau 843a4bf3902SArnaldo Carvalho de Melo INIT_LIST_HEAD(&newdmsk->dccpms_pending); 844a4bf3902SArnaldo Carvalho de Melo INIT_LIST_HEAD(&newdmsk->dccpms_conf); 845afe00251SAndrea Bittau 846a4bf3902SArnaldo Carvalho de Melo list_for_each_entry(opt, &olddmsk->dccpms_pending, dccpop_node) { 847afe00251SAndrea Bittau struct dccp_opt_pend *newopt; 848afe00251SAndrea Bittau /* copy the value of the option */ 849eed73417SArnaldo Carvalho de Melo u8 *val = kmemdup(opt->dccpop_val, opt->dccpop_len, GFP_ATOMIC); 850afe00251SAndrea Bittau 851afe00251SAndrea Bittau if (val == NULL) 852afe00251SAndrea Bittau goto out_clean; 853afe00251SAndrea Bittau 854eed73417SArnaldo Carvalho de Melo newopt = kmemdup(opt, sizeof(*newopt), GFP_ATOMIC); 855afe00251SAndrea Bittau if (newopt == NULL) { 856afe00251SAndrea Bittau kfree(val); 857afe00251SAndrea Bittau goto out_clean; 858afe00251SAndrea Bittau } 859afe00251SAndrea Bittau 860afe00251SAndrea Bittau /* insert the option */ 861afe00251SAndrea Bittau newopt->dccpop_val = val; 862a4bf3902SArnaldo Carvalho de Melo list_add_tail(&newopt->dccpop_node, &newdmsk->dccpms_pending); 863afe00251SAndrea Bittau 864afe00251SAndrea Bittau /* XXX what happens with backlogs and multiple connections at 865afe00251SAndrea Bittau * once... 866afe00251SAndrea Bittau */ 867afe00251SAndrea Bittau /* the master socket no longer needs to worry about confirms */ 86868907dadSRandy Dunlap opt->dccpop_sc = NULL; /* it's not a memleak---new socket has it */ 869afe00251SAndrea Bittau 870afe00251SAndrea Bittau /* reset state for a new socket */ 871afe00251SAndrea Bittau opt->dccpop_conf = 0; 872afe00251SAndrea Bittau } 873afe00251SAndrea Bittau 874afe00251SAndrea Bittau /* XXX not doing anything about the conf queue */ 875afe00251SAndrea Bittau 876afe00251SAndrea Bittau out: 877afe00251SAndrea Bittau return rc; 878afe00251SAndrea Bittau 879afe00251SAndrea Bittau out_clean: 8808ca0d17bSArnaldo Carvalho de Melo dccp_feat_clean(newdmsk); 881afe00251SAndrea Bittau rc = -ENOMEM; 882afe00251SAndrea Bittau goto out; 883afe00251SAndrea Bittau } 884afe00251SAndrea Bittau 885afe00251SAndrea Bittau EXPORT_SYMBOL_GPL(dccp_feat_clone); 886afe00251SAndrea Bittau 887*e8ef967aSGerrit Renker int dccp_feat_init(struct sock *sk) 888afe00251SAndrea Bittau { 889*e8ef967aSGerrit Renker struct dccp_sock *dp = dccp_sk(sk); 890*e8ef967aSGerrit Renker struct dccp_minisock *dmsk = dccp_msk(sk); 891afe00251SAndrea Bittau int rc; 892afe00251SAndrea Bittau 893*e8ef967aSGerrit Renker INIT_LIST_HEAD(&dmsk->dccpms_pending); /* XXX no longer used */ 894*e8ef967aSGerrit Renker INIT_LIST_HEAD(&dmsk->dccpms_conf); /* XXX no longer used */ 895afe00251SAndrea Bittau 896afe00251SAndrea Bittau /* CCID L */ 897*e8ef967aSGerrit Renker rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 1, 0, 898a4bf3902SArnaldo Carvalho de Melo &dmsk->dccpms_tx_ccid, 1); 899afe00251SAndrea Bittau if (rc) 900afe00251SAndrea Bittau goto out; 901afe00251SAndrea Bittau 902afe00251SAndrea Bittau /* CCID R */ 903*e8ef967aSGerrit Renker rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 0, 0, 904a4bf3902SArnaldo Carvalho de Melo &dmsk->dccpms_rx_ccid, 1); 905afe00251SAndrea Bittau if (rc) 906afe00251SAndrea Bittau goto out; 907afe00251SAndrea Bittau 908afe00251SAndrea Bittau /* Ack ratio */ 909*e8ef967aSGerrit Renker rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0, 910*e8ef967aSGerrit Renker dmsk->dccpms_ack_ratio); 911afe00251SAndrea Bittau out: 912afe00251SAndrea Bittau return rc; 913afe00251SAndrea Bittau } 914afe00251SAndrea Bittau 915afe00251SAndrea Bittau EXPORT_SYMBOL_GPL(dccp_feat_init); 916c02fdc0eSGerrit Renker 917c02fdc0eSGerrit Renker #ifdef CONFIG_IP_DCCP_DEBUG 918c02fdc0eSGerrit Renker const char *dccp_feat_typename(const u8 type) 919c02fdc0eSGerrit Renker { 920c02fdc0eSGerrit Renker switch(type) { 921c02fdc0eSGerrit Renker case DCCPO_CHANGE_L: return("ChangeL"); 922c02fdc0eSGerrit Renker case DCCPO_CONFIRM_L: return("ConfirmL"); 923c02fdc0eSGerrit Renker case DCCPO_CHANGE_R: return("ChangeR"); 924c02fdc0eSGerrit Renker case DCCPO_CONFIRM_R: return("ConfirmR"); 925c02fdc0eSGerrit Renker /* the following case must not appear in feature negotation */ 926c02fdc0eSGerrit Renker default: dccp_pr_debug("unknown type %d [BUG!]\n", type); 927c02fdc0eSGerrit Renker } 928c02fdc0eSGerrit Renker return NULL; 929c02fdc0eSGerrit Renker } 930c02fdc0eSGerrit Renker 931c02fdc0eSGerrit Renker EXPORT_SYMBOL_GPL(dccp_feat_typename); 932c02fdc0eSGerrit Renker 933c02fdc0eSGerrit Renker const char *dccp_feat_name(const u8 feat) 934c02fdc0eSGerrit Renker { 935c02fdc0eSGerrit Renker static const char *feature_names[] = { 936c02fdc0eSGerrit Renker [DCCPF_RESERVED] = "Reserved", 937c02fdc0eSGerrit Renker [DCCPF_CCID] = "CCID", 938c02fdc0eSGerrit Renker [DCCPF_SHORT_SEQNOS] = "Allow Short Seqnos", 939c02fdc0eSGerrit Renker [DCCPF_SEQUENCE_WINDOW] = "Sequence Window", 940c02fdc0eSGerrit Renker [DCCPF_ECN_INCAPABLE] = "ECN Incapable", 941c02fdc0eSGerrit Renker [DCCPF_ACK_RATIO] = "Ack Ratio", 942c02fdc0eSGerrit Renker [DCCPF_SEND_ACK_VECTOR] = "Send ACK Vector", 943c02fdc0eSGerrit Renker [DCCPF_SEND_NDP_COUNT] = "Send NDP Count", 944c02fdc0eSGerrit Renker [DCCPF_MIN_CSUM_COVER] = "Min. Csum Coverage", 945c02fdc0eSGerrit Renker [DCCPF_DATA_CHECKSUM] = "Send Data Checksum", 946c02fdc0eSGerrit Renker }; 947dd6303dfSGerrit Renker if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC) 948dd6303dfSGerrit Renker return feature_names[DCCPF_RESERVED]; 949dd6303dfSGerrit Renker 9507d43d1a0SGerrit Renker if (feat == DCCPF_SEND_LEV_RATE) 9517d43d1a0SGerrit Renker return "Send Loss Event Rate"; 952c02fdc0eSGerrit Renker if (feat >= DCCPF_MIN_CCID_SPECIFIC) 953c02fdc0eSGerrit Renker return "CCID-specific"; 954c02fdc0eSGerrit Renker 955c02fdc0eSGerrit Renker return feature_names[feat]; 956c02fdc0eSGerrit Renker } 957c02fdc0eSGerrit Renker 958c02fdc0eSGerrit Renker EXPORT_SYMBOL_GPL(dccp_feat_name); 959c02fdc0eSGerrit Renker #endif /* CONFIG_IP_DCCP_DEBUG */ 960