diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-04 19:27:41 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-04 19:27:41 -0500 |
commit | d347da0deffa1d8f88f0d270eab040e4707c9916 (patch) | |
tree | e0911f2ef4d36a7b44f7a5379feabebbd37dcfc4 /net/dccp/ipv4.c | |
parent | c6c88bbde4d8b2ffe9886b7130b2e23781d424e5 (diff) | |
parent | 74cb8798222bb7d1aecb0acb91e6eeedf5feb948 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
Diffstat (limited to 'net/dccp/ipv4.c')
-rw-r--r-- | net/dccp/ipv4.c | 305 |
1 files changed, 77 insertions, 228 deletions
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 656e13e38cfb..3f244670764a 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c | |||
@@ -19,7 +19,9 @@ | |||
19 | 19 | ||
20 | #include <net/icmp.h> | 20 | #include <net/icmp.h> |
21 | #include <net/inet_hashtables.h> | 21 | #include <net/inet_hashtables.h> |
22 | #include <net/inet_sock.h> | ||
22 | #include <net/sock.h> | 23 | #include <net/sock.h> |
24 | #include <net/timewait_sock.h> | ||
23 | #include <net/tcp_states.h> | 25 | #include <net/tcp_states.h> |
24 | #include <net/xfrm.h> | 26 | #include <net/xfrm.h> |
25 | 27 | ||
@@ -37,7 +39,8 @@ EXPORT_SYMBOL_GPL(dccp_hashinfo); | |||
37 | 39 | ||
38 | static int dccp_v4_get_port(struct sock *sk, const unsigned short snum) | 40 | static int dccp_v4_get_port(struct sock *sk, const unsigned short snum) |
39 | { | 41 | { |
40 | return inet_csk_get_port(&dccp_hashinfo, sk, snum); | 42 | return inet_csk_get_port(&dccp_hashinfo, sk, snum, |
43 | inet_csk_bind_conflict); | ||
41 | } | 44 | } |
42 | 45 | ||
43 | static void dccp_v4_hash(struct sock *sk) | 46 | static void dccp_v4_hash(struct sock *sk) |
@@ -45,171 +48,14 @@ static void dccp_v4_hash(struct sock *sk) | |||
45 | inet_hash(&dccp_hashinfo, sk); | 48 | inet_hash(&dccp_hashinfo, sk); |
46 | } | 49 | } |
47 | 50 | ||
48 | static void dccp_v4_unhash(struct sock *sk) | 51 | void dccp_unhash(struct sock *sk) |
49 | { | 52 | { |
50 | inet_unhash(&dccp_hashinfo, sk); | 53 | inet_unhash(&dccp_hashinfo, sk); |
51 | } | 54 | } |
52 | 55 | ||
53 | /* called with local bh disabled */ | 56 | EXPORT_SYMBOL_GPL(dccp_unhash); |
54 | static int __dccp_v4_check_established(struct sock *sk, const __u16 lport, | ||
55 | struct inet_timewait_sock **twp) | ||
56 | { | ||
57 | struct inet_sock *inet = inet_sk(sk); | ||
58 | const u32 daddr = inet->rcv_saddr; | ||
59 | const u32 saddr = inet->daddr; | ||
60 | const int dif = sk->sk_bound_dev_if; | ||
61 | INET_ADDR_COOKIE(acookie, saddr, daddr) | ||
62 | const __u32 ports = INET_COMBINED_PORTS(inet->dport, lport); | ||
63 | unsigned int hash = inet_ehashfn(daddr, lport, saddr, inet->dport); | ||
64 | struct inet_ehash_bucket *head = inet_ehash_bucket(&dccp_hashinfo, hash); | ||
65 | const struct sock *sk2; | ||
66 | const struct hlist_node *node; | ||
67 | struct inet_timewait_sock *tw; | ||
68 | |||
69 | prefetch(head->chain.first); | ||
70 | write_lock(&head->lock); | ||
71 | |||
72 | /* Check TIME-WAIT sockets first. */ | ||
73 | sk_for_each(sk2, node, &(head + dccp_hashinfo.ehash_size)->chain) { | ||
74 | tw = inet_twsk(sk2); | ||
75 | |||
76 | if (INET_TW_MATCH(sk2, hash, acookie, saddr, daddr, ports, dif)) | ||
77 | goto not_unique; | ||
78 | } | ||
79 | tw = NULL; | ||
80 | |||
81 | /* And established part... */ | ||
82 | sk_for_each(sk2, node, &head->chain) { | ||
83 | if (INET_MATCH(sk2, hash, acookie, saddr, daddr, ports, dif)) | ||
84 | goto not_unique; | ||
85 | } | ||
86 | 57 | ||
87 | /* Must record num and sport now. Otherwise we will see | 58 | int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) |
88 | * in hash table socket with a funny identity. */ | ||
89 | inet->num = lport; | ||
90 | inet->sport = htons(lport); | ||
91 | sk->sk_hash = hash; | ||
92 | BUG_TRAP(sk_unhashed(sk)); | ||
93 | __sk_add_node(sk, &head->chain); | ||
94 | sock_prot_inc_use(sk->sk_prot); | ||
95 | write_unlock(&head->lock); | ||
96 | |||
97 | if (twp != NULL) { | ||
98 | *twp = tw; | ||
99 | NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED); | ||
100 | } else if (tw != NULL) { | ||
101 | /* Silly. Should hash-dance instead... */ | ||
102 | inet_twsk_deschedule(tw, &dccp_death_row); | ||
103 | NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED); | ||
104 | |||
105 | inet_twsk_put(tw); | ||
106 | } | ||
107 | |||
108 | return 0; | ||
109 | |||
110 | not_unique: | ||
111 | write_unlock(&head->lock); | ||
112 | return -EADDRNOTAVAIL; | ||
113 | } | ||
114 | |||
115 | /* | ||
116 | * Bind a port for a connect operation and hash it. | ||
117 | */ | ||
118 | static int dccp_v4_hash_connect(struct sock *sk) | ||
119 | { | ||
120 | const unsigned short snum = inet_sk(sk)->num; | ||
121 | struct inet_bind_hashbucket *head; | ||
122 | struct inet_bind_bucket *tb; | ||
123 | int ret; | ||
124 | |||
125 | if (snum == 0) { | ||
126 | int low = sysctl_local_port_range[0]; | ||
127 | int high = sysctl_local_port_range[1]; | ||
128 | int remaining = (high - low) + 1; | ||
129 | int rover = net_random() % (high - low) + low; | ||
130 | struct hlist_node *node; | ||
131 | struct inet_timewait_sock *tw = NULL; | ||
132 | |||
133 | local_bh_disable(); | ||
134 | do { | ||
135 | head = &dccp_hashinfo.bhash[inet_bhashfn(rover, | ||
136 | dccp_hashinfo.bhash_size)]; | ||
137 | spin_lock(&head->lock); | ||
138 | |||
139 | /* Does not bother with rcv_saddr checks, | ||
140 | * because the established check is already | ||
141 | * unique enough. | ||
142 | */ | ||
143 | inet_bind_bucket_for_each(tb, node, &head->chain) { | ||
144 | if (tb->port == rover) { | ||
145 | BUG_TRAP(!hlist_empty(&tb->owners)); | ||
146 | if (tb->fastreuse >= 0) | ||
147 | goto next_port; | ||
148 | if (!__dccp_v4_check_established(sk, | ||
149 | rover, | ||
150 | &tw)) | ||
151 | goto ok; | ||
152 | goto next_port; | ||
153 | } | ||
154 | } | ||
155 | |||
156 | tb = inet_bind_bucket_create(dccp_hashinfo.bind_bucket_cachep, | ||
157 | head, rover); | ||
158 | if (tb == NULL) { | ||
159 | spin_unlock(&head->lock); | ||
160 | break; | ||
161 | } | ||
162 | tb->fastreuse = -1; | ||
163 | goto ok; | ||
164 | |||
165 | next_port: | ||
166 | spin_unlock(&head->lock); | ||
167 | if (++rover > high) | ||
168 | rover = low; | ||
169 | } while (--remaining > 0); | ||
170 | |||
171 | local_bh_enable(); | ||
172 | |||
173 | return -EADDRNOTAVAIL; | ||
174 | |||
175 | ok: | ||
176 | /* All locks still held and bhs disabled */ | ||
177 | inet_bind_hash(sk, tb, rover); | ||
178 | if (sk_unhashed(sk)) { | ||
179 | inet_sk(sk)->sport = htons(rover); | ||
180 | __inet_hash(&dccp_hashinfo, sk, 0); | ||
181 | } | ||
182 | spin_unlock(&head->lock); | ||
183 | |||
184 | if (tw != NULL) { | ||
185 | inet_twsk_deschedule(tw, &dccp_death_row); | ||
186 | inet_twsk_put(tw); | ||
187 | } | ||
188 | |||
189 | ret = 0; | ||
190 | goto out; | ||
191 | } | ||
192 | |||
193 | head = &dccp_hashinfo.bhash[inet_bhashfn(snum, | ||
194 | dccp_hashinfo.bhash_size)]; | ||
195 | tb = inet_csk(sk)->icsk_bind_hash; | ||
196 | spin_lock_bh(&head->lock); | ||
197 | if (sk_head(&tb->owners) == sk && sk->sk_bind_node.next == NULL) { | ||
198 | __inet_hash(&dccp_hashinfo, sk, 0); | ||
199 | spin_unlock_bh(&head->lock); | ||
200 | return 0; | ||
201 | } else { | ||
202 | spin_unlock(&head->lock); | ||
203 | /* No definite answer... Walk to established hash table */ | ||
204 | ret = __dccp_v4_check_established(sk, snum, NULL); | ||
205 | out: | ||
206 | local_bh_enable(); | ||
207 | return ret; | ||
208 | } | ||
209 | } | ||
210 | |||
211 | static int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, | ||
212 | int addr_len) | ||
213 | { | 59 | { |
214 | struct inet_sock *inet = inet_sk(sk); | 60 | struct inet_sock *inet = inet_sk(sk); |
215 | struct dccp_sock *dp = dccp_sk(sk); | 61 | struct dccp_sock *dp = dccp_sk(sk); |
@@ -259,9 +105,9 @@ static int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, | |||
259 | inet->dport = usin->sin_port; | 105 | inet->dport = usin->sin_port; |
260 | inet->daddr = daddr; | 106 | inet->daddr = daddr; |
261 | 107 | ||
262 | dp->dccps_ext_header_len = 0; | 108 | inet_csk(sk)->icsk_ext_hdr_len = 0; |
263 | if (inet->opt != NULL) | 109 | if (inet->opt != NULL) |
264 | dp->dccps_ext_header_len = inet->opt->optlen; | 110 | inet_csk(sk)->icsk_ext_hdr_len = inet->opt->optlen; |
265 | /* | 111 | /* |
266 | * Socket identity is still unknown (sport may be zero). | 112 | * Socket identity is still unknown (sport may be zero). |
267 | * However we set state to DCCP_REQUESTING and not releasing socket | 113 | * However we set state to DCCP_REQUESTING and not releasing socket |
@@ -269,7 +115,7 @@ static int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, | |||
269 | * complete initialization after this. | 115 | * complete initialization after this. |
270 | */ | 116 | */ |
271 | dccp_set_state(sk, DCCP_REQUESTING); | 117 | dccp_set_state(sk, DCCP_REQUESTING); |
272 | err = dccp_v4_hash_connect(sk); | 118 | err = inet_hash_connect(&dccp_death_row, sk); |
273 | if (err != 0) | 119 | if (err != 0) |
274 | goto failure; | 120 | goto failure; |
275 | 121 | ||
@@ -287,16 +133,6 @@ static int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, | |||
287 | usin->sin_port); | 133 | usin->sin_port); |
288 | dccp_update_gss(sk, dp->dccps_iss); | 134 | dccp_update_gss(sk, dp->dccps_iss); |
289 | 135 | ||
290 | /* | ||
291 | * SWL and AWL are initially adjusted so that they are not less than | ||
292 | * the initial Sequence Numbers received and sent, respectively: | ||
293 | * SWL := max(GSR + 1 - floor(W/4), ISR), | ||
294 | * AWL := max(GSS - W' + 1, ISS). | ||
295 | * These adjustments MUST be applied only at the beginning of the | ||
296 | * connection. | ||
297 | */ | ||
298 | dccp_set_seqno(&dp->dccps_awl, max48(dp->dccps_awl, dp->dccps_iss)); | ||
299 | |||
300 | inet->id = dp->dccps_iss ^ jiffies; | 136 | inet->id = dp->dccps_iss ^ jiffies; |
301 | 137 | ||
302 | err = dccp_connect(sk); | 138 | err = dccp_connect(sk); |
@@ -316,6 +152,8 @@ failure: | |||
316 | goto out; | 152 | goto out; |
317 | } | 153 | } |
318 | 154 | ||
155 | EXPORT_SYMBOL_GPL(dccp_v4_connect); | ||
156 | |||
319 | /* | 157 | /* |
320 | * This routine does path mtu discovery as defined in RFC1191. | 158 | * This routine does path mtu discovery as defined in RFC1191. |
321 | */ | 159 | */ |
@@ -354,7 +192,7 @@ static inline void dccp_do_pmtu_discovery(struct sock *sk, | |||
354 | mtu = dst_mtu(dst); | 192 | mtu = dst_mtu(dst); |
355 | 193 | ||
356 | if (inet->pmtudisc != IP_PMTUDISC_DONT && | 194 | if (inet->pmtudisc != IP_PMTUDISC_DONT && |
357 | dp->dccps_pmtu_cookie > mtu) { | 195 | inet_csk(sk)->icsk_pmtu_cookie > mtu) { |
358 | dccp_sync_mss(sk, mtu); | 196 | dccp_sync_mss(sk, mtu); |
359 | 197 | ||
360 | /* | 198 | /* |
@@ -606,6 +444,17 @@ out: | |||
606 | sock_put(sk); | 444 | sock_put(sk); |
607 | } | 445 | } |
608 | 446 | ||
447 | /* This routine computes an IPv4 DCCP checksum. */ | ||
448 | void dccp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb) | ||
449 | { | ||
450 | const struct inet_sock *inet = inet_sk(sk); | ||
451 | struct dccp_hdr *dh = dccp_hdr(skb); | ||
452 | |||
453 | dh->dccph_checksum = dccp_v4_checksum(skb, inet->saddr, inet->daddr); | ||
454 | } | ||
455 | |||
456 | EXPORT_SYMBOL_GPL(dccp_v4_send_check); | ||
457 | |||
609 | int dccp_v4_send_reset(struct sock *sk, enum dccp_reset_codes code) | 458 | int dccp_v4_send_reset(struct sock *sk, enum dccp_reset_codes code) |
610 | { | 459 | { |
611 | struct sk_buff *skb; | 460 | struct sk_buff *skb; |
@@ -641,16 +490,6 @@ static inline u64 dccp_v4_init_sequence(const struct sock *sk, | |||
641 | dccp_hdr(skb)->dccph_sport); | 490 | dccp_hdr(skb)->dccph_sport); |
642 | } | 491 | } |
643 | 492 | ||
644 | static inline int dccp_bad_service_code(const struct sock *sk, | ||
645 | const __u32 service) | ||
646 | { | ||
647 | const struct dccp_sock *dp = dccp_sk(sk); | ||
648 | |||
649 | if (dp->dccps_service == service) | ||
650 | return 0; | ||
651 | return !dccp_list_has_service(dp->dccps_service_list, service); | ||
652 | } | ||
653 | |||
654 | int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | 493 | int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) |
655 | { | 494 | { |
656 | struct inet_request_sock *ireq; | 495 | struct inet_request_sock *ireq; |
@@ -662,7 +501,6 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
662 | const __u32 service = dccp_hdr_request(skb)->dccph_req_service; | 501 | const __u32 service = dccp_hdr_request(skb)->dccph_req_service; |
663 | struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); | 502 | struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); |
664 | __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY; | 503 | __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY; |
665 | struct dst_entry *dst = NULL; | ||
666 | 504 | ||
667 | /* Never answer to DCCP_PKT_REQUESTs send to broadcast or multicast */ | 505 | /* Never answer to DCCP_PKT_REQUESTs send to broadcast or multicast */ |
668 | if (((struct rtable *)skb->dst)->rt_flags & | 506 | if (((struct rtable *)skb->dst)->rt_flags & |
@@ -703,7 +541,6 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
703 | ireq = inet_rsk(req); | 541 | ireq = inet_rsk(req); |
704 | ireq->loc_addr = daddr; | 542 | ireq->loc_addr = daddr; |
705 | ireq->rmt_addr = saddr; | 543 | ireq->rmt_addr = saddr; |
706 | /* FIXME: Merge Aristeu's option parsing code when ready */ | ||
707 | req->rcv_wnd = 100; /* Fake, option parsing will get the | 544 | req->rcv_wnd = 100; /* Fake, option parsing will get the |
708 | right value */ | 545 | right value */ |
709 | ireq->opt = NULL; | 546 | ireq->opt = NULL; |
@@ -721,23 +558,22 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
721 | dreq->dreq_iss = dccp_v4_init_sequence(sk, skb); | 558 | dreq->dreq_iss = dccp_v4_init_sequence(sk, skb); |
722 | dreq->dreq_service = service; | 559 | dreq->dreq_service = service; |
723 | 560 | ||
724 | if (dccp_v4_send_response(sk, req, dst)) | 561 | if (dccp_v4_send_response(sk, req, NULL)) |
725 | goto drop_and_free; | 562 | goto drop_and_free; |
726 | 563 | ||
727 | inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT); | 564 | inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT); |
728 | return 0; | 565 | return 0; |
729 | 566 | ||
730 | drop_and_free: | 567 | drop_and_free: |
731 | /* | 568 | reqsk_free(req); |
732 | * FIXME: should be reqsk_free after implementing req->rsk_ops | ||
733 | */ | ||
734 | __reqsk_free(req); | ||
735 | drop: | 569 | drop: |
736 | DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS); | 570 | DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS); |
737 | dcb->dccpd_reset_code = reset_code; | 571 | dcb->dccpd_reset_code = reset_code; |
738 | return -1; | 572 | return -1; |
739 | } | 573 | } |
740 | 574 | ||
575 | EXPORT_SYMBOL_GPL(dccp_v4_conn_request); | ||
576 | |||
741 | /* | 577 | /* |
742 | * The three way handshake has completed - we got a valid ACK or DATAACK - | 578 | * The three way handshake has completed - we got a valid ACK or DATAACK - |
743 | * now create the new socket. | 579 | * now create the new socket. |
@@ -792,6 +628,8 @@ exit: | |||
792 | return NULL; | 628 | return NULL; |
793 | } | 629 | } |
794 | 630 | ||
631 | EXPORT_SYMBOL_GPL(dccp_v4_request_recv_sock); | ||
632 | |||
795 | static struct sock *dccp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) | 633 | static struct sock *dccp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) |
796 | { | 634 | { |
797 | const struct dccp_hdr *dh = dccp_hdr(skb); | 635 | const struct dccp_hdr *dh = dccp_hdr(skb); |
@@ -1011,7 +849,9 @@ discard: | |||
1011 | return 0; | 849 | return 0; |
1012 | } | 850 | } |
1013 | 851 | ||
1014 | static inline int dccp_invalid_packet(struct sk_buff *skb) | 852 | EXPORT_SYMBOL_GPL(dccp_v4_do_rcv); |
853 | |||
854 | int dccp_invalid_packet(struct sk_buff *skb) | ||
1015 | { | 855 | { |
1016 | const struct dccp_hdr *dh; | 856 | const struct dccp_hdr *dh; |
1017 | 857 | ||
@@ -1065,29 +905,30 @@ static inline int dccp_invalid_packet(struct sk_buff *skb) | |||
1065 | return 1; | 905 | return 1; |
1066 | } | 906 | } |
1067 | 907 | ||
1068 | /* If the header checksum is incorrect, drop packet and return */ | ||
1069 | if (dccp_v4_verify_checksum(skb, skb->nh.iph->saddr, | ||
1070 | skb->nh.iph->daddr) < 0) { | ||
1071 | LIMIT_NETDEBUG(KERN_WARNING "DCCP: header checksum is " | ||
1072 | "incorrect\n"); | ||
1073 | return 1; | ||
1074 | } | ||
1075 | |||
1076 | return 0; | 908 | return 0; |
1077 | } | 909 | } |
1078 | 910 | ||
911 | EXPORT_SYMBOL_GPL(dccp_invalid_packet); | ||
912 | |||
1079 | /* this is called when real data arrives */ | 913 | /* this is called when real data arrives */ |
1080 | int dccp_v4_rcv(struct sk_buff *skb) | 914 | int dccp_v4_rcv(struct sk_buff *skb) |
1081 | { | 915 | { |
1082 | const struct dccp_hdr *dh; | 916 | const struct dccp_hdr *dh; |
1083 | struct sock *sk; | 917 | struct sock *sk; |
1084 | int rc; | ||
1085 | 918 | ||
1086 | /* Step 1: Check header basics: */ | 919 | /* Step 1: Check header basics: */ |
1087 | 920 | ||
1088 | if (dccp_invalid_packet(skb)) | 921 | if (dccp_invalid_packet(skb)) |
1089 | goto discard_it; | 922 | goto discard_it; |
1090 | 923 | ||
924 | /* If the header checksum is incorrect, drop packet and return */ | ||
925 | if (dccp_v4_verify_checksum(skb, skb->nh.iph->saddr, | ||
926 | skb->nh.iph->daddr) < 0) { | ||
927 | LIMIT_NETDEBUG(KERN_WARNING "%s: incorrect header checksum\n", | ||
928 | __FUNCTION__); | ||
929 | goto discard_it; | ||
930 | } | ||
931 | |||
1091 | dh = dccp_hdr(skb); | 932 | dh = dccp_hdr(skb); |
1092 | 933 | ||
1093 | DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(skb); | 934 | DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(skb); |
@@ -1143,28 +984,10 @@ int dccp_v4_rcv(struct sk_buff *skb) | |||
1143 | goto do_time_wait; | 984 | goto do_time_wait; |
1144 | } | 985 | } |
1145 | 986 | ||
1146 | if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) { | 987 | if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) |
1147 | dccp_pr_debug("xfrm4_policy_check failed\n"); | ||
1148 | goto discard_and_relse; | 988 | goto discard_and_relse; |
1149 | } | ||
1150 | |||
1151 | if (sk_filter(sk, skb, 0)) { | ||
1152 | dccp_pr_debug("sk_filter failed\n"); | ||
1153 | goto discard_and_relse; | ||
1154 | } | ||
1155 | |||
1156 | skb->dev = NULL; | ||
1157 | |||
1158 | bh_lock_sock(sk); | ||
1159 | rc = 0; | ||
1160 | if (!sock_owned_by_user(sk)) | ||
1161 | rc = dccp_v4_do_rcv(sk, skb); | ||
1162 | else | ||
1163 | sk_add_backlog(sk, skb); | ||
1164 | bh_unlock_sock(sk); | ||
1165 | 989 | ||
1166 | sock_put(sk); | 990 | return sk_receive_skb(sk, skb); |
1167 | return rc; | ||
1168 | 991 | ||
1169 | no_dccp_socket: | 992 | no_dccp_socket: |
1170 | if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) | 993 | if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) |
@@ -1194,9 +1017,23 @@ do_time_wait: | |||
1194 | goto no_dccp_socket; | 1017 | goto no_dccp_socket; |
1195 | } | 1018 | } |
1196 | 1019 | ||
1197 | static int dccp_v4_init_sock(struct sock *sk) | 1020 | struct inet_connection_sock_af_ops dccp_ipv4_af_ops = { |
1021 | .queue_xmit = ip_queue_xmit, | ||
1022 | .send_check = dccp_v4_send_check, | ||
1023 | .rebuild_header = inet_sk_rebuild_header, | ||
1024 | .conn_request = dccp_v4_conn_request, | ||
1025 | .syn_recv_sock = dccp_v4_request_recv_sock, | ||
1026 | .net_header_len = sizeof(struct iphdr), | ||
1027 | .setsockopt = ip_setsockopt, | ||
1028 | .getsockopt = ip_getsockopt, | ||
1029 | .addr2sockaddr = inet_csk_addr2sockaddr, | ||
1030 | .sockaddr_len = sizeof(struct sockaddr_in), | ||
1031 | }; | ||
1032 | |||
1033 | int dccp_v4_init_sock(struct sock *sk) | ||
1198 | { | 1034 | { |
1199 | struct dccp_sock *dp = dccp_sk(sk); | 1035 | struct dccp_sock *dp = dccp_sk(sk); |
1036 | struct inet_connection_sock *icsk = inet_csk(sk); | ||
1200 | static int dccp_ctl_socket_init = 1; | 1037 | static int dccp_ctl_socket_init = 1; |
1201 | 1038 | ||
1202 | dccp_options_init(&dp->dccps_options); | 1039 | dccp_options_init(&dp->dccps_options); |
@@ -1236,9 +1073,11 @@ static int dccp_v4_init_sock(struct sock *sk) | |||
1236 | dccp_ctl_socket_init = 0; | 1073 | dccp_ctl_socket_init = 0; |
1237 | 1074 | ||
1238 | dccp_init_xmit_timers(sk); | 1075 | dccp_init_xmit_timers(sk); |
1239 | inet_csk(sk)->icsk_rto = DCCP_TIMEOUT_INIT; | 1076 | icsk->icsk_rto = DCCP_TIMEOUT_INIT; |
1240 | sk->sk_state = DCCP_CLOSED; | 1077 | sk->sk_state = DCCP_CLOSED; |
1241 | sk->sk_write_space = dccp_write_space; | 1078 | sk->sk_write_space = dccp_write_space; |
1079 | icsk->icsk_af_ops = &dccp_ipv4_af_ops; | ||
1080 | icsk->icsk_sync_mss = dccp_sync_mss; | ||
1242 | dp->dccps_mss_cache = 536; | 1081 | dp->dccps_mss_cache = 536; |
1243 | dp->dccps_role = DCCP_ROLE_UNDEFINED; | 1082 | dp->dccps_role = DCCP_ROLE_UNDEFINED; |
1244 | dp->dccps_service = DCCP_SERVICE_INVALID_VALUE; | 1083 | dp->dccps_service = DCCP_SERVICE_INVALID_VALUE; |
@@ -1246,7 +1085,9 @@ static int dccp_v4_init_sock(struct sock *sk) | |||
1246 | return 0; | 1085 | return 0; |
1247 | } | 1086 | } |
1248 | 1087 | ||
1249 | static int dccp_v4_destroy_sock(struct sock *sk) | 1088 | EXPORT_SYMBOL_GPL(dccp_v4_init_sock); |
1089 | |||
1090 | int dccp_v4_destroy_sock(struct sock *sk) | ||
1250 | { | 1091 | { |
1251 | struct dccp_sock *dp = dccp_sk(sk); | 1092 | struct dccp_sock *dp = dccp_sk(sk); |
1252 | 1093 | ||
@@ -1279,6 +1120,8 @@ static int dccp_v4_destroy_sock(struct sock *sk) | |||
1279 | return 0; | 1120 | return 0; |
1280 | } | 1121 | } |
1281 | 1122 | ||
1123 | EXPORT_SYMBOL_GPL(dccp_v4_destroy_sock); | ||
1124 | |||
1282 | static void dccp_v4_reqsk_destructor(struct request_sock *req) | 1125 | static void dccp_v4_reqsk_destructor(struct request_sock *req) |
1283 | { | 1126 | { |
1284 | kfree(inet_rsk(req)->opt); | 1127 | kfree(inet_rsk(req)->opt); |
@@ -1293,7 +1136,11 @@ static struct request_sock_ops dccp_request_sock_ops = { | |||
1293 | .send_reset = dccp_v4_ctl_send_reset, | 1136 | .send_reset = dccp_v4_ctl_send_reset, |
1294 | }; | 1137 | }; |
1295 | 1138 | ||
1296 | struct proto dccp_v4_prot = { | 1139 | static struct timewait_sock_ops dccp_timewait_sock_ops = { |
1140 | .twsk_obj_size = sizeof(struct inet_timewait_sock), | ||
1141 | }; | ||
1142 | |||
1143 | struct proto dccp_prot = { | ||
1297 | .name = "DCCP", | 1144 | .name = "DCCP", |
1298 | .owner = THIS_MODULE, | 1145 | .owner = THIS_MODULE, |
1299 | .close = dccp_close, | 1146 | .close = dccp_close, |
@@ -1307,7 +1154,7 @@ struct proto dccp_v4_prot = { | |||
1307 | .recvmsg = dccp_recvmsg, | 1154 | .recvmsg = dccp_recvmsg, |
1308 | .backlog_rcv = dccp_v4_do_rcv, | 1155 | .backlog_rcv = dccp_v4_do_rcv, |
1309 | .hash = dccp_v4_hash, | 1156 | .hash = dccp_v4_hash, |
1310 | .unhash = dccp_v4_unhash, | 1157 | .unhash = dccp_unhash, |
1311 | .accept = inet_csk_accept, | 1158 | .accept = inet_csk_accept, |
1312 | .get_port = dccp_v4_get_port, | 1159 | .get_port = dccp_v4_get_port, |
1313 | .shutdown = dccp_shutdown, | 1160 | .shutdown = dccp_shutdown, |
@@ -1316,5 +1163,7 @@ struct proto dccp_v4_prot = { | |||
1316 | .max_header = MAX_DCCP_HEADER, | 1163 | .max_header = MAX_DCCP_HEADER, |
1317 | .obj_size = sizeof(struct dccp_sock), | 1164 | .obj_size = sizeof(struct dccp_sock), |
1318 | .rsk_prot = &dccp_request_sock_ops, | 1165 | .rsk_prot = &dccp_request_sock_ops, |
1319 | .twsk_obj_size = sizeof(struct inet_timewait_sock), | 1166 | .twsk_prot = &dccp_timewait_sock_ops, |
1320 | }; | 1167 | }; |
1168 | |||
1169 | EXPORT_SYMBOL_GPL(dccp_prot); | ||