12bc78049SPatrick McHardy /*
22bc78049SPatrick McHardy  * DCCP connection tracking protocol helper
32bc78049SPatrick McHardy  *
42bc78049SPatrick McHardy  * Copyright (c) 2005, 2006, 2008 Patrick McHardy <kaber@trash.net>
52bc78049SPatrick McHardy  *
62bc78049SPatrick McHardy  * This program is free software; you can redistribute it and/or modify
72bc78049SPatrick McHardy  * it under the terms of the GNU General Public License version 2 as
82bc78049SPatrick McHardy  * published by the Free Software Foundation.
92bc78049SPatrick McHardy  *
102bc78049SPatrick McHardy  */
112bc78049SPatrick McHardy #include <linux/kernel.h>
122bc78049SPatrick McHardy #include <linux/module.h>
132bc78049SPatrick McHardy #include <linux/init.h>
142bc78049SPatrick McHardy #include <linux/sysctl.h>
152bc78049SPatrick McHardy #include <linux/spinlock.h>
162bc78049SPatrick McHardy #include <linux/skbuff.h>
172bc78049SPatrick McHardy #include <linux/dccp.h>
185a0e3ad6STejun Heo #include <linux/slab.h>
192bc78049SPatrick McHardy 
201546000fSCyrill Gorcunov #include <net/net_namespace.h>
211546000fSCyrill Gorcunov #include <net/netns/generic.h>
221546000fSCyrill Gorcunov 
232bc78049SPatrick McHardy #include <linux/netfilter/nfnetlink_conntrack.h>
242bc78049SPatrick McHardy #include <net/netfilter/nf_conntrack.h>
252bc78049SPatrick McHardy #include <net/netfilter/nf_conntrack_l4proto.h>
26b38b1f61SPablo Neira Ayuso #include <net/netfilter/nf_conntrack_ecache.h>
272bc78049SPatrick McHardy #include <net/netfilter/nf_log.h>
282bc78049SPatrick McHardy 
292bc78049SPatrick McHardy /* Timeouts are based on values from RFC4340:
302bc78049SPatrick McHardy  *
312bc78049SPatrick McHardy  * - REQUEST:
322bc78049SPatrick McHardy  *
332bc78049SPatrick McHardy  *   8.1.2. Client Request
342bc78049SPatrick McHardy  *
352bc78049SPatrick McHardy  *   A client MAY give up on its DCCP-Requests after some time
362bc78049SPatrick McHardy  *   (3 minutes, for example).
372bc78049SPatrick McHardy  *
382bc78049SPatrick McHardy  * - RESPOND:
392bc78049SPatrick McHardy  *
402bc78049SPatrick McHardy  *   8.1.3. Server Response
412bc78049SPatrick McHardy  *
422bc78049SPatrick McHardy  *   It MAY also leave the RESPOND state for CLOSED after a timeout of
432bc78049SPatrick McHardy  *   not less than 4MSL (8 minutes);
442bc78049SPatrick McHardy  *
452bc78049SPatrick McHardy  * - PARTOPEN:
462bc78049SPatrick McHardy  *
472bc78049SPatrick McHardy  *   8.1.5. Handshake Completion
482bc78049SPatrick McHardy  *
492bc78049SPatrick McHardy  *   If the client remains in PARTOPEN for more than 4MSL (8 minutes),
502bc78049SPatrick McHardy  *   it SHOULD reset the connection with Reset Code 2, "Aborted".
512bc78049SPatrick McHardy  *
522bc78049SPatrick McHardy  * - OPEN:
532bc78049SPatrick McHardy  *
542bc78049SPatrick McHardy  *   The DCCP timestamp overflows after 11.9 hours. If the connection
552bc78049SPatrick McHardy  *   stays idle this long the sequence number won't be recognized
562bc78049SPatrick McHardy  *   as valid anymore.
572bc78049SPatrick McHardy  *
582bc78049SPatrick McHardy  * - CLOSEREQ/CLOSING:
592bc78049SPatrick McHardy  *
602bc78049SPatrick McHardy  *   8.3. Termination
612bc78049SPatrick McHardy  *
622bc78049SPatrick McHardy  *   The retransmission timer should initially be set to go off in two
632bc78049SPatrick McHardy  *   round-trip times and should back off to not less than once every
642bc78049SPatrick McHardy  *   64 seconds ...
652bc78049SPatrick McHardy  *
662bc78049SPatrick McHardy  * - TIMEWAIT:
672bc78049SPatrick McHardy  *
682bc78049SPatrick McHardy  *   4.3. States
692bc78049SPatrick McHardy  *
702bc78049SPatrick McHardy  *   A server or client socket remains in this state for 2MSL (4 minutes)
712bc78049SPatrick McHardy  *   after the connection has been town down, ...
722bc78049SPatrick McHardy  */
732bc78049SPatrick McHardy 
742bc78049SPatrick McHardy #define DCCP_MSL (2 * 60 * HZ)
752bc78049SPatrick McHardy 
762bc78049SPatrick McHardy static const char * const dccp_state_names[] = {
772bc78049SPatrick McHardy 	[CT_DCCP_NONE]		= "NONE",
782bc78049SPatrick McHardy 	[CT_DCCP_REQUEST]	= "REQUEST",
792bc78049SPatrick McHardy 	[CT_DCCP_RESPOND]	= "RESPOND",
802bc78049SPatrick McHardy 	[CT_DCCP_PARTOPEN]	= "PARTOPEN",
812bc78049SPatrick McHardy 	[CT_DCCP_OPEN]		= "OPEN",
822bc78049SPatrick McHardy 	[CT_DCCP_CLOSEREQ]	= "CLOSEREQ",
832bc78049SPatrick McHardy 	[CT_DCCP_CLOSING]	= "CLOSING",
842bc78049SPatrick McHardy 	[CT_DCCP_TIMEWAIT]	= "TIMEWAIT",
852bc78049SPatrick McHardy 	[CT_DCCP_IGNORE]	= "IGNORE",
862bc78049SPatrick McHardy 	[CT_DCCP_INVALID]	= "INVALID",
872bc78049SPatrick McHardy };
882bc78049SPatrick McHardy 
892bc78049SPatrick McHardy #define sNO	CT_DCCP_NONE
902bc78049SPatrick McHardy #define sRQ	CT_DCCP_REQUEST
912bc78049SPatrick McHardy #define sRS	CT_DCCP_RESPOND
922bc78049SPatrick McHardy #define sPO	CT_DCCP_PARTOPEN
932bc78049SPatrick McHardy #define sOP	CT_DCCP_OPEN
942bc78049SPatrick McHardy #define sCR	CT_DCCP_CLOSEREQ
952bc78049SPatrick McHardy #define sCG	CT_DCCP_CLOSING
962bc78049SPatrick McHardy #define sTW	CT_DCCP_TIMEWAIT
972bc78049SPatrick McHardy #define sIG	CT_DCCP_IGNORE
982bc78049SPatrick McHardy #define sIV	CT_DCCP_INVALID
992bc78049SPatrick McHardy 
1002bc78049SPatrick McHardy /*
10125985edcSLucas De Marchi  * DCCP state transition table
1022bc78049SPatrick McHardy  *
1032bc78049SPatrick McHardy  * The assumption is the same as for TCP tracking:
1042bc78049SPatrick McHardy  *
1052bc78049SPatrick McHardy  * We are the man in the middle. All the packets go through us but might
1062bc78049SPatrick McHardy  * get lost in transit to the destination. It is assumed that the destination
1072bc78049SPatrick McHardy  * can't receive segments we haven't seen.
1082bc78049SPatrick McHardy  *
1092bc78049SPatrick McHardy  * The following states exist:
1102bc78049SPatrick McHardy  *
1112bc78049SPatrick McHardy  * NONE:	Initial state, expecting Request
1122bc78049SPatrick McHardy  * REQUEST:	Request seen, waiting for Response from server
1132bc78049SPatrick McHardy  * RESPOND:	Response from server seen, waiting for Ack from client
1142bc78049SPatrick McHardy  * PARTOPEN:	Ack after Response seen, waiting for packet other than Response,
1152bc78049SPatrick McHardy  * 		Reset or Sync from server
1162bc78049SPatrick McHardy  * OPEN:	Packet other than Response, Reset or Sync seen
1172bc78049SPatrick McHardy  * CLOSEREQ:	CloseReq from server seen, expecting Close from client
1182bc78049SPatrick McHardy  * CLOSING:	Close seen, expecting Reset
1192bc78049SPatrick McHardy  * TIMEWAIT:	Reset seen
1202bc78049SPatrick McHardy  * IGNORE:	Not determinable whether packet is valid
1212bc78049SPatrick McHardy  *
1222bc78049SPatrick McHardy  * Some states exist only on one side of the connection: REQUEST, RESPOND,
1232bc78049SPatrick McHardy  * PARTOPEN, CLOSEREQ. For the other side these states are equivalent to
1242bc78049SPatrick McHardy  * the one it was in before.
1252bc78049SPatrick McHardy  *
1262bc78049SPatrick McHardy  * Packets are marked as ignored (sIG) if we don't know if they're valid
1272bc78049SPatrick McHardy  * (for example a reincarnation of a connection we didn't notice is dead
1282bc78049SPatrick McHardy  * already) and the server may send back a connection closing Reset or a
1292bc78049SPatrick McHardy  * Response. They're also used for Sync/SyncAck packets, which we don't
1302bc78049SPatrick McHardy  * care about.
1312bc78049SPatrick McHardy  */
1322bc78049SPatrick McHardy static const u_int8_t
1332bc78049SPatrick McHardy dccp_state_table[CT_DCCP_ROLE_MAX + 1][DCCP_PKT_SYNCACK + 1][CT_DCCP_MAX + 1] = {
1342bc78049SPatrick McHardy 	[CT_DCCP_ROLE_CLIENT] = {
1352bc78049SPatrick McHardy 		[DCCP_PKT_REQUEST] = {
1362bc78049SPatrick McHardy 		/*
1372bc78049SPatrick McHardy 		 * sNO -> sRQ		Regular Request
1382bc78049SPatrick McHardy 		 * sRQ -> sRQ		Retransmitted Request or reincarnation
1392bc78049SPatrick McHardy 		 * sRS -> sRS		Retransmitted Request (apparently Response
1402bc78049SPatrick McHardy 		 * 			got lost after we saw it) or reincarnation
1412bc78049SPatrick McHardy 		 * sPO -> sIG		Ignore, conntrack might be out of sync
1422bc78049SPatrick McHardy 		 * sOP -> sIG		Ignore, conntrack might be out of sync
1432bc78049SPatrick McHardy 		 * sCR -> sIG		Ignore, conntrack might be out of sync
1442bc78049SPatrick McHardy 		 * sCG -> sIG		Ignore, conntrack might be out of sync
1452bc78049SPatrick McHardy 		 * sTW -> sRQ		Reincarnation
1462bc78049SPatrick McHardy 		 *
1472bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO. sOP, sCR, sCG, sTW, */
1482bc78049SPatrick McHardy 			sRQ, sRQ, sRS, sIG, sIG, sIG, sIG, sRQ,
1492bc78049SPatrick McHardy 		},
1502bc78049SPatrick McHardy 		[DCCP_PKT_RESPONSE] = {
1512bc78049SPatrick McHardy 		/*
1522bc78049SPatrick McHardy 		 * sNO -> sIV		Invalid
1532bc78049SPatrick McHardy 		 * sRQ -> sIG		Ignore, might be response to ignored Request
1542bc78049SPatrick McHardy 		 * sRS -> sIG		Ignore, might be response to ignored Request
1552bc78049SPatrick McHardy 		 * sPO -> sIG		Ignore, might be response to ignored Request
1562bc78049SPatrick McHardy 		 * sOP -> sIG		Ignore, might be response to ignored Request
1572bc78049SPatrick McHardy 		 * sCR -> sIG		Ignore, might be response to ignored Request
1582bc78049SPatrick McHardy 		 * sCG -> sIG		Ignore, might be response to ignored Request
1592bc78049SPatrick McHardy 		 * sTW -> sIV		Invalid, reincarnation in reverse direction
1602bc78049SPatrick McHardy 		 *			goes through sRQ
1612bc78049SPatrick McHardy 		 *
1622bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
1632bc78049SPatrick McHardy 			sIV, sIG, sIG, sIG, sIG, sIG, sIG, sIV,
1642bc78049SPatrick McHardy 		},
1652bc78049SPatrick McHardy 		[DCCP_PKT_ACK] = {
1662bc78049SPatrick McHardy 		/*
1672bc78049SPatrick McHardy 		 * sNO -> sIV		No connection
1682bc78049SPatrick McHardy 		 * sRQ -> sIV		No connection
1692bc78049SPatrick McHardy 		 * sRS -> sPO		Ack for Response, move to PARTOPEN (8.1.5.)
1702bc78049SPatrick McHardy 		 * sPO -> sPO		Retransmitted Ack for Response, remain in PARTOPEN
1712bc78049SPatrick McHardy 		 * sOP -> sOP		Regular ACK, remain in OPEN
1722bc78049SPatrick McHardy 		 * sCR -> sCR		Ack in CLOSEREQ MAY be processed (8.3.)
1732bc78049SPatrick McHardy 		 * sCG -> sCG		Ack in CLOSING MAY be processed (8.3.)
1742bc78049SPatrick McHardy 		 * sTW -> sIV
1752bc78049SPatrick McHardy 		 *
1762bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
1772bc78049SPatrick McHardy 			sIV, sIV, sPO, sPO, sOP, sCR, sCG, sIV
1782bc78049SPatrick McHardy 		},
1792bc78049SPatrick McHardy 		[DCCP_PKT_DATA] = {
1802bc78049SPatrick McHardy 		/*
1812bc78049SPatrick McHardy 		 * sNO -> sIV		No connection
1822bc78049SPatrick McHardy 		 * sRQ -> sIV		No connection
1832bc78049SPatrick McHardy 		 * sRS -> sIV		No connection
1842bc78049SPatrick McHardy 		 * sPO -> sIV		MUST use DataAck in PARTOPEN state (8.1.5.)
1852bc78049SPatrick McHardy 		 * sOP -> sOP		Regular Data packet
1862bc78049SPatrick McHardy 		 * sCR -> sCR		Data in CLOSEREQ MAY be processed (8.3.)
1872bc78049SPatrick McHardy 		 * sCG -> sCG		Data in CLOSING MAY be processed (8.3.)
1882bc78049SPatrick McHardy 		 * sTW -> sIV
1892bc78049SPatrick McHardy 		 *
1902bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
1912bc78049SPatrick McHardy 			sIV, sIV, sIV, sIV, sOP, sCR, sCG, sIV,
1922bc78049SPatrick McHardy 		},
1932bc78049SPatrick McHardy 		[DCCP_PKT_DATAACK] = {
1942bc78049SPatrick McHardy 		/*
1952bc78049SPatrick McHardy 		 * sNO -> sIV		No connection
1962bc78049SPatrick McHardy 		 * sRQ -> sIV		No connection
1972bc78049SPatrick McHardy 		 * sRS -> sPO		Ack for Response, move to PARTOPEN (8.1.5.)
1982bc78049SPatrick McHardy 		 * sPO -> sPO		Remain in PARTOPEN state
1992bc78049SPatrick McHardy 		 * sOP -> sOP		Regular DataAck packet in OPEN state
2002bc78049SPatrick McHardy 		 * sCR -> sCR		DataAck in CLOSEREQ MAY be processed (8.3.)
2012bc78049SPatrick McHardy 		 * sCG -> sCG		DataAck in CLOSING MAY be processed (8.3.)
2022bc78049SPatrick McHardy 		 * sTW -> sIV
2032bc78049SPatrick McHardy 		 *
2042bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
2052bc78049SPatrick McHardy 			sIV, sIV, sPO, sPO, sOP, sCR, sCG, sIV
2062bc78049SPatrick McHardy 		},
2072bc78049SPatrick McHardy 		[DCCP_PKT_CLOSEREQ] = {
2082bc78049SPatrick McHardy 		/*
2092bc78049SPatrick McHardy 		 * CLOSEREQ may only be sent by the server.
2102bc78049SPatrick McHardy 		 *
2112bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
2122bc78049SPatrick McHardy 			sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV
2132bc78049SPatrick McHardy 		},
2142bc78049SPatrick McHardy 		[DCCP_PKT_CLOSE] = {
2152bc78049SPatrick McHardy 		/*
2162bc78049SPatrick McHardy 		 * sNO -> sIV		No connection
2172bc78049SPatrick McHardy 		 * sRQ -> sIV		No connection
2182bc78049SPatrick McHardy 		 * sRS -> sIV		No connection
2192bc78049SPatrick McHardy 		 * sPO -> sCG		Client-initiated close
2202bc78049SPatrick McHardy 		 * sOP -> sCG		Client-initiated close
2212bc78049SPatrick McHardy 		 * sCR -> sCG		Close in response to CloseReq (8.3.)
2222bc78049SPatrick McHardy 		 * sCG -> sCG		Retransmit
2232bc78049SPatrick McHardy 		 * sTW -> sIV		Late retransmit, already in TIME_WAIT
2242bc78049SPatrick McHardy 		 *
2252bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
2262bc78049SPatrick McHardy 			sIV, sIV, sIV, sCG, sCG, sCG, sIV, sIV
2272bc78049SPatrick McHardy 		},
2282bc78049SPatrick McHardy 		[DCCP_PKT_RESET] = {
2292bc78049SPatrick McHardy 		/*
2302bc78049SPatrick McHardy 		 * sNO -> sIV		No connection
2312bc78049SPatrick McHardy 		 * sRQ -> sTW		Sync received or timeout, SHOULD send Reset (8.1.1.)
2322bc78049SPatrick McHardy 		 * sRS -> sTW		Response received without Request
2332bc78049SPatrick McHardy 		 * sPO -> sTW		Timeout, SHOULD send Reset (8.1.5.)
2342bc78049SPatrick McHardy 		 * sOP -> sTW		Connection reset
2352bc78049SPatrick McHardy 		 * sCR -> sTW		Connection reset
2362bc78049SPatrick McHardy 		 * sCG -> sTW		Connection reset
2372bc78049SPatrick McHardy 		 * sTW -> sIG		Ignore (don't refresh timer)
2382bc78049SPatrick McHardy 		 *
2392bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
2402bc78049SPatrick McHardy 			sIV, sTW, sTW, sTW, sTW, sTW, sTW, sIG
2412bc78049SPatrick McHardy 		},
2422bc78049SPatrick McHardy 		[DCCP_PKT_SYNC] = {
2432bc78049SPatrick McHardy 		/*
2442bc78049SPatrick McHardy 		 * We currently ignore Sync packets
2452bc78049SPatrick McHardy 		 *
2462bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
2472bc78049SPatrick McHardy 			sIG, sIG, sIG, sIG, sIG, sIG, sIG, sIG,
2482bc78049SPatrick McHardy 		},
2492bc78049SPatrick McHardy 		[DCCP_PKT_SYNCACK] = {
2502bc78049SPatrick McHardy 		/*
2512bc78049SPatrick McHardy 		 * We currently ignore SyncAck packets
2522bc78049SPatrick McHardy 		 *
2532bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
2542bc78049SPatrick McHardy 			sIG, sIG, sIG, sIG, sIG, sIG, sIG, sIG,
2552bc78049SPatrick McHardy 		},
2562bc78049SPatrick McHardy 	},
2572bc78049SPatrick McHardy 	[CT_DCCP_ROLE_SERVER] = {
2582bc78049SPatrick McHardy 		[DCCP_PKT_REQUEST] = {
2592bc78049SPatrick McHardy 		/*
2602bc78049SPatrick McHardy 		 * sNO -> sIV		Invalid
2612bc78049SPatrick McHardy 		 * sRQ -> sIG		Ignore, conntrack might be out of sync
2622bc78049SPatrick McHardy 		 * sRS -> sIG		Ignore, conntrack might be out of sync
2632bc78049SPatrick McHardy 		 * sPO -> sIG		Ignore, conntrack might be out of sync
2642bc78049SPatrick McHardy 		 * sOP -> sIG		Ignore, conntrack might be out of sync
2652bc78049SPatrick McHardy 		 * sCR -> sIG		Ignore, conntrack might be out of sync
2662bc78049SPatrick McHardy 		 * sCG -> sIG		Ignore, conntrack might be out of sync
2672bc78049SPatrick McHardy 		 * sTW -> sRQ		Reincarnation, must reverse roles
2682bc78049SPatrick McHardy 		 *
2692bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
2702bc78049SPatrick McHardy 			sIV, sIG, sIG, sIG, sIG, sIG, sIG, sRQ
2712bc78049SPatrick McHardy 		},
2722bc78049SPatrick McHardy 		[DCCP_PKT_RESPONSE] = {
2732bc78049SPatrick McHardy 		/*
2742bc78049SPatrick McHardy 		 * sNO -> sIV		Response without Request
2752bc78049SPatrick McHardy 		 * sRQ -> sRS		Response to clients Request
2762bc78049SPatrick McHardy 		 * sRS -> sRS		Retransmitted Response (8.1.3. SHOULD NOT)
2772bc78049SPatrick McHardy 		 * sPO -> sIG		Response to an ignored Request or late retransmit
2782bc78049SPatrick McHardy 		 * sOP -> sIG		Ignore, might be response to ignored Request
2792bc78049SPatrick McHardy 		 * sCR -> sIG		Ignore, might be response to ignored Request
2802bc78049SPatrick McHardy 		 * sCG -> sIG		Ignore, might be response to ignored Request
2812bc78049SPatrick McHardy 		 * sTW -> sIV		Invalid, Request from client in sTW moves to sRQ
2822bc78049SPatrick McHardy 		 *
2832bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
2842bc78049SPatrick McHardy 			sIV, sRS, sRS, sIG, sIG, sIG, sIG, sIV
2852bc78049SPatrick McHardy 		},
2862bc78049SPatrick McHardy 		[DCCP_PKT_ACK] = {
2872bc78049SPatrick McHardy 		/*
2882bc78049SPatrick McHardy 		 * sNO -> sIV		No connection
2892bc78049SPatrick McHardy 		 * sRQ -> sIV		No connection
2902bc78049SPatrick McHardy 		 * sRS -> sIV		No connection
2912bc78049SPatrick McHardy 		 * sPO -> sOP		Enter OPEN state (8.1.5.)
2922bc78049SPatrick McHardy 		 * sOP -> sOP		Regular Ack in OPEN state
2932bc78049SPatrick McHardy 		 * sCR -> sIV		Waiting for Close from client
2942bc78049SPatrick McHardy 		 * sCG -> sCG		Ack in CLOSING MAY be processed (8.3.)
2952bc78049SPatrick McHardy 		 * sTW -> sIV
2962bc78049SPatrick McHardy 		 *
2972bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
2982bc78049SPatrick McHardy 			sIV, sIV, sIV, sOP, sOP, sIV, sCG, sIV
2992bc78049SPatrick McHardy 		},
3002bc78049SPatrick McHardy 		[DCCP_PKT_DATA] = {
3012bc78049SPatrick McHardy 		/*
3022bc78049SPatrick McHardy 		 * sNO -> sIV		No connection
3032bc78049SPatrick McHardy 		 * sRQ -> sIV		No connection
3042bc78049SPatrick McHardy 		 * sRS -> sIV		No connection
3052bc78049SPatrick McHardy 		 * sPO -> sOP		Enter OPEN state (8.1.5.)
3062bc78049SPatrick McHardy 		 * sOP -> sOP		Regular Data packet in OPEN state
3072bc78049SPatrick McHardy 		 * sCR -> sIV		Waiting for Close from client
3082bc78049SPatrick McHardy 		 * sCG -> sCG		Data in CLOSING MAY be processed (8.3.)
3092bc78049SPatrick McHardy 		 * sTW -> sIV
3102bc78049SPatrick McHardy 		 *
3112bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
3122bc78049SPatrick McHardy 			sIV, sIV, sIV, sOP, sOP, sIV, sCG, sIV
3132bc78049SPatrick McHardy 		},
3142bc78049SPatrick McHardy 		[DCCP_PKT_DATAACK] = {
3152bc78049SPatrick McHardy 		/*
3162bc78049SPatrick McHardy 		 * sNO -> sIV		No connection
3172bc78049SPatrick McHardy 		 * sRQ -> sIV		No connection
3182bc78049SPatrick McHardy 		 * sRS -> sIV		No connection
3192bc78049SPatrick McHardy 		 * sPO -> sOP		Enter OPEN state (8.1.5.)
3202bc78049SPatrick McHardy 		 * sOP -> sOP		Regular DataAck in OPEN state
3212bc78049SPatrick McHardy 		 * sCR -> sIV		Waiting for Close from client
3222bc78049SPatrick McHardy 		 * sCG -> sCG		Data in CLOSING MAY be processed (8.3.)
3232bc78049SPatrick McHardy 		 * sTW -> sIV
3242bc78049SPatrick McHardy 		 *
3252bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
3262bc78049SPatrick McHardy 			sIV, sIV, sIV, sOP, sOP, sIV, sCG, sIV
3272bc78049SPatrick McHardy 		},
3282bc78049SPatrick McHardy 		[DCCP_PKT_CLOSEREQ] = {
3292bc78049SPatrick McHardy 		/*
3302bc78049SPatrick McHardy 		 * sNO -> sIV		No connection
3312bc78049SPatrick McHardy 		 * sRQ -> sIV		No connection
3322bc78049SPatrick McHardy 		 * sRS -> sIV		No connection
3332bc78049SPatrick McHardy 		 * sPO -> sOP -> sCR	Move directly to CLOSEREQ (8.1.5.)
3342bc78049SPatrick McHardy 		 * sOP -> sCR		CloseReq in OPEN state
3352bc78049SPatrick McHardy 		 * sCR -> sCR		Retransmit
3362bc78049SPatrick McHardy 		 * sCG -> sCR		Simultaneous close, client sends another Close
3372bc78049SPatrick McHardy 		 * sTW -> sIV		Already closed
3382bc78049SPatrick McHardy 		 *
3392bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
3402bc78049SPatrick McHardy 			sIV, sIV, sIV, sCR, sCR, sCR, sCR, sIV
3412bc78049SPatrick McHardy 		},
3422bc78049SPatrick McHardy 		[DCCP_PKT_CLOSE] = {
3432bc78049SPatrick McHardy 		/*
3442bc78049SPatrick McHardy 		 * sNO -> sIV		No connection
3452bc78049SPatrick McHardy 		 * sRQ -> sIV		No connection
3462bc78049SPatrick McHardy 		 * sRS -> sIV		No connection
3472bc78049SPatrick McHardy 		 * sPO -> sOP -> sCG	Move direcly to CLOSING
3482bc78049SPatrick McHardy 		 * sOP -> sCG		Move to CLOSING
3492bc78049SPatrick McHardy 		 * sCR -> sIV		Close after CloseReq is invalid
3502bc78049SPatrick McHardy 		 * sCG -> sCG		Retransmit
3512bc78049SPatrick McHardy 		 * sTW -> sIV		Already closed
3522bc78049SPatrick McHardy 		 *
3532bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
3542bc78049SPatrick McHardy 			sIV, sIV, sIV, sCG, sCG, sIV, sCG, sIV
3552bc78049SPatrick McHardy 		},
3562bc78049SPatrick McHardy 		[DCCP_PKT_RESET] = {
3572bc78049SPatrick McHardy 		/*
3582bc78049SPatrick McHardy 		 * sNO -> sIV		No connection
3592bc78049SPatrick McHardy 		 * sRQ -> sTW		Reset in response to Request
3602bc78049SPatrick McHardy 		 * sRS -> sTW		Timeout, SHOULD send Reset (8.1.3.)
3612bc78049SPatrick McHardy 		 * sPO -> sTW		Timeout, SHOULD send Reset (8.1.3.)
3622bc78049SPatrick McHardy 		 * sOP -> sTW
3632bc78049SPatrick McHardy 		 * sCR -> sTW
3642bc78049SPatrick McHardy 		 * sCG -> sTW
3652bc78049SPatrick McHardy 		 * sTW -> sIG		Ignore (don't refresh timer)
3662bc78049SPatrick McHardy 		 *
3672bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW, sTW */
3682bc78049SPatrick McHardy 			sIV, sTW, sTW, sTW, sTW, sTW, sTW, sTW, sIG
3692bc78049SPatrick McHardy 		},
3702bc78049SPatrick McHardy 		[DCCP_PKT_SYNC] = {
3712bc78049SPatrick McHardy 		/*
3722bc78049SPatrick McHardy 		 * We currently ignore Sync packets
3732bc78049SPatrick McHardy 		 *
3742bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
3752bc78049SPatrick McHardy 			sIG, sIG, sIG, sIG, sIG, sIG, sIG, sIG,
3762bc78049SPatrick McHardy 		},
3772bc78049SPatrick McHardy 		[DCCP_PKT_SYNCACK] = {
3782bc78049SPatrick McHardy 		/*
3792bc78049SPatrick McHardy 		 * We currently ignore SyncAck packets
3802bc78049SPatrick McHardy 		 *
3812bc78049SPatrick McHardy 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
3822bc78049SPatrick McHardy 			sIG, sIG, sIG, sIG, sIG, sIG, sIG, sIG,
3832bc78049SPatrick McHardy 		},
3842bc78049SPatrick McHardy 	},
3852bc78049SPatrick McHardy };
3862bc78049SPatrick McHardy 
3871546000fSCyrill Gorcunov /* this module per-net specifics */
388f99189b1SEric Dumazet static int dccp_net_id __read_mostly;
3891546000fSCyrill Gorcunov struct dccp_net {
39054b8873fSGao feng 	struct nf_proto_net pn;
3911546000fSCyrill Gorcunov 	int dccp_loose;
3921546000fSCyrill Gorcunov 	unsigned int dccp_timeout[CT_DCCP_MAX + 1];
3931546000fSCyrill Gorcunov };
3941546000fSCyrill Gorcunov 
3951546000fSCyrill Gorcunov static inline struct dccp_net *dccp_pernet(struct net *net)
3961546000fSCyrill Gorcunov {
3971546000fSCyrill Gorcunov 	return net_generic(net, dccp_net_id);
3981546000fSCyrill Gorcunov }
3991546000fSCyrill Gorcunov 
40009f263cdSJan Engelhardt static bool dccp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff,
401a31f1adcSEric W. Biederman 			      struct net *net, struct nf_conntrack_tuple *tuple)
4022bc78049SPatrick McHardy {
4032bc78049SPatrick McHardy 	struct dccp_hdr _hdr, *dh;
4042bc78049SPatrick McHardy 
4052bc78049SPatrick McHardy 	dh = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
4062bc78049SPatrick McHardy 	if (dh == NULL)
40709f263cdSJan Engelhardt 		return false;
4082bc78049SPatrick McHardy 
4092bc78049SPatrick McHardy 	tuple->src.u.dccp.port = dh->dccph_sport;
4102bc78049SPatrick McHardy 	tuple->dst.u.dccp.port = dh->dccph_dport;
41109f263cdSJan Engelhardt 	return true;
4122bc78049SPatrick McHardy }
4132bc78049SPatrick McHardy 
41409f263cdSJan Engelhardt static bool dccp_invert_tuple(struct nf_conntrack_tuple *inv,
4152bc78049SPatrick McHardy 			      const struct nf_conntrack_tuple *tuple)
4162bc78049SPatrick McHardy {
4172bc78049SPatrick McHardy 	inv->src.u.dccp.port = tuple->dst.u.dccp.port;
4182bc78049SPatrick McHardy 	inv->dst.u.dccp.port = tuple->src.u.dccp.port;
41909f263cdSJan Engelhardt 	return true;
4202bc78049SPatrick McHardy }
4212bc78049SPatrick McHardy 
42209f263cdSJan Engelhardt static bool dccp_new(struct nf_conn *ct, const struct sk_buff *skb,
4232c8503f5SPablo Neira Ayuso 		     unsigned int dataoff, unsigned int *timeouts)
4242bc78049SPatrick McHardy {
425c2a2c7e0SAlexey Dobriyan 	struct net *net = nf_ct_net(ct);
4261546000fSCyrill Gorcunov 	struct dccp_net *dn;
4272bc78049SPatrick McHardy 	struct dccp_hdr _dh, *dh;
4282bc78049SPatrick McHardy 	const char *msg;
4292bc78049SPatrick McHardy 	u_int8_t state;
4302bc78049SPatrick McHardy 
431b22f5126SDaniel Borkmann 	dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &_dh);
4322bc78049SPatrick McHardy 	BUG_ON(dh == NULL);
4332bc78049SPatrick McHardy 
4342bc78049SPatrick McHardy 	state = dccp_state_table[CT_DCCP_ROLE_CLIENT][dh->dccph_type][CT_DCCP_NONE];
4352bc78049SPatrick McHardy 	switch (state) {
4362bc78049SPatrick McHardy 	default:
4371546000fSCyrill Gorcunov 		dn = dccp_pernet(net);
4381546000fSCyrill Gorcunov 		if (dn->dccp_loose == 0) {
4392bc78049SPatrick McHardy 			msg = "nf_ct_dccp: not picking up existing connection ";
4402bc78049SPatrick McHardy 			goto out_invalid;
4412bc78049SPatrick McHardy 		}
4422bc78049SPatrick McHardy 	case CT_DCCP_REQUEST:
4432bc78049SPatrick McHardy 		break;
4442bc78049SPatrick McHardy 	case CT_DCCP_INVALID:
4452bc78049SPatrick McHardy 		msg = "nf_ct_dccp: invalid state transition ";
4462bc78049SPatrick McHardy 		goto out_invalid;
4472bc78049SPatrick McHardy 	}
4482bc78049SPatrick McHardy 
4492bc78049SPatrick McHardy 	ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_CLIENT;
4502bc78049SPatrick McHardy 	ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_SERVER;
4512bc78049SPatrick McHardy 	ct->proto.dccp.state = CT_DCCP_NONE;
452e5fc9e7aSChangli Gao 	ct->proto.dccp.last_pkt = DCCP_PKT_REQUEST;
453e5fc9e7aSChangli Gao 	ct->proto.dccp.last_dir = IP_CT_DIR_ORIGINAL;
454e5fc9e7aSChangli Gao 	ct->proto.dccp.handshake_seq = 0;
45509f263cdSJan Engelhardt 	return true;
4562bc78049SPatrick McHardy 
4572bc78049SPatrick McHardy out_invalid:
458c2a2c7e0SAlexey Dobriyan 	if (LOG_INVALID(net, IPPROTO_DCCP))
45930e0c6a6SGao feng 		nf_log_packet(net, nf_ct_l3num(ct), 0, skb, NULL, NULL,
460138aef7dSDaniel Borkmann 			      NULL, "%s", msg);
46109f263cdSJan Engelhardt 	return false;
4622bc78049SPatrick McHardy }
4632bc78049SPatrick McHardy 
4642bc78049SPatrick McHardy static u64 dccp_ack_seq(const struct dccp_hdr *dh)
4652bc78049SPatrick McHardy {
4662bc78049SPatrick McHardy 	const struct dccp_hdr_ack_bits *dhack;
4672bc78049SPatrick McHardy 
4682bc78049SPatrick McHardy 	dhack = (void *)dh + __dccp_basic_hdr_len(dh);
4692bc78049SPatrick McHardy 	return ((u64)ntohs(dhack->dccph_ack_nr_high) << 32) +
4702bc78049SPatrick McHardy 		     ntohl(dhack->dccph_ack_nr_low);
4712bc78049SPatrick McHardy }
4722bc78049SPatrick McHardy 
4732c8503f5SPablo Neira Ayuso static unsigned int *dccp_get_timeouts(struct net *net)
4742c8503f5SPablo Neira Ayuso {
4752c8503f5SPablo Neira Ayuso 	return dccp_pernet(net)->dccp_timeout;
4762c8503f5SPablo Neira Ayuso }
4772c8503f5SPablo Neira Ayuso 
4782bc78049SPatrick McHardy static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb,
4792bc78049SPatrick McHardy 		       unsigned int dataoff, enum ip_conntrack_info ctinfo,
4802c8503f5SPablo Neira Ayuso 		       u_int8_t pf, unsigned int hooknum,
4812c8503f5SPablo Neira Ayuso 		       unsigned int *timeouts)
4822bc78049SPatrick McHardy {
483c2a2c7e0SAlexey Dobriyan 	struct net *net = nf_ct_net(ct);
4842bc78049SPatrick McHardy 	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
4852bc78049SPatrick McHardy 	struct dccp_hdr _dh, *dh;
4862bc78049SPatrick McHardy 	u_int8_t type, old_state, new_state;
4872bc78049SPatrick McHardy 	enum ct_dccp_roles role;
4882bc78049SPatrick McHardy 
489b22f5126SDaniel Borkmann 	dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &_dh);
4902bc78049SPatrick McHardy 	BUG_ON(dh == NULL);
4912bc78049SPatrick McHardy 	type = dh->dccph_type;
4922bc78049SPatrick McHardy 
4932bc78049SPatrick McHardy 	if (type == DCCP_PKT_RESET &&
4942bc78049SPatrick McHardy 	    !test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
4952bc78049SPatrick McHardy 		/* Tear down connection immediately if only reply is a RESET */
496718d4ad9SFabian Hugelshofer 		nf_ct_kill_acct(ct, ctinfo, skb);
4972bc78049SPatrick McHardy 		return NF_ACCEPT;
4982bc78049SPatrick McHardy 	}
4992bc78049SPatrick McHardy 
500440f0d58SPatrick McHardy 	spin_lock_bh(&ct->lock);
5012bc78049SPatrick McHardy 
5022bc78049SPatrick McHardy 	role = ct->proto.dccp.role[dir];
5032bc78049SPatrick McHardy 	old_state = ct->proto.dccp.state;
5042bc78049SPatrick McHardy 	new_state = dccp_state_table[role][type][old_state];
5052bc78049SPatrick McHardy 
5062bc78049SPatrick McHardy 	switch (new_state) {
5072bc78049SPatrick McHardy 	case CT_DCCP_REQUEST:
5082bc78049SPatrick McHardy 		if (old_state == CT_DCCP_TIMEWAIT &&
5092bc78049SPatrick McHardy 		    role == CT_DCCP_ROLE_SERVER) {
5102bc78049SPatrick McHardy 			/* Reincarnation in the reverse direction: reopen and
5112bc78049SPatrick McHardy 			 * reverse client/server roles. */
5122bc78049SPatrick McHardy 			ct->proto.dccp.role[dir] = CT_DCCP_ROLE_CLIENT;
5132bc78049SPatrick McHardy 			ct->proto.dccp.role[!dir] = CT_DCCP_ROLE_SERVER;
5142bc78049SPatrick McHardy 		}
5152bc78049SPatrick McHardy 		break;
5162bc78049SPatrick McHardy 	case CT_DCCP_RESPOND:
5172bc78049SPatrick McHardy 		if (old_state == CT_DCCP_REQUEST)
5182bc78049SPatrick McHardy 			ct->proto.dccp.handshake_seq = dccp_hdr_seq(dh);
5192bc78049SPatrick McHardy 		break;
5202bc78049SPatrick McHardy 	case CT_DCCP_PARTOPEN:
5212bc78049SPatrick McHardy 		if (old_state == CT_DCCP_RESPOND &&
5222bc78049SPatrick McHardy 		    type == DCCP_PKT_ACK &&
5232bc78049SPatrick McHardy 		    dccp_ack_seq(dh) == ct->proto.dccp.handshake_seq)
5242bc78049SPatrick McHardy 			set_bit(IPS_ASSURED_BIT, &ct->status);
5252bc78049SPatrick McHardy 		break;
5262bc78049SPatrick McHardy 	case CT_DCCP_IGNORE:
5272bc78049SPatrick McHardy 		/*
5282bc78049SPatrick McHardy 		 * Connection tracking might be out of sync, so we ignore
5292bc78049SPatrick McHardy 		 * packets that might establish a new connection and resync
5302bc78049SPatrick McHardy 		 * if the server responds with a valid Response.
5312bc78049SPatrick McHardy 		 */
5322bc78049SPatrick McHardy 		if (ct->proto.dccp.last_dir == !dir &&
5332bc78049SPatrick McHardy 		    ct->proto.dccp.last_pkt == DCCP_PKT_REQUEST &&
5342bc78049SPatrick McHardy 		    type == DCCP_PKT_RESPONSE) {
5352bc78049SPatrick McHardy 			ct->proto.dccp.role[!dir] = CT_DCCP_ROLE_CLIENT;
5362bc78049SPatrick McHardy 			ct->proto.dccp.role[dir] = CT_DCCP_ROLE_SERVER;
5372bc78049SPatrick McHardy 			ct->proto.dccp.handshake_seq = dccp_hdr_seq(dh);
5382bc78049SPatrick McHardy 			new_state = CT_DCCP_RESPOND;
5392bc78049SPatrick McHardy 			break;
5402bc78049SPatrick McHardy 		}
5412bc78049SPatrick McHardy 		ct->proto.dccp.last_dir = dir;
5422bc78049SPatrick McHardy 		ct->proto.dccp.last_pkt = type;
5432bc78049SPatrick McHardy 
544440f0d58SPatrick McHardy 		spin_unlock_bh(&ct->lock);
545c2a2c7e0SAlexey Dobriyan 		if (LOG_INVALID(net, IPPROTO_DCCP))
54630e0c6a6SGao feng 			nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
5472bc78049SPatrick McHardy 				      "nf_ct_dccp: invalid packet ignored ");
5482bc78049SPatrick McHardy 		return NF_ACCEPT;
5492bc78049SPatrick McHardy 	case CT_DCCP_INVALID:
550440f0d58SPatrick McHardy 		spin_unlock_bh(&ct->lock);
551c2a2c7e0SAlexey Dobriyan 		if (LOG_INVALID(net, IPPROTO_DCCP))
55230e0c6a6SGao feng 			nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
5532bc78049SPatrick McHardy 				      "nf_ct_dccp: invalid state transition ");
5542bc78049SPatrick McHardy 		return -NF_ACCEPT;
5552bc78049SPatrick McHardy 	}
5562bc78049SPatrick McHardy 
5572bc78049SPatrick McHardy 	ct->proto.dccp.last_dir = dir;
5582bc78049SPatrick McHardy 	ct->proto.dccp.last_pkt = type;
5592bc78049SPatrick McHardy 	ct->proto.dccp.state = new_state;
560440f0d58SPatrick McHardy 	spin_unlock_bh(&ct->lock);
5611546000fSCyrill Gorcunov 
562b38b1f61SPablo Neira Ayuso 	if (new_state != old_state)
563b38b1f61SPablo Neira Ayuso 		nf_conntrack_event_cache(IPCT_PROTOINFO, ct);
564b38b1f61SPablo Neira Ayuso 
5652c8503f5SPablo Neira Ayuso 	nf_ct_refresh_acct(ct, ctinfo, skb, timeouts[new_state]);
5662bc78049SPatrick McHardy 
5672bc78049SPatrick McHardy 	return NF_ACCEPT;
5682bc78049SPatrick McHardy }
5692bc78049SPatrick McHardy 
5708fea97ecSPatrick McHardy static int dccp_error(struct net *net, struct nf_conn *tmpl,
5718fea97ecSPatrick McHardy 		      struct sk_buff *skb, unsigned int dataoff,
5728fea97ecSPatrick McHardy 		      enum ip_conntrack_info *ctinfo,
57374c51a14SAlexey Dobriyan 		      u_int8_t pf, unsigned int hooknum)
5742bc78049SPatrick McHardy {
5752bc78049SPatrick McHardy 	struct dccp_hdr _dh, *dh;
5762bc78049SPatrick McHardy 	unsigned int dccp_len = skb->len - dataoff;
5772bc78049SPatrick McHardy 	unsigned int cscov;
5782bc78049SPatrick McHardy 	const char *msg;
5792bc78049SPatrick McHardy 
580b22f5126SDaniel Borkmann 	dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &_dh);
5812bc78049SPatrick McHardy 	if (dh == NULL) {
5822bc78049SPatrick McHardy 		msg = "nf_ct_dccp: short packet ";
5832bc78049SPatrick McHardy 		goto out_invalid;
5842bc78049SPatrick McHardy 	}
5852bc78049SPatrick McHardy 
5862bc78049SPatrick McHardy 	if (dh->dccph_doff * 4 < sizeof(struct dccp_hdr) ||
5872bc78049SPatrick McHardy 	    dh->dccph_doff * 4 > dccp_len) {
5882bc78049SPatrick McHardy 		msg = "nf_ct_dccp: truncated/malformed packet ";
5892bc78049SPatrick McHardy 		goto out_invalid;
5902bc78049SPatrick McHardy 	}
5912bc78049SPatrick McHardy 
5922bc78049SPatrick McHardy 	cscov = dccp_len;
5932bc78049SPatrick McHardy 	if (dh->dccph_cscov) {
5942bc78049SPatrick McHardy 		cscov = (dh->dccph_cscov - 1) * 4;
5952bc78049SPatrick McHardy 		if (cscov > dccp_len) {
5962bc78049SPatrick McHardy 			msg = "nf_ct_dccp: bad checksum coverage ";
5972bc78049SPatrick McHardy 			goto out_invalid;
5982bc78049SPatrick McHardy 		}
5992bc78049SPatrick McHardy 	}
6002bc78049SPatrick McHardy 
601c04d0552SAlexey Dobriyan 	if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING &&
6022bc78049SPatrick McHardy 	    nf_checksum_partial(skb, hooknum, dataoff, cscov, IPPROTO_DCCP,
6032bc78049SPatrick McHardy 				pf)) {
6042bc78049SPatrick McHardy 		msg = "nf_ct_dccp: bad checksum ";
6052bc78049SPatrick McHardy 		goto out_invalid;
6062bc78049SPatrick McHardy 	}
6072bc78049SPatrick McHardy 
6082bc78049SPatrick McHardy 	if (dh->dccph_type >= DCCP_PKT_INVALID) {
6092bc78049SPatrick McHardy 		msg = "nf_ct_dccp: reserved packet type ";
6102bc78049SPatrick McHardy 		goto out_invalid;
6112bc78049SPatrick McHardy 	}
6122bc78049SPatrick McHardy 
6132bc78049SPatrick McHardy 	return NF_ACCEPT;
6142bc78049SPatrick McHardy 
6152bc78049SPatrick McHardy out_invalid:
616c2a2c7e0SAlexey Dobriyan 	if (LOG_INVALID(net, IPPROTO_DCCP))
617138aef7dSDaniel Borkmann 		nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL, "%s", msg);
6182bc78049SPatrick McHardy 	return -NF_ACCEPT;
6192bc78049SPatrick McHardy }
6202bc78049SPatrick McHardy 
621824f1fbeSJoe Perches static void dccp_print_tuple(struct seq_file *s,
6222bc78049SPatrick McHardy 			     const struct nf_conntrack_tuple *tuple)
6232bc78049SPatrick McHardy {
624824f1fbeSJoe Perches 	seq_printf(s, "sport=%hu dport=%hu ",
6252bc78049SPatrick McHardy 		   ntohs(tuple->src.u.dccp.port),
6262bc78049SPatrick McHardy 		   ntohs(tuple->dst.u.dccp.port));
6272bc78049SPatrick McHardy }
6282bc78049SPatrick McHardy 
62937246a58SSteven Rostedt (Red Hat) static void dccp_print_conntrack(struct seq_file *s, struct nf_conn *ct)
6302bc78049SPatrick McHardy {
63137246a58SSteven Rostedt (Red Hat) 	seq_printf(s, "%s ", dccp_state_names[ct->proto.dccp.state]);
6322bc78049SPatrick McHardy }
6332bc78049SPatrick McHardy 
634c0cd1156SIgor Maravić #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
6352bc78049SPatrick McHardy static int dccp_to_nlattr(struct sk_buff *skb, struct nlattr *nla,
636440f0d58SPatrick McHardy 			  struct nf_conn *ct)
6372bc78049SPatrick McHardy {
6382bc78049SPatrick McHardy 	struct nlattr *nest_parms;
6392bc78049SPatrick McHardy 
640440f0d58SPatrick McHardy 	spin_lock_bh(&ct->lock);
6412bc78049SPatrick McHardy 	nest_parms = nla_nest_start(skb, CTA_PROTOINFO_DCCP | NLA_F_NESTED);
6422bc78049SPatrick McHardy 	if (!nest_parms)
6432bc78049SPatrick McHardy 		goto nla_put_failure;
644516ee48fSDavid S. Miller 	if (nla_put_u8(skb, CTA_PROTOINFO_DCCP_STATE, ct->proto.dccp.state) ||
645516ee48fSDavid S. Miller 	    nla_put_u8(skb, CTA_PROTOINFO_DCCP_ROLE,
646516ee48fSDavid S. Miller 		       ct->proto.dccp.role[IP_CT_DIR_ORIGINAL]) ||
647516ee48fSDavid S. Miller 	    nla_put_be64(skb, CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ,
648b46f6dedSNicolas Dichtel 			 cpu_to_be64(ct->proto.dccp.handshake_seq),
649b46f6dedSNicolas Dichtel 			 CTA_PROTOINFO_DCCP_PAD))
650516ee48fSDavid S. Miller 		goto nla_put_failure;
6512bc78049SPatrick McHardy 	nla_nest_end(skb, nest_parms);
652440f0d58SPatrick McHardy 	spin_unlock_bh(&ct->lock);
6532bc78049SPatrick McHardy 	return 0;
6542bc78049SPatrick McHardy 
6552bc78049SPatrick McHardy nla_put_failure:
656440f0d58SPatrick McHardy 	spin_unlock_bh(&ct->lock);
6572bc78049SPatrick McHardy 	return -1;
6582bc78049SPatrick McHardy }
6592bc78049SPatrick McHardy 
6602bc78049SPatrick McHardy static const struct nla_policy dccp_nla_policy[CTA_PROTOINFO_DCCP_MAX + 1] = {
6612bc78049SPatrick McHardy 	[CTA_PROTOINFO_DCCP_STATE]	= { .type = NLA_U8 },
66271951b64SPablo Neira Ayuso 	[CTA_PROTOINFO_DCCP_ROLE]	= { .type = NLA_U8 },
663a17c8598SPablo Neira Ayuso 	[CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ] = { .type = NLA_U64 },
664b46f6dedSNicolas Dichtel 	[CTA_PROTOINFO_DCCP_PAD]	= { .type = NLA_UNSPEC },
6652bc78049SPatrick McHardy };
6662bc78049SPatrick McHardy 
6672bc78049SPatrick McHardy static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct)
6682bc78049SPatrick McHardy {
6692bc78049SPatrick McHardy 	struct nlattr *attr = cda[CTA_PROTOINFO_DCCP];
6702bc78049SPatrick McHardy 	struct nlattr *tb[CTA_PROTOINFO_DCCP_MAX + 1];
6712bc78049SPatrick McHardy 	int err;
6722bc78049SPatrick McHardy 
6732bc78049SPatrick McHardy 	if (!attr)
6742bc78049SPatrick McHardy 		return 0;
6752bc78049SPatrick McHardy 
6762bc78049SPatrick McHardy 	err = nla_parse_nested(tb, CTA_PROTOINFO_DCCP_MAX, attr,
6772bc78049SPatrick McHardy 			       dccp_nla_policy);
6782bc78049SPatrick McHardy 	if (err < 0)
6792bc78049SPatrick McHardy 		return err;
6802bc78049SPatrick McHardy 
6812bc78049SPatrick McHardy 	if (!tb[CTA_PROTOINFO_DCCP_STATE] ||
68271951b64SPablo Neira Ayuso 	    !tb[CTA_PROTOINFO_DCCP_ROLE] ||
68371951b64SPablo Neira Ayuso 	    nla_get_u8(tb[CTA_PROTOINFO_DCCP_ROLE]) > CT_DCCP_ROLE_MAX ||
68471951b64SPablo Neira Ayuso 	    nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]) >= CT_DCCP_IGNORE) {
6852bc78049SPatrick McHardy 		return -EINVAL;
68671951b64SPablo Neira Ayuso 	}
6872bc78049SPatrick McHardy 
688440f0d58SPatrick McHardy 	spin_lock_bh(&ct->lock);
6892bc78049SPatrick McHardy 	ct->proto.dccp.state = nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]);
69071951b64SPablo Neira Ayuso 	if (nla_get_u8(tb[CTA_PROTOINFO_DCCP_ROLE]) == CT_DCCP_ROLE_CLIENT) {
69171951b64SPablo Neira Ayuso 		ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_CLIENT;
69271951b64SPablo Neira Ayuso 		ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_SERVER;
69371951b64SPablo Neira Ayuso 	} else {
69471951b64SPablo Neira Ayuso 		ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_SERVER;
69571951b64SPablo Neira Ayuso 		ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_CLIENT;
69671951b64SPablo Neira Ayuso 	}
697a17c8598SPablo Neira Ayuso 	if (tb[CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ]) {
698a17c8598SPablo Neira Ayuso 		ct->proto.dccp.handshake_seq =
699a17c8598SPablo Neira Ayuso 		be64_to_cpu(nla_get_be64(tb[CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ]));
700a17c8598SPablo Neira Ayuso 	}
701440f0d58SPatrick McHardy 	spin_unlock_bh(&ct->lock);
7022bc78049SPatrick McHardy 	return 0;
7032bc78049SPatrick McHardy }
704a400c30eSHolger Eitzenberger 
705a400c30eSHolger Eitzenberger static int dccp_nlattr_size(void)
706a400c30eSHolger Eitzenberger {
707a400c30eSHolger Eitzenberger 	return nla_total_size(0)	/* CTA_PROTOINFO_DCCP */
708a400c30eSHolger Eitzenberger 		+ nla_policy_len(dccp_nla_policy, CTA_PROTOINFO_DCCP_MAX + 1);
709a400c30eSHolger Eitzenberger }
71050978462SPablo Neira Ayuso 
7112bc78049SPatrick McHardy #endif
7122bc78049SPatrick McHardy 
71350978462SPablo Neira Ayuso #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
71450978462SPablo Neira Ayuso 
71550978462SPablo Neira Ayuso #include <linux/netfilter/nfnetlink.h>
71650978462SPablo Neira Ayuso #include <linux/netfilter/nfnetlink_cttimeout.h>
71750978462SPablo Neira Ayuso 
7188264deb8SGao feng static int dccp_timeout_nlattr_to_obj(struct nlattr *tb[],
7198264deb8SGao feng 				      struct net *net, void *data)
72050978462SPablo Neira Ayuso {
7218264deb8SGao feng 	struct dccp_net *dn = dccp_pernet(net);
72250978462SPablo Neira Ayuso 	unsigned int *timeouts = data;
72350978462SPablo Neira Ayuso 	int i;
72450978462SPablo Neira Ayuso 
72550978462SPablo Neira Ayuso 	/* set default DCCP timeouts. */
72650978462SPablo Neira Ayuso 	for (i=0; i<CT_DCCP_MAX; i++)
72750978462SPablo Neira Ayuso 		timeouts[i] = dn->dccp_timeout[i];
72850978462SPablo Neira Ayuso 
72950978462SPablo Neira Ayuso 	/* there's a 1:1 mapping between attributes and protocol states. */
73050978462SPablo Neira Ayuso 	for (i=CTA_TIMEOUT_DCCP_UNSPEC+1; i<CTA_TIMEOUT_DCCP_MAX+1; i++) {
73150978462SPablo Neira Ayuso 		if (tb[i]) {
73250978462SPablo Neira Ayuso 			timeouts[i] = ntohl(nla_get_be32(tb[i])) * HZ;
73350978462SPablo Neira Ayuso 		}
73450978462SPablo Neira Ayuso 	}
73550978462SPablo Neira Ayuso 	return 0;
73650978462SPablo Neira Ayuso }
73750978462SPablo Neira Ayuso 
73850978462SPablo Neira Ayuso static int
73950978462SPablo Neira Ayuso dccp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
74050978462SPablo Neira Ayuso {
74150978462SPablo Neira Ayuso         const unsigned int *timeouts = data;
74250978462SPablo Neira Ayuso 	int i;
74350978462SPablo Neira Ayuso 
744516ee48fSDavid S. Miller 	for (i=CTA_TIMEOUT_DCCP_UNSPEC+1; i<CTA_TIMEOUT_DCCP_MAX+1; i++) {
745516ee48fSDavid S. Miller 		if (nla_put_be32(skb, i, htonl(timeouts[i] / HZ)))
746516ee48fSDavid S. Miller 			goto nla_put_failure;
747516ee48fSDavid S. Miller 	}
74850978462SPablo Neira Ayuso 	return 0;
74950978462SPablo Neira Ayuso 
75050978462SPablo Neira Ayuso nla_put_failure:
75150978462SPablo Neira Ayuso 	return -ENOSPC;
75250978462SPablo Neira Ayuso }
75350978462SPablo Neira Ayuso 
75450978462SPablo Neira Ayuso static const struct nla_policy
75550978462SPablo Neira Ayuso dccp_timeout_nla_policy[CTA_TIMEOUT_DCCP_MAX+1] = {
75650978462SPablo Neira Ayuso 	[CTA_TIMEOUT_DCCP_REQUEST]	= { .type = NLA_U32 },
75750978462SPablo Neira Ayuso 	[CTA_TIMEOUT_DCCP_RESPOND]	= { .type = NLA_U32 },
75850978462SPablo Neira Ayuso 	[CTA_TIMEOUT_DCCP_PARTOPEN]	= { .type = NLA_U32 },
75950978462SPablo Neira Ayuso 	[CTA_TIMEOUT_DCCP_OPEN]		= { .type = NLA_U32 },
76050978462SPablo Neira Ayuso 	[CTA_TIMEOUT_DCCP_CLOSEREQ]	= { .type = NLA_U32 },
76150978462SPablo Neira Ayuso 	[CTA_TIMEOUT_DCCP_CLOSING]	= { .type = NLA_U32 },
76250978462SPablo Neira Ayuso 	[CTA_TIMEOUT_DCCP_TIMEWAIT]	= { .type = NLA_U32 },
76350978462SPablo Neira Ayuso };
76450978462SPablo Neira Ayuso #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
76550978462SPablo Neira Ayuso 
7662bc78049SPatrick McHardy #ifdef CONFIG_SYSCTL
7671546000fSCyrill Gorcunov /* template, data assigned later */
7681546000fSCyrill Gorcunov static struct ctl_table dccp_sysctl_table[] = {
7692bc78049SPatrick McHardy 	{
7702bc78049SPatrick McHardy 		.procname	= "nf_conntrack_dccp_timeout_request",
7712bc78049SPatrick McHardy 		.maxlen		= sizeof(unsigned int),
7722bc78049SPatrick McHardy 		.mode		= 0644,
7732bc78049SPatrick McHardy 		.proc_handler	= proc_dointvec_jiffies,
7742bc78049SPatrick McHardy 	},
7752bc78049SPatrick McHardy 	{
7762bc78049SPatrick McHardy 		.procname	= "nf_conntrack_dccp_timeout_respond",
7772bc78049SPatrick McHardy 		.maxlen		= sizeof(unsigned int),
7782bc78049SPatrick McHardy 		.mode		= 0644,
7792bc78049SPatrick McHardy 		.proc_handler	= proc_dointvec_jiffies,
7802bc78049SPatrick McHardy 	},
7812bc78049SPatrick McHardy 	{
7822bc78049SPatrick McHardy 		.procname	= "nf_conntrack_dccp_timeout_partopen",
7832bc78049SPatrick McHardy 		.maxlen		= sizeof(unsigned int),
7842bc78049SPatrick McHardy 		.mode		= 0644,
7852bc78049SPatrick McHardy 		.proc_handler	= proc_dointvec_jiffies,
7862bc78049SPatrick McHardy 	},
7872bc78049SPatrick McHardy 	{
7882bc78049SPatrick McHardy 		.procname	= "nf_conntrack_dccp_timeout_open",
7892bc78049SPatrick McHardy 		.maxlen		= sizeof(unsigned int),
7902bc78049SPatrick McHardy 		.mode		= 0644,
7912bc78049SPatrick McHardy 		.proc_handler	= proc_dointvec_jiffies,
7922bc78049SPatrick McHardy 	},
7932bc78049SPatrick McHardy 	{
7942bc78049SPatrick McHardy 		.procname	= "nf_conntrack_dccp_timeout_closereq",
7952bc78049SPatrick McHardy 		.maxlen		= sizeof(unsigned int),
7962bc78049SPatrick McHardy 		.mode		= 0644,
7972bc78049SPatrick McHardy 		.proc_handler	= proc_dointvec_jiffies,
7982bc78049SPatrick McHardy 	},
7992bc78049SPatrick McHardy 	{
8002bc78049SPatrick McHardy 		.procname	= "nf_conntrack_dccp_timeout_closing",
8012bc78049SPatrick McHardy 		.maxlen		= sizeof(unsigned int),
8022bc78049SPatrick McHardy 		.mode		= 0644,
8032bc78049SPatrick McHardy 		.proc_handler	= proc_dointvec_jiffies,
8042bc78049SPatrick McHardy 	},
8052bc78049SPatrick McHardy 	{
8062bc78049SPatrick McHardy 		.procname	= "nf_conntrack_dccp_timeout_timewait",
8072bc78049SPatrick McHardy 		.maxlen		= sizeof(unsigned int),
8082bc78049SPatrick McHardy 		.mode		= 0644,
8092bc78049SPatrick McHardy 		.proc_handler	= proc_dointvec_jiffies,
8102bc78049SPatrick McHardy 	},
8112bc78049SPatrick McHardy 	{
8122bc78049SPatrick McHardy 		.procname	= "nf_conntrack_dccp_loose",
8131546000fSCyrill Gorcunov 		.maxlen		= sizeof(int),
8142bc78049SPatrick McHardy 		.mode		= 0644,
8152bc78049SPatrick McHardy 		.proc_handler	= proc_dointvec,
8162bc78049SPatrick McHardy 	},
817f8572d8fSEric W. Biederman 	{ }
8182bc78049SPatrick McHardy };
8192bc78049SPatrick McHardy #endif /* CONFIG_SYSCTL */
8202bc78049SPatrick McHardy 
821464dc801SEric W. Biederman static int dccp_kmemdup_sysctl_table(struct net *net, struct nf_proto_net *pn,
82254b8873fSGao feng 				     struct dccp_net *dn)
82384c39451SGao feng {
82454b8873fSGao feng #ifdef CONFIG_SYSCTL
82554b8873fSGao feng 	if (pn->ctl_table)
82654b8873fSGao feng 		return 0;
82784c39451SGao feng 
82884c39451SGao feng 	pn->ctl_table = kmemdup(dccp_sysctl_table,
82984c39451SGao feng 				sizeof(dccp_sysctl_table),
83084c39451SGao feng 				GFP_KERNEL);
83184c39451SGao feng 	if (!pn->ctl_table)
83284c39451SGao feng 		return -ENOMEM;
83384c39451SGao feng 
83484c39451SGao feng 	pn->ctl_table[0].data = &dn->dccp_timeout[CT_DCCP_REQUEST];
83584c39451SGao feng 	pn->ctl_table[1].data = &dn->dccp_timeout[CT_DCCP_RESPOND];
83684c39451SGao feng 	pn->ctl_table[2].data = &dn->dccp_timeout[CT_DCCP_PARTOPEN];
83784c39451SGao feng 	pn->ctl_table[3].data = &dn->dccp_timeout[CT_DCCP_OPEN];
83884c39451SGao feng 	pn->ctl_table[4].data = &dn->dccp_timeout[CT_DCCP_CLOSEREQ];
83984c39451SGao feng 	pn->ctl_table[5].data = &dn->dccp_timeout[CT_DCCP_CLOSING];
84084c39451SGao feng 	pn->ctl_table[6].data = &dn->dccp_timeout[CT_DCCP_TIMEWAIT];
84184c39451SGao feng 	pn->ctl_table[7].data = &dn->dccp_loose;
842464dc801SEric W. Biederman 
843464dc801SEric W. Biederman 	/* Don't export sysctls to unprivileged users */
844464dc801SEric W. Biederman 	if (net->user_ns != &init_user_ns)
845464dc801SEric W. Biederman 		pn->ctl_table[0].procname = NULL;
84684c39451SGao feng #endif
84784c39451SGao feng 	return 0;
84884c39451SGao feng }
84984c39451SGao feng 
85054b8873fSGao feng static int dccp_init_net(struct net *net, u_int16_t proto)
85154b8873fSGao feng {
85254b8873fSGao feng 	struct dccp_net *dn = dccp_pernet(net);
85354b8873fSGao feng 	struct nf_proto_net *pn = &dn->pn;
85454b8873fSGao feng 
85554b8873fSGao feng 	if (!pn->users) {
85654b8873fSGao feng 		/* default values */
85754b8873fSGao feng 		dn->dccp_loose = 1;
85854b8873fSGao feng 		dn->dccp_timeout[CT_DCCP_REQUEST]	= 2 * DCCP_MSL;
85954b8873fSGao feng 		dn->dccp_timeout[CT_DCCP_RESPOND]	= 4 * DCCP_MSL;
86054b8873fSGao feng 		dn->dccp_timeout[CT_DCCP_PARTOPEN]	= 4 * DCCP_MSL;
86154b8873fSGao feng 		dn->dccp_timeout[CT_DCCP_OPEN]		= 12 * 3600 * HZ;
86254b8873fSGao feng 		dn->dccp_timeout[CT_DCCP_CLOSEREQ]	= 64 * HZ;
86354b8873fSGao feng 		dn->dccp_timeout[CT_DCCP_CLOSING]	= 64 * HZ;
86454b8873fSGao feng 		dn->dccp_timeout[CT_DCCP_TIMEWAIT]	= 2 * DCCP_MSL;
86554b8873fSGao feng 	}
86654b8873fSGao feng 
867464dc801SEric W. Biederman 	return dccp_kmemdup_sysctl_table(net, pn, dn);
86854b8873fSGao feng }
86954b8873fSGao feng 
8702bc78049SPatrick McHardy static struct nf_conntrack_l4proto dccp_proto4 __read_mostly = {
8712bc78049SPatrick McHardy 	.l3proto		= AF_INET,
8722bc78049SPatrick McHardy 	.l4proto		= IPPROTO_DCCP,
8732bc78049SPatrick McHardy 	.name			= "dccp",
8742bc78049SPatrick McHardy 	.pkt_to_tuple		= dccp_pkt_to_tuple,
8752bc78049SPatrick McHardy 	.invert_tuple		= dccp_invert_tuple,
8762bc78049SPatrick McHardy 	.new			= dccp_new,
8772bc78049SPatrick McHardy 	.packet			= dccp_packet,
8782c8503f5SPablo Neira Ayuso 	.get_timeouts		= dccp_get_timeouts,
8792bc78049SPatrick McHardy 	.error			= dccp_error,
8802bc78049SPatrick McHardy 	.print_tuple		= dccp_print_tuple,
8812bc78049SPatrick McHardy 	.print_conntrack	= dccp_print_conntrack,
882c0cd1156SIgor Maravić #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
8832bc78049SPatrick McHardy 	.to_nlattr		= dccp_to_nlattr,
884a400c30eSHolger Eitzenberger 	.nlattr_size		= dccp_nlattr_size,
8852bc78049SPatrick McHardy 	.from_nlattr		= nlattr_to_dccp,
8862bc78049SPatrick McHardy 	.tuple_to_nlattr	= nf_ct_port_tuple_to_nlattr,
887a400c30eSHolger Eitzenberger 	.nlattr_tuple_size	= nf_ct_port_nlattr_tuple_size,
8882bc78049SPatrick McHardy 	.nlattr_to_tuple	= nf_ct_port_nlattr_to_tuple,
8892bc78049SPatrick McHardy 	.nla_policy		= nf_ct_port_nla_policy,
8902bc78049SPatrick McHardy #endif
89150978462SPablo Neira Ayuso #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
89250978462SPablo Neira Ayuso 	.ctnl_timeout		= {
89350978462SPablo Neira Ayuso 		.nlattr_to_obj	= dccp_timeout_nlattr_to_obj,
89450978462SPablo Neira Ayuso 		.obj_to_nlattr	= dccp_timeout_obj_to_nlattr,
89550978462SPablo Neira Ayuso 		.nlattr_max	= CTA_TIMEOUT_DCCP_MAX,
89650978462SPablo Neira Ayuso 		.obj_size	= sizeof(unsigned int) * CT_DCCP_MAX,
89750978462SPablo Neira Ayuso 		.nla_policy	= dccp_timeout_nla_policy,
89850978462SPablo Neira Ayuso 	},
89950978462SPablo Neira Ayuso #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
90084c39451SGao feng 	.net_id			= &dccp_net_id,
90184c39451SGao feng 	.init_net		= dccp_init_net,
9022bc78049SPatrick McHardy };
9032bc78049SPatrick McHardy 
9042bc78049SPatrick McHardy static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = {
9052bc78049SPatrick McHardy 	.l3proto		= AF_INET6,
9062bc78049SPatrick McHardy 	.l4proto		= IPPROTO_DCCP,
9072bc78049SPatrick McHardy 	.name			= "dccp",
9082bc78049SPatrick McHardy 	.pkt_to_tuple		= dccp_pkt_to_tuple,
9092bc78049SPatrick McHardy 	.invert_tuple		= dccp_invert_tuple,
9102bc78049SPatrick McHardy 	.new			= dccp_new,
9112bc78049SPatrick McHardy 	.packet			= dccp_packet,
9122c8503f5SPablo Neira Ayuso 	.get_timeouts		= dccp_get_timeouts,
9132bc78049SPatrick McHardy 	.error			= dccp_error,
9142bc78049SPatrick McHardy 	.print_tuple		= dccp_print_tuple,
9152bc78049SPatrick McHardy 	.print_conntrack	= dccp_print_conntrack,
916c0cd1156SIgor Maravić #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
9172bc78049SPatrick McHardy 	.to_nlattr		= dccp_to_nlattr,
9185ff48294SPatrick McHardy 	.nlattr_size		= dccp_nlattr_size,
9192bc78049SPatrick McHardy 	.from_nlattr		= nlattr_to_dccp,
9202bc78049SPatrick McHardy 	.tuple_to_nlattr	= nf_ct_port_tuple_to_nlattr,
921a400c30eSHolger Eitzenberger 	.nlattr_tuple_size	= nf_ct_port_nlattr_tuple_size,
9222bc78049SPatrick McHardy 	.nlattr_to_tuple	= nf_ct_port_nlattr_to_tuple,
9232bc78049SPatrick McHardy 	.nla_policy		= nf_ct_port_nla_policy,
9242bc78049SPatrick McHardy #endif
92550978462SPablo Neira Ayuso #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
92650978462SPablo Neira Ayuso 	.ctnl_timeout		= {
92750978462SPablo Neira Ayuso 		.nlattr_to_obj	= dccp_timeout_nlattr_to_obj,
92850978462SPablo Neira Ayuso 		.obj_to_nlattr	= dccp_timeout_obj_to_nlattr,
92950978462SPablo Neira Ayuso 		.nlattr_max	= CTA_TIMEOUT_DCCP_MAX,
93050978462SPablo Neira Ayuso 		.obj_size	= sizeof(unsigned int) * CT_DCCP_MAX,
93150978462SPablo Neira Ayuso 		.nla_policy	= dccp_timeout_nla_policy,
93250978462SPablo Neira Ayuso 	},
93350978462SPablo Neira Ayuso #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
93484c39451SGao feng 	.net_id			= &dccp_net_id,
93584c39451SGao feng 	.init_net		= dccp_init_net,
9361546000fSCyrill Gorcunov };
9371546000fSCyrill Gorcunov 
9381546000fSCyrill Gorcunov static __net_init int dccp_net_init(struct net *net)
9391546000fSCyrill Gorcunov {
94084c39451SGao feng 	int ret = 0;
941c296bb4dSGao feng 	ret = nf_ct_l4proto_pernet_register(net, &dccp_proto4);
94284c39451SGao feng 	if (ret < 0) {
943c296bb4dSGao feng 		pr_err("nf_conntrack_dccp4: pernet registration failed.\n");
94484c39451SGao feng 		goto out;
9451546000fSCyrill Gorcunov 	}
946c296bb4dSGao feng 	ret = nf_ct_l4proto_pernet_register(net, &dccp_proto6);
94784c39451SGao feng 	if (ret < 0) {
948c296bb4dSGao feng 		pr_err("nf_conntrack_dccp6: pernet registration failed.\n");
94984c39451SGao feng 		goto cleanup_dccp4;
95084c39451SGao feng 	}
9511546000fSCyrill Gorcunov 	return 0;
95284c39451SGao feng cleanup_dccp4:
953c296bb4dSGao feng 	nf_ct_l4proto_pernet_unregister(net, &dccp_proto4);
95484c39451SGao feng out:
95584c39451SGao feng 	return ret;
9561546000fSCyrill Gorcunov }
9571546000fSCyrill Gorcunov 
9581546000fSCyrill Gorcunov static __net_exit void dccp_net_exit(struct net *net)
9591546000fSCyrill Gorcunov {
960c296bb4dSGao feng 	nf_ct_l4proto_pernet_unregister(net, &dccp_proto6);
961c296bb4dSGao feng 	nf_ct_l4proto_pernet_unregister(net, &dccp_proto4);
9621546000fSCyrill Gorcunov }
9631546000fSCyrill Gorcunov 
9641546000fSCyrill Gorcunov static struct pernet_operations dccp_net_ops = {
9651546000fSCyrill Gorcunov 	.init = dccp_net_init,
9661546000fSCyrill Gorcunov 	.exit = dccp_net_exit,
96732b51f92SEric W. Biederman 	.id   = &dccp_net_id,
96832b51f92SEric W. Biederman 	.size = sizeof(struct dccp_net),
9692bc78049SPatrick McHardy };
9702bc78049SPatrick McHardy 
9712bc78049SPatrick McHardy static int __init nf_conntrack_proto_dccp_init(void)
9722bc78049SPatrick McHardy {
973c296bb4dSGao feng 	int ret;
974c296bb4dSGao feng 
9750d98da5dSGao feng 	ret = register_pernet_subsys(&dccp_net_ops);
9760d98da5dSGao feng 	if (ret < 0)
9770d98da5dSGao feng 		goto out_pernet;
9780d98da5dSGao feng 
979c296bb4dSGao feng 	ret = nf_ct_l4proto_register(&dccp_proto4);
980c296bb4dSGao feng 	if (ret < 0)
981c296bb4dSGao feng 		goto out_dccp4;
982c296bb4dSGao feng 
983c296bb4dSGao feng 	ret = nf_ct_l4proto_register(&dccp_proto6);
984c296bb4dSGao feng 	if (ret < 0)
985c296bb4dSGao feng 		goto out_dccp6;
986c296bb4dSGao feng 
987c296bb4dSGao feng 	return 0;
988c296bb4dSGao feng out_dccp6:
989c296bb4dSGao feng 	nf_ct_l4proto_unregister(&dccp_proto4);
990c296bb4dSGao feng out_dccp4:
9910d98da5dSGao feng 	unregister_pernet_subsys(&dccp_net_ops);
9920d98da5dSGao feng out_pernet:
993c296bb4dSGao feng 	return ret;
9942bc78049SPatrick McHardy }
9952bc78049SPatrick McHardy 
9962bc78049SPatrick McHardy static void __exit nf_conntrack_proto_dccp_fini(void)
9972bc78049SPatrick McHardy {
998c296bb4dSGao feng 	nf_ct_l4proto_unregister(&dccp_proto6);
999c296bb4dSGao feng 	nf_ct_l4proto_unregister(&dccp_proto4);
100032b51f92SEric W. Biederman 	unregister_pernet_subsys(&dccp_net_ops);
10012bc78049SPatrick McHardy }
10022bc78049SPatrick McHardy 
10032bc78049SPatrick McHardy module_init(nf_conntrack_proto_dccp_init);
10042bc78049SPatrick McHardy module_exit(nf_conntrack_proto_dccp_fini);
10052bc78049SPatrick McHardy 
10062bc78049SPatrick McHardy MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
10072bc78049SPatrick McHardy MODULE_DESCRIPTION("DCCP connection tracking protocol helper");
10082bc78049SPatrick McHardy MODULE_LICENSE("GPL");
1009