diff options
Diffstat (limited to 'net/dccp/ipv4.c')
-rw-r--r-- | net/dccp/ipv4.c | 38 |
1 files changed, 33 insertions, 5 deletions
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 2afaa464e7f0..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 | ||
667 | static 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 | |||
664 | int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | 677 | int 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,13 +682,22 @@ 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; | ||
686 | struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); | ||
687 | __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY; | ||
672 | struct dst_entry *dst = NULL; | 688 | struct dst_entry *dst = NULL; |
673 | 689 | ||
674 | /* Never answer to DCCP_PKT_REQUESTs send to broadcast or multicast */ | 690 | /* Never answer to DCCP_PKT_REQUESTs send to broadcast or multicast */ |
675 | if (((struct rtable *)skb->dst)->rt_flags & | 691 | if (((struct rtable *)skb->dst)->rt_flags & |
676 | (RTCF_BROADCAST | RTCF_MULTICAST)) | 692 | (RTCF_BROADCAST | RTCF_MULTICAST)) { |
693 | reset_code = DCCP_RESET_CODE_NO_CONNECTION; | ||
677 | goto drop; | 694 | goto drop; |
695 | } | ||
678 | 696 | ||
697 | if (dccp_bad_service_code(sk, service)) { | ||
698 | reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE; | ||
699 | goto drop; | ||
700 | } | ||
679 | /* | 701 | /* |
680 | * TW buckets are converted to open requests without | 702 | * TW buckets are converted to open requests without |
681 | * limitations, they conserve resources and peer is | 703 | * limitations, they conserve resources and peer is |
@@ -718,9 +740,9 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
718 | * dccp_create_openreq_child. | 740 | * dccp_create_openreq_child. |
719 | */ | 741 | */ |
720 | dreq = dccp_rsk(req); | 742 | dreq = dccp_rsk(req); |
721 | dreq->dreq_isr = DCCP_SKB_CB(skb)->dccpd_seq; | 743 | dreq->dreq_isr = dcb->dccpd_seq; |
722 | dreq->dreq_iss = dccp_v4_init_sequence(sk, skb); | 744 | dreq->dreq_iss = dccp_v4_init_sequence(sk, skb); |
723 | dreq->dreq_service = dccp_hdr_request(skb)->dccph_req_service; | 745 | dreq->dreq_service = service; |
724 | 746 | ||
725 | if (dccp_v4_send_response(sk, req, dst)) | 747 | if (dccp_v4_send_response(sk, req, dst)) |
726 | goto drop_and_free; | 748 | goto drop_and_free; |
@@ -735,6 +757,7 @@ drop_and_free: | |||
735 | __reqsk_free(req); | 757 | __reqsk_free(req); |
736 | drop: | 758 | drop: |
737 | DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS); | 759 | DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS); |
760 | dcb->dccpd_reset_code = reset_code; | ||
738 | return -1; | 761 | return -1; |
739 | } | 762 | } |
740 | 763 | ||
@@ -1005,7 +1028,6 @@ int dccp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
1005 | return 0; | 1028 | return 0; |
1006 | 1029 | ||
1007 | reset: | 1030 | reset: |
1008 | DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_NO_CONNECTION; | ||
1009 | dccp_v4_ctl_send_reset(skb); | 1031 | dccp_v4_ctl_send_reset(skb); |
1010 | discard: | 1032 | discard: |
1011 | kfree_skb(skb); | 1033 | kfree_skb(skb); |
@@ -1280,6 +1302,7 @@ static int dccp_v4_init_sock(struct sock *sk) | |||
1280 | sk->sk_write_space = dccp_write_space; | 1302 | sk->sk_write_space = dccp_write_space; |
1281 | dp->dccps_mss_cache = 536; | 1303 | dp->dccps_mss_cache = 536; |
1282 | dp->dccps_role = DCCP_ROLE_UNDEFINED; | 1304 | dp->dccps_role = DCCP_ROLE_UNDEFINED; |
1305 | dp->dccps_service = DCCP_SERVICE_INVALID_VALUE; | ||
1283 | 1306 | ||
1284 | return 0; | 1307 | return 0; |
1285 | } | 1308 | } |
@@ -1301,6 +1324,11 @@ static int dccp_v4_destroy_sock(struct sock *sk) | |||
1301 | if (inet_csk(sk)->icsk_bind_hash != NULL) | 1324 | if (inet_csk(sk)->icsk_bind_hash != NULL) |
1302 | inet_put_port(&dccp_hashinfo, sk); | 1325 | inet_put_port(&dccp_hashinfo, sk); |
1303 | 1326 | ||
1327 | if (dp->dccps_service_list != NULL) { | ||
1328 | kfree(dp->dccps_service_list); | ||
1329 | dp->dccps_service_list = NULL; | ||
1330 | } | ||
1331 | |||
1304 | ccid_hc_rx_exit(dp->dccps_hc_rx_ccid, sk); | 1332 | ccid_hc_rx_exit(dp->dccps_hc_rx_ccid, sk); |
1305 | ccid_hc_tx_exit(dp->dccps_hc_tx_ccid, sk); | 1333 | ccid_hc_tx_exit(dp->dccps_hc_tx_ccid, sk); |
1306 | dccp_ackpkts_free(dp->dccps_hc_rx_ackpkts); | 1334 | dccp_ackpkts_free(dp->dccps_hc_rx_ackpkts); |