1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
22bc78049SPatrick McHardy /*
32bc78049SPatrick McHardy  * DCCP connection tracking protocol helper
42bc78049SPatrick McHardy  *
52bc78049SPatrick McHardy  * Copyright (c) 2005, 2006, 2008 Patrick McHardy <kaber@trash.net>
62bc78049SPatrick McHardy  */
72bc78049SPatrick McHardy #include <linux/kernel.h>
82bc78049SPatrick McHardy #include <linux/init.h>
92bc78049SPatrick McHardy #include <linux/sysctl.h>
102bc78049SPatrick McHardy #include <linux/spinlock.h>
112bc78049SPatrick McHardy #include <linux/skbuff.h>
122bc78049SPatrick McHardy #include <linux/dccp.h>
135a0e3ad6STejun Heo #include <linux/slab.h>
142bc78049SPatrick McHardy 
151546000fSCyrill Gorcunov #include <net/net_namespace.h>
161546000fSCyrill Gorcunov #include <net/netns/generic.h>
171546000fSCyrill Gorcunov 
182bc78049SPatrick McHardy #include <linux/netfilter/nfnetlink_conntrack.h>
192bc78049SPatrick McHardy #include <net/netfilter/nf_conntrack.h>
202bc78049SPatrick McHardy #include <net/netfilter/nf_conntrack_l4proto.h>
21b38b1f61SPablo Neira Ayuso #include <net/netfilter/nf_conntrack_ecache.h>
22c779e849SFlorian Westphal #include <net/netfilter/nf_conntrack_timeout.h>
232bc78049SPatrick McHardy #include <net/netfilter/nf_log.h>
242bc78049SPatrick McHardy 
252bc78049SPatrick McHardy /* Timeouts are based on values from RFC4340:
262bc78049SPatrick McHardy  *
272bc78049SPatrick McHardy  * - REQUEST:
282bc78049SPatrick McHardy  *
292bc78049SPatrick McHardy  *   8.1.2. Client Request
302bc78049SPatrick McHardy  *
312bc78049SPatrick McHardy  *   A client MAY give up on its DCCP-Requests after some time
322bc78049SPatrick McHardy  *   (3 minutes, for example).
332bc78049SPatrick McHardy  *
342bc78049SPatrick McHardy  * - RESPOND:
352bc78049SPatrick McHardy  *
362bc78049SPatrick McHardy  *   8.1.3. Server Response
372bc78049SPatrick McHardy  *
382bc78049SPatrick McHardy  *   It MAY also leave the RESPOND state for CLOSED after a timeout of
392bc78049SPatrick McHardy  *   not less than 4MSL (8 minutes);
402bc78049SPatrick McHardy  *
412bc78049SPatrick McHardy  * - PARTOPEN:
422bc78049SPatrick McHardy  *
432bc78049SPatrick McHardy  *   8.1.5. Handshake Completion
442bc78049SPatrick McHardy  *
452bc78049SPatrick McHardy  *   If the client remains in PARTOPEN for more than 4MSL (8 minutes),
462bc78049SPatrick McHardy  *   it SHOULD reset the connection with Reset Code 2, "Aborted".
472bc78049SPatrick McHardy  *
482bc78049SPatrick McHardy  * - OPEN:
492bc78049SPatrick McHardy  *
502bc78049SPatrick McHardy  *   The DCCP timestamp overflows after 11.9 hours. If the connection
512bc78049SPatrick McHardy  *   stays idle this long the sequence number won't be recognized
522bc78049SPatrick McHardy  *   as valid anymore.
532bc78049SPatrick McHardy  *
542bc78049SPatrick McHardy  * - CLOSEREQ/CLOSING:
552bc78049SPatrick McHardy  *
562bc78049SPatrick McHardy  *   8.3. Termination
572bc78049SPatrick McHardy  *
582bc78049SPatrick McHardy  *   The retransmission timer should initially be set to go off in two
592bc78049SPatrick McHardy  *   round-trip times and should back off to not less than once every
602bc78049SPatrick McHardy  *   64 seconds ...
612bc78049SPatrick McHardy  *
622bc78049SPatrick McHardy  * - TIMEWAIT:
632bc78049SPatrick McHardy  *
642bc78049SPatrick McHardy  *   4.3. States
652bc78049SPatrick McHardy  *
662bc78049SPatrick McHardy  *   A server or client socket remains in this state for 2MSL (4 minutes)
672bc78049SPatrick McHardy  *   after the connection has been town down, ...
682bc78049SPatrick McHardy  */
692bc78049SPatrick McHardy 
702bc78049SPatrick McHardy #define DCCP_MSL (2 * 60 * HZ)
712bc78049SPatrick McHardy 
72*a927d777SZhu Wang #ifdef CONFIG_NF_CONNTRACK_PROCFS
732bc78049SPatrick McHardy static const char * const dccp_state_names[] = {
742bc78049SPatrick McHardy 	[CT_DCCP_NONE]		= "NONE",
752bc78049SPatrick McHardy 	[CT_DCCP_REQUEST]	= "REQUEST",
762bc78049SPatrick McHardy 	[CT_DCCP_RESPOND]	= "RESPOND",
772bc78049SPatrick McHardy 	[CT_DCCP_PARTOPEN]	= "PARTOPEN",
782bc78049SPatrick McHardy 	[CT_DCCP_OPEN]		= "OPEN",
792bc78049SPatrick McHardy 	[CT_DCCP_CLOSEREQ]	= "CLOSEREQ",
802bc78049SPatrick McHardy 	[CT_DCCP_CLOSING]	= "CLOSING",
812bc78049SPatrick McHardy 	[CT_DCCP_TIMEWAIT]	= "TIMEWAIT",
822bc78049SPatrick McHardy 	[CT_DCCP_IGNORE]	= "IGNORE",
832bc78049SPatrick McHardy 	[CT_DCCP_INVALID]	= "INVALID",
842bc78049SPatrick McHardy };
85*a927d777SZhu Wang #endif
862bc78049SPatrick McHardy 
872bc78049SPatrick McHardy #define sNO	CT_DCCP_NONE
882bc78049SPatrick McHardy #define sRQ	CT_DCCP_REQUEST
892bc78049SPatrick McHardy #define sRS	CT_DCCP_RESPOND
902bc78049SPatrick McHardy #define sPO	CT_DCCP_PARTOPEN
912bc78049SPatrick McHardy #define sOP	CT_DCCP_OPEN
922bc78049SPatrick McHardy #define sCR	CT_DCCP_CLOSEREQ
932bc78049SPatrick McHardy #define sCG	CT_DCCP_CLOSING
942bc78049SPatrick McHardy #define sTW	CT_DCCP_TIMEWAIT
952bc78049SPatrick McHardy #define sIG	CT_DCCP_IGNORE
962bc78049SPatrick McHardy #define sIV	CT_DCCP_INVALID
972bc78049SPatrick McHardy 
982bc78049SPatrick McHardy /*
9925985edcSLucas De Marchi  * DCCP state transition table
1002bc78049SPatrick McHardy  *
1012bc78049SPatrick McHardy  * The assumption is the same as for TCP tracking:
1022bc78049SPatrick McHardy  *
1032bc78049SPatrick McHardy  * We are the man in the middle. All the packets go through us but might
1042bc78049SPatrick McHardy  * get lost in transit to the destination. It is assumed that the destination
1052bc78049SPatrick McHardy  * can't receive segments we haven't seen.
1062bc78049SPatrick McHardy  *
1072bc78049SPatrick McHardy  * The following states exist:
1082bc78049SPatrick McHardy  *
1092bc78049SPatrick McHardy  * NONE:	Initial state, expecting Request
1102bc78049SPatrick McHardy  * REQUEST:	Request seen, waiting for Response from server
1112bc78049SPatrick McHardy  * RESPOND:	Response from server seen, waiting for Ack from client
1122bc78049SPatrick McHardy  * PARTOPEN:	Ack after Response seen, waiting for packet other than Response,
1132bc78049SPatrick McHardy  * 		Reset or Sync from server
1142bc78049SPatrick McHardy  * OPEN:	Packet other than Response, Reset or Sync seen
1152bc78049SPatrick McHardy  * CLOSEREQ:	CloseReq from server seen, expecting Close from client
1162bc78049SPatrick McHardy  * CLOSING:	Close seen, expecting Reset
1172bc78049SPatrick McHardy  * TIMEWAIT:	Reset seen
1182bc78049SPatrick McHardy  * IGNORE:	Not determinable whether packet is valid
1192bc78049SPatrick McHardy  *
1202bc78049SPatrick McHardy  * Some states exist only on one side of the connection: REQUEST, RESPOND,
1212bc78049SPatrick McHardy  * PARTOPEN, CLOSEREQ. For the other side these states are equivalent to
1222bc78049SPatrick McHardy  * the one it was in before.
1232bc78049SPatrick McHardy  *
1242bc78049SPatrick McHardy  * Packets are marked as ignored (sIG) if we don't know if they're valid
1252bc78049SPatrick McHardy  * (for example a reincarnation of a connection we didn't notice is dead
1262bc78049SPatrick McHardy  * already) and the server may send back a connection closing Reset or a
1272bc78049SPatrick McHardy  * Response. They're also used for Sync/SyncAck packets, which we don't
1282bc78049SPatrick McHardy  * care about.
1292bc78049SPatrick McHardy  */
1302bc78049SPatrick McHardy static const u_int8_t
1312bc78049SPatrick McHardy dccp_state_table[CT_DCCP_ROLE_MAX + 1][DCCP_PKT_SYNCACK + 1][CT_DCCP_MAX + 1] = {
1322bc78049SPatrick McHardy 	[CT_DCCP_ROLE_CLIENT] = {
1332bc78049SPatrick McHardy 		[DCCP_PKT_REQUEST] = {
1342bc78049SPatrick McHardy 		/*
1352bc78049SPatrick McHardy 		 * sNO -> sRQ		Regular Request
1362bc78049SPatrick McHardy 		 * sRQ -> sRQ		Retransmitted Request or reincarnation
1372bc78049SPatrick McHardy 		 * sRS -> sRS		Retransmitted Request (apparently Response
1382bc78049SPatrick McHardy 		 * 			got lost after we saw it) or reincarnation
1392bc78049SPatrick McHardy 		 * sPO -> sIG		Ignore, conntrack might be out of sync
1402bc78049SPatrick McHardy 		 * sOP -> sIG		Ignore, conntrack might be out of sync
1412bc78049SPatrick McHardy 		 * sCR -> sIG		Ignore, conntrack might be out of sync
1422bc78049SPatrick McHardy 		 * sCG -> sIG		Ignore, conntrack might be out of sync
1432bc78049SPatrick McHardy 		 * sTW -> sRQ		Reincarnation
1442bc78049SPatrick McHardy 		 *
1452bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO. sOP, sCR, sCG, sTW, */
1462bc78049SPatrick McHardy 			sRQ, sRQ, sRS, sIG, sIG, sIG, sIG, sRQ,
1472bc78049SPatrick McHardy 		},
1482bc78049SPatrick McHardy 		[DCCP_PKT_RESPONSE] = {
1492bc78049SPatrick McHardy 		/*
1502bc78049SPatrick McHardy 		 * sNO -> sIV		Invalid
1512bc78049SPatrick McHardy 		 * sRQ -> sIG		Ignore, might be response to ignored Request
1522bc78049SPatrick McHardy 		 * sRS -> sIG		Ignore, might be response to ignored Request
1532bc78049SPatrick McHardy 		 * sPO -> sIG		Ignore, might be response to ignored Request
1542bc78049SPatrick McHardy 		 * sOP -> sIG		Ignore, might be response to ignored Request
1552bc78049SPatrick McHardy 		 * sCR -> sIG		Ignore, might be response to ignored Request
1562bc78049SPatrick McHardy 		 * sCG -> sIG		Ignore, might be response to ignored Request
1572bc78049SPatrick McHardy 		 * sTW -> sIV		Invalid, reincarnation in reverse direction
1582bc78049SPatrick McHardy 		 *			goes through sRQ
1592bc78049SPatrick McHardy 		 *
1602bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
1612bc78049SPatrick McHardy 			sIV, sIG, sIG, sIG, sIG, sIG, sIG, sIV,
1622bc78049SPatrick McHardy 		},
1632bc78049SPatrick McHardy 		[DCCP_PKT_ACK] = {
1642bc78049SPatrick McHardy 		/*
1652bc78049SPatrick McHardy 		 * sNO -> sIV		No connection
1662bc78049SPatrick McHardy 		 * sRQ -> sIV		No connection
1672bc78049SPatrick McHardy 		 * sRS -> sPO		Ack for Response, move to PARTOPEN (8.1.5.)
1682bc78049SPatrick McHardy 		 * sPO -> sPO		Retransmitted Ack for Response, remain in PARTOPEN
1692bc78049SPatrick McHardy 		 * sOP -> sOP		Regular ACK, remain in OPEN
1702bc78049SPatrick McHardy 		 * sCR -> sCR		Ack in CLOSEREQ MAY be processed (8.3.)
1712bc78049SPatrick McHardy 		 * sCG -> sCG		Ack in CLOSING MAY be processed (8.3.)
1722bc78049SPatrick McHardy 		 * sTW -> sIV
1732bc78049SPatrick McHardy 		 *
1742bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
1752bc78049SPatrick McHardy 			sIV, sIV, sPO, sPO, sOP, sCR, sCG, sIV
1762bc78049SPatrick McHardy 		},
1772bc78049SPatrick McHardy 		[DCCP_PKT_DATA] = {
1782bc78049SPatrick McHardy 		/*
1792bc78049SPatrick McHardy 		 * sNO -> sIV		No connection
1802bc78049SPatrick McHardy 		 * sRQ -> sIV		No connection
1812bc78049SPatrick McHardy 		 * sRS -> sIV		No connection
1822bc78049SPatrick McHardy 		 * sPO -> sIV		MUST use DataAck in PARTOPEN state (8.1.5.)
1832bc78049SPatrick McHardy 		 * sOP -> sOP		Regular Data packet
1842bc78049SPatrick McHardy 		 * sCR -> sCR		Data in CLOSEREQ MAY be processed (8.3.)
1852bc78049SPatrick McHardy 		 * sCG -> sCG		Data in CLOSING MAY be processed (8.3.)
1862bc78049SPatrick McHardy 		 * sTW -> sIV
1872bc78049SPatrick McHardy 		 *
1882bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
1892bc78049SPatrick McHardy 			sIV, sIV, sIV, sIV, sOP, sCR, sCG, sIV,
1902bc78049SPatrick McHardy 		},
1912bc78049SPatrick McHardy 		[DCCP_PKT_DATAACK] = {
1922bc78049SPatrick McHardy 		/*
1932bc78049SPatrick McHardy 		 * sNO -> sIV		No connection
1942bc78049SPatrick McHardy 		 * sRQ -> sIV		No connection
1952bc78049SPatrick McHardy 		 * sRS -> sPO		Ack for Response, move to PARTOPEN (8.1.5.)
1962bc78049SPatrick McHardy 		 * sPO -> sPO		Remain in PARTOPEN state
1972bc78049SPatrick McHardy 		 * sOP -> sOP		Regular DataAck packet in OPEN state
1982bc78049SPatrick McHardy 		 * sCR -> sCR		DataAck in CLOSEREQ MAY be processed (8.3.)
1992bc78049SPatrick McHardy 		 * sCG -> sCG		DataAck in CLOSING MAY be processed (8.3.)
2002bc78049SPatrick McHardy 		 * sTW -> sIV
2012bc78049SPatrick McHardy 		 *
2022bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
2032bc78049SPatrick McHardy 			sIV, sIV, sPO, sPO, sOP, sCR, sCG, sIV
2042bc78049SPatrick McHardy 		},
2052bc78049SPatrick McHardy 		[DCCP_PKT_CLOSEREQ] = {
2062bc78049SPatrick McHardy 		/*
2072bc78049SPatrick McHardy 		 * CLOSEREQ may only be sent by the server.
2082bc78049SPatrick McHardy 		 *
2092bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
2102bc78049SPatrick McHardy 			sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV
2112bc78049SPatrick McHardy 		},
2122bc78049SPatrick McHardy 		[DCCP_PKT_CLOSE] = {
2132bc78049SPatrick McHardy 		/*
2142bc78049SPatrick McHardy 		 * sNO -> sIV		No connection
2152bc78049SPatrick McHardy 		 * sRQ -> sIV		No connection
2162bc78049SPatrick McHardy 		 * sRS -> sIV		No connection
2172bc78049SPatrick McHardy 		 * sPO -> sCG		Client-initiated close
2182bc78049SPatrick McHardy 		 * sOP -> sCG		Client-initiated close
2192bc78049SPatrick McHardy 		 * sCR -> sCG		Close in response to CloseReq (8.3.)
2202bc78049SPatrick McHardy 		 * sCG -> sCG		Retransmit
2212bc78049SPatrick McHardy 		 * sTW -> sIV		Late retransmit, already in TIME_WAIT
2222bc78049SPatrick McHardy 		 *
2232bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
2242bc78049SPatrick McHardy 			sIV, sIV, sIV, sCG, sCG, sCG, sIV, sIV
2252bc78049SPatrick McHardy 		},
2262bc78049SPatrick McHardy 		[DCCP_PKT_RESET] = {
2272bc78049SPatrick McHardy 		/*
2282bc78049SPatrick McHardy 		 * sNO -> sIV		No connection
2292bc78049SPatrick McHardy 		 * sRQ -> sTW		Sync received or timeout, SHOULD send Reset (8.1.1.)
2302bc78049SPatrick McHardy 		 * sRS -> sTW		Response received without Request
2312bc78049SPatrick McHardy 		 * sPO -> sTW		Timeout, SHOULD send Reset (8.1.5.)
2322bc78049SPatrick McHardy 		 * sOP -> sTW		Connection reset
2332bc78049SPatrick McHardy 		 * sCR -> sTW		Connection reset
2342bc78049SPatrick McHardy 		 * sCG -> sTW		Connection reset
2352bc78049SPatrick McHardy 		 * sTW -> sIG		Ignore (don't refresh timer)
2362bc78049SPatrick McHardy 		 *
2372bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
2382bc78049SPatrick McHardy 			sIV, sTW, sTW, sTW, sTW, sTW, sTW, sIG
2392bc78049SPatrick McHardy 		},
2402bc78049SPatrick McHardy 		[DCCP_PKT_SYNC] = {
2412bc78049SPatrick McHardy 		/*
2422bc78049SPatrick McHardy 		 * We currently ignore Sync packets
2432bc78049SPatrick McHardy 		 *
2442bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
2456613b617SFlorian Westphal 			sIV, sIG, sIG, sIG, sIG, sIG, sIG, sIG,
2462bc78049SPatrick McHardy 		},
2472bc78049SPatrick McHardy 		[DCCP_PKT_SYNCACK] = {
2482bc78049SPatrick McHardy 		/*
2492bc78049SPatrick McHardy 		 * We currently ignore SyncAck packets
2502bc78049SPatrick McHardy 		 *
2512bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
2526613b617SFlorian Westphal 			sIV, sIG, sIG, sIG, sIG, sIG, sIG, sIG,
2532bc78049SPatrick McHardy 		},
2542bc78049SPatrick McHardy 	},
2552bc78049SPatrick McHardy 	[CT_DCCP_ROLE_SERVER] = {
2562bc78049SPatrick McHardy 		[DCCP_PKT_REQUEST] = {
2572bc78049SPatrick McHardy 		/*
2582bc78049SPatrick McHardy 		 * sNO -> sIV		Invalid
2592bc78049SPatrick McHardy 		 * sRQ -> sIG		Ignore, conntrack might be out of sync
2602bc78049SPatrick McHardy 		 * sRS -> sIG		Ignore, conntrack might be out of sync
2612bc78049SPatrick McHardy 		 * sPO -> sIG		Ignore, conntrack might be out of sync
2622bc78049SPatrick McHardy 		 * sOP -> sIG		Ignore, conntrack might be out of sync
2632bc78049SPatrick McHardy 		 * sCR -> sIG		Ignore, conntrack might be out of sync
2642bc78049SPatrick McHardy 		 * sCG -> sIG		Ignore, conntrack might be out of sync
2652bc78049SPatrick McHardy 		 * sTW -> sRQ		Reincarnation, must reverse roles
2662bc78049SPatrick McHardy 		 *
2672bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
2682bc78049SPatrick McHardy 			sIV, sIG, sIG, sIG, sIG, sIG, sIG, sRQ
2692bc78049SPatrick McHardy 		},
2702bc78049SPatrick McHardy 		[DCCP_PKT_RESPONSE] = {
2712bc78049SPatrick McHardy 		/*
2722bc78049SPatrick McHardy 		 * sNO -> sIV		Response without Request
2732bc78049SPatrick McHardy 		 * sRQ -> sRS		Response to clients Request
2742bc78049SPatrick McHardy 		 * sRS -> sRS		Retransmitted Response (8.1.3. SHOULD NOT)
2752bc78049SPatrick McHardy 		 * sPO -> sIG		Response to an ignored Request or late retransmit
2762bc78049SPatrick McHardy 		 * sOP -> sIG		Ignore, might be response to ignored Request
2772bc78049SPatrick McHardy 		 * sCR -> sIG		Ignore, might be response to ignored Request
2782bc78049SPatrick McHardy 		 * sCG -> sIG		Ignore, might be response to ignored Request
2792bc78049SPatrick McHardy 		 * sTW -> sIV		Invalid, Request from client in sTW moves to sRQ
2802bc78049SPatrick McHardy 		 *
2812bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
2822bc78049SPatrick McHardy 			sIV, sRS, sRS, sIG, sIG, sIG, sIG, sIV
2832bc78049SPatrick McHardy 		},
2842bc78049SPatrick McHardy 		[DCCP_PKT_ACK] = {
2852bc78049SPatrick McHardy 		/*
2862bc78049SPatrick McHardy 		 * sNO -> sIV		No connection
2872bc78049SPatrick McHardy 		 * sRQ -> sIV		No connection
2882bc78049SPatrick McHardy 		 * sRS -> sIV		No connection
2892bc78049SPatrick McHardy 		 * sPO -> sOP		Enter OPEN state (8.1.5.)
2902bc78049SPatrick McHardy 		 * sOP -> sOP		Regular Ack in OPEN state
2912bc78049SPatrick McHardy 		 * sCR -> sIV		Waiting for Close from client
2922bc78049SPatrick McHardy 		 * sCG -> sCG		Ack in CLOSING MAY be processed (8.3.)
2932bc78049SPatrick McHardy 		 * sTW -> sIV
2942bc78049SPatrick McHardy 		 *
2952bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
2962bc78049SPatrick McHardy 			sIV, sIV, sIV, sOP, sOP, sIV, sCG, sIV
2972bc78049SPatrick McHardy 		},
2982bc78049SPatrick McHardy 		[DCCP_PKT_DATA] = {
2992bc78049SPatrick McHardy 		/*
3002bc78049SPatrick McHardy 		 * sNO -> sIV		No connection
3012bc78049SPatrick McHardy 		 * sRQ -> sIV		No connection
3022bc78049SPatrick McHardy 		 * sRS -> sIV		No connection
3032bc78049SPatrick McHardy 		 * sPO -> sOP		Enter OPEN state (8.1.5.)
3042bc78049SPatrick McHardy 		 * sOP -> sOP		Regular Data packet in OPEN state
3052bc78049SPatrick McHardy 		 * sCR -> sIV		Waiting for Close from client
3062bc78049SPatrick McHardy 		 * sCG -> sCG		Data in CLOSING MAY be processed (8.3.)
3072bc78049SPatrick McHardy 		 * sTW -> sIV
3082bc78049SPatrick McHardy 		 *
3092bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
3102bc78049SPatrick McHardy 			sIV, sIV, sIV, sOP, sOP, sIV, sCG, sIV
3112bc78049SPatrick McHardy 		},
3122bc78049SPatrick McHardy 		[DCCP_PKT_DATAACK] = {
3132bc78049SPatrick McHardy 		/*
3142bc78049SPatrick McHardy 		 * sNO -> sIV		No connection
3152bc78049SPatrick McHardy 		 * sRQ -> sIV		No connection
3162bc78049SPatrick McHardy 		 * sRS -> sIV		No connection
3172bc78049SPatrick McHardy 		 * sPO -> sOP		Enter OPEN state (8.1.5.)
3182bc78049SPatrick McHardy 		 * sOP -> sOP		Regular DataAck in OPEN state
3192bc78049SPatrick McHardy 		 * sCR -> sIV		Waiting for Close from client
3202bc78049SPatrick McHardy 		 * sCG -> sCG		Data in CLOSING MAY be processed (8.3.)
3212bc78049SPatrick McHardy 		 * sTW -> sIV
3222bc78049SPatrick McHardy 		 *
3232bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
3242bc78049SPatrick McHardy 			sIV, sIV, sIV, sOP, sOP, sIV, sCG, sIV
3252bc78049SPatrick McHardy 		},
3262bc78049SPatrick McHardy 		[DCCP_PKT_CLOSEREQ] = {
3272bc78049SPatrick McHardy 		/*
3282bc78049SPatrick McHardy 		 * sNO -> sIV		No connection
3292bc78049SPatrick McHardy 		 * sRQ -> sIV		No connection
3302bc78049SPatrick McHardy 		 * sRS -> sIV		No connection
3312bc78049SPatrick McHardy 		 * sPO -> sOP -> sCR	Move directly to CLOSEREQ (8.1.5.)
3322bc78049SPatrick McHardy 		 * sOP -> sCR		CloseReq in OPEN state
3332bc78049SPatrick McHardy 		 * sCR -> sCR		Retransmit
3342bc78049SPatrick McHardy 		 * sCG -> sCR		Simultaneous close, client sends another Close
3352bc78049SPatrick McHardy 		 * sTW -> sIV		Already closed
3362bc78049SPatrick McHardy 		 *
3372bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
3382bc78049SPatrick McHardy 			sIV, sIV, sIV, sCR, sCR, sCR, sCR, sIV
3392bc78049SPatrick McHardy 		},
3402bc78049SPatrick McHardy 		[DCCP_PKT_CLOSE] = {
3412bc78049SPatrick McHardy 		/*
3422bc78049SPatrick McHardy 		 * sNO -> sIV		No connection
3432bc78049SPatrick McHardy 		 * sRQ -> sIV		No connection
3442bc78049SPatrick McHardy 		 * sRS -> sIV		No connection
3452bc78049SPatrick McHardy 		 * sPO -> sOP -> sCG	Move direcly to CLOSING
3462bc78049SPatrick McHardy 		 * sOP -> sCG		Move to CLOSING
3472bc78049SPatrick McHardy 		 * sCR -> sIV		Close after CloseReq is invalid
3482bc78049SPatrick McHardy 		 * sCG -> sCG		Retransmit
3492bc78049SPatrick McHardy 		 * sTW -> sIV		Already closed
3502bc78049SPatrick McHardy 		 *
3512bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
3522bc78049SPatrick McHardy 			sIV, sIV, sIV, sCG, sCG, sIV, sCG, sIV
3532bc78049SPatrick McHardy 		},
3542bc78049SPatrick McHardy 		[DCCP_PKT_RESET] = {
3552bc78049SPatrick McHardy 		/*
3562bc78049SPatrick McHardy 		 * sNO -> sIV		No connection
3572bc78049SPatrick McHardy 		 * sRQ -> sTW		Reset in response to Request
3582bc78049SPatrick McHardy 		 * sRS -> sTW		Timeout, SHOULD send Reset (8.1.3.)
3592bc78049SPatrick McHardy 		 * sPO -> sTW		Timeout, SHOULD send Reset (8.1.3.)
3602bc78049SPatrick McHardy 		 * sOP -> sTW
3612bc78049SPatrick McHardy 		 * sCR -> sTW
3622bc78049SPatrick McHardy 		 * sCG -> sTW
3632bc78049SPatrick McHardy 		 * sTW -> sIG		Ignore (don't refresh timer)
3642bc78049SPatrick McHardy 		 *
3652bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW, sTW */
3662bc78049SPatrick McHardy 			sIV, sTW, sTW, sTW, sTW, sTW, sTW, sTW, sIG
3672bc78049SPatrick McHardy 		},
3682bc78049SPatrick McHardy 		[DCCP_PKT_SYNC] = {
3692bc78049SPatrick McHardy 		/*
3702bc78049SPatrick McHardy 		 * We currently ignore Sync packets
3712bc78049SPatrick McHardy 		 *
3722bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
3736613b617SFlorian Westphal 			sIV, sIG, sIG, sIG, sIG, sIG, sIG, sIG,
3742bc78049SPatrick McHardy 		},
3752bc78049SPatrick McHardy 		[DCCP_PKT_SYNCACK] = {
3762bc78049SPatrick McHardy 		/*
3772bc78049SPatrick McHardy 		 * We currently ignore SyncAck packets
3782bc78049SPatrick McHardy 		 *
3792bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
3806613b617SFlorian Westphal 			sIV, sIG, sIG, sIG, sIG, sIG, sIG, sIG,
3812bc78049SPatrick McHardy 		},
3822bc78049SPatrick McHardy 	},
3832bc78049SPatrick McHardy };
3842bc78049SPatrick McHardy 
3859976fc6eSFlorian Westphal static noinline bool
dccp_new(struct nf_conn * ct,const struct sk_buff * skb,const struct dccp_hdr * dh,const struct nf_hook_state * hook_state)3869976fc6eSFlorian Westphal dccp_new(struct nf_conn *ct, const struct sk_buff *skb,
38762eec0d7SFlorian Westphal 	 const struct dccp_hdr *dh,
38862eec0d7SFlorian Westphal 	 const struct nf_hook_state *hook_state)
3892bc78049SPatrick McHardy {
390c2a2c7e0SAlexey Dobriyan 	struct net *net = nf_ct_net(ct);
391c51d3901SDavide Caratti 	struct nf_dccp_net *dn;
3922bc78049SPatrick McHardy 	const char *msg;
3932bc78049SPatrick McHardy 	u_int8_t state;
3942bc78049SPatrick McHardy 
3952bc78049SPatrick McHardy 	state = dccp_state_table[CT_DCCP_ROLE_CLIENT][dh->dccph_type][CT_DCCP_NONE];
3962bc78049SPatrick McHardy 	switch (state) {
3972bc78049SPatrick McHardy 	default:
398a95a7774SPablo Neira Ayuso 		dn = nf_dccp_pernet(net);
3991546000fSCyrill Gorcunov 		if (dn->dccp_loose == 0) {
4003d0b527bSFlorian Westphal 			msg = "not picking up existing connection ";
4012bc78049SPatrick McHardy 			goto out_invalid;
4022bc78049SPatrick McHardy 		}
403c2168e6bSGustavo A. R. Silva 		break;
4042bc78049SPatrick McHardy 	case CT_DCCP_REQUEST:
4052bc78049SPatrick McHardy 		break;
4062bc78049SPatrick McHardy 	case CT_DCCP_INVALID:
4073d0b527bSFlorian Westphal 		msg = "invalid state transition ";
4082bc78049SPatrick McHardy 		goto out_invalid;
4092bc78049SPatrick McHardy 	}
4102bc78049SPatrick McHardy 
4112bc78049SPatrick McHardy 	ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_CLIENT;
4122bc78049SPatrick McHardy 	ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_SERVER;
4132bc78049SPatrick McHardy 	ct->proto.dccp.state = CT_DCCP_NONE;
414e5fc9e7aSChangli Gao 	ct->proto.dccp.last_pkt = DCCP_PKT_REQUEST;
415e5fc9e7aSChangli Gao 	ct->proto.dccp.last_dir = IP_CT_DIR_ORIGINAL;
416e5fc9e7aSChangli Gao 	ct->proto.dccp.handshake_seq = 0;
41709f263cdSJan Engelhardt 	return true;
4182bc78049SPatrick McHardy 
4192bc78049SPatrick McHardy out_invalid:
42062eec0d7SFlorian Westphal 	nf_ct_l4proto_log_invalid(skb, ct, hook_state, "%s", msg);
42109f263cdSJan Engelhardt 	return false;
4222bc78049SPatrick McHardy }
4232bc78049SPatrick McHardy 
dccp_ack_seq(const struct dccp_hdr * dh)4242bc78049SPatrick McHardy static u64 dccp_ack_seq(const struct dccp_hdr *dh)
4252bc78049SPatrick McHardy {
4262bc78049SPatrick McHardy 	const struct dccp_hdr_ack_bits *dhack;
4272bc78049SPatrick McHardy 
4282bc78049SPatrick McHardy 	dhack = (void *)dh + __dccp_basic_hdr_len(dh);
4292bc78049SPatrick McHardy 	return ((u64)ntohs(dhack->dccph_ack_nr_high) << 32) +
4302bc78049SPatrick McHardy 		     ntohl(dhack->dccph_ack_nr_low);
4312bc78049SPatrick McHardy }
4322bc78049SPatrick McHardy 
dccp_error(const struct dccp_hdr * dh,struct sk_buff * skb,unsigned int dataoff,const struct nf_hook_state * state)4330150ffbaSFlorian Westphal static bool dccp_error(const struct dccp_hdr *dh,
4340150ffbaSFlorian Westphal 		       struct sk_buff *skb, unsigned int dataoff,
4350150ffbaSFlorian Westphal 		       const struct nf_hook_state *state)
4360150ffbaSFlorian Westphal {
437ff0a3a7dSFlorian Westphal 	static const unsigned long require_seq48 = 1 << DCCP_PKT_REQUEST |
438ff0a3a7dSFlorian Westphal 						   1 << DCCP_PKT_RESPONSE |
439ff0a3a7dSFlorian Westphal 						   1 << DCCP_PKT_CLOSEREQ |
440ff0a3a7dSFlorian Westphal 						   1 << DCCP_PKT_CLOSE |
441ff0a3a7dSFlorian Westphal 						   1 << DCCP_PKT_RESET |
442ff0a3a7dSFlorian Westphal 						   1 << DCCP_PKT_SYNC |
443ff0a3a7dSFlorian Westphal 						   1 << DCCP_PKT_SYNCACK;
4440150ffbaSFlorian Westphal 	unsigned int dccp_len = skb->len - dataoff;
4450150ffbaSFlorian Westphal 	unsigned int cscov;
4460150ffbaSFlorian Westphal 	const char *msg;
447ff0a3a7dSFlorian Westphal 	u8 type;
448ff0a3a7dSFlorian Westphal 
449ff0a3a7dSFlorian Westphal 	BUILD_BUG_ON(DCCP_PKT_INVALID >= BITS_PER_LONG);
4500150ffbaSFlorian Westphal 
4510150ffbaSFlorian Westphal 	if (dh->dccph_doff * 4 < sizeof(struct dccp_hdr) ||
4520150ffbaSFlorian Westphal 	    dh->dccph_doff * 4 > dccp_len) {
4530150ffbaSFlorian Westphal 		msg = "nf_ct_dccp: truncated/malformed packet ";
4540150ffbaSFlorian Westphal 		goto out_invalid;
4550150ffbaSFlorian Westphal 	}
4560150ffbaSFlorian Westphal 
4570150ffbaSFlorian Westphal 	cscov = dccp_len;
4580150ffbaSFlorian Westphal 	if (dh->dccph_cscov) {
4590150ffbaSFlorian Westphal 		cscov = (dh->dccph_cscov - 1) * 4;
4600150ffbaSFlorian Westphal 		if (cscov > dccp_len) {
4610150ffbaSFlorian Westphal 			msg = "nf_ct_dccp: bad checksum coverage ";
4620150ffbaSFlorian Westphal 			goto out_invalid;
4630150ffbaSFlorian Westphal 		}
4640150ffbaSFlorian Westphal 	}
4650150ffbaSFlorian Westphal 
4660150ffbaSFlorian Westphal 	if (state->hook == NF_INET_PRE_ROUTING &&
4670150ffbaSFlorian Westphal 	    state->net->ct.sysctl_checksum &&
4680150ffbaSFlorian Westphal 	    nf_checksum_partial(skb, state->hook, dataoff, cscov,
4690150ffbaSFlorian Westphal 				IPPROTO_DCCP, state->pf)) {
4700150ffbaSFlorian Westphal 		msg = "nf_ct_dccp: bad checksum ";
4710150ffbaSFlorian Westphal 		goto out_invalid;
4720150ffbaSFlorian Westphal 	}
4730150ffbaSFlorian Westphal 
474ff0a3a7dSFlorian Westphal 	type = dh->dccph_type;
475ff0a3a7dSFlorian Westphal 	if (type >= DCCP_PKT_INVALID) {
4760150ffbaSFlorian Westphal 		msg = "nf_ct_dccp: reserved packet type ";
4770150ffbaSFlorian Westphal 		goto out_invalid;
4780150ffbaSFlorian Westphal 	}
479ff0a3a7dSFlorian Westphal 
480ff0a3a7dSFlorian Westphal 	if (test_bit(type, &require_seq48) && !dh->dccph_x) {
481ff0a3a7dSFlorian Westphal 		msg = "nf_ct_dccp: type lacks 48bit sequence numbers";
482ff0a3a7dSFlorian Westphal 		goto out_invalid;
483ff0a3a7dSFlorian Westphal 	}
484ff0a3a7dSFlorian Westphal 
4850150ffbaSFlorian Westphal 	return false;
4860150ffbaSFlorian Westphal out_invalid:
48762eec0d7SFlorian Westphal 	nf_l4proto_log_invalid(skb, state, IPPROTO_DCCP, "%s", msg);
4880150ffbaSFlorian Westphal 	return true;
4890150ffbaSFlorian Westphal }
4900150ffbaSFlorian Westphal 
491ff0a3a7dSFlorian Westphal struct nf_conntrack_dccp_buf {
492ff0a3a7dSFlorian Westphal 	struct dccp_hdr dh;	 /* generic header part */
493ff0a3a7dSFlorian Westphal 	struct dccp_hdr_ext ext; /* optional depending dh->dccph_x */
494ff0a3a7dSFlorian Westphal 	union {			 /* depends on header type */
495ff0a3a7dSFlorian Westphal 		struct dccp_hdr_ack_bits ack;
496ff0a3a7dSFlorian Westphal 		struct dccp_hdr_request req;
497ff0a3a7dSFlorian Westphal 		struct dccp_hdr_response response;
498ff0a3a7dSFlorian Westphal 		struct dccp_hdr_reset rst;
499ff0a3a7dSFlorian Westphal 	} u;
500ff0a3a7dSFlorian Westphal };
501ff0a3a7dSFlorian Westphal 
502ff0a3a7dSFlorian Westphal static struct dccp_hdr *
dccp_header_pointer(const struct sk_buff * skb,int offset,const struct dccp_hdr * dh,struct nf_conntrack_dccp_buf * buf)503ff0a3a7dSFlorian Westphal dccp_header_pointer(const struct sk_buff *skb, int offset, const struct dccp_hdr *dh,
504ff0a3a7dSFlorian Westphal 		    struct nf_conntrack_dccp_buf *buf)
505ff0a3a7dSFlorian Westphal {
506ff0a3a7dSFlorian Westphal 	unsigned int hdrlen = __dccp_hdr_len(dh);
507ff0a3a7dSFlorian Westphal 
508ff0a3a7dSFlorian Westphal 	if (hdrlen > sizeof(*buf))
509ff0a3a7dSFlorian Westphal 		return NULL;
510ff0a3a7dSFlorian Westphal 
511ff0a3a7dSFlorian Westphal 	return skb_header_pointer(skb, offset, hdrlen, buf);
512ff0a3a7dSFlorian Westphal }
513ff0a3a7dSFlorian Westphal 
nf_conntrack_dccp_packet(struct nf_conn * ct,struct sk_buff * skb,unsigned int dataoff,enum ip_conntrack_info ctinfo,const struct nf_hook_state * state)514a47c5404SFlorian Westphal int nf_conntrack_dccp_packet(struct nf_conn *ct, struct sk_buff *skb,
515a47c5404SFlorian Westphal 			     unsigned int dataoff,
516a47c5404SFlorian Westphal 			     enum ip_conntrack_info ctinfo,
51793e66024SFlorian Westphal 			     const struct nf_hook_state *state)
5182bc78049SPatrick McHardy {
5192bc78049SPatrick McHardy 	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
520ff0a3a7dSFlorian Westphal 	struct nf_conntrack_dccp_buf _dh;
5212bc78049SPatrick McHardy 	u_int8_t type, old_state, new_state;
5222bc78049SPatrick McHardy 	enum ct_dccp_roles role;
523c779e849SFlorian Westphal 	unsigned int *timeouts;
524ff0a3a7dSFlorian Westphal 	struct dccp_hdr *dh;
5252bc78049SPatrick McHardy 
526ff0a3a7dSFlorian Westphal 	dh = skb_header_pointer(skb, dataoff, sizeof(*dh), &_dh.dh);
5279976fc6eSFlorian Westphal 	if (!dh)
5289976fc6eSFlorian Westphal 		return NF_DROP;
5299976fc6eSFlorian Westphal 
5300150ffbaSFlorian Westphal 	if (dccp_error(dh, skb, dataoff, state))
5310150ffbaSFlorian Westphal 		return -NF_ACCEPT;
5320150ffbaSFlorian Westphal 
533ff0a3a7dSFlorian Westphal 	/* pull again, including possible 48 bit sequences and subtype header */
534ff0a3a7dSFlorian Westphal 	dh = dccp_header_pointer(skb, dataoff, dh, &_dh);
535ff0a3a7dSFlorian Westphal 	if (!dh)
536ff0a3a7dSFlorian Westphal 		return NF_DROP;
537ff0a3a7dSFlorian Westphal 
5382bc78049SPatrick McHardy 	type = dh->dccph_type;
53962eec0d7SFlorian Westphal 	if (!nf_ct_is_confirmed(ct) && !dccp_new(ct, skb, dh, state))
5409976fc6eSFlorian Westphal 		return -NF_ACCEPT;
5412bc78049SPatrick McHardy 
5422bc78049SPatrick McHardy 	if (type == DCCP_PKT_RESET &&
5432bc78049SPatrick McHardy 	    !test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
5442bc78049SPatrick McHardy 		/* Tear down connection immediately if only reply is a RESET */
545718d4ad9SFabian Hugelshofer 		nf_ct_kill_acct(ct, ctinfo, skb);
5462bc78049SPatrick McHardy 		return NF_ACCEPT;
5472bc78049SPatrick McHardy 	}
5482bc78049SPatrick McHardy 
549440f0d58SPatrick McHardy 	spin_lock_bh(&ct->lock);
5502bc78049SPatrick McHardy 
5512bc78049SPatrick McHardy 	role = ct->proto.dccp.role[dir];
5522bc78049SPatrick McHardy 	old_state = ct->proto.dccp.state;
5532bc78049SPatrick McHardy 	new_state = dccp_state_table[role][type][old_state];
5542bc78049SPatrick McHardy 
5552bc78049SPatrick McHardy 	switch (new_state) {
5562bc78049SPatrick McHardy 	case CT_DCCP_REQUEST:
5572bc78049SPatrick McHardy 		if (old_state == CT_DCCP_TIMEWAIT &&
5582bc78049SPatrick McHardy 		    role == CT_DCCP_ROLE_SERVER) {
5592bc78049SPatrick McHardy 			/* Reincarnation in the reverse direction: reopen and
5602bc78049SPatrick McHardy 			 * reverse client/server roles. */
5612bc78049SPatrick McHardy 			ct->proto.dccp.role[dir] = CT_DCCP_ROLE_CLIENT;
5622bc78049SPatrick McHardy 			ct->proto.dccp.role[!dir] = CT_DCCP_ROLE_SERVER;
5632bc78049SPatrick McHardy 		}
5642bc78049SPatrick McHardy 		break;
5652bc78049SPatrick McHardy 	case CT_DCCP_RESPOND:
5662bc78049SPatrick McHardy 		if (old_state == CT_DCCP_REQUEST)
5672bc78049SPatrick McHardy 			ct->proto.dccp.handshake_seq = dccp_hdr_seq(dh);
5682bc78049SPatrick McHardy 		break;
5692bc78049SPatrick McHardy 	case CT_DCCP_PARTOPEN:
5702bc78049SPatrick McHardy 		if (old_state == CT_DCCP_RESPOND &&
5712bc78049SPatrick McHardy 		    type == DCCP_PKT_ACK &&
5722bc78049SPatrick McHardy 		    dccp_ack_seq(dh) == ct->proto.dccp.handshake_seq)
5732bc78049SPatrick McHardy 			set_bit(IPS_ASSURED_BIT, &ct->status);
5742bc78049SPatrick McHardy 		break;
5752bc78049SPatrick McHardy 	case CT_DCCP_IGNORE:
5762bc78049SPatrick McHardy 		/*
5772bc78049SPatrick McHardy 		 * Connection tracking might be out of sync, so we ignore
5782bc78049SPatrick McHardy 		 * packets that might establish a new connection and resync
5792bc78049SPatrick McHardy 		 * if the server responds with a valid Response.
5802bc78049SPatrick McHardy 		 */
5812bc78049SPatrick McHardy 		if (ct->proto.dccp.last_dir == !dir &&
5822bc78049SPatrick McHardy 		    ct->proto.dccp.last_pkt == DCCP_PKT_REQUEST &&
5832bc78049SPatrick McHardy 		    type == DCCP_PKT_RESPONSE) {
5842bc78049SPatrick McHardy 			ct->proto.dccp.role[!dir] = CT_DCCP_ROLE_CLIENT;
5852bc78049SPatrick McHardy 			ct->proto.dccp.role[dir] = CT_DCCP_ROLE_SERVER;
5862bc78049SPatrick McHardy 			ct->proto.dccp.handshake_seq = dccp_hdr_seq(dh);
5872bc78049SPatrick McHardy 			new_state = CT_DCCP_RESPOND;
5882bc78049SPatrick McHardy 			break;
5892bc78049SPatrick McHardy 		}
5902bc78049SPatrick McHardy 		ct->proto.dccp.last_dir = dir;
5912bc78049SPatrick McHardy 		ct->proto.dccp.last_pkt = type;
5922bc78049SPatrick McHardy 
593440f0d58SPatrick McHardy 		spin_unlock_bh(&ct->lock);
59462eec0d7SFlorian Westphal 		nf_ct_l4proto_log_invalid(skb, ct, state, "%s", "invalid packet");
5952bc78049SPatrick McHardy 		return NF_ACCEPT;
5962bc78049SPatrick McHardy 	case CT_DCCP_INVALID:
597440f0d58SPatrick McHardy 		spin_unlock_bh(&ct->lock);
59862eec0d7SFlorian Westphal 		nf_ct_l4proto_log_invalid(skb, ct, state, "%s", "invalid state transition");
5992bc78049SPatrick McHardy 		return -NF_ACCEPT;
6002bc78049SPatrick McHardy 	}
6012bc78049SPatrick McHardy 
6022bc78049SPatrick McHardy 	ct->proto.dccp.last_dir = dir;
6032bc78049SPatrick McHardy 	ct->proto.dccp.last_pkt = type;
6042bc78049SPatrick McHardy 	ct->proto.dccp.state = new_state;
605440f0d58SPatrick McHardy 	spin_unlock_bh(&ct->lock);
6061546000fSCyrill Gorcunov 
607b38b1f61SPablo Neira Ayuso 	if (new_state != old_state)
608b38b1f61SPablo Neira Ayuso 		nf_conntrack_event_cache(IPCT_PROTOINFO, ct);
609b38b1f61SPablo Neira Ayuso 
610c779e849SFlorian Westphal 	timeouts = nf_ct_timeout_lookup(ct);
611c779e849SFlorian Westphal 	if (!timeouts)
612a95a7774SPablo Neira Ayuso 		timeouts = nf_dccp_pernet(nf_ct_net(ct))->dccp_timeout;
6132c8503f5SPablo Neira Ayuso 	nf_ct_refresh_acct(ct, ctinfo, skb, timeouts[new_state]);
6142bc78049SPatrick McHardy 
6152bc78049SPatrick McHardy 	return NF_ACCEPT;
6162bc78049SPatrick McHardy }
6172bc78049SPatrick McHardy 
dccp_can_early_drop(const struct nf_conn * ct)618c6dd940bSFlorian Westphal static bool dccp_can_early_drop(const struct nf_conn *ct)
619c6dd940bSFlorian Westphal {
620c6dd940bSFlorian Westphal 	switch (ct->proto.dccp.state) {
621c6dd940bSFlorian Westphal 	case CT_DCCP_CLOSEREQ:
622c6dd940bSFlorian Westphal 	case CT_DCCP_CLOSING:
623c6dd940bSFlorian Westphal 	case CT_DCCP_TIMEWAIT:
624c6dd940bSFlorian Westphal 		return true;
625c6dd940bSFlorian Westphal 	default:
626c6dd940bSFlorian Westphal 		break;
627c6dd940bSFlorian Westphal 	}
628c6dd940bSFlorian Westphal 
629c6dd940bSFlorian Westphal 	return false;
630c6dd940bSFlorian Westphal }
631c6dd940bSFlorian Westphal 
632ea48cc83SFlorian Westphal #ifdef CONFIG_NF_CONNTRACK_PROCFS
dccp_print_conntrack(struct seq_file * s,struct nf_conn * ct)63337246a58SSteven Rostedt (Red Hat) static void dccp_print_conntrack(struct seq_file *s, struct nf_conn *ct)
6342bc78049SPatrick McHardy {
63537246a58SSteven Rostedt (Red Hat) 	seq_printf(s, "%s ", dccp_state_names[ct->proto.dccp.state]);
6362bc78049SPatrick McHardy }
637ea48cc83SFlorian Westphal #endif
6382bc78049SPatrick McHardy 
639c0cd1156SIgor Maravić #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
dccp_to_nlattr(struct sk_buff * skb,struct nlattr * nla,struct nf_conn * ct,bool destroy)6402bc78049SPatrick McHardy static int dccp_to_nlattr(struct sk_buff *skb, struct nlattr *nla,
64186d21fc7SFlorian Westphal 			  struct nf_conn *ct, bool destroy)
6422bc78049SPatrick McHardy {
6432bc78049SPatrick McHardy 	struct nlattr *nest_parms;
6442bc78049SPatrick McHardy 
645440f0d58SPatrick McHardy 	spin_lock_bh(&ct->lock);
646ae0be8deSMichal Kubecek 	nest_parms = nla_nest_start(skb, CTA_PROTOINFO_DCCP);
6472bc78049SPatrick McHardy 	if (!nest_parms)
6482bc78049SPatrick McHardy 		goto nla_put_failure;
64986d21fc7SFlorian Westphal 	if (nla_put_u8(skb, CTA_PROTOINFO_DCCP_STATE, ct->proto.dccp.state))
65086d21fc7SFlorian Westphal 		goto nla_put_failure;
65186d21fc7SFlorian Westphal 
65286d21fc7SFlorian Westphal 	if (destroy)
65386d21fc7SFlorian Westphal 		goto skip_state;
65486d21fc7SFlorian Westphal 
65586d21fc7SFlorian Westphal 	if (nla_put_u8(skb, CTA_PROTOINFO_DCCP_ROLE,
656516ee48fSDavid S. Miller 		       ct->proto.dccp.role[IP_CT_DIR_ORIGINAL]) ||
657516ee48fSDavid S. Miller 	    nla_put_be64(skb, CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ,
658b46f6dedSNicolas Dichtel 			 cpu_to_be64(ct->proto.dccp.handshake_seq),
659b46f6dedSNicolas Dichtel 			 CTA_PROTOINFO_DCCP_PAD))
660516ee48fSDavid S. Miller 		goto nla_put_failure;
66186d21fc7SFlorian Westphal skip_state:
6622bc78049SPatrick McHardy 	nla_nest_end(skb, nest_parms);
663440f0d58SPatrick McHardy 	spin_unlock_bh(&ct->lock);
66486d21fc7SFlorian Westphal 
6652bc78049SPatrick McHardy 	return 0;
6662bc78049SPatrick McHardy 
6672bc78049SPatrick McHardy nla_put_failure:
668440f0d58SPatrick McHardy 	spin_unlock_bh(&ct->lock);
6692bc78049SPatrick McHardy 	return -1;
6702bc78049SPatrick McHardy }
6712bc78049SPatrick McHardy 
6722bc78049SPatrick McHardy static const struct nla_policy dccp_nla_policy[CTA_PROTOINFO_DCCP_MAX + 1] = {
6732bc78049SPatrick McHardy 	[CTA_PROTOINFO_DCCP_STATE]	= { .type = NLA_U8 },
67471951b64SPablo Neira Ayuso 	[CTA_PROTOINFO_DCCP_ROLE]	= { .type = NLA_U8 },
675a17c8598SPablo Neira Ayuso 	[CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ] = { .type = NLA_U64 },
676b46f6dedSNicolas Dichtel 	[CTA_PROTOINFO_DCCP_PAD]	= { .type = NLA_UNSPEC },
6772bc78049SPatrick McHardy };
6782bc78049SPatrick McHardy 
67939215846SFlorian Westphal #define DCCP_NLATTR_SIZE ( \
68039215846SFlorian Westphal 	NLA_ALIGN(NLA_HDRLEN + 1) + \
68139215846SFlorian Westphal 	NLA_ALIGN(NLA_HDRLEN + 1) + \
68239215846SFlorian Westphal 	NLA_ALIGN(NLA_HDRLEN + sizeof(u64)) + \
68339215846SFlorian Westphal 	NLA_ALIGN(NLA_HDRLEN + 0))
68439215846SFlorian Westphal 
nlattr_to_dccp(struct nlattr * cda[],struct nf_conn * ct)6852bc78049SPatrick McHardy static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct)
6862bc78049SPatrick McHardy {
6872bc78049SPatrick McHardy 	struct nlattr *attr = cda[CTA_PROTOINFO_DCCP];
6882bc78049SPatrick McHardy 	struct nlattr *tb[CTA_PROTOINFO_DCCP_MAX + 1];
6892bc78049SPatrick McHardy 	int err;
6902bc78049SPatrick McHardy 
6912bc78049SPatrick McHardy 	if (!attr)
6922bc78049SPatrick McHardy 		return 0;
6932bc78049SPatrick McHardy 
6948cb08174SJohannes Berg 	err = nla_parse_nested_deprecated(tb, CTA_PROTOINFO_DCCP_MAX, attr,
695fceb6435SJohannes Berg 					  dccp_nla_policy, NULL);
6962bc78049SPatrick McHardy 	if (err < 0)
6972bc78049SPatrick McHardy 		return err;
6982bc78049SPatrick McHardy 
6992bc78049SPatrick McHardy 	if (!tb[CTA_PROTOINFO_DCCP_STATE] ||
70071951b64SPablo Neira Ayuso 	    !tb[CTA_PROTOINFO_DCCP_ROLE] ||
70171951b64SPablo Neira Ayuso 	    nla_get_u8(tb[CTA_PROTOINFO_DCCP_ROLE]) > CT_DCCP_ROLE_MAX ||
70271951b64SPablo Neira Ayuso 	    nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]) >= CT_DCCP_IGNORE) {
7032bc78049SPatrick McHardy 		return -EINVAL;
70471951b64SPablo Neira Ayuso 	}
7052bc78049SPatrick McHardy 
706440f0d58SPatrick McHardy 	spin_lock_bh(&ct->lock);
7072bc78049SPatrick McHardy 	ct->proto.dccp.state = nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]);
70871951b64SPablo Neira Ayuso 	if (nla_get_u8(tb[CTA_PROTOINFO_DCCP_ROLE]) == CT_DCCP_ROLE_CLIENT) {
70971951b64SPablo Neira Ayuso 		ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_CLIENT;
71071951b64SPablo Neira Ayuso 		ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_SERVER;
71171951b64SPablo Neira Ayuso 	} else {
71271951b64SPablo Neira Ayuso 		ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_SERVER;
71371951b64SPablo Neira Ayuso 		ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_CLIENT;
71471951b64SPablo Neira Ayuso 	}
715a17c8598SPablo Neira Ayuso 	if (tb[CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ]) {
716a17c8598SPablo Neira Ayuso 		ct->proto.dccp.handshake_seq =
717a17c8598SPablo Neira Ayuso 		be64_to_cpu(nla_get_be64(tb[CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ]));
718a17c8598SPablo Neira Ayuso 	}
719440f0d58SPatrick McHardy 	spin_unlock_bh(&ct->lock);
7202bc78049SPatrick McHardy 	return 0;
7212bc78049SPatrick McHardy }
7222bc78049SPatrick McHardy #endif
7232bc78049SPatrick McHardy 
724a874752aSPablo Neira Ayuso #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
72550978462SPablo Neira Ayuso 
72650978462SPablo Neira Ayuso #include <linux/netfilter/nfnetlink.h>
72750978462SPablo Neira Ayuso #include <linux/netfilter/nfnetlink_cttimeout.h>
72850978462SPablo Neira Ayuso 
dccp_timeout_nlattr_to_obj(struct nlattr * tb[],struct net * net,void * data)7298264deb8SGao feng static int dccp_timeout_nlattr_to_obj(struct nlattr *tb[],
7308264deb8SGao feng 				      struct net *net, void *data)
73150978462SPablo Neira Ayuso {
732a95a7774SPablo Neira Ayuso 	struct nf_dccp_net *dn = nf_dccp_pernet(net);
73350978462SPablo Neira Ayuso 	unsigned int *timeouts = data;
73450978462SPablo Neira Ayuso 	int i;
73550978462SPablo Neira Ayuso 
7361d9a7acdSFlorian Westphal 	if (!timeouts)
7371d9a7acdSFlorian Westphal 		 timeouts = dn->dccp_timeout;
7381d9a7acdSFlorian Westphal 
73950978462SPablo Neira Ayuso 	/* set default DCCP timeouts. */
74050978462SPablo Neira Ayuso 	for (i=0; i<CT_DCCP_MAX; i++)
74150978462SPablo Neira Ayuso 		timeouts[i] = dn->dccp_timeout[i];
74250978462SPablo Neira Ayuso 
74350978462SPablo Neira Ayuso 	/* there's a 1:1 mapping between attributes and protocol states. */
74450978462SPablo Neira Ayuso 	for (i=CTA_TIMEOUT_DCCP_UNSPEC+1; i<CTA_TIMEOUT_DCCP_MAX+1; i++) {
74550978462SPablo Neira Ayuso 		if (tb[i]) {
74650978462SPablo Neira Ayuso 			timeouts[i] = ntohl(nla_get_be32(tb[i])) * HZ;
74750978462SPablo Neira Ayuso 		}
74850978462SPablo Neira Ayuso 	}
749ef39078dSFlorian Westphal 
750ef39078dSFlorian Westphal 	timeouts[CTA_TIMEOUT_DCCP_UNSPEC] = timeouts[CTA_TIMEOUT_DCCP_REQUEST];
75150978462SPablo Neira Ayuso 	return 0;
75250978462SPablo Neira Ayuso }
75350978462SPablo Neira Ayuso 
75450978462SPablo Neira Ayuso static int
dccp_timeout_obj_to_nlattr(struct sk_buff * skb,const void * data)75550978462SPablo Neira Ayuso dccp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
75650978462SPablo Neira Ayuso {
75750978462SPablo Neira Ayuso         const unsigned int *timeouts = data;
75850978462SPablo Neira Ayuso 	int i;
75950978462SPablo Neira Ayuso 
760516ee48fSDavid S. Miller 	for (i=CTA_TIMEOUT_DCCP_UNSPEC+1; i<CTA_TIMEOUT_DCCP_MAX+1; i++) {
761516ee48fSDavid S. Miller 		if (nla_put_be32(skb, i, htonl(timeouts[i] / HZ)))
762516ee48fSDavid S. Miller 			goto nla_put_failure;
763516ee48fSDavid S. Miller 	}
76450978462SPablo Neira Ayuso 	return 0;
76550978462SPablo Neira Ayuso 
76650978462SPablo Neira Ayuso nla_put_failure:
76750978462SPablo Neira Ayuso 	return -ENOSPC;
76850978462SPablo Neira Ayuso }
76950978462SPablo Neira Ayuso 
77050978462SPablo Neira Ayuso static const struct nla_policy
77150978462SPablo Neira Ayuso dccp_timeout_nla_policy[CTA_TIMEOUT_DCCP_MAX+1] = {
77250978462SPablo Neira Ayuso 	[CTA_TIMEOUT_DCCP_REQUEST]	= { .type = NLA_U32 },
77350978462SPablo Neira Ayuso 	[CTA_TIMEOUT_DCCP_RESPOND]	= { .type = NLA_U32 },
77450978462SPablo Neira Ayuso 	[CTA_TIMEOUT_DCCP_PARTOPEN]	= { .type = NLA_U32 },
77550978462SPablo Neira Ayuso 	[CTA_TIMEOUT_DCCP_OPEN]		= { .type = NLA_U32 },
77650978462SPablo Neira Ayuso 	[CTA_TIMEOUT_DCCP_CLOSEREQ]	= { .type = NLA_U32 },
77750978462SPablo Neira Ayuso 	[CTA_TIMEOUT_DCCP_CLOSING]	= { .type = NLA_U32 },
77850978462SPablo Neira Ayuso 	[CTA_TIMEOUT_DCCP_TIMEWAIT]	= { .type = NLA_U32 },
77950978462SPablo Neira Ayuso };
780a874752aSPablo Neira Ayuso #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */
78150978462SPablo Neira Ayuso 
nf_conntrack_dccp_init_net(struct net * net)7822a389de8SFlorian Westphal void nf_conntrack_dccp_init_net(struct net *net)
78354b8873fSGao feng {
784a95a7774SPablo Neira Ayuso 	struct nf_dccp_net *dn = nf_dccp_pernet(net);
78554b8873fSGao feng 
78654b8873fSGao feng 	/* default values */
78754b8873fSGao feng 	dn->dccp_loose = 1;
78854b8873fSGao feng 	dn->dccp_timeout[CT_DCCP_REQUEST]	= 2 * DCCP_MSL;
78954b8873fSGao feng 	dn->dccp_timeout[CT_DCCP_RESPOND]	= 4 * DCCP_MSL;
79054b8873fSGao feng 	dn->dccp_timeout[CT_DCCP_PARTOPEN]	= 4 * DCCP_MSL;
79154b8873fSGao feng 	dn->dccp_timeout[CT_DCCP_OPEN]		= 12 * 3600 * HZ;
79254b8873fSGao feng 	dn->dccp_timeout[CT_DCCP_CLOSEREQ]	= 64 * HZ;
79354b8873fSGao feng 	dn->dccp_timeout[CT_DCCP_CLOSING]	= 64 * HZ;
79454b8873fSGao feng 	dn->dccp_timeout[CT_DCCP_TIMEWAIT]	= 2 * DCCP_MSL;
795ef39078dSFlorian Westphal 
796ef39078dSFlorian Westphal 	/* timeouts[0] is unused, make it same as SYN_SENT so
797ef39078dSFlorian Westphal 	 * ->timeouts[0] contains 'new' timeout, like udp or icmp.
798ef39078dSFlorian Westphal 	 */
799ef39078dSFlorian Westphal 	dn->dccp_timeout[CT_DCCP_NONE] = dn->dccp_timeout[CT_DCCP_REQUEST];
80054b8873fSGao feng }
80154b8873fSGao feng 
802dd2934a9SFlorian Westphal const struct nf_conntrack_l4proto nf_conntrack_l4proto_dccp = {
8032bc78049SPatrick McHardy 	.l4proto		= IPPROTO_DCCP,
804c6dd940bSFlorian Westphal 	.can_early_drop		= dccp_can_early_drop,
805ea48cc83SFlorian Westphal #ifdef CONFIG_NF_CONNTRACK_PROCFS
8062bc78049SPatrick McHardy 	.print_conntrack	= dccp_print_conntrack,
807ea48cc83SFlorian Westphal #endif
808c0cd1156SIgor Maravić #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
80939215846SFlorian Westphal 	.nlattr_size		= DCCP_NLATTR_SIZE,
8102bc78049SPatrick McHardy 	.to_nlattr		= dccp_to_nlattr,
8112bc78049SPatrick McHardy 	.from_nlattr		= nlattr_to_dccp,
8122bc78049SPatrick McHardy 	.tuple_to_nlattr	= nf_ct_port_tuple_to_nlattr,
813a400c30eSHolger Eitzenberger 	.nlattr_tuple_size	= nf_ct_port_nlattr_tuple_size,
8142bc78049SPatrick McHardy 	.nlattr_to_tuple	= nf_ct_port_nlattr_to_tuple,
8152bc78049SPatrick McHardy 	.nla_policy		= nf_ct_port_nla_policy,
8162bc78049SPatrick McHardy #endif
817a874752aSPablo Neira Ayuso #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
81850978462SPablo Neira Ayuso 	.ctnl_timeout		= {
81950978462SPablo Neira Ayuso 		.nlattr_to_obj	= dccp_timeout_nlattr_to_obj,
82050978462SPablo Neira Ayuso 		.obj_to_nlattr	= dccp_timeout_obj_to_nlattr,
82150978462SPablo Neira Ayuso 		.nlattr_max	= CTA_TIMEOUT_DCCP_MAX,
82250978462SPablo Neira Ayuso 		.obj_size	= sizeof(unsigned int) * CT_DCCP_MAX,
82350978462SPablo Neira Ayuso 		.nla_policy	= dccp_timeout_nla_policy,
82450978462SPablo Neira Ayuso 	},
825a874752aSPablo Neira Ayuso #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */
8262bc78049SPatrick McHardy };
827