diff options
author | Andrea Bittau <a.bittau@cs.ucl.ac.uk> | 2006-03-21 02:43:56 +0100 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2006-03-21 02:43:56 +0100 |
commit | afe00251dd9b53d51de91ff0099961f42bbf3754 (patch) | |
tree | a56aa987140662cf3e6e65be402b8591298c5ced /net/dccp/proto.c | |
parent | [DCCP] CCID2: Initial CCID2 (TCP-Like) implementation (diff) | |
download | linux-afe00251dd9b53d51de91ff0099961f42bbf3754.tar.xz linux-afe00251dd9b53d51de91ff0099961f42bbf3754.zip |
[DCCP]: Initial feature negotiation implementation
Still needs more work, but boots and doesn't crashes, even
does some negotiation!
18:38:52.174934 127.0.0.1.43458 > 127.0.0.1.5001: request <change_l ack_ratio 2, change_r ccid 2, change_l ccid 2>
18:38:52.218526 127.0.0.1.5001 > 127.0.0.1.43458: response <nop, nop, change_l ack_ratio 2, confirm_r ccid 2 2, confirm_l ccid 2 2, confirm_r ack_ratio 2>
18:38:52.185398 127.0.0.1.43458 > 127.0.0.1.5001: <nop, confirm_r ack_ratio 2, ack_vector0 0x00, elapsed_time 212>
:-)
Signed-off-by: Andrea Bittau <a.bittau@cs.ucl.ac.uk>
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/dccp/proto.c')
-rw-r--r-- | net/dccp/proto.c | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 81ad24953710..1a8cf8ecfe63 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -37,6 +37,7 @@ #include "ccid.h" #include "dccp.h" +#include "feat.h" DEFINE_SNMP_STAT(struct dccp_mib, dccp_statistics) __read_mostly; @@ -255,6 +256,39 @@ static int dccp_setsockopt_service(struct sock *sk, const u32 service, return 0; } +/* byte 1 is feature. the rest is the preference list */ +static int dccp_setsockopt_change(struct sock *sk, int type, + struct dccp_so_feat __user *optval) +{ + struct dccp_so_feat opt; + u8 *val; + int rc; + + if (copy_from_user(&opt, optval, sizeof(opt))) + return -EFAULT; + + val = kmalloc(opt.dccpsf_len, GFP_KERNEL); + if (!val) + return -ENOMEM; + + if (copy_from_user(val, opt.dccpsf_val, opt.dccpsf_len)) { + rc = -EFAULT; + goto out_free_val; + } + + rc = dccp_feat_change(sk, type, opt.dccpsf_feat, val, opt.dccpsf_len, + GFP_KERNEL); + if (rc) + goto out_free_val; + +out: + return rc; + +out_free_val: + kfree(val); + goto out; +} + int dccp_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen) { @@ -284,6 +318,25 @@ int dccp_setsockopt(struct sock *sk, int level, int optname, case DCCP_SOCKOPT_PACKET_SIZE: dp->dccps_packet_size = val; break; + + case DCCP_SOCKOPT_CHANGE_L: + if (optlen != sizeof(struct dccp_so_feat)) + err = -EINVAL; + else + err = dccp_setsockopt_change(sk, DCCPO_CHANGE_L, + (struct dccp_so_feat *) + optval); + break; + + case DCCP_SOCKOPT_CHANGE_R: + if (optlen != sizeof(struct dccp_so_feat)) + err = -EINVAL; + else + err = dccp_setsockopt_change(sk, DCCPO_CHANGE_R, + (struct dccp_so_feat *) + optval); + break; + default: err = -ENOPROTOOPT; break; |