diff options
Diffstat (limited to 'net/dccp/ipv4.c')
-rw-r--r-- | net/dccp/ipv4.c | 333 |
1 files changed, 159 insertions, 174 deletions
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index dc0487b5bace..29047995c695 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c | |||
@@ -18,8 +18,10 @@ | |||
18 | #include <linux/random.h> | 18 | #include <linux/random.h> |
19 | 19 | ||
20 | #include <net/icmp.h> | 20 | #include <net/icmp.h> |
21 | #include <net/inet_common.h> | ||
21 | #include <net/inet_hashtables.h> | 22 | #include <net/inet_hashtables.h> |
22 | #include <net/inet_sock.h> | 23 | #include <net/inet_sock.h> |
24 | #include <net/protocol.h> | ||
23 | #include <net/sock.h> | 25 | #include <net/sock.h> |
24 | #include <net/timewait_sock.h> | 26 | #include <net/timewait_sock.h> |
25 | #include <net/tcp_states.h> | 27 | #include <net/tcp_states.h> |
@@ -28,14 +30,14 @@ | |||
28 | #include "ackvec.h" | 30 | #include "ackvec.h" |
29 | #include "ccid.h" | 31 | #include "ccid.h" |
30 | #include "dccp.h" | 32 | #include "dccp.h" |
33 | #include "feat.h" | ||
31 | 34 | ||
32 | struct inet_hashinfo __cacheline_aligned dccp_hashinfo = { | 35 | /* |
33 | .lhash_lock = RW_LOCK_UNLOCKED, | 36 | * This is the global socket data structure used for responding to |
34 | .lhash_users = ATOMIC_INIT(0), | 37 | * the Out-of-the-blue (OOTB) packets. A control sock will be created |
35 | .lhash_wait = __WAIT_QUEUE_HEAD_INITIALIZER(dccp_hashinfo.lhash_wait), | 38 | * for this socket at the initialization time. |
36 | }; | 39 | */ |
37 | 40 | static struct socket *dccp_v4_ctl_socket; | |
38 | EXPORT_SYMBOL_GPL(dccp_hashinfo); | ||
39 | 41 | ||
40 | static int dccp_v4_get_port(struct sock *sk, const unsigned short snum) | 42 | static int dccp_v4_get_port(struct sock *sk, const unsigned short snum) |
41 | { | 43 | { |
@@ -43,18 +45,6 @@ static int dccp_v4_get_port(struct sock *sk, const unsigned short snum) | |||
43 | inet_csk_bind_conflict); | 45 | inet_csk_bind_conflict); |
44 | } | 46 | } |
45 | 47 | ||
46 | static void dccp_v4_hash(struct sock *sk) | ||
47 | { | ||
48 | inet_hash(&dccp_hashinfo, sk); | ||
49 | } | ||
50 | |||
51 | void dccp_unhash(struct sock *sk) | ||
52 | { | ||
53 | inet_unhash(&dccp_hashinfo, sk); | ||
54 | } | ||
55 | |||
56 | EXPORT_SYMBOL_GPL(dccp_unhash); | ||
57 | |||
58 | int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | 48 | int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) |
59 | { | 49 | { |
60 | struct inet_sock *inet = inet_sk(sk); | 50 | struct inet_sock *inet = inet_sk(sk); |
@@ -207,11 +197,12 @@ static inline void dccp_do_pmtu_discovery(struct sock *sk, | |||
207 | } /* else let the usual retransmit timer handle it */ | 197 | } /* else let the usual retransmit timer handle it */ |
208 | } | 198 | } |
209 | 199 | ||
210 | static void dccp_v4_ctl_send_ack(struct sk_buff *rxskb) | 200 | static void dccp_v4_reqsk_send_ack(struct sk_buff *rxskb, |
201 | struct request_sock *req) | ||
211 | { | 202 | { |
212 | int err; | 203 | int err; |
213 | struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh; | 204 | struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh; |
214 | const int dccp_hdr_ack_len = sizeof(struct dccp_hdr) + | 205 | const u32 dccp_hdr_ack_len = sizeof(struct dccp_hdr) + |
215 | sizeof(struct dccp_hdr_ext) + | 206 | sizeof(struct dccp_hdr_ext) + |
216 | sizeof(struct dccp_hdr_ack_bits); | 207 | sizeof(struct dccp_hdr_ack_bits); |
217 | struct sk_buff *skb; | 208 | struct sk_buff *skb; |
@@ -219,12 +210,12 @@ static void dccp_v4_ctl_send_ack(struct sk_buff *rxskb) | |||
219 | if (((struct rtable *)rxskb->dst)->rt_type != RTN_LOCAL) | 210 | if (((struct rtable *)rxskb->dst)->rt_type != RTN_LOCAL) |
220 | return; | 211 | return; |
221 | 212 | ||
222 | skb = alloc_skb(MAX_DCCP_HEADER + 15, GFP_ATOMIC); | 213 | skb = alloc_skb(dccp_v4_ctl_socket->sk->sk_prot->max_header, GFP_ATOMIC); |
223 | if (skb == NULL) | 214 | if (skb == NULL) |
224 | return; | 215 | return; |
225 | 216 | ||
226 | /* Reserve space for headers. */ | 217 | /* Reserve space for headers. */ |
227 | skb_reserve(skb, MAX_DCCP_HEADER); | 218 | skb_reserve(skb, dccp_v4_ctl_socket->sk->sk_prot->max_header); |
228 | 219 | ||
229 | skb->dst = dst_clone(rxskb->dst); | 220 | skb->dst = dst_clone(rxskb->dst); |
230 | 221 | ||
@@ -243,11 +234,11 @@ static void dccp_v4_ctl_send_ack(struct sk_buff *rxskb) | |||
243 | dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), | 234 | dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), |
244 | DCCP_SKB_CB(rxskb)->dccpd_seq); | 235 | DCCP_SKB_CB(rxskb)->dccpd_seq); |
245 | 236 | ||
246 | bh_lock_sock(dccp_ctl_socket->sk); | 237 | bh_lock_sock(dccp_v4_ctl_socket->sk); |
247 | err = ip_build_and_send_pkt(skb, dccp_ctl_socket->sk, | 238 | err = ip_build_and_send_pkt(skb, dccp_v4_ctl_socket->sk, |
248 | rxskb->nh.iph->daddr, | 239 | rxskb->nh.iph->daddr, |
249 | rxskb->nh.iph->saddr, NULL); | 240 | rxskb->nh.iph->saddr, NULL); |
250 | bh_unlock_sock(dccp_ctl_socket->sk); | 241 | bh_unlock_sock(dccp_v4_ctl_socket->sk); |
251 | 242 | ||
252 | if (err == NET_XMIT_CN || err == 0) { | 243 | if (err == NET_XMIT_CN || err == 0) { |
253 | DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS); | 244 | DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS); |
@@ -255,12 +246,6 @@ static void dccp_v4_ctl_send_ack(struct sk_buff *rxskb) | |||
255 | } | 246 | } |
256 | } | 247 | } |
257 | 248 | ||
258 | static void dccp_v4_reqsk_send_ack(struct sk_buff *skb, | ||
259 | struct request_sock *req) | ||
260 | { | ||
261 | dccp_v4_ctl_send_ack(skb); | ||
262 | } | ||
263 | |||
264 | static int dccp_v4_send_response(struct sock *sk, struct request_sock *req, | 249 | static int dccp_v4_send_response(struct sock *sk, struct request_sock *req, |
265 | struct dst_entry *dst) | 250 | struct dst_entry *dst) |
266 | { | 251 | { |
@@ -275,7 +260,10 @@ static int dccp_v4_send_response(struct sock *sk, struct request_sock *req, | |||
275 | skb = dccp_make_response(sk, dst, req); | 260 | skb = dccp_make_response(sk, dst, req); |
276 | if (skb != NULL) { | 261 | if (skb != NULL) { |
277 | const struct inet_request_sock *ireq = inet_rsk(req); | 262 | const struct inet_request_sock *ireq = inet_rsk(req); |
263 | struct dccp_hdr *dh = dccp_hdr(skb); | ||
278 | 264 | ||
265 | dh->dccph_checksum = dccp_v4_checksum(skb, ireq->loc_addr, | ||
266 | ireq->rmt_addr); | ||
279 | memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); | 267 | memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); |
280 | err = ip_build_and_send_pkt(skb, sk, ireq->loc_addr, | 268 | err = ip_build_and_send_pkt(skb, sk, ireq->loc_addr, |
281 | ireq->rmt_addr, | 269 | ireq->rmt_addr, |
@@ -301,7 +289,7 @@ out: | |||
301 | * check at all. A more general error queue to queue errors for later handling | 289 | * check at all. A more general error queue to queue errors for later handling |
302 | * is probably better. | 290 | * is probably better. |
303 | */ | 291 | */ |
304 | void dccp_v4_err(struct sk_buff *skb, u32 info) | 292 | static void dccp_v4_err(struct sk_buff *skb, u32 info) |
305 | { | 293 | { |
306 | const struct iphdr *iph = (struct iphdr *)skb->data; | 294 | const struct iphdr *iph = (struct iphdr *)skb->data; |
307 | const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + | 295 | const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + |
@@ -456,32 +444,6 @@ void dccp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb) | |||
456 | 444 | ||
457 | EXPORT_SYMBOL_GPL(dccp_v4_send_check); | 445 | EXPORT_SYMBOL_GPL(dccp_v4_send_check); |
458 | 446 | ||
459 | int dccp_v4_send_reset(struct sock *sk, enum dccp_reset_codes code) | ||
460 | { | ||
461 | struct sk_buff *skb; | ||
462 | /* | ||
463 | * FIXME: what if rebuild_header fails? | ||
464 | * Should we be doing a rebuild_header here? | ||
465 | */ | ||
466 | int err = inet_sk_rebuild_header(sk); | ||
467 | |||
468 | if (err != 0) | ||
469 | return err; | ||
470 | |||
471 | skb = dccp_make_reset(sk, sk->sk_dst_cache, code); | ||
472 | if (skb != NULL) { | ||
473 | const struct inet_sock *inet = inet_sk(sk); | ||
474 | |||
475 | memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); | ||
476 | err = ip_build_and_send_pkt(skb, sk, | ||
477 | inet->saddr, inet->daddr, NULL); | ||
478 | if (err == NET_XMIT_CN) | ||
479 | err = 0; | ||
480 | } | ||
481 | |||
482 | return err; | ||
483 | } | ||
484 | |||
485 | static inline u64 dccp_v4_init_sequence(const struct sock *sk, | 447 | static inline u64 dccp_v4_init_sequence(const struct sock *sk, |
486 | const struct sk_buff *skb) | 448 | const struct sk_buff *skb) |
487 | { | 449 | { |
@@ -497,9 +459,9 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
497 | struct dccp_sock dp; | 459 | struct dccp_sock dp; |
498 | struct request_sock *req; | 460 | struct request_sock *req; |
499 | struct dccp_request_sock *dreq; | 461 | struct dccp_request_sock *dreq; |
500 | const __u32 saddr = skb->nh.iph->saddr; | 462 | const __be32 saddr = skb->nh.iph->saddr; |
501 | const __u32 daddr = skb->nh.iph->daddr; | 463 | const __be32 daddr = skb->nh.iph->daddr; |
502 | const __u32 service = dccp_hdr_request(skb)->dccph_req_service; | 464 | const __be32 service = dccp_hdr_request(skb)->dccph_req_service; |
503 | struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); | 465 | struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); |
504 | __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY; | 466 | __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY; |
505 | 467 | ||
@@ -535,7 +497,8 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
535 | if (req == NULL) | 497 | if (req == NULL) |
536 | goto drop; | 498 | goto drop; |
537 | 499 | ||
538 | /* FIXME: process options */ | 500 | if (dccp_parse_options(sk, skb)) |
501 | goto drop; | ||
539 | 502 | ||
540 | dccp_openreq_init(req, &dp, skb); | 503 | dccp_openreq_init(req, &dp, skb); |
541 | 504 | ||
@@ -660,8 +623,8 @@ static struct sock *dccp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) | |||
660 | return sk; | 623 | return sk; |
661 | } | 624 | } |
662 | 625 | ||
663 | int dccp_v4_checksum(const struct sk_buff *skb, const u32 saddr, | 626 | int dccp_v4_checksum(const struct sk_buff *skb, const __be32 saddr, |
664 | const u32 daddr) | 627 | const __be32 daddr) |
665 | { | 628 | { |
666 | const struct dccp_hdr* dh = dccp_hdr(skb); | 629 | const struct dccp_hdr* dh = dccp_hdr(skb); |
667 | int checksum_len; | 630 | int checksum_len; |
@@ -680,8 +643,10 @@ int dccp_v4_checksum(const struct sk_buff *skb, const u32 saddr, | |||
680 | IPPROTO_DCCP, tmp); | 643 | IPPROTO_DCCP, tmp); |
681 | } | 644 | } |
682 | 645 | ||
646 | EXPORT_SYMBOL_GPL(dccp_v4_checksum); | ||
647 | |||
683 | static int dccp_v4_verify_checksum(struct sk_buff *skb, | 648 | static int dccp_v4_verify_checksum(struct sk_buff *skb, |
684 | const u32 saddr, const u32 daddr) | 649 | const __be32 saddr, const __be32 daddr) |
685 | { | 650 | { |
686 | struct dccp_hdr *dh = dccp_hdr(skb); | 651 | struct dccp_hdr *dh = dccp_hdr(skb); |
687 | int checksum_len; | 652 | int checksum_len; |
@@ -741,16 +706,17 @@ static void dccp_v4_ctl_send_reset(struct sk_buff *rxskb) | |||
741 | if (((struct rtable *)rxskb->dst)->rt_type != RTN_LOCAL) | 706 | if (((struct rtable *)rxskb->dst)->rt_type != RTN_LOCAL) |
742 | return; | 707 | return; |
743 | 708 | ||
744 | dst = dccp_v4_route_skb(dccp_ctl_socket->sk, rxskb); | 709 | dst = dccp_v4_route_skb(dccp_v4_ctl_socket->sk, rxskb); |
745 | if (dst == NULL) | 710 | if (dst == NULL) |
746 | return; | 711 | return; |
747 | 712 | ||
748 | skb = alloc_skb(MAX_DCCP_HEADER + 15, GFP_ATOMIC); | 713 | skb = alloc_skb(dccp_v4_ctl_socket->sk->sk_prot->max_header, |
714 | GFP_ATOMIC); | ||
749 | if (skb == NULL) | 715 | if (skb == NULL) |
750 | goto out; | 716 | goto out; |
751 | 717 | ||
752 | /* Reserve space for headers. */ | 718 | /* Reserve space for headers. */ |
753 | skb_reserve(skb, MAX_DCCP_HEADER); | 719 | skb_reserve(skb, dccp_v4_ctl_socket->sk->sk_prot->max_header); |
754 | skb->dst = dst_clone(dst); | 720 | skb->dst = dst_clone(dst); |
755 | 721 | ||
756 | skb->h.raw = skb_push(skb, dccp_hdr_reset_len); | 722 | skb->h.raw = skb_push(skb, dccp_hdr_reset_len); |
@@ -778,11 +744,11 @@ static void dccp_v4_ctl_send_reset(struct sk_buff *rxskb) | |||
778 | dh->dccph_checksum = dccp_v4_checksum(skb, rxskb->nh.iph->saddr, | 744 | dh->dccph_checksum = dccp_v4_checksum(skb, rxskb->nh.iph->saddr, |
779 | rxskb->nh.iph->daddr); | 745 | rxskb->nh.iph->daddr); |
780 | 746 | ||
781 | bh_lock_sock(dccp_ctl_socket->sk); | 747 | bh_lock_sock(dccp_v4_ctl_socket->sk); |
782 | err = ip_build_and_send_pkt(skb, dccp_ctl_socket->sk, | 748 | err = ip_build_and_send_pkt(skb, dccp_v4_ctl_socket->sk, |
783 | rxskb->nh.iph->daddr, | 749 | rxskb->nh.iph->daddr, |
784 | rxskb->nh.iph->saddr, NULL); | 750 | rxskb->nh.iph->saddr, NULL); |
785 | bh_unlock_sock(dccp_ctl_socket->sk); | 751 | bh_unlock_sock(dccp_v4_ctl_socket->sk); |
786 | 752 | ||
787 | if (err == NET_XMIT_CN || err == 0) { | 753 | if (err == NET_XMIT_CN || err == 0) { |
788 | DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS); | 754 | DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS); |
@@ -912,7 +878,7 @@ int dccp_invalid_packet(struct sk_buff *skb) | |||
912 | EXPORT_SYMBOL_GPL(dccp_invalid_packet); | 878 | EXPORT_SYMBOL_GPL(dccp_invalid_packet); |
913 | 879 | ||
914 | /* this is called when real data arrives */ | 880 | /* this is called when real data arrives */ |
915 | int dccp_v4_rcv(struct sk_buff *skb) | 881 | static int dccp_v4_rcv(struct sk_buff *skb) |
916 | { | 882 | { |
917 | const struct dccp_hdr *dh; | 883 | const struct dccp_hdr *dh; |
918 | struct sock *sk; | 884 | struct sock *sk; |
@@ -1019,111 +985,37 @@ do_time_wait: | |||
1019 | goto no_dccp_socket; | 985 | goto no_dccp_socket; |
1020 | } | 986 | } |
1021 | 987 | ||
1022 | struct inet_connection_sock_af_ops dccp_ipv4_af_ops = { | 988 | static struct inet_connection_sock_af_ops dccp_ipv4_af_ops = { |
1023 | .queue_xmit = ip_queue_xmit, | 989 | .queue_xmit = ip_queue_xmit, |
1024 | .send_check = dccp_v4_send_check, | 990 | .send_check = dccp_v4_send_check, |
1025 | .rebuild_header = inet_sk_rebuild_header, | 991 | .rebuild_header = inet_sk_rebuild_header, |
1026 | .conn_request = dccp_v4_conn_request, | 992 | .conn_request = dccp_v4_conn_request, |
1027 | .syn_recv_sock = dccp_v4_request_recv_sock, | 993 | .syn_recv_sock = dccp_v4_request_recv_sock, |
1028 | .net_header_len = sizeof(struct iphdr), | 994 | .net_header_len = sizeof(struct iphdr), |
1029 | .setsockopt = ip_setsockopt, | 995 | .setsockopt = ip_setsockopt, |
1030 | .getsockopt = ip_getsockopt, | 996 | .getsockopt = ip_getsockopt, |
1031 | .addr2sockaddr = inet_csk_addr2sockaddr, | 997 | .addr2sockaddr = inet_csk_addr2sockaddr, |
1032 | .sockaddr_len = sizeof(struct sockaddr_in), | 998 | .sockaddr_len = sizeof(struct sockaddr_in), |
999 | #ifdef CONFIG_COMPAT | ||
1000 | .compat_setsockopt = compat_ip_setsockopt, | ||
1001 | .compat_getsockopt = compat_ip_getsockopt, | ||
1002 | #endif | ||
1033 | }; | 1003 | }; |
1034 | 1004 | ||
1035 | int dccp_v4_init_sock(struct sock *sk) | 1005 | static int dccp_v4_init_sock(struct sock *sk) |
1036 | { | ||
1037 | struct dccp_sock *dp = dccp_sk(sk); | ||
1038 | struct inet_connection_sock *icsk = inet_csk(sk); | ||
1039 | static int dccp_ctl_socket_init = 1; | ||
1040 | |||
1041 | dccp_options_init(&dp->dccps_options); | ||
1042 | do_gettimeofday(&dp->dccps_epoch); | ||
1043 | |||
1044 | if (dp->dccps_options.dccpo_send_ack_vector) { | ||
1045 | dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(DCCP_MAX_ACKVEC_LEN, | ||
1046 | GFP_KERNEL); | ||
1047 | if (dp->dccps_hc_rx_ackvec == NULL) | ||
1048 | return -ENOMEM; | ||
1049 | } | ||
1050 | |||
1051 | /* | ||
1052 | * FIXME: We're hardcoding the CCID, and doing this at this point makes | ||
1053 | * the listening (master) sock get CCID control blocks, which is not | ||
1054 | * necessary, but for now, to not mess with the test userspace apps, | ||
1055 | * lets leave it here, later the real solution is to do this in a | ||
1056 | * setsockopt(CCIDs-I-want/accept). -acme | ||
1057 | */ | ||
1058 | if (likely(!dccp_ctl_socket_init)) { | ||
1059 | dp->dccps_hc_rx_ccid = ccid_init(dp->dccps_options.dccpo_rx_ccid, | ||
1060 | sk); | ||
1061 | dp->dccps_hc_tx_ccid = ccid_init(dp->dccps_options.dccpo_tx_ccid, | ||
1062 | sk); | ||
1063 | if (dp->dccps_hc_rx_ccid == NULL || | ||
1064 | dp->dccps_hc_tx_ccid == NULL) { | ||
1065 | ccid_exit(dp->dccps_hc_rx_ccid, sk); | ||
1066 | ccid_exit(dp->dccps_hc_tx_ccid, sk); | ||
1067 | if (dp->dccps_options.dccpo_send_ack_vector) { | ||
1068 | dccp_ackvec_free(dp->dccps_hc_rx_ackvec); | ||
1069 | dp->dccps_hc_rx_ackvec = NULL; | ||
1070 | } | ||
1071 | dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL; | ||
1072 | return -ENOMEM; | ||
1073 | } | ||
1074 | } else | ||
1075 | dccp_ctl_socket_init = 0; | ||
1076 | |||
1077 | dccp_init_xmit_timers(sk); | ||
1078 | icsk->icsk_rto = DCCP_TIMEOUT_INIT; | ||
1079 | sk->sk_state = DCCP_CLOSED; | ||
1080 | sk->sk_write_space = dccp_write_space; | ||
1081 | icsk->icsk_af_ops = &dccp_ipv4_af_ops; | ||
1082 | icsk->icsk_sync_mss = dccp_sync_mss; | ||
1083 | dp->dccps_mss_cache = 536; | ||
1084 | dp->dccps_role = DCCP_ROLE_UNDEFINED; | ||
1085 | dp->dccps_service = DCCP_SERVICE_INVALID_VALUE; | ||
1086 | |||
1087 | return 0; | ||
1088 | } | ||
1089 | |||
1090 | EXPORT_SYMBOL_GPL(dccp_v4_init_sock); | ||
1091 | |||
1092 | int dccp_v4_destroy_sock(struct sock *sk) | ||
1093 | { | 1006 | { |
1094 | struct dccp_sock *dp = dccp_sk(sk); | 1007 | static __u8 dccp_v4_ctl_sock_initialized; |
1008 | int err = dccp_init_sock(sk, dccp_v4_ctl_sock_initialized); | ||
1095 | 1009 | ||
1096 | /* | 1010 | if (err == 0) { |
1097 | * DCCP doesn't use sk_write_queue, just sk_send_head | 1011 | if (unlikely(!dccp_v4_ctl_sock_initialized)) |
1098 | * for retransmissions | 1012 | dccp_v4_ctl_sock_initialized = 1; |
1099 | */ | 1013 | inet_csk(sk)->icsk_af_ops = &dccp_ipv4_af_ops; |
1100 | if (sk->sk_send_head != NULL) { | ||
1101 | kfree_skb(sk->sk_send_head); | ||
1102 | sk->sk_send_head = NULL; | ||
1103 | } | 1014 | } |
1104 | 1015 | ||
1105 | /* Clean up a referenced DCCP bind bucket. */ | 1016 | return err; |
1106 | if (inet_csk(sk)->icsk_bind_hash != NULL) | ||
1107 | inet_put_port(&dccp_hashinfo, sk); | ||
1108 | |||
1109 | kfree(dp->dccps_service_list); | ||
1110 | dp->dccps_service_list = NULL; | ||
1111 | |||
1112 | ccid_hc_rx_exit(dp->dccps_hc_rx_ccid, sk); | ||
1113 | ccid_hc_tx_exit(dp->dccps_hc_tx_ccid, sk); | ||
1114 | if (dp->dccps_options.dccpo_send_ack_vector) { | ||
1115 | dccp_ackvec_free(dp->dccps_hc_rx_ackvec); | ||
1116 | dp->dccps_hc_rx_ackvec = NULL; | ||
1117 | } | ||
1118 | ccid_exit(dp->dccps_hc_rx_ccid, sk); | ||
1119 | ccid_exit(dp->dccps_hc_tx_ccid, sk); | ||
1120 | dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL; | ||
1121 | |||
1122 | return 0; | ||
1123 | } | 1017 | } |
1124 | 1018 | ||
1125 | EXPORT_SYMBOL_GPL(dccp_v4_destroy_sock); | ||
1126 | |||
1127 | static void dccp_v4_reqsk_destructor(struct request_sock *req) | 1019 | static void dccp_v4_reqsk_destructor(struct request_sock *req) |
1128 | { | 1020 | { |
1129 | kfree(inet_rsk(req)->opt); | 1021 | kfree(inet_rsk(req)->opt); |
@@ -1142,7 +1034,7 @@ static struct timewait_sock_ops dccp_timewait_sock_ops = { | |||
1142 | .twsk_obj_size = sizeof(struct inet_timewait_sock), | 1034 | .twsk_obj_size = sizeof(struct inet_timewait_sock), |
1143 | }; | 1035 | }; |
1144 | 1036 | ||
1145 | struct proto dccp_prot = { | 1037 | static struct proto dccp_v4_prot = { |
1146 | .name = "DCCP", | 1038 | .name = "DCCP", |
1147 | .owner = THIS_MODULE, | 1039 | .owner = THIS_MODULE, |
1148 | .close = dccp_close, | 1040 | .close = dccp_close, |
@@ -1155,17 +1047,110 @@ struct proto dccp_prot = { | |||
1155 | .sendmsg = dccp_sendmsg, | 1047 | .sendmsg = dccp_sendmsg, |
1156 | .recvmsg = dccp_recvmsg, | 1048 | .recvmsg = dccp_recvmsg, |
1157 | .backlog_rcv = dccp_v4_do_rcv, | 1049 | .backlog_rcv = dccp_v4_do_rcv, |
1158 | .hash = dccp_v4_hash, | 1050 | .hash = dccp_hash, |
1159 | .unhash = dccp_unhash, | 1051 | .unhash = dccp_unhash, |
1160 | .accept = inet_csk_accept, | 1052 | .accept = inet_csk_accept, |
1161 | .get_port = dccp_v4_get_port, | 1053 | .get_port = dccp_v4_get_port, |
1162 | .shutdown = dccp_shutdown, | 1054 | .shutdown = dccp_shutdown, |
1163 | .destroy = dccp_v4_destroy_sock, | 1055 | .destroy = dccp_destroy_sock, |
1164 | .orphan_count = &dccp_orphan_count, | 1056 | .orphan_count = &dccp_orphan_count, |
1165 | .max_header = MAX_DCCP_HEADER, | 1057 | .max_header = MAX_DCCP_HEADER, |
1166 | .obj_size = sizeof(struct dccp_sock), | 1058 | .obj_size = sizeof(struct dccp_sock), |
1167 | .rsk_prot = &dccp_request_sock_ops, | 1059 | .rsk_prot = &dccp_request_sock_ops, |
1168 | .twsk_prot = &dccp_timewait_sock_ops, | 1060 | .twsk_prot = &dccp_timewait_sock_ops, |
1061 | #ifdef CONFIG_COMPAT | ||
1062 | .compat_setsockopt = compat_dccp_setsockopt, | ||
1063 | .compat_getsockopt = compat_dccp_getsockopt, | ||
1064 | #endif | ||
1065 | }; | ||
1066 | |||
1067 | static struct net_protocol dccp_v4_protocol = { | ||
1068 | .handler = dccp_v4_rcv, | ||
1069 | .err_handler = dccp_v4_err, | ||
1070 | .no_policy = 1, | ||
1071 | }; | ||
1072 | |||
1073 | static const struct proto_ops inet_dccp_ops = { | ||
1074 | .family = PF_INET, | ||
1075 | .owner = THIS_MODULE, | ||
1076 | .release = inet_release, | ||
1077 | .bind = inet_bind, | ||
1078 | .connect = inet_stream_connect, | ||
1079 | .socketpair = sock_no_socketpair, | ||
1080 | .accept = inet_accept, | ||
1081 | .getname = inet_getname, | ||
1082 | /* FIXME: work on tcp_poll to rename it to inet_csk_poll */ | ||
1083 | .poll = dccp_poll, | ||
1084 | .ioctl = inet_ioctl, | ||
1085 | /* FIXME: work on inet_listen to rename it to sock_common_listen */ | ||
1086 | .listen = inet_dccp_listen, | ||
1087 | .shutdown = inet_shutdown, | ||
1088 | .setsockopt = sock_common_setsockopt, | ||
1089 | .getsockopt = sock_common_getsockopt, | ||
1090 | .sendmsg = inet_sendmsg, | ||
1091 | .recvmsg = sock_common_recvmsg, | ||
1092 | .mmap = sock_no_mmap, | ||
1093 | .sendpage = sock_no_sendpage, | ||
1094 | #ifdef CONFIG_COMPAT | ||
1095 | .compat_setsockopt = compat_sock_common_setsockopt, | ||
1096 | .compat_getsockopt = compat_sock_common_getsockopt, | ||
1097 | #endif | ||
1169 | }; | 1098 | }; |
1170 | 1099 | ||
1171 | EXPORT_SYMBOL_GPL(dccp_prot); | 1100 | static struct inet_protosw dccp_v4_protosw = { |
1101 | .type = SOCK_DCCP, | ||
1102 | .protocol = IPPROTO_DCCP, | ||
1103 | .prot = &dccp_v4_prot, | ||
1104 | .ops = &inet_dccp_ops, | ||
1105 | .capability = -1, | ||
1106 | .no_check = 0, | ||
1107 | .flags = INET_PROTOSW_ICSK, | ||
1108 | }; | ||
1109 | |||
1110 | static int __init dccp_v4_init(void) | ||
1111 | { | ||
1112 | int err = proto_register(&dccp_v4_prot, 1); | ||
1113 | |||
1114 | if (err != 0) | ||
1115 | goto out; | ||
1116 | |||
1117 | err = inet_add_protocol(&dccp_v4_protocol, IPPROTO_DCCP); | ||
1118 | if (err != 0) | ||
1119 | goto out_proto_unregister; | ||
1120 | |||
1121 | inet_register_protosw(&dccp_v4_protosw); | ||
1122 | |||
1123 | err = inet_csk_ctl_sock_create(&dccp_v4_ctl_socket, PF_INET, | ||
1124 | SOCK_DCCP, IPPROTO_DCCP); | ||
1125 | if (err) | ||
1126 | goto out_unregister_protosw; | ||
1127 | out: | ||
1128 | return err; | ||
1129 | out_unregister_protosw: | ||
1130 | inet_unregister_protosw(&dccp_v4_protosw); | ||
1131 | inet_del_protocol(&dccp_v4_protocol, IPPROTO_DCCP); | ||
1132 | out_proto_unregister: | ||
1133 | proto_unregister(&dccp_v4_prot); | ||
1134 | goto out; | ||
1135 | } | ||
1136 | |||
1137 | static void __exit dccp_v4_exit(void) | ||
1138 | { | ||
1139 | inet_unregister_protosw(&dccp_v4_protosw); | ||
1140 | inet_del_protocol(&dccp_v4_protocol, IPPROTO_DCCP); | ||
1141 | proto_unregister(&dccp_v4_prot); | ||
1142 | } | ||
1143 | |||
1144 | module_init(dccp_v4_init); | ||
1145 | module_exit(dccp_v4_exit); | ||
1146 | |||
1147 | /* | ||
1148 | * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33) | ||
1149 | * values directly, Also cover the case where the protocol is not specified, | ||
1150 | * i.e. net-pf-PF_INET-proto-0-type-SOCK_DCCP | ||
1151 | */ | ||
1152 | MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-33-type-6"); | ||
1153 | MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-0-type-6"); | ||
1154 | MODULE_LICENSE("GPL"); | ||
1155 | MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>"); | ||
1156 | MODULE_DESCRIPTION("DCCP - Datagram Congestion Controlled Protocol"); | ||