diff options
-rw-r--r-- | Documentation/networking/dccp.txt | 6 | ||||
-rw-r--r-- | include/linux/dccp.h | 3 | ||||
-rw-r--r-- | net/dccp/output.c | 6 | ||||
-rw-r--r-- | net/dccp/proto.c | 13 |
4 files changed, 25 insertions, 3 deletions
diff --git a/Documentation/networking/dccp.txt b/Documentation/networking/dccp.txt index d76905a5a087..39131a3c78f8 100644 --- a/Documentation/networking/dccp.txt +++ b/Documentation/networking/dccp.txt | |||
@@ -57,6 +57,12 @@ can be set before calling bind(). | |||
57 | DCCP_SOCKOPT_GET_CUR_MPS is read-only and retrieves the current maximum packet | 57 | DCCP_SOCKOPT_GET_CUR_MPS is read-only and retrieves the current maximum packet |
58 | size (application payload size) in bytes, see RFC 4340, section 14. | 58 | size (application payload size) in bytes, see RFC 4340, section 14. |
59 | 59 | ||
60 | DCCP_SOCKOPT_SERVER_TIMEWAIT enables the server (listening socket) to hold | ||
61 | timewait state when closing the connection (RFC 4340, 8.3). The usual case is | ||
62 | that the closing server sends a CloseReq, whereupon the client holds timewait | ||
63 | state. When this boolean socket option is on, the server sends a Close instead | ||
64 | and will enter TIMEWAIT. This option must be set after accept() returns. | ||
65 | |||
60 | DCCP_SOCKOPT_SEND_CSCOV and DCCP_SOCKOPT_RECV_CSCOV are used for setting the | 66 | DCCP_SOCKOPT_SEND_CSCOV and DCCP_SOCKOPT_RECV_CSCOV are used for setting the |
61 | partial checksum coverage (RFC 4340, sec. 9.2). The default is that checksums | 67 | partial checksum coverage (RFC 4340, sec. 9.2). The default is that checksums |
62 | always cover the entire packet and that only fully covered application data is | 68 | always cover the entire packet and that only fully covered application data is |
diff --git a/include/linux/dccp.h b/include/linux/dccp.h index 312b989c7edb..c676021603f5 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h | |||
@@ -205,6 +205,7 @@ struct dccp_so_feat { | |||
205 | #define DCCP_SOCKOPT_CHANGE_L 3 | 205 | #define DCCP_SOCKOPT_CHANGE_L 3 |
206 | #define DCCP_SOCKOPT_CHANGE_R 4 | 206 | #define DCCP_SOCKOPT_CHANGE_R 4 |
207 | #define DCCP_SOCKOPT_GET_CUR_MPS 5 | 207 | #define DCCP_SOCKOPT_GET_CUR_MPS 5 |
208 | #define DCCP_SOCKOPT_SERVER_TIMEWAIT 6 | ||
208 | #define DCCP_SOCKOPT_SEND_CSCOV 10 | 209 | #define DCCP_SOCKOPT_SEND_CSCOV 10 |
209 | #define DCCP_SOCKOPT_RECV_CSCOV 11 | 210 | #define DCCP_SOCKOPT_RECV_CSCOV 11 |
210 | #define DCCP_SOCKOPT_CCID_RX_INFO 128 | 211 | #define DCCP_SOCKOPT_CCID_RX_INFO 128 |
@@ -492,6 +493,7 @@ struct dccp_ackvec; | |||
492 | * @dccps_role - role of this sock, one of %dccp_role | 493 | * @dccps_role - role of this sock, one of %dccp_role |
493 | * @dccps_hc_rx_insert_options - receiver wants to add options when acking | 494 | * @dccps_hc_rx_insert_options - receiver wants to add options when acking |
494 | * @dccps_hc_tx_insert_options - sender wants to add options when sending | 495 | * @dccps_hc_tx_insert_options - sender wants to add options when sending |
496 | * @dccps_server_timewait - server holds timewait state on close (RFC 4340, 8.3) | ||
495 | * @dccps_xmit_timer - timer for when CCID is not ready to send | 497 | * @dccps_xmit_timer - timer for when CCID is not ready to send |
496 | * @dccps_syn_rtt - RTT sample from Request/Response exchange (in usecs) | 498 | * @dccps_syn_rtt - RTT sample from Request/Response exchange (in usecs) |
497 | */ | 499 | */ |
@@ -528,6 +530,7 @@ struct dccp_sock { | |||
528 | enum dccp_role dccps_role:2; | 530 | enum dccp_role dccps_role:2; |
529 | __u8 dccps_hc_rx_insert_options:1; | 531 | __u8 dccps_hc_rx_insert_options:1; |
530 | __u8 dccps_hc_tx_insert_options:1; | 532 | __u8 dccps_hc_tx_insert_options:1; |
533 | __u8 dccps_server_timewait:1; | ||
531 | struct timer_list dccps_xmit_timer; | 534 | struct timer_list dccps_xmit_timer; |
532 | }; | 535 | }; |
533 | 536 | ||
diff --git a/net/dccp/output.c b/net/dccp/output.c index e97584aa4898..b2e17910930d 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c | |||
@@ -567,8 +567,10 @@ void dccp_send_close(struct sock *sk, const int active) | |||
567 | 567 | ||
568 | /* Reserve space for headers and prepare control bits. */ | 568 | /* Reserve space for headers and prepare control bits. */ |
569 | skb_reserve(skb, sk->sk_prot->max_header); | 569 | skb_reserve(skb, sk->sk_prot->max_header); |
570 | DCCP_SKB_CB(skb)->dccpd_type = dp->dccps_role == DCCP_ROLE_CLIENT ? | 570 | if (dp->dccps_role == DCCP_ROLE_SERVER && !dp->dccps_server_timewait) |
571 | DCCP_PKT_CLOSE : DCCP_PKT_CLOSEREQ; | 571 | DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_CLOSEREQ; |
572 | else | ||
573 | DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_CLOSE; | ||
572 | 574 | ||
573 | if (active) { | 575 | if (active) { |
574 | dccp_write_xmit(sk, 1); | 576 | dccp_write_xmit(sk, 1); |
diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 8a73c8f98d76..cc87c500bfb8 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c | |||
@@ -551,6 +551,12 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname, | |||
551 | (struct dccp_so_feat __user *) | 551 | (struct dccp_so_feat __user *) |
552 | optval); | 552 | optval); |
553 | break; | 553 | break; |
554 | case DCCP_SOCKOPT_SERVER_TIMEWAIT: | ||
555 | if (dp->dccps_role != DCCP_ROLE_SERVER) | ||
556 | err = -EOPNOTSUPP; | ||
557 | else | ||
558 | dp->dccps_server_timewait = (val != 0); | ||
559 | break; | ||
554 | case DCCP_SOCKOPT_SEND_CSCOV: /* sender side, RFC 4340, sec. 9.2 */ | 560 | case DCCP_SOCKOPT_SEND_CSCOV: /* sender side, RFC 4340, sec. 9.2 */ |
555 | if (val < 0 || val > 15) | 561 | if (val < 0 || val > 15) |
556 | err = -EINVAL; | 562 | err = -EINVAL; |
@@ -653,6 +659,10 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname, | |||
653 | val = dp->dccps_mss_cache; | 659 | val = dp->dccps_mss_cache; |
654 | len = sizeof(val); | 660 | len = sizeof(val); |
655 | break; | 661 | break; |
662 | case DCCP_SOCKOPT_SERVER_TIMEWAIT: | ||
663 | val = dp->dccps_server_timewait; | ||
664 | len = sizeof(val); | ||
665 | break; | ||
656 | case DCCP_SOCKOPT_SEND_CSCOV: | 666 | case DCCP_SOCKOPT_SEND_CSCOV: |
657 | val = dp->dccps_pcslen; | 667 | val = dp->dccps_pcslen; |
658 | len = sizeof(val); | 668 | len = sizeof(val); |
@@ -918,7 +928,8 @@ static void dccp_terminate_connection(struct sock *sk) | |||
918 | case DCCP_OPEN: | 928 | case DCCP_OPEN: |
919 | dccp_send_close(sk, 1); | 929 | dccp_send_close(sk, 1); |
920 | 930 | ||
921 | if (dccp_sk(sk)->dccps_role == DCCP_ROLE_SERVER) | 931 | if (dccp_sk(sk)->dccps_role == DCCP_ROLE_SERVER && |
932 | !dccp_sk(sk)->dccps_server_timewait) | ||
922 | next_state = DCCP_ACTIVE_CLOSEREQ; | 933 | next_state = DCCP_ACTIVE_CLOSEREQ; |
923 | else | 934 | else |
924 | next_state = DCCP_CLOSING; | 935 | next_state = DCCP_CLOSING; |