diff options
Diffstat (limited to 'net/dccp/ipv4.c')
| -rw-r--r-- | net/dccp/ipv4.c | 113 |
1 files changed, 53 insertions, 60 deletions
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 2afaa464e7f0..ae088d1347af 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include <net/tcp_states.h> | 23 | #include <net/tcp_states.h> |
| 24 | #include <net/xfrm.h> | 24 | #include <net/xfrm.h> |
| 25 | 25 | ||
| 26 | #include "ackvec.h" | ||
| 26 | #include "ccid.h" | 27 | #include "ccid.h" |
| 27 | #include "dccp.h" | 28 | #include "dccp.h" |
| 28 | 29 | ||
| @@ -61,27 +62,27 @@ static int __dccp_v4_check_established(struct sock *sk, const __u16 lport, | |||
| 61 | const int dif = sk->sk_bound_dev_if; | 62 | const int dif = sk->sk_bound_dev_if; |
| 62 | INET_ADDR_COOKIE(acookie, saddr, daddr) | 63 | INET_ADDR_COOKIE(acookie, saddr, daddr) |
| 63 | const __u32 ports = INET_COMBINED_PORTS(inet->dport, lport); | 64 | const __u32 ports = INET_COMBINED_PORTS(inet->dport, lport); |
| 64 | const int hash = inet_ehashfn(daddr, lport, saddr, inet->dport, | 65 | unsigned int hash = inet_ehashfn(daddr, lport, saddr, inet->dport); |
| 65 | dccp_hashinfo.ehash_size); | 66 | struct inet_ehash_bucket *head = inet_ehash_bucket(&dccp_hashinfo, hash); |
| 66 | struct inet_ehash_bucket *head = &dccp_hashinfo.ehash[hash]; | ||
| 67 | const struct sock *sk2; | 67 | const struct sock *sk2; |
| 68 | const struct hlist_node *node; | 68 | const struct hlist_node *node; |
| 69 | struct inet_timewait_sock *tw; | 69 | struct inet_timewait_sock *tw; |
| 70 | 70 | ||
| 71 | prefetch(head->chain.first); | ||
| 71 | write_lock(&head->lock); | 72 | write_lock(&head->lock); |
| 72 | 73 | ||
| 73 | /* Check TIME-WAIT sockets first. */ | 74 | /* Check TIME-WAIT sockets first. */ |
| 74 | sk_for_each(sk2, node, &(head + dccp_hashinfo.ehash_size)->chain) { | 75 | sk_for_each(sk2, node, &(head + dccp_hashinfo.ehash_size)->chain) { |
| 75 | tw = inet_twsk(sk2); | 76 | tw = inet_twsk(sk2); |
| 76 | 77 | ||
| 77 | if (INET_TW_MATCH(sk2, acookie, saddr, daddr, ports, dif)) | 78 | if (INET_TW_MATCH(sk2, hash, acookie, saddr, daddr, ports, dif)) |
| 78 | goto not_unique; | 79 | goto not_unique; |
| 79 | } | 80 | } |
| 80 | tw = NULL; | 81 | tw = NULL; |
| 81 | 82 | ||
| 82 | /* And established part... */ | 83 | /* And established part... */ |
| 83 | sk_for_each(sk2, node, &head->chain) { | 84 | sk_for_each(sk2, node, &head->chain) { |
| 84 | if (INET_MATCH(sk2, acookie, saddr, daddr, ports, dif)) | 85 | if (INET_MATCH(sk2, hash, acookie, saddr, daddr, ports, dif)) |
| 85 | goto not_unique; | 86 | goto not_unique; |
| 86 | } | 87 | } |
| 87 | 88 | ||
| @@ -89,7 +90,7 @@ static int __dccp_v4_check_established(struct sock *sk, const __u16 lport, | |||
| 89 | * in hash table socket with a funny identity. */ | 90 | * in hash table socket with a funny identity. */ |
| 90 | inet->num = lport; | 91 | inet->num = lport; |
| 91 | inet->sport = htons(lport); | 92 | inet->sport = htons(lport); |
| 92 | sk->sk_hashent = hash; | 93 | sk->sk_hash = hash; |
| 93 | BUG_TRAP(sk_unhashed(sk)); | 94 | BUG_TRAP(sk_unhashed(sk)); |
| 94 | __sk_add_node(sk, &head->chain); | 95 | __sk_add_node(sk, &head->chain); |
| 95 | sock_prot_inc_use(sk->sk_prot); | 96 | sock_prot_inc_use(sk->sk_prot); |
| @@ -246,6 +247,9 @@ static int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, | |||
| 246 | 247 | ||
| 247 | dp->dccps_role = DCCP_ROLE_CLIENT; | 248 | dp->dccps_role = DCCP_ROLE_CLIENT; |
| 248 | 249 | ||
| 250 | if (dccp_service_not_initialized(sk)) | ||
| 251 | return -EPROTO; | ||
| 252 | |||
| 249 | if (addr_len < sizeof(struct sockaddr_in)) | 253 | if (addr_len < sizeof(struct sockaddr_in)) |
| 250 | return -EINVAL; | 254 | return -EINVAL; |
| 251 | 255 | ||
| @@ -661,6 +665,16 @@ static inline u64 dccp_v4_init_sequence(const struct sock *sk, | |||
| 661 | dccp_hdr(skb)->dccph_sport); | 665 | dccp_hdr(skb)->dccph_sport); |
| 662 | } | 666 | } |
| 663 | 667 | ||
| 668 | static inline int dccp_bad_service_code(const struct sock *sk, | ||
| 669 | const __u32 service) | ||
| 670 | { | ||
| 671 | const struct dccp_sock *dp = dccp_sk(sk); | ||
| 672 | |||
| 673 | if (dp->dccps_service == service) | ||
| 674 | return 0; | ||
| 675 | return !dccp_list_has_service(dp->dccps_service_list, service); | ||
| 676 | } | ||
| 677 | |||
| 664 | int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | 678 | int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) |
| 665 | { | 679 | { |
| 666 | struct inet_request_sock *ireq; | 680 | struct inet_request_sock *ireq; |
| @@ -669,13 +683,22 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
| 669 | struct dccp_request_sock *dreq; | 683 | struct dccp_request_sock *dreq; |
| 670 | const __u32 saddr = skb->nh.iph->saddr; | 684 | const __u32 saddr = skb->nh.iph->saddr; |
| 671 | const __u32 daddr = skb->nh.iph->daddr; | 685 | const __u32 daddr = skb->nh.iph->daddr; |
| 686 | const __u32 service = dccp_hdr_request(skb)->dccph_req_service; | ||
| 687 | struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); | ||
| 688 | __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY; | ||
| 672 | struct dst_entry *dst = NULL; | 689 | struct dst_entry *dst = NULL; |
| 673 | 690 | ||
| 674 | /* Never answer to DCCP_PKT_REQUESTs send to broadcast or multicast */ | 691 | /* Never answer to DCCP_PKT_REQUESTs send to broadcast or multicast */ |
| 675 | if (((struct rtable *)skb->dst)->rt_flags & | 692 | if (((struct rtable *)skb->dst)->rt_flags & |
| 676 | (RTCF_BROADCAST | RTCF_MULTICAST)) | 693 | (RTCF_BROADCAST | RTCF_MULTICAST)) { |
| 694 | reset_code = DCCP_RESET_CODE_NO_CONNECTION; | ||
| 677 | goto drop; | 695 | goto drop; |
| 696 | } | ||
| 678 | 697 | ||
| 698 | if (dccp_bad_service_code(sk, service)) { | ||
| 699 | reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE; | ||
| 700 | goto drop; | ||
| 701 | } | ||
| 679 | /* | 702 | /* |
| 680 | * TW buckets are converted to open requests without | 703 | * TW buckets are converted to open requests without |
| 681 | * limitations, they conserve resources and peer is | 704 | * limitations, they conserve resources and peer is |
| @@ -718,9 +741,9 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
| 718 | * dccp_create_openreq_child. | 741 | * dccp_create_openreq_child. |
| 719 | */ | 742 | */ |
| 720 | dreq = dccp_rsk(req); | 743 | dreq = dccp_rsk(req); |
| 721 | dreq->dreq_isr = DCCP_SKB_CB(skb)->dccpd_seq; | 744 | dreq->dreq_isr = dcb->dccpd_seq; |
| 722 | dreq->dreq_iss = dccp_v4_init_sequence(sk, skb); | 745 | dreq->dreq_iss = dccp_v4_init_sequence(sk, skb); |
| 723 | dreq->dreq_service = dccp_hdr_request(skb)->dccph_req_service; | 746 | dreq->dreq_service = service; |
| 724 | 747 | ||
| 725 | if (dccp_v4_send_response(sk, req, dst)) | 748 | if (dccp_v4_send_response(sk, req, dst)) |
| 726 | goto drop_and_free; | 749 | goto drop_and_free; |
| @@ -735,6 +758,7 @@ drop_and_free: | |||
| 735 | __reqsk_free(req); | 758 | __reqsk_free(req); |
| 736 | drop: | 759 | drop: |
| 737 | DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS); | 760 | DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS); |
| 761 | dcb->dccpd_reset_code = reset_code; | ||
| 738 | return -1; | 762 | return -1; |
| 739 | } | 763 | } |
| 740 | 764 | ||
| @@ -1005,7 +1029,6 @@ int dccp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
| 1005 | return 0; | 1029 | return 0; |
| 1006 | 1030 | ||
| 1007 | reset: | 1031 | reset: |
| 1008 | DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_NO_CONNECTION; | ||
| 1009 | dccp_v4_ctl_send_reset(skb); | 1032 | dccp_v4_ctl_send_reset(skb); |
| 1010 | discard: | 1033 | discard: |
| 1011 | kfree_skb(skb); | 1034 | kfree_skb(skb); |
| @@ -1090,45 +1113,7 @@ int dccp_v4_rcv(struct sk_buff *skb) | |||
| 1090 | goto discard_it; | 1113 | goto discard_it; |
| 1091 | 1114 | ||
| 1092 | dh = dccp_hdr(skb); | 1115 | dh = dccp_hdr(skb); |
| 1093 | #if 0 | ||
| 1094 | /* | ||
| 1095 | * Use something like this to simulate some DATA/DATAACK loss to test | ||
| 1096 | * dccp_ackpkts_add, you'll get something like this on a session that | ||
| 1097 | * sends 10 DATA/DATAACK packets: | ||
| 1098 | * | ||
| 1099 | * ackpkts_print: 281473596467422 |0,0|3,0|0,0|3,0|0,0|3,0|0,0|3,0|0,1| | ||
| 1100 | * | ||
| 1101 | * 0, 0 means: DCCP_ACKPKTS_STATE_RECEIVED, RLE == just this packet | ||
| 1102 | * 0, 1 means: DCCP_ACKPKTS_STATE_RECEIVED, RLE == two adjacent packets | ||
| 1103 | * with the same state | ||
| 1104 | * 3, 0 means: DCCP_ACKPKTS_STATE_NOT_RECEIVED, RLE == just this packet | ||
| 1105 | * | ||
| 1106 | * So... | ||
| 1107 | * | ||
| 1108 | * 281473596467422 was received | ||
| 1109 | * 281473596467421 was not received | ||
| 1110 | * 281473596467420 was received | ||
| 1111 | * 281473596467419 was not received | ||
| 1112 | * 281473596467418 was received | ||
| 1113 | * 281473596467417 was not received | ||
| 1114 | * 281473596467416 was received | ||
| 1115 | * 281473596467415 was not received | ||
| 1116 | * 281473596467414 was received | ||
| 1117 | * 281473596467413 was received (this one was the 3way handshake | ||
| 1118 | * RESPONSE) | ||
| 1119 | * | ||
| 1120 | */ | ||
| 1121 | if (dh->dccph_type == DCCP_PKT_DATA || | ||
| 1122 | dh->dccph_type == DCCP_PKT_DATAACK) { | ||
| 1123 | static int discard = 0; | ||
| 1124 | 1116 | ||
| 1125 | if (discard) { | ||
| 1126 | discard = 0; | ||
| 1127 | goto discard_it; | ||
| 1128 | } | ||
| 1129 | discard = 1; | ||
| 1130 | } | ||
| 1131 | #endif | ||
| 1132 | DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(skb); | 1117 | DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(skb); |
| 1133 | DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type; | 1118 | DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type; |
| 1134 | 1119 | ||
| @@ -1242,11 +1227,9 @@ static int dccp_v4_init_sock(struct sock *sk) | |||
| 1242 | do_gettimeofday(&dp->dccps_epoch); | 1227 | do_gettimeofday(&dp->dccps_epoch); |
| 1243 | 1228 | ||
| 1244 | if (dp->dccps_options.dccpo_send_ack_vector) { | 1229 | if (dp->dccps_options.dccpo_send_ack_vector) { |
| 1245 | dp->dccps_hc_rx_ackpkts = | 1230 | dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(DCCP_MAX_ACKVEC_LEN, |
| 1246 | dccp_ackpkts_alloc(DCCP_MAX_ACK_VECTOR_LEN, | 1231 | GFP_KERNEL); |
| 1247 | GFP_KERNEL); | 1232 | if (dp->dccps_hc_rx_ackvec == NULL) |
| 1248 | |||
| 1249 | if (dp->dccps_hc_rx_ackpkts == NULL) | ||
| 1250 | return -ENOMEM; | 1233 | return -ENOMEM; |
| 1251 | } | 1234 | } |
| 1252 | 1235 | ||
| @@ -1258,16 +1241,18 @@ static int dccp_v4_init_sock(struct sock *sk) | |||
| 1258 | * setsockopt(CCIDs-I-want/accept). -acme | 1241 | * setsockopt(CCIDs-I-want/accept). -acme |
| 1259 | */ | 1242 | */ |
| 1260 | if (likely(!dccp_ctl_socket_init)) { | 1243 | if (likely(!dccp_ctl_socket_init)) { |
| 1261 | dp->dccps_hc_rx_ccid = ccid_init(dp->dccps_options.dccpo_ccid, | 1244 | dp->dccps_hc_rx_ccid = ccid_init(dp->dccps_options.dccpo_rx_ccid, |
| 1262 | sk); | 1245 | sk); |
| 1263 | dp->dccps_hc_tx_ccid = ccid_init(dp->dccps_options.dccpo_ccid, | 1246 | dp->dccps_hc_tx_ccid = ccid_init(dp->dccps_options.dccpo_tx_ccid, |
| 1264 | sk); | 1247 | sk); |
| 1265 | if (dp->dccps_hc_rx_ccid == NULL || | 1248 | if (dp->dccps_hc_rx_ccid == NULL || |
| 1266 | dp->dccps_hc_tx_ccid == NULL) { | 1249 | dp->dccps_hc_tx_ccid == NULL) { |
| 1267 | ccid_exit(dp->dccps_hc_rx_ccid, sk); | 1250 | ccid_exit(dp->dccps_hc_rx_ccid, sk); |
| 1268 | ccid_exit(dp->dccps_hc_tx_ccid, sk); | 1251 | ccid_exit(dp->dccps_hc_tx_ccid, sk); |
| 1269 | dccp_ackpkts_free(dp->dccps_hc_rx_ackpkts); | 1252 | if (dp->dccps_options.dccpo_send_ack_vector) { |
| 1270 | dp->dccps_hc_rx_ackpkts = NULL; | 1253 | dccp_ackvec_free(dp->dccps_hc_rx_ackvec); |
| 1254 | dp->dccps_hc_rx_ackvec = NULL; | ||
| 1255 | } | ||
| 1271 | dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL; | 1256 | dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL; |
| 1272 | return -ENOMEM; | 1257 | return -ENOMEM; |
| 1273 | } | 1258 | } |
| @@ -1280,6 +1265,7 @@ static int dccp_v4_init_sock(struct sock *sk) | |||
| 1280 | sk->sk_write_space = dccp_write_space; | 1265 | sk->sk_write_space = dccp_write_space; |
| 1281 | dp->dccps_mss_cache = 536; | 1266 | dp->dccps_mss_cache = 536; |
| 1282 | dp->dccps_role = DCCP_ROLE_UNDEFINED; | 1267 | dp->dccps_role = DCCP_ROLE_UNDEFINED; |
| 1268 | dp->dccps_service = DCCP_SERVICE_INVALID_VALUE; | ||
| 1283 | 1269 | ||
| 1284 | return 0; | 1270 | return 0; |
| 1285 | } | 1271 | } |
| @@ -1301,10 +1287,17 @@ static int dccp_v4_destroy_sock(struct sock *sk) | |||
| 1301 | if (inet_csk(sk)->icsk_bind_hash != NULL) | 1287 | if (inet_csk(sk)->icsk_bind_hash != NULL) |
| 1302 | inet_put_port(&dccp_hashinfo, sk); | 1288 | inet_put_port(&dccp_hashinfo, sk); |
| 1303 | 1289 | ||
| 1290 | if (dp->dccps_service_list != NULL) { | ||
| 1291 | kfree(dp->dccps_service_list); | ||
| 1292 | dp->dccps_service_list = NULL; | ||
| 1293 | } | ||
| 1294 | |||
| 1304 | ccid_hc_rx_exit(dp->dccps_hc_rx_ccid, sk); | 1295 | ccid_hc_rx_exit(dp->dccps_hc_rx_ccid, sk); |
| 1305 | ccid_hc_tx_exit(dp->dccps_hc_tx_ccid, sk); | 1296 | ccid_hc_tx_exit(dp->dccps_hc_tx_ccid, sk); |
| 1306 | dccp_ackpkts_free(dp->dccps_hc_rx_ackpkts); | 1297 | if (dp->dccps_options.dccpo_send_ack_vector) { |
| 1307 | dp->dccps_hc_rx_ackpkts = NULL; | 1298 | dccp_ackvec_free(dp->dccps_hc_rx_ackvec); |
| 1299 | dp->dccps_hc_rx_ackvec = NULL; | ||
| 1300 | } | ||
| 1308 | ccid_exit(dp->dccps_hc_rx_ccid, sk); | 1301 | ccid_exit(dp->dccps_hc_rx_ccid, sk); |
| 1309 | ccid_exit(dp->dccps_hc_tx_ccid, sk); | 1302 | ccid_exit(dp->dccps_hc_tx_ccid, sk); |
| 1310 | dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL; | 1303 | dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL; |
