tproxy: split off ipv6 defragmentation to a separate module
[linux-2.6.git] / net / dccp / feat.c
index f94c7c9..df7dd26 100644 (file)
@@ -3,7 +3,6 @@
  *
  *  Feature negotiation for the DCCP protocol (RFC 4340, section 6)
  *
- *  Copyright (c) 2008 The University of Aberdeen, Scotland, UK
  *  Copyright (c) 2008 Gerrit Renker <gerrit@erg.abdn.ac.uk>
  *  Rewrote from scratch, some bits from earlier code by
  *  Copyright (c) 2005 Andrea Bittau <a.bittau@cs.ucl.ac.uk>
@@ -13,7 +12,6 @@
  *  -----------
  *  o Feature negotiation is coordinated with connection setup (as in TCP), wild
  *    changes of parameters of an established connection are not supported.
- *  o Changing NN values (Ack Ratio only) is supported in state OPEN/PARTOPEN.
  *  o All currently known SP features have 1-byte quantities. If in the future
  *    extensions of RFCs 4340..42 define features with item lengths larger than
  *    one byte, a feature-specific extension of the code will be required.
@@ -24,6 +22,7 @@
  *  2 of the License, or (at your option) any later version.
  */
 #include <linux/module.h>
+#include <linux/slab.h>
 #include "ccid.h"
 #include "feat.h"
 
@@ -41,7 +40,7 @@ int           sysctl_dccp_rx_ccid         __read_mostly = 2,
 static int dccp_hdlr_ccid(struct sock *sk, u64 ccid, bool rx)
 {
        struct dccp_sock *dp = dccp_sk(sk);
-       struct ccid *new_ccid = ccid_new(ccid, sk, rx, gfp_any());
+       struct ccid *new_ccid = ccid_new(ccid, sk, rx);
 
        if (new_ccid == NULL)
                return -ENOMEM;
@@ -74,18 +73,6 @@ static int dccp_hdlr_seq_win(struct sock *sk, u64 seq_win, bool rx)
 
 static int dccp_hdlr_ack_ratio(struct sock *sk, u64 ratio, bool rx)
 {
-#ifndef __CCID2_COPES_GRACEFULLY_WITH_DYNAMIC_ACK_RATIO_UPDATES__
-       /*
-        * FIXME: This is required until several problems in the CCID-2 code are
-        * resolved. The CCID-2 code currently does not cope well; using dynamic
-        * Ack Ratios greater than 1 caused instabilities. These were manifest
-        * in hangups and long RTO timeouts (1...3 seconds). Until this has been
-        * stabilised, it is safer not to activate dynamic Ack Ratio changes.
-        */
-       dccp_pr_debug("Not changing %s Ack Ratio from 1 to %u\n",
-                     rx ? "RX" : "TX", (u16)ratio);
-       ratio = 1;
-#endif
        if (rx)
                dccp_sk(sk)->dccps_r_ack_ratio = ratio;
        else
@@ -213,8 +200,13 @@ static u8 dccp_feat_type(u8 feat_num)
 static int dccp_feat_default_value(u8 feat_num)
 {
        int idx = dccp_feat_index(feat_num);
+       /*
+        * There are no default values for unknown features, so encountering a
+        * negative index here indicates a serious problem somewhere else.
+        */
+       DCCP_BUG_ON(idx < 0);
 
-       return idx < 0 ? : dccp_feat_table[idx].default_value;
+       return idx < 0 ? 0 : dccp_feat_table[idx].default_value;
 }
 
 /*
@@ -222,7 +214,7 @@ static int dccp_feat_default_value(u8 feat_num)
  */
 static const char *dccp_feat_fname(const u8 feat)
 {
-       static const char *feature_names[] = {
+       static const char *const feature_names[] = {
                [DCCPF_RESERVED]        = "Reserved",
                [DCCPF_CCID]            = "CCID",
                [DCCPF_SHORT_SEQNOS]    = "Allow Short Seqnos",
@@ -245,8 +237,9 @@ static const char *dccp_feat_fname(const u8 feat)
        return feature_names[feat];
 }
 
-static const char *dccp_feat_sname[] = { "DEFAULT", "INITIALISING", "CHANGING",
-                                        "UNSTABLE", "STABLE" };
+static const char *const dccp_feat_sname[] = {
+       "DEFAULT", "INITIALISING", "CHANGING", "UNSTABLE", "STABLE",
+};
 
 #ifdef CONFIG_IP_DCCP_DEBUG
 static const char *dccp_feat_oname(const u8 opt)
@@ -350,20 +343,6 @@ static int __dccp_feat_activate(struct sock *sk, const int idx,
        return dccp_feat_table[idx].activation_hdlr(sk, val, rx);
 }
 
-/**
- * dccp_feat_activate  -  Activate feature value on socket
- * @sk: fully connected DCCP socket (after handshake is complete)
- * @feat_num: feature to activate, one of %dccp_feature_numbers
- * @local: whether local (1) or remote (0) @feat_num is meant
- * @fval: the value (SP or NN) to activate, or NULL to use the default value
- * For general use this function is preferable over __dccp_feat_activate().
- */
-static int dccp_feat_activate(struct sock *sk, u8 feat_num, bool local,
-                             dccp_feat_val const *fval)
-{
-       return __dccp_feat_activate(sk, dccp_feat_index(feat_num), local, fval);
-}
-
 /* Test for "Req'd" feature (RFC 4340, 6.4) */
 static inline int dccp_feat_must_be_understood(u8 feat_num)
 {
@@ -438,11 +417,12 @@ static struct dccp_feat_entry *dccp_feat_list_lookup(struct list_head *fn_list,
 {
        struct dccp_feat_entry *entry;
 
-       list_for_each_entry(entry, fn_list, node)
+       list_for_each_entry(entry, fn_list, node) {
                if (entry->feat_num == feat_num && entry->is_local == is_local)
                        return entry;
                else if (entry->feat_num > feat_num)
                        break;
+       }
        return NULL;
 }
 
@@ -761,48 +741,6 @@ int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val)
        return __feat_register_nn(&dccp_sk(sk)->dccps_featneg, feat, 0, val);
 }
 
-/**
- * dccp_feat_signal_nn_change  -  Update NN values for an established connection
- * @sk: DCCP socket of an established connection
- * @feat: NN feature number from %dccp_feature_numbers
- * @nn_val: the new value to use
- * This function is used to communicate NN updates out-of-band. The difference
- * to feature negotiation during connection setup is that values are activated
- * immediately after validation, i.e. we don't wait for the Confirm: either the
- * value is accepted by the peer (and then the waiting is futile), or it is not
- * (Reset or empty Confirm). We don't accept empty Confirms - transmitted values
- * are validated, and the peer "MUST accept any valid value" (RFC 4340, 6.3.2).
- */
-int dccp_feat_signal_nn_change(struct sock *sk, u8 feat, u64 nn_val)
-{
-       struct list_head *fn = &dccp_sk(sk)->dccps_featneg;
-       dccp_feat_val fval = { .nn = nn_val };
-       struct dccp_feat_entry *entry;
-
-       if (sk->sk_state != DCCP_OPEN && sk->sk_state != DCCP_PARTOPEN)
-               return 0;
-
-       if (dccp_feat_type(feat) != FEAT_NN ||
-           !dccp_feat_is_valid_nn_val(feat, nn_val))
-               return -EINVAL;
-
-       entry = dccp_feat_list_lookup(fn, feat, 1);
-       if (entry != NULL) {
-               dccp_pr_debug("Ignoring %llu, entry %llu exists in state %s\n",
-                             (unsigned long long)nn_val,
-                             (unsigned long long)entry->val.nn,
-                             dccp_feat_sname[entry->state]);
-               return 0;
-       }
-
-       if (dccp_feat_activate(sk, feat, 1, &fval))
-               return -EADV;
-
-       inet_csk_schedule_ack(sk);
-       return dccp_feat_push_change(fn, feat, 1, 0, &fval);
-}
-EXPORT_SYMBOL_GPL(dccp_feat_signal_nn_change);
-
 /*
  *     Tracking features whose value depend on the choice of CCID
  *
@@ -1259,93 +1197,6 @@ confirmation_failed:
 }
 
 /**
- * dccp_feat_handle_nn_established  -  Fast-path reception of NN options
- * @sk:                socket of an established DCCP connection
- * @mandatory: whether @opt was preceded by a Mandatory option
- * @opt:       %DCCPO_CHANGE_L | %DCCPO_CONFIRM_R (NN only)
- * @feat:      NN number, one of %dccp_feature_numbers
- * @val:       NN value
- * @len:       length of @val in bytes
- * This function combines the functionality of change_recv/confirm_recv, with
- * the following differences (reset codes are the same):
- *    - cleanup after receiving the Confirm;
- *    - values are directly activated after successful parsing;
- *    - deliberately restricted to NN features.
- * The restriction to NN features is essential since SP features can have non-
- * predictable outcomes (depending on the remote configuration), and are inter-
- * dependent (CCIDs for instance cause further dependencies).
- */
-static u8 dccp_feat_handle_nn_established(struct sock *sk, u8 mandatory, u8 opt,
-                                         u8 feat, u8 *val, u8 len)
-{
-       struct list_head *fn = &dccp_sk(sk)->dccps_featneg;
-       const bool local = (opt == DCCPO_CONFIRM_R);
-       struct dccp_feat_entry *entry;
-       u8 type = dccp_feat_type(feat);
-       dccp_feat_val fval;
-
-       dccp_feat_print_opt(opt, feat, val, len, mandatory);
-
-       /* Ignore non-mandatory unknown and non-NN features */
-       if (type == FEAT_UNKNOWN) {
-               if (local && !mandatory)
-                       return 0;
-               goto fast_path_unknown;
-       } else if (type != FEAT_NN) {
-               return 0;
-       }
-
-       /*
-        * We don't accept empty Confirms, since in fast-path feature
-        * negotiation the values are enabled immediately after sending
-        * the Change option.
-        * Empty Changes on the other hand are invalid (RFC 4340, 6.1).
-        */
-       if (len == 0 || len > sizeof(fval.nn))
-               goto fast_path_unknown;
-
-       if (opt == DCCPO_CHANGE_L) {
-               fval.nn = dccp_decode_value_var(val, len);
-               if (!dccp_feat_is_valid_nn_val(feat, fval.nn))
-                       goto fast_path_unknown;
-
-               if (dccp_feat_push_confirm(fn, feat, local, &fval) ||
-                   dccp_feat_activate(sk, feat, local, &fval))
-                       return DCCP_RESET_CODE_TOO_BUSY;
-
-               /* set the `Ack Pending' flag to piggyback a Confirm */
-               inet_csk_schedule_ack(sk);
-
-       } else if (opt == DCCPO_CONFIRM_R) {
-               entry = dccp_feat_list_lookup(fn, feat, local);
-               if (entry == NULL || entry->state != FEAT_CHANGING)
-                       return 0;
-
-               fval.nn = dccp_decode_value_var(val, len);
-               if (fval.nn != entry->val.nn) {
-                       DCCP_WARN("Bogus Confirm for non-existing value\n");
-                       goto fast_path_failed;
-               }
-
-               /* It has been confirmed - so remove the entry */
-               dccp_feat_list_pop(entry);
-
-       } else {
-               DCCP_WARN("Received illegal option %u\n", opt);
-               goto fast_path_failed;
-       }
-       return 0;
-
-fast_path_unknown:
-       if (!mandatory)
-               return dccp_push_empty_confirm(fn, feat, local);
-
-fast_path_failed:
-       return mandatory ? DCCP_RESET_CODE_MANDATORY_ERROR
-                        : DCCP_RESET_CODE_OPTION_ERROR;
-}
-
-/**
  * dccp_feat_parse_options  -  Process Feature-Negotiation Options
  * @sk: for general use and used by the client during connection setup
  * @dreq: used by the server during connection setup
@@ -1380,15 +1231,6 @@ int dccp_feat_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
                        return dccp_feat_confirm_recv(fn, mandatory, opt, feat,
                                                      val, len, server);
                }
-               break;
-       /*
-        *      Support for exchanging NN options on an established connection
-        *      This is currently restricted to Ack Ratio (RFC 4341, 6.1.2)
-        */
-       case DCCP_OPEN:
-       case DCCP_PARTOPEN:
-               return dccp_feat_handle_nn_established(sk, mandatory, opt, feat,
-                                                      val, len);
        }
        return 0;       /* ignore FN options in all other states */
 }
@@ -1441,11 +1283,6 @@ int dccp_feat_init(struct sock *sk)
            ccid_get_builtin_ccids(&rx.val, &rx.len))
                return -ENOBUFS;
 
-       /* Pre-load all CCID modules that are going to be advertised */
-       rc = -EUNATCH;
-       if (ccid_request_modules(tx.val, tx.len))
-               goto free_ccid_lists;
-
        if (!dccp_feat_prefer(sysctl_dccp_tx_ccid, tx.val, tx.len) ||
            !dccp_feat_prefer(sysctl_dccp_rx_ccid, rx.val, rx.len))
                goto free_ccid_lists;