1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0-only */
2*4882a593Smuzhiyun #ifndef _CCID_H
3*4882a593Smuzhiyun #define _CCID_H
4*4882a593Smuzhiyun /*
5*4882a593Smuzhiyun * net/dccp/ccid.h
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * An implementation of the DCCP protocol
8*4882a593Smuzhiyun * Arnaldo Carvalho de Melo <acme@conectiva.com.br>
9*4882a593Smuzhiyun *
10*4882a593Smuzhiyun * CCID infrastructure
11*4882a593Smuzhiyun */
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include <net/sock.h>
14*4882a593Smuzhiyun #include <linux/compiler.h>
15*4882a593Smuzhiyun #include <linux/dccp.h>
16*4882a593Smuzhiyun #include <linux/list.h>
17*4882a593Smuzhiyun #include <linux/module.h>
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun /* maximum value for a CCID (RFC 4340, 19.5) */
20*4882a593Smuzhiyun #define CCID_MAX 255
21*4882a593Smuzhiyun #define CCID_SLAB_NAME_LENGTH 32
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun struct tcp_info;
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun /**
26*4882a593Smuzhiyun * struct ccid_operations - Interface to Congestion-Control Infrastructure
27*4882a593Smuzhiyun *
28*4882a593Smuzhiyun * @ccid_id: numerical CCID ID (up to %CCID_MAX, cf. table 5 in RFC 4340, 10.)
29*4882a593Smuzhiyun * @ccid_ccmps: the CCMPS including network/transport headers (0 when disabled)
30*4882a593Smuzhiyun * @ccid_name: alphabetical identifier string for @ccid_id
31*4882a593Smuzhiyun * @ccid_hc_{r,t}x_slab: memory pool for the receiver/sender half-connection
32*4882a593Smuzhiyun * @ccid_hc_{r,t}x_obj_size: size of the receiver/sender half-connection socket
33*4882a593Smuzhiyun *
34*4882a593Smuzhiyun * @ccid_hc_{r,t}x_init: CCID-specific initialisation routine (before startup)
35*4882a593Smuzhiyun * @ccid_hc_{r,t}x_exit: CCID-specific cleanup routine (before destruction)
36*4882a593Smuzhiyun * @ccid_hc_rx_packet_recv: implements the HC-receiver side
37*4882a593Smuzhiyun * @ccid_hc_{r,t}x_parse_options: parsing routine for CCID/HC-specific options
38*4882a593Smuzhiyun * @ccid_hc_{r,t}x_insert_options: insert routine for CCID/HC-specific options
39*4882a593Smuzhiyun * @ccid_hc_tx_packet_recv: implements feedback processing for the HC-sender
40*4882a593Smuzhiyun * @ccid_hc_tx_send_packet: implements the sending part of the HC-sender
41*4882a593Smuzhiyun * @ccid_hc_tx_packet_sent: does accounting for packets in flight by HC-sender
42*4882a593Smuzhiyun * @ccid_hc_{r,t}x_get_info: INET_DIAG information for HC-receiver/sender
43*4882a593Smuzhiyun * @ccid_hc_{r,t}x_getsockopt: socket options specific to HC-receiver/sender
44*4882a593Smuzhiyun */
45*4882a593Smuzhiyun struct ccid_operations {
46*4882a593Smuzhiyun unsigned char ccid_id;
47*4882a593Smuzhiyun __u32 ccid_ccmps;
48*4882a593Smuzhiyun const char *ccid_name;
49*4882a593Smuzhiyun struct kmem_cache *ccid_hc_rx_slab,
50*4882a593Smuzhiyun *ccid_hc_tx_slab;
51*4882a593Smuzhiyun char ccid_hc_rx_slab_name[CCID_SLAB_NAME_LENGTH];
52*4882a593Smuzhiyun char ccid_hc_tx_slab_name[CCID_SLAB_NAME_LENGTH];
53*4882a593Smuzhiyun __u32 ccid_hc_rx_obj_size,
54*4882a593Smuzhiyun ccid_hc_tx_obj_size;
55*4882a593Smuzhiyun /* Interface Routines */
56*4882a593Smuzhiyun int (*ccid_hc_rx_init)(struct ccid *ccid, struct sock *sk);
57*4882a593Smuzhiyun int (*ccid_hc_tx_init)(struct ccid *ccid, struct sock *sk);
58*4882a593Smuzhiyun void (*ccid_hc_rx_exit)(struct sock *sk);
59*4882a593Smuzhiyun void (*ccid_hc_tx_exit)(struct sock *sk);
60*4882a593Smuzhiyun void (*ccid_hc_rx_packet_recv)(struct sock *sk,
61*4882a593Smuzhiyun struct sk_buff *skb);
62*4882a593Smuzhiyun int (*ccid_hc_rx_parse_options)(struct sock *sk, u8 pkt,
63*4882a593Smuzhiyun u8 opt, u8 *val, u8 len);
64*4882a593Smuzhiyun int (*ccid_hc_rx_insert_options)(struct sock *sk,
65*4882a593Smuzhiyun struct sk_buff *skb);
66*4882a593Smuzhiyun void (*ccid_hc_tx_packet_recv)(struct sock *sk,
67*4882a593Smuzhiyun struct sk_buff *skb);
68*4882a593Smuzhiyun int (*ccid_hc_tx_parse_options)(struct sock *sk, u8 pkt,
69*4882a593Smuzhiyun u8 opt, u8 *val, u8 len);
70*4882a593Smuzhiyun int (*ccid_hc_tx_send_packet)(struct sock *sk,
71*4882a593Smuzhiyun struct sk_buff *skb);
72*4882a593Smuzhiyun void (*ccid_hc_tx_packet_sent)(struct sock *sk,
73*4882a593Smuzhiyun unsigned int len);
74*4882a593Smuzhiyun void (*ccid_hc_rx_get_info)(struct sock *sk,
75*4882a593Smuzhiyun struct tcp_info *info);
76*4882a593Smuzhiyun void (*ccid_hc_tx_get_info)(struct sock *sk,
77*4882a593Smuzhiyun struct tcp_info *info);
78*4882a593Smuzhiyun int (*ccid_hc_rx_getsockopt)(struct sock *sk,
79*4882a593Smuzhiyun const int optname, int len,
80*4882a593Smuzhiyun u32 __user *optval,
81*4882a593Smuzhiyun int __user *optlen);
82*4882a593Smuzhiyun int (*ccid_hc_tx_getsockopt)(struct sock *sk,
83*4882a593Smuzhiyun const int optname, int len,
84*4882a593Smuzhiyun u32 __user *optval,
85*4882a593Smuzhiyun int __user *optlen);
86*4882a593Smuzhiyun };
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun extern struct ccid_operations ccid2_ops;
89*4882a593Smuzhiyun #ifdef CONFIG_IP_DCCP_CCID3
90*4882a593Smuzhiyun extern struct ccid_operations ccid3_ops;
91*4882a593Smuzhiyun #endif
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun int ccid_initialize_builtins(void);
94*4882a593Smuzhiyun void ccid_cleanup_builtins(void);
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun struct ccid {
97*4882a593Smuzhiyun struct ccid_operations *ccid_ops;
98*4882a593Smuzhiyun char ccid_priv[];
99*4882a593Smuzhiyun };
100*4882a593Smuzhiyun
ccid_priv(const struct ccid * ccid)101*4882a593Smuzhiyun static inline void *ccid_priv(const struct ccid *ccid)
102*4882a593Smuzhiyun {
103*4882a593Smuzhiyun return (void *)ccid->ccid_priv;
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun bool ccid_support_check(u8 const *ccid_array, u8 array_len);
107*4882a593Smuzhiyun int ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len);
108*4882a593Smuzhiyun int ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
109*4882a593Smuzhiyun char __user *, int __user *);
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun struct ccid *ccid_new(const u8 id, struct sock *sk, bool rx);
112*4882a593Smuzhiyun
ccid_get_current_rx_ccid(struct dccp_sock * dp)113*4882a593Smuzhiyun static inline int ccid_get_current_rx_ccid(struct dccp_sock *dp)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun struct ccid *ccid = dp->dccps_hc_rx_ccid;
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun if (ccid == NULL || ccid->ccid_ops == NULL)
118*4882a593Smuzhiyun return -1;
119*4882a593Smuzhiyun return ccid->ccid_ops->ccid_id;
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun
ccid_get_current_tx_ccid(struct dccp_sock * dp)122*4882a593Smuzhiyun static inline int ccid_get_current_tx_ccid(struct dccp_sock *dp)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun struct ccid *ccid = dp->dccps_hc_tx_ccid;
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun if (ccid == NULL || ccid->ccid_ops == NULL)
127*4882a593Smuzhiyun return -1;
128*4882a593Smuzhiyun return ccid->ccid_ops->ccid_id;
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun void ccid_hc_rx_delete(struct ccid *ccid, struct sock *sk);
132*4882a593Smuzhiyun void ccid_hc_tx_delete(struct ccid *ccid, struct sock *sk);
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun /*
135*4882a593Smuzhiyun * Congestion control of queued data packets via CCID decision.
136*4882a593Smuzhiyun *
137*4882a593Smuzhiyun * The TX CCID performs its congestion-control by indicating whether and when a
138*4882a593Smuzhiyun * queued packet may be sent, using the return code of ccid_hc_tx_send_packet().
139*4882a593Smuzhiyun * The following modes are supported via the symbolic constants below:
140*4882a593Smuzhiyun * - timer-based pacing (CCID returns a delay value in milliseconds);
141*4882a593Smuzhiyun * - autonomous dequeueing (CCID internally schedules dccps_xmitlet).
142*4882a593Smuzhiyun */
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun enum ccid_dequeueing_decision {
145*4882a593Smuzhiyun CCID_PACKET_SEND_AT_ONCE = 0x00000, /* "green light": no delay */
146*4882a593Smuzhiyun CCID_PACKET_DELAY_MAX = 0x0FFFF, /* maximum delay in msecs */
147*4882a593Smuzhiyun CCID_PACKET_DELAY = 0x10000, /* CCID msec-delay mode */
148*4882a593Smuzhiyun CCID_PACKET_WILL_DEQUEUE_LATER = 0x20000, /* CCID autonomous mode */
149*4882a593Smuzhiyun CCID_PACKET_ERR = 0xF0000, /* error condition */
150*4882a593Smuzhiyun };
151*4882a593Smuzhiyun
ccid_packet_dequeue_eval(const int return_code)152*4882a593Smuzhiyun static inline int ccid_packet_dequeue_eval(const int return_code)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun if (return_code < 0)
155*4882a593Smuzhiyun return CCID_PACKET_ERR;
156*4882a593Smuzhiyun if (return_code == 0)
157*4882a593Smuzhiyun return CCID_PACKET_SEND_AT_ONCE;
158*4882a593Smuzhiyun if (return_code <= CCID_PACKET_DELAY_MAX)
159*4882a593Smuzhiyun return CCID_PACKET_DELAY;
160*4882a593Smuzhiyun return return_code;
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun
ccid_hc_tx_send_packet(struct ccid * ccid,struct sock * sk,struct sk_buff * skb)163*4882a593Smuzhiyun static inline int ccid_hc_tx_send_packet(struct ccid *ccid, struct sock *sk,
164*4882a593Smuzhiyun struct sk_buff *skb)
165*4882a593Smuzhiyun {
166*4882a593Smuzhiyun if (ccid->ccid_ops->ccid_hc_tx_send_packet != NULL)
167*4882a593Smuzhiyun return ccid->ccid_ops->ccid_hc_tx_send_packet(sk, skb);
168*4882a593Smuzhiyun return CCID_PACKET_SEND_AT_ONCE;
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun
ccid_hc_tx_packet_sent(struct ccid * ccid,struct sock * sk,unsigned int len)171*4882a593Smuzhiyun static inline void ccid_hc_tx_packet_sent(struct ccid *ccid, struct sock *sk,
172*4882a593Smuzhiyun unsigned int len)
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun if (ccid->ccid_ops->ccid_hc_tx_packet_sent != NULL)
175*4882a593Smuzhiyun ccid->ccid_ops->ccid_hc_tx_packet_sent(sk, len);
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun
ccid_hc_rx_packet_recv(struct ccid * ccid,struct sock * sk,struct sk_buff * skb)178*4882a593Smuzhiyun static inline void ccid_hc_rx_packet_recv(struct ccid *ccid, struct sock *sk,
179*4882a593Smuzhiyun struct sk_buff *skb)
180*4882a593Smuzhiyun {
181*4882a593Smuzhiyun if (ccid->ccid_ops->ccid_hc_rx_packet_recv != NULL)
182*4882a593Smuzhiyun ccid->ccid_ops->ccid_hc_rx_packet_recv(sk, skb);
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun
ccid_hc_tx_packet_recv(struct ccid * ccid,struct sock * sk,struct sk_buff * skb)185*4882a593Smuzhiyun static inline void ccid_hc_tx_packet_recv(struct ccid *ccid, struct sock *sk,
186*4882a593Smuzhiyun struct sk_buff *skb)
187*4882a593Smuzhiyun {
188*4882a593Smuzhiyun if (ccid->ccid_ops->ccid_hc_tx_packet_recv != NULL)
189*4882a593Smuzhiyun ccid->ccid_ops->ccid_hc_tx_packet_recv(sk, skb);
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun /**
193*4882a593Smuzhiyun * ccid_hc_tx_parse_options - Parse CCID-specific options sent by the receiver
194*4882a593Smuzhiyun * @pkt: type of packet that @opt appears on (RFC 4340, 5.1)
195*4882a593Smuzhiyun * @opt: the CCID-specific option type (RFC 4340, 5.8 and 10.3)
196*4882a593Smuzhiyun * @val: value of @opt
197*4882a593Smuzhiyun * @len: length of @val in bytes
198*4882a593Smuzhiyun */
ccid_hc_tx_parse_options(struct ccid * ccid,struct sock * sk,u8 pkt,u8 opt,u8 * val,u8 len)199*4882a593Smuzhiyun static inline int ccid_hc_tx_parse_options(struct ccid *ccid, struct sock *sk,
200*4882a593Smuzhiyun u8 pkt, u8 opt, u8 *val, u8 len)
201*4882a593Smuzhiyun {
202*4882a593Smuzhiyun if (!ccid || !ccid->ccid_ops->ccid_hc_tx_parse_options)
203*4882a593Smuzhiyun return 0;
204*4882a593Smuzhiyun return ccid->ccid_ops->ccid_hc_tx_parse_options(sk, pkt, opt, val, len);
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun /**
208*4882a593Smuzhiyun * ccid_hc_rx_parse_options - Parse CCID-specific options sent by the sender
209*4882a593Smuzhiyun * Arguments are analogous to ccid_hc_tx_parse_options()
210*4882a593Smuzhiyun */
ccid_hc_rx_parse_options(struct ccid * ccid,struct sock * sk,u8 pkt,u8 opt,u8 * val,u8 len)211*4882a593Smuzhiyun static inline int ccid_hc_rx_parse_options(struct ccid *ccid, struct sock *sk,
212*4882a593Smuzhiyun u8 pkt, u8 opt, u8 *val, u8 len)
213*4882a593Smuzhiyun {
214*4882a593Smuzhiyun if (!ccid || !ccid->ccid_ops->ccid_hc_rx_parse_options)
215*4882a593Smuzhiyun return 0;
216*4882a593Smuzhiyun return ccid->ccid_ops->ccid_hc_rx_parse_options(sk, pkt, opt, val, len);
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun
ccid_hc_rx_insert_options(struct ccid * ccid,struct sock * sk,struct sk_buff * skb)219*4882a593Smuzhiyun static inline int ccid_hc_rx_insert_options(struct ccid *ccid, struct sock *sk,
220*4882a593Smuzhiyun struct sk_buff *skb)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun if (ccid->ccid_ops->ccid_hc_rx_insert_options != NULL)
223*4882a593Smuzhiyun return ccid->ccid_ops->ccid_hc_rx_insert_options(sk, skb);
224*4882a593Smuzhiyun return 0;
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun
ccid_hc_rx_get_info(struct ccid * ccid,struct sock * sk,struct tcp_info * info)227*4882a593Smuzhiyun static inline void ccid_hc_rx_get_info(struct ccid *ccid, struct sock *sk,
228*4882a593Smuzhiyun struct tcp_info *info)
229*4882a593Smuzhiyun {
230*4882a593Smuzhiyun if (ccid->ccid_ops->ccid_hc_rx_get_info != NULL)
231*4882a593Smuzhiyun ccid->ccid_ops->ccid_hc_rx_get_info(sk, info);
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun
ccid_hc_tx_get_info(struct ccid * ccid,struct sock * sk,struct tcp_info * info)234*4882a593Smuzhiyun static inline void ccid_hc_tx_get_info(struct ccid *ccid, struct sock *sk,
235*4882a593Smuzhiyun struct tcp_info *info)
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun if (ccid->ccid_ops->ccid_hc_tx_get_info != NULL)
238*4882a593Smuzhiyun ccid->ccid_ops->ccid_hc_tx_get_info(sk, info);
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun
ccid_hc_rx_getsockopt(struct ccid * ccid,struct sock * sk,const int optname,int len,u32 __user * optval,int __user * optlen)241*4882a593Smuzhiyun static inline int ccid_hc_rx_getsockopt(struct ccid *ccid, struct sock *sk,
242*4882a593Smuzhiyun const int optname, int len,
243*4882a593Smuzhiyun u32 __user *optval, int __user *optlen)
244*4882a593Smuzhiyun {
245*4882a593Smuzhiyun int rc = -ENOPROTOOPT;
246*4882a593Smuzhiyun if (ccid != NULL && ccid->ccid_ops->ccid_hc_rx_getsockopt != NULL)
247*4882a593Smuzhiyun rc = ccid->ccid_ops->ccid_hc_rx_getsockopt(sk, optname, len,
248*4882a593Smuzhiyun optval, optlen);
249*4882a593Smuzhiyun return rc;
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun
ccid_hc_tx_getsockopt(struct ccid * ccid,struct sock * sk,const int optname,int len,u32 __user * optval,int __user * optlen)252*4882a593Smuzhiyun static inline int ccid_hc_tx_getsockopt(struct ccid *ccid, struct sock *sk,
253*4882a593Smuzhiyun const int optname, int len,
254*4882a593Smuzhiyun u32 __user *optval, int __user *optlen)
255*4882a593Smuzhiyun {
256*4882a593Smuzhiyun int rc = -ENOPROTOOPT;
257*4882a593Smuzhiyun if (ccid != NULL && ccid->ccid_ops->ccid_hc_tx_getsockopt != NULL)
258*4882a593Smuzhiyun rc = ccid->ccid_ops->ccid_hc_tx_getsockopt(sk, optname, len,
259*4882a593Smuzhiyun optval, optlen);
260*4882a593Smuzhiyun return rc;
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun #endif /* _CCID_H */
263