mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 03:01:39 -04:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6: (108 commits) ehea: Fixing statistics bonding: Fix lockdep warning after bond_vlan_rx_register() tunnels: Fix tunnels change rcu protection caif-u5500: Build config for CAIF shared mem driver caif-u5500: CAIF shared memory mailbox interface caif-u5500: CAIF shared memory transport protocol caif-u5500: Adding shared memory include drivers/isdn: delete double assignment drivers/net/typhoon.c: delete double assignment drivers/net/sb1000.c: delete double assignment qlcnic: define valid vlan id range qlcnic: reduce rx ring size qlcnic: fix mac learning ehea: fix use after free inetpeer: __rcu annotations fib_rules: __rcu annotates ctarget tunnels: add __rcu annotations net: add __rcu annotations to protocol ipv4: add __rcu annotations to routes.c qlge: bugfix: Restoring the vlan setting. ...
This commit is contained in:
commit
22cdbd1d57
145 changed files with 4008 additions and 1822 deletions
|
|
@ -346,8 +346,8 @@ int garp_request_join(const struct net_device *dev,
|
|||
const struct garp_application *appl,
|
||||
const void *data, u8 len, u8 type)
|
||||
{
|
||||
struct garp_port *port = dev->garp_port;
|
||||
struct garp_applicant *app = port->applicants[appl->type];
|
||||
struct garp_port *port = rtnl_dereference(dev->garp_port);
|
||||
struct garp_applicant *app = rtnl_dereference(port->applicants[appl->type]);
|
||||
struct garp_attr *attr;
|
||||
|
||||
spin_lock_bh(&app->lock);
|
||||
|
|
@ -366,8 +366,8 @@ void garp_request_leave(const struct net_device *dev,
|
|||
const struct garp_application *appl,
|
||||
const void *data, u8 len, u8 type)
|
||||
{
|
||||
struct garp_port *port = dev->garp_port;
|
||||
struct garp_applicant *app = port->applicants[appl->type];
|
||||
struct garp_port *port = rtnl_dereference(dev->garp_port);
|
||||
struct garp_applicant *app = rtnl_dereference(port->applicants[appl->type]);
|
||||
struct garp_attr *attr;
|
||||
|
||||
spin_lock_bh(&app->lock);
|
||||
|
|
@ -546,11 +546,11 @@ static int garp_init_port(struct net_device *dev)
|
|||
|
||||
static void garp_release_port(struct net_device *dev)
|
||||
{
|
||||
struct garp_port *port = dev->garp_port;
|
||||
struct garp_port *port = rtnl_dereference(dev->garp_port);
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i <= GARP_APPLICATION_MAX; i++) {
|
||||
if (port->applicants[i])
|
||||
if (rtnl_dereference(port->applicants[i]))
|
||||
return;
|
||||
}
|
||||
rcu_assign_pointer(dev->garp_port, NULL);
|
||||
|
|
@ -565,7 +565,7 @@ int garp_init_applicant(struct net_device *dev, struct garp_application *appl)
|
|||
|
||||
ASSERT_RTNL();
|
||||
|
||||
if (!dev->garp_port) {
|
||||
if (!rtnl_dereference(dev->garp_port)) {
|
||||
err = garp_init_port(dev);
|
||||
if (err < 0)
|
||||
goto err1;
|
||||
|
|
@ -601,8 +601,8 @@ EXPORT_SYMBOL_GPL(garp_init_applicant);
|
|||
|
||||
void garp_uninit_applicant(struct net_device *dev, struct garp_application *appl)
|
||||
{
|
||||
struct garp_port *port = dev->garp_port;
|
||||
struct garp_applicant *app = port->applicants[appl->type];
|
||||
struct garp_port *port = rtnl_dereference(dev->garp_port);
|
||||
struct garp_applicant *app = rtnl_dereference(port->applicants[appl->type]);
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@
|
|||
#define GARP_ADDR_MAX 0x2F
|
||||
#define GARP_ADDR_RANGE (GARP_ADDR_MAX - GARP_ADDR_MIN)
|
||||
|
||||
static const struct stp_proto *garp_protos[GARP_ADDR_RANGE + 1] __read_mostly;
|
||||
static const struct stp_proto *stp_proto __read_mostly;
|
||||
static const struct stp_proto __rcu *garp_protos[GARP_ADDR_RANGE + 1] __read_mostly;
|
||||
static const struct stp_proto __rcu *stp_proto __read_mostly;
|
||||
|
||||
static struct llc_sap *sap __read_mostly;
|
||||
static unsigned int sap_registered;
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
|
|||
|
||||
ASSERT_RTNL();
|
||||
|
||||
grp = real_dev->vlgrp;
|
||||
grp = rtnl_dereference(real_dev->vlgrp);
|
||||
BUG_ON(!grp);
|
||||
|
||||
/* Take it out of our own structures, but be sure to interlock with
|
||||
|
|
@ -177,7 +177,7 @@ int register_vlan_dev(struct net_device *dev)
|
|||
struct vlan_group *grp, *ngrp = NULL;
|
||||
int err;
|
||||
|
||||
grp = real_dev->vlgrp;
|
||||
grp = rtnl_dereference(real_dev->vlgrp);
|
||||
if (!grp) {
|
||||
ngrp = grp = vlan_group_alloc(real_dev);
|
||||
if (!grp)
|
||||
|
|
@ -385,7 +385,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
|
|||
dev->netdev_ops->ndo_vlan_rx_add_vid(dev, 0);
|
||||
}
|
||||
|
||||
grp = dev->vlgrp;
|
||||
grp = rtnl_dereference(dev->vlgrp);
|
||||
if (!grp)
|
||||
goto out;
|
||||
|
||||
|
|
|
|||
|
|
@ -1685,10 +1685,10 @@ EXPORT_SYMBOL(netif_device_attach);
|
|||
|
||||
static bool can_checksum_protocol(unsigned long features, __be16 protocol)
|
||||
{
|
||||
return ((features & NETIF_F_GEN_CSUM) ||
|
||||
((features & NETIF_F_IP_CSUM) &&
|
||||
return ((features & NETIF_F_NO_CSUM) ||
|
||||
((features & NETIF_F_V4_CSUM) &&
|
||||
protocol == htons(ETH_P_IP)) ||
|
||||
((features & NETIF_F_IPV6_CSUM) &&
|
||||
((features & NETIF_F_V6_CSUM) &&
|
||||
protocol == htons(ETH_P_IPV6)) ||
|
||||
((features & NETIF_F_FCOE_CRC) &&
|
||||
protocol == htons(ETH_P_FCOE)));
|
||||
|
|
@ -1696,22 +1696,18 @@ static bool can_checksum_protocol(unsigned long features, __be16 protocol)
|
|||
|
||||
static bool dev_can_checksum(struct net_device *dev, struct sk_buff *skb)
|
||||
{
|
||||
__be16 protocol = skb->protocol;
|
||||
int features = dev->features;
|
||||
|
||||
if (vlan_tx_tag_present(skb))
|
||||
if (vlan_tx_tag_present(skb)) {
|
||||
features &= dev->vlan_features;
|
||||
|
||||
if (can_checksum_protocol(features, skb->protocol))
|
||||
return true;
|
||||
|
||||
if (skb->protocol == htons(ETH_P_8021Q)) {
|
||||
} else if (protocol == htons(ETH_P_8021Q)) {
|
||||
struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
|
||||
if (can_checksum_protocol(dev->features & dev->vlan_features,
|
||||
veh->h_vlan_encapsulated_proto))
|
||||
return true;
|
||||
protocol = veh->h_vlan_encapsulated_proto;
|
||||
features &= dev->vlan_features;
|
||||
}
|
||||
|
||||
return false;
|
||||
return can_checksum_protocol(features, protocol);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2213,7 +2209,7 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,
|
|||
}
|
||||
|
||||
static DEFINE_PER_CPU(int, xmit_recursion);
|
||||
#define RECURSION_LIMIT 3
|
||||
#define RECURSION_LIMIT 10
|
||||
|
||||
/**
|
||||
* dev_queue_xmit - transmit a buffer
|
||||
|
|
@ -2413,7 +2409,7 @@ EXPORT_SYMBOL(__skb_get_rxhash);
|
|||
#ifdef CONFIG_RPS
|
||||
|
||||
/* One global table that all flow-based protocols share. */
|
||||
struct rps_sock_flow_table *rps_sock_flow_table __read_mostly;
|
||||
struct rps_sock_flow_table __rcu *rps_sock_flow_table __read_mostly;
|
||||
EXPORT_SYMBOL(rps_sock_flow_table);
|
||||
|
||||
/*
|
||||
|
|
@ -2425,7 +2421,7 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb,
|
|||
struct rps_dev_flow **rflowp)
|
||||
{
|
||||
struct netdev_rx_queue *rxqueue;
|
||||
struct rps_map *map = NULL;
|
||||
struct rps_map *map;
|
||||
struct rps_dev_flow_table *flow_table;
|
||||
struct rps_sock_flow_table *sock_flow_table;
|
||||
int cpu = -1;
|
||||
|
|
@ -2444,15 +2440,15 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb,
|
|||
} else
|
||||
rxqueue = dev->_rx;
|
||||
|
||||
if (rxqueue->rps_map) {
|
||||
map = rcu_dereference(rxqueue->rps_map);
|
||||
if (map && map->len == 1) {
|
||||
map = rcu_dereference(rxqueue->rps_map);
|
||||
if (map) {
|
||||
if (map->len == 1) {
|
||||
tcpu = map->cpus[0];
|
||||
if (cpu_online(tcpu))
|
||||
cpu = tcpu;
|
||||
goto done;
|
||||
}
|
||||
} else if (!rxqueue->rps_flow_table) {
|
||||
} else if (!rcu_dereference_raw(rxqueue->rps_flow_table)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
|
@ -5416,7 +5412,7 @@ void netdev_run_todo(void)
|
|||
/* paranoia */
|
||||
BUG_ON(netdev_refcnt_read(dev));
|
||||
WARN_ON(rcu_dereference_raw(dev->ip_ptr));
|
||||
WARN_ON(dev->ip6_ptr);
|
||||
WARN_ON(rcu_dereference_raw(dev->ip6_ptr));
|
||||
WARN_ON(dev->dn_ptr);
|
||||
|
||||
if (dev->destructor)
|
||||
|
|
|
|||
|
|
@ -351,12 +351,12 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
|
|||
|
||||
list_for_each_entry(r, &ops->rules_list, list) {
|
||||
if (r->pref == rule->target) {
|
||||
rule->ctarget = r;
|
||||
RCU_INIT_POINTER(rule->ctarget, r);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rule->ctarget == NULL)
|
||||
if (rcu_dereference_protected(rule->ctarget, 1) == NULL)
|
||||
unresolved = 1;
|
||||
} else if (rule->action == FR_ACT_GOTO)
|
||||
goto errout_free;
|
||||
|
|
@ -373,6 +373,11 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
|
|||
|
||||
fib_rule_get(rule);
|
||||
|
||||
if (last)
|
||||
list_add_rcu(&rule->list, &last->list);
|
||||
else
|
||||
list_add_rcu(&rule->list, &ops->rules_list);
|
||||
|
||||
if (ops->unresolved_rules) {
|
||||
/*
|
||||
* There are unresolved goto rules in the list, check if
|
||||
|
|
@ -381,7 +386,7 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
|
|||
list_for_each_entry(r, &ops->rules_list, list) {
|
||||
if (r->action == FR_ACT_GOTO &&
|
||||
r->target == rule->pref) {
|
||||
BUG_ON(r->ctarget != NULL);
|
||||
BUG_ON(rtnl_dereference(r->ctarget) != NULL);
|
||||
rcu_assign_pointer(r->ctarget, rule);
|
||||
if (--ops->unresolved_rules == 0)
|
||||
break;
|
||||
|
|
@ -395,11 +400,6 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
|
|||
if (unresolved)
|
||||
ops->unresolved_rules++;
|
||||
|
||||
if (last)
|
||||
list_add_rcu(&rule->list, &last->list);
|
||||
else
|
||||
list_add_rcu(&rule->list, &ops->rules_list);
|
||||
|
||||
notify_rule_change(RTM_NEWRULE, rule, ops, nlh, NETLINK_CB(skb).pid);
|
||||
flush_route_cache(ops);
|
||||
rules_ops_put(ops);
|
||||
|
|
@ -487,7 +487,7 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
|
|||
*/
|
||||
if (ops->nr_goto_rules > 0) {
|
||||
list_for_each_entry(tmp, &ops->rules_list, list) {
|
||||
if (tmp->ctarget == rule) {
|
||||
if (rtnl_dereference(tmp->ctarget) == rule) {
|
||||
rcu_assign_pointer(tmp->ctarget, NULL);
|
||||
ops->unresolved_rules++;
|
||||
}
|
||||
|
|
@ -545,7 +545,8 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule,
|
|||
frh->action = rule->action;
|
||||
frh->flags = rule->flags;
|
||||
|
||||
if (rule->action == FR_ACT_GOTO && rule->ctarget == NULL)
|
||||
if (rule->action == FR_ACT_GOTO &&
|
||||
rcu_dereference_raw(rule->ctarget) == NULL)
|
||||
frh->flags |= FIB_RULE_UNRESOLVED;
|
||||
|
||||
if (rule->iifname[0]) {
|
||||
|
|
|
|||
|
|
@ -89,8 +89,8 @@ int sk_filter(struct sock *sk, struct sk_buff *skb)
|
|||
rcu_read_lock_bh();
|
||||
filter = rcu_dereference_bh(sk->sk_filter);
|
||||
if (filter) {
|
||||
unsigned int pkt_len = sk_run_filter(skb, filter->insns,
|
||||
filter->len);
|
||||
unsigned int pkt_len = sk_run_filter(skb, filter->insns, filter->len);
|
||||
|
||||
err = pkt_len ? pskb_trim(skb, pkt_len) : -EPERM;
|
||||
}
|
||||
rcu_read_unlock_bh();
|
||||
|
|
|
|||
|
|
@ -598,7 +598,8 @@ static ssize_t store_rps_map(struct netdev_rx_queue *queue,
|
|||
}
|
||||
|
||||
spin_lock(&rps_map_lock);
|
||||
old_map = queue->rps_map;
|
||||
old_map = rcu_dereference_protected(queue->rps_map,
|
||||
lockdep_is_held(&rps_map_lock));
|
||||
rcu_assign_pointer(queue->rps_map, map);
|
||||
spin_unlock(&rps_map_lock);
|
||||
|
||||
|
|
@ -677,7 +678,8 @@ static ssize_t store_rps_dev_flow_table_cnt(struct netdev_rx_queue *queue,
|
|||
table = NULL;
|
||||
|
||||
spin_lock(&rps_dev_flow_lock);
|
||||
old_table = queue->rps_flow_table;
|
||||
old_table = rcu_dereference_protected(queue->rps_flow_table,
|
||||
lockdep_is_held(&rps_dev_flow_lock));
|
||||
rcu_assign_pointer(queue->rps_flow_table, table);
|
||||
spin_unlock(&rps_dev_flow_lock);
|
||||
|
||||
|
|
@ -705,13 +707,17 @@ static void rx_queue_release(struct kobject *kobj)
|
|||
{
|
||||
struct netdev_rx_queue *queue = to_rx_queue(kobj);
|
||||
struct netdev_rx_queue *first = queue->first;
|
||||
struct rps_map *map;
|
||||
struct rps_dev_flow_table *flow_table;
|
||||
|
||||
if (queue->rps_map)
|
||||
call_rcu(&queue->rps_map->rcu, rps_map_release);
|
||||
|
||||
if (queue->rps_flow_table)
|
||||
call_rcu(&queue->rps_flow_table->rcu,
|
||||
rps_dev_flow_table_release);
|
||||
map = rcu_dereference_raw(queue->rps_map);
|
||||
if (map)
|
||||
call_rcu(&map->rcu, rps_map_release);
|
||||
|
||||
flow_table = rcu_dereference_raw(queue->rps_flow_table);
|
||||
if (flow_table)
|
||||
call_rcu(&flow_table->rcu, rps_dev_flow_table_release);
|
||||
|
||||
if (atomic_dec_and_test(&first->count))
|
||||
kfree(first);
|
||||
|
|
|
|||
|
|
@ -42,7 +42,9 @@ static int net_assign_generic(struct net *net, int id, void *data)
|
|||
BUG_ON(!mutex_is_locked(&net_mutex));
|
||||
BUG_ON(id == 0);
|
||||
|
||||
ng = old_ng = net->gen;
|
||||
old_ng = rcu_dereference_protected(net->gen,
|
||||
lockdep_is_held(&net_mutex));
|
||||
ng = old_ng;
|
||||
if (old_ng->len >= id)
|
||||
goto assign;
|
||||
|
||||
|
|
|
|||
|
|
@ -771,10 +771,10 @@ done:
|
|||
static unsigned long num_arg(const char __user * user_buffer,
|
||||
unsigned long maxlen, unsigned long *num)
|
||||
{
|
||||
int i = 0;
|
||||
int i;
|
||||
*num = 0;
|
||||
|
||||
for (; i < maxlen; i++) {
|
||||
for (i = 0; i < maxlen; i++) {
|
||||
char c;
|
||||
if (get_user(c, &user_buffer[i]))
|
||||
return -EFAULT;
|
||||
|
|
@ -789,9 +789,9 @@ static unsigned long num_arg(const char __user * user_buffer,
|
|||
|
||||
static int strn_len(const char __user * user_buffer, unsigned int maxlen)
|
||||
{
|
||||
int i = 0;
|
||||
int i;
|
||||
|
||||
for (; i < maxlen; i++) {
|
||||
for (i = 0; i < maxlen; i++) {
|
||||
char c;
|
||||
if (get_user(c, &user_buffer[i]))
|
||||
return -EFAULT;
|
||||
|
|
@ -846,7 +846,7 @@ static ssize_t pktgen_if_write(struct file *file,
|
|||
{
|
||||
struct seq_file *seq = file->private_data;
|
||||
struct pktgen_dev *pkt_dev = seq->private;
|
||||
int i = 0, max, len;
|
||||
int i, max, len;
|
||||
char name[16], valstr[32];
|
||||
unsigned long value = 0;
|
||||
char *pg_result = NULL;
|
||||
|
|
@ -860,13 +860,13 @@ static ssize_t pktgen_if_write(struct file *file,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
max = count - i;
|
||||
tmp = count_trail_chars(&user_buffer[i], max);
|
||||
max = count;
|
||||
tmp = count_trail_chars(user_buffer, max);
|
||||
if (tmp < 0) {
|
||||
pr_warning("illegal format\n");
|
||||
return tmp;
|
||||
}
|
||||
i += tmp;
|
||||
i = tmp;
|
||||
|
||||
/* Read variable name */
|
||||
|
||||
|
|
@ -1764,7 +1764,7 @@ static ssize_t pktgen_thread_write(struct file *file,
|
|||
{
|
||||
struct seq_file *seq = file->private_data;
|
||||
struct pktgen_thread *t = seq->private;
|
||||
int i = 0, max, len, ret;
|
||||
int i, max, len, ret;
|
||||
char name[40];
|
||||
char *pg_result;
|
||||
|
||||
|
|
@ -1773,12 +1773,12 @@ static ssize_t pktgen_thread_write(struct file *file,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
max = count - i;
|
||||
len = count_trail_chars(&user_buffer[i], max);
|
||||
max = count;
|
||||
len = count_trail_chars(user_buffer, max);
|
||||
if (len < 0)
|
||||
return len;
|
||||
|
||||
i += len;
|
||||
i = len;
|
||||
|
||||
/* Read variable name */
|
||||
|
||||
|
|
@ -1975,7 +1975,7 @@ static struct net_device *pktgen_dev_get_by_name(struct pktgen_dev *pkt_dev,
|
|||
const char *ifname)
|
||||
{
|
||||
char b[IFNAMSIZ+5];
|
||||
int i = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; ifname[i] != '@'; i++) {
|
||||
if (i == IFNAMSIZ)
|
||||
|
|
@ -2519,8 +2519,8 @@ static void free_SAs(struct pktgen_dev *pkt_dev)
|
|||
{
|
||||
if (pkt_dev->cflows) {
|
||||
/* let go of the SAs if we have them */
|
||||
int i = 0;
|
||||
for (; i < pkt_dev->cflows; i++) {
|
||||
int i;
|
||||
for (i = 0; i < pkt_dev->cflows; i++) {
|
||||
struct xfrm_state *x = pkt_dev->flows[i].x;
|
||||
if (x) {
|
||||
xfrm_state_put(x);
|
||||
|
|
|
|||
|
|
@ -1225,7 +1225,7 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority)
|
|||
sock_reset_flag(newsk, SOCK_DONE);
|
||||
skb_queue_head_init(&newsk->sk_error_queue);
|
||||
|
||||
filter = newsk->sk_filter;
|
||||
filter = rcu_dereference_protected(newsk->sk_filter, 1);
|
||||
if (filter != NULL)
|
||||
sk_filter_charge(newsk, filter);
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,8 @@ static int rps_sock_flow_sysctl(ctl_table *table, int write,
|
|||
|
||||
mutex_lock(&sock_flow_mutex);
|
||||
|
||||
orig_sock_table = rps_sock_flow_table;
|
||||
orig_sock_table = rcu_dereference_protected(rps_sock_flow_table,
|
||||
lockdep_is_held(&sock_flow_mutex));
|
||||
size = orig_size = orig_sock_table ? orig_sock_table->mask + 1 : 0;
|
||||
|
||||
ret = proc_dointvec(&tmp, write, buffer, lenp, ppos);
|
||||
|
|
|
|||
|
|
@ -120,11 +120,12 @@ static inline void fn_rebuild_zone(struct fn_zone *fz,
|
|||
struct fib_node *f;
|
||||
|
||||
hlist_for_each_entry_safe(f, node, n, &old_ht[i], fn_hash) {
|
||||
struct hlist_head __rcu *new_head;
|
||||
struct hlist_head *new_head;
|
||||
|
||||
hlist_del_rcu(&f->fn_hash);
|
||||
|
||||
new_head = &fz->fz_hash[fn_hash(f->fn_key, fz)];
|
||||
new_head = rcu_dereference_protected(fz->fz_hash, 1) +
|
||||
fn_hash(f->fn_key, fz);
|
||||
hlist_add_head_rcu(&f->fn_hash, new_head);
|
||||
}
|
||||
}
|
||||
|
|
@ -179,8 +180,8 @@ static void fn_rehash_zone(struct fn_zone *fz)
|
|||
memcpy(&nfz, fz, sizeof(nfz));
|
||||
|
||||
write_seqlock_bh(&fz->fz_lock);
|
||||
old_ht = fz->fz_hash;
|
||||
nfz.fz_hash = ht;
|
||||
old_ht = rcu_dereference_protected(fz->fz_hash, 1);
|
||||
RCU_INIT_POINTER(nfz.fz_hash, ht);
|
||||
nfz.fz_hashmask = new_hashmask;
|
||||
nfz.fz_divisor = new_divisor;
|
||||
fn_rebuild_zone(&nfz, old_ht, old_divisor);
|
||||
|
|
@ -236,7 +237,7 @@ fn_new_zone(struct fn_hash *table, int z)
|
|||
seqlock_init(&fz->fz_lock);
|
||||
fz->fz_divisor = z ? EMBEDDED_HASH_SIZE : 1;
|
||||
fz->fz_hashmask = fz->fz_divisor - 1;
|
||||
fz->fz_hash = fz->fz_embedded_hash;
|
||||
RCU_INIT_POINTER(fz->fz_hash, fz->fz_embedded_hash);
|
||||
fz->fz_order = z;
|
||||
fz->fz_revorder = 32 - z;
|
||||
fz->fz_mask = inet_make_mask(z);
|
||||
|
|
@ -272,7 +273,7 @@ int fib_table_lookup(struct fib_table *tb,
|
|||
for (fz = rcu_dereference(t->fn_zone_list);
|
||||
fz != NULL;
|
||||
fz = rcu_dereference(fz->fz_next)) {
|
||||
struct hlist_head __rcu *head;
|
||||
struct hlist_head *head;
|
||||
struct hlist_node *node;
|
||||
struct fib_node *f;
|
||||
__be32 k;
|
||||
|
|
@ -282,7 +283,7 @@ int fib_table_lookup(struct fib_table *tb,
|
|||
seq = read_seqbegin(&fz->fz_lock);
|
||||
k = fz_key(flp->fl4_dst, fz);
|
||||
|
||||
head = &fz->fz_hash[fn_hash(k, fz)];
|
||||
head = rcu_dereference(fz->fz_hash) + fn_hash(k, fz);
|
||||
hlist_for_each_entry_rcu(f, node, head, fn_hash) {
|
||||
if (f->fn_key != k)
|
||||
continue;
|
||||
|
|
@ -311,6 +312,7 @@ void fib_table_select_default(struct fib_table *tb,
|
|||
struct fib_info *last_resort;
|
||||
struct fn_hash *t = (struct fn_hash *)tb->tb_data;
|
||||
struct fn_zone *fz = t->fn_zones[0];
|
||||
struct hlist_head *head;
|
||||
|
||||
if (fz == NULL)
|
||||
return;
|
||||
|
|
@ -320,7 +322,8 @@ void fib_table_select_default(struct fib_table *tb,
|
|||
order = -1;
|
||||
|
||||
rcu_read_lock();
|
||||
hlist_for_each_entry_rcu(f, node, &fz->fz_hash[0], fn_hash) {
|
||||
head = rcu_dereference(fz->fz_hash);
|
||||
hlist_for_each_entry_rcu(f, node, head, fn_hash) {
|
||||
struct fib_alias *fa;
|
||||
|
||||
list_for_each_entry_rcu(fa, &f->fn_alias, fa_list) {
|
||||
|
|
@ -374,7 +377,7 @@ out:
|
|||
/* Insert node F to FZ. */
|
||||
static inline void fib_insert_node(struct fn_zone *fz, struct fib_node *f)
|
||||
{
|
||||
struct hlist_head *head = &fz->fz_hash[fn_hash(f->fn_key, fz)];
|
||||
struct hlist_head *head = rtnl_dereference(fz->fz_hash) + fn_hash(f->fn_key, fz);
|
||||
|
||||
hlist_add_head_rcu(&f->fn_hash, head);
|
||||
}
|
||||
|
|
@ -382,7 +385,7 @@ static inline void fib_insert_node(struct fn_zone *fz, struct fib_node *f)
|
|||
/* Return the node in FZ matching KEY. */
|
||||
static struct fib_node *fib_find_node(struct fn_zone *fz, __be32 key)
|
||||
{
|
||||
struct hlist_head *head = &fz->fz_hash[fn_hash(key, fz)];
|
||||
struct hlist_head *head = rtnl_dereference(fz->fz_hash) + fn_hash(key, fz);
|
||||
struct hlist_node *node;
|
||||
struct fib_node *f;
|
||||
|
||||
|
|
@ -662,7 +665,7 @@ int fib_table_delete(struct fib_table *tb, struct fib_config *cfg)
|
|||
|
||||
static int fn_flush_list(struct fn_zone *fz, int idx)
|
||||
{
|
||||
struct hlist_head *head = &fz->fz_hash[idx];
|
||||
struct hlist_head *head = rtnl_dereference(fz->fz_hash) + idx;
|
||||
struct hlist_node *node, *n;
|
||||
struct fib_node *f;
|
||||
int found = 0;
|
||||
|
|
@ -761,14 +764,15 @@ fn_hash_dump_zone(struct sk_buff *skb, struct netlink_callback *cb,
|
|||
struct fn_zone *fz)
|
||||
{
|
||||
int h, s_h;
|
||||
struct hlist_head *head = rcu_dereference(fz->fz_hash);
|
||||
|
||||
if (fz->fz_hash == NULL)
|
||||
if (head == NULL)
|
||||
return skb->len;
|
||||
s_h = cb->args[3];
|
||||
for (h = s_h; h < fz->fz_divisor; h++) {
|
||||
if (hlist_empty(&fz->fz_hash[h]))
|
||||
if (hlist_empty(head + h))
|
||||
continue;
|
||||
if (fn_hash_dump_bucket(skb, cb, tb, fz, &fz->fz_hash[h]) < 0) {
|
||||
if (fn_hash_dump_bucket(skb, cb, tb, fz, head + h) < 0) {
|
||||
cb->args[3] = h;
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -872,7 +876,7 @@ static struct fib_alias *fib_get_first(struct seq_file *seq)
|
|||
if (!iter->zone->fz_nent)
|
||||
continue;
|
||||
|
||||
iter->hash_head = iter->zone->fz_hash;
|
||||
iter->hash_head = rcu_dereference(iter->zone->fz_hash);
|
||||
maxslot = iter->zone->fz_divisor;
|
||||
|
||||
for (iter->bucket = 0; iter->bucket < maxslot;
|
||||
|
|
@ -957,7 +961,7 @@ static struct fib_alias *fib_get_next(struct seq_file *seq)
|
|||
goto out;
|
||||
|
||||
iter->bucket = 0;
|
||||
iter->hash_head = iter->zone->fz_hash;
|
||||
iter->hash_head = rcu_dereference(iter->zone->fz_hash);
|
||||
|
||||
hlist_for_each_entry(fn, node, iter->hash_head, fn_hash) {
|
||||
list_for_each_entry(fa, &fn->fn_alias, fa_list) {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
#include <net/gre.h>
|
||||
|
||||
|
||||
static const struct gre_protocol *gre_proto[GREPROTO_MAX] __read_mostly;
|
||||
static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly;
|
||||
static DEFINE_SPINLOCK(gre_proto_lock);
|
||||
|
||||
int gre_add_protocol(const struct gre_protocol *proto, u8 version)
|
||||
|
|
@ -51,7 +51,8 @@ int gre_del_protocol(const struct gre_protocol *proto, u8 version)
|
|||
goto err_out;
|
||||
|
||||
spin_lock(&gre_proto_lock);
|
||||
if (gre_proto[version] != proto)
|
||||
if (rcu_dereference_protected(gre_proto[version],
|
||||
lockdep_is_held(&gre_proto_lock)) != proto)
|
||||
goto err_out_unlock;
|
||||
rcu_assign_pointer(gre_proto[version], NULL);
|
||||
spin_unlock(&gre_proto_lock);
|
||||
|
|
|
|||
|
|
@ -72,18 +72,19 @@ static struct kmem_cache *peer_cachep __read_mostly;
|
|||
#define node_height(x) x->avl_height
|
||||
|
||||
#define peer_avl_empty ((struct inet_peer *)&peer_fake_node)
|
||||
#define peer_avl_empty_rcu ((struct inet_peer __rcu __force *)&peer_fake_node)
|
||||
static const struct inet_peer peer_fake_node = {
|
||||
.avl_left = peer_avl_empty,
|
||||
.avl_right = peer_avl_empty,
|
||||
.avl_left = peer_avl_empty_rcu,
|
||||
.avl_right = peer_avl_empty_rcu,
|
||||
.avl_height = 0
|
||||
};
|
||||
|
||||
static struct {
|
||||
struct inet_peer *root;
|
||||
struct inet_peer __rcu *root;
|
||||
spinlock_t lock;
|
||||
int total;
|
||||
} peers = {
|
||||
.root = peer_avl_empty,
|
||||
.root = peer_avl_empty_rcu,
|
||||
.lock = __SPIN_LOCK_UNLOCKED(peers.lock),
|
||||
.total = 0,
|
||||
};
|
||||
|
|
@ -156,11 +157,14 @@ static void unlink_from_unused(struct inet_peer *p)
|
|||
*/
|
||||
#define lookup(_daddr, _stack) \
|
||||
({ \
|
||||
struct inet_peer *u, **v; \
|
||||
struct inet_peer *u; \
|
||||
struct inet_peer __rcu **v; \
|
||||
\
|
||||
stackptr = _stack; \
|
||||
*stackptr++ = &peers.root; \
|
||||
for (u = peers.root; u != peer_avl_empty; ) { \
|
||||
for (u = rcu_dereference_protected(peers.root, \
|
||||
lockdep_is_held(&peers.lock)); \
|
||||
u != peer_avl_empty; ) { \
|
||||
if (_daddr == u->v4daddr) \
|
||||
break; \
|
||||
if ((__force __u32)_daddr < (__force __u32)u->v4daddr) \
|
||||
|
|
@ -168,7 +172,8 @@ static void unlink_from_unused(struct inet_peer *p)
|
|||
else \
|
||||
v = &u->avl_right; \
|
||||
*stackptr++ = v; \
|
||||
u = *v; \
|
||||
u = rcu_dereference_protected(*v, \
|
||||
lockdep_is_held(&peers.lock)); \
|
||||
} \
|
||||
u; \
|
||||
})
|
||||
|
|
@ -209,13 +214,17 @@ static struct inet_peer *lookup_rcu_bh(__be32 daddr)
|
|||
/* Called with local BH disabled and the pool lock held. */
|
||||
#define lookup_rightempty(start) \
|
||||
({ \
|
||||
struct inet_peer *u, **v; \
|
||||
struct inet_peer *u; \
|
||||
struct inet_peer __rcu **v; \
|
||||
*stackptr++ = &start->avl_left; \
|
||||
v = &start->avl_left; \
|
||||
for (u = *v; u->avl_right != peer_avl_empty; ) { \
|
||||
for (u = rcu_dereference_protected(*v, \
|
||||
lockdep_is_held(&peers.lock)); \
|
||||
u->avl_right != peer_avl_empty_rcu; ) { \
|
||||
v = &u->avl_right; \
|
||||
*stackptr++ = v; \
|
||||
u = *v; \
|
||||
u = rcu_dereference_protected(*v, \
|
||||
lockdep_is_held(&peers.lock)); \
|
||||
} \
|
||||
u; \
|
||||
})
|
||||
|
|
@ -224,74 +233,86 @@ static struct inet_peer *lookup_rcu_bh(__be32 daddr)
|
|||
* Variable names are the proof of operation correctness.
|
||||
* Look into mm/map_avl.c for more detail description of the ideas.
|
||||
*/
|
||||
static void peer_avl_rebalance(struct inet_peer **stack[],
|
||||
struct inet_peer ***stackend)
|
||||
static void peer_avl_rebalance(struct inet_peer __rcu **stack[],
|
||||
struct inet_peer __rcu ***stackend)
|
||||
{
|
||||
struct inet_peer **nodep, *node, *l, *r;
|
||||
struct inet_peer __rcu **nodep;
|
||||
struct inet_peer *node, *l, *r;
|
||||
int lh, rh;
|
||||
|
||||
while (stackend > stack) {
|
||||
nodep = *--stackend;
|
||||
node = *nodep;
|
||||
l = node->avl_left;
|
||||
r = node->avl_right;
|
||||
node = rcu_dereference_protected(*nodep,
|
||||
lockdep_is_held(&peers.lock));
|
||||
l = rcu_dereference_protected(node->avl_left,
|
||||
lockdep_is_held(&peers.lock));
|
||||
r = rcu_dereference_protected(node->avl_right,
|
||||
lockdep_is_held(&peers.lock));
|
||||
lh = node_height(l);
|
||||
rh = node_height(r);
|
||||
if (lh > rh + 1) { /* l: RH+2 */
|
||||
struct inet_peer *ll, *lr, *lrl, *lrr;
|
||||
int lrh;
|
||||
ll = l->avl_left;
|
||||
lr = l->avl_right;
|
||||
ll = rcu_dereference_protected(l->avl_left,
|
||||
lockdep_is_held(&peers.lock));
|
||||
lr = rcu_dereference_protected(l->avl_right,
|
||||
lockdep_is_held(&peers.lock));
|
||||
lrh = node_height(lr);
|
||||
if (lrh <= node_height(ll)) { /* ll: RH+1 */
|
||||
node->avl_left = lr; /* lr: RH or RH+1 */
|
||||
node->avl_right = r; /* r: RH */
|
||||
RCU_INIT_POINTER(node->avl_left, lr); /* lr: RH or RH+1 */
|
||||
RCU_INIT_POINTER(node->avl_right, r); /* r: RH */
|
||||
node->avl_height = lrh + 1; /* RH+1 or RH+2 */
|
||||
l->avl_left = ll; /* ll: RH+1 */
|
||||
l->avl_right = node; /* node: RH+1 or RH+2 */
|
||||
RCU_INIT_POINTER(l->avl_left, ll); /* ll: RH+1 */
|
||||
RCU_INIT_POINTER(l->avl_right, node); /* node: RH+1 or RH+2 */
|
||||
l->avl_height = node->avl_height + 1;
|
||||
*nodep = l;
|
||||
RCU_INIT_POINTER(*nodep, l);
|
||||
} else { /* ll: RH, lr: RH+1 */
|
||||
lrl = lr->avl_left; /* lrl: RH or RH-1 */
|
||||
lrr = lr->avl_right; /* lrr: RH or RH-1 */
|
||||
node->avl_left = lrr; /* lrr: RH or RH-1 */
|
||||
node->avl_right = r; /* r: RH */
|
||||
lrl = rcu_dereference_protected(lr->avl_left,
|
||||
lockdep_is_held(&peers.lock)); /* lrl: RH or RH-1 */
|
||||
lrr = rcu_dereference_protected(lr->avl_right,
|
||||
lockdep_is_held(&peers.lock)); /* lrr: RH or RH-1 */
|
||||
RCU_INIT_POINTER(node->avl_left, lrr); /* lrr: RH or RH-1 */
|
||||
RCU_INIT_POINTER(node->avl_right, r); /* r: RH */
|
||||
node->avl_height = rh + 1; /* node: RH+1 */
|
||||
l->avl_left = ll; /* ll: RH */
|
||||
l->avl_right = lrl; /* lrl: RH or RH-1 */
|
||||
RCU_INIT_POINTER(l->avl_left, ll); /* ll: RH */
|
||||
RCU_INIT_POINTER(l->avl_right, lrl); /* lrl: RH or RH-1 */
|
||||
l->avl_height = rh + 1; /* l: RH+1 */
|
||||
lr->avl_left = l; /* l: RH+1 */
|
||||
lr->avl_right = node; /* node: RH+1 */
|
||||
RCU_INIT_POINTER(lr->avl_left, l); /* l: RH+1 */
|
||||
RCU_INIT_POINTER(lr->avl_right, node); /* node: RH+1 */
|
||||
lr->avl_height = rh + 2;
|
||||
*nodep = lr;
|
||||
RCU_INIT_POINTER(*nodep, lr);
|
||||
}
|
||||
} else if (rh > lh + 1) { /* r: LH+2 */
|
||||
struct inet_peer *rr, *rl, *rlr, *rll;
|
||||
int rlh;
|
||||
rr = r->avl_right;
|
||||
rl = r->avl_left;
|
||||
rr = rcu_dereference_protected(r->avl_right,
|
||||
lockdep_is_held(&peers.lock));
|
||||
rl = rcu_dereference_protected(r->avl_left,
|
||||
lockdep_is_held(&peers.lock));
|
||||
rlh = node_height(rl);
|
||||
if (rlh <= node_height(rr)) { /* rr: LH+1 */
|
||||
node->avl_right = rl; /* rl: LH or LH+1 */
|
||||
node->avl_left = l; /* l: LH */
|
||||
RCU_INIT_POINTER(node->avl_right, rl); /* rl: LH or LH+1 */
|
||||
RCU_INIT_POINTER(node->avl_left, l); /* l: LH */
|
||||
node->avl_height = rlh + 1; /* LH+1 or LH+2 */
|
||||
r->avl_right = rr; /* rr: LH+1 */
|
||||
r->avl_left = node; /* node: LH+1 or LH+2 */
|
||||
RCU_INIT_POINTER(r->avl_right, rr); /* rr: LH+1 */
|
||||
RCU_INIT_POINTER(r->avl_left, node); /* node: LH+1 or LH+2 */
|
||||
r->avl_height = node->avl_height + 1;
|
||||
*nodep = r;
|
||||
RCU_INIT_POINTER(*nodep, r);
|
||||
} else { /* rr: RH, rl: RH+1 */
|
||||
rlr = rl->avl_right; /* rlr: LH or LH-1 */
|
||||
rll = rl->avl_left; /* rll: LH or LH-1 */
|
||||
node->avl_right = rll; /* rll: LH or LH-1 */
|
||||
node->avl_left = l; /* l: LH */
|
||||
rlr = rcu_dereference_protected(rl->avl_right,
|
||||
lockdep_is_held(&peers.lock)); /* rlr: LH or LH-1 */
|
||||
rll = rcu_dereference_protected(rl->avl_left,
|
||||
lockdep_is_held(&peers.lock)); /* rll: LH or LH-1 */
|
||||
RCU_INIT_POINTER(node->avl_right, rll); /* rll: LH or LH-1 */
|
||||
RCU_INIT_POINTER(node->avl_left, l); /* l: LH */
|
||||
node->avl_height = lh + 1; /* node: LH+1 */
|
||||
r->avl_right = rr; /* rr: LH */
|
||||
r->avl_left = rlr; /* rlr: LH or LH-1 */
|
||||
RCU_INIT_POINTER(r->avl_right, rr); /* rr: LH */
|
||||
RCU_INIT_POINTER(r->avl_left, rlr); /* rlr: LH or LH-1 */
|
||||
r->avl_height = lh + 1; /* r: LH+1 */
|
||||
rl->avl_right = r; /* r: LH+1 */
|
||||
rl->avl_left = node; /* node: LH+1 */
|
||||
RCU_INIT_POINTER(rl->avl_right, r); /* r: LH+1 */
|
||||
RCU_INIT_POINTER(rl->avl_left, node); /* node: LH+1 */
|
||||
rl->avl_height = lh + 2;
|
||||
*nodep = rl;
|
||||
RCU_INIT_POINTER(*nodep, rl);
|
||||
}
|
||||
} else {
|
||||
node->avl_height = (lh > rh ? lh : rh) + 1;
|
||||
|
|
@ -303,10 +324,10 @@ static void peer_avl_rebalance(struct inet_peer **stack[],
|
|||
#define link_to_pool(n) \
|
||||
do { \
|
||||
n->avl_height = 1; \
|
||||
n->avl_left = peer_avl_empty; \
|
||||
n->avl_right = peer_avl_empty; \
|
||||
smp_wmb(); /* lockless readers can catch us now */ \
|
||||
**--stackptr = n; \
|
||||
n->avl_left = peer_avl_empty_rcu; \
|
||||
n->avl_right = peer_avl_empty_rcu; \
|
||||
/* lockless readers can catch us now */ \
|
||||
rcu_assign_pointer(**--stackptr, n); \
|
||||
peer_avl_rebalance(stack, stackptr); \
|
||||
} while (0)
|
||||
|
||||
|
|
@ -330,24 +351,25 @@ static void unlink_from_pool(struct inet_peer *p)
|
|||
* We use refcnt=-1 to alert lockless readers this entry is deleted.
|
||||
*/
|
||||
if (atomic_cmpxchg(&p->refcnt, 1, -1) == 1) {
|
||||
struct inet_peer **stack[PEER_MAXDEPTH];
|
||||
struct inet_peer ***stackptr, ***delp;
|
||||
struct inet_peer __rcu **stack[PEER_MAXDEPTH];
|
||||
struct inet_peer __rcu ***stackptr, ***delp;
|
||||
if (lookup(p->v4daddr, stack) != p)
|
||||
BUG();
|
||||
delp = stackptr - 1; /* *delp[0] == p */
|
||||
if (p->avl_left == peer_avl_empty) {
|
||||
if (p->avl_left == peer_avl_empty_rcu) {
|
||||
*delp[0] = p->avl_right;
|
||||
--stackptr;
|
||||
} else {
|
||||
/* look for a node to insert instead of p */
|
||||
struct inet_peer *t;
|
||||
t = lookup_rightempty(p);
|
||||
BUG_ON(*stackptr[-1] != t);
|
||||
BUG_ON(rcu_dereference_protected(*stackptr[-1],
|
||||
lockdep_is_held(&peers.lock)) != t);
|
||||
**--stackptr = t->avl_left;
|
||||
/* t is removed, t->v4daddr > x->v4daddr for any
|
||||
* x in p->avl_left subtree.
|
||||
* Put t in the old place of p. */
|
||||
*delp[0] = t;
|
||||
RCU_INIT_POINTER(*delp[0], t);
|
||||
t->avl_left = p->avl_left;
|
||||
t->avl_right = p->avl_right;
|
||||
t->avl_height = p->avl_height;
|
||||
|
|
@ -414,7 +436,7 @@ static int cleanup_once(unsigned long ttl)
|
|||
struct inet_peer *inet_getpeer(__be32 daddr, int create)
|
||||
{
|
||||
struct inet_peer *p;
|
||||
struct inet_peer **stack[PEER_MAXDEPTH], ***stackptr;
|
||||
struct inet_peer __rcu **stack[PEER_MAXDEPTH], ***stackptr;
|
||||
|
||||
/* Look up for the address quickly, lockless.
|
||||
* Because of a concurrent writer, we might not find an existing entry.
|
||||
|
|
|
|||
|
|
@ -1072,6 +1072,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
|
|||
break;
|
||||
}
|
||||
ipgre_tunnel_unlink(ign, t);
|
||||
synchronize_net();
|
||||
t->parms.iph.saddr = p.iph.saddr;
|
||||
t->parms.iph.daddr = p.iph.daddr;
|
||||
t->parms.i_key = p.i_key;
|
||||
|
|
|
|||
|
|
@ -238,7 +238,7 @@ int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc)
|
|||
but receiver should be enough clever f.e. to forward mtrace requests,
|
||||
sent to multicast group to reach destination designated router.
|
||||
*/
|
||||
struct ip_ra_chain *ip_ra_chain;
|
||||
struct ip_ra_chain __rcu *ip_ra_chain;
|
||||
static DEFINE_SPINLOCK(ip_ra_lock);
|
||||
|
||||
|
||||
|
|
@ -253,7 +253,8 @@ static void ip_ra_destroy_rcu(struct rcu_head *head)
|
|||
int ip_ra_control(struct sock *sk, unsigned char on,
|
||||
void (*destructor)(struct sock *))
|
||||
{
|
||||
struct ip_ra_chain *ra, *new_ra, **rap;
|
||||
struct ip_ra_chain *ra, *new_ra;
|
||||
struct ip_ra_chain __rcu **rap;
|
||||
|
||||
if (sk->sk_type != SOCK_RAW || inet_sk(sk)->inet_num == IPPROTO_RAW)
|
||||
return -EINVAL;
|
||||
|
|
@ -261,7 +262,10 @@ int ip_ra_control(struct sock *sk, unsigned char on,
|
|||
new_ra = on ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
|
||||
|
||||
spin_lock_bh(&ip_ra_lock);
|
||||
for (rap = &ip_ra_chain; (ra = *rap) != NULL; rap = &ra->next) {
|
||||
for (rap = &ip_ra_chain;
|
||||
(ra = rcu_dereference_protected(*rap,
|
||||
lockdep_is_held(&ip_ra_lock))) != NULL;
|
||||
rap = &ra->next) {
|
||||
if (ra->sk == sk) {
|
||||
if (on) {
|
||||
spin_unlock_bh(&ip_ra_lock);
|
||||
|
|
|
|||
|
|
@ -676,6 +676,7 @@ ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
|
|||
}
|
||||
t = netdev_priv(dev);
|
||||
ipip_tunnel_unlink(ipn, t);
|
||||
synchronize_net();
|
||||
t->parms.iph.saddr = p.iph.saddr;
|
||||
t->parms.iph.daddr = p.iph.daddr;
|
||||
memcpy(dev->dev_addr, &p.iph.saddr, 4);
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
#include <linux/spinlock.h>
|
||||
#include <net/protocol.h>
|
||||
|
||||
const struct net_protocol *inet_protos[MAX_INET_PROTOS] __read_mostly;
|
||||
const struct net_protocol __rcu *inet_protos[MAX_INET_PROTOS] __read_mostly;
|
||||
|
||||
/*
|
||||
* Add a protocol handler to the hash tables
|
||||
|
|
@ -38,7 +38,8 @@ int inet_add_protocol(const struct net_protocol *prot, unsigned char protocol)
|
|||
{
|
||||
int hash = protocol & (MAX_INET_PROTOS - 1);
|
||||
|
||||
return !cmpxchg(&inet_protos[hash], NULL, prot) ? 0 : -1;
|
||||
return !cmpxchg((const struct net_protocol **)&inet_protos[hash],
|
||||
NULL, prot) ? 0 : -1;
|
||||
}
|
||||
EXPORT_SYMBOL(inet_add_protocol);
|
||||
|
||||
|
|
@ -50,7 +51,8 @@ int inet_del_protocol(const struct net_protocol *prot, unsigned char protocol)
|
|||
{
|
||||
int ret, hash = protocol & (MAX_INET_PROTOS - 1);
|
||||
|
||||
ret = (cmpxchg(&inet_protos[hash], prot, NULL) == prot) ? 0 : -1;
|
||||
ret = (cmpxchg((const struct net_protocol **)&inet_protos[hash],
|
||||
prot, NULL) == prot) ? 0 : -1;
|
||||
|
||||
synchronize_net();
|
||||
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ const __u8 ip_tos2prio[16] = {
|
|||
*/
|
||||
|
||||
struct rt_hash_bucket {
|
||||
struct rtable *chain;
|
||||
struct rtable __rcu *chain;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) || \
|
||||
|
|
@ -280,7 +280,7 @@ static struct rtable *rt_cache_get_first(struct seq_file *seq)
|
|||
struct rtable *r = NULL;
|
||||
|
||||
for (st->bucket = rt_hash_mask; st->bucket >= 0; --st->bucket) {
|
||||
if (!rt_hash_table[st->bucket].chain)
|
||||
if (!rcu_dereference_raw(rt_hash_table[st->bucket].chain))
|
||||
continue;
|
||||
rcu_read_lock_bh();
|
||||
r = rcu_dereference_bh(rt_hash_table[st->bucket].chain);
|
||||
|
|
@ -300,17 +300,17 @@ static struct rtable *__rt_cache_get_next(struct seq_file *seq,
|
|||
{
|
||||
struct rt_cache_iter_state *st = seq->private;
|
||||
|
||||
r = r->dst.rt_next;
|
||||
r = rcu_dereference_bh(r->dst.rt_next);
|
||||
while (!r) {
|
||||
rcu_read_unlock_bh();
|
||||
do {
|
||||
if (--st->bucket < 0)
|
||||
return NULL;
|
||||
} while (!rt_hash_table[st->bucket].chain);
|
||||
} while (!rcu_dereference_raw(rt_hash_table[st->bucket].chain));
|
||||
rcu_read_lock_bh();
|
||||
r = rt_hash_table[st->bucket].chain;
|
||||
r = rcu_dereference_bh(rt_hash_table[st->bucket].chain);
|
||||
}
|
||||
return rcu_dereference_bh(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
static struct rtable *rt_cache_get_next(struct seq_file *seq,
|
||||
|
|
@ -721,19 +721,23 @@ static void rt_do_flush(int process_context)
|
|||
for (i = 0; i <= rt_hash_mask; i++) {
|
||||
if (process_context && need_resched())
|
||||
cond_resched();
|
||||
rth = rt_hash_table[i].chain;
|
||||
rth = rcu_dereference_raw(rt_hash_table[i].chain);
|
||||
if (!rth)
|
||||
continue;
|
||||
|
||||
spin_lock_bh(rt_hash_lock_addr(i));
|
||||
#ifdef CONFIG_NET_NS
|
||||
{
|
||||
struct rtable ** prev, * p;
|
||||
struct rtable __rcu **prev;
|
||||
struct rtable *p;
|
||||
|
||||
rth = rt_hash_table[i].chain;
|
||||
rth = rcu_dereference_protected(rt_hash_table[i].chain,
|
||||
lockdep_is_held(rt_hash_lock_addr(i)));
|
||||
|
||||
/* defer releasing the head of the list after spin_unlock */
|
||||
for (tail = rth; tail; tail = tail->dst.rt_next)
|
||||
for (tail = rth; tail;
|
||||
tail = rcu_dereference_protected(tail->dst.rt_next,
|
||||
lockdep_is_held(rt_hash_lock_addr(i))))
|
||||
if (!rt_is_expired(tail))
|
||||
break;
|
||||
if (rth != tail)
|
||||
|
|
@ -741,8 +745,12 @@ static void rt_do_flush(int process_context)
|
|||
|
||||
/* call rt_free on entries after the tail requiring flush */
|
||||
prev = &rt_hash_table[i].chain;
|
||||
for (p = *prev; p; p = next) {
|
||||
next = p->dst.rt_next;
|
||||
for (p = rcu_dereference_protected(*prev,
|
||||
lockdep_is_held(rt_hash_lock_addr(i)));
|
||||
p != NULL;
|
||||
p = next) {
|
||||
next = rcu_dereference_protected(p->dst.rt_next,
|
||||
lockdep_is_held(rt_hash_lock_addr(i)));
|
||||
if (!rt_is_expired(p)) {
|
||||
prev = &p->dst.rt_next;
|
||||
} else {
|
||||
|
|
@ -752,14 +760,15 @@ static void rt_do_flush(int process_context)
|
|||
}
|
||||
}
|
||||
#else
|
||||
rth = rt_hash_table[i].chain;
|
||||
rt_hash_table[i].chain = NULL;
|
||||
rth = rcu_dereference_protected(rt_hash_table[i].chain,
|
||||
lockdep_is_held(rt_hash_lock_addr(i)));
|
||||
rcu_assign_pointer(rt_hash_table[i].chain, NULL);
|
||||
tail = NULL;
|
||||
#endif
|
||||
spin_unlock_bh(rt_hash_lock_addr(i));
|
||||
|
||||
for (; rth != tail; rth = next) {
|
||||
next = rth->dst.rt_next;
|
||||
next = rcu_dereference_protected(rth->dst.rt_next, 1);
|
||||
rt_free(rth);
|
||||
}
|
||||
}
|
||||
|
|
@ -790,7 +799,7 @@ static int has_noalias(const struct rtable *head, const struct rtable *rth)
|
|||
while (aux != rth) {
|
||||
if (compare_hash_inputs(&aux->fl, &rth->fl))
|
||||
return 0;
|
||||
aux = aux->dst.rt_next;
|
||||
aux = rcu_dereference_protected(aux->dst.rt_next, 1);
|
||||
}
|
||||
return ONE;
|
||||
}
|
||||
|
|
@ -799,7 +808,8 @@ static void rt_check_expire(void)
|
|||
{
|
||||
static unsigned int rover;
|
||||
unsigned int i = rover, goal;
|
||||
struct rtable *rth, **rthp;
|
||||
struct rtable *rth;
|
||||
struct rtable __rcu **rthp;
|
||||
unsigned long samples = 0;
|
||||
unsigned long sum = 0, sum2 = 0;
|
||||
unsigned long delta;
|
||||
|
|
@ -825,11 +835,12 @@ static void rt_check_expire(void)
|
|||
|
||||
samples++;
|
||||
|
||||
if (*rthp == NULL)
|
||||
if (rcu_dereference_raw(*rthp) == NULL)
|
||||
continue;
|
||||
length = 0;
|
||||
spin_lock_bh(rt_hash_lock_addr(i));
|
||||
while ((rth = *rthp) != NULL) {
|
||||
while ((rth = rcu_dereference_protected(*rthp,
|
||||
lockdep_is_held(rt_hash_lock_addr(i)))) != NULL) {
|
||||
prefetch(rth->dst.rt_next);
|
||||
if (rt_is_expired(rth)) {
|
||||
*rthp = rth->dst.rt_next;
|
||||
|
|
@ -941,7 +952,8 @@ static int rt_garbage_collect(struct dst_ops *ops)
|
|||
static unsigned long last_gc;
|
||||
static int rover;
|
||||
static int equilibrium;
|
||||
struct rtable *rth, **rthp;
|
||||
struct rtable *rth;
|
||||
struct rtable __rcu **rthp;
|
||||
unsigned long now = jiffies;
|
||||
int goal;
|
||||
int entries = dst_entries_get_fast(&ipv4_dst_ops);
|
||||
|
|
@ -995,7 +1007,8 @@ static int rt_garbage_collect(struct dst_ops *ops)
|
|||
k = (k + 1) & rt_hash_mask;
|
||||
rthp = &rt_hash_table[k].chain;
|
||||
spin_lock_bh(rt_hash_lock_addr(k));
|
||||
while ((rth = *rthp) != NULL) {
|
||||
while ((rth = rcu_dereference_protected(*rthp,
|
||||
lockdep_is_held(rt_hash_lock_addr(k)))) != NULL) {
|
||||
if (!rt_is_expired(rth) &&
|
||||
!rt_may_expire(rth, tmo, expire)) {
|
||||
tmo >>= 1;
|
||||
|
|
@ -1071,7 +1084,7 @@ static int slow_chain_length(const struct rtable *head)
|
|||
|
||||
while (rth) {
|
||||
length += has_noalias(head, rth);
|
||||
rth = rth->dst.rt_next;
|
||||
rth = rcu_dereference_protected(rth->dst.rt_next, 1);
|
||||
}
|
||||
return length >> FRACT_BITS;
|
||||
}
|
||||
|
|
@ -1079,9 +1092,9 @@ static int slow_chain_length(const struct rtable *head)
|
|||
static int rt_intern_hash(unsigned hash, struct rtable *rt,
|
||||
struct rtable **rp, struct sk_buff *skb, int ifindex)
|
||||
{
|
||||
struct rtable *rth, **rthp;
|
||||
struct rtable *rth, *cand;
|
||||
struct rtable __rcu **rthp, **candp;
|
||||
unsigned long now;
|
||||
struct rtable *cand, **candp;
|
||||
u32 min_score;
|
||||
int chain_length;
|
||||
int attempts = !in_softirq();
|
||||
|
|
@ -1128,7 +1141,8 @@ restart:
|
|||
rthp = &rt_hash_table[hash].chain;
|
||||
|
||||
spin_lock_bh(rt_hash_lock_addr(hash));
|
||||
while ((rth = *rthp) != NULL) {
|
||||
while ((rth = rcu_dereference_protected(*rthp,
|
||||
lockdep_is_held(rt_hash_lock_addr(hash)))) != NULL) {
|
||||
if (rt_is_expired(rth)) {
|
||||
*rthp = rth->dst.rt_next;
|
||||
rt_free(rth);
|
||||
|
|
@ -1324,12 +1338,14 @@ EXPORT_SYMBOL(__ip_select_ident);
|
|||
|
||||
static void rt_del(unsigned hash, struct rtable *rt)
|
||||
{
|
||||
struct rtable **rthp, *aux;
|
||||
struct rtable __rcu **rthp;
|
||||
struct rtable *aux;
|
||||
|
||||
rthp = &rt_hash_table[hash].chain;
|
||||
spin_lock_bh(rt_hash_lock_addr(hash));
|
||||
ip_rt_put(rt);
|
||||
while ((aux = *rthp) != NULL) {
|
||||
while ((aux = rcu_dereference_protected(*rthp,
|
||||
lockdep_is_held(rt_hash_lock_addr(hash)))) != NULL) {
|
||||
if (aux == rt || rt_is_expired(aux)) {
|
||||
*rthp = aux->dst.rt_next;
|
||||
rt_free(aux);
|
||||
|
|
@ -1346,7 +1362,8 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
|
|||
{
|
||||
int i, k;
|
||||
struct in_device *in_dev = __in_dev_get_rcu(dev);
|
||||
struct rtable *rth, **rthp;
|
||||
struct rtable *rth;
|
||||
struct rtable __rcu **rthp;
|
||||
__be32 skeys[2] = { saddr, 0 };
|
||||
int ikeys[2] = { dev->ifindex, 0 };
|
||||
struct netevent_redirect netevent;
|
||||
|
|
@ -1379,7 +1396,7 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
|
|||
unsigned hash = rt_hash(daddr, skeys[i], ikeys[k],
|
||||
rt_genid(net));
|
||||
|
||||
rthp=&rt_hash_table[hash].chain;
|
||||
rthp = &rt_hash_table[hash].chain;
|
||||
|
||||
while ((rth = rcu_dereference(*rthp)) != NULL) {
|
||||
struct rtable *rt;
|
||||
|
|
|
|||
|
|
@ -14,27 +14,32 @@
|
|||
#include <net/protocol.h>
|
||||
#include <net/xfrm.h>
|
||||
|
||||
static struct xfrm_tunnel *tunnel4_handlers __read_mostly;
|
||||
static struct xfrm_tunnel *tunnel64_handlers __read_mostly;
|
||||
static struct xfrm_tunnel __rcu *tunnel4_handlers __read_mostly;
|
||||
static struct xfrm_tunnel __rcu *tunnel64_handlers __read_mostly;
|
||||
static DEFINE_MUTEX(tunnel4_mutex);
|
||||
|
||||
static inline struct xfrm_tunnel **fam_handlers(unsigned short family)
|
||||
static inline struct xfrm_tunnel __rcu **fam_handlers(unsigned short family)
|
||||
{
|
||||
return (family == AF_INET) ? &tunnel4_handlers : &tunnel64_handlers;
|
||||
}
|
||||
|
||||
int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family)
|
||||
{
|
||||
struct xfrm_tunnel **pprev;
|
||||
struct xfrm_tunnel __rcu **pprev;
|
||||
struct xfrm_tunnel *t;
|
||||
|
||||
int ret = -EEXIST;
|
||||
int priority = handler->priority;
|
||||
|
||||
mutex_lock(&tunnel4_mutex);
|
||||
|
||||
for (pprev = fam_handlers(family); *pprev; pprev = &(*pprev)->next) {
|
||||
if ((*pprev)->priority > priority)
|
||||
for (pprev = fam_handlers(family);
|
||||
(t = rcu_dereference_protected(*pprev,
|
||||
lockdep_is_held(&tunnel4_mutex))) != NULL;
|
||||
pprev = &t->next) {
|
||||
if (t->priority > priority)
|
||||
break;
|
||||
if ((*pprev)->priority == priority)
|
||||
if (t->priority == priority)
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
|
@ -52,13 +57,17 @@ EXPORT_SYMBOL(xfrm4_tunnel_register);
|
|||
|
||||
int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family)
|
||||
{
|
||||
struct xfrm_tunnel **pprev;
|
||||
struct xfrm_tunnel __rcu **pprev;
|
||||
struct xfrm_tunnel *t;
|
||||
int ret = -ENOENT;
|
||||
|
||||
mutex_lock(&tunnel4_mutex);
|
||||
|
||||
for (pprev = fam_handlers(family); *pprev; pprev = &(*pprev)->next) {
|
||||
if (*pprev == handler) {
|
||||
for (pprev = fam_handlers(family);
|
||||
(t = rcu_dereference_protected(*pprev,
|
||||
lockdep_is_held(&tunnel4_mutex))) != NULL;
|
||||
pprev = &t->next) {
|
||||
if (t == handler) {
|
||||
*pprev = handler->next;
|
||||
ret = 0;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1413,7 +1413,7 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
|
|||
}
|
||||
}
|
||||
|
||||
if (sk->sk_filter) {
|
||||
if (rcu_dereference_raw(sk->sk_filter)) {
|
||||
if (udp_lib_checksum_complete(skb))
|
||||
goto drop;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -836,7 +836,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i
|
|||
{
|
||||
struct inet6_dev *idev = ifp->idev;
|
||||
struct in6_addr addr, *tmpaddr;
|
||||
unsigned long tmp_prefered_lft, tmp_valid_lft, tmp_cstamp, tmp_tstamp;
|
||||
unsigned long tmp_prefered_lft, tmp_valid_lft, tmp_cstamp, tmp_tstamp, age;
|
||||
unsigned long regen_advance;
|
||||
int tmp_plen;
|
||||
int ret = 0;
|
||||
|
|
@ -886,12 +886,13 @@ retry:
|
|||
goto out;
|
||||
}
|
||||
memcpy(&addr.s6_addr[8], idev->rndid, 8);
|
||||
age = (jiffies - ifp->tstamp) / HZ;
|
||||
tmp_valid_lft = min_t(__u32,
|
||||
ifp->valid_lft,
|
||||
idev->cnf.temp_valid_lft);
|
||||
idev->cnf.temp_valid_lft + age);
|
||||
tmp_prefered_lft = min_t(__u32,
|
||||
ifp->prefered_lft,
|
||||
idev->cnf.temp_prefered_lft -
|
||||
idev->cnf.temp_prefered_lft + age -
|
||||
idev->cnf.max_desync_factor);
|
||||
tmp_plen = ifp->prefix_len;
|
||||
max_addresses = idev->cnf.max_addresses;
|
||||
|
|
@ -1426,8 +1427,10 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp)
|
|||
{
|
||||
struct inet6_dev *idev = ifp->idev;
|
||||
|
||||
if (addrconf_dad_end(ifp))
|
||||
if (addrconf_dad_end(ifp)) {
|
||||
in6_ifa_put(ifp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (net_ratelimit())
|
||||
printk(KERN_INFO "%s: IPv6 duplicate address %pI6c detected!\n",
|
||||
|
|
@ -2021,10 +2024,11 @@ ok:
|
|||
ipv6_ifa_notify(0, ift);
|
||||
}
|
||||
|
||||
if (create && in6_dev->cnf.use_tempaddr > 0) {
|
||||
if ((create || list_empty(&in6_dev->tempaddr_list)) && in6_dev->cnf.use_tempaddr > 0) {
|
||||
/*
|
||||
* When a new public address is created as described in [ADDRCONF],
|
||||
* also create a new temporary address.
|
||||
* also create a new temporary address. Also create a temporary
|
||||
* address if it's enabled but no temporary address currently exists.
|
||||
*/
|
||||
read_unlock_bh(&in6_dev->lock);
|
||||
ipv6_create_tempaddr(ifp, NULL);
|
||||
|
|
|
|||
|
|
@ -1284,6 +1284,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
|||
t = netdev_priv(dev);
|
||||
|
||||
ip6_tnl_unlink(ip6n, t);
|
||||
synchronize_net();
|
||||
err = ip6_tnl_change(t, &p);
|
||||
ip6_tnl_link(ip6n, t);
|
||||
netdev_state_change(dev);
|
||||
|
|
@ -1371,6 +1372,7 @@ static void ip6_tnl_dev_setup(struct net_device *dev)
|
|||
dev->flags |= IFF_NOARP;
|
||||
dev->addr_len = sizeof(struct in6_addr);
|
||||
dev->features |= NETIF_F_NETNS_LOCAL;
|
||||
dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -343,6 +343,10 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
|
|||
break;
|
||||
|
||||
case IPV6_TRANSPARENT:
|
||||
if (!capable(CAP_NET_ADMIN)) {
|
||||
retv = -EPERM;
|
||||
break;
|
||||
}
|
||||
if (optlen < sizeof(int))
|
||||
goto e_inval;
|
||||
/* we don't have a separate transparent bit for IPV6 we use the one in the IPv4 socket */
|
||||
|
|
|
|||
|
|
@ -5,10 +5,15 @@
|
|||
menu "IPv6: Netfilter Configuration"
|
||||
depends on INET && IPV6 && NETFILTER
|
||||
|
||||
config NF_DEFRAG_IPV6
|
||||
tristate
|
||||
default n
|
||||
|
||||
config NF_CONNTRACK_IPV6
|
||||
tristate "IPv6 connection tracking support"
|
||||
depends on INET && IPV6 && NF_CONNTRACK
|
||||
default m if NETFILTER_ADVANCED=n
|
||||
select NF_DEFRAG_IPV6
|
||||
---help---
|
||||
Connection tracking keeps a record of what packets have passed
|
||||
through your machine, in order to figure out how they are related
|
||||
|
|
|
|||
|
|
@ -12,11 +12,14 @@ obj-$(CONFIG_IP6_NF_SECURITY) += ip6table_security.o
|
|||
|
||||
# objects for l3 independent conntrack
|
||||
nf_conntrack_ipv6-objs := nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o
|
||||
nf_defrag_ipv6-objs := nf_defrag_ipv6_hooks.o nf_conntrack_reasm.o
|
||||
|
||||
# l3 independent conntrack
|
||||
obj-$(CONFIG_NF_CONNTRACK_IPV6) += nf_conntrack_ipv6.o nf_defrag_ipv6.o
|
||||
|
||||
# defrag
|
||||
nf_defrag_ipv6-objs := nf_defrag_ipv6_hooks.o nf_conntrack_reasm.o
|
||||
obj-$(CONFIG_NF_DEFRAG_IPV6) += nf_defrag_ipv6.o
|
||||
|
||||
# matches
|
||||
obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o
|
||||
obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o
|
||||
|
|
|
|||
|
|
@ -625,21 +625,24 @@ int nf_ct_frag6_init(void)
|
|||
inet_frags_init_net(&nf_init_frags);
|
||||
inet_frags_init(&nf_frags);
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
nf_ct_frag6_sysctl_header = register_sysctl_paths(nf_net_netfilter_sysctl_path,
|
||||
nf_ct_frag6_sysctl_table);
|
||||
if (!nf_ct_frag6_sysctl_header) {
|
||||
inet_frags_fini(&nf_frags);
|
||||
return -ENOMEM;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nf_ct_frag6_cleanup(void)
|
||||
{
|
||||
#ifdef CONFIG_SYSCTL
|
||||
unregister_sysctl_table(nf_ct_frag6_sysctl_header);
|
||||
nf_ct_frag6_sysctl_header = NULL;
|
||||
|
||||
#endif
|
||||
inet_frags_fini(&nf_frags);
|
||||
|
||||
nf_init_frags.low_thresh = 0;
|
||||
|
|
|
|||
|
|
@ -25,13 +25,14 @@
|
|||
#include <linux/spinlock.h>
|
||||
#include <net/protocol.h>
|
||||
|
||||
const struct inet6_protocol *inet6_protos[MAX_INET_PROTOS] __read_mostly;
|
||||
const struct inet6_protocol __rcu *inet6_protos[MAX_INET_PROTOS] __read_mostly;
|
||||
|
||||
int inet6_add_protocol(const struct inet6_protocol *prot, unsigned char protocol)
|
||||
{
|
||||
int hash = protocol & (MAX_INET_PROTOS - 1);
|
||||
|
||||
return !cmpxchg(&inet6_protos[hash], NULL, prot) ? 0 : -1;
|
||||
return !cmpxchg((const struct inet6_protocol **)&inet6_protos[hash],
|
||||
NULL, prot) ? 0 : -1;
|
||||
}
|
||||
EXPORT_SYMBOL(inet6_add_protocol);
|
||||
|
||||
|
|
@ -43,7 +44,8 @@ int inet6_del_protocol(const struct inet6_protocol *prot, unsigned char protocol
|
|||
{
|
||||
int ret, hash = protocol & (MAX_INET_PROTOS - 1);
|
||||
|
||||
ret = (cmpxchg(&inet6_protos[hash], prot, NULL) == prot) ? 0 : -1;
|
||||
ret = (cmpxchg((const struct inet6_protocol **)&inet6_protos[hash],
|
||||
prot, NULL) == prot) ? 0 : -1;
|
||||
|
||||
synchronize_net();
|
||||
|
||||
|
|
|
|||
|
|
@ -373,7 +373,7 @@ void raw6_icmp_error(struct sk_buff *skb, int nexthdr,
|
|||
|
||||
static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb)
|
||||
{
|
||||
if ((raw6_sk(sk)->checksum || sk->sk_filter) &&
|
||||
if ((raw6_sk(sk)->checksum || rcu_dereference_raw(sk->sk_filter)) &&
|
||||
skb_checksum_complete(skb)) {
|
||||
atomic_inc(&sk->sk_drops);
|
||||
kfree_skb(skb);
|
||||
|
|
|
|||
|
|
@ -963,6 +963,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
|
|||
}
|
||||
t = netdev_priv(dev);
|
||||
ipip6_tunnel_unlink(sitn, t);
|
||||
synchronize_net();
|
||||
t->parms.iph.saddr = p.iph.saddr;
|
||||
t->parms.iph.daddr = p.iph.daddr;
|
||||
memcpy(dev->dev_addr, &p.iph.saddr, 4);
|
||||
|
|
|
|||
|
|
@ -30,23 +30,26 @@
|
|||
#include <net/protocol.h>
|
||||
#include <net/xfrm.h>
|
||||
|
||||
static struct xfrm6_tunnel *tunnel6_handlers __read_mostly;
|
||||
static struct xfrm6_tunnel *tunnel46_handlers __read_mostly;
|
||||
static struct xfrm6_tunnel __rcu *tunnel6_handlers __read_mostly;
|
||||
static struct xfrm6_tunnel __rcu *tunnel46_handlers __read_mostly;
|
||||
static DEFINE_MUTEX(tunnel6_mutex);
|
||||
|
||||
int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family)
|
||||
{
|
||||
struct xfrm6_tunnel **pprev;
|
||||
struct xfrm6_tunnel __rcu **pprev;
|
||||
struct xfrm6_tunnel *t;
|
||||
int ret = -EEXIST;
|
||||
int priority = handler->priority;
|
||||
|
||||
mutex_lock(&tunnel6_mutex);
|
||||
|
||||
for (pprev = (family == AF_INET6) ? &tunnel6_handlers : &tunnel46_handlers;
|
||||
*pprev; pprev = &(*pprev)->next) {
|
||||
if ((*pprev)->priority > priority)
|
||||
(t = rcu_dereference_protected(*pprev,
|
||||
lockdep_is_held(&tunnel6_mutex))) != NULL;
|
||||
pprev = &t->next) {
|
||||
if (t->priority > priority)
|
||||
break;
|
||||
if ((*pprev)->priority == priority)
|
||||
if (t->priority == priority)
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
|
@ -65,14 +68,17 @@ EXPORT_SYMBOL(xfrm6_tunnel_register);
|
|||
|
||||
int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family)
|
||||
{
|
||||
struct xfrm6_tunnel **pprev;
|
||||
struct xfrm6_tunnel __rcu **pprev;
|
||||
struct xfrm6_tunnel *t;
|
||||
int ret = -ENOENT;
|
||||
|
||||
mutex_lock(&tunnel6_mutex);
|
||||
|
||||
for (pprev = (family == AF_INET6) ? &tunnel6_handlers : &tunnel46_handlers;
|
||||
*pprev; pprev = &(*pprev)->next) {
|
||||
if (*pprev == handler) {
|
||||
(t = rcu_dereference_protected(*pprev,
|
||||
lockdep_is_held(&tunnel6_mutex))) != NULL;
|
||||
pprev = &t->next) {
|
||||
if (t == handler) {
|
||||
*pprev = handler->next;
|
||||
ret = 0;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -527,7 +527,7 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
|
|||
}
|
||||
}
|
||||
|
||||
if (sk->sk_filter) {
|
||||
if (rcu_dereference_raw(sk->sk_filter)) {
|
||||
if (udp_lib_checksum_complete(skb))
|
||||
goto drop;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,6 +111,10 @@ struct l2tp_net {
|
|||
spinlock_t l2tp_session_hlist_lock;
|
||||
};
|
||||
|
||||
static void l2tp_session_set_header_len(struct l2tp_session *session, int version);
|
||||
static void l2tp_tunnel_free(struct l2tp_tunnel *tunnel);
|
||||
static void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel);
|
||||
|
||||
static inline struct l2tp_net *l2tp_pernet(struct net *net)
|
||||
{
|
||||
BUG_ON(!net);
|
||||
|
|
@ -118,6 +122,34 @@ static inline struct l2tp_net *l2tp_pernet(struct net *net)
|
|||
return net_generic(net, l2tp_net_id);
|
||||
}
|
||||
|
||||
|
||||
/* Tunnel reference counts. Incremented per session that is added to
|
||||
* the tunnel.
|
||||
*/
|
||||
static inline void l2tp_tunnel_inc_refcount_1(struct l2tp_tunnel *tunnel)
|
||||
{
|
||||
atomic_inc(&tunnel->ref_count);
|
||||
}
|
||||
|
||||
static inline void l2tp_tunnel_dec_refcount_1(struct l2tp_tunnel *tunnel)
|
||||
{
|
||||
if (atomic_dec_and_test(&tunnel->ref_count))
|
||||
l2tp_tunnel_free(tunnel);
|
||||
}
|
||||
#ifdef L2TP_REFCNT_DEBUG
|
||||
#define l2tp_tunnel_inc_refcount(_t) do { \
|
||||
printk(KERN_DEBUG "l2tp_tunnel_inc_refcount: %s:%d %s: cnt=%d\n", __func__, __LINE__, (_t)->name, atomic_read(&_t->ref_count)); \
|
||||
l2tp_tunnel_inc_refcount_1(_t); \
|
||||
} while (0)
|
||||
#define l2tp_tunnel_dec_refcount(_t) do { \
|
||||
printk(KERN_DEBUG "l2tp_tunnel_dec_refcount: %s:%d %s: cnt=%d\n", __func__, __LINE__, (_t)->name, atomic_read(&_t->ref_count)); \
|
||||
l2tp_tunnel_dec_refcount_1(_t); \
|
||||
} while (0)
|
||||
#else
|
||||
#define l2tp_tunnel_inc_refcount(t) l2tp_tunnel_inc_refcount_1(t)
|
||||
#define l2tp_tunnel_dec_refcount(t) l2tp_tunnel_dec_refcount_1(t)
|
||||
#endif
|
||||
|
||||
/* Session hash global list for L2TPv3.
|
||||
* The session_id SHOULD be random according to RFC3931, but several
|
||||
* L2TP implementations use incrementing session_ids. So we do a real
|
||||
|
|
@ -699,8 +731,8 @@ EXPORT_SYMBOL(l2tp_recv_common);
|
|||
* Returns 1 if the packet was not a good data packet and could not be
|
||||
* forwarded. All such packets are passed up to userspace to deal with.
|
||||
*/
|
||||
int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb,
|
||||
int (*payload_hook)(struct sk_buff *skb))
|
||||
static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb,
|
||||
int (*payload_hook)(struct sk_buff *skb))
|
||||
{
|
||||
struct l2tp_session *session = NULL;
|
||||
unsigned char *ptr, *optr;
|
||||
|
|
@ -812,7 +844,6 @@ error:
|
|||
|
||||
return 1;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(l2tp_udp_recv_core);
|
||||
|
||||
/* UDP encapsulation receive handler. See net/ipv4/udp.c.
|
||||
* Return codes:
|
||||
|
|
@ -922,7 +953,8 @@ static int l2tp_build_l2tpv3_header(struct l2tp_session *session, void *buf)
|
|||
return bufp - optr;
|
||||
}
|
||||
|
||||
int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, size_t data_len)
|
||||
static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb,
|
||||
size_t data_len)
|
||||
{
|
||||
struct l2tp_tunnel *tunnel = session->tunnel;
|
||||
unsigned int len = skb->len;
|
||||
|
|
@ -970,7 +1002,6 @@ int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, size_t dat
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(l2tp_xmit_core);
|
||||
|
||||
/* Automatically called when the skb is freed.
|
||||
*/
|
||||
|
|
@ -1089,7 +1120,7 @@ EXPORT_SYMBOL_GPL(l2tp_xmit_skb);
|
|||
* The tunnel context is deleted only when all session sockets have been
|
||||
* closed.
|
||||
*/
|
||||
void l2tp_tunnel_destruct(struct sock *sk)
|
||||
static void l2tp_tunnel_destruct(struct sock *sk)
|
||||
{
|
||||
struct l2tp_tunnel *tunnel;
|
||||
|
||||
|
|
@ -1128,11 +1159,10 @@ void l2tp_tunnel_destruct(struct sock *sk)
|
|||
end:
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL(l2tp_tunnel_destruct);
|
||||
|
||||
/* When the tunnel is closed, all the attached sessions need to go too.
|
||||
*/
|
||||
void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel)
|
||||
static void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel)
|
||||
{
|
||||
int hash;
|
||||
struct hlist_node *walk;
|
||||
|
|
@ -1193,12 +1223,11 @@ again:
|
|||
}
|
||||
write_unlock_bh(&tunnel->hlist_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(l2tp_tunnel_closeall);
|
||||
|
||||
/* Really kill the tunnel.
|
||||
* Come here only when all sessions have been cleared from the tunnel.
|
||||
*/
|
||||
void l2tp_tunnel_free(struct l2tp_tunnel *tunnel)
|
||||
static void l2tp_tunnel_free(struct l2tp_tunnel *tunnel)
|
||||
{
|
||||
struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net);
|
||||
|
||||
|
|
@ -1217,7 +1246,6 @@ void l2tp_tunnel_free(struct l2tp_tunnel *tunnel)
|
|||
atomic_dec(&l2tp_tunnel_count);
|
||||
kfree(tunnel);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(l2tp_tunnel_free);
|
||||
|
||||
/* Create a socket for the tunnel, if one isn't set up by
|
||||
* userspace. This is used for static tunnels where there is no
|
||||
|
|
@ -1512,7 +1540,7 @@ EXPORT_SYMBOL_GPL(l2tp_session_delete);
|
|||
/* We come here whenever a session's send_seq, cookie_len or
|
||||
* l2specific_len parameters are set.
|
||||
*/
|
||||
void l2tp_session_set_header_len(struct l2tp_session *session, int version)
|
||||
static void l2tp_session_set_header_len(struct l2tp_session *session, int version)
|
||||
{
|
||||
if (version == L2TP_HDR_VER_2) {
|
||||
session->hdr_len = 6;
|
||||
|
|
@ -1525,7 +1553,6 @@ void l2tp_session_set_header_len(struct l2tp_session *session, int version)
|
|||
}
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(l2tp_session_set_header_len);
|
||||
|
||||
struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -231,48 +231,15 @@ extern int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_i
|
|||
extern int l2tp_tunnel_delete(struct l2tp_tunnel *tunnel);
|
||||
extern struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg);
|
||||
extern int l2tp_session_delete(struct l2tp_session *session);
|
||||
extern void l2tp_tunnel_free(struct l2tp_tunnel *tunnel);
|
||||
extern void l2tp_session_free(struct l2tp_session *session);
|
||||
extern void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, unsigned char *ptr, unsigned char *optr, u16 hdrflags, int length, int (*payload_hook)(struct sk_buff *skb));
|
||||
extern int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb, int (*payload_hook)(struct sk_buff *skb));
|
||||
extern int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb);
|
||||
|
||||
extern int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, size_t data_len);
|
||||
extern int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len);
|
||||
extern void l2tp_tunnel_destruct(struct sock *sk);
|
||||
extern void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel);
|
||||
extern void l2tp_session_set_header_len(struct l2tp_session *session, int version);
|
||||
|
||||
extern int l2tp_nl_register_ops(enum l2tp_pwtype pw_type, const struct l2tp_nl_cmd_ops *ops);
|
||||
extern void l2tp_nl_unregister_ops(enum l2tp_pwtype pw_type);
|
||||
|
||||
/* Tunnel reference counts. Incremented per session that is added to
|
||||
* the tunnel.
|
||||
*/
|
||||
static inline void l2tp_tunnel_inc_refcount_1(struct l2tp_tunnel *tunnel)
|
||||
{
|
||||
atomic_inc(&tunnel->ref_count);
|
||||
}
|
||||
|
||||
static inline void l2tp_tunnel_dec_refcount_1(struct l2tp_tunnel *tunnel)
|
||||
{
|
||||
if (atomic_dec_and_test(&tunnel->ref_count))
|
||||
l2tp_tunnel_free(tunnel);
|
||||
}
|
||||
#ifdef L2TP_REFCNT_DEBUG
|
||||
#define l2tp_tunnel_inc_refcount(_t) do { \
|
||||
printk(KERN_DEBUG "l2tp_tunnel_inc_refcount: %s:%d %s: cnt=%d\n", __func__, __LINE__, (_t)->name, atomic_read(&_t->ref_count)); \
|
||||
l2tp_tunnel_inc_refcount_1(_t); \
|
||||
} while (0)
|
||||
#define l2tp_tunnel_dec_refcount(_t) do { \
|
||||
printk(KERN_DEBUG "l2tp_tunnel_dec_refcount: %s:%d %s: cnt=%d\n", __func__, __LINE__, (_t)->name, atomic_read(&_t->ref_count)); \
|
||||
l2tp_tunnel_dec_refcount_1(_t); \
|
||||
} while (0)
|
||||
#else
|
||||
#define l2tp_tunnel_inc_refcount(t) l2tp_tunnel_inc_refcount_1(t)
|
||||
#define l2tp_tunnel_dec_refcount(t) l2tp_tunnel_dec_refcount_1(t)
|
||||
#endif
|
||||
|
||||
/* Session reference counts. Incremented when code obtains a reference
|
||||
* to a session.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -576,7 +576,7 @@ out:
|
|||
return copied;
|
||||
}
|
||||
|
||||
struct proto l2tp_ip_prot = {
|
||||
static struct proto l2tp_ip_prot = {
|
||||
.name = "L2TP/IP",
|
||||
.owner = THIS_MODULE,
|
||||
.init = l2tp_ip_open,
|
||||
|
|
|
|||
|
|
@ -456,6 +456,7 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
|
|||
if (!sta)
|
||||
return NULL;
|
||||
|
||||
sta->last_rx = jiffies;
|
||||
set_sta_flags(sta, WLAN_STA_AUTHORIZED);
|
||||
|
||||
/* make sure mandatory rates are always added */
|
||||
|
|
|
|||
|
|
@ -748,7 +748,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||
hw->queues = IEEE80211_MAX_QUEUES;
|
||||
|
||||
local->workqueue =
|
||||
create_singlethread_workqueue(wiphy_name(local->hw.wiphy));
|
||||
alloc_ordered_workqueue(wiphy_name(local->hw.wiphy), 0);
|
||||
if (!local->workqueue) {
|
||||
result = -ENOMEM;
|
||||
goto fail_workqueue;
|
||||
|
|
@ -962,12 +962,6 @@ static void __exit ieee80211_exit(void)
|
|||
rc80211_minstrel_ht_exit();
|
||||
rc80211_minstrel_exit();
|
||||
|
||||
/*
|
||||
* For key todo, it'll be empty by now but the work
|
||||
* might still be scheduled.
|
||||
*/
|
||||
flush_scheduled_work();
|
||||
|
||||
if (mesh_allocated)
|
||||
ieee80211s_stop();
|
||||
|
||||
|
|
|
|||
|
|
@ -329,6 +329,9 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
|
|||
* if needed.
|
||||
*/
|
||||
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
|
||||
/* Skip invalid rates */
|
||||
if (info->control.rates[i].idx < 0)
|
||||
break;
|
||||
/* Rate masking supports only legacy rates for now */
|
||||
if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS)
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -525,6 +525,7 @@ config NETFILTER_XT_TARGET_TPROXY
|
|||
depends on NETFILTER_XTABLES
|
||||
depends on NETFILTER_ADVANCED
|
||||
select NF_DEFRAG_IPV4
|
||||
select NF_DEFRAG_IPV6 if IP6_NF_IPTABLES
|
||||
help
|
||||
This option adds a `TPROXY' target, which is somewhat similar to
|
||||
REDIRECT. It can only be used in the mangle table and is useful
|
||||
|
|
@ -927,6 +928,7 @@ config NETFILTER_XT_MATCH_SOCKET
|
|||
depends on NETFILTER_ADVANCED
|
||||
depends on !NF_CONNTRACK || NF_CONNTRACK
|
||||
select NF_DEFRAG_IPV4
|
||||
select NF_DEFRAG_IPV6 if IP6_NF_IPTABLES
|
||||
help
|
||||
This option adds a `socket' match, which can be used to match
|
||||
packets for which a TCP or UDP socket lookup finds a valid socket.
|
||||
|
|
|
|||
|
|
@ -21,7 +21,9 @@
|
|||
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||
|
||||
#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
|
||||
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
||||
|
||||
#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
|
||||
#define XT_TPROXY_HAVE_IPV6 1
|
||||
#include <net/if_inet6.h>
|
||||
#include <net/addrconf.h>
|
||||
#include <linux/netfilter_ipv6/ip6_tables.h>
|
||||
|
|
@ -172,7 +174,7 @@ tproxy_tg4_v1(struct sk_buff *skb, const struct xt_action_param *par)
|
|||
return tproxy_tg4(skb, tgi->laddr.ip, tgi->lport, tgi->mark_mask, tgi->mark_value);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
||||
#ifdef XT_TPROXY_HAVE_IPV6
|
||||
|
||||
static inline const struct in6_addr *
|
||||
tproxy_laddr6(struct sk_buff *skb, const struct in6_addr *user_laddr,
|
||||
|
|
@ -372,7 +374,7 @@ static struct xt_target tproxy_tg_reg[] __read_mostly = {
|
|||
.hooks = 1 << NF_INET_PRE_ROUTING,
|
||||
.me = THIS_MODULE,
|
||||
},
|
||||
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
||||
#ifdef XT_TPROXY_HAVE_IPV6
|
||||
{
|
||||
.name = "TPROXY",
|
||||
.family = NFPROTO_IPV6,
|
||||
|
|
@ -391,7 +393,7 @@ static struct xt_target tproxy_tg_reg[] __read_mostly = {
|
|||
static int __init tproxy_tg_init(void)
|
||||
{
|
||||
nf_defrag_ipv4_enable();
|
||||
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
||||
#ifdef XT_TPROXY_HAVE_IPV6
|
||||
nf_defrag_ipv6_enable();
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
#include <linux/skbuff.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||
#include <linux/netfilter_ipv6/ip6_tables.h>
|
||||
#include <net/tcp.h>
|
||||
#include <net/udp.h>
|
||||
#include <net/icmp.h>
|
||||
|
|
@ -22,7 +21,12 @@
|
|||
#include <net/inet_sock.h>
|
||||
#include <net/netfilter/nf_tproxy_core.h>
|
||||
#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
|
||||
|
||||
#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
|
||||
#define XT_SOCKET_HAVE_IPV6 1
|
||||
#include <linux/netfilter_ipv6/ip6_tables.h>
|
||||
#include <net/netfilter/ipv6/nf_defrag_ipv6.h>
|
||||
#endif
|
||||
|
||||
#include <linux/netfilter/xt_socket.h>
|
||||
|
||||
|
|
@ -186,7 +190,7 @@ socket_mt4_v1(const struct sk_buff *skb, struct xt_action_param *par)
|
|||
return socket_match(skb, par, par->matchinfo);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
||||
#ifdef XT_SOCKET_HAVE_IPV6
|
||||
|
||||
static int
|
||||
extract_icmp6_fields(const struct sk_buff *skb,
|
||||
|
|
@ -331,7 +335,7 @@ static struct xt_match socket_mt_reg[] __read_mostly = {
|
|||
(1 << NF_INET_LOCAL_IN),
|
||||
.me = THIS_MODULE,
|
||||
},
|
||||
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
||||
#ifdef XT_SOCKET_HAVE_IPV6
|
||||
{
|
||||
.name = "socket",
|
||||
.revision = 1,
|
||||
|
|
@ -348,7 +352,7 @@ static struct xt_match socket_mt_reg[] __read_mostly = {
|
|||
static int __init socket_mt_init(void)
|
||||
{
|
||||
nf_defrag_ipv4_enable();
|
||||
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
||||
#ifdef XT_SOCKET_HAVE_IPV6
|
||||
nf_defrag_ipv6_enable();
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -83,9 +83,9 @@ struct netlink_sock {
|
|||
struct module *module;
|
||||
};
|
||||
|
||||
struct listeners_rcu_head {
|
||||
struct rcu_head rcu_head;
|
||||
void *ptr;
|
||||
struct listeners {
|
||||
struct rcu_head rcu;
|
||||
unsigned long masks[0];
|
||||
};
|
||||
|
||||
#define NETLINK_KERNEL_SOCKET 0x1
|
||||
|
|
@ -119,7 +119,7 @@ struct nl_pid_hash {
|
|||
struct netlink_table {
|
||||
struct nl_pid_hash hash;
|
||||
struct hlist_head mc_list;
|
||||
unsigned long *listeners;
|
||||
struct listeners __rcu *listeners;
|
||||
unsigned int nl_nonroot;
|
||||
unsigned int groups;
|
||||
struct mutex *cb_mutex;
|
||||
|
|
@ -338,7 +338,7 @@ netlink_update_listeners(struct sock *sk)
|
|||
if (i < NLGRPLONGS(nlk_sk(sk)->ngroups))
|
||||
mask |= nlk_sk(sk)->groups[i];
|
||||
}
|
||||
tbl->listeners[i] = mask;
|
||||
tbl->listeners->masks[i] = mask;
|
||||
}
|
||||
/* this function is only called with the netlink table "grabbed", which
|
||||
* makes sure updates are visible before bind or setsockopt return. */
|
||||
|
|
@ -936,7 +936,7 @@ EXPORT_SYMBOL(netlink_unicast);
|
|||
int netlink_has_listeners(struct sock *sk, unsigned int group)
|
||||
{
|
||||
int res = 0;
|
||||
unsigned long *listeners;
|
||||
struct listeners *listeners;
|
||||
|
||||
BUG_ON(!netlink_is_kernel(sk));
|
||||
|
||||
|
|
@ -944,7 +944,7 @@ int netlink_has_listeners(struct sock *sk, unsigned int group)
|
|||
listeners = rcu_dereference(nl_table[sk->sk_protocol].listeners);
|
||||
|
||||
if (group - 1 < nl_table[sk->sk_protocol].groups)
|
||||
res = test_bit(group - 1, listeners);
|
||||
res = test_bit(group - 1, listeners->masks);
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
|
|
@ -1498,7 +1498,7 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups,
|
|||
struct socket *sock;
|
||||
struct sock *sk;
|
||||
struct netlink_sock *nlk;
|
||||
unsigned long *listeners = NULL;
|
||||
struct listeners *listeners = NULL;
|
||||
|
||||
BUG_ON(!nl_table);
|
||||
|
||||
|
|
@ -1523,8 +1523,7 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups,
|
|||
if (groups < 32)
|
||||
groups = 32;
|
||||
|
||||
listeners = kzalloc(NLGRPSZ(groups) + sizeof(struct listeners_rcu_head),
|
||||
GFP_KERNEL);
|
||||
listeners = kzalloc(sizeof(*listeners) + NLGRPSZ(groups), GFP_KERNEL);
|
||||
if (!listeners)
|
||||
goto out_sock_release;
|
||||
|
||||
|
|
@ -1541,7 +1540,7 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups,
|
|||
netlink_table_grab();
|
||||
if (!nl_table[unit].registered) {
|
||||
nl_table[unit].groups = groups;
|
||||
nl_table[unit].listeners = listeners;
|
||||
rcu_assign_pointer(nl_table[unit].listeners, listeners);
|
||||
nl_table[unit].cb_mutex = cb_mutex;
|
||||
nl_table[unit].module = module;
|
||||
nl_table[unit].registered = 1;
|
||||
|
|
@ -1572,43 +1571,28 @@ netlink_kernel_release(struct sock *sk)
|
|||
EXPORT_SYMBOL(netlink_kernel_release);
|
||||
|
||||
|
||||
static void netlink_free_old_listeners(struct rcu_head *rcu_head)
|
||||
static void listeners_free_rcu(struct rcu_head *head)
|
||||
{
|
||||
struct listeners_rcu_head *lrh;
|
||||
|
||||
lrh = container_of(rcu_head, struct listeners_rcu_head, rcu_head);
|
||||
kfree(lrh->ptr);
|
||||
kfree(container_of(head, struct listeners, rcu));
|
||||
}
|
||||
|
||||
int __netlink_change_ngroups(struct sock *sk, unsigned int groups)
|
||||
{
|
||||
unsigned long *listeners, *old = NULL;
|
||||
struct listeners_rcu_head *old_rcu_head;
|
||||
struct listeners *new, *old;
|
||||
struct netlink_table *tbl = &nl_table[sk->sk_protocol];
|
||||
|
||||
if (groups < 32)
|
||||
groups = 32;
|
||||
|
||||
if (NLGRPSZ(tbl->groups) < NLGRPSZ(groups)) {
|
||||
listeners = kzalloc(NLGRPSZ(groups) +
|
||||
sizeof(struct listeners_rcu_head),
|
||||
GFP_ATOMIC);
|
||||
if (!listeners)
|
||||
new = kzalloc(sizeof(*new) + NLGRPSZ(groups), GFP_ATOMIC);
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
old = tbl->listeners;
|
||||
memcpy(listeners, old, NLGRPSZ(tbl->groups));
|
||||
rcu_assign_pointer(tbl->listeners, listeners);
|
||||
/*
|
||||
* Free the old memory after an RCU grace period so we
|
||||
* don't leak it. We use call_rcu() here in order to be
|
||||
* able to call this function from atomic contexts. The
|
||||
* allocation of this memory will have reserved enough
|
||||
* space for struct listeners_rcu_head at the end.
|
||||
*/
|
||||
old_rcu_head = (void *)(tbl->listeners +
|
||||
NLGRPLONGS(tbl->groups));
|
||||
old_rcu_head->ptr = old;
|
||||
call_rcu(&old_rcu_head->rcu_head, netlink_free_old_listeners);
|
||||
old = rcu_dereference_raw(tbl->listeners);
|
||||
memcpy(new->masks, old->masks, NLGRPSZ(tbl->groups));
|
||||
rcu_assign_pointer(tbl->listeners, new);
|
||||
|
||||
call_rcu(&old->rcu, listeners_free_rcu);
|
||||
}
|
||||
tbl->groups = groups;
|
||||
|
||||
|
|
@ -2104,18 +2088,17 @@ static void __net_exit netlink_net_exit(struct net *net)
|
|||
|
||||
static void __init netlink_add_usersock_entry(void)
|
||||
{
|
||||
unsigned long *listeners;
|
||||
struct listeners *listeners;
|
||||
int groups = 32;
|
||||
|
||||
listeners = kzalloc(NLGRPSZ(groups) + sizeof(struct listeners_rcu_head),
|
||||
GFP_KERNEL);
|
||||
listeners = kzalloc(sizeof(*listeners) + NLGRPSZ(groups), GFP_KERNEL);
|
||||
if (!listeners)
|
||||
panic("netlink_add_usersock_entry: Cannot allocate listneres\n");
|
||||
panic("netlink_add_usersock_entry: Cannot allocate listeners\n");
|
||||
|
||||
netlink_table_grab();
|
||||
|
||||
nl_table[NETLINK_USERSOCK].groups = groups;
|
||||
nl_table[NETLINK_USERSOCK].listeners = listeners;
|
||||
rcu_assign_pointer(nl_table[NETLINK_USERSOCK].listeners, listeners);
|
||||
nl_table[NETLINK_USERSOCK].module = THIS_MODULE;
|
||||
nl_table[NETLINK_USERSOCK].registered = 1;
|
||||
|
||||
|
|
|
|||
|
|
@ -1167,7 +1167,7 @@ static int ignore_request(struct wiphy *wiphy,
|
|||
return 0;
|
||||
return -EALREADY;
|
||||
}
|
||||
return REG_INTERSECT;
|
||||
return 0;
|
||||
case NL80211_REGDOM_SET_BY_DRIVER:
|
||||
if (last_request->initiator == NL80211_REGDOM_SET_BY_CORE) {
|
||||
if (regdom_changes(pending_request->alpha2))
|
||||
|
|
|
|||
Loading…
Reference in a new issue