blob: b26a4f8df4dc1c597e543e3067f2a9ca0c39f805 [file] [log] [blame]
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001/*
2 * net/dccp/ipv4.c
3 *
4 * An implementation of the DCCP protocol
5 * Arnaldo Carvalho de Melo <acme@conectiva.com.br>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 */
12
13#include <linux/config.h>
14#include <linux/dccp.h>
15#include <linux/icmp.h>
16#include <linux/module.h>
17#include <linux/skbuff.h>
18#include <linux/random.h>
19
20#include <net/icmp.h>
21#include <net/inet_hashtables.h>
Arnaldo Carvalho de Melo14c85022005-12-27 02:43:12 -020022#include <net/inet_sock.h>
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070023#include <net/sock.h>
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -080024#include <net/timewait_sock.h>
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070025#include <net/tcp_states.h>
26#include <net/xfrm.h>
27
Arnaldo Carvalho de Meloae31c332005-09-18 00:17:51 -070028#include "ackvec.h"
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070029#include "ccid.h"
30#include "dccp.h"
Andrea Bittauafe00252006-03-20 17:43:56 -080031#include "feat.h"
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070032
33struct inet_hashinfo __cacheline_aligned dccp_hashinfo = {
34 .lhash_lock = RW_LOCK_UNLOCKED,
35 .lhash_users = ATOMIC_INIT(0),
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -030036 .lhash_wait = __WAIT_QUEUE_HEAD_INITIALIZER(dccp_hashinfo.lhash_wait),
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070037};
38
Arnaldo Carvalho de Melo540722f2005-08-10 05:54:28 -030039EXPORT_SYMBOL_GPL(dccp_hashinfo);
40
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070041static int dccp_v4_get_port(struct sock *sk, const unsigned short snum)
42{
Arnaldo Carvalho de Melo971af182005-12-13 23:14:47 -080043 return inet_csk_get_port(&dccp_hashinfo, sk, snum,
44 inet_csk_bind_conflict);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070045}
46
47static void dccp_v4_hash(struct sock *sk)
48{
49 inet_hash(&dccp_hashinfo, sk);
50}
51
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -080052void dccp_unhash(struct sock *sk)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070053{
54 inet_unhash(&dccp_hashinfo, sk);
55}
56
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -080057EXPORT_SYMBOL_GPL(dccp_unhash);
58
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -080059int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070060{
61 struct inet_sock *inet = inet_sk(sk);
62 struct dccp_sock *dp = dccp_sk(sk);
63 const struct sockaddr_in *usin = (struct sockaddr_in *)uaddr;
64 struct rtable *rt;
65 u32 daddr, nexthop;
66 int tmp;
67 int err;
68
69 dp->dccps_role = DCCP_ROLE_CLIENT;
70
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -070071 if (dccp_service_not_initialized(sk))
72 return -EPROTO;
73
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070074 if (addr_len < sizeof(struct sockaddr_in))
75 return -EINVAL;
76
77 if (usin->sin_family != AF_INET)
78 return -EAFNOSUPPORT;
79
80 nexthop = daddr = usin->sin_addr.s_addr;
81 if (inet->opt != NULL && inet->opt->srr) {
82 if (daddr == 0)
83 return -EINVAL;
84 nexthop = inet->opt->faddr;
85 }
86
87 tmp = ip_route_connect(&rt, nexthop, inet->saddr,
88 RT_CONN_FLAGS(sk), sk->sk_bound_dev_if,
89 IPPROTO_DCCP,
90 inet->sport, usin->sin_port, sk);
91 if (tmp < 0)
92 return tmp;
93
94 if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) {
95 ip_rt_put(rt);
96 return -ENETUNREACH;
97 }
98
99 if (inet->opt == NULL || !inet->opt->srr)
100 daddr = rt->rt_dst;
101
102 if (inet->saddr == 0)
103 inet->saddr = rt->rt_src;
104 inet->rcv_saddr = inet->saddr;
105
106 inet->dport = usin->sin_port;
107 inet->daddr = daddr;
108
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800109 inet_csk(sk)->icsk_ext_hdr_len = 0;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700110 if (inet->opt != NULL)
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800111 inet_csk(sk)->icsk_ext_hdr_len = inet->opt->optlen;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700112 /*
113 * Socket identity is still unknown (sport may be zero).
114 * However we set state to DCCP_REQUESTING and not releasing socket
115 * lock select source port, enter ourselves into the hash tables and
116 * complete initialization after this.
117 */
118 dccp_set_state(sk, DCCP_REQUESTING);
Arnaldo Carvalho de Meloa7f5e7f2005-12-13 23:25:31 -0800119 err = inet_hash_connect(&dccp_death_row, sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700120 if (err != 0)
121 goto failure;
122
Patrick McHardy5d39a792006-01-31 17:35:35 -0800123 err = ip_route_newports(&rt, IPPROTO_DCCP, inet->sport, inet->dport,
124 sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700125 if (err != 0)
126 goto failure;
127
128 /* OK, now commit destination to socket. */
129 sk_setup_caps(sk, &rt->u.dst);
130
131 dp->dccps_gar =
132 dp->dccps_iss = secure_dccp_sequence_number(inet->saddr,
133 inet->daddr,
134 inet->sport,
135 usin->sin_port);
136 dccp_update_gss(sk, dp->dccps_iss);
137
138 inet->id = dp->dccps_iss ^ jiffies;
139
140 err = dccp_connect(sk);
141 rt = NULL;
142 if (err != 0)
143 goto failure;
144out:
145 return err;
146failure:
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -0300147 /*
148 * This unhashes the socket and releases the local port, if necessary.
149 */
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700150 dccp_set_state(sk, DCCP_CLOSED);
151 ip_rt_put(rt);
152 sk->sk_route_caps = 0;
153 inet->dport = 0;
154 goto out;
155}
156
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800157EXPORT_SYMBOL_GPL(dccp_v4_connect);
158
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700159/*
160 * This routine does path mtu discovery as defined in RFC1191.
161 */
162static inline void dccp_do_pmtu_discovery(struct sock *sk,
163 const struct iphdr *iph,
164 u32 mtu)
165{
166 struct dst_entry *dst;
167 const struct inet_sock *inet = inet_sk(sk);
168 const struct dccp_sock *dp = dccp_sk(sk);
169
170 /* We are not interested in DCCP_LISTEN and request_socks (RESPONSEs
171 * send out by Linux are always < 576bytes so they should go through
172 * unfragmented).
173 */
174 if (sk->sk_state == DCCP_LISTEN)
175 return;
176
177 /* We don't check in the destentry if pmtu discovery is forbidden
178 * on this route. We just assume that no packet_to_big packets
179 * are send back when pmtu discovery is not active.
180 * There is a small race when the user changes this flag in the
181 * route, but I think that's acceptable.
182 */
183 if ((dst = __sk_dst_check(sk, 0)) == NULL)
184 return;
185
186 dst->ops->update_pmtu(dst, mtu);
187
188 /* Something is about to be wrong... Remember soft error
189 * for the case, if this connection will not able to recover.
190 */
191 if (mtu < dst_mtu(dst) && ip_dont_fragment(sk, dst))
192 sk->sk_err_soft = EMSGSIZE;
193
194 mtu = dst_mtu(dst);
195
196 if (inet->pmtudisc != IP_PMTUDISC_DONT &&
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800197 inet_csk(sk)->icsk_pmtu_cookie > mtu) {
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700198 dccp_sync_mss(sk, mtu);
199
200 /*
201 * From: draft-ietf-dccp-spec-11.txt
202 *
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -0300203 * DCCP-Sync packets are the best choice for upward
204 * probing, since DCCP-Sync probes do not risk application
205 * data loss.
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700206 */
Arnaldo Carvalho de Meloe92ae932005-08-17 03:10:59 -0300207 dccp_send_sync(sk, dp->dccps_gsr, DCCP_PKT_SYNC);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700208 } /* else let the usual retransmit timer handle it */
209}
210
211static void dccp_v4_ctl_send_ack(struct sk_buff *rxskb)
212{
213 int err;
214 struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh;
215 const int dccp_hdr_ack_len = sizeof(struct dccp_hdr) +
216 sizeof(struct dccp_hdr_ext) +
217 sizeof(struct dccp_hdr_ack_bits);
218 struct sk_buff *skb;
219
220 if (((struct rtable *)rxskb->dst)->rt_type != RTN_LOCAL)
221 return;
222
223 skb = alloc_skb(MAX_DCCP_HEADER + 15, GFP_ATOMIC);
224 if (skb == NULL)
225 return;
226
227 /* Reserve space for headers. */
228 skb_reserve(skb, MAX_DCCP_HEADER);
229
230 skb->dst = dst_clone(rxskb->dst);
231
232 skb->h.raw = skb_push(skb, dccp_hdr_ack_len);
233 dh = dccp_hdr(skb);
234 memset(dh, 0, dccp_hdr_ack_len);
235
236 /* Build DCCP header and checksum it. */
237 dh->dccph_type = DCCP_PKT_ACK;
238 dh->dccph_sport = rxdh->dccph_dport;
239 dh->dccph_dport = rxdh->dccph_sport;
240 dh->dccph_doff = dccp_hdr_ack_len / 4;
241 dh->dccph_x = 1;
242
243 dccp_hdr_set_seq(dh, DCCP_SKB_CB(rxskb)->dccpd_ack_seq);
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -0300244 dccp_hdr_set_ack(dccp_hdr_ack_bits(skb),
245 DCCP_SKB_CB(rxskb)->dccpd_seq);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700246
247 bh_lock_sock(dccp_ctl_socket->sk);
248 err = ip_build_and_send_pkt(skb, dccp_ctl_socket->sk,
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -0300249 rxskb->nh.iph->daddr,
250 rxskb->nh.iph->saddr, NULL);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700251 bh_unlock_sock(dccp_ctl_socket->sk);
252
253 if (err == NET_XMIT_CN || err == 0) {
254 DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS);
255 DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS);
256 }
257}
258
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -0300259static void dccp_v4_reqsk_send_ack(struct sk_buff *skb,
260 struct request_sock *req)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700261{
262 dccp_v4_ctl_send_ack(skb);
263}
264
265static int dccp_v4_send_response(struct sock *sk, struct request_sock *req,
266 struct dst_entry *dst)
267{
268 int err = -1;
269 struct sk_buff *skb;
270
271 /* First, grab a route. */
272
273 if (dst == NULL && (dst = inet_csk_route_req(sk, req)) == NULL)
274 goto out;
275
276 skb = dccp_make_response(sk, dst, req);
277 if (skb != NULL) {
278 const struct inet_request_sock *ireq = inet_rsk(req);
279
Herbert Xu49c5bfa2005-10-18 12:03:28 +1000280 memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700281 err = ip_build_and_send_pkt(skb, sk, ireq->loc_addr,
282 ireq->rmt_addr,
283 ireq->opt);
284 if (err == NET_XMIT_CN)
285 err = 0;
286 }
287
288out:
289 dst_release(dst);
290 return err;
291}
292
293/*
294 * This routine is called by the ICMP module when it gets some sort of error
295 * condition. If err < 0 then the socket should be closed and the error
296 * returned to the user. If err > 0 it's just the icmp type << 8 | icmp code.
297 * After adjustment header points to the first 8 bytes of the tcp header. We
298 * need to find the appropriate port.
299 *
300 * The locking strategy used here is very "optimistic". When someone else
301 * accesses the socket the ICMP is just dropped and for some paths there is no
302 * check at all. A more general error queue to queue errors for later handling
303 * is probably better.
304 */
305void dccp_v4_err(struct sk_buff *skb, u32 info)
306{
307 const struct iphdr *iph = (struct iphdr *)skb->data;
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -0300308 const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data +
309 (iph->ihl << 2));
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700310 struct dccp_sock *dp;
311 struct inet_sock *inet;
312 const int type = skb->h.icmph->type;
313 const int code = skb->h.icmph->code;
314 struct sock *sk;
315 __u64 seq;
316 int err;
317
318 if (skb->len < (iph->ihl << 2) + 8) {
319 ICMP_INC_STATS_BH(ICMP_MIB_INERRORS);
320 return;
321 }
322
323 sk = inet_lookup(&dccp_hashinfo, iph->daddr, dh->dccph_dport,
324 iph->saddr, dh->dccph_sport, inet_iif(skb));
325 if (sk == NULL) {
326 ICMP_INC_STATS_BH(ICMP_MIB_INERRORS);
327 return;
328 }
329
330 if (sk->sk_state == DCCP_TIME_WAIT) {
331 inet_twsk_put((struct inet_timewait_sock *)sk);
332 return;
333 }
334
335 bh_lock_sock(sk);
336 /* If too many ICMPs get dropped on busy
337 * servers this needs to be solved differently.
338 */
339 if (sock_owned_by_user(sk))
340 NET_INC_STATS_BH(LINUX_MIB_LOCKDROPPEDICMPS);
341
342 if (sk->sk_state == DCCP_CLOSED)
343 goto out;
344
345 dp = dccp_sk(sk);
346 seq = dccp_hdr_seq(skb);
347 if (sk->sk_state != DCCP_LISTEN &&
348 !between48(seq, dp->dccps_swl, dp->dccps_swh)) {
349 NET_INC_STATS(LINUX_MIB_OUTOFWINDOWICMPS);
350 goto out;
351 }
352
353 switch (type) {
354 case ICMP_SOURCE_QUENCH:
355 /* Just silently ignore these. */
356 goto out;
357 case ICMP_PARAMETERPROB:
358 err = EPROTO;
359 break;
360 case ICMP_DEST_UNREACH:
361 if (code > NR_ICMP_UNREACH)
362 goto out;
363
364 if (code == ICMP_FRAG_NEEDED) { /* PMTU discovery (RFC1191) */
365 if (!sock_owned_by_user(sk))
366 dccp_do_pmtu_discovery(sk, iph, info);
367 goto out;
368 }
369
370 err = icmp_err_convert[code].errno;
371 break;
372 case ICMP_TIME_EXCEEDED:
373 err = EHOSTUNREACH;
374 break;
375 default:
376 goto out;
377 }
378
379 switch (sk->sk_state) {
380 struct request_sock *req , **prev;
381 case DCCP_LISTEN:
382 if (sock_owned_by_user(sk))
383 goto out;
384 req = inet_csk_search_req(sk, &prev, dh->dccph_dport,
385 iph->daddr, iph->saddr);
386 if (!req)
387 goto out;
388
389 /*
390 * ICMPs are not backlogged, hence we cannot get an established
391 * socket here.
392 */
393 BUG_TRAP(!req->sk);
394
395 if (seq != dccp_rsk(req)->dreq_iss) {
396 NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS);
397 goto out;
398 }
399 /*
400 * Still in RESPOND, just remove it silently.
401 * There is no good way to pass the error to the newly
402 * created socket, and POSIX does not want network
403 * errors returned from accept().
404 */
405 inet_csk_reqsk_queue_drop(sk, req, prev);
406 goto out;
407
408 case DCCP_REQUESTING:
409 case DCCP_RESPOND:
410 if (!sock_owned_by_user(sk)) {
411 DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS);
412 sk->sk_err = err;
413
414 sk->sk_error_report(sk);
415
416 dccp_done(sk);
417 } else
418 sk->sk_err_soft = err;
419 goto out;
420 }
421
422 /* If we've already connected we will keep trying
423 * until we time out, or the user gives up.
424 *
425 * rfc1122 4.2.3.9 allows to consider as hard errors
426 * only PROTO_UNREACH and PORT_UNREACH (well, FRAG_FAILED too,
427 * but it is obsoleted by pmtu discovery).
428 *
429 * Note, that in modern internet, where routing is unreliable
430 * and in each dark corner broken firewalls sit, sending random
431 * errors ordered by their masters even this two messages finally lose
432 * their original sense (even Linux sends invalid PORT_UNREACHs)
433 *
434 * Now we are in compliance with RFCs.
435 * --ANK (980905)
436 */
437
438 inet = inet_sk(sk);
439 if (!sock_owned_by_user(sk) && inet->recverr) {
440 sk->sk_err = err;
441 sk->sk_error_report(sk);
442 } else /* Only an error on timeout */
443 sk->sk_err_soft = err;
444out:
445 bh_unlock_sock(sk);
446 sock_put(sk);
447}
448
Arnaldo Carvalho de Melo57cca052005-12-13 23:16:16 -0800449/* This routine computes an IPv4 DCCP checksum. */
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800450void dccp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb)
Arnaldo Carvalho de Melo57cca052005-12-13 23:16:16 -0800451{
452 const struct inet_sock *inet = inet_sk(sk);
453 struct dccp_hdr *dh = dccp_hdr(skb);
454
455 dh->dccph_checksum = dccp_v4_checksum(skb, inet->saddr, inet->daddr);
456}
457
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800458EXPORT_SYMBOL_GPL(dccp_v4_send_check);
459
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700460static inline u64 dccp_v4_init_sequence(const struct sock *sk,
461 const struct sk_buff *skb)
462{
463 return secure_dccp_sequence_number(skb->nh.iph->daddr,
464 skb->nh.iph->saddr,
465 dccp_hdr(skb)->dccph_dport,
466 dccp_hdr(skb)->dccph_sport);
467}
468
469int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
470{
471 struct inet_request_sock *ireq;
472 struct dccp_sock dp;
473 struct request_sock *req;
474 struct dccp_request_sock *dreq;
Andrea Bittau60fe62e2006-03-20 19:23:32 -0800475 const __be32 saddr = skb->nh.iph->saddr;
476 const __be32 daddr = skb->nh.iph->daddr;
477 const __be32 service = dccp_hdr_request(skb)->dccph_req_service;
Arnaldo Carvalho de Melo0c10c5d2005-09-16 16:58:33 -0700478 struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
479 __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700480
481 /* Never answer to DCCP_PKT_REQUESTs send to broadcast or multicast */
482 if (((struct rtable *)skb->dst)->rt_flags &
Arnaldo Carvalho de Melo0c10c5d2005-09-16 16:58:33 -0700483 (RTCF_BROADCAST | RTCF_MULTICAST)) {
484 reset_code = DCCP_RESET_CODE_NO_CONNECTION;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700485 goto drop;
Arnaldo Carvalho de Melo0c10c5d2005-09-16 16:58:33 -0700486 }
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700487
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -0700488 if (dccp_bad_service_code(sk, service)) {
489 reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE;
490 goto drop;
491 }
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700492 /*
493 * TW buckets are converted to open requests without
494 * limitations, they conserve resources and peer is
495 * evidently real one.
496 */
497 if (inet_csk_reqsk_queue_is_full(sk))
498 goto drop;
499
500 /*
501 * Accept backlog is full. If we have already queued enough
502 * of warm entries in syn queue, drop request. It is better than
503 * clogging syn queue with openreqs with exponentially increasing
504 * timeout.
505 */
506 if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
507 goto drop;
508
509 req = reqsk_alloc(sk->sk_prot->rsk_prot);
510 if (req == NULL)
511 goto drop;
512
Andrea Bittauafe00252006-03-20 17:43:56 -0800513 if (dccp_parse_options(sk, skb))
514 goto drop;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700515
516 dccp_openreq_init(req, &dp, skb);
517
518 ireq = inet_rsk(req);
519 ireq->loc_addr = daddr;
520 ireq->rmt_addr = saddr;
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -0300521 req->rcv_wnd = 100; /* Fake, option parsing will get the
522 right value */
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700523 ireq->opt = NULL;
524
525 /*
526 * Step 3: Process LISTEN state
527 *
528 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie
529 *
530 * In fact we defer setting S.GSR, S.SWL, S.SWH to
531 * dccp_create_openreq_child.
532 */
533 dreq = dccp_rsk(req);
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -0700534 dreq->dreq_isr = dcb->dccpd_seq;
535 dreq->dreq_iss = dccp_v4_init_sequence(sk, skb);
536 dreq->dreq_service = service;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700537
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800538 if (dccp_v4_send_response(sk, req, NULL))
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700539 goto drop_and_free;
540
541 inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
542 return 0;
543
544drop_and_free:
Arnaldo Carvalho de Melofc44b982005-12-13 23:25:06 -0800545 reqsk_free(req);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700546drop:
547 DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS);
Arnaldo Carvalho de Melo0c10c5d2005-09-16 16:58:33 -0700548 dcb->dccpd_reset_code = reset_code;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700549 return -1;
550}
551
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800552EXPORT_SYMBOL_GPL(dccp_v4_conn_request);
553
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700554/*
555 * The three way handshake has completed - we got a valid ACK or DATAACK -
556 * now create the new socket.
557 *
558 * This is the equivalent of TCP's tcp_v4_syn_recv_sock
559 */
560struct sock *dccp_v4_request_recv_sock(struct sock *sk, struct sk_buff *skb,
561 struct request_sock *req,
562 struct dst_entry *dst)
563{
564 struct inet_request_sock *ireq;
565 struct inet_sock *newinet;
566 struct dccp_sock *newdp;
567 struct sock *newsk;
568
569 if (sk_acceptq_is_full(sk))
570 goto exit_overflow;
571
572 if (dst == NULL && (dst = inet_csk_route_req(sk, req)) == NULL)
573 goto exit;
574
575 newsk = dccp_create_openreq_child(sk, req, skb);
576 if (newsk == NULL)
577 goto exit;
578
579 sk_setup_caps(newsk, dst);
580
581 newdp = dccp_sk(newsk);
582 newinet = inet_sk(newsk);
583 ireq = inet_rsk(req);
584 newinet->daddr = ireq->rmt_addr;
585 newinet->rcv_saddr = ireq->loc_addr;
586 newinet->saddr = ireq->loc_addr;
587 newinet->opt = ireq->opt;
588 ireq->opt = NULL;
589 newinet->mc_index = inet_iif(skb);
590 newinet->mc_ttl = skb->nh.iph->ttl;
591 newinet->id = jiffies;
592
593 dccp_sync_mss(newsk, dst_mtu(dst));
594
595 __inet_hash(&dccp_hashinfo, newsk, 0);
596 __inet_inherit_port(&dccp_hashinfo, sk, newsk);
597
598 return newsk;
599
600exit_overflow:
601 NET_INC_STATS_BH(LINUX_MIB_LISTENOVERFLOWS);
602exit:
603 NET_INC_STATS_BH(LINUX_MIB_LISTENDROPS);
604 dst_release(dst);
605 return NULL;
606}
607
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800608EXPORT_SYMBOL_GPL(dccp_v4_request_recv_sock);
609
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700610static struct sock *dccp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
611{
612 const struct dccp_hdr *dh = dccp_hdr(skb);
613 const struct iphdr *iph = skb->nh.iph;
614 struct sock *nsk;
615 struct request_sock **prev;
616 /* Find possible connection requests. */
617 struct request_sock *req = inet_csk_search_req(sk, &prev,
618 dh->dccph_sport,
619 iph->saddr, iph->daddr);
620 if (req != NULL)
621 return dccp_check_req(sk, skb, req, prev);
622
623 nsk = __inet_lookup_established(&dccp_hashinfo,
624 iph->saddr, dh->dccph_sport,
625 iph->daddr, ntohs(dh->dccph_dport),
626 inet_iif(skb));
627 if (nsk != NULL) {
628 if (nsk->sk_state != DCCP_TIME_WAIT) {
629 bh_lock_sock(nsk);
630 return nsk;
631 }
632 inet_twsk_put((struct inet_timewait_sock *)nsk);
633 return NULL;
634 }
635
636 return sk;
637}
638
Andrea Bittau60fe62e2006-03-20 19:23:32 -0800639int dccp_v4_checksum(const struct sk_buff *skb, const __be32 saddr,
640 const __be32 daddr)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700641{
Yoshifumi Nishida95b81ef2005-08-09 20:15:35 -0700642 const struct dccp_hdr* dh = dccp_hdr(skb);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700643 int checksum_len;
644 u32 tmp;
645
646 if (dh->dccph_cscov == 0)
647 checksum_len = skb->len;
648 else {
649 checksum_len = (dh->dccph_cscov + dh->dccph_x) * sizeof(u32);
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -0300650 checksum_len = checksum_len < skb->len ? checksum_len :
651 skb->len;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700652 }
653
654 tmp = csum_partial((unsigned char *)dh, checksum_len, 0);
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -0300655 return csum_tcpudp_magic(saddr, daddr, checksum_len,
656 IPPROTO_DCCP, tmp);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700657}
658
Yoshifumi Nishida95b81ef2005-08-09 20:15:35 -0700659static int dccp_v4_verify_checksum(struct sk_buff *skb,
Andrea Bittau60fe62e2006-03-20 19:23:32 -0800660 const __be32 saddr, const __be32 daddr)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700661{
Yoshifumi Nishida95b81ef2005-08-09 20:15:35 -0700662 struct dccp_hdr *dh = dccp_hdr(skb);
663 int checksum_len;
664 u32 tmp;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700665
Yoshifumi Nishida95b81ef2005-08-09 20:15:35 -0700666 if (dh->dccph_cscov == 0)
667 checksum_len = skb->len;
668 else {
669 checksum_len = (dh->dccph_cscov + dh->dccph_x) * sizeof(u32);
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -0300670 checksum_len = checksum_len < skb->len ? checksum_len :
671 skb->len;
Yoshifumi Nishida95b81ef2005-08-09 20:15:35 -0700672 }
673 tmp = csum_partial((unsigned char *)dh, checksum_len, 0);
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -0300674 return csum_tcpudp_magic(saddr, daddr, checksum_len,
675 IPPROTO_DCCP, tmp) == 0 ? 0 : -1;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700676}
677
678static struct dst_entry* dccp_v4_route_skb(struct sock *sk,
679 struct sk_buff *skb)
680{
681 struct rtable *rt;
682 struct flowi fl = { .oif = ((struct rtable *)skb->dst)->rt_iif,
683 .nl_u = { .ip4_u =
684 { .daddr = skb->nh.iph->saddr,
685 .saddr = skb->nh.iph->daddr,
686 .tos = RT_CONN_FLAGS(sk) } },
687 .proto = sk->sk_protocol,
688 .uli_u = { .ports =
689 { .sport = dccp_hdr(skb)->dccph_dport,
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -0300690 .dport = dccp_hdr(skb)->dccph_sport }
691 }
692 };
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700693
694 if (ip_route_output_flow(&rt, &fl, sk, 0)) {
695 IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES);
696 return NULL;
697 }
698
699 return &rt->u.dst;
700}
701
Arnaldo Carvalho de Meloa1d3a352005-08-13 22:42:25 -0300702static void dccp_v4_ctl_send_reset(struct sk_buff *rxskb)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700703{
704 int err;
705 struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh;
706 const int dccp_hdr_reset_len = sizeof(struct dccp_hdr) +
707 sizeof(struct dccp_hdr_ext) +
708 sizeof(struct dccp_hdr_reset);
709 struct sk_buff *skb;
710 struct dst_entry *dst;
Arnaldo Carvalho de Melo2807d4f2005-08-21 05:33:48 -0300711 u64 seqno;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700712
713 /* Never send a reset in response to a reset. */
714 if (rxdh->dccph_type == DCCP_PKT_RESET)
715 return;
716
717 if (((struct rtable *)rxskb->dst)->rt_type != RTN_LOCAL)
718 return;
719
720 dst = dccp_v4_route_skb(dccp_ctl_socket->sk, rxskb);
721 if (dst == NULL)
722 return;
723
724 skb = alloc_skb(MAX_DCCP_HEADER + 15, GFP_ATOMIC);
725 if (skb == NULL)
726 goto out;
727
728 /* Reserve space for headers. */
729 skb_reserve(skb, MAX_DCCP_HEADER);
730 skb->dst = dst_clone(dst);
731
732 skb->h.raw = skb_push(skb, dccp_hdr_reset_len);
733 dh = dccp_hdr(skb);
734 memset(dh, 0, dccp_hdr_reset_len);
735
736 /* Build DCCP header and checksum it. */
737 dh->dccph_type = DCCP_PKT_RESET;
738 dh->dccph_sport = rxdh->dccph_dport;
739 dh->dccph_dport = rxdh->dccph_sport;
740 dh->dccph_doff = dccp_hdr_reset_len / 4;
741 dh->dccph_x = 1;
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -0300742 dccp_hdr_reset(skb)->dccph_reset_code =
743 DCCP_SKB_CB(rxskb)->dccpd_reset_code;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700744
Arnaldo Carvalho de Melo2807d4f2005-08-21 05:33:48 -0300745 /* See "8.3.1. Abnormal Termination" in draft-ietf-dccp-spec-11 */
746 seqno = 0;
747 if (DCCP_SKB_CB(rxskb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
748 dccp_set_seqno(&seqno, DCCP_SKB_CB(rxskb)->dccpd_ack_seq + 1);
749
750 dccp_hdr_set_seq(dh, seqno);
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -0300751 dccp_hdr_set_ack(dccp_hdr_ack_bits(skb),
752 DCCP_SKB_CB(rxskb)->dccpd_seq);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700753
Yoshifumi Nishida95b81ef2005-08-09 20:15:35 -0700754 dh->dccph_checksum = dccp_v4_checksum(skb, rxskb->nh.iph->saddr,
755 rxskb->nh.iph->daddr);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700756
757 bh_lock_sock(dccp_ctl_socket->sk);
758 err = ip_build_and_send_pkt(skb, dccp_ctl_socket->sk,
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -0300759 rxskb->nh.iph->daddr,
760 rxskb->nh.iph->saddr, NULL);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700761 bh_unlock_sock(dccp_ctl_socket->sk);
762
763 if (err == NET_XMIT_CN || err == 0) {
764 DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS);
765 DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS);
766 }
767out:
768 dst_release(dst);
769}
770
771int dccp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
772{
773 struct dccp_hdr *dh = dccp_hdr(skb);
774
775 if (sk->sk_state == DCCP_OPEN) { /* Fast path */
776 if (dccp_rcv_established(sk, skb, dh, skb->len))
777 goto reset;
778 return 0;
779 }
780
781 /*
782 * Step 3: Process LISTEN state
783 * If S.state == LISTEN,
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -0300784 * If P.type == Request or P contains a valid Init Cookie
785 * option,
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700786 * * Must scan the packet's options to check for an Init
787 * Cookie. Only the Init Cookie is processed here,
788 * however; other options are processed in Step 8. This
789 * scan need only be performed if the endpoint uses Init
790 * Cookies *
791 * * Generate a new socket and switch to that socket *
792 * Set S := new socket for this port pair
793 * S.state = RESPOND
794 * Choose S.ISS (initial seqno) or set from Init Cookie
795 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie
796 * Continue with S.state == RESPOND
797 * * A Response packet will be generated in Step 11 *
798 * Otherwise,
799 * Generate Reset(No Connection) unless P.type == Reset
800 * Drop packet and return
801 *
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -0300802 * NOTE: the check for the packet types is done in
803 * dccp_rcv_state_process
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700804 */
805 if (sk->sk_state == DCCP_LISTEN) {
806 struct sock *nsk = dccp_v4_hnd_req(sk, skb);
807
808 if (nsk == NULL)
809 goto discard;
810
811 if (nsk != sk) {
812 if (dccp_child_process(sk, nsk, skb))
813 goto reset;
814 return 0;
815 }
816 }
817
818 if (dccp_rcv_state_process(sk, skb, dh, skb->len))
819 goto reset;
820 return 0;
821
822reset:
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700823 dccp_v4_ctl_send_reset(skb);
824discard:
825 kfree_skb(skb);
826 return 0;
827}
828
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800829EXPORT_SYMBOL_GPL(dccp_v4_do_rcv);
830
831int dccp_invalid_packet(struct sk_buff *skb)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700832{
833 const struct dccp_hdr *dh;
834
835 if (skb->pkt_type != PACKET_HOST)
836 return 1;
837
838 if (!pskb_may_pull(skb, sizeof(struct dccp_hdr))) {
Arnaldo Carvalho de Meloc59eab42005-08-18 21:12:02 -0300839 LIMIT_NETDEBUG(KERN_WARNING "DCCP: pskb_may_pull failed\n");
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700840 return 1;
841 }
842
843 dh = dccp_hdr(skb);
844
845 /* If the packet type is not understood, drop packet and return */
846 if (dh->dccph_type >= DCCP_PKT_INVALID) {
Arnaldo Carvalho de Meloc59eab42005-08-18 21:12:02 -0300847 LIMIT_NETDEBUG(KERN_WARNING "DCCP: invalid packet type\n");
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700848 return 1;
849 }
850
851 /*
852 * If P.Data Offset is too small for packet type, or too large for
853 * packet, drop packet and return
854 */
855 if (dh->dccph_doff < dccp_hdr_len(skb) / sizeof(u32)) {
Arnaldo Carvalho de Meloc59eab42005-08-18 21:12:02 -0300856 LIMIT_NETDEBUG(KERN_WARNING "DCCP: P.Data Offset(%u) "
857 "too small 1\n",
858 dh->dccph_doff);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700859 return 1;
860 }
861
862 if (!pskb_may_pull(skb, dh->dccph_doff * sizeof(u32))) {
Arnaldo Carvalho de Meloc59eab42005-08-18 21:12:02 -0300863 LIMIT_NETDEBUG(KERN_WARNING "DCCP: P.Data Offset(%u) "
864 "too small 2\n",
865 dh->dccph_doff);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700866 return 1;
867 }
868
869 dh = dccp_hdr(skb);
870
871 /*
872 * If P.type is not Data, Ack, or DataAck and P.X == 0 (the packet
873 * has short sequence numbers), drop packet and return
874 */
875 if (dh->dccph_x == 0 &&
876 dh->dccph_type != DCCP_PKT_DATA &&
877 dh->dccph_type != DCCP_PKT_ACK &&
878 dh->dccph_type != DCCP_PKT_DATAACK) {
Arnaldo Carvalho de Meloc59eab42005-08-18 21:12:02 -0300879 LIMIT_NETDEBUG(KERN_WARNING "DCCP: P.type (%s) not Data, Ack "
880 "nor DataAck and P.X == 0\n",
881 dccp_packet_name(dh->dccph_type));
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700882 return 1;
883 }
884
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700885 return 0;
886}
887
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800888EXPORT_SYMBOL_GPL(dccp_invalid_packet);
889
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700890/* this is called when real data arrives */
891int dccp_v4_rcv(struct sk_buff *skb)
892{
893 const struct dccp_hdr *dh;
894 struct sock *sk;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700895
896 /* Step 1: Check header basics: */
897
898 if (dccp_invalid_packet(skb))
899 goto discard_it;
900
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800901 /* If the header checksum is incorrect, drop packet and return */
902 if (dccp_v4_verify_checksum(skb, skb->nh.iph->saddr,
903 skb->nh.iph->daddr) < 0) {
904 LIMIT_NETDEBUG(KERN_WARNING "%s: incorrect header checksum\n",
905 __FUNCTION__);
906 goto discard_it;
907 }
908
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700909 dh = dccp_hdr(skb);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700910
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700911 DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(skb);
912 DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type;
913
914 dccp_pr_debug("%8.8s "
915 "src=%u.%u.%u.%u@%-5d "
916 "dst=%u.%u.%u.%u@%-5d seq=%llu",
917 dccp_packet_name(dh->dccph_type),
918 NIPQUAD(skb->nh.iph->saddr), ntohs(dh->dccph_sport),
919 NIPQUAD(skb->nh.iph->daddr), ntohs(dh->dccph_dport),
David S. Millerf6ccf552005-08-09 20:27:14 -0700920 (unsigned long long) DCCP_SKB_CB(skb)->dccpd_seq);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700921
922 if (dccp_packet_without_ack(skb)) {
923 DCCP_SKB_CB(skb)->dccpd_ack_seq = DCCP_PKT_WITHOUT_ACK_SEQ;
924 dccp_pr_debug_cat("\n");
925 } else {
926 DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb);
David S. Millerf6ccf552005-08-09 20:27:14 -0700927 dccp_pr_debug_cat(", ack=%llu\n",
928 (unsigned long long)
929 DCCP_SKB_CB(skb)->dccpd_ack_seq);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700930 }
931
932 /* Step 2:
933 * Look up flow ID in table and get corresponding socket */
934 sk = __inet_lookup(&dccp_hashinfo,
935 skb->nh.iph->saddr, dh->dccph_sport,
936 skb->nh.iph->daddr, ntohs(dh->dccph_dport),
937 inet_iif(skb));
938
939 /*
940 * Step 2:
941 * If no socket ...
942 * Generate Reset(No Connection) unless P.type == Reset
943 * Drop packet and return
944 */
945 if (sk == NULL) {
946 dccp_pr_debug("failed to look up flow ID in table and "
947 "get corresponding socket\n");
948 goto no_dccp_socket;
949 }
950
951 /*
952 * Step 2:
953 * ... or S.state == TIMEWAIT,
954 * Generate Reset(No Connection) unless P.type == Reset
955 * Drop packet and return
956 */
957
958 if (sk->sk_state == DCCP_TIME_WAIT) {
Arnaldo Carvalho de Melo64cf1e52005-08-09 20:45:21 -0700959 dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: "
960 "do_time_wait\n");
961 goto do_time_wait;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700962 }
963
Arnaldo Carvalho de Melo25995ff2005-12-27 02:42:22 -0200964 if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb))
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700965 goto discard_and_relse;
Patrick McHardyeb9c7eb2006-01-06 23:06:30 -0800966 nf_reset(skb);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700967
Arnaldo Carvalho de Melo25995ff2005-12-27 02:42:22 -0200968 return sk_receive_skb(sk, skb);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700969
970no_dccp_socket:
971 if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
972 goto discard_it;
973 /*
974 * Step 2:
975 * Generate Reset(No Connection) unless P.type == Reset
976 * Drop packet and return
977 */
978 if (dh->dccph_type != DCCP_PKT_RESET) {
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -0300979 DCCP_SKB_CB(skb)->dccpd_reset_code =
980 DCCP_RESET_CODE_NO_CONNECTION;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700981 dccp_v4_ctl_send_reset(skb);
982 }
983
984discard_it:
985 /* Discard frame. */
986 kfree_skb(skb);
987 return 0;
988
989discard_and_relse:
990 sock_put(sk);
991 goto discard_it;
Arnaldo Carvalho de Melo64cf1e52005-08-09 20:45:21 -0700992
993do_time_wait:
994 inet_twsk_put((struct inet_timewait_sock *)sk);
995 goto no_dccp_socket;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700996}
997
Arnaldo Carvalho de Melo57cca052005-12-13 23:16:16 -0800998struct inet_connection_sock_af_ops dccp_ipv4_af_ops = {
999 .queue_xmit = ip_queue_xmit,
1000 .send_check = dccp_v4_send_check,
1001 .rebuild_header = inet_sk_rebuild_header,
1002 .conn_request = dccp_v4_conn_request,
1003 .syn_recv_sock = dccp_v4_request_recv_sock,
1004 .net_header_len = sizeof(struct iphdr),
1005 .setsockopt = ip_setsockopt,
1006 .getsockopt = ip_getsockopt,
1007 .addr2sockaddr = inet_csk_addr2sockaddr,
1008 .sockaddr_len = sizeof(struct sockaddr_in),
1009};
1010
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -08001011static int dccp_v4_init_sock(struct sock *sk)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001012{
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -08001013 const int err = dccp_init_sock(sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001014
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -08001015 if (err == 0)
1016 inet_csk(sk)->icsk_af_ops = &dccp_ipv4_af_ops;
1017 return err;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001018}
1019
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001020static void dccp_v4_reqsk_destructor(struct request_sock *req)
1021{
1022 kfree(inet_rsk(req)->opt);
1023}
1024
1025static struct request_sock_ops dccp_request_sock_ops = {
1026 .family = PF_INET,
1027 .obj_size = sizeof(struct dccp_request_sock),
1028 .rtx_syn_ack = dccp_v4_send_response,
1029 .send_ack = dccp_v4_reqsk_send_ack,
1030 .destructor = dccp_v4_reqsk_destructor,
1031 .send_reset = dccp_v4_ctl_send_reset,
1032};
1033
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -08001034static struct timewait_sock_ops dccp_timewait_sock_ops = {
1035 .twsk_obj_size = sizeof(struct inet_timewait_sock),
1036};
1037
Arnaldo Carvalho de Melo34ca6862005-12-13 23:23:32 -08001038struct proto dccp_prot = {
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001039 .name = "DCCP",
1040 .owner = THIS_MODULE,
1041 .close = dccp_close,
1042 .connect = dccp_v4_connect,
1043 .disconnect = dccp_disconnect,
1044 .ioctl = dccp_ioctl,
1045 .init = dccp_v4_init_sock,
1046 .setsockopt = dccp_setsockopt,
1047 .getsockopt = dccp_getsockopt,
1048 .sendmsg = dccp_sendmsg,
1049 .recvmsg = dccp_recvmsg,
1050 .backlog_rcv = dccp_v4_do_rcv,
1051 .hash = dccp_v4_hash,
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -08001052 .unhash = dccp_unhash,
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001053 .accept = inet_csk_accept,
1054 .get_port = dccp_v4_get_port,
1055 .shutdown = dccp_shutdown,
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -08001056 .destroy = dccp_destroy_sock,
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001057 .orphan_count = &dccp_orphan_count,
1058 .max_header = MAX_DCCP_HEADER,
1059 .obj_size = sizeof(struct dccp_sock),
1060 .rsk_prot = &dccp_request_sock_ops,
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -08001061 .twsk_prot = &dccp_timewait_sock_ops,
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001062};
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -08001063
1064EXPORT_SYMBOL_GPL(dccp_prot);