mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 10:41:38 -04:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Pull networking fixes from David Miller:
1) When we run a tap on netlink sockets, we have to copy mmap'd SKBs
instead of cloning them. From Daniel Borkmann.
2) When converting classical BPF into eBPF, fix the setting of the
source reg to BPF_REG_X. From Tycho Andersen.
3) Fix igmpv3/mldv2 report parsing in the bridge multicast code, from
Linus Lussing.
4) Fix dst refcounting for ipv6 tunnels, from Martin KaFai Lau.
5) Set NLM_F_REPLACE flag properly when replacing ipv6 routes, from
Roopa Prabhu.
6) Add some new cxgb4 PCI device IDs, from Hariprasad Shenai.
7) Fix headroom tests and SKB leaks in ipv6 fragmentation code, from
Florian Westphal.
8) Check DMA mapping errors in bna driver, from Ivan Vecera.
9) Several 8139cp bug fixes (dev_kfree_skb_any in interrupt context,
misclearing of interrupt status in TX timeout handler, etc.) from
David Woodhouse.
10) In tipc, reset SKB header pointer after skb_linearize(), from Erik
Hugne.
11) Fix autobind races et al. in netlink code, from Herbert Xu with
help from Tejun Heo and others.
12) Missing SET_NETDEV_DEV in sunvnet driver, from Sowmini Varadhan.
13) Fix various races in timewait timer and reqsk_queue_hadh_req, from
Eric Dumazet.
14) Fix array overruns in mac80211, from Johannes Berg and Dan
Carpenter.
15) Fix data race in rhashtable_rehash_one(), from Dmitriy Vyukov.
16) Fix race between poll_one_napi and napi_disable, from Neil Horman.
17) Fix byte order in geneve tunnel port config, from John W Linville.
18) Fix handling of ARP replies over lightweight tunnels, from Jiri
Benc.
19) We can loop when fib rule dumps cross multiple SKBs, fix from Wilson
Kok and Roopa Prabhu.
20) Several reference count handling bug fixes in the PHY/MDIO layer
from Russel King.
21) Fix lockdep splat in ppp_dev_uninit(), from Guillaume Nault.
22) Fix crash in icmp_route_lookup(), from David Ahern.
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net: (116 commits)
net: Fix panic in icmp_route_lookup
net: update docbook comment for __mdiobus_register()
ppp: fix lockdep splat in ppp_dev_uninit()
net: via/Kconfig: GENERIC_PCI_IOMAP required if PCI not selected
phy: marvell: add link partner advertised modes
net: fix net_device refcounting
phy: add phy_device_remove()
phy: fixed-phy: properly validate phy in fixed_phy_update_state()
net: fix phy refcounting in a bunch of drivers
of_mdio: fix MDIO phy device refcounting
phy: add proper phy struct device refcounting
phy: fix mdiobus module safety
net: dsa: fix of_mdio_find_bus() device refcount leak
phy: fix of_mdio_find_bus() device refcount leak
ip6_tunnel: Reduce log level in ip6_tnl_err() to debug
ip6_gre: Reduce log level in ip6gre_err() to debug
fib_rules: fix fib rule dumps across multiple skbs
bnx2x: byte swap rss_key to comply to Toeplitz specs
net: revert "net_sched: move tp->root allocation into fw_init()"
lwtunnel: remove source and destination UDP port config option
...
This commit is contained in:
commit
518a7cb698
117 changed files with 1697 additions and 639 deletions
|
|
@ -317,6 +317,9 @@ static int clip_constructor(struct neighbour *neigh)
|
|||
|
||||
static int clip_encap(struct atm_vcc *vcc, int mode)
|
||||
{
|
||||
if (!CLIP_VCC(vcc))
|
||||
return -EBADFD;
|
||||
|
||||
CLIP_VCC(vcc)->encap = mode;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2311,12 +2311,6 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
|
|||
if (!conn)
|
||||
return 1;
|
||||
|
||||
chan = conn->smp;
|
||||
if (!chan) {
|
||||
BT_ERR("SMP security requested but not available");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!hci_dev_test_flag(hcon->hdev, HCI_LE_ENABLED))
|
||||
return 1;
|
||||
|
||||
|
|
@ -2330,6 +2324,12 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
|
|||
if (smp_ltk_encrypt(conn, hcon->pending_sec_level))
|
||||
return 0;
|
||||
|
||||
chan = conn->smp;
|
||||
if (!chan) {
|
||||
BT_ERR("SMP security requested but not available");
|
||||
return 1;
|
||||
}
|
||||
|
||||
l2cap_chan_lock(chan);
|
||||
|
||||
/* If SMP is already in progress ignore this request */
|
||||
|
|
|
|||
|
|
@ -1006,7 +1006,7 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge *br,
|
|||
|
||||
ih = igmpv3_report_hdr(skb);
|
||||
num = ntohs(ih->ngrec);
|
||||
len = sizeof(*ih);
|
||||
len = skb_transport_offset(skb) + sizeof(*ih);
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
len += sizeof(*grec);
|
||||
|
|
@ -1067,7 +1067,7 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
|
|||
|
||||
icmp6h = icmp6_hdr(skb);
|
||||
num = ntohs(icmp6h->icmp6_dataun.un_data16[1]);
|
||||
len = sizeof(*icmp6h);
|
||||
len = skb_transport_offset(skb) + sizeof(*icmp6h);
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
__be16 *nsrcs, _nsrcs;
|
||||
|
|
|
|||
|
|
@ -4713,6 +4713,8 @@ void napi_disable(struct napi_struct *n)
|
|||
|
||||
while (test_and_set_bit(NAPI_STATE_SCHED, &n->state))
|
||||
msleep(1);
|
||||
while (test_and_set_bit(NAPI_STATE_NPSVC, &n->state))
|
||||
msleep(1);
|
||||
|
||||
hrtimer_cancel(&n->timer);
|
||||
|
||||
|
|
|
|||
|
|
@ -631,15 +631,17 @@ static int dump_rules(struct sk_buff *skb, struct netlink_callback *cb,
|
|||
{
|
||||
int idx = 0;
|
||||
struct fib_rule *rule;
|
||||
int err = 0;
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(rule, &ops->rules_list, list) {
|
||||
if (idx < cb->args[1])
|
||||
goto skip;
|
||||
|
||||
if (fib_nl_fill_rule(skb, rule, NETLINK_CB(cb->skb).portid,
|
||||
cb->nlh->nlmsg_seq, RTM_NEWRULE,
|
||||
NLM_F_MULTI, ops) < 0)
|
||||
err = fib_nl_fill_rule(skb, rule, NETLINK_CB(cb->skb).portid,
|
||||
cb->nlh->nlmsg_seq, RTM_NEWRULE,
|
||||
NLM_F_MULTI, ops);
|
||||
if (err)
|
||||
break;
|
||||
skip:
|
||||
idx++;
|
||||
|
|
@ -648,7 +650,7 @@ skip:
|
|||
cb->args[1] = idx;
|
||||
rules_ops_put(ops);
|
||||
|
||||
return skb->len;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int fib_nl_dumprule(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
|
|
@ -664,7 +666,9 @@ static int fib_nl_dumprule(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
if (ops == NULL)
|
||||
return -EAFNOSUPPORT;
|
||||
|
||||
return dump_rules(skb, cb, ops);
|
||||
dump_rules(skb, cb, ops);
|
||||
|
||||
return skb->len;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
|
|
|
|||
|
|
@ -478,9 +478,9 @@ do_pass:
|
|||
bpf_src = BPF_X;
|
||||
} else {
|
||||
insn->dst_reg = BPF_REG_A;
|
||||
insn->src_reg = BPF_REG_X;
|
||||
insn->imm = fp->k;
|
||||
bpf_src = BPF_SRC(fp->code);
|
||||
insn->src_reg = bpf_src == BPF_X ? BPF_REG_X : 0;
|
||||
}
|
||||
|
||||
/* Common case where 'jump_false' is next insn. */
|
||||
|
|
|
|||
|
|
@ -1481,6 +1481,15 @@ static int of_dev_node_match(struct device *dev, const void *data)
|
|||
return ret == 0 ? dev->of_node == data : ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* of_find_net_device_by_node - lookup the net device for the device node
|
||||
* @np: OF device node
|
||||
*
|
||||
* Looks up the net_device structure corresponding with the device node.
|
||||
* If successful, returns a pointer to the net_device with the embedded
|
||||
* struct device refcount incremented by one, or NULL on failure. The
|
||||
* refcount must be dropped when done with the net_device.
|
||||
*/
|
||||
struct net_device *of_find_net_device_by_node(struct device_node *np)
|
||||
{
|
||||
struct device *dev;
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ static void queue_process(struct work_struct *work)
|
|||
*/
|
||||
static int poll_one_napi(struct napi_struct *napi, int budget)
|
||||
{
|
||||
int work;
|
||||
int work = 0;
|
||||
|
||||
/* net_rx_action's ->poll() invocations and our's are
|
||||
* synchronized by this test which is only made while
|
||||
|
|
@ -151,7 +151,12 @@ static int poll_one_napi(struct napi_struct *napi, int budget)
|
|||
if (!test_bit(NAPI_STATE_SCHED, &napi->state))
|
||||
return budget;
|
||||
|
||||
set_bit(NAPI_STATE_NPSVC, &napi->state);
|
||||
/* If we set this bit but see that it has already been set,
|
||||
* that indicates that napi has been disabled and we need
|
||||
* to abort this operation
|
||||
*/
|
||||
if (test_and_set_bit(NAPI_STATE_NPSVC, &napi->state))
|
||||
goto out;
|
||||
|
||||
work = napi->poll(napi, budget);
|
||||
WARN_ONCE(work > budget, "%pF exceeded budget in poll\n", napi->poll);
|
||||
|
|
@ -159,6 +164,7 @@ static int poll_one_napi(struct napi_struct *napi, int budget)
|
|||
|
||||
clear_bit(NAPI_STATE_NPSVC, &napi->state);
|
||||
|
||||
out:
|
||||
return budget - work;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3047,6 +3047,7 @@ static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
u32 portid = NETLINK_CB(cb->skb).portid;
|
||||
u32 seq = cb->nlh->nlmsg_seq;
|
||||
u32 filter_mask = 0;
|
||||
int err;
|
||||
|
||||
if (nlmsg_len(cb->nlh) > sizeof(struct ifinfomsg)) {
|
||||
struct nlattr *extfilt;
|
||||
|
|
@ -3067,20 +3068,25 @@ static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
struct net_device *br_dev = netdev_master_upper_dev_get(dev);
|
||||
|
||||
if (br_dev && br_dev->netdev_ops->ndo_bridge_getlink) {
|
||||
if (idx >= cb->args[0] &&
|
||||
br_dev->netdev_ops->ndo_bridge_getlink(
|
||||
skb, portid, seq, dev, filter_mask,
|
||||
NLM_F_MULTI) < 0)
|
||||
break;
|
||||
if (idx >= cb->args[0]) {
|
||||
err = br_dev->netdev_ops->ndo_bridge_getlink(
|
||||
skb, portid, seq, dev,
|
||||
filter_mask, NLM_F_MULTI);
|
||||
if (err < 0 && err != -EOPNOTSUPP)
|
||||
break;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
|
||||
if (ops->ndo_bridge_getlink) {
|
||||
if (idx >= cb->args[0] &&
|
||||
ops->ndo_bridge_getlink(skb, portid, seq, dev,
|
||||
filter_mask,
|
||||
NLM_F_MULTI) < 0)
|
||||
break;
|
||||
if (idx >= cb->args[0]) {
|
||||
err = ops->ndo_bridge_getlink(skb, portid,
|
||||
seq, dev,
|
||||
filter_mask,
|
||||
NLM_F_MULTI);
|
||||
if (err < 0 && err != -EOPNOTSUPP)
|
||||
break;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2740,10 +2740,8 @@ static void req_prot_cleanup(struct request_sock_ops *rsk_prot)
|
|||
return;
|
||||
kfree(rsk_prot->slab_name);
|
||||
rsk_prot->slab_name = NULL;
|
||||
if (rsk_prot->slab) {
|
||||
kmem_cache_destroy(rsk_prot->slab);
|
||||
rsk_prot->slab = NULL;
|
||||
}
|
||||
kmem_cache_destroy(rsk_prot->slab);
|
||||
rsk_prot->slab = NULL;
|
||||
}
|
||||
|
||||
static int req_prot_init(const struct proto *prot)
|
||||
|
|
@ -2828,10 +2826,8 @@ void proto_unregister(struct proto *prot)
|
|||
list_del(&prot->node);
|
||||
mutex_unlock(&proto_list_mutex);
|
||||
|
||||
if (prot->slab != NULL) {
|
||||
kmem_cache_destroy(prot->slab);
|
||||
prot->slab = NULL;
|
||||
}
|
||||
kmem_cache_destroy(prot->slab);
|
||||
prot->slab = NULL;
|
||||
|
||||
req_prot_cleanup(prot->rsk_prot);
|
||||
|
||||
|
|
|
|||
|
|
@ -398,12 +398,8 @@ out_err:
|
|||
|
||||
void dccp_ackvec_exit(void)
|
||||
{
|
||||
if (dccp_ackvec_slab != NULL) {
|
||||
kmem_cache_destroy(dccp_ackvec_slab);
|
||||
dccp_ackvec_slab = NULL;
|
||||
}
|
||||
if (dccp_ackvec_record_slab != NULL) {
|
||||
kmem_cache_destroy(dccp_ackvec_record_slab);
|
||||
dccp_ackvec_record_slab = NULL;
|
||||
}
|
||||
kmem_cache_destroy(dccp_ackvec_slab);
|
||||
dccp_ackvec_slab = NULL;
|
||||
kmem_cache_destroy(dccp_ackvec_record_slab);
|
||||
dccp_ackvec_record_slab = NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,8 +95,7 @@ static struct kmem_cache *ccid_kmem_cache_create(int obj_size, char *slab_name_f
|
|||
|
||||
static void ccid_kmem_cache_destroy(struct kmem_cache *slab)
|
||||
{
|
||||
if (slab != NULL)
|
||||
kmem_cache_destroy(slab);
|
||||
kmem_cache_destroy(slab);
|
||||
}
|
||||
|
||||
static int __init ccid_activate(struct ccid_operations *ccid_ops)
|
||||
|
|
|
|||
|
|
@ -48,8 +48,6 @@ void dccp_time_wait(struct sock *sk, int state, int timeo)
|
|||
tw->tw_ipv6only = sk->sk_ipv6only;
|
||||
}
|
||||
#endif
|
||||
/* Linkage updates. */
|
||||
__inet_twsk_hashdance(tw, sk, &dccp_hashinfo);
|
||||
|
||||
/* Get the TIME_WAIT timeout firing. */
|
||||
if (timeo < rto)
|
||||
|
|
@ -60,6 +58,8 @@ void dccp_time_wait(struct sock *sk, int state, int timeo)
|
|||
timeo = DCCP_TIMEWAIT_LEN;
|
||||
|
||||
inet_twsk_schedule(tw, timeo);
|
||||
/* Linkage updates. */
|
||||
__inet_twsk_hashdance(tw, sk, &dccp_hashinfo);
|
||||
inet_twsk_put(tw);
|
||||
} else {
|
||||
/* Sorry, if we're out of memory, just CLOSE this
|
||||
|
|
|
|||
|
|
@ -634,6 +634,10 @@ static void dsa_of_free_platform_data(struct dsa_platform_data *pd)
|
|||
port_index++;
|
||||
}
|
||||
kfree(pd->chip[i].rtable);
|
||||
|
||||
/* Drop our reference to the MDIO bus device */
|
||||
if (pd->chip[i].host_dev)
|
||||
put_device(pd->chip[i].host_dev);
|
||||
}
|
||||
kfree(pd->chip);
|
||||
}
|
||||
|
|
@ -661,16 +665,22 @@ static int dsa_of_probe(struct device *dev)
|
|||
return -EPROBE_DEFER;
|
||||
|
||||
ethernet = of_parse_phandle(np, "dsa,ethernet", 0);
|
||||
if (!ethernet)
|
||||
return -EINVAL;
|
||||
if (!ethernet) {
|
||||
ret = -EINVAL;
|
||||
goto out_put_mdio;
|
||||
}
|
||||
|
||||
ethernet_dev = of_find_net_device_by_node(ethernet);
|
||||
if (!ethernet_dev)
|
||||
return -EPROBE_DEFER;
|
||||
if (!ethernet_dev) {
|
||||
ret = -EPROBE_DEFER;
|
||||
goto out_put_mdio;
|
||||
}
|
||||
|
||||
pd = kzalloc(sizeof(*pd), GFP_KERNEL);
|
||||
if (!pd)
|
||||
return -ENOMEM;
|
||||
if (!pd) {
|
||||
ret = -ENOMEM;
|
||||
goto out_put_ethernet;
|
||||
}
|
||||
|
||||
dev->platform_data = pd;
|
||||
pd->of_netdev = ethernet_dev;
|
||||
|
|
@ -691,7 +701,9 @@ static int dsa_of_probe(struct device *dev)
|
|||
cd = &pd->chip[chip_index];
|
||||
|
||||
cd->of_node = child;
|
||||
cd->host_dev = &mdio_bus->dev;
|
||||
|
||||
/* When assigning the host device, increment its refcount */
|
||||
cd->host_dev = get_device(&mdio_bus->dev);
|
||||
|
||||
sw_addr = of_get_property(child, "reg", NULL);
|
||||
if (!sw_addr)
|
||||
|
|
@ -711,6 +723,12 @@ static int dsa_of_probe(struct device *dev)
|
|||
ret = -EPROBE_DEFER;
|
||||
goto out_free_chip;
|
||||
}
|
||||
|
||||
/* Drop the mdio_bus device ref, replacing the host
|
||||
* device with the mdio_bus_switch device, keeping
|
||||
* the refcount from of_mdio_find_bus() above.
|
||||
*/
|
||||
put_device(cd->host_dev);
|
||||
cd->host_dev = &mdio_bus_switch->dev;
|
||||
}
|
||||
|
||||
|
|
@ -744,6 +762,10 @@ static int dsa_of_probe(struct device *dev)
|
|||
}
|
||||
}
|
||||
|
||||
/* The individual chips hold their own refcount on the mdio bus,
|
||||
* so drop ours */
|
||||
put_device(&mdio_bus->dev);
|
||||
|
||||
return 0;
|
||||
|
||||
out_free_chip:
|
||||
|
|
@ -751,6 +773,10 @@ out_free_chip:
|
|||
out_free:
|
||||
kfree(pd);
|
||||
dev->platform_data = NULL;
|
||||
out_put_ethernet:
|
||||
put_device(ðernet_dev->dev);
|
||||
out_put_mdio:
|
||||
put_device(&mdio_bus->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -762,6 +788,7 @@ static void dsa_of_remove(struct device *dev)
|
|||
return;
|
||||
|
||||
dsa_of_free_platform_data(pd);
|
||||
put_device(&pd->of_netdev->dev);
|
||||
kfree(pd);
|
||||
}
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ static int trailer_rcv(struct sk_buff *skb, struct net_device *dev,
|
|||
|
||||
trailer = skb_tail_pointer(skb) - 4;
|
||||
if (trailer[0] != 0x80 || (trailer[1] & 0xf8) != 0x00 ||
|
||||
(trailer[3] & 0xef) != 0x00 || trailer[3] != 0x00)
|
||||
(trailer[2] & 0xef) != 0x00 || trailer[3] != 0x00)
|
||||
goto out_drop;
|
||||
|
||||
source_port = trailer[1] & 7;
|
||||
|
|
|
|||
|
|
@ -113,6 +113,8 @@
|
|||
#include <net/arp.h>
|
||||
#include <net/ax25.h>
|
||||
#include <net/netrom.h>
|
||||
#include <net/dst_metadata.h>
|
||||
#include <net/ip_tunnels.h>
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
|
|
@ -296,7 +298,8 @@ static void arp_send_dst(int type, int ptype, __be32 dest_ip,
|
|||
struct net_device *dev, __be32 src_ip,
|
||||
const unsigned char *dest_hw,
|
||||
const unsigned char *src_hw,
|
||||
const unsigned char *target_hw, struct sk_buff *oskb)
|
||||
const unsigned char *target_hw,
|
||||
struct dst_entry *dst)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
|
|
@ -309,9 +312,7 @@ static void arp_send_dst(int type, int ptype, __be32 dest_ip,
|
|||
if (!skb)
|
||||
return;
|
||||
|
||||
if (oskb)
|
||||
skb_dst_copy(skb, oskb);
|
||||
|
||||
skb_dst_set(skb, dst);
|
||||
arp_xmit(skb);
|
||||
}
|
||||
|
||||
|
|
@ -333,6 +334,7 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
|
|||
__be32 target = *(__be32 *)neigh->primary_key;
|
||||
int probes = atomic_read(&neigh->probes);
|
||||
struct in_device *in_dev;
|
||||
struct dst_entry *dst = NULL;
|
||||
|
||||
rcu_read_lock();
|
||||
in_dev = __in_dev_get_rcu(dev);
|
||||
|
|
@ -381,9 +383,10 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
|
|||
}
|
||||
}
|
||||
|
||||
if (skb && !(dev->priv_flags & IFF_XMIT_DST_RELEASE))
|
||||
dst = dst_clone(skb_dst(skb));
|
||||
arp_send_dst(ARPOP_REQUEST, ETH_P_ARP, target, dev, saddr,
|
||||
dst_hw, dev->dev_addr, NULL,
|
||||
dev->priv_flags & IFF_XMIT_DST_RELEASE ? NULL : skb);
|
||||
dst_hw, dev->dev_addr, NULL, dst);
|
||||
}
|
||||
|
||||
static int arp_ignore(struct in_device *in_dev, __be32 sip, __be32 tip)
|
||||
|
|
@ -649,6 +652,7 @@ static int arp_process(struct sock *sk, struct sk_buff *skb)
|
|||
int addr_type;
|
||||
struct neighbour *n;
|
||||
struct net *net = dev_net(dev);
|
||||
struct dst_entry *reply_dst = NULL;
|
||||
bool is_garp = false;
|
||||
|
||||
/* arp_rcv below verifies the ARP header and verifies the device
|
||||
|
|
@ -749,13 +753,18 @@ static int arp_process(struct sock *sk, struct sk_buff *skb)
|
|||
* cache.
|
||||
*/
|
||||
|
||||
if (arp->ar_op == htons(ARPOP_REQUEST) && skb_metadata_dst(skb))
|
||||
reply_dst = (struct dst_entry *)
|
||||
iptunnel_metadata_reply(skb_metadata_dst(skb),
|
||||
GFP_ATOMIC);
|
||||
|
||||
/* Special case: IPv4 duplicate address detection packet (RFC2131) */
|
||||
if (sip == 0) {
|
||||
if (arp->ar_op == htons(ARPOP_REQUEST) &&
|
||||
inet_addr_type_dev_table(net, dev, tip) == RTN_LOCAL &&
|
||||
!arp_ignore(in_dev, sip, tip))
|
||||
arp_send(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha,
|
||||
dev->dev_addr, sha);
|
||||
arp_send_dst(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip,
|
||||
sha, dev->dev_addr, sha, reply_dst);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
@ -774,9 +783,10 @@ static int arp_process(struct sock *sk, struct sk_buff *skb)
|
|||
if (!dont_send) {
|
||||
n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
|
||||
if (n) {
|
||||
arp_send(ARPOP_REPLY, ETH_P_ARP, sip,
|
||||
dev, tip, sha, dev->dev_addr,
|
||||
sha);
|
||||
arp_send_dst(ARPOP_REPLY, ETH_P_ARP,
|
||||
sip, dev, tip, sha,
|
||||
dev->dev_addr, sha,
|
||||
reply_dst);
|
||||
neigh_release(n);
|
||||
}
|
||||
}
|
||||
|
|
@ -794,9 +804,10 @@ static int arp_process(struct sock *sk, struct sk_buff *skb)
|
|||
if (NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED ||
|
||||
skb->pkt_type == PACKET_HOST ||
|
||||
NEIGH_VAR(in_dev->arp_parms, PROXY_DELAY) == 0) {
|
||||
arp_send(ARPOP_REPLY, ETH_P_ARP, sip,
|
||||
dev, tip, sha, dev->dev_addr,
|
||||
sha);
|
||||
arp_send_dst(ARPOP_REPLY, ETH_P_ARP,
|
||||
sip, dev, tip, sha,
|
||||
dev->dev_addr, sha,
|
||||
reply_dst);
|
||||
} else {
|
||||
pneigh_enqueue(&arp_tbl,
|
||||
in_dev->arp_parms, skb);
|
||||
|
|
|
|||
|
|
@ -1426,7 +1426,7 @@ found:
|
|||
nh->nh_flags & RTNH_F_LINKDOWN &&
|
||||
!(fib_flags & FIB_LOOKUP_IGNORE_LINKSTATE))
|
||||
continue;
|
||||
if (!(flp->flowi4_flags & FLOWI_FLAG_VRFSRC)) {
|
||||
if (!(flp->flowi4_flags & FLOWI_FLAG_SKIP_NH_OIF)) {
|
||||
if (flp->flowi4_oif &&
|
||||
flp->flowi4_oif != nh->nh_oif)
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -427,7 +427,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
|
|||
fl4.flowi4_mark = mark;
|
||||
fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos);
|
||||
fl4.flowi4_proto = IPPROTO_ICMP;
|
||||
fl4.flowi4_oif = vrf_master_ifindex(skb->dev) ? : skb->dev->ifindex;
|
||||
fl4.flowi4_oif = vrf_master_ifindex(skb->dev);
|
||||
security_skb_classify_flow(skb, flowi4_to_flowi(&fl4));
|
||||
rt = ip_route_output_key(net, &fl4);
|
||||
if (IS_ERR(rt))
|
||||
|
|
@ -461,7 +461,7 @@ static struct rtable *icmp_route_lookup(struct net *net,
|
|||
fl4->flowi4_proto = IPPROTO_ICMP;
|
||||
fl4->fl4_icmp_type = type;
|
||||
fl4->fl4_icmp_code = code;
|
||||
fl4->flowi4_oif = vrf_master_ifindex(skb_in->dev) ? : skb_in->dev->ifindex;
|
||||
fl4->flowi4_oif = vrf_master_ifindex(skb_in->dev);
|
||||
|
||||
security_skb_classify_flow(skb_in, flowi4_to_flowi(fl4));
|
||||
rt = __ip_route_output_key(net, fl4);
|
||||
|
|
|
|||
|
|
@ -685,20 +685,20 @@ void reqsk_queue_hash_req(struct request_sock_queue *queue,
|
|||
req->num_timeout = 0;
|
||||
req->sk = NULL;
|
||||
|
||||
setup_timer(&req->rsk_timer, reqsk_timer_handler, (unsigned long)req);
|
||||
mod_timer_pinned(&req->rsk_timer, jiffies + timeout);
|
||||
req->rsk_hash = hash;
|
||||
|
||||
/* before letting lookups find us, make sure all req fields
|
||||
* are committed to memory and refcnt initialized.
|
||||
*/
|
||||
smp_wmb();
|
||||
atomic_set(&req->rsk_refcnt, 2);
|
||||
setup_timer(&req->rsk_timer, reqsk_timer_handler, (unsigned long)req);
|
||||
req->rsk_hash = hash;
|
||||
|
||||
spin_lock(&queue->syn_wait_lock);
|
||||
req->dl_next = lopt->syn_table[hash];
|
||||
lopt->syn_table[hash] = req;
|
||||
spin_unlock(&queue->syn_wait_lock);
|
||||
|
||||
mod_timer_pinned(&req->rsk_timer, jiffies + timeout);
|
||||
}
|
||||
EXPORT_SYMBOL(reqsk_queue_hash_req);
|
||||
|
||||
|
|
|
|||
|
|
@ -123,13 +123,15 @@ void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk,
|
|||
/*
|
||||
* Step 2: Hash TW into tcp ehash chain.
|
||||
* Notes :
|
||||
* - tw_refcnt is set to 3 because :
|
||||
* - tw_refcnt is set to 4 because :
|
||||
* - We have one reference from bhash chain.
|
||||
* - We have one reference from ehash chain.
|
||||
* - We have one reference from timer.
|
||||
* - One reference for ourself (our caller will release it).
|
||||
* We can use atomic_set() because prior spin_lock()/spin_unlock()
|
||||
* committed into memory all tw fields.
|
||||
*/
|
||||
atomic_set(&tw->tw_refcnt, 1 + 1 + 1);
|
||||
atomic_set(&tw->tw_refcnt, 4);
|
||||
inet_twsk_add_node_rcu(tw, &ehead->chain);
|
||||
|
||||
/* Step 3: Remove SK from hash chain */
|
||||
|
|
@ -217,7 +219,7 @@ void inet_twsk_deschedule_put(struct inet_timewait_sock *tw)
|
|||
}
|
||||
EXPORT_SYMBOL(inet_twsk_deschedule_put);
|
||||
|
||||
void inet_twsk_schedule(struct inet_timewait_sock *tw, const int timeo)
|
||||
void __inet_twsk_schedule(struct inet_timewait_sock *tw, int timeo, bool rearm)
|
||||
{
|
||||
/* timeout := RTO * 3.5
|
||||
*
|
||||
|
|
@ -245,12 +247,14 @@ void inet_twsk_schedule(struct inet_timewait_sock *tw, const int timeo)
|
|||
*/
|
||||
|
||||
tw->tw_kill = timeo <= 4*HZ;
|
||||
if (!mod_timer_pinned(&tw->tw_timer, jiffies + timeo)) {
|
||||
atomic_inc(&tw->tw_refcnt);
|
||||
if (!rearm) {
|
||||
BUG_ON(mod_timer_pinned(&tw->tw_timer, jiffies + timeo));
|
||||
atomic_inc(&tw->tw_dr->tw_count);
|
||||
} else {
|
||||
mod_timer_pending(&tw->tw_timer, jiffies + timeo);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(inet_twsk_schedule);
|
||||
EXPORT_SYMBOL_GPL(__inet_twsk_schedule);
|
||||
|
||||
void inet_twsk_purge(struct inet_hashinfo *hashinfo,
|
||||
struct inet_timewait_death_row *twdr, int family)
|
||||
|
|
|
|||
|
|
@ -46,12 +46,13 @@
|
|||
#include <net/net_namespace.h>
|
||||
#include <net/netns/generic.h>
|
||||
#include <net/rtnetlink.h>
|
||||
#include <net/dst_metadata.h>
|
||||
|
||||
int iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb,
|
||||
__be32 src, __be32 dst, __u8 proto,
|
||||
__u8 tos, __u8 ttl, __be16 df, bool xnet)
|
||||
{
|
||||
int pkt_len = skb->len;
|
||||
int pkt_len = skb->len - skb_inner_network_offset(skb);
|
||||
struct iphdr *iph;
|
||||
int err;
|
||||
|
||||
|
|
@ -119,6 +120,33 @@ int iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_proto)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(iptunnel_pull_header);
|
||||
|
||||
struct metadata_dst *iptunnel_metadata_reply(struct metadata_dst *md,
|
||||
gfp_t flags)
|
||||
{
|
||||
struct metadata_dst *res;
|
||||
struct ip_tunnel_info *dst, *src;
|
||||
|
||||
if (!md || md->u.tun_info.mode & IP_TUNNEL_INFO_TX)
|
||||
return NULL;
|
||||
|
||||
res = metadata_dst_alloc(0, flags);
|
||||
if (!res)
|
||||
return NULL;
|
||||
|
||||
dst = &res->u.tun_info;
|
||||
src = &md->u.tun_info;
|
||||
dst->key.tun_id = src->key.tun_id;
|
||||
if (src->mode & IP_TUNNEL_INFO_IPV6)
|
||||
memcpy(&dst->key.u.ipv6.dst, &src->key.u.ipv6.src,
|
||||
sizeof(struct in6_addr));
|
||||
else
|
||||
dst->key.u.ipv4.dst = src->key.u.ipv4.src;
|
||||
dst->mode = src->mode | IP_TUNNEL_INFO_TX;
|
||||
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iptunnel_metadata_reply);
|
||||
|
||||
struct sk_buff *iptunnel_handle_offloads(struct sk_buff *skb,
|
||||
bool csum_help,
|
||||
int gso_type_mask)
|
||||
|
|
@ -198,8 +226,6 @@ static const struct nla_policy ip_tun_policy[LWTUNNEL_IP_MAX + 1] = {
|
|||
[LWTUNNEL_IP_SRC] = { .type = NLA_U32 },
|
||||
[LWTUNNEL_IP_TTL] = { .type = NLA_U8 },
|
||||
[LWTUNNEL_IP_TOS] = { .type = NLA_U8 },
|
||||
[LWTUNNEL_IP_SPORT] = { .type = NLA_U16 },
|
||||
[LWTUNNEL_IP_DPORT] = { .type = NLA_U16 },
|
||||
[LWTUNNEL_IP_FLAGS] = { .type = NLA_U16 },
|
||||
};
|
||||
|
||||
|
|
@ -239,12 +265,6 @@ static int ip_tun_build_state(struct net_device *dev, struct nlattr *attr,
|
|||
if (tb[LWTUNNEL_IP_TOS])
|
||||
tun_info->key.tos = nla_get_u8(tb[LWTUNNEL_IP_TOS]);
|
||||
|
||||
if (tb[LWTUNNEL_IP_SPORT])
|
||||
tun_info->key.tp_src = nla_get_be16(tb[LWTUNNEL_IP_SPORT]);
|
||||
|
||||
if (tb[LWTUNNEL_IP_DPORT])
|
||||
tun_info->key.tp_dst = nla_get_be16(tb[LWTUNNEL_IP_DPORT]);
|
||||
|
||||
if (tb[LWTUNNEL_IP_FLAGS])
|
||||
tun_info->key.tun_flags = nla_get_u16(tb[LWTUNNEL_IP_FLAGS]);
|
||||
|
||||
|
|
@ -266,8 +286,6 @@ static int ip_tun_fill_encap_info(struct sk_buff *skb,
|
|||
nla_put_be32(skb, LWTUNNEL_IP_SRC, tun_info->key.u.ipv4.src) ||
|
||||
nla_put_u8(skb, LWTUNNEL_IP_TOS, tun_info->key.tos) ||
|
||||
nla_put_u8(skb, LWTUNNEL_IP_TTL, tun_info->key.ttl) ||
|
||||
nla_put_u16(skb, LWTUNNEL_IP_SPORT, tun_info->key.tp_src) ||
|
||||
nla_put_u16(skb, LWTUNNEL_IP_DPORT, tun_info->key.tp_dst) ||
|
||||
nla_put_u16(skb, LWTUNNEL_IP_FLAGS, tun_info->key.tun_flags))
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -281,8 +299,6 @@ static int ip_tun_encap_nlsize(struct lwtunnel_state *lwtstate)
|
|||
+ nla_total_size(4) /* LWTUNNEL_IP_SRC */
|
||||
+ nla_total_size(1) /* LWTUNNEL_IP_TOS */
|
||||
+ nla_total_size(1) /* LWTUNNEL_IP_TTL */
|
||||
+ nla_total_size(2) /* LWTUNNEL_IP_SPORT */
|
||||
+ nla_total_size(2) /* LWTUNNEL_IP_DPORT */
|
||||
+ nla_total_size(2); /* LWTUNNEL_IP_FLAGS */
|
||||
}
|
||||
|
||||
|
|
@ -305,8 +321,6 @@ static const struct nla_policy ip6_tun_policy[LWTUNNEL_IP6_MAX + 1] = {
|
|||
[LWTUNNEL_IP6_SRC] = { .len = sizeof(struct in6_addr) },
|
||||
[LWTUNNEL_IP6_HOPLIMIT] = { .type = NLA_U8 },
|
||||
[LWTUNNEL_IP6_TC] = { .type = NLA_U8 },
|
||||
[LWTUNNEL_IP6_SPORT] = { .type = NLA_U16 },
|
||||
[LWTUNNEL_IP6_DPORT] = { .type = NLA_U16 },
|
||||
[LWTUNNEL_IP6_FLAGS] = { .type = NLA_U16 },
|
||||
};
|
||||
|
||||
|
|
@ -346,12 +360,6 @@ static int ip6_tun_build_state(struct net_device *dev, struct nlattr *attr,
|
|||
if (tb[LWTUNNEL_IP6_TC])
|
||||
tun_info->key.tos = nla_get_u8(tb[LWTUNNEL_IP6_TC]);
|
||||
|
||||
if (tb[LWTUNNEL_IP6_SPORT])
|
||||
tun_info->key.tp_src = nla_get_be16(tb[LWTUNNEL_IP6_SPORT]);
|
||||
|
||||
if (tb[LWTUNNEL_IP6_DPORT])
|
||||
tun_info->key.tp_dst = nla_get_be16(tb[LWTUNNEL_IP6_DPORT]);
|
||||
|
||||
if (tb[LWTUNNEL_IP6_FLAGS])
|
||||
tun_info->key.tun_flags = nla_get_u16(tb[LWTUNNEL_IP6_FLAGS]);
|
||||
|
||||
|
|
@ -373,8 +381,6 @@ static int ip6_tun_fill_encap_info(struct sk_buff *skb,
|
|||
nla_put_in6_addr(skb, LWTUNNEL_IP6_SRC, &tun_info->key.u.ipv6.src) ||
|
||||
nla_put_u8(skb, LWTUNNEL_IP6_HOPLIMIT, tun_info->key.tos) ||
|
||||
nla_put_u8(skb, LWTUNNEL_IP6_TC, tun_info->key.ttl) ||
|
||||
nla_put_u16(skb, LWTUNNEL_IP6_SPORT, tun_info->key.tp_src) ||
|
||||
nla_put_u16(skb, LWTUNNEL_IP6_DPORT, tun_info->key.tp_dst) ||
|
||||
nla_put_u16(skb, LWTUNNEL_IP6_FLAGS, tun_info->key.tun_flags))
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -388,8 +394,6 @@ static int ip6_tun_encap_nlsize(struct lwtunnel_state *lwtstate)
|
|||
+ nla_total_size(16) /* LWTUNNEL_IP6_SRC */
|
||||
+ nla_total_size(1) /* LWTUNNEL_IP6_HOPLIMIT */
|
||||
+ nla_total_size(1) /* LWTUNNEL_IP6_TC */
|
||||
+ nla_total_size(2) /* LWTUNNEL_IP6_SPORT */
|
||||
+ nla_total_size(2) /* LWTUNNEL_IP6_DPORT */
|
||||
+ nla_total_size(2); /* LWTUNNEL_IP6_FLAGS */
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2045,6 +2045,7 @@ struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *fl4)
|
|||
struct fib_result res;
|
||||
struct rtable *rth;
|
||||
int orig_oif;
|
||||
int err = -ENETUNREACH;
|
||||
|
||||
res.tclassid = 0;
|
||||
res.fi = NULL;
|
||||
|
|
@ -2153,7 +2154,8 @@ struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *fl4)
|
|||
goto make_route;
|
||||
}
|
||||
|
||||
if (fib_lookup(net, fl4, &res, 0)) {
|
||||
err = fib_lookup(net, fl4, &res, 0);
|
||||
if (err) {
|
||||
res.fi = NULL;
|
||||
res.table = NULL;
|
||||
if (fl4->flowi4_oif) {
|
||||
|
|
@ -2181,7 +2183,7 @@ struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *fl4)
|
|||
res.type = RTN_UNICAST;
|
||||
goto make_route;
|
||||
}
|
||||
rth = ERR_PTR(-ENETUNREACH);
|
||||
rth = ERR_PTR(err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -154,14 +154,20 @@ static void bictcp_init(struct sock *sk)
|
|||
static void bictcp_cwnd_event(struct sock *sk, enum tcp_ca_event event)
|
||||
{
|
||||
if (event == CA_EVENT_TX_START) {
|
||||
s32 delta = tcp_time_stamp - tcp_sk(sk)->lsndtime;
|
||||
struct bictcp *ca = inet_csk_ca(sk);
|
||||
u32 now = tcp_time_stamp;
|
||||
s32 delta;
|
||||
|
||||
delta = now - tcp_sk(sk)->lsndtime;
|
||||
|
||||
/* We were application limited (idle) for a while.
|
||||
* Shift epoch_start to keep cwnd growth to cubic curve.
|
||||
*/
|
||||
if (ca->epoch_start && delta > 0)
|
||||
if (ca->epoch_start && delta > 0) {
|
||||
ca->epoch_start += delta;
|
||||
if (after(ca->epoch_start, now))
|
||||
ca->epoch_start = now;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -162,9 +162,9 @@ kill_with_rst:
|
|||
if (tcp_death_row.sysctl_tw_recycle &&
|
||||
tcptw->tw_ts_recent_stamp &&
|
||||
tcp_tw_remember_stamp(tw))
|
||||
inet_twsk_schedule(tw, tw->tw_timeout);
|
||||
inet_twsk_reschedule(tw, tw->tw_timeout);
|
||||
else
|
||||
inet_twsk_schedule(tw, TCP_TIMEWAIT_LEN);
|
||||
inet_twsk_reschedule(tw, TCP_TIMEWAIT_LEN);
|
||||
return TCP_TW_ACK;
|
||||
}
|
||||
|
||||
|
|
@ -201,7 +201,7 @@ kill:
|
|||
return TCP_TW_SUCCESS;
|
||||
}
|
||||
}
|
||||
inet_twsk_schedule(tw, TCP_TIMEWAIT_LEN);
|
||||
inet_twsk_reschedule(tw, TCP_TIMEWAIT_LEN);
|
||||
|
||||
if (tmp_opt.saw_tstamp) {
|
||||
tcptw->tw_ts_recent = tmp_opt.rcv_tsval;
|
||||
|
|
@ -251,7 +251,7 @@ kill:
|
|||
* Do not reschedule in the last case.
|
||||
*/
|
||||
if (paws_reject || th->ack)
|
||||
inet_twsk_schedule(tw, TCP_TIMEWAIT_LEN);
|
||||
inet_twsk_reschedule(tw, TCP_TIMEWAIT_LEN);
|
||||
|
||||
return tcp_timewait_check_oow_rate_limit(
|
||||
tw, skb, LINUX_MIB_TCPACKSKIPPEDTIMEWAIT);
|
||||
|
|
@ -322,9 +322,6 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
|
|||
} while (0);
|
||||
#endif
|
||||
|
||||
/* Linkage updates. */
|
||||
__inet_twsk_hashdance(tw, sk, &tcp_hashinfo);
|
||||
|
||||
/* Get the TIME_WAIT timeout firing. */
|
||||
if (timeo < rto)
|
||||
timeo = rto;
|
||||
|
|
@ -338,6 +335,8 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
|
|||
}
|
||||
|
||||
inet_twsk_schedule(tw, timeo);
|
||||
/* Linkage updates. */
|
||||
__inet_twsk_hashdance(tw, sk, &tcp_hashinfo);
|
||||
inet_twsk_put(tw);
|
||||
} else {
|
||||
/* Sorry, if we're out of memory, just CLOSE this
|
||||
|
|
|
|||
|
|
@ -2897,6 +2897,7 @@ void tcp_send_active_reset(struct sock *sk, gfp_t priority)
|
|||
skb_reserve(skb, MAX_TCP_HEADER);
|
||||
tcp_init_nondata_skb(skb, tcp_acceptable_seq(sk),
|
||||
TCPHDR_ACK | TCPHDR_RST);
|
||||
skb_mstamp_get(&skb->skb_mstamp);
|
||||
/* Send it off. */
|
||||
if (tcp_transmit_skb(sk, skb, 0, priority))
|
||||
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTFAILED);
|
||||
|
|
|
|||
|
|
@ -1024,7 +1024,8 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
|
|||
if (netif_index_is_vrf(net, ipc.oif)) {
|
||||
flowi4_init_output(fl4, ipc.oif, sk->sk_mark, tos,
|
||||
RT_SCOPE_UNIVERSE, sk->sk_protocol,
|
||||
(flow_flags | FLOWI_FLAG_VRFSRC),
|
||||
(flow_flags | FLOWI_FLAG_VRFSRC |
|
||||
FLOWI_FLAG_SKIP_NH_OIF),
|
||||
faddr, saddr, dport,
|
||||
inet->inet_sport);
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ static struct dst_entry *__xfrm4_dst_lookup(struct net *net, struct flowi4 *fl4,
|
|||
if (saddr)
|
||||
fl4->saddr = saddr->a4;
|
||||
|
||||
fl4->flowi4_flags = FLOWI_FLAG_SKIP_NH_OIF;
|
||||
|
||||
rt = __ip_route_output_key(net, fl4);
|
||||
if (!IS_ERR(rt))
|
||||
return &rt->dst;
|
||||
|
|
|
|||
|
|
@ -5127,13 +5127,12 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
|
|||
|
||||
rt = addrconf_get_prefix_route(&ifp->peer_addr, 128,
|
||||
ifp->idev->dev, 0, 0);
|
||||
if (rt && ip6_del_rt(rt))
|
||||
dst_free(&rt->dst);
|
||||
if (rt)
|
||||
ip6_del_rt(rt);
|
||||
}
|
||||
dst_hold(&ifp->rt->dst);
|
||||
|
||||
if (ip6_del_rt(ifp->rt))
|
||||
dst_free(&ifp->rt->dst);
|
||||
ip6_del_rt(ifp->rt);
|
||||
|
||||
rt_genid_bump_ipv6(net);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -155,6 +155,11 @@ static void node_free(struct fib6_node *fn)
|
|||
kmem_cache_free(fib6_node_kmem, fn);
|
||||
}
|
||||
|
||||
static void rt6_rcu_free(struct rt6_info *rt)
|
||||
{
|
||||
call_rcu(&rt->dst.rcu_head, dst_rcu_free);
|
||||
}
|
||||
|
||||
static void rt6_free_pcpu(struct rt6_info *non_pcpu_rt)
|
||||
{
|
||||
int cpu;
|
||||
|
|
@ -169,7 +174,7 @@ static void rt6_free_pcpu(struct rt6_info *non_pcpu_rt)
|
|||
ppcpu_rt = per_cpu_ptr(non_pcpu_rt->rt6i_pcpu, cpu);
|
||||
pcpu_rt = *ppcpu_rt;
|
||||
if (pcpu_rt) {
|
||||
dst_free(&pcpu_rt->dst);
|
||||
rt6_rcu_free(pcpu_rt);
|
||||
*ppcpu_rt = NULL;
|
||||
}
|
||||
}
|
||||
|
|
@ -181,7 +186,7 @@ static void rt6_release(struct rt6_info *rt)
|
|||
{
|
||||
if (atomic_dec_and_test(&rt->rt6i_ref)) {
|
||||
rt6_free_pcpu(rt);
|
||||
dst_free(&rt->dst);
|
||||
rt6_rcu_free(rt);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -846,7 +851,7 @@ add:
|
|||
*ins = rt;
|
||||
rt->rt6i_node = fn;
|
||||
atomic_inc(&rt->rt6i_ref);
|
||||
inet6_rt_notify(RTM_NEWROUTE, rt, info);
|
||||
inet6_rt_notify(RTM_NEWROUTE, rt, info, 0);
|
||||
info->nl_net->ipv6.rt6_stats->fib_rt_entries++;
|
||||
|
||||
if (!(fn->fn_flags & RTN_RTINFO)) {
|
||||
|
|
@ -872,7 +877,7 @@ add:
|
|||
rt->rt6i_node = fn;
|
||||
rt->dst.rt6_next = iter->dst.rt6_next;
|
||||
atomic_inc(&rt->rt6i_ref);
|
||||
inet6_rt_notify(RTM_NEWROUTE, rt, info);
|
||||
inet6_rt_notify(RTM_NEWROUTE, rt, info, NLM_F_REPLACE);
|
||||
if (!(fn->fn_flags & RTN_RTINFO)) {
|
||||
info->nl_net->ipv6.rt6_stats->fib_route_nodes++;
|
||||
fn->fn_flags |= RTN_RTINFO;
|
||||
|
|
@ -933,6 +938,10 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt,
|
|||
int replace_required = 0;
|
||||
int sernum = fib6_new_sernum(info->nl_net);
|
||||
|
||||
if (WARN_ON_ONCE((rt->dst.flags & DST_NOCACHE) &&
|
||||
!atomic_read(&rt->dst.__refcnt)))
|
||||
return -EINVAL;
|
||||
|
||||
if (info->nlh) {
|
||||
if (!(info->nlh->nlmsg_flags & NLM_F_CREATE))
|
||||
allow_create = 0;
|
||||
|
|
@ -1025,6 +1034,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt,
|
|||
fib6_start_gc(info->nl_net, rt);
|
||||
if (!(rt->rt6i_flags & RTF_CACHE))
|
||||
fib6_prune_clones(info->nl_net, pn);
|
||||
rt->dst.flags &= ~DST_NOCACHE;
|
||||
}
|
||||
|
||||
out:
|
||||
|
|
@ -1049,7 +1059,8 @@ out:
|
|||
atomic_inc(&pn->leaf->rt6i_ref);
|
||||
}
|
||||
#endif
|
||||
dst_free(&rt->dst);
|
||||
if (!(rt->dst.flags & DST_NOCACHE))
|
||||
dst_free(&rt->dst);
|
||||
}
|
||||
return err;
|
||||
|
||||
|
|
@ -1060,7 +1071,8 @@ out:
|
|||
st_failure:
|
||||
if (fn && !(fn->fn_flags & (RTN_RTINFO|RTN_ROOT)))
|
||||
fib6_repair_tree(info->nl_net, fn);
|
||||
dst_free(&rt->dst);
|
||||
if (!(rt->dst.flags & DST_NOCACHE))
|
||||
dst_free(&rt->dst);
|
||||
return err;
|
||||
#endif
|
||||
}
|
||||
|
|
@ -1410,7 +1422,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
|
|||
|
||||
fib6_purge_rt(rt, fn, net);
|
||||
|
||||
inet6_rt_notify(RTM_DELROUTE, rt, info);
|
||||
inet6_rt_notify(RTM_DELROUTE, rt, info, 0);
|
||||
rt6_release(rt);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -404,13 +404,13 @@ static void ip6gre_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
|
|||
struct ipv6_tlv_tnl_enc_lim *tel;
|
||||
__u32 mtu;
|
||||
case ICMPV6_DEST_UNREACH:
|
||||
net_warn_ratelimited("%s: Path to destination invalid or inactive!\n",
|
||||
t->parms.name);
|
||||
net_dbg_ratelimited("%s: Path to destination invalid or inactive!\n",
|
||||
t->parms.name);
|
||||
break;
|
||||
case ICMPV6_TIME_EXCEED:
|
||||
if (code == ICMPV6_EXC_HOPLIMIT) {
|
||||
net_warn_ratelimited("%s: Too small hop limit or routing loop in tunnel!\n",
|
||||
t->parms.name);
|
||||
net_dbg_ratelimited("%s: Too small hop limit or routing loop in tunnel!\n",
|
||||
t->parms.name);
|
||||
}
|
||||
break;
|
||||
case ICMPV6_PARAMPROB:
|
||||
|
|
@ -421,12 +421,12 @@ static void ip6gre_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
|
|||
if (teli && teli == be32_to_cpu(info) - 2) {
|
||||
tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->data[teli];
|
||||
if (tel->encap_limit == 0) {
|
||||
net_warn_ratelimited("%s: Too small encapsulation limit or routing loop in tunnel!\n",
|
||||
t->parms.name);
|
||||
net_dbg_ratelimited("%s: Too small encapsulation limit or routing loop in tunnel!\n",
|
||||
t->parms.name);
|
||||
}
|
||||
} else {
|
||||
net_warn_ratelimited("%s: Recipient unable to parse tunneled packet!\n",
|
||||
t->parms.name);
|
||||
net_dbg_ratelimited("%s: Recipient unable to parse tunneled packet!\n",
|
||||
t->parms.name);
|
||||
}
|
||||
break;
|
||||
case ICMPV6_PKT_TOOBIG:
|
||||
|
|
@ -634,20 +634,20 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
|
|||
}
|
||||
|
||||
if (!fl6->flowi6_mark)
|
||||
dst = ip6_tnl_dst_check(tunnel);
|
||||
dst = ip6_tnl_dst_get(tunnel);
|
||||
|
||||
if (!dst) {
|
||||
ndst = ip6_route_output(net, NULL, fl6);
|
||||
dst = ip6_route_output(net, NULL, fl6);
|
||||
|
||||
if (ndst->error)
|
||||
if (dst->error)
|
||||
goto tx_err_link_failure;
|
||||
ndst = xfrm_lookup(net, ndst, flowi6_to_flowi(fl6), NULL, 0);
|
||||
if (IS_ERR(ndst)) {
|
||||
err = PTR_ERR(ndst);
|
||||
ndst = NULL;
|
||||
dst = xfrm_lookup(net, dst, flowi6_to_flowi(fl6), NULL, 0);
|
||||
if (IS_ERR(dst)) {
|
||||
err = PTR_ERR(dst);
|
||||
dst = NULL;
|
||||
goto tx_err_link_failure;
|
||||
}
|
||||
dst = ndst;
|
||||
ndst = dst;
|
||||
}
|
||||
|
||||
tdev = dst->dev;
|
||||
|
|
@ -702,12 +702,9 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
|
|||
skb = new_skb;
|
||||
}
|
||||
|
||||
if (fl6->flowi6_mark) {
|
||||
skb_dst_set(skb, dst);
|
||||
ndst = NULL;
|
||||
} else {
|
||||
skb_dst_set_noref(skb, dst);
|
||||
}
|
||||
if (!fl6->flowi6_mark && ndst)
|
||||
ip6_tnl_dst_set(tunnel, ndst);
|
||||
skb_dst_set(skb, dst);
|
||||
|
||||
proto = NEXTHDR_GRE;
|
||||
if (encap_limit >= 0) {
|
||||
|
|
@ -762,14 +759,12 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
|
|||
skb_set_inner_protocol(skb, protocol);
|
||||
|
||||
ip6tunnel_xmit(NULL, skb, dev);
|
||||
if (ndst)
|
||||
ip6_tnl_dst_store(tunnel, ndst);
|
||||
return 0;
|
||||
tx_err_link_failure:
|
||||
stats->tx_carrier_errors++;
|
||||
dst_link_failure(skb);
|
||||
tx_err_dst_release:
|
||||
dst_release(ndst);
|
||||
dst_release(dst);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -1223,6 +1218,9 @@ static const struct net_device_ops ip6gre_netdev_ops = {
|
|||
|
||||
static void ip6gre_dev_free(struct net_device *dev)
|
||||
{
|
||||
struct ip6_tnl *t = netdev_priv(dev);
|
||||
|
||||
ip6_tnl_dst_destroy(t);
|
||||
free_percpu(dev->tstats);
|
||||
free_netdev(dev);
|
||||
}
|
||||
|
|
@ -1245,9 +1243,10 @@ static void ip6gre_tunnel_setup(struct net_device *dev)
|
|||
netif_keep_dst(dev);
|
||||
}
|
||||
|
||||
static int ip6gre_tunnel_init(struct net_device *dev)
|
||||
static int ip6gre_tunnel_init_common(struct net_device *dev)
|
||||
{
|
||||
struct ip6_tnl *tunnel;
|
||||
int ret;
|
||||
|
||||
tunnel = netdev_priv(dev);
|
||||
|
||||
|
|
@ -1255,16 +1254,37 @@ static int ip6gre_tunnel_init(struct net_device *dev)
|
|||
tunnel->net = dev_net(dev);
|
||||
strcpy(tunnel->parms.name, dev->name);
|
||||
|
||||
dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
|
||||
if (!dev->tstats)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = ip6_tnl_dst_init(tunnel);
|
||||
if (ret) {
|
||||
free_percpu(dev->tstats);
|
||||
dev->tstats = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ip6gre_tunnel_init(struct net_device *dev)
|
||||
{
|
||||
struct ip6_tnl *tunnel;
|
||||
int ret;
|
||||
|
||||
ret = ip6gre_tunnel_init_common(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
tunnel = netdev_priv(dev);
|
||||
|
||||
memcpy(dev->dev_addr, &tunnel->parms.laddr, sizeof(struct in6_addr));
|
||||
memcpy(dev->broadcast, &tunnel->parms.raddr, sizeof(struct in6_addr));
|
||||
|
||||
if (ipv6_addr_any(&tunnel->parms.raddr))
|
||||
dev->header_ops = &ip6gre_header_ops;
|
||||
|
||||
dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
|
||||
if (!dev->tstats)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1460,19 +1480,16 @@ static void ip6gre_netlink_parms(struct nlattr *data[],
|
|||
static int ip6gre_tap_init(struct net_device *dev)
|
||||
{
|
||||
struct ip6_tnl *tunnel;
|
||||
int ret;
|
||||
|
||||
ret = ip6gre_tunnel_init_common(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
tunnel = netdev_priv(dev);
|
||||
|
||||
tunnel->dev = dev;
|
||||
tunnel->net = dev_net(dev);
|
||||
strcpy(tunnel->parms.name, dev->name);
|
||||
|
||||
ip6gre_tnl_link_config(tunnel, 1);
|
||||
|
||||
dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
|
||||
if (!dev->tstats)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -586,20 +586,22 @@ int ip6_fragment(struct sock *sk, struct sk_buff *skb,
|
|||
frag_id = ipv6_select_ident(net, &ipv6_hdr(skb)->daddr,
|
||||
&ipv6_hdr(skb)->saddr);
|
||||
|
||||
hroom = LL_RESERVED_SPACE(rt->dst.dev);
|
||||
if (skb_has_frag_list(skb)) {
|
||||
int first_len = skb_pagelen(skb);
|
||||
struct sk_buff *frag2;
|
||||
|
||||
if (first_len - hlen > mtu ||
|
||||
((first_len - hlen) & 7) ||
|
||||
skb_cloned(skb))
|
||||
skb_cloned(skb) ||
|
||||
skb_headroom(skb) < (hroom + sizeof(struct frag_hdr)))
|
||||
goto slow_path;
|
||||
|
||||
skb_walk_frags(skb, frag) {
|
||||
/* Correct geometry. */
|
||||
if (frag->len > mtu ||
|
||||
((frag->len & 7) && frag->next) ||
|
||||
skb_headroom(frag) < hlen)
|
||||
skb_headroom(frag) < (hlen + hroom + sizeof(struct frag_hdr)))
|
||||
goto slow_path_clean;
|
||||
|
||||
/* Partially cloned skb? */
|
||||
|
|
@ -616,8 +618,6 @@ int ip6_fragment(struct sock *sk, struct sk_buff *skb,
|
|||
|
||||
err = 0;
|
||||
offset = 0;
|
||||
frag = skb_shinfo(skb)->frag_list;
|
||||
skb_frag_list_init(skb);
|
||||
/* BUILD HEADER */
|
||||
|
||||
*prevhdr = NEXTHDR_FRAGMENT;
|
||||
|
|
@ -625,8 +625,11 @@ int ip6_fragment(struct sock *sk, struct sk_buff *skb,
|
|||
if (!tmp_hdr) {
|
||||
IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
|
||||
IPSTATS_MIB_FRAGFAILS);
|
||||
return -ENOMEM;
|
||||
err = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
frag = skb_shinfo(skb)->frag_list;
|
||||
skb_frag_list_init(skb);
|
||||
|
||||
__skb_pull(skb, hlen);
|
||||
fh = (struct frag_hdr *)__skb_push(skb, sizeof(struct frag_hdr));
|
||||
|
|
@ -723,7 +726,6 @@ slow_path:
|
|||
*/
|
||||
|
||||
*prevhdr = NEXTHDR_FRAGMENT;
|
||||
hroom = LL_RESERVED_SPACE(rt->dst.dev);
|
||||
troom = rt->dst.dev->needed_tailroom;
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -126,36 +126,92 @@ static struct net_device_stats *ip6_get_stats(struct net_device *dev)
|
|||
* Locking : hash tables are protected by RCU and RTNL
|
||||
*/
|
||||
|
||||
struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t)
|
||||
static void ip6_tnl_per_cpu_dst_set(struct ip6_tnl_dst *idst,
|
||||
struct dst_entry *dst)
|
||||
{
|
||||
struct dst_entry *dst = t->dst_cache;
|
||||
|
||||
if (dst && dst->obsolete &&
|
||||
!dst->ops->check(dst, t->dst_cookie)) {
|
||||
t->dst_cache = NULL;
|
||||
dst_release(dst);
|
||||
return NULL;
|
||||
write_seqlock_bh(&idst->lock);
|
||||
dst_release(rcu_dereference_protected(
|
||||
idst->dst,
|
||||
lockdep_is_held(&idst->lock.lock)));
|
||||
if (dst) {
|
||||
dst_hold(dst);
|
||||
idst->cookie = rt6_get_cookie((struct rt6_info *)dst);
|
||||
} else {
|
||||
idst->cookie = 0;
|
||||
}
|
||||
rcu_assign_pointer(idst->dst, dst);
|
||||
write_sequnlock_bh(&idst->lock);
|
||||
}
|
||||
|
||||
struct dst_entry *ip6_tnl_dst_get(struct ip6_tnl *t)
|
||||
{
|
||||
struct ip6_tnl_dst *idst;
|
||||
struct dst_entry *dst;
|
||||
unsigned int seq;
|
||||
u32 cookie;
|
||||
|
||||
idst = raw_cpu_ptr(t->dst_cache);
|
||||
|
||||
rcu_read_lock();
|
||||
do {
|
||||
seq = read_seqbegin(&idst->lock);
|
||||
dst = rcu_dereference(idst->dst);
|
||||
cookie = idst->cookie;
|
||||
} while (read_seqretry(&idst->lock, seq));
|
||||
|
||||
if (dst && !atomic_inc_not_zero(&dst->__refcnt))
|
||||
dst = NULL;
|
||||
rcu_read_unlock();
|
||||
|
||||
if (dst && dst->obsolete && !dst->ops->check(dst, cookie)) {
|
||||
ip6_tnl_per_cpu_dst_set(idst, NULL);
|
||||
dst_release(dst);
|
||||
dst = NULL;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ip6_tnl_dst_check);
|
||||
EXPORT_SYMBOL_GPL(ip6_tnl_dst_get);
|
||||
|
||||
void ip6_tnl_dst_reset(struct ip6_tnl *t)
|
||||
{
|
||||
dst_release(t->dst_cache);
|
||||
t->dst_cache = NULL;
|
||||
int i;
|
||||
|
||||
for_each_possible_cpu(i)
|
||||
ip6_tnl_per_cpu_dst_set(raw_cpu_ptr(t->dst_cache), NULL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ip6_tnl_dst_reset);
|
||||
|
||||
void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst)
|
||||
void ip6_tnl_dst_set(struct ip6_tnl *t, struct dst_entry *dst)
|
||||
{
|
||||
struct rt6_info *rt = (struct rt6_info *) dst;
|
||||
t->dst_cookie = rt6_get_cookie(rt);
|
||||
dst_release(t->dst_cache);
|
||||
t->dst_cache = dst;
|
||||
ip6_tnl_per_cpu_dst_set(raw_cpu_ptr(t->dst_cache), dst);
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ip6_tnl_dst_store);
|
||||
EXPORT_SYMBOL_GPL(ip6_tnl_dst_set);
|
||||
|
||||
void ip6_tnl_dst_destroy(struct ip6_tnl *t)
|
||||
{
|
||||
if (!t->dst_cache)
|
||||
return;
|
||||
|
||||
ip6_tnl_dst_reset(t);
|
||||
free_percpu(t->dst_cache);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ip6_tnl_dst_destroy);
|
||||
|
||||
int ip6_tnl_dst_init(struct ip6_tnl *t)
|
||||
{
|
||||
int i;
|
||||
|
||||
t->dst_cache = alloc_percpu(struct ip6_tnl_dst);
|
||||
if (!t->dst_cache)
|
||||
return -ENOMEM;
|
||||
|
||||
for_each_possible_cpu(i)
|
||||
seqlock_init(&per_cpu_ptr(t->dst_cache, i)->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ip6_tnl_dst_init);
|
||||
|
||||
/**
|
||||
* ip6_tnl_lookup - fetch tunnel matching the end-point addresses
|
||||
|
|
@ -271,6 +327,9 @@ ip6_tnl_unlink(struct ip6_tnl_net *ip6n, struct ip6_tnl *t)
|
|||
|
||||
static void ip6_dev_free(struct net_device *dev)
|
||||
{
|
||||
struct ip6_tnl *t = netdev_priv(dev);
|
||||
|
||||
ip6_tnl_dst_destroy(t);
|
||||
free_percpu(dev->tstats);
|
||||
free_netdev(dev);
|
||||
}
|
||||
|
|
@ -510,14 +569,14 @@ ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt,
|
|||
struct ipv6_tlv_tnl_enc_lim *tel;
|
||||
__u32 mtu;
|
||||
case ICMPV6_DEST_UNREACH:
|
||||
net_warn_ratelimited("%s: Path to destination invalid or inactive!\n",
|
||||
t->parms.name);
|
||||
net_dbg_ratelimited("%s: Path to destination invalid or inactive!\n",
|
||||
t->parms.name);
|
||||
rel_msg = 1;
|
||||
break;
|
||||
case ICMPV6_TIME_EXCEED:
|
||||
if ((*code) == ICMPV6_EXC_HOPLIMIT) {
|
||||
net_warn_ratelimited("%s: Too small hop limit or routing loop in tunnel!\n",
|
||||
t->parms.name);
|
||||
net_dbg_ratelimited("%s: Too small hop limit or routing loop in tunnel!\n",
|
||||
t->parms.name);
|
||||
rel_msg = 1;
|
||||
}
|
||||
break;
|
||||
|
|
@ -529,13 +588,13 @@ ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt,
|
|||
if (teli && teli == *info - 2) {
|
||||
tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->data[teli];
|
||||
if (tel->encap_limit == 0) {
|
||||
net_warn_ratelimited("%s: Too small encapsulation limit or routing loop in tunnel!\n",
|
||||
t->parms.name);
|
||||
net_dbg_ratelimited("%s: Too small encapsulation limit or routing loop in tunnel!\n",
|
||||
t->parms.name);
|
||||
rel_msg = 1;
|
||||
}
|
||||
} else {
|
||||
net_warn_ratelimited("%s: Recipient unable to parse tunneled packet!\n",
|
||||
t->parms.name);
|
||||
net_dbg_ratelimited("%s: Recipient unable to parse tunneled packet!\n",
|
||||
t->parms.name);
|
||||
}
|
||||
break;
|
||||
case ICMPV6_PKT_TOOBIG:
|
||||
|
|
@ -1010,23 +1069,23 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
|
|||
memcpy(&fl6->daddr, addr6, sizeof(fl6->daddr));
|
||||
neigh_release(neigh);
|
||||
} else if (!fl6->flowi6_mark)
|
||||
dst = ip6_tnl_dst_check(t);
|
||||
dst = ip6_tnl_dst_get(t);
|
||||
|
||||
if (!ip6_tnl_xmit_ctl(t, &fl6->saddr, &fl6->daddr))
|
||||
goto tx_err_link_failure;
|
||||
|
||||
if (!dst) {
|
||||
ndst = ip6_route_output(net, NULL, fl6);
|
||||
dst = ip6_route_output(net, NULL, fl6);
|
||||
|
||||
if (ndst->error)
|
||||
if (dst->error)
|
||||
goto tx_err_link_failure;
|
||||
ndst = xfrm_lookup(net, ndst, flowi6_to_flowi(fl6), NULL, 0);
|
||||
if (IS_ERR(ndst)) {
|
||||
err = PTR_ERR(ndst);
|
||||
ndst = NULL;
|
||||
dst = xfrm_lookup(net, dst, flowi6_to_flowi(fl6), NULL, 0);
|
||||
if (IS_ERR(dst)) {
|
||||
err = PTR_ERR(dst);
|
||||
dst = NULL;
|
||||
goto tx_err_link_failure;
|
||||
}
|
||||
dst = ndst;
|
||||
ndst = dst;
|
||||
}
|
||||
|
||||
tdev = dst->dev;
|
||||
|
|
@ -1072,12 +1131,11 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
|
|||
consume_skb(skb);
|
||||
skb = new_skb;
|
||||
}
|
||||
if (fl6->flowi6_mark) {
|
||||
skb_dst_set(skb, dst);
|
||||
ndst = NULL;
|
||||
} else {
|
||||
skb_dst_set_noref(skb, dst);
|
||||
}
|
||||
|
||||
if (!fl6->flowi6_mark && ndst)
|
||||
ip6_tnl_dst_set(t, ndst);
|
||||
skb_dst_set(skb, dst);
|
||||
|
||||
skb->transport_header = skb->network_header;
|
||||
|
||||
proto = fl6->flowi6_proto;
|
||||
|
|
@ -1101,14 +1159,12 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
|
|||
ipv6h->saddr = fl6->saddr;
|
||||
ipv6h->daddr = fl6->daddr;
|
||||
ip6tunnel_xmit(NULL, skb, dev);
|
||||
if (ndst)
|
||||
ip6_tnl_dst_store(t, ndst);
|
||||
return 0;
|
||||
tx_err_link_failure:
|
||||
stats->tx_carrier_errors++;
|
||||
dst_link_failure(skb);
|
||||
tx_err_dst_release:
|
||||
dst_release(ndst);
|
||||
dst_release(dst);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -1573,12 +1629,21 @@ static inline int
|
|||
ip6_tnl_dev_init_gen(struct net_device *dev)
|
||||
{
|
||||
struct ip6_tnl *t = netdev_priv(dev);
|
||||
int ret;
|
||||
|
||||
t->dev = dev;
|
||||
t->net = dev_net(dev);
|
||||
dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
|
||||
if (!dev->tstats)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = ip6_tnl_dst_init(t);
|
||||
if (ret) {
|
||||
free_percpu(dev->tstats);
|
||||
dev->tstats = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1322,8 +1322,7 @@ static void ip6_link_failure(struct sk_buff *skb)
|
|||
if (rt) {
|
||||
if (rt->rt6i_flags & RTF_CACHE) {
|
||||
dst_hold(&rt->dst);
|
||||
if (ip6_del_rt(rt))
|
||||
dst_free(&rt->dst);
|
||||
ip6_del_rt(rt);
|
||||
} else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT)) {
|
||||
rt->rt6i_node->fn_sernum = -1;
|
||||
}
|
||||
|
|
@ -1886,9 +1885,11 @@ int ip6_route_info_create(struct fib6_config *cfg, struct rt6_info **rt_ret)
|
|||
rt->dst.input = ip6_pkt_prohibit;
|
||||
break;
|
||||
case RTN_THROW:
|
||||
case RTN_UNREACHABLE:
|
||||
default:
|
||||
rt->dst.error = (cfg->fc_type == RTN_THROW) ? -EAGAIN
|
||||
: -ENETUNREACH;
|
||||
: (cfg->fc_type == RTN_UNREACHABLE)
|
||||
? -EHOSTUNREACH : -ENETUNREACH;
|
||||
rt->dst.output = ip6_pkt_discard_out;
|
||||
rt->dst.input = ip6_pkt_discard;
|
||||
break;
|
||||
|
|
@ -2028,7 +2029,8 @@ static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info)
|
|||
struct fib6_table *table;
|
||||
struct net *net = dev_net(rt->dst.dev);
|
||||
|
||||
if (rt == net->ipv6.ip6_null_entry) {
|
||||
if (rt == net->ipv6.ip6_null_entry ||
|
||||
rt->dst.flags & DST_NOCACHE) {
|
||||
err = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -2515,6 +2517,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
|
|||
rt->rt6i_dst.addr = *addr;
|
||||
rt->rt6i_dst.plen = 128;
|
||||
rt->rt6i_table = fib6_get_table(net, RT6_TABLE_LOCAL);
|
||||
rt->dst.flags |= DST_NOCACHE;
|
||||
|
||||
atomic_set(&rt->dst.__refcnt, 1);
|
||||
|
||||
|
|
@ -3303,7 +3306,8 @@ errout:
|
|||
return err;
|
||||
}
|
||||
|
||||
void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info)
|
||||
void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info,
|
||||
unsigned int nlm_flags)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct net *net = info->nl_net;
|
||||
|
|
@ -3318,7 +3322,7 @@ void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info)
|
|||
goto errout;
|
||||
|
||||
err = rt6_fill_node(net, skb, rt, NULL, NULL, 0,
|
||||
event, info->portid, seq, 0, 0, 0);
|
||||
event, info->portid, seq, 0, 0, nlm_flags);
|
||||
if (err < 0) {
|
||||
/* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
|
||||
WARN_ON(err == -EMSGSIZE);
|
||||
|
|
|
|||
|
|
@ -2474,6 +2474,7 @@ static int ieee80211_set_cqm_rssi_config(struct wiphy *wiphy,
|
|||
|
||||
bss_conf->cqm_rssi_thold = rssi_thold;
|
||||
bss_conf->cqm_rssi_hyst = rssi_hyst;
|
||||
sdata->u.mgd.last_cqm_event_signal = 0;
|
||||
|
||||
/* tell the driver upon association, unless already associated */
|
||||
if (sdata->u.mgd.associated &&
|
||||
|
|
@ -2518,15 +2519,17 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
|
|||
continue;
|
||||
|
||||
for (j = 0; j < IEEE80211_HT_MCS_MASK_LEN; j++) {
|
||||
if (~sdata->rc_rateidx_mcs_mask[i][j])
|
||||
if (~sdata->rc_rateidx_mcs_mask[i][j]) {
|
||||
sdata->rc_has_mcs_mask[i] = true;
|
||||
|
||||
if (~sdata->rc_rateidx_vht_mcs_mask[i][j])
|
||||
sdata->rc_has_vht_mcs_mask[i] = true;
|
||||
|
||||
if (sdata->rc_has_mcs_mask[i] &&
|
||||
sdata->rc_has_vht_mcs_mask[i])
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; j < NL80211_VHT_NSS_MAX; j++) {
|
||||
if (~sdata->rc_rateidx_vht_mcs_mask[i][j]) {
|
||||
sdata->rc_has_vht_mcs_mask[i] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -107,12 +107,17 @@ EXPORT_SYMBOL(nf_log_register);
|
|||
|
||||
void nf_log_unregister(struct nf_logger *logger)
|
||||
{
|
||||
const struct nf_logger *log;
|
||||
int i;
|
||||
|
||||
mutex_lock(&nf_log_mutex);
|
||||
for (i = 0; i < NFPROTO_NUMPROTO; i++)
|
||||
RCU_INIT_POINTER(loggers[i][logger->type], NULL);
|
||||
for (i = 0; i < NFPROTO_NUMPROTO; i++) {
|
||||
log = nft_log_dereference(loggers[i][logger->type]);
|
||||
if (log == logger)
|
||||
RCU_INIT_POINTER(loggers[i][logger->type], NULL);
|
||||
}
|
||||
mutex_unlock(&nf_log_mutex);
|
||||
synchronize_rcu();
|
||||
}
|
||||
EXPORT_SYMBOL(nf_log_unregister);
|
||||
|
||||
|
|
|
|||
|
|
@ -619,6 +619,13 @@ struct nft_xt {
|
|||
|
||||
static struct nft_expr_type nft_match_type;
|
||||
|
||||
static bool nft_match_cmp(const struct xt_match *match,
|
||||
const char *name, u32 rev, u32 family)
|
||||
{
|
||||
return strcmp(match->name, name) == 0 && match->revision == rev &&
|
||||
(match->family == NFPROTO_UNSPEC || match->family == family);
|
||||
}
|
||||
|
||||
static const struct nft_expr_ops *
|
||||
nft_match_select_ops(const struct nft_ctx *ctx,
|
||||
const struct nlattr * const tb[])
|
||||
|
|
@ -626,7 +633,7 @@ nft_match_select_ops(const struct nft_ctx *ctx,
|
|||
struct nft_xt *nft_match;
|
||||
struct xt_match *match;
|
||||
char *mt_name;
|
||||
__u32 rev, family;
|
||||
u32 rev, family;
|
||||
|
||||
if (tb[NFTA_MATCH_NAME] == NULL ||
|
||||
tb[NFTA_MATCH_REV] == NULL ||
|
||||
|
|
@ -641,8 +648,7 @@ nft_match_select_ops(const struct nft_ctx *ctx,
|
|||
list_for_each_entry(nft_match, &nft_match_list, head) {
|
||||
struct xt_match *match = nft_match->ops.data;
|
||||
|
||||
if (strcmp(match->name, mt_name) == 0 &&
|
||||
match->revision == rev && match->family == family) {
|
||||
if (nft_match_cmp(match, mt_name, rev, family)) {
|
||||
if (!try_module_get(match->me))
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
|
|
@ -693,6 +699,13 @@ static LIST_HEAD(nft_target_list);
|
|||
|
||||
static struct nft_expr_type nft_target_type;
|
||||
|
||||
static bool nft_target_cmp(const struct xt_target *tg,
|
||||
const char *name, u32 rev, u32 family)
|
||||
{
|
||||
return strcmp(tg->name, name) == 0 && tg->revision == rev &&
|
||||
(tg->family == NFPROTO_UNSPEC || tg->family == family);
|
||||
}
|
||||
|
||||
static const struct nft_expr_ops *
|
||||
nft_target_select_ops(const struct nft_ctx *ctx,
|
||||
const struct nlattr * const tb[])
|
||||
|
|
@ -700,7 +713,7 @@ nft_target_select_ops(const struct nft_ctx *ctx,
|
|||
struct nft_xt *nft_target;
|
||||
struct xt_target *target;
|
||||
char *tg_name;
|
||||
__u32 rev, family;
|
||||
u32 rev, family;
|
||||
|
||||
if (tb[NFTA_TARGET_NAME] == NULL ||
|
||||
tb[NFTA_TARGET_REV] == NULL ||
|
||||
|
|
@ -715,8 +728,7 @@ nft_target_select_ops(const struct nft_ctx *ctx,
|
|||
list_for_each_entry(nft_target, &nft_target_list, head) {
|
||||
struct xt_target *target = nft_target->ops.data;
|
||||
|
||||
if (strcmp(target->name, tg_name) == 0 &&
|
||||
target->revision == rev && target->family == family) {
|
||||
if (nft_target_cmp(target, tg_name, rev, family)) {
|
||||
if (!try_module_get(target->me))
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
|
|
|
|||
|
|
@ -125,6 +125,24 @@ static inline u32 netlink_group_mask(u32 group)
|
|||
return group ? 1 << (group - 1) : 0;
|
||||
}
|
||||
|
||||
static struct sk_buff *netlink_to_full_skb(const struct sk_buff *skb,
|
||||
gfp_t gfp_mask)
|
||||
{
|
||||
unsigned int len = skb_end_offset(skb);
|
||||
struct sk_buff *new;
|
||||
|
||||
new = alloc_skb(len, gfp_mask);
|
||||
if (new == NULL)
|
||||
return NULL;
|
||||
|
||||
NETLINK_CB(new).portid = NETLINK_CB(skb).portid;
|
||||
NETLINK_CB(new).dst_group = NETLINK_CB(skb).dst_group;
|
||||
NETLINK_CB(new).creds = NETLINK_CB(skb).creds;
|
||||
|
||||
memcpy(skb_put(new, len), skb->data, len);
|
||||
return new;
|
||||
}
|
||||
|
||||
int netlink_add_tap(struct netlink_tap *nt)
|
||||
{
|
||||
if (unlikely(nt->dev->type != ARPHRD_NETLINK))
|
||||
|
|
@ -206,7 +224,11 @@ static int __netlink_deliver_tap_skb(struct sk_buff *skb,
|
|||
int ret = -ENOMEM;
|
||||
|
||||
dev_hold(dev);
|
||||
nskb = skb_clone(skb, GFP_ATOMIC);
|
||||
|
||||
if (netlink_skb_is_mmaped(skb) || is_vmalloc_addr(skb->head))
|
||||
nskb = netlink_to_full_skb(skb, GFP_ATOMIC);
|
||||
else
|
||||
nskb = skb_clone(skb, GFP_ATOMIC);
|
||||
if (nskb) {
|
||||
nskb->dev = dev;
|
||||
nskb->protocol = htons((u16) sk->sk_protocol);
|
||||
|
|
@ -279,11 +301,6 @@ static void netlink_rcv_wake(struct sock *sk)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_NETLINK_MMAP
|
||||
static bool netlink_skb_is_mmaped(const struct sk_buff *skb)
|
||||
{
|
||||
return NETLINK_CB(skb).flags & NETLINK_SKB_MMAPED;
|
||||
}
|
||||
|
||||
static bool netlink_rx_is_mmaped(struct sock *sk)
|
||||
{
|
||||
return nlk_sk(sk)->rx_ring.pg_vec != NULL;
|
||||
|
|
@ -846,7 +863,6 @@ static void netlink_ring_set_copied(struct sock *sk, struct sk_buff *skb)
|
|||
}
|
||||
|
||||
#else /* CONFIG_NETLINK_MMAP */
|
||||
#define netlink_skb_is_mmaped(skb) false
|
||||
#define netlink_rx_is_mmaped(sk) false
|
||||
#define netlink_tx_is_mmaped(sk) false
|
||||
#define netlink_mmap sock_no_mmap
|
||||
|
|
@ -1094,8 +1110,8 @@ static int netlink_insert(struct sock *sk, u32 portid)
|
|||
|
||||
lock_sock(sk);
|
||||
|
||||
err = -EBUSY;
|
||||
if (nlk_sk(sk)->portid)
|
||||
err = nlk_sk(sk)->portid == portid ? 0 : -EBUSY;
|
||||
if (nlk_sk(sk)->bound)
|
||||
goto err;
|
||||
|
||||
err = -ENOMEM;
|
||||
|
|
@ -1115,10 +1131,14 @@ static int netlink_insert(struct sock *sk, u32 portid)
|
|||
err = -EOVERFLOW;
|
||||
if (err == -EEXIST)
|
||||
err = -EADDRINUSE;
|
||||
nlk_sk(sk)->portid = 0;
|
||||
sock_put(sk);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* We need to ensure that the socket is hashed and visible. */
|
||||
smp_wmb();
|
||||
nlk_sk(sk)->bound = portid;
|
||||
|
||||
err:
|
||||
release_sock(sk);
|
||||
return err;
|
||||
|
|
@ -1503,6 +1523,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr,
|
|||
struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr;
|
||||
int err;
|
||||
long unsigned int groups = nladdr->nl_groups;
|
||||
bool bound;
|
||||
|
||||
if (addr_len < sizeof(struct sockaddr_nl))
|
||||
return -EINVAL;
|
||||
|
|
@ -1519,9 +1540,14 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr,
|
|||
return err;
|
||||
}
|
||||
|
||||
if (nlk->portid)
|
||||
bound = nlk->bound;
|
||||
if (bound) {
|
||||
/* Ensure nlk->portid is up-to-date. */
|
||||
smp_rmb();
|
||||
|
||||
if (nladdr->nl_pid != nlk->portid)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (nlk->netlink_bind && groups) {
|
||||
int group;
|
||||
|
|
@ -1537,7 +1563,10 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr,
|
|||
}
|
||||
}
|
||||
|
||||
if (!nlk->portid) {
|
||||
/* No need for barriers here as we return to user-space without
|
||||
* using any of the bound attributes.
|
||||
*/
|
||||
if (!bound) {
|
||||
err = nladdr->nl_pid ?
|
||||
netlink_insert(sk, nladdr->nl_pid) :
|
||||
netlink_autobind(sock);
|
||||
|
|
@ -1585,7 +1614,10 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr,
|
|||
!netlink_allowed(sock, NL_CFG_F_NONROOT_SEND))
|
||||
return -EPERM;
|
||||
|
||||
if (!nlk->portid)
|
||||
/* No need for barriers here as we return to user-space without
|
||||
* using any of the bound attributes.
|
||||
*/
|
||||
if (!nlk->bound)
|
||||
err = netlink_autobind(sock);
|
||||
|
||||
if (err == 0) {
|
||||
|
|
@ -2426,10 +2458,13 @@ static int netlink_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
|
|||
dst_group = nlk->dst_group;
|
||||
}
|
||||
|
||||
if (!nlk->portid) {
|
||||
if (!nlk->bound) {
|
||||
err = netlink_autobind(sock);
|
||||
if (err)
|
||||
goto out;
|
||||
} else {
|
||||
/* Ensure nlk is hashed and visible. */
|
||||
smp_rmb();
|
||||
}
|
||||
|
||||
/* It's a really convoluted way for userland to ask for mmaped
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ struct netlink_sock {
|
|||
unsigned long state;
|
||||
size_t max_recvmsg_len;
|
||||
wait_queue_head_t wait;
|
||||
bool bound;
|
||||
bool cb_running;
|
||||
struct netlink_callback cb;
|
||||
struct mutex *cb_mutex;
|
||||
|
|
@ -59,6 +60,15 @@ static inline struct netlink_sock *nlk_sk(struct sock *sk)
|
|||
return container_of(sk, struct netlink_sock, sk);
|
||||
}
|
||||
|
||||
static inline bool netlink_skb_is_mmaped(const struct sk_buff *skb)
|
||||
{
|
||||
#ifdef CONFIG_NETLINK_MMAP
|
||||
return NETLINK_CB(skb).flags & NETLINK_SKB_MMAPED;
|
||||
#else
|
||||
return false;
|
||||
#endif /* CONFIG_NETLINK_MMAP */
|
||||
}
|
||||
|
||||
struct netlink_table {
|
||||
struct rhashtable hash;
|
||||
struct hlist_head mc_list;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@
|
|||
config OPENVSWITCH
|
||||
tristate "Open vSwitch"
|
||||
depends on INET
|
||||
depends on (!NF_CONNTRACK || NF_CONNTRACK)
|
||||
depends on !NF_CONNTRACK || \
|
||||
(NF_CONNTRACK && (!NF_DEFRAG_IPV6 || NF_DEFRAG_IPV6))
|
||||
select LIBCRC32C
|
||||
select MPLS
|
||||
select NET_MPLS_GSO
|
||||
|
|
|
|||
|
|
@ -275,13 +275,15 @@ static int ovs_ct_helper(struct sk_buff *skb, u16 proto)
|
|||
case NFPROTO_IPV6: {
|
||||
u8 nexthdr = ipv6_hdr(skb)->nexthdr;
|
||||
__be16 frag_off;
|
||||
int ofs;
|
||||
|
||||
protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr),
|
||||
&nexthdr, &frag_off);
|
||||
if (protoff < 0 || (frag_off & htons(~0x7)) != 0) {
|
||||
ofs = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr,
|
||||
&frag_off);
|
||||
if (ofs < 0 || (frag_off & htons(~0x7)) != 0) {
|
||||
pr_debug("proto header not found\n");
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
protoff = ofs;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -952,7 +952,7 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
|
|||
if (error)
|
||||
goto err_kfree_flow;
|
||||
|
||||
ovs_flow_mask_key(&new_flow->key, &key, &mask);
|
||||
ovs_flow_mask_key(&new_flow->key, &key, true, &mask);
|
||||
|
||||
/* Extract flow identifier. */
|
||||
error = ovs_nla_get_identifier(&new_flow->id, a[OVS_FLOW_ATTR_UFID],
|
||||
|
|
@ -1080,7 +1080,7 @@ static struct sw_flow_actions *get_flow_actions(struct net *net,
|
|||
struct sw_flow_key masked_key;
|
||||
int error;
|
||||
|
||||
ovs_flow_mask_key(&masked_key, key, mask);
|
||||
ovs_flow_mask_key(&masked_key, key, true, mask);
|
||||
error = ovs_nla_copy_actions(net, a, &masked_key, &acts, log);
|
||||
if (error) {
|
||||
OVS_NLERR(log,
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ struct ovs_len_tbl {
|
|||
};
|
||||
|
||||
#define OVS_ATTR_NESTED -1
|
||||
#define OVS_ATTR_VARIABLE -2
|
||||
|
||||
static void update_range(struct sw_flow_match *match,
|
||||
size_t offset, size_t size, bool is_mask)
|
||||
|
|
@ -304,6 +305,10 @@ size_t ovs_key_attr_size(void)
|
|||
+ nla_total_size(28); /* OVS_KEY_ATTR_ND */
|
||||
}
|
||||
|
||||
static const struct ovs_len_tbl ovs_vxlan_ext_key_lens[OVS_VXLAN_EXT_MAX + 1] = {
|
||||
[OVS_VXLAN_EXT_GBP] = { .len = sizeof(u32) },
|
||||
};
|
||||
|
||||
static const struct ovs_len_tbl ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1] = {
|
||||
[OVS_TUNNEL_KEY_ATTR_ID] = { .len = sizeof(u64) },
|
||||
[OVS_TUNNEL_KEY_ATTR_IPV4_SRC] = { .len = sizeof(u32) },
|
||||
|
|
@ -315,8 +320,9 @@ static const struct ovs_len_tbl ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1]
|
|||
[OVS_TUNNEL_KEY_ATTR_TP_SRC] = { .len = sizeof(u16) },
|
||||
[OVS_TUNNEL_KEY_ATTR_TP_DST] = { .len = sizeof(u16) },
|
||||
[OVS_TUNNEL_KEY_ATTR_OAM] = { .len = 0 },
|
||||
[OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = { .len = OVS_ATTR_NESTED },
|
||||
[OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS] = { .len = OVS_ATTR_NESTED },
|
||||
[OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = { .len = OVS_ATTR_VARIABLE },
|
||||
[OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS] = { .len = OVS_ATTR_NESTED,
|
||||
.next = ovs_vxlan_ext_key_lens },
|
||||
};
|
||||
|
||||
/* The size of the argument for each %OVS_KEY_ATTR_* Netlink attribute. */
|
||||
|
|
@ -349,6 +355,13 @@ static const struct ovs_len_tbl ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = {
|
|||
[OVS_KEY_ATTR_CT_LABEL] = { .len = sizeof(struct ovs_key_ct_label) },
|
||||
};
|
||||
|
||||
static bool check_attr_len(unsigned int attr_len, unsigned int expected_len)
|
||||
{
|
||||
return expected_len == attr_len ||
|
||||
expected_len == OVS_ATTR_NESTED ||
|
||||
expected_len == OVS_ATTR_VARIABLE;
|
||||
}
|
||||
|
||||
static bool is_all_zero(const u8 *fp, size_t size)
|
||||
{
|
||||
int i;
|
||||
|
|
@ -388,7 +401,7 @@ static int __parse_flow_nlattrs(const struct nlattr *attr,
|
|||
}
|
||||
|
||||
expected_len = ovs_key_lens[type].len;
|
||||
if (nla_len(nla) != expected_len && expected_len != OVS_ATTR_NESTED) {
|
||||
if (!check_attr_len(nla_len(nla), expected_len)) {
|
||||
OVS_NLERR(log, "Key %d has unexpected len %d expected %d",
|
||||
type, nla_len(nla), expected_len);
|
||||
return -EINVAL;
|
||||
|
|
@ -473,29 +486,50 @@ static int genev_tun_opt_from_nlattr(const struct nlattr *a,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct nla_policy vxlan_opt_policy[OVS_VXLAN_EXT_MAX + 1] = {
|
||||
[OVS_VXLAN_EXT_GBP] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static int vxlan_tun_opt_from_nlattr(const struct nlattr *a,
|
||||
static int vxlan_tun_opt_from_nlattr(const struct nlattr *attr,
|
||||
struct sw_flow_match *match, bool is_mask,
|
||||
bool log)
|
||||
{
|
||||
struct nlattr *tb[OVS_VXLAN_EXT_MAX+1];
|
||||
struct nlattr *a;
|
||||
int rem;
|
||||
unsigned long opt_key_offset;
|
||||
struct vxlan_metadata opts;
|
||||
int err;
|
||||
|
||||
BUILD_BUG_ON(sizeof(opts) > sizeof(match->key->tun_opts));
|
||||
|
||||
err = nla_parse_nested(tb, OVS_VXLAN_EXT_MAX, a, vxlan_opt_policy);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
memset(&opts, 0, sizeof(opts));
|
||||
nla_for_each_nested(a, attr, rem) {
|
||||
int type = nla_type(a);
|
||||
|
||||
if (tb[OVS_VXLAN_EXT_GBP])
|
||||
opts.gbp = nla_get_u32(tb[OVS_VXLAN_EXT_GBP]);
|
||||
if (type > OVS_VXLAN_EXT_MAX) {
|
||||
OVS_NLERR(log, "VXLAN extension %d out of range max %d",
|
||||
type, OVS_VXLAN_EXT_MAX);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!check_attr_len(nla_len(a),
|
||||
ovs_vxlan_ext_key_lens[type].len)) {
|
||||
OVS_NLERR(log, "VXLAN extension %d has unexpected len %d expected %d",
|
||||
type, nla_len(a),
|
||||
ovs_vxlan_ext_key_lens[type].len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case OVS_VXLAN_EXT_GBP:
|
||||
opts.gbp = nla_get_u32(a);
|
||||
break;
|
||||
default:
|
||||
OVS_NLERR(log, "Unknown VXLAN extension attribute %d",
|
||||
type);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
if (rem) {
|
||||
OVS_NLERR(log, "VXLAN extension message has %d unknown bytes.",
|
||||
rem);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!is_mask)
|
||||
SW_FLOW_KEY_PUT(match, tun_opts_len, sizeof(opts), false);
|
||||
|
|
@ -528,8 +562,8 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ovs_tunnel_key_lens[type].len != nla_len(a) &&
|
||||
ovs_tunnel_key_lens[type].len != OVS_ATTR_NESTED) {
|
||||
if (!check_attr_len(nla_len(a),
|
||||
ovs_tunnel_key_lens[type].len)) {
|
||||
OVS_NLERR(log, "Tunnel attr %d has unexpected len %d expected %d",
|
||||
type, nla_len(a), ovs_tunnel_key_lens[type].len);
|
||||
return -EINVAL;
|
||||
|
|
@ -1052,10 +1086,13 @@ static void nlattr_set(struct nlattr *attr, u8 val,
|
|||
|
||||
/* The nlattr stream should already have been validated */
|
||||
nla_for_each_nested(nla, attr, rem) {
|
||||
if (tbl && tbl[nla_type(nla)].len == OVS_ATTR_NESTED)
|
||||
nlattr_set(nla, val, tbl[nla_type(nla)].next);
|
||||
else
|
||||
if (tbl[nla_type(nla)].len == OVS_ATTR_NESTED) {
|
||||
if (tbl[nla_type(nla)].next)
|
||||
tbl = tbl[nla_type(nla)].next;
|
||||
nlattr_set(nla, val, tbl);
|
||||
} else {
|
||||
memset(nla_data(nla), val, nla_len(nla));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1922,8 +1959,7 @@ static int validate_set(const struct nlattr *a,
|
|||
key_len /= 2;
|
||||
|
||||
if (key_type > OVS_KEY_ATTR_MAX ||
|
||||
(ovs_key_lens[key_type].len != key_len &&
|
||||
ovs_key_lens[key_type].len != OVS_ATTR_NESTED))
|
||||
!check_attr_len(key_len, ovs_key_lens[key_type].len))
|
||||
return -EINVAL;
|
||||
|
||||
if (masked && !validate_masked(nla_data(ovs_key), key_len))
|
||||
|
|
|
|||
|
|
@ -57,20 +57,21 @@ static u16 range_n_bytes(const struct sw_flow_key_range *range)
|
|||
}
|
||||
|
||||
void ovs_flow_mask_key(struct sw_flow_key *dst, const struct sw_flow_key *src,
|
||||
const struct sw_flow_mask *mask)
|
||||
bool full, const struct sw_flow_mask *mask)
|
||||
{
|
||||
const long *m = (const long *)((const u8 *)&mask->key +
|
||||
mask->range.start);
|
||||
const long *s = (const long *)((const u8 *)src +
|
||||
mask->range.start);
|
||||
long *d = (long *)((u8 *)dst + mask->range.start);
|
||||
int start = full ? 0 : mask->range.start;
|
||||
int len = full ? sizeof *dst : range_n_bytes(&mask->range);
|
||||
const long *m = (const long *)((const u8 *)&mask->key + start);
|
||||
const long *s = (const long *)((const u8 *)src + start);
|
||||
long *d = (long *)((u8 *)dst + start);
|
||||
int i;
|
||||
|
||||
/* The memory outside of the 'mask->range' are not set since
|
||||
* further operations on 'dst' only uses contents within
|
||||
* 'mask->range'.
|
||||
/* If 'full' is true then all of 'dst' is fully initialized. Otherwise,
|
||||
* if 'full' is false the memory outside of the 'mask->range' is left
|
||||
* uninitialized. This can be used as an optimization when further
|
||||
* operations on 'dst' only use contents within 'mask->range'.
|
||||
*/
|
||||
for (i = 0; i < range_n_bytes(&mask->range); i += sizeof(long))
|
||||
for (i = 0; i < len; i += sizeof(long))
|
||||
*d++ = *s++ & *m++;
|
||||
}
|
||||
|
||||
|
|
@ -475,7 +476,7 @@ static struct sw_flow *masked_flow_lookup(struct table_instance *ti,
|
|||
u32 hash;
|
||||
struct sw_flow_key masked_key;
|
||||
|
||||
ovs_flow_mask_key(&masked_key, unmasked, mask);
|
||||
ovs_flow_mask_key(&masked_key, unmasked, false, mask);
|
||||
hash = flow_hash(&masked_key, &mask->range);
|
||||
head = find_bucket(ti, hash);
|
||||
hlist_for_each_entry_rcu(flow, head, flow_table.node[ti->node_ver]) {
|
||||
|
|
|
|||
|
|
@ -86,5 +86,5 @@ struct sw_flow *ovs_flow_tbl_lookup_ufid(struct flow_table *,
|
|||
bool ovs_flow_cmp(const struct sw_flow *, const struct sw_flow_match *);
|
||||
|
||||
void ovs_flow_mask_key(struct sw_flow_key *dst, const struct sw_flow_key *src,
|
||||
const struct sw_flow_mask *mask);
|
||||
bool full, const struct sw_flow_mask *mask);
|
||||
#endif /* flow_table.h */
|
||||
|
|
|
|||
|
|
@ -230,6 +230,8 @@ struct packet_skb_cb {
|
|||
} sa;
|
||||
};
|
||||
|
||||
#define vio_le() virtio_legacy_is_little_endian()
|
||||
|
||||
#define PACKET_SKB_CB(__skb) ((struct packet_skb_cb *)((__skb)->cb))
|
||||
|
||||
#define GET_PBDQC_FROM_RB(x) ((struct tpacket_kbdq_core *)(&(x)->prb_bdqc))
|
||||
|
|
@ -2680,15 +2682,15 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
|
|||
goto out_unlock;
|
||||
|
||||
if ((vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) &&
|
||||
(__virtio16_to_cpu(false, vnet_hdr.csum_start) +
|
||||
__virtio16_to_cpu(false, vnet_hdr.csum_offset) + 2 >
|
||||
__virtio16_to_cpu(false, vnet_hdr.hdr_len)))
|
||||
vnet_hdr.hdr_len = __cpu_to_virtio16(false,
|
||||
__virtio16_to_cpu(false, vnet_hdr.csum_start) +
|
||||
__virtio16_to_cpu(false, vnet_hdr.csum_offset) + 2);
|
||||
(__virtio16_to_cpu(vio_le(), vnet_hdr.csum_start) +
|
||||
__virtio16_to_cpu(vio_le(), vnet_hdr.csum_offset) + 2 >
|
||||
__virtio16_to_cpu(vio_le(), vnet_hdr.hdr_len)))
|
||||
vnet_hdr.hdr_len = __cpu_to_virtio16(vio_le(),
|
||||
__virtio16_to_cpu(vio_le(), vnet_hdr.csum_start) +
|
||||
__virtio16_to_cpu(vio_le(), vnet_hdr.csum_offset) + 2);
|
||||
|
||||
err = -EINVAL;
|
||||
if (__virtio16_to_cpu(false, vnet_hdr.hdr_len) > len)
|
||||
if (__virtio16_to_cpu(vio_le(), vnet_hdr.hdr_len) > len)
|
||||
goto out_unlock;
|
||||
|
||||
if (vnet_hdr.gso_type != VIRTIO_NET_HDR_GSO_NONE) {
|
||||
|
|
@ -2731,7 +2733,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
|
|||
hlen = LL_RESERVED_SPACE(dev);
|
||||
tlen = dev->needed_tailroom;
|
||||
skb = packet_alloc_skb(sk, hlen + tlen, hlen, len,
|
||||
__virtio16_to_cpu(false, vnet_hdr.hdr_len),
|
||||
__virtio16_to_cpu(vio_le(), vnet_hdr.hdr_len),
|
||||
msg->msg_flags & MSG_DONTWAIT, &err);
|
||||
if (skb == NULL)
|
||||
goto out_unlock;
|
||||
|
|
@ -2778,8 +2780,8 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
|
|||
|
||||
if (po->has_vnet_hdr) {
|
||||
if (vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
|
||||
u16 s = __virtio16_to_cpu(false, vnet_hdr.csum_start);
|
||||
u16 o = __virtio16_to_cpu(false, vnet_hdr.csum_offset);
|
||||
u16 s = __virtio16_to_cpu(vio_le(), vnet_hdr.csum_start);
|
||||
u16 o = __virtio16_to_cpu(vio_le(), vnet_hdr.csum_offset);
|
||||
if (!skb_partial_csum_set(skb, s, o)) {
|
||||
err = -EINVAL;
|
||||
goto out_free;
|
||||
|
|
@ -2787,7 +2789,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
|
|||
}
|
||||
|
||||
skb_shinfo(skb)->gso_size =
|
||||
__virtio16_to_cpu(false, vnet_hdr.gso_size);
|
||||
__virtio16_to_cpu(vio_le(), vnet_hdr.gso_size);
|
||||
skb_shinfo(skb)->gso_type = gso_type;
|
||||
|
||||
/* Header must be checked, and gso_segs computed. */
|
||||
|
|
@ -3161,9 +3163,9 @@ static int packet_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
|
|||
|
||||
/* This is a hint as to how much should be linear. */
|
||||
vnet_hdr.hdr_len =
|
||||
__cpu_to_virtio16(false, skb_headlen(skb));
|
||||
__cpu_to_virtio16(vio_le(), skb_headlen(skb));
|
||||
vnet_hdr.gso_size =
|
||||
__cpu_to_virtio16(false, sinfo->gso_size);
|
||||
__cpu_to_virtio16(vio_le(), sinfo->gso_size);
|
||||
if (sinfo->gso_type & SKB_GSO_TCPV4)
|
||||
vnet_hdr.gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
|
||||
else if (sinfo->gso_type & SKB_GSO_TCPV6)
|
||||
|
|
@ -3181,9 +3183,9 @@ static int packet_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
|
|||
|
||||
if (skb->ip_summed == CHECKSUM_PARTIAL) {
|
||||
vnet_hdr.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
|
||||
vnet_hdr.csum_start = __cpu_to_virtio16(false,
|
||||
vnet_hdr.csum_start = __cpu_to_virtio16(vio_le(),
|
||||
skb_checksum_start_offset(skb));
|
||||
vnet_hdr.csum_offset = __cpu_to_virtio16(false,
|
||||
vnet_hdr.csum_offset = __cpu_to_virtio16(vio_le(),
|
||||
skb->csum_offset);
|
||||
} else if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
|
||||
vnet_hdr.flags = VIRTIO_NET_HDR_F_DATA_VALID;
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@
|
|||
|
||||
struct fw_head {
|
||||
u32 mask;
|
||||
bool mask_set;
|
||||
struct fw_filter __rcu *ht[HTSIZE];
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
|
|
@ -84,7 +83,7 @@ static int fw_classify(struct sk_buff *skb, const struct tcf_proto *tp,
|
|||
}
|
||||
}
|
||||
} else {
|
||||
/* old method */
|
||||
/* Old method: classify the packet using its skb mark. */
|
||||
if (id && (TC_H_MAJ(id) == 0 ||
|
||||
!(TC_H_MAJ(id ^ tp->q->handle)))) {
|
||||
res->classid = id;
|
||||
|
|
@ -114,14 +113,9 @@ static unsigned long fw_get(struct tcf_proto *tp, u32 handle)
|
|||
|
||||
static int fw_init(struct tcf_proto *tp)
|
||||
{
|
||||
struct fw_head *head;
|
||||
|
||||
head = kzalloc(sizeof(struct fw_head), GFP_KERNEL);
|
||||
if (head == NULL)
|
||||
return -ENOBUFS;
|
||||
|
||||
head->mask_set = false;
|
||||
rcu_assign_pointer(tp->root, head);
|
||||
/* We don't allocate fw_head here, because in the old method
|
||||
* we don't need it at all.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -252,7 +246,7 @@ static int fw_change(struct net *net, struct sk_buff *in_skb,
|
|||
int err;
|
||||
|
||||
if (!opt)
|
||||
return handle ? -EINVAL : 0;
|
||||
return handle ? -EINVAL : 0; /* Succeed if it is old method. */
|
||||
|
||||
err = nla_parse_nested(tb, TCA_FW_MAX, opt, fw_policy);
|
||||
if (err < 0)
|
||||
|
|
@ -302,11 +296,17 @@ static int fw_change(struct net *net, struct sk_buff *in_skb,
|
|||
if (!handle)
|
||||
return -EINVAL;
|
||||
|
||||
if (!head->mask_set) {
|
||||
head->mask = 0xFFFFFFFF;
|
||||
if (!head) {
|
||||
u32 mask = 0xFFFFFFFF;
|
||||
if (tb[TCA_FW_MASK])
|
||||
head->mask = nla_get_u32(tb[TCA_FW_MASK]);
|
||||
head->mask_set = true;
|
||||
mask = nla_get_u32(tb[TCA_FW_MASK]);
|
||||
|
||||
head = kzalloc(sizeof(*head), GFP_KERNEL);
|
||||
if (!head)
|
||||
return -ENOBUFS;
|
||||
head->mask = mask;
|
||||
|
||||
rcu_assign_pointer(tp->root, head);
|
||||
}
|
||||
|
||||
f = kzalloc(sizeof(struct fw_filter), GFP_KERNEL);
|
||||
|
|
|
|||
|
|
@ -1186,7 +1186,7 @@ static void sctp_v4_del_protocol(void)
|
|||
unregister_inetaddr_notifier(&sctp_inetaddr_notifier);
|
||||
}
|
||||
|
||||
static int __net_init sctp_net_init(struct net *net)
|
||||
static int __net_init sctp_defaults_init(struct net *net)
|
||||
{
|
||||
int status;
|
||||
|
||||
|
|
@ -1279,12 +1279,6 @@ static int __net_init sctp_net_init(struct net *net)
|
|||
|
||||
sctp_dbg_objcnt_init(net);
|
||||
|
||||
/* Initialize the control inode/socket for handling OOTB packets. */
|
||||
if ((status = sctp_ctl_sock_init(net))) {
|
||||
pr_err("Failed to initialize the SCTP control sock\n");
|
||||
goto err_ctl_sock_init;
|
||||
}
|
||||
|
||||
/* Initialize the local address list. */
|
||||
INIT_LIST_HEAD(&net->sctp.local_addr_list);
|
||||
spin_lock_init(&net->sctp.local_addr_lock);
|
||||
|
|
@ -1300,9 +1294,6 @@ static int __net_init sctp_net_init(struct net *net)
|
|||
|
||||
return 0;
|
||||
|
||||
err_ctl_sock_init:
|
||||
sctp_dbg_objcnt_exit(net);
|
||||
sctp_proc_exit(net);
|
||||
err_init_proc:
|
||||
cleanup_sctp_mibs(net);
|
||||
err_init_mibs:
|
||||
|
|
@ -1311,15 +1302,12 @@ err_sysctl_register:
|
|||
return status;
|
||||
}
|
||||
|
||||
static void __net_exit sctp_net_exit(struct net *net)
|
||||
static void __net_exit sctp_defaults_exit(struct net *net)
|
||||
{
|
||||
/* Free the local address list */
|
||||
sctp_free_addr_wq(net);
|
||||
sctp_free_local_addr_list(net);
|
||||
|
||||
/* Free the control endpoint. */
|
||||
inet_ctl_sock_destroy(net->sctp.ctl_sock);
|
||||
|
||||
sctp_dbg_objcnt_exit(net);
|
||||
|
||||
sctp_proc_exit(net);
|
||||
|
|
@ -1327,9 +1315,32 @@ static void __net_exit sctp_net_exit(struct net *net)
|
|||
sctp_sysctl_net_unregister(net);
|
||||
}
|
||||
|
||||
static struct pernet_operations sctp_net_ops = {
|
||||
.init = sctp_net_init,
|
||||
.exit = sctp_net_exit,
|
||||
static struct pernet_operations sctp_defaults_ops = {
|
||||
.init = sctp_defaults_init,
|
||||
.exit = sctp_defaults_exit,
|
||||
};
|
||||
|
||||
static int __net_init sctp_ctrlsock_init(struct net *net)
|
||||
{
|
||||
int status;
|
||||
|
||||
/* Initialize the control inode/socket for handling OOTB packets. */
|
||||
status = sctp_ctl_sock_init(net);
|
||||
if (status)
|
||||
pr_err("Failed to initialize the SCTP control sock\n");
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void __net_init sctp_ctrlsock_exit(struct net *net)
|
||||
{
|
||||
/* Free the control endpoint. */
|
||||
inet_ctl_sock_destroy(net->sctp.ctl_sock);
|
||||
}
|
||||
|
||||
static struct pernet_operations sctp_ctrlsock_ops = {
|
||||
.init = sctp_ctrlsock_init,
|
||||
.exit = sctp_ctrlsock_exit,
|
||||
};
|
||||
|
||||
/* Initialize the universe into something sensible. */
|
||||
|
|
@ -1462,8 +1473,11 @@ static __init int sctp_init(void)
|
|||
sctp_v4_pf_init();
|
||||
sctp_v6_pf_init();
|
||||
|
||||
status = sctp_v4_protosw_init();
|
||||
status = register_pernet_subsys(&sctp_defaults_ops);
|
||||
if (status)
|
||||
goto err_register_defaults;
|
||||
|
||||
status = sctp_v4_protosw_init();
|
||||
if (status)
|
||||
goto err_protosw_init;
|
||||
|
||||
|
|
@ -1471,9 +1485,9 @@ static __init int sctp_init(void)
|
|||
if (status)
|
||||
goto err_v6_protosw_init;
|
||||
|
||||
status = register_pernet_subsys(&sctp_net_ops);
|
||||
status = register_pernet_subsys(&sctp_ctrlsock_ops);
|
||||
if (status)
|
||||
goto err_register_pernet_subsys;
|
||||
goto err_register_ctrlsock;
|
||||
|
||||
status = sctp_v4_add_protocol();
|
||||
if (status)
|
||||
|
|
@ -1489,12 +1503,14 @@ out:
|
|||
err_v6_add_protocol:
|
||||
sctp_v4_del_protocol();
|
||||
err_add_protocol:
|
||||
unregister_pernet_subsys(&sctp_net_ops);
|
||||
err_register_pernet_subsys:
|
||||
unregister_pernet_subsys(&sctp_ctrlsock_ops);
|
||||
err_register_ctrlsock:
|
||||
sctp_v6_protosw_exit();
|
||||
err_v6_protosw_init:
|
||||
sctp_v4_protosw_exit();
|
||||
err_protosw_init:
|
||||
unregister_pernet_subsys(&sctp_defaults_ops);
|
||||
err_register_defaults:
|
||||
sctp_v4_pf_exit();
|
||||
sctp_v6_pf_exit();
|
||||
sctp_sysctl_unregister();
|
||||
|
|
@ -1527,12 +1543,14 @@ static __exit void sctp_exit(void)
|
|||
sctp_v6_del_protocol();
|
||||
sctp_v4_del_protocol();
|
||||
|
||||
unregister_pernet_subsys(&sctp_net_ops);
|
||||
unregister_pernet_subsys(&sctp_ctrlsock_ops);
|
||||
|
||||
/* Free protosw registrations */
|
||||
sctp_v6_protosw_exit();
|
||||
sctp_v4_protosw_exit();
|
||||
|
||||
unregister_pernet_subsys(&sctp_defaults_ops);
|
||||
|
||||
/* Unregister with socket layer. */
|
||||
sctp_v6_pf_exit();
|
||||
sctp_v4_pf_exit();
|
||||
|
|
|
|||
|
|
@ -539,6 +539,7 @@ bool tipc_msg_lookup_dest(struct net *net, struct sk_buff *skb, int *err)
|
|||
*err = -TIPC_ERR_NO_NAME;
|
||||
if (skb_linearize(skb))
|
||||
return false;
|
||||
msg = buf_msg(skb);
|
||||
if (msg_reroute_cnt(msg))
|
||||
return false;
|
||||
dnode = addr_domain(net, msg_lookup_scope(msg));
|
||||
|
|
|
|||
Loading…
Reference in a new issue