| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  *  net/dccp/ipv4.c | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  An implementation of the DCCP protocol | 
					
						
							|  |  |  |  *  Arnaldo Carvalho de Melo <acme@conectiva.com.br> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *	This program is free software; you can redistribute it and/or | 
					
						
							|  |  |  |  *	modify it under the terms of the GNU General Public License | 
					
						
							|  |  |  |  *	as published by the Free Software Foundation; either version | 
					
						
							|  |  |  |  *	2 of the License, or (at your option) any later version. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/dccp.h>
 | 
					
						
							|  |  |  | #include <linux/icmp.h>
 | 
					
						
							|  |  |  | #include <linux/module.h>
 | 
					
						
							|  |  |  | #include <linux/skbuff.h>
 | 
					
						
							|  |  |  | #include <linux/random.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <net/icmp.h>
 | 
					
						
							| 
									
										
										
										
											2006-03-20 21:25:11 -08:00
										 |  |  | #include <net/inet_common.h>
 | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | #include <net/inet_hashtables.h>
 | 
					
						
							| 
									
										
										
										
											2005-12-27 02:43:12 -02:00
										 |  |  | #include <net/inet_sock.h>
 | 
					
						
							| 
									
										
										
										
											2006-03-20 21:25:11 -08:00
										 |  |  | #include <net/protocol.h>
 | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | #include <net/sock.h>
 | 
					
						
							| 
									
										
										
										
											2005-12-13 23:25:19 -08:00
										 |  |  | #include <net/timewait_sock.h>
 | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | #include <net/tcp_states.h>
 | 
					
						
							|  |  |  | #include <net/xfrm.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-18 00:17:51 -07:00
										 |  |  | #include "ackvec.h"
 | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | #include "ccid.h"
 | 
					
						
							|  |  |  | #include "dccp.h"
 | 
					
						
							| 
									
										
										
											
												[DCCP]: Initial feature negotiation implementation
Still needs more work, but boots and doesn't crashes, even
does some negotiation!
18:38:52.174934  127.0.0.1.43458 > 127.0.0.1.5001: request <change_l ack_ratio 2, change_r ccid 2, change_l ccid 2>
18:38:52.218526  127.0.0.1.5001 > 127.0.0.1.43458: response <nop, nop, change_l ack_ratio 2, confirm_r ccid 2 2, confirm_l ccid 2 2, confirm_r ack_ratio 2>
18:38:52.185398  127.0.0.1.43458 > 127.0.0.1.5001: <nop, confirm_r ack_ratio 2, ack_vector0 0x00, elapsed_time 212>
:-)
Signed-off-by: Andrea Bittau <a.bittau@cs.ucl.ac.uk>
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
											
										 
											2006-03-20 17:43:56 -08:00
										 |  |  | #include "feat.h"
 | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-03-20 22:00:37 -08:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * This is the global socket data structure used for responding to | 
					
						
							|  |  |  |  * the Out-of-the-blue (OOTB) packets. A control sock will be created | 
					
						
							|  |  |  |  * for this socket at the initialization time. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static struct socket *dccp_v4_ctl_socket; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | static int dccp_v4_get_port(struct sock *sk, const unsigned short snum) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2005-12-13 23:14:47 -08:00
										 |  |  | 	return inet_csk_get_port(&dccp_hashinfo, sk, snum, | 
					
						
							|  |  |  | 				 inet_csk_bind_conflict); | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-12-13 23:24:16 -08:00
										 |  |  | int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct inet_sock *inet = inet_sk(sk); | 
					
						
							|  |  |  | 	struct dccp_sock *dp = dccp_sk(sk); | 
					
						
							|  |  |  | 	const struct sockaddr_in *usin = (struct sockaddr_in *)uaddr; | 
					
						
							|  |  |  | 	struct rtable *rt; | 
					
						
							| 
									
										
										
										
											2006-09-26 21:27:15 -07:00
										 |  |  | 	__be32 daddr, nexthop; | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	int tmp; | 
					
						
							|  |  |  | 	int err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dp->dccps_role = DCCP_ROLE_CLIENT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (addr_len < sizeof(struct sockaddr_in)) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (usin->sin_family != AF_INET) | 
					
						
							|  |  |  | 		return -EAFNOSUPPORT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	nexthop = daddr = usin->sin_addr.s_addr; | 
					
						
							|  |  |  | 	if (inet->opt != NULL && inet->opt->srr) { | 
					
						
							|  |  |  | 		if (daddr == 0) | 
					
						
							|  |  |  | 			return -EINVAL; | 
					
						
							|  |  |  | 		nexthop = inet->opt->faddr; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tmp = ip_route_connect(&rt, nexthop, inet->saddr, | 
					
						
							|  |  |  | 			       RT_CONN_FLAGS(sk), sk->sk_bound_dev_if, | 
					
						
							|  |  |  | 			       IPPROTO_DCCP, | 
					
						
							| 
									
										
										
										
											2007-02-08 02:09:21 -08:00
										 |  |  | 			       inet->sport, usin->sin_port, sk, 1); | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	if (tmp < 0) | 
					
						
							|  |  |  | 		return tmp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) { | 
					
						
							|  |  |  | 		ip_rt_put(rt); | 
					
						
							|  |  |  | 		return -ENETUNREACH; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (inet->opt == NULL || !inet->opt->srr) | 
					
						
							|  |  |  | 		daddr = rt->rt_dst; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (inet->saddr == 0) | 
					
						
							|  |  |  | 		inet->saddr = rt->rt_src; | 
					
						
							|  |  |  | 	inet->rcv_saddr = inet->saddr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	inet->dport = usin->sin_port; | 
					
						
							|  |  |  | 	inet->daddr = daddr; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-12-13 23:26:10 -08:00
										 |  |  | 	inet_csk(sk)->icsk_ext_hdr_len = 0; | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	if (inet->opt != NULL) | 
					
						
							| 
									
										
										
										
											2005-12-13 23:26:10 -08:00
										 |  |  | 		inet_csk(sk)->icsk_ext_hdr_len = inet->opt->optlen; | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Socket identity is still unknown (sport may be zero). | 
					
						
							|  |  |  | 	 * However we set state to DCCP_REQUESTING and not releasing socket | 
					
						
							|  |  |  | 	 * lock select source port, enter ourselves into the hash tables and | 
					
						
							|  |  |  | 	 * complete initialization after this. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	dccp_set_state(sk, DCCP_REQUESTING); | 
					
						
							| 
									
										
										
										
											2005-12-13 23:25:31 -08:00
										 |  |  | 	err = inet_hash_connect(&dccp_death_row, sk); | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	if (err != 0) | 
					
						
							|  |  |  | 		goto failure; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-01-31 17:35:35 -08:00
										 |  |  | 	err = ip_route_newports(&rt, IPPROTO_DCCP, inet->sport, inet->dport, | 
					
						
							| 
									
										
										
										
											2007-02-09 23:24:38 +09:00
										 |  |  | 				sk); | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	if (err != 0) | 
					
						
							|  |  |  | 		goto failure; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* OK, now commit destination to socket.  */ | 
					
						
							|  |  |  | 	sk_setup_caps(sk, &rt->u.dst); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-11-13 13:34:38 -02:00
										 |  |  | 	dp->dccps_iss = secure_dccp_sequence_number(inet->saddr, inet->daddr, | 
					
						
							|  |  |  | 						    inet->sport, inet->dport); | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	inet->id = dp->dccps_iss ^ jiffies; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err = dccp_connect(sk); | 
					
						
							|  |  |  | 	rt = NULL; | 
					
						
							|  |  |  | 	if (err != 0) | 
					
						
							|  |  |  | 		goto failure; | 
					
						
							|  |  |  | out: | 
					
						
							|  |  |  | 	return err; | 
					
						
							|  |  |  | failure: | 
					
						
							| 
									
										
										
										
											2005-08-13 20:34:54 -03:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * This unhashes the socket and releases the local port, if necessary. | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	dccp_set_state(sk, DCCP_CLOSED); | 
					
						
							|  |  |  | 	ip_rt_put(rt); | 
					
						
							|  |  |  | 	sk->sk_route_caps = 0; | 
					
						
							|  |  |  | 	inet->dport = 0; | 
					
						
							|  |  |  | 	goto out; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-12-13 23:24:16 -08:00
										 |  |  | EXPORT_SYMBOL_GPL(dccp_v4_connect); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * This routine does path mtu discovery as defined in RFC1191. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static inline void dccp_do_pmtu_discovery(struct sock *sk, | 
					
						
							|  |  |  | 					  const struct iphdr *iph, | 
					
						
							|  |  |  | 					  u32 mtu) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct dst_entry *dst; | 
					
						
							|  |  |  | 	const struct inet_sock *inet = inet_sk(sk); | 
					
						
							|  |  |  | 	const struct dccp_sock *dp = dccp_sk(sk); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* We are not interested in DCCP_LISTEN and request_socks (RESPONSEs
 | 
					
						
							|  |  |  | 	 * send out by Linux are always < 576bytes so they should go through | 
					
						
							|  |  |  | 	 * unfragmented). | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (sk->sk_state == DCCP_LISTEN) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* We don't check in the destentry if pmtu discovery is forbidden
 | 
					
						
							|  |  |  | 	 * on this route. We just assume that no packet_to_big packets | 
					
						
							|  |  |  | 	 * are send back when pmtu discovery is not active. | 
					
						
							| 
									
										
										
										
											2007-02-09 23:24:38 +09:00
										 |  |  | 	 * There is a small race when the user changes this flag in the | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	 * route, but I think that's acceptable. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if ((dst = __sk_dst_check(sk, 0)) == NULL) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dst->ops->update_pmtu(dst, mtu); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Something is about to be wrong... Remember soft error
 | 
					
						
							|  |  |  | 	 * for the case, if this connection will not able to recover. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (mtu < dst_mtu(dst) && ip_dont_fragment(sk, dst)) | 
					
						
							|  |  |  | 		sk->sk_err_soft = EMSGSIZE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mtu = dst_mtu(dst); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (inet->pmtudisc != IP_PMTUDISC_DONT && | 
					
						
							| 
									
										
										
										
											2005-12-13 23:26:10 -08:00
										 |  |  | 	    inet_csk(sk)->icsk_pmtu_cookie > mtu) { | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 		dccp_sync_mss(sk, mtu); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/*
 | 
					
						
							| 
									
										
										
										
											2006-10-24 16:17:51 -07:00
										 |  |  | 		 * From RFC 4340, sec. 14.1: | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 		 * | 
					
						
							| 
									
										
										
										
											2005-08-13 20:34:54 -03:00
										 |  |  | 		 *	DCCP-Sync packets are the best choice for upward | 
					
						
							|  |  |  | 		 *	probing, since DCCP-Sync probes do not risk application | 
					
						
							|  |  |  | 		 *	data loss. | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2005-08-17 03:10:59 -03:00
										 |  |  | 		dccp_send_sync(sk, dp->dccps_gsr, DCCP_PKT_SYNC); | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	} /* else let the usual retransmit timer handle it */ | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * This routine is called by the ICMP module when it gets some sort of error | 
					
						
							|  |  |  |  * condition. If err < 0 then the socket should be closed and the error | 
					
						
							|  |  |  |  * returned to the user. If err > 0 it's just the icmp type << 8 | icmp code. | 
					
						
							|  |  |  |  * After adjustment header points to the first 8 bytes of the tcp header. We | 
					
						
							|  |  |  |  * need to find the appropriate port. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The locking strategy used here is very "optimistic". When someone else | 
					
						
							|  |  |  |  * accesses the socket the ICMP is just dropped and for some paths there is no | 
					
						
							|  |  |  |  * check at all. A more general error queue to queue errors for later handling | 
					
						
							|  |  |  |  * is probably better. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2006-03-20 21:25:11 -08:00
										 |  |  | static void dccp_v4_err(struct sk_buff *skb, u32 info) | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	const struct iphdr *iph = (struct iphdr *)skb->data; | 
					
						
							| 
									
										
										
										
											2005-08-13 20:34:54 -03:00
										 |  |  | 	const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + | 
					
						
							|  |  |  | 							(iph->ihl << 2)); | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	struct dccp_sock *dp; | 
					
						
							|  |  |  | 	struct inet_sock *inet; | 
					
						
							| 
									
										
										
										
											2007-03-13 14:43:18 -03:00
										 |  |  | 	const int type = icmp_hdr(skb)->type; | 
					
						
							|  |  |  | 	const int code = icmp_hdr(skb)->code; | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	struct sock *sk; | 
					
						
							|  |  |  | 	__u64 seq; | 
					
						
							|  |  |  | 	int err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (skb->len < (iph->ihl << 2) + 8) { | 
					
						
							|  |  |  | 		ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sk = inet_lookup(&dccp_hashinfo, iph->daddr, dh->dccph_dport, | 
					
						
							|  |  |  | 			 iph->saddr, dh->dccph_sport, inet_iif(skb)); | 
					
						
							|  |  |  | 	if (sk == NULL) { | 
					
						
							|  |  |  | 		ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (sk->sk_state == DCCP_TIME_WAIT) { | 
					
						
							| 
									
										
										
										
											2006-10-10 19:41:46 -07:00
										 |  |  | 		inet_twsk_put(inet_twsk(sk)); | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bh_lock_sock(sk); | 
					
						
							|  |  |  | 	/* If too many ICMPs get dropped on busy
 | 
					
						
							|  |  |  | 	 * servers this needs to be solved differently. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (sock_owned_by_user(sk)) | 
					
						
							|  |  |  | 		NET_INC_STATS_BH(LINUX_MIB_LOCKDROPPEDICMPS); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (sk->sk_state == DCCP_CLOSED) | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dp = dccp_sk(sk); | 
					
						
							| 
									
										
										
										
											2007-10-24 10:12:09 -02:00
										 |  |  | 	seq = dccp_hdr_seq(dh); | 
					
						
							| 
									
										
										
										
											2007-10-24 10:18:06 -02:00
										 |  |  | 	if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_LISTEN) && | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	    !between48(seq, dp->dccps_swl, dp->dccps_swh)) { | 
					
						
							| 
									
										
										
										
											2006-11-16 12:23:58 -02:00
										 |  |  | 		NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS); | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (type) { | 
					
						
							|  |  |  | 	case ICMP_SOURCE_QUENCH: | 
					
						
							|  |  |  | 		/* Just silently ignore these. */ | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 	case ICMP_PARAMETERPROB: | 
					
						
							|  |  |  | 		err = EPROTO; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case ICMP_DEST_UNREACH: | 
					
						
							|  |  |  | 		if (code > NR_ICMP_UNREACH) | 
					
						
							|  |  |  | 			goto out; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (code == ICMP_FRAG_NEEDED) { /* PMTU discovery (RFC1191) */ | 
					
						
							|  |  |  | 			if (!sock_owned_by_user(sk)) | 
					
						
							|  |  |  | 				dccp_do_pmtu_discovery(sk, iph, info); | 
					
						
							|  |  |  | 			goto out; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		err = icmp_err_convert[code].errno; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case ICMP_TIME_EXCEEDED: | 
					
						
							|  |  |  | 		err = EHOSTUNREACH; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (sk->sk_state) { | 
					
						
							|  |  |  | 		struct request_sock *req , **prev; | 
					
						
							|  |  |  | 	case DCCP_LISTEN: | 
					
						
							|  |  |  | 		if (sock_owned_by_user(sk)) | 
					
						
							|  |  |  | 			goto out; | 
					
						
							|  |  |  | 		req = inet_csk_search_req(sk, &prev, dh->dccph_dport, | 
					
						
							|  |  |  | 					  iph->daddr, iph->saddr); | 
					
						
							|  |  |  | 		if (!req) | 
					
						
							|  |  |  | 			goto out; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * ICMPs are not backlogged, hence we cannot get an established | 
					
						
							|  |  |  | 		 * socket here. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		BUG_TRAP(!req->sk); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (seq != dccp_rsk(req)->dreq_iss) { | 
					
						
							|  |  |  | 			NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS); | 
					
						
							|  |  |  | 			goto out; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * Still in RESPOND, just remove it silently. | 
					
						
							|  |  |  | 		 * There is no good way to pass the error to the newly | 
					
						
							|  |  |  | 		 * created socket, and POSIX does not want network | 
					
						
							|  |  |  | 		 * errors returned from accept(). | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		inet_csk_reqsk_queue_drop(sk, req, prev); | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case DCCP_REQUESTING: | 
					
						
							|  |  |  | 	case DCCP_RESPOND: | 
					
						
							|  |  |  | 		if (!sock_owned_by_user(sk)) { | 
					
						
							|  |  |  | 			DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS); | 
					
						
							|  |  |  | 			sk->sk_err = err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			sk->sk_error_report(sk); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			dccp_done(sk); | 
					
						
							|  |  |  | 		} else | 
					
						
							|  |  |  | 			sk->sk_err_soft = err; | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* If we've already connected we will keep trying
 | 
					
						
							|  |  |  | 	 * until we time out, or the user gives up. | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * rfc1122 4.2.3.9 allows to consider as hard errors | 
					
						
							|  |  |  | 	 * only PROTO_UNREACH and PORT_UNREACH (well, FRAG_FAILED too, | 
					
						
							|  |  |  | 	 * but it is obsoleted by pmtu discovery). | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * Note, that in modern internet, where routing is unreliable | 
					
						
							|  |  |  | 	 * and in each dark corner broken firewalls sit, sending random | 
					
						
							|  |  |  | 	 * errors ordered by their masters even this two messages finally lose | 
					
						
							|  |  |  | 	 * their original sense (even Linux sends invalid PORT_UNREACHs) | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * Now we are in compliance with RFCs. | 
					
						
							|  |  |  | 	 *							--ANK (980905) | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	inet = inet_sk(sk); | 
					
						
							|  |  |  | 	if (!sock_owned_by_user(sk) && inet->recverr) { | 
					
						
							|  |  |  | 		sk->sk_err = err; | 
					
						
							|  |  |  | 		sk->sk_error_report(sk); | 
					
						
							|  |  |  | 	} else /* Only an error on timeout */ | 
					
						
							|  |  |  | 		sk->sk_err_soft = err; | 
					
						
							|  |  |  | out: | 
					
						
							|  |  |  | 	bh_unlock_sock(sk); | 
					
						
							|  |  |  | 	sock_put(sk); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-11-14 21:28:51 -08:00
										 |  |  | static inline __sum16 dccp_v4_csum_finish(struct sk_buff *skb, | 
					
						
							| 
									
										
										
										
											2006-11-10 17:43:06 -02:00
										 |  |  | 				      __be32 src, __be32 dst) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return csum_tcpudp_magic(src, dst, skb->len, IPPROTO_DCCP, skb->csum); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void dccp_v4_send_check(struct sock *sk, int unused, struct sk_buff *skb) | 
					
						
							| 
									
										
										
										
											2005-12-13 23:16:16 -08:00
										 |  |  | { | 
					
						
							|  |  |  | 	const struct inet_sock *inet = inet_sk(sk); | 
					
						
							|  |  |  | 	struct dccp_hdr *dh = dccp_hdr(skb); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-11-10 17:43:06 -02:00
										 |  |  | 	dccp_csum_outgoing(skb); | 
					
						
							|  |  |  | 	dh->dccph_checksum = dccp_v4_csum_finish(skb, inet->saddr, inet->daddr); | 
					
						
							| 
									
										
										
										
											2005-12-13 23:16:16 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-12-13 23:24:16 -08:00
										 |  |  | EXPORT_SYMBOL_GPL(dccp_v4_send_check); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-11-13 13:31:50 -02:00
										 |  |  | static inline u64 dccp_v4_init_sequence(const struct sk_buff *skb) | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-04-20 22:47:35 -07:00
										 |  |  | 	return secure_dccp_sequence_number(ip_hdr(skb)->daddr, | 
					
						
							|  |  |  | 					   ip_hdr(skb)->saddr, | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 					   dccp_hdr(skb)->dccph_dport, | 
					
						
							|  |  |  | 					   dccp_hdr(skb)->dccph_sport); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * The three way handshake has completed - we got a valid ACK or DATAACK - | 
					
						
							|  |  |  |  * now create the new socket. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This is the equivalent of TCP's tcp_v4_syn_recv_sock | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | struct sock *dccp_v4_request_recv_sock(struct sock *sk, struct sk_buff *skb, | 
					
						
							|  |  |  | 				       struct request_sock *req, | 
					
						
							|  |  |  | 				       struct dst_entry *dst) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct inet_request_sock *ireq; | 
					
						
							|  |  |  | 	struct inet_sock *newinet; | 
					
						
							|  |  |  | 	struct sock *newsk; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (sk_acceptq_is_full(sk)) | 
					
						
							|  |  |  | 		goto exit_overflow; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (dst == NULL && (dst = inet_csk_route_req(sk, req)) == NULL) | 
					
						
							|  |  |  | 		goto exit; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	newsk = dccp_create_openreq_child(sk, req, skb); | 
					
						
							|  |  |  | 	if (newsk == NULL) | 
					
						
							|  |  |  | 		goto exit; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sk_setup_caps(newsk, dst); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	newinet		   = inet_sk(newsk); | 
					
						
							|  |  |  | 	ireq		   = inet_rsk(req); | 
					
						
							|  |  |  | 	newinet->daddr	   = ireq->rmt_addr; | 
					
						
							|  |  |  | 	newinet->rcv_saddr = ireq->loc_addr; | 
					
						
							|  |  |  | 	newinet->saddr	   = ireq->loc_addr; | 
					
						
							|  |  |  | 	newinet->opt	   = ireq->opt; | 
					
						
							|  |  |  | 	ireq->opt	   = NULL; | 
					
						
							|  |  |  | 	newinet->mc_index  = inet_iif(skb); | 
					
						
							| 
									
										
										
										
											2007-04-20 22:47:35 -07:00
										 |  |  | 	newinet->mc_ttl	   = ip_hdr(skb)->ttl; | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	newinet->id	   = jiffies; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dccp_sync_mss(newsk, dst_mtu(dst)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	__inet_hash(&dccp_hashinfo, newsk, 0); | 
					
						
							|  |  |  | 	__inet_inherit_port(&dccp_hashinfo, sk, newsk); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return newsk; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | exit_overflow: | 
					
						
							|  |  |  | 	NET_INC_STATS_BH(LINUX_MIB_LISTENOVERFLOWS); | 
					
						
							|  |  |  | exit: | 
					
						
							|  |  |  | 	NET_INC_STATS_BH(LINUX_MIB_LISTENDROPS); | 
					
						
							|  |  |  | 	dst_release(dst); | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-12-13 23:24:16 -08:00
										 |  |  | EXPORT_SYMBOL_GPL(dccp_v4_request_recv_sock); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | static struct sock *dccp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	const struct dccp_hdr *dh = dccp_hdr(skb); | 
					
						
							| 
									
										
										
										
											2007-04-20 22:47:35 -07:00
										 |  |  | 	const struct iphdr *iph = ip_hdr(skb); | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	struct sock *nsk; | 
					
						
							|  |  |  | 	struct request_sock **prev; | 
					
						
							|  |  |  | 	/* Find possible connection requests. */ | 
					
						
							|  |  |  | 	struct request_sock *req = inet_csk_search_req(sk, &prev, | 
					
						
							|  |  |  | 						       dh->dccph_sport, | 
					
						
							|  |  |  | 						       iph->saddr, iph->daddr); | 
					
						
							|  |  |  | 	if (req != NULL) | 
					
						
							|  |  |  | 		return dccp_check_req(sk, skb, req, prev); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-09 15:47:12 -07:00
										 |  |  | 	nsk = inet_lookup_established(&dccp_hashinfo, | 
					
						
							|  |  |  | 				      iph->saddr, dh->dccph_sport, | 
					
						
							|  |  |  | 				      iph->daddr, dh->dccph_dport, | 
					
						
							|  |  |  | 				      inet_iif(skb)); | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	if (nsk != NULL) { | 
					
						
							|  |  |  | 		if (nsk->sk_state != DCCP_TIME_WAIT) { | 
					
						
							|  |  |  | 			bh_lock_sock(nsk); | 
					
						
							|  |  |  | 			return nsk; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2006-10-10 19:41:46 -07:00
										 |  |  | 		inet_twsk_put(inet_twsk(nsk)); | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return sk; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct dst_entry* dccp_v4_route_skb(struct sock *sk, | 
					
						
							|  |  |  | 					   struct sk_buff *skb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct rtable *rt; | 
					
						
							|  |  |  | 	struct flowi fl = { .oif = ((struct rtable *)skb->dst)->rt_iif, | 
					
						
							|  |  |  | 			    .nl_u = { .ip4_u = | 
					
						
							| 
									
										
										
										
											2007-04-20 22:47:35 -07:00
										 |  |  | 				      { .daddr = ip_hdr(skb)->saddr, | 
					
						
							|  |  |  | 					.saddr = ip_hdr(skb)->daddr, | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 					.tos = RT_CONN_FLAGS(sk) } }, | 
					
						
							|  |  |  | 			    .proto = sk->sk_protocol, | 
					
						
							|  |  |  | 			    .uli_u = { .ports = | 
					
						
							|  |  |  | 				       { .sport = dccp_hdr(skb)->dccph_dport, | 
					
						
							| 
									
										
										
										
											2005-08-13 20:34:54 -03:00
										 |  |  | 					 .dport = dccp_hdr(skb)->dccph_sport } | 
					
						
							| 
									
										
										
										
											2006-12-10 16:01:18 -02:00
										 |  |  | 				     } | 
					
						
							| 
									
										
										
										
											2005-08-13 20:34:54 -03:00
										 |  |  | 			  }; | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-04 23:12:42 -07:00
										 |  |  | 	security_skb_classify_flow(skb, &fl); | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	if (ip_route_output_flow(&rt, &fl, sk, 0)) { | 
					
						
							|  |  |  | 		IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return &rt->u.dst; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-11-10 12:52:36 -02:00
										 |  |  | static int dccp_v4_send_response(struct sock *sk, struct request_sock *req, | 
					
						
							|  |  |  | 				 struct dst_entry *dst) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int err = -1; | 
					
						
							|  |  |  | 	struct sk_buff *skb; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* First, grab a route. */ | 
					
						
							| 
									
										
										
										
											2007-02-09 23:24:38 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-11-10 12:52:36 -02:00
										 |  |  | 	if (dst == NULL && (dst = inet_csk_route_req(sk, req)) == NULL) | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	skb = dccp_make_response(sk, dst, req); | 
					
						
							|  |  |  | 	if (skb != NULL) { | 
					
						
							|  |  |  | 		const struct inet_request_sock *ireq = inet_rsk(req); | 
					
						
							|  |  |  | 		struct dccp_hdr *dh = dccp_hdr(skb); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-11-10 17:43:06 -02:00
										 |  |  | 		dh->dccph_checksum = dccp_v4_csum_finish(skb, ireq->loc_addr, | 
					
						
							|  |  |  | 							      ireq->rmt_addr); | 
					
						
							| 
									
										
										
										
											2006-11-10 12:52:36 -02:00
										 |  |  | 		memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); | 
					
						
							|  |  |  | 		err = ip_build_and_send_pkt(skb, sk, ireq->loc_addr, | 
					
						
							|  |  |  | 					    ireq->rmt_addr, | 
					
						
							|  |  |  | 					    ireq->opt); | 
					
						
							| 
									
										
										
										
											2006-11-14 11:21:36 -02:00
										 |  |  | 		err = net_xmit_eval(err); | 
					
						
							| 
									
										
										
										
											2006-11-10 12:52:36 -02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | out: | 
					
						
							|  |  |  | 	dst_release(dst); | 
					
						
							|  |  |  | 	return err; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-11-14 19:07:45 -08:00
										 |  |  | static void dccp_v4_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	int err; | 
					
						
							| 
									
										
										
										
											2007-04-20 22:47:35 -07:00
										 |  |  | 	const struct iphdr *rxiph; | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	struct sk_buff *skb; | 
					
						
							|  |  |  | 	struct dst_entry *dst; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Never send a reset in response to a reset. */ | 
					
						
							| 
									
										
											  
											
												[DCCP]: Factor out common code for generating Resets
This factors code common to dccp_v{4,6}_ctl_send_reset into a separate function,
and adds support for filling in the Data 1 ... Data 3 fields from RFC 4340, 5.6.
It is useful to have this separate, since the following Reset codes will always
be generated from the control socket rather than via dccp_send_reset:
 * Code 3, "No Connection", cf. 8.3.1;
 * Code 4, "Packet Error" (identification for Data 1 added);
 * Code 5, "Option Error" (identification for Data 1..3 added, will be used later);
 * Code 6, "Mandatory Error" (same as Option Error);
 * Code 7, "Connection Refused" (what on Earth is the difference to "No Connection"?);
 * Code 8, "Bad Service Code";
 * Code 9, "Too Busy";
 * Code 10, "Bad Init Cookie" (not used).
Code 0 is not recommended by the RFC, the following codes would be used in
dccp_send_reset() instead, since they all relate to an established DCCP connection:
 * Code 1, "Closed";
 * Code 2, "Aborted";
 * Code 11, "Aggression Penalty" (12.3).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
											
										 
											2007-09-26 14:35:19 -03:00
										 |  |  | 	if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET) | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (((struct rtable *)rxskb->dst)->rt_type != RTN_LOCAL) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-03-20 22:00:37 -08:00
										 |  |  | 	dst = dccp_v4_route_skb(dccp_v4_ctl_socket->sk, rxskb); | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	if (dst == NULL) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												[DCCP]: Factor out common code for generating Resets
This factors code common to dccp_v{4,6}_ctl_send_reset into a separate function,
and adds support for filling in the Data 1 ... Data 3 fields from RFC 4340, 5.6.
It is useful to have this separate, since the following Reset codes will always
be generated from the control socket rather than via dccp_send_reset:
 * Code 3, "No Connection", cf. 8.3.1;
 * Code 4, "Packet Error" (identification for Data 1 added);
 * Code 5, "Option Error" (identification for Data 1..3 added, will be used later);
 * Code 6, "Mandatory Error" (same as Option Error);
 * Code 7, "Connection Refused" (what on Earth is the difference to "No Connection"?);
 * Code 8, "Bad Service Code";
 * Code 9, "Too Busy";
 * Code 10, "Bad Init Cookie" (not used).
Code 0 is not recommended by the RFC, the following codes would be used in
dccp_send_reset() instead, since they all relate to an established DCCP connection:
 * Code 1, "Closed";
 * Code 2, "Aborted";
 * Code 11, "Aggression Penalty" (12.3).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
											
										 
											2007-09-26 14:35:19 -03:00
										 |  |  | 	skb = dccp_ctl_make_reset(dccp_v4_ctl_socket, rxskb); | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	if (skb == NULL) | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-04-20 22:47:35 -07:00
										 |  |  | 	rxiph = ip_hdr(rxskb); | 
					
						
							| 
									
										
											  
											
												[DCCP]: Factor out common code for generating Resets
This factors code common to dccp_v{4,6}_ctl_send_reset into a separate function,
and adds support for filling in the Data 1 ... Data 3 fields from RFC 4340, 5.6.
It is useful to have this separate, since the following Reset codes will always
be generated from the control socket rather than via dccp_send_reset:
 * Code 3, "No Connection", cf. 8.3.1;
 * Code 4, "Packet Error" (identification for Data 1 added);
 * Code 5, "Option Error" (identification for Data 1..3 added, will be used later);
 * Code 6, "Mandatory Error" (same as Option Error);
 * Code 7, "Connection Refused" (what on Earth is the difference to "No Connection"?);
 * Code 8, "Bad Service Code";
 * Code 9, "Too Busy";
 * Code 10, "Bad Init Cookie" (not used).
Code 0 is not recommended by the RFC, the following codes would be used in
dccp_send_reset() instead, since they all relate to an established DCCP connection:
 * Code 1, "Closed";
 * Code 2, "Aborted";
 * Code 11, "Aggression Penalty" (12.3).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
											
										 
											2007-09-26 14:35:19 -03:00
										 |  |  | 	dccp_hdr(skb)->dccph_checksum = dccp_v4_csum_finish(skb, rxiph->saddr, | 
					
						
							|  |  |  | 								 rxiph->daddr); | 
					
						
							|  |  |  | 	skb->dst = dst_clone(dst); | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-03-20 22:00:37 -08:00
										 |  |  | 	bh_lock_sock(dccp_v4_ctl_socket->sk); | 
					
						
							|  |  |  | 	err = ip_build_and_send_pkt(skb, dccp_v4_ctl_socket->sk, | 
					
						
							| 
									
										
										
										
											2007-04-20 22:47:35 -07:00
										 |  |  | 				    rxiph->daddr, rxiph->saddr, NULL); | 
					
						
							| 
									
										
										
										
											2006-03-20 22:00:37 -08:00
										 |  |  | 	bh_unlock_sock(dccp_v4_ctl_socket->sk); | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-11-14 11:21:36 -02:00
										 |  |  | 	if (net_xmit_eval(err) == 0) { | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 		DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS); | 
					
						
							|  |  |  | 		DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | out: | 
					
						
							|  |  |  | 	 dst_release(dst); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-11-10 12:52:36 -02:00
										 |  |  | static void dccp_v4_reqsk_destructor(struct request_sock *req) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	kfree(inet_rsk(req)->opt); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct request_sock_ops dccp_request_sock_ops __read_mostly = { | 
					
						
							|  |  |  | 	.family		= PF_INET, | 
					
						
							|  |  |  | 	.obj_size	= sizeof(struct dccp_request_sock), | 
					
						
							|  |  |  | 	.rtx_syn_ack	= dccp_v4_send_response, | 
					
						
							|  |  |  | 	.send_ack	= dccp_reqsk_send_ack, | 
					
						
							|  |  |  | 	.destructor	= dccp_v4_reqsk_destructor, | 
					
						
							|  |  |  | 	.send_reset	= dccp_v4_ctl_send_reset, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct inet_request_sock *ireq; | 
					
						
							|  |  |  | 	struct request_sock *req; | 
					
						
							|  |  |  | 	struct dccp_request_sock *dreq; | 
					
						
							| 
									
										
										
										
											2006-12-10 16:01:18 -02:00
										 |  |  | 	const __be32 service = dccp_hdr_request(skb)->dccph_req_service; | 
					
						
							| 
									
										
										
										
											2006-11-10 12:52:36 -02:00
										 |  |  | 	struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Never answer to DCCP_PKT_REQUESTs send to broadcast or multicast */ | 
					
						
							|  |  |  | 	if (((struct rtable *)skb->dst)->rt_flags & | 
					
						
							| 
									
										
											  
											
												[DCCP]: Twice the wrong reset code in receiving connection-Requests
This fixes two bugs in processing of connection-Requests in
v{4,6}_conn_request:
 1. Due to using the variable `reset_code', the Reset code generated
    internally by dccp_parse_options() is overwritten with the
    initialised value ("Too Busy") of reset_code, which is not what is
    intended.
 2. When receiving a connection-Request on a multicast or broadcast
    address, no Reset should be generated, to avoid storms of such
    packets. Instead of jumping to the `drop' label, the
    v{4,6}_conn_request functions now return 0. Below is why in my
    understanding this is correct:
    When the conn_request function returns < 0, then the caller,
    dccp_rcv_state_process(), returns 1. In all instances where
    dccp_rcv_state_process is called (dccp_v4_do_rcv, dccp_v6_do_rcv,
    and dccp_child_process), a return value of != 0 from
    dccp_rcv_state_process() means that a Reset is generated.
    If on the other hand the conn_request function returns 0, the
    packet is discarded and no Reset is generated.
Note: There may be a related problem when sending the Response, due to
the following.
	if (dccp_v6_send_response(sk, req, NULL))
		goto drop_and_free;
	/* ... */
	drop_and_free:
		return -1;
In this case, if send_response fails due to transmission errors, the
next thing that is generated is a Reset with a code "Too Busy". I
haven't been able to conjure up such a condition, but it might be good
to change the behaviour here also (not done by this patch).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
											
										 
											2007-10-04 14:52:28 -07:00
										 |  |  | 	    (RTCF_BROADCAST | RTCF_MULTICAST)) | 
					
						
							|  |  |  | 		return 0;	/* discard, don't send a reset here */ | 
					
						
							| 
									
										
										
										
											2006-11-10 12:52:36 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (dccp_bad_service_code(sk, service)) { | 
					
						
							| 
									
										
											  
											
												[DCCP]: Twice the wrong reset code in receiving connection-Requests
This fixes two bugs in processing of connection-Requests in
v{4,6}_conn_request:
 1. Due to using the variable `reset_code', the Reset code generated
    internally by dccp_parse_options() is overwritten with the
    initialised value ("Too Busy") of reset_code, which is not what is
    intended.
 2. When receiving a connection-Request on a multicast or broadcast
    address, no Reset should be generated, to avoid storms of such
    packets. Instead of jumping to the `drop' label, the
    v{4,6}_conn_request functions now return 0. Below is why in my
    understanding this is correct:
    When the conn_request function returns < 0, then the caller,
    dccp_rcv_state_process(), returns 1. In all instances where
    dccp_rcv_state_process is called (dccp_v4_do_rcv, dccp_v6_do_rcv,
    and dccp_child_process), a return value of != 0 from
    dccp_rcv_state_process() means that a Reset is generated.
    If on the other hand the conn_request function returns 0, the
    packet is discarded and no Reset is generated.
Note: There may be a related problem when sending the Response, due to
the following.
	if (dccp_v6_send_response(sk, req, NULL))
		goto drop_and_free;
	/* ... */
	drop_and_free:
		return -1;
In this case, if send_response fails due to transmission errors, the
next thing that is generated is a Reset with a code "Too Busy". I
haven't been able to conjure up such a condition, but it might be good
to change the behaviour here also (not done by this patch).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
											
										 
											2007-10-04 14:52:28 -07:00
										 |  |  | 		dcb->dccpd_reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE; | 
					
						
							| 
									
										
										
										
											2006-11-10 12:52:36 -02:00
										 |  |  | 		goto drop; | 
					
						
							| 
									
										
										
										
											2006-12-10 16:01:18 -02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-11-10 12:52:36 -02:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * TW buckets are converted to open requests without | 
					
						
							|  |  |  | 	 * limitations, they conserve resources and peer is | 
					
						
							|  |  |  | 	 * evidently real one. | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
											  
											
												[DCCP]: Twice the wrong reset code in receiving connection-Requests
This fixes two bugs in processing of connection-Requests in
v{4,6}_conn_request:
 1. Due to using the variable `reset_code', the Reset code generated
    internally by dccp_parse_options() is overwritten with the
    initialised value ("Too Busy") of reset_code, which is not what is
    intended.
 2. When receiving a connection-Request on a multicast or broadcast
    address, no Reset should be generated, to avoid storms of such
    packets. Instead of jumping to the `drop' label, the
    v{4,6}_conn_request functions now return 0. Below is why in my
    understanding this is correct:
    When the conn_request function returns < 0, then the caller,
    dccp_rcv_state_process(), returns 1. In all instances where
    dccp_rcv_state_process is called (dccp_v4_do_rcv, dccp_v6_do_rcv,
    and dccp_child_process), a return value of != 0 from
    dccp_rcv_state_process() means that a Reset is generated.
    If on the other hand the conn_request function returns 0, the
    packet is discarded and no Reset is generated.
Note: There may be a related problem when sending the Response, due to
the following.
	if (dccp_v6_send_response(sk, req, NULL))
		goto drop_and_free;
	/* ... */
	drop_and_free:
		return -1;
In this case, if send_response fails due to transmission errors, the
next thing that is generated is a Reset with a code "Too Busy". I
haven't been able to conjure up such a condition, but it might be good
to change the behaviour here also (not done by this patch).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
											
										 
											2007-10-04 14:52:28 -07:00
										 |  |  | 	dcb->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY; | 
					
						
							| 
									
										
										
										
											2006-11-10 12:52:36 -02:00
										 |  |  | 	if (inet_csk_reqsk_queue_is_full(sk)) | 
					
						
							|  |  |  | 		goto drop; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Accept backlog is full. If we have already queued enough | 
					
						
							|  |  |  | 	 * of warm entries in syn queue, drop request. It is better than | 
					
						
							|  |  |  | 	 * clogging syn queue with openreqs with exponentially increasing | 
					
						
							|  |  |  | 	 * timeout. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) | 
					
						
							|  |  |  | 		goto drop; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	req = reqsk_alloc(&dccp_request_sock_ops); | 
					
						
							|  |  |  | 	if (req == NULL) | 
					
						
							|  |  |  | 		goto drop; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (dccp_parse_options(sk, skb)) | 
					
						
							|  |  |  | 		goto drop_and_free; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-11-10 16:08:37 -02:00
										 |  |  | 	dccp_reqsk_init(req, skb); | 
					
						
							| 
									
										
										
										
											2006-11-10 12:52:36 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (security_inet_conn_request(sk, skb, req)) | 
					
						
							|  |  |  | 		goto drop_and_free; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ireq = inet_rsk(req); | 
					
						
							| 
									
										
										
										
											2007-04-20 22:47:35 -07:00
										 |  |  | 	ireq->loc_addr = ip_hdr(skb)->daddr; | 
					
						
							|  |  |  | 	ireq->rmt_addr = ip_hdr(skb)->saddr; | 
					
						
							| 
									
										
										
										
											2006-11-10 12:52:36 -02:00
										 |  |  | 	ireq->opt	= NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-12-10 16:01:18 -02:00
										 |  |  | 	/*
 | 
					
						
							| 
									
										
										
										
											2006-11-10 12:52:36 -02:00
										 |  |  | 	 * Step 3: Process LISTEN state | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * In fact we defer setting S.GSR, S.SWL, S.SWH to | 
					
						
							|  |  |  | 	 * dccp_create_openreq_child. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	dreq = dccp_rsk(req); | 
					
						
							|  |  |  | 	dreq->dreq_isr	   = dcb->dccpd_seq; | 
					
						
							| 
									
										
										
										
											2006-11-13 13:31:50 -02:00
										 |  |  | 	dreq->dreq_iss	   = dccp_v4_init_sequence(skb); | 
					
						
							| 
									
										
										
										
											2006-11-10 12:52:36 -02:00
										 |  |  | 	dreq->dreq_service = service; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (dccp_v4_send_response(sk, req, NULL)) | 
					
						
							|  |  |  | 		goto drop_and_free; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | drop_and_free: | 
					
						
							|  |  |  | 	reqsk_free(req); | 
					
						
							|  |  |  | drop: | 
					
						
							|  |  |  | 	DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS); | 
					
						
							|  |  |  | 	return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | EXPORT_SYMBOL_GPL(dccp_v4_conn_request); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | int dccp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct dccp_hdr *dh = dccp_hdr(skb); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (sk->sk_state == DCCP_OPEN) { /* Fast path */ | 
					
						
							|  |  |  | 		if (dccp_rcv_established(sk, skb, dh, skb->len)) | 
					
						
							|  |  |  | 			goto reset; | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 *  Step 3: Process LISTEN state | 
					
						
							| 
									
										
										
										
											2006-11-10 16:29:14 -02:00
										 |  |  | 	 *	 If P.type == Request or P contains a valid Init Cookie option, | 
					
						
							|  |  |  | 	 *	      (* Must scan the packet's options to check for Init | 
					
						
							|  |  |  | 	 *		 Cookies.  Only Init Cookies are processed here, | 
					
						
							|  |  |  | 	 *		 however; other options are processed in Step 8.  This | 
					
						
							|  |  |  | 	 *		 scan need only be performed if the endpoint uses Init | 
					
						
							|  |  |  | 	 *		 Cookies *) | 
					
						
							|  |  |  | 	 *	      (* Generate a new socket and switch to that socket *) | 
					
						
							|  |  |  | 	 *	      Set S := new socket for this port pair | 
					
						
							|  |  |  | 	 *	      S.state = RESPOND | 
					
						
							|  |  |  | 	 *	      Choose S.ISS (initial seqno) or set from Init Cookies | 
					
						
							|  |  |  | 	 *	      Initialize S.GAR := S.ISS | 
					
						
							|  |  |  | 	 *	      Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies | 
					
						
							|  |  |  | 	 *	      Continue with S.state == RESPOND | 
					
						
							|  |  |  | 	 *	      (* A Response packet will be generated in Step 11 *) | 
					
						
							|  |  |  | 	 *	 Otherwise, | 
					
						
							|  |  |  | 	 *	      Generate Reset(No Connection) unless P.type == Reset | 
					
						
							|  |  |  | 	 *	      Drop packet and return | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	 * | 
					
						
							| 
									
										
										
										
											2005-08-13 20:34:54 -03:00
										 |  |  | 	 * NOTE: the check for the packet types is done in | 
					
						
							|  |  |  | 	 *	 dccp_rcv_state_process | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	 */ | 
					
						
							|  |  |  | 	if (sk->sk_state == DCCP_LISTEN) { | 
					
						
							|  |  |  | 		struct sock *nsk = dccp_v4_hnd_req(sk, skb); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (nsk == NULL) | 
					
						
							|  |  |  | 			goto discard; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (nsk != sk) { | 
					
						
							|  |  |  | 			if (dccp_child_process(sk, nsk, skb)) | 
					
						
							|  |  |  | 				goto reset; | 
					
						
							|  |  |  | 			return 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (dccp_rcv_state_process(sk, skb, dh, skb->len)) | 
					
						
							|  |  |  | 		goto reset; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | reset: | 
					
						
							| 
									
										
										
										
											2006-11-14 19:07:45 -08:00
										 |  |  | 	dccp_v4_ctl_send_reset(sk, skb); | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | discard: | 
					
						
							|  |  |  | 	kfree_skb(skb); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-12-13 23:24:16 -08:00
										 |  |  | EXPORT_SYMBOL_GPL(dccp_v4_do_rcv); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-11-14 12:57:34 -02:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  *	dccp_invalid_packet  -  check for malformed packets | 
					
						
							|  |  |  |  *	Implements RFC 4340, 8.5:  Step 1: Check header basics | 
					
						
							|  |  |  |  *	Packets that fail these checks are ignored and do not receive Resets. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2005-12-13 23:24:16 -08:00
										 |  |  | int dccp_invalid_packet(struct sk_buff *skb) | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	const struct dccp_hdr *dh; | 
					
						
							| 
									
										
										
										
											2006-11-10 17:43:06 -02:00
										 |  |  | 	unsigned int cscov; | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (skb->pkt_type != PACKET_HOST) | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-11-14 12:57:34 -02:00
										 |  |  | 	/* If the packet is shorter than 12 bytes, drop packet and return */ | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	if (!pskb_may_pull(skb, sizeof(struct dccp_hdr))) { | 
					
						
							| 
									
										
										
										
											2006-11-20 18:39:23 -02:00
										 |  |  | 		DCCP_WARN("pskb_may_pull failed\n"); | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dh = dccp_hdr(skb); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-11-14 12:57:34 -02:00
										 |  |  | 	/* If P.type is not understood, drop packet and return */ | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	if (dh->dccph_type >= DCCP_PKT_INVALID) { | 
					
						
							| 
									
										
										
										
											2006-11-20 18:39:23 -02:00
										 |  |  | 		DCCP_WARN("invalid packet type\n"); | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							| 
									
										
										
										
											2006-11-14 12:57:34 -02:00
										 |  |  | 	 * If P.Data Offset is too small for packet type, drop packet and return | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	 */ | 
					
						
							|  |  |  | 	if (dh->dccph_doff < dccp_hdr_len(skb) / sizeof(u32)) { | 
					
						
							| 
									
										
										
										
											2006-11-20 18:39:23 -02:00
										 |  |  | 		DCCP_WARN("P.Data Offset(%u) too small\n", dh->dccph_doff); | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-11-14 12:57:34 -02:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * If P.Data Offset is too too large for packet, drop packet and return | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	if (!pskb_may_pull(skb, dh->dccph_doff * sizeof(u32))) { | 
					
						
							| 
									
										
										
										
											2006-11-20 18:39:23 -02:00
										 |  |  | 		DCCP_WARN("P.Data Offset(%u) too large\n", dh->dccph_doff); | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * If P.type is not Data, Ack, or DataAck and P.X == 0 (the packet | 
					
						
							|  |  |  | 	 * has short sequence numbers), drop packet and return | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2006-11-14 12:57:34 -02:00
										 |  |  | 	if (dh->dccph_type >= DCCP_PKT_DATA    && | 
					
						
							|  |  |  | 	    dh->dccph_type <= DCCP_PKT_DATAACK && dh->dccph_x == 0)  { | 
					
						
							| 
									
										
										
										
											2006-11-20 18:39:23 -02:00
										 |  |  | 		DCCP_WARN("P.type (%s) not Data || [Data]Ack, while P.X == 0\n", | 
					
						
							|  |  |  | 			  dccp_packet_name(dh->dccph_type)); | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-11-10 17:43:06 -02:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * If P.CsCov is too large for the packet size, drop packet and return. | 
					
						
							|  |  |  | 	 * This must come _before_ checksumming (not as RFC 4340 suggests). | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	cscov = dccp_csum_coverage(skb); | 
					
						
							|  |  |  | 	if (cscov > skb->len) { | 
					
						
							| 
									
										
										
										
											2006-11-20 18:39:23 -02:00
										 |  |  | 		DCCP_WARN("P.CsCov %u exceeds packet length %d\n", | 
					
						
							|  |  |  | 			  dh->dccph_cscov, skb->len); | 
					
						
							| 
									
										
										
										
											2006-11-10 17:43:06 -02:00
										 |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* If header checksum is incorrect, drop packet and return.
 | 
					
						
							|  |  |  | 	 * (This step is completed in the AF-dependent functions.) */ | 
					
						
							|  |  |  | 	skb->csum = skb_checksum(skb, 0, cscov, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-12-13 23:24:16 -08:00
										 |  |  | EXPORT_SYMBOL_GPL(dccp_invalid_packet); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | /* this is called when real data arrives */ | 
					
						
							| 
									
										
										
										
											2006-03-20 21:25:11 -08:00
										 |  |  | static int dccp_v4_rcv(struct sk_buff *skb) | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	const struct dccp_hdr *dh; | 
					
						
							| 
									
										
										
										
											2007-04-20 22:47:35 -07:00
										 |  |  | 	const struct iphdr *iph; | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	struct sock *sk; | 
					
						
							| 
									
										
										
										
											2006-11-10 17:43:06 -02:00
										 |  |  | 	int min_cov; | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-11-10 17:43:06 -02:00
										 |  |  | 	/* Step 1: Check header basics */ | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (dccp_invalid_packet(skb)) | 
					
						
							|  |  |  | 		goto discard_it; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-04-20 22:47:35 -07:00
										 |  |  | 	iph = ip_hdr(skb); | 
					
						
							| 
									
										
										
										
											2006-11-10 17:43:06 -02:00
										 |  |  | 	/* Step 1: If header checksum is incorrect, drop packet and return */ | 
					
						
							| 
									
										
										
										
											2007-04-20 22:47:35 -07:00
										 |  |  | 	if (dccp_v4_csum_finish(skb, iph->saddr, iph->daddr)) { | 
					
						
							| 
									
										
										
										
											2006-11-20 18:39:23 -02:00
										 |  |  | 		DCCP_WARN("dropped packet with invalid checksum\n"); | 
					
						
							| 
									
										
										
										
											2005-12-13 23:24:16 -08:00
										 |  |  | 		goto discard_it; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	dh = dccp_hdr(skb); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-24 10:12:09 -02:00
										 |  |  | 	DCCP_SKB_CB(skb)->dccpd_seq  = dccp_hdr_seq(dh); | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dccp_pr_debug("%8.8s " | 
					
						
							|  |  |  | 		      "src=%u.%u.%u.%u@%-5d " | 
					
						
							|  |  |  | 		      "dst=%u.%u.%u.%u@%-5d seq=%llu", | 
					
						
							|  |  |  | 		      dccp_packet_name(dh->dccph_type), | 
					
						
							| 
									
										
										
										
											2007-04-20 22:47:35 -07:00
										 |  |  | 		      NIPQUAD(iph->saddr), ntohs(dh->dccph_sport), | 
					
						
							|  |  |  | 		      NIPQUAD(iph->daddr), ntohs(dh->dccph_dport), | 
					
						
							| 
									
										
										
										
											2005-08-09 20:27:14 -07:00
										 |  |  | 		      (unsigned long long) DCCP_SKB_CB(skb)->dccpd_seq); | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (dccp_packet_without_ack(skb)) { | 
					
						
							|  |  |  | 		DCCP_SKB_CB(skb)->dccpd_ack_seq = DCCP_PKT_WITHOUT_ACK_SEQ; | 
					
						
							|  |  |  | 		dccp_pr_debug_cat("\n"); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb); | 
					
						
							| 
									
										
										
										
											2006-11-10 11:46:34 -02:00
										 |  |  | 		dccp_pr_debug_cat(", ack=%llu\n", (unsigned long long) | 
					
						
							| 
									
										
										
										
											2005-08-09 20:27:14 -07:00
										 |  |  | 				  DCCP_SKB_CB(skb)->dccpd_ack_seq); | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Step 2:
 | 
					
						
							| 
									
										
										
										
											2006-12-10 16:01:18 -02:00
										 |  |  | 	 *	Look up flow ID in table and get corresponding socket */ | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	sk = __inet_lookup(&dccp_hashinfo, | 
					
						
							| 
									
										
										
										
											2007-04-20 22:47:35 -07:00
										 |  |  | 			   iph->saddr, dh->dccph_sport, | 
					
						
							|  |  |  | 			   iph->daddr, dh->dccph_dport, inet_iif(skb)); | 
					
						
							| 
									
										
										
										
											2006-12-10 16:01:18 -02:00
										 |  |  | 	/*
 | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	 * Step 2: | 
					
						
							| 
									
										
										
										
											2006-12-10 16:01:18 -02:00
										 |  |  | 	 *	If no socket ... | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	 */ | 
					
						
							|  |  |  | 	if (sk == NULL) { | 
					
						
							|  |  |  | 		dccp_pr_debug("failed to look up flow ID in table and " | 
					
						
							|  |  |  | 			      "get corresponding socket\n"); | 
					
						
							|  |  |  | 		goto no_dccp_socket; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-12-10 16:01:18 -02:00
										 |  |  | 	/*
 | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	 * Step 2: | 
					
						
							| 
									
										
										
										
											2006-12-10 16:01:18 -02:00
										 |  |  | 	 *	... or S.state == TIMEWAIT, | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	 *		Generate Reset(No Connection) unless P.type == Reset | 
					
						
							|  |  |  | 	 *		Drop packet and return | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (sk->sk_state == DCCP_TIME_WAIT) { | 
					
						
							| 
									
										
										
										
											2006-11-10 11:46:34 -02:00
										 |  |  | 		dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: do_time_wait\n"); | 
					
						
							|  |  |  | 		inet_twsk_put(inet_twsk(sk)); | 
					
						
							|  |  |  | 		goto no_dccp_socket; | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-11-10 17:43:06 -02:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage | 
					
						
							| 
									
										
										
										
											2006-12-10 16:01:18 -02:00
										 |  |  | 	 *	o if MinCsCov = 0, only packets with CsCov = 0 are accepted | 
					
						
							|  |  |  | 	 *	o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov | 
					
						
							| 
									
										
										
										
											2006-11-10 17:43:06 -02:00
										 |  |  | 	 */ | 
					
						
							|  |  |  | 	min_cov = dccp_sk(sk)->dccps_pcrlen; | 
					
						
							|  |  |  | 	if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov))  { | 
					
						
							|  |  |  | 		dccp_pr_debug("Packet CsCov %d does not satisfy MinCsCov %d\n", | 
					
						
							|  |  |  | 			      dh->dccph_cscov, min_cov); | 
					
						
							|  |  |  | 		/* FIXME: "Such packets SHOULD be reported using Data Dropped
 | 
					
						
							|  |  |  | 		 *         options (Section 11.7) with Drop Code 0, Protocol | 
					
						
							|  |  |  | 		 *         Constraints."                                     */ | 
					
						
							|  |  |  | 		goto discard_and_relse; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-12-27 02:42:22 -02:00
										 |  |  | 	if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 		goto discard_and_relse; | 
					
						
							| 
									
										
										
										
											2006-01-06 23:06:30 -08:00
										 |  |  | 	nf_reset(skb); | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-11-16 14:06:06 -02:00
										 |  |  | 	return sk_receive_skb(sk, skb, 1); | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | no_dccp_socket: | 
					
						
							|  |  |  | 	if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) | 
					
						
							|  |  |  | 		goto discard_it; | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Step 2: | 
					
						
							| 
									
										
										
										
											2006-12-10 16:01:18 -02:00
										 |  |  | 	 *	If no socket ... | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	 *		Generate Reset(No Connection) unless P.type == Reset | 
					
						
							|  |  |  | 	 *		Drop packet and return | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (dh->dccph_type != DCCP_PKT_RESET) { | 
					
						
							| 
									
										
										
										
											2005-08-13 20:34:54 -03:00
										 |  |  | 		DCCP_SKB_CB(skb)->dccpd_reset_code = | 
					
						
							|  |  |  | 					DCCP_RESET_CODE_NO_CONNECTION; | 
					
						
							| 
									
										
										
										
											2006-11-14 19:07:45 -08:00
										 |  |  | 		dccp_v4_ctl_send_reset(sk, skb); | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | discard_it: | 
					
						
							|  |  |  | 	kfree_skb(skb); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | discard_and_relse: | 
					
						
							|  |  |  | 	sock_put(sk); | 
					
						
							|  |  |  | 	goto discard_it; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-03-20 21:25:11 -08:00
										 |  |  | static struct inet_connection_sock_af_ops dccp_ipv4_af_ops = { | 
					
						
							| 
									
										
										
										
											2006-03-20 22:48:35 -08:00
										 |  |  | 	.queue_xmit	   = ip_queue_xmit, | 
					
						
							|  |  |  | 	.send_check	   = dccp_v4_send_check, | 
					
						
							|  |  |  | 	.rebuild_header	   = inet_sk_rebuild_header, | 
					
						
							|  |  |  | 	.conn_request	   = dccp_v4_conn_request, | 
					
						
							|  |  |  | 	.syn_recv_sock	   = dccp_v4_request_recv_sock, | 
					
						
							|  |  |  | 	.net_header_len	   = sizeof(struct iphdr), | 
					
						
							|  |  |  | 	.setsockopt	   = ip_setsockopt, | 
					
						
							|  |  |  | 	.getsockopt	   = ip_getsockopt, | 
					
						
							|  |  |  | 	.addr2sockaddr	   = inet_csk_addr2sockaddr, | 
					
						
							|  |  |  | 	.sockaddr_len	   = sizeof(struct sockaddr_in), | 
					
						
							| 
									
										
										
										
											2006-03-20 22:45:21 -08:00
										 |  |  | #ifdef CONFIG_COMPAT
 | 
					
						
							| 
									
										
										
										
											2006-03-20 22:48:35 -08:00
										 |  |  | 	.compat_setsockopt = compat_ip_setsockopt, | 
					
						
							|  |  |  | 	.compat_getsockopt = compat_ip_getsockopt, | 
					
						
							| 
									
										
										
										
											2006-03-20 22:45:21 -08:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2005-12-13 23:16:16 -08:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-03-20 21:23:15 -08:00
										 |  |  | static int dccp_v4_init_sock(struct sock *sk) | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2006-03-20 22:00:37 -08:00
										 |  |  | 	static __u8 dccp_v4_ctl_sock_initialized; | 
					
						
							|  |  |  | 	int err = dccp_init_sock(sk, dccp_v4_ctl_sock_initialized); | 
					
						
							| 
									
										
										
										
											2005-12-13 23:24:16 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-03-20 22:00:37 -08:00
										 |  |  | 	if (err == 0) { | 
					
						
							|  |  |  | 		if (unlikely(!dccp_v4_ctl_sock_initialized)) | 
					
						
							|  |  |  | 			dccp_v4_ctl_sock_initialized = 1; | 
					
						
							| 
									
										
										
										
											2006-03-20 21:23:15 -08:00
										 |  |  | 		inet_csk(sk)->icsk_af_ops = &dccp_ipv4_af_ops; | 
					
						
							| 
									
										
										
										
											2006-03-20 22:00:37 -08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-03-20 21:23:15 -08:00
										 |  |  | 	return err; | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-12-13 23:25:19 -08:00
										 |  |  | static struct timewait_sock_ops dccp_timewait_sock_ops = { | 
					
						
							|  |  |  | 	.twsk_obj_size	= sizeof(struct inet_timewait_sock), | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-05 23:42:25 -08:00
										 |  |  | DEFINE_PROTO_INUSE(dccp_v4) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-03-20 21:58:29 -08:00
										 |  |  | static struct proto dccp_v4_prot = { | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	.name			= "DCCP", | 
					
						
							|  |  |  | 	.owner			= THIS_MODULE, | 
					
						
							|  |  |  | 	.close			= dccp_close, | 
					
						
							|  |  |  | 	.connect		= dccp_v4_connect, | 
					
						
							|  |  |  | 	.disconnect		= dccp_disconnect, | 
					
						
							|  |  |  | 	.ioctl			= dccp_ioctl, | 
					
						
							|  |  |  | 	.init			= dccp_v4_init_sock, | 
					
						
							|  |  |  | 	.setsockopt		= dccp_setsockopt, | 
					
						
							|  |  |  | 	.getsockopt		= dccp_getsockopt, | 
					
						
							|  |  |  | 	.sendmsg		= dccp_sendmsg, | 
					
						
							|  |  |  | 	.recvmsg		= dccp_recvmsg, | 
					
						
							|  |  |  | 	.backlog_rcv		= dccp_v4_do_rcv, | 
					
						
							| 
									
										
										
										
											2006-03-20 21:23:39 -08:00
										 |  |  | 	.hash			= dccp_hash, | 
					
						
							| 
									
										
										
										
											2005-12-13 23:24:16 -08:00
										 |  |  | 	.unhash			= dccp_unhash, | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	.accept			= inet_csk_accept, | 
					
						
							|  |  |  | 	.get_port		= dccp_v4_get_port, | 
					
						
							|  |  |  | 	.shutdown		= dccp_shutdown, | 
					
						
							| 
									
										
										
										
											2006-03-20 21:23:15 -08:00
										 |  |  | 	.destroy		= dccp_destroy_sock, | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | 	.orphan_count		= &dccp_orphan_count, | 
					
						
							|  |  |  | 	.max_header		= MAX_DCCP_HEADER, | 
					
						
							|  |  |  | 	.obj_size		= sizeof(struct dccp_sock), | 
					
						
							|  |  |  | 	.rsk_prot		= &dccp_request_sock_ops, | 
					
						
							| 
									
										
										
										
											2005-12-13 23:25:19 -08:00
										 |  |  | 	.twsk_prot		= &dccp_timewait_sock_ops, | 
					
						
							| 
									
										
										
										
											2006-03-20 22:48:35 -08:00
										 |  |  | #ifdef CONFIG_COMPAT
 | 
					
						
							|  |  |  | 	.compat_setsockopt	= compat_dccp_setsockopt, | 
					
						
							|  |  |  | 	.compat_getsockopt	= compat_dccp_getsockopt, | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2007-11-05 23:42:25 -08:00
										 |  |  | 	REF_PROTO_INUSE(dccp_v4) | 
					
						
							| 
									
										
										
										
											2005-08-09 20:14:34 -07:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2005-12-13 23:25:19 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-03-20 21:25:11 -08:00
										 |  |  | static struct net_protocol dccp_v4_protocol = { | 
					
						
							|  |  |  | 	.handler	= dccp_v4_rcv, | 
					
						
							|  |  |  | 	.err_handler	= dccp_v4_err, | 
					
						
							|  |  |  | 	.no_policy	= 1, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const struct proto_ops inet_dccp_ops = { | 
					
						
							| 
									
										
										
										
											2006-03-20 22:48:35 -08:00
										 |  |  | 	.family		   = PF_INET, | 
					
						
							|  |  |  | 	.owner		   = THIS_MODULE, | 
					
						
							|  |  |  | 	.release	   = inet_release, | 
					
						
							|  |  |  | 	.bind		   = inet_bind, | 
					
						
							|  |  |  | 	.connect	   = inet_stream_connect, | 
					
						
							|  |  |  | 	.socketpair	   = sock_no_socketpair, | 
					
						
							|  |  |  | 	.accept		   = inet_accept, | 
					
						
							|  |  |  | 	.getname	   = inet_getname, | 
					
						
							| 
									
										
										
										
											2006-03-20 21:25:11 -08:00
										 |  |  | 	/* FIXME: work on tcp_poll to rename it to inet_csk_poll */ | 
					
						
							| 
									
										
										
										
											2006-03-20 22:48:35 -08:00
										 |  |  | 	.poll		   = dccp_poll, | 
					
						
							|  |  |  | 	.ioctl		   = inet_ioctl, | 
					
						
							| 
									
										
										
										
											2006-03-20 21:25:11 -08:00
										 |  |  | 	/* FIXME: work on inet_listen to rename it to sock_common_listen */ | 
					
						
							| 
									
										
										
										
											2006-03-20 22:48:35 -08:00
										 |  |  | 	.listen		   = inet_dccp_listen, | 
					
						
							|  |  |  | 	.shutdown	   = inet_shutdown, | 
					
						
							|  |  |  | 	.setsockopt	   = sock_common_setsockopt, | 
					
						
							|  |  |  | 	.getsockopt	   = sock_common_getsockopt, | 
					
						
							|  |  |  | 	.sendmsg	   = inet_sendmsg, | 
					
						
							|  |  |  | 	.recvmsg	   = sock_common_recvmsg, | 
					
						
							|  |  |  | 	.mmap		   = sock_no_mmap, | 
					
						
							|  |  |  | 	.sendpage	   = sock_no_sendpage, | 
					
						
							| 
									
										
										
										
											2006-03-20 22:45:21 -08:00
										 |  |  | #ifdef CONFIG_COMPAT
 | 
					
						
							| 
									
										
										
										
											2006-03-20 22:48:35 -08:00
										 |  |  | 	.compat_setsockopt = compat_sock_common_setsockopt, | 
					
						
							|  |  |  | 	.compat_getsockopt = compat_sock_common_getsockopt, | 
					
						
							| 
									
										
										
										
											2006-03-20 22:45:21 -08:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2006-03-20 21:25:11 -08:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct inet_protosw dccp_v4_protosw = { | 
					
						
							|  |  |  | 	.type		= SOCK_DCCP, | 
					
						
							|  |  |  | 	.protocol	= IPPROTO_DCCP, | 
					
						
							|  |  |  | 	.prot		= &dccp_v4_prot, | 
					
						
							|  |  |  | 	.ops		= &inet_dccp_ops, | 
					
						
							|  |  |  | 	.capability	= -1, | 
					
						
							|  |  |  | 	.no_check	= 0, | 
					
						
							|  |  |  | 	.flags		= INET_PROTOSW_ICSK, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int __init dccp_v4_init(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int err = proto_register(&dccp_v4_prot, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (err != 0) | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err = inet_add_protocol(&dccp_v4_protocol, IPPROTO_DCCP); | 
					
						
							|  |  |  | 	if (err != 0) | 
					
						
							|  |  |  | 		goto out_proto_unregister; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	inet_register_protosw(&dccp_v4_protosw); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-03-20 22:01:03 -08:00
										 |  |  | 	err = inet_csk_ctl_sock_create(&dccp_v4_ctl_socket, PF_INET, | 
					
						
							|  |  |  | 				       SOCK_DCCP, IPPROTO_DCCP); | 
					
						
							| 
									
										
										
										
											2006-03-20 21:25:11 -08:00
										 |  |  | 	if (err) | 
					
						
							|  |  |  | 		goto out_unregister_protosw; | 
					
						
							|  |  |  | out: | 
					
						
							|  |  |  | 	return err; | 
					
						
							|  |  |  | out_unregister_protosw: | 
					
						
							|  |  |  | 	inet_unregister_protosw(&dccp_v4_protosw); | 
					
						
							|  |  |  | 	inet_del_protocol(&dccp_v4_protocol, IPPROTO_DCCP); | 
					
						
							|  |  |  | out_proto_unregister: | 
					
						
							|  |  |  | 	proto_unregister(&dccp_v4_prot); | 
					
						
							|  |  |  | 	goto out; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void __exit dccp_v4_exit(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	inet_unregister_protosw(&dccp_v4_protosw); | 
					
						
							|  |  |  | 	inet_del_protocol(&dccp_v4_protocol, IPPROTO_DCCP); | 
					
						
							|  |  |  | 	proto_unregister(&dccp_v4_prot); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module_init(dccp_v4_init); | 
					
						
							|  |  |  | module_exit(dccp_v4_exit); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33) | 
					
						
							|  |  |  |  * values directly, Also cover the case where the protocol is not specified, | 
					
						
							|  |  |  |  * i.e. net-pf-PF_INET-proto-0-type-SOCK_DCCP | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2007-10-21 16:45:03 -07:00
										 |  |  | MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, 33, 6); | 
					
						
							|  |  |  | MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, 0, 6); | 
					
						
							| 
									
										
										
										
											2006-03-20 21:25:11 -08:00
										 |  |  | MODULE_LICENSE("GPL"); | 
					
						
							|  |  |  | MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>"); | 
					
						
							|  |  |  | MODULE_DESCRIPTION("DCCP - Datagram Congestion Controlled Protocol"); |