diff options
Diffstat (limited to 'net')
196 files changed, 2125 insertions, 1284 deletions
diff --git a/net/ax25/ax25_ip.c b/net/ax25/ax25_ip.c index 70417e9b932d..314bbc8010fb 100644 --- a/net/ax25/ax25_ip.c +++ b/net/ax25/ax25_ip.c | |||
| @@ -114,6 +114,7 @@ netdev_tx_t ax25_ip_xmit(struct sk_buff *skb) | |||
| 114 | dst = (ax25_address *)(bp + 1); | 114 | dst = (ax25_address *)(bp + 1); |
| 115 | src = (ax25_address *)(bp + 8); | 115 | src = (ax25_address *)(bp + 8); |
| 116 | 116 | ||
| 117 | ax25_route_lock_use(); | ||
| 117 | route = ax25_get_route(dst, NULL); | 118 | route = ax25_get_route(dst, NULL); |
| 118 | if (route) { | 119 | if (route) { |
| 119 | digipeat = route->digipeat; | 120 | digipeat = route->digipeat; |
| @@ -206,9 +207,8 @@ netdev_tx_t ax25_ip_xmit(struct sk_buff *skb) | |||
| 206 | ax25_queue_xmit(skb, dev); | 207 | ax25_queue_xmit(skb, dev); |
| 207 | 208 | ||
| 208 | put: | 209 | put: |
| 209 | if (route) | ||
| 210 | ax25_put_route(route); | ||
| 211 | 210 | ||
| 211 | ax25_route_lock_unuse(); | ||
| 212 | return NETDEV_TX_OK; | 212 | return NETDEV_TX_OK; |
| 213 | } | 213 | } |
| 214 | 214 | ||
diff --git a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c index a0eff323af12..66f74c85cf6b 100644 --- a/net/ax25/ax25_route.c +++ b/net/ax25/ax25_route.c | |||
| @@ -40,7 +40,7 @@ | |||
| 40 | #include <linux/export.h> | 40 | #include <linux/export.h> |
| 41 | 41 | ||
| 42 | static ax25_route *ax25_route_list; | 42 | static ax25_route *ax25_route_list; |
| 43 | static DEFINE_RWLOCK(ax25_route_lock); | 43 | DEFINE_RWLOCK(ax25_route_lock); |
| 44 | 44 | ||
| 45 | void ax25_rt_device_down(struct net_device *dev) | 45 | void ax25_rt_device_down(struct net_device *dev) |
| 46 | { | 46 | { |
| @@ -335,6 +335,7 @@ const struct seq_operations ax25_rt_seqops = { | |||
| 335 | * Find AX.25 route | 335 | * Find AX.25 route |
| 336 | * | 336 | * |
| 337 | * Only routes with a reference count of zero can be destroyed. | 337 | * Only routes with a reference count of zero can be destroyed. |
| 338 | * Must be called with ax25_route_lock read locked. | ||
| 338 | */ | 339 | */ |
| 339 | ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev) | 340 | ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev) |
| 340 | { | 341 | { |
| @@ -342,7 +343,6 @@ ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev) | |||
| 342 | ax25_route *ax25_def_rt = NULL; | 343 | ax25_route *ax25_def_rt = NULL; |
| 343 | ax25_route *ax25_rt; | 344 | ax25_route *ax25_rt; |
| 344 | 345 | ||
| 345 | read_lock(&ax25_route_lock); | ||
| 346 | /* | 346 | /* |
| 347 | * Bind to the physical interface we heard them on, or the default | 347 | * Bind to the physical interface we heard them on, or the default |
| 348 | * route if none is found; | 348 | * route if none is found; |
| @@ -365,11 +365,6 @@ ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev) | |||
| 365 | if (ax25_spe_rt != NULL) | 365 | if (ax25_spe_rt != NULL) |
| 366 | ax25_rt = ax25_spe_rt; | 366 | ax25_rt = ax25_spe_rt; |
| 367 | 367 | ||
| 368 | if (ax25_rt != NULL) | ||
| 369 | ax25_hold_route(ax25_rt); | ||
| 370 | |||
| 371 | read_unlock(&ax25_route_lock); | ||
| 372 | |||
| 373 | return ax25_rt; | 368 | return ax25_rt; |
| 374 | } | 369 | } |
| 375 | 370 | ||
| @@ -400,9 +395,12 @@ int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr) | |||
| 400 | ax25_route *ax25_rt; | 395 | ax25_route *ax25_rt; |
| 401 | int err = 0; | 396 | int err = 0; |
| 402 | 397 | ||
| 403 | if ((ax25_rt = ax25_get_route(addr, NULL)) == NULL) | 398 | ax25_route_lock_use(); |
| 399 | ax25_rt = ax25_get_route(addr, NULL); | ||
| 400 | if (!ax25_rt) { | ||
| 401 | ax25_route_lock_unuse(); | ||
| 404 | return -EHOSTUNREACH; | 402 | return -EHOSTUNREACH; |
| 405 | 403 | } | |
| 406 | if ((ax25->ax25_dev = ax25_dev_ax25dev(ax25_rt->dev)) == NULL) { | 404 | if ((ax25->ax25_dev = ax25_dev_ax25dev(ax25_rt->dev)) == NULL) { |
| 407 | err = -EHOSTUNREACH; | 405 | err = -EHOSTUNREACH; |
| 408 | goto put; | 406 | goto put; |
| @@ -437,8 +435,7 @@ int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr) | |||
| 437 | } | 435 | } |
| 438 | 436 | ||
| 439 | put: | 437 | put: |
| 440 | ax25_put_route(ax25_rt); | 438 | ax25_route_lock_unuse(); |
| 441 | |||
| 442 | return err; | 439 | return err; |
| 443 | } | 440 | } |
| 444 | 441 | ||
diff --git a/net/batman-adv/bat_v_elp.c b/net/batman-adv/bat_v_elp.c index e8090f099eb8..ef0dec20c7d8 100644 --- a/net/batman-adv/bat_v_elp.c +++ b/net/batman-adv/bat_v_elp.c | |||
| @@ -104,6 +104,9 @@ static u32 batadv_v_elp_get_throughput(struct batadv_hardif_neigh_node *neigh) | |||
| 104 | 104 | ||
| 105 | ret = cfg80211_get_station(real_netdev, neigh->addr, &sinfo); | 105 | ret = cfg80211_get_station(real_netdev, neigh->addr, &sinfo); |
| 106 | 106 | ||
| 107 | /* free the TID stats immediately */ | ||
| 108 | cfg80211_sinfo_release_content(&sinfo); | ||
| 109 | |||
| 107 | dev_put(real_netdev); | 110 | dev_put(real_netdev); |
| 108 | if (ret == -ENOENT) { | 111 | if (ret == -ENOENT) { |
| 109 | /* Node is not associated anymore! It would be | 112 | /* Node is not associated anymore! It would be |
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index 508f4416dfc9..415d494cbe22 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c | |||
| @@ -20,7 +20,6 @@ | |||
| 20 | #include "main.h" | 20 | #include "main.h" |
| 21 | 21 | ||
| 22 | #include <linux/atomic.h> | 22 | #include <linux/atomic.h> |
| 23 | #include <linux/bug.h> | ||
| 24 | #include <linux/byteorder/generic.h> | 23 | #include <linux/byteorder/generic.h> |
| 25 | #include <linux/errno.h> | 24 | #include <linux/errno.h> |
| 26 | #include <linux/gfp.h> | 25 | #include <linux/gfp.h> |
| @@ -179,8 +178,10 @@ static bool batadv_is_on_batman_iface(const struct net_device *net_dev) | |||
| 179 | parent_dev = __dev_get_by_index((struct net *)parent_net, | 178 | parent_dev = __dev_get_by_index((struct net *)parent_net, |
| 180 | dev_get_iflink(net_dev)); | 179 | dev_get_iflink(net_dev)); |
| 181 | /* if we got a NULL parent_dev there is something broken.. */ | 180 | /* if we got a NULL parent_dev there is something broken.. */ |
| 182 | if (WARN(!parent_dev, "Cannot find parent device")) | 181 | if (!parent_dev) { |
| 182 | pr_err("Cannot find parent device\n"); | ||
| 183 | return false; | 183 | return false; |
| 184 | } | ||
| 184 | 185 | ||
| 185 | if (batadv_mutual_parents(net_dev, net, parent_dev, parent_net)) | 186 | if (batadv_mutual_parents(net_dev, net, parent_dev, parent_net)) |
| 186 | return false; | 187 | return false; |
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index 5db5a0a4c959..ffc83bebfe40 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c | |||
| @@ -221,10 +221,14 @@ static netdev_tx_t batadv_interface_tx(struct sk_buff *skb, | |||
| 221 | 221 | ||
| 222 | netif_trans_update(soft_iface); | 222 | netif_trans_update(soft_iface); |
| 223 | vid = batadv_get_vid(skb, 0); | 223 | vid = batadv_get_vid(skb, 0); |
| 224 | |||
| 225 | skb_reset_mac_header(skb); | ||
| 224 | ethhdr = eth_hdr(skb); | 226 | ethhdr = eth_hdr(skb); |
| 225 | 227 | ||
| 226 | switch (ntohs(ethhdr->h_proto)) { | 228 | switch (ntohs(ethhdr->h_proto)) { |
| 227 | case ETH_P_8021Q: | 229 | case ETH_P_8021Q: |
| 230 | if (!pskb_may_pull(skb, sizeof(*vhdr))) | ||
| 231 | goto dropped; | ||
| 228 | vhdr = vlan_eth_hdr(skb); | 232 | vhdr = vlan_eth_hdr(skb); |
| 229 | 233 | ||
| 230 | /* drop batman-in-batman packets to prevent loops */ | 234 | /* drop batman-in-batman packets to prevent loops */ |
diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c index fa2644d276ef..e31e1b20f7f4 100644 --- a/net/bpf/test_run.c +++ b/net/bpf/test_run.c | |||
| @@ -13,27 +13,13 @@ | |||
| 13 | #include <net/sock.h> | 13 | #include <net/sock.h> |
| 14 | #include <net/tcp.h> | 14 | #include <net/tcp.h> |
| 15 | 15 | ||
| 16 | static __always_inline u32 bpf_test_run_one(struct bpf_prog *prog, void *ctx, | 16 | static int bpf_test_run(struct bpf_prog *prog, void *ctx, u32 repeat, |
| 17 | struct bpf_cgroup_storage *storage[MAX_BPF_CGROUP_STORAGE_TYPE]) | 17 | u32 *retval, u32 *time) |
| 18 | { | ||
| 19 | u32 ret; | ||
| 20 | |||
| 21 | preempt_disable(); | ||
| 22 | rcu_read_lock(); | ||
| 23 | bpf_cgroup_storage_set(storage); | ||
| 24 | ret = BPF_PROG_RUN(prog, ctx); | ||
| 25 | rcu_read_unlock(); | ||
| 26 | preempt_enable(); | ||
| 27 | |||
| 28 | return ret; | ||
| 29 | } | ||
| 30 | |||
| 31 | static int bpf_test_run(struct bpf_prog *prog, void *ctx, u32 repeat, u32 *ret, | ||
| 32 | u32 *time) | ||
| 33 | { | 18 | { |
| 34 | struct bpf_cgroup_storage *storage[MAX_BPF_CGROUP_STORAGE_TYPE] = { 0 }; | 19 | struct bpf_cgroup_storage *storage[MAX_BPF_CGROUP_STORAGE_TYPE] = { 0 }; |
| 35 | enum bpf_cgroup_storage_type stype; | 20 | enum bpf_cgroup_storage_type stype; |
| 36 | u64 time_start, time_spent = 0; | 21 | u64 time_start, time_spent = 0; |
| 22 | int ret = 0; | ||
| 37 | u32 i; | 23 | u32 i; |
| 38 | 24 | ||
| 39 | for_each_cgroup_storage_type(stype) { | 25 | for_each_cgroup_storage_type(stype) { |
| @@ -48,25 +34,42 @@ static int bpf_test_run(struct bpf_prog *prog, void *ctx, u32 repeat, u32 *ret, | |||
| 48 | 34 | ||
| 49 | if (!repeat) | 35 | if (!repeat) |
| 50 | repeat = 1; | 36 | repeat = 1; |
| 37 | |||
| 38 | rcu_read_lock(); | ||
| 39 | preempt_disable(); | ||
| 51 | time_start = ktime_get_ns(); | 40 | time_start = ktime_get_ns(); |
| 52 | for (i = 0; i < repeat; i++) { | 41 | for (i = 0; i < repeat; i++) { |
| 53 | *ret = bpf_test_run_one(prog, ctx, storage); | 42 | bpf_cgroup_storage_set(storage); |
| 43 | *retval = BPF_PROG_RUN(prog, ctx); | ||
| 44 | |||
| 45 | if (signal_pending(current)) { | ||
| 46 | ret = -EINTR; | ||
| 47 | break; | ||
| 48 | } | ||
| 49 | |||
| 54 | if (need_resched()) { | 50 | if (need_resched()) { |
| 55 | if (signal_pending(current)) | ||
| 56 | break; | ||
| 57 | time_spent += ktime_get_ns() - time_start; | 51 | time_spent += ktime_get_ns() - time_start; |
| 52 | preempt_enable(); | ||
| 53 | rcu_read_unlock(); | ||
| 54 | |||
| 58 | cond_resched(); | 55 | cond_resched(); |
| 56 | |||
| 57 | rcu_read_lock(); | ||
| 58 | preempt_disable(); | ||
| 59 | time_start = ktime_get_ns(); | 59 | time_start = ktime_get_ns(); |
| 60 | } | 60 | } |
| 61 | } | 61 | } |
| 62 | time_spent += ktime_get_ns() - time_start; | 62 | time_spent += ktime_get_ns() - time_start; |
| 63 | preempt_enable(); | ||
| 64 | rcu_read_unlock(); | ||
| 65 | |||
| 63 | do_div(time_spent, repeat); | 66 | do_div(time_spent, repeat); |
| 64 | *time = time_spent > U32_MAX ? U32_MAX : (u32)time_spent; | 67 | *time = time_spent > U32_MAX ? U32_MAX : (u32)time_spent; |
| 65 | 68 | ||
| 66 | for_each_cgroup_storage_type(stype) | 69 | for_each_cgroup_storage_type(stype) |
| 67 | bpf_cgroup_storage_free(storage[stype]); | 70 | bpf_cgroup_storage_free(storage[stype]); |
| 68 | 71 | ||
| 69 | return 0; | 72 | return ret; |
| 70 | } | 73 | } |
| 71 | 74 | ||
| 72 | static int bpf_test_finish(const union bpf_attr *kattr, | 75 | static int bpf_test_finish(const union bpf_attr *kattr, |
diff --git a/net/bpfilter/bpfilter_kern.c b/net/bpfilter/bpfilter_kern.c index 7acfc83087d5..7ee4fea93637 100644 --- a/net/bpfilter/bpfilter_kern.c +++ b/net/bpfilter/bpfilter_kern.c | |||
| @@ -13,39 +13,24 @@ | |||
| 13 | extern char bpfilter_umh_start; | 13 | extern char bpfilter_umh_start; |
| 14 | extern char bpfilter_umh_end; | 14 | extern char bpfilter_umh_end; |
| 15 | 15 | ||
| 16 | static struct umh_info info; | 16 | static void shutdown_umh(void) |
| 17 | /* since ip_getsockopt() can run in parallel, serialize access to umh */ | ||
| 18 | static DEFINE_MUTEX(bpfilter_lock); | ||
| 19 | |||
| 20 | static void shutdown_umh(struct umh_info *info) | ||
| 21 | { | 17 | { |
| 22 | struct task_struct *tsk; | 18 | struct task_struct *tsk; |
| 23 | 19 | ||
| 24 | if (!info->pid) | 20 | if (bpfilter_ops.stop) |
| 25 | return; | 21 | return; |
| 26 | tsk = get_pid_task(find_vpid(info->pid), PIDTYPE_PID); | 22 | |
| 23 | tsk = get_pid_task(find_vpid(bpfilter_ops.info.pid), PIDTYPE_PID); | ||
| 27 | if (tsk) { | 24 | if (tsk) { |
| 28 | force_sig(SIGKILL, tsk); | 25 | force_sig(SIGKILL, tsk); |
| 29 | put_task_struct(tsk); | 26 | put_task_struct(tsk); |
| 30 | } | 27 | } |
| 31 | fput(info->pipe_to_umh); | ||
| 32 | fput(info->pipe_from_umh); | ||
| 33 | info->pid = 0; | ||
| 34 | } | 28 | } |
| 35 | 29 | ||
| 36 | static void __stop_umh(void) | 30 | static void __stop_umh(void) |
| 37 | { | 31 | { |
| 38 | if (IS_ENABLED(CONFIG_INET)) { | 32 | if (IS_ENABLED(CONFIG_INET)) |
| 39 | bpfilter_process_sockopt = NULL; | 33 | shutdown_umh(); |
| 40 | shutdown_umh(&info); | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | static void stop_umh(void) | ||
| 45 | { | ||
| 46 | mutex_lock(&bpfilter_lock); | ||
| 47 | __stop_umh(); | ||
| 48 | mutex_unlock(&bpfilter_lock); | ||
| 49 | } | 34 | } |
| 50 | 35 | ||
| 51 | static int __bpfilter_process_sockopt(struct sock *sk, int optname, | 36 | static int __bpfilter_process_sockopt(struct sock *sk, int optname, |
| @@ -63,10 +48,10 @@ static int __bpfilter_process_sockopt(struct sock *sk, int optname, | |||
| 63 | req.cmd = optname; | 48 | req.cmd = optname; |
| 64 | req.addr = (long __force __user)optval; | 49 | req.addr = (long __force __user)optval; |
| 65 | req.len = optlen; | 50 | req.len = optlen; |
| 66 | mutex_lock(&bpfilter_lock); | 51 | if (!bpfilter_ops.info.pid) |
| 67 | if (!info.pid) | ||
| 68 | goto out; | 52 | goto out; |
| 69 | n = __kernel_write(info.pipe_to_umh, &req, sizeof(req), &pos); | 53 | n = __kernel_write(bpfilter_ops.info.pipe_to_umh, &req, sizeof(req), |
| 54 | &pos); | ||
| 70 | if (n != sizeof(req)) { | 55 | if (n != sizeof(req)) { |
| 71 | pr_err("write fail %zd\n", n); | 56 | pr_err("write fail %zd\n", n); |
| 72 | __stop_umh(); | 57 | __stop_umh(); |
| @@ -74,7 +59,8 @@ static int __bpfilter_process_sockopt(struct sock *sk, int optname, | |||
| 74 | goto out; | 59 | goto out; |
| 75 | } | 60 | } |
| 76 | pos = 0; | 61 | pos = 0; |
| 77 | n = kernel_read(info.pipe_from_umh, &reply, sizeof(reply), &pos); | 62 | n = kernel_read(bpfilter_ops.info.pipe_from_umh, &reply, sizeof(reply), |
| 63 | &pos); | ||
| 78 | if (n != sizeof(reply)) { | 64 | if (n != sizeof(reply)) { |
| 79 | pr_err("read fail %zd\n", n); | 65 | pr_err("read fail %zd\n", n); |
| 80 | __stop_umh(); | 66 | __stop_umh(); |
| @@ -83,37 +69,59 @@ static int __bpfilter_process_sockopt(struct sock *sk, int optname, | |||
| 83 | } | 69 | } |
| 84 | ret = reply.status; | 70 | ret = reply.status; |
| 85 | out: | 71 | out: |
| 86 | mutex_unlock(&bpfilter_lock); | ||
| 87 | return ret; | 72 | return ret; |
| 88 | } | 73 | } |
| 89 | 74 | ||
| 90 | static int __init load_umh(void) | 75 | static int start_umh(void) |
| 91 | { | 76 | { |
| 92 | int err; | 77 | int err; |
| 93 | 78 | ||
| 94 | /* fork usermode process */ | 79 | /* fork usermode process */ |
| 95 | info.cmdline = "bpfilter_umh"; | ||
| 96 | err = fork_usermode_blob(&bpfilter_umh_start, | 80 | err = fork_usermode_blob(&bpfilter_umh_start, |
| 97 | &bpfilter_umh_end - &bpfilter_umh_start, | 81 | &bpfilter_umh_end - &bpfilter_umh_start, |
| 98 | &info); | 82 | &bpfilter_ops.info); |
| 99 | if (err) | 83 | if (err) |
| 100 | return err; | 84 | return err; |
| 101 | pr_info("Loaded bpfilter_umh pid %d\n", info.pid); | 85 | bpfilter_ops.stop = false; |
| 86 | pr_info("Loaded bpfilter_umh pid %d\n", bpfilter_ops.info.pid); | ||
| 102 | 87 | ||
| 103 | /* health check that usermode process started correctly */ | 88 | /* health check that usermode process started correctly */ |
| 104 | if (__bpfilter_process_sockopt(NULL, 0, NULL, 0, 0) != 0) { | 89 | if (__bpfilter_process_sockopt(NULL, 0, NULL, 0, 0) != 0) { |
| 105 | stop_umh(); | 90 | shutdown_umh(); |
| 106 | return -EFAULT; | 91 | return -EFAULT; |
| 107 | } | 92 | } |
| 108 | if (IS_ENABLED(CONFIG_INET)) | ||
| 109 | bpfilter_process_sockopt = &__bpfilter_process_sockopt; | ||
| 110 | 93 | ||
| 111 | return 0; | 94 | return 0; |
| 112 | } | 95 | } |
| 113 | 96 | ||
| 97 | static int __init load_umh(void) | ||
| 98 | { | ||
| 99 | int err; | ||
| 100 | |||
| 101 | mutex_lock(&bpfilter_ops.lock); | ||
| 102 | if (!bpfilter_ops.stop) { | ||
| 103 | err = -EFAULT; | ||
| 104 | goto out; | ||
| 105 | } | ||
| 106 | err = start_umh(); | ||
| 107 | if (!err && IS_ENABLED(CONFIG_INET)) { | ||
| 108 | bpfilter_ops.sockopt = &__bpfilter_process_sockopt; | ||
| 109 | bpfilter_ops.start = &start_umh; | ||
| 110 | } | ||
| 111 | out: | ||
| 112 | mutex_unlock(&bpfilter_ops.lock); | ||
| 113 | return err; | ||
| 114 | } | ||
| 115 | |||
| 114 | static void __exit fini_umh(void) | 116 | static void __exit fini_umh(void) |
| 115 | { | 117 | { |
| 116 | stop_umh(); | 118 | mutex_lock(&bpfilter_ops.lock); |
| 119 | if (IS_ENABLED(CONFIG_INET)) { | ||
| 120 | shutdown_umh(); | ||
| 121 | bpfilter_ops.start = NULL; | ||
| 122 | bpfilter_ops.sockopt = NULL; | ||
| 123 | } | ||
| 124 | mutex_unlock(&bpfilter_ops.lock); | ||
| 117 | } | 125 | } |
| 118 | module_init(load_umh); | 126 | module_init(load_umh); |
| 119 | module_exit(fini_umh); | 127 | module_exit(fini_umh); |
diff --git a/net/bpfilter/bpfilter_umh_blob.S b/net/bpfilter/bpfilter_umh_blob.S index 40311d10d2f2..9ea6100dca87 100644 --- a/net/bpfilter/bpfilter_umh_blob.S +++ b/net/bpfilter/bpfilter_umh_blob.S | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
| 2 | .section .init.rodata, "a" | 2 | .section .rodata, "a" |
| 3 | .global bpfilter_umh_start | 3 | .global bpfilter_umh_start |
| 4 | bpfilter_umh_start: | 4 | bpfilter_umh_start: |
| 5 | .incbin "net/bpfilter/bpfilter_umh" | 5 | .incbin "net/bpfilter/bpfilter_umh" |
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index fe3c758791ca..9e14767500ea 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c | |||
| @@ -1128,6 +1128,8 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p, | |||
| 1128 | err = -ENOMEM; | 1128 | err = -ENOMEM; |
| 1129 | goto err_unlock; | 1129 | goto err_unlock; |
| 1130 | } | 1130 | } |
| 1131 | if (swdev_notify) | ||
| 1132 | fdb->added_by_user = 1; | ||
| 1131 | fdb->added_by_external_learn = 1; | 1133 | fdb->added_by_external_learn = 1; |
| 1132 | fdb_notify(br, fdb, RTM_NEWNEIGH, swdev_notify); | 1134 | fdb_notify(br, fdb, RTM_NEWNEIGH, swdev_notify); |
| 1133 | } else { | 1135 | } else { |
| @@ -1147,6 +1149,9 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p, | |||
| 1147 | modified = true; | 1149 | modified = true; |
| 1148 | } | 1150 | } |
| 1149 | 1151 | ||
| 1152 | if (swdev_notify) | ||
| 1153 | fdb->added_by_user = 1; | ||
| 1154 | |||
| 1150 | if (modified) | 1155 | if (modified) |
| 1151 | fdb_notify(br, fdb, RTM_NEWNEIGH, swdev_notify); | 1156 | fdb_notify(br, fdb, RTM_NEWNEIGH, swdev_notify); |
| 1152 | } | 1157 | } |
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c index 5372e2042adf..48ddc60b4fbd 100644 --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c | |||
| @@ -36,10 +36,10 @@ static inline int should_deliver(const struct net_bridge_port *p, | |||
| 36 | 36 | ||
| 37 | int br_dev_queue_push_xmit(struct net *net, struct sock *sk, struct sk_buff *skb) | 37 | int br_dev_queue_push_xmit(struct net *net, struct sock *sk, struct sk_buff *skb) |
| 38 | { | 38 | { |
| 39 | skb_push(skb, ETH_HLEN); | ||
| 39 | if (!is_skb_forwardable(skb->dev, skb)) | 40 | if (!is_skb_forwardable(skb->dev, skb)) |
| 40 | goto drop; | 41 | goto drop; |
| 41 | 42 | ||
| 42 | skb_push(skb, ETH_HLEN); | ||
| 43 | br_drop_fake_rtable(skb); | 43 | br_drop_fake_rtable(skb); |
| 44 | 44 | ||
| 45 | if (skb->ip_summed == CHECKSUM_PARTIAL && | 45 | if (skb->ip_summed == CHECKSUM_PARTIAL && |
| @@ -65,6 +65,7 @@ EXPORT_SYMBOL_GPL(br_dev_queue_push_xmit); | |||
| 65 | 65 | ||
| 66 | int br_forward_finish(struct net *net, struct sock *sk, struct sk_buff *skb) | 66 | int br_forward_finish(struct net *net, struct sock *sk, struct sk_buff *skb) |
| 67 | { | 67 | { |
| 68 | skb->tstamp = 0; | ||
| 68 | return NF_HOOK(NFPROTO_BRIDGE, NF_BR_POST_ROUTING, | 69 | return NF_HOOK(NFPROTO_BRIDGE, NF_BR_POST_ROUTING, |
| 69 | net, sk, skb, NULL, skb->dev, | 70 | net, sk, skb, NULL, skb->dev, |
| 70 | br_dev_queue_push_xmit); | 71 | br_dev_queue_push_xmit); |
| @@ -97,12 +98,11 @@ static void __br_forward(const struct net_bridge_port *to, | |||
| 97 | net = dev_net(indev); | 98 | net = dev_net(indev); |
| 98 | } else { | 99 | } else { |
| 99 | if (unlikely(netpoll_tx_running(to->br->dev))) { | 100 | if (unlikely(netpoll_tx_running(to->br->dev))) { |
| 100 | if (!is_skb_forwardable(skb->dev, skb)) { | 101 | skb_push(skb, ETH_HLEN); |
| 102 | if (!is_skb_forwardable(skb->dev, skb)) | ||
| 101 | kfree_skb(skb); | 103 | kfree_skb(skb); |
| 102 | } else { | 104 | else |
| 103 | skb_push(skb, ETH_HLEN); | ||
| 104 | br_netpoll_send_skb(to, skb); | 105 | br_netpoll_send_skb(to, skb); |
| 105 | } | ||
| 106 | return; | 106 | return; |
| 107 | } | 107 | } |
| 108 | br_hook = NF_BR_LOCAL_OUT; | 108 | br_hook = NF_BR_LOCAL_OUT; |
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 3aeff0895669..ac92b2eb32b1 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c | |||
| @@ -1204,14 +1204,7 @@ static void br_multicast_query_received(struct net_bridge *br, | |||
| 1204 | return; | 1204 | return; |
| 1205 | 1205 | ||
| 1206 | br_multicast_update_query_timer(br, query, max_delay); | 1206 | br_multicast_update_query_timer(br, query, max_delay); |
| 1207 | 1207 | br_multicast_mark_router(br, port); | |
| 1208 | /* Based on RFC4541, section 2.1.1 IGMP Forwarding Rules, | ||
| 1209 | * the arrival port for IGMP Queries where the source address | ||
| 1210 | * is 0.0.0.0 should not be added to router port list. | ||
| 1211 | */ | ||
| 1212 | if ((saddr->proto == htons(ETH_P_IP) && saddr->u.ip4) || | ||
| 1213 | saddr->proto == htons(ETH_P_IPV6)) | ||
| 1214 | br_multicast_mark_router(br, port); | ||
| 1215 | } | 1208 | } |
| 1216 | 1209 | ||
| 1217 | static void br_ip4_multicast_query(struct net_bridge *br, | 1210 | static void br_ip4_multicast_query(struct net_bridge *br, |
diff --git a/net/bridge/br_netfilter_hooks.c b/net/bridge/br_netfilter_hooks.c index d21a23698410..c93c35bb73dd 100644 --- a/net/bridge/br_netfilter_hooks.c +++ b/net/bridge/br_netfilter_hooks.c | |||
| @@ -265,7 +265,7 @@ int br_nf_pre_routing_finish_bridge(struct net *net, struct sock *sk, struct sk_ | |||
| 265 | struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb); | 265 | struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb); |
| 266 | int ret; | 266 | int ret; |
| 267 | 267 | ||
| 268 | if (neigh->hh.hh_len) { | 268 | if ((neigh->nud_state & NUD_CONNECTED) && neigh->hh.hh_len) { |
| 269 | neigh_hh_bridge(&neigh->hh, skb); | 269 | neigh_hh_bridge(&neigh->hh, skb); |
| 270 | skb->dev = nf_bridge->physindev; | 270 | skb->dev = nf_bridge->physindev; |
| 271 | ret = br_handle_frame_finish(net, sk, skb); | 271 | ret = br_handle_frame_finish(net, sk, skb); |
diff --git a/net/bridge/br_netfilter_ipv6.c b/net/bridge/br_netfilter_ipv6.c index 94039f588f1d..564710f88f93 100644 --- a/net/bridge/br_netfilter_ipv6.c +++ b/net/bridge/br_netfilter_ipv6.c | |||
| @@ -131,6 +131,7 @@ int br_validate_ipv6(struct net *net, struct sk_buff *skb) | |||
| 131 | IPSTATS_MIB_INDISCARDS); | 131 | IPSTATS_MIB_INDISCARDS); |
| 132 | goto drop; | 132 | goto drop; |
| 133 | } | 133 | } |
| 134 | hdr = ipv6_hdr(skb); | ||
| 134 | } | 135 | } |
| 135 | if (hdr->nexthdr == NEXTHDR_HOP && br_nf_check_hbh_len(skb)) | 136 | if (hdr->nexthdr == NEXTHDR_HOP && br_nf_check_hbh_len(skb)) |
| 136 | goto drop; | 137 | goto drop; |
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index d240b3e7919f..eabf8bf28a3f 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h | |||
| @@ -107,6 +107,7 @@ struct br_tunnel_info { | |||
| 107 | /* private vlan flags */ | 107 | /* private vlan flags */ |
| 108 | enum { | 108 | enum { |
| 109 | BR_VLFLAG_PER_PORT_STATS = BIT(0), | 109 | BR_VLFLAG_PER_PORT_STATS = BIT(0), |
| 110 | BR_VLFLAG_ADDED_BY_SWITCHDEV = BIT(1), | ||
| 110 | }; | 111 | }; |
| 111 | 112 | ||
| 112 | /** | 113 | /** |
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index 4a2f31157ef5..96abf8feb9dc 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c | |||
| @@ -80,16 +80,18 @@ static bool __vlan_add_flags(struct net_bridge_vlan *v, u16 flags) | |||
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | static int __vlan_vid_add(struct net_device *dev, struct net_bridge *br, | 82 | static int __vlan_vid_add(struct net_device *dev, struct net_bridge *br, |
| 83 | u16 vid, u16 flags, struct netlink_ext_ack *extack) | 83 | struct net_bridge_vlan *v, u16 flags, |
| 84 | struct netlink_ext_ack *extack) | ||
| 84 | { | 85 | { |
| 85 | int err; | 86 | int err; |
| 86 | 87 | ||
| 87 | /* Try switchdev op first. In case it is not supported, fallback to | 88 | /* Try switchdev op first. In case it is not supported, fallback to |
| 88 | * 8021q add. | 89 | * 8021q add. |
| 89 | */ | 90 | */ |
| 90 | err = br_switchdev_port_vlan_add(dev, vid, flags, extack); | 91 | err = br_switchdev_port_vlan_add(dev, v->vid, flags, extack); |
| 91 | if (err == -EOPNOTSUPP) | 92 | if (err == -EOPNOTSUPP) |
| 92 | return vlan_vid_add(dev, br->vlan_proto, vid); | 93 | return vlan_vid_add(dev, br->vlan_proto, v->vid); |
| 94 | v->priv_flags |= BR_VLFLAG_ADDED_BY_SWITCHDEV; | ||
| 93 | return err; | 95 | return err; |
| 94 | } | 96 | } |
| 95 | 97 | ||
| @@ -121,19 +123,17 @@ static void __vlan_del_list(struct net_bridge_vlan *v) | |||
| 121 | } | 123 | } |
| 122 | 124 | ||
| 123 | static int __vlan_vid_del(struct net_device *dev, struct net_bridge *br, | 125 | static int __vlan_vid_del(struct net_device *dev, struct net_bridge *br, |
| 124 | u16 vid) | 126 | const struct net_bridge_vlan *v) |
| 125 | { | 127 | { |
| 126 | int err; | 128 | int err; |
| 127 | 129 | ||
| 128 | /* Try switchdev op first. In case it is not supported, fallback to | 130 | /* Try switchdev op first. In case it is not supported, fallback to |
| 129 | * 8021q del. | 131 | * 8021q del. |
| 130 | */ | 132 | */ |
| 131 | err = br_switchdev_port_vlan_del(dev, vid); | 133 | err = br_switchdev_port_vlan_del(dev, v->vid); |
| 132 | if (err == -EOPNOTSUPP) { | 134 | if (!(v->priv_flags & BR_VLFLAG_ADDED_BY_SWITCHDEV)) |
| 133 | vlan_vid_del(dev, br->vlan_proto, vid); | 135 | vlan_vid_del(dev, br->vlan_proto, v->vid); |
| 134 | return 0; | 136 | return err == -EOPNOTSUPP ? 0 : err; |
| 135 | } | ||
| 136 | return err; | ||
| 137 | } | 137 | } |
| 138 | 138 | ||
| 139 | /* Returns a master vlan, if it didn't exist it gets created. In all cases a | 139 | /* Returns a master vlan, if it didn't exist it gets created. In all cases a |
| @@ -242,7 +242,7 @@ static int __vlan_add(struct net_bridge_vlan *v, u16 flags, | |||
| 242 | * This ensures tagged traffic enters the bridge when | 242 | * This ensures tagged traffic enters the bridge when |
| 243 | * promiscuous mode is disabled by br_manage_promisc(). | 243 | * promiscuous mode is disabled by br_manage_promisc(). |
| 244 | */ | 244 | */ |
| 245 | err = __vlan_vid_add(dev, br, v->vid, flags, extack); | 245 | err = __vlan_vid_add(dev, br, v, flags, extack); |
| 246 | if (err) | 246 | if (err) |
| 247 | goto out; | 247 | goto out; |
| 248 | 248 | ||
| @@ -305,7 +305,7 @@ out_fdb_insert: | |||
| 305 | 305 | ||
| 306 | out_filt: | 306 | out_filt: |
| 307 | if (p) { | 307 | if (p) { |
| 308 | __vlan_vid_del(dev, br, v->vid); | 308 | __vlan_vid_del(dev, br, v); |
| 309 | if (masterv) { | 309 | if (masterv) { |
| 310 | if (v->stats && masterv->stats != v->stats) | 310 | if (v->stats && masterv->stats != v->stats) |
| 311 | free_percpu(v->stats); | 311 | free_percpu(v->stats); |
| @@ -338,7 +338,7 @@ static int __vlan_del(struct net_bridge_vlan *v) | |||
| 338 | 338 | ||
| 339 | __vlan_delete_pvid(vg, v->vid); | 339 | __vlan_delete_pvid(vg, v->vid); |
| 340 | if (p) { | 340 | if (p) { |
| 341 | err = __vlan_vid_del(p->dev, p->br, v->vid); | 341 | err = __vlan_vid_del(p->dev, p->br, v); |
| 342 | if (err) | 342 | if (err) |
| 343 | goto out; | 343 | goto out; |
| 344 | } else { | 344 | } else { |
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 491828713e0b..6693e209efe8 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c | |||
| @@ -1137,14 +1137,16 @@ static int do_replace(struct net *net, const void __user *user, | |||
| 1137 | tmp.name[sizeof(tmp.name) - 1] = 0; | 1137 | tmp.name[sizeof(tmp.name) - 1] = 0; |
| 1138 | 1138 | ||
| 1139 | countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids; | 1139 | countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids; |
| 1140 | newinfo = vmalloc(sizeof(*newinfo) + countersize); | 1140 | newinfo = __vmalloc(sizeof(*newinfo) + countersize, GFP_KERNEL_ACCOUNT, |
| 1141 | PAGE_KERNEL); | ||
| 1141 | if (!newinfo) | 1142 | if (!newinfo) |
| 1142 | return -ENOMEM; | 1143 | return -ENOMEM; |
| 1143 | 1144 | ||
| 1144 | if (countersize) | 1145 | if (countersize) |
| 1145 | memset(newinfo->counters, 0, countersize); | 1146 | memset(newinfo->counters, 0, countersize); |
| 1146 | 1147 | ||
| 1147 | newinfo->entries = vmalloc(tmp.entries_size); | 1148 | newinfo->entries = __vmalloc(tmp.entries_size, GFP_KERNEL_ACCOUNT, |
| 1149 | PAGE_KERNEL); | ||
| 1148 | if (!newinfo->entries) { | 1150 | if (!newinfo->entries) { |
| 1149 | ret = -ENOMEM; | 1151 | ret = -ENOMEM; |
| 1150 | goto free_newinfo; | 1152 | goto free_newinfo; |
| @@ -2291,9 +2293,12 @@ static int compat_do_replace(struct net *net, void __user *user, | |||
| 2291 | 2293 | ||
| 2292 | xt_compat_lock(NFPROTO_BRIDGE); | 2294 | xt_compat_lock(NFPROTO_BRIDGE); |
| 2293 | 2295 | ||
| 2294 | ret = xt_compat_init_offsets(NFPROTO_BRIDGE, tmp.nentries); | 2296 | if (tmp.nentries) { |
| 2295 | if (ret < 0) | 2297 | ret = xt_compat_init_offsets(NFPROTO_BRIDGE, tmp.nentries); |
| 2296 | goto out_unlock; | 2298 | if (ret < 0) |
| 2299 | goto out_unlock; | ||
| 2300 | } | ||
| 2301 | |||
| 2297 | ret = compat_copy_entries(entries_tmp, tmp.entries_size, &state); | 2302 | ret = compat_copy_entries(entries_tmp, tmp.entries_size, &state); |
| 2298 | if (ret < 0) | 2303 | if (ret < 0) |
| 2299 | goto out_unlock; | 2304 | goto out_unlock; |
diff --git a/net/bridge/netfilter/nft_reject_bridge.c b/net/bridge/netfilter/nft_reject_bridge.c index 08cbed7d940e..419e8edf23ba 100644 --- a/net/bridge/netfilter/nft_reject_bridge.c +++ b/net/bridge/netfilter/nft_reject_bridge.c | |||
| @@ -229,6 +229,7 @@ static bool reject6_br_csum_ok(struct sk_buff *skb, int hook) | |||
| 229 | pskb_trim_rcsum(skb, ntohs(ip6h->payload_len) + sizeof(*ip6h))) | 229 | pskb_trim_rcsum(skb, ntohs(ip6h->payload_len) + sizeof(*ip6h))) |
| 230 | return false; | 230 | return false; |
| 231 | 231 | ||
| 232 | ip6h = ipv6_hdr(skb); | ||
| 232 | thoff = ipv6_skip_exthdr(skb, ((u8*)(ip6h+1) - skb->data), &proto, &fo); | 233 | thoff = ipv6_skip_exthdr(skb, ((u8*)(ip6h+1) - skb->data), &proto, &fo); |
| 233 | if (thoff < 0 || thoff >= skb->len || (fo & htons(~0x7)) != 0) | 234 | if (thoff < 0 || thoff >= skb->len || (fo & htons(~0x7)) != 0) |
| 234 | return false; | 235 | return false; |
diff --git a/net/can/bcm.c b/net/can/bcm.c index 0af8f0db892a..79bb8afa9c0c 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c | |||
| @@ -67,6 +67,9 @@ | |||
| 67 | */ | 67 | */ |
| 68 | #define MAX_NFRAMES 256 | 68 | #define MAX_NFRAMES 256 |
| 69 | 69 | ||
| 70 | /* limit timers to 400 days for sending/timeouts */ | ||
| 71 | #define BCM_TIMER_SEC_MAX (400 * 24 * 60 * 60) | ||
| 72 | |||
| 70 | /* use of last_frames[index].flags */ | 73 | /* use of last_frames[index].flags */ |
| 71 | #define RX_RECV 0x40 /* received data for this element */ | 74 | #define RX_RECV 0x40 /* received data for this element */ |
| 72 | #define RX_THR 0x80 /* element not been sent due to throttle feature */ | 75 | #define RX_THR 0x80 /* element not been sent due to throttle feature */ |
| @@ -140,6 +143,22 @@ static inline ktime_t bcm_timeval_to_ktime(struct bcm_timeval tv) | |||
| 140 | return ktime_set(tv.tv_sec, tv.tv_usec * NSEC_PER_USEC); | 143 | return ktime_set(tv.tv_sec, tv.tv_usec * NSEC_PER_USEC); |
| 141 | } | 144 | } |
| 142 | 145 | ||
| 146 | /* check limitations for timeval provided by user */ | ||
| 147 | static bool bcm_is_invalid_tv(struct bcm_msg_head *msg_head) | ||
| 148 | { | ||
| 149 | if ((msg_head->ival1.tv_sec < 0) || | ||
| 150 | (msg_head->ival1.tv_sec > BCM_TIMER_SEC_MAX) || | ||
| 151 | (msg_head->ival1.tv_usec < 0) || | ||
| 152 | (msg_head->ival1.tv_usec >= USEC_PER_SEC) || | ||
| 153 | (msg_head->ival2.tv_sec < 0) || | ||
| 154 | (msg_head->ival2.tv_sec > BCM_TIMER_SEC_MAX) || | ||
| 155 | (msg_head->ival2.tv_usec < 0) || | ||
| 156 | (msg_head->ival2.tv_usec >= USEC_PER_SEC)) | ||
| 157 | return true; | ||
| 158 | |||
| 159 | return false; | ||
| 160 | } | ||
| 161 | |||
| 143 | #define CFSIZ(flags) ((flags & CAN_FD_FRAME) ? CANFD_MTU : CAN_MTU) | 162 | #define CFSIZ(flags) ((flags & CAN_FD_FRAME) ? CANFD_MTU : CAN_MTU) |
| 144 | #define OPSIZ sizeof(struct bcm_op) | 163 | #define OPSIZ sizeof(struct bcm_op) |
| 145 | #define MHSIZ sizeof(struct bcm_msg_head) | 164 | #define MHSIZ sizeof(struct bcm_msg_head) |
| @@ -873,6 +892,10 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, | |||
| 873 | if (msg_head->nframes < 1 || msg_head->nframes > MAX_NFRAMES) | 892 | if (msg_head->nframes < 1 || msg_head->nframes > MAX_NFRAMES) |
| 874 | return -EINVAL; | 893 | return -EINVAL; |
| 875 | 894 | ||
| 895 | /* check timeval limitations */ | ||
| 896 | if ((msg_head->flags & SETTIMER) && bcm_is_invalid_tv(msg_head)) | ||
| 897 | return -EINVAL; | ||
| 898 | |||
| 876 | /* check the given can_id */ | 899 | /* check the given can_id */ |
| 877 | op = bcm_find_op(&bo->tx_ops, msg_head, ifindex); | 900 | op = bcm_find_op(&bo->tx_ops, msg_head, ifindex); |
| 878 | if (op) { | 901 | if (op) { |
| @@ -1053,6 +1076,10 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, | |||
| 1053 | (!(msg_head->can_id & CAN_RTR_FLAG)))) | 1076 | (!(msg_head->can_id & CAN_RTR_FLAG)))) |
| 1054 | return -EINVAL; | 1077 | return -EINVAL; |
| 1055 | 1078 | ||
| 1079 | /* check timeval limitations */ | ||
| 1080 | if ((msg_head->flags & SETTIMER) && bcm_is_invalid_tv(msg_head)) | ||
| 1081 | return -EINVAL; | ||
| 1082 | |||
| 1056 | /* check the given can_id */ | 1083 | /* check the given can_id */ |
| 1057 | op = bcm_find_op(&bo->rx_ops, msg_head, ifindex); | 1084 | op = bcm_find_op(&bo->rx_ops, msg_head, ifindex); |
| 1058 | if (op) { | 1085 | if (op) { |
diff --git a/net/can/gw.c b/net/can/gw.c index faa3da88a127..53859346dc9a 100644 --- a/net/can/gw.c +++ b/net/can/gw.c | |||
| @@ -416,13 +416,29 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data) | |||
| 416 | while (modidx < MAX_MODFUNCTIONS && gwj->mod.modfunc[modidx]) | 416 | while (modidx < MAX_MODFUNCTIONS && gwj->mod.modfunc[modidx]) |
| 417 | (*gwj->mod.modfunc[modidx++])(cf, &gwj->mod); | 417 | (*gwj->mod.modfunc[modidx++])(cf, &gwj->mod); |
| 418 | 418 | ||
| 419 | /* check for checksum updates when the CAN frame has been modified */ | 419 | /* Has the CAN frame been modified? */ |
| 420 | if (modidx) { | 420 | if (modidx) { |
| 421 | if (gwj->mod.csumfunc.crc8) | 421 | /* get available space for the processed CAN frame type */ |
| 422 | int max_len = nskb->len - offsetof(struct can_frame, data); | ||
| 423 | |||
| 424 | /* dlc may have changed, make sure it fits to the CAN frame */ | ||
| 425 | if (cf->can_dlc > max_len) | ||
| 426 | goto out_delete; | ||
| 427 | |||
| 428 | /* check for checksum updates in classic CAN length only */ | ||
| 429 | if (gwj->mod.csumfunc.crc8) { | ||
| 430 | if (cf->can_dlc > 8) | ||
| 431 | goto out_delete; | ||
| 432 | |||
| 422 | (*gwj->mod.csumfunc.crc8)(cf, &gwj->mod.csum.crc8); | 433 | (*gwj->mod.csumfunc.crc8)(cf, &gwj->mod.csum.crc8); |
| 434 | } | ||
| 435 | |||
| 436 | if (gwj->mod.csumfunc.xor) { | ||
| 437 | if (cf->can_dlc > 8) | ||
| 438 | goto out_delete; | ||
| 423 | 439 | ||
| 424 | if (gwj->mod.csumfunc.xor) | ||
| 425 | (*gwj->mod.csumfunc.xor)(cf, &gwj->mod.csum.xor); | 440 | (*gwj->mod.csumfunc.xor)(cf, &gwj->mod.csum.xor); |
| 441 | } | ||
| 426 | } | 442 | } |
| 427 | 443 | ||
| 428 | /* clear the skb timestamp if not configured the other way */ | 444 | /* clear the skb timestamp if not configured the other way */ |
| @@ -434,6 +450,14 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data) | |||
| 434 | gwj->dropped_frames++; | 450 | gwj->dropped_frames++; |
| 435 | else | 451 | else |
| 436 | gwj->handled_frames++; | 452 | gwj->handled_frames++; |
| 453 | |||
| 454 | return; | ||
| 455 | |||
| 456 | out_delete: | ||
| 457 | /* delete frame due to misconfiguration */ | ||
| 458 | gwj->deleted_frames++; | ||
| 459 | kfree_skb(nskb); | ||
| 460 | return; | ||
| 437 | } | 461 | } |
| 438 | 462 | ||
| 439 | static inline int cgw_register_filter(struct net *net, struct cgw_job *gwj) | 463 | static inline int cgw_register_filter(struct net *net, struct cgw_job *gwj) |
diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c index 87afb9ec4c68..9cab80207ced 100644 --- a/net/ceph/ceph_common.c +++ b/net/ceph/ceph_common.c | |||
| @@ -255,6 +255,7 @@ enum { | |||
| 255 | Opt_nocephx_sign_messages, | 255 | Opt_nocephx_sign_messages, |
| 256 | Opt_tcp_nodelay, | 256 | Opt_tcp_nodelay, |
| 257 | Opt_notcp_nodelay, | 257 | Opt_notcp_nodelay, |
| 258 | Opt_abort_on_full, | ||
| 258 | }; | 259 | }; |
| 259 | 260 | ||
| 260 | static match_table_t opt_tokens = { | 261 | static match_table_t opt_tokens = { |
| @@ -280,6 +281,7 @@ static match_table_t opt_tokens = { | |||
| 280 | {Opt_nocephx_sign_messages, "nocephx_sign_messages"}, | 281 | {Opt_nocephx_sign_messages, "nocephx_sign_messages"}, |
| 281 | {Opt_tcp_nodelay, "tcp_nodelay"}, | 282 | {Opt_tcp_nodelay, "tcp_nodelay"}, |
| 282 | {Opt_notcp_nodelay, "notcp_nodelay"}, | 283 | {Opt_notcp_nodelay, "notcp_nodelay"}, |
| 284 | {Opt_abort_on_full, "abort_on_full"}, | ||
| 283 | {-1, NULL} | 285 | {-1, NULL} |
| 284 | }; | 286 | }; |
| 285 | 287 | ||
| @@ -535,6 +537,10 @@ ceph_parse_options(char *options, const char *dev_name, | |||
| 535 | opt->flags &= ~CEPH_OPT_TCP_NODELAY; | 537 | opt->flags &= ~CEPH_OPT_TCP_NODELAY; |
| 536 | break; | 538 | break; |
| 537 | 539 | ||
| 540 | case Opt_abort_on_full: | ||
| 541 | opt->flags |= CEPH_OPT_ABORT_ON_FULL; | ||
| 542 | break; | ||
| 543 | |||
| 538 | default: | 544 | default: |
| 539 | BUG_ON(token); | 545 | BUG_ON(token); |
| 540 | } | 546 | } |
| @@ -549,7 +555,8 @@ out: | |||
| 549 | } | 555 | } |
| 550 | EXPORT_SYMBOL(ceph_parse_options); | 556 | EXPORT_SYMBOL(ceph_parse_options); |
| 551 | 557 | ||
| 552 | int ceph_print_client_options(struct seq_file *m, struct ceph_client *client) | 558 | int ceph_print_client_options(struct seq_file *m, struct ceph_client *client, |
| 559 | bool show_all) | ||
| 553 | { | 560 | { |
| 554 | struct ceph_options *opt = client->options; | 561 | struct ceph_options *opt = client->options; |
| 555 | size_t pos = m->count; | 562 | size_t pos = m->count; |
| @@ -574,6 +581,8 @@ int ceph_print_client_options(struct seq_file *m, struct ceph_client *client) | |||
| 574 | seq_puts(m, "nocephx_sign_messages,"); | 581 | seq_puts(m, "nocephx_sign_messages,"); |
| 575 | if ((opt->flags & CEPH_OPT_TCP_NODELAY) == 0) | 582 | if ((opt->flags & CEPH_OPT_TCP_NODELAY) == 0) |
| 576 | seq_puts(m, "notcp_nodelay,"); | 583 | seq_puts(m, "notcp_nodelay,"); |
| 584 | if (show_all && (opt->flags & CEPH_OPT_ABORT_ON_FULL)) | ||
| 585 | seq_puts(m, "abort_on_full,"); | ||
| 577 | 586 | ||
| 578 | if (opt->mount_timeout != CEPH_MOUNT_TIMEOUT_DEFAULT) | 587 | if (opt->mount_timeout != CEPH_MOUNT_TIMEOUT_DEFAULT) |
| 579 | seq_printf(m, "mount_timeout=%d,", | 588 | seq_printf(m, "mount_timeout=%d,", |
diff --git a/net/ceph/debugfs.c b/net/ceph/debugfs.c index 02952605d121..46f65709a6ff 100644 --- a/net/ceph/debugfs.c +++ b/net/ceph/debugfs.c | |||
| @@ -375,7 +375,7 @@ static int client_options_show(struct seq_file *s, void *p) | |||
| 375 | struct ceph_client *client = s->private; | 375 | struct ceph_client *client = s->private; |
| 376 | int ret; | 376 | int ret; |
| 377 | 377 | ||
| 378 | ret = ceph_print_client_options(s, client); | 378 | ret = ceph_print_client_options(s, client, true); |
| 379 | if (ret) | 379 | if (ret) |
| 380 | return ret; | 380 | return ret; |
| 381 | 381 | ||
diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index d5718284db57..7e71b0df1fbc 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c | |||
| @@ -2058,6 +2058,8 @@ static int process_connect(struct ceph_connection *con) | |||
| 2058 | dout("process_connect on %p tag %d\n", con, (int)con->in_tag); | 2058 | dout("process_connect on %p tag %d\n", con, (int)con->in_tag); |
| 2059 | 2059 | ||
| 2060 | if (con->auth) { | 2060 | if (con->auth) { |
| 2061 | int len = le32_to_cpu(con->in_reply.authorizer_len); | ||
| 2062 | |||
| 2061 | /* | 2063 | /* |
| 2062 | * Any connection that defines ->get_authorizer() | 2064 | * Any connection that defines ->get_authorizer() |
| 2063 | * should also define ->add_authorizer_challenge() and | 2065 | * should also define ->add_authorizer_challenge() and |
| @@ -2067,8 +2069,7 @@ static int process_connect(struct ceph_connection *con) | |||
| 2067 | */ | 2069 | */ |
| 2068 | if (con->in_reply.tag == CEPH_MSGR_TAG_CHALLENGE_AUTHORIZER) { | 2070 | if (con->in_reply.tag == CEPH_MSGR_TAG_CHALLENGE_AUTHORIZER) { |
| 2069 | ret = con->ops->add_authorizer_challenge( | 2071 | ret = con->ops->add_authorizer_challenge( |
| 2070 | con, con->auth->authorizer_reply_buf, | 2072 | con, con->auth->authorizer_reply_buf, len); |
| 2071 | le32_to_cpu(con->in_reply.authorizer_len)); | ||
| 2072 | if (ret < 0) | 2073 | if (ret < 0) |
| 2073 | return ret; | 2074 | return ret; |
| 2074 | 2075 | ||
| @@ -2078,10 +2079,12 @@ static int process_connect(struct ceph_connection *con) | |||
| 2078 | return 0; | 2079 | return 0; |
| 2079 | } | 2080 | } |
| 2080 | 2081 | ||
| 2081 | ret = con->ops->verify_authorizer_reply(con); | 2082 | if (len) { |
| 2082 | if (ret < 0) { | 2083 | ret = con->ops->verify_authorizer_reply(con); |
| 2083 | con->error_msg = "bad authorize reply"; | 2084 | if (ret < 0) { |
| 2084 | return ret; | 2085 | con->error_msg = "bad authorize reply"; |
| 2086 | return ret; | ||
| 2087 | } | ||
| 2085 | } | 2088 | } |
| 2086 | } | 2089 | } |
| 2087 | 2090 | ||
| @@ -3206,9 +3209,10 @@ void ceph_con_keepalive(struct ceph_connection *con) | |||
| 3206 | dout("con_keepalive %p\n", con); | 3209 | dout("con_keepalive %p\n", con); |
| 3207 | mutex_lock(&con->mutex); | 3210 | mutex_lock(&con->mutex); |
| 3208 | clear_standby(con); | 3211 | clear_standby(con); |
| 3212 | con_flag_set(con, CON_FLAG_KEEPALIVE_PENDING); | ||
| 3209 | mutex_unlock(&con->mutex); | 3213 | mutex_unlock(&con->mutex); |
| 3210 | if (con_flag_test_and_set(con, CON_FLAG_KEEPALIVE_PENDING) == 0 && | 3214 | |
| 3211 | con_flag_test_and_set(con, CON_FLAG_WRITE_PENDING) == 0) | 3215 | if (con_flag_test_and_set(con, CON_FLAG_WRITE_PENDING) == 0) |
| 3212 | queue_con(con); | 3216 | queue_con(con); |
| 3213 | } | 3217 | } |
| 3214 | EXPORT_SYMBOL(ceph_con_keepalive); | 3218 | EXPORT_SYMBOL(ceph_con_keepalive); |
diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index d23a9f81f3d7..fa9530dd876e 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c | |||
| @@ -2315,7 +2315,7 @@ again: | |||
| 2315 | (ceph_osdmap_flag(osdc, CEPH_OSDMAP_FULL) || | 2315 | (ceph_osdmap_flag(osdc, CEPH_OSDMAP_FULL) || |
| 2316 | pool_full(osdc, req->r_t.base_oloc.pool))) { | 2316 | pool_full(osdc, req->r_t.base_oloc.pool))) { |
| 2317 | dout("req %p full/pool_full\n", req); | 2317 | dout("req %p full/pool_full\n", req); |
| 2318 | if (osdc->abort_on_full) { | 2318 | if (ceph_test_opt(osdc->client, ABORT_ON_FULL)) { |
| 2319 | err = -ENOSPC; | 2319 | err = -ENOSPC; |
| 2320 | } else { | 2320 | } else { |
| 2321 | pr_warn_ratelimited("FULL or reached pool quota\n"); | 2321 | pr_warn_ratelimited("FULL or reached pool quota\n"); |
| @@ -2545,7 +2545,7 @@ static void ceph_osdc_abort_on_full(struct ceph_osd_client *osdc) | |||
| 2545 | { | 2545 | { |
| 2546 | bool victims = false; | 2546 | bool victims = false; |
| 2547 | 2547 | ||
| 2548 | if (osdc->abort_on_full && | 2548 | if (ceph_test_opt(osdc->client, ABORT_ON_FULL) && |
| 2549 | (ceph_osdmap_flag(osdc, CEPH_OSDMAP_FULL) || have_pool_full(osdc))) | 2549 | (ceph_osdmap_flag(osdc, CEPH_OSDMAP_FULL) || have_pool_full(osdc))) |
| 2550 | for_each_request(osdc, abort_on_full_fn, &victims); | 2550 | for_each_request(osdc, abort_on_full_fn, &victims); |
| 2551 | } | 2551 | } |
diff --git a/net/compat.c b/net/compat.c index 959d1c51826d..3d348198004f 100644 --- a/net/compat.c +++ b/net/compat.c | |||
| @@ -388,8 +388,12 @@ static int __compat_sys_setsockopt(int fd, int level, int optname, | |||
| 388 | char __user *optval, unsigned int optlen) | 388 | char __user *optval, unsigned int optlen) |
| 389 | { | 389 | { |
| 390 | int err; | 390 | int err; |
| 391 | struct socket *sock = sockfd_lookup(fd, &err); | 391 | struct socket *sock; |
| 392 | |||
| 393 | if (optlen > INT_MAX) | ||
| 394 | return -EINVAL; | ||
| 392 | 395 | ||
| 396 | sock = sockfd_lookup(fd, &err); | ||
| 393 | if (sock) { | 397 | if (sock) { |
| 394 | err = security_socket_setsockopt(sock, level, optname); | 398 | err = security_socket_setsockopt(sock, level, optname); |
| 395 | if (err) { | 399 | if (err) { |
diff --git a/net/core/dev.c b/net/core/dev.c index 82f20022259d..5d03889502eb 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
| @@ -8152,7 +8152,7 @@ static netdev_features_t netdev_sync_upper_features(struct net_device *lower, | |||
| 8152 | netdev_features_t feature; | 8152 | netdev_features_t feature; |
| 8153 | int feature_bit; | 8153 | int feature_bit; |
| 8154 | 8154 | ||
| 8155 | for_each_netdev_feature(&upper_disables, feature_bit) { | 8155 | for_each_netdev_feature(upper_disables, feature_bit) { |
| 8156 | feature = __NETIF_F_BIT(feature_bit); | 8156 | feature = __NETIF_F_BIT(feature_bit); |
| 8157 | if (!(upper->wanted_features & feature) | 8157 | if (!(upper->wanted_features & feature) |
| 8158 | && (features & feature)) { | 8158 | && (features & feature)) { |
| @@ -8172,7 +8172,7 @@ static void netdev_sync_lower_features(struct net_device *upper, | |||
| 8172 | netdev_features_t feature; | 8172 | netdev_features_t feature; |
| 8173 | int feature_bit; | 8173 | int feature_bit; |
| 8174 | 8174 | ||
| 8175 | for_each_netdev_feature(&upper_disables, feature_bit) { | 8175 | for_each_netdev_feature(upper_disables, feature_bit) { |
| 8176 | feature = __NETIF_F_BIT(feature_bit); | 8176 | feature = __NETIF_F_BIT(feature_bit); |
| 8177 | if (!(features & feature) && (lower->features & feature)) { | 8177 | if (!(features & feature) && (lower->features & feature)) { |
| 8178 | netdev_dbg(upper, "Disabling feature %pNF on lower dev %s.\n", | 8178 | netdev_dbg(upper, "Disabling feature %pNF on lower dev %s.\n", |
| @@ -8712,6 +8712,9 @@ int init_dummy_netdev(struct net_device *dev) | |||
| 8712 | set_bit(__LINK_STATE_PRESENT, &dev->state); | 8712 | set_bit(__LINK_STATE_PRESENT, &dev->state); |
| 8713 | set_bit(__LINK_STATE_START, &dev->state); | 8713 | set_bit(__LINK_STATE_START, &dev->state); |
| 8714 | 8714 | ||
| 8715 | /* napi_busy_loop stats accounting wants this */ | ||
| 8716 | dev_net_set(dev, &init_net); | ||
| 8717 | |||
| 8715 | /* Note : We dont allocate pcpu_refcnt for dummy devices, | 8718 | /* Note : We dont allocate pcpu_refcnt for dummy devices, |
| 8716 | * because users of this 'device' dont need to change | 8719 | * because users of this 'device' dont need to change |
| 8717 | * its refcount. | 8720 | * its refcount. |
diff --git a/net/core/filter.c b/net/core/filter.c index 447dd1bad31f..f7d0004fc160 100644 --- a/net/core/filter.c +++ b/net/core/filter.c | |||
| @@ -2020,18 +2020,19 @@ static inline int __bpf_tx_skb(struct net_device *dev, struct sk_buff *skb) | |||
| 2020 | static int __bpf_redirect_no_mac(struct sk_buff *skb, struct net_device *dev, | 2020 | static int __bpf_redirect_no_mac(struct sk_buff *skb, struct net_device *dev, |
| 2021 | u32 flags) | 2021 | u32 flags) |
| 2022 | { | 2022 | { |
| 2023 | /* skb->mac_len is not set on normal egress */ | 2023 | unsigned int mlen = skb_network_offset(skb); |
| 2024 | unsigned int mlen = skb->network_header - skb->mac_header; | ||
| 2025 | 2024 | ||
| 2026 | __skb_pull(skb, mlen); | 2025 | if (mlen) { |
| 2026 | __skb_pull(skb, mlen); | ||
| 2027 | 2027 | ||
| 2028 | /* At ingress, the mac header has already been pulled once. | 2028 | /* At ingress, the mac header has already been pulled once. |
| 2029 | * At egress, skb_pospull_rcsum has to be done in case that | 2029 | * At egress, skb_pospull_rcsum has to be done in case that |
| 2030 | * the skb is originated from ingress (i.e. a forwarded skb) | 2030 | * the skb is originated from ingress (i.e. a forwarded skb) |
| 2031 | * to ensure that rcsum starts at net header. | 2031 | * to ensure that rcsum starts at net header. |
| 2032 | */ | 2032 | */ |
| 2033 | if (!skb_at_tc_ingress(skb)) | 2033 | if (!skb_at_tc_ingress(skb)) |
| 2034 | skb_postpull_rcsum(skb, skb_mac_header(skb), mlen); | 2034 | skb_postpull_rcsum(skb, skb_mac_header(skb), mlen); |
| 2035 | } | ||
| 2035 | skb_pop_mac_header(skb); | 2036 | skb_pop_mac_header(skb); |
| 2036 | skb_reset_mac_len(skb); | 2037 | skb_reset_mac_len(skb); |
| 2037 | return flags & BPF_F_INGRESS ? | 2038 | return flags & BPF_F_INGRESS ? |
| @@ -2788,8 +2789,7 @@ static int bpf_skb_proto_4_to_6(struct sk_buff *skb) | |||
| 2788 | u32 off = skb_mac_header_len(skb); | 2789 | u32 off = skb_mac_header_len(skb); |
| 2789 | int ret; | 2790 | int ret; |
| 2790 | 2791 | ||
| 2791 | /* SCTP uses GSO_BY_FRAGS, thus cannot adjust it. */ | 2792 | if (!skb_is_gso_tcp(skb)) |
| 2792 | if (skb_is_gso(skb) && unlikely(skb_is_gso_sctp(skb))) | ||
| 2793 | return -ENOTSUPP; | 2793 | return -ENOTSUPP; |
| 2794 | 2794 | ||
| 2795 | ret = skb_cow(skb, len_diff); | 2795 | ret = skb_cow(skb, len_diff); |
| @@ -2830,8 +2830,7 @@ static int bpf_skb_proto_6_to_4(struct sk_buff *skb) | |||
| 2830 | u32 off = skb_mac_header_len(skb); | 2830 | u32 off = skb_mac_header_len(skb); |
| 2831 | int ret; | 2831 | int ret; |
| 2832 | 2832 | ||
| 2833 | /* SCTP uses GSO_BY_FRAGS, thus cannot adjust it. */ | 2833 | if (!skb_is_gso_tcp(skb)) |
| 2834 | if (skb_is_gso(skb) && unlikely(skb_is_gso_sctp(skb))) | ||
| 2835 | return -ENOTSUPP; | 2834 | return -ENOTSUPP; |
| 2836 | 2835 | ||
| 2837 | ret = skb_unclone(skb, GFP_ATOMIC); | 2836 | ret = skb_unclone(skb, GFP_ATOMIC); |
| @@ -2956,8 +2955,7 @@ static int bpf_skb_net_grow(struct sk_buff *skb, u32 len_diff) | |||
| 2956 | u32 off = skb_mac_header_len(skb) + bpf_skb_net_base_len(skb); | 2955 | u32 off = skb_mac_header_len(skb) + bpf_skb_net_base_len(skb); |
| 2957 | int ret; | 2956 | int ret; |
| 2958 | 2957 | ||
| 2959 | /* SCTP uses GSO_BY_FRAGS, thus cannot adjust it. */ | 2958 | if (!skb_is_gso_tcp(skb)) |
| 2960 | if (skb_is_gso(skb) && unlikely(skb_is_gso_sctp(skb))) | ||
| 2961 | return -ENOTSUPP; | 2959 | return -ENOTSUPP; |
| 2962 | 2960 | ||
| 2963 | ret = skb_cow(skb, len_diff); | 2961 | ret = skb_cow(skb, len_diff); |
| @@ -2986,8 +2984,7 @@ static int bpf_skb_net_shrink(struct sk_buff *skb, u32 len_diff) | |||
| 2986 | u32 off = skb_mac_header_len(skb) + bpf_skb_net_base_len(skb); | 2984 | u32 off = skb_mac_header_len(skb) + bpf_skb_net_base_len(skb); |
| 2987 | int ret; | 2985 | int ret; |
| 2988 | 2986 | ||
| 2989 | /* SCTP uses GSO_BY_FRAGS, thus cannot adjust it. */ | 2987 | if (!skb_is_gso_tcp(skb)) |
| 2990 | if (skb_is_gso(skb) && unlikely(skb_is_gso_sctp(skb))) | ||
| 2991 | return -ENOTSUPP; | 2988 | return -ENOTSUPP; |
| 2992 | 2989 | ||
| 2993 | ret = skb_unclone(skb, GFP_ATOMIC); | 2990 | ret = skb_unclone(skb, GFP_ATOMIC); |
| @@ -4111,14 +4108,20 @@ BPF_CALL_5(bpf_setsockopt, struct bpf_sock_ops_kern *, bpf_sock, | |||
| 4111 | /* Only some socketops are supported */ | 4108 | /* Only some socketops are supported */ |
| 4112 | switch (optname) { | 4109 | switch (optname) { |
| 4113 | case SO_RCVBUF: | 4110 | case SO_RCVBUF: |
| 4111 | val = min_t(u32, val, sysctl_rmem_max); | ||
| 4114 | sk->sk_userlocks |= SOCK_RCVBUF_LOCK; | 4112 | sk->sk_userlocks |= SOCK_RCVBUF_LOCK; |
| 4115 | sk->sk_rcvbuf = max_t(int, val * 2, SOCK_MIN_RCVBUF); | 4113 | sk->sk_rcvbuf = max_t(int, val * 2, SOCK_MIN_RCVBUF); |
| 4116 | break; | 4114 | break; |
| 4117 | case SO_SNDBUF: | 4115 | case SO_SNDBUF: |
| 4116 | val = min_t(u32, val, sysctl_wmem_max); | ||
| 4118 | sk->sk_userlocks |= SOCK_SNDBUF_LOCK; | 4117 | sk->sk_userlocks |= SOCK_SNDBUF_LOCK; |
| 4119 | sk->sk_sndbuf = max_t(int, val * 2, SOCK_MIN_SNDBUF); | 4118 | sk->sk_sndbuf = max_t(int, val * 2, SOCK_MIN_SNDBUF); |
| 4120 | break; | 4119 | break; |
| 4121 | case SO_MAX_PACING_RATE: /* 32bit version */ | 4120 | case SO_MAX_PACING_RATE: /* 32bit version */ |
| 4121 | if (val != ~0U) | ||
| 4122 | cmpxchg(&sk->sk_pacing_status, | ||
| 4123 | SK_PACING_NONE, | ||
| 4124 | SK_PACING_NEEDED); | ||
| 4122 | sk->sk_max_pacing_rate = (val == ~0U) ? ~0UL : val; | 4125 | sk->sk_max_pacing_rate = (val == ~0U) ? ~0UL : val; |
| 4123 | sk->sk_pacing_rate = min(sk->sk_pacing_rate, | 4126 | sk->sk_pacing_rate = min(sk->sk_pacing_rate, |
| 4124 | sk->sk_max_pacing_rate); | 4127 | sk->sk_max_pacing_rate); |
| @@ -4132,7 +4135,10 @@ BPF_CALL_5(bpf_setsockopt, struct bpf_sock_ops_kern *, bpf_sock, | |||
| 4132 | sk->sk_rcvlowat = val ? : 1; | 4135 | sk->sk_rcvlowat = val ? : 1; |
| 4133 | break; | 4136 | break; |
| 4134 | case SO_MARK: | 4137 | case SO_MARK: |
| 4135 | sk->sk_mark = val; | 4138 | if (sk->sk_mark != val) { |
| 4139 | sk->sk_mark = val; | ||
| 4140 | sk_dst_reset(sk); | ||
| 4141 | } | ||
| 4136 | break; | 4142 | break; |
| 4137 | default: | 4143 | default: |
| 4138 | ret = -EINVAL; | 4144 | ret = -EINVAL; |
| @@ -4203,7 +4209,7 @@ BPF_CALL_5(bpf_setsockopt, struct bpf_sock_ops_kern *, bpf_sock, | |||
| 4203 | /* Only some options are supported */ | 4209 | /* Only some options are supported */ |
| 4204 | switch (optname) { | 4210 | switch (optname) { |
| 4205 | case TCP_BPF_IW: | 4211 | case TCP_BPF_IW: |
| 4206 | if (val <= 0 || tp->data_segs_out > 0) | 4212 | if (val <= 0 || tp->data_segs_out > tp->syn_data) |
| 4207 | ret = -EINVAL; | 4213 | ret = -EINVAL; |
| 4208 | else | 4214 | else |
| 4209 | tp->snd_cwnd = val; | 4215 | tp->snd_cwnd = val; |
| @@ -5309,7 +5315,7 @@ bpf_base_func_proto(enum bpf_func_id func_id) | |||
| 5309 | case BPF_FUNC_trace_printk: | 5315 | case BPF_FUNC_trace_printk: |
| 5310 | if (capable(CAP_SYS_ADMIN)) | 5316 | if (capable(CAP_SYS_ADMIN)) |
| 5311 | return bpf_get_trace_printk_proto(); | 5317 | return bpf_get_trace_printk_proto(); |
| 5312 | /* else: fall through */ | 5318 | /* else, fall through */ |
| 5313 | default: | 5319 | default: |
| 5314 | return NULL; | 5320 | return NULL; |
| 5315 | } | 5321 | } |
diff --git a/net/core/lwt_bpf.c b/net/core/lwt_bpf.c index 3e85437f7106..a648568c5e8f 100644 --- a/net/core/lwt_bpf.c +++ b/net/core/lwt_bpf.c | |||
| @@ -63,6 +63,7 @@ static int run_lwt_bpf(struct sk_buff *skb, struct bpf_lwt_prog *lwt, | |||
| 63 | lwt->name ? : "<unknown>"); | 63 | lwt->name ? : "<unknown>"); |
| 64 | ret = BPF_OK; | 64 | ret = BPF_OK; |
| 65 | } else { | 65 | } else { |
| 66 | skb_reset_mac_header(skb); | ||
| 66 | ret = skb_do_redirect(skb); | 67 | ret = skb_do_redirect(skb); |
| 67 | if (ret == 0) | 68 | if (ret == 0) |
| 68 | ret = BPF_REDIRECT; | 69 | ret = BPF_REDIRECT; |
diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 763a7b08df67..4230400b9a30 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 18 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
| 19 | 19 | ||
| 20 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
| 21 | #include <linux/kmemleak.h> | ||
| 21 | #include <linux/types.h> | 22 | #include <linux/types.h> |
| 22 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
| 23 | #include <linux/module.h> | 24 | #include <linux/module.h> |
| @@ -443,12 +444,14 @@ static struct neigh_hash_table *neigh_hash_alloc(unsigned int shift) | |||
| 443 | ret = kmalloc(sizeof(*ret), GFP_ATOMIC); | 444 | ret = kmalloc(sizeof(*ret), GFP_ATOMIC); |
| 444 | if (!ret) | 445 | if (!ret) |
| 445 | return NULL; | 446 | return NULL; |
| 446 | if (size <= PAGE_SIZE) | 447 | if (size <= PAGE_SIZE) { |
| 447 | buckets = kzalloc(size, GFP_ATOMIC); | 448 | buckets = kzalloc(size, GFP_ATOMIC); |
| 448 | else | 449 | } else { |
| 449 | buckets = (struct neighbour __rcu **) | 450 | buckets = (struct neighbour __rcu **) |
| 450 | __get_free_pages(GFP_ATOMIC | __GFP_ZERO, | 451 | __get_free_pages(GFP_ATOMIC | __GFP_ZERO, |
| 451 | get_order(size)); | 452 | get_order(size)); |
| 453 | kmemleak_alloc(buckets, size, 1, GFP_ATOMIC); | ||
| 454 | } | ||
| 452 | if (!buckets) { | 455 | if (!buckets) { |
| 453 | kfree(ret); | 456 | kfree(ret); |
| 454 | return NULL; | 457 | return NULL; |
| @@ -468,10 +471,12 @@ static void neigh_hash_free_rcu(struct rcu_head *head) | |||
| 468 | size_t size = (1 << nht->hash_shift) * sizeof(struct neighbour *); | 471 | size_t size = (1 << nht->hash_shift) * sizeof(struct neighbour *); |
| 469 | struct neighbour __rcu **buckets = nht->hash_buckets; | 472 | struct neighbour __rcu **buckets = nht->hash_buckets; |
| 470 | 473 | ||
| 471 | if (size <= PAGE_SIZE) | 474 | if (size <= PAGE_SIZE) { |
| 472 | kfree(buckets); | 475 | kfree(buckets); |
| 473 | else | 476 | } else { |
| 477 | kmemleak_free(buckets); | ||
| 474 | free_pages((unsigned long)buckets, get_order(size)); | 478 | free_pages((unsigned long)buckets, get_order(size)); |
| 479 | } | ||
| 475 | kfree(nht); | 480 | kfree(nht); |
| 476 | } | 481 | } |
| 477 | 482 | ||
| @@ -1002,7 +1007,7 @@ static void neigh_probe(struct neighbour *neigh) | |||
| 1002 | if (neigh->ops->solicit) | 1007 | if (neigh->ops->solicit) |
| 1003 | neigh->ops->solicit(neigh, skb); | 1008 | neigh->ops->solicit(neigh, skb); |
| 1004 | atomic_inc(&neigh->probes); | 1009 | atomic_inc(&neigh->probes); |
| 1005 | kfree_skb(skb); | 1010 | consume_skb(skb); |
| 1006 | } | 1011 | } |
| 1007 | 1012 | ||
| 1008 | /* Called when a timer expires for a neighbour entry. */ | 1013 | /* Called when a timer expires for a neighbour entry. */ |
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 37317ffec146..2415d9cb9b89 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
| @@ -356,6 +356,8 @@ static void *__netdev_alloc_frag(unsigned int fragsz, gfp_t gfp_mask) | |||
| 356 | */ | 356 | */ |
| 357 | void *netdev_alloc_frag(unsigned int fragsz) | 357 | void *netdev_alloc_frag(unsigned int fragsz) |
| 358 | { | 358 | { |
| 359 | fragsz = SKB_DATA_ALIGN(fragsz); | ||
| 360 | |||
| 359 | return __netdev_alloc_frag(fragsz, GFP_ATOMIC); | 361 | return __netdev_alloc_frag(fragsz, GFP_ATOMIC); |
| 360 | } | 362 | } |
| 361 | EXPORT_SYMBOL(netdev_alloc_frag); | 363 | EXPORT_SYMBOL(netdev_alloc_frag); |
| @@ -369,6 +371,8 @@ static void *__napi_alloc_frag(unsigned int fragsz, gfp_t gfp_mask) | |||
| 369 | 371 | ||
| 370 | void *napi_alloc_frag(unsigned int fragsz) | 372 | void *napi_alloc_frag(unsigned int fragsz) |
| 371 | { | 373 | { |
| 374 | fragsz = SKB_DATA_ALIGN(fragsz); | ||
| 375 | |||
| 372 | return __napi_alloc_frag(fragsz, GFP_ATOMIC); | 376 | return __napi_alloc_frag(fragsz, GFP_ATOMIC); |
| 373 | } | 377 | } |
| 374 | EXPORT_SYMBOL(napi_alloc_frag); | 378 | EXPORT_SYMBOL(napi_alloc_frag); |
| @@ -5270,7 +5274,6 @@ struct sk_buff *alloc_skb_with_frags(unsigned long header_len, | |||
| 5270 | unsigned long chunk; | 5274 | unsigned long chunk; |
| 5271 | struct sk_buff *skb; | 5275 | struct sk_buff *skb; |
| 5272 | struct page *page; | 5276 | struct page *page; |
| 5273 | gfp_t gfp_head; | ||
| 5274 | int i; | 5277 | int i; |
| 5275 | 5278 | ||
| 5276 | *errcode = -EMSGSIZE; | 5279 | *errcode = -EMSGSIZE; |
| @@ -5280,12 +5283,8 @@ struct sk_buff *alloc_skb_with_frags(unsigned long header_len, | |||
| 5280 | if (npages > MAX_SKB_FRAGS) | 5283 | if (npages > MAX_SKB_FRAGS) |
| 5281 | return NULL; | 5284 | return NULL; |
| 5282 | 5285 | ||
| 5283 | gfp_head = gfp_mask; | ||
| 5284 | if (gfp_head & __GFP_DIRECT_RECLAIM) | ||
| 5285 | gfp_head |= __GFP_RETRY_MAYFAIL; | ||
| 5286 | |||
| 5287 | *errcode = -ENOBUFS; | 5286 | *errcode = -ENOBUFS; |
| 5288 | skb = alloc_skb(header_len, gfp_head); | 5287 | skb = alloc_skb(header_len, gfp_mask); |
| 5289 | if (!skb) | 5288 | if (!skb) |
| 5290 | return NULL; | 5289 | return NULL; |
| 5291 | 5290 | ||
diff --git a/net/core/skmsg.c b/net/core/skmsg.c index d6d5c20d7044..8c826603bf36 100644 --- a/net/core/skmsg.c +++ b/net/core/skmsg.c | |||
| @@ -545,8 +545,7 @@ static void sk_psock_destroy_deferred(struct work_struct *gc) | |||
| 545 | struct sk_psock *psock = container_of(gc, struct sk_psock, gc); | 545 | struct sk_psock *psock = container_of(gc, struct sk_psock, gc); |
| 546 | 546 | ||
| 547 | /* No sk_callback_lock since already detached. */ | 547 | /* No sk_callback_lock since already detached. */ |
| 548 | if (psock->parser.enabled) | 548 | strp_done(&psock->parser.strp); |
| 549 | strp_done(&psock->parser.strp); | ||
| 550 | 549 | ||
| 551 | cancel_work_sync(&psock->work); | 550 | cancel_work_sync(&psock->work); |
| 552 | 551 | ||
diff --git a/net/core/sock.c b/net/core/sock.c index 6aa2e7e0b4fb..bc3512f230a3 100644 --- a/net/core/sock.c +++ b/net/core/sock.c | |||
| @@ -2380,7 +2380,7 @@ int __sk_mem_raise_allocated(struct sock *sk, int size, int amt, int kind) | |||
| 2380 | } | 2380 | } |
| 2381 | 2381 | ||
| 2382 | if (sk_has_memory_pressure(sk)) { | 2382 | if (sk_has_memory_pressure(sk)) { |
| 2383 | int alloc; | 2383 | u64 alloc; |
| 2384 | 2384 | ||
| 2385 | if (!sk_under_memory_pressure(sk)) | 2385 | if (!sk_under_memory_pressure(sk)) |
| 2386 | return 1; | 2386 | return 1; |
diff --git a/net/dccp/ccid.h b/net/dccp/ccid.h index 6eb837a47b5c..baaaeb2b2c42 100644 --- a/net/dccp/ccid.h +++ b/net/dccp/ccid.h | |||
| @@ -202,7 +202,7 @@ static inline void ccid_hc_tx_packet_recv(struct ccid *ccid, struct sock *sk, | |||
| 202 | static inline int ccid_hc_tx_parse_options(struct ccid *ccid, struct sock *sk, | 202 | static inline int ccid_hc_tx_parse_options(struct ccid *ccid, struct sock *sk, |
| 203 | u8 pkt, u8 opt, u8 *val, u8 len) | 203 | u8 pkt, u8 opt, u8 *val, u8 len) |
| 204 | { | 204 | { |
| 205 | if (ccid->ccid_ops->ccid_hc_tx_parse_options == NULL) | 205 | if (!ccid || !ccid->ccid_ops->ccid_hc_tx_parse_options) |
| 206 | return 0; | 206 | return 0; |
| 207 | return ccid->ccid_ops->ccid_hc_tx_parse_options(sk, pkt, opt, val, len); | 207 | return ccid->ccid_ops->ccid_hc_tx_parse_options(sk, pkt, opt, val, len); |
| 208 | } | 208 | } |
| @@ -214,7 +214,7 @@ static inline int ccid_hc_tx_parse_options(struct ccid *ccid, struct sock *sk, | |||
| 214 | static inline int ccid_hc_rx_parse_options(struct ccid *ccid, struct sock *sk, | 214 | static inline int ccid_hc_rx_parse_options(struct ccid *ccid, struct sock *sk, |
| 215 | u8 pkt, u8 opt, u8 *val, u8 len) | 215 | u8 pkt, u8 opt, u8 *val, u8 len) |
| 216 | { | 216 | { |
| 217 | if (ccid->ccid_ops->ccid_hc_rx_parse_options == NULL) | 217 | if (!ccid || !ccid->ccid_ops->ccid_hc_rx_parse_options) |
| 218 | return 0; | 218 | return 0; |
| 219 | return ccid->ccid_ops->ccid_hc_rx_parse_options(sk, pkt, opt, val, len); | 219 | return ccid->ccid_ops->ccid_hc_rx_parse_options(sk, pkt, opt, val, len); |
| 220 | } | 220 | } |
diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index d0b3e69c6b39..0962f9201baa 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c | |||
| @@ -56,7 +56,7 @@ | |||
| 56 | #include <net/dn_neigh.h> | 56 | #include <net/dn_neigh.h> |
| 57 | #include <net/dn_fib.h> | 57 | #include <net/dn_fib.h> |
| 58 | 58 | ||
| 59 | #define DN_IFREQ_SIZE (sizeof(struct ifreq) - sizeof(struct sockaddr) + sizeof(struct sockaddr_dn)) | 59 | #define DN_IFREQ_SIZE (offsetof(struct ifreq, ifr_ifru) + sizeof(struct sockaddr_dn)) |
| 60 | 60 | ||
| 61 | static char dn_rt_all_end_mcast[ETH_ALEN] = {0xAB,0x00,0x00,0x04,0x00,0x00}; | 61 | static char dn_rt_all_end_mcast[ETH_ALEN] = {0xAB,0x00,0x00,0x04,0x00,0x00}; |
| 62 | static char dn_rt_all_rt_mcast[ETH_ALEN] = {0xAB,0x00,0x00,0x03,0x00,0x00}; | 62 | static char dn_rt_all_rt_mcast[ETH_ALEN] = {0xAB,0x00,0x00,0x03,0x00,0x00}; |
diff --git a/net/dsa/master.c b/net/dsa/master.c index 71bb15f491c8..54f5551fb799 100644 --- a/net/dsa/master.c +++ b/net/dsa/master.c | |||
| @@ -205,6 +205,8 @@ static void dsa_master_reset_mtu(struct net_device *dev) | |||
| 205 | rtnl_unlock(); | 205 | rtnl_unlock(); |
| 206 | } | 206 | } |
| 207 | 207 | ||
| 208 | static struct lock_class_key dsa_master_addr_list_lock_key; | ||
| 209 | |||
| 208 | int dsa_master_setup(struct net_device *dev, struct dsa_port *cpu_dp) | 210 | int dsa_master_setup(struct net_device *dev, struct dsa_port *cpu_dp) |
| 209 | { | 211 | { |
| 210 | int ret; | 212 | int ret; |
| @@ -218,6 +220,8 @@ int dsa_master_setup(struct net_device *dev, struct dsa_port *cpu_dp) | |||
| 218 | wmb(); | 220 | wmb(); |
| 219 | 221 | ||
| 220 | dev->dsa_ptr = cpu_dp; | 222 | dev->dsa_ptr = cpu_dp; |
| 223 | lockdep_set_class(&dev->addr_list_lock, | ||
| 224 | &dsa_master_addr_list_lock_key); | ||
| 221 | 225 | ||
| 222 | ret = dsa_master_ethtool_setup(dev); | 226 | ret = dsa_master_ethtool_setup(dev); |
| 223 | if (ret) | 227 | if (ret) |
diff --git a/net/dsa/port.c b/net/dsa/port.c index 2d7e01b23572..2a2a878b5ce3 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c | |||
| @@ -69,7 +69,6 @@ static void dsa_port_set_state_now(struct dsa_port *dp, u8 state) | |||
| 69 | 69 | ||
| 70 | int dsa_port_enable(struct dsa_port *dp, struct phy_device *phy) | 70 | int dsa_port_enable(struct dsa_port *dp, struct phy_device *phy) |
| 71 | { | 71 | { |
| 72 | u8 stp_state = dp->bridge_dev ? BR_STATE_BLOCKING : BR_STATE_FORWARDING; | ||
| 73 | struct dsa_switch *ds = dp->ds; | 72 | struct dsa_switch *ds = dp->ds; |
| 74 | int port = dp->index; | 73 | int port = dp->index; |
| 75 | int err; | 74 | int err; |
| @@ -80,7 +79,8 @@ int dsa_port_enable(struct dsa_port *dp, struct phy_device *phy) | |||
| 80 | return err; | 79 | return err; |
| 81 | } | 80 | } |
| 82 | 81 | ||
| 83 | dsa_port_set_state_now(dp, stp_state); | 82 | if (!dp->bridge_dev) |
| 83 | dsa_port_set_state_now(dp, BR_STATE_FORWARDING); | ||
| 84 | 84 | ||
| 85 | return 0; | 85 | return 0; |
| 86 | } | 86 | } |
| @@ -90,7 +90,8 @@ void dsa_port_disable(struct dsa_port *dp, struct phy_device *phy) | |||
| 90 | struct dsa_switch *ds = dp->ds; | 90 | struct dsa_switch *ds = dp->ds; |
| 91 | int port = dp->index; | 91 | int port = dp->index; |
| 92 | 92 | ||
| 93 | dsa_port_set_state_now(dp, BR_STATE_DISABLED); | 93 | if (!dp->bridge_dev) |
| 94 | dsa_port_set_state_now(dp, BR_STATE_DISABLED); | ||
| 94 | 95 | ||
| 95 | if (ds->ops->port_disable) | 96 | if (ds->ops->port_disable) |
| 96 | ds->ops->port_disable(ds, port, phy); | 97 | ds->ops->port_disable(ds, port, phy); |
diff --git a/net/dsa/slave.c b/net/dsa/slave.c index a3fcc1d01615..a1c9fe155057 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c | |||
| @@ -140,11 +140,14 @@ static int dsa_slave_close(struct net_device *dev) | |||
| 140 | static void dsa_slave_change_rx_flags(struct net_device *dev, int change) | 140 | static void dsa_slave_change_rx_flags(struct net_device *dev, int change) |
| 141 | { | 141 | { |
| 142 | struct net_device *master = dsa_slave_to_master(dev); | 142 | struct net_device *master = dsa_slave_to_master(dev); |
| 143 | 143 | if (dev->flags & IFF_UP) { | |
| 144 | if (change & IFF_ALLMULTI) | 144 | if (change & IFF_ALLMULTI) |
| 145 | dev_set_allmulti(master, dev->flags & IFF_ALLMULTI ? 1 : -1); | 145 | dev_set_allmulti(master, |
| 146 | if (change & IFF_PROMISC) | 146 | dev->flags & IFF_ALLMULTI ? 1 : -1); |
| 147 | dev_set_promiscuity(master, dev->flags & IFF_PROMISC ? 1 : -1); | 147 | if (change & IFF_PROMISC) |
| 148 | dev_set_promiscuity(master, | ||
| 149 | dev->flags & IFF_PROMISC ? 1 : -1); | ||
| 150 | } | ||
| 148 | } | 151 | } |
| 149 | 152 | ||
| 150 | static void dsa_slave_set_rx_mode(struct net_device *dev) | 153 | static void dsa_slave_set_rx_mode(struct net_device *dev) |
| @@ -639,7 +642,7 @@ static int dsa_slave_set_eee(struct net_device *dev, struct ethtool_eee *e) | |||
| 639 | int ret; | 642 | int ret; |
| 640 | 643 | ||
| 641 | /* Port's PHY and MAC both need to be EEE capable */ | 644 | /* Port's PHY and MAC both need to be EEE capable */ |
| 642 | if (!dev->phydev && !dp->pl) | 645 | if (!dev->phydev || !dp->pl) |
| 643 | return -ENODEV; | 646 | return -ENODEV; |
| 644 | 647 | ||
| 645 | if (!ds->ops->set_mac_eee) | 648 | if (!ds->ops->set_mac_eee) |
| @@ -659,7 +662,7 @@ static int dsa_slave_get_eee(struct net_device *dev, struct ethtool_eee *e) | |||
| 659 | int ret; | 662 | int ret; |
| 660 | 663 | ||
| 661 | /* Port's PHY and MAC both need to be EEE capable */ | 664 | /* Port's PHY and MAC both need to be EEE capable */ |
| 662 | if (!dev->phydev && !dp->pl) | 665 | if (!dev->phydev || !dp->pl) |
| 663 | return -ENODEV; | 666 | return -ENODEV; |
| 664 | 667 | ||
| 665 | if (!ds->ops->get_mac_eee) | 668 | if (!ds->ops->get_mac_eee) |
diff --git a/net/ipv4/bpfilter/sockopt.c b/net/ipv4/bpfilter/sockopt.c index 5e04ed25bc0e..1e976bb93d99 100644 --- a/net/ipv4/bpfilter/sockopt.c +++ b/net/ipv4/bpfilter/sockopt.c | |||
| @@ -1,28 +1,54 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | #include <linux/init.h> | ||
| 3 | #include <linux/module.h> | ||
| 2 | #include <linux/uaccess.h> | 4 | #include <linux/uaccess.h> |
| 3 | #include <linux/bpfilter.h> | 5 | #include <linux/bpfilter.h> |
| 4 | #include <uapi/linux/bpf.h> | 6 | #include <uapi/linux/bpf.h> |
| 5 | #include <linux/wait.h> | 7 | #include <linux/wait.h> |
| 6 | #include <linux/kmod.h> | 8 | #include <linux/kmod.h> |
| 9 | #include <linux/fs.h> | ||
| 10 | #include <linux/file.h> | ||
| 7 | 11 | ||
| 8 | int (*bpfilter_process_sockopt)(struct sock *sk, int optname, | 12 | struct bpfilter_umh_ops bpfilter_ops; |
| 9 | char __user *optval, | 13 | EXPORT_SYMBOL_GPL(bpfilter_ops); |
| 10 | unsigned int optlen, bool is_set); | 14 | |
| 11 | EXPORT_SYMBOL_GPL(bpfilter_process_sockopt); | 15 | static void bpfilter_umh_cleanup(struct umh_info *info) |
| 16 | { | ||
| 17 | mutex_lock(&bpfilter_ops.lock); | ||
| 18 | bpfilter_ops.stop = true; | ||
| 19 | fput(info->pipe_to_umh); | ||
| 20 | fput(info->pipe_from_umh); | ||
| 21 | info->pid = 0; | ||
| 22 | mutex_unlock(&bpfilter_ops.lock); | ||
| 23 | } | ||
| 12 | 24 | ||
| 13 | static int bpfilter_mbox_request(struct sock *sk, int optname, | 25 | static int bpfilter_mbox_request(struct sock *sk, int optname, |
| 14 | char __user *optval, | 26 | char __user *optval, |
| 15 | unsigned int optlen, bool is_set) | 27 | unsigned int optlen, bool is_set) |
| 16 | { | 28 | { |
| 17 | if (!bpfilter_process_sockopt) { | 29 | int err; |
| 18 | int err = request_module("bpfilter"); | 30 | mutex_lock(&bpfilter_ops.lock); |
| 31 | if (!bpfilter_ops.sockopt) { | ||
| 32 | mutex_unlock(&bpfilter_ops.lock); | ||
| 33 | err = request_module("bpfilter"); | ||
| 34 | mutex_lock(&bpfilter_ops.lock); | ||
| 19 | 35 | ||
| 20 | if (err) | 36 | if (err) |
| 21 | return err; | 37 | goto out; |
| 22 | if (!bpfilter_process_sockopt) | 38 | if (!bpfilter_ops.sockopt) { |
| 23 | return -ECHILD; | 39 | err = -ECHILD; |
| 40 | goto out; | ||
| 41 | } | ||
| 42 | } | ||
| 43 | if (bpfilter_ops.stop) { | ||
| 44 | err = bpfilter_ops.start(); | ||
| 45 | if (err) | ||
| 46 | goto out; | ||
| 24 | } | 47 | } |
| 25 | return bpfilter_process_sockopt(sk, optname, optval, optlen, is_set); | 48 | err = bpfilter_ops.sockopt(sk, optname, optval, optlen, is_set); |
| 49 | out: | ||
| 50 | mutex_unlock(&bpfilter_ops.lock); | ||
| 51 | return err; | ||
| 26 | } | 52 | } |
| 27 | 53 | ||
| 28 | int bpfilter_ip_set_sockopt(struct sock *sk, int optname, char __user *optval, | 54 | int bpfilter_ip_set_sockopt(struct sock *sk, int optname, char __user *optval, |
| @@ -41,3 +67,15 @@ int bpfilter_ip_get_sockopt(struct sock *sk, int optname, char __user *optval, | |||
| 41 | 67 | ||
| 42 | return bpfilter_mbox_request(sk, optname, optval, len, false); | 68 | return bpfilter_mbox_request(sk, optname, optval, len, false); |
| 43 | } | 69 | } |
| 70 | |||
| 71 | static int __init bpfilter_sockopt_init(void) | ||
| 72 | { | ||
| 73 | mutex_init(&bpfilter_ops.lock); | ||
| 74 | bpfilter_ops.stop = true; | ||
| 75 | bpfilter_ops.info.cmdline = "bpfilter_umh"; | ||
| 76 | bpfilter_ops.info.cleanup = &bpfilter_umh_cleanup; | ||
| 77 | |||
| 78 | return 0; | ||
| 79 | } | ||
| 80 | |||
| 81 | module_init(bpfilter_sockopt_init); | ||
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 04ba321ae5ce..e258a00b4a3d 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c | |||
| @@ -1826,7 +1826,7 @@ put_tgt_net: | |||
| 1826 | if (fillargs.netnsid >= 0) | 1826 | if (fillargs.netnsid >= 0) |
| 1827 | put_net(tgt_net); | 1827 | put_net(tgt_net); |
| 1828 | 1828 | ||
| 1829 | return err < 0 ? err : skb->len; | 1829 | return skb->len ? : err; |
| 1830 | } | 1830 | } |
| 1831 | 1831 | ||
| 1832 | static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh, | 1832 | static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh, |
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 5459f41fc26f..10e809b296ec 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c | |||
| @@ -328,7 +328,7 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info * | |||
| 328 | skb->len += tailen; | 328 | skb->len += tailen; |
| 329 | skb->data_len += tailen; | 329 | skb->data_len += tailen; |
| 330 | skb->truesize += tailen; | 330 | skb->truesize += tailen; |
| 331 | if (sk) | 331 | if (sk && sk_fullsock(sk)) |
| 332 | refcount_add(tailen, &sk->sk_wmem_alloc); | 332 | refcount_add(tailen, &sk->sk_wmem_alloc); |
| 333 | 333 | ||
| 334 | goto out; | 334 | goto out; |
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 6df95be96311..fe4f6a624238 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c | |||
| @@ -203,7 +203,7 @@ static void fib_flush(struct net *net) | |||
| 203 | struct fib_table *tb; | 203 | struct fib_table *tb; |
| 204 | 204 | ||
| 205 | hlist_for_each_entry_safe(tb, tmp, head, tb_hlist) | 205 | hlist_for_each_entry_safe(tb, tmp, head, tb_hlist) |
| 206 | flushed += fib_table_flush(net, tb); | 206 | flushed += fib_table_flush(net, tb, false); |
| 207 | } | 207 | } |
| 208 | 208 | ||
| 209 | if (flushed) | 209 | if (flushed) |
| @@ -1463,7 +1463,7 @@ static void ip_fib_net_exit(struct net *net) | |||
| 1463 | 1463 | ||
| 1464 | hlist_for_each_entry_safe(tb, tmp, head, tb_hlist) { | 1464 | hlist_for_each_entry_safe(tb, tmp, head, tb_hlist) { |
| 1465 | hlist_del(&tb->tb_hlist); | 1465 | hlist_del(&tb->tb_hlist); |
| 1466 | fib_table_flush(net, tb); | 1466 | fib_table_flush(net, tb, true); |
| 1467 | fib_free_table(tb); | 1467 | fib_free_table(tb); |
| 1468 | } | 1468 | } |
| 1469 | } | 1469 | } |
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 237c9f72b265..a573e37e0615 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c | |||
| @@ -1856,7 +1856,7 @@ void fib_table_flush_external(struct fib_table *tb) | |||
| 1856 | } | 1856 | } |
| 1857 | 1857 | ||
| 1858 | /* Caller must hold RTNL. */ | 1858 | /* Caller must hold RTNL. */ |
| 1859 | int fib_table_flush(struct net *net, struct fib_table *tb) | 1859 | int fib_table_flush(struct net *net, struct fib_table *tb, bool flush_all) |
| 1860 | { | 1860 | { |
| 1861 | struct trie *t = (struct trie *)tb->tb_data; | 1861 | struct trie *t = (struct trie *)tb->tb_data; |
| 1862 | struct key_vector *pn = t->kv; | 1862 | struct key_vector *pn = t->kv; |
| @@ -1904,8 +1904,17 @@ int fib_table_flush(struct net *net, struct fib_table *tb) | |||
| 1904 | hlist_for_each_entry_safe(fa, tmp, &n->leaf, fa_list) { | 1904 | hlist_for_each_entry_safe(fa, tmp, &n->leaf, fa_list) { |
| 1905 | struct fib_info *fi = fa->fa_info; | 1905 | struct fib_info *fi = fa->fa_info; |
| 1906 | 1906 | ||
| 1907 | if (!fi || !(fi->fib_flags & RTNH_F_DEAD) || | 1907 | if (!fi || tb->tb_id != fa->tb_id || |
| 1908 | tb->tb_id != fa->tb_id) { | 1908 | (!(fi->fib_flags & RTNH_F_DEAD) && |
| 1909 | !fib_props[fa->fa_type].error)) { | ||
| 1910 | slen = fa->fa_slen; | ||
| 1911 | continue; | ||
| 1912 | } | ||
| 1913 | |||
| 1914 | /* Do not flush error routes if network namespace is | ||
| 1915 | * not being dismantled | ||
| 1916 | */ | ||
| 1917 | if (!flush_all && fib_props[fa->fa_type].error) { | ||
| 1909 | slen = fa->fa_slen; | 1918 | slen = fa->fa_slen; |
| 1910 | continue; | 1919 | continue; |
| 1911 | } | 1920 | } |
diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c index 0c9f171fb085..437070d1ffb1 100644 --- a/net/ipv4/fou.c +++ b/net/ipv4/fou.c | |||
| @@ -1020,10 +1020,11 @@ static int gue_err(struct sk_buff *skb, u32 info) | |||
| 1020 | { | 1020 | { |
| 1021 | int transport_offset = skb_transport_offset(skb); | 1021 | int transport_offset = skb_transport_offset(skb); |
| 1022 | struct guehdr *guehdr; | 1022 | struct guehdr *guehdr; |
| 1023 | size_t optlen; | 1023 | size_t len, optlen; |
| 1024 | int ret; | 1024 | int ret; |
| 1025 | 1025 | ||
| 1026 | if (skb->len < sizeof(struct udphdr) + sizeof(struct guehdr)) | 1026 | len = sizeof(struct udphdr) + sizeof(struct guehdr); |
| 1027 | if (!pskb_may_pull(skb, len)) | ||
| 1027 | return -EINVAL; | 1028 | return -EINVAL; |
| 1028 | 1029 | ||
| 1029 | guehdr = (struct guehdr *)&udp_hdr(skb)[1]; | 1030 | guehdr = (struct guehdr *)&udp_hdr(skb)[1]; |
| @@ -1058,6 +1059,10 @@ static int gue_err(struct sk_buff *skb, u32 info) | |||
| 1058 | 1059 | ||
| 1059 | optlen = guehdr->hlen << 2; | 1060 | optlen = guehdr->hlen << 2; |
| 1060 | 1061 | ||
| 1062 | if (!pskb_may_pull(skb, len + optlen)) | ||
| 1063 | return -EINVAL; | ||
| 1064 | |||
| 1065 | guehdr = (struct guehdr *)&udp_hdr(skb)[1]; | ||
| 1061 | if (validate_gue_flags(guehdr, optlen)) | 1066 | if (validate_gue_flags(guehdr, optlen)) |
| 1062 | return -EINVAL; | 1067 | return -EINVAL; |
| 1063 | 1068 | ||
| @@ -1065,7 +1070,8 @@ static int gue_err(struct sk_buff *skb, u32 info) | |||
| 1065 | * recursion. Besides, this kind of encapsulation can't even be | 1070 | * recursion. Besides, this kind of encapsulation can't even be |
| 1066 | * configured currently. Discard this. | 1071 | * configured currently. Discard this. |
| 1067 | */ | 1072 | */ |
| 1068 | if (guehdr->proto_ctype == IPPROTO_UDP) | 1073 | if (guehdr->proto_ctype == IPPROTO_UDP || |
| 1074 | guehdr->proto_ctype == IPPROTO_UDPLITE) | ||
| 1069 | return -EOPNOTSUPP; | 1075 | return -EOPNOTSUPP; |
| 1070 | 1076 | ||
| 1071 | skb_set_transport_header(skb, -(int)sizeof(struct icmphdr)); | 1077 | skb_set_transport_header(skb, -(int)sizeof(struct icmphdr)); |
diff --git a/net/ipv4/gre_demux.c b/net/ipv4/gre_demux.c index a4bf22ee3aed..7c4a41dc04bb 100644 --- a/net/ipv4/gre_demux.c +++ b/net/ipv4/gre_demux.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include <linux/spinlock.h> | 25 | #include <linux/spinlock.h> |
| 26 | #include <net/protocol.h> | 26 | #include <net/protocol.h> |
| 27 | #include <net/gre.h> | 27 | #include <net/gre.h> |
| 28 | #include <net/erspan.h> | ||
| 28 | 29 | ||
| 29 | #include <net/icmp.h> | 30 | #include <net/icmp.h> |
| 30 | #include <net/route.h> | 31 | #include <net/route.h> |
| @@ -119,6 +120,22 @@ int gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, | |||
| 119 | hdr_len += 4; | 120 | hdr_len += 4; |
| 120 | } | 121 | } |
| 121 | tpi->hdr_len = hdr_len; | 122 | tpi->hdr_len = hdr_len; |
| 123 | |||
| 124 | /* ERSPAN ver 1 and 2 protocol sets GRE key field | ||
| 125 | * to 0 and sets the configured key in the | ||
| 126 | * inner erspan header field | ||
| 127 | */ | ||
| 128 | if (greh->protocol == htons(ETH_P_ERSPAN) || | ||
| 129 | greh->protocol == htons(ETH_P_ERSPAN2)) { | ||
| 130 | struct erspan_base_hdr *ershdr; | ||
| 131 | |||
| 132 | if (!pskb_may_pull(skb, nhs + hdr_len + sizeof(*ershdr))) | ||
| 133 | return -EINVAL; | ||
| 134 | |||
| 135 | ershdr = (struct erspan_base_hdr *)options; | ||
| 136 | tpi->key = cpu_to_be32(get_session_id(ershdr)); | ||
| 137 | } | ||
| 138 | |||
| 122 | return hdr_len; | 139 | return hdr_len; |
| 123 | } | 140 | } |
| 124 | EXPORT_SYMBOL(gre_parse_header); | 141 | EXPORT_SYMBOL(gre_parse_header); |
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index 1a4e9ff02762..5731670c560b 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c | |||
| @@ -108,6 +108,7 @@ static size_t inet_sk_attr_size(struct sock *sk, | |||
| 108 | + nla_total_size(1) /* INET_DIAG_TOS */ | 108 | + nla_total_size(1) /* INET_DIAG_TOS */ |
| 109 | + nla_total_size(1) /* INET_DIAG_TCLASS */ | 109 | + nla_total_size(1) /* INET_DIAG_TCLASS */ |
| 110 | + nla_total_size(4) /* INET_DIAG_MARK */ | 110 | + nla_total_size(4) /* INET_DIAG_MARK */ |
| 111 | + nla_total_size(4) /* INET_DIAG_CLASS_ID */ | ||
| 111 | + nla_total_size(sizeof(struct inet_diag_meminfo)) | 112 | + nla_total_size(sizeof(struct inet_diag_meminfo)) |
| 112 | + nla_total_size(sizeof(struct inet_diag_msg)) | 113 | + nla_total_size(sizeof(struct inet_diag_msg)) |
| 113 | + nla_total_size(SK_MEMINFO_VARS * sizeof(u32)) | 114 | + nla_total_size(SK_MEMINFO_VARS * sizeof(u32)) |
| @@ -287,12 +288,19 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk, | |||
| 287 | goto errout; | 288 | goto errout; |
| 288 | } | 289 | } |
| 289 | 290 | ||
| 290 | if (ext & (1 << (INET_DIAG_CLASS_ID - 1))) { | 291 | if (ext & (1 << (INET_DIAG_CLASS_ID - 1)) || |
| 292 | ext & (1 << (INET_DIAG_TCLASS - 1))) { | ||
| 291 | u32 classid = 0; | 293 | u32 classid = 0; |
| 292 | 294 | ||
| 293 | #ifdef CONFIG_SOCK_CGROUP_DATA | 295 | #ifdef CONFIG_SOCK_CGROUP_DATA |
| 294 | classid = sock_cgroup_classid(&sk->sk_cgrp_data); | 296 | classid = sock_cgroup_classid(&sk->sk_cgrp_data); |
| 295 | #endif | 297 | #endif |
| 298 | /* Fallback to socket priority if class id isn't set. | ||
| 299 | * Classful qdiscs use it as direct reference to class. | ||
| 300 | * For cgroup2 classid is always zero. | ||
| 301 | */ | ||
| 302 | if (!classid) | ||
| 303 | classid = sk->sk_priority; | ||
| 296 | 304 | ||
| 297 | if (nla_put_u32(skb, INET_DIAG_CLASS_ID, classid)) | 305 | if (nla_put_u32(skb, INET_DIAG_CLASS_ID, classid)) |
| 298 | goto errout; | 306 | goto errout; |
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c index d757b9642d0d..be778599bfed 100644 --- a/net/ipv4/inetpeer.c +++ b/net/ipv4/inetpeer.c | |||
| @@ -216,6 +216,7 @@ struct inet_peer *inet_getpeer(struct inet_peer_base *base, | |||
| 216 | atomic_set(&p->rid, 0); | 216 | atomic_set(&p->rid, 0); |
| 217 | p->metrics[RTAX_LOCK-1] = INETPEER_METRICS_NEW; | 217 | p->metrics[RTAX_LOCK-1] = INETPEER_METRICS_NEW; |
| 218 | p->rate_tokens = 0; | 218 | p->rate_tokens = 0; |
| 219 | p->n_redirects = 0; | ||
| 219 | /* 60*HZ is arbitrary, but chosen enough high so that the first | 220 | /* 60*HZ is arbitrary, but chosen enough high so that the first |
| 220 | * calculation of tokens is at its maximum. | 221 | * calculation of tokens is at its maximum. |
| 221 | */ | 222 | */ |
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index d1d09f3e5f9e..6ae89f2b541b 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c | |||
| @@ -268,20 +268,11 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, | |||
| 268 | int len; | 268 | int len; |
| 269 | 269 | ||
| 270 | itn = net_generic(net, erspan_net_id); | 270 | itn = net_generic(net, erspan_net_id); |
| 271 | len = gre_hdr_len + sizeof(*ershdr); | ||
| 272 | |||
| 273 | /* Check based hdr len */ | ||
| 274 | if (unlikely(!pskb_may_pull(skb, len))) | ||
| 275 | return PACKET_REJECT; | ||
| 276 | 271 | ||
| 277 | iph = ip_hdr(skb); | 272 | iph = ip_hdr(skb); |
| 278 | ershdr = (struct erspan_base_hdr *)(skb->data + gre_hdr_len); | 273 | ershdr = (struct erspan_base_hdr *)(skb->data + gre_hdr_len); |
| 279 | ver = ershdr->ver; | 274 | ver = ershdr->ver; |
| 280 | 275 | ||
| 281 | /* The original GRE header does not have key field, | ||
| 282 | * Use ERSPAN 10-bit session ID as key. | ||
| 283 | */ | ||
| 284 | tpi->key = cpu_to_be32(get_session_id(ershdr)); | ||
| 285 | tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, | 276 | tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, |
| 286 | tpi->flags | TUNNEL_KEY, | 277 | tpi->flags | TUNNEL_KEY, |
| 287 | iph->saddr, iph->daddr, tpi->key); | 278 | iph->saddr, iph->daddr, tpi->key); |
| @@ -569,8 +560,7 @@ err_free_skb: | |||
| 569 | dev->stats.tx_dropped++; | 560 | dev->stats.tx_dropped++; |
| 570 | } | 561 | } |
| 571 | 562 | ||
| 572 | static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev, | 563 | static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev) |
| 573 | __be16 proto) | ||
| 574 | { | 564 | { |
| 575 | struct ip_tunnel *tunnel = netdev_priv(dev); | 565 | struct ip_tunnel *tunnel = netdev_priv(dev); |
| 576 | struct ip_tunnel_info *tun_info; | 566 | struct ip_tunnel_info *tun_info; |
| @@ -578,10 +568,10 @@ static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev, | |||
| 578 | struct erspan_metadata *md; | 568 | struct erspan_metadata *md; |
| 579 | struct rtable *rt = NULL; | 569 | struct rtable *rt = NULL; |
| 580 | bool truncate = false; | 570 | bool truncate = false; |
| 571 | __be16 df, proto; | ||
| 581 | struct flowi4 fl; | 572 | struct flowi4 fl; |
| 582 | int tunnel_hlen; | 573 | int tunnel_hlen; |
| 583 | int version; | 574 | int version; |
| 584 | __be16 df; | ||
| 585 | int nhoff; | 575 | int nhoff; |
| 586 | int thoff; | 576 | int thoff; |
| 587 | 577 | ||
| @@ -626,18 +616,20 @@ static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev, | |||
| 626 | if (version == 1) { | 616 | if (version == 1) { |
| 627 | erspan_build_header(skb, ntohl(tunnel_id_to_key32(key->tun_id)), | 617 | erspan_build_header(skb, ntohl(tunnel_id_to_key32(key->tun_id)), |
| 628 | ntohl(md->u.index), truncate, true); | 618 | ntohl(md->u.index), truncate, true); |
| 619 | proto = htons(ETH_P_ERSPAN); | ||
| 629 | } else if (version == 2) { | 620 | } else if (version == 2) { |
| 630 | erspan_build_header_v2(skb, | 621 | erspan_build_header_v2(skb, |
| 631 | ntohl(tunnel_id_to_key32(key->tun_id)), | 622 | ntohl(tunnel_id_to_key32(key->tun_id)), |
| 632 | md->u.md2.dir, | 623 | md->u.md2.dir, |
| 633 | get_hwid(&md->u.md2), | 624 | get_hwid(&md->u.md2), |
| 634 | truncate, true); | 625 | truncate, true); |
| 626 | proto = htons(ETH_P_ERSPAN2); | ||
| 635 | } else { | 627 | } else { |
| 636 | goto err_free_rt; | 628 | goto err_free_rt; |
| 637 | } | 629 | } |
| 638 | 630 | ||
| 639 | gre_build_header(skb, 8, TUNNEL_SEQ, | 631 | gre_build_header(skb, 8, TUNNEL_SEQ, |
| 640 | htons(ETH_P_ERSPAN), 0, htonl(tunnel->o_seqno++)); | 632 | proto, 0, htonl(tunnel->o_seqno++)); |
| 641 | 633 | ||
| 642 | df = key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0; | 634 | df = key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0; |
| 643 | 635 | ||
| @@ -721,12 +713,13 @@ static netdev_tx_t erspan_xmit(struct sk_buff *skb, | |||
| 721 | { | 713 | { |
| 722 | struct ip_tunnel *tunnel = netdev_priv(dev); | 714 | struct ip_tunnel *tunnel = netdev_priv(dev); |
| 723 | bool truncate = false; | 715 | bool truncate = false; |
| 716 | __be16 proto; | ||
| 724 | 717 | ||
| 725 | if (!pskb_inet_may_pull(skb)) | 718 | if (!pskb_inet_may_pull(skb)) |
| 726 | goto free_skb; | 719 | goto free_skb; |
| 727 | 720 | ||
| 728 | if (tunnel->collect_md) { | 721 | if (tunnel->collect_md) { |
| 729 | erspan_fb_xmit(skb, dev, skb->protocol); | 722 | erspan_fb_xmit(skb, dev); |
| 730 | return NETDEV_TX_OK; | 723 | return NETDEV_TX_OK; |
| 731 | } | 724 | } |
| 732 | 725 | ||
| @@ -742,19 +735,22 @@ static netdev_tx_t erspan_xmit(struct sk_buff *skb, | |||
| 742 | } | 735 | } |
| 743 | 736 | ||
| 744 | /* Push ERSPAN header */ | 737 | /* Push ERSPAN header */ |
| 745 | if (tunnel->erspan_ver == 1) | 738 | if (tunnel->erspan_ver == 1) { |
| 746 | erspan_build_header(skb, ntohl(tunnel->parms.o_key), | 739 | erspan_build_header(skb, ntohl(tunnel->parms.o_key), |
| 747 | tunnel->index, | 740 | tunnel->index, |
| 748 | truncate, true); | 741 | truncate, true); |
| 749 | else if (tunnel->erspan_ver == 2) | 742 | proto = htons(ETH_P_ERSPAN); |
| 743 | } else if (tunnel->erspan_ver == 2) { | ||
| 750 | erspan_build_header_v2(skb, ntohl(tunnel->parms.o_key), | 744 | erspan_build_header_v2(skb, ntohl(tunnel->parms.o_key), |
| 751 | tunnel->dir, tunnel->hwid, | 745 | tunnel->dir, tunnel->hwid, |
| 752 | truncate, true); | 746 | truncate, true); |
| 753 | else | 747 | proto = htons(ETH_P_ERSPAN2); |
| 748 | } else { | ||
| 754 | goto free_skb; | 749 | goto free_skb; |
| 750 | } | ||
| 755 | 751 | ||
| 756 | tunnel->parms.o_flags &= ~TUNNEL_KEY; | 752 | tunnel->parms.o_flags &= ~TUNNEL_KEY; |
| 757 | __gre_xmit(skb, dev, &tunnel->parms.iph, htons(ETH_P_ERSPAN)); | 753 | __gre_xmit(skb, dev, &tunnel->parms.iph, proto); |
| 758 | return NETDEV_TX_OK; | 754 | return NETDEV_TX_OK; |
| 759 | 755 | ||
| 760 | free_skb: | 756 | free_skb: |
| @@ -1459,12 +1455,31 @@ static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev) | |||
| 1459 | { | 1455 | { |
| 1460 | struct ip_tunnel *t = netdev_priv(dev); | 1456 | struct ip_tunnel *t = netdev_priv(dev); |
| 1461 | struct ip_tunnel_parm *p = &t->parms; | 1457 | struct ip_tunnel_parm *p = &t->parms; |
| 1458 | __be16 o_flags = p->o_flags; | ||
| 1459 | |||
| 1460 | if (t->erspan_ver == 1 || t->erspan_ver == 2) { | ||
| 1461 | if (!t->collect_md) | ||
| 1462 | o_flags |= TUNNEL_KEY; | ||
| 1463 | |||
| 1464 | if (nla_put_u8(skb, IFLA_GRE_ERSPAN_VER, t->erspan_ver)) | ||
| 1465 | goto nla_put_failure; | ||
| 1466 | |||
| 1467 | if (t->erspan_ver == 1) { | ||
| 1468 | if (nla_put_u32(skb, IFLA_GRE_ERSPAN_INDEX, t->index)) | ||
| 1469 | goto nla_put_failure; | ||
| 1470 | } else { | ||
| 1471 | if (nla_put_u8(skb, IFLA_GRE_ERSPAN_DIR, t->dir)) | ||
| 1472 | goto nla_put_failure; | ||
| 1473 | if (nla_put_u16(skb, IFLA_GRE_ERSPAN_HWID, t->hwid)) | ||
| 1474 | goto nla_put_failure; | ||
| 1475 | } | ||
| 1476 | } | ||
| 1462 | 1477 | ||
| 1463 | if (nla_put_u32(skb, IFLA_GRE_LINK, p->link) || | 1478 | if (nla_put_u32(skb, IFLA_GRE_LINK, p->link) || |
| 1464 | nla_put_be16(skb, IFLA_GRE_IFLAGS, | 1479 | nla_put_be16(skb, IFLA_GRE_IFLAGS, |
| 1465 | gre_tnl_flags_to_gre_flags(p->i_flags)) || | 1480 | gre_tnl_flags_to_gre_flags(p->i_flags)) || |
| 1466 | nla_put_be16(skb, IFLA_GRE_OFLAGS, | 1481 | nla_put_be16(skb, IFLA_GRE_OFLAGS, |
| 1467 | gre_tnl_flags_to_gre_flags(p->o_flags)) || | 1482 | gre_tnl_flags_to_gre_flags(o_flags)) || |
| 1468 | nla_put_be32(skb, IFLA_GRE_IKEY, p->i_key) || | 1483 | nla_put_be32(skb, IFLA_GRE_IKEY, p->i_key) || |
| 1469 | nla_put_be32(skb, IFLA_GRE_OKEY, p->o_key) || | 1484 | nla_put_be32(skb, IFLA_GRE_OKEY, p->o_key) || |
| 1470 | nla_put_in_addr(skb, IFLA_GRE_LOCAL, p->iph.saddr) || | 1485 | nla_put_in_addr(skb, IFLA_GRE_LOCAL, p->iph.saddr) || |
| @@ -1494,19 +1509,6 @@ static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev) | |||
| 1494 | goto nla_put_failure; | 1509 | goto nla_put_failure; |
| 1495 | } | 1510 | } |
| 1496 | 1511 | ||
| 1497 | if (nla_put_u8(skb, IFLA_GRE_ERSPAN_VER, t->erspan_ver)) | ||
| 1498 | goto nla_put_failure; | ||
| 1499 | |||
| 1500 | if (t->erspan_ver == 1) { | ||
| 1501 | if (nla_put_u32(skb, IFLA_GRE_ERSPAN_INDEX, t->index)) | ||
| 1502 | goto nla_put_failure; | ||
| 1503 | } else if (t->erspan_ver == 2) { | ||
| 1504 | if (nla_put_u8(skb, IFLA_GRE_ERSPAN_DIR, t->dir)) | ||
| 1505 | goto nla_put_failure; | ||
| 1506 | if (nla_put_u16(skb, IFLA_GRE_ERSPAN_HWID, t->hwid)) | ||
| 1507 | goto nla_put_failure; | ||
| 1508 | } | ||
| 1509 | |||
| 1510 | return 0; | 1512 | return 0; |
| 1511 | 1513 | ||
| 1512 | nla_put_failure: | 1514 | nla_put_failure: |
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 26921f6b3b92..51d8efba6de2 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c | |||
| @@ -488,6 +488,7 @@ static struct sk_buff *ip_rcv_core(struct sk_buff *skb, struct net *net) | |||
| 488 | goto drop; | 488 | goto drop; |
| 489 | } | 489 | } |
| 490 | 490 | ||
| 491 | iph = ip_hdr(skb); | ||
| 491 | skb->transport_header = skb->network_header + iph->ihl*4; | 492 | skb->transport_header = skb->network_header + iph->ihl*4; |
| 492 | 493 | ||
| 493 | /* Remove any debris in the socket control block */ | 494 | /* Remove any debris in the socket control block */ |
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index fffcc130900e..82f341e84fae 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c | |||
| @@ -148,19 +148,17 @@ static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb) | |||
| 148 | 148 | ||
| 149 | static void ip_cmsg_recv_dstaddr(struct msghdr *msg, struct sk_buff *skb) | 149 | static void ip_cmsg_recv_dstaddr(struct msghdr *msg, struct sk_buff *skb) |
| 150 | { | 150 | { |
| 151 | __be16 _ports[2], *ports; | ||
| 151 | struct sockaddr_in sin; | 152 | struct sockaddr_in sin; |
| 152 | __be16 *ports; | ||
| 153 | int end; | ||
| 154 | |||
| 155 | end = skb_transport_offset(skb) + 4; | ||
| 156 | if (end > 0 && !pskb_may_pull(skb, end)) | ||
| 157 | return; | ||
| 158 | 153 | ||
| 159 | /* All current transport protocols have the port numbers in the | 154 | /* All current transport protocols have the port numbers in the |
| 160 | * first four bytes of the transport header and this function is | 155 | * first four bytes of the transport header and this function is |
| 161 | * written with this assumption in mind. | 156 | * written with this assumption in mind. |
| 162 | */ | 157 | */ |
| 163 | ports = (__be16 *)skb_transport_header(skb); | 158 | ports = skb_header_pointer(skb, skb_transport_offset(skb), |
| 159 | sizeof(_ports), &_ports); | ||
| 160 | if (!ports) | ||
| 161 | return; | ||
| 164 | 162 | ||
| 165 | sin.sin_family = AF_INET; | 163 | sin.sin_family = AF_INET; |
| 166 | sin.sin_addr.s_addr = ip_hdr(skb)->daddr; | 164 | sin.sin_addr.s_addr = ip_hdr(skb)->daddr; |
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index c4f5602308ed..054d01c16dc6 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c | |||
| @@ -644,13 +644,19 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, | |||
| 644 | dst = tnl_params->daddr; | 644 | dst = tnl_params->daddr; |
| 645 | if (dst == 0) { | 645 | if (dst == 0) { |
| 646 | /* NBMA tunnel */ | 646 | /* NBMA tunnel */ |
| 647 | struct ip_tunnel_info *tun_info; | ||
| 647 | 648 | ||
| 648 | if (!skb_dst(skb)) { | 649 | if (!skb_dst(skb)) { |
| 649 | dev->stats.tx_fifo_errors++; | 650 | dev->stats.tx_fifo_errors++; |
| 650 | goto tx_error; | 651 | goto tx_error; |
| 651 | } | 652 | } |
| 652 | 653 | ||
| 653 | if (skb->protocol == htons(ETH_P_IP)) { | 654 | tun_info = skb_tunnel_info(skb); |
| 655 | if (tun_info && (tun_info->mode & IP_TUNNEL_INFO_TX) && | ||
| 656 | ip_tunnel_info_af(tun_info) == AF_INET && | ||
| 657 | tun_info->key.u.ipv4.dst) | ||
| 658 | dst = tun_info->key.u.ipv4.dst; | ||
| 659 | else if (skb->protocol == htons(ETH_P_IP)) { | ||
| 654 | rt = skb_rtable(skb); | 660 | rt = skb_rtable(skb); |
| 655 | dst = rt_nexthop(rt, inner_iph->daddr); | 661 | dst = rt_nexthop(rt, inner_iph->daddr); |
| 656 | } | 662 | } |
diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c index d7b43e700023..68a21bf75dd0 100644 --- a/net/ipv4/ip_vti.c +++ b/net/ipv4/ip_vti.c | |||
| @@ -74,6 +74,33 @@ drop: | |||
| 74 | return 0; | 74 | return 0; |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | static int vti_input_ipip(struct sk_buff *skb, int nexthdr, __be32 spi, | ||
| 78 | int encap_type) | ||
| 79 | { | ||
| 80 | struct ip_tunnel *tunnel; | ||
| 81 | const struct iphdr *iph = ip_hdr(skb); | ||
| 82 | struct net *net = dev_net(skb->dev); | ||
| 83 | struct ip_tunnel_net *itn = net_generic(net, vti_net_id); | ||
| 84 | |||
| 85 | tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY, | ||
| 86 | iph->saddr, iph->daddr, 0); | ||
| 87 | if (tunnel) { | ||
| 88 | if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) | ||
| 89 | goto drop; | ||
| 90 | |||
| 91 | XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = tunnel; | ||
| 92 | |||
| 93 | skb->dev = tunnel->dev; | ||
| 94 | |||
| 95 | return xfrm_input(skb, nexthdr, spi, encap_type); | ||
| 96 | } | ||
| 97 | |||
| 98 | return -EINVAL; | ||
| 99 | drop: | ||
| 100 | kfree_skb(skb); | ||
| 101 | return 0; | ||
| 102 | } | ||
| 103 | |||
| 77 | static int vti_rcv(struct sk_buff *skb) | 104 | static int vti_rcv(struct sk_buff *skb) |
| 78 | { | 105 | { |
| 79 | XFRM_SPI_SKB_CB(skb)->family = AF_INET; | 106 | XFRM_SPI_SKB_CB(skb)->family = AF_INET; |
| @@ -82,6 +109,14 @@ static int vti_rcv(struct sk_buff *skb) | |||
| 82 | return vti_input(skb, ip_hdr(skb)->protocol, 0, 0); | 109 | return vti_input(skb, ip_hdr(skb)->protocol, 0, 0); |
| 83 | } | 110 | } |
| 84 | 111 | ||
| 112 | static int vti_rcv_ipip(struct sk_buff *skb) | ||
| 113 | { | ||
| 114 | XFRM_SPI_SKB_CB(skb)->family = AF_INET; | ||
| 115 | XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr); | ||
| 116 | |||
| 117 | return vti_input_ipip(skb, ip_hdr(skb)->protocol, ip_hdr(skb)->saddr, 0); | ||
| 118 | } | ||
| 119 | |||
| 85 | static int vti_rcv_cb(struct sk_buff *skb, int err) | 120 | static int vti_rcv_cb(struct sk_buff *skb, int err) |
| 86 | { | 121 | { |
| 87 | unsigned short family; | 122 | unsigned short family; |
| @@ -435,6 +470,12 @@ static struct xfrm4_protocol vti_ipcomp4_protocol __read_mostly = { | |||
| 435 | .priority = 100, | 470 | .priority = 100, |
| 436 | }; | 471 | }; |
| 437 | 472 | ||
| 473 | static struct xfrm_tunnel ipip_handler __read_mostly = { | ||
| 474 | .handler = vti_rcv_ipip, | ||
| 475 | .err_handler = vti4_err, | ||
| 476 | .priority = 0, | ||
| 477 | }; | ||
| 478 | |||
| 438 | static int __net_init vti_init_net(struct net *net) | 479 | static int __net_init vti_init_net(struct net *net) |
| 439 | { | 480 | { |
| 440 | int err; | 481 | int err; |
| @@ -603,6 +644,13 @@ static int __init vti_init(void) | |||
| 603 | if (err < 0) | 644 | if (err < 0) |
| 604 | goto xfrm_proto_comp_failed; | 645 | goto xfrm_proto_comp_failed; |
| 605 | 646 | ||
| 647 | msg = "ipip tunnel"; | ||
| 648 | err = xfrm4_tunnel_register(&ipip_handler, AF_INET); | ||
| 649 | if (err < 0) { | ||
| 650 | pr_info("%s: cant't register tunnel\n",__func__); | ||
| 651 | goto xfrm_tunnel_failed; | ||
| 652 | } | ||
| 653 | |||
| 606 | msg = "netlink interface"; | 654 | msg = "netlink interface"; |
| 607 | err = rtnl_link_register(&vti_link_ops); | 655 | err = rtnl_link_register(&vti_link_ops); |
| 608 | if (err < 0) | 656 | if (err < 0) |
| @@ -612,6 +660,8 @@ static int __init vti_init(void) | |||
| 612 | 660 | ||
| 613 | rtnl_link_failed: | 661 | rtnl_link_failed: |
| 614 | xfrm4_protocol_deregister(&vti_ipcomp4_protocol, IPPROTO_COMP); | 662 | xfrm4_protocol_deregister(&vti_ipcomp4_protocol, IPPROTO_COMP); |
| 663 | xfrm_tunnel_failed: | ||
| 664 | xfrm4_tunnel_deregister(&ipip_handler, AF_INET); | ||
| 615 | xfrm_proto_comp_failed: | 665 | xfrm_proto_comp_failed: |
| 616 | xfrm4_protocol_deregister(&vti_ah4_protocol, IPPROTO_AH); | 666 | xfrm4_protocol_deregister(&vti_ah4_protocol, IPPROTO_AH); |
| 617 | xfrm_proto_ah_failed: | 667 | xfrm_proto_ah_failed: |
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index b61977db9b7f..2a909e5f9ba0 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c | |||
| @@ -846,9 +846,9 @@ static int clusterip_net_init(struct net *net) | |||
| 846 | 846 | ||
| 847 | static void clusterip_net_exit(struct net *net) | 847 | static void clusterip_net_exit(struct net *net) |
| 848 | { | 848 | { |
| 849 | #ifdef CONFIG_PROC_FS | ||
| 849 | struct clusterip_net *cn = clusterip_pernet(net); | 850 | struct clusterip_net *cn = clusterip_pernet(net); |
| 850 | 851 | ||
| 851 | #ifdef CONFIG_PROC_FS | ||
| 852 | mutex_lock(&cn->mutex); | 852 | mutex_lock(&cn->mutex); |
| 853 | proc_remove(cn->procdir); | 853 | proc_remove(cn->procdir); |
| 854 | cn->procdir = NULL; | 854 | cn->procdir = NULL; |
diff --git a/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c b/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c index 2687db015b6f..fa2ba7c500e4 100644 --- a/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c | |||
| @@ -215,6 +215,7 @@ int nf_nat_icmp_reply_translation(struct sk_buff *skb, | |||
| 215 | 215 | ||
| 216 | /* Change outer to look like the reply to an incoming packet */ | 216 | /* Change outer to look like the reply to an incoming packet */ |
| 217 | nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple); | 217 | nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple); |
| 218 | target.dst.protonum = IPPROTO_ICMP; | ||
| 218 | if (!nf_nat_ipv4_manip_pkt(skb, 0, &target, manip)) | 219 | if (!nf_nat_ipv4_manip_pkt(skb, 0, &target, manip)) |
| 219 | return 0; | 220 | return 0; |
| 220 | 221 | ||
diff --git a/net/ipv4/netfilter/nf_nat_snmp_basic_main.c b/net/ipv4/netfilter/nf_nat_snmp_basic_main.c index a0aa13bcabda..0a8a60c1bf9a 100644 --- a/net/ipv4/netfilter/nf_nat_snmp_basic_main.c +++ b/net/ipv4/netfilter/nf_nat_snmp_basic_main.c | |||
| @@ -105,6 +105,8 @@ static void fast_csum(struct snmp_ctx *ctx, unsigned char offset) | |||
| 105 | int snmp_version(void *context, size_t hdrlen, unsigned char tag, | 105 | int snmp_version(void *context, size_t hdrlen, unsigned char tag, |
| 106 | const void *data, size_t datalen) | 106 | const void *data, size_t datalen) |
| 107 | { | 107 | { |
| 108 | if (datalen != 1) | ||
| 109 | return -EINVAL; | ||
| 108 | if (*(unsigned char *)data > 1) | 110 | if (*(unsigned char *)data > 1) |
| 109 | return -ENOTSUPP; | 111 | return -ENOTSUPP; |
| 110 | return 1; | 112 | return 1; |
| @@ -114,8 +116,11 @@ int snmp_helper(void *context, size_t hdrlen, unsigned char tag, | |||
| 114 | const void *data, size_t datalen) | 116 | const void *data, size_t datalen) |
| 115 | { | 117 | { |
| 116 | struct snmp_ctx *ctx = (struct snmp_ctx *)context; | 118 | struct snmp_ctx *ctx = (struct snmp_ctx *)context; |
| 117 | __be32 *pdata = (__be32 *)data; | 119 | __be32 *pdata; |
| 118 | 120 | ||
| 121 | if (datalen != 4) | ||
| 122 | return -EINVAL; | ||
| 123 | pdata = (__be32 *)data; | ||
| 119 | if (*pdata == ctx->from) { | 124 | if (*pdata == ctx->from) { |
| 120 | pr_debug("%s: %pI4 to %pI4\n", __func__, | 125 | pr_debug("%s: %pI4 to %pI4\n", __func__, |
| 121 | (void *)&ctx->from, (void *)&ctx->to); | 126 | (void *)&ctx->from, (void *)&ctx->to); |
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index ce92f73cf104..5163b64f8fb3 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
| @@ -887,13 +887,15 @@ void ip_rt_send_redirect(struct sk_buff *skb) | |||
| 887 | /* No redirected packets during ip_rt_redirect_silence; | 887 | /* No redirected packets during ip_rt_redirect_silence; |
| 888 | * reset the algorithm. | 888 | * reset the algorithm. |
| 889 | */ | 889 | */ |
| 890 | if (time_after(jiffies, peer->rate_last + ip_rt_redirect_silence)) | 890 | if (time_after(jiffies, peer->rate_last + ip_rt_redirect_silence)) { |
| 891 | peer->rate_tokens = 0; | 891 | peer->rate_tokens = 0; |
| 892 | peer->n_redirects = 0; | ||
| 893 | } | ||
| 892 | 894 | ||
| 893 | /* Too many ignored redirects; do not send anything | 895 | /* Too many ignored redirects; do not send anything |
| 894 | * set dst.rate_last to the last seen redirected packet. | 896 | * set dst.rate_last to the last seen redirected packet. |
| 895 | */ | 897 | */ |
| 896 | if (peer->rate_tokens >= ip_rt_redirect_number) { | 898 | if (peer->n_redirects >= ip_rt_redirect_number) { |
| 897 | peer->rate_last = jiffies; | 899 | peer->rate_last = jiffies; |
| 898 | goto out_put_peer; | 900 | goto out_put_peer; |
| 899 | } | 901 | } |
| @@ -910,6 +912,7 @@ void ip_rt_send_redirect(struct sk_buff *skb) | |||
| 910 | icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, gw); | 912 | icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, gw); |
| 911 | peer->rate_last = jiffies; | 913 | peer->rate_last = jiffies; |
| 912 | ++peer->rate_tokens; | 914 | ++peer->rate_tokens; |
| 915 | ++peer->n_redirects; | ||
| 913 | #ifdef CONFIG_IP_ROUTE_VERBOSE | 916 | #ifdef CONFIG_IP_ROUTE_VERBOSE |
| 914 | if (log_martians && | 917 | if (log_martians && |
| 915 | peer->rate_tokens == ip_rt_redirect_number) | 918 | peer->rate_tokens == ip_rt_redirect_number) |
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 27e2f6837062..cf3c5095c10e 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
| @@ -1186,7 +1186,7 @@ int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size) | |||
| 1186 | flags = msg->msg_flags; | 1186 | flags = msg->msg_flags; |
| 1187 | 1187 | ||
| 1188 | if (flags & MSG_ZEROCOPY && size && sock_flag(sk, SOCK_ZEROCOPY)) { | 1188 | if (flags & MSG_ZEROCOPY && size && sock_flag(sk, SOCK_ZEROCOPY)) { |
| 1189 | if (sk->sk_state != TCP_ESTABLISHED) { | 1189 | if ((1 << sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) { |
| 1190 | err = -EINVAL; | 1190 | err = -EINVAL; |
| 1191 | goto out_err; | 1191 | goto out_err; |
| 1192 | } | 1192 | } |
| @@ -2528,6 +2528,7 @@ void tcp_write_queue_purge(struct sock *sk) | |||
| 2528 | sk_mem_reclaim(sk); | 2528 | sk_mem_reclaim(sk); |
| 2529 | tcp_clear_all_retrans_hints(tcp_sk(sk)); | 2529 | tcp_clear_all_retrans_hints(tcp_sk(sk)); |
| 2530 | tcp_sk(sk)->packets_out = 0; | 2530 | tcp_sk(sk)->packets_out = 0; |
| 2531 | inet_csk(sk)->icsk_backoff = 0; | ||
| 2531 | } | 2532 | } |
| 2532 | 2533 | ||
| 2533 | int tcp_disconnect(struct sock *sk, int flags) | 2534 | int tcp_disconnect(struct sock *sk, int flags) |
| @@ -2576,7 +2577,6 @@ int tcp_disconnect(struct sock *sk, int flags) | |||
| 2576 | tp->write_seq += tp->max_window + 2; | 2577 | tp->write_seq += tp->max_window + 2; |
| 2577 | if (tp->write_seq == 0) | 2578 | if (tp->write_seq == 0) |
| 2578 | tp->write_seq = 1; | 2579 | tp->write_seq = 1; |
| 2579 | icsk->icsk_backoff = 0; | ||
| 2580 | tp->snd_cwnd = 2; | 2580 | tp->snd_cwnd = 2; |
| 2581 | icsk->icsk_probes_out = 0; | 2581 | icsk->icsk_probes_out = 0; |
| 2582 | tp->snd_ssthresh = TCP_INFINITE_SSTHRESH; | 2582 | tp->snd_ssthresh = TCP_INFINITE_SSTHRESH; |
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index efc6fef692ff..ec3cea9d6828 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
| @@ -536,12 +536,15 @@ int tcp_v4_err(struct sk_buff *icmp_skb, u32 info) | |||
| 536 | if (sock_owned_by_user(sk)) | 536 | if (sock_owned_by_user(sk)) |
| 537 | break; | 537 | break; |
| 538 | 538 | ||
| 539 | skb = tcp_rtx_queue_head(sk); | ||
| 540 | if (WARN_ON_ONCE(!skb)) | ||
| 541 | break; | ||
| 542 | |||
| 539 | icsk->icsk_backoff--; | 543 | icsk->icsk_backoff--; |
| 540 | icsk->icsk_rto = tp->srtt_us ? __tcp_set_rto(tp) : | 544 | icsk->icsk_rto = tp->srtt_us ? __tcp_set_rto(tp) : |
| 541 | TCP_TIMEOUT_INIT; | 545 | TCP_TIMEOUT_INIT; |
| 542 | icsk->icsk_rto = inet_csk_rto_backoff(icsk, TCP_RTO_MAX); | 546 | icsk->icsk_rto = inet_csk_rto_backoff(icsk, TCP_RTO_MAX); |
| 543 | 547 | ||
| 544 | skb = tcp_rtx_queue_head(sk); | ||
| 545 | 548 | ||
| 546 | tcp_mstamp_refresh(tp); | 549 | tcp_mstamp_refresh(tp); |
| 547 | delta_us = (u32)(tp->tcp_mstamp - tcp_skb_timestamp_us(skb)); | 550 | delta_us = (u32)(tp->tcp_mstamp - tcp_skb_timestamp_us(skb)); |
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 730bc44dbad9..ccc78f3a4b60 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
| @@ -2347,6 +2347,7 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, | |||
| 2347 | /* "skb_mstamp_ns" is used as a start point for the retransmit timer */ | 2347 | /* "skb_mstamp_ns" is used as a start point for the retransmit timer */ |
| 2348 | skb->skb_mstamp_ns = tp->tcp_wstamp_ns = tp->tcp_clock_cache; | 2348 | skb->skb_mstamp_ns = tp->tcp_wstamp_ns = tp->tcp_clock_cache; |
| 2349 | list_move_tail(&skb->tcp_tsorted_anchor, &tp->tsorted_sent_queue); | 2349 | list_move_tail(&skb->tcp_tsorted_anchor, &tp->tsorted_sent_queue); |
| 2350 | tcp_init_tso_segs(skb, mss_now); | ||
| 2350 | goto repair; /* Skip network transmission */ | 2351 | goto repair; /* Skip network transmission */ |
| 2351 | } | 2352 | } |
| 2352 | 2353 | ||
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index f87dbc78b6bc..71a29e9c0620 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c | |||
| @@ -226,7 +226,7 @@ static int tcp_write_timeout(struct sock *sk) | |||
| 226 | if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) { | 226 | if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) { |
| 227 | if (icsk->icsk_retransmits) { | 227 | if (icsk->icsk_retransmits) { |
| 228 | dst_negative_advice(sk); | 228 | dst_negative_advice(sk); |
| 229 | } else if (!tp->syn_data && !tp->syn_fastopen) { | 229 | } else { |
| 230 | sk_rethink_txhash(sk); | 230 | sk_rethink_txhash(sk); |
| 231 | } | 231 | } |
| 232 | retry_until = icsk->icsk_syn_retries ? : net->ipv4.sysctl_tcp_syn_retries; | 232 | retry_until = icsk->icsk_syn_retries ? : net->ipv4.sysctl_tcp_syn_retries; |
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 3fb0ed5e4789..372fdc5381a9 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
| @@ -562,10 +562,12 @@ static int __udp4_lib_err_encap_no_sk(struct sk_buff *skb, u32 info) | |||
| 562 | 562 | ||
| 563 | for (i = 0; i < MAX_IPTUN_ENCAP_OPS; i++) { | 563 | for (i = 0; i < MAX_IPTUN_ENCAP_OPS; i++) { |
| 564 | int (*handler)(struct sk_buff *skb, u32 info); | 564 | int (*handler)(struct sk_buff *skb, u32 info); |
| 565 | const struct ip_tunnel_encap_ops *encap; | ||
| 565 | 566 | ||
| 566 | if (!iptun_encaps[i]) | 567 | encap = rcu_dereference(iptun_encaps[i]); |
| 568 | if (!encap) | ||
| 567 | continue; | 569 | continue; |
| 568 | handler = rcu_dereference(iptun_encaps[i]->err_handler); | 570 | handler = encap->err_handler; |
| 569 | if (handler && !handler(skb, info)) | 571 | if (handler && !handler(skb, info)) |
| 570 | return 0; | 572 | return 0; |
| 571 | } | 573 | } |
| @@ -847,15 +849,23 @@ static int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4, | |||
| 847 | const int hlen = skb_network_header_len(skb) + | 849 | const int hlen = skb_network_header_len(skb) + |
| 848 | sizeof(struct udphdr); | 850 | sizeof(struct udphdr); |
| 849 | 851 | ||
| 850 | if (hlen + cork->gso_size > cork->fragsize) | 852 | if (hlen + cork->gso_size > cork->fragsize) { |
| 853 | kfree_skb(skb); | ||
| 851 | return -EINVAL; | 854 | return -EINVAL; |
| 852 | if (skb->len > cork->gso_size * UDP_MAX_SEGMENTS) | 855 | } |
| 856 | if (skb->len > cork->gso_size * UDP_MAX_SEGMENTS) { | ||
| 857 | kfree_skb(skb); | ||
| 853 | return -EINVAL; | 858 | return -EINVAL; |
| 854 | if (sk->sk_no_check_tx) | 859 | } |
| 860 | if (sk->sk_no_check_tx) { | ||
| 861 | kfree_skb(skb); | ||
| 855 | return -EINVAL; | 862 | return -EINVAL; |
| 863 | } | ||
| 856 | if (skb->ip_summed != CHECKSUM_PARTIAL || is_udplite || | 864 | if (skb->ip_summed != CHECKSUM_PARTIAL || is_udplite || |
| 857 | dst_xfrm(skb_dst(skb))) | 865 | dst_xfrm(skb_dst(skb))) { |
| 866 | kfree_skb(skb); | ||
| 858 | return -EIO; | 867 | return -EIO; |
| 868 | } | ||
| 859 | 869 | ||
| 860 | skb_shinfo(skb)->gso_size = cork->gso_size; | 870 | skb_shinfo(skb)->gso_size = cork->gso_size; |
| 861 | skb_shinfo(skb)->gso_type = SKB_GSO_UDP_L4; | 871 | skb_shinfo(skb)->gso_type = SKB_GSO_UDP_L4; |
| @@ -1918,7 +1928,7 @@ void udp_lib_rehash(struct sock *sk, u16 newhash) | |||
| 1918 | } | 1928 | } |
| 1919 | EXPORT_SYMBOL(udp_lib_rehash); | 1929 | EXPORT_SYMBOL(udp_lib_rehash); |
| 1920 | 1930 | ||
| 1921 | static void udp_v4_rehash(struct sock *sk) | 1931 | void udp_v4_rehash(struct sock *sk) |
| 1922 | { | 1932 | { |
| 1923 | u16 new_hash = ipv4_portaddr_hash(sock_net(sk), | 1933 | u16 new_hash = ipv4_portaddr_hash(sock_net(sk), |
| 1924 | inet_sk(sk)->inet_rcv_saddr, | 1934 | inet_sk(sk)->inet_rcv_saddr, |
diff --git a/net/ipv4/udp_impl.h b/net/ipv4/udp_impl.h index 322672655419..6b2fa77eeb1c 100644 --- a/net/ipv4/udp_impl.h +++ b/net/ipv4/udp_impl.h | |||
| @@ -10,6 +10,7 @@ int __udp4_lib_rcv(struct sk_buff *, struct udp_table *, int); | |||
| 10 | int __udp4_lib_err(struct sk_buff *, u32, struct udp_table *); | 10 | int __udp4_lib_err(struct sk_buff *, u32, struct udp_table *); |
| 11 | 11 | ||
| 12 | int udp_v4_get_port(struct sock *sk, unsigned short snum); | 12 | int udp_v4_get_port(struct sock *sk, unsigned short snum); |
| 13 | void udp_v4_rehash(struct sock *sk); | ||
| 13 | 14 | ||
| 14 | int udp_setsockopt(struct sock *sk, int level, int optname, | 15 | int udp_setsockopt(struct sock *sk, int level, int optname, |
| 15 | char __user *optval, unsigned int optlen); | 16 | char __user *optval, unsigned int optlen); |
diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c index 39c7f17d916f..3c94b8f0ff27 100644 --- a/net/ipv4/udplite.c +++ b/net/ipv4/udplite.c | |||
| @@ -53,6 +53,7 @@ struct proto udplite_prot = { | |||
| 53 | .sendpage = udp_sendpage, | 53 | .sendpage = udp_sendpage, |
| 54 | .hash = udp_lib_hash, | 54 | .hash = udp_lib_hash, |
| 55 | .unhash = udp_lib_unhash, | 55 | .unhash = udp_lib_unhash, |
| 56 | .rehash = udp_v4_rehash, | ||
| 56 | .get_port = udp_v4_get_port, | 57 | .get_port = udp_v4_get_port, |
| 57 | .memory_allocated = &udp_memory_allocated, | 58 | .memory_allocated = &udp_memory_allocated, |
| 58 | .sysctl_mem = sysctl_udp_mem, | 59 | .sysctl_mem = sysctl_udp_mem, |
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 8eeec6eb2bd3..72ffd3d760ff 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
| @@ -1165,7 +1165,8 @@ check_cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long *expires) | |||
| 1165 | list_for_each_entry(ifa, &idev->addr_list, if_list) { | 1165 | list_for_each_entry(ifa, &idev->addr_list, if_list) { |
| 1166 | if (ifa == ifp) | 1166 | if (ifa == ifp) |
| 1167 | continue; | 1167 | continue; |
| 1168 | if (!ipv6_prefix_equal(&ifa->addr, &ifp->addr, | 1168 | if (ifa->prefix_len != ifp->prefix_len || |
| 1169 | !ipv6_prefix_equal(&ifa->addr, &ifp->addr, | ||
| 1169 | ifp->prefix_len)) | 1170 | ifp->prefix_len)) |
| 1170 | continue; | 1171 | continue; |
| 1171 | if (ifa->flags & (IFA_F_PERMANENT | IFA_F_NOPREFIXROUTE)) | 1172 | if (ifa->flags & (IFA_F_PERMANENT | IFA_F_NOPREFIXROUTE)) |
| @@ -3495,8 +3496,8 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, | |||
| 3495 | 3496 | ||
| 3496 | if (!addrconf_link_ready(dev)) { | 3497 | if (!addrconf_link_ready(dev)) { |
| 3497 | /* device is not ready yet. */ | 3498 | /* device is not ready yet. */ |
| 3498 | pr_info("ADDRCONF(NETDEV_UP): %s: link is not ready\n", | 3499 | pr_debug("ADDRCONF(NETDEV_UP): %s: link is not ready\n", |
| 3499 | dev->name); | 3500 | dev->name); |
| 3500 | break; | 3501 | break; |
| 3501 | } | 3502 | } |
| 3502 | 3503 | ||
| @@ -5120,6 +5121,8 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, | |||
| 5120 | if (idev) { | 5121 | if (idev) { |
| 5121 | err = in6_dump_addrs(idev, skb, cb, s_ip_idx, | 5122 | err = in6_dump_addrs(idev, skb, cb, s_ip_idx, |
| 5122 | &fillargs); | 5123 | &fillargs); |
| 5124 | if (err > 0) | ||
| 5125 | err = 0; | ||
| 5123 | } | 5126 | } |
| 5124 | goto put_tgt_net; | 5127 | goto put_tgt_net; |
| 5125 | } | 5128 | } |
| @@ -5154,7 +5157,7 @@ put_tgt_net: | |||
| 5154 | if (fillargs.netnsid >= 0) | 5157 | if (fillargs.netnsid >= 0) |
| 5155 | put_net(tgt_net); | 5158 | put_net(tgt_net); |
| 5156 | 5159 | ||
| 5157 | return err < 0 ? err : skb->len; | 5160 | return skb->len ? : err; |
| 5158 | } | 5161 | } |
| 5159 | 5162 | ||
| 5160 | static int inet6_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) | 5163 | static int inet6_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) |
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 0bfb6cc0a30a..d99753b5e39b 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
| @@ -310,6 +310,7 @@ static int __inet6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len, | |||
| 310 | 310 | ||
| 311 | /* Check if the address belongs to the host. */ | 311 | /* Check if the address belongs to the host. */ |
| 312 | if (addr_type == IPV6_ADDR_MAPPED) { | 312 | if (addr_type == IPV6_ADDR_MAPPED) { |
| 313 | struct net_device *dev = NULL; | ||
| 313 | int chk_addr_ret; | 314 | int chk_addr_ret; |
| 314 | 315 | ||
| 315 | /* Binding to v4-mapped address on a v6-only socket | 316 | /* Binding to v4-mapped address on a v6-only socket |
| @@ -320,9 +321,20 @@ static int __inet6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len, | |||
| 320 | goto out; | 321 | goto out; |
| 321 | } | 322 | } |
| 322 | 323 | ||
| 324 | rcu_read_lock(); | ||
| 325 | if (sk->sk_bound_dev_if) { | ||
| 326 | dev = dev_get_by_index_rcu(net, sk->sk_bound_dev_if); | ||
| 327 | if (!dev) { | ||
| 328 | err = -ENODEV; | ||
| 329 | goto out_unlock; | ||
| 330 | } | ||
| 331 | } | ||
| 332 | |||
| 323 | /* Reproduce AF_INET checks to make the bindings consistent */ | 333 | /* Reproduce AF_INET checks to make the bindings consistent */ |
| 324 | v4addr = addr->sin6_addr.s6_addr32[3]; | 334 | v4addr = addr->sin6_addr.s6_addr32[3]; |
| 325 | chk_addr_ret = inet_addr_type(net, v4addr); | 335 | chk_addr_ret = inet_addr_type_dev_table(net, dev, v4addr); |
| 336 | rcu_read_unlock(); | ||
| 337 | |||
| 326 | if (!inet_can_nonlocal_bind(net, inet) && | 338 | if (!inet_can_nonlocal_bind(net, inet) && |
| 327 | v4addr != htonl(INADDR_ANY) && | 339 | v4addr != htonl(INADDR_ANY) && |
| 328 | chk_addr_ret != RTN_LOCAL && | 340 | chk_addr_ret != RTN_LOCAL && |
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index bde08aa549f3..ee4a4e54d016 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c | |||
| @@ -341,6 +341,7 @@ void ipv6_local_error(struct sock *sk, int err, struct flowi6 *fl6, u32 info) | |||
| 341 | skb_reset_network_header(skb); | 341 | skb_reset_network_header(skb); |
| 342 | iph = ipv6_hdr(skb); | 342 | iph = ipv6_hdr(skb); |
| 343 | iph->daddr = fl6->daddr; | 343 | iph->daddr = fl6->daddr; |
| 344 | ip6_flow_hdr(iph, 0, 0); | ||
| 344 | 345 | ||
| 345 | serr = SKB_EXT_ERR(skb); | 346 | serr = SKB_EXT_ERR(skb); |
| 346 | serr->ee.ee_errno = err; | 347 | serr->ee.ee_errno = err; |
| @@ -700,17 +701,15 @@ void ip6_datagram_recv_specific_ctl(struct sock *sk, struct msghdr *msg, | |||
| 700 | } | 701 | } |
| 701 | if (np->rxopt.bits.rxorigdstaddr) { | 702 | if (np->rxopt.bits.rxorigdstaddr) { |
| 702 | struct sockaddr_in6 sin6; | 703 | struct sockaddr_in6 sin6; |
| 703 | __be16 *ports; | 704 | __be16 _ports[2], *ports; |
| 704 | int end; | ||
| 705 | 705 | ||
| 706 | end = skb_transport_offset(skb) + 4; | 706 | ports = skb_header_pointer(skb, skb_transport_offset(skb), |
| 707 | if (end <= 0 || pskb_may_pull(skb, end)) { | 707 | sizeof(_ports), &_ports); |
| 708 | if (ports) { | ||
| 708 | /* All current transport protocols have the port numbers in the | 709 | /* All current transport protocols have the port numbers in the |
| 709 | * first four bytes of the transport header and this function is | 710 | * first four bytes of the transport header and this function is |
| 710 | * written with this assumption in mind. | 711 | * written with this assumption in mind. |
| 711 | */ | 712 | */ |
| 712 | ports = (__be16 *)skb_transport_header(skb); | ||
| 713 | |||
| 714 | sin6.sin6_family = AF_INET6; | 713 | sin6.sin6_family = AF_INET6; |
| 715 | sin6.sin6_addr = ipv6_hdr(skb)->daddr; | 714 | sin6.sin6_addr = ipv6_hdr(skb)->daddr; |
| 716 | sin6.sin6_port = ports[1]; | 715 | sin6.sin6_port = ports[1]; |
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 5afe9f83374d..239d4a65ad6e 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c | |||
| @@ -296,7 +296,7 @@ int esp6_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info | |||
| 296 | skb->len += tailen; | 296 | skb->len += tailen; |
| 297 | skb->data_len += tailen; | 297 | skb->data_len += tailen; |
| 298 | skb->truesize += tailen; | 298 | skb->truesize += tailen; |
| 299 | if (sk) | 299 | if (sk && sk_fullsock(sk)) |
| 300 | refcount_add(tailen, &sk->sk_wmem_alloc); | 300 | refcount_add(tailen, &sk->sk_wmem_alloc); |
| 301 | 301 | ||
| 302 | goto out; | 302 | goto out; |
diff --git a/net/ipv6/fou6.c b/net/ipv6/fou6.c index bd675c61deb1..867474abe269 100644 --- a/net/ipv6/fou6.c +++ b/net/ipv6/fou6.c | |||
| @@ -72,7 +72,7 @@ static int gue6_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e, | |||
| 72 | 72 | ||
| 73 | static int gue6_err_proto_handler(int proto, struct sk_buff *skb, | 73 | static int gue6_err_proto_handler(int proto, struct sk_buff *skb, |
| 74 | struct inet6_skb_parm *opt, | 74 | struct inet6_skb_parm *opt, |
| 75 | u8 type, u8 code, int offset, u32 info) | 75 | u8 type, u8 code, int offset, __be32 info) |
| 76 | { | 76 | { |
| 77 | const struct inet6_protocol *ipprot; | 77 | const struct inet6_protocol *ipprot; |
| 78 | 78 | ||
| @@ -90,10 +90,11 @@ static int gue6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 90 | { | 90 | { |
| 91 | int transport_offset = skb_transport_offset(skb); | 91 | int transport_offset = skb_transport_offset(skb); |
| 92 | struct guehdr *guehdr; | 92 | struct guehdr *guehdr; |
| 93 | size_t optlen; | 93 | size_t len, optlen; |
| 94 | int ret; | 94 | int ret; |
| 95 | 95 | ||
| 96 | if (skb->len < sizeof(struct udphdr) + sizeof(struct guehdr)) | 96 | len = sizeof(struct udphdr) + sizeof(struct guehdr); |
| 97 | if (!pskb_may_pull(skb, len)) | ||
| 97 | return -EINVAL; | 98 | return -EINVAL; |
| 98 | 99 | ||
| 99 | guehdr = (struct guehdr *)&udp_hdr(skb)[1]; | 100 | guehdr = (struct guehdr *)&udp_hdr(skb)[1]; |
| @@ -128,9 +129,21 @@ static int gue6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 128 | 129 | ||
| 129 | optlen = guehdr->hlen << 2; | 130 | optlen = guehdr->hlen << 2; |
| 130 | 131 | ||
| 132 | if (!pskb_may_pull(skb, len + optlen)) | ||
| 133 | return -EINVAL; | ||
| 134 | |||
| 135 | guehdr = (struct guehdr *)&udp_hdr(skb)[1]; | ||
| 131 | if (validate_gue_flags(guehdr, optlen)) | 136 | if (validate_gue_flags(guehdr, optlen)) |
| 132 | return -EINVAL; | 137 | return -EINVAL; |
| 133 | 138 | ||
| 139 | /* Handling exceptions for direct UDP encapsulation in GUE would lead to | ||
| 140 | * recursion. Besides, this kind of encapsulation can't even be | ||
| 141 | * configured currently. Discard this. | ||
| 142 | */ | ||
| 143 | if (guehdr->proto_ctype == IPPROTO_UDP || | ||
| 144 | guehdr->proto_ctype == IPPROTO_UDPLITE) | ||
| 145 | return -EOPNOTSUPP; | ||
| 146 | |||
| 134 | skb_set_transport_header(skb, -(int)sizeof(struct icmp6hdr)); | 147 | skb_set_transport_header(skb, -(int)sizeof(struct icmp6hdr)); |
| 135 | ret = gue6_err_proto_handler(guehdr->proto_ctype, skb, | 148 | ret = gue6_err_proto_handler(guehdr->proto_ctype, skb, |
| 136 | opt, type, code, offset, info); | 149 | opt, type, code, offset, info); |
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 5d7aa2c2770c..bbcdfd299692 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c | |||
| @@ -423,10 +423,10 @@ static int icmp6_iif(const struct sk_buff *skb) | |||
| 423 | static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info, | 423 | static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info, |
| 424 | const struct in6_addr *force_saddr) | 424 | const struct in6_addr *force_saddr) |
| 425 | { | 425 | { |
| 426 | struct net *net = dev_net(skb->dev); | ||
| 427 | struct inet6_dev *idev = NULL; | 426 | struct inet6_dev *idev = NULL; |
| 428 | struct ipv6hdr *hdr = ipv6_hdr(skb); | 427 | struct ipv6hdr *hdr = ipv6_hdr(skb); |
| 429 | struct sock *sk; | 428 | struct sock *sk; |
| 429 | struct net *net; | ||
| 430 | struct ipv6_pinfo *np; | 430 | struct ipv6_pinfo *np; |
| 431 | const struct in6_addr *saddr = NULL; | 431 | const struct in6_addr *saddr = NULL; |
| 432 | struct dst_entry *dst; | 432 | struct dst_entry *dst; |
| @@ -437,12 +437,16 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info, | |||
| 437 | int iif = 0; | 437 | int iif = 0; |
| 438 | int addr_type = 0; | 438 | int addr_type = 0; |
| 439 | int len; | 439 | int len; |
| 440 | u32 mark = IP6_REPLY_MARK(net, skb->mark); | 440 | u32 mark; |
| 441 | 441 | ||
| 442 | if ((u8 *)hdr < skb->head || | 442 | if ((u8 *)hdr < skb->head || |
| 443 | (skb_network_header(skb) + sizeof(*hdr)) > skb_tail_pointer(skb)) | 443 | (skb_network_header(skb) + sizeof(*hdr)) > skb_tail_pointer(skb)) |
| 444 | return; | 444 | return; |
| 445 | 445 | ||
| 446 | if (!skb->dev) | ||
| 447 | return; | ||
| 448 | net = dev_net(skb->dev); | ||
| 449 | mark = IP6_REPLY_MARK(net, skb->mark); | ||
| 446 | /* | 450 | /* |
| 447 | * Make sure we respect the rules | 451 | * Make sure we respect the rules |
| 448 | * i.e. RFC 1885 2.4(e) | 452 | * i.e. RFC 1885 2.4(e) |
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 09d0826742f8..26f25b6e2833 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c | |||
| @@ -534,13 +534,9 @@ static int ip6erspan_rcv(struct sk_buff *skb, int gre_hdr_len, | |||
| 534 | struct ip6_tnl *tunnel; | 534 | struct ip6_tnl *tunnel; |
| 535 | u8 ver; | 535 | u8 ver; |
| 536 | 536 | ||
| 537 | if (unlikely(!pskb_may_pull(skb, sizeof(*ershdr)))) | ||
| 538 | return PACKET_REJECT; | ||
| 539 | |||
| 540 | ipv6h = ipv6_hdr(skb); | 537 | ipv6h = ipv6_hdr(skb); |
| 541 | ershdr = (struct erspan_base_hdr *)skb->data; | 538 | ershdr = (struct erspan_base_hdr *)skb->data; |
| 542 | ver = ershdr->ver; | 539 | ver = ershdr->ver; |
| 543 | tpi->key = cpu_to_be32(get_session_id(ershdr)); | ||
| 544 | 540 | ||
| 545 | tunnel = ip6gre_tunnel_lookup(skb->dev, | 541 | tunnel = ip6gre_tunnel_lookup(skb->dev, |
| 546 | &ipv6h->saddr, &ipv6h->daddr, tpi->key, | 542 | &ipv6h->saddr, &ipv6h->daddr, tpi->key, |
| @@ -922,6 +918,7 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb, | |||
| 922 | __u8 dsfield = false; | 918 | __u8 dsfield = false; |
| 923 | struct flowi6 fl6; | 919 | struct flowi6 fl6; |
| 924 | int err = -EINVAL; | 920 | int err = -EINVAL; |
| 921 | __be16 proto; | ||
| 925 | __u32 mtu; | 922 | __u32 mtu; |
| 926 | int nhoff; | 923 | int nhoff; |
| 927 | int thoff; | 924 | int thoff; |
| @@ -1035,8 +1032,9 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb, | |||
| 1035 | } | 1032 | } |
| 1036 | 1033 | ||
| 1037 | /* Push GRE header. */ | 1034 | /* Push GRE header. */ |
| 1038 | gre_build_header(skb, 8, TUNNEL_SEQ, | 1035 | proto = (t->parms.erspan_ver == 1) ? htons(ETH_P_ERSPAN) |
| 1039 | htons(ETH_P_ERSPAN), 0, htonl(t->o_seqno++)); | 1036 | : htons(ETH_P_ERSPAN2); |
| 1037 | gre_build_header(skb, 8, TUNNEL_SEQ, proto, 0, htonl(t->o_seqno++)); | ||
| 1040 | 1038 | ||
| 1041 | /* TooBig packet may have updated dst->dev's mtu */ | 1039 | /* TooBig packet may have updated dst->dev's mtu */ |
| 1042 | if (!t->parms.collect_md && dst && dst_mtu(dst) > dst->dev->mtu) | 1040 | if (!t->parms.collect_md && dst && dst_mtu(dst) > dst->dev->mtu) |
| @@ -1169,6 +1167,10 @@ static void ip6gre_tnl_copy_tnl_parm(struct ip6_tnl *t, | |||
| 1169 | t->parms.i_flags = p->i_flags; | 1167 | t->parms.i_flags = p->i_flags; |
| 1170 | t->parms.o_flags = p->o_flags; | 1168 | t->parms.o_flags = p->o_flags; |
| 1171 | t->parms.fwmark = p->fwmark; | 1169 | t->parms.fwmark = p->fwmark; |
| 1170 | t->parms.erspan_ver = p->erspan_ver; | ||
| 1171 | t->parms.index = p->index; | ||
| 1172 | t->parms.dir = p->dir; | ||
| 1173 | t->parms.hwid = p->hwid; | ||
| 1172 | dst_cache_reset(&t->dst_cache); | 1174 | dst_cache_reset(&t->dst_cache); |
| 1173 | } | 1175 | } |
| 1174 | 1176 | ||
| @@ -1717,6 +1719,27 @@ static int ip6erspan_tap_validate(struct nlattr *tb[], struct nlattr *data[], | |||
| 1717 | return 0; | 1719 | return 0; |
| 1718 | } | 1720 | } |
| 1719 | 1721 | ||
| 1722 | static void ip6erspan_set_version(struct nlattr *data[], | ||
| 1723 | struct __ip6_tnl_parm *parms) | ||
| 1724 | { | ||
| 1725 | if (!data) | ||
| 1726 | return; | ||
| 1727 | |||
| 1728 | parms->erspan_ver = 1; | ||
| 1729 | if (data[IFLA_GRE_ERSPAN_VER]) | ||
| 1730 | parms->erspan_ver = nla_get_u8(data[IFLA_GRE_ERSPAN_VER]); | ||
| 1731 | |||
| 1732 | if (parms->erspan_ver == 1) { | ||
| 1733 | if (data[IFLA_GRE_ERSPAN_INDEX]) | ||
| 1734 | parms->index = nla_get_u32(data[IFLA_GRE_ERSPAN_INDEX]); | ||
| 1735 | } else if (parms->erspan_ver == 2) { | ||
| 1736 | if (data[IFLA_GRE_ERSPAN_DIR]) | ||
| 1737 | parms->dir = nla_get_u8(data[IFLA_GRE_ERSPAN_DIR]); | ||
| 1738 | if (data[IFLA_GRE_ERSPAN_HWID]) | ||
| 1739 | parms->hwid = nla_get_u16(data[IFLA_GRE_ERSPAN_HWID]); | ||
| 1740 | } | ||
| 1741 | } | ||
| 1742 | |||
| 1720 | static void ip6gre_netlink_parms(struct nlattr *data[], | 1743 | static void ip6gre_netlink_parms(struct nlattr *data[], |
| 1721 | struct __ip6_tnl_parm *parms) | 1744 | struct __ip6_tnl_parm *parms) |
| 1722 | { | 1745 | { |
| @@ -1765,20 +1788,6 @@ static void ip6gre_netlink_parms(struct nlattr *data[], | |||
| 1765 | 1788 | ||
| 1766 | if (data[IFLA_GRE_COLLECT_METADATA]) | 1789 | if (data[IFLA_GRE_COLLECT_METADATA]) |
| 1767 | parms->collect_md = true; | 1790 | parms->collect_md = true; |
| 1768 | |||
| 1769 | parms->erspan_ver = 1; | ||
| 1770 | if (data[IFLA_GRE_ERSPAN_VER]) | ||
| 1771 | parms->erspan_ver = nla_get_u8(data[IFLA_GRE_ERSPAN_VER]); | ||
| 1772 | |||
| 1773 | if (parms->erspan_ver == 1) { | ||
| 1774 | if (data[IFLA_GRE_ERSPAN_INDEX]) | ||
| 1775 | parms->index = nla_get_u32(data[IFLA_GRE_ERSPAN_INDEX]); | ||
| 1776 | } else if (parms->erspan_ver == 2) { | ||
| 1777 | if (data[IFLA_GRE_ERSPAN_DIR]) | ||
| 1778 | parms->dir = nla_get_u8(data[IFLA_GRE_ERSPAN_DIR]); | ||
| 1779 | if (data[IFLA_GRE_ERSPAN_HWID]) | ||
| 1780 | parms->hwid = nla_get_u16(data[IFLA_GRE_ERSPAN_HWID]); | ||
| 1781 | } | ||
| 1782 | } | 1791 | } |
| 1783 | 1792 | ||
| 1784 | static int ip6gre_tap_init(struct net_device *dev) | 1793 | static int ip6gre_tap_init(struct net_device *dev) |
| @@ -2025,9 +2034,9 @@ static int ip6gre_changelink(struct net_device *dev, struct nlattr *tb[], | |||
| 2025 | struct nlattr *data[], | 2034 | struct nlattr *data[], |
| 2026 | struct netlink_ext_ack *extack) | 2035 | struct netlink_ext_ack *extack) |
| 2027 | { | 2036 | { |
| 2028 | struct ip6gre_net *ign = net_generic(dev_net(dev), ip6gre_net_id); | 2037 | struct ip6_tnl *t = netdev_priv(dev); |
| 2038 | struct ip6gre_net *ign = net_generic(t->net, ip6gre_net_id); | ||
| 2029 | struct __ip6_tnl_parm p; | 2039 | struct __ip6_tnl_parm p; |
| 2030 | struct ip6_tnl *t; | ||
| 2031 | 2040 | ||
| 2032 | t = ip6gre_changelink_common(dev, tb, data, &p, extack); | 2041 | t = ip6gre_changelink_common(dev, tb, data, &p, extack); |
| 2033 | if (IS_ERR(t)) | 2042 | if (IS_ERR(t)) |
| @@ -2096,12 +2105,31 @@ static int ip6gre_fill_info(struct sk_buff *skb, const struct net_device *dev) | |||
| 2096 | { | 2105 | { |
| 2097 | struct ip6_tnl *t = netdev_priv(dev); | 2106 | struct ip6_tnl *t = netdev_priv(dev); |
| 2098 | struct __ip6_tnl_parm *p = &t->parms; | 2107 | struct __ip6_tnl_parm *p = &t->parms; |
| 2108 | __be16 o_flags = p->o_flags; | ||
| 2109 | |||
| 2110 | if (p->erspan_ver == 1 || p->erspan_ver == 2) { | ||
| 2111 | if (!p->collect_md) | ||
| 2112 | o_flags |= TUNNEL_KEY; | ||
| 2113 | |||
| 2114 | if (nla_put_u8(skb, IFLA_GRE_ERSPAN_VER, p->erspan_ver)) | ||
| 2115 | goto nla_put_failure; | ||
| 2116 | |||
| 2117 | if (p->erspan_ver == 1) { | ||
| 2118 | if (nla_put_u32(skb, IFLA_GRE_ERSPAN_INDEX, p->index)) | ||
| 2119 | goto nla_put_failure; | ||
| 2120 | } else { | ||
| 2121 | if (nla_put_u8(skb, IFLA_GRE_ERSPAN_DIR, p->dir)) | ||
| 2122 | goto nla_put_failure; | ||
| 2123 | if (nla_put_u16(skb, IFLA_GRE_ERSPAN_HWID, p->hwid)) | ||
| 2124 | goto nla_put_failure; | ||
| 2125 | } | ||
| 2126 | } | ||
| 2099 | 2127 | ||
| 2100 | if (nla_put_u32(skb, IFLA_GRE_LINK, p->link) || | 2128 | if (nla_put_u32(skb, IFLA_GRE_LINK, p->link) || |
| 2101 | nla_put_be16(skb, IFLA_GRE_IFLAGS, | 2129 | nla_put_be16(skb, IFLA_GRE_IFLAGS, |
| 2102 | gre_tnl_flags_to_gre_flags(p->i_flags)) || | 2130 | gre_tnl_flags_to_gre_flags(p->i_flags)) || |
| 2103 | nla_put_be16(skb, IFLA_GRE_OFLAGS, | 2131 | nla_put_be16(skb, IFLA_GRE_OFLAGS, |
| 2104 | gre_tnl_flags_to_gre_flags(p->o_flags)) || | 2132 | gre_tnl_flags_to_gre_flags(o_flags)) || |
| 2105 | nla_put_be32(skb, IFLA_GRE_IKEY, p->i_key) || | 2133 | nla_put_be32(skb, IFLA_GRE_IKEY, p->i_key) || |
| 2106 | nla_put_be32(skb, IFLA_GRE_OKEY, p->o_key) || | 2134 | nla_put_be32(skb, IFLA_GRE_OKEY, p->o_key) || |
| 2107 | nla_put_in6_addr(skb, IFLA_GRE_LOCAL, &p->laddr) || | 2135 | nla_put_in6_addr(skb, IFLA_GRE_LOCAL, &p->laddr) || |
| @@ -2110,8 +2138,7 @@ static int ip6gre_fill_info(struct sk_buff *skb, const struct net_device *dev) | |||
| 2110 | nla_put_u8(skb, IFLA_GRE_ENCAP_LIMIT, p->encap_limit) || | 2138 | nla_put_u8(skb, IFLA_GRE_ENCAP_LIMIT, p->encap_limit) || |
| 2111 | nla_put_be32(skb, IFLA_GRE_FLOWINFO, p->flowinfo) || | 2139 | nla_put_be32(skb, IFLA_GRE_FLOWINFO, p->flowinfo) || |
| 2112 | nla_put_u32(skb, IFLA_GRE_FLAGS, p->flags) || | 2140 | nla_put_u32(skb, IFLA_GRE_FLAGS, p->flags) || |
| 2113 | nla_put_u32(skb, IFLA_GRE_FWMARK, p->fwmark) || | 2141 | nla_put_u32(skb, IFLA_GRE_FWMARK, p->fwmark)) |
| 2114 | nla_put_u32(skb, IFLA_GRE_ERSPAN_INDEX, p->index)) | ||
| 2115 | goto nla_put_failure; | 2142 | goto nla_put_failure; |
| 2116 | 2143 | ||
| 2117 | if (nla_put_u16(skb, IFLA_GRE_ENCAP_TYPE, | 2144 | if (nla_put_u16(skb, IFLA_GRE_ENCAP_TYPE, |
| @@ -2129,19 +2156,6 @@ static int ip6gre_fill_info(struct sk_buff *skb, const struct net_device *dev) | |||
| 2129 | goto nla_put_failure; | 2156 | goto nla_put_failure; |
| 2130 | } | 2157 | } |
| 2131 | 2158 | ||
| 2132 | if (nla_put_u8(skb, IFLA_GRE_ERSPAN_VER, p->erspan_ver)) | ||
| 2133 | goto nla_put_failure; | ||
| 2134 | |||
| 2135 | if (p->erspan_ver == 1) { | ||
| 2136 | if (nla_put_u32(skb, IFLA_GRE_ERSPAN_INDEX, p->index)) | ||
| 2137 | goto nla_put_failure; | ||
| 2138 | } else if (p->erspan_ver == 2) { | ||
| 2139 | if (nla_put_u8(skb, IFLA_GRE_ERSPAN_DIR, p->dir)) | ||
| 2140 | goto nla_put_failure; | ||
| 2141 | if (nla_put_u16(skb, IFLA_GRE_ERSPAN_HWID, p->hwid)) | ||
| 2142 | goto nla_put_failure; | ||
| 2143 | } | ||
| 2144 | |||
| 2145 | return 0; | 2159 | return 0; |
| 2146 | 2160 | ||
| 2147 | nla_put_failure: | 2161 | nla_put_failure: |
| @@ -2196,6 +2210,7 @@ static int ip6erspan_newlink(struct net *src_net, struct net_device *dev, | |||
| 2196 | int err; | 2210 | int err; |
| 2197 | 2211 | ||
| 2198 | ip6gre_netlink_parms(data, &nt->parms); | 2212 | ip6gre_netlink_parms(data, &nt->parms); |
| 2213 | ip6erspan_set_version(data, &nt->parms); | ||
| 2199 | ign = net_generic(net, ip6gre_net_id); | 2214 | ign = net_generic(net, ip6gre_net_id); |
| 2200 | 2215 | ||
| 2201 | if (nt->parms.collect_md) { | 2216 | if (nt->parms.collect_md) { |
| @@ -2241,6 +2256,7 @@ static int ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[], | |||
| 2241 | if (IS_ERR(t)) | 2256 | if (IS_ERR(t)) |
| 2242 | return PTR_ERR(t); | 2257 | return PTR_ERR(t); |
| 2243 | 2258 | ||
| 2259 | ip6erspan_set_version(data, &p); | ||
| 2244 | ip6gre_tunnel_unlink_md(ign, t); | 2260 | ip6gre_tunnel_unlink_md(ign, t); |
| 2245 | ip6gre_tunnel_unlink(ign, t); | 2261 | ip6gre_tunnel_unlink(ign, t); |
| 2246 | ip6erspan_tnl_change(t, &p, !tb[IFLA_MTU]); | 2262 | ip6erspan_tnl_change(t, &p, !tb[IFLA_MTU]); |
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 30337b38274b..cc01aa3f2b5e 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c | |||
| @@ -1516,6 +1516,9 @@ static void mroute_clean_tables(struct mr_table *mrt, bool all) | |||
| 1516 | continue; | 1516 | continue; |
| 1517 | rhltable_remove(&mrt->mfc_hash, &c->mnode, ip6mr_rht_params); | 1517 | rhltable_remove(&mrt->mfc_hash, &c->mnode, ip6mr_rht_params); |
| 1518 | list_del_rcu(&c->list); | 1518 | list_del_rcu(&c->list); |
| 1519 | call_ip6mr_mfc_entry_notifiers(read_pnet(&mrt->net), | ||
| 1520 | FIB_EVENT_ENTRY_DEL, | ||
| 1521 | (struct mfc6_cache *)c, mrt->id); | ||
| 1519 | mr6_netlink_event(mrt, (struct mfc6_cache *)c, RTM_DELROUTE); | 1522 | mr6_netlink_event(mrt, (struct mfc6_cache *)c, RTM_DELROUTE); |
| 1520 | mr_cache_put(c); | 1523 | mr_cache_put(c); |
| 1521 | } | 1524 | } |
| @@ -1524,10 +1527,6 @@ static void mroute_clean_tables(struct mr_table *mrt, bool all) | |||
| 1524 | spin_lock_bh(&mfc_unres_lock); | 1527 | spin_lock_bh(&mfc_unres_lock); |
| 1525 | list_for_each_entry_safe(c, tmp, &mrt->mfc_unres_queue, list) { | 1528 | list_for_each_entry_safe(c, tmp, &mrt->mfc_unres_queue, list) { |
| 1526 | list_del(&c->list); | 1529 | list_del(&c->list); |
| 1527 | call_ip6mr_mfc_entry_notifiers(read_pnet(&mrt->net), | ||
| 1528 | FIB_EVENT_ENTRY_DEL, | ||
| 1529 | (struct mfc6_cache *)c, | ||
| 1530 | mrt->id); | ||
| 1531 | mr6_netlink_event(mrt, (struct mfc6_cache *)c, | 1530 | mr6_netlink_event(mrt, (struct mfc6_cache *)c, |
| 1532 | RTM_DELROUTE); | 1531 | RTM_DELROUTE); |
| 1533 | ip6mr_destroy_unres(mrt, (struct mfc6_cache *)c); | 1532 | ip6mr_destroy_unres(mrt, (struct mfc6_cache *)c); |
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index 8b075f0bc351..6d0b1f3e927b 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c | |||
| @@ -23,9 +23,11 @@ int ip6_route_me_harder(struct net *net, struct sk_buff *skb) | |||
| 23 | struct sock *sk = sk_to_full_sk(skb->sk); | 23 | struct sock *sk = sk_to_full_sk(skb->sk); |
| 24 | unsigned int hh_len; | 24 | unsigned int hh_len; |
| 25 | struct dst_entry *dst; | 25 | struct dst_entry *dst; |
| 26 | int strict = (ipv6_addr_type(&iph->daddr) & | ||
| 27 | (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL)); | ||
| 26 | struct flowi6 fl6 = { | 28 | struct flowi6 fl6 = { |
| 27 | .flowi6_oif = sk && sk->sk_bound_dev_if ? sk->sk_bound_dev_if : | 29 | .flowi6_oif = sk && sk->sk_bound_dev_if ? sk->sk_bound_dev_if : |
| 28 | rt6_need_strict(&iph->daddr) ? skb_dst(skb)->dev->ifindex : 0, | 30 | strict ? skb_dst(skb)->dev->ifindex : 0, |
| 29 | .flowi6_mark = skb->mark, | 31 | .flowi6_mark = skb->mark, |
| 30 | .flowi6_uid = sock_net_uid(net, sk), | 32 | .flowi6_uid = sock_net_uid(net, sk), |
| 31 | .daddr = iph->daddr, | 33 | .daddr = iph->daddr, |
diff --git a/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c b/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c index 23022447eb49..7a41ee3c11b4 100644 --- a/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c | |||
| @@ -226,6 +226,7 @@ int nf_nat_icmpv6_reply_translation(struct sk_buff *skb, | |||
| 226 | } | 226 | } |
| 227 | 227 | ||
| 228 | nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple); | 228 | nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple); |
| 229 | target.dst.protonum = IPPROTO_ICMPV6; | ||
| 229 | if (!nf_nat_ipv6_manip_pkt(skb, 0, &target, manip)) | 230 | if (!nf_nat_ipv6_manip_pkt(skb, 0, &target, manip)) |
| 230 | return 0; | 231 | return 0; |
| 231 | 232 | ||
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 40b225f87d5e..ce15dc4ccbfa 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
| @@ -1274,18 +1274,29 @@ static DEFINE_SPINLOCK(rt6_exception_lock); | |||
| 1274 | static void rt6_remove_exception(struct rt6_exception_bucket *bucket, | 1274 | static void rt6_remove_exception(struct rt6_exception_bucket *bucket, |
| 1275 | struct rt6_exception *rt6_ex) | 1275 | struct rt6_exception *rt6_ex) |
| 1276 | { | 1276 | { |
| 1277 | struct fib6_info *from; | ||
| 1277 | struct net *net; | 1278 | struct net *net; |
| 1278 | 1279 | ||
| 1279 | if (!bucket || !rt6_ex) | 1280 | if (!bucket || !rt6_ex) |
| 1280 | return; | 1281 | return; |
| 1281 | 1282 | ||
| 1282 | net = dev_net(rt6_ex->rt6i->dst.dev); | 1283 | net = dev_net(rt6_ex->rt6i->dst.dev); |
| 1284 | net->ipv6.rt6_stats->fib_rt_cache--; | ||
| 1285 | |||
| 1286 | /* purge completely the exception to allow releasing the held resources: | ||
| 1287 | * some [sk] cache may keep the dst around for unlimited time | ||
| 1288 | */ | ||
| 1289 | from = rcu_dereference_protected(rt6_ex->rt6i->from, | ||
| 1290 | lockdep_is_held(&rt6_exception_lock)); | ||
| 1291 | rcu_assign_pointer(rt6_ex->rt6i->from, NULL); | ||
| 1292 | fib6_info_release(from); | ||
| 1293 | dst_dev_put(&rt6_ex->rt6i->dst); | ||
| 1294 | |||
| 1283 | hlist_del_rcu(&rt6_ex->hlist); | 1295 | hlist_del_rcu(&rt6_ex->hlist); |
| 1284 | dst_release(&rt6_ex->rt6i->dst); | 1296 | dst_release(&rt6_ex->rt6i->dst); |
| 1285 | kfree_rcu(rt6_ex, rcu); | 1297 | kfree_rcu(rt6_ex, rcu); |
| 1286 | WARN_ON_ONCE(!bucket->depth); | 1298 | WARN_ON_ONCE(!bucket->depth); |
| 1287 | bucket->depth--; | 1299 | bucket->depth--; |
| 1288 | net->ipv6.rt6_stats->fib_rt_cache--; | ||
| 1289 | } | 1300 | } |
| 1290 | 1301 | ||
| 1291 | /* Remove oldest rt6_ex in bucket and free the memory | 1302 | /* Remove oldest rt6_ex in bucket and free the memory |
| @@ -1599,15 +1610,15 @@ static int rt6_remove_exception_rt(struct rt6_info *rt) | |||
| 1599 | static void rt6_update_exception_stamp_rt(struct rt6_info *rt) | 1610 | static void rt6_update_exception_stamp_rt(struct rt6_info *rt) |
| 1600 | { | 1611 | { |
| 1601 | struct rt6_exception_bucket *bucket; | 1612 | struct rt6_exception_bucket *bucket; |
| 1602 | struct fib6_info *from = rt->from; | ||
| 1603 | struct in6_addr *src_key = NULL; | 1613 | struct in6_addr *src_key = NULL; |
| 1604 | struct rt6_exception *rt6_ex; | 1614 | struct rt6_exception *rt6_ex; |
| 1605 | 1615 | struct fib6_info *from; | |
| 1606 | if (!from || | ||
| 1607 | !(rt->rt6i_flags & RTF_CACHE)) | ||
| 1608 | return; | ||
| 1609 | 1616 | ||
| 1610 | rcu_read_lock(); | 1617 | rcu_read_lock(); |
| 1618 | from = rcu_dereference(rt->from); | ||
| 1619 | if (!from || !(rt->rt6i_flags & RTF_CACHE)) | ||
| 1620 | goto unlock; | ||
| 1621 | |||
| 1611 | bucket = rcu_dereference(from->rt6i_exception_bucket); | 1622 | bucket = rcu_dereference(from->rt6i_exception_bucket); |
| 1612 | 1623 | ||
| 1613 | #ifdef CONFIG_IPV6_SUBTREES | 1624 | #ifdef CONFIG_IPV6_SUBTREES |
| @@ -1626,6 +1637,7 @@ static void rt6_update_exception_stamp_rt(struct rt6_info *rt) | |||
| 1626 | if (rt6_ex) | 1637 | if (rt6_ex) |
| 1627 | rt6_ex->stamp = jiffies; | 1638 | rt6_ex->stamp = jiffies; |
| 1628 | 1639 | ||
| 1640 | unlock: | ||
| 1629 | rcu_read_unlock(); | 1641 | rcu_read_unlock(); |
| 1630 | } | 1642 | } |
| 1631 | 1643 | ||
| @@ -2742,20 +2754,24 @@ static int ip6_route_check_nh_onlink(struct net *net, | |||
| 2742 | u32 tbid = l3mdev_fib_table(dev) ? : RT_TABLE_MAIN; | 2754 | u32 tbid = l3mdev_fib_table(dev) ? : RT_TABLE_MAIN; |
| 2743 | const struct in6_addr *gw_addr = &cfg->fc_gateway; | 2755 | const struct in6_addr *gw_addr = &cfg->fc_gateway; |
| 2744 | u32 flags = RTF_LOCAL | RTF_ANYCAST | RTF_REJECT; | 2756 | u32 flags = RTF_LOCAL | RTF_ANYCAST | RTF_REJECT; |
| 2757 | struct fib6_info *from; | ||
| 2745 | struct rt6_info *grt; | 2758 | struct rt6_info *grt; |
| 2746 | int err; | 2759 | int err; |
| 2747 | 2760 | ||
| 2748 | err = 0; | 2761 | err = 0; |
| 2749 | grt = ip6_nh_lookup_table(net, cfg, gw_addr, tbid, 0); | 2762 | grt = ip6_nh_lookup_table(net, cfg, gw_addr, tbid, 0); |
| 2750 | if (grt) { | 2763 | if (grt) { |
| 2764 | rcu_read_lock(); | ||
| 2765 | from = rcu_dereference(grt->from); | ||
| 2751 | if (!grt->dst.error && | 2766 | if (!grt->dst.error && |
| 2752 | /* ignore match if it is the default route */ | 2767 | /* ignore match if it is the default route */ |
| 2753 | grt->from && !ipv6_addr_any(&grt->from->fib6_dst.addr) && | 2768 | from && !ipv6_addr_any(&from->fib6_dst.addr) && |
| 2754 | (grt->rt6i_flags & flags || dev != grt->dst.dev)) { | 2769 | (grt->rt6i_flags & flags || dev != grt->dst.dev)) { |
| 2755 | NL_SET_ERR_MSG(extack, | 2770 | NL_SET_ERR_MSG(extack, |
| 2756 | "Nexthop has invalid gateway or device mismatch"); | 2771 | "Nexthop has invalid gateway or device mismatch"); |
| 2757 | err = -EINVAL; | 2772 | err = -EINVAL; |
| 2758 | } | 2773 | } |
| 2774 | rcu_read_unlock(); | ||
| 2759 | 2775 | ||
| 2760 | ip6_rt_put(grt); | 2776 | ip6_rt_put(grt); |
| 2761 | } | 2777 | } |
| @@ -4251,17 +4267,6 @@ struct rt6_nh { | |||
| 4251 | struct list_head next; | 4267 | struct list_head next; |
| 4252 | }; | 4268 | }; |
| 4253 | 4269 | ||
| 4254 | static void ip6_print_replace_route_err(struct list_head *rt6_nh_list) | ||
| 4255 | { | ||
| 4256 | struct rt6_nh *nh; | ||
| 4257 | |||
| 4258 | list_for_each_entry(nh, rt6_nh_list, next) { | ||
| 4259 | pr_warn("IPV6: multipath route replace failed (check consistency of installed routes): %pI6c nexthop %pI6c ifi %d\n", | ||
| 4260 | &nh->r_cfg.fc_dst, &nh->r_cfg.fc_gateway, | ||
| 4261 | nh->r_cfg.fc_ifindex); | ||
| 4262 | } | ||
| 4263 | } | ||
| 4264 | |||
| 4265 | static int ip6_route_info_append(struct net *net, | 4270 | static int ip6_route_info_append(struct net *net, |
| 4266 | struct list_head *rt6_nh_list, | 4271 | struct list_head *rt6_nh_list, |
| 4267 | struct fib6_info *rt, | 4272 | struct fib6_info *rt, |
| @@ -4407,7 +4412,8 @@ static int ip6_route_multipath_add(struct fib6_config *cfg, | |||
| 4407 | nh->fib6_info = NULL; | 4412 | nh->fib6_info = NULL; |
| 4408 | if (err) { | 4413 | if (err) { |
| 4409 | if (replace && nhn) | 4414 | if (replace && nhn) |
| 4410 | ip6_print_replace_route_err(&rt6_nh_list); | 4415 | NL_SET_ERR_MSG_MOD(extack, |
| 4416 | "multipath route replace failed (check consistency of installed routes)"); | ||
| 4411 | err_nh = nh; | 4417 | err_nh = nh; |
| 4412 | goto add_errout; | 4418 | goto add_errout; |
| 4413 | } | 4419 | } |
| @@ -4659,7 +4665,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb, | |||
| 4659 | table = rt->fib6_table->tb6_id; | 4665 | table = rt->fib6_table->tb6_id; |
| 4660 | else | 4666 | else |
| 4661 | table = RT6_TABLE_UNSPEC; | 4667 | table = RT6_TABLE_UNSPEC; |
| 4662 | rtm->rtm_table = table; | 4668 | rtm->rtm_table = table < 256 ? table : RT_TABLE_COMPAT; |
| 4663 | if (nla_put_u32(skb, RTA_TABLE, table)) | 4669 | if (nla_put_u32(skb, RTA_TABLE, table)) |
| 4664 | goto nla_put_failure; | 4670 | goto nla_put_failure; |
| 4665 | 4671 | ||
diff --git a/net/ipv6/seg6.c b/net/ipv6/seg6.c index 8d0ba757a46c..9b2f272ca164 100644 --- a/net/ipv6/seg6.c +++ b/net/ipv6/seg6.c | |||
| @@ -221,9 +221,7 @@ static int seg6_genl_get_tunsrc(struct sk_buff *skb, struct genl_info *info) | |||
| 221 | rcu_read_unlock(); | 221 | rcu_read_unlock(); |
| 222 | 222 | ||
| 223 | genlmsg_end(msg, hdr); | 223 | genlmsg_end(msg, hdr); |
| 224 | genlmsg_reply(msg, info); | 224 | return genlmsg_reply(msg, info); |
| 225 | |||
| 226 | return 0; | ||
| 227 | 225 | ||
| 228 | nla_put_failure: | 226 | nla_put_failure: |
| 229 | rcu_read_unlock(); | 227 | rcu_read_unlock(); |
diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c index 8181ee7e1e27..ee5403cbe655 100644 --- a/net/ipv6/seg6_iptunnel.c +++ b/net/ipv6/seg6_iptunnel.c | |||
| @@ -146,6 +146,8 @@ int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh, int proto) | |||
| 146 | } else { | 146 | } else { |
| 147 | ip6_flow_hdr(hdr, 0, flowlabel); | 147 | ip6_flow_hdr(hdr, 0, flowlabel); |
| 148 | hdr->hop_limit = ip6_dst_hoplimit(skb_dst(skb)); | 148 | hdr->hop_limit = ip6_dst_hoplimit(skb_dst(skb)); |
| 149 | |||
| 150 | memset(IP6CB(skb), 0, sizeof(*IP6CB(skb))); | ||
| 149 | } | 151 | } |
| 150 | 152 | ||
| 151 | hdr->nexthdr = NEXTHDR_ROUTING; | 153 | hdr->nexthdr = NEXTHDR_ROUTING; |
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 1e03305c0549..e8a1dabef803 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
| @@ -546,7 +546,8 @@ static int ipip6_err(struct sk_buff *skb, u32 info) | |||
| 546 | } | 546 | } |
| 547 | 547 | ||
| 548 | err = 0; | 548 | err = 0; |
| 549 | if (!ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4, type, data_len)) | 549 | if (__in6_dev_get(skb->dev) && |
| 550 | !ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4, type, data_len)) | ||
| 550 | goto out; | 551 | goto out; |
| 551 | 552 | ||
| 552 | if (t->parms.iph.daddr == 0) | 553 | if (t->parms.iph.daddr == 0) |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 9cbf363172bd..b444483cdb2b 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
| @@ -102,7 +102,7 @@ int udp_v6_get_port(struct sock *sk, unsigned short snum) | |||
| 102 | return udp_lib_get_port(sk, snum, hash2_nulladdr); | 102 | return udp_lib_get_port(sk, snum, hash2_nulladdr); |
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | static void udp_v6_rehash(struct sock *sk) | 105 | void udp_v6_rehash(struct sock *sk) |
| 106 | { | 106 | { |
| 107 | u16 new_hash = ipv6_portaddr_hash(sock_net(sk), | 107 | u16 new_hash = ipv6_portaddr_hash(sock_net(sk), |
| 108 | &sk->sk_v6_rcv_saddr, | 108 | &sk->sk_v6_rcv_saddr, |
| @@ -288,8 +288,8 @@ int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, | |||
| 288 | int peeked, peeking, off; | 288 | int peeked, peeking, off; |
| 289 | int err; | 289 | int err; |
| 290 | int is_udplite = IS_UDPLITE(sk); | 290 | int is_udplite = IS_UDPLITE(sk); |
| 291 | struct udp_mib __percpu *mib; | ||
| 291 | bool checksum_valid = false; | 292 | bool checksum_valid = false; |
| 292 | struct udp_mib *mib; | ||
| 293 | int is_udp4; | 293 | int is_udp4; |
| 294 | 294 | ||
| 295 | if (flags & MSG_ERRQUEUE) | 295 | if (flags & MSG_ERRQUEUE) |
| @@ -420,17 +420,19 @@ EXPORT_SYMBOL(udpv6_encap_enable); | |||
| 420 | */ | 420 | */ |
| 421 | static int __udp6_lib_err_encap_no_sk(struct sk_buff *skb, | 421 | static int __udp6_lib_err_encap_no_sk(struct sk_buff *skb, |
| 422 | struct inet6_skb_parm *opt, | 422 | struct inet6_skb_parm *opt, |
| 423 | u8 type, u8 code, int offset, u32 info) | 423 | u8 type, u8 code, int offset, __be32 info) |
| 424 | { | 424 | { |
| 425 | int i; | 425 | int i; |
| 426 | 426 | ||
| 427 | for (i = 0; i < MAX_IPTUN_ENCAP_OPS; i++) { | 427 | for (i = 0; i < MAX_IPTUN_ENCAP_OPS; i++) { |
| 428 | int (*handler)(struct sk_buff *skb, struct inet6_skb_parm *opt, | 428 | int (*handler)(struct sk_buff *skb, struct inet6_skb_parm *opt, |
| 429 | u8 type, u8 code, int offset, u32 info); | 429 | u8 type, u8 code, int offset, __be32 info); |
| 430 | const struct ip6_tnl_encap_ops *encap; | ||
| 430 | 431 | ||
| 431 | if (!ip6tun_encaps[i]) | 432 | encap = rcu_dereference(ip6tun_encaps[i]); |
| 433 | if (!encap) | ||
| 432 | continue; | 434 | continue; |
| 433 | handler = rcu_dereference(ip6tun_encaps[i]->err_handler); | 435 | handler = encap->err_handler; |
| 434 | if (handler && !handler(skb, opt, type, code, offset, info)) | 436 | if (handler && !handler(skb, opt, type, code, offset, info)) |
| 435 | return 0; | 437 | return 0; |
| 436 | } | 438 | } |
| @@ -1132,15 +1134,23 @@ static int udp_v6_send_skb(struct sk_buff *skb, struct flowi6 *fl6, | |||
| 1132 | const int hlen = skb_network_header_len(skb) + | 1134 | const int hlen = skb_network_header_len(skb) + |
| 1133 | sizeof(struct udphdr); | 1135 | sizeof(struct udphdr); |
| 1134 | 1136 | ||
| 1135 | if (hlen + cork->gso_size > cork->fragsize) | 1137 | if (hlen + cork->gso_size > cork->fragsize) { |
| 1138 | kfree_skb(skb); | ||
| 1136 | return -EINVAL; | 1139 | return -EINVAL; |
| 1137 | if (skb->len > cork->gso_size * UDP_MAX_SEGMENTS) | 1140 | } |
| 1141 | if (skb->len > cork->gso_size * UDP_MAX_SEGMENTS) { | ||
| 1142 | kfree_skb(skb); | ||
| 1138 | return -EINVAL; | 1143 | return -EINVAL; |
| 1139 | if (udp_sk(sk)->no_check6_tx) | 1144 | } |
| 1145 | if (udp_sk(sk)->no_check6_tx) { | ||
| 1146 | kfree_skb(skb); | ||
| 1140 | return -EINVAL; | 1147 | return -EINVAL; |
| 1148 | } | ||
| 1141 | if (skb->ip_summed != CHECKSUM_PARTIAL || is_udplite || | 1149 | if (skb->ip_summed != CHECKSUM_PARTIAL || is_udplite || |
| 1142 | dst_xfrm(skb_dst(skb))) | 1150 | dst_xfrm(skb_dst(skb))) { |
| 1151 | kfree_skb(skb); | ||
| 1143 | return -EIO; | 1152 | return -EIO; |
| 1153 | } | ||
| 1144 | 1154 | ||
| 1145 | skb_shinfo(skb)->gso_size = cork->gso_size; | 1155 | skb_shinfo(skb)->gso_size = cork->gso_size; |
| 1146 | skb_shinfo(skb)->gso_type = SKB_GSO_UDP_L4; | 1156 | skb_shinfo(skb)->gso_type = SKB_GSO_UDP_L4; |
| @@ -1390,10 +1400,7 @@ do_udp_sendmsg: | |||
| 1390 | ipc6.opt = opt; | 1400 | ipc6.opt = opt; |
| 1391 | 1401 | ||
| 1392 | fl6.flowi6_proto = sk->sk_protocol; | 1402 | fl6.flowi6_proto = sk->sk_protocol; |
| 1393 | if (!ipv6_addr_any(daddr)) | 1403 | fl6.daddr = *daddr; |
| 1394 | fl6.daddr = *daddr; | ||
| 1395 | else | ||
| 1396 | fl6.daddr.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */ | ||
| 1397 | if (ipv6_addr_any(&fl6.saddr) && !ipv6_addr_any(&np->saddr)) | 1404 | if (ipv6_addr_any(&fl6.saddr) && !ipv6_addr_any(&np->saddr)) |
| 1398 | fl6.saddr = np->saddr; | 1405 | fl6.saddr = np->saddr; |
| 1399 | fl6.fl6_sport = inet->inet_sport; | 1406 | fl6.fl6_sport = inet->inet_sport; |
| @@ -1421,6 +1428,9 @@ do_udp_sendmsg: | |||
| 1421 | } | 1428 | } |
| 1422 | } | 1429 | } |
| 1423 | 1430 | ||
| 1431 | if (ipv6_addr_any(&fl6.daddr)) | ||
| 1432 | fl6.daddr.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */ | ||
| 1433 | |||
| 1424 | final_p = fl6_update_dst(&fl6, opt, &final); | 1434 | final_p = fl6_update_dst(&fl6, opt, &final); |
| 1425 | if (final_p) | 1435 | if (final_p) |
| 1426 | connected = false; | 1436 | connected = false; |
diff --git a/net/ipv6/udp_impl.h b/net/ipv6/udp_impl.h index 5730e6503cb4..20e324b6f358 100644 --- a/net/ipv6/udp_impl.h +++ b/net/ipv6/udp_impl.h | |||
| @@ -13,6 +13,7 @@ int __udp6_lib_err(struct sk_buff *, struct inet6_skb_parm *, u8, u8, int, | |||
| 13 | __be32, struct udp_table *); | 13 | __be32, struct udp_table *); |
| 14 | 14 | ||
| 15 | int udp_v6_get_port(struct sock *sk, unsigned short snum); | 15 | int udp_v6_get_port(struct sock *sk, unsigned short snum); |
| 16 | void udp_v6_rehash(struct sock *sk); | ||
| 16 | 17 | ||
| 17 | int udpv6_getsockopt(struct sock *sk, int level, int optname, | 18 | int udpv6_getsockopt(struct sock *sk, int level, int optname, |
| 18 | char __user *optval, int __user *optlen); | 19 | char __user *optval, int __user *optlen); |
diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c index a125aebc29e5..f35907836444 100644 --- a/net/ipv6/udplite.c +++ b/net/ipv6/udplite.c | |||
| @@ -49,6 +49,7 @@ struct proto udplitev6_prot = { | |||
| 49 | .recvmsg = udpv6_recvmsg, | 49 | .recvmsg = udpv6_recvmsg, |
| 50 | .hash = udp_lib_hash, | 50 | .hash = udp_lib_hash, |
| 51 | .unhash = udp_lib_unhash, | 51 | .unhash = udp_lib_unhash, |
| 52 | .rehash = udp_v6_rehash, | ||
| 52 | .get_port = udp_v6_get_port, | 53 | .get_port = udp_v6_get_port, |
| 53 | .memory_allocated = &udp_memory_allocated, | 54 | .memory_allocated = &udp_memory_allocated, |
| 54 | .sysctl_mem = sysctl_udp_mem, | 55 | .sysctl_mem = sysctl_udp_mem, |
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index f5b4febeaa25..bc65db782bfb 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c | |||
| @@ -344,8 +344,8 @@ static void __net_exit xfrm6_tunnel_net_exit(struct net *net) | |||
| 344 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); | 344 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); |
| 345 | unsigned int i; | 345 | unsigned int i; |
| 346 | 346 | ||
| 347 | xfrm_state_flush(net, IPSEC_PROTO_ANY, false); | ||
| 348 | xfrm_flush_gc(); | 347 | xfrm_flush_gc(); |
| 348 | xfrm_state_flush(net, IPSEC_PROTO_ANY, false, true); | ||
| 349 | 349 | ||
| 350 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++) | 350 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++) |
| 351 | WARN_ON_ONCE(!hlist_empty(&xfrm6_tn->spi_byaddr[i])); | 351 | WARN_ON_ONCE(!hlist_empty(&xfrm6_tn->spi_byaddr[i])); |
diff --git a/net/key/af_key.c b/net/key/af_key.c index 655c787f9d54..5651c29cb5bd 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c | |||
| @@ -196,30 +196,22 @@ static int pfkey_release(struct socket *sock) | |||
| 196 | return 0; | 196 | return 0; |
| 197 | } | 197 | } |
| 198 | 198 | ||
| 199 | static int pfkey_broadcast_one(struct sk_buff *skb, struct sk_buff **skb2, | 199 | static int pfkey_broadcast_one(struct sk_buff *skb, gfp_t allocation, |
| 200 | gfp_t allocation, struct sock *sk) | 200 | struct sock *sk) |
| 201 | { | 201 | { |
| 202 | int err = -ENOBUFS; | 202 | int err = -ENOBUFS; |
| 203 | 203 | ||
| 204 | sock_hold(sk); | 204 | if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf) |
| 205 | if (*skb2 == NULL) { | 205 | return err; |
| 206 | if (refcount_read(&skb->users) != 1) { | 206 | |
| 207 | *skb2 = skb_clone(skb, allocation); | 207 | skb = skb_clone(skb, allocation); |
| 208 | } else { | 208 | |
| 209 | *skb2 = skb; | 209 | if (skb) { |
| 210 | refcount_inc(&skb->users); | 210 | skb_set_owner_r(skb, sk); |
| 211 | } | 211 | skb_queue_tail(&sk->sk_receive_queue, skb); |
| 212 | } | 212 | sk->sk_data_ready(sk); |
| 213 | if (*skb2 != NULL) { | 213 | err = 0; |
| 214 | if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) { | ||
| 215 | skb_set_owner_r(*skb2, sk); | ||
| 216 | skb_queue_tail(&sk->sk_receive_queue, *skb2); | ||
| 217 | sk->sk_data_ready(sk); | ||
| 218 | *skb2 = NULL; | ||
| 219 | err = 0; | ||
| 220 | } | ||
| 221 | } | 214 | } |
| 222 | sock_put(sk); | ||
| 223 | return err; | 215 | return err; |
| 224 | } | 216 | } |
| 225 | 217 | ||
| @@ -234,7 +226,6 @@ static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation, | |||
| 234 | { | 226 | { |
| 235 | struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); | 227 | struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); |
| 236 | struct sock *sk; | 228 | struct sock *sk; |
| 237 | struct sk_buff *skb2 = NULL; | ||
| 238 | int err = -ESRCH; | 229 | int err = -ESRCH; |
| 239 | 230 | ||
| 240 | /* XXX Do we need something like netlink_overrun? I think | 231 | /* XXX Do we need something like netlink_overrun? I think |
| @@ -253,7 +244,7 @@ static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation, | |||
| 253 | * socket. | 244 | * socket. |
| 254 | */ | 245 | */ |
| 255 | if (pfk->promisc) | 246 | if (pfk->promisc) |
| 256 | pfkey_broadcast_one(skb, &skb2, GFP_ATOMIC, sk); | 247 | pfkey_broadcast_one(skb, GFP_ATOMIC, sk); |
| 257 | 248 | ||
| 258 | /* the exact target will be processed later */ | 249 | /* the exact target will be processed later */ |
| 259 | if (sk == one_sk) | 250 | if (sk == one_sk) |
| @@ -268,7 +259,7 @@ static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation, | |||
| 268 | continue; | 259 | continue; |
| 269 | } | 260 | } |
| 270 | 261 | ||
| 271 | err2 = pfkey_broadcast_one(skb, &skb2, GFP_ATOMIC, sk); | 262 | err2 = pfkey_broadcast_one(skb, GFP_ATOMIC, sk); |
| 272 | 263 | ||
| 273 | /* Error is cleared after successful sending to at least one | 264 | /* Error is cleared after successful sending to at least one |
| 274 | * registered KM */ | 265 | * registered KM */ |
| @@ -278,9 +269,8 @@ static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation, | |||
| 278 | rcu_read_unlock(); | 269 | rcu_read_unlock(); |
| 279 | 270 | ||
| 280 | if (one_sk != NULL) | 271 | if (one_sk != NULL) |
| 281 | err = pfkey_broadcast_one(skb, &skb2, allocation, one_sk); | 272 | err = pfkey_broadcast_one(skb, allocation, one_sk); |
| 282 | 273 | ||
| 283 | kfree_skb(skb2); | ||
| 284 | kfree_skb(skb); | 274 | kfree_skb(skb); |
| 285 | return err; | 275 | return err; |
| 286 | } | 276 | } |
| @@ -1783,7 +1773,7 @@ static int pfkey_flush(struct sock *sk, struct sk_buff *skb, const struct sadb_m | |||
| 1783 | if (proto == 0) | 1773 | if (proto == 0) |
| 1784 | return -EINVAL; | 1774 | return -EINVAL; |
| 1785 | 1775 | ||
| 1786 | err = xfrm_state_flush(net, proto, true); | 1776 | err = xfrm_state_flush(net, proto, true, false); |
| 1787 | err2 = unicast_flush_resp(sk, hdr); | 1777 | err2 = unicast_flush_resp(sk, hdr); |
| 1788 | if (err || err2) { | 1778 | if (err || err2) { |
| 1789 | if (err == -ESRCH) /* empty table - go quietly */ | 1779 | if (err == -ESRCH) /* empty table - go quietly */ |
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 26f1d435696a..fed6becc5daf 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c | |||
| @@ -83,8 +83,7 @@ | |||
| 83 | #define L2TP_SLFLAG_S 0x40000000 | 83 | #define L2TP_SLFLAG_S 0x40000000 |
| 84 | #define L2TP_SL_SEQ_MASK 0x00ffffff | 84 | #define L2TP_SL_SEQ_MASK 0x00ffffff |
| 85 | 85 | ||
| 86 | #define L2TP_HDR_SIZE_SEQ 10 | 86 | #define L2TP_HDR_SIZE_MAX 14 |
| 87 | #define L2TP_HDR_SIZE_NOSEQ 6 | ||
| 88 | 87 | ||
| 89 | /* Default trace flags */ | 88 | /* Default trace flags */ |
| 90 | #define L2TP_DEFAULT_DEBUG_FLAGS 0 | 89 | #define L2TP_DEFAULT_DEBUG_FLAGS 0 |
| @@ -808,7 +807,7 @@ static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb) | |||
| 808 | __skb_pull(skb, sizeof(struct udphdr)); | 807 | __skb_pull(skb, sizeof(struct udphdr)); |
| 809 | 808 | ||
| 810 | /* Short packet? */ | 809 | /* Short packet? */ |
| 811 | if (!pskb_may_pull(skb, L2TP_HDR_SIZE_SEQ)) { | 810 | if (!pskb_may_pull(skb, L2TP_HDR_SIZE_MAX)) { |
| 812 | l2tp_info(tunnel, L2TP_MSG_DATA, | 811 | l2tp_info(tunnel, L2TP_MSG_DATA, |
| 813 | "%s: recv short packet (len=%d)\n", | 812 | "%s: recv short packet (len=%d)\n", |
| 814 | tunnel->name, skb->len); | 813 | tunnel->name, skb->len); |
| @@ -884,6 +883,10 @@ static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb) | |||
| 884 | goto error; | 883 | goto error; |
| 885 | } | 884 | } |
| 886 | 885 | ||
| 886 | if (tunnel->version == L2TP_HDR_VER_3 && | ||
| 887 | l2tp_v3_ensure_opt_in_linear(session, skb, &ptr, &optr)) | ||
| 888 | goto error; | ||
| 889 | |||
| 887 | l2tp_recv_common(session, skb, ptr, optr, hdrflags, length); | 890 | l2tp_recv_common(session, skb, ptr, optr, hdrflags, length); |
| 888 | l2tp_session_dec_refcount(session); | 891 | l2tp_session_dec_refcount(session); |
| 889 | 892 | ||
diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h index 9c9afe94d389..b2ce90260c35 100644 --- a/net/l2tp/l2tp_core.h +++ b/net/l2tp/l2tp_core.h | |||
| @@ -301,6 +301,26 @@ static inline bool l2tp_tunnel_uses_xfrm(const struct l2tp_tunnel *tunnel) | |||
| 301 | } | 301 | } |
| 302 | #endif | 302 | #endif |
| 303 | 303 | ||
| 304 | static inline int l2tp_v3_ensure_opt_in_linear(struct l2tp_session *session, struct sk_buff *skb, | ||
| 305 | unsigned char **ptr, unsigned char **optr) | ||
| 306 | { | ||
| 307 | int opt_len = session->peer_cookie_len + l2tp_get_l2specific_len(session); | ||
| 308 | |||
| 309 | if (opt_len > 0) { | ||
| 310 | int off = *ptr - *optr; | ||
| 311 | |||
| 312 | if (!pskb_may_pull(skb, off + opt_len)) | ||
| 313 | return -1; | ||
| 314 | |||
| 315 | if (skb->data != *optr) { | ||
| 316 | *optr = skb->data; | ||
| 317 | *ptr = skb->data + off; | ||
| 318 | } | ||
| 319 | } | ||
| 320 | |||
| 321 | return 0; | ||
| 322 | } | ||
| 323 | |||
| 304 | #define l2tp_printk(ptr, type, func, fmt, ...) \ | 324 | #define l2tp_printk(ptr, type, func, fmt, ...) \ |
| 305 | do { \ | 325 | do { \ |
| 306 | if (((ptr)->debug) & (type)) \ | 326 | if (((ptr)->debug) & (type)) \ |
diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index 35f6f86d4dcc..d4c60523c549 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c | |||
| @@ -165,6 +165,9 @@ static int l2tp_ip_recv(struct sk_buff *skb) | |||
| 165 | print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, ptr, length); | 165 | print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, ptr, length); |
| 166 | } | 166 | } |
| 167 | 167 | ||
| 168 | if (l2tp_v3_ensure_opt_in_linear(session, skb, &ptr, &optr)) | ||
| 169 | goto discard_sess; | ||
| 170 | |||
| 168 | l2tp_recv_common(session, skb, ptr, optr, 0, skb->len); | 171 | l2tp_recv_common(session, skb, ptr, optr, 0, skb->len); |
| 169 | l2tp_session_dec_refcount(session); | 172 | l2tp_session_dec_refcount(session); |
| 170 | 173 | ||
diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c index 237f1a4a0b0c..0ae6899edac0 100644 --- a/net/l2tp/l2tp_ip6.c +++ b/net/l2tp/l2tp_ip6.c | |||
| @@ -178,6 +178,9 @@ static int l2tp_ip6_recv(struct sk_buff *skb) | |||
| 178 | print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, ptr, length); | 178 | print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, ptr, length); |
| 179 | } | 179 | } |
| 180 | 180 | ||
| 181 | if (l2tp_v3_ensure_opt_in_linear(session, skb, &ptr, &optr)) | ||
| 182 | goto discard_sess; | ||
| 183 | |||
| 181 | l2tp_recv_common(session, skb, ptr, optr, 0, skb->len); | 184 | l2tp_recv_common(session, skb, ptr, optr, 0, skb->len); |
| 182 | l2tp_session_dec_refcount(session); | 185 | l2tp_session_dec_refcount(session); |
| 183 | 186 | ||
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 69e831bc317b..54821fb1a960 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
| @@ -8,7 +8,7 @@ | |||
| 8 | * Copyright 2007, Michael Wu <flamingice@sourmilk.net> | 8 | * Copyright 2007, Michael Wu <flamingice@sourmilk.net> |
| 9 | * Copyright 2007-2010, Intel Corporation | 9 | * Copyright 2007-2010, Intel Corporation |
| 10 | * Copyright(c) 2015-2017 Intel Deutschland GmbH | 10 | * Copyright(c) 2015-2017 Intel Deutschland GmbH |
| 11 | * Copyright (C) 2018 Intel Corporation | 11 | * Copyright (C) 2018 - 2019 Intel Corporation |
| 12 | * | 12 | * |
| 13 | * This program is free software; you can redistribute it and/or modify | 13 | * This program is free software; you can redistribute it and/or modify |
| 14 | * it under the terms of the GNU General Public License version 2 as | 14 | * it under the terms of the GNU General Public License version 2 as |
| @@ -366,6 +366,8 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
| 366 | 366 | ||
| 367 | set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state); | 367 | set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state); |
| 368 | 368 | ||
| 369 | ieee80211_agg_stop_txq(sta, tid); | ||
| 370 | |||
| 369 | spin_unlock_bh(&sta->lock); | 371 | spin_unlock_bh(&sta->lock); |
| 370 | 372 | ||
| 371 | ht_dbg(sta->sdata, "Tx BA session stop requested for %pM tid %u\n", | 373 | ht_dbg(sta->sdata, "Tx BA session stop requested for %pM tid %u\n", |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index de65fe3ed9cc..96496b2c1670 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
| @@ -941,6 +941,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
| 941 | BSS_CHANGED_P2P_PS | | 941 | BSS_CHANGED_P2P_PS | |
| 942 | BSS_CHANGED_TXPOWER; | 942 | BSS_CHANGED_TXPOWER; |
| 943 | int err; | 943 | int err; |
| 944 | int prev_beacon_int; | ||
| 944 | 945 | ||
| 945 | old = sdata_dereference(sdata->u.ap.beacon, sdata); | 946 | old = sdata_dereference(sdata->u.ap.beacon, sdata); |
| 946 | if (old) | 947 | if (old) |
| @@ -963,6 +964,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
| 963 | 964 | ||
| 964 | sdata->needed_rx_chains = sdata->local->rx_chains; | 965 | sdata->needed_rx_chains = sdata->local->rx_chains; |
| 965 | 966 | ||
| 967 | prev_beacon_int = sdata->vif.bss_conf.beacon_int; | ||
| 966 | sdata->vif.bss_conf.beacon_int = params->beacon_interval; | 968 | sdata->vif.bss_conf.beacon_int = params->beacon_interval; |
| 967 | 969 | ||
| 968 | if (params->he_cap) | 970 | if (params->he_cap) |
| @@ -974,8 +976,10 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
| 974 | if (!err) | 976 | if (!err) |
| 975 | ieee80211_vif_copy_chanctx_to_vlans(sdata, false); | 977 | ieee80211_vif_copy_chanctx_to_vlans(sdata, false); |
| 976 | mutex_unlock(&local->mtx); | 978 | mutex_unlock(&local->mtx); |
| 977 | if (err) | 979 | if (err) { |
| 980 | sdata->vif.bss_conf.beacon_int = prev_beacon_int; | ||
| 978 | return err; | 981 | return err; |
| 982 | } | ||
| 979 | 983 | ||
| 980 | /* | 984 | /* |
| 981 | * Apply control port protocol, this allows us to | 985 | * Apply control port protocol, this allows us to |
| @@ -1490,6 +1494,10 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
| 1490 | if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) | 1494 | if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) |
| 1491 | sta->sta.tdls = true; | 1495 | sta->sta.tdls = true; |
| 1492 | 1496 | ||
| 1497 | if (sta->sta.tdls && sdata->vif.type == NL80211_IFTYPE_STATION && | ||
| 1498 | !sdata->u.mgd.associated) | ||
| 1499 | return -EINVAL; | ||
| 1500 | |||
| 1493 | err = sta_apply_parameters(local, sta, params); | 1501 | err = sta_apply_parameters(local, sta, params); |
| 1494 | if (err) { | 1502 | if (err) { |
| 1495 | sta_info_free(local, sta); | 1503 | sta_info_free(local, sta); |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 87a729926734..977dea436ee8 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
| @@ -615,13 +615,13 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, | |||
| 615 | * We need a bit of data queued to build aggregates properly, so | 615 | * We need a bit of data queued to build aggregates properly, so |
| 616 | * instruct the TCP stack to allow more than a single ms of data | 616 | * instruct the TCP stack to allow more than a single ms of data |
| 617 | * to be queued in the stack. The value is a bit-shift of 1 | 617 | * to be queued in the stack. The value is a bit-shift of 1 |
| 618 | * second, so 8 is ~4ms of queued data. Only affects local TCP | 618 | * second, so 7 is ~8ms of queued data. Only affects local TCP |
| 619 | * sockets. | 619 | * sockets. |
| 620 | * This is the default, anyhow - drivers may need to override it | 620 | * This is the default, anyhow - drivers may need to override it |
| 621 | * for local reasons (longer buffers, longer completion time, or | 621 | * for local reasons (longer buffers, longer completion time, or |
| 622 | * similar). | 622 | * similar). |
| 623 | */ | 623 | */ |
| 624 | local->hw.tx_sk_pacing_shift = 8; | 624 | local->hw.tx_sk_pacing_shift = 7; |
| 625 | 625 | ||
| 626 | /* set up some defaults */ | 626 | /* set up some defaults */ |
| 627 | local->hw.queues = 1; | 627 | local->hw.queues = 1; |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index cad6592c52a1..2ec7011a4d07 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
| @@ -70,6 +70,7 @@ enum mesh_deferred_task_flags { | |||
| 70 | * @dst: mesh path destination mac address | 70 | * @dst: mesh path destination mac address |
| 71 | * @mpp: mesh proxy mac address | 71 | * @mpp: mesh proxy mac address |
| 72 | * @rhash: rhashtable list pointer | 72 | * @rhash: rhashtable list pointer |
| 73 | * @walk_list: linked list containing all mesh_path objects. | ||
| 73 | * @gate_list: list pointer for known gates list | 74 | * @gate_list: list pointer for known gates list |
| 74 | * @sdata: mesh subif | 75 | * @sdata: mesh subif |
| 75 | * @next_hop: mesh neighbor to which frames for this destination will be | 76 | * @next_hop: mesh neighbor to which frames for this destination will be |
| @@ -105,6 +106,7 @@ struct mesh_path { | |||
| 105 | u8 dst[ETH_ALEN]; | 106 | u8 dst[ETH_ALEN]; |
| 106 | u8 mpp[ETH_ALEN]; /* used for MPP or MAP */ | 107 | u8 mpp[ETH_ALEN]; /* used for MPP or MAP */ |
| 107 | struct rhash_head rhash; | 108 | struct rhash_head rhash; |
| 109 | struct hlist_node walk_list; | ||
| 108 | struct hlist_node gate_list; | 110 | struct hlist_node gate_list; |
| 109 | struct ieee80211_sub_if_data *sdata; | 111 | struct ieee80211_sub_if_data *sdata; |
| 110 | struct sta_info __rcu *next_hop; | 112 | struct sta_info __rcu *next_hop; |
| @@ -133,12 +135,16 @@ struct mesh_path { | |||
| 133 | * gate's mpath may or may not be resolved and active. | 135 | * gate's mpath may or may not be resolved and active. |
| 134 | * @gates_lock: protects updates to known_gates | 136 | * @gates_lock: protects updates to known_gates |
| 135 | * @rhead: the rhashtable containing struct mesh_paths, keyed by dest addr | 137 | * @rhead: the rhashtable containing struct mesh_paths, keyed by dest addr |
| 138 | * @walk_head: linked list containging all mesh_path objects | ||
| 139 | * @walk_lock: lock protecting walk_head | ||
| 136 | * @entries: number of entries in the table | 140 | * @entries: number of entries in the table |
| 137 | */ | 141 | */ |
| 138 | struct mesh_table { | 142 | struct mesh_table { |
| 139 | struct hlist_head known_gates; | 143 | struct hlist_head known_gates; |
| 140 | spinlock_t gates_lock; | 144 | spinlock_t gates_lock; |
| 141 | struct rhashtable rhead; | 145 | struct rhashtable rhead; |
| 146 | struct hlist_head walk_head; | ||
| 147 | spinlock_t walk_lock; | ||
| 142 | atomic_t entries; /* Up to MAX_MESH_NEIGHBOURS */ | 148 | atomic_t entries; /* Up to MAX_MESH_NEIGHBOURS */ |
| 143 | }; | 149 | }; |
| 144 | 150 | ||
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index a5125624a76d..88a6d5e18ccc 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c | |||
| @@ -59,8 +59,10 @@ static struct mesh_table *mesh_table_alloc(void) | |||
| 59 | return NULL; | 59 | return NULL; |
| 60 | 60 | ||
| 61 | INIT_HLIST_HEAD(&newtbl->known_gates); | 61 | INIT_HLIST_HEAD(&newtbl->known_gates); |
| 62 | INIT_HLIST_HEAD(&newtbl->walk_head); | ||
| 62 | atomic_set(&newtbl->entries, 0); | 63 | atomic_set(&newtbl->entries, 0); |
| 63 | spin_lock_init(&newtbl->gates_lock); | 64 | spin_lock_init(&newtbl->gates_lock); |
| 65 | spin_lock_init(&newtbl->walk_lock); | ||
| 64 | 66 | ||
| 65 | return newtbl; | 67 | return newtbl; |
| 66 | } | 68 | } |
| @@ -249,28 +251,15 @@ mpp_path_lookup(struct ieee80211_sub_if_data *sdata, const u8 *dst) | |||
| 249 | static struct mesh_path * | 251 | static struct mesh_path * |
| 250 | __mesh_path_lookup_by_idx(struct mesh_table *tbl, int idx) | 252 | __mesh_path_lookup_by_idx(struct mesh_table *tbl, int idx) |
| 251 | { | 253 | { |
| 252 | int i = 0, ret; | 254 | int i = 0; |
| 253 | struct mesh_path *mpath = NULL; | 255 | struct mesh_path *mpath; |
| 254 | struct rhashtable_iter iter; | ||
| 255 | |||
| 256 | ret = rhashtable_walk_init(&tbl->rhead, &iter, GFP_ATOMIC); | ||
| 257 | if (ret) | ||
| 258 | return NULL; | ||
| 259 | |||
| 260 | rhashtable_walk_start(&iter); | ||
| 261 | 256 | ||
| 262 | while ((mpath = rhashtable_walk_next(&iter))) { | 257 | hlist_for_each_entry_rcu(mpath, &tbl->walk_head, walk_list) { |
| 263 | if (IS_ERR(mpath) && PTR_ERR(mpath) == -EAGAIN) | ||
| 264 | continue; | ||
| 265 | if (IS_ERR(mpath)) | ||
| 266 | break; | ||
| 267 | if (i++ == idx) | 258 | if (i++ == idx) |
| 268 | break; | 259 | break; |
| 269 | } | 260 | } |
| 270 | rhashtable_walk_stop(&iter); | ||
| 271 | rhashtable_walk_exit(&iter); | ||
| 272 | 261 | ||
| 273 | if (IS_ERR(mpath) || !mpath) | 262 | if (!mpath) |
| 274 | return NULL; | 263 | return NULL; |
| 275 | 264 | ||
| 276 | if (mpath_expired(mpath)) { | 265 | if (mpath_expired(mpath)) { |
| @@ -432,6 +421,7 @@ struct mesh_path *mesh_path_add(struct ieee80211_sub_if_data *sdata, | |||
| 432 | return ERR_PTR(-ENOMEM); | 421 | return ERR_PTR(-ENOMEM); |
| 433 | 422 | ||
| 434 | tbl = sdata->u.mesh.mesh_paths; | 423 | tbl = sdata->u.mesh.mesh_paths; |
| 424 | spin_lock_bh(&tbl->walk_lock); | ||
| 435 | do { | 425 | do { |
| 436 | ret = rhashtable_lookup_insert_fast(&tbl->rhead, | 426 | ret = rhashtable_lookup_insert_fast(&tbl->rhead, |
| 437 | &new_mpath->rhash, | 427 | &new_mpath->rhash, |
| @@ -441,20 +431,20 @@ struct mesh_path *mesh_path_add(struct ieee80211_sub_if_data *sdata, | |||
| 441 | mpath = rhashtable_lookup_fast(&tbl->rhead, | 431 | mpath = rhashtable_lookup_fast(&tbl->rhead, |
| 442 | dst, | 432 | dst, |
| 443 | mesh_rht_params); | 433 | mesh_rht_params); |
| 444 | 434 | else if (!ret) | |
| 435 | hlist_add_head(&new_mpath->walk_list, &tbl->walk_head); | ||
| 445 | } while (unlikely(ret == -EEXIST && !mpath)); | 436 | } while (unlikely(ret == -EEXIST && !mpath)); |
| 437 | spin_unlock_bh(&tbl->walk_lock); | ||
| 446 | 438 | ||
| 447 | if (ret && ret != -EEXIST) | 439 | if (ret) { |
| 448 | return ERR_PTR(ret); | ||
| 449 | |||
| 450 | /* At this point either new_mpath was added, or we found a | ||
| 451 | * matching entry already in the table; in the latter case | ||
| 452 | * free the unnecessary new entry. | ||
| 453 | */ | ||
| 454 | if (ret == -EEXIST) { | ||
| 455 | kfree(new_mpath); | 440 | kfree(new_mpath); |
| 441 | |||
| 442 | if (ret != -EEXIST) | ||
| 443 | return ERR_PTR(ret); | ||
| 444 | |||
| 456 | new_mpath = mpath; | 445 | new_mpath = mpath; |
| 457 | } | 446 | } |
| 447 | |||
| 458 | sdata->u.mesh.mesh_paths_generation++; | 448 | sdata->u.mesh.mesh_paths_generation++; |
| 459 | return new_mpath; | 449 | return new_mpath; |
| 460 | } | 450 | } |
| @@ -480,9 +470,17 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata, | |||
| 480 | 470 | ||
| 481 | memcpy(new_mpath->mpp, mpp, ETH_ALEN); | 471 | memcpy(new_mpath->mpp, mpp, ETH_ALEN); |
| 482 | tbl = sdata->u.mesh.mpp_paths; | 472 | tbl = sdata->u.mesh.mpp_paths; |
| 473 | |||
| 474 | spin_lock_bh(&tbl->walk_lock); | ||
| 483 | ret = rhashtable_lookup_insert_fast(&tbl->rhead, | 475 | ret = rhashtable_lookup_insert_fast(&tbl->rhead, |
| 484 | &new_mpath->rhash, | 476 | &new_mpath->rhash, |
| 485 | mesh_rht_params); | 477 | mesh_rht_params); |
| 478 | if (!ret) | ||
| 479 | hlist_add_head_rcu(&new_mpath->walk_list, &tbl->walk_head); | ||
| 480 | spin_unlock_bh(&tbl->walk_lock); | ||
| 481 | |||
| 482 | if (ret) | ||
| 483 | kfree(new_mpath); | ||
| 486 | 484 | ||
| 487 | sdata->u.mesh.mpp_paths_generation++; | 485 | sdata->u.mesh.mpp_paths_generation++; |
| 488 | return ret; | 486 | return ret; |
| @@ -503,20 +501,9 @@ void mesh_plink_broken(struct sta_info *sta) | |||
| 503 | struct mesh_table *tbl = sdata->u.mesh.mesh_paths; | 501 | struct mesh_table *tbl = sdata->u.mesh.mesh_paths; |
| 504 | static const u8 bcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; | 502 | static const u8 bcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; |
| 505 | struct mesh_path *mpath; | 503 | struct mesh_path *mpath; |
| 506 | struct rhashtable_iter iter; | ||
| 507 | int ret; | ||
| 508 | |||
| 509 | ret = rhashtable_walk_init(&tbl->rhead, &iter, GFP_ATOMIC); | ||
| 510 | if (ret) | ||
| 511 | return; | ||
| 512 | 504 | ||
| 513 | rhashtable_walk_start(&iter); | 505 | rcu_read_lock(); |
| 514 | 506 | hlist_for_each_entry_rcu(mpath, &tbl->walk_head, walk_list) { | |
| 515 | while ((mpath = rhashtable_walk_next(&iter))) { | ||
| 516 | if (IS_ERR(mpath) && PTR_ERR(mpath) == -EAGAIN) | ||
| 517 | continue; | ||
| 518 | if (IS_ERR(mpath)) | ||
| 519 | break; | ||
| 520 | if (rcu_access_pointer(mpath->next_hop) == sta && | 507 | if (rcu_access_pointer(mpath->next_hop) == sta && |
| 521 | mpath->flags & MESH_PATH_ACTIVE && | 508 | mpath->flags & MESH_PATH_ACTIVE && |
| 522 | !(mpath->flags & MESH_PATH_FIXED)) { | 509 | !(mpath->flags & MESH_PATH_FIXED)) { |
| @@ -530,8 +517,7 @@ void mesh_plink_broken(struct sta_info *sta) | |||
| 530 | WLAN_REASON_MESH_PATH_DEST_UNREACHABLE, bcast); | 517 | WLAN_REASON_MESH_PATH_DEST_UNREACHABLE, bcast); |
| 531 | } | 518 | } |
| 532 | } | 519 | } |
| 533 | rhashtable_walk_stop(&iter); | 520 | rcu_read_unlock(); |
| 534 | rhashtable_walk_exit(&iter); | ||
| 535 | } | 521 | } |
| 536 | 522 | ||
| 537 | static void mesh_path_free_rcu(struct mesh_table *tbl, | 523 | static void mesh_path_free_rcu(struct mesh_table *tbl, |
| @@ -551,6 +537,7 @@ static void mesh_path_free_rcu(struct mesh_table *tbl, | |||
| 551 | 537 | ||
| 552 | static void __mesh_path_del(struct mesh_table *tbl, struct mesh_path *mpath) | 538 | static void __mesh_path_del(struct mesh_table *tbl, struct mesh_path *mpath) |
| 553 | { | 539 | { |
| 540 | hlist_del_rcu(&mpath->walk_list); | ||
| 554 | rhashtable_remove_fast(&tbl->rhead, &mpath->rhash, mesh_rht_params); | 541 | rhashtable_remove_fast(&tbl->rhead, &mpath->rhash, mesh_rht_params); |
| 555 | mesh_path_free_rcu(tbl, mpath); | 542 | mesh_path_free_rcu(tbl, mpath); |
| 556 | } | 543 | } |
| @@ -571,27 +558,14 @@ void mesh_path_flush_by_nexthop(struct sta_info *sta) | |||
| 571 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 558 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
| 572 | struct mesh_table *tbl = sdata->u.mesh.mesh_paths; | 559 | struct mesh_table *tbl = sdata->u.mesh.mesh_paths; |
| 573 | struct mesh_path *mpath; | 560 | struct mesh_path *mpath; |
| 574 | struct rhashtable_iter iter; | 561 | struct hlist_node *n; |
| 575 | int ret; | ||
| 576 | |||
| 577 | ret = rhashtable_walk_init(&tbl->rhead, &iter, GFP_ATOMIC); | ||
| 578 | if (ret) | ||
| 579 | return; | ||
| 580 | |||
| 581 | rhashtable_walk_start(&iter); | ||
| 582 | |||
| 583 | while ((mpath = rhashtable_walk_next(&iter))) { | ||
| 584 | if (IS_ERR(mpath) && PTR_ERR(mpath) == -EAGAIN) | ||
| 585 | continue; | ||
| 586 | if (IS_ERR(mpath)) | ||
| 587 | break; | ||
| 588 | 562 | ||
| 563 | spin_lock_bh(&tbl->walk_lock); | ||
| 564 | hlist_for_each_entry_safe(mpath, n, &tbl->walk_head, walk_list) { | ||
| 589 | if (rcu_access_pointer(mpath->next_hop) == sta) | 565 | if (rcu_access_pointer(mpath->next_hop) == sta) |
| 590 | __mesh_path_del(tbl, mpath); | 566 | __mesh_path_del(tbl, mpath); |
| 591 | } | 567 | } |
| 592 | 568 | spin_unlock_bh(&tbl->walk_lock); | |
| 593 | rhashtable_walk_stop(&iter); | ||
| 594 | rhashtable_walk_exit(&iter); | ||
| 595 | } | 569 | } |
| 596 | 570 | ||
| 597 | static void mpp_flush_by_proxy(struct ieee80211_sub_if_data *sdata, | 571 | static void mpp_flush_by_proxy(struct ieee80211_sub_if_data *sdata, |
| @@ -599,51 +573,26 @@ static void mpp_flush_by_proxy(struct ieee80211_sub_if_data *sdata, | |||
| 599 | { | 573 | { |
| 600 | struct mesh_table *tbl = sdata->u.mesh.mpp_paths; | 574 | struct mesh_table *tbl = sdata->u.mesh.mpp_paths; |
| 601 | struct mesh_path *mpath; | 575 | struct mesh_path *mpath; |
| 602 | struct rhashtable_iter iter; | 576 | struct hlist_node *n; |
| 603 | int ret; | ||
| 604 | |||
| 605 | ret = rhashtable_walk_init(&tbl->rhead, &iter, GFP_ATOMIC); | ||
| 606 | if (ret) | ||
| 607 | return; | ||
| 608 | |||
| 609 | rhashtable_walk_start(&iter); | ||
| 610 | |||
| 611 | while ((mpath = rhashtable_walk_next(&iter))) { | ||
| 612 | if (IS_ERR(mpath) && PTR_ERR(mpath) == -EAGAIN) | ||
| 613 | continue; | ||
| 614 | if (IS_ERR(mpath)) | ||
| 615 | break; | ||
| 616 | 577 | ||
| 578 | spin_lock_bh(&tbl->walk_lock); | ||
| 579 | hlist_for_each_entry_safe(mpath, n, &tbl->walk_head, walk_list) { | ||
| 617 | if (ether_addr_equal(mpath->mpp, proxy)) | 580 | if (ether_addr_equal(mpath->mpp, proxy)) |
| 618 | __mesh_path_del(tbl, mpath); | 581 | __mesh_path_del(tbl, mpath); |
| 619 | } | 582 | } |
| 620 | 583 | spin_unlock_bh(&tbl->walk_lock); | |
| 621 | rhashtable_walk_stop(&iter); | ||
| 622 | rhashtable_walk_exit(&iter); | ||
| 623 | } | 584 | } |
| 624 | 585 | ||
| 625 | static void table_flush_by_iface(struct mesh_table *tbl) | 586 | static void table_flush_by_iface(struct mesh_table *tbl) |
| 626 | { | 587 | { |
| 627 | struct mesh_path *mpath; | 588 | struct mesh_path *mpath; |
| 628 | struct rhashtable_iter iter; | 589 | struct hlist_node *n; |
| 629 | int ret; | ||
| 630 | |||
| 631 | ret = rhashtable_walk_init(&tbl->rhead, &iter, GFP_ATOMIC); | ||
| 632 | if (ret) | ||
| 633 | return; | ||
| 634 | |||
| 635 | rhashtable_walk_start(&iter); | ||
| 636 | 590 | ||
| 637 | while ((mpath = rhashtable_walk_next(&iter))) { | 591 | spin_lock_bh(&tbl->walk_lock); |
| 638 | if (IS_ERR(mpath) && PTR_ERR(mpath) == -EAGAIN) | 592 | hlist_for_each_entry_safe(mpath, n, &tbl->walk_head, walk_list) { |
| 639 | continue; | ||
| 640 | if (IS_ERR(mpath)) | ||
| 641 | break; | ||
| 642 | __mesh_path_del(tbl, mpath); | 593 | __mesh_path_del(tbl, mpath); |
| 643 | } | 594 | } |
| 644 | 595 | spin_unlock_bh(&tbl->walk_lock); | |
| 645 | rhashtable_walk_stop(&iter); | ||
| 646 | rhashtable_walk_exit(&iter); | ||
| 647 | } | 596 | } |
| 648 | 597 | ||
| 649 | /** | 598 | /** |
| @@ -675,15 +624,15 @@ static int table_path_del(struct mesh_table *tbl, | |||
| 675 | { | 624 | { |
| 676 | struct mesh_path *mpath; | 625 | struct mesh_path *mpath; |
| 677 | 626 | ||
| 678 | rcu_read_lock(); | 627 | spin_lock_bh(&tbl->walk_lock); |
| 679 | mpath = rhashtable_lookup_fast(&tbl->rhead, addr, mesh_rht_params); | 628 | mpath = rhashtable_lookup_fast(&tbl->rhead, addr, mesh_rht_params); |
| 680 | if (!mpath) { | 629 | if (!mpath) { |
| 681 | rcu_read_unlock(); | 630 | spin_unlock_bh(&tbl->walk_lock); |
| 682 | return -ENXIO; | 631 | return -ENXIO; |
| 683 | } | 632 | } |
| 684 | 633 | ||
| 685 | __mesh_path_del(tbl, mpath); | 634 | __mesh_path_del(tbl, mpath); |
| 686 | rcu_read_unlock(); | 635 | spin_unlock_bh(&tbl->walk_lock); |
| 687 | return 0; | 636 | return 0; |
| 688 | } | 637 | } |
| 689 | 638 | ||
| @@ -854,28 +803,16 @@ void mesh_path_tbl_expire(struct ieee80211_sub_if_data *sdata, | |||
| 854 | struct mesh_table *tbl) | 803 | struct mesh_table *tbl) |
| 855 | { | 804 | { |
| 856 | struct mesh_path *mpath; | 805 | struct mesh_path *mpath; |
| 857 | struct rhashtable_iter iter; | 806 | struct hlist_node *n; |
| 858 | int ret; | ||
| 859 | 807 | ||
| 860 | ret = rhashtable_walk_init(&tbl->rhead, &iter, GFP_KERNEL); | 808 | spin_lock_bh(&tbl->walk_lock); |
| 861 | if (ret) | 809 | hlist_for_each_entry_safe(mpath, n, &tbl->walk_head, walk_list) { |
| 862 | return; | ||
| 863 | |||
| 864 | rhashtable_walk_start(&iter); | ||
| 865 | |||
| 866 | while ((mpath = rhashtable_walk_next(&iter))) { | ||
| 867 | if (IS_ERR(mpath) && PTR_ERR(mpath) == -EAGAIN) | ||
| 868 | continue; | ||
| 869 | if (IS_ERR(mpath)) | ||
| 870 | break; | ||
| 871 | if ((!(mpath->flags & MESH_PATH_RESOLVING)) && | 810 | if ((!(mpath->flags & MESH_PATH_RESOLVING)) && |
| 872 | (!(mpath->flags & MESH_PATH_FIXED)) && | 811 | (!(mpath->flags & MESH_PATH_FIXED)) && |
| 873 | time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE)) | 812 | time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE)) |
| 874 | __mesh_path_del(tbl, mpath); | 813 | __mesh_path_del(tbl, mpath); |
| 875 | } | 814 | } |
| 876 | 815 | spin_unlock_bh(&tbl->walk_lock); | |
| 877 | rhashtable_walk_stop(&iter); | ||
| 878 | rhashtable_walk_exit(&iter); | ||
| 879 | } | 816 | } |
| 880 | 817 | ||
| 881 | void mesh_path_expire(struct ieee80211_sub_if_data *sdata) | 818 | void mesh_path_expire(struct ieee80211_sub_if_data *sdata) |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 45aad3d3108c..c2a6da5d80da 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
| @@ -231,7 +231,7 @@ static void ieee80211_handle_mu_mimo_mon(struct ieee80211_sub_if_data *sdata, | |||
| 231 | struct ieee80211_hdr_3addr hdr; | 231 | struct ieee80211_hdr_3addr hdr; |
| 232 | u8 category; | 232 | u8 category; |
| 233 | u8 action_code; | 233 | u8 action_code; |
| 234 | } __packed action; | 234 | } __packed __aligned(2) action; |
| 235 | 235 | ||
| 236 | if (!sdata) | 236 | if (!sdata) |
| 237 | return; | 237 | return; |
| @@ -2644,6 +2644,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
| 2644 | struct ieee80211_sub_if_data *sdata = rx->sdata; | 2644 | struct ieee80211_sub_if_data *sdata = rx->sdata; |
| 2645 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 2645 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
| 2646 | u16 ac, q, hdrlen; | 2646 | u16 ac, q, hdrlen; |
| 2647 | int tailroom = 0; | ||
| 2647 | 2648 | ||
| 2648 | hdr = (struct ieee80211_hdr *) skb->data; | 2649 | hdr = (struct ieee80211_hdr *) skb->data; |
| 2649 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | 2650 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
| @@ -2723,15 +2724,21 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
| 2723 | skb_set_queue_mapping(skb, q); | 2724 | skb_set_queue_mapping(skb, q); |
| 2724 | 2725 | ||
| 2725 | if (!--mesh_hdr->ttl) { | 2726 | if (!--mesh_hdr->ttl) { |
| 2726 | IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_ttl); | 2727 | if (!is_multicast_ether_addr(hdr->addr1)) |
| 2728 | IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, | ||
| 2729 | dropped_frames_ttl); | ||
| 2727 | goto out; | 2730 | goto out; |
| 2728 | } | 2731 | } |
| 2729 | 2732 | ||
| 2730 | if (!ifmsh->mshcfg.dot11MeshForwarding) | 2733 | if (!ifmsh->mshcfg.dot11MeshForwarding) |
| 2731 | goto out; | 2734 | goto out; |
| 2732 | 2735 | ||
| 2736 | if (sdata->crypto_tx_tailroom_needed_cnt) | ||
| 2737 | tailroom = IEEE80211_ENCRYPT_TAILROOM; | ||
| 2738 | |||
| 2733 | fwd_skb = skb_copy_expand(skb, local->tx_headroom + | 2739 | fwd_skb = skb_copy_expand(skb, local->tx_headroom + |
| 2734 | sdata->encrypt_headroom, 0, GFP_ATOMIC); | 2740 | sdata->encrypt_headroom, |
| 2741 | tailroom, GFP_ATOMIC); | ||
| 2735 | if (!fwd_skb) | 2742 | if (!fwd_skb) |
| 2736 | goto out; | 2743 | goto out; |
| 2737 | 2744 | ||
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index f170d6c6629a..928f13a208b0 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
| @@ -1938,9 +1938,16 @@ static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata, | |||
| 1938 | int head_need, bool may_encrypt) | 1938 | int head_need, bool may_encrypt) |
| 1939 | { | 1939 | { |
| 1940 | struct ieee80211_local *local = sdata->local; | 1940 | struct ieee80211_local *local = sdata->local; |
| 1941 | struct ieee80211_hdr *hdr; | ||
| 1942 | bool enc_tailroom; | ||
| 1941 | int tail_need = 0; | 1943 | int tail_need = 0; |
| 1942 | 1944 | ||
| 1943 | if (may_encrypt && sdata->crypto_tx_tailroom_needed_cnt) { | 1945 | hdr = (struct ieee80211_hdr *) skb->data; |
| 1946 | enc_tailroom = may_encrypt && | ||
| 1947 | (sdata->crypto_tx_tailroom_needed_cnt || | ||
| 1948 | ieee80211_is_mgmt(hdr->frame_control)); | ||
| 1949 | |||
| 1950 | if (enc_tailroom) { | ||
| 1944 | tail_need = IEEE80211_ENCRYPT_TAILROOM; | 1951 | tail_need = IEEE80211_ENCRYPT_TAILROOM; |
| 1945 | tail_need -= skb_tailroom(skb); | 1952 | tail_need -= skb_tailroom(skb); |
| 1946 | tail_need = max_t(int, tail_need, 0); | 1953 | tail_need = max_t(int, tail_need, 0); |
| @@ -1948,8 +1955,7 @@ static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata, | |||
| 1948 | 1955 | ||
| 1949 | if (skb_cloned(skb) && | 1956 | if (skb_cloned(skb) && |
| 1950 | (!ieee80211_hw_check(&local->hw, SUPPORTS_CLONED_SKBS) || | 1957 | (!ieee80211_hw_check(&local->hw, SUPPORTS_CLONED_SKBS) || |
| 1951 | !skb_clone_writable(skb, ETH_HLEN) || | 1958 | !skb_clone_writable(skb, ETH_HLEN) || enc_tailroom)) |
| 1952 | (may_encrypt && sdata->crypto_tx_tailroom_needed_cnt))) | ||
| 1953 | I802_DEBUG_INC(local->tx_expand_skb_head_cloned); | 1959 | I802_DEBUG_INC(local->tx_expand_skb_head_cloned); |
| 1954 | else if (head_need || tail_need) | 1960 | else if (head_need || tail_need) |
| 1955 | I802_DEBUG_INC(local->tx_expand_skb_head); | 1961 | I802_DEBUG_INC(local->tx_expand_skb_head); |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index d0eb38b890aa..ba950ae974fc 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
| @@ -5,7 +5,7 @@ | |||
| 5 | * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> | 5 | * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> |
| 6 | * Copyright 2013-2014 Intel Mobile Communications GmbH | 6 | * Copyright 2013-2014 Intel Mobile Communications GmbH |
| 7 | * Copyright (C) 2015-2017 Intel Deutschland GmbH | 7 | * Copyright (C) 2015-2017 Intel Deutschland GmbH |
| 8 | * Copyright (C) 2018 Intel Corporation | 8 | * Copyright (C) 2018-2019 Intel Corporation |
| 9 | * | 9 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of the GNU General Public License version 2 as | 11 | * it under the terms of the GNU General Public License version 2 as |
| @@ -2146,6 +2146,10 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
| 2146 | case NL80211_IFTYPE_AP_VLAN: | 2146 | case NL80211_IFTYPE_AP_VLAN: |
| 2147 | case NL80211_IFTYPE_MONITOR: | 2147 | case NL80211_IFTYPE_MONITOR: |
| 2148 | break; | 2148 | break; |
| 2149 | case NL80211_IFTYPE_ADHOC: | ||
| 2150 | if (sdata->vif.bss_conf.ibss_joined) | ||
| 2151 | WARN_ON(drv_join_ibss(local, sdata)); | ||
| 2152 | /* fall through */ | ||
| 2149 | default: | 2153 | default: |
| 2150 | ieee80211_reconfig_stations(sdata); | 2154 | ieee80211_reconfig_stations(sdata); |
| 2151 | /* fall through */ | 2155 | /* fall through */ |
diff --git a/net/netfilter/ipvs/Kconfig b/net/netfilter/ipvs/Kconfig index cad48d07c818..8401cefd9f65 100644 --- a/net/netfilter/ipvs/Kconfig +++ b/net/netfilter/ipvs/Kconfig | |||
| @@ -29,6 +29,7 @@ config IP_VS_IPV6 | |||
| 29 | bool "IPv6 support for IPVS" | 29 | bool "IPv6 support for IPVS" |
| 30 | depends on IPV6 = y || IP_VS = IPV6 | 30 | depends on IPV6 = y || IP_VS = IPV6 |
| 31 | select IP6_NF_IPTABLES | 31 | select IP6_NF_IPTABLES |
| 32 | select NF_DEFRAG_IPV6 | ||
| 32 | ---help--- | 33 | ---help--- |
| 33 | Add IPv6 support to IPVS. | 34 | Add IPv6 support to IPVS. |
| 34 | 35 | ||
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index fe9abf3cc10a..235205c93e14 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c | |||
| @@ -1536,14 +1536,12 @@ ip_vs_try_to_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb, | |||
| 1536 | /* sorry, all this trouble for a no-hit :) */ | 1536 | /* sorry, all this trouble for a no-hit :) */ |
| 1537 | IP_VS_DBG_PKT(12, af, pp, skb, iph->off, | 1537 | IP_VS_DBG_PKT(12, af, pp, skb, iph->off, |
| 1538 | "ip_vs_in: packet continues traversal as normal"); | 1538 | "ip_vs_in: packet continues traversal as normal"); |
| 1539 | if (iph->fragoffs) { | 1539 | |
| 1540 | /* Fragment that couldn't be mapped to a conn entry | 1540 | /* Fragment couldn't be mapped to a conn entry */ |
| 1541 | * is missing module nf_defrag_ipv6 | 1541 | if (iph->fragoffs) |
| 1542 | */ | ||
| 1543 | IP_VS_DBG_RL("Unhandled frag, load nf_defrag_ipv6\n"); | ||
| 1544 | IP_VS_DBG_PKT(7, af, pp, skb, iph->off, | 1542 | IP_VS_DBG_PKT(7, af, pp, skb, iph->off, |
| 1545 | "unhandled fragment"); | 1543 | "unhandled fragment"); |
| 1546 | } | 1544 | |
| 1547 | *verdict = NF_ACCEPT; | 1545 | *verdict = NF_ACCEPT; |
| 1548 | return 0; | 1546 | return 0; |
| 1549 | } | 1547 | } |
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index 432141f04af3..ac8d848d7624 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c | |||
| @@ -43,6 +43,7 @@ | |||
| 43 | #ifdef CONFIG_IP_VS_IPV6 | 43 | #ifdef CONFIG_IP_VS_IPV6 |
| 44 | #include <net/ipv6.h> | 44 | #include <net/ipv6.h> |
| 45 | #include <net/ip6_route.h> | 45 | #include <net/ip6_route.h> |
| 46 | #include <net/netfilter/ipv6/nf_defrag_ipv6.h> | ||
| 46 | #endif | 47 | #endif |
| 47 | #include <net/route.h> | 48 | #include <net/route.h> |
| 48 | #include <net/sock.h> | 49 | #include <net/sock.h> |
| @@ -900,11 +901,17 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest, | |||
| 900 | 901 | ||
| 901 | #ifdef CONFIG_IP_VS_IPV6 | 902 | #ifdef CONFIG_IP_VS_IPV6 |
| 902 | if (udest->af == AF_INET6) { | 903 | if (udest->af == AF_INET6) { |
| 904 | int ret; | ||
| 905 | |||
| 903 | atype = ipv6_addr_type(&udest->addr.in6); | 906 | atype = ipv6_addr_type(&udest->addr.in6); |
| 904 | if ((!(atype & IPV6_ADDR_UNICAST) || | 907 | if ((!(atype & IPV6_ADDR_UNICAST) || |
| 905 | atype & IPV6_ADDR_LINKLOCAL) && | 908 | atype & IPV6_ADDR_LINKLOCAL) && |
| 906 | !__ip_vs_addr_is_local_v6(svc->ipvs->net, &udest->addr.in6)) | 909 | !__ip_vs_addr_is_local_v6(svc->ipvs->net, &udest->addr.in6)) |
| 907 | return -EINVAL; | 910 | return -EINVAL; |
| 911 | |||
| 912 | ret = nf_defrag_ipv6_enable(svc->ipvs->net); | ||
| 913 | if (ret) | ||
| 914 | return ret; | ||
| 908 | } else | 915 | } else |
| 909 | #endif | 916 | #endif |
| 910 | { | 917 | { |
| @@ -1228,6 +1235,10 @@ ip_vs_add_service(struct netns_ipvs *ipvs, struct ip_vs_service_user_kern *u, | |||
| 1228 | ret = -EINVAL; | 1235 | ret = -EINVAL; |
| 1229 | goto out_err; | 1236 | goto out_err; |
| 1230 | } | 1237 | } |
| 1238 | |||
| 1239 | ret = nf_defrag_ipv6_enable(ipvs->net); | ||
| 1240 | if (ret) | ||
| 1241 | goto out_err; | ||
| 1231 | } | 1242 | } |
| 1232 | #endif | 1243 | #endif |
| 1233 | 1244 | ||
| @@ -2221,6 +2232,18 @@ static int ip_vs_set_timeout(struct netns_ipvs *ipvs, struct ip_vs_timeout_user | |||
| 2221 | u->udp_timeout); | 2232 | u->udp_timeout); |
| 2222 | 2233 | ||
| 2223 | #ifdef CONFIG_IP_VS_PROTO_TCP | 2234 | #ifdef CONFIG_IP_VS_PROTO_TCP |
| 2235 | if (u->tcp_timeout < 0 || u->tcp_timeout > (INT_MAX / HZ) || | ||
| 2236 | u->tcp_fin_timeout < 0 || u->tcp_fin_timeout > (INT_MAX / HZ)) { | ||
| 2237 | return -EINVAL; | ||
| 2238 | } | ||
| 2239 | #endif | ||
| 2240 | |||
| 2241 | #ifdef CONFIG_IP_VS_PROTO_UDP | ||
| 2242 | if (u->udp_timeout < 0 || u->udp_timeout > (INT_MAX / HZ)) | ||
| 2243 | return -EINVAL; | ||
| 2244 | #endif | ||
| 2245 | |||
| 2246 | #ifdef CONFIG_IP_VS_PROTO_TCP | ||
| 2224 | if (u->tcp_timeout) { | 2247 | if (u->tcp_timeout) { |
| 2225 | pd = ip_vs_proto_data_get(ipvs, IPPROTO_TCP); | 2248 | pd = ip_vs_proto_data_get(ipvs, IPPROTO_TCP); |
| 2226 | pd->timeout_table[IP_VS_TCP_S_ESTABLISHED] | 2249 | pd->timeout_table[IP_VS_TCP_S_ESTABLISHED] |
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 741b533148ba..db4d46332e86 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c | |||
| @@ -1007,6 +1007,22 @@ nf_conntrack_tuple_taken(const struct nf_conntrack_tuple *tuple, | |||
| 1007 | } | 1007 | } |
| 1008 | 1008 | ||
| 1009 | if (nf_ct_key_equal(h, tuple, zone, net)) { | 1009 | if (nf_ct_key_equal(h, tuple, zone, net)) { |
| 1010 | /* Tuple is taken already, so caller will need to find | ||
| 1011 | * a new source port to use. | ||
| 1012 | * | ||
| 1013 | * Only exception: | ||
| 1014 | * If the *original tuples* are identical, then both | ||
| 1015 | * conntracks refer to the same flow. | ||
| 1016 | * This is a rare situation, it can occur e.g. when | ||
| 1017 | * more than one UDP packet is sent from same socket | ||
| 1018 | * in different threads. | ||
| 1019 | * | ||
| 1020 | * Let nf_ct_resolve_clash() deal with this later. | ||
| 1021 | */ | ||
| 1022 | if (nf_ct_tuple_equal(&ignored_conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple, | ||
| 1023 | &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple)) | ||
| 1024 | continue; | ||
| 1025 | |||
| 1010 | NF_CT_STAT_INC_ATOMIC(net, found); | 1026 | NF_CT_STAT_INC_ATOMIC(net, found); |
| 1011 | rcu_read_unlock(); | 1027 | rcu_read_unlock(); |
| 1012 | return 1; | 1028 | return 1; |
diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c index fa0844e2a68d..c0c72ae9df42 100644 --- a/net/netfilter/nf_flow_table_core.c +++ b/net/netfilter/nf_flow_table_core.c | |||
| @@ -28,6 +28,7 @@ flow_offload_fill_dir(struct flow_offload *flow, struct nf_conn *ct, | |||
| 28 | { | 28 | { |
| 29 | struct flow_offload_tuple *ft = &flow->tuplehash[dir].tuple; | 29 | struct flow_offload_tuple *ft = &flow->tuplehash[dir].tuple; |
| 30 | struct nf_conntrack_tuple *ctt = &ct->tuplehash[dir].tuple; | 30 | struct nf_conntrack_tuple *ctt = &ct->tuplehash[dir].tuple; |
| 31 | struct dst_entry *other_dst = route->tuple[!dir].dst; | ||
| 31 | struct dst_entry *dst = route->tuple[dir].dst; | 32 | struct dst_entry *dst = route->tuple[dir].dst; |
| 32 | 33 | ||
| 33 | ft->dir = dir; | 34 | ft->dir = dir; |
| @@ -50,8 +51,8 @@ flow_offload_fill_dir(struct flow_offload *flow, struct nf_conn *ct, | |||
| 50 | ft->src_port = ctt->src.u.tcp.port; | 51 | ft->src_port = ctt->src.u.tcp.port; |
| 51 | ft->dst_port = ctt->dst.u.tcp.port; | 52 | ft->dst_port = ctt->dst.u.tcp.port; |
| 52 | 53 | ||
| 53 | ft->iifidx = route->tuple[dir].ifindex; | 54 | ft->iifidx = other_dst->dev->ifindex; |
| 54 | ft->oifidx = route->tuple[!dir].ifindex; | 55 | ft->oifidx = dst->dev->ifindex; |
| 55 | ft->dst_cache = dst; | 56 | ft->dst_cache = dst; |
| 56 | } | 57 | } |
| 57 | 58 | ||
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 2b0a93300dd7..4893f248dfdc 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c | |||
| @@ -116,6 +116,23 @@ static void nft_trans_destroy(struct nft_trans *trans) | |||
| 116 | kfree(trans); | 116 | kfree(trans); |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | static void nft_set_trans_bind(const struct nft_ctx *ctx, struct nft_set *set) | ||
| 120 | { | ||
| 121 | struct net *net = ctx->net; | ||
| 122 | struct nft_trans *trans; | ||
| 123 | |||
| 124 | if (!nft_set_is_anonymous(set)) | ||
| 125 | return; | ||
| 126 | |||
| 127 | list_for_each_entry_reverse(trans, &net->nft.commit_list, list) { | ||
| 128 | if (trans->msg_type == NFT_MSG_NEWSET && | ||
| 129 | nft_trans_set(trans) == set) { | ||
| 130 | nft_trans_set_bound(trans) = true; | ||
| 131 | break; | ||
| 132 | } | ||
| 133 | } | ||
| 134 | } | ||
| 135 | |||
| 119 | static int nf_tables_register_hook(struct net *net, | 136 | static int nf_tables_register_hook(struct net *net, |
| 120 | const struct nft_table *table, | 137 | const struct nft_table *table, |
| 121 | struct nft_chain *chain) | 138 | struct nft_chain *chain) |
| @@ -211,18 +228,6 @@ static int nft_delchain(struct nft_ctx *ctx) | |||
| 211 | return err; | 228 | return err; |
| 212 | } | 229 | } |
| 213 | 230 | ||
| 214 | /* either expr ops provide both activate/deactivate, or neither */ | ||
| 215 | static bool nft_expr_check_ops(const struct nft_expr_ops *ops) | ||
| 216 | { | ||
| 217 | if (!ops) | ||
| 218 | return true; | ||
| 219 | |||
| 220 | if (WARN_ON_ONCE((!ops->activate ^ !ops->deactivate))) | ||
| 221 | return false; | ||
| 222 | |||
| 223 | return true; | ||
| 224 | } | ||
| 225 | |||
| 226 | static void nft_rule_expr_activate(const struct nft_ctx *ctx, | 231 | static void nft_rule_expr_activate(const struct nft_ctx *ctx, |
| 227 | struct nft_rule *rule) | 232 | struct nft_rule *rule) |
| 228 | { | 233 | { |
| @@ -238,14 +243,15 @@ static void nft_rule_expr_activate(const struct nft_ctx *ctx, | |||
| 238 | } | 243 | } |
| 239 | 244 | ||
| 240 | static void nft_rule_expr_deactivate(const struct nft_ctx *ctx, | 245 | static void nft_rule_expr_deactivate(const struct nft_ctx *ctx, |
| 241 | struct nft_rule *rule) | 246 | struct nft_rule *rule, |
| 247 | enum nft_trans_phase phase) | ||
| 242 | { | 248 | { |
| 243 | struct nft_expr *expr; | 249 | struct nft_expr *expr; |
| 244 | 250 | ||
| 245 | expr = nft_expr_first(rule); | 251 | expr = nft_expr_first(rule); |
| 246 | while (expr != nft_expr_last(rule) && expr->ops) { | 252 | while (expr != nft_expr_last(rule) && expr->ops) { |
| 247 | if (expr->ops->deactivate) | 253 | if (expr->ops->deactivate) |
| 248 | expr->ops->deactivate(ctx, expr); | 254 | expr->ops->deactivate(ctx, expr, phase); |
| 249 | 255 | ||
| 250 | expr = nft_expr_next(expr); | 256 | expr = nft_expr_next(expr); |
| 251 | } | 257 | } |
| @@ -296,7 +302,7 @@ static int nft_delrule(struct nft_ctx *ctx, struct nft_rule *rule) | |||
| 296 | nft_trans_destroy(trans); | 302 | nft_trans_destroy(trans); |
| 297 | return err; | 303 | return err; |
| 298 | } | 304 | } |
| 299 | nft_rule_expr_deactivate(ctx, rule); | 305 | nft_rule_expr_deactivate(ctx, rule, NFT_TRANS_PREPARE); |
| 300 | 306 | ||
| 301 | return 0; | 307 | return 0; |
| 302 | } | 308 | } |
| @@ -307,6 +313,9 @@ static int nft_delrule_by_chain(struct nft_ctx *ctx) | |||
| 307 | int err; | 313 | int err; |
| 308 | 314 | ||
| 309 | list_for_each_entry(rule, &ctx->chain->rules, list) { | 315 | list_for_each_entry(rule, &ctx->chain->rules, list) { |
| 316 | if (!nft_is_active_next(ctx->net, rule)) | ||
| 317 | continue; | ||
| 318 | |||
| 310 | err = nft_delrule(ctx, rule); | 319 | err = nft_delrule(ctx, rule); |
| 311 | if (err < 0) | 320 | if (err < 0) |
| 312 | return err; | 321 | return err; |
| @@ -1929,9 +1938,6 @@ static int nf_tables_delchain(struct net *net, struct sock *nlsk, | |||
| 1929 | */ | 1938 | */ |
| 1930 | int nft_register_expr(struct nft_expr_type *type) | 1939 | int nft_register_expr(struct nft_expr_type *type) |
| 1931 | { | 1940 | { |
| 1932 | if (!nft_expr_check_ops(type->ops)) | ||
| 1933 | return -EINVAL; | ||
| 1934 | |||
| 1935 | nfnl_lock(NFNL_SUBSYS_NFTABLES); | 1941 | nfnl_lock(NFNL_SUBSYS_NFTABLES); |
| 1936 | if (type->family == NFPROTO_UNSPEC) | 1942 | if (type->family == NFPROTO_UNSPEC) |
| 1937 | list_add_tail_rcu(&type->list, &nf_tables_expressions); | 1943 | list_add_tail_rcu(&type->list, &nf_tables_expressions); |
| @@ -2079,10 +2085,6 @@ static int nf_tables_expr_parse(const struct nft_ctx *ctx, | |||
| 2079 | err = PTR_ERR(ops); | 2085 | err = PTR_ERR(ops); |
| 2080 | goto err1; | 2086 | goto err1; |
| 2081 | } | 2087 | } |
| 2082 | if (!nft_expr_check_ops(ops)) { | ||
| 2083 | err = -EINVAL; | ||
| 2084 | goto err1; | ||
| 2085 | } | ||
| 2086 | } else | 2088 | } else |
| 2087 | ops = type->ops; | 2089 | ops = type->ops; |
| 2088 | 2090 | ||
| @@ -2304,7 +2306,6 @@ static int __nf_tables_dump_rules(struct sk_buff *skb, | |||
| 2304 | struct net *net = sock_net(skb->sk); | 2306 | struct net *net = sock_net(skb->sk); |
| 2305 | unsigned int s_idx = cb->args[0]; | 2307 | unsigned int s_idx = cb->args[0]; |
| 2306 | const struct nft_rule *rule; | 2308 | const struct nft_rule *rule; |
| 2307 | int rc = 1; | ||
| 2308 | 2309 | ||
| 2309 | list_for_each_entry_rcu(rule, &chain->rules, list) { | 2310 | list_for_each_entry_rcu(rule, &chain->rules, list) { |
| 2310 | if (!nft_is_active(net, rule)) | 2311 | if (!nft_is_active(net, rule)) |
| @@ -2321,16 +2322,13 @@ static int __nf_tables_dump_rules(struct sk_buff *skb, | |||
| 2321 | NLM_F_MULTI | NLM_F_APPEND, | 2322 | NLM_F_MULTI | NLM_F_APPEND, |
| 2322 | table->family, | 2323 | table->family, |
| 2323 | table, chain, rule) < 0) | 2324 | table, chain, rule) < 0) |
| 2324 | goto out_unfinished; | 2325 | return 1; |
| 2325 | 2326 | ||
| 2326 | nl_dump_check_consistent(cb, nlmsg_hdr(skb)); | 2327 | nl_dump_check_consistent(cb, nlmsg_hdr(skb)); |
| 2327 | cont: | 2328 | cont: |
| 2328 | (*idx)++; | 2329 | (*idx)++; |
| 2329 | } | 2330 | } |
| 2330 | rc = 0; | 2331 | return 0; |
| 2331 | out_unfinished: | ||
| 2332 | cb->args[0] = *idx; | ||
| 2333 | return rc; | ||
| 2334 | } | 2332 | } |
| 2335 | 2333 | ||
| 2336 | static int nf_tables_dump_rules(struct sk_buff *skb, | 2334 | static int nf_tables_dump_rules(struct sk_buff *skb, |
| @@ -2354,7 +2352,7 @@ static int nf_tables_dump_rules(struct sk_buff *skb, | |||
| 2354 | if (ctx && ctx->table && strcmp(ctx->table, table->name) != 0) | 2352 | if (ctx && ctx->table && strcmp(ctx->table, table->name) != 0) |
| 2355 | continue; | 2353 | continue; |
| 2356 | 2354 | ||
| 2357 | if (ctx && ctx->chain) { | 2355 | if (ctx && ctx->table && ctx->chain) { |
| 2358 | struct rhlist_head *list, *tmp; | 2356 | struct rhlist_head *list, *tmp; |
| 2359 | 2357 | ||
| 2360 | list = rhltable_lookup(&table->chains_ht, ctx->chain, | 2358 | list = rhltable_lookup(&table->chains_ht, ctx->chain, |
| @@ -2382,6 +2380,8 @@ static int nf_tables_dump_rules(struct sk_buff *skb, | |||
| 2382 | } | 2380 | } |
| 2383 | done: | 2381 | done: |
| 2384 | rcu_read_unlock(); | 2382 | rcu_read_unlock(); |
| 2383 | |||
| 2384 | cb->args[0] = idx; | ||
| 2385 | return skb->len; | 2385 | return skb->len; |
| 2386 | } | 2386 | } |
| 2387 | 2387 | ||
| @@ -2513,7 +2513,7 @@ static void nf_tables_rule_destroy(const struct nft_ctx *ctx, | |||
| 2513 | static void nf_tables_rule_release(const struct nft_ctx *ctx, | 2513 | static void nf_tables_rule_release(const struct nft_ctx *ctx, |
| 2514 | struct nft_rule *rule) | 2514 | struct nft_rule *rule) |
| 2515 | { | 2515 | { |
| 2516 | nft_rule_expr_deactivate(ctx, rule); | 2516 | nft_rule_expr_deactivate(ctx, rule, NFT_TRANS_RELEASE); |
| 2517 | nf_tables_rule_destroy(ctx, rule); | 2517 | nf_tables_rule_destroy(ctx, rule); |
| 2518 | } | 2518 | } |
| 2519 | 2519 | ||
| @@ -3710,39 +3710,30 @@ int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set, | |||
| 3710 | bind: | 3710 | bind: |
| 3711 | binding->chain = ctx->chain; | 3711 | binding->chain = ctx->chain; |
| 3712 | list_add_tail_rcu(&binding->list, &set->bindings); | 3712 | list_add_tail_rcu(&binding->list, &set->bindings); |
| 3713 | nft_set_trans_bind(ctx, set); | ||
| 3714 | |||
| 3713 | return 0; | 3715 | return 0; |
| 3714 | } | 3716 | } |
| 3715 | EXPORT_SYMBOL_GPL(nf_tables_bind_set); | 3717 | EXPORT_SYMBOL_GPL(nf_tables_bind_set); |
| 3716 | 3718 | ||
| 3717 | void nf_tables_rebind_set(const struct nft_ctx *ctx, struct nft_set *set, | ||
| 3718 | struct nft_set_binding *binding) | ||
| 3719 | { | ||
| 3720 | if (list_empty(&set->bindings) && nft_set_is_anonymous(set) && | ||
| 3721 | nft_is_active(ctx->net, set)) | ||
| 3722 | list_add_tail_rcu(&set->list, &ctx->table->sets); | ||
| 3723 | |||
| 3724 | list_add_tail_rcu(&binding->list, &set->bindings); | ||
| 3725 | } | ||
| 3726 | EXPORT_SYMBOL_GPL(nf_tables_rebind_set); | ||
| 3727 | |||
| 3728 | void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set, | 3719 | void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set, |
| 3729 | struct nft_set_binding *binding) | 3720 | struct nft_set_binding *binding, bool event) |
| 3730 | { | 3721 | { |
| 3731 | list_del_rcu(&binding->list); | 3722 | list_del_rcu(&binding->list); |
| 3732 | 3723 | ||
| 3733 | if (list_empty(&set->bindings) && nft_set_is_anonymous(set) && | 3724 | if (list_empty(&set->bindings) && nft_set_is_anonymous(set)) { |
| 3734 | nft_is_active(ctx->net, set)) | ||
| 3735 | list_del_rcu(&set->list); | 3725 | list_del_rcu(&set->list); |
| 3726 | if (event) | ||
| 3727 | nf_tables_set_notify(ctx, set, NFT_MSG_DELSET, | ||
| 3728 | GFP_KERNEL); | ||
| 3729 | } | ||
| 3736 | } | 3730 | } |
| 3737 | EXPORT_SYMBOL_GPL(nf_tables_unbind_set); | 3731 | EXPORT_SYMBOL_GPL(nf_tables_unbind_set); |
| 3738 | 3732 | ||
| 3739 | void nf_tables_destroy_set(const struct nft_ctx *ctx, struct nft_set *set) | 3733 | void nf_tables_destroy_set(const struct nft_ctx *ctx, struct nft_set *set) |
| 3740 | { | 3734 | { |
| 3741 | if (list_empty(&set->bindings) && nft_set_is_anonymous(set) && | 3735 | if (list_empty(&set->bindings) && nft_set_is_anonymous(set)) |
| 3742 | nft_is_active(ctx->net, set)) { | ||
| 3743 | nf_tables_set_notify(ctx, set, NFT_MSG_DELSET, GFP_ATOMIC); | ||
| 3744 | nft_set_destroy(set); | 3736 | nft_set_destroy(set); |
| 3745 | } | ||
| 3746 | } | 3737 | } |
| 3747 | EXPORT_SYMBOL_GPL(nf_tables_destroy_set); | 3738 | EXPORT_SYMBOL_GPL(nf_tables_destroy_set); |
| 3748 | 3739 | ||
| @@ -4508,6 +4499,8 @@ err6: | |||
| 4508 | err5: | 4499 | err5: |
| 4509 | kfree(trans); | 4500 | kfree(trans); |
| 4510 | err4: | 4501 | err4: |
| 4502 | if (obj) | ||
| 4503 | obj->use--; | ||
| 4511 | kfree(elem.priv); | 4504 | kfree(elem.priv); |
| 4512 | err3: | 4505 | err3: |
| 4513 | if (nla[NFTA_SET_ELEM_DATA] != NULL) | 4506 | if (nla[NFTA_SET_ELEM_DATA] != NULL) |
| @@ -6535,6 +6528,9 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb) | |||
| 6535 | nf_tables_rule_notify(&trans->ctx, | 6528 | nf_tables_rule_notify(&trans->ctx, |
| 6536 | nft_trans_rule(trans), | 6529 | nft_trans_rule(trans), |
| 6537 | NFT_MSG_DELRULE); | 6530 | NFT_MSG_DELRULE); |
| 6531 | nft_rule_expr_deactivate(&trans->ctx, | ||
| 6532 | nft_trans_rule(trans), | ||
| 6533 | NFT_TRANS_COMMIT); | ||
| 6538 | break; | 6534 | break; |
| 6539 | case NFT_MSG_NEWSET: | 6535 | case NFT_MSG_NEWSET: |
| 6540 | nft_clear(net, nft_trans_set(trans)); | 6536 | nft_clear(net, nft_trans_set(trans)); |
| @@ -6621,7 +6617,8 @@ static void nf_tables_abort_release(struct nft_trans *trans) | |||
| 6621 | nf_tables_rule_destroy(&trans->ctx, nft_trans_rule(trans)); | 6617 | nf_tables_rule_destroy(&trans->ctx, nft_trans_rule(trans)); |
| 6622 | break; | 6618 | break; |
| 6623 | case NFT_MSG_NEWSET: | 6619 | case NFT_MSG_NEWSET: |
| 6624 | nft_set_destroy(nft_trans_set(trans)); | 6620 | if (!nft_trans_set_bound(trans)) |
| 6621 | nft_set_destroy(nft_trans_set(trans)); | ||
| 6625 | break; | 6622 | break; |
| 6626 | case NFT_MSG_NEWSETELEM: | 6623 | case NFT_MSG_NEWSETELEM: |
| 6627 | nft_set_elem_destroy(nft_trans_elem_set(trans), | 6624 | nft_set_elem_destroy(nft_trans_elem_set(trans), |
| @@ -6682,7 +6679,9 @@ static int __nf_tables_abort(struct net *net) | |||
| 6682 | case NFT_MSG_NEWRULE: | 6679 | case NFT_MSG_NEWRULE: |
| 6683 | trans->ctx.chain->use--; | 6680 | trans->ctx.chain->use--; |
| 6684 | list_del_rcu(&nft_trans_rule(trans)->list); | 6681 | list_del_rcu(&nft_trans_rule(trans)->list); |
| 6685 | nft_rule_expr_deactivate(&trans->ctx, nft_trans_rule(trans)); | 6682 | nft_rule_expr_deactivate(&trans->ctx, |
| 6683 | nft_trans_rule(trans), | ||
| 6684 | NFT_TRANS_ABORT); | ||
| 6686 | break; | 6685 | break; |
| 6687 | case NFT_MSG_DELRULE: | 6686 | case NFT_MSG_DELRULE: |
| 6688 | trans->ctx.chain->use++; | 6687 | trans->ctx.chain->use++; |
| @@ -6692,7 +6691,8 @@ static int __nf_tables_abort(struct net *net) | |||
| 6692 | break; | 6691 | break; |
| 6693 | case NFT_MSG_NEWSET: | 6692 | case NFT_MSG_NEWSET: |
| 6694 | trans->ctx.table->use--; | 6693 | trans->ctx.table->use--; |
| 6695 | list_del_rcu(&nft_trans_set(trans)->list); | 6694 | if (!nft_trans_set_bound(trans)) |
| 6695 | list_del_rcu(&nft_trans_set(trans)->list); | ||
| 6696 | break; | 6696 | break; |
| 6697 | case NFT_MSG_DELSET: | 6697 | case NFT_MSG_DELSET: |
| 6698 | trans->ctx.table->use++; | 6698 | trans->ctx.table->use++; |
diff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c index 6f41dd74729d..1f1d90c1716b 100644 --- a/net/netfilter/nfnetlink_osf.c +++ b/net/netfilter/nfnetlink_osf.c | |||
| @@ -66,6 +66,7 @@ static bool nf_osf_match_one(const struct sk_buff *skb, | |||
| 66 | int ttl_check, | 66 | int ttl_check, |
| 67 | struct nf_osf_hdr_ctx *ctx) | 67 | struct nf_osf_hdr_ctx *ctx) |
| 68 | { | 68 | { |
| 69 | const __u8 *optpinit = ctx->optp; | ||
| 69 | unsigned int check_WSS = 0; | 70 | unsigned int check_WSS = 0; |
| 70 | int fmatch = FMATCH_WRONG; | 71 | int fmatch = FMATCH_WRONG; |
| 71 | int foptsize, optnum; | 72 | int foptsize, optnum; |
| @@ -155,6 +156,9 @@ static bool nf_osf_match_one(const struct sk_buff *skb, | |||
| 155 | } | 156 | } |
| 156 | } | 157 | } |
| 157 | 158 | ||
| 159 | if (fmatch != FMATCH_OK) | ||
| 160 | ctx->optp = optpinit; | ||
| 161 | |||
| 158 | return fmatch == FMATCH_OK; | 162 | return fmatch == FMATCH_OK; |
| 159 | } | 163 | } |
| 160 | 164 | ||
diff --git a/net/netfilter/nft_compat.c b/net/netfilter/nft_compat.c index 7334e0b80a5e..0a4bad55a8aa 100644 --- a/net/netfilter/nft_compat.c +++ b/net/netfilter/nft_compat.c | |||
| @@ -22,11 +22,15 @@ | |||
| 22 | #include <linux/netfilter_bridge/ebtables.h> | 22 | #include <linux/netfilter_bridge/ebtables.h> |
| 23 | #include <linux/netfilter_arp/arp_tables.h> | 23 | #include <linux/netfilter_arp/arp_tables.h> |
| 24 | #include <net/netfilter/nf_tables.h> | 24 | #include <net/netfilter/nf_tables.h> |
| 25 | #include <net/netns/generic.h> | ||
| 25 | 26 | ||
| 26 | struct nft_xt { | 27 | struct nft_xt { |
| 27 | struct list_head head; | 28 | struct list_head head; |
| 28 | struct nft_expr_ops ops; | 29 | struct nft_expr_ops ops; |
| 29 | unsigned int refcnt; | 30 | refcount_t refcnt; |
| 31 | |||
| 32 | /* used only when transaction mutex is locked */ | ||
| 33 | unsigned int listcnt; | ||
| 30 | 34 | ||
| 31 | /* Unlike other expressions, ops doesn't have static storage duration. | 35 | /* Unlike other expressions, ops doesn't have static storage duration. |
| 32 | * nft core assumes they do. We use kfree_rcu so that nft core can | 36 | * nft core assumes they do. We use kfree_rcu so that nft core can |
| @@ -43,10 +47,39 @@ struct nft_xt_match_priv { | |||
| 43 | void *info; | 47 | void *info; |
| 44 | }; | 48 | }; |
| 45 | 49 | ||
| 50 | struct nft_compat_net { | ||
| 51 | struct list_head nft_target_list; | ||
| 52 | struct list_head nft_match_list; | ||
| 53 | }; | ||
| 54 | |||
| 55 | static unsigned int nft_compat_net_id __read_mostly; | ||
| 56 | static struct nft_expr_type nft_match_type; | ||
| 57 | static struct nft_expr_type nft_target_type; | ||
| 58 | |||
| 59 | static struct nft_compat_net *nft_compat_pernet(struct net *net) | ||
| 60 | { | ||
| 61 | return net_generic(net, nft_compat_net_id); | ||
| 62 | } | ||
| 63 | |||
| 64 | static void nft_xt_get(struct nft_xt *xt) | ||
| 65 | { | ||
| 66 | /* refcount_inc() warns on 0 -> 1 transition, but we can't | ||
| 67 | * init the reference count to 1 in .select_ops -- we can't | ||
| 68 | * undo such an increase when another expression inside the same | ||
| 69 | * rule fails afterwards. | ||
| 70 | */ | ||
| 71 | if (xt->listcnt == 0) | ||
| 72 | refcount_set(&xt->refcnt, 1); | ||
| 73 | else | ||
| 74 | refcount_inc(&xt->refcnt); | ||
| 75 | |||
| 76 | xt->listcnt++; | ||
| 77 | } | ||
| 78 | |||
| 46 | static bool nft_xt_put(struct nft_xt *xt) | 79 | static bool nft_xt_put(struct nft_xt *xt) |
| 47 | { | 80 | { |
| 48 | if (--xt->refcnt == 0) { | 81 | if (refcount_dec_and_test(&xt->refcnt)) { |
| 49 | list_del(&xt->head); | 82 | WARN_ON_ONCE(!list_empty(&xt->head)); |
| 50 | kfree_rcu(xt, rcu_head); | 83 | kfree_rcu(xt, rcu_head); |
| 51 | return true; | 84 | return true; |
| 52 | } | 85 | } |
| @@ -273,7 +306,7 @@ nft_target_init(const struct nft_ctx *ctx, const struct nft_expr *expr, | |||
| 273 | return -EINVAL; | 306 | return -EINVAL; |
| 274 | 307 | ||
| 275 | nft_xt = container_of(expr->ops, struct nft_xt, ops); | 308 | nft_xt = container_of(expr->ops, struct nft_xt, ops); |
| 276 | nft_xt->refcnt++; | 309 | nft_xt_get(nft_xt); |
| 277 | return 0; | 310 | return 0; |
| 278 | } | 311 | } |
| 279 | 312 | ||
| @@ -282,6 +315,7 @@ nft_target_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) | |||
| 282 | { | 315 | { |
| 283 | struct xt_target *target = expr->ops->data; | 316 | struct xt_target *target = expr->ops->data; |
| 284 | void *info = nft_expr_priv(expr); | 317 | void *info = nft_expr_priv(expr); |
| 318 | struct module *me = target->me; | ||
| 285 | struct xt_tgdtor_param par; | 319 | struct xt_tgdtor_param par; |
| 286 | 320 | ||
| 287 | par.net = ctx->net; | 321 | par.net = ctx->net; |
| @@ -292,7 +326,7 @@ nft_target_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) | |||
| 292 | par.target->destroy(&par); | 326 | par.target->destroy(&par); |
| 293 | 327 | ||
| 294 | if (nft_xt_put(container_of(expr->ops, struct nft_xt, ops))) | 328 | if (nft_xt_put(container_of(expr->ops, struct nft_xt, ops))) |
| 295 | module_put(target->me); | 329 | module_put(me); |
| 296 | } | 330 | } |
| 297 | 331 | ||
| 298 | static int nft_extension_dump_info(struct sk_buff *skb, int attr, | 332 | static int nft_extension_dump_info(struct sk_buff *skb, int attr, |
| @@ -486,7 +520,7 @@ __nft_match_init(const struct nft_ctx *ctx, const struct nft_expr *expr, | |||
| 486 | return ret; | 520 | return ret; |
| 487 | 521 | ||
| 488 | nft_xt = container_of(expr->ops, struct nft_xt, ops); | 522 | nft_xt = container_of(expr->ops, struct nft_xt, ops); |
| 489 | nft_xt->refcnt++; | 523 | nft_xt_get(nft_xt); |
| 490 | return 0; | 524 | return 0; |
| 491 | } | 525 | } |
| 492 | 526 | ||
| @@ -540,6 +574,18 @@ nft_match_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) | |||
| 540 | __nft_match_destroy(ctx, expr, nft_expr_priv(expr)); | 574 | __nft_match_destroy(ctx, expr, nft_expr_priv(expr)); |
| 541 | } | 575 | } |
| 542 | 576 | ||
| 577 | static void nft_compat_deactivate(const struct nft_ctx *ctx, | ||
| 578 | const struct nft_expr *expr, | ||
| 579 | enum nft_trans_phase phase) | ||
| 580 | { | ||
| 581 | struct nft_xt *xt = container_of(expr->ops, struct nft_xt, ops); | ||
| 582 | |||
| 583 | if (phase == NFT_TRANS_ABORT || phase == NFT_TRANS_COMMIT) { | ||
| 584 | if (--xt->listcnt == 0) | ||
| 585 | list_del_init(&xt->head); | ||
| 586 | } | ||
| 587 | } | ||
| 588 | |||
| 543 | static void | 589 | static void |
| 544 | nft_match_large_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) | 590 | nft_match_large_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) |
| 545 | { | 591 | { |
| @@ -734,10 +780,6 @@ static const struct nfnetlink_subsystem nfnl_compat_subsys = { | |||
| 734 | .cb = nfnl_nft_compat_cb, | 780 | .cb = nfnl_nft_compat_cb, |
| 735 | }; | 781 | }; |
| 736 | 782 | ||
| 737 | static LIST_HEAD(nft_match_list); | ||
| 738 | |||
| 739 | static struct nft_expr_type nft_match_type; | ||
| 740 | |||
| 741 | static bool nft_match_cmp(const struct xt_match *match, | 783 | static bool nft_match_cmp(const struct xt_match *match, |
| 742 | const char *name, u32 rev, u32 family) | 784 | const char *name, u32 rev, u32 family) |
| 743 | { | 785 | { |
| @@ -749,6 +791,7 @@ static const struct nft_expr_ops * | |||
| 749 | nft_match_select_ops(const struct nft_ctx *ctx, | 791 | nft_match_select_ops(const struct nft_ctx *ctx, |
| 750 | const struct nlattr * const tb[]) | 792 | const struct nlattr * const tb[]) |
| 751 | { | 793 | { |
| 794 | struct nft_compat_net *cn; | ||
| 752 | struct nft_xt *nft_match; | 795 | struct nft_xt *nft_match; |
| 753 | struct xt_match *match; | 796 | struct xt_match *match; |
| 754 | unsigned int matchsize; | 797 | unsigned int matchsize; |
| @@ -765,8 +808,10 @@ nft_match_select_ops(const struct nft_ctx *ctx, | |||
| 765 | rev = ntohl(nla_get_be32(tb[NFTA_MATCH_REV])); | 808 | rev = ntohl(nla_get_be32(tb[NFTA_MATCH_REV])); |
| 766 | family = ctx->family; | 809 | family = ctx->family; |
| 767 | 810 | ||
| 811 | cn = nft_compat_pernet(ctx->net); | ||
| 812 | |||
| 768 | /* Re-use the existing match if it's already loaded. */ | 813 | /* Re-use the existing match if it's already loaded. */ |
| 769 | list_for_each_entry(nft_match, &nft_match_list, head) { | 814 | list_for_each_entry(nft_match, &cn->nft_match_list, head) { |
| 770 | struct xt_match *match = nft_match->ops.data; | 815 | struct xt_match *match = nft_match->ops.data; |
| 771 | 816 | ||
| 772 | if (nft_match_cmp(match, mt_name, rev, family)) | 817 | if (nft_match_cmp(match, mt_name, rev, family)) |
| @@ -789,11 +834,12 @@ nft_match_select_ops(const struct nft_ctx *ctx, | |||
| 789 | goto err; | 834 | goto err; |
| 790 | } | 835 | } |
| 791 | 836 | ||
| 792 | nft_match->refcnt = 0; | 837 | refcount_set(&nft_match->refcnt, 0); |
| 793 | nft_match->ops.type = &nft_match_type; | 838 | nft_match->ops.type = &nft_match_type; |
| 794 | nft_match->ops.eval = nft_match_eval; | 839 | nft_match->ops.eval = nft_match_eval; |
| 795 | nft_match->ops.init = nft_match_init; | 840 | nft_match->ops.init = nft_match_init; |
| 796 | nft_match->ops.destroy = nft_match_destroy; | 841 | nft_match->ops.destroy = nft_match_destroy; |
| 842 | nft_match->ops.deactivate = nft_compat_deactivate; | ||
| 797 | nft_match->ops.dump = nft_match_dump; | 843 | nft_match->ops.dump = nft_match_dump; |
| 798 | nft_match->ops.validate = nft_match_validate; | 844 | nft_match->ops.validate = nft_match_validate; |
| 799 | nft_match->ops.data = match; | 845 | nft_match->ops.data = match; |
| @@ -810,7 +856,8 @@ nft_match_select_ops(const struct nft_ctx *ctx, | |||
| 810 | 856 | ||
| 811 | nft_match->ops.size = matchsize; | 857 | nft_match->ops.size = matchsize; |
| 812 | 858 | ||
| 813 | list_add(&nft_match->head, &nft_match_list); | 859 | nft_match->listcnt = 0; |
| 860 | list_add(&nft_match->head, &cn->nft_match_list); | ||
| 814 | 861 | ||
| 815 | return &nft_match->ops; | 862 | return &nft_match->ops; |
| 816 | err: | 863 | err: |
| @@ -826,10 +873,6 @@ static struct nft_expr_type nft_match_type __read_mostly = { | |||
| 826 | .owner = THIS_MODULE, | 873 | .owner = THIS_MODULE, |
| 827 | }; | 874 | }; |
| 828 | 875 | ||
| 829 | static LIST_HEAD(nft_target_list); | ||
| 830 | |||
| 831 | static struct nft_expr_type nft_target_type; | ||
| 832 | |||
| 833 | static bool nft_target_cmp(const struct xt_target *tg, | 876 | static bool nft_target_cmp(const struct xt_target *tg, |
| 834 | const char *name, u32 rev, u32 family) | 877 | const char *name, u32 rev, u32 family) |
| 835 | { | 878 | { |
| @@ -841,6 +884,7 @@ static const struct nft_expr_ops * | |||
| 841 | nft_target_select_ops(const struct nft_ctx *ctx, | 884 | nft_target_select_ops(const struct nft_ctx *ctx, |
| 842 | const struct nlattr * const tb[]) | 885 | const struct nlattr * const tb[]) |
| 843 | { | 886 | { |
| 887 | struct nft_compat_net *cn; | ||
| 844 | struct nft_xt *nft_target; | 888 | struct nft_xt *nft_target; |
| 845 | struct xt_target *target; | 889 | struct xt_target *target; |
| 846 | char *tg_name; | 890 | char *tg_name; |
| @@ -861,8 +905,9 @@ nft_target_select_ops(const struct nft_ctx *ctx, | |||
| 861 | strcmp(tg_name, "standard") == 0) | 905 | strcmp(tg_name, "standard") == 0) |
| 862 | return ERR_PTR(-EINVAL); | 906 | return ERR_PTR(-EINVAL); |
| 863 | 907 | ||
| 908 | cn = nft_compat_pernet(ctx->net); | ||
| 864 | /* Re-use the existing target if it's already loaded. */ | 909 | /* Re-use the existing target if it's already loaded. */ |
| 865 | list_for_each_entry(nft_target, &nft_target_list, head) { | 910 | list_for_each_entry(nft_target, &cn->nft_target_list, head) { |
| 866 | struct xt_target *target = nft_target->ops.data; | 911 | struct xt_target *target = nft_target->ops.data; |
| 867 | 912 | ||
| 868 | if (!target->target) | 913 | if (!target->target) |
| @@ -893,11 +938,12 @@ nft_target_select_ops(const struct nft_ctx *ctx, | |||
| 893 | goto err; | 938 | goto err; |
| 894 | } | 939 | } |
| 895 | 940 | ||
| 896 | nft_target->refcnt = 0; | 941 | refcount_set(&nft_target->refcnt, 0); |
| 897 | nft_target->ops.type = &nft_target_type; | 942 | nft_target->ops.type = &nft_target_type; |
| 898 | nft_target->ops.size = NFT_EXPR_SIZE(XT_ALIGN(target->targetsize)); | 943 | nft_target->ops.size = NFT_EXPR_SIZE(XT_ALIGN(target->targetsize)); |
| 899 | nft_target->ops.init = nft_target_init; | 944 | nft_target->ops.init = nft_target_init; |
| 900 | nft_target->ops.destroy = nft_target_destroy; | 945 | nft_target->ops.destroy = nft_target_destroy; |
| 946 | nft_target->ops.deactivate = nft_compat_deactivate; | ||
| 901 | nft_target->ops.dump = nft_target_dump; | 947 | nft_target->ops.dump = nft_target_dump; |
| 902 | nft_target->ops.validate = nft_target_validate; | 948 | nft_target->ops.validate = nft_target_validate; |
| 903 | nft_target->ops.data = target; | 949 | nft_target->ops.data = target; |
| @@ -907,7 +953,8 @@ nft_target_select_ops(const struct nft_ctx *ctx, | |||
| 907 | else | 953 | else |
| 908 | nft_target->ops.eval = nft_target_eval_xt; | 954 | nft_target->ops.eval = nft_target_eval_xt; |
| 909 | 955 | ||
| 910 | list_add(&nft_target->head, &nft_target_list); | 956 | nft_target->listcnt = 0; |
| 957 | list_add(&nft_target->head, &cn->nft_target_list); | ||
| 911 | 958 | ||
| 912 | return &nft_target->ops; | 959 | return &nft_target->ops; |
| 913 | err: | 960 | err: |
| @@ -923,13 +970,74 @@ static struct nft_expr_type nft_target_type __read_mostly = { | |||
| 923 | .owner = THIS_MODULE, | 970 | .owner = THIS_MODULE, |
| 924 | }; | 971 | }; |
| 925 | 972 | ||
| 973 | static int __net_init nft_compat_init_net(struct net *net) | ||
| 974 | { | ||
| 975 | struct nft_compat_net *cn = nft_compat_pernet(net); | ||
| 976 | |||
| 977 | INIT_LIST_HEAD(&cn->nft_target_list); | ||
| 978 | INIT_LIST_HEAD(&cn->nft_match_list); | ||
| 979 | |||
| 980 | return 0; | ||
| 981 | } | ||
| 982 | |||
| 983 | static void __net_exit nft_compat_exit_net(struct net *net) | ||
| 984 | { | ||
| 985 | struct nft_compat_net *cn = nft_compat_pernet(net); | ||
| 986 | struct nft_xt *xt, *next; | ||
| 987 | |||
| 988 | if (list_empty(&cn->nft_match_list) && | ||
| 989 | list_empty(&cn->nft_target_list)) | ||
| 990 | return; | ||
| 991 | |||
| 992 | /* If there was an error that caused nft_xt expr to not be initialized | ||
| 993 | * fully and noone else requested the same expression later, the lists | ||
| 994 | * contain 0-refcount entries that still hold module reference. | ||
| 995 | * | ||
| 996 | * Clean them here. | ||
| 997 | */ | ||
| 998 | mutex_lock(&net->nft.commit_mutex); | ||
| 999 | list_for_each_entry_safe(xt, next, &cn->nft_target_list, head) { | ||
| 1000 | struct xt_target *target = xt->ops.data; | ||
| 1001 | |||
| 1002 | list_del_init(&xt->head); | ||
| 1003 | |||
| 1004 | if (refcount_read(&xt->refcnt)) | ||
| 1005 | continue; | ||
| 1006 | module_put(target->me); | ||
| 1007 | kfree(xt); | ||
| 1008 | } | ||
| 1009 | |||
| 1010 | list_for_each_entry_safe(xt, next, &cn->nft_match_list, head) { | ||
| 1011 | struct xt_match *match = xt->ops.data; | ||
| 1012 | |||
| 1013 | list_del_init(&xt->head); | ||
| 1014 | |||
| 1015 | if (refcount_read(&xt->refcnt)) | ||
| 1016 | continue; | ||
| 1017 | module_put(match->me); | ||
| 1018 | kfree(xt); | ||
| 1019 | } | ||
| 1020 | mutex_unlock(&net->nft.commit_mutex); | ||
| 1021 | } | ||
| 1022 | |||
| 1023 | static struct pernet_operations nft_compat_net_ops = { | ||
| 1024 | .init = nft_compat_init_net, | ||
| 1025 | .exit = nft_compat_exit_net, | ||
| 1026 | .id = &nft_compat_net_id, | ||
| 1027 | .size = sizeof(struct nft_compat_net), | ||
| 1028 | }; | ||
| 1029 | |||
| 926 | static int __init nft_compat_module_init(void) | 1030 | static int __init nft_compat_module_init(void) |
| 927 | { | 1031 | { |
| 928 | int ret; | 1032 | int ret; |
| 929 | 1033 | ||
| 1034 | ret = register_pernet_subsys(&nft_compat_net_ops); | ||
| 1035 | if (ret < 0) | ||
| 1036 | goto err_target; | ||
| 1037 | |||
| 930 | ret = nft_register_expr(&nft_match_type); | 1038 | ret = nft_register_expr(&nft_match_type); |
| 931 | if (ret < 0) | 1039 | if (ret < 0) |
| 932 | return ret; | 1040 | goto err_pernet; |
| 933 | 1041 | ||
| 934 | ret = nft_register_expr(&nft_target_type); | 1042 | ret = nft_register_expr(&nft_target_type); |
| 935 | if (ret < 0) | 1043 | if (ret < 0) |
| @@ -942,45 +1050,21 @@ static int __init nft_compat_module_init(void) | |||
| 942 | } | 1050 | } |
| 943 | 1051 | ||
| 944 | return ret; | 1052 | return ret; |
| 945 | |||
| 946 | err_target: | 1053 | err_target: |
| 947 | nft_unregister_expr(&nft_target_type); | 1054 | nft_unregister_expr(&nft_target_type); |
| 948 | err_match: | 1055 | err_match: |
| 949 | nft_unregister_expr(&nft_match_type); | 1056 | nft_unregister_expr(&nft_match_type); |
| 1057 | err_pernet: | ||
| 1058 | unregister_pernet_subsys(&nft_compat_net_ops); | ||
| 950 | return ret; | 1059 | return ret; |
| 951 | } | 1060 | } |
| 952 | 1061 | ||
| 953 | static void __exit nft_compat_module_exit(void) | 1062 | static void __exit nft_compat_module_exit(void) |
| 954 | { | 1063 | { |
| 955 | struct nft_xt *xt, *next; | ||
| 956 | |||
| 957 | /* list should be empty here, it can be non-empty only in case there | ||
| 958 | * was an error that caused nft_xt expr to not be initialized fully | ||
| 959 | * and noone else requested the same expression later. | ||
| 960 | * | ||
| 961 | * In this case, the lists contain 0-refcount entries that still | ||
| 962 | * hold module reference. | ||
| 963 | */ | ||
| 964 | list_for_each_entry_safe(xt, next, &nft_target_list, head) { | ||
| 965 | struct xt_target *target = xt->ops.data; | ||
| 966 | |||
| 967 | if (WARN_ON_ONCE(xt->refcnt)) | ||
| 968 | continue; | ||
| 969 | module_put(target->me); | ||
| 970 | kfree(xt); | ||
| 971 | } | ||
| 972 | |||
| 973 | list_for_each_entry_safe(xt, next, &nft_match_list, head) { | ||
| 974 | struct xt_match *match = xt->ops.data; | ||
| 975 | |||
| 976 | if (WARN_ON_ONCE(xt->refcnt)) | ||
| 977 | continue; | ||
| 978 | module_put(match->me); | ||
| 979 | kfree(xt); | ||
| 980 | } | ||
| 981 | nfnetlink_subsys_unregister(&nfnl_compat_subsys); | 1064 | nfnetlink_subsys_unregister(&nfnl_compat_subsys); |
| 982 | nft_unregister_expr(&nft_target_type); | 1065 | nft_unregister_expr(&nft_target_type); |
| 983 | nft_unregister_expr(&nft_match_type); | 1066 | nft_unregister_expr(&nft_match_type); |
| 1067 | unregister_pernet_subsys(&nft_compat_net_ops); | ||
| 984 | } | 1068 | } |
| 985 | 1069 | ||
| 986 | MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_NFT_COMPAT); | 1070 | MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_NFT_COMPAT); |
diff --git a/net/netfilter/nft_dynset.c b/net/netfilter/nft_dynset.c index 07d4efd3d851..f1172f99752b 100644 --- a/net/netfilter/nft_dynset.c +++ b/net/netfilter/nft_dynset.c | |||
| @@ -235,20 +235,17 @@ err1: | |||
| 235 | return err; | 235 | return err; |
| 236 | } | 236 | } |
| 237 | 237 | ||
| 238 | static void nft_dynset_activate(const struct nft_ctx *ctx, | ||
| 239 | const struct nft_expr *expr) | ||
| 240 | { | ||
| 241 | struct nft_dynset *priv = nft_expr_priv(expr); | ||
| 242 | |||
| 243 | nf_tables_rebind_set(ctx, priv->set, &priv->binding); | ||
| 244 | } | ||
| 245 | |||
| 246 | static void nft_dynset_deactivate(const struct nft_ctx *ctx, | 238 | static void nft_dynset_deactivate(const struct nft_ctx *ctx, |
| 247 | const struct nft_expr *expr) | 239 | const struct nft_expr *expr, |
| 240 | enum nft_trans_phase phase) | ||
| 248 | { | 241 | { |
| 249 | struct nft_dynset *priv = nft_expr_priv(expr); | 242 | struct nft_dynset *priv = nft_expr_priv(expr); |
| 250 | 243 | ||
| 251 | nf_tables_unbind_set(ctx, priv->set, &priv->binding); | 244 | if (phase == NFT_TRANS_PREPARE) |
| 245 | return; | ||
| 246 | |||
| 247 | nf_tables_unbind_set(ctx, priv->set, &priv->binding, | ||
| 248 | phase == NFT_TRANS_COMMIT); | ||
| 252 | } | 249 | } |
| 253 | 250 | ||
| 254 | static void nft_dynset_destroy(const struct nft_ctx *ctx, | 251 | static void nft_dynset_destroy(const struct nft_ctx *ctx, |
| @@ -296,7 +293,6 @@ static const struct nft_expr_ops nft_dynset_ops = { | |||
| 296 | .eval = nft_dynset_eval, | 293 | .eval = nft_dynset_eval, |
| 297 | .init = nft_dynset_init, | 294 | .init = nft_dynset_init, |
| 298 | .destroy = nft_dynset_destroy, | 295 | .destroy = nft_dynset_destroy, |
| 299 | .activate = nft_dynset_activate, | ||
| 300 | .deactivate = nft_dynset_deactivate, | 296 | .deactivate = nft_dynset_deactivate, |
| 301 | .dump = nft_dynset_dump, | 297 | .dump = nft_dynset_dump, |
| 302 | }; | 298 | }; |
diff --git a/net/netfilter/nft_flow_offload.c b/net/netfilter/nft_flow_offload.c index 974525eb92df..6e6b9adf7d38 100644 --- a/net/netfilter/nft_flow_offload.c +++ b/net/netfilter/nft_flow_offload.c | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #include <net/netfilter/nf_conntrack_core.h> | 12 | #include <net/netfilter/nf_conntrack_core.h> |
| 13 | #include <linux/netfilter/nf_conntrack_common.h> | 13 | #include <linux/netfilter/nf_conntrack_common.h> |
| 14 | #include <net/netfilter/nf_flow_table.h> | 14 | #include <net/netfilter/nf_flow_table.h> |
| 15 | #include <net/netfilter/nf_conntrack_helper.h> | ||
| 15 | 16 | ||
| 16 | struct nft_flow_offload { | 17 | struct nft_flow_offload { |
| 17 | struct nft_flowtable *flowtable; | 18 | struct nft_flowtable *flowtable; |
| @@ -29,10 +30,12 @@ static int nft_flow_route(const struct nft_pktinfo *pkt, | |||
| 29 | memset(&fl, 0, sizeof(fl)); | 30 | memset(&fl, 0, sizeof(fl)); |
| 30 | switch (nft_pf(pkt)) { | 31 | switch (nft_pf(pkt)) { |
| 31 | case NFPROTO_IPV4: | 32 | case NFPROTO_IPV4: |
| 32 | fl.u.ip4.daddr = ct->tuplehash[!dir].tuple.dst.u3.ip; | 33 | fl.u.ip4.daddr = ct->tuplehash[dir].tuple.src.u3.ip; |
| 34 | fl.u.ip4.flowi4_oif = nft_in(pkt)->ifindex; | ||
| 33 | break; | 35 | break; |
| 34 | case NFPROTO_IPV6: | 36 | case NFPROTO_IPV6: |
| 35 | fl.u.ip6.daddr = ct->tuplehash[!dir].tuple.dst.u3.in6; | 37 | fl.u.ip6.daddr = ct->tuplehash[dir].tuple.src.u3.in6; |
| 38 | fl.u.ip6.flowi6_oif = nft_in(pkt)->ifindex; | ||
| 36 | break; | 39 | break; |
| 37 | } | 40 | } |
| 38 | 41 | ||
| @@ -41,9 +44,7 @@ static int nft_flow_route(const struct nft_pktinfo *pkt, | |||
| 41 | return -ENOENT; | 44 | return -ENOENT; |
| 42 | 45 | ||
| 43 | route->tuple[dir].dst = this_dst; | 46 | route->tuple[dir].dst = this_dst; |
| 44 | route->tuple[dir].ifindex = nft_in(pkt)->ifindex; | ||
| 45 | route->tuple[!dir].dst = other_dst; | 47 | route->tuple[!dir].dst = other_dst; |
| 46 | route->tuple[!dir].ifindex = nft_out(pkt)->ifindex; | ||
| 47 | 48 | ||
| 48 | return 0; | 49 | return 0; |
| 49 | } | 50 | } |
| @@ -66,6 +67,7 @@ static void nft_flow_offload_eval(const struct nft_expr *expr, | |||
| 66 | { | 67 | { |
| 67 | struct nft_flow_offload *priv = nft_expr_priv(expr); | 68 | struct nft_flow_offload *priv = nft_expr_priv(expr); |
| 68 | struct nf_flowtable *flowtable = &priv->flowtable->data; | 69 | struct nf_flowtable *flowtable = &priv->flowtable->data; |
| 70 | const struct nf_conn_help *help; | ||
| 69 | enum ip_conntrack_info ctinfo; | 71 | enum ip_conntrack_info ctinfo; |
| 70 | struct nf_flow_route route; | 72 | struct nf_flow_route route; |
| 71 | struct flow_offload *flow; | 73 | struct flow_offload *flow; |
| @@ -88,7 +90,8 @@ static void nft_flow_offload_eval(const struct nft_expr *expr, | |||
| 88 | goto out; | 90 | goto out; |
| 89 | } | 91 | } |
| 90 | 92 | ||
| 91 | if (test_bit(IPS_HELPER_BIT, &ct->status)) | 93 | help = nfct_help(ct); |
| 94 | if (help) | ||
| 92 | goto out; | 95 | goto out; |
| 93 | 96 | ||
| 94 | if (ctinfo == IP_CT_NEW || | 97 | if (ctinfo == IP_CT_NEW || |
diff --git a/net/netfilter/nft_immediate.c b/net/netfilter/nft_immediate.c index 0777a93211e2..3f6d1d2a6281 100644 --- a/net/netfilter/nft_immediate.c +++ b/net/netfilter/nft_immediate.c | |||
| @@ -72,10 +72,14 @@ static void nft_immediate_activate(const struct nft_ctx *ctx, | |||
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | static void nft_immediate_deactivate(const struct nft_ctx *ctx, | 74 | static void nft_immediate_deactivate(const struct nft_ctx *ctx, |
| 75 | const struct nft_expr *expr) | 75 | const struct nft_expr *expr, |
| 76 | enum nft_trans_phase phase) | ||
| 76 | { | 77 | { |
| 77 | const struct nft_immediate_expr *priv = nft_expr_priv(expr); | 78 | const struct nft_immediate_expr *priv = nft_expr_priv(expr); |
| 78 | 79 | ||
| 80 | if (phase == NFT_TRANS_COMMIT) | ||
| 81 | return; | ||
| 82 | |||
| 79 | return nft_data_release(&priv->data, nft_dreg_to_type(priv->dreg)); | 83 | return nft_data_release(&priv->data, nft_dreg_to_type(priv->dreg)); |
| 80 | } | 84 | } |
| 81 | 85 | ||
diff --git a/net/netfilter/nft_lookup.c b/net/netfilter/nft_lookup.c index 227b2b15a19c..14496da5141d 100644 --- a/net/netfilter/nft_lookup.c +++ b/net/netfilter/nft_lookup.c | |||
| @@ -121,20 +121,17 @@ static int nft_lookup_init(const struct nft_ctx *ctx, | |||
| 121 | return 0; | 121 | return 0; |
| 122 | } | 122 | } |
| 123 | 123 | ||
| 124 | static void nft_lookup_activate(const struct nft_ctx *ctx, | ||
| 125 | const struct nft_expr *expr) | ||
| 126 | { | ||
| 127 | struct nft_lookup *priv = nft_expr_priv(expr); | ||
| 128 | |||
| 129 | nf_tables_rebind_set(ctx, priv->set, &priv->binding); | ||
| 130 | } | ||
| 131 | |||
| 132 | static void nft_lookup_deactivate(const struct nft_ctx *ctx, | 124 | static void nft_lookup_deactivate(const struct nft_ctx *ctx, |
| 133 | const struct nft_expr *expr) | 125 | const struct nft_expr *expr, |
| 126 | enum nft_trans_phase phase) | ||
| 134 | { | 127 | { |
| 135 | struct nft_lookup *priv = nft_expr_priv(expr); | 128 | struct nft_lookup *priv = nft_expr_priv(expr); |
| 136 | 129 | ||
| 137 | nf_tables_unbind_set(ctx, priv->set, &priv->binding); | 130 | if (phase == NFT_TRANS_PREPARE) |
| 131 | return; | ||
| 132 | |||
| 133 | nf_tables_unbind_set(ctx, priv->set, &priv->binding, | ||
| 134 | phase == NFT_TRANS_COMMIT); | ||
| 138 | } | 135 | } |
| 139 | 136 | ||
| 140 | static void nft_lookup_destroy(const struct nft_ctx *ctx, | 137 | static void nft_lookup_destroy(const struct nft_ctx *ctx, |
| @@ -225,7 +222,6 @@ static const struct nft_expr_ops nft_lookup_ops = { | |||
| 225 | .size = NFT_EXPR_SIZE(sizeof(struct nft_lookup)), | 222 | .size = NFT_EXPR_SIZE(sizeof(struct nft_lookup)), |
| 226 | .eval = nft_lookup_eval, | 223 | .eval = nft_lookup_eval, |
| 227 | .init = nft_lookup_init, | 224 | .init = nft_lookup_init, |
| 228 | .activate = nft_lookup_activate, | ||
| 229 | .deactivate = nft_lookup_deactivate, | 225 | .deactivate = nft_lookup_deactivate, |
| 230 | .destroy = nft_lookup_destroy, | 226 | .destroy = nft_lookup_destroy, |
| 231 | .dump = nft_lookup_dump, | 227 | .dump = nft_lookup_dump, |
diff --git a/net/netfilter/nft_objref.c b/net/netfilter/nft_objref.c index a3185ca2a3a9..ae178e914486 100644 --- a/net/netfilter/nft_objref.c +++ b/net/netfilter/nft_objref.c | |||
| @@ -155,20 +155,17 @@ nla_put_failure: | |||
| 155 | return -1; | 155 | return -1; |
| 156 | } | 156 | } |
| 157 | 157 | ||
| 158 | static void nft_objref_map_activate(const struct nft_ctx *ctx, | ||
| 159 | const struct nft_expr *expr) | ||
| 160 | { | ||
| 161 | struct nft_objref_map *priv = nft_expr_priv(expr); | ||
| 162 | |||
| 163 | nf_tables_rebind_set(ctx, priv->set, &priv->binding); | ||
| 164 | } | ||
| 165 | |||
| 166 | static void nft_objref_map_deactivate(const struct nft_ctx *ctx, | 158 | static void nft_objref_map_deactivate(const struct nft_ctx *ctx, |
| 167 | const struct nft_expr *expr) | 159 | const struct nft_expr *expr, |
| 160 | enum nft_trans_phase phase) | ||
| 168 | { | 161 | { |
| 169 | struct nft_objref_map *priv = nft_expr_priv(expr); | 162 | struct nft_objref_map *priv = nft_expr_priv(expr); |
| 170 | 163 | ||
| 171 | nf_tables_unbind_set(ctx, priv->set, &priv->binding); | 164 | if (phase == NFT_TRANS_PREPARE) |
| 165 | return; | ||
| 166 | |||
| 167 | nf_tables_unbind_set(ctx, priv->set, &priv->binding, | ||
| 168 | phase == NFT_TRANS_COMMIT); | ||
| 172 | } | 169 | } |
| 173 | 170 | ||
| 174 | static void nft_objref_map_destroy(const struct nft_ctx *ctx, | 171 | static void nft_objref_map_destroy(const struct nft_ctx *ctx, |
| @@ -185,7 +182,6 @@ static const struct nft_expr_ops nft_objref_map_ops = { | |||
| 185 | .size = NFT_EXPR_SIZE(sizeof(struct nft_objref_map)), | 182 | .size = NFT_EXPR_SIZE(sizeof(struct nft_objref_map)), |
| 186 | .eval = nft_objref_map_eval, | 183 | .eval = nft_objref_map_eval, |
| 187 | .init = nft_objref_map_init, | 184 | .init = nft_objref_map_init, |
| 188 | .activate = nft_objref_map_activate, | ||
| 189 | .deactivate = nft_objref_map_deactivate, | 185 | .deactivate = nft_objref_map_deactivate, |
| 190 | .destroy = nft_objref_map_destroy, | 186 | .destroy = nft_objref_map_destroy, |
| 191 | .dump = nft_objref_map_dump, | 187 | .dump = nft_objref_map_dump, |
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index aecadd471e1d..13e1ac333fa4 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c | |||
| @@ -1899,7 +1899,7 @@ static int __init xt_init(void) | |||
| 1899 | seqcount_init(&per_cpu(xt_recseq, i)); | 1899 | seqcount_init(&per_cpu(xt_recseq, i)); |
| 1900 | } | 1900 | } |
| 1901 | 1901 | ||
| 1902 | xt = kmalloc_array(NFPROTO_NUMPROTO, sizeof(struct xt_af), GFP_KERNEL); | 1902 | xt = kcalloc(NFPROTO_NUMPROTO, sizeof(struct xt_af), GFP_KERNEL); |
| 1903 | if (!xt) | 1903 | if (!xt) |
| 1904 | return -ENOMEM; | 1904 | return -ENOMEM; |
| 1905 | 1905 | ||
diff --git a/net/netrom/nr_timer.c b/net/netrom/nr_timer.c index cbd51ed5a2d7..908e53ab47a4 100644 --- a/net/netrom/nr_timer.c +++ b/net/netrom/nr_timer.c | |||
| @@ -52,21 +52,21 @@ void nr_start_t1timer(struct sock *sk) | |||
| 52 | { | 52 | { |
| 53 | struct nr_sock *nr = nr_sk(sk); | 53 | struct nr_sock *nr = nr_sk(sk); |
| 54 | 54 | ||
| 55 | mod_timer(&nr->t1timer, jiffies + nr->t1); | 55 | sk_reset_timer(sk, &nr->t1timer, jiffies + nr->t1); |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | void nr_start_t2timer(struct sock *sk) | 58 | void nr_start_t2timer(struct sock *sk) |
| 59 | { | 59 | { |
| 60 | struct nr_sock *nr = nr_sk(sk); | 60 | struct nr_sock *nr = nr_sk(sk); |
| 61 | 61 | ||
| 62 | mod_timer(&nr->t2timer, jiffies + nr->t2); | 62 | sk_reset_timer(sk, &nr->t2timer, jiffies + nr->t2); |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | void nr_start_t4timer(struct sock *sk) | 65 | void nr_start_t4timer(struct sock *sk) |
| 66 | { | 66 | { |
| 67 | struct nr_sock *nr = nr_sk(sk); | 67 | struct nr_sock *nr = nr_sk(sk); |
| 68 | 68 | ||
| 69 | mod_timer(&nr->t4timer, jiffies + nr->t4); | 69 | sk_reset_timer(sk, &nr->t4timer, jiffies + nr->t4); |
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | void nr_start_idletimer(struct sock *sk) | 72 | void nr_start_idletimer(struct sock *sk) |
| @@ -74,37 +74,37 @@ void nr_start_idletimer(struct sock *sk) | |||
| 74 | struct nr_sock *nr = nr_sk(sk); | 74 | struct nr_sock *nr = nr_sk(sk); |
| 75 | 75 | ||
| 76 | if (nr->idle > 0) | 76 | if (nr->idle > 0) |
| 77 | mod_timer(&nr->idletimer, jiffies + nr->idle); | 77 | sk_reset_timer(sk, &nr->idletimer, jiffies + nr->idle); |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | void nr_start_heartbeat(struct sock *sk) | 80 | void nr_start_heartbeat(struct sock *sk) |
| 81 | { | 81 | { |
| 82 | mod_timer(&sk->sk_timer, jiffies + 5 * HZ); | 82 | sk_reset_timer(sk, &sk->sk_timer, jiffies + 5 * HZ); |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | void nr_stop_t1timer(struct sock *sk) | 85 | void nr_stop_t1timer(struct sock *sk) |
| 86 | { | 86 | { |
| 87 | del_timer(&nr_sk(sk)->t1timer); | 87 | sk_stop_timer(sk, &nr_sk(sk)->t1timer); |
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | void nr_stop_t2timer(struct sock *sk) | 90 | void nr_stop_t2timer(struct sock *sk) |
| 91 | { | 91 | { |
| 92 | del_timer(&nr_sk(sk)->t2timer); | 92 | sk_stop_timer(sk, &nr_sk(sk)->t2timer); |
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | void nr_stop_t4timer(struct sock *sk) | 95 | void nr_stop_t4timer(struct sock *sk) |
| 96 | { | 96 | { |
| 97 | del_timer(&nr_sk(sk)->t4timer); | 97 | sk_stop_timer(sk, &nr_sk(sk)->t4timer); |
| 98 | } | 98 | } |
| 99 | 99 | ||
| 100 | void nr_stop_idletimer(struct sock *sk) | 100 | void nr_stop_idletimer(struct sock *sk) |
| 101 | { | 101 | { |
| 102 | del_timer(&nr_sk(sk)->idletimer); | 102 | sk_stop_timer(sk, &nr_sk(sk)->idletimer); |
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | void nr_stop_heartbeat(struct sock *sk) | 105 | void nr_stop_heartbeat(struct sock *sk) |
| 106 | { | 106 | { |
| 107 | del_timer(&sk->sk_timer); | 107 | sk_stop_timer(sk, &sk->sk_timer); |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | int nr_t1timer_running(struct sock *sk) | 110 | int nr_t1timer_running(struct sock *sk) |
diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c index 57e07768c9d1..f54cf17ef7a8 100644 --- a/net/openvswitch/flow.c +++ b/net/openvswitch/flow.c | |||
| @@ -276,10 +276,12 @@ static int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key) | |||
| 276 | 276 | ||
| 277 | nexthdr = ipv6_find_hdr(skb, &payload_ofs, -1, &frag_off, &flags); | 277 | nexthdr = ipv6_find_hdr(skb, &payload_ofs, -1, &frag_off, &flags); |
| 278 | if (flags & IP6_FH_F_FRAG) { | 278 | if (flags & IP6_FH_F_FRAG) { |
| 279 | if (frag_off) | 279 | if (frag_off) { |
| 280 | key->ip.frag = OVS_FRAG_TYPE_LATER; | 280 | key->ip.frag = OVS_FRAG_TYPE_LATER; |
| 281 | else | 281 | key->ip.proto = nexthdr; |
| 282 | key->ip.frag = OVS_FRAG_TYPE_FIRST; | 282 | return 0; |
| 283 | } | ||
| 284 | key->ip.frag = OVS_FRAG_TYPE_FIRST; | ||
| 283 | } else { | 285 | } else { |
| 284 | key->ip.frag = OVS_FRAG_TYPE_NONE; | 286 | key->ip.frag = OVS_FRAG_TYPE_NONE; |
| 285 | } | 287 | } |
diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index 435a4bdf8f89..691da853bef5 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c | |||
| @@ -500,7 +500,7 @@ static int __parse_flow_nlattrs(const struct nlattr *attr, | |||
| 500 | return -EINVAL; | 500 | return -EINVAL; |
| 501 | } | 501 | } |
| 502 | 502 | ||
| 503 | if (!nz || !is_all_zero(nla_data(nla), expected_len)) { | 503 | if (!nz || !is_all_zero(nla_data(nla), nla_len(nla))) { |
| 504 | attrs |= 1 << type; | 504 | attrs |= 1 << type; |
| 505 | a[type] = nla; | 505 | a[type] = nla; |
| 506 | } | 506 | } |
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index eedacdebcd4c..1cd1d83a4be0 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
| @@ -2628,7 +2628,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) | |||
| 2628 | addr = saddr->sll_halen ? saddr->sll_addr : NULL; | 2628 | addr = saddr->sll_halen ? saddr->sll_addr : NULL; |
| 2629 | dev = dev_get_by_index(sock_net(&po->sk), saddr->sll_ifindex); | 2629 | dev = dev_get_by_index(sock_net(&po->sk), saddr->sll_ifindex); |
| 2630 | if (addr && dev && saddr->sll_halen < dev->addr_len) | 2630 | if (addr && dev && saddr->sll_halen < dev->addr_len) |
| 2631 | goto out; | 2631 | goto out_put; |
| 2632 | } | 2632 | } |
| 2633 | 2633 | ||
| 2634 | err = -ENXIO; | 2634 | err = -ENXIO; |
| @@ -2828,7 +2828,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) | |||
| 2828 | addr = saddr->sll_halen ? saddr->sll_addr : NULL; | 2828 | addr = saddr->sll_halen ? saddr->sll_addr : NULL; |
| 2829 | dev = dev_get_by_index(sock_net(sk), saddr->sll_ifindex); | 2829 | dev = dev_get_by_index(sock_net(sk), saddr->sll_ifindex); |
| 2830 | if (addr && dev && saddr->sll_halen < dev->addr_len) | 2830 | if (addr && dev && saddr->sll_halen < dev->addr_len) |
| 2831 | goto out; | 2831 | goto out_unlock; |
| 2832 | } | 2832 | } |
| 2833 | 2833 | ||
| 2834 | err = -ENXIO; | 2834 | err = -ENXIO; |
| @@ -2887,7 +2887,8 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) | |||
| 2887 | goto out_free; | 2887 | goto out_free; |
| 2888 | } else if (reserve) { | 2888 | } else if (reserve) { |
| 2889 | skb_reserve(skb, -reserve); | 2889 | skb_reserve(skb, -reserve); |
| 2890 | if (len < reserve) | 2890 | if (len < reserve + sizeof(struct ipv6hdr) && |
| 2891 | dev->min_header_len != dev->hard_header_len) | ||
| 2891 | skb_reset_network_header(skb); | 2892 | skb_reset_network_header(skb); |
| 2892 | } | 2893 | } |
| 2893 | 2894 | ||
| @@ -4291,7 +4292,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, | |||
| 4291 | rb->frames_per_block = req->tp_block_size / req->tp_frame_size; | 4292 | rb->frames_per_block = req->tp_block_size / req->tp_frame_size; |
| 4292 | if (unlikely(rb->frames_per_block == 0)) | 4293 | if (unlikely(rb->frames_per_block == 0)) |
| 4293 | goto out; | 4294 | goto out; |
| 4294 | if (unlikely(req->tp_block_size > UINT_MAX / req->tp_block_nr)) | 4295 | if (unlikely(rb->frames_per_block > UINT_MAX / req->tp_block_nr)) |
| 4295 | goto out; | 4296 | goto out; |
| 4296 | if (unlikely((rb->frames_per_block * req->tp_block_nr) != | 4297 | if (unlikely((rb->frames_per_block * req->tp_block_nr) != |
| 4297 | req->tp_frame_nr)) | 4298 | req->tp_frame_nr)) |
diff --git a/net/phonet/pep.c b/net/phonet/pep.c index 9fc76b19cd3c..db3473540303 100644 --- a/net/phonet/pep.c +++ b/net/phonet/pep.c | |||
| @@ -132,7 +132,7 @@ static int pep_indicate(struct sock *sk, u8 id, u8 code, | |||
| 132 | ph->utid = 0; | 132 | ph->utid = 0; |
| 133 | ph->message_id = id; | 133 | ph->message_id = id; |
| 134 | ph->pipe_handle = pn->pipe_handle; | 134 | ph->pipe_handle = pn->pipe_handle; |
| 135 | ph->data[0] = code; | 135 | ph->error_code = code; |
| 136 | return pn_skb_send(sk, skb, NULL); | 136 | return pn_skb_send(sk, skb, NULL); |
| 137 | } | 137 | } |
| 138 | 138 | ||
| @@ -153,7 +153,7 @@ static int pipe_handler_request(struct sock *sk, u8 id, u8 code, | |||
| 153 | ph->utid = id; /* whatever */ | 153 | ph->utid = id; /* whatever */ |
| 154 | ph->message_id = id; | 154 | ph->message_id = id; |
| 155 | ph->pipe_handle = pn->pipe_handle; | 155 | ph->pipe_handle = pn->pipe_handle; |
| 156 | ph->data[0] = code; | 156 | ph->error_code = code; |
| 157 | return pn_skb_send(sk, skb, NULL); | 157 | return pn_skb_send(sk, skb, NULL); |
| 158 | } | 158 | } |
| 159 | 159 | ||
| @@ -208,7 +208,7 @@ static int pep_ctrlreq_error(struct sock *sk, struct sk_buff *oskb, u8 code, | |||
| 208 | struct pnpipehdr *ph; | 208 | struct pnpipehdr *ph; |
| 209 | struct sockaddr_pn dst; | 209 | struct sockaddr_pn dst; |
| 210 | u8 data[4] = { | 210 | u8 data[4] = { |
| 211 | oph->data[0], /* PEP type */ | 211 | oph->pep_type, /* PEP type */ |
| 212 | code, /* error code, at an unusual offset */ | 212 | code, /* error code, at an unusual offset */ |
| 213 | PAD, PAD, | 213 | PAD, PAD, |
| 214 | }; | 214 | }; |
| @@ -221,7 +221,7 @@ static int pep_ctrlreq_error(struct sock *sk, struct sk_buff *oskb, u8 code, | |||
| 221 | ph->utid = oph->utid; | 221 | ph->utid = oph->utid; |
| 222 | ph->message_id = PNS_PEP_CTRL_RESP; | 222 | ph->message_id = PNS_PEP_CTRL_RESP; |
| 223 | ph->pipe_handle = oph->pipe_handle; | 223 | ph->pipe_handle = oph->pipe_handle; |
| 224 | ph->data[0] = oph->data[1]; /* CTRL id */ | 224 | ph->data0 = oph->data[0]; /* CTRL id */ |
| 225 | 225 | ||
| 226 | pn_skb_get_src_sockaddr(oskb, &dst); | 226 | pn_skb_get_src_sockaddr(oskb, &dst); |
| 227 | return pn_skb_send(sk, skb, &dst); | 227 | return pn_skb_send(sk, skb, &dst); |
| @@ -272,17 +272,17 @@ static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb) | |||
| 272 | return -EINVAL; | 272 | return -EINVAL; |
| 273 | 273 | ||
| 274 | hdr = pnp_hdr(skb); | 274 | hdr = pnp_hdr(skb); |
| 275 | if (hdr->data[0] != PN_PEP_TYPE_COMMON) { | 275 | if (hdr->pep_type != PN_PEP_TYPE_COMMON) { |
| 276 | net_dbg_ratelimited("Phonet unknown PEP type: %u\n", | 276 | net_dbg_ratelimited("Phonet unknown PEP type: %u\n", |
| 277 | (unsigned int)hdr->data[0]); | 277 | (unsigned int)hdr->pep_type); |
| 278 | return -EOPNOTSUPP; | 278 | return -EOPNOTSUPP; |
| 279 | } | 279 | } |
| 280 | 280 | ||
| 281 | switch (hdr->data[1]) { | 281 | switch (hdr->data[0]) { |
| 282 | case PN_PEP_IND_FLOW_CONTROL: | 282 | case PN_PEP_IND_FLOW_CONTROL: |
| 283 | switch (pn->tx_fc) { | 283 | switch (pn->tx_fc) { |
| 284 | case PN_LEGACY_FLOW_CONTROL: | 284 | case PN_LEGACY_FLOW_CONTROL: |
| 285 | switch (hdr->data[4]) { | 285 | switch (hdr->data[3]) { |
| 286 | case PEP_IND_BUSY: | 286 | case PEP_IND_BUSY: |
| 287 | atomic_set(&pn->tx_credits, 0); | 287 | atomic_set(&pn->tx_credits, 0); |
| 288 | break; | 288 | break; |
| @@ -292,7 +292,7 @@ static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb) | |||
| 292 | } | 292 | } |
| 293 | break; | 293 | break; |
| 294 | case PN_ONE_CREDIT_FLOW_CONTROL: | 294 | case PN_ONE_CREDIT_FLOW_CONTROL: |
| 295 | if (hdr->data[4] == PEP_IND_READY) | 295 | if (hdr->data[3] == PEP_IND_READY) |
| 296 | atomic_set(&pn->tx_credits, wake = 1); | 296 | atomic_set(&pn->tx_credits, wake = 1); |
| 297 | break; | 297 | break; |
| 298 | } | 298 | } |
| @@ -301,12 +301,12 @@ static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb) | |||
| 301 | case PN_PEP_IND_ID_MCFC_GRANT_CREDITS: | 301 | case PN_PEP_IND_ID_MCFC_GRANT_CREDITS: |
| 302 | if (pn->tx_fc != PN_MULTI_CREDIT_FLOW_CONTROL) | 302 | if (pn->tx_fc != PN_MULTI_CREDIT_FLOW_CONTROL) |
| 303 | break; | 303 | break; |
| 304 | atomic_add(wake = hdr->data[4], &pn->tx_credits); | 304 | atomic_add(wake = hdr->data[3], &pn->tx_credits); |
| 305 | break; | 305 | break; |
| 306 | 306 | ||
| 307 | default: | 307 | default: |
| 308 | net_dbg_ratelimited("Phonet unknown PEP indication: %u\n", | 308 | net_dbg_ratelimited("Phonet unknown PEP indication: %u\n", |
| 309 | (unsigned int)hdr->data[1]); | 309 | (unsigned int)hdr->data[0]); |
| 310 | return -EOPNOTSUPP; | 310 | return -EOPNOTSUPP; |
| 311 | } | 311 | } |
| 312 | if (wake) | 312 | if (wake) |
| @@ -318,7 +318,7 @@ static int pipe_rcv_created(struct sock *sk, struct sk_buff *skb) | |||
| 318 | { | 318 | { |
| 319 | struct pep_sock *pn = pep_sk(sk); | 319 | struct pep_sock *pn = pep_sk(sk); |
| 320 | struct pnpipehdr *hdr = pnp_hdr(skb); | 320 | struct pnpipehdr *hdr = pnp_hdr(skb); |
| 321 | u8 n_sb = hdr->data[0]; | 321 | u8 n_sb = hdr->data0; |
| 322 | 322 | ||
| 323 | pn->rx_fc = pn->tx_fc = PN_LEGACY_FLOW_CONTROL; | 323 | pn->rx_fc = pn->tx_fc = PN_LEGACY_FLOW_CONTROL; |
| 324 | __skb_pull(skb, sizeof(*hdr)); | 324 | __skb_pull(skb, sizeof(*hdr)); |
| @@ -506,7 +506,7 @@ static int pep_connresp_rcv(struct sock *sk, struct sk_buff *skb) | |||
| 506 | return -ECONNREFUSED; | 506 | return -ECONNREFUSED; |
| 507 | 507 | ||
| 508 | /* Parse sub-blocks */ | 508 | /* Parse sub-blocks */ |
| 509 | n_sb = hdr->data[4]; | 509 | n_sb = hdr->data[3]; |
| 510 | while (n_sb > 0) { | 510 | while (n_sb > 0) { |
| 511 | u8 type, buf[6], len = sizeof(buf); | 511 | u8 type, buf[6], len = sizeof(buf); |
| 512 | const u8 *data = pep_get_sb(skb, &type, &len, buf); | 512 | const u8 *data = pep_get_sb(skb, &type, &len, buf); |
| @@ -739,7 +739,7 @@ static int pipe_do_remove(struct sock *sk) | |||
| 739 | ph->utid = 0; | 739 | ph->utid = 0; |
| 740 | ph->message_id = PNS_PIPE_REMOVE_REQ; | 740 | ph->message_id = PNS_PIPE_REMOVE_REQ; |
| 741 | ph->pipe_handle = pn->pipe_handle; | 741 | ph->pipe_handle = pn->pipe_handle; |
| 742 | ph->data[0] = PAD; | 742 | ph->data0 = PAD; |
| 743 | return pn_skb_send(sk, skb, NULL); | 743 | return pn_skb_send(sk, skb, NULL); |
| 744 | } | 744 | } |
| 745 | 745 | ||
| @@ -817,7 +817,7 @@ static struct sock *pep_sock_accept(struct sock *sk, int flags, int *errp, | |||
| 817 | peer_type = hdr->other_pep_type << 8; | 817 | peer_type = hdr->other_pep_type << 8; |
| 818 | 818 | ||
| 819 | /* Parse sub-blocks (options) */ | 819 | /* Parse sub-blocks (options) */ |
| 820 | n_sb = hdr->data[4]; | 820 | n_sb = hdr->data[3]; |
| 821 | while (n_sb > 0) { | 821 | while (n_sb > 0) { |
| 822 | u8 type, buf[1], len = sizeof(buf); | 822 | u8 type, buf[1], len = sizeof(buf); |
| 823 | const u8 *data = pep_get_sb(skb, &type, &len, buf); | 823 | const u8 *data = pep_get_sb(skb, &type, &len, buf); |
| @@ -1109,7 +1109,7 @@ static int pipe_skb_send(struct sock *sk, struct sk_buff *skb) | |||
| 1109 | ph->utid = 0; | 1109 | ph->utid = 0; |
| 1110 | if (pn->aligned) { | 1110 | if (pn->aligned) { |
| 1111 | ph->message_id = PNS_PIPE_ALIGNED_DATA; | 1111 | ph->message_id = PNS_PIPE_ALIGNED_DATA; |
| 1112 | ph->data[0] = 0; /* padding */ | 1112 | ph->data0 = 0; /* padding */ |
| 1113 | } else | 1113 | } else |
| 1114 | ph->message_id = PNS_PIPE_DATA; | 1114 | ph->message_id = PNS_PIPE_DATA; |
| 1115 | ph->pipe_handle = pn->pipe_handle; | 1115 | ph->pipe_handle = pn->pipe_handle; |
diff --git a/net/rds/bind.c b/net/rds/bind.c index 762d2c6788a3..17c9d9f0c848 100644 --- a/net/rds/bind.c +++ b/net/rds/bind.c | |||
| @@ -78,10 +78,10 @@ struct rds_sock *rds_find_bound(const struct in6_addr *addr, __be16 port, | |||
| 78 | __rds_create_bind_key(key, addr, port, scope_id); | 78 | __rds_create_bind_key(key, addr, port, scope_id); |
| 79 | rcu_read_lock(); | 79 | rcu_read_lock(); |
| 80 | rs = rhashtable_lookup(&bind_hash_table, key, ht_parms); | 80 | rs = rhashtable_lookup(&bind_hash_table, key, ht_parms); |
| 81 | if (rs && !sock_flag(rds_rs_to_sk(rs), SOCK_DEAD)) | 81 | if (rs && (sock_flag(rds_rs_to_sk(rs), SOCK_DEAD) || |
| 82 | rds_sock_addref(rs); | 82 | !refcount_inc_not_zero(&rds_rs_to_sk(rs)->sk_refcnt))) |
| 83 | else | ||
| 84 | rs = NULL; | 83 | rs = NULL; |
| 84 | |||
| 85 | rcu_read_unlock(); | 85 | rcu_read_unlock(); |
| 86 | 86 | ||
| 87 | rdsdebug("returning rs %p for %pI6c:%u\n", rs, addr, | 87 | rdsdebug("returning rs %p for %pI6c:%u\n", rs, addr, |
diff --git a/net/rds/ib_send.c b/net/rds/ib_send.c index 2dcb555e6350..4e0c36acf866 100644 --- a/net/rds/ib_send.c +++ b/net/rds/ib_send.c | |||
| @@ -522,7 +522,7 @@ int rds_ib_xmit(struct rds_connection *conn, struct rds_message *rm, | |||
| 522 | if (be32_to_cpu(rm->m_inc.i_hdr.h_len) == 0) | 522 | if (be32_to_cpu(rm->m_inc.i_hdr.h_len) == 0) |
| 523 | i = 1; | 523 | i = 1; |
| 524 | else | 524 | else |
| 525 | i = ceil(be32_to_cpu(rm->m_inc.i_hdr.h_len), RDS_FRAG_SIZE); | 525 | i = DIV_ROUND_UP(be32_to_cpu(rm->m_inc.i_hdr.h_len), RDS_FRAG_SIZE); |
| 526 | 526 | ||
| 527 | work_alloc = rds_ib_ring_alloc(&ic->i_send_ring, i, &pos); | 527 | work_alloc = rds_ib_ring_alloc(&ic->i_send_ring, i, &pos); |
| 528 | if (work_alloc == 0) { | 528 | if (work_alloc == 0) { |
| @@ -879,7 +879,7 @@ int rds_ib_xmit_rdma(struct rds_connection *conn, struct rm_rdma_op *op) | |||
| 879 | * Instead of knowing how to return a partial rdma read/write we insist that there | 879 | * Instead of knowing how to return a partial rdma read/write we insist that there |
| 880 | * be enough work requests to send the entire message. | 880 | * be enough work requests to send the entire message. |
| 881 | */ | 881 | */ |
| 882 | i = ceil(op->op_count, max_sge); | 882 | i = DIV_ROUND_UP(op->op_count, max_sge); |
| 883 | 883 | ||
| 884 | work_alloc = rds_ib_ring_alloc(&ic->i_send_ring, i, &pos); | 884 | work_alloc = rds_ib_ring_alloc(&ic->i_send_ring, i, &pos); |
| 885 | if (work_alloc != i) { | 885 | if (work_alloc != i) { |
diff --git a/net/rds/message.c b/net/rds/message.c index f139420ba1f6..50f13f1d4ae0 100644 --- a/net/rds/message.c +++ b/net/rds/message.c | |||
| @@ -341,7 +341,7 @@ struct rds_message *rds_message_map_pages(unsigned long *page_addrs, unsigned in | |||
| 341 | { | 341 | { |
| 342 | struct rds_message *rm; | 342 | struct rds_message *rm; |
| 343 | unsigned int i; | 343 | unsigned int i; |
| 344 | int num_sgs = ceil(total_len, PAGE_SIZE); | 344 | int num_sgs = DIV_ROUND_UP(total_len, PAGE_SIZE); |
| 345 | int extra_bytes = num_sgs * sizeof(struct scatterlist); | 345 | int extra_bytes = num_sgs * sizeof(struct scatterlist); |
| 346 | int ret; | 346 | int ret; |
| 347 | 347 | ||
| @@ -351,7 +351,7 @@ struct rds_message *rds_message_map_pages(unsigned long *page_addrs, unsigned in | |||
| 351 | 351 | ||
| 352 | set_bit(RDS_MSG_PAGEVEC, &rm->m_flags); | 352 | set_bit(RDS_MSG_PAGEVEC, &rm->m_flags); |
| 353 | rm->m_inc.i_hdr.h_len = cpu_to_be32(total_len); | 353 | rm->m_inc.i_hdr.h_len = cpu_to_be32(total_len); |
| 354 | rm->data.op_nents = ceil(total_len, PAGE_SIZE); | 354 | rm->data.op_nents = DIV_ROUND_UP(total_len, PAGE_SIZE); |
| 355 | rm->data.op_sg = rds_message_alloc_sgs(rm, num_sgs, &ret); | 355 | rm->data.op_sg = rds_message_alloc_sgs(rm, num_sgs, &ret); |
| 356 | if (!rm->data.op_sg) { | 356 | if (!rm->data.op_sg) { |
| 357 | rds_message_put(rm); | 357 | rds_message_put(rm); |
diff --git a/net/rds/rds.h b/net/rds/rds.h index 02ec4a3b2799..4ffe100ff5e6 100644 --- a/net/rds/rds.h +++ b/net/rds/rds.h | |||
| @@ -48,10 +48,6 @@ void rdsdebug(char *fmt, ...) | |||
| 48 | } | 48 | } |
| 49 | #endif | 49 | #endif |
| 50 | 50 | ||
| 51 | /* XXX is there one of these somewhere? */ | ||
| 52 | #define ceil(x, y) \ | ||
| 53 | ({ unsigned long __x = (x), __y = (y); (__x + __y - 1) / __y; }) | ||
| 54 | |||
| 55 | #define RDS_FRAG_SHIFT 12 | 51 | #define RDS_FRAG_SHIFT 12 |
| 56 | #define RDS_FRAG_SIZE ((unsigned int)(1 << RDS_FRAG_SHIFT)) | 52 | #define RDS_FRAG_SIZE ((unsigned int)(1 << RDS_FRAG_SHIFT)) |
| 57 | 53 | ||
diff --git a/net/rds/send.c b/net/rds/send.c index 3d822bad7de9..fd8b687d5c05 100644 --- a/net/rds/send.c +++ b/net/rds/send.c | |||
| @@ -1107,7 +1107,7 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len) | |||
| 1107 | size_t total_payload_len = payload_len, rdma_payload_len = 0; | 1107 | size_t total_payload_len = payload_len, rdma_payload_len = 0; |
| 1108 | bool zcopy = ((msg->msg_flags & MSG_ZEROCOPY) && | 1108 | bool zcopy = ((msg->msg_flags & MSG_ZEROCOPY) && |
| 1109 | sock_flag(rds_rs_to_sk(rs), SOCK_ZEROCOPY)); | 1109 | sock_flag(rds_rs_to_sk(rs), SOCK_ZEROCOPY)); |
| 1110 | int num_sgs = ceil(payload_len, PAGE_SIZE); | 1110 | int num_sgs = DIV_ROUND_UP(payload_len, PAGE_SIZE); |
| 1111 | int namelen; | 1111 | int namelen; |
| 1112 | struct rds_iov_vector_arr vct; | 1112 | struct rds_iov_vector_arr vct; |
| 1113 | int ind; | 1113 | int ind; |
diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c index 77e9f85a2c92..f2ff21d7df08 100644 --- a/net/rose/rose_route.c +++ b/net/rose/rose_route.c | |||
| @@ -850,6 +850,7 @@ void rose_link_device_down(struct net_device *dev) | |||
| 850 | 850 | ||
| 851 | /* | 851 | /* |
| 852 | * Route a frame to an appropriate AX.25 connection. | 852 | * Route a frame to an appropriate AX.25 connection. |
| 853 | * A NULL ax25_cb indicates an internally generated frame. | ||
| 853 | */ | 854 | */ |
| 854 | int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25) | 855 | int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25) |
| 855 | { | 856 | { |
| @@ -867,6 +868,10 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25) | |||
| 867 | 868 | ||
| 868 | if (skb->len < ROSE_MIN_LEN) | 869 | if (skb->len < ROSE_MIN_LEN) |
| 869 | return res; | 870 | return res; |
| 871 | |||
| 872 | if (!ax25) | ||
| 873 | return rose_loopback_queue(skb, NULL); | ||
| 874 | |||
| 870 | frametype = skb->data[2]; | 875 | frametype = skb->data[2]; |
| 871 | lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF); | 876 | lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF); |
| 872 | if (frametype == ROSE_CALL_REQUEST && | 877 | if (frametype == ROSE_CALL_REQUEST && |
diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c index a2522f9d71e2..96f2952bbdfd 100644 --- a/net/rxrpc/af_rxrpc.c +++ b/net/rxrpc/af_rxrpc.c | |||
| @@ -419,76 +419,6 @@ u32 rxrpc_kernel_get_epoch(struct socket *sock, struct rxrpc_call *call) | |||
| 419 | EXPORT_SYMBOL(rxrpc_kernel_get_epoch); | 419 | EXPORT_SYMBOL(rxrpc_kernel_get_epoch); |
| 420 | 420 | ||
| 421 | /** | 421 | /** |
| 422 | * rxrpc_kernel_check_call - Check a call's state | ||
| 423 | * @sock: The socket the call is on | ||
| 424 | * @call: The call to check | ||
| 425 | * @_compl: Where to store the completion state | ||
| 426 | * @_abort_code: Where to store any abort code | ||
| 427 | * | ||
| 428 | * Allow a kernel service to query the state of a call and find out the manner | ||
| 429 | * of its termination if it has completed. Returns -EINPROGRESS if the call is | ||
| 430 | * still going, 0 if the call finished successfully, -ECONNABORTED if the call | ||
| 431 | * was aborted and an appropriate error if the call failed in some other way. | ||
| 432 | */ | ||
| 433 | int rxrpc_kernel_check_call(struct socket *sock, struct rxrpc_call *call, | ||
| 434 | enum rxrpc_call_completion *_compl, u32 *_abort_code) | ||
| 435 | { | ||
| 436 | if (call->state != RXRPC_CALL_COMPLETE) | ||
| 437 | return -EINPROGRESS; | ||
| 438 | smp_rmb(); | ||
| 439 | *_compl = call->completion; | ||
| 440 | *_abort_code = call->abort_code; | ||
| 441 | return call->error; | ||
| 442 | } | ||
| 443 | EXPORT_SYMBOL(rxrpc_kernel_check_call); | ||
| 444 | |||
| 445 | /** | ||
| 446 | * rxrpc_kernel_retry_call - Allow a kernel service to retry a call | ||
| 447 | * @sock: The socket the call is on | ||
| 448 | * @call: The call to retry | ||
| 449 | * @srx: The address of the peer to contact | ||
| 450 | * @key: The security context to use (defaults to socket setting) | ||
| 451 | * | ||
| 452 | * Allow a kernel service to try resending a client call that failed due to a | ||
| 453 | * network error to a new address. The Tx queue is maintained intact, thereby | ||
| 454 | * relieving the need to re-encrypt any request data that has already been | ||
| 455 | * buffered. | ||
| 456 | */ | ||
| 457 | int rxrpc_kernel_retry_call(struct socket *sock, struct rxrpc_call *call, | ||
| 458 | struct sockaddr_rxrpc *srx, struct key *key) | ||
| 459 | { | ||
| 460 | struct rxrpc_conn_parameters cp; | ||
| 461 | struct rxrpc_sock *rx = rxrpc_sk(sock->sk); | ||
| 462 | int ret; | ||
| 463 | |||
| 464 | _enter("%d{%d}", call->debug_id, atomic_read(&call->usage)); | ||
| 465 | |||
| 466 | if (!key) | ||
| 467 | key = rx->key; | ||
| 468 | if (key && !key->payload.data[0]) | ||
| 469 | key = NULL; /* a no-security key */ | ||
| 470 | |||
| 471 | memset(&cp, 0, sizeof(cp)); | ||
| 472 | cp.local = rx->local; | ||
| 473 | cp.key = key; | ||
| 474 | cp.security_level = 0; | ||
| 475 | cp.exclusive = false; | ||
| 476 | cp.service_id = srx->srx_service; | ||
| 477 | |||
| 478 | mutex_lock(&call->user_mutex); | ||
| 479 | |||
| 480 | ret = rxrpc_prepare_call_for_retry(rx, call); | ||
| 481 | if (ret == 0) | ||
| 482 | ret = rxrpc_retry_client_call(rx, call, &cp, srx, GFP_KERNEL); | ||
| 483 | |||
| 484 | mutex_unlock(&call->user_mutex); | ||
| 485 | rxrpc_put_peer(cp.peer); | ||
| 486 | _leave(" = %d", ret); | ||
| 487 | return ret; | ||
| 488 | } | ||
| 489 | EXPORT_SYMBOL(rxrpc_kernel_retry_call); | ||
| 490 | |||
| 491 | /** | ||
| 492 | * rxrpc_kernel_new_call_notification - Get notifications of new calls | 422 | * rxrpc_kernel_new_call_notification - Get notifications of new calls |
| 493 | * @sock: The socket to intercept received messages on | 423 | * @sock: The socket to intercept received messages on |
| 494 | * @notify_new_call: Function to be called when new calls appear | 424 | * @notify_new_call: Function to be called when new calls appear |
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index bc628acf4f4f..4b1a534d290a 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h | |||
| @@ -476,7 +476,6 @@ enum rxrpc_call_flag { | |||
| 476 | RXRPC_CALL_EXPOSED, /* The call was exposed to the world */ | 476 | RXRPC_CALL_EXPOSED, /* The call was exposed to the world */ |
| 477 | RXRPC_CALL_RX_LAST, /* Received the last packet (at rxtx_top) */ | 477 | RXRPC_CALL_RX_LAST, /* Received the last packet (at rxtx_top) */ |
| 478 | RXRPC_CALL_TX_LAST, /* Last packet in Tx buffer (at rxtx_top) */ | 478 | RXRPC_CALL_TX_LAST, /* Last packet in Tx buffer (at rxtx_top) */ |
| 479 | RXRPC_CALL_TX_LASTQ, /* Last packet has been queued */ | ||
| 480 | RXRPC_CALL_SEND_PING, /* A ping will need to be sent */ | 479 | RXRPC_CALL_SEND_PING, /* A ping will need to be sent */ |
| 481 | RXRPC_CALL_PINGING, /* Ping in process */ | 480 | RXRPC_CALL_PINGING, /* Ping in process */ |
| 482 | RXRPC_CALL_RETRANS_TIMEOUT, /* Retransmission due to timeout occurred */ | 481 | RXRPC_CALL_RETRANS_TIMEOUT, /* Retransmission due to timeout occurred */ |
| @@ -518,6 +517,18 @@ enum rxrpc_call_state { | |||
| 518 | }; | 517 | }; |
| 519 | 518 | ||
| 520 | /* | 519 | /* |
| 520 | * Call completion condition (state == RXRPC_CALL_COMPLETE). | ||
| 521 | */ | ||
| 522 | enum rxrpc_call_completion { | ||
| 523 | RXRPC_CALL_SUCCEEDED, /* - Normal termination */ | ||
| 524 | RXRPC_CALL_REMOTELY_ABORTED, /* - call aborted by peer */ | ||
| 525 | RXRPC_CALL_LOCALLY_ABORTED, /* - call aborted locally on error or close */ | ||
| 526 | RXRPC_CALL_LOCAL_ERROR, /* - call failed due to local error */ | ||
| 527 | RXRPC_CALL_NETWORK_ERROR, /* - call terminated by network error */ | ||
| 528 | NR__RXRPC_CALL_COMPLETIONS | ||
| 529 | }; | ||
| 530 | |||
| 531 | /* | ||
| 521 | * Call Tx congestion management modes. | 532 | * Call Tx congestion management modes. |
| 522 | */ | 533 | */ |
| 523 | enum rxrpc_congest_mode { | 534 | enum rxrpc_congest_mode { |
| @@ -761,15 +772,9 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *, | |||
| 761 | struct sockaddr_rxrpc *, | 772 | struct sockaddr_rxrpc *, |
| 762 | struct rxrpc_call_params *, gfp_t, | 773 | struct rxrpc_call_params *, gfp_t, |
| 763 | unsigned int); | 774 | unsigned int); |
| 764 | int rxrpc_retry_client_call(struct rxrpc_sock *, | ||
| 765 | struct rxrpc_call *, | ||
| 766 | struct rxrpc_conn_parameters *, | ||
| 767 | struct sockaddr_rxrpc *, | ||
| 768 | gfp_t); | ||
| 769 | void rxrpc_incoming_call(struct rxrpc_sock *, struct rxrpc_call *, | 775 | void rxrpc_incoming_call(struct rxrpc_sock *, struct rxrpc_call *, |
| 770 | struct sk_buff *); | 776 | struct sk_buff *); |
| 771 | void rxrpc_release_call(struct rxrpc_sock *, struct rxrpc_call *); | 777 | void rxrpc_release_call(struct rxrpc_sock *, struct rxrpc_call *); |
| 772 | int rxrpc_prepare_call_for_retry(struct rxrpc_sock *, struct rxrpc_call *); | ||
| 773 | void rxrpc_release_calls_on_socket(struct rxrpc_sock *); | 778 | void rxrpc_release_calls_on_socket(struct rxrpc_sock *); |
| 774 | bool __rxrpc_queue_call(struct rxrpc_call *); | 779 | bool __rxrpc_queue_call(struct rxrpc_call *); |
| 775 | bool rxrpc_queue_call(struct rxrpc_call *); | 780 | bool rxrpc_queue_call(struct rxrpc_call *); |
diff --git a/net/rxrpc/call_object.c b/net/rxrpc/call_object.c index 8f1a8f85b1f9..8aa2937b069f 100644 --- a/net/rxrpc/call_object.c +++ b/net/rxrpc/call_object.c | |||
| @@ -325,48 +325,6 @@ error: | |||
| 325 | } | 325 | } |
| 326 | 326 | ||
| 327 | /* | 327 | /* |
| 328 | * Retry a call to a new address. It is expected that the Tx queue of the call | ||
| 329 | * will contain data previously packaged for an old call. | ||
| 330 | */ | ||
| 331 | int rxrpc_retry_client_call(struct rxrpc_sock *rx, | ||
| 332 | struct rxrpc_call *call, | ||
| 333 | struct rxrpc_conn_parameters *cp, | ||
| 334 | struct sockaddr_rxrpc *srx, | ||
| 335 | gfp_t gfp) | ||
| 336 | { | ||
| 337 | const void *here = __builtin_return_address(0); | ||
| 338 | int ret; | ||
| 339 | |||
| 340 | /* Set up or get a connection record and set the protocol parameters, | ||
| 341 | * including channel number and call ID. | ||
| 342 | */ | ||
| 343 | ret = rxrpc_connect_call(rx, call, cp, srx, gfp); | ||
| 344 | if (ret < 0) | ||
| 345 | goto error; | ||
| 346 | |||
| 347 | trace_rxrpc_call(call, rxrpc_call_connected, atomic_read(&call->usage), | ||
| 348 | here, NULL); | ||
| 349 | |||
| 350 | rxrpc_start_call_timer(call); | ||
| 351 | |||
| 352 | _net("CALL new %d on CONN %d", call->debug_id, call->conn->debug_id); | ||
| 353 | |||
| 354 | if (!test_and_set_bit(RXRPC_CALL_EV_RESEND, &call->events)) | ||
| 355 | rxrpc_queue_call(call); | ||
| 356 | |||
| 357 | _leave(" = 0"); | ||
| 358 | return 0; | ||
| 359 | |||
| 360 | error: | ||
| 361 | rxrpc_set_call_completion(call, RXRPC_CALL_LOCAL_ERROR, | ||
| 362 | RX_CALL_DEAD, ret); | ||
| 363 | trace_rxrpc_call(call, rxrpc_call_error, atomic_read(&call->usage), | ||
| 364 | here, ERR_PTR(ret)); | ||
| 365 | _leave(" = %d", ret); | ||
| 366 | return ret; | ||
| 367 | } | ||
| 368 | |||
| 369 | /* | ||
| 370 | * Set up an incoming call. call->conn points to the connection. | 328 | * Set up an incoming call. call->conn points to the connection. |
| 371 | * This is called in BH context and isn't allowed to fail. | 329 | * This is called in BH context and isn't allowed to fail. |
| 372 | */ | 330 | */ |
| @@ -534,61 +492,6 @@ void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call) | |||
| 534 | } | 492 | } |
| 535 | 493 | ||
| 536 | /* | 494 | /* |
| 537 | * Prepare a kernel service call for retry. | ||
| 538 | */ | ||
| 539 | int rxrpc_prepare_call_for_retry(struct rxrpc_sock *rx, struct rxrpc_call *call) | ||
| 540 | { | ||
| 541 | const void *here = __builtin_return_address(0); | ||
| 542 | int i; | ||
| 543 | u8 last = 0; | ||
| 544 | |||
| 545 | _enter("{%d,%d}", call->debug_id, atomic_read(&call->usage)); | ||
| 546 | |||
| 547 | trace_rxrpc_call(call, rxrpc_call_release, atomic_read(&call->usage), | ||
| 548 | here, (const void *)call->flags); | ||
| 549 | |||
| 550 | ASSERTCMP(call->state, ==, RXRPC_CALL_COMPLETE); | ||
| 551 | ASSERTCMP(call->completion, !=, RXRPC_CALL_REMOTELY_ABORTED); | ||
| 552 | ASSERTCMP(call->completion, !=, RXRPC_CALL_LOCALLY_ABORTED); | ||
| 553 | ASSERT(list_empty(&call->recvmsg_link)); | ||
| 554 | |||
| 555 | del_timer_sync(&call->timer); | ||
| 556 | |||
| 557 | _debug("RELEASE CALL %p (%d CONN %p)", call, call->debug_id, call->conn); | ||
| 558 | |||
| 559 | if (call->conn) | ||
| 560 | rxrpc_disconnect_call(call); | ||
| 561 | |||
| 562 | if (rxrpc_is_service_call(call) || | ||
| 563 | !call->tx_phase || | ||
| 564 | call->tx_hard_ack != 0 || | ||
| 565 | call->rx_hard_ack != 0 || | ||
| 566 | call->rx_top != 0) | ||
| 567 | return -EINVAL; | ||
| 568 | |||
| 569 | call->state = RXRPC_CALL_UNINITIALISED; | ||
| 570 | call->completion = RXRPC_CALL_SUCCEEDED; | ||
| 571 | call->call_id = 0; | ||
| 572 | call->cid = 0; | ||
| 573 | call->cong_cwnd = 0; | ||
| 574 | call->cong_extra = 0; | ||
| 575 | call->cong_ssthresh = 0; | ||
| 576 | call->cong_mode = 0; | ||
| 577 | call->cong_dup_acks = 0; | ||
| 578 | call->cong_cumul_acks = 0; | ||
| 579 | call->acks_lowest_nak = 0; | ||
| 580 | |||
| 581 | for (i = 0; i < RXRPC_RXTX_BUFF_SIZE; i++) { | ||
| 582 | last |= call->rxtx_annotations[i]; | ||
| 583 | call->rxtx_annotations[i] &= RXRPC_TX_ANNO_LAST; | ||
| 584 | call->rxtx_annotations[i] |= RXRPC_TX_ANNO_RETRANS; | ||
| 585 | } | ||
| 586 | |||
| 587 | _leave(" = 0"); | ||
| 588 | return 0; | ||
| 589 | } | ||
| 590 | |||
| 591 | /* | ||
| 592 | * release all the calls associated with a socket | 495 | * release all the calls associated with a socket |
| 593 | */ | 496 | */ |
| 594 | void rxrpc_release_calls_on_socket(struct rxrpc_sock *rx) | 497 | void rxrpc_release_calls_on_socket(struct rxrpc_sock *rx) |
diff --git a/net/rxrpc/conn_client.c b/net/rxrpc/conn_client.c index 521189f4b666..b2adfa825363 100644 --- a/net/rxrpc/conn_client.c +++ b/net/rxrpc/conn_client.c | |||
| @@ -562,10 +562,7 @@ static void rxrpc_activate_one_channel(struct rxrpc_connection *conn, | |||
| 562 | clear_bit(RXRPC_CONN_FINAL_ACK_0 + channel, &conn->flags); | 562 | clear_bit(RXRPC_CONN_FINAL_ACK_0 + channel, &conn->flags); |
| 563 | 563 | ||
| 564 | write_lock_bh(&call->state_lock); | 564 | write_lock_bh(&call->state_lock); |
| 565 | if (!test_bit(RXRPC_CALL_TX_LASTQ, &call->flags)) | 565 | call->state = RXRPC_CALL_CLIENT_SEND_REQUEST; |
| 566 | call->state = RXRPC_CALL_CLIENT_SEND_REQUEST; | ||
| 567 | else | ||
| 568 | call->state = RXRPC_CALL_CLIENT_AWAIT_REPLY; | ||
| 569 | write_unlock_bh(&call->state_lock); | 566 | write_unlock_bh(&call->state_lock); |
| 570 | 567 | ||
| 571 | rxrpc_see_call(call); | 568 | rxrpc_see_call(call); |
diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c index eaf19ebaa964..3f7bb11f3290 100644 --- a/net/rxrpc/recvmsg.c +++ b/net/rxrpc/recvmsg.c | |||
| @@ -596,6 +596,7 @@ error_requeue_call: | |||
| 596 | } | 596 | } |
| 597 | error_no_call: | 597 | error_no_call: |
| 598 | release_sock(&rx->sk); | 598 | release_sock(&rx->sk); |
| 599 | error_trace: | ||
| 599 | trace_rxrpc_recvmsg(call, rxrpc_recvmsg_return, 0, 0, 0, ret); | 600 | trace_rxrpc_recvmsg(call, rxrpc_recvmsg_return, 0, 0, 0, ret); |
| 600 | return ret; | 601 | return ret; |
| 601 | 602 | ||
| @@ -604,7 +605,7 @@ wait_interrupted: | |||
| 604 | wait_error: | 605 | wait_error: |
| 605 | finish_wait(sk_sleep(&rx->sk), &wait); | 606 | finish_wait(sk_sleep(&rx->sk), &wait); |
| 606 | call = NULL; | 607 | call = NULL; |
| 607 | goto error_no_call; | 608 | goto error_trace; |
| 608 | } | 609 | } |
| 609 | 610 | ||
| 610 | /** | 611 | /** |
diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c index be01f9c5d963..46c9312085b1 100644 --- a/net/rxrpc/sendmsg.c +++ b/net/rxrpc/sendmsg.c | |||
| @@ -169,10 +169,8 @@ static void rxrpc_queue_packet(struct rxrpc_sock *rx, struct rxrpc_call *call, | |||
| 169 | 169 | ||
| 170 | ASSERTCMP(seq, ==, call->tx_top + 1); | 170 | ASSERTCMP(seq, ==, call->tx_top + 1); |
| 171 | 171 | ||
| 172 | if (last) { | 172 | if (last) |
| 173 | annotation |= RXRPC_TX_ANNO_LAST; | 173 | annotation |= RXRPC_TX_ANNO_LAST; |
| 174 | set_bit(RXRPC_CALL_TX_LASTQ, &call->flags); | ||
| 175 | } | ||
| 176 | 174 | ||
| 177 | /* We have to set the timestamp before queueing as the retransmit | 175 | /* We have to set the timestamp before queueing as the retransmit |
| 178 | * algorithm can see the packet as soon as we queue it. | 176 | * algorithm can see the packet as soon as we queue it. |
| @@ -386,6 +384,11 @@ static int rxrpc_send_data(struct rxrpc_sock *rx, | |||
| 386 | call->tx_total_len -= copy; | 384 | call->tx_total_len -= copy; |
| 387 | } | 385 | } |
| 388 | 386 | ||
| 387 | /* check for the far side aborting the call or a network error | ||
| 388 | * occurring */ | ||
| 389 | if (call->state == RXRPC_CALL_COMPLETE) | ||
| 390 | goto call_terminated; | ||
| 391 | |||
| 389 | /* add the packet to the send queue if it's now full */ | 392 | /* add the packet to the send queue if it's now full */ |
| 390 | if (sp->remain <= 0 || | 393 | if (sp->remain <= 0 || |
| 391 | (msg_data_left(msg) == 0 && !more)) { | 394 | (msg_data_left(msg) == 0 && !more)) { |
| @@ -425,16 +428,6 @@ static int rxrpc_send_data(struct rxrpc_sock *rx, | |||
| 425 | notify_end_tx); | 428 | notify_end_tx); |
| 426 | skb = NULL; | 429 | skb = NULL; |
| 427 | } | 430 | } |
| 428 | |||
| 429 | /* Check for the far side aborting the call or a network error | ||
| 430 | * occurring. If this happens, save any packet that was under | ||
| 431 | * construction so that in the case of a network error, the | ||
| 432 | * call can be retried or redirected. | ||
| 433 | */ | ||
| 434 | if (call->state == RXRPC_CALL_COMPLETE) { | ||
| 435 | ret = call->error; | ||
| 436 | goto out; | ||
| 437 | } | ||
| 438 | } while (msg_data_left(msg) > 0); | 431 | } while (msg_data_left(msg) > 0); |
| 439 | 432 | ||
| 440 | success: | 433 | success: |
| @@ -444,6 +437,11 @@ out: | |||
| 444 | _leave(" = %d", ret); | 437 | _leave(" = %d", ret); |
| 445 | return ret; | 438 | return ret; |
| 446 | 439 | ||
| 440 | call_terminated: | ||
| 441 | rxrpc_free_skb(skb, rxrpc_skb_tx_freed); | ||
| 442 | _leave(" = %d", call->error); | ||
| 443 | return call->error; | ||
| 444 | |||
| 447 | maybe_error: | 445 | maybe_error: |
| 448 | if (copied) | 446 | if (copied) |
| 449 | goto success; | 447 | goto success; |
diff --git a/net/sched/act_tunnel_key.c b/net/sched/act_tunnel_key.c index c3b90fadaff6..8b43fe0130f7 100644 --- a/net/sched/act_tunnel_key.c +++ b/net/sched/act_tunnel_key.c | |||
| @@ -197,6 +197,15 @@ static const struct nla_policy tunnel_key_policy[TCA_TUNNEL_KEY_MAX + 1] = { | |||
| 197 | [TCA_TUNNEL_KEY_ENC_TTL] = { .type = NLA_U8 }, | 197 | [TCA_TUNNEL_KEY_ENC_TTL] = { .type = NLA_U8 }, |
| 198 | }; | 198 | }; |
| 199 | 199 | ||
| 200 | static void tunnel_key_release_params(struct tcf_tunnel_key_params *p) | ||
| 201 | { | ||
| 202 | if (!p) | ||
| 203 | return; | ||
| 204 | if (p->tcft_action == TCA_TUNNEL_KEY_ACT_SET) | ||
| 205 | dst_release(&p->tcft_enc_metadata->dst); | ||
| 206 | kfree_rcu(p, rcu); | ||
| 207 | } | ||
| 208 | |||
| 200 | static int tunnel_key_init(struct net *net, struct nlattr *nla, | 209 | static int tunnel_key_init(struct net *net, struct nlattr *nla, |
| 201 | struct nlattr *est, struct tc_action **a, | 210 | struct nlattr *est, struct tc_action **a, |
| 202 | int ovr, int bind, bool rtnl_held, | 211 | int ovr, int bind, bool rtnl_held, |
| @@ -360,8 +369,7 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla, | |||
| 360 | rcu_swap_protected(t->params, params_new, | 369 | rcu_swap_protected(t->params, params_new, |
| 361 | lockdep_is_held(&t->tcf_lock)); | 370 | lockdep_is_held(&t->tcf_lock)); |
| 362 | spin_unlock_bh(&t->tcf_lock); | 371 | spin_unlock_bh(&t->tcf_lock); |
| 363 | if (params_new) | 372 | tunnel_key_release_params(params_new); |
| 364 | kfree_rcu(params_new, rcu); | ||
| 365 | 373 | ||
| 366 | if (ret == ACT_P_CREATED) | 374 | if (ret == ACT_P_CREATED) |
| 367 | tcf_idr_insert(tn, *a); | 375 | tcf_idr_insert(tn, *a); |
| @@ -385,12 +393,7 @@ static void tunnel_key_release(struct tc_action *a) | |||
| 385 | struct tcf_tunnel_key_params *params; | 393 | struct tcf_tunnel_key_params *params; |
| 386 | 394 | ||
| 387 | params = rcu_dereference_protected(t->params, 1); | 395 | params = rcu_dereference_protected(t->params, 1); |
| 388 | if (params) { | 396 | tunnel_key_release_params(params); |
| 389 | if (params->tcft_action == TCA_TUNNEL_KEY_ACT_SET) | ||
| 390 | dst_release(¶ms->tcft_enc_metadata->dst); | ||
| 391 | |||
| 392 | kfree_rcu(params, rcu); | ||
| 393 | } | ||
| 394 | } | 397 | } |
| 395 | 398 | ||
| 396 | static int tunnel_key_geneve_opts_dump(struct sk_buff *skb, | 399 | static int tunnel_key_geneve_opts_dump(struct sk_buff *skb, |
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 8ce2a0507970..e2b5cb2eb34e 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c | |||
| @@ -1277,7 +1277,6 @@ EXPORT_SYMBOL(tcf_block_cb_unregister); | |||
| 1277 | int tcf_classify(struct sk_buff *skb, const struct tcf_proto *tp, | 1277 | int tcf_classify(struct sk_buff *skb, const struct tcf_proto *tp, |
| 1278 | struct tcf_result *res, bool compat_mode) | 1278 | struct tcf_result *res, bool compat_mode) |
| 1279 | { | 1279 | { |
| 1280 | __be16 protocol = tc_skb_protocol(skb); | ||
| 1281 | #ifdef CONFIG_NET_CLS_ACT | 1280 | #ifdef CONFIG_NET_CLS_ACT |
| 1282 | const int max_reclassify_loop = 4; | 1281 | const int max_reclassify_loop = 4; |
| 1283 | const struct tcf_proto *orig_tp = tp; | 1282 | const struct tcf_proto *orig_tp = tp; |
| @@ -1287,6 +1286,7 @@ int tcf_classify(struct sk_buff *skb, const struct tcf_proto *tp, | |||
| 1287 | reclassify: | 1286 | reclassify: |
| 1288 | #endif | 1287 | #endif |
| 1289 | for (; tp; tp = rcu_dereference_bh(tp->next)) { | 1288 | for (; tp; tp = rcu_dereference_bh(tp->next)) { |
| 1289 | __be16 protocol = tc_skb_protocol(skb); | ||
| 1290 | int err; | 1290 | int err; |
| 1291 | 1291 | ||
| 1292 | if (tp->protocol != protocol && | 1292 | if (tp->protocol != protocol && |
| @@ -1319,7 +1319,6 @@ reset: | |||
| 1319 | } | 1319 | } |
| 1320 | 1320 | ||
| 1321 | tp = first_tp; | 1321 | tp = first_tp; |
| 1322 | protocol = tc_skb_protocol(skb); | ||
| 1323 | goto reclassify; | 1322 | goto reclassify; |
| 1324 | #endif | 1323 | #endif |
| 1325 | } | 1324 | } |
diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c index dad04e710493..12ca9d13db83 100644 --- a/net/sched/cls_flower.c +++ b/net/sched/cls_flower.c | |||
| @@ -1290,17 +1290,23 @@ static int fl_change(struct net *net, struct sk_buff *in_skb, | |||
| 1290 | struct cls_fl_head *head = rtnl_dereference(tp->root); | 1290 | struct cls_fl_head *head = rtnl_dereference(tp->root); |
| 1291 | struct cls_fl_filter *fold = *arg; | 1291 | struct cls_fl_filter *fold = *arg; |
| 1292 | struct cls_fl_filter *fnew; | 1292 | struct cls_fl_filter *fnew; |
| 1293 | struct fl_flow_mask *mask; | ||
| 1293 | struct nlattr **tb; | 1294 | struct nlattr **tb; |
| 1294 | struct fl_flow_mask mask = {}; | ||
| 1295 | int err; | 1295 | int err; |
| 1296 | 1296 | ||
| 1297 | if (!tca[TCA_OPTIONS]) | 1297 | if (!tca[TCA_OPTIONS]) |
| 1298 | return -EINVAL; | 1298 | return -EINVAL; |
| 1299 | 1299 | ||
| 1300 | tb = kcalloc(TCA_FLOWER_MAX + 1, sizeof(struct nlattr *), GFP_KERNEL); | 1300 | mask = kzalloc(sizeof(struct fl_flow_mask), GFP_KERNEL); |
| 1301 | if (!tb) | 1301 | if (!mask) |
| 1302 | return -ENOBUFS; | 1302 | return -ENOBUFS; |
| 1303 | 1303 | ||
| 1304 | tb = kcalloc(TCA_FLOWER_MAX + 1, sizeof(struct nlattr *), GFP_KERNEL); | ||
| 1305 | if (!tb) { | ||
| 1306 | err = -ENOBUFS; | ||
| 1307 | goto errout_mask_alloc; | ||
| 1308 | } | ||
| 1309 | |||
| 1304 | err = nla_parse_nested(tb, TCA_FLOWER_MAX, tca[TCA_OPTIONS], | 1310 | err = nla_parse_nested(tb, TCA_FLOWER_MAX, tca[TCA_OPTIONS], |
| 1305 | fl_policy, NULL); | 1311 | fl_policy, NULL); |
| 1306 | if (err < 0) | 1312 | if (err < 0) |
| @@ -1343,12 +1349,12 @@ static int fl_change(struct net *net, struct sk_buff *in_skb, | |||
| 1343 | } | 1349 | } |
| 1344 | } | 1350 | } |
| 1345 | 1351 | ||
| 1346 | err = fl_set_parms(net, tp, fnew, &mask, base, tb, tca[TCA_RATE], ovr, | 1352 | err = fl_set_parms(net, tp, fnew, mask, base, tb, tca[TCA_RATE], ovr, |
| 1347 | tp->chain->tmplt_priv, extack); | 1353 | tp->chain->tmplt_priv, extack); |
| 1348 | if (err) | 1354 | if (err) |
| 1349 | goto errout_idr; | 1355 | goto errout_idr; |
| 1350 | 1356 | ||
| 1351 | err = fl_check_assign_mask(head, fnew, fold, &mask); | 1357 | err = fl_check_assign_mask(head, fnew, fold, mask); |
| 1352 | if (err) | 1358 | if (err) |
| 1353 | goto errout_idr; | 1359 | goto errout_idr; |
| 1354 | 1360 | ||
| @@ -1365,7 +1371,7 @@ static int fl_change(struct net *net, struct sk_buff *in_skb, | |||
| 1365 | if (!tc_skip_hw(fnew->flags)) { | 1371 | if (!tc_skip_hw(fnew->flags)) { |
| 1366 | err = fl_hw_replace_filter(tp, fnew, extack); | 1372 | err = fl_hw_replace_filter(tp, fnew, extack); |
| 1367 | if (err) | 1373 | if (err) |
| 1368 | goto errout_mask; | 1374 | goto errout_mask_ht; |
| 1369 | } | 1375 | } |
| 1370 | 1376 | ||
| 1371 | if (!tc_in_hw(fnew->flags)) | 1377 | if (!tc_in_hw(fnew->flags)) |
| @@ -1392,8 +1398,13 @@ static int fl_change(struct net *net, struct sk_buff *in_skb, | |||
| 1392 | } | 1398 | } |
| 1393 | 1399 | ||
| 1394 | kfree(tb); | 1400 | kfree(tb); |
| 1401 | kfree(mask); | ||
| 1395 | return 0; | 1402 | return 0; |
| 1396 | 1403 | ||
| 1404 | errout_mask_ht: | ||
| 1405 | rhashtable_remove_fast(&fnew->mask->ht, &fnew->ht_node, | ||
| 1406 | fnew->mask->filter_ht_params); | ||
| 1407 | |||
| 1397 | errout_mask: | 1408 | errout_mask: |
| 1398 | fl_mask_put(head, fnew->mask, false); | 1409 | fl_mask_put(head, fnew->mask, false); |
| 1399 | 1410 | ||
| @@ -1405,6 +1416,8 @@ errout: | |||
| 1405 | kfree(fnew); | 1416 | kfree(fnew); |
| 1406 | errout_tb: | 1417 | errout_tb: |
| 1407 | kfree(tb); | 1418 | kfree(tb); |
| 1419 | errout_mask_alloc: | ||
| 1420 | kfree(mask); | ||
| 1408 | return err; | 1421 | return err; |
| 1409 | } | 1422 | } |
| 1410 | 1423 | ||
diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c index 9ccc93f257db..38bb882bb958 100644 --- a/net/sched/cls_tcindex.c +++ b/net/sched/cls_tcindex.c | |||
| @@ -48,7 +48,7 @@ struct tcindex_data { | |||
| 48 | u32 hash; /* hash table size; 0 if undefined */ | 48 | u32 hash; /* hash table size; 0 if undefined */ |
| 49 | u32 alloc_hash; /* allocated size */ | 49 | u32 alloc_hash; /* allocated size */ |
| 50 | u32 fall_through; /* 0: only classify if explicit match */ | 50 | u32 fall_through; /* 0: only classify if explicit match */ |
| 51 | struct rcu_head rcu; | 51 | struct rcu_work rwork; |
| 52 | }; | 52 | }; |
| 53 | 53 | ||
| 54 | static inline int tcindex_filter_is_set(struct tcindex_filter_result *r) | 54 | static inline int tcindex_filter_is_set(struct tcindex_filter_result *r) |
| @@ -221,17 +221,11 @@ found: | |||
| 221 | return 0; | 221 | return 0; |
| 222 | } | 222 | } |
| 223 | 223 | ||
| 224 | static int tcindex_destroy_element(struct tcf_proto *tp, | 224 | static void tcindex_destroy_work(struct work_struct *work) |
| 225 | void *arg, struct tcf_walker *walker) | ||
| 226 | { | ||
| 227 | bool last; | ||
| 228 | |||
| 229 | return tcindex_delete(tp, arg, &last, NULL); | ||
| 230 | } | ||
| 231 | |||
| 232 | static void __tcindex_destroy(struct rcu_head *head) | ||
| 233 | { | 225 | { |
| 234 | struct tcindex_data *p = container_of(head, struct tcindex_data, rcu); | 226 | struct tcindex_data *p = container_of(to_rcu_work(work), |
| 227 | struct tcindex_data, | ||
| 228 | rwork); | ||
| 235 | 229 | ||
| 236 | kfree(p->perfect); | 230 | kfree(p->perfect); |
| 237 | kfree(p->h); | 231 | kfree(p->h); |
| @@ -258,9 +252,11 @@ static int tcindex_filter_result_init(struct tcindex_filter_result *r) | |||
| 258 | return tcf_exts_init(&r->exts, TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE); | 252 | return tcf_exts_init(&r->exts, TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE); |
| 259 | } | 253 | } |
| 260 | 254 | ||
| 261 | static void __tcindex_partial_destroy(struct rcu_head *head) | 255 | static void tcindex_partial_destroy_work(struct work_struct *work) |
| 262 | { | 256 | { |
| 263 | struct tcindex_data *p = container_of(head, struct tcindex_data, rcu); | 257 | struct tcindex_data *p = container_of(to_rcu_work(work), |
| 258 | struct tcindex_data, | ||
| 259 | rwork); | ||
| 264 | 260 | ||
| 265 | kfree(p->perfect); | 261 | kfree(p->perfect); |
| 266 | kfree(p); | 262 | kfree(p); |
| @@ -275,7 +271,7 @@ static void tcindex_free_perfect_hash(struct tcindex_data *cp) | |||
| 275 | kfree(cp->perfect); | 271 | kfree(cp->perfect); |
| 276 | } | 272 | } |
| 277 | 273 | ||
| 278 | static int tcindex_alloc_perfect_hash(struct tcindex_data *cp) | 274 | static int tcindex_alloc_perfect_hash(struct net *net, struct tcindex_data *cp) |
| 279 | { | 275 | { |
| 280 | int i, err = 0; | 276 | int i, err = 0; |
| 281 | 277 | ||
| @@ -289,6 +285,9 @@ static int tcindex_alloc_perfect_hash(struct tcindex_data *cp) | |||
| 289 | TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE); | 285 | TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE); |
| 290 | if (err < 0) | 286 | if (err < 0) |
| 291 | goto errout; | 287 | goto errout; |
| 288 | #ifdef CONFIG_NET_CLS_ACT | ||
| 289 | cp->perfect[i].exts.net = net; | ||
| 290 | #endif | ||
| 292 | } | 291 | } |
| 293 | 292 | ||
| 294 | return 0; | 293 | return 0; |
| @@ -305,9 +304,9 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, | |||
| 305 | struct nlattr *est, bool ovr, struct netlink_ext_ack *extack) | 304 | struct nlattr *est, bool ovr, struct netlink_ext_ack *extack) |
| 306 | { | 305 | { |
| 307 | struct tcindex_filter_result new_filter_result, *old_r = r; | 306 | struct tcindex_filter_result new_filter_result, *old_r = r; |
| 308 | struct tcindex_filter_result cr; | ||
| 309 | struct tcindex_data *cp = NULL, *oldp; | 307 | struct tcindex_data *cp = NULL, *oldp; |
| 310 | struct tcindex_filter *f = NULL; /* make gcc behave */ | 308 | struct tcindex_filter *f = NULL; /* make gcc behave */ |
| 309 | struct tcf_result cr = {}; | ||
| 311 | int err, balloc = 0; | 310 | int err, balloc = 0; |
| 312 | struct tcf_exts e; | 311 | struct tcf_exts e; |
| 313 | 312 | ||
| @@ -337,7 +336,7 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, | |||
| 337 | if (p->perfect) { | 336 | if (p->perfect) { |
| 338 | int i; | 337 | int i; |
| 339 | 338 | ||
| 340 | if (tcindex_alloc_perfect_hash(cp) < 0) | 339 | if (tcindex_alloc_perfect_hash(net, cp) < 0) |
| 341 | goto errout; | 340 | goto errout; |
| 342 | for (i = 0; i < cp->hash; i++) | 341 | for (i = 0; i < cp->hash; i++) |
| 343 | cp->perfect[i].res = p->perfect[i].res; | 342 | cp->perfect[i].res = p->perfect[i].res; |
| @@ -348,11 +347,8 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, | |||
| 348 | err = tcindex_filter_result_init(&new_filter_result); | 347 | err = tcindex_filter_result_init(&new_filter_result); |
| 349 | if (err < 0) | 348 | if (err < 0) |
| 350 | goto errout1; | 349 | goto errout1; |
| 351 | err = tcindex_filter_result_init(&cr); | ||
| 352 | if (err < 0) | ||
| 353 | goto errout1; | ||
| 354 | if (old_r) | 350 | if (old_r) |
| 355 | cr.res = r->res; | 351 | cr = r->res; |
| 356 | 352 | ||
| 357 | if (tb[TCA_TCINDEX_HASH]) | 353 | if (tb[TCA_TCINDEX_HASH]) |
| 358 | cp->hash = nla_get_u32(tb[TCA_TCINDEX_HASH]); | 354 | cp->hash = nla_get_u32(tb[TCA_TCINDEX_HASH]); |
| @@ -406,7 +402,7 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, | |||
| 406 | err = -ENOMEM; | 402 | err = -ENOMEM; |
| 407 | if (!cp->perfect && !cp->h) { | 403 | if (!cp->perfect && !cp->h) { |
| 408 | if (valid_perfect_hash(cp)) { | 404 | if (valid_perfect_hash(cp)) { |
| 409 | if (tcindex_alloc_perfect_hash(cp) < 0) | 405 | if (tcindex_alloc_perfect_hash(net, cp) < 0) |
| 410 | goto errout_alloc; | 406 | goto errout_alloc; |
| 411 | balloc = 1; | 407 | balloc = 1; |
| 412 | } else { | 408 | } else { |
| @@ -443,8 +439,8 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, | |||
| 443 | } | 439 | } |
| 444 | 440 | ||
| 445 | if (tb[TCA_TCINDEX_CLASSID]) { | 441 | if (tb[TCA_TCINDEX_CLASSID]) { |
| 446 | cr.res.classid = nla_get_u32(tb[TCA_TCINDEX_CLASSID]); | 442 | cr.classid = nla_get_u32(tb[TCA_TCINDEX_CLASSID]); |
| 447 | tcf_bind_filter(tp, &cr.res, base); | 443 | tcf_bind_filter(tp, &cr, base); |
| 448 | } | 444 | } |
| 449 | 445 | ||
| 450 | if (old_r && old_r != r) { | 446 | if (old_r && old_r != r) { |
| @@ -456,7 +452,7 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, | |||
| 456 | } | 452 | } |
| 457 | 453 | ||
| 458 | oldp = p; | 454 | oldp = p; |
| 459 | r->res = cr.res; | 455 | r->res = cr; |
| 460 | tcf_exts_change(&r->exts, &e); | 456 | tcf_exts_change(&r->exts, &e); |
| 461 | 457 | ||
| 462 | rcu_assign_pointer(tp->root, cp); | 458 | rcu_assign_pointer(tp->root, cp); |
| @@ -475,10 +471,12 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, | |||
| 475 | ; /* nothing */ | 471 | ; /* nothing */ |
| 476 | 472 | ||
| 477 | rcu_assign_pointer(*fp, f); | 473 | rcu_assign_pointer(*fp, f); |
| 474 | } else { | ||
| 475 | tcf_exts_destroy(&new_filter_result.exts); | ||
| 478 | } | 476 | } |
| 479 | 477 | ||
| 480 | if (oldp) | 478 | if (oldp) |
| 481 | call_rcu(&oldp->rcu, __tcindex_partial_destroy); | 479 | tcf_queue_work(&oldp->rwork, tcindex_partial_destroy_work); |
| 482 | return 0; | 480 | return 0; |
| 483 | 481 | ||
| 484 | errout_alloc: | 482 | errout_alloc: |
| @@ -487,7 +485,6 @@ errout_alloc: | |||
| 487 | else if (balloc == 2) | 485 | else if (balloc == 2) |
| 488 | kfree(cp->h); | 486 | kfree(cp->h); |
| 489 | errout1: | 487 | errout1: |
| 490 | tcf_exts_destroy(&cr.exts); | ||
| 491 | tcf_exts_destroy(&new_filter_result.exts); | 488 | tcf_exts_destroy(&new_filter_result.exts); |
| 492 | errout: | 489 | errout: |
| 493 | kfree(cp); | 490 | kfree(cp); |
| @@ -562,15 +559,34 @@ static void tcindex_destroy(struct tcf_proto *tp, | |||
| 562 | struct netlink_ext_ack *extack) | 559 | struct netlink_ext_ack *extack) |
| 563 | { | 560 | { |
| 564 | struct tcindex_data *p = rtnl_dereference(tp->root); | 561 | struct tcindex_data *p = rtnl_dereference(tp->root); |
| 565 | struct tcf_walker walker; | 562 | int i; |
| 566 | 563 | ||
| 567 | pr_debug("tcindex_destroy(tp %p),p %p\n", tp, p); | 564 | pr_debug("tcindex_destroy(tp %p),p %p\n", tp, p); |
| 568 | walker.count = 0; | ||
| 569 | walker.skip = 0; | ||
| 570 | walker.fn = tcindex_destroy_element; | ||
| 571 | tcindex_walk(tp, &walker); | ||
| 572 | 565 | ||
| 573 | call_rcu(&p->rcu, __tcindex_destroy); | 566 | if (p->perfect) { |
| 567 | for (i = 0; i < p->hash; i++) { | ||
| 568 | struct tcindex_filter_result *r = p->perfect + i; | ||
| 569 | |||
| 570 | tcf_unbind_filter(tp, &r->res); | ||
| 571 | if (tcf_exts_get_net(&r->exts)) | ||
| 572 | tcf_queue_work(&r->rwork, | ||
| 573 | tcindex_destroy_rexts_work); | ||
| 574 | else | ||
| 575 | __tcindex_destroy_rexts(r); | ||
| 576 | } | ||
| 577 | } | ||
| 578 | |||
| 579 | for (i = 0; p->h && i < p->hash; i++) { | ||
| 580 | struct tcindex_filter *f, *next; | ||
| 581 | bool last; | ||
| 582 | |||
| 583 | for (f = rtnl_dereference(p->h[i]); f; f = next) { | ||
| 584 | next = rtnl_dereference(f->next); | ||
| 585 | tcindex_delete(tp, &f->result, &last, NULL); | ||
| 586 | } | ||
| 587 | } | ||
| 588 | |||
| 589 | tcf_queue_work(&p->rwork, tcindex_destroy_work); | ||
| 574 | } | 590 | } |
| 575 | 591 | ||
| 576 | 592 | ||
diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c index b910cd5c56f7..73940293700d 100644 --- a/net/sched/sch_cake.c +++ b/net/sched/sch_cake.c | |||
| @@ -1667,7 +1667,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, | |||
| 1667 | if (skb_is_gso(skb) && q->rate_flags & CAKE_FLAG_SPLIT_GSO) { | 1667 | if (skb_is_gso(skb) && q->rate_flags & CAKE_FLAG_SPLIT_GSO) { |
| 1668 | struct sk_buff *segs, *nskb; | 1668 | struct sk_buff *segs, *nskb; |
| 1669 | netdev_features_t features = netif_skb_features(skb); | 1669 | netdev_features_t features = netif_skb_features(skb); |
| 1670 | unsigned int slen = 0; | 1670 | unsigned int slen = 0, numsegs = 0; |
| 1671 | 1671 | ||
| 1672 | segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK); | 1672 | segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK); |
| 1673 | if (IS_ERR_OR_NULL(segs)) | 1673 | if (IS_ERR_OR_NULL(segs)) |
| @@ -1683,6 +1683,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, | |||
| 1683 | flow_queue_add(flow, segs); | 1683 | flow_queue_add(flow, segs); |
| 1684 | 1684 | ||
| 1685 | sch->q.qlen++; | 1685 | sch->q.qlen++; |
| 1686 | numsegs++; | ||
| 1686 | slen += segs->len; | 1687 | slen += segs->len; |
| 1687 | q->buffer_used += segs->truesize; | 1688 | q->buffer_used += segs->truesize; |
| 1688 | b->packets++; | 1689 | b->packets++; |
| @@ -1696,7 +1697,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, | |||
| 1696 | sch->qstats.backlog += slen; | 1697 | sch->qstats.backlog += slen; |
| 1697 | q->avg_window_bytes += slen; | 1698 | q->avg_window_bytes += slen; |
| 1698 | 1699 | ||
| 1699 | qdisc_tree_reduce_backlog(sch, 1, len); | 1700 | qdisc_tree_reduce_backlog(sch, 1-numsegs, len-slen); |
| 1700 | consume_skb(skb); | 1701 | consume_skb(skb); |
| 1701 | } else { | 1702 | } else { |
| 1702 | /* not splitting */ | 1703 | /* not splitting */ |
diff --git a/net/sched/sch_cbs.c b/net/sched/sch_cbs.c index e689e11b6d0f..c6a502933fe7 100644 --- a/net/sched/sch_cbs.c +++ b/net/sched/sch_cbs.c | |||
| @@ -88,13 +88,14 @@ static int cbs_child_enqueue(struct sk_buff *skb, struct Qdisc *sch, | |||
| 88 | struct Qdisc *child, | 88 | struct Qdisc *child, |
| 89 | struct sk_buff **to_free) | 89 | struct sk_buff **to_free) |
| 90 | { | 90 | { |
| 91 | unsigned int len = qdisc_pkt_len(skb); | ||
| 91 | int err; | 92 | int err; |
| 92 | 93 | ||
| 93 | err = child->ops->enqueue(skb, child, to_free); | 94 | err = child->ops->enqueue(skb, child, to_free); |
| 94 | if (err != NET_XMIT_SUCCESS) | 95 | if (err != NET_XMIT_SUCCESS) |
| 95 | return err; | 96 | return err; |
| 96 | 97 | ||
| 97 | qdisc_qstats_backlog_inc(sch, skb); | 98 | sch->qstats.backlog += len; |
| 98 | sch->q.qlen++; | 99 | sch->q.qlen++; |
| 99 | 100 | ||
| 100 | return NET_XMIT_SUCCESS; | 101 | return NET_XMIT_SUCCESS; |
diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c index cdebaed0f8cf..09b800991065 100644 --- a/net/sched/sch_drr.c +++ b/net/sched/sch_drr.c | |||
| @@ -350,9 +350,11 @@ static struct drr_class *drr_classify(struct sk_buff *skb, struct Qdisc *sch, | |||
| 350 | static int drr_enqueue(struct sk_buff *skb, struct Qdisc *sch, | 350 | static int drr_enqueue(struct sk_buff *skb, struct Qdisc *sch, |
| 351 | struct sk_buff **to_free) | 351 | struct sk_buff **to_free) |
| 352 | { | 352 | { |
| 353 | unsigned int len = qdisc_pkt_len(skb); | ||
| 353 | struct drr_sched *q = qdisc_priv(sch); | 354 | struct drr_sched *q = qdisc_priv(sch); |
| 354 | struct drr_class *cl; | 355 | struct drr_class *cl; |
| 355 | int err = 0; | 356 | int err = 0; |
| 357 | bool first; | ||
| 356 | 358 | ||
| 357 | cl = drr_classify(skb, sch, &err); | 359 | cl = drr_classify(skb, sch, &err); |
| 358 | if (cl == NULL) { | 360 | if (cl == NULL) { |
| @@ -362,6 +364,7 @@ static int drr_enqueue(struct sk_buff *skb, struct Qdisc *sch, | |||
| 362 | return err; | 364 | return err; |
| 363 | } | 365 | } |
| 364 | 366 | ||
| 367 | first = !cl->qdisc->q.qlen; | ||
| 365 | err = qdisc_enqueue(skb, cl->qdisc, to_free); | 368 | err = qdisc_enqueue(skb, cl->qdisc, to_free); |
| 366 | if (unlikely(err != NET_XMIT_SUCCESS)) { | 369 | if (unlikely(err != NET_XMIT_SUCCESS)) { |
| 367 | if (net_xmit_drop_count(err)) { | 370 | if (net_xmit_drop_count(err)) { |
| @@ -371,12 +374,12 @@ static int drr_enqueue(struct sk_buff *skb, struct Qdisc *sch, | |||
| 371 | return err; | 374 | return err; |
| 372 | } | 375 | } |
| 373 | 376 | ||
| 374 | if (cl->qdisc->q.qlen == 1) { | 377 | if (first) { |
| 375 | list_add_tail(&cl->alist, &q->active); | 378 | list_add_tail(&cl->alist, &q->active); |
| 376 | cl->deficit = cl->quantum; | 379 | cl->deficit = cl->quantum; |
| 377 | } | 380 | } |
| 378 | 381 | ||
| 379 | qdisc_qstats_backlog_inc(sch, skb); | 382 | sch->qstats.backlog += len; |
| 380 | sch->q.qlen++; | 383 | sch->q.qlen++; |
| 381 | return err; | 384 | return err; |
| 382 | } | 385 | } |
diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c index f6f480784bc6..42471464ded3 100644 --- a/net/sched/sch_dsmark.c +++ b/net/sched/sch_dsmark.c | |||
| @@ -199,6 +199,7 @@ static struct tcf_block *dsmark_tcf_block(struct Qdisc *sch, unsigned long cl, | |||
| 199 | static int dsmark_enqueue(struct sk_buff *skb, struct Qdisc *sch, | 199 | static int dsmark_enqueue(struct sk_buff *skb, struct Qdisc *sch, |
| 200 | struct sk_buff **to_free) | 200 | struct sk_buff **to_free) |
| 201 | { | 201 | { |
| 202 | unsigned int len = qdisc_pkt_len(skb); | ||
| 202 | struct dsmark_qdisc_data *p = qdisc_priv(sch); | 203 | struct dsmark_qdisc_data *p = qdisc_priv(sch); |
| 203 | int err; | 204 | int err; |
| 204 | 205 | ||
| @@ -271,7 +272,7 @@ static int dsmark_enqueue(struct sk_buff *skb, struct Qdisc *sch, | |||
| 271 | return err; | 272 | return err; |
| 272 | } | 273 | } |
| 273 | 274 | ||
| 274 | qdisc_qstats_backlog_inc(sch, skb); | 275 | sch->qstats.backlog += len; |
| 275 | sch->q.qlen++; | 276 | sch->q.qlen++; |
| 276 | 277 | ||
| 277 | return NET_XMIT_SUCCESS; | 278 | return NET_XMIT_SUCCESS; |
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 66ba2ce2320f..968a85fe4d4a 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c | |||
| @@ -500,7 +500,7 @@ static void dev_watchdog_down(struct net_device *dev) | |||
| 500 | * netif_carrier_on - set carrier | 500 | * netif_carrier_on - set carrier |
| 501 | * @dev: network device | 501 | * @dev: network device |
| 502 | * | 502 | * |
| 503 | * Device has detected that carrier. | 503 | * Device has detected acquisition of carrier. |
| 504 | */ | 504 | */ |
| 505 | void netif_carrier_on(struct net_device *dev) | 505 | void netif_carrier_on(struct net_device *dev) |
| 506 | { | 506 | { |
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index b18ec1f6de60..24cc220a3218 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c | |||
| @@ -1539,8 +1539,10 @@ hfsc_dump_qdisc(struct Qdisc *sch, struct sk_buff *skb) | |||
| 1539 | static int | 1539 | static int |
| 1540 | hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) | 1540 | hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) |
| 1541 | { | 1541 | { |
| 1542 | unsigned int len = qdisc_pkt_len(skb); | ||
| 1542 | struct hfsc_class *cl; | 1543 | struct hfsc_class *cl; |
| 1543 | int uninitialized_var(err); | 1544 | int uninitialized_var(err); |
| 1545 | bool first; | ||
| 1544 | 1546 | ||
| 1545 | cl = hfsc_classify(skb, sch, &err); | 1547 | cl = hfsc_classify(skb, sch, &err); |
| 1546 | if (cl == NULL) { | 1548 | if (cl == NULL) { |
| @@ -1550,6 +1552,7 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) | |||
| 1550 | return err; | 1552 | return err; |
| 1551 | } | 1553 | } |
| 1552 | 1554 | ||
| 1555 | first = !cl->qdisc->q.qlen; | ||
| 1553 | err = qdisc_enqueue(skb, cl->qdisc, to_free); | 1556 | err = qdisc_enqueue(skb, cl->qdisc, to_free); |
| 1554 | if (unlikely(err != NET_XMIT_SUCCESS)) { | 1557 | if (unlikely(err != NET_XMIT_SUCCESS)) { |
| 1555 | if (net_xmit_drop_count(err)) { | 1558 | if (net_xmit_drop_count(err)) { |
| @@ -1559,9 +1562,7 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) | |||
| 1559 | return err; | 1562 | return err; |
| 1560 | } | 1563 | } |
| 1561 | 1564 | ||
| 1562 | if (cl->qdisc->q.qlen == 1) { | 1565 | if (first) { |
| 1563 | unsigned int len = qdisc_pkt_len(skb); | ||
| 1564 | |||
| 1565 | if (cl->cl_flags & HFSC_RSC) | 1566 | if (cl->cl_flags & HFSC_RSC) |
| 1566 | init_ed(cl, len); | 1567 | init_ed(cl, len); |
| 1567 | if (cl->cl_flags & HFSC_FSC) | 1568 | if (cl->cl_flags & HFSC_FSC) |
| @@ -1576,7 +1577,7 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) | |||
| 1576 | 1577 | ||
| 1577 | } | 1578 | } |
| 1578 | 1579 | ||
| 1579 | qdisc_qstats_backlog_inc(sch, skb); | 1580 | sch->qstats.backlog += len; |
| 1580 | sch->q.qlen++; | 1581 | sch->q.qlen++; |
| 1581 | 1582 | ||
| 1582 | return NET_XMIT_SUCCESS; | 1583 | return NET_XMIT_SUCCESS; |
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 58b449490757..30f9da7e1076 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c | |||
| @@ -581,6 +581,7 @@ static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch, | |||
| 581 | struct sk_buff **to_free) | 581 | struct sk_buff **to_free) |
| 582 | { | 582 | { |
| 583 | int uninitialized_var(ret); | 583 | int uninitialized_var(ret); |
| 584 | unsigned int len = qdisc_pkt_len(skb); | ||
| 584 | struct htb_sched *q = qdisc_priv(sch); | 585 | struct htb_sched *q = qdisc_priv(sch); |
| 585 | struct htb_class *cl = htb_classify(skb, sch, &ret); | 586 | struct htb_class *cl = htb_classify(skb, sch, &ret); |
| 586 | 587 | ||
| @@ -610,7 +611,7 @@ static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch, | |||
| 610 | htb_activate(q, cl); | 611 | htb_activate(q, cl); |
| 611 | } | 612 | } |
| 612 | 613 | ||
| 613 | qdisc_qstats_backlog_inc(sch, skb); | 614 | sch->qstats.backlog += len; |
| 614 | sch->q.qlen++; | 615 | sch->q.qlen++; |
| 615 | return NET_XMIT_SUCCESS; | 616 | return NET_XMIT_SUCCESS; |
| 616 | } | 617 | } |
diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index cdf68706e40f..847141cd900f 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c | |||
| @@ -72,6 +72,7 @@ prio_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr) | |||
| 72 | static int | 72 | static int |
| 73 | prio_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) | 73 | prio_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) |
| 74 | { | 74 | { |
| 75 | unsigned int len = qdisc_pkt_len(skb); | ||
| 75 | struct Qdisc *qdisc; | 76 | struct Qdisc *qdisc; |
| 76 | int ret; | 77 | int ret; |
| 77 | 78 | ||
| @@ -88,7 +89,7 @@ prio_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) | |||
| 88 | 89 | ||
| 89 | ret = qdisc_enqueue(skb, qdisc, to_free); | 90 | ret = qdisc_enqueue(skb, qdisc, to_free); |
| 90 | if (ret == NET_XMIT_SUCCESS) { | 91 | if (ret == NET_XMIT_SUCCESS) { |
| 91 | qdisc_qstats_backlog_inc(sch, skb); | 92 | sch->qstats.backlog += len; |
| 92 | sch->q.qlen++; | 93 | sch->q.qlen++; |
| 93 | return NET_XMIT_SUCCESS; | 94 | return NET_XMIT_SUCCESS; |
| 94 | } | 95 | } |
diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c index dc37c4ead439..29f5c4a24688 100644 --- a/net/sched/sch_qfq.c +++ b/net/sched/sch_qfq.c | |||
| @@ -1210,10 +1210,12 @@ static struct qfq_aggregate *qfq_choose_next_agg(struct qfq_sched *q) | |||
| 1210 | static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch, | 1210 | static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch, |
| 1211 | struct sk_buff **to_free) | 1211 | struct sk_buff **to_free) |
| 1212 | { | 1212 | { |
| 1213 | unsigned int len = qdisc_pkt_len(skb), gso_segs; | ||
| 1213 | struct qfq_sched *q = qdisc_priv(sch); | 1214 | struct qfq_sched *q = qdisc_priv(sch); |
| 1214 | struct qfq_class *cl; | 1215 | struct qfq_class *cl; |
| 1215 | struct qfq_aggregate *agg; | 1216 | struct qfq_aggregate *agg; |
| 1216 | int err = 0; | 1217 | int err = 0; |
| 1218 | bool first; | ||
| 1217 | 1219 | ||
| 1218 | cl = qfq_classify(skb, sch, &err); | 1220 | cl = qfq_classify(skb, sch, &err); |
| 1219 | if (cl == NULL) { | 1221 | if (cl == NULL) { |
| @@ -1224,17 +1226,18 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch, | |||
| 1224 | } | 1226 | } |
| 1225 | pr_debug("qfq_enqueue: cl = %x\n", cl->common.classid); | 1227 | pr_debug("qfq_enqueue: cl = %x\n", cl->common.classid); |
| 1226 | 1228 | ||
| 1227 | if (unlikely(cl->agg->lmax < qdisc_pkt_len(skb))) { | 1229 | if (unlikely(cl->agg->lmax < len)) { |
| 1228 | pr_debug("qfq: increasing maxpkt from %u to %u for class %u", | 1230 | pr_debug("qfq: increasing maxpkt from %u to %u for class %u", |
| 1229 | cl->agg->lmax, qdisc_pkt_len(skb), cl->common.classid); | 1231 | cl->agg->lmax, len, cl->common.classid); |
| 1230 | err = qfq_change_agg(sch, cl, cl->agg->class_weight, | 1232 | err = qfq_change_agg(sch, cl, cl->agg->class_weight, len); |
| 1231 | qdisc_pkt_len(skb)); | ||
| 1232 | if (err) { | 1233 | if (err) { |
| 1233 | cl->qstats.drops++; | 1234 | cl->qstats.drops++; |
| 1234 | return qdisc_drop(skb, sch, to_free); | 1235 | return qdisc_drop(skb, sch, to_free); |
| 1235 | } | 1236 | } |
| 1236 | } | 1237 | } |
| 1237 | 1238 | ||
| 1239 | gso_segs = skb_is_gso(skb) ? skb_shinfo(skb)->gso_segs : 1; | ||
| 1240 | first = !cl->qdisc->q.qlen; | ||
| 1238 | err = qdisc_enqueue(skb, cl->qdisc, to_free); | 1241 | err = qdisc_enqueue(skb, cl->qdisc, to_free); |
| 1239 | if (unlikely(err != NET_XMIT_SUCCESS)) { | 1242 | if (unlikely(err != NET_XMIT_SUCCESS)) { |
| 1240 | pr_debug("qfq_enqueue: enqueue failed %d\n", err); | 1243 | pr_debug("qfq_enqueue: enqueue failed %d\n", err); |
| @@ -1245,16 +1248,17 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch, | |||
| 1245 | return err; | 1248 | return err; |
| 1246 | } | 1249 | } |
| 1247 | 1250 | ||
| 1248 | bstats_update(&cl->bstats, skb); | 1251 | cl->bstats.bytes += len; |
| 1249 | qdisc_qstats_backlog_inc(sch, skb); | 1252 | cl->bstats.packets += gso_segs; |
| 1253 | sch->qstats.backlog += len; | ||
| 1250 | ++sch->q.qlen; | 1254 | ++sch->q.qlen; |
| 1251 | 1255 | ||
| 1252 | agg = cl->agg; | 1256 | agg = cl->agg; |
| 1253 | /* if the queue was not empty, then done here */ | 1257 | /* if the queue was not empty, then done here */ |
| 1254 | if (cl->qdisc->q.qlen != 1) { | 1258 | if (!first) { |
| 1255 | if (unlikely(skb == cl->qdisc->ops->peek(cl->qdisc)) && | 1259 | if (unlikely(skb == cl->qdisc->ops->peek(cl->qdisc)) && |
| 1256 | list_first_entry(&agg->active, struct qfq_class, alist) | 1260 | list_first_entry(&agg->active, struct qfq_class, alist) |
| 1257 | == cl && cl->deficit < qdisc_pkt_len(skb)) | 1261 | == cl && cl->deficit < len) |
| 1258 | list_move_tail(&cl->alist, &agg->active); | 1262 | list_move_tail(&cl->alist, &agg->active); |
| 1259 | 1263 | ||
| 1260 | return err; | 1264 | return err; |
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index 942dcca09cf2..7f272a9070c5 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c | |||
| @@ -185,6 +185,7 @@ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc *sch, | |||
| 185 | struct sk_buff **to_free) | 185 | struct sk_buff **to_free) |
| 186 | { | 186 | { |
| 187 | struct tbf_sched_data *q = qdisc_priv(sch); | 187 | struct tbf_sched_data *q = qdisc_priv(sch); |
| 188 | unsigned int len = qdisc_pkt_len(skb); | ||
| 188 | int ret; | 189 | int ret; |
| 189 | 190 | ||
| 190 | if (qdisc_pkt_len(skb) > q->max_size) { | 191 | if (qdisc_pkt_len(skb) > q->max_size) { |
| @@ -200,7 +201,7 @@ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc *sch, | |||
| 200 | return ret; | 201 | return ret; |
| 201 | } | 202 | } |
| 202 | 203 | ||
| 203 | qdisc_qstats_backlog_inc(sch, skb); | 204 | sch->qstats.backlog += len; |
| 204 | sch->q.qlen++; | 205 | sch->q.qlen++; |
| 205 | return NET_XMIT_SUCCESS; | 206 | return NET_XMIT_SUCCESS; |
| 206 | } | 207 | } |
diff --git a/net/sctp/diag.c b/net/sctp/diag.c index 078f01a8d582..435847d98b51 100644 --- a/net/sctp/diag.c +++ b/net/sctp/diag.c | |||
| @@ -256,6 +256,7 @@ static size_t inet_assoc_attr_size(struct sctp_association *asoc) | |||
| 256 | + nla_total_size(1) /* INET_DIAG_TOS */ | 256 | + nla_total_size(1) /* INET_DIAG_TOS */ |
| 257 | + nla_total_size(1) /* INET_DIAG_TCLASS */ | 257 | + nla_total_size(1) /* INET_DIAG_TCLASS */ |
| 258 | + nla_total_size(4) /* INET_DIAG_MARK */ | 258 | + nla_total_size(4) /* INET_DIAG_MARK */ |
| 259 | + nla_total_size(4) /* INET_DIAG_CLASS_ID */ | ||
| 259 | + nla_total_size(addrlen * asoc->peer.transport_count) | 260 | + nla_total_size(addrlen * asoc->peer.transport_count) |
| 260 | + nla_total_size(addrlen * addrcnt) | 261 | + nla_total_size(addrlen * addrcnt) |
| 261 | + nla_total_size(sizeof(struct inet_diag_meminfo)) | 262 | + nla_total_size(sizeof(struct inet_diag_meminfo)) |
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index b9ed271b7ef7..6200cd2b4b99 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c | |||
| @@ -97,11 +97,9 @@ static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev, | |||
| 97 | 97 | ||
| 98 | switch (ev) { | 98 | switch (ev) { |
| 99 | case NETDEV_UP: | 99 | case NETDEV_UP: |
| 100 | addr = kmalloc(sizeof(struct sctp_sockaddr_entry), GFP_ATOMIC); | 100 | addr = kzalloc(sizeof(*addr), GFP_ATOMIC); |
| 101 | if (addr) { | 101 | if (addr) { |
| 102 | addr->a.v6.sin6_family = AF_INET6; | 102 | addr->a.v6.sin6_family = AF_INET6; |
| 103 | addr->a.v6.sin6_port = 0; | ||
| 104 | addr->a.v6.sin6_flowinfo = 0; | ||
| 105 | addr->a.v6.sin6_addr = ifa->addr; | 103 | addr->a.v6.sin6_addr = ifa->addr; |
| 106 | addr->a.v6.sin6_scope_id = ifa->idev->dev->ifindex; | 104 | addr->a.v6.sin6_scope_id = ifa->idev->dev->ifindex; |
| 107 | addr->valid = 1; | 105 | addr->valid = 1; |
| @@ -282,7 +280,8 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, | |||
| 282 | 280 | ||
| 283 | if (saddr) { | 281 | if (saddr) { |
| 284 | fl6->saddr = saddr->v6.sin6_addr; | 282 | fl6->saddr = saddr->v6.sin6_addr; |
| 285 | fl6->fl6_sport = saddr->v6.sin6_port; | 283 | if (!fl6->fl6_sport) |
| 284 | fl6->fl6_sport = saddr->v6.sin6_port; | ||
| 286 | 285 | ||
| 287 | pr_debug("src=%pI6 - ", &fl6->saddr); | 286 | pr_debug("src=%pI6 - ", &fl6->saddr); |
| 288 | } | 287 | } |
| @@ -434,7 +433,6 @@ static void sctp_v6_copy_addrlist(struct list_head *addrlist, | |||
| 434 | addr = kzalloc(sizeof(*addr), GFP_ATOMIC); | 433 | addr = kzalloc(sizeof(*addr), GFP_ATOMIC); |
| 435 | if (addr) { | 434 | if (addr) { |
| 436 | addr->a.v6.sin6_family = AF_INET6; | 435 | addr->a.v6.sin6_family = AF_INET6; |
| 437 | addr->a.v6.sin6_port = 0; | ||
| 438 | addr->a.v6.sin6_addr = ifp->addr; | 436 | addr->a.v6.sin6_addr = ifp->addr; |
| 439 | addr->a.v6.sin6_scope_id = dev->ifindex; | 437 | addr->a.v6.sin6_scope_id = dev->ifindex; |
| 440 | addr->valid = 1; | 438 | addr->valid = 1; |
diff --git a/net/sctp/offload.c b/net/sctp/offload.c index 123e9f2dc226..edfcf16e704c 100644 --- a/net/sctp/offload.c +++ b/net/sctp/offload.c | |||
| @@ -36,6 +36,7 @@ static __le32 sctp_gso_make_checksum(struct sk_buff *skb) | |||
| 36 | { | 36 | { |
| 37 | skb->ip_summed = CHECKSUM_NONE; | 37 | skb->ip_summed = CHECKSUM_NONE; |
| 38 | skb->csum_not_inet = 0; | 38 | skb->csum_not_inet = 0; |
| 39 | gso_reset_checksum(skb, ~0); | ||
| 39 | return sctp_compute_cksum(skb, skb_transport_offset(skb)); | 40 | return sctp_compute_cksum(skb, skb_transport_offset(skb)); |
| 40 | } | 41 | } |
| 41 | 42 | ||
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index d5878ae55840..6abc8b274270 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c | |||
| @@ -101,7 +101,6 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist, | |||
| 101 | addr = kzalloc(sizeof(*addr), GFP_ATOMIC); | 101 | addr = kzalloc(sizeof(*addr), GFP_ATOMIC); |
| 102 | if (addr) { | 102 | if (addr) { |
| 103 | addr->a.v4.sin_family = AF_INET; | 103 | addr->a.v4.sin_family = AF_INET; |
| 104 | addr->a.v4.sin_port = 0; | ||
| 105 | addr->a.v4.sin_addr.s_addr = ifa->ifa_local; | 104 | addr->a.v4.sin_addr.s_addr = ifa->ifa_local; |
| 106 | addr->valid = 1; | 105 | addr->valid = 1; |
| 107 | INIT_LIST_HEAD(&addr->list); | 106 | INIT_LIST_HEAD(&addr->list); |
| @@ -441,7 +440,8 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr, | |||
| 441 | } | 440 | } |
| 442 | if (saddr) { | 441 | if (saddr) { |
| 443 | fl4->saddr = saddr->v4.sin_addr.s_addr; | 442 | fl4->saddr = saddr->v4.sin_addr.s_addr; |
| 444 | fl4->fl4_sport = saddr->v4.sin_port; | 443 | if (!fl4->fl4_sport) |
| 444 | fl4->fl4_sport = saddr->v4.sin_port; | ||
| 445 | } | 445 | } |
| 446 | 446 | ||
| 447 | pr_debug("%s: dst:%pI4, src:%pI4 - ", __func__, &fl4->daddr, | 447 | pr_debug("%s: dst:%pI4, src:%pI4 - ", __func__, &fl4->daddr, |
| @@ -776,10 +776,9 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev, | |||
| 776 | 776 | ||
| 777 | switch (ev) { | 777 | switch (ev) { |
| 778 | case NETDEV_UP: | 778 | case NETDEV_UP: |
| 779 | addr = kmalloc(sizeof(struct sctp_sockaddr_entry), GFP_ATOMIC); | 779 | addr = kzalloc(sizeof(*addr), GFP_ATOMIC); |
| 780 | if (addr) { | 780 | if (addr) { |
| 781 | addr->a.v4.sin_family = AF_INET; | 781 | addr->a.v4.sin_family = AF_INET; |
| 782 | addr->a.v4.sin_port = 0; | ||
| 783 | addr->a.v4.sin_addr.s_addr = ifa->ifa_local; | 782 | addr->a.v4.sin_addr.s_addr = ifa->ifa_local; |
| 784 | addr->valid = 1; | 783 | addr->valid = 1; |
| 785 | spin_lock_bh(&net->sctp.local_addr_lock); | 784 | spin_lock_bh(&net->sctp.local_addr_lock); |
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index f4ac6c592e13..d05c57664e36 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c | |||
| @@ -495,7 +495,10 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc, | |||
| 495 | * | 495 | * |
| 496 | * [INIT ACK back to where the INIT came from.] | 496 | * [INIT ACK back to where the INIT came from.] |
| 497 | */ | 497 | */ |
| 498 | retval->transport = chunk->transport; | 498 | if (chunk->transport) |
| 499 | retval->transport = | ||
| 500 | sctp_assoc_lookup_paddr(asoc, | ||
| 501 | &chunk->transport->ipaddr); | ||
| 499 | 502 | ||
| 500 | retval->subh.init_hdr = | 503 | retval->subh.init_hdr = |
| 501 | sctp_addto_chunk(retval, sizeof(initack), &initack); | 504 | sctp_addto_chunk(retval, sizeof(initack), &initack); |
| @@ -642,8 +645,10 @@ struct sctp_chunk *sctp_make_cookie_ack(const struct sctp_association *asoc, | |||
| 642 | * | 645 | * |
| 643 | * [COOKIE ACK back to where the COOKIE ECHO came from.] | 646 | * [COOKIE ACK back to where the COOKIE ECHO came from.] |
| 644 | */ | 647 | */ |
| 645 | if (retval && chunk) | 648 | if (retval && chunk && chunk->transport) |
| 646 | retval->transport = chunk->transport; | 649 | retval->transport = |
| 650 | sctp_assoc_lookup_paddr(asoc, | ||
| 651 | &chunk->transport->ipaddr); | ||
| 647 | 652 | ||
| 648 | return retval; | 653 | return retval; |
| 649 | } | 654 | } |
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index f93c3cf9e567..65d6d04546ae 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
| @@ -2027,7 +2027,7 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len) | |||
| 2027 | struct sctp_endpoint *ep = sctp_sk(sk)->ep; | 2027 | struct sctp_endpoint *ep = sctp_sk(sk)->ep; |
| 2028 | struct sctp_transport *transport = NULL; | 2028 | struct sctp_transport *transport = NULL; |
| 2029 | struct sctp_sndrcvinfo _sinfo, *sinfo; | 2029 | struct sctp_sndrcvinfo _sinfo, *sinfo; |
| 2030 | struct sctp_association *asoc; | 2030 | struct sctp_association *asoc, *tmp; |
| 2031 | struct sctp_cmsgs cmsgs; | 2031 | struct sctp_cmsgs cmsgs; |
| 2032 | union sctp_addr *daddr; | 2032 | union sctp_addr *daddr; |
| 2033 | bool new = false; | 2033 | bool new = false; |
| @@ -2053,7 +2053,7 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len) | |||
| 2053 | 2053 | ||
| 2054 | /* SCTP_SENDALL process */ | 2054 | /* SCTP_SENDALL process */ |
| 2055 | if ((sflags & SCTP_SENDALL) && sctp_style(sk, UDP)) { | 2055 | if ((sflags & SCTP_SENDALL) && sctp_style(sk, UDP)) { |
| 2056 | list_for_each_entry(asoc, &ep->asocs, asocs) { | 2056 | list_for_each_entry_safe(asoc, tmp, &ep->asocs, asocs) { |
| 2057 | err = sctp_sendmsg_check_sflags(asoc, sflags, msg, | 2057 | err = sctp_sendmsg_check_sflags(asoc, sflags, msg, |
| 2058 | msg_len); | 2058 | msg_len); |
| 2059 | if (err == 0) | 2059 | if (err == 0) |
diff --git a/net/sctp/stream.c b/net/sctp/stream.c index 3892e7630f3a..2936ed17bf9e 100644 --- a/net/sctp/stream.c +++ b/net/sctp/stream.c | |||
| @@ -84,6 +84,19 @@ static void fa_zero(struct flex_array *fa, size_t index, size_t count) | |||
| 84 | } | 84 | } |
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | static size_t fa_index(struct flex_array *fa, void *elem, size_t count) | ||
| 88 | { | ||
| 89 | size_t index = 0; | ||
| 90 | |||
| 91 | while (count--) { | ||
| 92 | if (elem == flex_array_get(fa, index)) | ||
| 93 | break; | ||
| 94 | index++; | ||
| 95 | } | ||
| 96 | |||
| 97 | return index; | ||
| 98 | } | ||
| 99 | |||
| 87 | /* Migrates chunks from stream queues to new stream queues if needed, | 100 | /* Migrates chunks from stream queues to new stream queues if needed, |
| 88 | * but not across associations. Also, removes those chunks to streams | 101 | * but not across associations. Also, removes those chunks to streams |
| 89 | * higher than the new max. | 102 | * higher than the new max. |
| @@ -131,8 +144,10 @@ static void sctp_stream_outq_migrate(struct sctp_stream *stream, | |||
| 131 | } | 144 | } |
| 132 | } | 145 | } |
| 133 | 146 | ||
| 134 | for (i = outcnt; i < stream->outcnt; i++) | 147 | for (i = outcnt; i < stream->outcnt; i++) { |
| 135 | kfree(SCTP_SO(stream, i)->ext); | 148 | kfree(SCTP_SO(stream, i)->ext); |
| 149 | SCTP_SO(stream, i)->ext = NULL; | ||
| 150 | } | ||
| 136 | } | 151 | } |
| 137 | 152 | ||
| 138 | static int sctp_stream_alloc_out(struct sctp_stream *stream, __u16 outcnt, | 153 | static int sctp_stream_alloc_out(struct sctp_stream *stream, __u16 outcnt, |
| @@ -147,6 +162,13 @@ static int sctp_stream_alloc_out(struct sctp_stream *stream, __u16 outcnt, | |||
| 147 | 162 | ||
| 148 | if (stream->out) { | 163 | if (stream->out) { |
| 149 | fa_copy(out, stream->out, 0, min(outcnt, stream->outcnt)); | 164 | fa_copy(out, stream->out, 0, min(outcnt, stream->outcnt)); |
| 165 | if (stream->out_curr) { | ||
| 166 | size_t index = fa_index(stream->out, stream->out_curr, | ||
| 167 | stream->outcnt); | ||
| 168 | |||
| 169 | BUG_ON(index == stream->outcnt); | ||
| 170 | stream->out_curr = flex_array_get(out, index); | ||
| 171 | } | ||
| 150 | fa_free(stream->out); | 172 | fa_free(stream->out); |
| 151 | } | 173 | } |
| 152 | 174 | ||
| @@ -585,9 +607,9 @@ struct sctp_chunk *sctp_process_strreset_outreq( | |||
| 585 | struct sctp_strreset_outreq *outreq = param.v; | 607 | struct sctp_strreset_outreq *outreq = param.v; |
| 586 | struct sctp_stream *stream = &asoc->stream; | 608 | struct sctp_stream *stream = &asoc->stream; |
| 587 | __u32 result = SCTP_STRRESET_DENIED; | 609 | __u32 result = SCTP_STRRESET_DENIED; |
| 588 | __u16 i, nums, flags = 0; | ||
| 589 | __be16 *str_p = NULL; | 610 | __be16 *str_p = NULL; |
| 590 | __u32 request_seq; | 611 | __u32 request_seq; |
| 612 | __u16 i, nums; | ||
| 591 | 613 | ||
| 592 | request_seq = ntohl(outreq->request_seq); | 614 | request_seq = ntohl(outreq->request_seq); |
| 593 | 615 | ||
| @@ -615,6 +637,15 @@ struct sctp_chunk *sctp_process_strreset_outreq( | |||
| 615 | if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ)) | 637 | if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ)) |
| 616 | goto out; | 638 | goto out; |
| 617 | 639 | ||
| 640 | nums = (ntohs(param.p->length) - sizeof(*outreq)) / sizeof(__u16); | ||
| 641 | str_p = outreq->list_of_streams; | ||
| 642 | for (i = 0; i < nums; i++) { | ||
| 643 | if (ntohs(str_p[i]) >= stream->incnt) { | ||
| 644 | result = SCTP_STRRESET_ERR_WRONG_SSN; | ||
| 645 | goto out; | ||
| 646 | } | ||
| 647 | } | ||
| 648 | |||
| 618 | if (asoc->strreset_chunk) { | 649 | if (asoc->strreset_chunk) { |
| 619 | if (!sctp_chunk_lookup_strreset_param( | 650 | if (!sctp_chunk_lookup_strreset_param( |
| 620 | asoc, outreq->response_seq, | 651 | asoc, outreq->response_seq, |
| @@ -637,32 +668,19 @@ struct sctp_chunk *sctp_process_strreset_outreq( | |||
| 637 | sctp_chunk_put(asoc->strreset_chunk); | 668 | sctp_chunk_put(asoc->strreset_chunk); |
| 638 | asoc->strreset_chunk = NULL; | 669 | asoc->strreset_chunk = NULL; |
| 639 | } | 670 | } |
| 640 | |||
| 641 | flags = SCTP_STREAM_RESET_INCOMING_SSN; | ||
| 642 | } | 671 | } |
| 643 | 672 | ||
| 644 | nums = (ntohs(param.p->length) - sizeof(*outreq)) / sizeof(__u16); | 673 | if (nums) |
| 645 | if (nums) { | ||
| 646 | str_p = outreq->list_of_streams; | ||
| 647 | for (i = 0; i < nums; i++) { | ||
| 648 | if (ntohs(str_p[i]) >= stream->incnt) { | ||
| 649 | result = SCTP_STRRESET_ERR_WRONG_SSN; | ||
| 650 | goto out; | ||
| 651 | } | ||
| 652 | } | ||
| 653 | |||
| 654 | for (i = 0; i < nums; i++) | 674 | for (i = 0; i < nums; i++) |
| 655 | SCTP_SI(stream, ntohs(str_p[i]))->mid = 0; | 675 | SCTP_SI(stream, ntohs(str_p[i]))->mid = 0; |
| 656 | } else { | 676 | else |
| 657 | for (i = 0; i < stream->incnt; i++) | 677 | for (i = 0; i < stream->incnt; i++) |
| 658 | SCTP_SI(stream, i)->mid = 0; | 678 | SCTP_SI(stream, i)->mid = 0; |
| 659 | } | ||
| 660 | 679 | ||
| 661 | result = SCTP_STRRESET_PERFORMED; | 680 | result = SCTP_STRRESET_PERFORMED; |
| 662 | 681 | ||
| 663 | *evp = sctp_ulpevent_make_stream_reset_event(asoc, | 682 | *evp = sctp_ulpevent_make_stream_reset_event(asoc, |
| 664 | flags | SCTP_STREAM_RESET_OUTGOING_SSN, nums, str_p, | 683 | SCTP_STREAM_RESET_INCOMING_SSN, nums, str_p, GFP_ATOMIC); |
| 665 | GFP_ATOMIC); | ||
| 666 | 684 | ||
| 667 | out: | 685 | out: |
| 668 | sctp_update_strreset_result(asoc, result); | 686 | sctp_update_strreset_result(asoc, result); |
| @@ -738,9 +756,6 @@ struct sctp_chunk *sctp_process_strreset_inreq( | |||
| 738 | 756 | ||
| 739 | result = SCTP_STRRESET_PERFORMED; | 757 | result = SCTP_STRRESET_PERFORMED; |
| 740 | 758 | ||
| 741 | *evp = sctp_ulpevent_make_stream_reset_event(asoc, | ||
| 742 | SCTP_STREAM_RESET_INCOMING_SSN, nums, str_p, GFP_ATOMIC); | ||
| 743 | |||
| 744 | out: | 759 | out: |
| 745 | sctp_update_strreset_result(asoc, result); | 760 | sctp_update_strreset_result(asoc, result); |
| 746 | err: | 761 | err: |
| @@ -873,6 +888,14 @@ struct sctp_chunk *sctp_process_strreset_addstrm_out( | |||
| 873 | if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ)) | 888 | if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ)) |
| 874 | goto out; | 889 | goto out; |
| 875 | 890 | ||
| 891 | in = ntohs(addstrm->number_of_streams); | ||
| 892 | incnt = stream->incnt + in; | ||
| 893 | if (!in || incnt > SCTP_MAX_STREAM) | ||
| 894 | goto out; | ||
| 895 | |||
| 896 | if (sctp_stream_alloc_in(stream, incnt, GFP_ATOMIC)) | ||
| 897 | goto out; | ||
| 898 | |||
| 876 | if (asoc->strreset_chunk) { | 899 | if (asoc->strreset_chunk) { |
| 877 | if (!sctp_chunk_lookup_strreset_param( | 900 | if (!sctp_chunk_lookup_strreset_param( |
| 878 | asoc, 0, SCTP_PARAM_RESET_ADD_IN_STREAMS)) { | 901 | asoc, 0, SCTP_PARAM_RESET_ADD_IN_STREAMS)) { |
| @@ -896,14 +919,6 @@ struct sctp_chunk *sctp_process_strreset_addstrm_out( | |||
| 896 | } | 919 | } |
| 897 | } | 920 | } |
| 898 | 921 | ||
| 899 | in = ntohs(addstrm->number_of_streams); | ||
| 900 | incnt = stream->incnt + in; | ||
| 901 | if (!in || incnt > SCTP_MAX_STREAM) | ||
| 902 | goto out; | ||
| 903 | |||
| 904 | if (sctp_stream_alloc_in(stream, incnt, GFP_ATOMIC)) | ||
| 905 | goto out; | ||
| 906 | |||
| 907 | stream->incnt = incnt; | 922 | stream->incnt = incnt; |
| 908 | 923 | ||
| 909 | result = SCTP_STRRESET_PERFORMED; | 924 | result = SCTP_STRRESET_PERFORMED; |
| @@ -973,9 +988,6 @@ struct sctp_chunk *sctp_process_strreset_addstrm_in( | |||
| 973 | 988 | ||
| 974 | result = SCTP_STRRESET_PERFORMED; | 989 | result = SCTP_STRRESET_PERFORMED; |
| 975 | 990 | ||
| 976 | *evp = sctp_ulpevent_make_stream_change_event(asoc, | ||
| 977 | 0, 0, ntohs(addstrm->number_of_streams), GFP_ATOMIC); | ||
| 978 | |||
| 979 | out: | 991 | out: |
| 980 | sctp_update_strreset_result(asoc, result); | 992 | sctp_update_strreset_result(asoc, result); |
| 981 | err: | 993 | err: |
| @@ -1036,10 +1048,10 @@ struct sctp_chunk *sctp_process_strreset_resp( | |||
| 1036 | sout->mid_uo = 0; | 1048 | sout->mid_uo = 0; |
| 1037 | } | 1049 | } |
| 1038 | } | 1050 | } |
| 1039 | |||
| 1040 | flags = SCTP_STREAM_RESET_OUTGOING_SSN; | ||
| 1041 | } | 1051 | } |
| 1042 | 1052 | ||
| 1053 | flags |= SCTP_STREAM_RESET_OUTGOING_SSN; | ||
| 1054 | |||
| 1043 | for (i = 0; i < stream->outcnt; i++) | 1055 | for (i = 0; i < stream->outcnt; i++) |
| 1044 | SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN; | 1056 | SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN; |
| 1045 | 1057 | ||
| @@ -1058,6 +1070,8 @@ struct sctp_chunk *sctp_process_strreset_resp( | |||
| 1058 | nums = (ntohs(inreq->param_hdr.length) - sizeof(*inreq)) / | 1070 | nums = (ntohs(inreq->param_hdr.length) - sizeof(*inreq)) / |
| 1059 | sizeof(__u16); | 1071 | sizeof(__u16); |
| 1060 | 1072 | ||
| 1073 | flags |= SCTP_STREAM_RESET_INCOMING_SSN; | ||
| 1074 | |||
| 1061 | *evp = sctp_ulpevent_make_stream_reset_event(asoc, flags, | 1075 | *evp = sctp_ulpevent_make_stream_reset_event(asoc, flags, |
| 1062 | nums, str_p, GFP_ATOMIC); | 1076 | nums, str_p, GFP_ATOMIC); |
| 1063 | } else if (req->type == SCTP_PARAM_RESET_TSN_REQUEST) { | 1077 | } else if (req->type == SCTP_PARAM_RESET_TSN_REQUEST) { |
diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 033696e6f74f..ad158d311ffa 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c | |||
| @@ -207,7 +207,8 @@ void sctp_transport_reset_hb_timer(struct sctp_transport *transport) | |||
| 207 | 207 | ||
| 208 | /* When a data chunk is sent, reset the heartbeat interval. */ | 208 | /* When a data chunk is sent, reset the heartbeat interval. */ |
| 209 | expires = jiffies + sctp_transport_timeout(transport); | 209 | expires = jiffies + sctp_transport_timeout(transport); |
| 210 | if (time_before(transport->hb_timer.expires, expires) && | 210 | if ((time_before(transport->hb_timer.expires, expires) || |
| 211 | !timer_pending(&transport->hb_timer)) && | ||
| 211 | !mod_timer(&transport->hb_timer, | 212 | !mod_timer(&transport->hb_timer, |
| 212 | expires + prandom_u32_max(transport->rto))) | 213 | expires + prandom_u32_max(transport->rto))) |
| 213 | sctp_transport_hold(transport); | 214 | sctp_transport_hold(transport); |
diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c index c4da4a78d369..b04a813fc865 100644 --- a/net/smc/af_smc.c +++ b/net/smc/af_smc.c | |||
| @@ -146,6 +146,9 @@ static int smc_release(struct socket *sock) | |||
| 146 | sock_set_flag(sk, SOCK_DEAD); | 146 | sock_set_flag(sk, SOCK_DEAD); |
| 147 | sk->sk_shutdown |= SHUTDOWN_MASK; | 147 | sk->sk_shutdown |= SHUTDOWN_MASK; |
| 148 | } | 148 | } |
| 149 | |||
| 150 | sk->sk_prot->unhash(sk); | ||
| 151 | |||
| 149 | if (smc->clcsock) { | 152 | if (smc->clcsock) { |
| 150 | if (smc->use_fallback && sk->sk_state == SMC_LISTEN) { | 153 | if (smc->use_fallback && sk->sk_state == SMC_LISTEN) { |
| 151 | /* wake up clcsock accept */ | 154 | /* wake up clcsock accept */ |
| @@ -170,7 +173,6 @@ static int smc_release(struct socket *sock) | |||
| 170 | smc_conn_free(&smc->conn); | 173 | smc_conn_free(&smc->conn); |
| 171 | release_sock(sk); | 174 | release_sock(sk); |
| 172 | 175 | ||
| 173 | sk->sk_prot->unhash(sk); | ||
| 174 | sock_put(sk); /* final sock_put */ | 176 | sock_put(sk); /* final sock_put */ |
| 175 | out: | 177 | out: |
| 176 | return rc; | 178 | return rc; |
| @@ -1503,6 +1505,11 @@ static int smc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, | |||
| 1503 | 1505 | ||
| 1504 | smc = smc_sk(sk); | 1506 | smc = smc_sk(sk); |
| 1505 | lock_sock(sk); | 1507 | lock_sock(sk); |
| 1508 | if (sk->sk_state == SMC_CLOSED && (sk->sk_shutdown & RCV_SHUTDOWN)) { | ||
| 1509 | /* socket was connected before, no more data to read */ | ||
| 1510 | rc = 0; | ||
| 1511 | goto out; | ||
| 1512 | } | ||
| 1506 | if ((sk->sk_state == SMC_INIT) || | 1513 | if ((sk->sk_state == SMC_INIT) || |
| 1507 | (sk->sk_state == SMC_LISTEN) || | 1514 | (sk->sk_state == SMC_LISTEN) || |
| 1508 | (sk->sk_state == SMC_CLOSED)) | 1515 | (sk->sk_state == SMC_CLOSED)) |
| @@ -1838,7 +1845,11 @@ static ssize_t smc_splice_read(struct socket *sock, loff_t *ppos, | |||
| 1838 | 1845 | ||
| 1839 | smc = smc_sk(sk); | 1846 | smc = smc_sk(sk); |
| 1840 | lock_sock(sk); | 1847 | lock_sock(sk); |
| 1841 | 1848 | if (sk->sk_state == SMC_CLOSED && (sk->sk_shutdown & RCV_SHUTDOWN)) { | |
| 1849 | /* socket was connected before, no more data to read */ | ||
| 1850 | rc = 0; | ||
| 1851 | goto out; | ||
| 1852 | } | ||
| 1842 | if (sk->sk_state == SMC_INIT || | 1853 | if (sk->sk_state == SMC_INIT || |
| 1843 | sk->sk_state == SMC_LISTEN || | 1854 | sk->sk_state == SMC_LISTEN || |
| 1844 | sk->sk_state == SMC_CLOSED) | 1855 | sk->sk_state == SMC_CLOSED) |
diff --git a/net/smc/smc.h b/net/smc/smc.h index 5721416d0605..adbdf195eb08 100644 --- a/net/smc/smc.h +++ b/net/smc/smc.h | |||
| @@ -113,9 +113,9 @@ struct smc_host_cdc_msg { /* Connection Data Control message */ | |||
| 113 | } __aligned(8); | 113 | } __aligned(8); |
| 114 | 114 | ||
| 115 | enum smc_urg_state { | 115 | enum smc_urg_state { |
| 116 | SMC_URG_VALID, /* data present */ | 116 | SMC_URG_VALID = 1, /* data present */ |
| 117 | SMC_URG_NOTYET, /* data pending */ | 117 | SMC_URG_NOTYET = 2, /* data pending */ |
| 118 | SMC_URG_READ /* data was already read */ | 118 | SMC_URG_READ = 3, /* data was already read */ |
| 119 | }; | 119 | }; |
| 120 | 120 | ||
| 121 | struct smc_connection { | 121 | struct smc_connection { |
diff --git a/net/smc/smc_cdc.c b/net/smc/smc_cdc.c index db83332ac1c8..fb07ad8d69a6 100644 --- a/net/smc/smc_cdc.c +++ b/net/smc/smc_cdc.c | |||
| @@ -21,13 +21,6 @@ | |||
| 21 | 21 | ||
| 22 | /********************************** send *************************************/ | 22 | /********************************** send *************************************/ |
| 23 | 23 | ||
| 24 | struct smc_cdc_tx_pend { | ||
| 25 | struct smc_connection *conn; /* socket connection */ | ||
| 26 | union smc_host_cursor cursor; /* tx sndbuf cursor sent */ | ||
| 27 | union smc_host_cursor p_cursor; /* rx RMBE cursor produced */ | ||
| 28 | u16 ctrl_seq; /* conn. tx sequence # */ | ||
| 29 | }; | ||
| 30 | |||
| 31 | /* handler for send/transmission completion of a CDC msg */ | 24 | /* handler for send/transmission completion of a CDC msg */ |
| 32 | static void smc_cdc_tx_handler(struct smc_wr_tx_pend_priv *pnd_snd, | 25 | static void smc_cdc_tx_handler(struct smc_wr_tx_pend_priv *pnd_snd, |
| 33 | struct smc_link *link, | 26 | struct smc_link *link, |
| @@ -61,12 +54,14 @@ static void smc_cdc_tx_handler(struct smc_wr_tx_pend_priv *pnd_snd, | |||
| 61 | 54 | ||
| 62 | int smc_cdc_get_free_slot(struct smc_connection *conn, | 55 | int smc_cdc_get_free_slot(struct smc_connection *conn, |
| 63 | struct smc_wr_buf **wr_buf, | 56 | struct smc_wr_buf **wr_buf, |
| 57 | struct smc_rdma_wr **wr_rdma_buf, | ||
| 64 | struct smc_cdc_tx_pend **pend) | 58 | struct smc_cdc_tx_pend **pend) |
| 65 | { | 59 | { |
| 66 | struct smc_link *link = &conn->lgr->lnk[SMC_SINGLE_LINK]; | 60 | struct smc_link *link = &conn->lgr->lnk[SMC_SINGLE_LINK]; |
| 67 | int rc; | 61 | int rc; |
| 68 | 62 | ||
| 69 | rc = smc_wr_tx_get_free_slot(link, smc_cdc_tx_handler, wr_buf, | 63 | rc = smc_wr_tx_get_free_slot(link, smc_cdc_tx_handler, wr_buf, |
| 64 | wr_rdma_buf, | ||
| 70 | (struct smc_wr_tx_pend_priv **)pend); | 65 | (struct smc_wr_tx_pend_priv **)pend); |
| 71 | if (!conn->alert_token_local) | 66 | if (!conn->alert_token_local) |
| 72 | /* abnormal termination */ | 67 | /* abnormal termination */ |
| @@ -96,6 +91,7 @@ int smc_cdc_msg_send(struct smc_connection *conn, | |||
| 96 | struct smc_wr_buf *wr_buf, | 91 | struct smc_wr_buf *wr_buf, |
| 97 | struct smc_cdc_tx_pend *pend) | 92 | struct smc_cdc_tx_pend *pend) |
| 98 | { | 93 | { |
| 94 | union smc_host_cursor cfed; | ||
| 99 | struct smc_link *link; | 95 | struct smc_link *link; |
| 100 | int rc; | 96 | int rc; |
| 101 | 97 | ||
| @@ -105,12 +101,10 @@ int smc_cdc_msg_send(struct smc_connection *conn, | |||
| 105 | 101 | ||
| 106 | conn->tx_cdc_seq++; | 102 | conn->tx_cdc_seq++; |
| 107 | conn->local_tx_ctrl.seqno = conn->tx_cdc_seq; | 103 | conn->local_tx_ctrl.seqno = conn->tx_cdc_seq; |
| 108 | smc_host_msg_to_cdc((struct smc_cdc_msg *)wr_buf, | 104 | smc_host_msg_to_cdc((struct smc_cdc_msg *)wr_buf, conn, &cfed); |
| 109 | &conn->local_tx_ctrl, conn); | ||
| 110 | rc = smc_wr_tx_send(link, (struct smc_wr_tx_pend_priv *)pend); | 105 | rc = smc_wr_tx_send(link, (struct smc_wr_tx_pend_priv *)pend); |
| 111 | if (!rc) | 106 | if (!rc) |
| 112 | smc_curs_copy(&conn->rx_curs_confirmed, | 107 | smc_curs_copy(&conn->rx_curs_confirmed, &cfed, conn); |
| 113 | &conn->local_tx_ctrl.cons, conn); | ||
| 114 | 108 | ||
| 115 | return rc; | 109 | return rc; |
| 116 | } | 110 | } |
| @@ -121,11 +115,14 @@ static int smcr_cdc_get_slot_and_msg_send(struct smc_connection *conn) | |||
| 121 | struct smc_wr_buf *wr_buf; | 115 | struct smc_wr_buf *wr_buf; |
| 122 | int rc; | 116 | int rc; |
| 123 | 117 | ||
| 124 | rc = smc_cdc_get_free_slot(conn, &wr_buf, &pend); | 118 | rc = smc_cdc_get_free_slot(conn, &wr_buf, NULL, &pend); |
| 125 | if (rc) | 119 | if (rc) |
| 126 | return rc; | 120 | return rc; |
| 127 | 121 | ||
| 128 | return smc_cdc_msg_send(conn, wr_buf, pend); | 122 | spin_lock_bh(&conn->send_lock); |
| 123 | rc = smc_cdc_msg_send(conn, wr_buf, pend); | ||
| 124 | spin_unlock_bh(&conn->send_lock); | ||
| 125 | return rc; | ||
| 129 | } | 126 | } |
| 130 | 127 | ||
| 131 | int smc_cdc_get_slot_and_msg_send(struct smc_connection *conn) | 128 | int smc_cdc_get_slot_and_msg_send(struct smc_connection *conn) |
diff --git a/net/smc/smc_cdc.h b/net/smc/smc_cdc.h index b5bfe38c7f9b..f1cdde9d4b89 100644 --- a/net/smc/smc_cdc.h +++ b/net/smc/smc_cdc.h | |||
| @@ -160,7 +160,9 @@ static inline void smcd_curs_copy(union smcd_cdc_cursor *tgt, | |||
| 160 | #endif | 160 | #endif |
| 161 | } | 161 | } |
| 162 | 162 | ||
| 163 | /* calculate cursor difference between old and new, where old <= new */ | 163 | /* calculate cursor difference between old and new, where old <= new and |
| 164 | * difference cannot exceed size | ||
| 165 | */ | ||
| 164 | static inline int smc_curs_diff(unsigned int size, | 166 | static inline int smc_curs_diff(unsigned int size, |
| 165 | union smc_host_cursor *old, | 167 | union smc_host_cursor *old, |
| 166 | union smc_host_cursor *new) | 168 | union smc_host_cursor *new) |
| @@ -185,28 +187,51 @@ static inline int smc_curs_comp(unsigned int size, | |||
| 185 | return smc_curs_diff(size, old, new); | 187 | return smc_curs_diff(size, old, new); |
| 186 | } | 188 | } |
| 187 | 189 | ||
| 190 | /* calculate cursor difference between old and new, where old <= new and | ||
| 191 | * difference may exceed size | ||
| 192 | */ | ||
| 193 | static inline int smc_curs_diff_large(unsigned int size, | ||
| 194 | union smc_host_cursor *old, | ||
| 195 | union smc_host_cursor *new) | ||
| 196 | { | ||
| 197 | if (old->wrap < new->wrap) | ||
| 198 | return min_t(int, | ||
| 199 | (size - old->count) + new->count + | ||
| 200 | (new->wrap - old->wrap - 1) * size, | ||
| 201 | size); | ||
| 202 | |||
| 203 | if (old->wrap > new->wrap) /* wrap has switched from 0xffff to 0x0000 */ | ||
| 204 | return min_t(int, | ||
| 205 | (size - old->count) + new->count + | ||
| 206 | (new->wrap + 0xffff - old->wrap) * size, | ||
| 207 | size); | ||
| 208 | |||
| 209 | return max_t(int, 0, (new->count - old->count)); | ||
| 210 | } | ||
| 211 | |||
| 188 | static inline void smc_host_cursor_to_cdc(union smc_cdc_cursor *peer, | 212 | static inline void smc_host_cursor_to_cdc(union smc_cdc_cursor *peer, |
| 189 | union smc_host_cursor *local, | 213 | union smc_host_cursor *local, |
| 214 | union smc_host_cursor *save, | ||
| 190 | struct smc_connection *conn) | 215 | struct smc_connection *conn) |
| 191 | { | 216 | { |
| 192 | union smc_host_cursor temp; | 217 | smc_curs_copy(save, local, conn); |
| 193 | 218 | peer->count = htonl(save->count); | |
| 194 | smc_curs_copy(&temp, local, conn); | 219 | peer->wrap = htons(save->wrap); |
| 195 | peer->count = htonl(temp.count); | ||
| 196 | peer->wrap = htons(temp.wrap); | ||
| 197 | /* peer->reserved = htons(0); must be ensured by caller */ | 220 | /* peer->reserved = htons(0); must be ensured by caller */ |
| 198 | } | 221 | } |
| 199 | 222 | ||
| 200 | static inline void smc_host_msg_to_cdc(struct smc_cdc_msg *peer, | 223 | static inline void smc_host_msg_to_cdc(struct smc_cdc_msg *peer, |
| 201 | struct smc_host_cdc_msg *local, | 224 | struct smc_connection *conn, |
| 202 | struct smc_connection *conn) | 225 | union smc_host_cursor *save) |
| 203 | { | 226 | { |
| 227 | struct smc_host_cdc_msg *local = &conn->local_tx_ctrl; | ||
| 228 | |||
| 204 | peer->common.type = local->common.type; | 229 | peer->common.type = local->common.type; |
| 205 | peer->len = local->len; | 230 | peer->len = local->len; |
| 206 | peer->seqno = htons(local->seqno); | 231 | peer->seqno = htons(local->seqno); |
| 207 | peer->token = htonl(local->token); | 232 | peer->token = htonl(local->token); |
| 208 | smc_host_cursor_to_cdc(&peer->prod, &local->prod, conn); | 233 | smc_host_cursor_to_cdc(&peer->prod, &local->prod, save, conn); |
| 209 | smc_host_cursor_to_cdc(&peer->cons, &local->cons, conn); | 234 | smc_host_cursor_to_cdc(&peer->cons, &local->cons, save, conn); |
| 210 | peer->prod_flags = local->prod_flags; | 235 | peer->prod_flags = local->prod_flags; |
| 211 | peer->conn_state_flags = local->conn_state_flags; | 236 | peer->conn_state_flags = local->conn_state_flags; |
| 212 | } | 237 | } |
| @@ -270,10 +295,16 @@ static inline void smc_cdc_msg_to_host(struct smc_host_cdc_msg *local, | |||
| 270 | smcr_cdc_msg_to_host(local, peer, conn); | 295 | smcr_cdc_msg_to_host(local, peer, conn); |
| 271 | } | 296 | } |
| 272 | 297 | ||
| 273 | struct smc_cdc_tx_pend; | 298 | struct smc_cdc_tx_pend { |
| 299 | struct smc_connection *conn; /* socket connection */ | ||
| 300 | union smc_host_cursor cursor; /* tx sndbuf cursor sent */ | ||
| 301 | union smc_host_cursor p_cursor; /* rx RMBE cursor produced */ | ||
| 302 | u16 ctrl_seq; /* conn. tx sequence # */ | ||
| 303 | }; | ||
| 274 | 304 | ||
| 275 | int smc_cdc_get_free_slot(struct smc_connection *conn, | 305 | int smc_cdc_get_free_slot(struct smc_connection *conn, |
| 276 | struct smc_wr_buf **wr_buf, | 306 | struct smc_wr_buf **wr_buf, |
| 307 | struct smc_rdma_wr **wr_rdma_buf, | ||
| 277 | struct smc_cdc_tx_pend **pend); | 308 | struct smc_cdc_tx_pend **pend); |
| 278 | void smc_cdc_tx_dismiss_slots(struct smc_connection *conn); | 309 | void smc_cdc_tx_dismiss_slots(struct smc_connection *conn); |
| 279 | int smc_cdc_msg_send(struct smc_connection *conn, struct smc_wr_buf *wr_buf, | 310 | int smc_cdc_msg_send(struct smc_connection *conn, struct smc_wr_buf *wr_buf, |
diff --git a/net/smc/smc_clc.c b/net/smc/smc_clc.c index 776e9dfc915d..d53fd588d1f5 100644 --- a/net/smc/smc_clc.c +++ b/net/smc/smc_clc.c | |||
| @@ -378,7 +378,7 @@ int smc_clc_send_decline(struct smc_sock *smc, u32 peer_diag_info) | |||
| 378 | vec.iov_len = sizeof(struct smc_clc_msg_decline); | 378 | vec.iov_len = sizeof(struct smc_clc_msg_decline); |
| 379 | len = kernel_sendmsg(smc->clcsock, &msg, &vec, 1, | 379 | len = kernel_sendmsg(smc->clcsock, &msg, &vec, 1, |
| 380 | sizeof(struct smc_clc_msg_decline)); | 380 | sizeof(struct smc_clc_msg_decline)); |
| 381 | if (len < sizeof(struct smc_clc_msg_decline)) | 381 | if (len < 0 || len < sizeof(struct smc_clc_msg_decline)) |
| 382 | len = -EPROTO; | 382 | len = -EPROTO; |
| 383 | return len > 0 ? 0 : len; | 383 | return len > 0 ? 0 : len; |
| 384 | } | 384 | } |
diff --git a/net/smc/smc_close.c b/net/smc/smc_close.c index ea2b87f29469..e39cadda1bf5 100644 --- a/net/smc/smc_close.c +++ b/net/smc/smc_close.c | |||
| @@ -345,14 +345,7 @@ static void smc_close_passive_work(struct work_struct *work) | |||
| 345 | 345 | ||
| 346 | switch (sk->sk_state) { | 346 | switch (sk->sk_state) { |
| 347 | case SMC_INIT: | 347 | case SMC_INIT: |
| 348 | if (atomic_read(&conn->bytes_to_rcv) || | 348 | sk->sk_state = SMC_APPCLOSEWAIT1; |
| 349 | (rxflags->peer_done_writing && | ||
| 350 | !smc_cdc_rxed_any_close(conn))) { | ||
| 351 | sk->sk_state = SMC_APPCLOSEWAIT1; | ||
| 352 | } else { | ||
| 353 | sk->sk_state = SMC_CLOSED; | ||
| 354 | sock_put(sk); /* passive closing */ | ||
| 355 | } | ||
| 356 | break; | 349 | break; |
| 357 | case SMC_ACTIVE: | 350 | case SMC_ACTIVE: |
| 358 | sk->sk_state = SMC_APPCLOSEWAIT1; | 351 | sk->sk_state = SMC_APPCLOSEWAIT1; |
diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c index 35c1cdc93e1c..aa1c551cee81 100644 --- a/net/smc/smc_core.c +++ b/net/smc/smc_core.c | |||
| @@ -128,6 +128,8 @@ static void smc_lgr_unregister_conn(struct smc_connection *conn) | |||
| 128 | { | 128 | { |
| 129 | struct smc_link_group *lgr = conn->lgr; | 129 | struct smc_link_group *lgr = conn->lgr; |
| 130 | 130 | ||
| 131 | if (!lgr) | ||
| 132 | return; | ||
| 131 | write_lock_bh(&lgr->conns_lock); | 133 | write_lock_bh(&lgr->conns_lock); |
| 132 | if (conn->alert_token_local) { | 134 | if (conn->alert_token_local) { |
| 133 | __smc_lgr_unregister_conn(conn); | 135 | __smc_lgr_unregister_conn(conn); |
| @@ -300,13 +302,13 @@ static void smc_buf_unuse(struct smc_connection *conn, | |||
| 300 | conn->sndbuf_desc->used = 0; | 302 | conn->sndbuf_desc->used = 0; |
| 301 | if (conn->rmb_desc) { | 303 | if (conn->rmb_desc) { |
| 302 | if (!conn->rmb_desc->regerr) { | 304 | if (!conn->rmb_desc->regerr) { |
| 303 | conn->rmb_desc->used = 0; | ||
| 304 | if (!lgr->is_smcd) { | 305 | if (!lgr->is_smcd) { |
| 305 | /* unregister rmb with peer */ | 306 | /* unregister rmb with peer */ |
| 306 | smc_llc_do_delete_rkey( | 307 | smc_llc_do_delete_rkey( |
| 307 | &lgr->lnk[SMC_SINGLE_LINK], | 308 | &lgr->lnk[SMC_SINGLE_LINK], |
| 308 | conn->rmb_desc); | 309 | conn->rmb_desc); |
| 309 | } | 310 | } |
| 311 | conn->rmb_desc->used = 0; | ||
| 310 | } else { | 312 | } else { |
| 311 | /* buf registration failed, reuse not possible */ | 313 | /* buf registration failed, reuse not possible */ |
| 312 | write_lock_bh(&lgr->rmbs_lock); | 314 | write_lock_bh(&lgr->rmbs_lock); |
| @@ -628,6 +630,8 @@ int smc_conn_create(struct smc_sock *smc, bool is_smcd, int srv_first_contact, | |||
| 628 | local_contact = SMC_REUSE_CONTACT; | 630 | local_contact = SMC_REUSE_CONTACT; |
| 629 | conn->lgr = lgr; | 631 | conn->lgr = lgr; |
| 630 | smc_lgr_register_conn(conn); /* add smc conn to lgr */ | 632 | smc_lgr_register_conn(conn); /* add smc conn to lgr */ |
| 633 | if (delayed_work_pending(&lgr->free_work)) | ||
| 634 | cancel_delayed_work(&lgr->free_work); | ||
| 631 | write_unlock_bh(&lgr->conns_lock); | 635 | write_unlock_bh(&lgr->conns_lock); |
| 632 | break; | 636 | break; |
| 633 | } | 637 | } |
diff --git a/net/smc/smc_core.h b/net/smc/smc_core.h index b00287989a3d..8806d2afa6ed 100644 --- a/net/smc/smc_core.h +++ b/net/smc/smc_core.h | |||
| @@ -52,6 +52,24 @@ enum smc_wr_reg_state { | |||
| 52 | FAILED /* ib_wr_reg_mr response: failure */ | 52 | FAILED /* ib_wr_reg_mr response: failure */ |
| 53 | }; | 53 | }; |
| 54 | 54 | ||
| 55 | struct smc_rdma_sge { /* sges for RDMA writes */ | ||
| 56 | struct ib_sge wr_tx_rdma_sge[SMC_IB_MAX_SEND_SGE]; | ||
| 57 | }; | ||
| 58 | |||
| 59 | #define SMC_MAX_RDMA_WRITES 2 /* max. # of RDMA writes per | ||
| 60 | * message send | ||
| 61 | */ | ||
| 62 | |||
| 63 | struct smc_rdma_sges { /* sges per message send */ | ||
| 64 | struct smc_rdma_sge tx_rdma_sge[SMC_MAX_RDMA_WRITES]; | ||
| 65 | }; | ||
| 66 | |||
| 67 | struct smc_rdma_wr { /* work requests per message | ||
| 68 | * send | ||
| 69 | */ | ||
| 70 | struct ib_rdma_wr wr_tx_rdma[SMC_MAX_RDMA_WRITES]; | ||
| 71 | }; | ||
| 72 | |||
| 55 | struct smc_link { | 73 | struct smc_link { |
| 56 | struct smc_ib_device *smcibdev; /* ib-device */ | 74 | struct smc_ib_device *smcibdev; /* ib-device */ |
| 57 | u8 ibport; /* port - values 1 | 2 */ | 75 | u8 ibport; /* port - values 1 | 2 */ |
| @@ -64,6 +82,8 @@ struct smc_link { | |||
| 64 | struct smc_wr_buf *wr_tx_bufs; /* WR send payload buffers */ | 82 | struct smc_wr_buf *wr_tx_bufs; /* WR send payload buffers */ |
| 65 | struct ib_send_wr *wr_tx_ibs; /* WR send meta data */ | 83 | struct ib_send_wr *wr_tx_ibs; /* WR send meta data */ |
| 66 | struct ib_sge *wr_tx_sges; /* WR send gather meta data */ | 84 | struct ib_sge *wr_tx_sges; /* WR send gather meta data */ |
| 85 | struct smc_rdma_sges *wr_tx_rdma_sges;/*RDMA WRITE gather meta data*/ | ||
| 86 | struct smc_rdma_wr *wr_tx_rdmas; /* WR RDMA WRITE */ | ||
| 67 | struct smc_wr_tx_pend *wr_tx_pends; /* WR send waiting for CQE */ | 87 | struct smc_wr_tx_pend *wr_tx_pends; /* WR send waiting for CQE */ |
| 68 | /* above four vectors have wr_tx_cnt elements and use the same index */ | 88 | /* above four vectors have wr_tx_cnt elements and use the same index */ |
| 69 | dma_addr_t wr_tx_dma_addr; /* DMA address of wr_tx_bufs */ | 89 | dma_addr_t wr_tx_dma_addr; /* DMA address of wr_tx_bufs */ |
diff --git a/net/smc/smc_ib.c b/net/smc/smc_ib.c index e519ef29c0ff..76487a16934e 100644 --- a/net/smc/smc_ib.c +++ b/net/smc/smc_ib.c | |||
| @@ -289,8 +289,8 @@ int smc_ib_create_protection_domain(struct smc_link *lnk) | |||
| 289 | 289 | ||
| 290 | static void smc_ib_qp_event_handler(struct ib_event *ibevent, void *priv) | 290 | static void smc_ib_qp_event_handler(struct ib_event *ibevent, void *priv) |
| 291 | { | 291 | { |
| 292 | struct smc_ib_device *smcibdev = | 292 | struct smc_link *lnk = (struct smc_link *)priv; |
| 293 | (struct smc_ib_device *)ibevent->device; | 293 | struct smc_ib_device *smcibdev = lnk->smcibdev; |
| 294 | u8 port_idx; | 294 | u8 port_idx; |
| 295 | 295 | ||
| 296 | switch (ibevent->event) { | 296 | switch (ibevent->event) { |
| @@ -298,7 +298,7 @@ static void smc_ib_qp_event_handler(struct ib_event *ibevent, void *priv) | |||
| 298 | case IB_EVENT_GID_CHANGE: | 298 | case IB_EVENT_GID_CHANGE: |
| 299 | case IB_EVENT_PORT_ERR: | 299 | case IB_EVENT_PORT_ERR: |
| 300 | case IB_EVENT_QP_ACCESS_ERR: | 300 | case IB_EVENT_QP_ACCESS_ERR: |
| 301 | port_idx = ibevent->element.port_num - 1; | 301 | port_idx = ibevent->element.qp->port - 1; |
| 302 | set_bit(port_idx, &smcibdev->port_event_mask); | 302 | set_bit(port_idx, &smcibdev->port_event_mask); |
| 303 | schedule_work(&smcibdev->port_event_work); | 303 | schedule_work(&smcibdev->port_event_work); |
| 304 | break; | 304 | break; |
diff --git a/net/smc/smc_llc.c b/net/smc/smc_llc.c index a6d3623d06f4..4fd60c522802 100644 --- a/net/smc/smc_llc.c +++ b/net/smc/smc_llc.c | |||
| @@ -166,7 +166,8 @@ static int smc_llc_add_pending_send(struct smc_link *link, | |||
| 166 | { | 166 | { |
| 167 | int rc; | 167 | int rc; |
| 168 | 168 | ||
| 169 | rc = smc_wr_tx_get_free_slot(link, smc_llc_tx_handler, wr_buf, pend); | 169 | rc = smc_wr_tx_get_free_slot(link, smc_llc_tx_handler, wr_buf, NULL, |
| 170 | pend); | ||
| 170 | if (rc < 0) | 171 | if (rc < 0) |
| 171 | return rc; | 172 | return rc; |
| 172 | BUILD_BUG_ON_MSG( | 173 | BUILD_BUG_ON_MSG( |
diff --git a/net/smc/smc_pnet.c b/net/smc/smc_pnet.c index 7cb3e4f07c10..632c3109dee5 100644 --- a/net/smc/smc_pnet.c +++ b/net/smc/smc_pnet.c | |||
| @@ -27,7 +27,7 @@ | |||
| 27 | static struct nla_policy smc_pnet_policy[SMC_PNETID_MAX + 1] = { | 27 | static struct nla_policy smc_pnet_policy[SMC_PNETID_MAX + 1] = { |
| 28 | [SMC_PNETID_NAME] = { | 28 | [SMC_PNETID_NAME] = { |
| 29 | .type = NLA_NUL_STRING, | 29 | .type = NLA_NUL_STRING, |
| 30 | .len = SMC_MAX_PNETID_LEN - 1 | 30 | .len = SMC_MAX_PNETID_LEN |
| 31 | }, | 31 | }, |
| 32 | [SMC_PNETID_ETHNAME] = { | 32 | [SMC_PNETID_ETHNAME] = { |
| 33 | .type = NLA_NUL_STRING, | 33 | .type = NLA_NUL_STRING, |
diff --git a/net/smc/smc_tx.c b/net/smc/smc_tx.c index d8366ed51757..f93f3580c100 100644 --- a/net/smc/smc_tx.c +++ b/net/smc/smc_tx.c | |||
| @@ -165,12 +165,11 @@ int smc_tx_sendmsg(struct smc_sock *smc, struct msghdr *msg, size_t len) | |||
| 165 | conn->local_tx_ctrl.prod_flags.urg_data_pending = 1; | 165 | conn->local_tx_ctrl.prod_flags.urg_data_pending = 1; |
| 166 | 166 | ||
| 167 | if (!atomic_read(&conn->sndbuf_space) || conn->urg_tx_pend) { | 167 | if (!atomic_read(&conn->sndbuf_space) || conn->urg_tx_pend) { |
| 168 | if (send_done) | ||
| 169 | return send_done; | ||
| 168 | rc = smc_tx_wait(smc, msg->msg_flags); | 170 | rc = smc_tx_wait(smc, msg->msg_flags); |
| 169 | if (rc) { | 171 | if (rc) |
| 170 | if (send_done) | ||
| 171 | return send_done; | ||
| 172 | goto out_err; | 172 | goto out_err; |
| 173 | } | ||
| 174 | continue; | 173 | continue; |
| 175 | } | 174 | } |
| 176 | 175 | ||
| @@ -267,27 +266,23 @@ int smcd_tx_ism_write(struct smc_connection *conn, void *data, size_t len, | |||
| 267 | 266 | ||
| 268 | /* sndbuf consumer: actual data transfer of one target chunk with RDMA write */ | 267 | /* sndbuf consumer: actual data transfer of one target chunk with RDMA write */ |
| 269 | static int smc_tx_rdma_write(struct smc_connection *conn, int peer_rmbe_offset, | 268 | static int smc_tx_rdma_write(struct smc_connection *conn, int peer_rmbe_offset, |
| 270 | int num_sges, struct ib_sge sges[]) | 269 | int num_sges, struct ib_rdma_wr *rdma_wr) |
| 271 | { | 270 | { |
| 272 | struct smc_link_group *lgr = conn->lgr; | 271 | struct smc_link_group *lgr = conn->lgr; |
| 273 | struct ib_rdma_wr rdma_wr; | ||
| 274 | struct smc_link *link; | 272 | struct smc_link *link; |
| 275 | int rc; | 273 | int rc; |
| 276 | 274 | ||
| 277 | memset(&rdma_wr, 0, sizeof(rdma_wr)); | ||
| 278 | link = &lgr->lnk[SMC_SINGLE_LINK]; | 275 | link = &lgr->lnk[SMC_SINGLE_LINK]; |
| 279 | rdma_wr.wr.wr_id = smc_wr_tx_get_next_wr_id(link); | 276 | rdma_wr->wr.wr_id = smc_wr_tx_get_next_wr_id(link); |
| 280 | rdma_wr.wr.sg_list = sges; | 277 | rdma_wr->wr.num_sge = num_sges; |
| 281 | rdma_wr.wr.num_sge = num_sges; | 278 | rdma_wr->remote_addr = |
| 282 | rdma_wr.wr.opcode = IB_WR_RDMA_WRITE; | ||
| 283 | rdma_wr.remote_addr = | ||
| 284 | lgr->rtokens[conn->rtoken_idx][SMC_SINGLE_LINK].dma_addr + | 279 | lgr->rtokens[conn->rtoken_idx][SMC_SINGLE_LINK].dma_addr + |
| 285 | /* RMBE within RMB */ | 280 | /* RMBE within RMB */ |
| 286 | conn->tx_off + | 281 | conn->tx_off + |
| 287 | /* offset within RMBE */ | 282 | /* offset within RMBE */ |
| 288 | peer_rmbe_offset; | 283 | peer_rmbe_offset; |
| 289 | rdma_wr.rkey = lgr->rtokens[conn->rtoken_idx][SMC_SINGLE_LINK].rkey; | 284 | rdma_wr->rkey = lgr->rtokens[conn->rtoken_idx][SMC_SINGLE_LINK].rkey; |
| 290 | rc = ib_post_send(link->roce_qp, &rdma_wr.wr, NULL); | 285 | rc = ib_post_send(link->roce_qp, &rdma_wr->wr, NULL); |
| 291 | if (rc) { | 286 | if (rc) { |
| 292 | conn->local_tx_ctrl.conn_state_flags.peer_conn_abort = 1; | 287 | conn->local_tx_ctrl.conn_state_flags.peer_conn_abort = 1; |
| 293 | smc_lgr_terminate(lgr); | 288 | smc_lgr_terminate(lgr); |
| @@ -314,24 +309,25 @@ static inline void smc_tx_advance_cursors(struct smc_connection *conn, | |||
| 314 | /* SMC-R helper for smc_tx_rdma_writes() */ | 309 | /* SMC-R helper for smc_tx_rdma_writes() */ |
| 315 | static int smcr_tx_rdma_writes(struct smc_connection *conn, size_t len, | 310 | static int smcr_tx_rdma_writes(struct smc_connection *conn, size_t len, |
| 316 | size_t src_off, size_t src_len, | 311 | size_t src_off, size_t src_len, |
| 317 | size_t dst_off, size_t dst_len) | 312 | size_t dst_off, size_t dst_len, |
| 313 | struct smc_rdma_wr *wr_rdma_buf) | ||
| 318 | { | 314 | { |
| 319 | dma_addr_t dma_addr = | 315 | dma_addr_t dma_addr = |
| 320 | sg_dma_address(conn->sndbuf_desc->sgt[SMC_SINGLE_LINK].sgl); | 316 | sg_dma_address(conn->sndbuf_desc->sgt[SMC_SINGLE_LINK].sgl); |
| 321 | struct smc_link *link = &conn->lgr->lnk[SMC_SINGLE_LINK]; | ||
| 322 | int src_len_sum = src_len, dst_len_sum = dst_len; | 317 | int src_len_sum = src_len, dst_len_sum = dst_len; |
| 323 | struct ib_sge sges[SMC_IB_MAX_SEND_SGE]; | ||
| 324 | int sent_count = src_off; | 318 | int sent_count = src_off; |
| 325 | int srcchunk, dstchunk; | 319 | int srcchunk, dstchunk; |
| 326 | int num_sges; | 320 | int num_sges; |
| 327 | int rc; | 321 | int rc; |
| 328 | 322 | ||
| 329 | for (dstchunk = 0; dstchunk < 2; dstchunk++) { | 323 | for (dstchunk = 0; dstchunk < 2; dstchunk++) { |
| 324 | struct ib_sge *sge = | ||
| 325 | wr_rdma_buf->wr_tx_rdma[dstchunk].wr.sg_list; | ||
| 326 | |||
| 330 | num_sges = 0; | 327 | num_sges = 0; |
| 331 | for (srcchunk = 0; srcchunk < 2; srcchunk++) { | 328 | for (srcchunk = 0; srcchunk < 2; srcchunk++) { |
| 332 | sges[srcchunk].addr = dma_addr + src_off; | 329 | sge[srcchunk].addr = dma_addr + src_off; |
| 333 | sges[srcchunk].length = src_len; | 330 | sge[srcchunk].length = src_len; |
| 334 | sges[srcchunk].lkey = link->roce_pd->local_dma_lkey; | ||
| 335 | num_sges++; | 331 | num_sges++; |
| 336 | 332 | ||
| 337 | src_off += src_len; | 333 | src_off += src_len; |
| @@ -344,7 +340,8 @@ static int smcr_tx_rdma_writes(struct smc_connection *conn, size_t len, | |||
| 344 | src_len = dst_len - src_len; /* remainder */ | 340 | src_len = dst_len - src_len; /* remainder */ |
| 345 | src_len_sum += src_len; | 341 | src_len_sum += src_len; |
| 346 | } | 342 | } |
| 347 | rc = smc_tx_rdma_write(conn, dst_off, num_sges, sges); | 343 | rc = smc_tx_rdma_write(conn, dst_off, num_sges, |
| 344 | &wr_rdma_buf->wr_tx_rdma[dstchunk]); | ||
| 348 | if (rc) | 345 | if (rc) |
| 349 | return rc; | 346 | return rc; |
| 350 | if (dst_len_sum == len) | 347 | if (dst_len_sum == len) |
| @@ -403,7 +400,8 @@ static int smcd_tx_rdma_writes(struct smc_connection *conn, size_t len, | |||
| 403 | /* sndbuf consumer: prepare all necessary (src&dst) chunks of data transmit; | 400 | /* sndbuf consumer: prepare all necessary (src&dst) chunks of data transmit; |
| 404 | * usable snd_wnd as max transmit | 401 | * usable snd_wnd as max transmit |
| 405 | */ | 402 | */ |
| 406 | static int smc_tx_rdma_writes(struct smc_connection *conn) | 403 | static int smc_tx_rdma_writes(struct smc_connection *conn, |
| 404 | struct smc_rdma_wr *wr_rdma_buf) | ||
| 407 | { | 405 | { |
| 408 | size_t len, src_len, dst_off, dst_len; /* current chunk values */ | 406 | size_t len, src_len, dst_off, dst_len; /* current chunk values */ |
| 409 | union smc_host_cursor sent, prep, prod, cons; | 407 | union smc_host_cursor sent, prep, prod, cons; |
| @@ -464,7 +462,7 @@ static int smc_tx_rdma_writes(struct smc_connection *conn) | |||
| 464 | dst_off, dst_len); | 462 | dst_off, dst_len); |
| 465 | else | 463 | else |
| 466 | rc = smcr_tx_rdma_writes(conn, len, sent.count, src_len, | 464 | rc = smcr_tx_rdma_writes(conn, len, sent.count, src_len, |
| 467 | dst_off, dst_len); | 465 | dst_off, dst_len, wr_rdma_buf); |
| 468 | if (rc) | 466 | if (rc) |
| 469 | return rc; | 467 | return rc; |
| 470 | 468 | ||
| @@ -485,31 +483,30 @@ static int smc_tx_rdma_writes(struct smc_connection *conn) | |||
| 485 | static int smcr_tx_sndbuf_nonempty(struct smc_connection *conn) | 483 | static int smcr_tx_sndbuf_nonempty(struct smc_connection *conn) |
| 486 | { | 484 | { |
| 487 | struct smc_cdc_producer_flags *pflags; | 485 | struct smc_cdc_producer_flags *pflags; |
| 486 | struct smc_rdma_wr *wr_rdma_buf; | ||
| 488 | struct smc_cdc_tx_pend *pend; | 487 | struct smc_cdc_tx_pend *pend; |
| 489 | struct smc_wr_buf *wr_buf; | 488 | struct smc_wr_buf *wr_buf; |
| 490 | int rc; | 489 | int rc; |
| 491 | 490 | ||
| 492 | spin_lock_bh(&conn->send_lock); | 491 | rc = smc_cdc_get_free_slot(conn, &wr_buf, &wr_rdma_buf, &pend); |
| 493 | rc = smc_cdc_get_free_slot(conn, &wr_buf, &pend); | ||
| 494 | if (rc < 0) { | 492 | if (rc < 0) { |
| 495 | if (rc == -EBUSY) { | 493 | if (rc == -EBUSY) { |
| 496 | struct smc_sock *smc = | 494 | struct smc_sock *smc = |
| 497 | container_of(conn, struct smc_sock, conn); | 495 | container_of(conn, struct smc_sock, conn); |
| 498 | 496 | ||
| 499 | if (smc->sk.sk_err == ECONNABORTED) { | 497 | if (smc->sk.sk_err == ECONNABORTED) |
| 500 | rc = sock_error(&smc->sk); | 498 | return sock_error(&smc->sk); |
| 501 | goto out_unlock; | ||
| 502 | } | ||
| 503 | rc = 0; | 499 | rc = 0; |
| 504 | if (conn->alert_token_local) /* connection healthy */ | 500 | if (conn->alert_token_local) /* connection healthy */ |
| 505 | mod_delayed_work(system_wq, &conn->tx_work, | 501 | mod_delayed_work(system_wq, &conn->tx_work, |
| 506 | SMC_TX_WORK_DELAY); | 502 | SMC_TX_WORK_DELAY); |
| 507 | } | 503 | } |
| 508 | goto out_unlock; | 504 | return rc; |
| 509 | } | 505 | } |
| 510 | 506 | ||
| 507 | spin_lock_bh(&conn->send_lock); | ||
| 511 | if (!conn->local_tx_ctrl.prod_flags.urg_data_present) { | 508 | if (!conn->local_tx_ctrl.prod_flags.urg_data_present) { |
| 512 | rc = smc_tx_rdma_writes(conn); | 509 | rc = smc_tx_rdma_writes(conn, wr_rdma_buf); |
| 513 | if (rc) { | 510 | if (rc) { |
| 514 | smc_wr_tx_put_slot(&conn->lgr->lnk[SMC_SINGLE_LINK], | 511 | smc_wr_tx_put_slot(&conn->lgr->lnk[SMC_SINGLE_LINK], |
| 515 | (struct smc_wr_tx_pend_priv *)pend); | 512 | (struct smc_wr_tx_pend_priv *)pend); |
| @@ -536,7 +533,7 @@ static int smcd_tx_sndbuf_nonempty(struct smc_connection *conn) | |||
| 536 | 533 | ||
| 537 | spin_lock_bh(&conn->send_lock); | 534 | spin_lock_bh(&conn->send_lock); |
| 538 | if (!pflags->urg_data_present) | 535 | if (!pflags->urg_data_present) |
| 539 | rc = smc_tx_rdma_writes(conn); | 536 | rc = smc_tx_rdma_writes(conn, NULL); |
| 540 | if (!rc) | 537 | if (!rc) |
| 541 | rc = smcd_cdc_msg_send(conn); | 538 | rc = smcd_cdc_msg_send(conn); |
| 542 | 539 | ||
| @@ -598,7 +595,8 @@ void smc_tx_consumer_update(struct smc_connection *conn, bool force) | |||
| 598 | if (to_confirm > conn->rmbe_update_limit) { | 595 | if (to_confirm > conn->rmbe_update_limit) { |
| 599 | smc_curs_copy(&prod, &conn->local_rx_ctrl.prod, conn); | 596 | smc_curs_copy(&prod, &conn->local_rx_ctrl.prod, conn); |
| 600 | sender_free = conn->rmb_desc->len - | 597 | sender_free = conn->rmb_desc->len - |
| 601 | smc_curs_diff(conn->rmb_desc->len, &prod, &cfed); | 598 | smc_curs_diff_large(conn->rmb_desc->len, |
| 599 | &cfed, &prod); | ||
| 602 | } | 600 | } |
| 603 | 601 | ||
| 604 | if (conn->local_rx_ctrl.prod_flags.cons_curs_upd_req || | 602 | if (conn->local_rx_ctrl.prod_flags.cons_curs_upd_req || |
diff --git a/net/smc/smc_wr.c b/net/smc/smc_wr.c index c2694750a6a8..253aa75dc2b6 100644 --- a/net/smc/smc_wr.c +++ b/net/smc/smc_wr.c | |||
| @@ -160,6 +160,7 @@ static inline int smc_wr_tx_get_free_slot_index(struct smc_link *link, u32 *idx) | |||
| 160 | * @link: Pointer to smc_link used to later send the message. | 160 | * @link: Pointer to smc_link used to later send the message. |
| 161 | * @handler: Send completion handler function pointer. | 161 | * @handler: Send completion handler function pointer. |
| 162 | * @wr_buf: Out value returns pointer to message buffer. | 162 | * @wr_buf: Out value returns pointer to message buffer. |
| 163 | * @wr_rdma_buf: Out value returns pointer to rdma work request. | ||
| 163 | * @wr_pend_priv: Out value returns pointer serving as handler context. | 164 | * @wr_pend_priv: Out value returns pointer serving as handler context. |
| 164 | * | 165 | * |
| 165 | * Return: 0 on success, or -errno on error. | 166 | * Return: 0 on success, or -errno on error. |
| @@ -167,6 +168,7 @@ static inline int smc_wr_tx_get_free_slot_index(struct smc_link *link, u32 *idx) | |||
| 167 | int smc_wr_tx_get_free_slot(struct smc_link *link, | 168 | int smc_wr_tx_get_free_slot(struct smc_link *link, |
| 168 | smc_wr_tx_handler handler, | 169 | smc_wr_tx_handler handler, |
| 169 | struct smc_wr_buf **wr_buf, | 170 | struct smc_wr_buf **wr_buf, |
| 171 | struct smc_rdma_wr **wr_rdma_buf, | ||
| 170 | struct smc_wr_tx_pend_priv **wr_pend_priv) | 172 | struct smc_wr_tx_pend_priv **wr_pend_priv) |
| 171 | { | 173 | { |
| 172 | struct smc_wr_tx_pend *wr_pend; | 174 | struct smc_wr_tx_pend *wr_pend; |
| @@ -204,6 +206,8 @@ int smc_wr_tx_get_free_slot(struct smc_link *link, | |||
| 204 | wr_ib = &link->wr_tx_ibs[idx]; | 206 | wr_ib = &link->wr_tx_ibs[idx]; |
| 205 | wr_ib->wr_id = wr_id; | 207 | wr_ib->wr_id = wr_id; |
| 206 | *wr_buf = &link->wr_tx_bufs[idx]; | 208 | *wr_buf = &link->wr_tx_bufs[idx]; |
| 209 | if (wr_rdma_buf) | ||
| 210 | *wr_rdma_buf = &link->wr_tx_rdmas[idx]; | ||
| 207 | *wr_pend_priv = &wr_pend->priv; | 211 | *wr_pend_priv = &wr_pend->priv; |
| 208 | return 0; | 212 | return 0; |
| 209 | } | 213 | } |
| @@ -218,10 +222,10 @@ int smc_wr_tx_put_slot(struct smc_link *link, | |||
| 218 | u32 idx = pend->idx; | 222 | u32 idx = pend->idx; |
| 219 | 223 | ||
| 220 | /* clear the full struct smc_wr_tx_pend including .priv */ | 224 | /* clear the full struct smc_wr_tx_pend including .priv */ |
| 221 | memset(&link->wr_tx_pends[pend->idx], 0, | 225 | memset(&link->wr_tx_pends[idx], 0, |
| 222 | sizeof(link->wr_tx_pends[pend->idx])); | 226 | sizeof(link->wr_tx_pends[idx])); |
| 223 | memset(&link->wr_tx_bufs[pend->idx], 0, | 227 | memset(&link->wr_tx_bufs[idx], 0, |
| 224 | sizeof(link->wr_tx_bufs[pend->idx])); | 228 | sizeof(link->wr_tx_bufs[idx])); |
| 225 | test_and_clear_bit(idx, link->wr_tx_mask); | 229 | test_and_clear_bit(idx, link->wr_tx_mask); |
| 226 | return 1; | 230 | return 1; |
| 227 | } | 231 | } |
| @@ -465,12 +469,26 @@ static void smc_wr_init_sge(struct smc_link *lnk) | |||
| 465 | lnk->wr_tx_dma_addr + i * SMC_WR_BUF_SIZE; | 469 | lnk->wr_tx_dma_addr + i * SMC_WR_BUF_SIZE; |
| 466 | lnk->wr_tx_sges[i].length = SMC_WR_TX_SIZE; | 470 | lnk->wr_tx_sges[i].length = SMC_WR_TX_SIZE; |
| 467 | lnk->wr_tx_sges[i].lkey = lnk->roce_pd->local_dma_lkey; | 471 | lnk->wr_tx_sges[i].lkey = lnk->roce_pd->local_dma_lkey; |
| 472 | lnk->wr_tx_rdma_sges[i].tx_rdma_sge[0].wr_tx_rdma_sge[0].lkey = | ||
| 473 | lnk->roce_pd->local_dma_lkey; | ||
| 474 | lnk->wr_tx_rdma_sges[i].tx_rdma_sge[0].wr_tx_rdma_sge[1].lkey = | ||
| 475 | lnk->roce_pd->local_dma_lkey; | ||
| 476 | lnk->wr_tx_rdma_sges[i].tx_rdma_sge[1].wr_tx_rdma_sge[0].lkey = | ||
| 477 | lnk->roce_pd->local_dma_lkey; | ||
| 478 | lnk->wr_tx_rdma_sges[i].tx_rdma_sge[1].wr_tx_rdma_sge[1].lkey = | ||
| 479 | lnk->roce_pd->local_dma_lkey; | ||
| 468 | lnk->wr_tx_ibs[i].next = NULL; | 480 | lnk->wr_tx_ibs[i].next = NULL; |
| 469 | lnk->wr_tx_ibs[i].sg_list = &lnk->wr_tx_sges[i]; | 481 | lnk->wr_tx_ibs[i].sg_list = &lnk->wr_tx_sges[i]; |
| 470 | lnk->wr_tx_ibs[i].num_sge = 1; | 482 | lnk->wr_tx_ibs[i].num_sge = 1; |
| 471 | lnk->wr_tx_ibs[i].opcode = IB_WR_SEND; | 483 | lnk->wr_tx_ibs[i].opcode = IB_WR_SEND; |
| 472 | lnk->wr_tx_ibs[i].send_flags = | 484 | lnk->wr_tx_ibs[i].send_flags = |
| 473 | IB_SEND_SIGNALED | IB_SEND_SOLICITED; | 485 | IB_SEND_SIGNALED | IB_SEND_SOLICITED; |
| 486 | lnk->wr_tx_rdmas[i].wr_tx_rdma[0].wr.opcode = IB_WR_RDMA_WRITE; | ||
| 487 | lnk->wr_tx_rdmas[i].wr_tx_rdma[1].wr.opcode = IB_WR_RDMA_WRITE; | ||
| 488 | lnk->wr_tx_rdmas[i].wr_tx_rdma[0].wr.sg_list = | ||
| 489 | lnk->wr_tx_rdma_sges[i].tx_rdma_sge[0].wr_tx_rdma_sge; | ||
| 490 | lnk->wr_tx_rdmas[i].wr_tx_rdma[1].wr.sg_list = | ||
| 491 | lnk->wr_tx_rdma_sges[i].tx_rdma_sge[1].wr_tx_rdma_sge; | ||
| 474 | } | 492 | } |
| 475 | for (i = 0; i < lnk->wr_rx_cnt; i++) { | 493 | for (i = 0; i < lnk->wr_rx_cnt; i++) { |
| 476 | lnk->wr_rx_sges[i].addr = | 494 | lnk->wr_rx_sges[i].addr = |
| @@ -521,8 +539,12 @@ void smc_wr_free_link_mem(struct smc_link *lnk) | |||
| 521 | lnk->wr_tx_mask = NULL; | 539 | lnk->wr_tx_mask = NULL; |
| 522 | kfree(lnk->wr_tx_sges); | 540 | kfree(lnk->wr_tx_sges); |
| 523 | lnk->wr_tx_sges = NULL; | 541 | lnk->wr_tx_sges = NULL; |
| 542 | kfree(lnk->wr_tx_rdma_sges); | ||
| 543 | lnk->wr_tx_rdma_sges = NULL; | ||
| 524 | kfree(lnk->wr_rx_sges); | 544 | kfree(lnk->wr_rx_sges); |
| 525 | lnk->wr_rx_sges = NULL; | 545 | lnk->wr_rx_sges = NULL; |
| 546 | kfree(lnk->wr_tx_rdmas); | ||
| 547 | lnk->wr_tx_rdmas = NULL; | ||
| 526 | kfree(lnk->wr_rx_ibs); | 548 | kfree(lnk->wr_rx_ibs); |
| 527 | lnk->wr_rx_ibs = NULL; | 549 | lnk->wr_rx_ibs = NULL; |
| 528 | kfree(lnk->wr_tx_ibs); | 550 | kfree(lnk->wr_tx_ibs); |
| @@ -552,10 +574,20 @@ int smc_wr_alloc_link_mem(struct smc_link *link) | |||
| 552 | GFP_KERNEL); | 574 | GFP_KERNEL); |
| 553 | if (!link->wr_rx_ibs) | 575 | if (!link->wr_rx_ibs) |
| 554 | goto no_mem_wr_tx_ibs; | 576 | goto no_mem_wr_tx_ibs; |
| 577 | link->wr_tx_rdmas = kcalloc(SMC_WR_BUF_CNT, | ||
| 578 | sizeof(link->wr_tx_rdmas[0]), | ||
| 579 | GFP_KERNEL); | ||
| 580 | if (!link->wr_tx_rdmas) | ||
| 581 | goto no_mem_wr_rx_ibs; | ||
| 582 | link->wr_tx_rdma_sges = kcalloc(SMC_WR_BUF_CNT, | ||
| 583 | sizeof(link->wr_tx_rdma_sges[0]), | ||
| 584 | GFP_KERNEL); | ||
| 585 | if (!link->wr_tx_rdma_sges) | ||
| 586 | goto no_mem_wr_tx_rdmas; | ||
| 555 | link->wr_tx_sges = kcalloc(SMC_WR_BUF_CNT, sizeof(link->wr_tx_sges[0]), | 587 | link->wr_tx_sges = kcalloc(SMC_WR_BUF_CNT, sizeof(link->wr_tx_sges[0]), |
| 556 | GFP_KERNEL); | 588 | GFP_KERNEL); |
| 557 | if (!link->wr_tx_sges) | 589 | if (!link->wr_tx_sges) |
| 558 | goto no_mem_wr_rx_ibs; | 590 | goto no_mem_wr_tx_rdma_sges; |
| 559 | link->wr_rx_sges = kcalloc(SMC_WR_BUF_CNT * 3, | 591 | link->wr_rx_sges = kcalloc(SMC_WR_BUF_CNT * 3, |
| 560 | sizeof(link->wr_rx_sges[0]), | 592 | sizeof(link->wr_rx_sges[0]), |
| 561 | GFP_KERNEL); | 593 | GFP_KERNEL); |
| @@ -579,6 +611,10 @@ no_mem_wr_rx_sges: | |||
| 579 | kfree(link->wr_rx_sges); | 611 | kfree(link->wr_rx_sges); |
| 580 | no_mem_wr_tx_sges: | 612 | no_mem_wr_tx_sges: |
| 581 | kfree(link->wr_tx_sges); | 613 | kfree(link->wr_tx_sges); |
| 614 | no_mem_wr_tx_rdma_sges: | ||
| 615 | kfree(link->wr_tx_rdma_sges); | ||
| 616 | no_mem_wr_tx_rdmas: | ||
| 617 | kfree(link->wr_tx_rdmas); | ||
| 582 | no_mem_wr_rx_ibs: | 618 | no_mem_wr_rx_ibs: |
| 583 | kfree(link->wr_rx_ibs); | 619 | kfree(link->wr_rx_ibs); |
| 584 | no_mem_wr_tx_ibs: | 620 | no_mem_wr_tx_ibs: |
diff --git a/net/smc/smc_wr.h b/net/smc/smc_wr.h index 1d85bb14fd6f..09bf32fd3959 100644 --- a/net/smc/smc_wr.h +++ b/net/smc/smc_wr.h | |||
| @@ -85,6 +85,7 @@ void smc_wr_add_dev(struct smc_ib_device *smcibdev); | |||
| 85 | 85 | ||
| 86 | int smc_wr_tx_get_free_slot(struct smc_link *link, smc_wr_tx_handler handler, | 86 | int smc_wr_tx_get_free_slot(struct smc_link *link, smc_wr_tx_handler handler, |
| 87 | struct smc_wr_buf **wr_buf, | 87 | struct smc_wr_buf **wr_buf, |
| 88 | struct smc_rdma_wr **wrs, | ||
| 88 | struct smc_wr_tx_pend_priv **wr_pend_priv); | 89 | struct smc_wr_tx_pend_priv **wr_pend_priv); |
| 89 | int smc_wr_tx_put_slot(struct smc_link *link, | 90 | int smc_wr_tx_put_slot(struct smc_link *link, |
| 90 | struct smc_wr_tx_pend_priv *wr_pend_priv); | 91 | struct smc_wr_tx_pend_priv *wr_pend_priv); |
diff --git a/net/socket.c b/net/socket.c index e89884e2197b..d80d87a395ea 100644 --- a/net/socket.c +++ b/net/socket.c | |||
| @@ -941,8 +941,7 @@ void dlci_ioctl_set(int (*hook) (unsigned int, void __user *)) | |||
| 941 | EXPORT_SYMBOL(dlci_ioctl_set); | 941 | EXPORT_SYMBOL(dlci_ioctl_set); |
| 942 | 942 | ||
| 943 | static long sock_do_ioctl(struct net *net, struct socket *sock, | 943 | static long sock_do_ioctl(struct net *net, struct socket *sock, |
| 944 | unsigned int cmd, unsigned long arg, | 944 | unsigned int cmd, unsigned long arg) |
| 945 | unsigned int ifreq_size) | ||
| 946 | { | 945 | { |
| 947 | int err; | 946 | int err; |
| 948 | void __user *argp = (void __user *)arg; | 947 | void __user *argp = (void __user *)arg; |
| @@ -968,11 +967,11 @@ static long sock_do_ioctl(struct net *net, struct socket *sock, | |||
| 968 | } else { | 967 | } else { |
| 969 | struct ifreq ifr; | 968 | struct ifreq ifr; |
| 970 | bool need_copyout; | 969 | bool need_copyout; |
| 971 | if (copy_from_user(&ifr, argp, ifreq_size)) | 970 | if (copy_from_user(&ifr, argp, sizeof(struct ifreq))) |
| 972 | return -EFAULT; | 971 | return -EFAULT; |
| 973 | err = dev_ioctl(net, cmd, &ifr, &need_copyout); | 972 | err = dev_ioctl(net, cmd, &ifr, &need_copyout); |
| 974 | if (!err && need_copyout) | 973 | if (!err && need_copyout) |
| 975 | if (copy_to_user(argp, &ifr, ifreq_size)) | 974 | if (copy_to_user(argp, &ifr, sizeof(struct ifreq))) |
| 976 | return -EFAULT; | 975 | return -EFAULT; |
| 977 | } | 976 | } |
| 978 | return err; | 977 | return err; |
| @@ -1071,8 +1070,7 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) | |||
| 1071 | err = open_related_ns(&net->ns, get_net_ns); | 1070 | err = open_related_ns(&net->ns, get_net_ns); |
| 1072 | break; | 1071 | break; |
| 1073 | default: | 1072 | default: |
| 1074 | err = sock_do_ioctl(net, sock, cmd, arg, | 1073 | err = sock_do_ioctl(net, sock, cmd, arg); |
| 1075 | sizeof(struct ifreq)); | ||
| 1076 | break; | 1074 | break; |
| 1077 | } | 1075 | } |
| 1078 | return err; | 1076 | return err; |
| @@ -2780,8 +2778,7 @@ static int do_siocgstamp(struct net *net, struct socket *sock, | |||
| 2780 | int err; | 2778 | int err; |
| 2781 | 2779 | ||
| 2782 | set_fs(KERNEL_DS); | 2780 | set_fs(KERNEL_DS); |
| 2783 | err = sock_do_ioctl(net, sock, cmd, (unsigned long)&ktv, | 2781 | err = sock_do_ioctl(net, sock, cmd, (unsigned long)&ktv); |
| 2784 | sizeof(struct compat_ifreq)); | ||
| 2785 | set_fs(old_fs); | 2782 | set_fs(old_fs); |
| 2786 | if (!err) | 2783 | if (!err) |
| 2787 | err = compat_put_timeval(&ktv, up); | 2784 | err = compat_put_timeval(&ktv, up); |
| @@ -2797,8 +2794,7 @@ static int do_siocgstampns(struct net *net, struct socket *sock, | |||
| 2797 | int err; | 2794 | int err; |
| 2798 | 2795 | ||
| 2799 | set_fs(KERNEL_DS); | 2796 | set_fs(KERNEL_DS); |
| 2800 | err = sock_do_ioctl(net, sock, cmd, (unsigned long)&kts, | 2797 | err = sock_do_ioctl(net, sock, cmd, (unsigned long)&kts); |
| 2801 | sizeof(struct compat_ifreq)); | ||
| 2802 | set_fs(old_fs); | 2798 | set_fs(old_fs); |
| 2803 | if (!err) | 2799 | if (!err) |
| 2804 | err = compat_put_timespec(&kts, up); | 2800 | err = compat_put_timespec(&kts, up); |
| @@ -2994,6 +2990,54 @@ static int compat_ifr_data_ioctl(struct net *net, unsigned int cmd, | |||
| 2994 | return dev_ioctl(net, cmd, &ifreq, NULL); | 2990 | return dev_ioctl(net, cmd, &ifreq, NULL); |
| 2995 | } | 2991 | } |
| 2996 | 2992 | ||
| 2993 | static int compat_ifreq_ioctl(struct net *net, struct socket *sock, | ||
| 2994 | unsigned int cmd, | ||
| 2995 | struct compat_ifreq __user *uifr32) | ||
| 2996 | { | ||
| 2997 | struct ifreq __user *uifr; | ||
| 2998 | int err; | ||
| 2999 | |||
| 3000 | /* Handle the fact that while struct ifreq has the same *layout* on | ||
| 3001 | * 32/64 for everything but ifreq::ifru_ifmap and ifreq::ifru_data, | ||
| 3002 | * which are handled elsewhere, it still has different *size* due to | ||
| 3003 | * ifreq::ifru_ifmap (which is 16 bytes on 32 bit, 24 bytes on 64-bit, | ||
| 3004 | * resulting in struct ifreq being 32 and 40 bytes respectively). | ||
| 3005 | * As a result, if the struct happens to be at the end of a page and | ||
| 3006 | * the next page isn't readable/writable, we get a fault. To prevent | ||
| 3007 | * that, copy back and forth to the full size. | ||
| 3008 | */ | ||
| 3009 | |||
| 3010 | uifr = compat_alloc_user_space(sizeof(*uifr)); | ||
| 3011 | if (copy_in_user(uifr, uifr32, sizeof(*uifr32))) | ||
| 3012 | return -EFAULT; | ||
| 3013 | |||
| 3014 | err = sock_do_ioctl(net, sock, cmd, (unsigned long)uifr); | ||
| 3015 | |||
| 3016 | if (!err) { | ||
| 3017 | switch (cmd) { | ||
| 3018 | case SIOCGIFFLAGS: | ||
| 3019 | case SIOCGIFMETRIC: | ||
| 3020 | case SIOCGIFMTU: | ||
| 3021 | case SIOCGIFMEM: | ||
| 3022 | case SIOCGIFHWADDR: | ||
| 3023 | case SIOCGIFINDEX: | ||
| 3024 | case SIOCGIFADDR: | ||
| 3025 | case SIOCGIFBRDADDR: | ||
| 3026 | case SIOCGIFDSTADDR: | ||
| 3027 | case SIOCGIFNETMASK: | ||
| 3028 | case SIOCGIFPFLAGS: | ||
| 3029 | case SIOCGIFTXQLEN: | ||
| 3030 | case SIOCGMIIPHY: | ||
| 3031 | case SIOCGMIIREG: | ||
| 3032 | case SIOCGIFNAME: | ||
| 3033 | if (copy_in_user(uifr32, uifr, sizeof(*uifr32))) | ||
| 3034 | err = -EFAULT; | ||
| 3035 | break; | ||
| 3036 | } | ||
| 3037 | } | ||
| 3038 | return err; | ||
| 3039 | } | ||
| 3040 | |||
| 2997 | static int compat_sioc_ifmap(struct net *net, unsigned int cmd, | 3041 | static int compat_sioc_ifmap(struct net *net, unsigned int cmd, |
| 2998 | struct compat_ifreq __user *uifr32) | 3042 | struct compat_ifreq __user *uifr32) |
| 2999 | { | 3043 | { |
| @@ -3109,8 +3153,7 @@ static int routing_ioctl(struct net *net, struct socket *sock, | |||
| 3109 | } | 3153 | } |
| 3110 | 3154 | ||
| 3111 | set_fs(KERNEL_DS); | 3155 | set_fs(KERNEL_DS); |
| 3112 | ret = sock_do_ioctl(net, sock, cmd, (unsigned long) r, | 3156 | ret = sock_do_ioctl(net, sock, cmd, (unsigned long) r); |
| 3113 | sizeof(struct compat_ifreq)); | ||
| 3114 | set_fs(old_fs); | 3157 | set_fs(old_fs); |
| 3115 | 3158 | ||
| 3116 | out: | 3159 | out: |
| @@ -3210,21 +3253,22 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, | |||
| 3210 | case SIOCSIFTXQLEN: | 3253 | case SIOCSIFTXQLEN: |
| 3211 | case SIOCBRADDIF: | 3254 | case SIOCBRADDIF: |
| 3212 | case SIOCBRDELIF: | 3255 | case SIOCBRDELIF: |
| 3256 | case SIOCGIFNAME: | ||
| 3213 | case SIOCSIFNAME: | 3257 | case SIOCSIFNAME: |
| 3214 | case SIOCGMIIPHY: | 3258 | case SIOCGMIIPHY: |
| 3215 | case SIOCGMIIREG: | 3259 | case SIOCGMIIREG: |
| 3216 | case SIOCSMIIREG: | 3260 | case SIOCSMIIREG: |
| 3217 | case SIOCSARP: | ||
| 3218 | case SIOCGARP: | ||
| 3219 | case SIOCDARP: | ||
| 3220 | case SIOCATMARK: | ||
| 3221 | case SIOCBONDENSLAVE: | 3261 | case SIOCBONDENSLAVE: |
| 3222 | case SIOCBONDRELEASE: | 3262 | case SIOCBONDRELEASE: |
| 3223 | case SIOCBONDSETHWADDR: | 3263 | case SIOCBONDSETHWADDR: |
| 3224 | case SIOCBONDCHANGEACTIVE: | 3264 | case SIOCBONDCHANGEACTIVE: |
| 3225 | case SIOCGIFNAME: | 3265 | return compat_ifreq_ioctl(net, sock, cmd, argp); |
| 3226 | return sock_do_ioctl(net, sock, cmd, arg, | 3266 | |
| 3227 | sizeof(struct compat_ifreq)); | 3267 | case SIOCSARP: |
| 3268 | case SIOCGARP: | ||
| 3269 | case SIOCDARP: | ||
| 3270 | case SIOCATMARK: | ||
| 3271 | return sock_do_ioctl(net, sock, cmd, arg); | ||
| 3228 | } | 3272 | } |
| 3229 | 3273 | ||
| 3230 | return -ENOIOCTLCMD; | 3274 | return -ENOIOCTLCMD; |
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index 1ff9768f5456..f3023bbc0b7f 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c | |||
| @@ -41,6 +41,9 @@ static unsigned long number_cred_unused; | |||
| 41 | 41 | ||
| 42 | static struct cred machine_cred = { | 42 | static struct cred machine_cred = { |
| 43 | .usage = ATOMIC_INIT(1), | 43 | .usage = ATOMIC_INIT(1), |
| 44 | #ifdef CONFIG_DEBUG_CREDENTIALS | ||
| 45 | .magic = CRED_MAGIC, | ||
| 46 | #endif | ||
| 44 | }; | 47 | }; |
| 45 | 48 | ||
| 46 | /* | 49 | /* |
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index dc86713b32b6..1531b0219344 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
| @@ -1549,8 +1549,10 @@ gss_marshal(struct rpc_task *task, __be32 *p) | |||
| 1549 | cred_len = p++; | 1549 | cred_len = p++; |
| 1550 | 1550 | ||
| 1551 | spin_lock(&ctx->gc_seq_lock); | 1551 | spin_lock(&ctx->gc_seq_lock); |
| 1552 | req->rq_seqno = ctx->gc_seq++; | 1552 | req->rq_seqno = (ctx->gc_seq < MAXSEQ) ? ctx->gc_seq++ : MAXSEQ; |
| 1553 | spin_unlock(&ctx->gc_seq_lock); | 1553 | spin_unlock(&ctx->gc_seq_lock); |
| 1554 | if (req->rq_seqno == MAXSEQ) | ||
| 1555 | goto out_expired; | ||
| 1554 | 1556 | ||
| 1555 | *p++ = htonl((u32) RPC_GSS_VERSION); | 1557 | *p++ = htonl((u32) RPC_GSS_VERSION); |
| 1556 | *p++ = htonl((u32) ctx->gc_proc); | 1558 | *p++ = htonl((u32) ctx->gc_proc); |
| @@ -1572,14 +1574,18 @@ gss_marshal(struct rpc_task *task, __be32 *p) | |||
| 1572 | mic.data = (u8 *)(p + 1); | 1574 | mic.data = (u8 *)(p + 1); |
| 1573 | maj_stat = gss_get_mic(ctx->gc_gss_ctx, &verf_buf, &mic); | 1575 | maj_stat = gss_get_mic(ctx->gc_gss_ctx, &verf_buf, &mic); |
| 1574 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) { | 1576 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) { |
| 1575 | clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); | 1577 | goto out_expired; |
| 1576 | } else if (maj_stat != 0) { | 1578 | } else if (maj_stat != 0) { |
| 1577 | printk("gss_marshal: gss_get_mic FAILED (%d)\n", maj_stat); | 1579 | pr_warn("gss_marshal: gss_get_mic FAILED (%d)\n", maj_stat); |
| 1580 | task->tk_status = -EIO; | ||
| 1578 | goto out_put_ctx; | 1581 | goto out_put_ctx; |
| 1579 | } | 1582 | } |
| 1580 | p = xdr_encode_opaque(p, NULL, mic.len); | 1583 | p = xdr_encode_opaque(p, NULL, mic.len); |
| 1581 | gss_put_ctx(ctx); | 1584 | gss_put_ctx(ctx); |
| 1582 | return p; | 1585 | return p; |
| 1586 | out_expired: | ||
| 1587 | clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); | ||
| 1588 | task->tk_status = -EKEYEXPIRED; | ||
| 1583 | out_put_ctx: | 1589 | out_put_ctx: |
| 1584 | gss_put_ctx(ctx); | 1590 | gss_put_ctx(ctx); |
| 1585 | return NULL; | 1591 | return NULL; |
diff --git a/net/sunrpc/auth_gss/gss_krb5_seqnum.c b/net/sunrpc/auth_gss/gss_krb5_seqnum.c index fb6656295204..507105127095 100644 --- a/net/sunrpc/auth_gss/gss_krb5_seqnum.c +++ b/net/sunrpc/auth_gss/gss_krb5_seqnum.c | |||
| @@ -44,7 +44,7 @@ krb5_make_rc4_seq_num(struct krb5_ctx *kctx, int direction, s32 seqnum, | |||
| 44 | unsigned char *cksum, unsigned char *buf) | 44 | unsigned char *cksum, unsigned char *buf) |
| 45 | { | 45 | { |
| 46 | struct crypto_sync_skcipher *cipher; | 46 | struct crypto_sync_skcipher *cipher; |
| 47 | unsigned char plain[8]; | 47 | unsigned char *plain; |
| 48 | s32 code; | 48 | s32 code; |
| 49 | 49 | ||
| 50 | dprintk("RPC: %s:\n", __func__); | 50 | dprintk("RPC: %s:\n", __func__); |
| @@ -52,6 +52,10 @@ krb5_make_rc4_seq_num(struct krb5_ctx *kctx, int direction, s32 seqnum, | |||
| 52 | if (IS_ERR(cipher)) | 52 | if (IS_ERR(cipher)) |
| 53 | return PTR_ERR(cipher); | 53 | return PTR_ERR(cipher); |
| 54 | 54 | ||
| 55 | plain = kmalloc(8, GFP_NOFS); | ||
| 56 | if (!plain) | ||
| 57 | return -ENOMEM; | ||
| 58 | |||
| 55 | plain[0] = (unsigned char) ((seqnum >> 24) & 0xff); | 59 | plain[0] = (unsigned char) ((seqnum >> 24) & 0xff); |
| 56 | plain[1] = (unsigned char) ((seqnum >> 16) & 0xff); | 60 | plain[1] = (unsigned char) ((seqnum >> 16) & 0xff); |
| 57 | plain[2] = (unsigned char) ((seqnum >> 8) & 0xff); | 61 | plain[2] = (unsigned char) ((seqnum >> 8) & 0xff); |
| @@ -67,6 +71,7 @@ krb5_make_rc4_seq_num(struct krb5_ctx *kctx, int direction, s32 seqnum, | |||
| 67 | 71 | ||
| 68 | code = krb5_encrypt(cipher, cksum, plain, buf, 8); | 72 | code = krb5_encrypt(cipher, cksum, plain, buf, 8); |
| 69 | out: | 73 | out: |
| 74 | kfree(plain); | ||
| 70 | crypto_free_sync_skcipher(cipher); | 75 | crypto_free_sync_skcipher(cipher); |
| 71 | return code; | 76 | return code; |
| 72 | } | 77 | } |
| @@ -77,12 +82,17 @@ krb5_make_seq_num(struct krb5_ctx *kctx, | |||
| 77 | u32 seqnum, | 82 | u32 seqnum, |
| 78 | unsigned char *cksum, unsigned char *buf) | 83 | unsigned char *cksum, unsigned char *buf) |
| 79 | { | 84 | { |
| 80 | unsigned char plain[8]; | 85 | unsigned char *plain; |
| 86 | s32 code; | ||
| 81 | 87 | ||
| 82 | if (kctx->enctype == ENCTYPE_ARCFOUR_HMAC) | 88 | if (kctx->enctype == ENCTYPE_ARCFOUR_HMAC) |
| 83 | return krb5_make_rc4_seq_num(kctx, direction, seqnum, | 89 | return krb5_make_rc4_seq_num(kctx, direction, seqnum, |
| 84 | cksum, buf); | 90 | cksum, buf); |
| 85 | 91 | ||
| 92 | plain = kmalloc(8, GFP_NOFS); | ||
| 93 | if (!plain) | ||
| 94 | return -ENOMEM; | ||
| 95 | |||
| 86 | plain[0] = (unsigned char) (seqnum & 0xff); | 96 | plain[0] = (unsigned char) (seqnum & 0xff); |
| 87 | plain[1] = (unsigned char) ((seqnum >> 8) & 0xff); | 97 | plain[1] = (unsigned char) ((seqnum >> 8) & 0xff); |
| 88 | plain[2] = (unsigned char) ((seqnum >> 16) & 0xff); | 98 | plain[2] = (unsigned char) ((seqnum >> 16) & 0xff); |
| @@ -93,7 +103,9 @@ krb5_make_seq_num(struct krb5_ctx *kctx, | |||
| 93 | plain[6] = direction; | 103 | plain[6] = direction; |
| 94 | plain[7] = direction; | 104 | plain[7] = direction; |
| 95 | 105 | ||
| 96 | return krb5_encrypt(key, cksum, plain, buf, 8); | 106 | code = krb5_encrypt(key, cksum, plain, buf, 8); |
| 107 | kfree(plain); | ||
| 108 | return code; | ||
| 97 | } | 109 | } |
| 98 | 110 | ||
| 99 | static s32 | 111 | static s32 |
| @@ -101,7 +113,7 @@ krb5_get_rc4_seq_num(struct krb5_ctx *kctx, unsigned char *cksum, | |||
| 101 | unsigned char *buf, int *direction, s32 *seqnum) | 113 | unsigned char *buf, int *direction, s32 *seqnum) |
| 102 | { | 114 | { |
| 103 | struct crypto_sync_skcipher *cipher; | 115 | struct crypto_sync_skcipher *cipher; |
| 104 | unsigned char plain[8]; | 116 | unsigned char *plain; |
| 105 | s32 code; | 117 | s32 code; |
| 106 | 118 | ||
| 107 | dprintk("RPC: %s:\n", __func__); | 119 | dprintk("RPC: %s:\n", __func__); |
| @@ -113,20 +125,28 @@ krb5_get_rc4_seq_num(struct krb5_ctx *kctx, unsigned char *cksum, | |||
| 113 | if (code) | 125 | if (code) |
| 114 | goto out; | 126 | goto out; |
| 115 | 127 | ||
| 128 | plain = kmalloc(8, GFP_NOFS); | ||
| 129 | if (!plain) { | ||
| 130 | code = -ENOMEM; | ||
| 131 | goto out; | ||
| 132 | } | ||
| 133 | |||
| 116 | code = krb5_decrypt(cipher, cksum, buf, plain, 8); | 134 | code = krb5_decrypt(cipher, cksum, buf, plain, 8); |
| 117 | if (code) | 135 | if (code) |
| 118 | goto out; | 136 | goto out_plain; |
| 119 | 137 | ||
| 120 | if ((plain[4] != plain[5]) || (plain[4] != plain[6]) | 138 | if ((plain[4] != plain[5]) || (plain[4] != plain[6]) |
| 121 | || (plain[4] != plain[7])) { | 139 | || (plain[4] != plain[7])) { |
| 122 | code = (s32)KG_BAD_SEQ; | 140 | code = (s32)KG_BAD_SEQ; |
| 123 | goto out; | 141 | goto out_plain; |
| 124 | } | 142 | } |
| 125 | 143 | ||
| 126 | *direction = plain[4]; | 144 | *direction = plain[4]; |
| 127 | 145 | ||
| 128 | *seqnum = ((plain[0] << 24) | (plain[1] << 16) | | 146 | *seqnum = ((plain[0] << 24) | (plain[1] << 16) | |
| 129 | (plain[2] << 8) | (plain[3])); | 147 | (plain[2] << 8) | (plain[3])); |
| 148 | out_plain: | ||
| 149 | kfree(plain); | ||
| 130 | out: | 150 | out: |
| 131 | crypto_free_sync_skcipher(cipher); | 151 | crypto_free_sync_skcipher(cipher); |
| 132 | return code; | 152 | return code; |
| @@ -139,7 +159,7 @@ krb5_get_seq_num(struct krb5_ctx *kctx, | |||
| 139 | int *direction, u32 *seqnum) | 159 | int *direction, u32 *seqnum) |
| 140 | { | 160 | { |
| 141 | s32 code; | 161 | s32 code; |
| 142 | unsigned char plain[8]; | 162 | unsigned char *plain; |
| 143 | struct crypto_sync_skcipher *key = kctx->seq; | 163 | struct crypto_sync_skcipher *key = kctx->seq; |
| 144 | 164 | ||
| 145 | dprintk("RPC: krb5_get_seq_num:\n"); | 165 | dprintk("RPC: krb5_get_seq_num:\n"); |
| @@ -147,18 +167,25 @@ krb5_get_seq_num(struct krb5_ctx *kctx, | |||
| 147 | if (kctx->enctype == ENCTYPE_ARCFOUR_HMAC) | 167 | if (kctx->enctype == ENCTYPE_ARCFOUR_HMAC) |
| 148 | return krb5_get_rc4_seq_num(kctx, cksum, buf, | 168 | return krb5_get_rc4_seq_num(kctx, cksum, buf, |
| 149 | direction, seqnum); | 169 | direction, seqnum); |
| 170 | plain = kmalloc(8, GFP_NOFS); | ||
| 171 | if (!plain) | ||
| 172 | return -ENOMEM; | ||
| 150 | 173 | ||
| 151 | if ((code = krb5_decrypt(key, cksum, buf, plain, 8))) | 174 | if ((code = krb5_decrypt(key, cksum, buf, plain, 8))) |
| 152 | return code; | 175 | goto out; |
| 153 | 176 | ||
| 154 | if ((plain[4] != plain[5]) || (plain[4] != plain[6]) || | 177 | if ((plain[4] != plain[5]) || (plain[4] != plain[6]) || |
| 155 | (plain[4] != plain[7])) | 178 | (plain[4] != plain[7])) { |
| 156 | return (s32)KG_BAD_SEQ; | 179 | code = (s32)KG_BAD_SEQ; |
| 180 | goto out; | ||
| 181 | } | ||
| 157 | 182 | ||
| 158 | *direction = plain[4]; | 183 | *direction = plain[4]; |
| 159 | 184 | ||
| 160 | *seqnum = ((plain[0]) | | 185 | *seqnum = ((plain[0]) | |
| 161 | (plain[1] << 8) | (plain[2] << 16) | (plain[3] << 24)); | 186 | (plain[1] << 8) | (plain[2] << 16) | (plain[3] << 24)); |
| 162 | 187 | ||
| 163 | return 0; | 188 | out: |
| 189 | kfree(plain); | ||
| 190 | return code; | ||
| 164 | } | 191 | } |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 71d9599b5816..d7ec6132c046 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
| @@ -1739,14 +1739,10 @@ rpc_xdr_encode(struct rpc_task *task) | |||
| 1739 | xdr_buf_init(&req->rq_rcv_buf, | 1739 | xdr_buf_init(&req->rq_rcv_buf, |
| 1740 | req->rq_rbuffer, | 1740 | req->rq_rbuffer, |
| 1741 | req->rq_rcvsize); | 1741 | req->rq_rcvsize); |
| 1742 | req->rq_bytes_sent = 0; | ||
| 1743 | 1742 | ||
| 1744 | p = rpc_encode_header(task); | 1743 | p = rpc_encode_header(task); |
| 1745 | if (p == NULL) { | 1744 | if (p == NULL) |
| 1746 | printk(KERN_INFO "RPC: couldn't encode RPC header, exit EIO\n"); | ||
| 1747 | rpc_exit(task, -EIO); | ||
| 1748 | return; | 1745 | return; |
| 1749 | } | ||
| 1750 | 1746 | ||
| 1751 | encode = task->tk_msg.rpc_proc->p_encode; | 1747 | encode = task->tk_msg.rpc_proc->p_encode; |
| 1752 | if (encode == NULL) | 1748 | if (encode == NULL) |
| @@ -1771,10 +1767,17 @@ call_encode(struct rpc_task *task) | |||
| 1771 | /* Did the encode result in an error condition? */ | 1767 | /* Did the encode result in an error condition? */ |
| 1772 | if (task->tk_status != 0) { | 1768 | if (task->tk_status != 0) { |
| 1773 | /* Was the error nonfatal? */ | 1769 | /* Was the error nonfatal? */ |
| 1774 | if (task->tk_status == -EAGAIN || task->tk_status == -ENOMEM) | 1770 | switch (task->tk_status) { |
| 1771 | case -EAGAIN: | ||
| 1772 | case -ENOMEM: | ||
| 1775 | rpc_delay(task, HZ >> 4); | 1773 | rpc_delay(task, HZ >> 4); |
| 1776 | else | 1774 | break; |
| 1775 | case -EKEYEXPIRED: | ||
| 1776 | task->tk_action = call_refresh; | ||
| 1777 | break; | ||
| 1778 | default: | ||
| 1777 | rpc_exit(task, task->tk_status); | 1779 | rpc_exit(task, task->tk_status); |
| 1780 | } | ||
| 1778 | return; | 1781 | return; |
| 1779 | } | 1782 | } |
| 1780 | 1783 | ||
| @@ -2336,7 +2339,8 @@ rpc_encode_header(struct rpc_task *task) | |||
| 2336 | *p++ = htonl(clnt->cl_vers); /* program version */ | 2339 | *p++ = htonl(clnt->cl_vers); /* program version */ |
| 2337 | *p++ = htonl(task->tk_msg.rpc_proc->p_proc); /* procedure */ | 2340 | *p++ = htonl(task->tk_msg.rpc_proc->p_proc); /* procedure */ |
| 2338 | p = rpcauth_marshcred(task, p); | 2341 | p = rpcauth_marshcred(task, p); |
| 2339 | req->rq_slen = xdr_adjust_iovec(&req->rq_svec[0], p); | 2342 | if (p) |
| 2343 | req->rq_slen = xdr_adjust_iovec(&req->rq_svec[0], p); | ||
| 2340 | return p; | 2344 | return p; |
| 2341 | } | 2345 | } |
| 2342 | 2346 | ||
diff --git a/net/sunrpc/debugfs.c b/net/sunrpc/debugfs.c index 45a033329cd4..19bb356230ed 100644 --- a/net/sunrpc/debugfs.c +++ b/net/sunrpc/debugfs.c | |||
| @@ -146,7 +146,7 @@ rpc_clnt_debugfs_register(struct rpc_clnt *clnt) | |||
| 146 | rcu_read_lock(); | 146 | rcu_read_lock(); |
| 147 | xprt = rcu_dereference(clnt->cl_xprt); | 147 | xprt = rcu_dereference(clnt->cl_xprt); |
| 148 | /* no "debugfs" dentry? Don't bother with the symlink. */ | 148 | /* no "debugfs" dentry? Don't bother with the symlink. */ |
| 149 | if (!xprt->debugfs) { | 149 | if (IS_ERR_OR_NULL(xprt->debugfs)) { |
| 150 | rcu_read_unlock(); | 150 | rcu_read_unlock(); |
| 151 | return; | 151 | return; |
| 152 | } | 152 | } |
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 73547d17d3c6..f1ec2110efeb 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
| @@ -1151,6 +1151,7 @@ xprt_request_enqueue_transmit(struct rpc_task *task) | |||
| 1151 | struct rpc_xprt *xprt = req->rq_xprt; | 1151 | struct rpc_xprt *xprt = req->rq_xprt; |
| 1152 | 1152 | ||
| 1153 | if (xprt_request_need_enqueue_transmit(task, req)) { | 1153 | if (xprt_request_need_enqueue_transmit(task, req)) { |
| 1154 | req->rq_bytes_sent = 0; | ||
| 1154 | spin_lock(&xprt->queue_lock); | 1155 | spin_lock(&xprt->queue_lock); |
| 1155 | /* | 1156 | /* |
| 1156 | * Requests that carry congestion control credits are added | 1157 | * Requests that carry congestion control credits are added |
| @@ -1177,7 +1178,7 @@ xprt_request_enqueue_transmit(struct rpc_task *task) | |||
| 1177 | INIT_LIST_HEAD(&req->rq_xmit2); | 1178 | INIT_LIST_HEAD(&req->rq_xmit2); |
| 1178 | goto out; | 1179 | goto out; |
| 1179 | } | 1180 | } |
| 1180 | } else { | 1181 | } else if (!req->rq_seqno) { |
| 1181 | list_for_each_entry(pos, &xprt->xmit_queue, rq_xmit) { | 1182 | list_for_each_entry(pos, &xprt->xmit_queue, rq_xmit) { |
| 1182 | if (pos->rq_task->tk_owner != task->tk_owner) | 1183 | if (pos->rq_task->tk_owner != task->tk_owner) |
| 1183 | continue; | 1184 | continue; |
diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c index cf51b8f9b15f..1f200119268c 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c +++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c | |||
| @@ -537,6 +537,99 @@ void svc_rdma_sync_reply_hdr(struct svcxprt_rdma *rdma, | |||
| 537 | DMA_TO_DEVICE); | 537 | DMA_TO_DEVICE); |
| 538 | } | 538 | } |
| 539 | 539 | ||
| 540 | /* If the xdr_buf has more elements than the device can | ||
| 541 | * transmit in a single RDMA Send, then the reply will | ||
| 542 | * have to be copied into a bounce buffer. | ||
| 543 | */ | ||
| 544 | static bool svc_rdma_pull_up_needed(struct svcxprt_rdma *rdma, | ||
| 545 | struct xdr_buf *xdr, | ||
| 546 | __be32 *wr_lst) | ||
| 547 | { | ||
| 548 | int elements; | ||
| 549 | |||
| 550 | /* xdr->head */ | ||
| 551 | elements = 1; | ||
| 552 | |||
| 553 | /* xdr->pages */ | ||
| 554 | if (!wr_lst) { | ||
| 555 | unsigned int remaining; | ||
| 556 | unsigned long pageoff; | ||
| 557 | |||
| 558 | pageoff = xdr->page_base & ~PAGE_MASK; | ||
| 559 | remaining = xdr->page_len; | ||
| 560 | while (remaining) { | ||
| 561 | ++elements; | ||
| 562 | remaining -= min_t(u32, PAGE_SIZE - pageoff, | ||
| 563 | remaining); | ||
| 564 | pageoff = 0; | ||
| 565 | } | ||
| 566 | } | ||
| 567 | |||
| 568 | /* xdr->tail */ | ||
| 569 | if (xdr->tail[0].iov_len) | ||
| 570 | ++elements; | ||
| 571 | |||
| 572 | /* assume 1 SGE is needed for the transport header */ | ||
| 573 | return elements >= rdma->sc_max_send_sges; | ||
| 574 | } | ||
| 575 | |||
| 576 | /* The device is not capable of sending the reply directly. | ||
| 577 | * Assemble the elements of @xdr into the transport header | ||
| 578 | * buffer. | ||
| 579 | */ | ||
| 580 | static int svc_rdma_pull_up_reply_msg(struct svcxprt_rdma *rdma, | ||
| 581 | struct svc_rdma_send_ctxt *ctxt, | ||
| 582 | struct xdr_buf *xdr, __be32 *wr_lst) | ||
| 583 | { | ||
| 584 | unsigned char *dst, *tailbase; | ||
| 585 | unsigned int taillen; | ||
| 586 | |||
| 587 | dst = ctxt->sc_xprt_buf; | ||
| 588 | dst += ctxt->sc_sges[0].length; | ||
| 589 | |||
| 590 | memcpy(dst, xdr->head[0].iov_base, xdr->head[0].iov_len); | ||
| 591 | dst += xdr->head[0].iov_len; | ||
| 592 | |||
| 593 | tailbase = xdr->tail[0].iov_base; | ||
| 594 | taillen = xdr->tail[0].iov_len; | ||
| 595 | if (wr_lst) { | ||
| 596 | u32 xdrpad; | ||
| 597 | |||
| 598 | xdrpad = xdr_padsize(xdr->page_len); | ||
| 599 | if (taillen && xdrpad) { | ||
| 600 | tailbase += xdrpad; | ||
| 601 | taillen -= xdrpad; | ||
| 602 | } | ||
| 603 | } else { | ||
| 604 | unsigned int len, remaining; | ||
| 605 | unsigned long pageoff; | ||
| 606 | struct page **ppages; | ||
| 607 | |||
| 608 | ppages = xdr->pages + (xdr->page_base >> PAGE_SHIFT); | ||
| 609 | pageoff = xdr->page_base & ~PAGE_MASK; | ||
| 610 | remaining = xdr->page_len; | ||
| 611 | while (remaining) { | ||
| 612 | len = min_t(u32, PAGE_SIZE - pageoff, remaining); | ||
| 613 | |||
| 614 | memcpy(dst, page_address(*ppages), len); | ||
| 615 | remaining -= len; | ||
| 616 | dst += len; | ||
| 617 | pageoff = 0; | ||
| 618 | } | ||
| 619 | } | ||
| 620 | |||
| 621 | if (taillen) | ||
| 622 | memcpy(dst, tailbase, taillen); | ||
| 623 | |||
| 624 | ctxt->sc_sges[0].length += xdr->len; | ||
| 625 | ib_dma_sync_single_for_device(rdma->sc_pd->device, | ||
| 626 | ctxt->sc_sges[0].addr, | ||
| 627 | ctxt->sc_sges[0].length, | ||
| 628 | DMA_TO_DEVICE); | ||
| 629 | |||
| 630 | return 0; | ||
| 631 | } | ||
| 632 | |||
| 540 | /* svc_rdma_map_reply_msg - Map the buffer holding RPC message | 633 | /* svc_rdma_map_reply_msg - Map the buffer holding RPC message |
| 541 | * @rdma: controlling transport | 634 | * @rdma: controlling transport |
| 542 | * @ctxt: send_ctxt for the Send WR | 635 | * @ctxt: send_ctxt for the Send WR |
| @@ -559,8 +652,10 @@ int svc_rdma_map_reply_msg(struct svcxprt_rdma *rdma, | |||
| 559 | u32 xdr_pad; | 652 | u32 xdr_pad; |
| 560 | int ret; | 653 | int ret; |
| 561 | 654 | ||
| 562 | if (++ctxt->sc_cur_sge_no >= rdma->sc_max_send_sges) | 655 | if (svc_rdma_pull_up_needed(rdma, xdr, wr_lst)) |
| 563 | return -EIO; | 656 | return svc_rdma_pull_up_reply_msg(rdma, ctxt, xdr, wr_lst); |
| 657 | |||
| 658 | ++ctxt->sc_cur_sge_no; | ||
| 564 | ret = svc_rdma_dma_map_buf(rdma, ctxt, | 659 | ret = svc_rdma_dma_map_buf(rdma, ctxt, |
| 565 | xdr->head[0].iov_base, | 660 | xdr->head[0].iov_base, |
| 566 | xdr->head[0].iov_len); | 661 | xdr->head[0].iov_len); |
| @@ -591,8 +686,7 @@ int svc_rdma_map_reply_msg(struct svcxprt_rdma *rdma, | |||
| 591 | while (remaining) { | 686 | while (remaining) { |
| 592 | len = min_t(u32, PAGE_SIZE - page_off, remaining); | 687 | len = min_t(u32, PAGE_SIZE - page_off, remaining); |
| 593 | 688 | ||
| 594 | if (++ctxt->sc_cur_sge_no >= rdma->sc_max_send_sges) | 689 | ++ctxt->sc_cur_sge_no; |
| 595 | return -EIO; | ||
| 596 | ret = svc_rdma_dma_map_page(rdma, ctxt, *ppages++, | 690 | ret = svc_rdma_dma_map_page(rdma, ctxt, *ppages++, |
| 597 | page_off, len); | 691 | page_off, len); |
| 598 | if (ret < 0) | 692 | if (ret < 0) |
| @@ -606,8 +700,7 @@ int svc_rdma_map_reply_msg(struct svcxprt_rdma *rdma, | |||
| 606 | len = xdr->tail[0].iov_len; | 700 | len = xdr->tail[0].iov_len; |
| 607 | tail: | 701 | tail: |
| 608 | if (len) { | 702 | if (len) { |
| 609 | if (++ctxt->sc_cur_sge_no >= rdma->sc_max_send_sges) | 703 | ++ctxt->sc_cur_sge_no; |
| 610 | return -EIO; | ||
| 611 | ret = svc_rdma_dma_map_buf(rdma, ctxt, base, len); | 704 | ret = svc_rdma_dma_map_buf(rdma, ctxt, base, len); |
| 612 | if (ret < 0) | 705 | if (ret < 0) |
| 613 | return ret; | 706 | return ret; |
diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c index 924c17d46903..57f86c63a463 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_transport.c +++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c | |||
| @@ -419,12 +419,9 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) | |||
| 419 | /* Transport header, head iovec, tail iovec */ | 419 | /* Transport header, head iovec, tail iovec */ |
| 420 | newxprt->sc_max_send_sges = 3; | 420 | newxprt->sc_max_send_sges = 3; |
| 421 | /* Add one SGE per page list entry */ | 421 | /* Add one SGE per page list entry */ |
| 422 | newxprt->sc_max_send_sges += svcrdma_max_req_size / PAGE_SIZE; | 422 | newxprt->sc_max_send_sges += (svcrdma_max_req_size / PAGE_SIZE) + 1; |
| 423 | if (newxprt->sc_max_send_sges > dev->attrs.max_send_sge) { | 423 | if (newxprt->sc_max_send_sges > dev->attrs.max_send_sge) |
| 424 | pr_err("svcrdma: too few Send SGEs available (%d needed)\n", | 424 | newxprt->sc_max_send_sges = dev->attrs.max_send_sge; |
| 425 | newxprt->sc_max_send_sges); | ||
| 426 | goto errout; | ||
| 427 | } | ||
| 428 | newxprt->sc_max_req_size = svcrdma_max_req_size; | 425 | newxprt->sc_max_req_size = svcrdma_max_req_size; |
| 429 | newxprt->sc_max_requests = svcrdma_max_requests; | 426 | newxprt->sc_max_requests = svcrdma_max_requests; |
| 430 | newxprt->sc_max_bc_requests = svcrdma_max_bc_requests; | 427 | newxprt->sc_max_bc_requests = svcrdma_max_bc_requests; |
diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 7749a2bf6887..21113bfd4eca 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c | |||
| @@ -527,7 +527,8 @@ rpcrdma_ep_create(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia, | |||
| 527 | 527 | ||
| 528 | sendcq = ib_alloc_cq(ia->ri_device, NULL, | 528 | sendcq = ib_alloc_cq(ia->ri_device, NULL, |
| 529 | ep->rep_attr.cap.max_send_wr + 1, | 529 | ep->rep_attr.cap.max_send_wr + 1, |
| 530 | 1, IB_POLL_WORKQUEUE); | 530 | ia->ri_device->num_comp_vectors > 1 ? 1 : 0, |
| 531 | IB_POLL_WORKQUEUE); | ||
| 531 | if (IS_ERR(sendcq)) { | 532 | if (IS_ERR(sendcq)) { |
| 532 | rc = PTR_ERR(sendcq); | 533 | rc = PTR_ERR(sendcq); |
| 533 | goto out1; | 534 | goto out1; |
| @@ -845,17 +846,13 @@ static int rpcrdma_sendctxs_create(struct rpcrdma_xprt *r_xprt) | |||
| 845 | for (i = 0; i <= buf->rb_sc_last; i++) { | 846 | for (i = 0; i <= buf->rb_sc_last; i++) { |
| 846 | sc = rpcrdma_sendctx_create(&r_xprt->rx_ia); | 847 | sc = rpcrdma_sendctx_create(&r_xprt->rx_ia); |
| 847 | if (!sc) | 848 | if (!sc) |
| 848 | goto out_destroy; | 849 | return -ENOMEM; |
| 849 | 850 | ||
| 850 | sc->sc_xprt = r_xprt; | 851 | sc->sc_xprt = r_xprt; |
| 851 | buf->rb_sc_ctxs[i] = sc; | 852 | buf->rb_sc_ctxs[i] = sc; |
| 852 | } | 853 | } |
| 853 | 854 | ||
| 854 | return 0; | 855 | return 0; |
| 855 | |||
| 856 | out_destroy: | ||
| 857 | rpcrdma_sendctxs_destroy(buf); | ||
| 858 | return -ENOMEM; | ||
| 859 | } | 856 | } |
| 860 | 857 | ||
| 861 | /* The sendctx queue is not guaranteed to have a size that is a | 858 | /* The sendctx queue is not guaranteed to have a size that is a |
| @@ -1113,8 +1110,10 @@ rpcrdma_buffer_create(struct rpcrdma_xprt *r_xprt) | |||
| 1113 | WQ_MEM_RECLAIM | WQ_HIGHPRI, | 1110 | WQ_MEM_RECLAIM | WQ_HIGHPRI, |
| 1114 | 0, | 1111 | 0, |
| 1115 | r_xprt->rx_xprt.address_strings[RPC_DISPLAY_ADDR]); | 1112 | r_xprt->rx_xprt.address_strings[RPC_DISPLAY_ADDR]); |
| 1116 | if (!buf->rb_completion_wq) | 1113 | if (!buf->rb_completion_wq) { |
| 1114 | rc = -ENOMEM; | ||
| 1117 | goto out; | 1115 | goto out; |
| 1116 | } | ||
| 1118 | 1117 | ||
| 1119 | return 0; | 1118 | return 0; |
| 1120 | out: | 1119 | out: |
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 13559e6a460b..7754aa3e434f 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
| @@ -48,6 +48,7 @@ | |||
| 48 | #include <net/udp.h> | 48 | #include <net/udp.h> |
| 49 | #include <net/tcp.h> | 49 | #include <net/tcp.h> |
| 50 | #include <linux/bvec.h> | 50 | #include <linux/bvec.h> |
| 51 | #include <linux/highmem.h> | ||
| 51 | #include <linux/uio.h> | 52 | #include <linux/uio.h> |
| 52 | 53 | ||
| 53 | #include <trace/events/sunrpc.h> | 54 | #include <trace/events/sunrpc.h> |
| @@ -376,6 +377,26 @@ xs_read_discard(struct socket *sock, struct msghdr *msg, int flags, | |||
| 376 | return sock_recvmsg(sock, msg, flags); | 377 | return sock_recvmsg(sock, msg, flags); |
| 377 | } | 378 | } |
| 378 | 379 | ||
| 380 | #if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE | ||
| 381 | static void | ||
| 382 | xs_flush_bvec(const struct bio_vec *bvec, size_t count, size_t seek) | ||
| 383 | { | ||
| 384 | struct bvec_iter bi = { | ||
| 385 | .bi_size = count, | ||
| 386 | }; | ||
| 387 | struct bio_vec bv; | ||
| 388 | |||
| 389 | bvec_iter_advance(bvec, &bi, seek & PAGE_MASK); | ||
| 390 | for_each_bvec(bv, bvec, bi, bi) | ||
| 391 | flush_dcache_page(bv.bv_page); | ||
| 392 | } | ||
| 393 | #else | ||
| 394 | static inline void | ||
| 395 | xs_flush_bvec(const struct bio_vec *bvec, size_t count, size_t seek) | ||
| 396 | { | ||
| 397 | } | ||
| 398 | #endif | ||
| 399 | |||
| 379 | static ssize_t | 400 | static ssize_t |
| 380 | xs_read_xdr_buf(struct socket *sock, struct msghdr *msg, int flags, | 401 | xs_read_xdr_buf(struct socket *sock, struct msghdr *msg, int flags, |
| 381 | struct xdr_buf *buf, size_t count, size_t seek, size_t *read) | 402 | struct xdr_buf *buf, size_t count, size_t seek, size_t *read) |
| @@ -409,6 +430,7 @@ xs_read_xdr_buf(struct socket *sock, struct msghdr *msg, int flags, | |||
| 409 | seek + buf->page_base); | 430 | seek + buf->page_base); |
| 410 | if (ret <= 0) | 431 | if (ret <= 0) |
| 411 | goto sock_err; | 432 | goto sock_err; |
| 433 | xs_flush_bvec(buf->bvec, ret, seek + buf->page_base); | ||
| 412 | offset += ret - buf->page_base; | 434 | offset += ret - buf->page_base; |
| 413 | if (offset == count || msg->msg_flags & (MSG_EOR|MSG_TRUNC)) | 435 | if (offset == count || msg->msg_flags & (MSG_EOR|MSG_TRUNC)) |
| 414 | goto out; | 436 | goto out; |
diff --git a/net/tipc/link.c b/net/tipc/link.c index 2792a3cae682..85ad5c0678d0 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c | |||
| @@ -1145,7 +1145,7 @@ static bool tipc_data_input(struct tipc_link *l, struct sk_buff *skb, | |||
| 1145 | default: | 1145 | default: |
| 1146 | pr_warn("Dropping received illegal msg type\n"); | 1146 | pr_warn("Dropping received illegal msg type\n"); |
| 1147 | kfree_skb(skb); | 1147 | kfree_skb(skb); |
| 1148 | return false; | 1148 | return true; |
| 1149 | }; | 1149 | }; |
| 1150 | } | 1150 | } |
| 1151 | 1151 | ||
| @@ -1425,6 +1425,10 @@ static void tipc_link_build_proto_msg(struct tipc_link *l, int mtyp, bool probe, | |||
| 1425 | l->rcv_unacked = 0; | 1425 | l->rcv_unacked = 0; |
| 1426 | } else { | 1426 | } else { |
| 1427 | /* RESET_MSG or ACTIVATE_MSG */ | 1427 | /* RESET_MSG or ACTIVATE_MSG */ |
| 1428 | if (mtyp == ACTIVATE_MSG) { | ||
| 1429 | msg_set_dest_session_valid(hdr, 1); | ||
| 1430 | msg_set_dest_session(hdr, l->peer_session); | ||
| 1431 | } | ||
| 1428 | msg_set_max_pkt(hdr, l->advertised_mtu); | 1432 | msg_set_max_pkt(hdr, l->advertised_mtu); |
| 1429 | strcpy(data, l->if_name); | 1433 | strcpy(data, l->if_name); |
| 1430 | msg_set_size(hdr, INT_H_SIZE + TIPC_MAX_IF_NAME); | 1434 | msg_set_size(hdr, INT_H_SIZE + TIPC_MAX_IF_NAME); |
| @@ -1642,6 +1646,17 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb, | |||
| 1642 | rc = tipc_link_fsm_evt(l, LINK_FAILURE_EVT); | 1646 | rc = tipc_link_fsm_evt(l, LINK_FAILURE_EVT); |
| 1643 | break; | 1647 | break; |
| 1644 | } | 1648 | } |
| 1649 | |||
| 1650 | /* If this endpoint was re-created while peer was ESTABLISHING | ||
| 1651 | * it doesn't know current session number. Force re-synch. | ||
| 1652 | */ | ||
| 1653 | if (mtyp == ACTIVATE_MSG && msg_dest_session_valid(hdr) && | ||
| 1654 | l->session != msg_dest_session(hdr)) { | ||
| 1655 | if (less(l->session, msg_dest_session(hdr))) | ||
| 1656 | l->session = msg_dest_session(hdr) + 1; | ||
| 1657 | break; | ||
| 1658 | } | ||
| 1659 | |||
| 1645 | /* ACTIVATE_MSG serves as PEER_RESET if link is already down */ | 1660 | /* ACTIVATE_MSG serves as PEER_RESET if link is already down */ |
| 1646 | if (mtyp == RESET_MSG || !link_is_up(l)) | 1661 | if (mtyp == RESET_MSG || !link_is_up(l)) |
| 1647 | rc = tipc_link_fsm_evt(l, LINK_PEER_RESET_EVT); | 1662 | rc = tipc_link_fsm_evt(l, LINK_PEER_RESET_EVT); |
diff --git a/net/tipc/msg.h b/net/tipc/msg.h index a0924956bb61..d7e4b8b93f9d 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h | |||
| @@ -360,6 +360,28 @@ static inline void msg_set_bcast_ack(struct tipc_msg *m, u16 n) | |||
| 360 | msg_set_bits(m, 1, 0, 0xffff, n); | 360 | msg_set_bits(m, 1, 0, 0xffff, n); |
| 361 | } | 361 | } |
| 362 | 362 | ||
| 363 | /* Note: reusing bits in word 1 for ACTIVATE_MSG only, to re-synch | ||
| 364 | * link peer session number | ||
| 365 | */ | ||
| 366 | static inline bool msg_dest_session_valid(struct tipc_msg *m) | ||
| 367 | { | ||
| 368 | return msg_bits(m, 1, 16, 0x1); | ||
| 369 | } | ||
| 370 | |||
| 371 | static inline void msg_set_dest_session_valid(struct tipc_msg *m, bool valid) | ||
| 372 | { | ||
| 373 | msg_set_bits(m, 1, 16, 0x1, valid); | ||
| 374 | } | ||
| 375 | |||
| 376 | static inline u16 msg_dest_session(struct tipc_msg *m) | ||
| 377 | { | ||
| 378 | return msg_bits(m, 1, 0, 0xffff); | ||
| 379 | } | ||
| 380 | |||
| 381 | static inline void msg_set_dest_session(struct tipc_msg *m, u16 n) | ||
| 382 | { | ||
| 383 | msg_set_bits(m, 1, 0, 0xffff, n); | ||
| 384 | } | ||
| 363 | 385 | ||
| 364 | /* | 386 | /* |
| 365 | * Word 2 | 387 | * Word 2 |
diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c index 40f5cae623a7..4ad3586da8f0 100644 --- a/net/tipc/netlink_compat.c +++ b/net/tipc/netlink_compat.c | |||
| @@ -87,6 +87,11 @@ static int tipc_skb_tailroom(struct sk_buff *skb) | |||
| 87 | return limit; | 87 | return limit; |
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | static inline int TLV_GET_DATA_LEN(struct tlv_desc *tlv) | ||
| 91 | { | ||
| 92 | return TLV_GET_LEN(tlv) - TLV_SPACE(0); | ||
| 93 | } | ||
| 94 | |||
| 90 | static int tipc_add_tlv(struct sk_buff *skb, u16 type, void *data, u16 len) | 95 | static int tipc_add_tlv(struct sk_buff *skb, u16 type, void *data, u16 len) |
| 91 | { | 96 | { |
| 92 | struct tlv_desc *tlv = (struct tlv_desc *)skb_tail_pointer(skb); | 97 | struct tlv_desc *tlv = (struct tlv_desc *)skb_tail_pointer(skb); |
| @@ -166,6 +171,11 @@ static struct sk_buff *tipc_get_err_tlv(char *str) | |||
| 166 | return buf; | 171 | return buf; |
| 167 | } | 172 | } |
| 168 | 173 | ||
| 174 | static inline bool string_is_valid(char *s, int len) | ||
| 175 | { | ||
| 176 | return memchr(s, '\0', len) ? true : false; | ||
| 177 | } | ||
| 178 | |||
| 169 | static int __tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump *cmd, | 179 | static int __tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump *cmd, |
| 170 | struct tipc_nl_compat_msg *msg, | 180 | struct tipc_nl_compat_msg *msg, |
| 171 | struct sk_buff *arg) | 181 | struct sk_buff *arg) |
| @@ -379,6 +389,7 @@ static int tipc_nl_compat_bearer_enable(struct tipc_nl_compat_cmd_doit *cmd, | |||
| 379 | struct nlattr *prop; | 389 | struct nlattr *prop; |
| 380 | struct nlattr *bearer; | 390 | struct nlattr *bearer; |
| 381 | struct tipc_bearer_config *b; | 391 | struct tipc_bearer_config *b; |
| 392 | int len; | ||
| 382 | 393 | ||
| 383 | b = (struct tipc_bearer_config *)TLV_DATA(msg->req); | 394 | b = (struct tipc_bearer_config *)TLV_DATA(msg->req); |
| 384 | 395 | ||
| @@ -386,6 +397,10 @@ static int tipc_nl_compat_bearer_enable(struct tipc_nl_compat_cmd_doit *cmd, | |||
| 386 | if (!bearer) | 397 | if (!bearer) |
| 387 | return -EMSGSIZE; | 398 | return -EMSGSIZE; |
| 388 | 399 | ||
| 400 | len = min_t(int, TLV_GET_DATA_LEN(msg->req), TIPC_MAX_BEARER_NAME); | ||
| 401 | if (!string_is_valid(b->name, len)) | ||
| 402 | return -EINVAL; | ||
| 403 | |||
| 389 | if (nla_put_string(skb, TIPC_NLA_BEARER_NAME, b->name)) | 404 | if (nla_put_string(skb, TIPC_NLA_BEARER_NAME, b->name)) |
| 390 | return -EMSGSIZE; | 405 | return -EMSGSIZE; |
| 391 | 406 | ||
| @@ -411,6 +426,7 @@ static int tipc_nl_compat_bearer_disable(struct tipc_nl_compat_cmd_doit *cmd, | |||
| 411 | { | 426 | { |
| 412 | char *name; | 427 | char *name; |
| 413 | struct nlattr *bearer; | 428 | struct nlattr *bearer; |
| 429 | int len; | ||
| 414 | 430 | ||
| 415 | name = (char *)TLV_DATA(msg->req); | 431 | name = (char *)TLV_DATA(msg->req); |
| 416 | 432 | ||
| @@ -418,6 +434,10 @@ static int tipc_nl_compat_bearer_disable(struct tipc_nl_compat_cmd_doit *cmd, | |||
| 418 | if (!bearer) | 434 | if (!bearer) |
| 419 | return -EMSGSIZE; | 435 | return -EMSGSIZE; |
| 420 | 436 | ||
| 437 | len = min_t(int, TLV_GET_DATA_LEN(msg->req), TIPC_MAX_BEARER_NAME); | ||
| 438 | if (!string_is_valid(name, len)) | ||
| 439 | return -EINVAL; | ||
| 440 | |||
| 421 | if (nla_put_string(skb, TIPC_NLA_BEARER_NAME, name)) | 441 | if (nla_put_string(skb, TIPC_NLA_BEARER_NAME, name)) |
| 422 | return -EMSGSIZE; | 442 | return -EMSGSIZE; |
| 423 | 443 | ||
| @@ -478,6 +498,7 @@ static int tipc_nl_compat_link_stat_dump(struct tipc_nl_compat_msg *msg, | |||
| 478 | struct nlattr *prop[TIPC_NLA_PROP_MAX + 1]; | 498 | struct nlattr *prop[TIPC_NLA_PROP_MAX + 1]; |
| 479 | struct nlattr *stats[TIPC_NLA_STATS_MAX + 1]; | 499 | struct nlattr *stats[TIPC_NLA_STATS_MAX + 1]; |
| 480 | int err; | 500 | int err; |
| 501 | int len; | ||
| 481 | 502 | ||
| 482 | if (!attrs[TIPC_NLA_LINK]) | 503 | if (!attrs[TIPC_NLA_LINK]) |
| 483 | return -EINVAL; | 504 | return -EINVAL; |
| @@ -504,6 +525,11 @@ static int tipc_nl_compat_link_stat_dump(struct tipc_nl_compat_msg *msg, | |||
| 504 | return err; | 525 | return err; |
| 505 | 526 | ||
| 506 | name = (char *)TLV_DATA(msg->req); | 527 | name = (char *)TLV_DATA(msg->req); |
| 528 | |||
| 529 | len = min_t(int, TLV_GET_DATA_LEN(msg->req), TIPC_MAX_LINK_NAME); | ||
| 530 | if (!string_is_valid(name, len)) | ||
| 531 | return -EINVAL; | ||
| 532 | |||
| 507 | if (strcmp(name, nla_data(link[TIPC_NLA_LINK_NAME])) != 0) | 533 | if (strcmp(name, nla_data(link[TIPC_NLA_LINK_NAME])) != 0) |
| 508 | return 0; | 534 | return 0; |
| 509 | 535 | ||
| @@ -644,6 +670,7 @@ static int tipc_nl_compat_media_set(struct sk_buff *skb, | |||
| 644 | struct nlattr *prop; | 670 | struct nlattr *prop; |
| 645 | struct nlattr *media; | 671 | struct nlattr *media; |
| 646 | struct tipc_link_config *lc; | 672 | struct tipc_link_config *lc; |
| 673 | int len; | ||
| 647 | 674 | ||
| 648 | lc = (struct tipc_link_config *)TLV_DATA(msg->req); | 675 | lc = (struct tipc_link_config *)TLV_DATA(msg->req); |
| 649 | 676 | ||
| @@ -651,6 +678,10 @@ static int tipc_nl_compat_media_set(struct sk_buff *skb, | |||
| 651 | if (!media) | 678 | if (!media) |
| 652 | return -EMSGSIZE; | 679 | return -EMSGSIZE; |
| 653 | 680 | ||
| 681 | len = min_t(int, TLV_GET_DATA_LEN(msg->req), TIPC_MAX_MEDIA_NAME); | ||
| 682 | if (!string_is_valid(lc->name, len)) | ||
| 683 | return -EINVAL; | ||
| 684 | |||
| 654 | if (nla_put_string(skb, TIPC_NLA_MEDIA_NAME, lc->name)) | 685 | if (nla_put_string(skb, TIPC_NLA_MEDIA_NAME, lc->name)) |
| 655 | return -EMSGSIZE; | 686 | return -EMSGSIZE; |
| 656 | 687 | ||
| @@ -671,6 +702,7 @@ static int tipc_nl_compat_bearer_set(struct sk_buff *skb, | |||
| 671 | struct nlattr *prop; | 702 | struct nlattr *prop; |
| 672 | struct nlattr *bearer; | 703 | struct nlattr *bearer; |
| 673 | struct tipc_link_config *lc; | 704 | struct tipc_link_config *lc; |
| 705 | int len; | ||
| 674 | 706 | ||
| 675 | lc = (struct tipc_link_config *)TLV_DATA(msg->req); | 707 | lc = (struct tipc_link_config *)TLV_DATA(msg->req); |
| 676 | 708 | ||
| @@ -678,6 +710,10 @@ static int tipc_nl_compat_bearer_set(struct sk_buff *skb, | |||
| 678 | if (!bearer) | 710 | if (!bearer) |
| 679 | return -EMSGSIZE; | 711 | return -EMSGSIZE; |
| 680 | 712 | ||
| 713 | len = min_t(int, TLV_GET_DATA_LEN(msg->req), TIPC_MAX_MEDIA_NAME); | ||
| 714 | if (!string_is_valid(lc->name, len)) | ||
| 715 | return -EINVAL; | ||
| 716 | |||
| 681 | if (nla_put_string(skb, TIPC_NLA_BEARER_NAME, lc->name)) | 717 | if (nla_put_string(skb, TIPC_NLA_BEARER_NAME, lc->name)) |
| 682 | return -EMSGSIZE; | 718 | return -EMSGSIZE; |
| 683 | 719 | ||
| @@ -726,9 +762,14 @@ static int tipc_nl_compat_link_set(struct tipc_nl_compat_cmd_doit *cmd, | |||
| 726 | struct tipc_link_config *lc; | 762 | struct tipc_link_config *lc; |
| 727 | struct tipc_bearer *bearer; | 763 | struct tipc_bearer *bearer; |
| 728 | struct tipc_media *media; | 764 | struct tipc_media *media; |
| 765 | int len; | ||
| 729 | 766 | ||
| 730 | lc = (struct tipc_link_config *)TLV_DATA(msg->req); | 767 | lc = (struct tipc_link_config *)TLV_DATA(msg->req); |
| 731 | 768 | ||
| 769 | len = min_t(int, TLV_GET_DATA_LEN(msg->req), TIPC_MAX_LINK_NAME); | ||
| 770 | if (!string_is_valid(lc->name, len)) | ||
| 771 | return -EINVAL; | ||
| 772 | |||
| 732 | media = tipc_media_find(lc->name); | 773 | media = tipc_media_find(lc->name); |
| 733 | if (media) { | 774 | if (media) { |
| 734 | cmd->doit = &__tipc_nl_media_set; | 775 | cmd->doit = &__tipc_nl_media_set; |
| @@ -750,6 +791,7 @@ static int tipc_nl_compat_link_reset_stats(struct tipc_nl_compat_cmd_doit *cmd, | |||
| 750 | { | 791 | { |
| 751 | char *name; | 792 | char *name; |
| 752 | struct nlattr *link; | 793 | struct nlattr *link; |
| 794 | int len; | ||
| 753 | 795 | ||
| 754 | name = (char *)TLV_DATA(msg->req); | 796 | name = (char *)TLV_DATA(msg->req); |
| 755 | 797 | ||
| @@ -757,6 +799,10 @@ static int tipc_nl_compat_link_reset_stats(struct tipc_nl_compat_cmd_doit *cmd, | |||
| 757 | if (!link) | 799 | if (!link) |
| 758 | return -EMSGSIZE; | 800 | return -EMSGSIZE; |
| 759 | 801 | ||
| 802 | len = min_t(int, TLV_GET_DATA_LEN(msg->req), TIPC_MAX_LINK_NAME); | ||
| 803 | if (!string_is_valid(name, len)) | ||
| 804 | return -EINVAL; | ||
| 805 | |||
| 760 | if (nla_put_string(skb, TIPC_NLA_LINK_NAME, name)) | 806 | if (nla_put_string(skb, TIPC_NLA_LINK_NAME, name)) |
| 761 | return -EMSGSIZE; | 807 | return -EMSGSIZE; |
| 762 | 808 | ||
| @@ -778,6 +824,8 @@ static int tipc_nl_compat_name_table_dump_header(struct tipc_nl_compat_msg *msg) | |||
| 778 | }; | 824 | }; |
| 779 | 825 | ||
| 780 | ntq = (struct tipc_name_table_query *)TLV_DATA(msg->req); | 826 | ntq = (struct tipc_name_table_query *)TLV_DATA(msg->req); |
| 827 | if (TLV_GET_DATA_LEN(msg->req) < sizeof(struct tipc_name_table_query)) | ||
| 828 | return -EINVAL; | ||
| 781 | 829 | ||
| 782 | depth = ntohl(ntq->depth); | 830 | depth = ntohl(ntq->depth); |
| 783 | 831 | ||
| @@ -904,8 +952,10 @@ static int tipc_nl_compat_publ_dump(struct tipc_nl_compat_msg *msg, u32 sock) | |||
| 904 | 952 | ||
| 905 | hdr = genlmsg_put(args, 0, 0, &tipc_genl_family, NLM_F_MULTI, | 953 | hdr = genlmsg_put(args, 0, 0, &tipc_genl_family, NLM_F_MULTI, |
| 906 | TIPC_NL_PUBL_GET); | 954 | TIPC_NL_PUBL_GET); |
| 907 | if (!hdr) | 955 | if (!hdr) { |
| 956 | kfree_skb(args); | ||
| 908 | return -EMSGSIZE; | 957 | return -EMSGSIZE; |
| 958 | } | ||
| 909 | 959 | ||
| 910 | nest = nla_nest_start(args, TIPC_NLA_SOCK); | 960 | nest = nla_nest_start(args, TIPC_NLA_SOCK); |
| 911 | if (!nest) { | 961 | if (!nest) { |
| @@ -1206,7 +1256,7 @@ static int tipc_nl_compat_recv(struct sk_buff *skb, struct genl_info *info) | |||
| 1206 | } | 1256 | } |
| 1207 | 1257 | ||
| 1208 | len = nlmsg_attrlen(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN); | 1258 | len = nlmsg_attrlen(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN); |
| 1209 | if (len && !TLV_OK(msg.req, len)) { | 1259 | if (!len || !TLV_OK(msg.req, len)) { |
| 1210 | msg.rep = tipc_get_err_tlv(TIPC_CFG_NOT_SUPPORTED); | 1260 | msg.rep = tipc_get_err_tlv(TIPC_CFG_NOT_SUPPORTED); |
| 1211 | err = -EOPNOTSUPP; | 1261 | err = -EOPNOTSUPP; |
| 1212 | goto send; | 1262 | goto send; |
diff --git a/net/tipc/node.c b/net/tipc/node.c index db2a6c3e0be9..2dc4919ab23c 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c | |||
| @@ -830,15 +830,16 @@ static void tipc_node_link_down(struct tipc_node *n, int bearer_id, bool delete) | |||
| 830 | tipc_node_write_lock(n); | 830 | tipc_node_write_lock(n); |
| 831 | if (!tipc_link_is_establishing(l)) { | 831 | if (!tipc_link_is_establishing(l)) { |
| 832 | __tipc_node_link_down(n, &bearer_id, &xmitq, &maddr); | 832 | __tipc_node_link_down(n, &bearer_id, &xmitq, &maddr); |
| 833 | if (delete) { | ||
| 834 | kfree(l); | ||
| 835 | le->link = NULL; | ||
| 836 | n->link_cnt--; | ||
| 837 | } | ||
| 838 | } else { | 833 | } else { |
| 839 | /* Defuse pending tipc_node_link_up() */ | 834 | /* Defuse pending tipc_node_link_up() */ |
| 835 | tipc_link_reset(l); | ||
| 840 | tipc_link_fsm_evt(l, LINK_RESET_EVT); | 836 | tipc_link_fsm_evt(l, LINK_RESET_EVT); |
| 841 | } | 837 | } |
| 838 | if (delete) { | ||
| 839 | kfree(l); | ||
| 840 | le->link = NULL; | ||
| 841 | n->link_cnt--; | ||
| 842 | } | ||
| 842 | trace_tipc_node_link_down(n, true, "node link down or deleted!"); | 843 | trace_tipc_node_link_down(n, true, "node link down or deleted!"); |
| 843 | tipc_node_write_unlock(n); | 844 | tipc_node_write_unlock(n); |
| 844 | if (delete) | 845 | if (delete) |
diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 1217c90a363b..684f2125fc6b 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c | |||
| @@ -388,7 +388,7 @@ static int tipc_sk_sock_err(struct socket *sock, long *timeout) | |||
| 388 | rc_ = tipc_sk_sock_err((sock_), timeo_); \ | 388 | rc_ = tipc_sk_sock_err((sock_), timeo_); \ |
| 389 | if (rc_) \ | 389 | if (rc_) \ |
| 390 | break; \ | 390 | break; \ |
| 391 | prepare_to_wait(sk_sleep(sk_), &wait_, TASK_INTERRUPTIBLE); \ | 391 | add_wait_queue(sk_sleep(sk_), &wait_); \ |
| 392 | release_sock(sk_); \ | 392 | release_sock(sk_); \ |
| 393 | *(timeo_) = wait_woken(&wait_, TASK_INTERRUPTIBLE, *(timeo_)); \ | 393 | *(timeo_) = wait_woken(&wait_, TASK_INTERRUPTIBLE, *(timeo_)); \ |
| 394 | sched_annotate_sleep(); \ | 394 | sched_annotate_sleep(); \ |
| @@ -1677,7 +1677,7 @@ static void tipc_sk_send_ack(struct tipc_sock *tsk) | |||
| 1677 | static int tipc_wait_for_rcvmsg(struct socket *sock, long *timeop) | 1677 | static int tipc_wait_for_rcvmsg(struct socket *sock, long *timeop) |
| 1678 | { | 1678 | { |
| 1679 | struct sock *sk = sock->sk; | 1679 | struct sock *sk = sock->sk; |
| 1680 | DEFINE_WAIT(wait); | 1680 | DEFINE_WAIT_FUNC(wait, woken_wake_function); |
| 1681 | long timeo = *timeop; | 1681 | long timeo = *timeop; |
| 1682 | int err = sock_error(sk); | 1682 | int err = sock_error(sk); |
| 1683 | 1683 | ||
| @@ -1685,15 +1685,17 @@ static int tipc_wait_for_rcvmsg(struct socket *sock, long *timeop) | |||
| 1685 | return err; | 1685 | return err; |
| 1686 | 1686 | ||
| 1687 | for (;;) { | 1687 | for (;;) { |
| 1688 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | ||
| 1689 | if (timeo && skb_queue_empty(&sk->sk_receive_queue)) { | 1688 | if (timeo && skb_queue_empty(&sk->sk_receive_queue)) { |
| 1690 | if (sk->sk_shutdown & RCV_SHUTDOWN) { | 1689 | if (sk->sk_shutdown & RCV_SHUTDOWN) { |
| 1691 | err = -ENOTCONN; | 1690 | err = -ENOTCONN; |
| 1692 | break; | 1691 | break; |
| 1693 | } | 1692 | } |
| 1693 | add_wait_queue(sk_sleep(sk), &wait); | ||
| 1694 | release_sock(sk); | 1694 | release_sock(sk); |
| 1695 | timeo = schedule_timeout(timeo); | 1695 | timeo = wait_woken(&wait, TASK_INTERRUPTIBLE, timeo); |
| 1696 | sched_annotate_sleep(); | ||
| 1696 | lock_sock(sk); | 1697 | lock_sock(sk); |
| 1698 | remove_wait_queue(sk_sleep(sk), &wait); | ||
| 1697 | } | 1699 | } |
| 1698 | err = 0; | 1700 | err = 0; |
| 1699 | if (!skb_queue_empty(&sk->sk_receive_queue)) | 1701 | if (!skb_queue_empty(&sk->sk_receive_queue)) |
| @@ -1709,7 +1711,6 @@ static int tipc_wait_for_rcvmsg(struct socket *sock, long *timeop) | |||
| 1709 | if (err) | 1711 | if (err) |
| 1710 | break; | 1712 | break; |
| 1711 | } | 1713 | } |
| 1712 | finish_wait(sk_sleep(sk), &wait); | ||
| 1713 | *timeop = timeo; | 1714 | *timeop = timeo; |
| 1714 | return err; | 1715 | return err; |
| 1715 | } | 1716 | } |
diff --git a/net/tipc/topsrv.c b/net/tipc/topsrv.c index efb16f69bd2c..a457c0fbbef1 100644 --- a/net/tipc/topsrv.c +++ b/net/tipc/topsrv.c | |||
| @@ -398,7 +398,7 @@ static int tipc_conn_rcv_from_sock(struct tipc_conn *con) | |||
| 398 | ret = sock_recvmsg(con->sock, &msg, MSG_DONTWAIT); | 398 | ret = sock_recvmsg(con->sock, &msg, MSG_DONTWAIT); |
| 399 | if (ret == -EWOULDBLOCK) | 399 | if (ret == -EWOULDBLOCK) |
| 400 | return -EWOULDBLOCK; | 400 | return -EWOULDBLOCK; |
| 401 | if (ret > 0) { | 401 | if (ret == sizeof(s)) { |
| 402 | read_lock_bh(&sk->sk_callback_lock); | 402 | read_lock_bh(&sk->sk_callback_lock); |
| 403 | ret = tipc_conn_rcv_sub(srv, con, &s); | 403 | ret = tipc_conn_rcv_sub(srv, con, &s); |
| 404 | read_unlock_bh(&sk->sk_callback_lock); | 404 | read_unlock_bh(&sk->sk_callback_lock); |
diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index 11cdc8f7db63..bf5b54b513bc 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c | |||
| @@ -439,6 +439,8 @@ static int tls_do_encryption(struct sock *sk, | |||
| 439 | struct scatterlist *sge = sk_msg_elem(msg_en, start); | 439 | struct scatterlist *sge = sk_msg_elem(msg_en, start); |
| 440 | int rc; | 440 | int rc; |
| 441 | 441 | ||
| 442 | memcpy(rec->iv_data, tls_ctx->tx.iv, sizeof(rec->iv_data)); | ||
| 443 | |||
| 442 | sge->offset += tls_ctx->tx.prepend_size; | 444 | sge->offset += tls_ctx->tx.prepend_size; |
| 443 | sge->length -= tls_ctx->tx.prepend_size; | 445 | sge->length -= tls_ctx->tx.prepend_size; |
| 444 | 446 | ||
| @@ -448,7 +450,7 @@ static int tls_do_encryption(struct sock *sk, | |||
| 448 | aead_request_set_ad(aead_req, TLS_AAD_SPACE_SIZE); | 450 | aead_request_set_ad(aead_req, TLS_AAD_SPACE_SIZE); |
| 449 | aead_request_set_crypt(aead_req, rec->sg_aead_in, | 451 | aead_request_set_crypt(aead_req, rec->sg_aead_in, |
| 450 | rec->sg_aead_out, | 452 | rec->sg_aead_out, |
| 451 | data_len, tls_ctx->tx.iv); | 453 | data_len, rec->iv_data); |
| 452 | 454 | ||
| 453 | aead_request_set_callback(aead_req, CRYPTO_TFM_REQ_MAY_BACKLOG, | 455 | aead_request_set_callback(aead_req, CRYPTO_TFM_REQ_MAY_BACKLOG, |
| 454 | tls_encrypt_done, sk); | 456 | tls_encrypt_done, sk); |
| @@ -1792,7 +1794,9 @@ void tls_sw_free_resources_tx(struct sock *sk) | |||
| 1792 | if (atomic_read(&ctx->encrypt_pending)) | 1794 | if (atomic_read(&ctx->encrypt_pending)) |
| 1793 | crypto_wait_req(-EINPROGRESS, &ctx->async_wait); | 1795 | crypto_wait_req(-EINPROGRESS, &ctx->async_wait); |
| 1794 | 1796 | ||
| 1797 | release_sock(sk); | ||
| 1795 | cancel_delayed_work_sync(&ctx->tx_work.work); | 1798 | cancel_delayed_work_sync(&ctx->tx_work.work); |
| 1799 | lock_sock(sk); | ||
| 1796 | 1800 | ||
| 1797 | /* Tx whatever records we can transmit and abandon the rest */ | 1801 | /* Tx whatever records we can transmit and abandon the rest */ |
| 1798 | tls_tx_records(sk, -1); | 1802 | tls_tx_records(sk, -1); |
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 74d1eed7cbd4..a95d479caeea 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c | |||
| @@ -890,7 +890,7 @@ retry: | |||
| 890 | addr->hash ^= sk->sk_type; | 890 | addr->hash ^= sk->sk_type; |
| 891 | 891 | ||
| 892 | __unix_remove_socket(sk); | 892 | __unix_remove_socket(sk); |
| 893 | u->addr = addr; | 893 | smp_store_release(&u->addr, addr); |
| 894 | __unix_insert_socket(&unix_socket_table[addr->hash], sk); | 894 | __unix_insert_socket(&unix_socket_table[addr->hash], sk); |
| 895 | spin_unlock(&unix_table_lock); | 895 | spin_unlock(&unix_table_lock); |
| 896 | err = 0; | 896 | err = 0; |
| @@ -1060,7 +1060,7 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
| 1060 | 1060 | ||
| 1061 | err = 0; | 1061 | err = 0; |
| 1062 | __unix_remove_socket(sk); | 1062 | __unix_remove_socket(sk); |
| 1063 | u->addr = addr; | 1063 | smp_store_release(&u->addr, addr); |
| 1064 | __unix_insert_socket(list, sk); | 1064 | __unix_insert_socket(list, sk); |
| 1065 | 1065 | ||
| 1066 | out_unlock: | 1066 | out_unlock: |
| @@ -1331,15 +1331,29 @@ restart: | |||
| 1331 | RCU_INIT_POINTER(newsk->sk_wq, &newu->peer_wq); | 1331 | RCU_INIT_POINTER(newsk->sk_wq, &newu->peer_wq); |
| 1332 | otheru = unix_sk(other); | 1332 | otheru = unix_sk(other); |
| 1333 | 1333 | ||
| 1334 | /* copy address information from listening to new sock*/ | 1334 | /* copy address information from listening to new sock |
| 1335 | if (otheru->addr) { | 1335 | * |
| 1336 | refcount_inc(&otheru->addr->refcnt); | 1336 | * The contents of *(otheru->addr) and otheru->path |
| 1337 | newu->addr = otheru->addr; | 1337 | * are seen fully set up here, since we have found |
| 1338 | } | 1338 | * otheru in hash under unix_table_lock. Insertion |
| 1339 | * into the hash chain we'd found it in had been done | ||
| 1340 | * in an earlier critical area protected by unix_table_lock, | ||
| 1341 | * the same one where we'd set *(otheru->addr) contents, | ||
| 1342 | * as well as otheru->path and otheru->addr itself. | ||
| 1343 | * | ||
| 1344 | * Using smp_store_release() here to set newu->addr | ||
| 1345 | * is enough to make those stores, as well as stores | ||
| 1346 | * to newu->path visible to anyone who gets newu->addr | ||
| 1347 | * by smp_load_acquire(). IOW, the same warranties | ||
| 1348 | * as for unix_sock instances bound in unix_bind() or | ||
| 1349 | * in unix_autobind(). | ||
| 1350 | */ | ||
| 1339 | if (otheru->path.dentry) { | 1351 | if (otheru->path.dentry) { |
| 1340 | path_get(&otheru->path); | 1352 | path_get(&otheru->path); |
| 1341 | newu->path = otheru->path; | 1353 | newu->path = otheru->path; |
| 1342 | } | 1354 | } |
| 1355 | refcount_inc(&otheru->addr->refcnt); | ||
| 1356 | smp_store_release(&newu->addr, otheru->addr); | ||
| 1343 | 1357 | ||
| 1344 | /* Set credentials */ | 1358 | /* Set credentials */ |
| 1345 | copy_peercred(sk, other); | 1359 | copy_peercred(sk, other); |
| @@ -1453,7 +1467,7 @@ out: | |||
| 1453 | static int unix_getname(struct socket *sock, struct sockaddr *uaddr, int peer) | 1467 | static int unix_getname(struct socket *sock, struct sockaddr *uaddr, int peer) |
| 1454 | { | 1468 | { |
| 1455 | struct sock *sk = sock->sk; | 1469 | struct sock *sk = sock->sk; |
| 1456 | struct unix_sock *u; | 1470 | struct unix_address *addr; |
| 1457 | DECLARE_SOCKADDR(struct sockaddr_un *, sunaddr, uaddr); | 1471 | DECLARE_SOCKADDR(struct sockaddr_un *, sunaddr, uaddr); |
| 1458 | int err = 0; | 1472 | int err = 0; |
| 1459 | 1473 | ||
| @@ -1468,19 +1482,15 @@ static int unix_getname(struct socket *sock, struct sockaddr *uaddr, int peer) | |||
| 1468 | sock_hold(sk); | 1482 | sock_hold(sk); |
| 1469 | } | 1483 | } |
| 1470 | 1484 | ||
| 1471 | u = unix_sk(sk); | 1485 | addr = smp_load_acquire(&unix_sk(sk)->addr); |
| 1472 | unix_state_lock(sk); | 1486 | if (!addr) { |
| 1473 | if (!u->addr) { | ||
| 1474 | sunaddr->sun_family = AF_UNIX; | 1487 | sunaddr->sun_family = AF_UNIX; |
| 1475 | sunaddr->sun_path[0] = 0; | 1488 | sunaddr->sun_path[0] = 0; |
| 1476 | err = sizeof(short); | 1489 | err = sizeof(short); |
| 1477 | } else { | 1490 | } else { |
| 1478 | struct unix_address *addr = u->addr; | ||
| 1479 | |||
| 1480 | err = addr->len; | 1491 | err = addr->len; |
| 1481 | memcpy(sunaddr, addr->name, addr->len); | 1492 | memcpy(sunaddr, addr->name, addr->len); |
| 1482 | } | 1493 | } |
| 1483 | unix_state_unlock(sk); | ||
| 1484 | sock_put(sk); | 1494 | sock_put(sk); |
| 1485 | out: | 1495 | out: |
| 1486 | return err; | 1496 | return err; |
| @@ -2073,11 +2083,11 @@ static int unix_seqpacket_recvmsg(struct socket *sock, struct msghdr *msg, | |||
| 2073 | 2083 | ||
| 2074 | static void unix_copy_addr(struct msghdr *msg, struct sock *sk) | 2084 | static void unix_copy_addr(struct msghdr *msg, struct sock *sk) |
| 2075 | { | 2085 | { |
| 2076 | struct unix_sock *u = unix_sk(sk); | 2086 | struct unix_address *addr = smp_load_acquire(&unix_sk(sk)->addr); |
| 2077 | 2087 | ||
| 2078 | if (u->addr) { | 2088 | if (addr) { |
| 2079 | msg->msg_namelen = u->addr->len; | 2089 | msg->msg_namelen = addr->len; |
| 2080 | memcpy(msg->msg_name, u->addr->name, u->addr->len); | 2090 | memcpy(msg->msg_name, addr->name, addr->len); |
| 2081 | } | 2091 | } |
| 2082 | } | 2092 | } |
| 2083 | 2093 | ||
| @@ -2581,15 +2591,14 @@ static int unix_open_file(struct sock *sk) | |||
| 2581 | if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) | 2591 | if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) |
| 2582 | return -EPERM; | 2592 | return -EPERM; |
| 2583 | 2593 | ||
| 2584 | unix_state_lock(sk); | 2594 | if (!smp_load_acquire(&unix_sk(sk)->addr)) |
| 2595 | return -ENOENT; | ||
| 2596 | |||
| 2585 | path = unix_sk(sk)->path; | 2597 | path = unix_sk(sk)->path; |
| 2586 | if (!path.dentry) { | 2598 | if (!path.dentry) |
| 2587 | unix_state_unlock(sk); | ||
| 2588 | return -ENOENT; | 2599 | return -ENOENT; |
| 2589 | } | ||
| 2590 | 2600 | ||
| 2591 | path_get(&path); | 2601 | path_get(&path); |
| 2592 | unix_state_unlock(sk); | ||
| 2593 | 2602 | ||
| 2594 | fd = get_unused_fd_flags(O_CLOEXEC); | 2603 | fd = get_unused_fd_flags(O_CLOEXEC); |
| 2595 | if (fd < 0) | 2604 | if (fd < 0) |
| @@ -2830,7 +2839,7 @@ static int unix_seq_show(struct seq_file *seq, void *v) | |||
| 2830 | (s->sk_state == TCP_ESTABLISHED ? SS_CONNECTING : SS_DISCONNECTING), | 2839 | (s->sk_state == TCP_ESTABLISHED ? SS_CONNECTING : SS_DISCONNECTING), |
| 2831 | sock_i_ino(s)); | 2840 | sock_i_ino(s)); |
| 2832 | 2841 | ||
| 2833 | if (u->addr) { | 2842 | if (u->addr) { // under unix_table_lock here |
| 2834 | int i, len; | 2843 | int i, len; |
| 2835 | seq_putc(seq, ' '); | 2844 | seq_putc(seq, ' '); |
| 2836 | 2845 | ||
diff --git a/net/unix/diag.c b/net/unix/diag.c index 384c84e83462..3183d9b8ab33 100644 --- a/net/unix/diag.c +++ b/net/unix/diag.c | |||
| @@ -10,7 +10,8 @@ | |||
| 10 | 10 | ||
| 11 | static int sk_diag_dump_name(struct sock *sk, struct sk_buff *nlskb) | 11 | static int sk_diag_dump_name(struct sock *sk, struct sk_buff *nlskb) |
| 12 | { | 12 | { |
| 13 | struct unix_address *addr = unix_sk(sk)->addr; | 13 | /* might or might not have unix_table_lock */ |
| 14 | struct unix_address *addr = smp_load_acquire(&unix_sk(sk)->addr); | ||
| 14 | 15 | ||
| 15 | if (!addr) | 16 | if (!addr) |
| 16 | return 0; | 17 | return 0; |
diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c index 5d3cce9e8744..15eb5d3d4750 100644 --- a/net/vmw_vsock/virtio_transport.c +++ b/net/vmw_vsock/virtio_transport.c | |||
| @@ -75,6 +75,9 @@ static u32 virtio_transport_get_local_cid(void) | |||
| 75 | { | 75 | { |
| 76 | struct virtio_vsock *vsock = virtio_vsock_get(); | 76 | struct virtio_vsock *vsock = virtio_vsock_get(); |
| 77 | 77 | ||
| 78 | if (!vsock) | ||
| 79 | return VMADDR_CID_ANY; | ||
| 80 | |||
| 78 | return vsock->guest_cid; | 81 | return vsock->guest_cid; |
| 79 | } | 82 | } |
| 80 | 83 | ||
| @@ -584,10 +587,6 @@ static int virtio_vsock_probe(struct virtio_device *vdev) | |||
| 584 | 587 | ||
| 585 | virtio_vsock_update_guest_cid(vsock); | 588 | virtio_vsock_update_guest_cid(vsock); |
| 586 | 589 | ||
| 587 | ret = vsock_core_init(&virtio_transport.transport); | ||
| 588 | if (ret < 0) | ||
| 589 | goto out_vqs; | ||
| 590 | |||
| 591 | vsock->rx_buf_nr = 0; | 590 | vsock->rx_buf_nr = 0; |
| 592 | vsock->rx_buf_max_nr = 0; | 591 | vsock->rx_buf_max_nr = 0; |
| 593 | atomic_set(&vsock->queued_replies, 0); | 592 | atomic_set(&vsock->queued_replies, 0); |
| @@ -618,8 +617,6 @@ static int virtio_vsock_probe(struct virtio_device *vdev) | |||
| 618 | mutex_unlock(&the_virtio_vsock_mutex); | 617 | mutex_unlock(&the_virtio_vsock_mutex); |
| 619 | return 0; | 618 | return 0; |
| 620 | 619 | ||
| 621 | out_vqs: | ||
| 622 | vsock->vdev->config->del_vqs(vsock->vdev); | ||
| 623 | out: | 620 | out: |
| 624 | kfree(vsock); | 621 | kfree(vsock); |
| 625 | mutex_unlock(&the_virtio_vsock_mutex); | 622 | mutex_unlock(&the_virtio_vsock_mutex); |
| @@ -637,6 +634,9 @@ static void virtio_vsock_remove(struct virtio_device *vdev) | |||
| 637 | flush_work(&vsock->event_work); | 634 | flush_work(&vsock->event_work); |
| 638 | flush_work(&vsock->send_pkt_work); | 635 | flush_work(&vsock->send_pkt_work); |
| 639 | 636 | ||
| 637 | /* Reset all connected sockets when the device disappear */ | ||
| 638 | vsock_for_each_connected_socket(virtio_vsock_reset_sock); | ||
| 639 | |||
| 640 | vdev->config->reset(vdev); | 640 | vdev->config->reset(vdev); |
| 641 | 641 | ||
| 642 | mutex_lock(&vsock->rx_lock); | 642 | mutex_lock(&vsock->rx_lock); |
| @@ -669,7 +669,6 @@ static void virtio_vsock_remove(struct virtio_device *vdev) | |||
| 669 | 669 | ||
| 670 | mutex_lock(&the_virtio_vsock_mutex); | 670 | mutex_lock(&the_virtio_vsock_mutex); |
| 671 | the_virtio_vsock = NULL; | 671 | the_virtio_vsock = NULL; |
| 672 | vsock_core_exit(); | ||
| 673 | mutex_unlock(&the_virtio_vsock_mutex); | 672 | mutex_unlock(&the_virtio_vsock_mutex); |
| 674 | 673 | ||
| 675 | vdev->config->del_vqs(vdev); | 674 | vdev->config->del_vqs(vdev); |
| @@ -702,14 +701,28 @@ static int __init virtio_vsock_init(void) | |||
| 702 | virtio_vsock_workqueue = alloc_workqueue("virtio_vsock", 0, 0); | 701 | virtio_vsock_workqueue = alloc_workqueue("virtio_vsock", 0, 0); |
| 703 | if (!virtio_vsock_workqueue) | 702 | if (!virtio_vsock_workqueue) |
| 704 | return -ENOMEM; | 703 | return -ENOMEM; |
| 704 | |||
| 705 | ret = register_virtio_driver(&virtio_vsock_driver); | 705 | ret = register_virtio_driver(&virtio_vsock_driver); |
| 706 | if (ret) | 706 | if (ret) |
| 707 | destroy_workqueue(virtio_vsock_workqueue); | 707 | goto out_wq; |
| 708 | |||
| 709 | ret = vsock_core_init(&virtio_transport.transport); | ||
| 710 | if (ret) | ||
| 711 | goto out_vdr; | ||
| 712 | |||
| 713 | return 0; | ||
| 714 | |||
| 715 | out_vdr: | ||
| 716 | unregister_virtio_driver(&virtio_vsock_driver); | ||
| 717 | out_wq: | ||
| 718 | destroy_workqueue(virtio_vsock_workqueue); | ||
| 708 | return ret; | 719 | return ret; |
| 720 | |||
| 709 | } | 721 | } |
| 710 | 722 | ||
| 711 | static void __exit virtio_vsock_exit(void) | 723 | static void __exit virtio_vsock_exit(void) |
| 712 | { | 724 | { |
| 725 | vsock_core_exit(); | ||
| 713 | unregister_virtio_driver(&virtio_vsock_driver); | 726 | unregister_virtio_driver(&virtio_vsock_driver); |
| 714 | destroy_workqueue(virtio_vsock_workqueue); | 727 | destroy_workqueue(virtio_vsock_workqueue); |
| 715 | } | 728 | } |
diff --git a/net/vmw_vsock/vmci_transport.c b/net/vmw_vsock/vmci_transport.c index c361ce782412..c3d5ab01fba7 100644 --- a/net/vmw_vsock/vmci_transport.c +++ b/net/vmw_vsock/vmci_transport.c | |||
| @@ -1651,6 +1651,10 @@ static void vmci_transport_cleanup(struct work_struct *work) | |||
| 1651 | 1651 | ||
| 1652 | static void vmci_transport_destruct(struct vsock_sock *vsk) | 1652 | static void vmci_transport_destruct(struct vsock_sock *vsk) |
| 1653 | { | 1653 | { |
| 1654 | /* transport can be NULL if we hit a failure at init() time */ | ||
| 1655 | if (!vmci_trans(vsk)) | ||
| 1656 | return; | ||
| 1657 | |||
| 1654 | /* Ensure that the detach callback doesn't use the sk/vsk | 1658 | /* Ensure that the detach callback doesn't use the sk/vsk |
| 1655 | * we are about to destruct. | 1659 | * we are about to destruct. |
| 1656 | */ | 1660 | */ |
diff --git a/net/wireless/ap.c b/net/wireless/ap.c index 882d97bdc6bf..550ac9d827fe 100644 --- a/net/wireless/ap.c +++ b/net/wireless/ap.c | |||
| @@ -41,6 +41,8 @@ int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, | |||
| 41 | cfg80211_sched_dfs_chan_update(rdev); | 41 | cfg80211_sched_dfs_chan_update(rdev); |
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | schedule_work(&cfg80211_disconnect_work); | ||
| 45 | |||
| 44 | return err; | 46 | return err; |
| 45 | } | 47 | } |
| 46 | 48 | ||
diff --git a/net/wireless/core.c b/net/wireless/core.c index 623dfe5e211c..b36ad8efb5e5 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
| @@ -1068,6 +1068,8 @@ static void __cfg80211_unregister_wdev(struct wireless_dev *wdev, bool sync) | |||
| 1068 | 1068 | ||
| 1069 | ASSERT_RTNL(); | 1069 | ASSERT_RTNL(); |
| 1070 | 1070 | ||
| 1071 | flush_work(&wdev->pmsr_free_wk); | ||
| 1072 | |||
| 1071 | nl80211_notify_iface(rdev, wdev, NL80211_CMD_DEL_INTERFACE); | 1073 | nl80211_notify_iface(rdev, wdev, NL80211_CMD_DEL_INTERFACE); |
| 1072 | 1074 | ||
| 1073 | list_del_rcu(&wdev->list); | 1075 | list_del_rcu(&wdev->list); |
diff --git a/net/wireless/core.h b/net/wireless/core.h index c5d6f3418601..f6b40563dc63 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
| @@ -445,6 +445,8 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev); | |||
| 445 | bool cfg80211_does_bw_fit_range(const struct ieee80211_freq_range *freq_range, | 445 | bool cfg80211_does_bw_fit_range(const struct ieee80211_freq_range *freq_range, |
| 446 | u32 center_freq_khz, u32 bw_khz); | 446 | u32 center_freq_khz, u32 bw_khz); |
| 447 | 447 | ||
| 448 | extern struct work_struct cfg80211_disconnect_work; | ||
| 449 | |||
| 448 | /** | 450 | /** |
| 449 | * cfg80211_chandef_dfs_usable - checks if chandef is DFS usable | 451 | * cfg80211_chandef_dfs_usable - checks if chandef is DFS usable |
| 450 | * @wiphy: the wiphy to validate against | 452 | * @wiphy: the wiphy to validate against |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 5e49492d5911..d91a408db113 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
| @@ -250,7 +250,7 @@ nl80211_pmsr_ftm_req_attr_policy[NL80211_PMSR_FTM_REQ_ATTR_MAX + 1] = { | |||
| 250 | [NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION] = | 250 | [NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION] = |
| 251 | NLA_POLICY_MAX(NLA_U8, 15), | 251 | NLA_POLICY_MAX(NLA_U8, 15), |
| 252 | [NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST] = | 252 | [NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST] = |
| 253 | NLA_POLICY_MAX(NLA_U8, 15), | 253 | NLA_POLICY_MAX(NLA_U8, 31), |
| 254 | [NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES] = { .type = NLA_U8 }, | 254 | [NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES] = { .type = NLA_U8 }, |
| 255 | [NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI] = { .type = NLA_FLAG }, | 255 | [NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI] = { .type = NLA_FLAG }, |
| 256 | [NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC] = { .type = NLA_FLAG }, | 256 | [NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC] = { .type = NLA_FLAG }, |
| @@ -555,7 +555,7 @@ const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { | |||
| 555 | }, | 555 | }, |
| 556 | [NL80211_ATTR_TIMEOUT] = NLA_POLICY_MIN(NLA_U32, 1), | 556 | [NL80211_ATTR_TIMEOUT] = NLA_POLICY_MIN(NLA_U32, 1), |
| 557 | [NL80211_ATTR_PEER_MEASUREMENTS] = | 557 | [NL80211_ATTR_PEER_MEASUREMENTS] = |
| 558 | NLA_POLICY_NESTED(NL80211_PMSR_FTM_REQ_ATTR_MAX, | 558 | NLA_POLICY_NESTED(NL80211_PMSR_ATTR_MAX, |
| 559 | nl80211_pmsr_attr_policy), | 559 | nl80211_pmsr_attr_policy), |
| 560 | }; | 560 | }; |
| 561 | 561 | ||
diff --git a/net/wireless/pmsr.c b/net/wireless/pmsr.c index de9286703280..0216ab555249 100644 --- a/net/wireless/pmsr.c +++ b/net/wireless/pmsr.c | |||
| @@ -256,8 +256,7 @@ int nl80211_pmsr_start(struct sk_buff *skb, struct genl_info *info) | |||
| 256 | if (err) | 256 | if (err) |
| 257 | goto out_err; | 257 | goto out_err; |
| 258 | } else { | 258 | } else { |
| 259 | memcpy(req->mac_addr, nla_data(info->attrs[NL80211_ATTR_MAC]), | 259 | memcpy(req->mac_addr, wdev_address(wdev), ETH_ALEN); |
| 260 | ETH_ALEN); | ||
| 261 | memset(req->mac_addr_mask, 0xff, ETH_ALEN); | 260 | memset(req->mac_addr_mask, 0xff, ETH_ALEN); |
| 262 | } | 261 | } |
| 263 | 262 | ||
| @@ -272,6 +271,7 @@ int nl80211_pmsr_start(struct sk_buff *skb, struct genl_info *info) | |||
| 272 | 271 | ||
| 273 | req->n_peers = count; | 272 | req->n_peers = count; |
| 274 | req->cookie = cfg80211_assign_cookie(rdev); | 273 | req->cookie = cfg80211_assign_cookie(rdev); |
| 274 | req->nl_portid = info->snd_portid; | ||
| 275 | 275 | ||
| 276 | err = rdev_start_pmsr(rdev, wdev, req); | 276 | err = rdev_start_pmsr(rdev, wdev, req); |
| 277 | if (err) | 277 | if (err) |
| @@ -530,14 +530,14 @@ free: | |||
| 530 | } | 530 | } |
| 531 | EXPORT_SYMBOL_GPL(cfg80211_pmsr_report); | 531 | EXPORT_SYMBOL_GPL(cfg80211_pmsr_report); |
| 532 | 532 | ||
| 533 | void cfg80211_pmsr_free_wk(struct work_struct *work) | 533 | static void cfg80211_pmsr_process_abort(struct wireless_dev *wdev) |
| 534 | { | 534 | { |
| 535 | struct wireless_dev *wdev = container_of(work, struct wireless_dev, | ||
| 536 | pmsr_free_wk); | ||
| 537 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); | 535 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); |
| 538 | struct cfg80211_pmsr_request *req, *tmp; | 536 | struct cfg80211_pmsr_request *req, *tmp; |
| 539 | LIST_HEAD(free_list); | 537 | LIST_HEAD(free_list); |
| 540 | 538 | ||
| 539 | lockdep_assert_held(&wdev->mtx); | ||
| 540 | |||
| 541 | spin_lock_bh(&wdev->pmsr_lock); | 541 | spin_lock_bh(&wdev->pmsr_lock); |
| 542 | list_for_each_entry_safe(req, tmp, &wdev->pmsr_list, list) { | 542 | list_for_each_entry_safe(req, tmp, &wdev->pmsr_list, list) { |
| 543 | if (req->nl_portid) | 543 | if (req->nl_portid) |
| @@ -547,14 +547,22 @@ void cfg80211_pmsr_free_wk(struct work_struct *work) | |||
| 547 | spin_unlock_bh(&wdev->pmsr_lock); | 547 | spin_unlock_bh(&wdev->pmsr_lock); |
| 548 | 548 | ||
| 549 | list_for_each_entry_safe(req, tmp, &free_list, list) { | 549 | list_for_each_entry_safe(req, tmp, &free_list, list) { |
| 550 | wdev_lock(wdev); | ||
| 551 | rdev_abort_pmsr(rdev, wdev, req); | 550 | rdev_abort_pmsr(rdev, wdev, req); |
| 552 | wdev_unlock(wdev); | ||
| 553 | 551 | ||
| 554 | kfree(req); | 552 | kfree(req); |
| 555 | } | 553 | } |
| 556 | } | 554 | } |
| 557 | 555 | ||
| 556 | void cfg80211_pmsr_free_wk(struct work_struct *work) | ||
| 557 | { | ||
| 558 | struct wireless_dev *wdev = container_of(work, struct wireless_dev, | ||
| 559 | pmsr_free_wk); | ||
| 560 | |||
| 561 | wdev_lock(wdev); | ||
| 562 | cfg80211_pmsr_process_abort(wdev); | ||
| 563 | wdev_unlock(wdev); | ||
| 564 | } | ||
| 565 | |||
| 558 | void cfg80211_pmsr_wdev_down(struct wireless_dev *wdev) | 566 | void cfg80211_pmsr_wdev_down(struct wireless_dev *wdev) |
| 559 | { | 567 | { |
| 560 | struct cfg80211_pmsr_request *req; | 568 | struct cfg80211_pmsr_request *req; |
| @@ -568,8 +576,8 @@ void cfg80211_pmsr_wdev_down(struct wireless_dev *wdev) | |||
| 568 | spin_unlock_bh(&wdev->pmsr_lock); | 576 | spin_unlock_bh(&wdev->pmsr_lock); |
| 569 | 577 | ||
| 570 | if (found) | 578 | if (found) |
| 571 | schedule_work(&wdev->pmsr_free_wk); | 579 | cfg80211_pmsr_process_abort(wdev); |
| 572 | flush_work(&wdev->pmsr_free_wk); | 580 | |
| 573 | WARN_ON(!list_empty(&wdev->pmsr_list)); | 581 | WARN_ON(!list_empty(&wdev->pmsr_list)); |
| 574 | } | 582 | } |
| 575 | 583 | ||
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index ecfb1a06dbb2..dd58b9909ac9 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
| @@ -1024,8 +1024,13 @@ static void regdb_fw_cb(const struct firmware *fw, void *context) | |||
| 1024 | } | 1024 | } |
| 1025 | 1025 | ||
| 1026 | rtnl_lock(); | 1026 | rtnl_lock(); |
| 1027 | if (WARN_ON(regdb && !IS_ERR(regdb))) { | 1027 | if (regdb && !IS_ERR(regdb)) { |
| 1028 | /* just restore and free new db */ | 1028 | /* negative case - a bug |
| 1029 | * positive case - can happen due to race in case of multiple cb's in | ||
| 1030 | * queue, due to usage of asynchronous callback | ||
| 1031 | * | ||
| 1032 | * Either case, just restore and free new db. | ||
| 1033 | */ | ||
| 1029 | } else if (set_error) { | 1034 | } else if (set_error) { |
| 1030 | regdb = ERR_PTR(set_error); | 1035 | regdb = ERR_PTR(set_error); |
| 1031 | } else if (fw) { | 1036 | } else if (fw) { |
| @@ -1255,7 +1260,7 @@ static bool is_valid_rd(const struct ieee80211_regdomain *rd) | |||
| 1255 | * definitions (the "2.4 GHz band", the "5 GHz band" and the "60GHz band"), | 1260 | * definitions (the "2.4 GHz band", the "5 GHz band" and the "60GHz band"), |
| 1256 | * however it is safe for now to assume that a frequency rule should not be | 1261 | * however it is safe for now to assume that a frequency rule should not be |
| 1257 | * part of a frequency's band if the start freq or end freq are off by more | 1262 | * part of a frequency's band if the start freq or end freq are off by more |
| 1258 | * than 2 GHz for the 2.4 and 5 GHz bands, and by more than 10 GHz for the | 1263 | * than 2 GHz for the 2.4 and 5 GHz bands, and by more than 20 GHz for the |
| 1259 | * 60 GHz band. | 1264 | * 60 GHz band. |
| 1260 | * This resolution can be lowered and should be considered as we add | 1265 | * This resolution can be lowered and should be considered as we add |
| 1261 | * regulatory rule support for other "bands". | 1266 | * regulatory rule support for other "bands". |
| @@ -1270,7 +1275,7 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range, | |||
| 1270 | * with the Channel starting frequency above 45 GHz. | 1275 | * with the Channel starting frequency above 45 GHz. |
| 1271 | */ | 1276 | */ |
| 1272 | u32 limit = freq_khz > 45 * ONE_GHZ_IN_KHZ ? | 1277 | u32 limit = freq_khz > 45 * ONE_GHZ_IN_KHZ ? |
| 1273 | 10 * ONE_GHZ_IN_KHZ : 2 * ONE_GHZ_IN_KHZ; | 1278 | 20 * ONE_GHZ_IN_KHZ : 2 * ONE_GHZ_IN_KHZ; |
| 1274 | if (abs(freq_khz - freq_range->start_freq_khz) <= limit) | 1279 | if (abs(freq_khz - freq_range->start_freq_khz) <= limit) |
| 1275 | return true; | 1280 | return true; |
| 1276 | if (abs(freq_khz - freq_range->end_freq_khz) <= limit) | 1281 | if (abs(freq_khz - freq_range->end_freq_khz) <= limit) |
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index f741d8376a46..7d34cb884840 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
| @@ -667,7 +667,7 @@ static void disconnect_work(struct work_struct *work) | |||
| 667 | rtnl_unlock(); | 667 | rtnl_unlock(); |
| 668 | } | 668 | } |
| 669 | 669 | ||
| 670 | static DECLARE_WORK(cfg80211_disconnect_work, disconnect_work); | 670 | DECLARE_WORK(cfg80211_disconnect_work, disconnect_work); |
| 671 | 671 | ||
| 672 | 672 | ||
| 673 | /* | 673 | /* |
diff --git a/net/wireless/util.c b/net/wireless/util.c index cd48cdd582c0..ec30e3732c7b 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
| @@ -5,7 +5,7 @@ | |||
| 5 | * Copyright 2007-2009 Johannes Berg <johannes@sipsolutions.net> | 5 | * Copyright 2007-2009 Johannes Berg <johannes@sipsolutions.net> |
| 6 | * Copyright 2013-2014 Intel Mobile Communications GmbH | 6 | * Copyright 2013-2014 Intel Mobile Communications GmbH |
| 7 | * Copyright 2017 Intel Deutschland GmbH | 7 | * Copyright 2017 Intel Deutschland GmbH |
| 8 | * Copyright (C) 2018 Intel Corporation | 8 | * Copyright (C) 2018-2019 Intel Corporation |
| 9 | */ | 9 | */ |
| 10 | #include <linux/export.h> | 10 | #include <linux/export.h> |
| 11 | #include <linux/bitops.h> | 11 | #include <linux/bitops.h> |
| @@ -19,6 +19,7 @@ | |||
| 19 | #include <linux/mpls.h> | 19 | #include <linux/mpls.h> |
| 20 | #include <linux/gcd.h> | 20 | #include <linux/gcd.h> |
| 21 | #include <linux/bitfield.h> | 21 | #include <linux/bitfield.h> |
| 22 | #include <linux/nospec.h> | ||
| 22 | #include "core.h" | 23 | #include "core.h" |
| 23 | #include "rdev-ops.h" | 24 | #include "rdev-ops.h" |
| 24 | 25 | ||
| @@ -715,20 +716,25 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb, | |||
| 715 | { | 716 | { |
| 716 | unsigned int dscp; | 717 | unsigned int dscp; |
| 717 | unsigned char vlan_priority; | 718 | unsigned char vlan_priority; |
| 719 | unsigned int ret; | ||
| 718 | 720 | ||
| 719 | /* skb->priority values from 256->263 are magic values to | 721 | /* skb->priority values from 256->263 are magic values to |
| 720 | * directly indicate a specific 802.1d priority. This is used | 722 | * directly indicate a specific 802.1d priority. This is used |
| 721 | * to allow 802.1d priority to be passed directly in from VLAN | 723 | * to allow 802.1d priority to be passed directly in from VLAN |
| 722 | * tags, etc. | 724 | * tags, etc. |
| 723 | */ | 725 | */ |
| 724 | if (skb->priority >= 256 && skb->priority <= 263) | 726 | if (skb->priority >= 256 && skb->priority <= 263) { |
| 725 | return skb->priority - 256; | 727 | ret = skb->priority - 256; |
| 728 | goto out; | ||
| 729 | } | ||
| 726 | 730 | ||
| 727 | if (skb_vlan_tag_present(skb)) { | 731 | if (skb_vlan_tag_present(skb)) { |
| 728 | vlan_priority = (skb_vlan_tag_get(skb) & VLAN_PRIO_MASK) | 732 | vlan_priority = (skb_vlan_tag_get(skb) & VLAN_PRIO_MASK) |
| 729 | >> VLAN_PRIO_SHIFT; | 733 | >> VLAN_PRIO_SHIFT; |
| 730 | if (vlan_priority > 0) | 734 | if (vlan_priority > 0) { |
| 731 | return vlan_priority; | 735 | ret = vlan_priority; |
| 736 | goto out; | ||
| 737 | } | ||
| 732 | } | 738 | } |
| 733 | 739 | ||
| 734 | switch (skb->protocol) { | 740 | switch (skb->protocol) { |
| @@ -747,8 +753,9 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb, | |||
| 747 | if (!mpls) | 753 | if (!mpls) |
| 748 | return 0; | 754 | return 0; |
| 749 | 755 | ||
| 750 | return (ntohl(mpls->entry) & MPLS_LS_TC_MASK) | 756 | ret = (ntohl(mpls->entry) & MPLS_LS_TC_MASK) |
| 751 | >> MPLS_LS_TC_SHIFT; | 757 | >> MPLS_LS_TC_SHIFT; |
| 758 | goto out; | ||
| 752 | } | 759 | } |
| 753 | case htons(ETH_P_80221): | 760 | case htons(ETH_P_80221): |
| 754 | /* 802.21 is always network control traffic */ | 761 | /* 802.21 is always network control traffic */ |
| @@ -761,18 +768,24 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb, | |||
| 761 | unsigned int i, tmp_dscp = dscp >> 2; | 768 | unsigned int i, tmp_dscp = dscp >> 2; |
| 762 | 769 | ||
| 763 | for (i = 0; i < qos_map->num_des; i++) { | 770 | for (i = 0; i < qos_map->num_des; i++) { |
| 764 | if (tmp_dscp == qos_map->dscp_exception[i].dscp) | 771 | if (tmp_dscp == qos_map->dscp_exception[i].dscp) { |
| 765 | return qos_map->dscp_exception[i].up; | 772 | ret = qos_map->dscp_exception[i].up; |
| 773 | goto out; | ||
| 774 | } | ||
| 766 | } | 775 | } |
| 767 | 776 | ||
| 768 | for (i = 0; i < 8; i++) { | 777 | for (i = 0; i < 8; i++) { |
| 769 | if (tmp_dscp >= qos_map->up[i].low && | 778 | if (tmp_dscp >= qos_map->up[i].low && |
| 770 | tmp_dscp <= qos_map->up[i].high) | 779 | tmp_dscp <= qos_map->up[i].high) { |
| 771 | return i; | 780 | ret = i; |
| 781 | goto out; | ||
| 782 | } | ||
| 772 | } | 783 | } |
| 773 | } | 784 | } |
| 774 | 785 | ||
| 775 | return dscp >> 5; | 786 | ret = dscp >> 5; |
| 787 | out: | ||
| 788 | return array_index_nospec(ret, IEEE80211_NUM_TIDS); | ||
| 776 | } | 789 | } |
| 777 | EXPORT_SYMBOL(cfg80211_classify8021d); | 790 | EXPORT_SYMBOL(cfg80211_classify8021d); |
| 778 | 791 | ||
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 5121729b8b63..eff31348e20b 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c | |||
| @@ -352,17 +352,15 @@ static unsigned int x25_new_lci(struct x25_neigh *nb) | |||
| 352 | unsigned int lci = 1; | 352 | unsigned int lci = 1; |
| 353 | struct sock *sk; | 353 | struct sock *sk; |
| 354 | 354 | ||
| 355 | read_lock_bh(&x25_list_lock); | 355 | while ((sk = x25_find_socket(lci, nb)) != NULL) { |
| 356 | |||
| 357 | while ((sk = __x25_find_socket(lci, nb)) != NULL) { | ||
| 358 | sock_put(sk); | 356 | sock_put(sk); |
| 359 | if (++lci == 4096) { | 357 | if (++lci == 4096) { |
| 360 | lci = 0; | 358 | lci = 0; |
| 361 | break; | 359 | break; |
| 362 | } | 360 | } |
| 361 | cond_resched(); | ||
| 363 | } | 362 | } |
| 364 | 363 | ||
| 365 | read_unlock_bh(&x25_list_lock); | ||
| 366 | return lci; | 364 | return lci; |
| 367 | } | 365 | } |
| 368 | 366 | ||
| @@ -681,8 +679,7 @@ static int x25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
| 681 | struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr; | 679 | struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr; |
| 682 | int len, i, rc = 0; | 680 | int len, i, rc = 0; |
| 683 | 681 | ||
| 684 | if (!sock_flag(sk, SOCK_ZAPPED) || | 682 | if (addr_len != sizeof(struct sockaddr_x25) || |
| 685 | addr_len != sizeof(struct sockaddr_x25) || | ||
| 686 | addr->sx25_family != AF_X25) { | 683 | addr->sx25_family != AF_X25) { |
| 687 | rc = -EINVAL; | 684 | rc = -EINVAL; |
| 688 | goto out; | 685 | goto out; |
| @@ -701,9 +698,13 @@ static int x25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
| 701 | } | 698 | } |
| 702 | 699 | ||
| 703 | lock_sock(sk); | 700 | lock_sock(sk); |
| 704 | x25_sk(sk)->source_addr = addr->sx25_addr; | 701 | if (sock_flag(sk, SOCK_ZAPPED)) { |
| 705 | x25_insert_socket(sk); | 702 | x25_sk(sk)->source_addr = addr->sx25_addr; |
| 706 | sock_reset_flag(sk, SOCK_ZAPPED); | 703 | x25_insert_socket(sk); |
| 704 | sock_reset_flag(sk, SOCK_ZAPPED); | ||
| 705 | } else { | ||
| 706 | rc = -EINVAL; | ||
| 707 | } | ||
| 707 | release_sock(sk); | 708 | release_sock(sk); |
| 708 | SOCK_DEBUG(sk, "x25_bind: socket is bound\n"); | 709 | SOCK_DEBUG(sk, "x25_bind: socket is bound\n"); |
| 709 | out: | 710 | out: |
diff --git a/net/xdp/xdp_umem.c b/net/xdp/xdp_umem.c index a264cf2accd0..37e1fe180769 100644 --- a/net/xdp/xdp_umem.c +++ b/net/xdp/xdp_umem.c | |||
| @@ -41,13 +41,20 @@ void xdp_del_sk_umem(struct xdp_umem *umem, struct xdp_sock *xs) | |||
| 41 | * not know if the device has more tx queues than rx, or the opposite. | 41 | * not know if the device has more tx queues than rx, or the opposite. |
| 42 | * This might also change during run time. | 42 | * This might also change during run time. |
| 43 | */ | 43 | */ |
| 44 | static void xdp_reg_umem_at_qid(struct net_device *dev, struct xdp_umem *umem, | 44 | static int xdp_reg_umem_at_qid(struct net_device *dev, struct xdp_umem *umem, |
| 45 | u16 queue_id) | 45 | u16 queue_id) |
| 46 | { | 46 | { |
| 47 | if (queue_id >= max_t(unsigned int, | ||
| 48 | dev->real_num_rx_queues, | ||
| 49 | dev->real_num_tx_queues)) | ||
| 50 | return -EINVAL; | ||
| 51 | |||
| 47 | if (queue_id < dev->real_num_rx_queues) | 52 | if (queue_id < dev->real_num_rx_queues) |
| 48 | dev->_rx[queue_id].umem = umem; | 53 | dev->_rx[queue_id].umem = umem; |
| 49 | if (queue_id < dev->real_num_tx_queues) | 54 | if (queue_id < dev->real_num_tx_queues) |
| 50 | dev->_tx[queue_id].umem = umem; | 55 | dev->_tx[queue_id].umem = umem; |
| 56 | |||
| 57 | return 0; | ||
| 51 | } | 58 | } |
| 52 | 59 | ||
| 53 | struct xdp_umem *xdp_get_umem_from_qid(struct net_device *dev, | 60 | struct xdp_umem *xdp_get_umem_from_qid(struct net_device *dev, |
| @@ -88,7 +95,10 @@ int xdp_umem_assign_dev(struct xdp_umem *umem, struct net_device *dev, | |||
| 88 | goto out_rtnl_unlock; | 95 | goto out_rtnl_unlock; |
| 89 | } | 96 | } |
| 90 | 97 | ||
| 91 | xdp_reg_umem_at_qid(dev, umem, queue_id); | 98 | err = xdp_reg_umem_at_qid(dev, umem, queue_id); |
| 99 | if (err) | ||
| 100 | goto out_rtnl_unlock; | ||
| 101 | |||
| 92 | umem->dev = dev; | 102 | umem->dev = dev; |
| 93 | umem->queue_id = queue_id; | 103 | umem->queue_id = queue_id; |
| 94 | if (force_copy) | 104 | if (force_copy) |
| @@ -115,9 +125,10 @@ int xdp_umem_assign_dev(struct xdp_umem *umem, struct net_device *dev, | |||
| 115 | return 0; | 125 | return 0; |
| 116 | 126 | ||
| 117 | err_unreg_umem: | 127 | err_unreg_umem: |
| 118 | xdp_clear_umem_at_qid(dev, queue_id); | ||
| 119 | if (!force_zc) | 128 | if (!force_zc) |
| 120 | err = 0; /* fallback to copy mode */ | 129 | err = 0; /* fallback to copy mode */ |
| 130 | if (err) | ||
| 131 | xdp_clear_umem_at_qid(dev, queue_id); | ||
| 121 | out_rtnl_unlock: | 132 | out_rtnl_unlock: |
| 122 | rtnl_unlock(); | 133 | rtnl_unlock(); |
| 123 | return err; | 134 | return err; |
| @@ -249,10 +260,10 @@ static int xdp_umem_pin_pages(struct xdp_umem *umem) | |||
| 249 | if (!umem->pgs) | 260 | if (!umem->pgs) |
| 250 | return -ENOMEM; | 261 | return -ENOMEM; |
| 251 | 262 | ||
| 252 | down_write(¤t->mm->mmap_sem); | 263 | down_read(¤t->mm->mmap_sem); |
| 253 | npgs = get_user_pages(umem->address, umem->npgs, | 264 | npgs = get_user_pages_longterm(umem->address, umem->npgs, |
| 254 | gup_flags, &umem->pgs[0], NULL); | 265 | gup_flags, &umem->pgs[0], NULL); |
| 255 | up_write(¤t->mm->mmap_sem); | 266 | up_read(¤t->mm->mmap_sem); |
| 256 | 267 | ||
| 257 | if (npgs != umem->npgs) { | 268 | if (npgs != umem->npgs) { |
| 258 | if (npgs >= 0) { | 269 | if (npgs >= 0) { |
diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c index a03268454a27..85e4fe4f18cc 100644 --- a/net/xdp/xsk.c +++ b/net/xdp/xsk.c | |||
| @@ -366,7 +366,6 @@ static int xsk_release(struct socket *sock) | |||
| 366 | 366 | ||
| 367 | xskq_destroy(xs->rx); | 367 | xskq_destroy(xs->rx); |
| 368 | xskq_destroy(xs->tx); | 368 | xskq_destroy(xs->tx); |
| 369 | xdp_put_umem(xs->umem); | ||
| 370 | 369 | ||
| 371 | sock_orphan(sk); | 370 | sock_orphan(sk); |
| 372 | sock->sk = NULL; | 371 | sock->sk = NULL; |
| @@ -669,6 +668,8 @@ static int xsk_mmap(struct file *file, struct socket *sock, | |||
| 669 | if (!umem) | 668 | if (!umem) |
| 670 | return -EINVAL; | 669 | return -EINVAL; |
| 671 | 670 | ||
| 671 | /* Matches the smp_wmb() in XDP_UMEM_REG */ | ||
| 672 | smp_rmb(); | ||
| 672 | if (offset == XDP_UMEM_PGOFF_FILL_RING) | 673 | if (offset == XDP_UMEM_PGOFF_FILL_RING) |
| 673 | q = READ_ONCE(umem->fq); | 674 | q = READ_ONCE(umem->fq); |
| 674 | else if (offset == XDP_UMEM_PGOFF_COMPLETION_RING) | 675 | else if (offset == XDP_UMEM_PGOFF_COMPLETION_RING) |
| @@ -678,6 +679,8 @@ static int xsk_mmap(struct file *file, struct socket *sock, | |||
| 678 | if (!q) | 679 | if (!q) |
| 679 | return -EINVAL; | 680 | return -EINVAL; |
| 680 | 681 | ||
| 682 | /* Matches the smp_wmb() in xsk_init_queue */ | ||
| 683 | smp_rmb(); | ||
| 681 | qpg = virt_to_head_page(q->ring); | 684 | qpg = virt_to_head_page(q->ring); |
| 682 | if (size > (PAGE_SIZE << compound_order(qpg))) | 685 | if (size > (PAGE_SIZE << compound_order(qpg))) |
| 683 | return -EINVAL; | 686 | return -EINVAL; |
| @@ -714,6 +717,18 @@ static const struct proto_ops xsk_proto_ops = { | |||
| 714 | .sendpage = sock_no_sendpage, | 717 | .sendpage = sock_no_sendpage, |
| 715 | }; | 718 | }; |
| 716 | 719 | ||
| 720 | static void xsk_destruct(struct sock *sk) | ||
| 721 | { | ||
| 722 | struct xdp_sock *xs = xdp_sk(sk); | ||
| 723 | |||
| 724 | if (!sock_flag(sk, SOCK_DEAD)) | ||
| 725 | return; | ||
| 726 | |||
| 727 | xdp_put_umem(xs->umem); | ||
| 728 | |||
| 729 | sk_refcnt_debug_dec(sk); | ||
| 730 | } | ||
| 731 | |||
| 717 | static int xsk_create(struct net *net, struct socket *sock, int protocol, | 732 | static int xsk_create(struct net *net, struct socket *sock, int protocol, |
| 718 | int kern) | 733 | int kern) |
| 719 | { | 734 | { |
| @@ -740,6 +755,9 @@ static int xsk_create(struct net *net, struct socket *sock, int protocol, | |||
| 740 | 755 | ||
| 741 | sk->sk_family = PF_XDP; | 756 | sk->sk_family = PF_XDP; |
| 742 | 757 | ||
| 758 | sk->sk_destruct = xsk_destruct; | ||
| 759 | sk_refcnt_debug_inc(sk); | ||
| 760 | |||
| 743 | sock_set_flag(sk, SOCK_RCU_FREE); | 761 | sock_set_flag(sk, SOCK_RCU_FREE); |
| 744 | 762 | ||
| 745 | xs = xdp_sk(sk); | 763 | xs = xdp_sk(sk); |
diff --git a/net/xfrm/xfrm_interface.c b/net/xfrm/xfrm_interface.c index 6be8c7df15bb..dbb3c1945b5c 100644 --- a/net/xfrm/xfrm_interface.c +++ b/net/xfrm/xfrm_interface.c | |||
| @@ -76,10 +76,10 @@ static struct xfrm_if *xfrmi_decode_session(struct sk_buff *skb) | |||
| 76 | int ifindex; | 76 | int ifindex; |
| 77 | struct xfrm_if *xi; | 77 | struct xfrm_if *xi; |
| 78 | 78 | ||
| 79 | if (!skb->dev) | 79 | if (!secpath_exists(skb) || !skb->dev) |
| 80 | return NULL; | 80 | return NULL; |
| 81 | 81 | ||
| 82 | xfrmn = net_generic(dev_net(skb->dev), xfrmi_net_id); | 82 | xfrmn = net_generic(xs_net(xfrm_input_state(skb)), xfrmi_net_id); |
| 83 | ifindex = skb->dev->ifindex; | 83 | ifindex = skb->dev->ifindex; |
| 84 | 84 | ||
| 85 | for_each_xfrmi_rcu(xfrmn->xfrmi[0], xi) { | 85 | for_each_xfrmi_rcu(xfrmn->xfrmi[0], xi) { |
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 934492bad8e0..8d1a898d0ba5 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
| @@ -680,16 +680,6 @@ static void xfrm_hash_resize(struct work_struct *work) | |||
| 680 | mutex_unlock(&hash_resize_mutex); | 680 | mutex_unlock(&hash_resize_mutex); |
| 681 | } | 681 | } |
| 682 | 682 | ||
| 683 | static void xfrm_hash_reset_inexact_table(struct net *net) | ||
| 684 | { | ||
| 685 | struct xfrm_pol_inexact_bin *b; | ||
| 686 | |||
| 687 | lockdep_assert_held(&net->xfrm.xfrm_policy_lock); | ||
| 688 | |||
| 689 | list_for_each_entry(b, &net->xfrm.inexact_bins, inexact_bins) | ||
| 690 | INIT_HLIST_HEAD(&b->hhead); | ||
| 691 | } | ||
| 692 | |||
| 693 | /* Make sure *pol can be inserted into fastbin. | 683 | /* Make sure *pol can be inserted into fastbin. |
| 694 | * Useful to check that later insert requests will be sucessful | 684 | * Useful to check that later insert requests will be sucessful |
| 695 | * (provided xfrm_policy_lock is held throughout). | 685 | * (provided xfrm_policy_lock is held throughout). |
| @@ -833,13 +823,13 @@ static void xfrm_policy_inexact_list_reinsert(struct net *net, | |||
| 833 | u16 family) | 823 | u16 family) |
| 834 | { | 824 | { |
| 835 | unsigned int matched_s, matched_d; | 825 | unsigned int matched_s, matched_d; |
| 836 | struct hlist_node *newpos = NULL; | ||
| 837 | struct xfrm_policy *policy, *p; | 826 | struct xfrm_policy *policy, *p; |
| 838 | 827 | ||
| 839 | matched_s = 0; | 828 | matched_s = 0; |
| 840 | matched_d = 0; | 829 | matched_d = 0; |
| 841 | 830 | ||
| 842 | list_for_each_entry_reverse(policy, &net->xfrm.policy_all, walk.all) { | 831 | list_for_each_entry_reverse(policy, &net->xfrm.policy_all, walk.all) { |
| 832 | struct hlist_node *newpos = NULL; | ||
| 843 | bool matches_s, matches_d; | 833 | bool matches_s, matches_d; |
| 844 | 834 | ||
| 845 | if (!policy->bydst_reinsert) | 835 | if (!policy->bydst_reinsert) |
| @@ -849,16 +839,19 @@ static void xfrm_policy_inexact_list_reinsert(struct net *net, | |||
| 849 | 839 | ||
| 850 | policy->bydst_reinsert = false; | 840 | policy->bydst_reinsert = false; |
| 851 | hlist_for_each_entry(p, &n->hhead, bydst) { | 841 | hlist_for_each_entry(p, &n->hhead, bydst) { |
| 852 | if (policy->priority >= p->priority) | 842 | if (policy->priority > p->priority) |
| 843 | newpos = &p->bydst; | ||
| 844 | else if (policy->priority == p->priority && | ||
| 845 | policy->pos > p->pos) | ||
| 853 | newpos = &p->bydst; | 846 | newpos = &p->bydst; |
| 854 | else | 847 | else |
| 855 | break; | 848 | break; |
| 856 | } | 849 | } |
| 857 | 850 | ||
| 858 | if (newpos) | 851 | if (newpos) |
| 859 | hlist_add_behind(&policy->bydst, newpos); | 852 | hlist_add_behind_rcu(&policy->bydst, newpos); |
| 860 | else | 853 | else |
| 861 | hlist_add_head(&policy->bydst, &n->hhead); | 854 | hlist_add_head_rcu(&policy->bydst, &n->hhead); |
| 862 | 855 | ||
| 863 | /* paranoia checks follow. | 856 | /* paranoia checks follow. |
| 864 | * Check that the reinserted policy matches at least | 857 | * Check that the reinserted policy matches at least |
| @@ -893,12 +886,13 @@ static void xfrm_policy_inexact_node_reinsert(struct net *net, | |||
| 893 | struct rb_root *new, | 886 | struct rb_root *new, |
| 894 | u16 family) | 887 | u16 family) |
| 895 | { | 888 | { |
| 896 | struct rb_node **p, *parent = NULL; | ||
| 897 | struct xfrm_pol_inexact_node *node; | 889 | struct xfrm_pol_inexact_node *node; |
| 890 | struct rb_node **p, *parent; | ||
| 898 | 891 | ||
| 899 | /* we should not have another subtree here */ | 892 | /* we should not have another subtree here */ |
| 900 | WARN_ON_ONCE(!RB_EMPTY_ROOT(&n->root)); | 893 | WARN_ON_ONCE(!RB_EMPTY_ROOT(&n->root)); |
| 901 | 894 | restart: | |
| 895 | parent = NULL; | ||
| 902 | p = &new->rb_node; | 896 | p = &new->rb_node; |
| 903 | while (*p) { | 897 | while (*p) { |
| 904 | u8 prefixlen; | 898 | u8 prefixlen; |
| @@ -918,12 +912,11 @@ static void xfrm_policy_inexact_node_reinsert(struct net *net, | |||
| 918 | } else { | 912 | } else { |
| 919 | struct xfrm_policy *tmp; | 913 | struct xfrm_policy *tmp; |
| 920 | 914 | ||
| 921 | hlist_for_each_entry(tmp, &node->hhead, bydst) | 915 | hlist_for_each_entry(tmp, &n->hhead, bydst) { |
| 922 | tmp->bydst_reinsert = true; | ||
| 923 | hlist_for_each_entry(tmp, &n->hhead, bydst) | ||
| 924 | tmp->bydst_reinsert = true; | 916 | tmp->bydst_reinsert = true; |
| 917 | hlist_del_rcu(&tmp->bydst); | ||
| 918 | } | ||
| 925 | 919 | ||
| 926 | INIT_HLIST_HEAD(&node->hhead); | ||
| 927 | xfrm_policy_inexact_list_reinsert(net, node, family); | 920 | xfrm_policy_inexact_list_reinsert(net, node, family); |
| 928 | 921 | ||
| 929 | if (node->prefixlen == n->prefixlen) { | 922 | if (node->prefixlen == n->prefixlen) { |
| @@ -935,8 +928,7 @@ static void xfrm_policy_inexact_node_reinsert(struct net *net, | |||
| 935 | kfree_rcu(n, rcu); | 928 | kfree_rcu(n, rcu); |
| 936 | n = node; | 929 | n = node; |
| 937 | n->prefixlen = prefixlen; | 930 | n->prefixlen = prefixlen; |
| 938 | *p = new->rb_node; | 931 | goto restart; |
| 939 | parent = NULL; | ||
| 940 | } | 932 | } |
| 941 | } | 933 | } |
| 942 | 934 | ||
| @@ -965,12 +957,11 @@ static void xfrm_policy_inexact_node_merge(struct net *net, | |||
| 965 | family); | 957 | family); |
| 966 | } | 958 | } |
| 967 | 959 | ||
| 968 | hlist_for_each_entry(tmp, &v->hhead, bydst) | 960 | hlist_for_each_entry(tmp, &v->hhead, bydst) { |
| 969 | tmp->bydst_reinsert = true; | ||
| 970 | hlist_for_each_entry(tmp, &n->hhead, bydst) | ||
| 971 | tmp->bydst_reinsert = true; | 961 | tmp->bydst_reinsert = true; |
| 962 | hlist_del_rcu(&tmp->bydst); | ||
| 963 | } | ||
| 972 | 964 | ||
| 973 | INIT_HLIST_HEAD(&n->hhead); | ||
| 974 | xfrm_policy_inexact_list_reinsert(net, n, family); | 965 | xfrm_policy_inexact_list_reinsert(net, n, family); |
| 975 | } | 966 | } |
| 976 | 967 | ||
| @@ -1235,6 +1226,7 @@ static void xfrm_hash_rebuild(struct work_struct *work) | |||
| 1235 | } while (read_seqretry(&net->xfrm.policy_hthresh.lock, seq)); | 1226 | } while (read_seqretry(&net->xfrm.policy_hthresh.lock, seq)); |
| 1236 | 1227 | ||
| 1237 | spin_lock_bh(&net->xfrm.xfrm_policy_lock); | 1228 | spin_lock_bh(&net->xfrm.xfrm_policy_lock); |
| 1229 | write_seqcount_begin(&xfrm_policy_hash_generation); | ||
| 1238 | 1230 | ||
| 1239 | /* make sure that we can insert the indirect policies again before | 1231 | /* make sure that we can insert the indirect policies again before |
| 1240 | * we start with destructive action. | 1232 | * we start with destructive action. |
| @@ -1278,10 +1270,14 @@ static void xfrm_hash_rebuild(struct work_struct *work) | |||
| 1278 | } | 1270 | } |
| 1279 | 1271 | ||
| 1280 | /* reset the bydst and inexact table in all directions */ | 1272 | /* reset the bydst and inexact table in all directions */ |
| 1281 | xfrm_hash_reset_inexact_table(net); | ||
| 1282 | |||
| 1283 | for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { | 1273 | for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { |
| 1284 | INIT_HLIST_HEAD(&net->xfrm.policy_inexact[dir]); | 1274 | struct hlist_node *n; |
| 1275 | |||
| 1276 | hlist_for_each_entry_safe(policy, n, | ||
| 1277 | &net->xfrm.policy_inexact[dir], | ||
| 1278 | bydst_inexact_list) | ||
| 1279 | hlist_del_init(&policy->bydst_inexact_list); | ||
| 1280 | |||
| 1285 | hmask = net->xfrm.policy_bydst[dir].hmask; | 1281 | hmask = net->xfrm.policy_bydst[dir].hmask; |
| 1286 | odst = net->xfrm.policy_bydst[dir].table; | 1282 | odst = net->xfrm.policy_bydst[dir].table; |
| 1287 | for (i = hmask; i >= 0; i--) | 1283 | for (i = hmask; i >= 0; i--) |
| @@ -1313,6 +1309,9 @@ static void xfrm_hash_rebuild(struct work_struct *work) | |||
| 1313 | newpos = NULL; | 1309 | newpos = NULL; |
| 1314 | chain = policy_hash_bysel(net, &policy->selector, | 1310 | chain = policy_hash_bysel(net, &policy->selector, |
| 1315 | policy->family, dir); | 1311 | policy->family, dir); |
| 1312 | |||
| 1313 | hlist_del_rcu(&policy->bydst); | ||
| 1314 | |||
| 1316 | if (!chain) { | 1315 | if (!chain) { |
| 1317 | void *p = xfrm_policy_inexact_insert(policy, dir, 0); | 1316 | void *p = xfrm_policy_inexact_insert(policy, dir, 0); |
| 1318 | 1317 | ||
| @@ -1334,6 +1333,7 @@ static void xfrm_hash_rebuild(struct work_struct *work) | |||
| 1334 | 1333 | ||
| 1335 | out_unlock: | 1334 | out_unlock: |
| 1336 | __xfrm_policy_inexact_flush(net); | 1335 | __xfrm_policy_inexact_flush(net); |
| 1336 | write_seqcount_end(&xfrm_policy_hash_generation); | ||
| 1337 | spin_unlock_bh(&net->xfrm.xfrm_policy_lock); | 1337 | spin_unlock_bh(&net->xfrm.xfrm_policy_lock); |
| 1338 | 1338 | ||
| 1339 | mutex_unlock(&hash_resize_mutex); | 1339 | mutex_unlock(&hash_resize_mutex); |
| @@ -2600,7 +2600,10 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, | |||
| 2600 | dst_copy_metrics(dst1, dst); | 2600 | dst_copy_metrics(dst1, dst); |
| 2601 | 2601 | ||
| 2602 | if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) { | 2602 | if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) { |
| 2603 | __u32 mark = xfrm_smark_get(fl->flowi_mark, xfrm[i]); | 2603 | __u32 mark = 0; |
| 2604 | |||
| 2605 | if (xfrm[i]->props.smark.v || xfrm[i]->props.smark.m) | ||
| 2606 | mark = xfrm_smark_get(fl->flowi_mark, xfrm[i]); | ||
| 2604 | 2607 | ||
| 2605 | family = xfrm[i]->props.family; | 2608 | family = xfrm[i]->props.family; |
| 2606 | dst = xfrm_dst_lookup(xfrm[i], tos, fl->flowi_oif, | 2609 | dst = xfrm_dst_lookup(xfrm[i], tos, fl->flowi_oif, |
| @@ -3311,8 +3314,10 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
| 3311 | 3314 | ||
| 3312 | if (ifcb) { | 3315 | if (ifcb) { |
| 3313 | xi = ifcb->decode_session(skb); | 3316 | xi = ifcb->decode_session(skb); |
| 3314 | if (xi) | 3317 | if (xi) { |
| 3315 | if_id = xi->p.if_id; | 3318 | if_id = xi->p.if_id; |
| 3319 | net = xi->net; | ||
| 3320 | } | ||
| 3316 | } | 3321 | } |
| 3317 | rcu_read_unlock(); | 3322 | rcu_read_unlock(); |
| 3318 | 3323 | ||
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 23c92891758a..1bb971f46fc6 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
| @@ -432,7 +432,7 @@ void xfrm_state_free(struct xfrm_state *x) | |||
| 432 | } | 432 | } |
| 433 | EXPORT_SYMBOL(xfrm_state_free); | 433 | EXPORT_SYMBOL(xfrm_state_free); |
| 434 | 434 | ||
| 435 | static void xfrm_state_gc_destroy(struct xfrm_state *x) | 435 | static void ___xfrm_state_destroy(struct xfrm_state *x) |
| 436 | { | 436 | { |
| 437 | tasklet_hrtimer_cancel(&x->mtimer); | 437 | tasklet_hrtimer_cancel(&x->mtimer); |
| 438 | del_timer_sync(&x->rtimer); | 438 | del_timer_sync(&x->rtimer); |
| @@ -474,7 +474,7 @@ static void xfrm_state_gc_task(struct work_struct *work) | |||
| 474 | synchronize_rcu(); | 474 | synchronize_rcu(); |
| 475 | 475 | ||
| 476 | hlist_for_each_entry_safe(x, tmp, &gc_list, gclist) | 476 | hlist_for_each_entry_safe(x, tmp, &gc_list, gclist) |
| 477 | xfrm_state_gc_destroy(x); | 477 | ___xfrm_state_destroy(x); |
| 478 | } | 478 | } |
| 479 | 479 | ||
| 480 | static enum hrtimer_restart xfrm_timer_handler(struct hrtimer *me) | 480 | static enum hrtimer_restart xfrm_timer_handler(struct hrtimer *me) |
| @@ -598,14 +598,19 @@ struct xfrm_state *xfrm_state_alloc(struct net *net) | |||
| 598 | } | 598 | } |
| 599 | EXPORT_SYMBOL(xfrm_state_alloc); | 599 | EXPORT_SYMBOL(xfrm_state_alloc); |
| 600 | 600 | ||
| 601 | void __xfrm_state_destroy(struct xfrm_state *x) | 601 | void __xfrm_state_destroy(struct xfrm_state *x, bool sync) |
| 602 | { | 602 | { |
| 603 | WARN_ON(x->km.state != XFRM_STATE_DEAD); | 603 | WARN_ON(x->km.state != XFRM_STATE_DEAD); |
| 604 | 604 | ||
| 605 | spin_lock_bh(&xfrm_state_gc_lock); | 605 | if (sync) { |
| 606 | hlist_add_head(&x->gclist, &xfrm_state_gc_list); | 606 | synchronize_rcu(); |
| 607 | spin_unlock_bh(&xfrm_state_gc_lock); | 607 | ___xfrm_state_destroy(x); |
| 608 | schedule_work(&xfrm_state_gc_work); | 608 | } else { |
| 609 | spin_lock_bh(&xfrm_state_gc_lock); | ||
| 610 | hlist_add_head(&x->gclist, &xfrm_state_gc_list); | ||
| 611 | spin_unlock_bh(&xfrm_state_gc_lock); | ||
| 612 | schedule_work(&xfrm_state_gc_work); | ||
| 613 | } | ||
| 609 | } | 614 | } |
| 610 | EXPORT_SYMBOL(__xfrm_state_destroy); | 615 | EXPORT_SYMBOL(__xfrm_state_destroy); |
| 611 | 616 | ||
| @@ -708,7 +713,7 @@ xfrm_dev_state_flush_secctx_check(struct net *net, struct net_device *dev, bool | |||
| 708 | } | 713 | } |
| 709 | #endif | 714 | #endif |
| 710 | 715 | ||
| 711 | int xfrm_state_flush(struct net *net, u8 proto, bool task_valid) | 716 | int xfrm_state_flush(struct net *net, u8 proto, bool task_valid, bool sync) |
| 712 | { | 717 | { |
| 713 | int i, err = 0, cnt = 0; | 718 | int i, err = 0, cnt = 0; |
| 714 | 719 | ||
| @@ -730,7 +735,10 @@ restart: | |||
| 730 | err = xfrm_state_delete(x); | 735 | err = xfrm_state_delete(x); |
| 731 | xfrm_audit_state_delete(x, err ? 0 : 1, | 736 | xfrm_audit_state_delete(x, err ? 0 : 1, |
| 732 | task_valid); | 737 | task_valid); |
| 733 | xfrm_state_put(x); | 738 | if (sync) |
| 739 | xfrm_state_put_sync(x); | ||
| 740 | else | ||
| 741 | xfrm_state_put(x); | ||
| 734 | if (!err) | 742 | if (!err) |
| 735 | cnt++; | 743 | cnt++; |
| 736 | 744 | ||
| @@ -2215,7 +2223,7 @@ void xfrm_state_delete_tunnel(struct xfrm_state *x) | |||
| 2215 | if (atomic_read(&t->tunnel_users) == 2) | 2223 | if (atomic_read(&t->tunnel_users) == 2) |
| 2216 | xfrm_state_delete(t); | 2224 | xfrm_state_delete(t); |
| 2217 | atomic_dec(&t->tunnel_users); | 2225 | atomic_dec(&t->tunnel_users); |
| 2218 | xfrm_state_put(t); | 2226 | xfrm_state_put_sync(t); |
| 2219 | x->tunnel = NULL; | 2227 | x->tunnel = NULL; |
| 2220 | } | 2228 | } |
| 2221 | } | 2229 | } |
| @@ -2375,8 +2383,8 @@ void xfrm_state_fini(struct net *net) | |||
| 2375 | unsigned int sz; | 2383 | unsigned int sz; |
| 2376 | 2384 | ||
| 2377 | flush_work(&net->xfrm.state_hash_work); | 2385 | flush_work(&net->xfrm.state_hash_work); |
| 2378 | xfrm_state_flush(net, IPSEC_PROTO_ANY, false); | ||
| 2379 | flush_work(&xfrm_state_gc_work); | 2386 | flush_work(&xfrm_state_gc_work); |
| 2387 | xfrm_state_flush(net, IPSEC_PROTO_ANY, false, true); | ||
| 2380 | 2388 | ||
| 2381 | WARN_ON(!list_empty(&net->xfrm.state_all)); | 2389 | WARN_ON(!list_empty(&net->xfrm.state_all)); |
| 2382 | 2390 | ||
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 277c1c46fe94..a131f9ff979e 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
| @@ -1488,10 +1488,15 @@ static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family) | |||
| 1488 | if (!ut[i].family) | 1488 | if (!ut[i].family) |
| 1489 | ut[i].family = family; | 1489 | ut[i].family = family; |
| 1490 | 1490 | ||
| 1491 | if ((ut[i].mode == XFRM_MODE_TRANSPORT) && | 1491 | switch (ut[i].mode) { |
| 1492 | (ut[i].family != prev_family)) | 1492 | case XFRM_MODE_TUNNEL: |
| 1493 | return -EINVAL; | 1493 | case XFRM_MODE_BEET: |
| 1494 | 1494 | break; | |
| 1495 | default: | ||
| 1496 | if (ut[i].family != prev_family) | ||
| 1497 | return -EINVAL; | ||
| 1498 | break; | ||
| 1499 | } | ||
| 1495 | if (ut[i].mode >= XFRM_MODE_MAX) | 1500 | if (ut[i].mode >= XFRM_MODE_MAX) |
| 1496 | return -EINVAL; | 1501 | return -EINVAL; |
| 1497 | 1502 | ||
| @@ -1927,7 +1932,7 @@ static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
| 1927 | struct xfrm_usersa_flush *p = nlmsg_data(nlh); | 1932 | struct xfrm_usersa_flush *p = nlmsg_data(nlh); |
| 1928 | int err; | 1933 | int err; |
| 1929 | 1934 | ||
| 1930 | err = xfrm_state_flush(net, p->proto, true); | 1935 | err = xfrm_state_flush(net, p->proto, true, false); |
| 1931 | if (err) { | 1936 | if (err) { |
| 1932 | if (err == -ESRCH) /* empty table */ | 1937 | if (err == -ESRCH) /* empty table */ |
| 1933 | return 0; | 1938 | return 0; |
