]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - net/dccp/feat.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/shaggy...
[karo-tx-linux.git] / net / dccp / feat.c
index 99d7b7f9efa92422c4eb083910524b622a1bba80..a1b0682ee77c7f9af2b72dae2afb38f4decd9f97 100644 (file)
  *      2 of the License, or (at your option) any later version.
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 
 #include "dccp.h"
+#include "ccid.h"
 #include "feat.h"
 
 #define DCCP_FEAT_SP_NOAGREE (-123)
 
-int dccp_feat_change(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len,
-                    gfp_t gfp)
+int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
+                    u8 *val, u8 len, gfp_t gfp)
 {
-       struct dccp_sock *dp = dccp_sk(sk);
        struct dccp_opt_pend *opt;
 
        dccp_pr_debug("feat change type=%d feat=%d\n", type, feature);
 
+       /* XXX sanity check feat change request */
+
        /* check if that feature is already being negotiated */
-       list_for_each_entry(opt, &dp->dccps_options.dccpo_pending,
-                           dccpop_node) {
+       list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
                /* ok we found a negotiation for this option already */
                if (opt->dccpop_feat == feature && opt->dccpop_type == type) {
                        dccp_pr_debug("Replacing old\n");
@@ -56,17 +56,55 @@ int dccp_feat_change(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len,
 
        BUG_ON(opt->dccpop_val == NULL);
 
-       list_add_tail(&opt->dccpop_node, &dp->dccps_options.dccpo_pending);
+       list_add_tail(&opt->dccpop_node, &dmsk->dccpms_pending);
        return 0;
 }
 
 EXPORT_SYMBOL_GPL(dccp_feat_change);
 
+static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+       struct dccp_minisock *dmsk = dccp_msk(sk);
+       /* figure out if we are changing our CCID or the peer's */
+       const int rx = type == DCCPO_CHANGE_R;
+       const u8 ccid_nr = rx ? dmsk->dccpms_rx_ccid : dmsk->dccpms_tx_ccid;
+       struct ccid *new_ccid;
+
+       /* Check if nothing is being changed. */
+       if (ccid_nr == new_ccid_nr)
+               return 0;
+
+       new_ccid = ccid_new(new_ccid_nr, sk, rx, GFP_ATOMIC);
+       if (new_ccid == NULL)
+               return -ENOMEM;
+
+       if (rx) {
+               ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
+               dp->dccps_hc_rx_ccid = new_ccid;
+               dmsk->dccpms_rx_ccid = new_ccid_nr;
+       } else {
+               ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
+               dp->dccps_hc_tx_ccid = new_ccid;
+               dmsk->dccpms_tx_ccid = new_ccid_nr;
+       }
+
+       return 0;
+}
+
 /* XXX taking only u8 vals */
 static int dccp_feat_update(struct sock *sk, u8 type, u8 feat, u8 val)
 {
-       /* FIXME implement */
        dccp_pr_debug("changing [%d] feat %d to %d\n", type, feat, val);
+
+       switch (feat) {
+       case DCCPF_CCID:
+               return dccp_feat_update_ccid(sk, type, val);
+       default:
+               dccp_pr_debug("IMPLEMENT changing [%d] feat %d to %d\n",
+                             type, feat, val);
+               break;
+       }
        return 0;
 }
 
@@ -118,9 +156,9 @@ static int dccp_feat_reconcile(struct sock *sk, struct dccp_opt_pend *opt,
                case DCCPF_CCID:
                        /* XXX did i get this right? =P */
                        if (opt->dccpop_type == DCCPO_CHANGE_L)
-                               res = &dp->dccps_options.dccpo_tx_ccid;
+                               res = &dccp_msk(sk)->dccpms_tx_ccid;
                        else
-                               res = &dp->dccps_options.dccpo_rx_ccid;
+                               res = &dccp_msk(sk)->dccpms_rx_ccid;
                        break;
 
                default:
@@ -165,7 +203,7 @@ static int dccp_feat_reconcile(struct sock *sk, struct dccp_opt_pend *opt,
        if (rc) {
                kfree(opt->dccpop_sc->dccpoc_val);
                kfree(opt->dccpop_sc);
-               opt->dccpop_sc = 0;
+               opt->dccpop_sc = NULL;
                return rc;
        }
 
@@ -185,7 +223,7 @@ static int dccp_feat_reconcile(struct sock *sk, struct dccp_opt_pend *opt,
 
 static int dccp_feat_sp(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
 {
-       struct dccp_sock *dp = dccp_sk(sk);
+       struct dccp_minisock *dmsk = dccp_msk(sk);
        struct dccp_opt_pend *opt;
        int rc = 1;
        u8 t;
@@ -201,8 +239,7 @@ static int dccp_feat_sp(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
                t = DCCPO_CHANGE_L;
 
        /* find our preference list for this feature */
-       list_for_each_entry(opt, &dp->dccps_options.dccpo_pending,
-                           dccpop_node) {
+       list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
                if (opt->dccpop_type != t || opt->dccpop_feat != feature)
                        continue;
 
@@ -224,7 +261,7 @@ static int dccp_feat_sp(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
 static int dccp_feat_nn(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
 {
        struct dccp_opt_pend *opt;
-       struct dccp_sock *dp = dccp_sk(sk);
+       struct dccp_minisock *dmsk = dccp_msk(sk);
        u8 *copy;
        int rc;
 
@@ -263,14 +300,14 @@ static int dccp_feat_nn(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
        }
 
        dccp_pr_debug("Confirming NN feature %d (val=%d)\n", feature, *copy);
-       list_add_tail(&opt->dccpop_node, &dp->dccps_options.dccpo_conf);
+       list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf);
 
        return 0;
 }
 
-static void dccp_feat_empty_confirm(struct sock *sk, u8 type, u8 feature)
+static void dccp_feat_empty_confirm(struct dccp_minisock *dmsk,
+                                   u8 type, u8 feature)
 {
-       struct dccp_sock *dp = dccp_sk(sk);
        /* XXX check if other confirms for that are queued and recycle slot */
        struct dccp_opt_pend *opt = kzalloc(sizeof(*opt), GFP_ATOMIC);
 
@@ -284,25 +321,24 @@ static void dccp_feat_empty_confirm(struct sock *sk, u8 type, u8 feature)
        opt->dccpop_type = type == DCCPO_CHANGE_L ? DCCPO_CONFIRM_R :
                                                    DCCPO_CONFIRM_L;
        opt->dccpop_feat = feature;
-       opt->dccpop_val  = 0;
+       opt->dccpop_val  = NULL;
        opt->dccpop_len  = 0;
 
        /* change feature */
        dccp_pr_debug("Empty confirm feature %d type %d\n", feature, type);
-       list_add_tail(&opt->dccpop_node, &dp->dccps_options.dccpo_conf);
+       list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf);
 }
 
 static void dccp_feat_flush_confirm(struct sock *sk)
 {
-       struct dccp_sock *dp = dccp_sk(sk);
+       struct dccp_minisock *dmsk = dccp_msk(sk);
        /* Check if there is anything to confirm in the first place */
-       int yes = !list_empty(&dp->dccps_options.dccpo_conf);
+       int yes = !list_empty(&dmsk->dccpms_conf);
 
        if (!yes) {
                struct dccp_opt_pend *opt;
 
-               list_for_each_entry(opt, &dp->dccps_options.dccpo_pending,
-                                   dccpop_node) {
+               list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
                        if (opt->dccpop_conf) {
                                yes = 1;
                                break;
@@ -350,7 +386,7 @@ int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
                 * mandatory
                 */
                if (rc != DCCP_FEAT_SP_NOAGREE)
-                       dccp_feat_empty_confirm(sk, type, feature);
+                       dccp_feat_empty_confirm(dccp_msk(sk), type, feature);
        }
 
        /* generate the confirm [if required] */
@@ -366,7 +402,7 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 {
        u8 t;
        struct dccp_opt_pend *opt;
-       struct dccp_sock *dp = dccp_sk(sk);
+       struct dccp_minisock *dmsk = dccp_msk(sk);
        int rc = 1;
        int all_confirmed = 1;
 
@@ -377,8 +413,7 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
        /* locate our change request */
        t = type == DCCPO_CONFIRM_L ? DCCPO_CHANGE_R : DCCPO_CHANGE_L;
 
-       list_for_each_entry(opt, &dp->dccps_options.dccpo_pending,
-                           dccpop_node) {
+       list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
                if (!opt->dccpop_conf && opt->dccpop_type == t &&
                    opt->dccpop_feat == feature) {
                        /* we found it */
@@ -419,12 +454,11 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 
 EXPORT_SYMBOL_GPL(dccp_feat_confirm_recv);
 
-void dccp_feat_clean(struct sock *sk)
+void dccp_feat_clean(struct dccp_minisock *dmsk)
 {
-       struct dccp_sock *dp = dccp_sk(sk);
        struct dccp_opt_pend *opt, *next;
 
-       list_for_each_entry_safe(opt, next, &dp->dccps_options.dccpo_pending,
+       list_for_each_entry_safe(opt, next, &dmsk->dccpms_pending,
                                 dccpop_node) {
                 BUG_ON(opt->dccpop_val == NULL);
                 kfree(opt->dccpop_val);
@@ -437,16 +471,15 @@ void dccp_feat_clean(struct sock *sk)
 
                 kfree(opt);
         }
-       INIT_LIST_HEAD(&dp->dccps_options.dccpo_pending);
+       INIT_LIST_HEAD(&dmsk->dccpms_pending);
 
-       list_for_each_entry_safe(opt, next, &dp->dccps_options.dccpo_conf,
-                                dccpop_node) {
+       list_for_each_entry_safe(opt, next, &dmsk->dccpms_conf, dccpop_node) {
                BUG_ON(opt == NULL);
                if (opt->dccpop_val != NULL)
                        kfree(opt->dccpop_val);
                kfree(opt);
        }
-       INIT_LIST_HEAD(&dp->dccps_options.dccpo_conf);
+       INIT_LIST_HEAD(&dmsk->dccpms_conf);
 }
 
 EXPORT_SYMBOL_GPL(dccp_feat_clean);
@@ -457,16 +490,15 @@ EXPORT_SYMBOL_GPL(dccp_feat_clean);
  */
 int dccp_feat_clone(struct sock *oldsk, struct sock *newsk)
 {
-       struct dccp_sock *olddp = dccp_sk(oldsk);
-       struct dccp_sock *newdp = dccp_sk(newsk);
+       struct dccp_minisock *olddmsk = dccp_msk(oldsk);
+       struct dccp_minisock *newdmsk = dccp_msk(newsk);
        struct dccp_opt_pend *opt;
        int rc = 0;
 
-       INIT_LIST_HEAD(&newdp->dccps_options.dccpo_pending);
-       INIT_LIST_HEAD(&newdp->dccps_options.dccpo_conf);
+       INIT_LIST_HEAD(&newdmsk->dccpms_pending);
+       INIT_LIST_HEAD(&newdmsk->dccpms_conf);
 
-       list_for_each_entry(opt, &olddp->dccps_options.dccpo_pending,
-                           dccpop_node) {
+       list_for_each_entry(opt, &olddmsk->dccpms_pending, dccpop_node) {
                struct dccp_opt_pend *newopt;
                /* copy the value of the option */
                u8 *val = kmalloc(opt->dccpop_len, GFP_ATOMIC);
@@ -484,14 +516,13 @@ int dccp_feat_clone(struct sock *oldsk, struct sock *newsk)
                /* insert the option */
                memcpy(newopt, opt, sizeof(*newopt));
                newopt->dccpop_val = val;
-               list_add_tail(&newopt->dccpop_node,
-                             &newdp->dccps_options.dccpo_pending);
+               list_add_tail(&newopt->dccpop_node, &newdmsk->dccpms_pending);
 
                /* XXX what happens with backlogs and multiple connections at
                 * once...
                 */
                /* the master socket no longer needs to worry about confirms */
-               opt->dccpop_sc = 0; /* it's not a memleak---new socket has it */
+               opt->dccpop_sc = NULL; /* it's not a memleak---new socket has it */
 
                /* reset state for a new socket */
                opt->dccpop_conf = 0;
@@ -503,50 +534,50 @@ out:
        return rc;
 
 out_clean:
-       dccp_feat_clean(newsk);
+       dccp_feat_clean(newdmsk);
        rc = -ENOMEM;
        goto out;
 }
 
 EXPORT_SYMBOL_GPL(dccp_feat_clone);
 
-static int __dccp_feat_init(struct sock *sk, u8 type, u8 feat, u8 *val, u8 len)
+static int __dccp_feat_init(struct dccp_minisock *dmsk, u8 type, u8 feat,
+                           u8 *val, u8 len)
 {
        int rc = -ENOMEM;
        u8 *copy = kmalloc(len, GFP_KERNEL);
 
        if (copy != NULL) {
                memcpy(copy, val, len);
-               rc = dccp_feat_change(sk, type, feat, copy, len, GFP_KERNEL);
+               rc = dccp_feat_change(dmsk, type, feat, copy, len, GFP_KERNEL);
                if (rc)
                        kfree(copy);
        }
        return rc;
 }
 
-int dccp_feat_init(struct sock *sk)
+int dccp_feat_init(struct dccp_minisock *dmsk)
 {
-       struct dccp_sock *dp = dccp_sk(sk);
        int rc;
 
-       INIT_LIST_HEAD(&dp->dccps_options.dccpo_pending);
-       INIT_LIST_HEAD(&dp->dccps_options.dccpo_conf);
+       INIT_LIST_HEAD(&dmsk->dccpms_pending);
+       INIT_LIST_HEAD(&dmsk->dccpms_conf);
 
        /* CCID L */
-       rc = __dccp_feat_init(sk, DCCPO_CHANGE_L, DCCPF_CCID,
-                             &dp->dccps_options.dccpo_tx_ccid, 1);
+       rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_CCID,
+                             &dmsk->dccpms_tx_ccid, 1);
        if (rc)
                goto out;
 
        /* CCID R */
-       rc = __dccp_feat_init(sk, DCCPO_CHANGE_R, DCCPF_CCID,
-                             &dp->dccps_options.dccpo_rx_ccid, 1);
+       rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_R, DCCPF_CCID,
+                             &dmsk->dccpms_rx_ccid, 1);
        if (rc)
                goto out;
 
        /* Ack ratio */
-       rc = __dccp_feat_init(sk, DCCPO_CHANGE_L, DCCPF_ACK_RATIO,
-                             &dp->dccps_options.dccpo_ack_ratio, 1);
+       rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_ACK_RATIO,
+                             &dmsk->dccpms_ack_ratio, 1);
 out:
        return rc;
 }