162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci#ifndef _CCID_H
362306a36Sopenharmony_ci#define _CCID_H
462306a36Sopenharmony_ci/*
562306a36Sopenharmony_ci *  net/dccp/ccid.h
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *  An implementation of the DCCP protocol
862306a36Sopenharmony_ci *  Arnaldo Carvalho de Melo <acme@conectiva.com.br>
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci *  CCID infrastructure
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <net/sock.h>
1462306a36Sopenharmony_ci#include <linux/compiler.h>
1562306a36Sopenharmony_ci#include <linux/dccp.h>
1662306a36Sopenharmony_ci#include <linux/list.h>
1762306a36Sopenharmony_ci#include <linux/module.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/* maximum value for a CCID (RFC 4340, 19.5) */
2062306a36Sopenharmony_ci#define CCID_MAX		255
2162306a36Sopenharmony_ci#define CCID_SLAB_NAME_LENGTH	32
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistruct tcp_info;
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/**
2662306a36Sopenharmony_ci *  struct ccid_operations  -  Interface to Congestion-Control Infrastructure
2762306a36Sopenharmony_ci *
2862306a36Sopenharmony_ci *  @ccid_id: numerical CCID ID (up to %CCID_MAX, cf. table 5 in RFC 4340, 10.)
2962306a36Sopenharmony_ci *  @ccid_ccmps: the CCMPS including network/transport headers (0 when disabled)
3062306a36Sopenharmony_ci *  @ccid_name: alphabetical identifier string for @ccid_id
3162306a36Sopenharmony_ci *  @ccid_hc_{r,t}x_slab: memory pool for the receiver/sender half-connection
3262306a36Sopenharmony_ci *  @ccid_hc_{r,t}x_obj_size: size of the receiver/sender half-connection socket
3362306a36Sopenharmony_ci *
3462306a36Sopenharmony_ci *  @ccid_hc_{r,t}x_init: CCID-specific initialisation routine (before startup)
3562306a36Sopenharmony_ci *  @ccid_hc_{r,t}x_exit: CCID-specific cleanup routine (before destruction)
3662306a36Sopenharmony_ci *  @ccid_hc_rx_packet_recv: implements the HC-receiver side
3762306a36Sopenharmony_ci *  @ccid_hc_{r,t}x_parse_options: parsing routine for CCID/HC-specific options
3862306a36Sopenharmony_ci *  @ccid_hc_{r,t}x_insert_options: insert routine for CCID/HC-specific options
3962306a36Sopenharmony_ci *  @ccid_hc_tx_packet_recv: implements feedback processing for the HC-sender
4062306a36Sopenharmony_ci *  @ccid_hc_tx_send_packet: implements the sending part of the HC-sender
4162306a36Sopenharmony_ci *  @ccid_hc_tx_packet_sent: does accounting for packets in flight by HC-sender
4262306a36Sopenharmony_ci *  @ccid_hc_{r,t}x_get_info: INET_DIAG information for HC-receiver/sender
4362306a36Sopenharmony_ci *  @ccid_hc_{r,t}x_getsockopt: socket options specific to HC-receiver/sender
4462306a36Sopenharmony_ci */
4562306a36Sopenharmony_cistruct ccid_operations {
4662306a36Sopenharmony_ci	unsigned char		ccid_id;
4762306a36Sopenharmony_ci	__u32			ccid_ccmps;
4862306a36Sopenharmony_ci	const char		*ccid_name;
4962306a36Sopenharmony_ci	struct kmem_cache	*ccid_hc_rx_slab,
5062306a36Sopenharmony_ci				*ccid_hc_tx_slab;
5162306a36Sopenharmony_ci	char			ccid_hc_rx_slab_name[CCID_SLAB_NAME_LENGTH];
5262306a36Sopenharmony_ci	char			ccid_hc_tx_slab_name[CCID_SLAB_NAME_LENGTH];
5362306a36Sopenharmony_ci	__u32			ccid_hc_rx_obj_size,
5462306a36Sopenharmony_ci				ccid_hc_tx_obj_size;
5562306a36Sopenharmony_ci	/* Interface Routines */
5662306a36Sopenharmony_ci	int		(*ccid_hc_rx_init)(struct ccid *ccid, struct sock *sk);
5762306a36Sopenharmony_ci	int		(*ccid_hc_tx_init)(struct ccid *ccid, struct sock *sk);
5862306a36Sopenharmony_ci	void		(*ccid_hc_rx_exit)(struct sock *sk);
5962306a36Sopenharmony_ci	void		(*ccid_hc_tx_exit)(struct sock *sk);
6062306a36Sopenharmony_ci	void		(*ccid_hc_rx_packet_recv)(struct sock *sk,
6162306a36Sopenharmony_ci						  struct sk_buff *skb);
6262306a36Sopenharmony_ci	int		(*ccid_hc_rx_parse_options)(struct sock *sk, u8 pkt,
6362306a36Sopenharmony_ci						    u8 opt, u8 *val, u8 len);
6462306a36Sopenharmony_ci	int		(*ccid_hc_rx_insert_options)(struct sock *sk,
6562306a36Sopenharmony_ci						     struct sk_buff *skb);
6662306a36Sopenharmony_ci	void		(*ccid_hc_tx_packet_recv)(struct sock *sk,
6762306a36Sopenharmony_ci						  struct sk_buff *skb);
6862306a36Sopenharmony_ci	int		(*ccid_hc_tx_parse_options)(struct sock *sk, u8 pkt,
6962306a36Sopenharmony_ci						    u8 opt, u8 *val, u8 len);
7062306a36Sopenharmony_ci	int		(*ccid_hc_tx_send_packet)(struct sock *sk,
7162306a36Sopenharmony_ci						  struct sk_buff *skb);
7262306a36Sopenharmony_ci	void		(*ccid_hc_tx_packet_sent)(struct sock *sk,
7362306a36Sopenharmony_ci						  unsigned int len);
7462306a36Sopenharmony_ci	void		(*ccid_hc_rx_get_info)(struct sock *sk,
7562306a36Sopenharmony_ci					       struct tcp_info *info);
7662306a36Sopenharmony_ci	void		(*ccid_hc_tx_get_info)(struct sock *sk,
7762306a36Sopenharmony_ci					       struct tcp_info *info);
7862306a36Sopenharmony_ci	int		(*ccid_hc_rx_getsockopt)(struct sock *sk,
7962306a36Sopenharmony_ci						 const int optname, int len,
8062306a36Sopenharmony_ci						 u32 __user *optval,
8162306a36Sopenharmony_ci						 int __user *optlen);
8262306a36Sopenharmony_ci	int		(*ccid_hc_tx_getsockopt)(struct sock *sk,
8362306a36Sopenharmony_ci						 const int optname, int len,
8462306a36Sopenharmony_ci						 u32 __user *optval,
8562306a36Sopenharmony_ci						 int __user *optlen);
8662306a36Sopenharmony_ci};
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ciextern struct ccid_operations ccid2_ops;
8962306a36Sopenharmony_ci#ifdef CONFIG_IP_DCCP_CCID3
9062306a36Sopenharmony_ciextern struct ccid_operations ccid3_ops;
9162306a36Sopenharmony_ci#endif
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ciint ccid_initialize_builtins(void);
9462306a36Sopenharmony_civoid ccid_cleanup_builtins(void);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistruct ccid {
9762306a36Sopenharmony_ci	struct ccid_operations *ccid_ops;
9862306a36Sopenharmony_ci	char		       ccid_priv[];
9962306a36Sopenharmony_ci};
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistatic inline void *ccid_priv(const struct ccid *ccid)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	return (void *)ccid->ccid_priv;
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cibool ccid_support_check(u8 const *ccid_array, u8 array_len);
10762306a36Sopenharmony_ciint ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len);
10862306a36Sopenharmony_ciint ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
10962306a36Sopenharmony_ci				  char __user *, int __user *);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistruct ccid *ccid_new(const u8 id, struct sock *sk, bool rx);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistatic inline int ccid_get_current_rx_ccid(struct dccp_sock *dp)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	struct ccid *ccid = dp->dccps_hc_rx_ccid;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	if (ccid == NULL || ccid->ccid_ops == NULL)
11862306a36Sopenharmony_ci		return -1;
11962306a36Sopenharmony_ci	return ccid->ccid_ops->ccid_id;
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic inline int ccid_get_current_tx_ccid(struct dccp_sock *dp)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	struct ccid *ccid = dp->dccps_hc_tx_ccid;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	if (ccid == NULL || ccid->ccid_ops == NULL)
12762306a36Sopenharmony_ci		return -1;
12862306a36Sopenharmony_ci	return ccid->ccid_ops->ccid_id;
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_civoid ccid_hc_rx_delete(struct ccid *ccid, struct sock *sk);
13262306a36Sopenharmony_civoid ccid_hc_tx_delete(struct ccid *ccid, struct sock *sk);
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci/*
13562306a36Sopenharmony_ci * Congestion control of queued data packets via CCID decision.
13662306a36Sopenharmony_ci *
13762306a36Sopenharmony_ci * The TX CCID performs its congestion-control by indicating whether and when a
13862306a36Sopenharmony_ci * queued packet may be sent, using the return code of ccid_hc_tx_send_packet().
13962306a36Sopenharmony_ci * The following modes are supported via the symbolic constants below:
14062306a36Sopenharmony_ci * - timer-based pacing    (CCID returns a delay value in milliseconds);
14162306a36Sopenharmony_ci * - autonomous dequeueing (CCID internally schedules dccps_xmitlet).
14262306a36Sopenharmony_ci */
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cienum ccid_dequeueing_decision {
14562306a36Sopenharmony_ci	CCID_PACKET_SEND_AT_ONCE =	 0x00000,  /* "green light": no delay */
14662306a36Sopenharmony_ci	CCID_PACKET_DELAY_MAX =		 0x0FFFF,  /* maximum delay in msecs  */
14762306a36Sopenharmony_ci	CCID_PACKET_DELAY =		 0x10000,  /* CCID msec-delay mode */
14862306a36Sopenharmony_ci	CCID_PACKET_WILL_DEQUEUE_LATER = 0x20000,  /* CCID autonomous mode */
14962306a36Sopenharmony_ci	CCID_PACKET_ERR =		 0xF0000,  /* error condition */
15062306a36Sopenharmony_ci};
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic inline int ccid_packet_dequeue_eval(const int return_code)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	if (return_code < 0)
15562306a36Sopenharmony_ci		return CCID_PACKET_ERR;
15662306a36Sopenharmony_ci	if (return_code == 0)
15762306a36Sopenharmony_ci		return CCID_PACKET_SEND_AT_ONCE;
15862306a36Sopenharmony_ci	if (return_code <= CCID_PACKET_DELAY_MAX)
15962306a36Sopenharmony_ci		return CCID_PACKET_DELAY;
16062306a36Sopenharmony_ci	return return_code;
16162306a36Sopenharmony_ci}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cistatic inline int ccid_hc_tx_send_packet(struct ccid *ccid, struct sock *sk,
16462306a36Sopenharmony_ci					 struct sk_buff *skb)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	if (ccid->ccid_ops->ccid_hc_tx_send_packet != NULL)
16762306a36Sopenharmony_ci		return ccid->ccid_ops->ccid_hc_tx_send_packet(sk, skb);
16862306a36Sopenharmony_ci	return CCID_PACKET_SEND_AT_ONCE;
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cistatic inline void ccid_hc_tx_packet_sent(struct ccid *ccid, struct sock *sk,
17262306a36Sopenharmony_ci					  unsigned int len)
17362306a36Sopenharmony_ci{
17462306a36Sopenharmony_ci	if (ccid->ccid_ops->ccid_hc_tx_packet_sent != NULL)
17562306a36Sopenharmony_ci		ccid->ccid_ops->ccid_hc_tx_packet_sent(sk, len);
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_cistatic inline void ccid_hc_rx_packet_recv(struct ccid *ccid, struct sock *sk,
17962306a36Sopenharmony_ci					  struct sk_buff *skb)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	if (ccid->ccid_ops->ccid_hc_rx_packet_recv != NULL)
18262306a36Sopenharmony_ci		ccid->ccid_ops->ccid_hc_rx_packet_recv(sk, skb);
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistatic inline void ccid_hc_tx_packet_recv(struct ccid *ccid, struct sock *sk,
18662306a36Sopenharmony_ci					  struct sk_buff *skb)
18762306a36Sopenharmony_ci{
18862306a36Sopenharmony_ci	if (ccid->ccid_ops->ccid_hc_tx_packet_recv != NULL)
18962306a36Sopenharmony_ci		ccid->ccid_ops->ccid_hc_tx_packet_recv(sk, skb);
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci/**
19362306a36Sopenharmony_ci * ccid_hc_tx_parse_options  -  Parse CCID-specific options sent by the receiver
19462306a36Sopenharmony_ci * @pkt: type of packet that @opt appears on (RFC 4340, 5.1)
19562306a36Sopenharmony_ci * @opt: the CCID-specific option type (RFC 4340, 5.8 and 10.3)
19662306a36Sopenharmony_ci * @val: value of @opt
19762306a36Sopenharmony_ci * @len: length of @val in bytes
19862306a36Sopenharmony_ci */
19962306a36Sopenharmony_cistatic inline int ccid_hc_tx_parse_options(struct ccid *ccid, struct sock *sk,
20062306a36Sopenharmony_ci					   u8 pkt, u8 opt, u8 *val, u8 len)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	if (!ccid || !ccid->ccid_ops->ccid_hc_tx_parse_options)
20362306a36Sopenharmony_ci		return 0;
20462306a36Sopenharmony_ci	return ccid->ccid_ops->ccid_hc_tx_parse_options(sk, pkt, opt, val, len);
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci/**
20862306a36Sopenharmony_ci * ccid_hc_rx_parse_options  -  Parse CCID-specific options sent by the sender
20962306a36Sopenharmony_ci * Arguments are analogous to ccid_hc_tx_parse_options()
21062306a36Sopenharmony_ci */
21162306a36Sopenharmony_cistatic inline int ccid_hc_rx_parse_options(struct ccid *ccid, struct sock *sk,
21262306a36Sopenharmony_ci					   u8 pkt, u8 opt, u8 *val, u8 len)
21362306a36Sopenharmony_ci{
21462306a36Sopenharmony_ci	if (!ccid || !ccid->ccid_ops->ccid_hc_rx_parse_options)
21562306a36Sopenharmony_ci		return 0;
21662306a36Sopenharmony_ci	return ccid->ccid_ops->ccid_hc_rx_parse_options(sk, pkt, opt, val, len);
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistatic inline int ccid_hc_rx_insert_options(struct ccid *ccid, struct sock *sk,
22062306a36Sopenharmony_ci					    struct sk_buff *skb)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	if (ccid->ccid_ops->ccid_hc_rx_insert_options != NULL)
22362306a36Sopenharmony_ci		return ccid->ccid_ops->ccid_hc_rx_insert_options(sk, skb);
22462306a36Sopenharmony_ci	return 0;
22562306a36Sopenharmony_ci}
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_cistatic inline void ccid_hc_rx_get_info(struct ccid *ccid, struct sock *sk,
22862306a36Sopenharmony_ci				       struct tcp_info *info)
22962306a36Sopenharmony_ci{
23062306a36Sopenharmony_ci	if (ccid->ccid_ops->ccid_hc_rx_get_info != NULL)
23162306a36Sopenharmony_ci		ccid->ccid_ops->ccid_hc_rx_get_info(sk, info);
23262306a36Sopenharmony_ci}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_cistatic inline void ccid_hc_tx_get_info(struct ccid *ccid, struct sock *sk,
23562306a36Sopenharmony_ci				       struct tcp_info *info)
23662306a36Sopenharmony_ci{
23762306a36Sopenharmony_ci	if (ccid->ccid_ops->ccid_hc_tx_get_info != NULL)
23862306a36Sopenharmony_ci		ccid->ccid_ops->ccid_hc_tx_get_info(sk, info);
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistatic inline int ccid_hc_rx_getsockopt(struct ccid *ccid, struct sock *sk,
24262306a36Sopenharmony_ci					const int optname, int len,
24362306a36Sopenharmony_ci					u32 __user *optval, int __user *optlen)
24462306a36Sopenharmony_ci{
24562306a36Sopenharmony_ci	int rc = -ENOPROTOOPT;
24662306a36Sopenharmony_ci	if (ccid != NULL && ccid->ccid_ops->ccid_hc_rx_getsockopt != NULL)
24762306a36Sopenharmony_ci		rc = ccid->ccid_ops->ccid_hc_rx_getsockopt(sk, optname, len,
24862306a36Sopenharmony_ci						 optval, optlen);
24962306a36Sopenharmony_ci	return rc;
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistatic inline int ccid_hc_tx_getsockopt(struct ccid *ccid, struct sock *sk,
25362306a36Sopenharmony_ci					const int optname, int len,
25462306a36Sopenharmony_ci					u32 __user *optval, int __user *optlen)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	int rc = -ENOPROTOOPT;
25762306a36Sopenharmony_ci	if (ccid != NULL && ccid->ccid_ops->ccid_hc_tx_getsockopt != NULL)
25862306a36Sopenharmony_ci		rc = ccid->ccid_ops->ccid_hc_tx_getsockopt(sk, optname, len,
25962306a36Sopenharmony_ci						 optval, optlen);
26062306a36Sopenharmony_ci	return rc;
26162306a36Sopenharmony_ci}
26262306a36Sopenharmony_ci#endif /* _CCID_H */
263