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,
4012bc78049SPatrick McHardy 			      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 
4312bc78049SPatrick McHardy 	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,
46030e0c6a6SGao feng 			      NULL, 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 
4892bc78049SPatrick McHardy 	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 
5802bc78049SPatrick McHardy 	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))
61730e0c6a6SGao feng 		nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL, msg);
6182bc78049SPatrick McHardy 	return -NF_ACCEPT;
6192bc78049SPatrick McHardy }
6202bc78049SPatrick McHardy 
6212bc78049SPatrick McHardy static int dccp_print_tuple(struct seq_file *s,
6222bc78049SPatrick McHardy 			    const struct nf_conntrack_tuple *tuple)
6232bc78049SPatrick McHardy {
6242bc78049SPatrick McHardy 	return 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 
629440f0d58SPatrick McHardy static int dccp_print_conntrack(struct seq_file *s, struct nf_conn *ct)
6302bc78049SPatrick McHardy {
6312bc78049SPatrick McHardy 	return 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,
648516ee48fSDavid S. Miller 			 cpu_to_be64(ct->proto.dccp.handshake_seq)))
649516ee48fSDavid S. Miller 		goto nla_put_failure;
6502bc78049SPatrick McHardy 	nla_nest_end(skb, nest_parms);
651440f0d58SPatrick McHardy 	spin_unlock_bh(&ct->lock);
6522bc78049SPatrick McHardy 	return 0;
6532bc78049SPatrick McHardy 
6542bc78049SPatrick McHardy nla_put_failure:
655440f0d58SPatrick McHardy 	spin_unlock_bh(&ct->lock);
6562bc78049SPatrick McHardy 	return -1;
6572bc78049SPatrick McHardy }
6582bc78049SPatrick McHardy 
6592bc78049SPatrick McHardy static const struct nla_policy dccp_nla_policy[CTA_PROTOINFO_DCCP_MAX + 1] = {
6602bc78049SPatrick McHardy 	[CTA_PROTOINFO_DCCP_STATE]	= { .type = NLA_U8 },
66171951b64SPablo Neira Ayuso 	[CTA_PROTOINFO_DCCP_ROLE]	= { .type = NLA_U8 },
662a17c8598SPablo Neira Ayuso 	[CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ] = { .type = NLA_U64 },
6632bc78049SPatrick McHardy };
6642bc78049SPatrick McHardy 
6652bc78049SPatrick McHardy static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct)
6662bc78049SPatrick McHardy {
6672bc78049SPatrick McHardy 	struct nlattr *attr = cda[CTA_PROTOINFO_DCCP];
6682bc78049SPatrick McHardy 	struct nlattr *tb[CTA_PROTOINFO_DCCP_MAX + 1];
6692bc78049SPatrick McHardy 	int err;
6702bc78049SPatrick McHardy 
6712bc78049SPatrick McHardy 	if (!attr)
6722bc78049SPatrick McHardy 		return 0;
6732bc78049SPatrick McHardy 
6742bc78049SPatrick McHardy 	err = nla_parse_nested(tb, CTA_PROTOINFO_DCCP_MAX, attr,
6752bc78049SPatrick McHardy 			       dccp_nla_policy);
6762bc78049SPatrick McHardy 	if (err < 0)
6772bc78049SPatrick McHardy 		return err;
6782bc78049SPatrick McHardy 
6792bc78049SPatrick McHardy 	if (!tb[CTA_PROTOINFO_DCCP_STATE] ||
68071951b64SPablo Neira Ayuso 	    !tb[CTA_PROTOINFO_DCCP_ROLE] ||
68171951b64SPablo Neira Ayuso 	    nla_get_u8(tb[CTA_PROTOINFO_DCCP_ROLE]) > CT_DCCP_ROLE_MAX ||
68271951b64SPablo Neira Ayuso 	    nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]) >= CT_DCCP_IGNORE) {
6832bc78049SPatrick McHardy 		return -EINVAL;
68471951b64SPablo Neira Ayuso 	}
6852bc78049SPatrick McHardy 
686440f0d58SPatrick McHardy 	spin_lock_bh(&ct->lock);
6872bc78049SPatrick McHardy 	ct->proto.dccp.state = nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]);
68871951b64SPablo Neira Ayuso 	if (nla_get_u8(tb[CTA_PROTOINFO_DCCP_ROLE]) == CT_DCCP_ROLE_CLIENT) {
68971951b64SPablo Neira Ayuso 		ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_CLIENT;
69071951b64SPablo Neira Ayuso 		ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_SERVER;
69171951b64SPablo Neira Ayuso 	} else {
69271951b64SPablo Neira Ayuso 		ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_SERVER;
69371951b64SPablo Neira Ayuso 		ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_CLIENT;
69471951b64SPablo Neira Ayuso 	}
695a17c8598SPablo Neira Ayuso 	if (tb[CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ]) {
696a17c8598SPablo Neira Ayuso 		ct->proto.dccp.handshake_seq =
697a17c8598SPablo Neira Ayuso 		be64_to_cpu(nla_get_be64(tb[CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ]));
698a17c8598SPablo Neira Ayuso 	}
699440f0d58SPatrick McHardy 	spin_unlock_bh(&ct->lock);
7002bc78049SPatrick McHardy 	return 0;
7012bc78049SPatrick McHardy }
702a400c30eSHolger Eitzenberger 
703a400c30eSHolger Eitzenberger static int dccp_nlattr_size(void)
704a400c30eSHolger Eitzenberger {
705a400c30eSHolger Eitzenberger 	return nla_total_size(0)	/* CTA_PROTOINFO_DCCP */
706a400c30eSHolger Eitzenberger 		+ nla_policy_len(dccp_nla_policy, CTA_PROTOINFO_DCCP_MAX + 1);
707a400c30eSHolger Eitzenberger }
70850978462SPablo Neira Ayuso 
7092bc78049SPatrick McHardy #endif
7102bc78049SPatrick McHardy 
71150978462SPablo Neira Ayuso #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
71250978462SPablo Neira Ayuso 
71350978462SPablo Neira Ayuso #include <linux/netfilter/nfnetlink.h>
71450978462SPablo Neira Ayuso #include <linux/netfilter/nfnetlink_cttimeout.h>
71550978462SPablo Neira Ayuso 
7168264deb8SGao feng static int dccp_timeout_nlattr_to_obj(struct nlattr *tb[],
7178264deb8SGao feng 				      struct net *net, void *data)
71850978462SPablo Neira Ayuso {
7198264deb8SGao feng 	struct dccp_net *dn = dccp_pernet(net);
72050978462SPablo Neira Ayuso 	unsigned int *timeouts = data;
72150978462SPablo Neira Ayuso 	int i;
72250978462SPablo Neira Ayuso 
72350978462SPablo Neira Ayuso 	/* set default DCCP timeouts. */
72450978462SPablo Neira Ayuso 	for (i=0; i<CT_DCCP_MAX; i++)
72550978462SPablo Neira Ayuso 		timeouts[i] = dn->dccp_timeout[i];
72650978462SPablo Neira Ayuso 
72750978462SPablo Neira Ayuso 	/* there's a 1:1 mapping between attributes and protocol states. */
72850978462SPablo Neira Ayuso 	for (i=CTA_TIMEOUT_DCCP_UNSPEC+1; i<CTA_TIMEOUT_DCCP_MAX+1; i++) {
72950978462SPablo Neira Ayuso 		if (tb[i]) {
73050978462SPablo Neira Ayuso 			timeouts[i] = ntohl(nla_get_be32(tb[i])) * HZ;
73150978462SPablo Neira Ayuso 		}
73250978462SPablo Neira Ayuso 	}
73350978462SPablo Neira Ayuso 	return 0;
73450978462SPablo Neira Ayuso }
73550978462SPablo Neira Ayuso 
73650978462SPablo Neira Ayuso static int
73750978462SPablo Neira Ayuso dccp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
73850978462SPablo Neira Ayuso {
73950978462SPablo Neira Ayuso         const unsigned int *timeouts = data;
74050978462SPablo Neira Ayuso 	int i;
74150978462SPablo Neira Ayuso 
742516ee48fSDavid S. Miller 	for (i=CTA_TIMEOUT_DCCP_UNSPEC+1; i<CTA_TIMEOUT_DCCP_MAX+1; i++) {
743516ee48fSDavid S. Miller 		if (nla_put_be32(skb, i, htonl(timeouts[i] / HZ)))
744516ee48fSDavid S. Miller 			goto nla_put_failure;
745516ee48fSDavid S. Miller 	}
74650978462SPablo Neira Ayuso 	return 0;
74750978462SPablo Neira Ayuso 
74850978462SPablo Neira Ayuso nla_put_failure:
74950978462SPablo Neira Ayuso 	return -ENOSPC;
75050978462SPablo Neira Ayuso }
75150978462SPablo Neira Ayuso 
75250978462SPablo Neira Ayuso static const struct nla_policy
75350978462SPablo Neira Ayuso dccp_timeout_nla_policy[CTA_TIMEOUT_DCCP_MAX+1] = {
75450978462SPablo Neira Ayuso 	[CTA_TIMEOUT_DCCP_REQUEST]	= { .type = NLA_U32 },
75550978462SPablo Neira Ayuso 	[CTA_TIMEOUT_DCCP_RESPOND]	= { .type = NLA_U32 },
75650978462SPablo Neira Ayuso 	[CTA_TIMEOUT_DCCP_PARTOPEN]	= { .type = NLA_U32 },
75750978462SPablo Neira Ayuso 	[CTA_TIMEOUT_DCCP_OPEN]		= { .type = NLA_U32 },
75850978462SPablo Neira Ayuso 	[CTA_TIMEOUT_DCCP_CLOSEREQ]	= { .type = NLA_U32 },
75950978462SPablo Neira Ayuso 	[CTA_TIMEOUT_DCCP_CLOSING]	= { .type = NLA_U32 },
76050978462SPablo Neira Ayuso 	[CTA_TIMEOUT_DCCP_TIMEWAIT]	= { .type = NLA_U32 },
76150978462SPablo Neira Ayuso };
76250978462SPablo Neira Ayuso #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
76350978462SPablo Neira Ayuso 
7642bc78049SPatrick McHardy #ifdef CONFIG_SYSCTL
7651546000fSCyrill Gorcunov /* template, data assigned later */
7661546000fSCyrill Gorcunov static struct ctl_table dccp_sysctl_table[] = {
7672bc78049SPatrick McHardy 	{
7682bc78049SPatrick McHardy 		.procname	= "nf_conntrack_dccp_timeout_request",
7692bc78049SPatrick McHardy 		.maxlen		= sizeof(unsigned int),
7702bc78049SPatrick McHardy 		.mode		= 0644,
7712bc78049SPatrick McHardy 		.proc_handler	= proc_dointvec_jiffies,
7722bc78049SPatrick McHardy 	},
7732bc78049SPatrick McHardy 	{
7742bc78049SPatrick McHardy 		.procname	= "nf_conntrack_dccp_timeout_respond",
7752bc78049SPatrick McHardy 		.maxlen		= sizeof(unsigned int),
7762bc78049SPatrick McHardy 		.mode		= 0644,
7772bc78049SPatrick McHardy 		.proc_handler	= proc_dointvec_jiffies,
7782bc78049SPatrick McHardy 	},
7792bc78049SPatrick McHardy 	{
7802bc78049SPatrick McHardy 		.procname	= "nf_conntrack_dccp_timeout_partopen",
7812bc78049SPatrick McHardy 		.maxlen		= sizeof(unsigned int),
7822bc78049SPatrick McHardy 		.mode		= 0644,
7832bc78049SPatrick McHardy 		.proc_handler	= proc_dointvec_jiffies,
7842bc78049SPatrick McHardy 	},
7852bc78049SPatrick McHardy 	{
7862bc78049SPatrick McHardy 		.procname	= "nf_conntrack_dccp_timeout_open",
7872bc78049SPatrick McHardy 		.maxlen		= sizeof(unsigned int),
7882bc78049SPatrick McHardy 		.mode		= 0644,
7892bc78049SPatrick McHardy 		.proc_handler	= proc_dointvec_jiffies,
7902bc78049SPatrick McHardy 	},
7912bc78049SPatrick McHardy 	{
7922bc78049SPatrick McHardy 		.procname	= "nf_conntrack_dccp_timeout_closereq",
7932bc78049SPatrick McHardy 		.maxlen		= sizeof(unsigned int),
7942bc78049SPatrick McHardy 		.mode		= 0644,
7952bc78049SPatrick McHardy 		.proc_handler	= proc_dointvec_jiffies,
7962bc78049SPatrick McHardy 	},
7972bc78049SPatrick McHardy 	{
7982bc78049SPatrick McHardy 		.procname	= "nf_conntrack_dccp_timeout_closing",
7992bc78049SPatrick McHardy 		.maxlen		= sizeof(unsigned int),
8002bc78049SPatrick McHardy 		.mode		= 0644,
8012bc78049SPatrick McHardy 		.proc_handler	= proc_dointvec_jiffies,
8022bc78049SPatrick McHardy 	},
8032bc78049SPatrick McHardy 	{
8042bc78049SPatrick McHardy 		.procname	= "nf_conntrack_dccp_timeout_timewait",
8052bc78049SPatrick McHardy 		.maxlen		= sizeof(unsigned int),
8062bc78049SPatrick McHardy 		.mode		= 0644,
8072bc78049SPatrick McHardy 		.proc_handler	= proc_dointvec_jiffies,
8082bc78049SPatrick McHardy 	},
8092bc78049SPatrick McHardy 	{
8102bc78049SPatrick McHardy 		.procname	= "nf_conntrack_dccp_loose",
8111546000fSCyrill Gorcunov 		.maxlen		= sizeof(int),
8122bc78049SPatrick McHardy 		.mode		= 0644,
8132bc78049SPatrick McHardy 		.proc_handler	= proc_dointvec,
8142bc78049SPatrick McHardy 	},
815f8572d8fSEric W. Biederman 	{ }
8162bc78049SPatrick McHardy };
8172bc78049SPatrick McHardy #endif /* CONFIG_SYSCTL */
8182bc78049SPatrick McHardy 
819464dc801SEric W. Biederman static int dccp_kmemdup_sysctl_table(struct net *net, struct nf_proto_net *pn,
82054b8873fSGao feng 				     struct dccp_net *dn)
82184c39451SGao feng {
82254b8873fSGao feng #ifdef CONFIG_SYSCTL
82354b8873fSGao feng 	if (pn->ctl_table)
82454b8873fSGao feng 		return 0;
82584c39451SGao feng 
82684c39451SGao feng 	pn->ctl_table = kmemdup(dccp_sysctl_table,
82784c39451SGao feng 				sizeof(dccp_sysctl_table),
82884c39451SGao feng 				GFP_KERNEL);
82984c39451SGao feng 	if (!pn->ctl_table)
83084c39451SGao feng 		return -ENOMEM;
83184c39451SGao feng 
83284c39451SGao feng 	pn->ctl_table[0].data = &dn->dccp_timeout[CT_DCCP_REQUEST];
83384c39451SGao feng 	pn->ctl_table[1].data = &dn->dccp_timeout[CT_DCCP_RESPOND];
83484c39451SGao feng 	pn->ctl_table[2].data = &dn->dccp_timeout[CT_DCCP_PARTOPEN];
83584c39451SGao feng 	pn->ctl_table[3].data = &dn->dccp_timeout[CT_DCCP_OPEN];
83684c39451SGao feng 	pn->ctl_table[4].data = &dn->dccp_timeout[CT_DCCP_CLOSEREQ];
83784c39451SGao feng 	pn->ctl_table[5].data = &dn->dccp_timeout[CT_DCCP_CLOSING];
83884c39451SGao feng 	pn->ctl_table[6].data = &dn->dccp_timeout[CT_DCCP_TIMEWAIT];
83984c39451SGao feng 	pn->ctl_table[7].data = &dn->dccp_loose;
840464dc801SEric W. Biederman 
841464dc801SEric W. Biederman 	/* Don't export sysctls to unprivileged users */
842464dc801SEric W. Biederman 	if (net->user_ns != &init_user_ns)
843464dc801SEric W. Biederman 		pn->ctl_table[0].procname = NULL;
84484c39451SGao feng #endif
84584c39451SGao feng 	return 0;
84684c39451SGao feng }
84784c39451SGao feng 
84854b8873fSGao feng static int dccp_init_net(struct net *net, u_int16_t proto)
84954b8873fSGao feng {
85054b8873fSGao feng 	struct dccp_net *dn = dccp_pernet(net);
85154b8873fSGao feng 	struct nf_proto_net *pn = &dn->pn;
85254b8873fSGao feng 
85354b8873fSGao feng 	if (!pn->users) {
85454b8873fSGao feng 		/* default values */
85554b8873fSGao feng 		dn->dccp_loose = 1;
85654b8873fSGao feng 		dn->dccp_timeout[CT_DCCP_REQUEST]	= 2 * DCCP_MSL;
85754b8873fSGao feng 		dn->dccp_timeout[CT_DCCP_RESPOND]	= 4 * DCCP_MSL;
85854b8873fSGao feng 		dn->dccp_timeout[CT_DCCP_PARTOPEN]	= 4 * DCCP_MSL;
85954b8873fSGao feng 		dn->dccp_timeout[CT_DCCP_OPEN]		= 12 * 3600 * HZ;
86054b8873fSGao feng 		dn->dccp_timeout[CT_DCCP_CLOSEREQ]	= 64 * HZ;
86154b8873fSGao feng 		dn->dccp_timeout[CT_DCCP_CLOSING]	= 64 * HZ;
86254b8873fSGao feng 		dn->dccp_timeout[CT_DCCP_TIMEWAIT]	= 2 * DCCP_MSL;
86354b8873fSGao feng 	}
86454b8873fSGao feng 
865464dc801SEric W. Biederman 	return dccp_kmemdup_sysctl_table(net, pn, dn);
86654b8873fSGao feng }
86754b8873fSGao feng 
8682bc78049SPatrick McHardy static struct nf_conntrack_l4proto dccp_proto4 __read_mostly = {
8692bc78049SPatrick McHardy 	.l3proto		= AF_INET,
8702bc78049SPatrick McHardy 	.l4proto		= IPPROTO_DCCP,
8712bc78049SPatrick McHardy 	.name			= "dccp",
8722bc78049SPatrick McHardy 	.pkt_to_tuple		= dccp_pkt_to_tuple,
8732bc78049SPatrick McHardy 	.invert_tuple		= dccp_invert_tuple,
8742bc78049SPatrick McHardy 	.new			= dccp_new,
8752bc78049SPatrick McHardy 	.packet			= dccp_packet,
8762c8503f5SPablo Neira Ayuso 	.get_timeouts		= dccp_get_timeouts,
8772bc78049SPatrick McHardy 	.error			= dccp_error,
8782bc78049SPatrick McHardy 	.print_tuple		= dccp_print_tuple,
8792bc78049SPatrick McHardy 	.print_conntrack	= dccp_print_conntrack,
880c0cd1156SIgor Maravić #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
8812bc78049SPatrick McHardy 	.to_nlattr		= dccp_to_nlattr,
882a400c30eSHolger Eitzenberger 	.nlattr_size		= dccp_nlattr_size,
8832bc78049SPatrick McHardy 	.from_nlattr		= nlattr_to_dccp,
8842bc78049SPatrick McHardy 	.tuple_to_nlattr	= nf_ct_port_tuple_to_nlattr,
885a400c30eSHolger Eitzenberger 	.nlattr_tuple_size	= nf_ct_port_nlattr_tuple_size,
8862bc78049SPatrick McHardy 	.nlattr_to_tuple	= nf_ct_port_nlattr_to_tuple,
8872bc78049SPatrick McHardy 	.nla_policy		= nf_ct_port_nla_policy,
8882bc78049SPatrick McHardy #endif
88950978462SPablo Neira Ayuso #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
89050978462SPablo Neira Ayuso 	.ctnl_timeout		= {
89150978462SPablo Neira Ayuso 		.nlattr_to_obj	= dccp_timeout_nlattr_to_obj,
89250978462SPablo Neira Ayuso 		.obj_to_nlattr	= dccp_timeout_obj_to_nlattr,
89350978462SPablo Neira Ayuso 		.nlattr_max	= CTA_TIMEOUT_DCCP_MAX,
89450978462SPablo Neira Ayuso 		.obj_size	= sizeof(unsigned int) * CT_DCCP_MAX,
89550978462SPablo Neira Ayuso 		.nla_policy	= dccp_timeout_nla_policy,
89650978462SPablo Neira Ayuso 	},
89750978462SPablo Neira Ayuso #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
89884c39451SGao feng 	.net_id			= &dccp_net_id,
89984c39451SGao feng 	.init_net		= dccp_init_net,
9002bc78049SPatrick McHardy };
9012bc78049SPatrick McHardy 
9022bc78049SPatrick McHardy static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = {
9032bc78049SPatrick McHardy 	.l3proto		= AF_INET6,
9042bc78049SPatrick McHardy 	.l4proto		= IPPROTO_DCCP,
9052bc78049SPatrick McHardy 	.name			= "dccp",
9062bc78049SPatrick McHardy 	.pkt_to_tuple		= dccp_pkt_to_tuple,
9072bc78049SPatrick McHardy 	.invert_tuple		= dccp_invert_tuple,
9082bc78049SPatrick McHardy 	.new			= dccp_new,
9092bc78049SPatrick McHardy 	.packet			= dccp_packet,
9102c8503f5SPablo Neira Ayuso 	.get_timeouts		= dccp_get_timeouts,
9112bc78049SPatrick McHardy 	.error			= dccp_error,
9122bc78049SPatrick McHardy 	.print_tuple		= dccp_print_tuple,
9132bc78049SPatrick McHardy 	.print_conntrack	= dccp_print_conntrack,
914c0cd1156SIgor Maravić #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
9152bc78049SPatrick McHardy 	.to_nlattr		= dccp_to_nlattr,
9165ff48294SPatrick McHardy 	.nlattr_size		= dccp_nlattr_size,
9172bc78049SPatrick McHardy 	.from_nlattr		= nlattr_to_dccp,
9182bc78049SPatrick McHardy 	.tuple_to_nlattr	= nf_ct_port_tuple_to_nlattr,
919a400c30eSHolger Eitzenberger 	.nlattr_tuple_size	= nf_ct_port_nlattr_tuple_size,
9202bc78049SPatrick McHardy 	.nlattr_to_tuple	= nf_ct_port_nlattr_to_tuple,
9212bc78049SPatrick McHardy 	.nla_policy		= nf_ct_port_nla_policy,
9222bc78049SPatrick McHardy #endif
92350978462SPablo Neira Ayuso #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
92450978462SPablo Neira Ayuso 	.ctnl_timeout		= {
92550978462SPablo Neira Ayuso 		.nlattr_to_obj	= dccp_timeout_nlattr_to_obj,
92650978462SPablo Neira Ayuso 		.obj_to_nlattr	= dccp_timeout_obj_to_nlattr,
92750978462SPablo Neira Ayuso 		.nlattr_max	= CTA_TIMEOUT_DCCP_MAX,
92850978462SPablo Neira Ayuso 		.obj_size	= sizeof(unsigned int) * CT_DCCP_MAX,
92950978462SPablo Neira Ayuso 		.nla_policy	= dccp_timeout_nla_policy,
93050978462SPablo Neira Ayuso 	},
93150978462SPablo Neira Ayuso #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
93284c39451SGao feng 	.net_id			= &dccp_net_id,
93384c39451SGao feng 	.init_net		= dccp_init_net,
9341546000fSCyrill Gorcunov };
9351546000fSCyrill Gorcunov 
9361546000fSCyrill Gorcunov static __net_init int dccp_net_init(struct net *net)
9371546000fSCyrill Gorcunov {
93884c39451SGao feng 	int ret = 0;
939c296bb4dSGao feng 	ret = nf_ct_l4proto_pernet_register(net, &dccp_proto4);
94084c39451SGao feng 	if (ret < 0) {
941c296bb4dSGao feng 		pr_err("nf_conntrack_dccp4: pernet registration failed.\n");
94284c39451SGao feng 		goto out;
9431546000fSCyrill Gorcunov 	}
944c296bb4dSGao feng 	ret = nf_ct_l4proto_pernet_register(net, &dccp_proto6);
94584c39451SGao feng 	if (ret < 0) {
946c296bb4dSGao feng 		pr_err("nf_conntrack_dccp6: pernet registration failed.\n");
94784c39451SGao feng 		goto cleanup_dccp4;
94884c39451SGao feng 	}
9491546000fSCyrill Gorcunov 	return 0;
95084c39451SGao feng cleanup_dccp4:
951c296bb4dSGao feng 	nf_ct_l4proto_pernet_unregister(net, &dccp_proto4);
95284c39451SGao feng out:
95384c39451SGao feng 	return ret;
9541546000fSCyrill Gorcunov }
9551546000fSCyrill Gorcunov 
9561546000fSCyrill Gorcunov static __net_exit void dccp_net_exit(struct net *net)
9571546000fSCyrill Gorcunov {
958c296bb4dSGao feng 	nf_ct_l4proto_pernet_unregister(net, &dccp_proto6);
959c296bb4dSGao feng 	nf_ct_l4proto_pernet_unregister(net, &dccp_proto4);
9601546000fSCyrill Gorcunov }
9611546000fSCyrill Gorcunov 
9621546000fSCyrill Gorcunov static struct pernet_operations dccp_net_ops = {
9631546000fSCyrill Gorcunov 	.init = dccp_net_init,
9641546000fSCyrill Gorcunov 	.exit = dccp_net_exit,
96532b51f92SEric W. Biederman 	.id   = &dccp_net_id,
96632b51f92SEric W. Biederman 	.size = sizeof(struct dccp_net),
9672bc78049SPatrick McHardy };
9682bc78049SPatrick McHardy 
9692bc78049SPatrick McHardy static int __init nf_conntrack_proto_dccp_init(void)
9702bc78049SPatrick McHardy {
971c296bb4dSGao feng 	int ret;
972c296bb4dSGao feng 
9730d98da5dSGao feng 	ret = register_pernet_subsys(&dccp_net_ops);
9740d98da5dSGao feng 	if (ret < 0)
9750d98da5dSGao feng 		goto out_pernet;
9760d98da5dSGao feng 
977c296bb4dSGao feng 	ret = nf_ct_l4proto_register(&dccp_proto4);
978c296bb4dSGao feng 	if (ret < 0)
979c296bb4dSGao feng 		goto out_dccp4;
980c296bb4dSGao feng 
981c296bb4dSGao feng 	ret = nf_ct_l4proto_register(&dccp_proto6);
982c296bb4dSGao feng 	if (ret < 0)
983c296bb4dSGao feng 		goto out_dccp6;
984c296bb4dSGao feng 
985c296bb4dSGao feng 	return 0;
986c296bb4dSGao feng out_dccp6:
987c296bb4dSGao feng 	nf_ct_l4proto_unregister(&dccp_proto4);
988c296bb4dSGao feng out_dccp4:
9890d98da5dSGao feng 	unregister_pernet_subsys(&dccp_net_ops);
9900d98da5dSGao feng out_pernet:
991c296bb4dSGao feng 	return ret;
9922bc78049SPatrick McHardy }
9932bc78049SPatrick McHardy 
9942bc78049SPatrick McHardy static void __exit nf_conntrack_proto_dccp_fini(void)
9952bc78049SPatrick McHardy {
996c296bb4dSGao feng 	nf_ct_l4proto_unregister(&dccp_proto6);
997c296bb4dSGao feng 	nf_ct_l4proto_unregister(&dccp_proto4);
99832b51f92SEric W. Biederman 	unregister_pernet_subsys(&dccp_net_ops);
9992bc78049SPatrick McHardy }
10002bc78049SPatrick McHardy 
10012bc78049SPatrick McHardy module_init(nf_conntrack_proto_dccp_init);
10022bc78049SPatrick McHardy module_exit(nf_conntrack_proto_dccp_fini);
10032bc78049SPatrick McHardy 
10042bc78049SPatrick McHardy MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
10052bc78049SPatrick McHardy MODULE_DESCRIPTION("DCCP connection tracking protocol helper");
10062bc78049SPatrick McHardy MODULE_LICENSE("GPL");
1007