aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@mandriva.com>2005-09-16 19:58:40 -0400
committerDavid S. Miller <davem@davemloft.net>2005-09-16 19:58:40 -0400
commit67e6b629212fa9ffb7420e8a88a41806af637e28 (patch)
tree64f07616a23b657f3eb06e1daedf2450f6fbfc60
parent0c10c5d96865ce611d6a780888eff0ef4fab358b (diff)
[DCCP]: Introduce DCCP_SOCKOPT_SERVICE
As discussed in the dccp@vger mailing list: Now applications have to use setsockopt(DCCP_SOCKOPT_SERVICE, service[s]), prior to calling listen() and connect(). An array of unsigned ints can be passed meaning that the listening sock accepts connection requests for several services. With this we can ditch struct sockaddr_dccp and use only sockaddr_in (and sockaddr_in6 in the future). Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/dccp.h40
-rw-r--r--net/dccp/dccp.h9
-rw-r--r--net/dccp/ipv4.c30
-rw-r--r--net/dccp/minisocks.c6
-rw-r--r--net/dccp/output.c14
-rw-r--r--net/dccp/proto.c85
6 files changed, 154 insertions, 30 deletions
diff --git a/include/linux/dccp.h b/include/linux/dccp.h
index 8bf4bacb5051..0e72708677e4 100644
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -4,16 +4,6 @@
4#include <linux/types.h> 4#include <linux/types.h>
5#include <asm/byteorder.h> 5#include <asm/byteorder.h>
6 6
7/* Structure describing an Internet (DCCP) socket address. */
8struct sockaddr_dccp {
9 __u16 sdccp_family; /* Address family */
10 __u16 sdccp_port; /* Port number */
11 __u32 sdccp_addr; /* Internet address */
12 __u32 sdccp_service; /* Service */
13 /* Pad to size of `struct sockaddr': 16 bytes . */
14 __u32 sdccp_pad;
15};
16
17/** 7/**
18 * struct dccp_hdr - generic part of DCCP packet header 8 * struct dccp_hdr - generic part of DCCP packet header
19 * 9 *
@@ -188,6 +178,9 @@ enum {
188 178
189/* DCCP socket options */ 179/* DCCP socket options */
190#define DCCP_SOCKOPT_PACKET_SIZE 1 180#define DCCP_SOCKOPT_PACKET_SIZE 1
181#define DCCP_SOCKOPT_SERVICE 2
182
183#define DCCP_SERVICE_LIST_MAX_LEN 32
191 184
192#ifdef __KERNEL__ 185#ifdef __KERNEL__
193 186
@@ -382,6 +375,25 @@ enum dccp_role {
382 DCCP_ROLE_SERVER, 375 DCCP_ROLE_SERVER,
383}; 376};
384 377
378struct dccp_service_list {
379 __u32 dccpsl_nr;
380 __u32 dccpsl_list[0];
381};
382
383#define DCCP_SERVICE_INVALID_VALUE htonl((__u32)-1)
384
385static inline int dccp_list_has_service(const struct dccp_service_list *sl,
386 const u32 service)
387{
388 if (likely(sl != NULL)) {
389 u32 i = sl->dccpsl_nr;
390 while (i--)
391 if (sl->dccpsl_list[i] == service)
392 return 1;
393 }
394 return 0;
395}
396
385/** 397/**
386 * struct dccp_sock - DCCP socket state 398 * struct dccp_sock - DCCP socket state
387 * 399 *
@@ -417,7 +429,8 @@ struct dccp_sock {
417 __u64 dccps_gss; 429 __u64 dccps_gss;
418 __u64 dccps_gsr; 430 __u64 dccps_gsr;
419 __u64 dccps_gar; 431 __u64 dccps_gar;
420 unsigned long dccps_service; 432 __u32 dccps_service;
433 struct dccp_service_list *dccps_service_list;
421 struct timeval dccps_timestamp_time; 434 struct timeval dccps_timestamp_time;
422 __u32 dccps_timestamp_echo; 435 __u32 dccps_timestamp_echo;
423 __u32 dccps_packet_size; 436 __u32 dccps_packet_size;
@@ -443,6 +456,11 @@ static inline struct dccp_sock *dccp_sk(const struct sock *sk)
443 return (struct dccp_sock *)sk; 456 return (struct dccp_sock *)sk;
444} 457}
445 458
459static inline int dccp_service_not_initialized(const struct sock *sk)
460{
461 return dccp_sk(sk)->dccps_service == DCCP_SERVICE_INVALID_VALUE;
462}
463
446static inline const char *dccp_role(const struct sock *sk) 464static inline const char *dccp_role(const struct sock *sk)
447{ 465{
448 switch (dccp_sk(sk)->dccps_role) { 466 switch (dccp_sk(sk)->dccps_role) {
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h
index 95c4630b3b18..be7a660b6b24 100644
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -258,13 +258,12 @@ extern int dccp_v4_send_reset(struct sock *sk,
258extern void dccp_send_close(struct sock *sk, const int active); 258extern void dccp_send_close(struct sock *sk, const int active);
259 259
260struct dccp_skb_cb { 260struct dccp_skb_cb {
261 __u8 dccpd_type; 261 __u8 dccpd_type:4;
262 __u8 dccpd_reset_code; 262 __u8 dccpd_ccval:4;
263 __u8 dccpd_service; 263 __u8 dccpd_reset_code;
264 __u8 dccpd_ccval; 264 __u16 dccpd_opt_len;
265 __u64 dccpd_seq; 265 __u64 dccpd_seq;
266 __u64 dccpd_ack_seq; 266 __u64 dccpd_ack_seq;
267 int dccpd_opt_len;
268}; 267};
269 268
270#define DCCP_SKB_CB(__skb) ((struct dccp_skb_cb *)&((__skb)->cb[0])) 269#define DCCP_SKB_CB(__skb) ((struct dccp_skb_cb *)&((__skb)->cb[0]))
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index e09907d8b7da..94a440b2685b 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -246,6 +246,9 @@ static int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr,
246 246
247 dp->dccps_role = DCCP_ROLE_CLIENT; 247 dp->dccps_role = DCCP_ROLE_CLIENT;
248 248
249 if (dccp_service_not_initialized(sk))
250 return -EPROTO;
251
249 if (addr_len < sizeof(struct sockaddr_in)) 252 if (addr_len < sizeof(struct sockaddr_in))
250 return -EINVAL; 253 return -EINVAL;
251 254
@@ -661,6 +664,16 @@ static inline u64 dccp_v4_init_sequence(const struct sock *sk,
661 dccp_hdr(skb)->dccph_sport); 664 dccp_hdr(skb)->dccph_sport);
662} 665}
663 666
667static inline int dccp_bad_service_code(const struct sock *sk,
668 const __u32 service)
669{
670 const struct dccp_sock *dp = dccp_sk(sk);
671
672 if (dp->dccps_service == service)
673 return 0;
674 return !dccp_list_has_service(dp->dccps_service_list, service);
675}
676
664int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) 677int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
665{ 678{
666 struct inet_request_sock *ireq; 679 struct inet_request_sock *ireq;
@@ -669,6 +682,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
669 struct dccp_request_sock *dreq; 682 struct dccp_request_sock *dreq;
670 const __u32 saddr = skb->nh.iph->saddr; 683 const __u32 saddr = skb->nh.iph->saddr;
671 const __u32 daddr = skb->nh.iph->daddr; 684 const __u32 daddr = skb->nh.iph->daddr;
685 const __u32 service = dccp_hdr_request(skb)->dccph_req_service;
672 struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); 686 struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
673 __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY; 687 __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY;
674 struct dst_entry *dst = NULL; 688 struct dst_entry *dst = NULL;
@@ -680,6 +694,10 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
680 goto drop; 694 goto drop;
681 } 695 }
682 696
697 if (dccp_bad_service_code(sk, service)) {
698 reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE;
699 goto drop;
700 }
683 /* 701 /*
684 * TW buckets are converted to open requests without 702 * TW buckets are converted to open requests without
685 * limitations, they conserve resources and peer is 703 * limitations, they conserve resources and peer is
@@ -722,9 +740,9 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
722 * dccp_create_openreq_child. 740 * dccp_create_openreq_child.
723 */ 741 */
724 dreq = dccp_rsk(req); 742 dreq = dccp_rsk(req);
725 dreq->dreq_isr = dcb->dccpd_seq; 743 dreq->dreq_isr = dcb->dccpd_seq;
726 dreq->dreq_iss = dccp_v4_init_sequence(sk, skb); 744 dreq->dreq_iss = dccp_v4_init_sequence(sk, skb);
727 dreq->dreq_service = dccp_hdr_request(skb)->dccph_req_service; 745 dreq->dreq_service = service;
728 746
729 if (dccp_v4_send_response(sk, req, dst)) 747 if (dccp_v4_send_response(sk, req, dst))
730 goto drop_and_free; 748 goto drop_and_free;
@@ -1284,6 +1302,7 @@ static int dccp_v4_init_sock(struct sock *sk)
1284 sk->sk_write_space = dccp_write_space; 1302 sk->sk_write_space = dccp_write_space;
1285 dp->dccps_mss_cache = 536; 1303 dp->dccps_mss_cache = 536;
1286 dp->dccps_role = DCCP_ROLE_UNDEFINED; 1304 dp->dccps_role = DCCP_ROLE_UNDEFINED;
1305 dp->dccps_service = DCCP_SERVICE_INVALID_VALUE;
1287 1306
1288 return 0; 1307 return 0;
1289} 1308}
@@ -1305,6 +1324,11 @@ static int dccp_v4_destroy_sock(struct sock *sk)
1305 if (inet_csk(sk)->icsk_bind_hash != NULL) 1324 if (inet_csk(sk)->icsk_bind_hash != NULL)
1306 inet_put_port(&dccp_hashinfo, sk); 1325 inet_put_port(&dccp_hashinfo, sk);
1307 1326
1327 if (dp->dccps_service_list != NULL) {
1328 kfree(dp->dccps_service_list);
1329 dp->dccps_service_list = NULL;
1330 }
1331
1308 ccid_hc_rx_exit(dp->dccps_hc_rx_ccid, sk); 1332 ccid_hc_rx_exit(dp->dccps_hc_rx_ccid, sk);
1309 ccid_hc_tx_exit(dp->dccps_hc_tx_ccid, sk); 1333 ccid_hc_tx_exit(dp->dccps_hc_tx_ccid, sk);
1310 dccp_ackpkts_free(dp->dccps_hc_rx_ackpkts); 1334 dccp_ackpkts_free(dp->dccps_hc_rx_ackpkts);
diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c
index 18461bc04cbe..933e10db1789 100644
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -93,9 +93,11 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
93 struct inet_connection_sock *newicsk = inet_csk(sk); 93 struct inet_connection_sock *newicsk = inet_csk(sk);
94 struct dccp_sock *newdp = dccp_sk(newsk); 94 struct dccp_sock *newdp = dccp_sk(newsk);
95 95
96 newdp->dccps_role = DCCP_ROLE_SERVER;
96 newdp->dccps_hc_rx_ackpkts = NULL; 97 newdp->dccps_hc_rx_ackpkts = NULL;
97 newdp->dccps_role = DCCP_ROLE_SERVER; 98 newdp->dccps_service_list = NULL;
98 newicsk->icsk_rto = DCCP_TIMEOUT_INIT; 99 newdp->dccps_service = dreq->dreq_service;
100 newicsk->icsk_rto = DCCP_TIMEOUT_INIT;
99 do_gettimeofday(&newdp->dccps_epoch); 101 do_gettimeofday(&newdp->dccps_epoch);
100 102
101 if (newdp->dccps_options.dccpo_send_ack_vector) { 103 if (newdp->dccps_options.dccpo_send_ack_vector) {
diff --git a/net/dccp/output.c b/net/dccp/output.c
index ea6d0e91e511..156b1d29a156 100644
--- a/net/dccp/output.c
+++ b/net/dccp/output.c
@@ -85,7 +85,7 @@ int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb)
85 switch (dcb->dccpd_type) { 85 switch (dcb->dccpd_type) {
86 case DCCP_PKT_REQUEST: 86 case DCCP_PKT_REQUEST:
87 dccp_hdr_request(skb)->dccph_req_service = 87 dccp_hdr_request(skb)->dccph_req_service =
88 dcb->dccpd_service; 88 dp->dccps_service;
89 break; 89 break;
90 case DCCP_PKT_RESET: 90 case DCCP_PKT_RESET:
91 dccp_hdr_reset(skb)->dccph_reset_code = 91 dccp_hdr_reset(skb)->dccph_reset_code =
@@ -270,6 +270,7 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst,
270 struct request_sock *req) 270 struct request_sock *req)
271{ 271{
272 struct dccp_hdr *dh; 272 struct dccp_hdr *dh;
273 struct dccp_request_sock *dreq;
273 const int dccp_header_size = sizeof(struct dccp_hdr) + 274 const int dccp_header_size = sizeof(struct dccp_hdr) +
274 sizeof(struct dccp_hdr_ext) + 275 sizeof(struct dccp_hdr_ext) +
275 sizeof(struct dccp_hdr_response); 276 sizeof(struct dccp_hdr_response);
@@ -285,8 +286,9 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst,
285 skb->dst = dst_clone(dst); 286 skb->dst = dst_clone(dst);
286 skb->csum = 0; 287 skb->csum = 0;
287 288
289 dreq = dccp_rsk(req);
288 DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESPONSE; 290 DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESPONSE;
289 DCCP_SKB_CB(skb)->dccpd_seq = dccp_rsk(req)->dreq_iss; 291 DCCP_SKB_CB(skb)->dccpd_seq = dreq->dreq_iss;
290 dccp_insert_options(sk, skb); 292 dccp_insert_options(sk, skb);
291 293
292 skb->h.raw = skb_push(skb, dccp_header_size); 294 skb->h.raw = skb_push(skb, dccp_header_size);
@@ -300,8 +302,9 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst,
300 DCCP_SKB_CB(skb)->dccpd_opt_len) / 4; 302 DCCP_SKB_CB(skb)->dccpd_opt_len) / 4;
301 dh->dccph_type = DCCP_PKT_RESPONSE; 303 dh->dccph_type = DCCP_PKT_RESPONSE;
302 dh->dccph_x = 1; 304 dh->dccph_x = 1;
303 dccp_hdr_set_seq(dh, dccp_rsk(req)->dreq_iss); 305 dccp_hdr_set_seq(dh, dreq->dreq_iss);
304 dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dccp_rsk(req)->dreq_isr); 306 dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dreq->dreq_isr);
307 dccp_hdr_response(skb)->dccph_resp_service = dreq->dreq_service;
305 308
306 dh->dccph_checksum = dccp_v4_checksum(skb, inet_rsk(req)->loc_addr, 309 dh->dccph_checksum = dccp_v4_checksum(skb, inet_rsk(req)->loc_addr,
307 inet_rsk(req)->rmt_addr); 310 inet_rsk(req)->rmt_addr);
@@ -397,9 +400,6 @@ int dccp_connect(struct sock *sk)
397 skb_reserve(skb, MAX_DCCP_HEADER); 400 skb_reserve(skb, MAX_DCCP_HEADER);
398 401
399 DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_REQUEST; 402 DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_REQUEST;
400 /* FIXME: set service to something meaningful, coming
401 * from userspace*/
402 DCCP_SKB_CB(skb)->dccpd_service = 0;
403 skb->csum = 0; 403 skb->csum = 0;
404 skb_set_owner_w(skb, sk); 404 skb_set_owner_w(skb, sk);
405 405
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index 18a0e69c9dc7..9bda2868eba6 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -94,7 +94,15 @@ EXPORT_SYMBOL_GPL(dccp_state_name);
94 94
95static inline int dccp_listen_start(struct sock *sk) 95static inline int dccp_listen_start(struct sock *sk)
96{ 96{
97 dccp_sk(sk)->dccps_role = DCCP_ROLE_LISTEN; 97 struct dccp_sock *dp = dccp_sk(sk);
98
99 dp->dccps_role = DCCP_ROLE_LISTEN;
100 /*
101 * Apps need to use setsockopt(DCCP_SOCKOPT_SERVICE)
102 * before calling listen()
103 */
104 if (dccp_service_not_initialized(sk))
105 return -EPROTO;
98 return inet_csk_listen_start(sk, TCP_SYNQ_HSIZE); 106 return inet_csk_listen_start(sk, TCP_SYNQ_HSIZE);
99} 107}
100 108
@@ -202,6 +210,42 @@ int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg)
202 return -ENOIOCTLCMD; 210 return -ENOIOCTLCMD;
203} 211}
204 212
213static int dccp_setsockopt_service(struct sock *sk, const u32 service,
214 char __user *optval, int optlen)
215{
216 struct dccp_sock *dp = dccp_sk(sk);
217 struct dccp_service_list *sl = NULL;
218
219 if (service == DCCP_SERVICE_INVALID_VALUE ||
220 optlen > DCCP_SERVICE_LIST_MAX_LEN * sizeof(u32))
221 return -EINVAL;
222
223 if (optlen > sizeof(service)) {
224 sl = kmalloc(optlen, GFP_KERNEL);
225 if (sl == NULL)
226 return -ENOMEM;
227
228 sl->dccpsl_nr = optlen / sizeof(u32) - 1;
229 if (copy_from_user(sl->dccpsl_list,
230 optval + sizeof(service),
231 optlen - sizeof(service)) ||
232 dccp_list_has_service(sl, DCCP_SERVICE_INVALID_VALUE)) {
233 kfree(sl);
234 return -EFAULT;
235 }
236 }
237
238 lock_sock(sk);
239 dp->dccps_service = service;
240
241 if (dp->dccps_service_list != NULL)
242 kfree(dp->dccps_service_list);
243
244 dp->dccps_service_list = sl;
245 release_sock(sk);
246 return 0;
247}
248
205int dccp_setsockopt(struct sock *sk, int level, int optname, 249int dccp_setsockopt(struct sock *sk, int level, int optname,
206 char __user *optval, int optlen) 250 char __user *optval, int optlen)
207{ 251{
@@ -218,8 +262,10 @@ int dccp_setsockopt(struct sock *sk, int level, int optname,
218 if (get_user(val, (int __user *)optval)) 262 if (get_user(val, (int __user *)optval))
219 return -EFAULT; 263 return -EFAULT;
220 264
221 lock_sock(sk); 265 if (optname == DCCP_SOCKOPT_SERVICE)
266 return dccp_setsockopt_service(sk, val, optval, optlen);
222 267
268 lock_sock(sk);
223 dp = dccp_sk(sk); 269 dp = dccp_sk(sk);
224 err = 0; 270 err = 0;
225 271
@@ -236,6 +282,37 @@ int dccp_setsockopt(struct sock *sk, int level, int optname,
236 return err; 282 return err;
237} 283}
238 284
285static int dccp_getsockopt_service(struct sock *sk, int len,
286 u32 __user *optval,
287 int __user *optlen)
288{
289 const struct dccp_sock *dp = dccp_sk(sk);
290 const struct dccp_service_list *sl;
291 int err = -ENOENT, slen = 0, total_len = sizeof(u32);
292
293 lock_sock(sk);
294 if (dccp_service_not_initialized(sk))
295 goto out;
296
297 if ((sl = dp->dccps_service_list) != NULL) {
298 slen = sl->dccpsl_nr * sizeof(u32);
299 total_len += slen;
300 }
301
302 err = -EINVAL;
303 if (total_len > len)
304 goto out;
305
306 err = 0;
307 if (put_user(total_len, optlen) ||
308 put_user(dp->dccps_service, optval) ||
309 (sl != NULL && copy_to_user(optval + 1, sl->dccpsl_list, slen)))
310 err = -EFAULT;
311out:
312 release_sock(sk);
313 return err;
314}
315
239int dccp_getsockopt(struct sock *sk, int level, int optname, 316int dccp_getsockopt(struct sock *sk, int level, int optname,
240 char __user *optval, int __user *optlen) 317 char __user *optval, int __user *optlen)
241{ 318{
@@ -248,6 +325,10 @@ int dccp_getsockopt(struct sock *sk, int level, int optname,
248 if (get_user(len, optlen)) 325 if (get_user(len, optlen))
249 return -EFAULT; 326 return -EFAULT;
250 327
328 if (optname == DCCP_SOCKOPT_SERVICE)
329 return dccp_getsockopt_service(sk, len,
330 (u32 __user *)optval, optlen);
331
251 len = min_t(unsigned int, len, sizeof(int)); 332 len = min_t(unsigned int, len, sizeof(int));
252 if (len < 0) 333 if (len < 0)
253 return -EINVAL; 334 return -EINVAL;