diff options
Diffstat (limited to 'net')
63 files changed, 823 insertions, 316 deletions
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..b85ca809e509 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c | |||
@@ -221,6 +221,8 @@ 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)) { |
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 5e55cef0cec3..6693e209efe8 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c | |||
@@ -2293,9 +2293,12 @@ static int compat_do_replace(struct net *net, void __user *user, | |||
2293 | 2293 | ||
2294 | xt_compat_lock(NFPROTO_BRIDGE); | 2294 | xt_compat_lock(NFPROTO_BRIDGE); |
2295 | 2295 | ||
2296 | ret = xt_compat_init_offsets(NFPROTO_BRIDGE, tmp.nentries); | 2296 | if (tmp.nentries) { |
2297 | if (ret < 0) | 2297 | ret = xt_compat_init_offsets(NFPROTO_BRIDGE, tmp.nentries); |
2298 | goto out_unlock; | 2298 | if (ret < 0) |
2299 | goto out_unlock; | ||
2300 | } | ||
2301 | |||
2299 | ret = compat_copy_entries(entries_tmp, tmp.entries_size, &state); | 2302 | ret = compat_copy_entries(entries_tmp, tmp.entries_size, &state); |
2300 | if (ret < 0) | 2303 | if (ret < 0) |
2301 | goto out_unlock; | 2304 | goto out_unlock; |
diff --git a/net/core/dev.c b/net/core/dev.c index 82f20022259d..8e276e0192a1 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -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 7559d6835ecb..7a54dc11ac2d 100644 --- a/net/core/filter.c +++ b/net/core/filter.c | |||
@@ -4112,10 +4112,12 @@ BPF_CALL_5(bpf_setsockopt, struct bpf_sock_ops_kern *, bpf_sock, | |||
4112 | /* Only some socketops are supported */ | 4112 | /* Only some socketops are supported */ |
4113 | switch (optname) { | 4113 | switch (optname) { |
4114 | case SO_RCVBUF: | 4114 | case SO_RCVBUF: |
4115 | val = min_t(u32, val, sysctl_rmem_max); | ||
4115 | sk->sk_userlocks |= SOCK_RCVBUF_LOCK; | 4116 | sk->sk_userlocks |= SOCK_RCVBUF_LOCK; |
4116 | sk->sk_rcvbuf = max_t(int, val * 2, SOCK_MIN_RCVBUF); | 4117 | sk->sk_rcvbuf = max_t(int, val * 2, SOCK_MIN_RCVBUF); |
4117 | break; | 4118 | break; |
4118 | case SO_SNDBUF: | 4119 | case SO_SNDBUF: |
4120 | val = min_t(u32, val, sysctl_wmem_max); | ||
4119 | sk->sk_userlocks |= SOCK_SNDBUF_LOCK; | 4121 | sk->sk_userlocks |= SOCK_SNDBUF_LOCK; |
4120 | sk->sk_sndbuf = max_t(int, val * 2, SOCK_MIN_SNDBUF); | 4122 | sk->sk_sndbuf = max_t(int, val * 2, SOCK_MIN_SNDBUF); |
4121 | break; | 4123 | break; |
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/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/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/ip_gre.c b/net/ipv4/ip_gre.c index 20a64fe6254b..3978f807fa8b 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c | |||
@@ -1455,12 +1455,17 @@ static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev) | |||
1455 | { | 1455 | { |
1456 | struct ip_tunnel *t = netdev_priv(dev); | 1456 | struct ip_tunnel *t = netdev_priv(dev); |
1457 | 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 | !t->collect_md) | ||
1462 | o_flags |= TUNNEL_KEY; | ||
1458 | 1463 | ||
1459 | if (nla_put_u32(skb, IFLA_GRE_LINK, p->link) || | 1464 | if (nla_put_u32(skb, IFLA_GRE_LINK, p->link) || |
1460 | nla_put_be16(skb, IFLA_GRE_IFLAGS, | 1465 | nla_put_be16(skb, IFLA_GRE_IFLAGS, |
1461 | gre_tnl_flags_to_gre_flags(p->i_flags)) || | 1466 | gre_tnl_flags_to_gre_flags(p->i_flags)) || |
1462 | nla_put_be16(skb, IFLA_GRE_OFLAGS, | 1467 | nla_put_be16(skb, IFLA_GRE_OFLAGS, |
1463 | gre_tnl_flags_to_gre_flags(p->o_flags)) || | 1468 | gre_tnl_flags_to_gre_flags(o_flags)) || |
1464 | nla_put_be32(skb, IFLA_GRE_IKEY, p->i_key) || | 1469 | nla_put_be32(skb, IFLA_GRE_IKEY, p->i_key) || |
1465 | nla_put_be32(skb, IFLA_GRE_OKEY, p->o_key) || | 1470 | nla_put_be32(skb, IFLA_GRE_OKEY, p->o_key) || |
1466 | nla_put_in_addr(skb, IFLA_GRE_LOCAL, p->iph.saddr) || | 1471 | nla_put_in_addr(skb, IFLA_GRE_LOCAL, p->iph.saddr) || |
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/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 4416368dbd49..801a9a0c217e 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c | |||
@@ -2098,12 +2098,17 @@ static int ip6gre_fill_info(struct sk_buff *skb, const struct net_device *dev) | |||
2098 | { | 2098 | { |
2099 | struct ip6_tnl *t = netdev_priv(dev); | 2099 | struct ip6_tnl *t = netdev_priv(dev); |
2100 | struct __ip6_tnl_parm *p = &t->parms; | 2100 | struct __ip6_tnl_parm *p = &t->parms; |
2101 | __be16 o_flags = p->o_flags; | ||
2102 | |||
2103 | if ((p->erspan_ver == 1 || p->erspan_ver == 2) && | ||
2104 | !p->collect_md) | ||
2105 | o_flags |= TUNNEL_KEY; | ||
2101 | 2106 | ||
2102 | if (nla_put_u32(skb, IFLA_GRE_LINK, p->link) || | 2107 | if (nla_put_u32(skb, IFLA_GRE_LINK, p->link) || |
2103 | nla_put_be16(skb, IFLA_GRE_IFLAGS, | 2108 | nla_put_be16(skb, IFLA_GRE_IFLAGS, |
2104 | gre_tnl_flags_to_gre_flags(p->i_flags)) || | 2109 | gre_tnl_flags_to_gre_flags(p->i_flags)) || |
2105 | nla_put_be16(skb, IFLA_GRE_OFLAGS, | 2110 | nla_put_be16(skb, IFLA_GRE_OFLAGS, |
2106 | gre_tnl_flags_to_gre_flags(p->o_flags)) || | 2111 | gre_tnl_flags_to_gre_flags(o_flags)) || |
2107 | nla_put_be32(skb, IFLA_GRE_IKEY, p->i_key) || | 2112 | nla_put_be32(skb, IFLA_GRE_IKEY, p->i_key) || |
2108 | nla_put_be32(skb, IFLA_GRE_OKEY, p->o_key) || | 2113 | nla_put_be32(skb, IFLA_GRE_OKEY, p->o_key) || |
2109 | nla_put_in6_addr(skb, IFLA_GRE_LOCAL, &p->laddr) || | 2114 | nla_put_in6_addr(skb, IFLA_GRE_LOCAL, &p->laddr) || |
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/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/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/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/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index 432141f04af3..7d6318664eb2 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c | |||
@@ -2221,6 +2221,18 @@ static int ip_vs_set_timeout(struct netns_ipvs *ipvs, struct ip_vs_timeout_user | |||
2221 | u->udp_timeout); | 2221 | u->udp_timeout); |
2222 | 2222 | ||
2223 | #ifdef CONFIG_IP_VS_PROTO_TCP | 2223 | #ifdef CONFIG_IP_VS_PROTO_TCP |
2224 | if (u->tcp_timeout < 0 || u->tcp_timeout > (INT_MAX / HZ) || | ||
2225 | u->tcp_fin_timeout < 0 || u->tcp_fin_timeout > (INT_MAX / HZ)) { | ||
2226 | return -EINVAL; | ||
2227 | } | ||
2228 | #endif | ||
2229 | |||
2230 | #ifdef CONFIG_IP_VS_PROTO_UDP | ||
2231 | if (u->udp_timeout < 0 || u->udp_timeout > (INT_MAX / HZ)) | ||
2232 | return -EINVAL; | ||
2233 | #endif | ||
2234 | |||
2235 | #ifdef CONFIG_IP_VS_PROTO_TCP | ||
2224 | if (u->tcp_timeout) { | 2236 | if (u->tcp_timeout) { |
2225 | pd = ip_vs_proto_data_get(ipvs, IPPROTO_TCP); | 2237 | pd = ip_vs_proto_data_get(ipvs, IPPROTO_TCP); |
2226 | pd->timeout_table[IP_VS_TCP_S_ESTABLISHED] | 2238 | 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_tables_api.c b/net/netfilter/nf_tables_api.c index fb07f6cfc719..5a92f23f179f 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 | } |
@@ -1929,9 +1935,6 @@ static int nf_tables_delchain(struct net *net, struct sock *nlsk, | |||
1929 | */ | 1935 | */ |
1930 | int nft_register_expr(struct nft_expr_type *type) | 1936 | int nft_register_expr(struct nft_expr_type *type) |
1931 | { | 1937 | { |
1932 | if (!nft_expr_check_ops(type->ops)) | ||
1933 | return -EINVAL; | ||
1934 | |||
1935 | nfnl_lock(NFNL_SUBSYS_NFTABLES); | 1938 | nfnl_lock(NFNL_SUBSYS_NFTABLES); |
1936 | if (type->family == NFPROTO_UNSPEC) | 1939 | if (type->family == NFPROTO_UNSPEC) |
1937 | list_add_tail_rcu(&type->list, &nf_tables_expressions); | 1940 | list_add_tail_rcu(&type->list, &nf_tables_expressions); |
@@ -2079,10 +2082,6 @@ static int nf_tables_expr_parse(const struct nft_ctx *ctx, | |||
2079 | err = PTR_ERR(ops); | 2082 | err = PTR_ERR(ops); |
2080 | goto err1; | 2083 | goto err1; |
2081 | } | 2084 | } |
2082 | if (!nft_expr_check_ops(ops)) { | ||
2083 | err = -EINVAL; | ||
2084 | goto err1; | ||
2085 | } | ||
2086 | } else | 2085 | } else |
2087 | ops = type->ops; | 2086 | ops = type->ops; |
2088 | 2087 | ||
@@ -2511,7 +2510,7 @@ static void nf_tables_rule_destroy(const struct nft_ctx *ctx, | |||
2511 | static void nf_tables_rule_release(const struct nft_ctx *ctx, | 2510 | static void nf_tables_rule_release(const struct nft_ctx *ctx, |
2512 | struct nft_rule *rule) | 2511 | struct nft_rule *rule) |
2513 | { | 2512 | { |
2514 | nft_rule_expr_deactivate(ctx, rule); | 2513 | nft_rule_expr_deactivate(ctx, rule, NFT_TRANS_RELEASE); |
2515 | nf_tables_rule_destroy(ctx, rule); | 2514 | nf_tables_rule_destroy(ctx, rule); |
2516 | } | 2515 | } |
2517 | 2516 | ||
@@ -3708,39 +3707,30 @@ int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set, | |||
3708 | bind: | 3707 | bind: |
3709 | binding->chain = ctx->chain; | 3708 | binding->chain = ctx->chain; |
3710 | list_add_tail_rcu(&binding->list, &set->bindings); | 3709 | list_add_tail_rcu(&binding->list, &set->bindings); |
3710 | nft_set_trans_bind(ctx, set); | ||
3711 | |||
3711 | return 0; | 3712 | return 0; |
3712 | } | 3713 | } |
3713 | EXPORT_SYMBOL_GPL(nf_tables_bind_set); | 3714 | EXPORT_SYMBOL_GPL(nf_tables_bind_set); |
3714 | 3715 | ||
3715 | void nf_tables_rebind_set(const struct nft_ctx *ctx, struct nft_set *set, | ||
3716 | struct nft_set_binding *binding) | ||
3717 | { | ||
3718 | if (list_empty(&set->bindings) && nft_set_is_anonymous(set) && | ||
3719 | nft_is_active(ctx->net, set)) | ||
3720 | list_add_tail_rcu(&set->list, &ctx->table->sets); | ||
3721 | |||
3722 | list_add_tail_rcu(&binding->list, &set->bindings); | ||
3723 | } | ||
3724 | EXPORT_SYMBOL_GPL(nf_tables_rebind_set); | ||
3725 | |||
3726 | void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set, | 3716 | void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set, |
3727 | struct nft_set_binding *binding) | 3717 | struct nft_set_binding *binding, bool event) |
3728 | { | 3718 | { |
3729 | list_del_rcu(&binding->list); | 3719 | list_del_rcu(&binding->list); |
3730 | 3720 | ||
3731 | if (list_empty(&set->bindings) && nft_set_is_anonymous(set) && | 3721 | if (list_empty(&set->bindings) && nft_set_is_anonymous(set)) { |
3732 | nft_is_active(ctx->net, set)) | ||
3733 | list_del_rcu(&set->list); | 3722 | list_del_rcu(&set->list); |
3723 | if (event) | ||
3724 | nf_tables_set_notify(ctx, set, NFT_MSG_DELSET, | ||
3725 | GFP_KERNEL); | ||
3726 | } | ||
3734 | } | 3727 | } |
3735 | EXPORT_SYMBOL_GPL(nf_tables_unbind_set); | 3728 | EXPORT_SYMBOL_GPL(nf_tables_unbind_set); |
3736 | 3729 | ||
3737 | void nf_tables_destroy_set(const struct nft_ctx *ctx, struct nft_set *set) | 3730 | void nf_tables_destroy_set(const struct nft_ctx *ctx, struct nft_set *set) |
3738 | { | 3731 | { |
3739 | if (list_empty(&set->bindings) && nft_set_is_anonymous(set) && | 3732 | if (list_empty(&set->bindings) && nft_set_is_anonymous(set)) |
3740 | nft_is_active(ctx->net, set)) { | ||
3741 | nf_tables_set_notify(ctx, set, NFT_MSG_DELSET, GFP_ATOMIC); | ||
3742 | nft_set_destroy(set); | 3733 | nft_set_destroy(set); |
3743 | } | ||
3744 | } | 3734 | } |
3745 | EXPORT_SYMBOL_GPL(nf_tables_destroy_set); | 3735 | EXPORT_SYMBOL_GPL(nf_tables_destroy_set); |
3746 | 3736 | ||
@@ -6535,6 +6525,9 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb) | |||
6535 | nf_tables_rule_notify(&trans->ctx, | 6525 | nf_tables_rule_notify(&trans->ctx, |
6536 | nft_trans_rule(trans), | 6526 | nft_trans_rule(trans), |
6537 | NFT_MSG_DELRULE); | 6527 | NFT_MSG_DELRULE); |
6528 | nft_rule_expr_deactivate(&trans->ctx, | ||
6529 | nft_trans_rule(trans), | ||
6530 | NFT_TRANS_COMMIT); | ||
6538 | break; | 6531 | break; |
6539 | case NFT_MSG_NEWSET: | 6532 | case NFT_MSG_NEWSET: |
6540 | nft_clear(net, nft_trans_set(trans)); | 6533 | nft_clear(net, nft_trans_set(trans)); |
@@ -6621,7 +6614,8 @@ static void nf_tables_abort_release(struct nft_trans *trans) | |||
6621 | nf_tables_rule_destroy(&trans->ctx, nft_trans_rule(trans)); | 6614 | nf_tables_rule_destroy(&trans->ctx, nft_trans_rule(trans)); |
6622 | break; | 6615 | break; |
6623 | case NFT_MSG_NEWSET: | 6616 | case NFT_MSG_NEWSET: |
6624 | nft_set_destroy(nft_trans_set(trans)); | 6617 | if (!nft_trans_set_bound(trans)) |
6618 | nft_set_destroy(nft_trans_set(trans)); | ||
6625 | break; | 6619 | break; |
6626 | case NFT_MSG_NEWSETELEM: | 6620 | case NFT_MSG_NEWSETELEM: |
6627 | nft_set_elem_destroy(nft_trans_elem_set(trans), | 6621 | nft_set_elem_destroy(nft_trans_elem_set(trans), |
@@ -6682,7 +6676,9 @@ static int __nf_tables_abort(struct net *net) | |||
6682 | case NFT_MSG_NEWRULE: | 6676 | case NFT_MSG_NEWRULE: |
6683 | trans->ctx.chain->use--; | 6677 | trans->ctx.chain->use--; |
6684 | list_del_rcu(&nft_trans_rule(trans)->list); | 6678 | list_del_rcu(&nft_trans_rule(trans)->list); |
6685 | nft_rule_expr_deactivate(&trans->ctx, nft_trans_rule(trans)); | 6679 | nft_rule_expr_deactivate(&trans->ctx, |
6680 | nft_trans_rule(trans), | ||
6681 | NFT_TRANS_ABORT); | ||
6686 | break; | 6682 | break; |
6687 | case NFT_MSG_DELRULE: | 6683 | case NFT_MSG_DELRULE: |
6688 | trans->ctx.chain->use++; | 6684 | trans->ctx.chain->use++; |
@@ -6692,7 +6688,8 @@ static int __nf_tables_abort(struct net *net) | |||
6692 | break; | 6688 | break; |
6693 | case NFT_MSG_NEWSET: | 6689 | case NFT_MSG_NEWSET: |
6694 | trans->ctx.table->use--; | 6690 | trans->ctx.table->use--; |
6695 | list_del_rcu(&nft_trans_set(trans)->list); | 6691 | if (!nft_trans_set_bound(trans)) |
6692 | list_del_rcu(&nft_trans_set(trans)->list); | ||
6696 | break; | 6693 | break; |
6697 | case NFT_MSG_DELSET: | 6694 | case NFT_MSG_DELSET: |
6698 | trans->ctx.table->use++; | 6695 | 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..fe64df848365 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 | ||
@@ -486,7 +519,7 @@ __nft_match_init(const struct nft_ctx *ctx, const struct nft_expr *expr, | |||
486 | return ret; | 519 | return ret; |
487 | 520 | ||
488 | nft_xt = container_of(expr->ops, struct nft_xt, ops); | 521 | nft_xt = container_of(expr->ops, struct nft_xt, ops); |
489 | nft_xt->refcnt++; | 522 | nft_xt_get(nft_xt); |
490 | return 0; | 523 | return 0; |
491 | } | 524 | } |
492 | 525 | ||
@@ -540,6 +573,18 @@ nft_match_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) | |||
540 | __nft_match_destroy(ctx, expr, nft_expr_priv(expr)); | 573 | __nft_match_destroy(ctx, expr, nft_expr_priv(expr)); |
541 | } | 574 | } |
542 | 575 | ||
576 | static void nft_compat_deactivate(const struct nft_ctx *ctx, | ||
577 | const struct nft_expr *expr, | ||
578 | enum nft_trans_phase phase) | ||
579 | { | ||
580 | struct nft_xt *xt = container_of(expr->ops, struct nft_xt, ops); | ||
581 | |||
582 | if (phase == NFT_TRANS_ABORT || phase == NFT_TRANS_COMMIT) { | ||
583 | if (--xt->listcnt == 0) | ||
584 | list_del_init(&xt->head); | ||
585 | } | ||
586 | } | ||
587 | |||
543 | static void | 588 | static void |
544 | nft_match_large_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) | 589 | nft_match_large_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) |
545 | { | 590 | { |
@@ -734,10 +779,6 @@ static const struct nfnetlink_subsystem nfnl_compat_subsys = { | |||
734 | .cb = nfnl_nft_compat_cb, | 779 | .cb = nfnl_nft_compat_cb, |
735 | }; | 780 | }; |
736 | 781 | ||
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, | 782 | static bool nft_match_cmp(const struct xt_match *match, |
742 | const char *name, u32 rev, u32 family) | 783 | const char *name, u32 rev, u32 family) |
743 | { | 784 | { |
@@ -749,6 +790,7 @@ static const struct nft_expr_ops * | |||
749 | nft_match_select_ops(const struct nft_ctx *ctx, | 790 | nft_match_select_ops(const struct nft_ctx *ctx, |
750 | const struct nlattr * const tb[]) | 791 | const struct nlattr * const tb[]) |
751 | { | 792 | { |
793 | struct nft_compat_net *cn; | ||
752 | struct nft_xt *nft_match; | 794 | struct nft_xt *nft_match; |
753 | struct xt_match *match; | 795 | struct xt_match *match; |
754 | unsigned int matchsize; | 796 | unsigned int matchsize; |
@@ -765,8 +807,10 @@ nft_match_select_ops(const struct nft_ctx *ctx, | |||
765 | rev = ntohl(nla_get_be32(tb[NFTA_MATCH_REV])); | 807 | rev = ntohl(nla_get_be32(tb[NFTA_MATCH_REV])); |
766 | family = ctx->family; | 808 | family = ctx->family; |
767 | 809 | ||
810 | cn = nft_compat_pernet(ctx->net); | ||
811 | |||
768 | /* Re-use the existing match if it's already loaded. */ | 812 | /* Re-use the existing match if it's already loaded. */ |
769 | list_for_each_entry(nft_match, &nft_match_list, head) { | 813 | list_for_each_entry(nft_match, &cn->nft_match_list, head) { |
770 | struct xt_match *match = nft_match->ops.data; | 814 | struct xt_match *match = nft_match->ops.data; |
771 | 815 | ||
772 | if (nft_match_cmp(match, mt_name, rev, family)) | 816 | if (nft_match_cmp(match, mt_name, rev, family)) |
@@ -789,11 +833,12 @@ nft_match_select_ops(const struct nft_ctx *ctx, | |||
789 | goto err; | 833 | goto err; |
790 | } | 834 | } |
791 | 835 | ||
792 | nft_match->refcnt = 0; | 836 | refcount_set(&nft_match->refcnt, 0); |
793 | nft_match->ops.type = &nft_match_type; | 837 | nft_match->ops.type = &nft_match_type; |
794 | nft_match->ops.eval = nft_match_eval; | 838 | nft_match->ops.eval = nft_match_eval; |
795 | nft_match->ops.init = nft_match_init; | 839 | nft_match->ops.init = nft_match_init; |
796 | nft_match->ops.destroy = nft_match_destroy; | 840 | nft_match->ops.destroy = nft_match_destroy; |
841 | nft_match->ops.deactivate = nft_compat_deactivate; | ||
797 | nft_match->ops.dump = nft_match_dump; | 842 | nft_match->ops.dump = nft_match_dump; |
798 | nft_match->ops.validate = nft_match_validate; | 843 | nft_match->ops.validate = nft_match_validate; |
799 | nft_match->ops.data = match; | 844 | nft_match->ops.data = match; |
@@ -810,7 +855,8 @@ nft_match_select_ops(const struct nft_ctx *ctx, | |||
810 | 855 | ||
811 | nft_match->ops.size = matchsize; | 856 | nft_match->ops.size = matchsize; |
812 | 857 | ||
813 | list_add(&nft_match->head, &nft_match_list); | 858 | nft_match->listcnt = 0; |
859 | list_add(&nft_match->head, &cn->nft_match_list); | ||
814 | 860 | ||
815 | return &nft_match->ops; | 861 | return &nft_match->ops; |
816 | err: | 862 | err: |
@@ -826,10 +872,6 @@ static struct nft_expr_type nft_match_type __read_mostly = { | |||
826 | .owner = THIS_MODULE, | 872 | .owner = THIS_MODULE, |
827 | }; | 873 | }; |
828 | 874 | ||
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, | 875 | static bool nft_target_cmp(const struct xt_target *tg, |
834 | const char *name, u32 rev, u32 family) | 876 | const char *name, u32 rev, u32 family) |
835 | { | 877 | { |
@@ -841,6 +883,7 @@ static const struct nft_expr_ops * | |||
841 | nft_target_select_ops(const struct nft_ctx *ctx, | 883 | nft_target_select_ops(const struct nft_ctx *ctx, |
842 | const struct nlattr * const tb[]) | 884 | const struct nlattr * const tb[]) |
843 | { | 885 | { |
886 | struct nft_compat_net *cn; | ||
844 | struct nft_xt *nft_target; | 887 | struct nft_xt *nft_target; |
845 | struct xt_target *target; | 888 | struct xt_target *target; |
846 | char *tg_name; | 889 | char *tg_name; |
@@ -861,8 +904,9 @@ nft_target_select_ops(const struct nft_ctx *ctx, | |||
861 | strcmp(tg_name, "standard") == 0) | 904 | strcmp(tg_name, "standard") == 0) |
862 | return ERR_PTR(-EINVAL); | 905 | return ERR_PTR(-EINVAL); |
863 | 906 | ||
907 | cn = nft_compat_pernet(ctx->net); | ||
864 | /* Re-use the existing target if it's already loaded. */ | 908 | /* Re-use the existing target if it's already loaded. */ |
865 | list_for_each_entry(nft_target, &nft_target_list, head) { | 909 | list_for_each_entry(nft_target, &cn->nft_target_list, head) { |
866 | struct xt_target *target = nft_target->ops.data; | 910 | struct xt_target *target = nft_target->ops.data; |
867 | 911 | ||
868 | if (!target->target) | 912 | if (!target->target) |
@@ -893,11 +937,12 @@ nft_target_select_ops(const struct nft_ctx *ctx, | |||
893 | goto err; | 937 | goto err; |
894 | } | 938 | } |
895 | 939 | ||
896 | nft_target->refcnt = 0; | 940 | refcount_set(&nft_target->refcnt, 0); |
897 | nft_target->ops.type = &nft_target_type; | 941 | nft_target->ops.type = &nft_target_type; |
898 | nft_target->ops.size = NFT_EXPR_SIZE(XT_ALIGN(target->targetsize)); | 942 | nft_target->ops.size = NFT_EXPR_SIZE(XT_ALIGN(target->targetsize)); |
899 | nft_target->ops.init = nft_target_init; | 943 | nft_target->ops.init = nft_target_init; |
900 | nft_target->ops.destroy = nft_target_destroy; | 944 | nft_target->ops.destroy = nft_target_destroy; |
945 | nft_target->ops.deactivate = nft_compat_deactivate; | ||
901 | nft_target->ops.dump = nft_target_dump; | 946 | nft_target->ops.dump = nft_target_dump; |
902 | nft_target->ops.validate = nft_target_validate; | 947 | nft_target->ops.validate = nft_target_validate; |
903 | nft_target->ops.data = target; | 948 | nft_target->ops.data = target; |
@@ -907,7 +952,8 @@ nft_target_select_ops(const struct nft_ctx *ctx, | |||
907 | else | 952 | else |
908 | nft_target->ops.eval = nft_target_eval_xt; | 953 | nft_target->ops.eval = nft_target_eval_xt; |
909 | 954 | ||
910 | list_add(&nft_target->head, &nft_target_list); | 955 | nft_target->listcnt = 0; |
956 | list_add(&nft_target->head, &cn->nft_target_list); | ||
911 | 957 | ||
912 | return &nft_target->ops; | 958 | return &nft_target->ops; |
913 | err: | 959 | err: |
@@ -923,13 +969,74 @@ static struct nft_expr_type nft_target_type __read_mostly = { | |||
923 | .owner = THIS_MODULE, | 969 | .owner = THIS_MODULE, |
924 | }; | 970 | }; |
925 | 971 | ||
972 | static int __net_init nft_compat_init_net(struct net *net) | ||
973 | { | ||
974 | struct nft_compat_net *cn = nft_compat_pernet(net); | ||
975 | |||
976 | INIT_LIST_HEAD(&cn->nft_target_list); | ||
977 | INIT_LIST_HEAD(&cn->nft_match_list); | ||
978 | |||
979 | return 0; | ||
980 | } | ||
981 | |||
982 | static void __net_exit nft_compat_exit_net(struct net *net) | ||
983 | { | ||
984 | struct nft_compat_net *cn = nft_compat_pernet(net); | ||
985 | struct nft_xt *xt, *next; | ||
986 | |||
987 | if (list_empty(&cn->nft_match_list) && | ||
988 | list_empty(&cn->nft_target_list)) | ||
989 | return; | ||
990 | |||
991 | /* If there was an error that caused nft_xt expr to not be initialized | ||
992 | * fully and noone else requested the same expression later, the lists | ||
993 | * contain 0-refcount entries that still hold module reference. | ||
994 | * | ||
995 | * Clean them here. | ||
996 | */ | ||
997 | mutex_lock(&net->nft.commit_mutex); | ||
998 | list_for_each_entry_safe(xt, next, &cn->nft_target_list, head) { | ||
999 | struct xt_target *target = xt->ops.data; | ||
1000 | |||
1001 | list_del_init(&xt->head); | ||
1002 | |||
1003 | if (refcount_read(&xt->refcnt)) | ||
1004 | continue; | ||
1005 | module_put(target->me); | ||
1006 | kfree(xt); | ||
1007 | } | ||
1008 | |||
1009 | list_for_each_entry_safe(xt, next, &cn->nft_match_list, head) { | ||
1010 | struct xt_match *match = xt->ops.data; | ||
1011 | |||
1012 | list_del_init(&xt->head); | ||
1013 | |||
1014 | if (refcount_read(&xt->refcnt)) | ||
1015 | continue; | ||
1016 | module_put(match->me); | ||
1017 | kfree(xt); | ||
1018 | } | ||
1019 | mutex_unlock(&net->nft.commit_mutex); | ||
1020 | } | ||
1021 | |||
1022 | static struct pernet_operations nft_compat_net_ops = { | ||
1023 | .init = nft_compat_init_net, | ||
1024 | .exit = nft_compat_exit_net, | ||
1025 | .id = &nft_compat_net_id, | ||
1026 | .size = sizeof(struct nft_compat_net), | ||
1027 | }; | ||
1028 | |||
926 | static int __init nft_compat_module_init(void) | 1029 | static int __init nft_compat_module_init(void) |
927 | { | 1030 | { |
928 | int ret; | 1031 | int ret; |
929 | 1032 | ||
1033 | ret = register_pernet_subsys(&nft_compat_net_ops); | ||
1034 | if (ret < 0) | ||
1035 | goto err_target; | ||
1036 | |||
930 | ret = nft_register_expr(&nft_match_type); | 1037 | ret = nft_register_expr(&nft_match_type); |
931 | if (ret < 0) | 1038 | if (ret < 0) |
932 | return ret; | 1039 | goto err_pernet; |
933 | 1040 | ||
934 | ret = nft_register_expr(&nft_target_type); | 1041 | ret = nft_register_expr(&nft_target_type); |
935 | if (ret < 0) | 1042 | if (ret < 0) |
@@ -942,45 +1049,21 @@ static int __init nft_compat_module_init(void) | |||
942 | } | 1049 | } |
943 | 1050 | ||
944 | return ret; | 1051 | return ret; |
945 | |||
946 | err_target: | 1052 | err_target: |
947 | nft_unregister_expr(&nft_target_type); | 1053 | nft_unregister_expr(&nft_target_type); |
948 | err_match: | 1054 | err_match: |
949 | nft_unregister_expr(&nft_match_type); | 1055 | nft_unregister_expr(&nft_match_type); |
1056 | err_pernet: | ||
1057 | unregister_pernet_subsys(&nft_compat_net_ops); | ||
950 | return ret; | 1058 | return ret; |
951 | } | 1059 | } |
952 | 1060 | ||
953 | static void __exit nft_compat_module_exit(void) | 1061 | static void __exit nft_compat_module_exit(void) |
954 | { | 1062 | { |
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); | 1063 | nfnetlink_subsys_unregister(&nfnl_compat_subsys); |
982 | nft_unregister_expr(&nft_target_type); | 1064 | nft_unregister_expr(&nft_target_type); |
983 | nft_unregister_expr(&nft_match_type); | 1065 | nft_unregister_expr(&nft_match_type); |
1066 | unregister_pernet_subsys(&nft_compat_net_ops); | ||
984 | } | 1067 | } |
985 | 1068 | ||
986 | MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_NFT_COMPAT); | 1069 | 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_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/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/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/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/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/sched/cls_flower.c b/net/sched/cls_flower.c index f6aa57fbbbaf..12ca9d13db83 100644 --- a/net/sched/cls_flower.c +++ b/net/sched/cls_flower.c | |||
@@ -1371,7 +1371,7 @@ static int fl_change(struct net *net, struct sk_buff *in_skb, | |||
1371 | if (!tc_skip_hw(fnew->flags)) { | 1371 | if (!tc_skip_hw(fnew->flags)) { |
1372 | err = fl_hw_replace_filter(tp, fnew, extack); | 1372 | err = fl_hw_replace_filter(tp, fnew, extack); |
1373 | if (err) | 1373 | if (err) |
1374 | goto errout_mask; | 1374 | goto errout_mask_ht; |
1375 | } | 1375 | } |
1376 | 1376 | ||
1377 | if (!tc_in_hw(fnew->flags)) | 1377 | if (!tc_in_hw(fnew->flags)) |
@@ -1401,6 +1401,10 @@ static int fl_change(struct net *net, struct sk_buff *in_skb, | |||
1401 | kfree(mask); | 1401 | kfree(mask); |
1402 | return 0; | 1402 | return 0; |
1403 | 1403 | ||
1404 | errout_mask_ht: | ||
1405 | rhashtable_remove_fast(&fnew->mask->ht, &fnew->ht_node, | ||
1406 | fnew->mask->filter_ht_params); | ||
1407 | |||
1404 | errout_mask: | 1408 | errout_mask: |
1405 | fl_mask_put(head, fnew->mask, false); | 1409 | fl_mask_put(head, fnew->mask, false); |
1406 | 1410 | ||
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 80e0ae5534ec..f24633114dfd 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. |
@@ -147,6 +160,13 @@ static int sctp_stream_alloc_out(struct sctp_stream *stream, __u16 outcnt, | |||
147 | 160 | ||
148 | if (stream->out) { | 161 | if (stream->out) { |
149 | fa_copy(out, stream->out, 0, min(outcnt, stream->outcnt)); | 162 | fa_copy(out, stream->out, 0, min(outcnt, stream->outcnt)); |
163 | if (stream->out_curr) { | ||
164 | size_t index = fa_index(stream->out, stream->out_curr, | ||
165 | stream->outcnt); | ||
166 | |||
167 | BUG_ON(index == stream->outcnt); | ||
168 | stream->out_curr = flex_array_get(out, index); | ||
169 | } | ||
150 | fa_free(stream->out); | 170 | fa_free(stream->out); |
151 | } | 171 | } |
152 | 172 | ||
diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c index c4e56602e0c6..b04a813fc865 100644 --- a/net/smc/af_smc.c +++ b/net/smc/af_smc.c | |||
@@ -1505,6 +1505,11 @@ static int smc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, | |||
1505 | 1505 | ||
1506 | smc = smc_sk(sk); | 1506 | smc = smc_sk(sk); |
1507 | 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 | } | ||
1508 | if ((sk->sk_state == SMC_INIT) || | 1513 | if ((sk->sk_state == SMC_INIT) || |
1509 | (sk->sk_state == SMC_LISTEN) || | 1514 | (sk->sk_state == SMC_LISTEN) || |
1510 | (sk->sk_state == SMC_CLOSED)) | 1515 | (sk->sk_state == SMC_CLOSED)) |
@@ -1840,7 +1845,11 @@ static ssize_t smc_splice_read(struct socket *sock, loff_t *ppos, | |||
1840 | 1845 | ||
1841 | smc = smc_sk(sk); | 1846 | smc = smc_sk(sk); |
1842 | lock_sock(sk); | 1847 | lock_sock(sk); |
1843 | 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 | } | ||
1844 | if (sk->sk_state == SMC_INIT || | 1853 | if (sk->sk_state == SMC_INIT || |
1845 | sk->sk_state == SMC_LISTEN || | 1854 | sk->sk_state == SMC_LISTEN || |
1846 | sk->sk_state == SMC_CLOSED) | 1855 | sk->sk_state == SMC_CLOSED) |
diff --git a/net/smc/smc_cdc.c b/net/smc/smc_cdc.c index db83332ac1c8..a712c9f8699b 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 | ||
@@ -107,10 +103,10 @@ int smc_cdc_msg_send(struct smc_connection *conn, | |||
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, |
109 | &conn->local_tx_ctrl, conn); | 105 | &conn->local_tx_ctrl, conn); |
106 | smc_curs_copy(&cfed, &((struct smc_host_cdc_msg *)wr_buf)->cons, conn); | ||
110 | rc = smc_wr_tx_send(link, (struct smc_wr_tx_pend_priv *)pend); | 107 | rc = smc_wr_tx_send(link, (struct smc_wr_tx_pend_priv *)pend); |
111 | if (!rc) | 108 | if (!rc) |
112 | smc_curs_copy(&conn->rx_curs_confirmed, | 109 | smc_curs_copy(&conn->rx_curs_confirmed, &cfed, conn); |
113 | &conn->local_tx_ctrl.cons, conn); | ||
114 | 110 | ||
115 | return rc; | 111 | return rc; |
116 | } | 112 | } |
@@ -121,11 +117,14 @@ static int smcr_cdc_get_slot_and_msg_send(struct smc_connection *conn) | |||
121 | struct smc_wr_buf *wr_buf; | 117 | struct smc_wr_buf *wr_buf; |
122 | int rc; | 118 | int rc; |
123 | 119 | ||
124 | rc = smc_cdc_get_free_slot(conn, &wr_buf, &pend); | 120 | rc = smc_cdc_get_free_slot(conn, &wr_buf, NULL, &pend); |
125 | if (rc) | 121 | if (rc) |
126 | return rc; | 122 | return rc; |
127 | 123 | ||
128 | return smc_cdc_msg_send(conn, wr_buf, pend); | 124 | spin_lock_bh(&conn->send_lock); |
125 | rc = smc_cdc_msg_send(conn, wr_buf, pend); | ||
126 | spin_unlock_bh(&conn->send_lock); | ||
127 | return rc; | ||
129 | } | 128 | } |
130 | 129 | ||
131 | int smc_cdc_get_slot_and_msg_send(struct smc_connection *conn) | 130 | 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..271e2524dc8f 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,6 +187,28 @@ 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, |
190 | struct smc_connection *conn) | 214 | struct smc_connection *conn) |
@@ -270,10 +294,16 @@ static inline void smc_cdc_msg_to_host(struct smc_host_cdc_msg *local, | |||
270 | smcr_cdc_msg_to_host(local, peer, conn); | 294 | smcr_cdc_msg_to_host(local, peer, conn); |
271 | } | 295 | } |
272 | 296 | ||
273 | struct smc_cdc_tx_pend; | 297 | struct smc_cdc_tx_pend { |
298 | struct smc_connection *conn; /* socket connection */ | ||
299 | union smc_host_cursor cursor; /* tx sndbuf cursor sent */ | ||
300 | union smc_host_cursor p_cursor; /* rx RMBE cursor produced */ | ||
301 | u16 ctrl_seq; /* conn. tx sequence # */ | ||
302 | }; | ||
274 | 303 | ||
275 | int smc_cdc_get_free_slot(struct smc_connection *conn, | 304 | int smc_cdc_get_free_slot(struct smc_connection *conn, |
276 | struct smc_wr_buf **wr_buf, | 305 | struct smc_wr_buf **wr_buf, |
306 | struct smc_rdma_wr **wr_rdma_buf, | ||
277 | struct smc_cdc_tx_pend **pend); | 307 | struct smc_cdc_tx_pend **pend); |
278 | void smc_cdc_tx_dismiss_slots(struct smc_connection *conn); | 308 | 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, | 309 | 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/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/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/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/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.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/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/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 934492bad8e0..ba0a4048c846 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, |
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 277c1c46fe94..c6d26afcf89d 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 | ||