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 95e8ef967aSGerrit Renker static int dccp_feat_default_value(u8 feat_num) 96e8ef967aSGerrit Renker { 97e8ef967aSGerrit Renker int idx = dccp_feat_index(feat_num); 98e8ef967aSGerrit Renker /* 99e8ef967aSGerrit Renker * There are no default values for unknown features, so encountering a 100e8ef967aSGerrit Renker * negative index here indicates a serious problem somewhere else. 101e8ef967aSGerrit Renker */ 102e8ef967aSGerrit Renker DCCP_BUG_ON(idx < 0); 103e8ef967aSGerrit Renker 104e8ef967aSGerrit Renker return idx < 0 ? 0 : dccp_feat_table[idx].default_value; 105e8ef967aSGerrit Renker } 106e8ef967aSGerrit 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 */ 1690c116839SGerrit Renker static struct dccp_feat_entry *dccp_feat_list_lookup(struct list_head *fn_list, 1700c116839SGerrit Renker u8 feat_num, bool is_local) 1710c116839SGerrit Renker { 1720c116839SGerrit Renker struct dccp_feat_entry *entry; 1730c116839SGerrit Renker 1743d3e35aaSGerrit Renker list_for_each_entry(entry, fn_list, node) { 1750c116839SGerrit Renker if (entry->feat_num == feat_num && entry->is_local == is_local) 1760c116839SGerrit Renker return entry; 1770c116839SGerrit Renker else if (entry->feat_num > feat_num) 1780c116839SGerrit Renker break; 1793d3e35aaSGerrit Renker } 1800c116839SGerrit Renker return NULL; 1810c116839SGerrit Renker } 18261e6473eSGerrit Renker 183e8ef967aSGerrit Renker /** 184e8ef967aSGerrit Renker * dccp_feat_entry_new - Central list update routine (called by all others) 185e8ef967aSGerrit Renker * @head: list to add to 186e8ef967aSGerrit Renker * @feat: feature number 187e8ef967aSGerrit Renker * @local: whether the local (1) or remote feature with number @feat is meant 188e8ef967aSGerrit Renker * This is the only constructor and serves to ensure the above invariants. 189e8ef967aSGerrit Renker */ 190e8ef967aSGerrit Renker static struct dccp_feat_entry * 191e8ef967aSGerrit Renker dccp_feat_entry_new(struct list_head *head, u8 feat, bool local) 192e8ef967aSGerrit Renker { 193e8ef967aSGerrit Renker struct dccp_feat_entry *entry; 194e8ef967aSGerrit Renker 195e8ef967aSGerrit Renker list_for_each_entry(entry, head, node) 196e8ef967aSGerrit Renker if (entry->feat_num == feat && entry->is_local == local) { 197e8ef967aSGerrit Renker dccp_feat_val_destructor(entry->feat_num, &entry->val); 198e8ef967aSGerrit Renker return entry; 199e8ef967aSGerrit Renker } else if (entry->feat_num > feat) { 200e8ef967aSGerrit Renker head = &entry->node; 201e8ef967aSGerrit Renker break; 202e8ef967aSGerrit Renker } 203e8ef967aSGerrit Renker 204e8ef967aSGerrit Renker entry = kmalloc(sizeof(*entry), gfp_any()); 205e8ef967aSGerrit Renker if (entry != NULL) { 206e8ef967aSGerrit Renker entry->feat_num = feat; 207e8ef967aSGerrit Renker entry->is_local = local; 208e8ef967aSGerrit Renker list_add_tail(&entry->node, head); 209e8ef967aSGerrit Renker } 210e8ef967aSGerrit Renker return entry; 211e8ef967aSGerrit Renker } 212e8ef967aSGerrit Renker 213e8ef967aSGerrit Renker /** 214e8ef967aSGerrit Renker * dccp_feat_push_change - Add/overwrite a Change option in the list 215e8ef967aSGerrit Renker * @fn_list: feature-negotiation list to update 216e8ef967aSGerrit Renker * @feat: one of %dccp_feature_numbers 217e8ef967aSGerrit Renker * @local: whether local (1) or remote (0) @feat_num is meant 218e8ef967aSGerrit Renker * @needs_mandatory: whether to use Mandatory feature negotiation options 219e8ef967aSGerrit Renker * @fval: pointer to NN/SP value to be inserted (will be copied) 220e8ef967aSGerrit Renker */ 221e8ef967aSGerrit Renker static int dccp_feat_push_change(struct list_head *fn_list, u8 feat, u8 local, 222e8ef967aSGerrit Renker u8 mandatory, dccp_feat_val *fval) 223e8ef967aSGerrit Renker { 224e8ef967aSGerrit Renker struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local); 225e8ef967aSGerrit Renker 226e8ef967aSGerrit Renker if (new == NULL) 227e8ef967aSGerrit Renker return -ENOMEM; 228e8ef967aSGerrit Renker 229e8ef967aSGerrit Renker new->feat_num = feat; 230e8ef967aSGerrit Renker new->is_local = local; 231e8ef967aSGerrit Renker new->state = FEAT_INITIALISING; 232e8ef967aSGerrit Renker new->needs_confirm = 0; 233e8ef967aSGerrit Renker new->empty_confirm = 0; 234e8ef967aSGerrit Renker new->val = *fval; 235e8ef967aSGerrit Renker new->needs_mandatory = mandatory; 236e8ef967aSGerrit Renker 237e8ef967aSGerrit Renker return 0; 238e8ef967aSGerrit Renker } 239e8ef967aSGerrit Renker 24061e6473eSGerrit Renker static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry) 24161e6473eSGerrit Renker { 24261e6473eSGerrit Renker list_del(&entry->node); 24361e6473eSGerrit Renker dccp_feat_entry_destructor(entry); 24461e6473eSGerrit Renker } 24561e6473eSGerrit Renker 24661e6473eSGerrit Renker void dccp_feat_list_purge(struct list_head *fn_list) 24761e6473eSGerrit Renker { 24861e6473eSGerrit Renker struct dccp_feat_entry *entry, *next; 24961e6473eSGerrit Renker 25061e6473eSGerrit Renker list_for_each_entry_safe(entry, next, fn_list, node) 25161e6473eSGerrit Renker dccp_feat_entry_destructor(entry); 25261e6473eSGerrit Renker INIT_LIST_HEAD(fn_list); 25361e6473eSGerrit Renker } 25461e6473eSGerrit Renker EXPORT_SYMBOL_GPL(dccp_feat_list_purge); 25561e6473eSGerrit Renker 256ac75773cSGerrit Renker /* generate @to as full clone of @from - @to must not contain any nodes */ 257ac75773cSGerrit Renker int dccp_feat_clone_list(struct list_head const *from, struct list_head *to) 258ac75773cSGerrit Renker { 259ac75773cSGerrit Renker struct dccp_feat_entry *entry, *new; 260ac75773cSGerrit Renker 261ac75773cSGerrit Renker INIT_LIST_HEAD(to); 262ac75773cSGerrit Renker list_for_each_entry(entry, from, node) { 263ac75773cSGerrit Renker new = dccp_feat_clone_entry(entry); 264ac75773cSGerrit Renker if (new == NULL) 265ac75773cSGerrit Renker goto cloning_failed; 266ac75773cSGerrit Renker list_add_tail(&new->node, to); 267ac75773cSGerrit Renker } 268ac75773cSGerrit Renker return 0; 269ac75773cSGerrit Renker 270ac75773cSGerrit Renker cloning_failed: 271ac75773cSGerrit Renker dccp_feat_list_purge(to); 272ac75773cSGerrit Renker return -ENOMEM; 273ac75773cSGerrit Renker } 274ac75773cSGerrit Renker 2750971d17cSGerrit Renker /** 2760971d17cSGerrit Renker * dccp_feat_valid_nn_length - Enforce length constraints on NN options 2770971d17cSGerrit Renker * Length is between 0 and %DCCP_OPTVAL_MAXLEN. Used for outgoing packets only, 2780971d17cSGerrit Renker * incoming options are accepted as long as their values are valid. 2790971d17cSGerrit Renker */ 2800971d17cSGerrit Renker static u8 dccp_feat_valid_nn_length(u8 feat_num) 2810971d17cSGerrit Renker { 2820971d17cSGerrit Renker if (feat_num == DCCPF_ACK_RATIO) /* RFC 4340, 11.3 and 6.6.8 */ 2830971d17cSGerrit Renker return 2; 2840971d17cSGerrit Renker if (feat_num == DCCPF_SEQUENCE_WINDOW) /* RFC 4340, 7.5.2 and 6.5 */ 2850971d17cSGerrit Renker return 6; 2860971d17cSGerrit Renker return 0; 2870971d17cSGerrit Renker } 2880971d17cSGerrit Renker 289e8ef967aSGerrit Renker static u8 dccp_feat_is_valid_nn_val(u8 feat_num, u64 val) 290e8ef967aSGerrit Renker { 291e8ef967aSGerrit Renker switch (feat_num) { 292e8ef967aSGerrit Renker case DCCPF_ACK_RATIO: 293e8ef967aSGerrit Renker return val <= DCCPF_ACK_RATIO_MAX; 294e8ef967aSGerrit Renker case DCCPF_SEQUENCE_WINDOW: 295e8ef967aSGerrit Renker return val >= DCCPF_SEQ_WMIN && val <= DCCPF_SEQ_WMAX; 296e8ef967aSGerrit Renker } 297e8ef967aSGerrit Renker return 0; /* feature unknown - so we can't tell */ 298e8ef967aSGerrit Renker } 299e8ef967aSGerrit Renker 300e8ef967aSGerrit Renker /* check that SP values are within the ranges defined in RFC 4340 */ 301e8ef967aSGerrit Renker static u8 dccp_feat_is_valid_sp_val(u8 feat_num, u8 val) 302e8ef967aSGerrit Renker { 303e8ef967aSGerrit Renker switch (feat_num) { 304e8ef967aSGerrit Renker case DCCPF_CCID: 305e8ef967aSGerrit Renker return val == DCCPC_CCID2 || val == DCCPC_CCID3; 306e8ef967aSGerrit Renker /* Type-check Boolean feature values: */ 307e8ef967aSGerrit Renker case DCCPF_SHORT_SEQNOS: 308e8ef967aSGerrit Renker case DCCPF_ECN_INCAPABLE: 309e8ef967aSGerrit Renker case DCCPF_SEND_ACK_VECTOR: 310e8ef967aSGerrit Renker case DCCPF_SEND_NDP_COUNT: 311e8ef967aSGerrit Renker case DCCPF_DATA_CHECKSUM: 312e8ef967aSGerrit Renker case DCCPF_SEND_LEV_RATE: 313e8ef967aSGerrit Renker return val < 2; 314e8ef967aSGerrit Renker case DCCPF_MIN_CSUM_COVER: 315e8ef967aSGerrit Renker return val < 16; 316e8ef967aSGerrit Renker } 317e8ef967aSGerrit Renker return 0; /* feature unknown */ 318e8ef967aSGerrit Renker } 319e8ef967aSGerrit Renker 320e8ef967aSGerrit Renker static u8 dccp_feat_sp_list_ok(u8 feat_num, u8 const *sp_list, u8 sp_len) 321e8ef967aSGerrit Renker { 322e8ef967aSGerrit Renker if (sp_list == NULL || sp_len < 1) 323e8ef967aSGerrit Renker return 0; 324e8ef967aSGerrit Renker while (sp_len--) 325e8ef967aSGerrit Renker if (!dccp_feat_is_valid_sp_val(feat_num, *sp_list++)) 326e8ef967aSGerrit Renker return 0; 327e8ef967aSGerrit Renker return 1; 328e8ef967aSGerrit Renker } 329e8ef967aSGerrit Renker 330e8ef967aSGerrit Renker /** 3310971d17cSGerrit Renker * dccp_feat_insert_opts - Generate FN options from current list state 3320971d17cSGerrit Renker * @skb: next sk_buff to be sent to the peer 3330971d17cSGerrit Renker * @dp: for client during handshake and general negotiation 3340971d17cSGerrit Renker * @dreq: used by the server only (all Changes/Confirms in LISTEN/RESPOND) 3350971d17cSGerrit Renker */ 3360971d17cSGerrit Renker int dccp_feat_insert_opts(struct dccp_sock *dp, struct dccp_request_sock *dreq, 3370971d17cSGerrit Renker struct sk_buff *skb) 3380971d17cSGerrit Renker { 3390971d17cSGerrit Renker struct list_head *fn = dreq ? &dreq->dreq_featneg : &dp->dccps_featneg; 3400971d17cSGerrit Renker struct dccp_feat_entry *pos, *next; 3410971d17cSGerrit Renker u8 opt, type, len, *ptr, nn_in_nbo[DCCP_OPTVAL_MAXLEN]; 3420971d17cSGerrit Renker bool rpt; 3430971d17cSGerrit Renker 3440971d17cSGerrit Renker /* put entries into @skb in the order they appear in the list */ 3450971d17cSGerrit Renker list_for_each_entry_safe_reverse(pos, next, fn, node) { 3460971d17cSGerrit Renker opt = dccp_feat_genopt(pos); 3470971d17cSGerrit Renker type = dccp_feat_type(pos->feat_num); 3480971d17cSGerrit Renker rpt = false; 3490971d17cSGerrit Renker 3500971d17cSGerrit Renker if (pos->empty_confirm) { 3510971d17cSGerrit Renker len = 0; 3520971d17cSGerrit Renker ptr = NULL; 3530971d17cSGerrit Renker } else { 3540971d17cSGerrit Renker if (type == FEAT_SP) { 3550971d17cSGerrit Renker len = pos->val.sp.len; 3560971d17cSGerrit Renker ptr = pos->val.sp.vec; 3570971d17cSGerrit Renker rpt = pos->needs_confirm; 3580971d17cSGerrit Renker } else if (type == FEAT_NN) { 3590971d17cSGerrit Renker len = dccp_feat_valid_nn_length(pos->feat_num); 3600971d17cSGerrit Renker ptr = nn_in_nbo; 3610971d17cSGerrit Renker dccp_encode_value_var(pos->val.nn, ptr, len); 3620971d17cSGerrit Renker } else { 3630971d17cSGerrit Renker DCCP_BUG("unknown feature %u", pos->feat_num); 3640971d17cSGerrit Renker return -1; 3650971d17cSGerrit Renker } 3660971d17cSGerrit Renker } 3670971d17cSGerrit Renker 3680971d17cSGerrit Renker if (dccp_insert_fn_opt(skb, opt, pos->feat_num, ptr, len, rpt)) 3690971d17cSGerrit Renker return -1; 3700971d17cSGerrit Renker if (pos->needs_mandatory && dccp_insert_option_mandatory(skb)) 3710971d17cSGerrit Renker return -1; 3720971d17cSGerrit Renker /* 3730971d17cSGerrit Renker * Enter CHANGING after transmitting the Change option (6.6.2). 3740971d17cSGerrit Renker */ 3750971d17cSGerrit Renker if (pos->state == FEAT_INITIALISING) 3760971d17cSGerrit Renker pos->state = FEAT_CHANGING; 3770971d17cSGerrit Renker } 3780971d17cSGerrit Renker return 0; 3790971d17cSGerrit Renker } 3800971d17cSGerrit Renker 3810971d17cSGerrit Renker /** 382e8ef967aSGerrit Renker * __feat_register_nn - Register new NN value on socket 383e8ef967aSGerrit Renker * @fn: feature-negotiation list to register with 384e8ef967aSGerrit Renker * @feat: an NN feature from %dccp_feature_numbers 385e8ef967aSGerrit Renker * @mandatory: use Mandatory option if 1 386e8ef967aSGerrit Renker * @nn_val: value to register (restricted to 4 bytes) 387e8ef967aSGerrit Renker * Note that NN features are local by definition (RFC 4340, 6.3.2). 388e8ef967aSGerrit Renker */ 389e8ef967aSGerrit Renker static int __feat_register_nn(struct list_head *fn, u8 feat, 390e8ef967aSGerrit Renker u8 mandatory, u64 nn_val) 391e8ef967aSGerrit Renker { 392e8ef967aSGerrit Renker dccp_feat_val fval = { .nn = nn_val }; 393e8ef967aSGerrit Renker 394e8ef967aSGerrit Renker if (dccp_feat_type(feat) != FEAT_NN || 395e8ef967aSGerrit Renker !dccp_feat_is_valid_nn_val(feat, nn_val)) 396e8ef967aSGerrit Renker return -EINVAL; 397e8ef967aSGerrit Renker 398e8ef967aSGerrit Renker /* Don't bother with default values, they will be activated anyway. */ 399e8ef967aSGerrit Renker if (nn_val - (u64)dccp_feat_default_value(feat) == 0) 400e8ef967aSGerrit Renker return 0; 401e8ef967aSGerrit Renker 402e8ef967aSGerrit Renker return dccp_feat_push_change(fn, feat, 1, mandatory, &fval); 403e8ef967aSGerrit Renker } 404e8ef967aSGerrit Renker 405e8ef967aSGerrit Renker /** 406e8ef967aSGerrit Renker * __feat_register_sp - Register new SP value/list on socket 407e8ef967aSGerrit Renker * @fn: feature-negotiation list to register with 408e8ef967aSGerrit Renker * @feat: an SP feature from %dccp_feature_numbers 409e8ef967aSGerrit Renker * @is_local: whether the local (1) or the remote (0) @feat is meant 410e8ef967aSGerrit Renker * @mandatory: use Mandatory option if 1 411e8ef967aSGerrit Renker * @sp_val: SP value followed by optional preference list 412e8ef967aSGerrit Renker * @sp_len: length of @sp_val in bytes 413e8ef967aSGerrit Renker */ 414e8ef967aSGerrit Renker static int __feat_register_sp(struct list_head *fn, u8 feat, u8 is_local, 415e8ef967aSGerrit Renker u8 mandatory, u8 const *sp_val, u8 sp_len) 416e8ef967aSGerrit Renker { 417e8ef967aSGerrit Renker dccp_feat_val fval; 418e8ef967aSGerrit Renker 419e8ef967aSGerrit Renker if (dccp_feat_type(feat) != FEAT_SP || 420e8ef967aSGerrit Renker !dccp_feat_sp_list_ok(feat, sp_val, sp_len)) 421e8ef967aSGerrit Renker return -EINVAL; 422e8ef967aSGerrit Renker 423d90ebcbfSGerrit Renker /* Avoid negotiating alien CCIDs by only advertising supported ones */ 424d90ebcbfSGerrit Renker if (feat == DCCPF_CCID && !ccid_support_check(sp_val, sp_len)) 425d90ebcbfSGerrit Renker return -EOPNOTSUPP; 426d90ebcbfSGerrit Renker 427e8ef967aSGerrit Renker if (dccp_feat_clone_sp_val(&fval, sp_val, sp_len)) 428e8ef967aSGerrit Renker return -ENOMEM; 429e8ef967aSGerrit Renker 430e8ef967aSGerrit Renker return dccp_feat_push_change(fn, feat, is_local, mandatory, &fval); 431e8ef967aSGerrit Renker } 432e8ef967aSGerrit Renker 43349aebc66SGerrit Renker /** 43449aebc66SGerrit Renker * dccp_feat_register_sp - Register requests to change SP feature values 43549aebc66SGerrit Renker * @sk: client or listening socket 43649aebc66SGerrit Renker * @feat: one of %dccp_feature_numbers 43749aebc66SGerrit Renker * @is_local: whether the local (1) or remote (0) @feat is meant 43849aebc66SGerrit Renker * @list: array of preferred values, in descending order of preference 43949aebc66SGerrit Renker * @len: length of @list in bytes 44049aebc66SGerrit Renker */ 44149aebc66SGerrit Renker int dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local, 44249aebc66SGerrit Renker u8 const *list, u8 len) 44349aebc66SGerrit Renker { /* any changes must be registered before establishing the connection */ 44449aebc66SGerrit Renker if (sk->sk_state != DCCP_CLOSED) 44549aebc66SGerrit Renker return -EISCONN; 44649aebc66SGerrit Renker if (dccp_feat_type(feat) != FEAT_SP) 44719443178SChris Wright return -EINVAL; 44849aebc66SGerrit Renker return __feat_register_sp(&dccp_sk(sk)->dccps_featneg, feat, is_local, 44949aebc66SGerrit Renker 0, list, len); 450afe00251SAndrea Bittau } 451afe00251SAndrea Bittau 45249aebc66SGerrit Renker /* Analogous to dccp_feat_register_sp(), but for non-negotiable values */ 45349aebc66SGerrit Renker int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val) 45449aebc66SGerrit Renker { 45549aebc66SGerrit Renker /* any changes must be registered before establishing the connection */ 45649aebc66SGerrit Renker if (sk->sk_state != DCCP_CLOSED) 45749aebc66SGerrit Renker return -EISCONN; 45849aebc66SGerrit Renker if (dccp_feat_type(feat) != FEAT_NN) 45949aebc66SGerrit Renker return -EINVAL; 46049aebc66SGerrit Renker return __feat_register_nn(&dccp_sk(sk)->dccps_featneg, feat, 0, val); 461afe00251SAndrea Bittau } 462afe00251SAndrea Bittau 4639eca0a47SGerrit Renker /* 4649eca0a47SGerrit Renker * Tracking features whose value depend on the choice of CCID 4659eca0a47SGerrit Renker * 4669eca0a47SGerrit Renker * This is designed with an extension in mind so that a list walk could be done 4679eca0a47SGerrit Renker * before activating any features. However, the existing framework was found to 4689eca0a47SGerrit Renker * work satisfactorily up until now, the automatic verification is left open. 4699eca0a47SGerrit Renker * When adding new CCIDs, add a corresponding dependency table here. 4709eca0a47SGerrit Renker */ 4719eca0a47SGerrit Renker static const struct ccid_dependency *dccp_feat_ccid_deps(u8 ccid, bool is_local) 4729eca0a47SGerrit Renker { 4739eca0a47SGerrit Renker static const struct ccid_dependency ccid2_dependencies[2][2] = { 4749eca0a47SGerrit Renker /* 4759eca0a47SGerrit Renker * CCID2 mandates Ack Vectors (RFC 4341, 4.): as CCID is a TX 4769eca0a47SGerrit Renker * feature and Send Ack Vector is an RX feature, `is_local' 4779eca0a47SGerrit Renker * needs to be reversed. 4789eca0a47SGerrit Renker */ 4799eca0a47SGerrit Renker { /* Dependencies of the receiver-side (remote) CCID2 */ 4809eca0a47SGerrit Renker { 4819eca0a47SGerrit Renker .dependent_feat = DCCPF_SEND_ACK_VECTOR, 4829eca0a47SGerrit Renker .is_local = true, 4839eca0a47SGerrit Renker .is_mandatory = true, 4849eca0a47SGerrit Renker .val = 1 4859eca0a47SGerrit Renker }, 4869eca0a47SGerrit Renker { 0, 0, 0, 0 } 4879eca0a47SGerrit Renker }, 4889eca0a47SGerrit Renker { /* Dependencies of the sender-side (local) CCID2 */ 4899eca0a47SGerrit Renker { 4909eca0a47SGerrit Renker .dependent_feat = DCCPF_SEND_ACK_VECTOR, 4919eca0a47SGerrit Renker .is_local = false, 4929eca0a47SGerrit Renker .is_mandatory = true, 4939eca0a47SGerrit Renker .val = 1 4949eca0a47SGerrit Renker }, 4959eca0a47SGerrit Renker { 0, 0, 0, 0 } 4969eca0a47SGerrit Renker } 4979eca0a47SGerrit Renker }; 4989eca0a47SGerrit Renker static const struct ccid_dependency ccid3_dependencies[2][5] = { 4999eca0a47SGerrit Renker { /* 5009eca0a47SGerrit Renker * Dependencies of the receiver-side CCID3 5019eca0a47SGerrit Renker */ 5029eca0a47SGerrit Renker { /* locally disable Ack Vectors */ 5039eca0a47SGerrit Renker .dependent_feat = DCCPF_SEND_ACK_VECTOR, 5049eca0a47SGerrit Renker .is_local = true, 5059eca0a47SGerrit Renker .is_mandatory = false, 5069eca0a47SGerrit Renker .val = 0 5079eca0a47SGerrit Renker }, 5089eca0a47SGerrit Renker { /* see below why Send Loss Event Rate is on */ 5099eca0a47SGerrit Renker .dependent_feat = DCCPF_SEND_LEV_RATE, 5109eca0a47SGerrit Renker .is_local = true, 5119eca0a47SGerrit Renker .is_mandatory = true, 5129eca0a47SGerrit Renker .val = 1 5139eca0a47SGerrit Renker }, 5149eca0a47SGerrit Renker { /* NDP Count is needed as per RFC 4342, 6.1.1 */ 5159eca0a47SGerrit Renker .dependent_feat = DCCPF_SEND_NDP_COUNT, 5169eca0a47SGerrit Renker .is_local = false, 5179eca0a47SGerrit Renker .is_mandatory = true, 5189eca0a47SGerrit Renker .val = 1 5199eca0a47SGerrit Renker }, 5209eca0a47SGerrit Renker { 0, 0, 0, 0 }, 5219eca0a47SGerrit Renker }, 5229eca0a47SGerrit Renker { /* 5239eca0a47SGerrit Renker * CCID3 at the TX side: we request that the HC-receiver 5249eca0a47SGerrit Renker * will not send Ack Vectors (they will be ignored, so 5259eca0a47SGerrit Renker * Mandatory is not set); we enable Send Loss Event Rate 5269eca0a47SGerrit Renker * (Mandatory since the implementation does not support 5279eca0a47SGerrit Renker * the Loss Intervals option of RFC 4342, 8.6). 5289eca0a47SGerrit Renker * The last two options are for peer's information only. 5299eca0a47SGerrit Renker */ 5309eca0a47SGerrit Renker { 5319eca0a47SGerrit Renker .dependent_feat = DCCPF_SEND_ACK_VECTOR, 5329eca0a47SGerrit Renker .is_local = false, 5339eca0a47SGerrit Renker .is_mandatory = false, 5349eca0a47SGerrit Renker .val = 0 5359eca0a47SGerrit Renker }, 5369eca0a47SGerrit Renker { 5379eca0a47SGerrit Renker .dependent_feat = DCCPF_SEND_LEV_RATE, 5389eca0a47SGerrit Renker .is_local = false, 5399eca0a47SGerrit Renker .is_mandatory = true, 5409eca0a47SGerrit Renker .val = 1 5419eca0a47SGerrit Renker }, 5429eca0a47SGerrit Renker { /* this CCID does not support Ack Ratio */ 5439eca0a47SGerrit Renker .dependent_feat = DCCPF_ACK_RATIO, 5449eca0a47SGerrit Renker .is_local = true, 5459eca0a47SGerrit Renker .is_mandatory = false, 5469eca0a47SGerrit Renker .val = 0 5479eca0a47SGerrit Renker }, 5489eca0a47SGerrit Renker { /* tell receiver we are sending NDP counts */ 5499eca0a47SGerrit Renker .dependent_feat = DCCPF_SEND_NDP_COUNT, 5509eca0a47SGerrit Renker .is_local = true, 5519eca0a47SGerrit Renker .is_mandatory = false, 5529eca0a47SGerrit Renker .val = 1 5539eca0a47SGerrit Renker }, 5549eca0a47SGerrit Renker { 0, 0, 0, 0 } 5559eca0a47SGerrit Renker } 5569eca0a47SGerrit Renker }; 5579eca0a47SGerrit Renker switch (ccid) { 5589eca0a47SGerrit Renker case DCCPC_CCID2: 5599eca0a47SGerrit Renker return ccid2_dependencies[is_local]; 5609eca0a47SGerrit Renker case DCCPC_CCID3: 5619eca0a47SGerrit Renker return ccid3_dependencies[is_local]; 5629eca0a47SGerrit Renker default: 5639eca0a47SGerrit Renker return NULL; 5649eca0a47SGerrit Renker } 5659eca0a47SGerrit Renker } 5669eca0a47SGerrit Renker 5679eca0a47SGerrit Renker /** 5689eca0a47SGerrit Renker * dccp_feat_propagate_ccid - Resolve dependencies of features on choice of CCID 5699eca0a47SGerrit Renker * @fn: feature-negotiation list to update 5709eca0a47SGerrit Renker * @id: CCID number to track 5719eca0a47SGerrit Renker * @is_local: whether TX CCID (1) or RX CCID (0) is meant 5729eca0a47SGerrit Renker * This function needs to be called after registering all other features. 5739eca0a47SGerrit Renker */ 5749eca0a47SGerrit Renker static int dccp_feat_propagate_ccid(struct list_head *fn, u8 id, bool is_local) 5759eca0a47SGerrit Renker { 5769eca0a47SGerrit Renker const struct ccid_dependency *table = dccp_feat_ccid_deps(id, is_local); 5779eca0a47SGerrit Renker int i, rc = (table == NULL); 5789eca0a47SGerrit Renker 5799eca0a47SGerrit Renker for (i = 0; rc == 0 && table[i].dependent_feat != DCCPF_RESERVED; i++) 5809eca0a47SGerrit Renker if (dccp_feat_type(table[i].dependent_feat) == FEAT_SP) 5819eca0a47SGerrit Renker rc = __feat_register_sp(fn, table[i].dependent_feat, 5829eca0a47SGerrit Renker table[i].is_local, 5839eca0a47SGerrit Renker table[i].is_mandatory, 5849eca0a47SGerrit Renker &table[i].val, 1); 5859eca0a47SGerrit Renker else 5869eca0a47SGerrit Renker rc = __feat_register_nn(fn, table[i].dependent_feat, 5879eca0a47SGerrit Renker table[i].is_mandatory, 5889eca0a47SGerrit Renker table[i].val); 5899eca0a47SGerrit Renker return rc; 5909eca0a47SGerrit Renker } 5919eca0a47SGerrit Renker 5929eca0a47SGerrit Renker /** 5939eca0a47SGerrit Renker * dccp_feat_finalise_settings - Finalise settings before starting negotiation 5949eca0a47SGerrit Renker * @dp: client or listening socket (settings will be inherited) 5959eca0a47SGerrit Renker * This is called after all registrations (socket initialisation, sysctls, and 5969eca0a47SGerrit Renker * sockopt calls), and before sending the first packet containing Change options 5979eca0a47SGerrit Renker * (ie. client-Request or server-Response), to ensure internal consistency. 5989eca0a47SGerrit Renker */ 5999eca0a47SGerrit Renker int dccp_feat_finalise_settings(struct dccp_sock *dp) 6009eca0a47SGerrit Renker { 6019eca0a47SGerrit Renker struct list_head *fn = &dp->dccps_featneg; 6029eca0a47SGerrit Renker struct dccp_feat_entry *entry; 6039eca0a47SGerrit Renker int i = 2, ccids[2] = { -1, -1 }; 6049eca0a47SGerrit Renker 6059eca0a47SGerrit Renker /* 6069eca0a47SGerrit Renker * Propagating CCIDs: 6079eca0a47SGerrit Renker * 1) not useful to propagate CCID settings if this host advertises more 6089eca0a47SGerrit Renker * than one CCID: the choice of CCID may still change - if this is 6099eca0a47SGerrit Renker * the client, or if this is the server and the client sends 6109eca0a47SGerrit Renker * singleton CCID values. 6119eca0a47SGerrit Renker * 2) since is that propagate_ccid changes the list, we defer changing 6129eca0a47SGerrit Renker * the sorted list until after the traversal. 6139eca0a47SGerrit Renker */ 6149eca0a47SGerrit Renker list_for_each_entry(entry, fn, node) 6159eca0a47SGerrit Renker if (entry->feat_num == DCCPF_CCID && entry->val.sp.len == 1) 6169eca0a47SGerrit Renker ccids[entry->is_local] = entry->val.sp.vec[0]; 6179eca0a47SGerrit Renker while (i--) 6189eca0a47SGerrit Renker if (ccids[i] > 0 && dccp_feat_propagate_ccid(fn, ccids[i], i)) 6199eca0a47SGerrit Renker return -1; 6209eca0a47SGerrit Renker return 0; 6219eca0a47SGerrit Renker } 6229eca0a47SGerrit Renker 6230c116839SGerrit Renker /** 6240c116839SGerrit Renker * dccp_feat_server_ccid_dependencies - Resolve CCID-dependent features 6250c116839SGerrit Renker * It is the server which resolves the dependencies once the CCID has been 6260c116839SGerrit Renker * fully negotiated. If no CCID has been negotiated, it uses the default CCID. 6270c116839SGerrit Renker */ 6280c116839SGerrit Renker int dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq) 6290c116839SGerrit Renker { 6300c116839SGerrit Renker struct list_head *fn = &dreq->dreq_featneg; 6310c116839SGerrit Renker struct dccp_feat_entry *entry; 6320c116839SGerrit Renker u8 is_local, ccid; 6330c116839SGerrit Renker 6340c116839SGerrit Renker for (is_local = 0; is_local <= 1; is_local++) { 6350c116839SGerrit Renker entry = dccp_feat_list_lookup(fn, DCCPF_CCID, is_local); 6360c116839SGerrit Renker 6370c116839SGerrit Renker if (entry != NULL && !entry->empty_confirm) 6380c116839SGerrit Renker ccid = entry->val.sp.vec[0]; 6390c116839SGerrit Renker else 6400c116839SGerrit Renker ccid = dccp_feat_default_value(DCCPF_CCID); 6410c116839SGerrit Renker 6420c116839SGerrit Renker if (dccp_feat_propagate_ccid(fn, ccid, is_local)) 6430c116839SGerrit Renker return -1; 6440c116839SGerrit Renker } 6450c116839SGerrit Renker return 0; 6460c116839SGerrit Renker } 6470c116839SGerrit Renker 6486ffd30fbSAndrea Bittau static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr) 6496ffd30fbSAndrea Bittau { 6506ffd30fbSAndrea Bittau struct dccp_sock *dp = dccp_sk(sk); 651a4bf3902SArnaldo Carvalho de Melo struct dccp_minisock *dmsk = dccp_msk(sk); 6526ffd30fbSAndrea Bittau /* figure out if we are changing our CCID or the peer's */ 6536ffd30fbSAndrea Bittau const int rx = type == DCCPO_CHANGE_R; 654a4bf3902SArnaldo Carvalho de Melo const u8 ccid_nr = rx ? dmsk->dccpms_rx_ccid : dmsk->dccpms_tx_ccid; 6556ffd30fbSAndrea Bittau struct ccid *new_ccid; 6566ffd30fbSAndrea Bittau 6576ffd30fbSAndrea Bittau /* Check if nothing is being changed. */ 6586ffd30fbSAndrea Bittau if (ccid_nr == new_ccid_nr) 6596ffd30fbSAndrea Bittau return 0; 6606ffd30fbSAndrea Bittau 6616ffd30fbSAndrea Bittau new_ccid = ccid_new(new_ccid_nr, sk, rx, GFP_ATOMIC); 6626ffd30fbSAndrea Bittau if (new_ccid == NULL) 6636ffd30fbSAndrea Bittau return -ENOMEM; 6646ffd30fbSAndrea Bittau 6656ffd30fbSAndrea Bittau if (rx) { 6666ffd30fbSAndrea Bittau ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk); 6676ffd30fbSAndrea Bittau dp->dccps_hc_rx_ccid = new_ccid; 668a4bf3902SArnaldo Carvalho de Melo dmsk->dccpms_rx_ccid = new_ccid_nr; 6696ffd30fbSAndrea Bittau } else { 6706ffd30fbSAndrea Bittau ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk); 6716ffd30fbSAndrea Bittau dp->dccps_hc_tx_ccid = new_ccid; 672a4bf3902SArnaldo Carvalho de Melo dmsk->dccpms_tx_ccid = new_ccid_nr; 6736ffd30fbSAndrea Bittau } 6746ffd30fbSAndrea Bittau 6756ffd30fbSAndrea Bittau return 0; 6766ffd30fbSAndrea Bittau } 6776ffd30fbSAndrea Bittau 678afe00251SAndrea Bittau static int dccp_feat_update(struct sock *sk, u8 type, u8 feat, u8 val) 679afe00251SAndrea Bittau { 680c02fdc0eSGerrit Renker dccp_feat_debug(type, feat, val); 6816ffd30fbSAndrea Bittau 6826ffd30fbSAndrea Bittau switch (feat) { 6836ffd30fbSAndrea Bittau case DCCPF_CCID: 6846ffd30fbSAndrea Bittau return dccp_feat_update_ccid(sk, type, val); 6856ffd30fbSAndrea Bittau default: 686c02fdc0eSGerrit Renker dccp_pr_debug("UNIMPLEMENTED: %s(%d, ...)\n", 687c02fdc0eSGerrit Renker dccp_feat_typename(type), feat); 6886ffd30fbSAndrea Bittau break; 6896ffd30fbSAndrea Bittau } 690afe00251SAndrea Bittau return 0; 691afe00251SAndrea Bittau } 692afe00251SAndrea Bittau 693*75757a7dSGerrit Renker /* Select the first entry in @servlist that also occurs in @clilist (6.3.1) */ 694*75757a7dSGerrit Renker static int dccp_feat_preflist_match(u8 *servlist, u8 slen, u8 *clilist, u8 clen) 695*75757a7dSGerrit Renker { 696*75757a7dSGerrit Renker u8 c, s; 697*75757a7dSGerrit Renker 698*75757a7dSGerrit Renker for (s = 0; s < slen; s++) 699*75757a7dSGerrit Renker for (c = 0; c < clen; c++) 700*75757a7dSGerrit Renker if (servlist[s] == clilist[c]) 701*75757a7dSGerrit Renker return servlist[s]; 702*75757a7dSGerrit Renker return -1; 703*75757a7dSGerrit Renker } 704*75757a7dSGerrit Renker 705*75757a7dSGerrit Renker /** 706*75757a7dSGerrit Renker * dccp_feat_prefer - Move preferred entry to the start of array 707*75757a7dSGerrit Renker * Reorder the @array_len elements in @array so that @preferred_value comes 708*75757a7dSGerrit Renker * first. Returns >0 to indicate that @preferred_value does occur in @array. 709*75757a7dSGerrit Renker */ 710*75757a7dSGerrit Renker static u8 dccp_feat_prefer(u8 preferred_value, u8 *array, u8 array_len) 711*75757a7dSGerrit Renker { 712*75757a7dSGerrit Renker u8 i, does_occur = 0; 713*75757a7dSGerrit Renker 714*75757a7dSGerrit Renker if (array != NULL) { 715*75757a7dSGerrit Renker for (i = 0; i < array_len; i++) 716*75757a7dSGerrit Renker if (array[i] == preferred_value) { 717*75757a7dSGerrit Renker array[i] = array[0]; 718*75757a7dSGerrit Renker does_occur++; 719*75757a7dSGerrit Renker } 720*75757a7dSGerrit Renker if (does_occur) 721*75757a7dSGerrit Renker array[0] = preferred_value; 722*75757a7dSGerrit Renker } 723*75757a7dSGerrit Renker return does_occur; 724*75757a7dSGerrit Renker } 725*75757a7dSGerrit Renker 726*75757a7dSGerrit Renker /** 727*75757a7dSGerrit Renker * dccp_feat_reconcile - Reconcile SP preference lists 728*75757a7dSGerrit Renker * @fval: SP list to reconcile into 729*75757a7dSGerrit Renker * @arr: received SP preference list 730*75757a7dSGerrit Renker * @len: length of @arr in bytes 731*75757a7dSGerrit Renker * @is_server: whether this side is the server (and @fv is the server's list) 732*75757a7dSGerrit Renker * @reorder: whether to reorder the list in @fv after reconciling with @arr 733*75757a7dSGerrit Renker * When successful, > 0 is returned and the reconciled list is in @fval. 734*75757a7dSGerrit Renker * A value of 0 means that negotiation failed (no shared entry). 735*75757a7dSGerrit Renker */ 736*75757a7dSGerrit Renker static int dccp_feat_reconcile(dccp_feat_val *fv, u8 *arr, u8 len, 737*75757a7dSGerrit Renker bool is_server, bool reorder) 738*75757a7dSGerrit Renker { 739*75757a7dSGerrit Renker int rc; 740*75757a7dSGerrit Renker 741*75757a7dSGerrit Renker if (!fv->sp.vec || !arr) { 742*75757a7dSGerrit Renker DCCP_CRIT("NULL feature value or array"); 743*75757a7dSGerrit Renker return 0; 744*75757a7dSGerrit Renker } 745*75757a7dSGerrit Renker 746*75757a7dSGerrit Renker if (is_server) 747*75757a7dSGerrit Renker rc = dccp_feat_preflist_match(fv->sp.vec, fv->sp.len, arr, len); 748*75757a7dSGerrit Renker else 749*75757a7dSGerrit Renker rc = dccp_feat_preflist_match(arr, len, fv->sp.vec, fv->sp.len); 750*75757a7dSGerrit Renker 751*75757a7dSGerrit Renker if (!reorder) 752*75757a7dSGerrit Renker return rc; 753*75757a7dSGerrit Renker if (rc < 0) 754*75757a7dSGerrit Renker return 0; 755*75757a7dSGerrit Renker 756*75757a7dSGerrit Renker /* 757*75757a7dSGerrit Renker * Reorder list: used for activating features and in dccp_insert_fn_opt. 758*75757a7dSGerrit Renker */ 759*75757a7dSGerrit Renker return dccp_feat_prefer(rc, fv->sp.vec, fv->sp.len); 760*75757a7dSGerrit Renker } 761*75757a7dSGerrit Renker 762*75757a7dSGerrit Renker #ifdef __this_is_the_old_framework_and_will_be_removed_later_in_a_subsequent_patch 763afe00251SAndrea Bittau static int dccp_feat_reconcile(struct sock *sk, struct dccp_opt_pend *opt, 764afe00251SAndrea Bittau u8 *rpref, u8 rlen) 765afe00251SAndrea Bittau { 766afe00251SAndrea Bittau struct dccp_sock *dp = dccp_sk(sk); 767afe00251SAndrea Bittau u8 *spref, slen, *res = NULL; 768afe00251SAndrea Bittau int i, j, rc, agree = 1; 769afe00251SAndrea Bittau 770afe00251SAndrea Bittau BUG_ON(rpref == NULL); 771afe00251SAndrea Bittau 772afe00251SAndrea Bittau /* check if we are the black sheep */ 773afe00251SAndrea Bittau if (dp->dccps_role == DCCP_ROLE_CLIENT) { 774afe00251SAndrea Bittau spref = rpref; 775afe00251SAndrea Bittau slen = rlen; 776afe00251SAndrea Bittau rpref = opt->dccpop_val; 777afe00251SAndrea Bittau rlen = opt->dccpop_len; 778afe00251SAndrea Bittau } else { 779afe00251SAndrea Bittau spref = opt->dccpop_val; 780afe00251SAndrea Bittau slen = opt->dccpop_len; 781afe00251SAndrea Bittau } 782afe00251SAndrea Bittau /* 783afe00251SAndrea Bittau * Now we have server preference list in spref and client preference in 784afe00251SAndrea Bittau * rpref 785afe00251SAndrea Bittau */ 786afe00251SAndrea Bittau BUG_ON(spref == NULL); 787afe00251SAndrea Bittau BUG_ON(rpref == NULL); 788afe00251SAndrea Bittau 789afe00251SAndrea Bittau /* FIXME sanity check vals */ 790afe00251SAndrea Bittau 791afe00251SAndrea Bittau /* Are values in any order? XXX Lame "algorithm" here */ 792afe00251SAndrea Bittau for (i = 0; i < slen; i++) { 793afe00251SAndrea Bittau for (j = 0; j < rlen; j++) { 794afe00251SAndrea Bittau if (spref[i] == rpref[j]) { 795afe00251SAndrea Bittau res = &spref[i]; 796afe00251SAndrea Bittau break; 797afe00251SAndrea Bittau } 798afe00251SAndrea Bittau } 799afe00251SAndrea Bittau if (res) 800afe00251SAndrea Bittau break; 801afe00251SAndrea Bittau } 802afe00251SAndrea Bittau 803afe00251SAndrea Bittau /* we didn't agree on anything */ 804afe00251SAndrea Bittau if (res == NULL) { 805afe00251SAndrea Bittau /* confirm previous value */ 806afe00251SAndrea Bittau switch (opt->dccpop_feat) { 807afe00251SAndrea Bittau case DCCPF_CCID: 808afe00251SAndrea Bittau /* XXX did i get this right? =P */ 809afe00251SAndrea Bittau if (opt->dccpop_type == DCCPO_CHANGE_L) 810a4bf3902SArnaldo Carvalho de Melo res = &dccp_msk(sk)->dccpms_tx_ccid; 811afe00251SAndrea Bittau else 812a4bf3902SArnaldo Carvalho de Melo res = &dccp_msk(sk)->dccpms_rx_ccid; 813afe00251SAndrea Bittau break; 814afe00251SAndrea Bittau 815afe00251SAndrea Bittau default: 81659348b19SGerrit Renker DCCP_BUG("Fell through, feat=%d", opt->dccpop_feat); 81759348b19SGerrit Renker /* XXX implement res */ 818afe00251SAndrea Bittau return -EFAULT; 819afe00251SAndrea Bittau } 820afe00251SAndrea Bittau 821afe00251SAndrea Bittau dccp_pr_debug("Don't agree... reconfirming %d\n", *res); 822afe00251SAndrea Bittau agree = 0; /* this is used for mandatory options... */ 823afe00251SAndrea Bittau } 824afe00251SAndrea Bittau 825afe00251SAndrea Bittau /* need to put result and our preference list */ 826afe00251SAndrea Bittau rlen = 1 + opt->dccpop_len; 827afe00251SAndrea Bittau rpref = kmalloc(rlen, GFP_ATOMIC); 828afe00251SAndrea Bittau if (rpref == NULL) 829afe00251SAndrea Bittau return -ENOMEM; 830afe00251SAndrea Bittau 831afe00251SAndrea Bittau *rpref = *res; 832afe00251SAndrea Bittau memcpy(&rpref[1], opt->dccpop_val, opt->dccpop_len); 833afe00251SAndrea Bittau 834afe00251SAndrea Bittau /* put it in the "confirm queue" */ 835afe00251SAndrea Bittau if (opt->dccpop_sc == NULL) { 836afe00251SAndrea Bittau opt->dccpop_sc = kmalloc(sizeof(*opt->dccpop_sc), GFP_ATOMIC); 837afe00251SAndrea Bittau if (opt->dccpop_sc == NULL) { 838afe00251SAndrea Bittau kfree(rpref); 839afe00251SAndrea Bittau return -ENOMEM; 840afe00251SAndrea Bittau } 841afe00251SAndrea Bittau } else { 842afe00251SAndrea Bittau /* recycle the confirm slot */ 843afe00251SAndrea Bittau BUG_ON(opt->dccpop_sc->dccpoc_val == NULL); 844afe00251SAndrea Bittau kfree(opt->dccpop_sc->dccpoc_val); 845afe00251SAndrea Bittau dccp_pr_debug("recycling confirm slot\n"); 846afe00251SAndrea Bittau } 847afe00251SAndrea Bittau memset(opt->dccpop_sc, 0, sizeof(*opt->dccpop_sc)); 848afe00251SAndrea Bittau 849afe00251SAndrea Bittau opt->dccpop_sc->dccpoc_val = rpref; 850afe00251SAndrea Bittau opt->dccpop_sc->dccpoc_len = rlen; 851afe00251SAndrea Bittau 852afe00251SAndrea Bittau /* update the option on our side [we are about to send the confirm] */ 853afe00251SAndrea Bittau rc = dccp_feat_update(sk, opt->dccpop_type, opt->dccpop_feat, *res); 854afe00251SAndrea Bittau if (rc) { 855afe00251SAndrea Bittau kfree(opt->dccpop_sc->dccpoc_val); 856afe00251SAndrea Bittau kfree(opt->dccpop_sc); 85768907dadSRandy Dunlap opt->dccpop_sc = NULL; 858afe00251SAndrea Bittau return rc; 859afe00251SAndrea Bittau } 860afe00251SAndrea Bittau 861afe00251SAndrea Bittau dccp_pr_debug("Will confirm %d\n", *rpref); 862afe00251SAndrea Bittau 863afe00251SAndrea Bittau /* say we want to change to X but we just got a confirm X, suppress our 864afe00251SAndrea Bittau * change 865afe00251SAndrea Bittau */ 866afe00251SAndrea Bittau if (!opt->dccpop_conf) { 867afe00251SAndrea Bittau if (*opt->dccpop_val == *res) 868afe00251SAndrea Bittau opt->dccpop_conf = 1; 869afe00251SAndrea Bittau dccp_pr_debug("won't ask for change of same feature\n"); 870afe00251SAndrea Bittau } 871afe00251SAndrea Bittau 872afe00251SAndrea Bittau return agree ? 0 : DCCP_FEAT_SP_NOAGREE; /* used for mandatory opts */ 873afe00251SAndrea Bittau } 874afe00251SAndrea Bittau 875afe00251SAndrea Bittau static int dccp_feat_sp(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) 876afe00251SAndrea Bittau { 877a4bf3902SArnaldo Carvalho de Melo struct dccp_minisock *dmsk = dccp_msk(sk); 878afe00251SAndrea Bittau struct dccp_opt_pend *opt; 879afe00251SAndrea Bittau int rc = 1; 880afe00251SAndrea Bittau u8 t; 881afe00251SAndrea Bittau 882afe00251SAndrea Bittau /* 883afe00251SAndrea Bittau * We received a CHANGE. We gotta match it against our own preference 884afe00251SAndrea Bittau * list. If we got a CHANGE_R it means it's a change for us, so we need 885afe00251SAndrea Bittau * to compare our CHANGE_L list. 886afe00251SAndrea Bittau */ 887afe00251SAndrea Bittau if (type == DCCPO_CHANGE_L) 888afe00251SAndrea Bittau t = DCCPO_CHANGE_R; 889afe00251SAndrea Bittau else 890afe00251SAndrea Bittau t = DCCPO_CHANGE_L; 891afe00251SAndrea Bittau 892afe00251SAndrea Bittau /* find our preference list for this feature */ 893a4bf3902SArnaldo Carvalho de Melo list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { 894afe00251SAndrea Bittau if (opt->dccpop_type != t || opt->dccpop_feat != feature) 895afe00251SAndrea Bittau continue; 896afe00251SAndrea Bittau 897afe00251SAndrea Bittau /* find the winner from the two preference lists */ 898afe00251SAndrea Bittau rc = dccp_feat_reconcile(sk, opt, val, len); 899afe00251SAndrea Bittau break; 900afe00251SAndrea Bittau } 901afe00251SAndrea Bittau 902afe00251SAndrea Bittau /* We didn't deal with the change. This can happen if we have no 903afe00251SAndrea Bittau * preference list for the feature. In fact, it just shouldn't 904afe00251SAndrea Bittau * happen---if we understand a feature, we should have a preference list 905afe00251SAndrea Bittau * with at least the default value. 906afe00251SAndrea Bittau */ 907afe00251SAndrea Bittau BUG_ON(rc == 1); 908afe00251SAndrea Bittau 909afe00251SAndrea Bittau return rc; 910afe00251SAndrea Bittau } 911afe00251SAndrea Bittau 912afe00251SAndrea Bittau static int dccp_feat_nn(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) 913afe00251SAndrea Bittau { 914afe00251SAndrea Bittau struct dccp_opt_pend *opt; 915a4bf3902SArnaldo Carvalho de Melo struct dccp_minisock *dmsk = dccp_msk(sk); 916afe00251SAndrea Bittau u8 *copy; 917afe00251SAndrea Bittau int rc; 918afe00251SAndrea Bittau 919c02fdc0eSGerrit Renker /* NN features must be Change L (sec. 6.3.2) */ 920c02fdc0eSGerrit Renker if (type != DCCPO_CHANGE_L) { 921c02fdc0eSGerrit Renker dccp_pr_debug("received %s for NN feature %d\n", 922c02fdc0eSGerrit Renker dccp_feat_typename(type), feature); 923afe00251SAndrea Bittau return -EFAULT; 924afe00251SAndrea Bittau } 925afe00251SAndrea Bittau 926afe00251SAndrea Bittau /* XXX sanity check opt val */ 927afe00251SAndrea Bittau 928afe00251SAndrea Bittau /* copy option so we can confirm it */ 929afe00251SAndrea Bittau opt = kzalloc(sizeof(*opt), GFP_ATOMIC); 930afe00251SAndrea Bittau if (opt == NULL) 931afe00251SAndrea Bittau return -ENOMEM; 932afe00251SAndrea Bittau 933eed73417SArnaldo Carvalho de Melo copy = kmemdup(val, len, GFP_ATOMIC); 934afe00251SAndrea Bittau if (copy == NULL) { 935afe00251SAndrea Bittau kfree(opt); 936afe00251SAndrea Bittau return -ENOMEM; 937afe00251SAndrea Bittau } 938afe00251SAndrea Bittau 939afe00251SAndrea Bittau opt->dccpop_type = DCCPO_CONFIRM_R; /* NN can only confirm R */ 940afe00251SAndrea Bittau opt->dccpop_feat = feature; 941afe00251SAndrea Bittau opt->dccpop_val = copy; 942afe00251SAndrea Bittau opt->dccpop_len = len; 943afe00251SAndrea Bittau 944afe00251SAndrea Bittau /* change feature */ 945afe00251SAndrea Bittau rc = dccp_feat_update(sk, type, feature, *val); 946afe00251SAndrea Bittau if (rc) { 947afe00251SAndrea Bittau kfree(opt->dccpop_val); 948afe00251SAndrea Bittau kfree(opt); 949afe00251SAndrea Bittau return rc; 950afe00251SAndrea Bittau } 951afe00251SAndrea Bittau 952c02fdc0eSGerrit Renker dccp_feat_debug(type, feature, *copy); 953c02fdc0eSGerrit Renker 954a4bf3902SArnaldo Carvalho de Melo list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf); 955afe00251SAndrea Bittau 956afe00251SAndrea Bittau return 0; 957afe00251SAndrea Bittau } 958*75757a7dSGerrit Renker #endif /* (later) */ 959afe00251SAndrea Bittau 9608ca0d17bSArnaldo Carvalho de Melo static void dccp_feat_empty_confirm(struct dccp_minisock *dmsk, 9618ca0d17bSArnaldo Carvalho de Melo u8 type, u8 feature) 962afe00251SAndrea Bittau { 963afe00251SAndrea Bittau /* XXX check if other confirms for that are queued and recycle slot */ 964afe00251SAndrea Bittau struct dccp_opt_pend *opt = kzalloc(sizeof(*opt), GFP_ATOMIC); 965afe00251SAndrea Bittau 966afe00251SAndrea Bittau if (opt == NULL) { 967afe00251SAndrea Bittau /* XXX what do we do? Ignoring should be fine. It's a change 968afe00251SAndrea Bittau * after all =P 969afe00251SAndrea Bittau */ 970afe00251SAndrea Bittau return; 971afe00251SAndrea Bittau } 972afe00251SAndrea Bittau 973c02fdc0eSGerrit Renker switch (type) { 974e576de82SJesper Juhl case DCCPO_CHANGE_L: 975e576de82SJesper Juhl opt->dccpop_type = DCCPO_CONFIRM_R; 976e576de82SJesper Juhl break; 977e576de82SJesper Juhl case DCCPO_CHANGE_R: 978e576de82SJesper Juhl opt->dccpop_type = DCCPO_CONFIRM_L; 979e576de82SJesper Juhl break; 980e576de82SJesper Juhl default: 981e576de82SJesper Juhl DCCP_WARN("invalid type %d\n", type); 982e576de82SJesper Juhl kfree(opt); 983e576de82SJesper Juhl return; 984c02fdc0eSGerrit Renker } 985afe00251SAndrea Bittau opt->dccpop_feat = feature; 98668907dadSRandy Dunlap opt->dccpop_val = NULL; 987afe00251SAndrea Bittau opt->dccpop_len = 0; 988afe00251SAndrea Bittau 989afe00251SAndrea Bittau /* change feature */ 990c02fdc0eSGerrit Renker dccp_pr_debug("Empty %s(%d)\n", dccp_feat_typename(type), feature); 991c02fdc0eSGerrit Renker 992a4bf3902SArnaldo Carvalho de Melo list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf); 993afe00251SAndrea Bittau } 994afe00251SAndrea Bittau 995afe00251SAndrea Bittau static void dccp_feat_flush_confirm(struct sock *sk) 996afe00251SAndrea Bittau { 997a4bf3902SArnaldo Carvalho de Melo struct dccp_minisock *dmsk = dccp_msk(sk); 998afe00251SAndrea Bittau /* Check if there is anything to confirm in the first place */ 999a4bf3902SArnaldo Carvalho de Melo int yes = !list_empty(&dmsk->dccpms_conf); 1000afe00251SAndrea Bittau 1001afe00251SAndrea Bittau if (!yes) { 1002afe00251SAndrea Bittau struct dccp_opt_pend *opt; 1003afe00251SAndrea Bittau 1004a4bf3902SArnaldo Carvalho de Melo list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { 1005afe00251SAndrea Bittau if (opt->dccpop_conf) { 1006afe00251SAndrea Bittau yes = 1; 1007afe00251SAndrea Bittau break; 1008afe00251SAndrea Bittau } 1009afe00251SAndrea Bittau } 1010afe00251SAndrea Bittau } 1011afe00251SAndrea Bittau 1012afe00251SAndrea Bittau if (!yes) 1013afe00251SAndrea Bittau return; 1014afe00251SAndrea Bittau 1015afe00251SAndrea Bittau /* OK there is something to confirm... */ 1016afe00251SAndrea Bittau /* XXX check if packet is in flight? Send delayed ack?? */ 1017afe00251SAndrea Bittau if (sk->sk_state == DCCP_OPEN) 1018afe00251SAndrea Bittau dccp_send_ack(sk); 1019afe00251SAndrea Bittau } 1020afe00251SAndrea Bittau 1021afe00251SAndrea Bittau int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) 1022afe00251SAndrea Bittau { 1023afe00251SAndrea Bittau int rc; 1024afe00251SAndrea Bittau 1025f74e91b6SGerrit Renker /* Ignore Change requests other than during connection setup */ 1026f74e91b6SGerrit Renker if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING) 1027f74e91b6SGerrit Renker return 0; 1028c02fdc0eSGerrit Renker dccp_feat_debug(type, feature, *val); 1029afe00251SAndrea Bittau 1030afe00251SAndrea Bittau /* figure out if it's SP or NN feature */ 1031afe00251SAndrea Bittau switch (feature) { 1032afe00251SAndrea Bittau /* deal with SP features */ 1033afe00251SAndrea Bittau case DCCPF_CCID: 1034*75757a7dSGerrit Renker /* XXX Obsoleted by next patch 1035*75757a7dSGerrit Renker rc = dccp_feat_sp(sk, type, feature, val, len); */ 1036afe00251SAndrea Bittau break; 1037afe00251SAndrea Bittau 1038afe00251SAndrea Bittau /* deal with NN features */ 1039afe00251SAndrea Bittau case DCCPF_ACK_RATIO: 1040*75757a7dSGerrit Renker /* XXX Obsoleted by next patch 1041*75757a7dSGerrit Renker rc = dccp_feat_nn(sk, type, feature, val, len); */ 1042afe00251SAndrea Bittau break; 1043afe00251SAndrea Bittau 1044afe00251SAndrea Bittau /* XXX implement other features */ 1045afe00251SAndrea Bittau default: 1046c02fdc0eSGerrit Renker dccp_pr_debug("UNIMPLEMENTED: not handling %s(%d, ...)\n", 1047c02fdc0eSGerrit Renker dccp_feat_typename(type), feature); 1048afe00251SAndrea Bittau rc = -EFAULT; 1049afe00251SAndrea Bittau break; 1050afe00251SAndrea Bittau } 1051afe00251SAndrea Bittau 1052afe00251SAndrea Bittau /* check if there were problems changing features */ 1053afe00251SAndrea Bittau if (rc) { 1054afe00251SAndrea Bittau /* If we don't agree on SP, we sent a confirm for old value. 1055afe00251SAndrea Bittau * However we propagate rc to caller in case option was 1056afe00251SAndrea Bittau * mandatory 1057afe00251SAndrea Bittau */ 1058afe00251SAndrea Bittau if (rc != DCCP_FEAT_SP_NOAGREE) 10598ca0d17bSArnaldo Carvalho de Melo dccp_feat_empty_confirm(dccp_msk(sk), type, feature); 1060afe00251SAndrea Bittau } 1061afe00251SAndrea Bittau 1062afe00251SAndrea Bittau /* generate the confirm [if required] */ 1063afe00251SAndrea Bittau dccp_feat_flush_confirm(sk); 1064afe00251SAndrea Bittau 1065afe00251SAndrea Bittau return rc; 1066afe00251SAndrea Bittau } 1067afe00251SAndrea Bittau 1068afe00251SAndrea Bittau EXPORT_SYMBOL_GPL(dccp_feat_change_recv); 1069afe00251SAndrea Bittau 1070afe00251SAndrea Bittau int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, 1071afe00251SAndrea Bittau u8 *val, u8 len) 1072afe00251SAndrea Bittau { 1073afe00251SAndrea Bittau u8 t; 1074afe00251SAndrea Bittau struct dccp_opt_pend *opt; 1075a4bf3902SArnaldo Carvalho de Melo struct dccp_minisock *dmsk = dccp_msk(sk); 1076c02fdc0eSGerrit Renker int found = 0; 1077afe00251SAndrea Bittau int all_confirmed = 1; 1078afe00251SAndrea Bittau 1079f74e91b6SGerrit Renker /* Ignore Confirm options other than during connection setup */ 1080f74e91b6SGerrit Renker if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING) 1081f74e91b6SGerrit Renker return 0; 1082c02fdc0eSGerrit Renker dccp_feat_debug(type, feature, *val); 1083afe00251SAndrea Bittau 1084afe00251SAndrea Bittau /* locate our change request */ 1085c02fdc0eSGerrit Renker switch (type) { 1086c02fdc0eSGerrit Renker case DCCPO_CONFIRM_L: t = DCCPO_CHANGE_R; break; 1087c02fdc0eSGerrit Renker case DCCPO_CONFIRM_R: t = DCCPO_CHANGE_L; break; 108859348b19SGerrit Renker default: DCCP_WARN("invalid type %d\n", type); 1089c02fdc0eSGerrit Renker return 1; 1090c02fdc0eSGerrit Renker 1091c02fdc0eSGerrit Renker } 1092c02fdc0eSGerrit Renker /* XXX sanity check feature value */ 1093afe00251SAndrea Bittau 1094a4bf3902SArnaldo Carvalho de Melo list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { 1095afe00251SAndrea Bittau if (!opt->dccpop_conf && opt->dccpop_type == t && 1096afe00251SAndrea Bittau opt->dccpop_feat == feature) { 1097c02fdc0eSGerrit Renker found = 1; 1098c02fdc0eSGerrit Renker dccp_pr_debug("feature %d found\n", opt->dccpop_feat); 1099c02fdc0eSGerrit Renker 1100afe00251SAndrea Bittau /* XXX do sanity check */ 1101afe00251SAndrea Bittau 1102afe00251SAndrea Bittau opt->dccpop_conf = 1; 1103afe00251SAndrea Bittau 1104afe00251SAndrea Bittau /* We got a confirmation---change the option */ 1105afe00251SAndrea Bittau dccp_feat_update(sk, opt->dccpop_type, 1106afe00251SAndrea Bittau opt->dccpop_feat, *val); 1107afe00251SAndrea Bittau 1108c02fdc0eSGerrit Renker /* XXX check the return value of dccp_feat_update */ 1109afe00251SAndrea Bittau break; 1110afe00251SAndrea Bittau } 1111afe00251SAndrea Bittau 1112afe00251SAndrea Bittau if (!opt->dccpop_conf) 1113afe00251SAndrea Bittau all_confirmed = 0; 1114afe00251SAndrea Bittau } 1115afe00251SAndrea Bittau 1116c02fdc0eSGerrit Renker if (!found) 1117c02fdc0eSGerrit Renker dccp_pr_debug("%s(%d, ...) never requested\n", 1118c02fdc0eSGerrit Renker dccp_feat_typename(type), feature); 1119afe00251SAndrea Bittau return 0; 1120afe00251SAndrea Bittau } 1121afe00251SAndrea Bittau 1122afe00251SAndrea Bittau EXPORT_SYMBOL_GPL(dccp_feat_confirm_recv); 1123afe00251SAndrea Bittau 11248ca0d17bSArnaldo Carvalho de Melo void dccp_feat_clean(struct dccp_minisock *dmsk) 1125afe00251SAndrea Bittau { 1126afe00251SAndrea Bittau struct dccp_opt_pend *opt, *next; 1127afe00251SAndrea Bittau 1128a4bf3902SArnaldo Carvalho de Melo list_for_each_entry_safe(opt, next, &dmsk->dccpms_pending, 1129afe00251SAndrea Bittau dccpop_node) { 1130afe00251SAndrea Bittau BUG_ON(opt->dccpop_val == NULL); 1131afe00251SAndrea Bittau kfree(opt->dccpop_val); 1132afe00251SAndrea Bittau 1133afe00251SAndrea Bittau if (opt->dccpop_sc != NULL) { 1134afe00251SAndrea Bittau BUG_ON(opt->dccpop_sc->dccpoc_val == NULL); 1135afe00251SAndrea Bittau kfree(opt->dccpop_sc->dccpoc_val); 1136afe00251SAndrea Bittau kfree(opt->dccpop_sc); 1137afe00251SAndrea Bittau } 1138afe00251SAndrea Bittau 1139afe00251SAndrea Bittau kfree(opt); 1140afe00251SAndrea Bittau } 1141a4bf3902SArnaldo Carvalho de Melo INIT_LIST_HEAD(&dmsk->dccpms_pending); 1142afe00251SAndrea Bittau 1143a4bf3902SArnaldo Carvalho de Melo list_for_each_entry_safe(opt, next, &dmsk->dccpms_conf, dccpop_node) { 1144afe00251SAndrea Bittau BUG_ON(opt == NULL); 1145afe00251SAndrea Bittau if (opt->dccpop_val != NULL) 1146afe00251SAndrea Bittau kfree(opt->dccpop_val); 1147afe00251SAndrea Bittau kfree(opt); 1148afe00251SAndrea Bittau } 1149a4bf3902SArnaldo Carvalho de Melo INIT_LIST_HEAD(&dmsk->dccpms_conf); 1150afe00251SAndrea Bittau } 1151afe00251SAndrea Bittau 1152afe00251SAndrea Bittau EXPORT_SYMBOL_GPL(dccp_feat_clean); 1153afe00251SAndrea Bittau 1154afe00251SAndrea Bittau /* this is to be called only when a listening sock creates its child. It is 1155afe00251SAndrea Bittau * assumed by the function---the confirm is not duplicated, but rather it is 1156afe00251SAndrea Bittau * "passed on". 1157afe00251SAndrea Bittau */ 1158afe00251SAndrea Bittau int dccp_feat_clone(struct sock *oldsk, struct sock *newsk) 1159afe00251SAndrea Bittau { 1160a4bf3902SArnaldo Carvalho de Melo struct dccp_minisock *olddmsk = dccp_msk(oldsk); 1161a4bf3902SArnaldo Carvalho de Melo struct dccp_minisock *newdmsk = dccp_msk(newsk); 1162afe00251SAndrea Bittau struct dccp_opt_pend *opt; 1163afe00251SAndrea Bittau int rc = 0; 1164afe00251SAndrea Bittau 1165a4bf3902SArnaldo Carvalho de Melo INIT_LIST_HEAD(&newdmsk->dccpms_pending); 1166a4bf3902SArnaldo Carvalho de Melo INIT_LIST_HEAD(&newdmsk->dccpms_conf); 1167afe00251SAndrea Bittau 1168a4bf3902SArnaldo Carvalho de Melo list_for_each_entry(opt, &olddmsk->dccpms_pending, dccpop_node) { 1169afe00251SAndrea Bittau struct dccp_opt_pend *newopt; 1170afe00251SAndrea Bittau /* copy the value of the option */ 1171eed73417SArnaldo Carvalho de Melo u8 *val = kmemdup(opt->dccpop_val, opt->dccpop_len, GFP_ATOMIC); 1172afe00251SAndrea Bittau 1173afe00251SAndrea Bittau if (val == NULL) 1174afe00251SAndrea Bittau goto out_clean; 1175afe00251SAndrea Bittau 1176eed73417SArnaldo Carvalho de Melo newopt = kmemdup(opt, sizeof(*newopt), GFP_ATOMIC); 1177afe00251SAndrea Bittau if (newopt == NULL) { 1178afe00251SAndrea Bittau kfree(val); 1179afe00251SAndrea Bittau goto out_clean; 1180afe00251SAndrea Bittau } 1181afe00251SAndrea Bittau 1182afe00251SAndrea Bittau /* insert the option */ 1183afe00251SAndrea Bittau newopt->dccpop_val = val; 1184a4bf3902SArnaldo Carvalho de Melo list_add_tail(&newopt->dccpop_node, &newdmsk->dccpms_pending); 1185afe00251SAndrea Bittau 1186afe00251SAndrea Bittau /* XXX what happens with backlogs and multiple connections at 1187afe00251SAndrea Bittau * once... 1188afe00251SAndrea Bittau */ 1189afe00251SAndrea Bittau /* the master socket no longer needs to worry about confirms */ 119068907dadSRandy Dunlap opt->dccpop_sc = NULL; /* it's not a memleak---new socket has it */ 1191afe00251SAndrea Bittau 1192afe00251SAndrea Bittau /* reset state for a new socket */ 1193afe00251SAndrea Bittau opt->dccpop_conf = 0; 1194afe00251SAndrea Bittau } 1195afe00251SAndrea Bittau 1196afe00251SAndrea Bittau /* XXX not doing anything about the conf queue */ 1197afe00251SAndrea Bittau 1198afe00251SAndrea Bittau out: 1199afe00251SAndrea Bittau return rc; 1200afe00251SAndrea Bittau 1201afe00251SAndrea Bittau out_clean: 12028ca0d17bSArnaldo Carvalho de Melo dccp_feat_clean(newdmsk); 1203afe00251SAndrea Bittau rc = -ENOMEM; 1204afe00251SAndrea Bittau goto out; 1205afe00251SAndrea Bittau } 1206afe00251SAndrea Bittau 1207afe00251SAndrea Bittau EXPORT_SYMBOL_GPL(dccp_feat_clone); 1208afe00251SAndrea Bittau 1209e8ef967aSGerrit Renker int dccp_feat_init(struct sock *sk) 1210afe00251SAndrea Bittau { 1211e8ef967aSGerrit Renker struct dccp_sock *dp = dccp_sk(sk); 1212e8ef967aSGerrit Renker struct dccp_minisock *dmsk = dccp_msk(sk); 1213afe00251SAndrea Bittau int rc; 1214afe00251SAndrea Bittau 1215e8ef967aSGerrit Renker INIT_LIST_HEAD(&dmsk->dccpms_pending); /* XXX no longer used */ 1216e8ef967aSGerrit Renker INIT_LIST_HEAD(&dmsk->dccpms_conf); /* XXX no longer used */ 1217afe00251SAndrea Bittau 1218afe00251SAndrea Bittau /* CCID L */ 1219e8ef967aSGerrit Renker rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 1, 0, 1220a4bf3902SArnaldo Carvalho de Melo &dmsk->dccpms_tx_ccid, 1); 1221afe00251SAndrea Bittau if (rc) 1222afe00251SAndrea Bittau goto out; 1223afe00251SAndrea Bittau 1224afe00251SAndrea Bittau /* CCID R */ 1225e8ef967aSGerrit Renker rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 0, 0, 1226a4bf3902SArnaldo Carvalho de Melo &dmsk->dccpms_rx_ccid, 1); 1227afe00251SAndrea Bittau if (rc) 1228afe00251SAndrea Bittau goto out; 1229afe00251SAndrea Bittau 1230afe00251SAndrea Bittau /* Ack ratio */ 1231e8ef967aSGerrit Renker rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0, 123249aebc66SGerrit Renker dp->dccps_l_ack_ratio); 1233afe00251SAndrea Bittau out: 1234afe00251SAndrea Bittau return rc; 1235afe00251SAndrea Bittau } 1236afe00251SAndrea Bittau 1237afe00251SAndrea Bittau EXPORT_SYMBOL_GPL(dccp_feat_init); 1238c02fdc0eSGerrit Renker 1239c02fdc0eSGerrit Renker #ifdef CONFIG_IP_DCCP_DEBUG 1240c02fdc0eSGerrit Renker const char *dccp_feat_typename(const u8 type) 1241c02fdc0eSGerrit Renker { 1242c02fdc0eSGerrit Renker switch(type) { 1243c02fdc0eSGerrit Renker case DCCPO_CHANGE_L: return("ChangeL"); 1244c02fdc0eSGerrit Renker case DCCPO_CONFIRM_L: return("ConfirmL"); 1245c02fdc0eSGerrit Renker case DCCPO_CHANGE_R: return("ChangeR"); 1246c02fdc0eSGerrit Renker case DCCPO_CONFIRM_R: return("ConfirmR"); 1247c02fdc0eSGerrit Renker /* the following case must not appear in feature negotation */ 1248c02fdc0eSGerrit Renker default: dccp_pr_debug("unknown type %d [BUG!]\n", type); 1249c02fdc0eSGerrit Renker } 1250c02fdc0eSGerrit Renker return NULL; 1251c02fdc0eSGerrit Renker } 1252c02fdc0eSGerrit Renker 1253c02fdc0eSGerrit Renker EXPORT_SYMBOL_GPL(dccp_feat_typename); 1254c02fdc0eSGerrit Renker 1255c02fdc0eSGerrit Renker const char *dccp_feat_name(const u8 feat) 1256c02fdc0eSGerrit Renker { 1257c02fdc0eSGerrit Renker static const char *feature_names[] = { 1258c02fdc0eSGerrit Renker [DCCPF_RESERVED] = "Reserved", 1259c02fdc0eSGerrit Renker [DCCPF_CCID] = "CCID", 1260c02fdc0eSGerrit Renker [DCCPF_SHORT_SEQNOS] = "Allow Short Seqnos", 1261c02fdc0eSGerrit Renker [DCCPF_SEQUENCE_WINDOW] = "Sequence Window", 1262c02fdc0eSGerrit Renker [DCCPF_ECN_INCAPABLE] = "ECN Incapable", 1263c02fdc0eSGerrit Renker [DCCPF_ACK_RATIO] = "Ack Ratio", 1264c02fdc0eSGerrit Renker [DCCPF_SEND_ACK_VECTOR] = "Send ACK Vector", 1265c02fdc0eSGerrit Renker [DCCPF_SEND_NDP_COUNT] = "Send NDP Count", 1266c02fdc0eSGerrit Renker [DCCPF_MIN_CSUM_COVER] = "Min. Csum Coverage", 1267c02fdc0eSGerrit Renker [DCCPF_DATA_CHECKSUM] = "Send Data Checksum", 1268c02fdc0eSGerrit Renker }; 1269dd6303dfSGerrit Renker if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC) 1270dd6303dfSGerrit Renker return feature_names[DCCPF_RESERVED]; 1271dd6303dfSGerrit Renker 12727d43d1a0SGerrit Renker if (feat == DCCPF_SEND_LEV_RATE) 12737d43d1a0SGerrit Renker return "Send Loss Event Rate"; 1274c02fdc0eSGerrit Renker if (feat >= DCCPF_MIN_CCID_SPECIFIC) 1275c02fdc0eSGerrit Renker return "CCID-specific"; 1276c02fdc0eSGerrit Renker 1277c02fdc0eSGerrit Renker return feature_names[feat]; 1278c02fdc0eSGerrit Renker } 1279c02fdc0eSGerrit Renker 1280c02fdc0eSGerrit Renker EXPORT_SYMBOL_GPL(dccp_feat_name); 1281c02fdc0eSGerrit Renker #endif /* CONFIG_IP_DCCP_DEBUG */ 1282