diff options
-rw-r--r-- | include/linux/dccp.h | 2 | ||||
-rw-r--r-- | net/dccp/ccid.h | 31 | ||||
-rw-r--r-- | net/dccp/ccids/ccid3.c | 56 | ||||
-rw-r--r-- | net/dccp/proto.c | 17 |
4 files changed, 100 insertions, 6 deletions
diff --git a/include/linux/dccp.h b/include/linux/dccp.h index 13f9b78483fc..71fab4311e92 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h | |||
@@ -179,6 +179,8 @@ enum { | |||
179 | /* DCCP socket options */ | 179 | /* DCCP socket options */ |
180 | #define DCCP_SOCKOPT_PACKET_SIZE 1 | 180 | #define DCCP_SOCKOPT_PACKET_SIZE 1 |
181 | #define DCCP_SOCKOPT_SERVICE 2 | 181 | #define DCCP_SOCKOPT_SERVICE 2 |
182 | #define DCCP_SOCKOPT_CCID_RX_INFO 128 | ||
183 | #define DCCP_SOCKOPT_CCID_TX_INFO 192 | ||
182 | 184 | ||
183 | #define DCCP_SERVICE_LIST_MAX_LEN 32 | 185 | #define DCCP_SERVICE_LIST_MAX_LEN 32 |
184 | 186 | ||
diff --git a/net/dccp/ccid.h b/net/dccp/ccid.h index 962f1e9e2f7e..21e55142dcd3 100644 --- a/net/dccp/ccid.h +++ b/net/dccp/ccid.h | |||
@@ -14,6 +14,7 @@ | |||
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <net/sock.h> | 16 | #include <net/sock.h> |
17 | #include <linux/compiler.h> | ||
17 | #include <linux/dccp.h> | 18 | #include <linux/dccp.h> |
18 | #include <linux/list.h> | 19 | #include <linux/list.h> |
19 | #include <linux/module.h> | 20 | #include <linux/module.h> |
@@ -54,6 +55,14 @@ struct ccid { | |||
54 | struct tcp_info *info); | 55 | struct tcp_info *info); |
55 | void (*ccid_hc_tx_get_info)(struct sock *sk, | 56 | void (*ccid_hc_tx_get_info)(struct sock *sk, |
56 | struct tcp_info *info); | 57 | struct tcp_info *info); |
58 | int (*ccid_hc_rx_getsockopt)(struct sock *sk, | ||
59 | const int optname, int len, | ||
60 | u32 __user *optval, | ||
61 | int __user *optlen); | ||
62 | int (*ccid_hc_tx_getsockopt)(struct sock *sk, | ||
63 | const int optname, int len, | ||
64 | u32 __user *optval, | ||
65 | int __user *optlen); | ||
57 | }; | 66 | }; |
58 | 67 | ||
59 | extern int ccid_register(struct ccid *ccid); | 68 | extern int ccid_register(struct ccid *ccid); |
@@ -177,4 +186,26 @@ static inline void ccid_hc_tx_get_info(struct ccid *ccid, struct sock *sk, | |||
177 | if (ccid->ccid_hc_tx_get_info != NULL) | 186 | if (ccid->ccid_hc_tx_get_info != NULL) |
178 | ccid->ccid_hc_tx_get_info(sk, info); | 187 | ccid->ccid_hc_tx_get_info(sk, info); |
179 | } | 188 | } |
189 | |||
190 | static inline int ccid_hc_rx_getsockopt(struct ccid *ccid, struct sock *sk, | ||
191 | const int optname, int len, | ||
192 | u32 __user *optval, int __user *optlen) | ||
193 | { | ||
194 | int rc = -ENOPROTOOPT; | ||
195 | if (ccid->ccid_hc_rx_getsockopt != NULL) | ||
196 | rc = ccid->ccid_hc_rx_getsockopt(sk, optname, len, | ||
197 | optval, optlen); | ||
198 | return rc; | ||
199 | } | ||
200 | |||
201 | static inline int ccid_hc_tx_getsockopt(struct ccid *ccid, struct sock *sk, | ||
202 | const int optname, int len, | ||
203 | u32 __user *optval, int __user *optlen) | ||
204 | { | ||
205 | int rc = -ENOPROTOOPT; | ||
206 | if (ccid->ccid_hc_tx_getsockopt != NULL) | ||
207 | rc = ccid->ccid_hc_tx_getsockopt(sk, optname, len, | ||
208 | optval, optlen); | ||
209 | return rc; | ||
210 | } | ||
180 | #endif /* _CCID_H */ | 211 | #endif /* _CCID_H */ |
diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 38aa84986118..aa68e0ab274d 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c | |||
@@ -1120,6 +1120,60 @@ static void ccid3_hc_tx_get_info(struct sock *sk, struct tcp_info *info) | |||
1120 | info->tcpi_rtt = hctx->ccid3hctx_rtt; | 1120 | info->tcpi_rtt = hctx->ccid3hctx_rtt; |
1121 | } | 1121 | } |
1122 | 1122 | ||
1123 | static int ccid3_hc_rx_getsockopt(struct sock *sk, const int optname, int len, | ||
1124 | u32 __user *optval, int __user *optlen) | ||
1125 | { | ||
1126 | const struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); | ||
1127 | const void *val; | ||
1128 | |||
1129 | /* Listen socks doesn't have a private CCID block */ | ||
1130 | if (sk->sk_state == DCCP_LISTEN) | ||
1131 | return -EINVAL; | ||
1132 | |||
1133 | switch (optname) { | ||
1134 | case DCCP_SOCKOPT_CCID_RX_INFO: | ||
1135 | if (len < sizeof(hcrx->ccid3hcrx_tfrc)) | ||
1136 | return -EINVAL; | ||
1137 | len = sizeof(hcrx->ccid3hcrx_tfrc); | ||
1138 | val = &hcrx->ccid3hcrx_tfrc; | ||
1139 | break; | ||
1140 | default: | ||
1141 | return -ENOPROTOOPT; | ||
1142 | } | ||
1143 | |||
1144 | if (put_user(len, optlen) || copy_to_user(optval, val, len)) | ||
1145 | return -EFAULT; | ||
1146 | |||
1147 | return 0; | ||
1148 | } | ||
1149 | |||
1150 | static int ccid3_hc_tx_getsockopt(struct sock *sk, const int optname, int len, | ||
1151 | u32 __user *optval, int __user *optlen) | ||
1152 | { | ||
1153 | const struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); | ||
1154 | const void *val; | ||
1155 | |||
1156 | /* Listen socks doesn't have a private CCID block */ | ||
1157 | if (sk->sk_state == DCCP_LISTEN) | ||
1158 | return -EINVAL; | ||
1159 | |||
1160 | switch (optname) { | ||
1161 | case DCCP_SOCKOPT_CCID_TX_INFO: | ||
1162 | if (len < sizeof(hctx->ccid3hctx_tfrc)) | ||
1163 | return -EINVAL; | ||
1164 | len = sizeof(hctx->ccid3hctx_tfrc); | ||
1165 | val = &hctx->ccid3hctx_tfrc; | ||
1166 | break; | ||
1167 | default: | ||
1168 | return -ENOPROTOOPT; | ||
1169 | } | ||
1170 | |||
1171 | if (put_user(len, optlen) || copy_to_user(optval, val, len)) | ||
1172 | return -EFAULT; | ||
1173 | |||
1174 | return 0; | ||
1175 | } | ||
1176 | |||
1123 | static struct ccid ccid3 = { | 1177 | static struct ccid ccid3 = { |
1124 | .ccid_id = 3, | 1178 | .ccid_id = 3, |
1125 | .ccid_name = "ccid3", | 1179 | .ccid_name = "ccid3", |
@@ -1139,6 +1193,8 @@ static struct ccid ccid3 = { | |||
1139 | .ccid_hc_rx_packet_recv = ccid3_hc_rx_packet_recv, | 1193 | .ccid_hc_rx_packet_recv = ccid3_hc_rx_packet_recv, |
1140 | .ccid_hc_rx_get_info = ccid3_hc_rx_get_info, | 1194 | .ccid_hc_rx_get_info = ccid3_hc_rx_get_info, |
1141 | .ccid_hc_tx_get_info = ccid3_hc_tx_get_info, | 1195 | .ccid_hc_tx_get_info = ccid3_hc_tx_get_info, |
1196 | .ccid_hc_rx_getsockopt = ccid3_hc_rx_getsockopt, | ||
1197 | .ccid_hc_tx_getsockopt = ccid3_hc_tx_getsockopt, | ||
1142 | }; | 1198 | }; |
1143 | 1199 | ||
1144 | module_param(ccid3_debug, int, 0444); | 1200 | module_param(ccid3_debug, int, 0444); |
diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 9bda2868eba6..a1cfd0e9e3bc 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c | |||
@@ -325,12 +325,7 @@ int dccp_getsockopt(struct sock *sk, int level, int optname, | |||
325 | if (get_user(len, optlen)) | 325 | if (get_user(len, optlen)) |
326 | return -EFAULT; | 326 | return -EFAULT; |
327 | 327 | ||
328 | if (optname == DCCP_SOCKOPT_SERVICE) | 328 | if (len < sizeof(int)) |
329 | return dccp_getsockopt_service(sk, len, | ||
330 | (u32 __user *)optval, optlen); | ||
331 | |||
332 | len = min_t(unsigned int, len, sizeof(int)); | ||
333 | if (len < 0) | ||
334 | return -EINVAL; | 329 | return -EINVAL; |
335 | 330 | ||
336 | dp = dccp_sk(sk); | 331 | dp = dccp_sk(sk); |
@@ -338,7 +333,17 @@ int dccp_getsockopt(struct sock *sk, int level, int optname, | |||
338 | switch (optname) { | 333 | switch (optname) { |
339 | case DCCP_SOCKOPT_PACKET_SIZE: | 334 | case DCCP_SOCKOPT_PACKET_SIZE: |
340 | val = dp->dccps_packet_size; | 335 | val = dp->dccps_packet_size; |
336 | len = sizeof(dp->dccps_packet_size); | ||
341 | break; | 337 | break; |
338 | case DCCP_SOCKOPT_SERVICE: | ||
339 | return dccp_getsockopt_service(sk, len, | ||
340 | (u32 __user *)optval, optlen); | ||
341 | case 128 ... 191: | ||
342 | return ccid_hc_rx_getsockopt(dp->dccps_hc_rx_ccid, sk, optname, | ||
343 | len, (u32 __user *)optval, optlen); | ||
344 | case 192 ... 255: | ||
345 | return ccid_hc_tx_getsockopt(dp->dccps_hc_tx_ccid, sk, optname, | ||
346 | len, (u32 __user *)optval, optlen); | ||
342 | default: | 347 | default: |
343 | return -ENOPROTOOPT; | 348 | return -ENOPROTOOPT; |
344 | } | 349 | } |