diff options
-rw-r--r-- | net/dccp/feat.c | 43 |
1 files changed, 42 insertions, 1 deletions
diff --git a/net/dccp/feat.c b/net/dccp/feat.c index 99d7b7f9efa9..ed0851fa3cb3 100644 --- a/net/dccp/feat.c +++ b/net/dccp/feat.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | 15 | ||
16 | #include "dccp.h" | 16 | #include "dccp.h" |
17 | #include "ccid.h" | ||
17 | #include "feat.h" | 18 | #include "feat.h" |
18 | 19 | ||
19 | #define DCCP_FEAT_SP_NOAGREE (-123) | 20 | #define DCCP_FEAT_SP_NOAGREE (-123) |
@@ -26,6 +27,8 @@ int dccp_feat_change(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len, | |||
26 | 27 | ||
27 | dccp_pr_debug("feat change type=%d feat=%d\n", type, feature); | 28 | dccp_pr_debug("feat change type=%d feat=%d\n", type, feature); |
28 | 29 | ||
30 | /* XXX sanity check feat change request */ | ||
31 | |||
29 | /* check if that feature is already being negotiated */ | 32 | /* check if that feature is already being negotiated */ |
30 | list_for_each_entry(opt, &dp->dccps_options.dccpo_pending, | 33 | list_for_each_entry(opt, &dp->dccps_options.dccpo_pending, |
31 | dccpop_node) { | 34 | dccpop_node) { |
@@ -62,11 +65,49 @@ int dccp_feat_change(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len, | |||
62 | 65 | ||
63 | EXPORT_SYMBOL_GPL(dccp_feat_change); | 66 | EXPORT_SYMBOL_GPL(dccp_feat_change); |
64 | 67 | ||
68 | static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr) | ||
69 | { | ||
70 | struct dccp_sock *dp = dccp_sk(sk); | ||
71 | /* figure out if we are changing our CCID or the peer's */ | ||
72 | const int rx = type == DCCPO_CHANGE_R; | ||
73 | const u8 ccid_nr = rx ? dp->dccps_options.dccpo_rx_ccid : | ||
74 | dp->dccps_options.dccpo_tx_ccid; | ||
75 | struct ccid *new_ccid; | ||
76 | |||
77 | /* Check if nothing is being changed. */ | ||
78 | if (ccid_nr == new_ccid_nr) | ||
79 | return 0; | ||
80 | |||
81 | new_ccid = ccid_new(new_ccid_nr, sk, rx, GFP_ATOMIC); | ||
82 | if (new_ccid == NULL) | ||
83 | return -ENOMEM; | ||
84 | |||
85 | if (rx) { | ||
86 | ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk); | ||
87 | dp->dccps_hc_rx_ccid = new_ccid; | ||
88 | dp->dccps_options.dccpo_rx_ccid = new_ccid_nr; | ||
89 | } else { | ||
90 | ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk); | ||
91 | dp->dccps_hc_tx_ccid = new_ccid; | ||
92 | dp->dccps_options.dccpo_tx_ccid = new_ccid_nr; | ||
93 | } | ||
94 | |||
95 | return 0; | ||
96 | } | ||
97 | |||
65 | /* XXX taking only u8 vals */ | 98 | /* XXX taking only u8 vals */ |
66 | static int dccp_feat_update(struct sock *sk, u8 type, u8 feat, u8 val) | 99 | static int dccp_feat_update(struct sock *sk, u8 type, u8 feat, u8 val) |
67 | { | 100 | { |
68 | /* FIXME implement */ | ||
69 | dccp_pr_debug("changing [%d] feat %d to %d\n", type, feat, val); | 101 | dccp_pr_debug("changing [%d] feat %d to %d\n", type, feat, val); |
102 | |||
103 | switch (feat) { | ||
104 | case DCCPF_CCID: | ||
105 | return dccp_feat_update_ccid(sk, type, val); | ||
106 | default: | ||
107 | dccp_pr_debug("IMPLEMENT changing [%d] feat %d to %d\n", | ||
108 | type, feat, val); | ||
109 | break; | ||
110 | } | ||
70 | return 0; | 111 | return 0; |
71 | } | 112 | } |
72 | 113 | ||