@@ -126,16 +126,18 @@ DCCP_SOCKOPT_RECV_CSCOV is for the receiver and has a different meaning: it
restrictive this setting (see [RFC 4340, sec. 9.2.1]). Partial coverage
settings are inherited to the child socket after accept().
-The following two options apply to CCID 3 exclusively and are getsockopt()-only.
-In either case, a TFRC info struct (defined in <linux/tfrc.h>) is returned.
-
-DCCP_SOCKOPT_CCID_RX_INFO
- Returns a ``struct tfrc_rx_info`` in optval; the buffer for optval and
- optlen must be set to at least sizeof(struct tfrc_rx_info).
-
-DCCP_SOCKOPT_CCID_TX_INFO
- Returns a ``struct tfrc_tx_info`` in optval; the buffer for optval and
- optlen must be set to at least sizeof(struct tfrc_tx_info).
+DCCP_SOCKOPT_CCID_RX_INFO (CCID3 only, getsockopt() only)
+ Returns a ``struct tfrc_rx_info`` (defined in <linux/tfrc.h>) in optval;
+ the buffer for optval and optlen must be at least sizeof(struct tfrc_rx_info).
+
+DCCP_SOCKOPT_CCID_TX_INFO (getsockopt() only)
+ CCID 3:
+ Returns a ``struct tfrc_tx_info`` (defined in <linux/tfrc.h>) in optval;
+ the buffer for optval and optlen must be at least sizeof(struct tfrc_tx_info).
+
+ CCID 2:
+ Returns a ``struct ccid2_tx_info`` (defined in <uapi/linux/dccp.h>) in optval;
+ the buffer for optval and optlen must be at least sizeof(struct ccid2_tx_info).
On unidirectional connections it is useful to close the unused half-connection
via shutdown (SHUT_WR or SHUT_RD): this will reduce per-packet processing costs.
@@ -47,6 +47,22 @@ struct dccp_hdr {
__be16 dccph_seq;
};
+/** struct ccid2_tx_info (Congestion Control Infos)
+ *
+ * @tx_cwnd: max number of packets the path can handle
+ * @tx_srtt: smoothed RTT estimate, scaled by 2^3
+ * @tx_pipe: estimate of "in flight" packets
+ * @buffer_fill number of bytes in send buffer
+ * @cur_mss current MSS (in bytes) (pMTU - header_sizes)
+ */
+struct ccid2_tx_info {
+ __u32 tx_cwnd;
+ __u32 tx_srtt;
+ __u32 tx_pipe;
+ int buffer_fill;
+ __u32 cur_mss;
+};
+
/**
* struct dccp_hdr_ext - the low bits of a 48 bit seq packet
*
@@ -22,6 +22,37 @@ static bool ccid2_debug;
#define ccid2_pr_debug(format, a...)
#endif
+int ccid2_hc_tx_getsockopt(struct sock *sk, const int optname, int len,
+ u32 __user *optval, int __user *optlen)
+{
+ const struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
+ struct dccp_sock *dp = dccp_sk(sk);
+ struct ccid2_tx_info ccid2_info;
+ const void *val;
+
+ switch (optname) {
+ case DCCP_SOCKOPT_CCID_TX_INFO:
+ if (len < sizeof(ccid2_info))
+ return -EINVAL;
+ memset(&ccid2_info, 0, sizeof(ccid2_info));
+ ccid2_info.tx_cwnd = hc->tx_cwnd;
+ ccid2_info.tx_srtt = hc->tx_srtt;
+ ccid2_info.tx_pipe = hc->tx_pipe;
+ ccid2_info.buffer_fill = sk_wmem_alloc_get(sk);
+ ccid2_info.cur_mss = dp->dccps_mss_cache;
+ len = sizeof(ccid2_info);
+ val = &ccid2_info;
+ break;
+ default:
+ return -ENOPROTOOPT;
+ }
+
+ if (put_user(len, optlen) || copy_to_user(optval, val, len))
+ return -EFAULT;
+
+ return 0;
+}
+
static int ccid2_hc_tx_alloc_seq(struct ccid2_hc_tx_sock *hc)
{
struct ccid2_seq *seqp;
@@ -785,6 +816,7 @@ struct ccid_operations ccid2_ops = {
.ccid_hc_tx_packet_recv = ccid2_hc_tx_packet_recv,
.ccid_hc_rx_obj_size = sizeof(struct ccid2_hc_rx_sock),
.ccid_hc_rx_packet_recv = ccid2_hc_rx_packet_recv,
+ .ccid_hc_tx_getsockopt = ccid2_hc_tx_getsockopt,
};
#ifdef CONFIG_IP_DCCP_CCID2_DEBUG