aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/tcp.c133
1 files changed, 131 insertions, 2 deletions
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index ba03ac80435a..c8666b70cde0 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2085,8 +2085,9 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
2085 int val; 2085 int val;
2086 int err = 0; 2086 int err = 0;
2087 2087
2088 /* This is a string value all the others are int's */ 2088 /* These are data/string values, all the others are ints */
2089 if (optname == TCP_CONGESTION) { 2089 switch (optname) {
2090 case TCP_CONGESTION: {
2090 char name[TCP_CA_NAME_MAX]; 2091 char name[TCP_CA_NAME_MAX];
2091 2092
2092 if (optlen < 1) 2093 if (optlen < 1)
@@ -2103,6 +2104,93 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
2103 release_sock(sk); 2104 release_sock(sk);
2104 return err; 2105 return err;
2105 } 2106 }
2107 case TCP_COOKIE_TRANSACTIONS: {
2108 struct tcp_cookie_transactions ctd;
2109 struct tcp_cookie_values *cvp = NULL;
2110
2111 if (sizeof(ctd) > optlen)
2112 return -EINVAL;
2113 if (copy_from_user(&ctd, optval, sizeof(ctd)))
2114 return -EFAULT;
2115
2116 if (ctd.tcpct_used > sizeof(ctd.tcpct_value) ||
2117 ctd.tcpct_s_data_desired > TCP_MSS_DESIRED)
2118 return -EINVAL;
2119
2120 if (ctd.tcpct_cookie_desired == 0) {
2121 /* default to global value */
2122 } else if ((0x1 & ctd.tcpct_cookie_desired) ||
2123 ctd.tcpct_cookie_desired > TCP_COOKIE_MAX ||
2124 ctd.tcpct_cookie_desired < TCP_COOKIE_MIN) {
2125 return -EINVAL;
2126 }
2127
2128 if (TCP_COOKIE_OUT_NEVER & ctd.tcpct_flags) {
2129 /* Supercedes all other values */
2130 lock_sock(sk);
2131 if (tp->cookie_values != NULL) {
2132 kref_put(&tp->cookie_values->kref,
2133 tcp_cookie_values_release);
2134 tp->cookie_values = NULL;
2135 }
2136 tp->rx_opt.cookie_in_always = 0; /* false */
2137 tp->rx_opt.cookie_out_never = 1; /* true */
2138 release_sock(sk);
2139 return err;
2140 }
2141
2142 /* Allocate ancillary memory before locking.
2143 */
2144 if (ctd.tcpct_used > 0 ||
2145 (tp->cookie_values == NULL &&
2146 (sysctl_tcp_cookie_size > 0 ||
2147 ctd.tcpct_cookie_desired > 0 ||
2148 ctd.tcpct_s_data_desired > 0))) {
2149 cvp = kzalloc(sizeof(*cvp) + ctd.tcpct_used,
2150 GFP_KERNEL);
2151 if (cvp == NULL)
2152 return -ENOMEM;
2153 }
2154 lock_sock(sk);
2155 tp->rx_opt.cookie_in_always =
2156 (TCP_COOKIE_IN_ALWAYS & ctd.tcpct_flags);
2157 tp->rx_opt.cookie_out_never = 0; /* false */
2158
2159 if (tp->cookie_values != NULL) {
2160 if (cvp != NULL) {
2161 /* Changed values are recorded by a changed
2162 * pointer, ensuring the cookie will differ,
2163 * without separately hashing each value later.
2164 */
2165 kref_put(&tp->cookie_values->kref,
2166 tcp_cookie_values_release);
2167 kref_init(&cvp->kref);
2168 tp->cookie_values = cvp;
2169 } else {
2170 cvp = tp->cookie_values;
2171 }
2172 }
2173 if (cvp != NULL) {
2174 cvp->cookie_desired = ctd.tcpct_cookie_desired;
2175
2176 if (ctd.tcpct_used > 0) {
2177 memcpy(cvp->s_data_payload, ctd.tcpct_value,
2178 ctd.tcpct_used);
2179 cvp->s_data_desired = ctd.tcpct_used;
2180 cvp->s_data_constant = 1; /* true */
2181 } else {
2182 /* No constant payload data. */
2183 cvp->s_data_desired = ctd.tcpct_s_data_desired;
2184 cvp->s_data_constant = 0; /* false */
2185 }
2186 }
2187 release_sock(sk);
2188 return err;
2189 }
2190 default:
2191 /* fallthru */
2192 break;
2193 };
2106 2194
2107 if (optlen < sizeof(int)) 2195 if (optlen < sizeof(int))
2108 return -EINVAL; 2196 return -EINVAL;
@@ -2427,6 +2515,47 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
2427 if (copy_to_user(optval, icsk->icsk_ca_ops->name, len)) 2515 if (copy_to_user(optval, icsk->icsk_ca_ops->name, len))
2428 return -EFAULT; 2516 return -EFAULT;
2429 return 0; 2517 return 0;
2518
2519 case TCP_COOKIE_TRANSACTIONS: {
2520 struct tcp_cookie_transactions ctd;
2521 struct tcp_cookie_values *cvp = tp->cookie_values;
2522
2523 if (get_user(len, optlen))
2524 return -EFAULT;
2525 if (len < sizeof(ctd))
2526 return -EINVAL;
2527
2528 memset(&ctd, 0, sizeof(ctd));
2529 ctd.tcpct_flags = (tp->rx_opt.cookie_in_always ?
2530 TCP_COOKIE_IN_ALWAYS : 0)
2531 | (tp->rx_opt.cookie_out_never ?
2532 TCP_COOKIE_OUT_NEVER : 0);
2533
2534 if (cvp != NULL) {
2535 ctd.tcpct_flags |= (cvp->s_data_in ?
2536 TCP_S_DATA_IN : 0)
2537 | (cvp->s_data_out ?
2538 TCP_S_DATA_OUT : 0);
2539
2540 ctd.tcpct_cookie_desired = cvp->cookie_desired;
2541 ctd.tcpct_s_data_desired = cvp->s_data_desired;
2542
2543 /* Cookie(s) saved, return as nonce */
2544 if (sizeof(ctd.tcpct_value) < cvp->cookie_pair_size) {
2545 /* impossible? */
2546 return -EINVAL;
2547 }
2548 memcpy(&ctd.tcpct_value[0], &cvp->cookie_pair[0],
2549 cvp->cookie_pair_size);
2550 ctd.tcpct_used = cvp->cookie_pair_size;
2551 }
2552
2553 if (put_user(sizeof(ctd), optlen))
2554 return -EFAULT;
2555 if (copy_to_user(optval, &ctd, sizeof(ctd)))
2556 return -EFAULT;
2557 return 0;
2558 }
2430 default: 2559 default:
2431 return -ENOPROTOOPT; 2560 return -ENOPROTOOPT;
2432 } 2561 }