summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/core/dev.c8
-rw-r--r--net/core/dst.c17
-rw-r--r--net/core/neighbour.c4
-rw-r--r--net/core/rtnetlink.c8
-rw-r--r--net/decnet/dn_dev.c2
-rw-r--r--net/decnet/dn_rules.c2
-rw-r--r--net/ipv4/arp.c11
-rw-r--r--net/ipv4/cipso_ipv4.c64
-rw-r--r--net/ipv4/devinet.c415
-rw-r--r--net/ipv4/fib_frontend.c2
-rw-r--r--net/ipv4/fib_rules.c2
-rw-r--r--net/ipv4/igmp.c18
-rw-r--r--net/ipv4/ip_output.c4
-rw-r--r--net/ipv4/ipmr.c23
-rw-r--r--net/ipv4/netfilter/ip_tables.c81
-rw-r--r--net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c13
-rw-r--r--net/ipv4/proc.c2
-rw-r--r--net/ipv4/route.c14
-rw-r--r--net/ipv4/sysctl_net_ipv4.c6
-rw-r--r--net/ipv4/tcp_ipv4.c2
-rw-r--r--net/ipv4/tcp_probe.c6
-rw-r--r--net/ipv4/tcp_timer.c4
-rw-r--r--net/ipv4/udp.c241
-rw-r--r--net/ipv4/udp_impl.h6
-rw-r--r--net/ipv4/udplite.c7
-rw-r--r--net/ipv6/addrconf.c2
-rw-r--r--net/ipv6/fib6_rules.c2
-rw-r--r--net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c9
-rw-r--r--net/ipv6/route.c2
-rw-r--r--net/ipv6/udp.c21
-rw-r--r--net/ipv6/udp_impl.h2
-rw-r--r--net/ipv6/udplite.c2
-rw-r--r--net/irda/irlap_event.c28
-rw-r--r--net/irda/irlap_frame.c3
-rw-r--r--net/key/af_key.c10
-rw-r--r--net/netfilter/nf_conntrack_amanda.c12
-rw-r--r--net/netfilter/nf_conntrack_core.c26
-rw-r--r--net/netfilter/nf_conntrack_expect.c4
-rw-r--r--net/netfilter/nf_conntrack_helper.c2
-rw-r--r--net/netfilter/nf_conntrack_netlink.c34
-rw-r--r--net/netfilter/nf_conntrack_proto_gre.c2
-rw-r--r--net/netlabel/netlabel_cipso_v4.c2
-rw-r--r--net/netlabel/netlabel_kapi.c43
-rw-r--r--net/netlabel/netlabel_mgmt.c2
-rw-r--r--net/netlabel/netlabel_unlabeled.c2
-rw-r--r--net/netlink/attr.c8
-rw-r--r--net/netlink/genetlink.c2
-rw-r--r--net/sched/sch_atm.c1
-rw-r--r--net/sched/sch_cbq.c8
-rw-r--r--net/unix/af_unix.c13
-rw-r--r--net/xfrm/xfrm_policy.c63
-rw-r--r--net/xfrm/xfrm_state.c46
-rw-r--r--net/xfrm/xfrm_user.c9
53 files changed, 639 insertions, 683 deletions
diff --git a/net/core/dev.c b/net/core/dev.c
index 5a7f20f78574..26090621ea6b 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2577,7 +2577,7 @@ unsigned dev_get_flags(const struct net_device *dev)
int dev_change_flags(struct net_device *dev, unsigned flags)
{
- int ret;
+ int ret, changes;
int old_flags = dev->flags;
/*
@@ -2632,8 +2632,10 @@ int dev_change_flags(struct net_device *dev, unsigned flags)
dev_set_allmulti(dev, inc);
}
- if (old_flags ^ dev->flags)
- rtmsg_ifinfo(RTM_NEWLINK, dev, old_flags ^ dev->flags);
+ /* Exclude state transition flags, already notified */
+ changes = (old_flags ^ dev->flags) & ~(IFF_UP | IFF_RUNNING);
+ if (changes)
+ rtmsg_ifinfo(RTM_NEWLINK, dev, changes);
return ret;
}
diff --git a/net/core/dst.c b/net/core/dst.c
index 764bccb3d992..c6a05879d58c 100644
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -111,13 +111,7 @@ out:
spin_unlock(&dst_lock);
}
-static int dst_discard_in(struct sk_buff *skb)
-{
- kfree_skb(skb);
- return 0;
-}
-
-static int dst_discard_out(struct sk_buff *skb)
+static int dst_discard(struct sk_buff *skb)
{
kfree_skb(skb);
return 0;
@@ -138,8 +132,7 @@ void * dst_alloc(struct dst_ops * ops)
dst->ops = ops;
dst->lastuse = jiffies;
dst->path = dst;
- dst->input = dst_discard_in;
- dst->output = dst_discard_out;
+ dst->input = dst->output = dst_discard;
#if RT_CACHE_DEBUG >= 2
atomic_inc(&dst_total);
#endif
@@ -153,8 +146,7 @@ static void ___dst_free(struct dst_entry * dst)
protocol module is unloaded.
*/
if (dst->dev == NULL || !(dst->dev->flags&IFF_UP)) {
- dst->input = dst_discard_in;
- dst->output = dst_discard_out;
+ dst->input = dst->output = dst_discard;
}
dst->obsolete = 2;
}
@@ -242,8 +234,7 @@ static inline void dst_ifdown(struct dst_entry *dst, struct net_device *dev,
return;
if (!unregister) {
- dst->input = dst_discard_in;
- dst->output = dst_discard_out;
+ dst->input = dst->output = dst_discard;
} else {
dst->dev = &loopback_dev;
dev_hold(&loopback_dev);
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 6f3bb73053c2..9df26a07f067 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -1761,7 +1761,7 @@ static inline struct neigh_parms *lookup_neigh_params(struct neigh_table *tbl,
return NULL;
}
-static struct nla_policy nl_neightbl_policy[NDTA_MAX+1] __read_mostly = {
+static const struct nla_policy nl_neightbl_policy[NDTA_MAX+1] = {
[NDTA_NAME] = { .type = NLA_STRING },
[NDTA_THRESH1] = { .type = NLA_U32 },
[NDTA_THRESH2] = { .type = NLA_U32 },
@@ -1770,7 +1770,7 @@ static struct nla_policy nl_neightbl_policy[NDTA_MAX+1] __read_mostly = {
[NDTA_PARMS] = { .type = NLA_NESTED },
};
-static struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] __read_mostly = {
+static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {
[NDTPA_IFINDEX] = { .type = NLA_U32 },
[NDTPA_QUEUE_LEN] = { .type = NLA_U32 },
[NDTPA_PROXY_QLEN] = { .type = NLA_U32 },
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 27da9cdec6a8..02e8bf084277 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -551,7 +551,7 @@ cont:
return skb->len;
}
-static struct nla_policy ifla_policy[IFLA_MAX+1] __read_mostly = {
+static const struct nla_policy ifla_policy[IFLA_MAX+1] = {
[IFLA_IFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ-1 },
[IFLA_MAP] = { .len = sizeof(struct rtnl_link_ifmap) },
[IFLA_MTU] = { .type = NLA_U32 },
@@ -580,7 +580,7 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
err = -EINVAL;
ifm = nlmsg_data(nlh);
- if (ifm->ifi_index >= 0)
+ if (ifm->ifi_index > 0)
dev = dev_get_by_index(ifm->ifi_index);
else if (tb[IFLA_IFNAME])
dev = dev_get_by_name(ifname);
@@ -672,7 +672,7 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
* name provided implies that a name change has been
* requested.
*/
- if (ifm->ifi_index >= 0 && ifname[0]) {
+ if (ifm->ifi_index > 0 && ifname[0]) {
err = dev_change_name(dev, ifname);
if (err < 0)
goto errout_dev;
@@ -740,7 +740,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
return err;
ifm = nlmsg_data(nlh);
- if (ifm->ifi_index >= 0) {
+ if (ifm->ifi_index > 0) {
dev = dev_get_by_index(ifm->ifi_index);
if (dev == NULL)
return -ENODEV;
diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c
index 764a56a13e38..ab41c1879fd4 100644
--- a/net/decnet/dn_dev.c
+++ b/net/decnet/dn_dev.c
@@ -638,7 +638,7 @@ static struct dn_dev *dn_dev_by_index(int ifindex)
return dn_dev;
}
-static struct nla_policy dn_ifa_policy[IFA_MAX+1] __read_mostly = {
+static const struct nla_policy dn_ifa_policy[IFA_MAX+1] = {
[IFA_ADDRESS] = { .type = NLA_U16 },
[IFA_LOCAL] = { .type = NLA_U16 },
[IFA_LABEL] = { .type = NLA_STRING,
diff --git a/net/decnet/dn_rules.c b/net/decnet/dn_rules.c
index 17a1932216d6..84ff3dd37070 100644
--- a/net/decnet/dn_rules.c
+++ b/net/decnet/dn_rules.c
@@ -108,7 +108,7 @@ errout:
return err;
}
-static struct nla_policy dn_fib_rule_policy[FRA_MAX+1] __read_mostly = {
+static const struct nla_policy dn_fib_rule_policy[FRA_MAX+1] = {
FRA_GENERIC_POLICY,
};
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index 7110779a0244..e00767e8ebd9 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -877,7 +877,7 @@ static int arp_process(struct sk_buff *skb)
n = __neigh_lookup(&arp_tbl, &sip, dev, 0);
- if (ipv4_devconf.arp_accept) {
+ if (IPV4_DEVCONF_ALL(ARP_ACCEPT)) {
/* Unsolicited ARP is not accepted by default.
It is possible, that this option should be enabled for some
devices (strip is candidate)
@@ -987,11 +987,11 @@ static int arp_req_set(struct arpreq *r, struct net_device * dev)
return 0;
}
if (dev == NULL) {
- ipv4_devconf.proxy_arp = 1;
+ IPV4_DEVCONF_ALL(PROXY_ARP) = 1;
return 0;
}
if (__in_dev_get_rtnl(dev)) {
- __in_dev_get_rtnl(dev)->cnf.proxy_arp = 1;
+ IN_DEV_CONF_SET(__in_dev_get_rtnl(dev), PROXY_ARP, 1);
return 0;
}
return -ENXIO;
@@ -1093,11 +1093,12 @@ static int arp_req_delete(struct arpreq *r, struct net_device * dev)
return pneigh_delete(&arp_tbl, &ip, dev);
if (mask == 0) {
if (dev == NULL) {
- ipv4_devconf.proxy_arp = 0;
+ IPV4_DEVCONF_ALL(PROXY_ARP) = 0;
return 0;
}
if (__in_dev_get_rtnl(dev)) {
- __in_dev_get_rtnl(dev)->cnf.proxy_arp = 0;
+ IN_DEV_CONF_SET(__in_dev_get_rtnl(dev),
+ PROXY_ARP, 0);
return 0;
}
return -ENXIO;
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index 86a2b52aad38..ab56a052ce31 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -45,6 +45,7 @@
#include <net/cipso_ipv4.h>
#include <asm/atomic.h>
#include <asm/bug.h>
+#include <asm/unaligned.h>
struct cipso_v4_domhsh_entry {
char *domain;
@@ -1000,7 +1001,7 @@ static int cipso_v4_map_cat_enum_valid(const struct cipso_v4_doi *doi_def,
return -EFAULT;
for (iter = 0; iter < enumcat_len; iter += 2) {
- cat = ntohs(*((__be16 *)&enumcat[iter]));
+ cat = ntohs(get_unaligned((__be16 *)&enumcat[iter]));
if (cat <= cat_prev)
return -EFAULT;
cat_prev = cat;
@@ -1068,8 +1069,8 @@ static int cipso_v4_map_cat_enum_ntoh(const struct cipso_v4_doi *doi_def,
for (iter = 0; iter < net_cat_len; iter += 2) {
ret_val = netlbl_secattr_catmap_setbit(secattr->mls_cat,
- ntohs(*((__be16 *)&net_cat[iter])),
- GFP_ATOMIC);
+ ntohs(get_unaligned((__be16 *)&net_cat[iter])),
+ GFP_ATOMIC);
if (ret_val != 0)
return ret_val;
}
@@ -1102,9 +1103,10 @@ static int cipso_v4_map_cat_rng_valid(const struct cipso_v4_doi *doi_def,
return -EFAULT;
for (iter = 0; iter < rngcat_len; iter += 4) {
- cat_high = ntohs(*((__be16 *)&rngcat[iter]));
+ cat_high = ntohs(get_unaligned((__be16 *)&rngcat[iter]));
if ((iter + 4) <= rngcat_len)
- cat_low = ntohs(*((__be16 *)&rngcat[iter + 2]));
+ cat_low = ntohs(
+ get_unaligned((__be16 *)&rngcat[iter + 2]));
else
cat_low = 0;
@@ -1201,9 +1203,10 @@ static int cipso_v4_map_cat_rng_ntoh(const struct cipso_v4_doi *doi_def,
u16 cat_high;
for (net_iter = 0; net_iter < net_cat_len; net_iter += 4) {
- cat_high = ntohs(*((__be16 *)&net_cat[net_iter]));
+ cat_high = ntohs(get_unaligned((__be16 *)&net_cat[net_iter]));
if ((net_iter + 4) <= net_cat_len)
- cat_low = ntohs(*((__be16 *)&net_cat[net_iter + 2]));
+ cat_low = ntohs(
+ get_unaligned((__be16 *)&net_cat[net_iter + 2]));
else
cat_low = 0;
@@ -1565,7 +1568,7 @@ int cipso_v4_validate(unsigned char **option)
}
rcu_read_lock();
- doi_def = cipso_v4_doi_search(ntohl(*((__be32 *)&opt[2])));
+ doi_def = cipso_v4_doi_search(ntohl(get_unaligned((__be32 *)&opt[2])));
if (doi_def == NULL) {
err_offset = 2;
goto validate_return_locked;
@@ -1709,22 +1712,22 @@ void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway)
}
/**
- * cipso_v4_socket_setattr - Add a CIPSO option to a socket
- * @sock: the socket
+ * cipso_v4_sock_setattr - Add a CIPSO option to a socket
+ * @sk: the socket
* @doi_def: the CIPSO DOI to use
* @secattr: the specific security attributes of the socket
*
* Description:
* Set the CIPSO option on the given socket using the DOI definition and
* security attributes passed to the function. This function requires
- * exclusive access to @sock->sk, which means it either needs to be in the
- * process of being created or locked via lock_sock(sock->sk). Returns zero on
- * success and negative values on failure.
+ * exclusive access to @sk, which means it either needs to be in the
+ * process of being created or locked. Returns zero on success and negative
+ * values on failure.
*
*/
-int cipso_v4_socket_setattr(const struct socket *sock,
- const struct cipso_v4_doi *doi_def,
- const struct netlbl_lsm_secattr *secattr)
+int cipso_v4_sock_setattr(struct sock *sk,
+ const struct cipso_v4_doi *doi_def,
+ const struct netlbl_lsm_secattr *secattr)
{
int ret_val = -EPERM;
u32 iter;
@@ -1732,7 +1735,6 @@ int cipso_v4_socket_setattr(const struct socket *sock,
u32 buf_len = 0;
u32 opt_len;
struct ip_options *opt = NULL;
- struct sock *sk;
struct inet_sock *sk_inet;
struct inet_connection_sock *sk_conn;
@@ -1740,7 +1742,6 @@ int cipso_v4_socket_setattr(const struct socket *sock,
* defined yet but it is not a problem as the only users of these
* "lite" PF_INET sockets are functions which do an accept() call
* afterwards so we will label the socket as part of the accept(). */
- sk = sock->sk;
if (sk == NULL)
return 0;
@@ -1858,7 +1859,7 @@ int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
if (ret_val == 0)
return ret_val;
- doi = ntohl(*(__be32 *)&cipso_ptr[2]);
+ doi = ntohl(get_unaligned((__be32 *)&cipso_ptr[2]));
rcu_read_lock();
doi_def = cipso_v4_doi_search(doi);
if (doi_def == NULL) {
@@ -1892,29 +1893,6 @@ int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
}
/**
- * cipso_v4_socket_getattr - Get the security attributes from a socket
- * @sock: the socket
- * @secattr: the security attributes
- *
- * Description:
- * Query @sock to see if there is a CIPSO option attached to the socket and if
- * there is return the CIPSO security attributes in @secattr. Returns zero on
- * success and negative values on failure.
- *
- */
-int cipso_v4_socket_getattr(const struct socket *sock,
- struct netlbl_lsm_secattr *secattr)
-{
- int ret_val;
-
- lock_sock(sock->sk);
- ret_val = cipso_v4_sock_getattr(sock->sk, secattr);
- release_sock(sock->sk);
-
- return ret_val;
-}
-
-/**
* cipso_v4_skbuff_getattr - Get the security attributes from the CIPSO option
* @skb: the packet
* @secattr: the security attributes
@@ -1936,7 +1914,7 @@ int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
if (cipso_v4_cache_check(cipso_ptr, cipso_ptr[1], secattr) == 0)
return 0;
- doi = ntohl(*(__be32 *)&cipso_ptr[2]);
+ doi = ntohl(get_unaligned((__be32 *)&cipso_ptr[2]));
rcu_read_lock();
doi_def = cipso_v4_doi_search(doi);
if (doi_def == NULL)
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 7f95e6e9beeb..abf6352f990f 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -64,21 +64,27 @@
#include <net/rtnetlink.h>
struct ipv4_devconf ipv4_devconf = {
- .accept_redirects = 1,
- .send_redirects = 1,
- .secure_redirects = 1,
- .shared_media = 1,
+ .data = {
+ [NET_IPV4_CONF_ACCEPT_REDIRECTS - 1] = 1,
+ [NET_IPV4_CONF_SEND_REDIRECTS - 1] = 1,
+ [NET_IPV4_CONF_SECURE_REDIRECTS - 1] = 1,
+ [NET_IPV4_CONF_SHARED_MEDIA - 1] = 1,
+ },
};
static struct ipv4_devconf ipv4_devconf_dflt = {
- .accept_redirects = 1,
- .send_redirects = 1,
- .secure_redirects = 1,
- .shared_media = 1,
- .accept_source_route = 1,
+ .data = {
+ [NET_IPV4_CONF_ACCEPT_REDIRECTS - 1] = 1,
+ [NET_IPV4_CONF_SEND_REDIRECTS - 1] = 1,
+ [NET_IPV4_CONF_SECURE_REDIRECTS - 1] = 1,
+ [NET_IPV4_CONF_SHARED_MEDIA - 1] = 1,
+ [NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE - 1] = 1,
+ },
};
-static struct nla_policy ifa_ipv4_policy[IFA_MAX+1] __read_mostly = {
+#define IPV4_DEVCONF_DFLT(attr) IPV4_DEVCONF(ipv4_devconf_dflt, attr)
+
+static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = {
[IFA_LOCAL] = { .type = NLA_U32 },
[IFA_ADDRESS] = { .type = NLA_U32 },
[IFA_BROADCAST] = { .type = NLA_U32 },
@@ -141,7 +147,7 @@ void in_dev_finish_destroy(struct in_device *idev)
}
}
-struct in_device *inetdev_init(struct net_device *dev)
+static struct in_device *inetdev_init(struct net_device *dev)
{
struct in_device *in_dev;
@@ -321,12 +327,8 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
}
}
- if (destroy) {
+ if (destroy)
inet_free_ifa(ifa1);
-
- if (!in_dev->ifa_list)
- inetdev_destroy(in_dev);
- }
}
static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
@@ -399,12 +401,10 @@ static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
ASSERT_RTNL();
if (!in_dev) {
- in_dev = inetdev_init(dev);
- if (!in_dev) {
- inet_free_ifa(ifa);
- return -ENOBUFS;
- }
+ inet_free_ifa(ifa);
+ return -ENOBUFS;
}
+ ipv4_devconf_setall(in_dev);
if (ifa->ifa_dev != in_dev) {
BUG_TRAP(!ifa->ifa_dev);
in_dev_hold(in_dev);
@@ -514,13 +514,12 @@ static struct in_ifaddr *rtm_to_ifaddr(struct nlmsghdr *nlh)
in_dev = __in_dev_get_rtnl(dev);
if (in_dev == NULL) {
- in_dev = inetdev_init(dev);
- if (in_dev == NULL) {
- err = -ENOBUFS;
- goto errout;
- }
+ err = -ENOBUFS;
+ goto errout;
}
+ ipv4_devconf_setall(in_dev);
+
ifa = inet_alloc_ifa();
if (ifa == NULL) {
/*
@@ -1057,11 +1056,12 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
if (!in_dev) {
if (event == NETDEV_REGISTER) {
in_dev = inetdev_init(dev);
- if (!in_dev)
- panic("devinet: Failed to create loopback\n");
if (dev == &loopback_dev) {
- in_dev->cnf.no_xfrm = 1;
- in_dev->cnf.no_policy = 1;
+ if (!in_dev)
+ panic("devinet: "
+ "Failed to create loopback\n");
+ IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
+ IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
}
}
goto out;
@@ -1237,13 +1237,98 @@ errout:
#ifdef CONFIG_SYSCTL
+static void devinet_copy_dflt_conf(int i)
+{
+ struct net_device *dev;
+
+ read_lock(&dev_base_lock);
+ for_each_netdev(dev) {
+ struct in_device *in_dev;
+ rcu_read_lock();
+ in_dev = __in_dev_get_rcu(dev);
+ if (in_dev && !test_bit(i, in_dev->cnf.state))
+ in_dev->cnf.data[i] = ipv4_devconf_dflt.data[i];
+ rcu_read_unlock();
+ }
+ read_unlock(&dev_base_lock);
+}
+
+static int devinet_conf_proc(ctl_table *ctl, int write,
+ struct file* filp, void __user *buffer,
+ size_t *lenp, loff_t *ppos)
+{
+ int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
+
+ if (write) {
+ struct ipv4_devconf *cnf = ctl->extra1;
+ int i = (int *)ctl->data - cnf->data;
+
+ set_bit(i, cnf->state);
+
+ if (cnf == &ipv4_devconf_dflt)
+ devinet_copy_dflt_conf(i);
+ }
+
+ return ret;
+}
+
+static int devinet_conf_sysctl(ctl_table *table, int __user *name, int nlen,
+ void __user *oldval, size_t __user *oldlenp,
+ void __user *newval, size_t newlen)
+{
+ struct ipv4_devconf *cnf;
+ int *valp = table->data;
+ int new;
+ int i;
+
+ if (!newval || !newlen)
+ return 0;
+
+ if (newlen != sizeof(int))
+ return -EINVAL;
+
+ if (get_user(new, (int __user *)newval))
+ return -EFAULT;
+
+ if (new == *valp)
+ return 0;
+
+ if (oldval && oldlenp) {
+ size_t len;
+
+ if (get_user(len, oldlenp))
+ return -EFAULT;
+
+ if (len) {
+ if (len > table->maxlen)
+ len = table->maxlen;
+ if (copy_to_user(oldval, valp, len))
+ return -EFAULT;
+ if (put_user(len, oldlenp))
+ return -EFAULT;
+ }
+ }
+
+ *valp = new;
+
+ cnf = table->extra1;
+ i = (int *)table->data - cnf->data;
+
+ set_bit(i, cnf->state);
+
+ if (cnf == &ipv4_devconf_dflt)
+ devinet_copy_dflt_conf(i);
+
+ return 1;
+}
+
void inet_forward_change(void)
{
struct net_device *dev;
- int on = ipv4_devconf.forwarding;
+ int on = IPV4_DEVCONF_ALL(FORWARDING);
- ipv4_devconf.accept_redirects = !on;
- ipv4_devconf_dflt.forwarding = on;
+ IPV4_DEVCONF_ALL(ACCEPT_REDIRECTS) = !on;
+ IPV4_DEVCONF_DFLT(FORWARDING) = on;
read_lock(&dev_base_lock);
for_each_netdev(dev) {
@@ -1251,7 +1336,7 @@ void inet_forward_change(void)
rcu_read_lock();
in_dev = __in_dev_get_rcu(dev);
if (in_dev)
- in_dev->cnf.forwarding = on;
+ IN_DEV_CONF_SET(in_dev, FORWARDING, on);
rcu_read_unlock();
}
read_unlock(&dev_base_lock);
@@ -1268,9 +1353,9 @@ static int devinet_sysctl_forward(ctl_table *ctl, int write,
int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
if (write && *valp != val) {
- if (valp == &ipv4_devconf.forwarding)
+ if (valp == &IPV4_DEVCONF_ALL(FORWARDING))
inet_forward_change();
- else if (valp != &ipv4_devconf_dflt.forwarding)
+ else if (valp != &IPV4_DEVCONF_DFLT(FORWARDING))
rt_cache_flush(0);
}
@@ -1295,42 +1380,43 @@ int ipv4_doint_and_flush_strategy(ctl_table *table, int __user *name, int nlen,
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen)
{
- int *valp = table->data;
- int new;
+ int ret = devinet_conf_sysctl(table, name, nlen, oldval, oldlenp,
+ newval, newlen);
- if (!newval || !newlen)
- return 0;
+ if (ret == 1)
+ rt_cache_flush(0);
- if (newlen != sizeof(int))
- return -EINVAL;
+ return ret;
+}
- if (get_user(new, (int __user *)newval))
- return -EFAULT;
- if (new == *valp)
- return 0;
+#define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc, sysctl) \
+ { \
+ .ctl_name = NET_IPV4_CONF_ ## attr, \
+ .procname = name, \
+ .data = ipv4_devconf.data + \
+ NET_IPV4_CONF_ ## attr - 1, \
+ .maxlen = sizeof(int), \
+ .mode = mval, \
+ .proc_handler = proc, \
+ .strategy = sysctl, \
+ .extra1 = &ipv4_devconf, \
+ }
- if (oldval && oldlenp) {
- size_t len;
+#define DEVINET_SYSCTL_RW_ENTRY(attr, name) \
+ DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc, \
+ devinet_conf_sysctl)
- if (get_user(len, oldlenp))
- return -EFAULT;
+#define DEVINET_SYSCTL_RO_ENTRY(attr, name) \
+ DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc, \
+ devinet_conf_sysctl)
- if (len) {
- if (len > table->maxlen)
- len = table->maxlen;
- if (copy_to_user(oldval, valp, len))
- return -EFAULT;
- if (put_user(len, oldlenp))
- return -EFAULT;
- }
- }
-
- *valp = new;
- rt_cache_flush(0);
- return 1;
-}
+#define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc, sysctl) \
+ DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc, sysctl)
+#define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \
+ DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush, \
+ ipv4_doint_and_flush_strategy)
static struct devinet_sysctl_table {
struct ctl_table_header *sysctl_header;
@@ -1341,178 +1427,34 @@ static struct devinet_sysctl_table {
ctl_table devinet_root_dir[2];
} devinet_sysctl = {
.devinet_vars = {
- {
- .ctl_name = NET_IPV4_CONF_FORWARDING,
- .procname = "forwarding",
- .data = &ipv4_devconf.forwarding,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &devinet_sysctl_forward,
- },
- {
- .ctl_name = NET_IPV4_CONF_MC_FORWARDING,
- .procname = "mc_forwarding",
- .data = &ipv4_devconf.mc_forwarding,
- .maxlen = sizeof(int),
- .mode = 0444,
- .proc_handler = &proc_dointvec,
- },
- {
- .ctl_name = NET_IPV4_CONF_ACCEPT_REDIRECTS,
- .procname = "accept_redirects",
- .data = &ipv4_devconf.accept_redirects,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec,
- },
- {
- .ctl_name = NET_IPV4_CONF_SECURE_REDIRECTS,
- .procname = "secure_redirects",
- .data = &ipv4_devconf.secure_redirects,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec,
- },
- {
- .ctl_name = NET_IPV4_CONF_SHARED_MEDIA,
- .procname = "shared_media",
- .data = &ipv4_devconf.shared_media,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec,
- },
- {
- .ctl_name = NET_IPV4_CONF_RP_FILTER,
- .procname = "rp_filter",
- .data = &ipv4_devconf.rp_filter,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec,
- },
- {
- .ctl_name = NET_IPV4_CONF_SEND_REDIRECTS,
- .procname = "send_redirects",
- .data = &ipv4_devconf.send_redirects,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec,
- },
- {
- .ctl_name = NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE,
- .procname = "accept_source_route",
- .data = &ipv4_devconf.accept_source_route,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec,
- },
- {
- .ctl_name = NET_IPV4_CONF_PROXY_ARP,
- .procname = "proxy_arp",
- .data = &ipv4_devconf.proxy_arp,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec,
- },
- {
- .ctl_name = NET_IPV4_CONF_MEDIUM_ID,
- .procname = "medium_id",
- .data = &ipv4_devconf.medium_id,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec,
- },
- {
- .ctl_name = NET_IPV4_CONF_BOOTP_RELAY,
- .procname = "bootp_relay",
- .data = &ipv4_devconf.bootp_relay,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec,
- },
- {
- .ctl_name = NET_IPV4_CONF_LOG_MARTIANS,
- .procname = "log_martians",
- .data = &ipv4_devconf.log_martians,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec,
- },
- {
- .ctl_name = NET_IPV4_CONF_TAG,
- .procname = "tag",
- .data = &ipv4_devconf.tag,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec,
- },
- {
- .ctl_name = NET_IPV4_CONF_ARPFILTER,
- .procname = "arp_filter",
- .data = &ipv4_devconf.arp_filter,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec,
- },
- {
- .ctl_name = NET_IPV4_CONF_ARP_ANNOUNCE,
- .procname = "arp_announce",
- .data = &ipv4_devconf.arp_announce,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec,
- },
- {
- .ctl_name = NET_IPV4_CONF_ARP_IGNORE,
- .procname = "arp_ignore",
- .data = &ipv4_devconf.arp_ignore,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec,
- },
- {
- .ctl_name = NET_IPV4_CONF_ARP_ACCEPT,
- .procname = "arp_accept",
- .data = &ipv4_devconf.arp_accept,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec,
- },
- {
- .ctl_name = NET_IPV4_CONF_NOXFRM,
- .procname = "disable_xfrm",
- .data = &ipv4_devconf.no_xfrm,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &ipv4_doint_and_flush,
- .strategy = &ipv4_doint_and_flush_strategy,
- },
- {
- .ctl_name = NET_IPV4_CONF_NOPOLICY,
- .procname = "disable_policy",
- .data = &ipv4_devconf.no_policy,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &ipv4_doint_and_flush,
- .strategy = &ipv4_doint_and_flush_strategy,
- },
- {
- .ctl_name = NET_IPV4_CONF_FORCE_IGMP_VERSION,
- .procname = "force_igmp_version",
- .data = &ipv4_devconf.force_igmp_version,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &ipv4_doint_and_flush,
- .strategy = &ipv4_doint_and_flush_strategy,
- },
- {
- .ctl_name = NET_IPV4_CONF_PROMOTE_SECONDARIES,
- .procname = "promote_secondaries",
- .data = &ipv4_devconf.promote_secondaries,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &ipv4_doint_and_flush,
- .strategy = &ipv4_doint_and_flush_strategy,
- },
+ DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
+ devinet_sysctl_forward,
+ devinet_conf_sysctl),
+ DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
+
+ DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),
+ DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"),
+ DEVINET_SYSCTL_RW_ENTRY(SHARED_MEDIA, "shared_media"),
+ DEVINET_SYSCTL_RW_ENTRY(RP_FILTER, "rp_filter"),
+ DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"),
+ DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE,
+ "accept_source_route"),
+ DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"),
+ DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"),
+ DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"),
+ DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"),
+ DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"),
+ DEVINET_SYSCTL_RW_ENTRY(ARPFILTER, "arp_filter"),
+ DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"),
+ DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
+ DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),
+
+ DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
+ DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
+ DEVINET_SYSCTL_FLUSHING_ENTRY(FORCE_IGMP_VERSION,
+ "force_igmp_version"),
+ DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,
+ "promote_secondaries"),
},
.devinet_dev = {
{
@@ -1561,6 +1503,7 @@ static void devinet_sysctl_register(struct in_device *in_dev,
return;
for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
+ t->devinet_vars[i].extra1 = p;
}
if (dev) {
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 9ad1f6252a97..311d633f7f39 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -441,7 +441,7 @@ int ip_rt_ioctl(unsigned int cmd, void __user *arg)
return -EINVAL;
}
-struct nla_policy rtm_ipv4_policy[RTA_MAX+1] __read_mostly = {
+const struct nla_policy rtm_ipv4_policy[RTA_MAX+1] = {
[RTA_DST] = { .type = NLA_U32 },
[RTA_SRC] = { .type = NLA_U32 },
[RTA_IIF] = { .type = NLA_U32 },
diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c
index 33083ad52e9f..2a947840210e 100644
--- a/net/ipv4/fib_rules.c
+++ b/net/ipv4/fib_rules.c
@@ -169,7 +169,7 @@ static struct fib_table *fib_empty_table(void)
return NULL;
}
-static struct nla_policy fib4_rule_policy[FRA_MAX+1] __read_mostly = {
+static const struct nla_policy fib4_rule_policy[FRA_MAX+1] = {
FRA_GENERIC_POLICY,
[FRA_FLOW] = { .type = NLA_U32 },
};
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index f4dd47453108..a646409c2d06 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -128,14 +128,16 @@
* contradict to specs provided this delay is small enough.
*/
-#define IGMP_V1_SEEN(in_dev) (ipv4_devconf.force_igmp_version == 1 || \
- (in_dev)->cnf.force_igmp_version == 1 || \
- ((in_dev)->mr_v1_seen && \
- time_before(jiffies, (in_dev)->mr_v1_seen)))
-#define IGMP_V2_SEEN(in_dev) (ipv4_devconf.force_igmp_version == 2 || \
- (in_dev)->cnf.force_igmp_version == 2 || \
- ((in_dev)->mr_v2_seen && \
- time_before(jiffies, (in_dev)->mr_v2_seen)))
+#define IGMP_V1_SEEN(in_dev) \
+ (IPV4_DEVCONF_ALL(FORCE_IGMP_VERSION) == 1 || \
+ IN_DEV_CONF_GET((in_dev), FORCE_IGMP_VERSION) == 1 || \
+ ((in_dev)->mr_v1_seen && \
+ time_before(jiffies, (in_dev)->mr_v1_seen)))
+#define IGMP_V2_SEEN(in_dev) \
+ (IPV4_DEVCONF_ALL(FORCE_IGMP_VERSION) == 2 || \
+ IN_DEV_CONF_GET((in_dev), FORCE_IGMP_VERSION) == 2 || \
+ ((in_dev)->mr_v2_seen && \
+ time_before(jiffies, (in_dev)->mr_v2_seen)))
static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im);
static void igmpv3_del_delrec(struct in_device *in_dev, __be32 multiaddr);
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index d6427d918512..34ea4547ebbe 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -1352,7 +1352,8 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar
}
{
- struct flowi fl = { .nl_u = { .ip4_u =
+ struct flowi fl = { .oif = arg->bound_dev_if,
+ .nl_u = { .ip4_u =
{ .daddr = daddr,
.saddr = rt->rt_spec_dst,
.tos = RT_TOS(ip_hdr(skb)->tos) } },
@@ -1376,6 +1377,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar
inet->tos = ip_hdr(skb)->tos;
sk->sk_priority = skb->priority;
sk->sk_protocol = ip_hdr(skb)->protocol;
+ sk->sk_bound_dev_if = arg->bound_dev_if;
ip_append_data(sk, ip_reply_glue_bits, arg->iov->iov_base, len, 0,
&ipc, rt, MSG_DONTWAIT);
if ((skb = skb_peek(&sk->sk_write_queue)) != NULL) {
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 0ebae413ae87..d96582acdf69 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -152,9 +152,11 @@ struct net_device *ipmr_new_tunnel(struct vifctl *v)
dev->flags |= IFF_MULTICAST;
in_dev = __in_dev_get_rtnl(dev);
- if (in_dev == NULL && (in_dev = inetdev_init(dev)) == NULL)
+ if (in_dev == NULL)
goto failure;
- in_dev->cnf.rp_filter = 0;
+
+ ipv4_devconf_setall(in_dev);
+ IPV4_DEVCONF(in_dev->cnf, RP_FILTER) = 0;
if (dev_open(dev))
goto failure;
@@ -218,10 +220,15 @@ static struct net_device *ipmr_reg_vif(void)
}
dev->iflink = 0;
- if ((in_dev = inetdev_init(dev)) == NULL)
+ rcu_read_lock();
+ if ((in_dev = __in_dev_get_rcu(dev)) == NULL) {
+ rcu_read_unlock();
goto failure;
+ }
- in_dev->cnf.rp_filter = 0;
+ ipv4_devconf_setall(in_dev);
+ IPV4_DEVCONF(in_dev->cnf, RP_FILTER) = 0;
+ rcu_read_unlock();
if (dev_open(dev))
goto failure;
@@ -281,7 +288,7 @@ static int vif_delete(int vifi)
dev_set_allmulti(dev, -1);
if ((in_dev = __in_dev_get_rtnl(dev)) != NULL) {
- in_dev->cnf.mc_forwarding--;
+ IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)--;
ip_rt_multicast_event(in_dev);
}
@@ -426,7 +433,7 @@ static int vif_add(struct vifctl *vifc, int mrtsock)
if ((in_dev = __in_dev_get_rtnl(dev)) == NULL)
return -EADDRNOTAVAIL;
- in_dev->cnf.mc_forwarding++;
+ IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)++;
dev_set_allmulti(dev, +1);
ip_rt_multicast_event(in_dev);
@@ -841,7 +848,7 @@ static void mrtsock_destruct(struct sock *sk)
{
rtnl_lock();
if (sk == mroute_socket) {
- ipv4_devconf.mc_forwarding--;
+ IPV4_DEVCONF_ALL(MC_FORWARDING)--;
write_lock_bh(&mrt_lock);
mroute_socket=NULL;
@@ -890,7 +897,7 @@ int ip_mroute_setsockopt(struct sock *sk,int optname,char __user *optval,int opt
mroute_socket=sk;
write_unlock_bh(&mrt_lock);
- ipv4_devconf.mc_forwarding++;
+ IPV4_DEVCONF_ALL(MC_FORWARDING)++;
}
rtnl_unlock();
return ret;
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index e3f83bf160d9..9bacf1a03630 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -499,7 +499,8 @@ check_entry(struct ipt_entry *e, const char *name)
}
static inline int check_match(struct ipt_entry_match *m, const char *name,
- const struct ipt_ip *ip, unsigned int hookmask)
+ const struct ipt_ip *ip, unsigned int hookmask,
+ unsigned int *i)
{
struct xt_match *match;
int ret;
@@ -515,6 +516,8 @@ static inline int check_match(struct ipt_entry_match *m, const char *name,
m->u.kernel.match->name);
ret = -EINVAL;
}
+ if (!ret)
+ (*i)++;
return ret;
}
@@ -537,11 +540,10 @@ find_check_match(struct ipt_entry_match *m,
}
m->u.kernel.match = match;
- ret = check_match(m, name, ip, hookmask);
+ ret = check_match(m, name, ip, hookmask, i);
if (ret)
goto err;
- (*i)++;
return 0;
err:
module_put(m->u.kernel.match->me);
@@ -1425,7 +1427,7 @@ out:
}
static inline int
-compat_check_calc_match(struct ipt_entry_match *m,
+compat_find_calc_match(struct ipt_entry_match *m,
const char *name,
const struct ipt_ip *ip,
unsigned int hookmask,
@@ -1449,6 +1451,31 @@ compat_check_calc_match(struct ipt_entry_match *m,
}
static inline int
+compat_release_match(struct ipt_entry_match *m, unsigned int *i)
+{
+ if (i && (*i)-- == 0)
+ return 1;
+
+ module_put(m->u.kernel.match->me);
+ return 0;
+}
+
+static inline int
+compat_release_entry(struct ipt_entry *e, unsigned int *i)
+{
+ struct ipt_entry_target *t;
+
+ if (i && (*i)-- == 0)
+ return 1;
+
+ /* Cleanup all matches */
+ IPT_MATCH_ITERATE(e, compat_release_match, NULL);
+ t = ipt_get_target(e);
+ module_put(t->u.kernel.target->me);
+ return 0;
+}
+
+static inline int
check_compat_entry_size_and_hooks(struct ipt_entry *e,
struct xt_table_info *newinfo,
unsigned int *size,
@@ -1485,10 +1512,10 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e,
off = 0;
entry_offset = (void *)e - (void *)base;
j = 0;
- ret = IPT_MATCH_ITERATE(e, compat_check_calc_match, name, &e->ip,
+ ret = IPT_MATCH_ITERATE(e, compat_find_calc_match, name, &e->ip,
e->comefrom, &off, &j);
if (ret != 0)
- goto cleanup_matches;
+ goto release_matches;
t = ipt_get_target(e);
target = try_then_request_module(xt_find_target(AF_INET,
@@ -1499,7 +1526,7 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e,
duprintf("check_compat_entry_size_and_hooks: `%s' not found\n",
t->u.user.name);
ret = target ? PTR_ERR(target) : -ENOENT;
- goto cleanup_matches;
+ goto release_matches;
}
t->u.kernel.target = target;
@@ -1526,8 +1553,8 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e,
out:
module_put(t->u.kernel.target->me);
-cleanup_matches:
- IPT_MATCH_ITERATE(e, cleanup_match, &j);
+release_matches:
+ IPT_MATCH_ITERATE(e, compat_release_match, &j);
return ret;
}
@@ -1574,15 +1601,26 @@ static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
return ret;
}
-static inline int compat_check_entry(struct ipt_entry *e, const char *name)
+static inline int compat_check_entry(struct ipt_entry *e, const char *name,
+ unsigned int *i)
{
- int ret;
+ int j, ret;
- ret = IPT_MATCH_ITERATE(e, check_match, name, &e->ip, e->comefrom);
+ j = 0;
+ ret = IPT_MATCH_ITERATE(e, check_match, name, &e->ip, e->comefrom, &j);
if (ret)
- return ret;
+ goto cleanup_matches;
+
+ ret = check_target(e, name);
+ if (ret)
+ goto cleanup_matches;
- return check_target(e, name);
+ (*i)++;
+ return 0;
+
+ cleanup_matches:
+ IPT_MATCH_ITERATE(e, cleanup_match, &j);
+ return ret;
}
static int
@@ -1673,10 +1711,17 @@ translate_compat_table(const char *name,
if (!mark_source_chains(newinfo, valid_hooks, entry1))
goto free_newinfo;
+ i = 0;
ret = IPT_ENTRY_ITERATE(entry1, newinfo->size, compat_check_entry,
- name);
- if (ret)
- goto free_newinfo;
+ name, &i);
+ if (ret) {
+ j -= i;
+ IPT_ENTRY_ITERATE_CONTINUE(entry1, newinfo->size, i,
+ compat_release_entry, &j);
+ IPT_ENTRY_ITERATE(entry1, newinfo->size, cleanup_entry, &i);
+ xt_free_table_info(newinfo);
+ return ret;
+ }
/* And one copy for every other CPU */
for_each_possible_cpu(i)
@@ -1691,7 +1736,7 @@ translate_compat_table(const char *name,
free_newinfo:
xt_free_table_info(newinfo);
out:
- IPT_ENTRY_ITERATE(entry0, total_size, cleanup_entry, &j);
+ IPT_ENTRY_ITERATE(entry0, total_size, compat_release_entry, &j);
return ret;
out_unlock:
compat_flush_offsets();
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index fd62a41d69cc..6dc72a815f77 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -133,6 +133,7 @@ static unsigned int ipv4_conntrack_help(unsigned int hooknum,
struct nf_conn *ct;
enum ip_conntrack_info ctinfo;
struct nf_conn_help *help;
+ struct nf_conntrack_helper *helper;
/* This is where we call the helper: as the packet goes out. */
ct = nf_ct_get(*pskb, &ctinfo);
@@ -140,12 +141,14 @@ static unsigned int ipv4_conntrack_help(unsigned int hooknum,
return NF_ACCEPT;
help = nfct_help(ct);
- if (!help || !help->helper)
+ if (!help)
return NF_ACCEPT;
-
- return help->helper->help(pskb,
- skb_network_offset(*pskb) + ip_hdrlen(*pskb),
- ct, ctinfo);
+ /* rcu_read_lock()ed by nf_hook_slow */
+ helper = rcu_dereference(help->helper);
+ if (!helper)
+ return NF_ACCEPT;
+ return helper->help(pskb, skb_network_offset(*pskb) + ip_hdrlen(*pskb),
+ ct, ctinfo);
}
static unsigned int ipv4_conntrack_defrag(unsigned int hooknum,
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c
index cdbc6c135849..3b690cf2a4ee 100644
--- a/net/ipv4/proc.c
+++ b/net/ipv4/proc.c
@@ -260,7 +260,7 @@ static int snmp_seq_show(struct seq_file *seq, void *v)
seq_printf(seq, " %s", snmp4_ipstats_list[i].name);
seq_printf(seq, "\nIp: %d %d",
- ipv4_devconf.forwarding ? 1 : 2, sysctl_ip_default_ttl);
+ IPV4_DEVCONF_ALL(FORWARDING) ? 1 : 2, sysctl_ip_default_ttl);
for (i = 0; snmp4_ipstats_list[i].name != NULL; i++)
seq_printf(seq, " %lu",
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 8603cfb271f2..29ca63e81ced 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1636,7 +1636,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
atomic_set(&rth->u.dst.__refcnt, 1);
rth->u.dst.flags= DST_HOST;
- if (in_dev->cnf.no_policy)
+ if (IN_DEV_CONF_GET(in_dev, NOPOLICY))
rth->u.dst.flags |= DST_NOPOLICY;
rth->fl.fl4_dst = daddr;
rth->rt_dst = daddr;
@@ -1778,9 +1778,9 @@ static inline int __mkroute_input(struct sk_buff *skb,
if (res->fi->fib_nhs > 1)
rth->u.dst.flags |= DST_BALANCED;
#endif
- if (in_dev->cnf.no_policy)
+ if (IN_DEV_CONF_GET(in_dev, NOPOLICY))
rth->u.dst.flags |= DST_NOPOLICY;
- if (out_dev->cnf.no_xfrm)
+ if (IN_DEV_CONF_GET(out_dev, NOXFRM))
rth->u.dst.flags |= DST_NOXFRM;
rth->fl.fl4_dst = daddr;
rth->rt_dst = daddr;
@@ -2021,7 +2021,7 @@ local_input:
atomic_set(&rth->u.dst.__refcnt, 1);
rth->u.dst.flags= DST_HOST;
- if (in_dev->cnf.no_policy)
+ if (IN_DEV_CONF_GET(in_dev, NOPOLICY))
rth->u.dst.flags |= DST_NOPOLICY;
rth->fl.fl4_dst = daddr;
rth->rt_dst = daddr;
@@ -2218,9 +2218,9 @@ static inline int __mkroute_output(struct rtable **result,
rth->u.dst.flags |= DST_BALANCED;
}
#endif
- if (in_dev->cnf.no_xfrm)
+ if (IN_DEV_CONF_GET(in_dev, NOXFRM))
rth->u.dst.flags |= DST_NOXFRM;
- if (in_dev->cnf.no_policy)
+ if (IN_DEV_CONF_GET(in_dev, NOPOLICY))
rth->u.dst.flags |= DST_NOPOLICY;
rth->fl.fl4_dst = oldflp->fl4_dst;
@@ -2759,7 +2759,7 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
__be32 dst = rt->rt_dst;
if (MULTICAST(dst) && !LOCAL_MCAST(dst) &&
- ipv4_devconf.mc_forwarding) {
+ IPV4_DEVCONF_ALL(MC_FORWARDING)) {
int err = ipmr_get_route(skb, r, nowait);
if (err <= 0) {
if (!nowait) {
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 6817d6485df5..53ef0f4bbdaa 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -37,12 +37,12 @@ static
int ipv4_sysctl_forward(ctl_table *ctl, int write, struct file * filp,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
- int val = ipv4_devconf.forwarding;
+ int val = IPV4_DEVCONF_ALL(FORWARDING);
int ret;
ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
- if (write && ipv4_devconf.forwarding != val)
+ if (write && IPV4_DEVCONF_ALL(FORWARDING) != val)
inet_forward_change();
return ret;
@@ -222,7 +222,7 @@ ctl_table ipv4_table[] = {
{
.ctl_name = NET_IPV4_FORWARD,
.procname = "ip_forward",
- .data = &ipv4_devconf.forwarding,
+ .data = &IPV4_DEVCONF_ALL(FORWARDING),
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &ipv4_sysctl_forward,
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 47c61055eb60..97e294e82679 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -705,6 +705,8 @@ static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk,
ip_hdr(skb)->saddr, /* XXX */
arg.iov[0].iov_len, IPPROTO_TCP, 0);
arg.csumoffset = offsetof(struct tcphdr, check) / 2;
+ if (twsk)
+ arg.bound_dev_if = twsk->tw_sk.tw_bound_dev_if;
ip_send_reply(tcp_socket->sk, skb, &arg, arg.iov[0].iov_len);
diff --git a/net/ipv4/tcp_probe.c b/net/ipv4/tcp_probe.c
index 760165a0800c..d9323dfff826 100644
--- a/net/ipv4/tcp_probe.c
+++ b/net/ipv4/tcp_probe.c
@@ -63,6 +63,9 @@ struct {
* FIXME: causes an extra copy
*/
static void printl(const char *fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+
+static void printl(const char *fmt, ...)
{
va_list args;
int len;
@@ -80,8 +83,7 @@ static void printl(const char *fmt, ...)
kfifo_put(tcpw.fifo, tbuf, len);
wake_up(&tcpw.wait);
-} __attribute__ ((format (printf, 1, 2)));
-
+}
/*
* Hook inserted to be called before each receive packet.
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index e61340150ba6..e9b151b3a598 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -292,9 +292,9 @@ static void tcp_retransmit_timer(struct sock *sk)
* we cannot allow such beasts to hang infinitely.
*/
#ifdef TCP_DEBUG
- if (net_ratelimit()) {
+ if (1) {
struct inet_sock *inet = inet_sk(sk);
- printk(KERN_DEBUG "TCP: Treason uncloaked! Peer %u.%u.%u.%u:%u/%u shrinks window %u:%u. Repaired.\n",
+ LIMIT_NETDEBUG(KERN_DEBUG "TCP: Treason uncloaked! Peer %u.%u.%u.%u:%u/%u shrinks window %u:%u. Repaired.\n",
NIPQUAD(inet->daddr), ntohs(inet->dport),
inet->num, tp->snd_una, tp->snd_nxt);
}
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 5da703e699da..facb7e29304e 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -114,36 +114,14 @@ DEFINE_RWLOCK(udp_hash_lock);
static int udp_port_rover;
-/*
- * Note about this hash function :
- * Typical use is probably daddr = 0, only dport is going to vary hash
- */
-static inline unsigned int udp_hash_port(__u16 port)
-{
- return port;
-}
-
-static inline int __udp_lib_port_inuse(unsigned int hash, int port,
- const struct sock *this_sk,
- struct hlist_head udptable[],
- const struct udp_get_port_ops *ops)
+static inline int __udp_lib_lport_inuse(__u16 num, struct hlist_head udptable[])
{
struct sock *sk;
struct hlist_node *node;
- struct inet_sock *inet;
- sk_for_each(sk, node, &udptable[hash & (UDP_HTABLE_SIZE - 1)]) {
- if (sk->sk_hash != hash)
- continue;
- inet = inet_sk(sk);
- if (inet->num != port)
- continue;
- if (this_sk) {
- if (ops->saddr_cmp(sk, this_sk))
- return 1;
- } else if (ops->saddr_any(sk))
+ sk_for_each(sk, node, &udptable[num & (UDP_HTABLE_SIZE - 1)])
+ if (sk->sk_hash == num)
return 1;
- }
return 0;
}
@@ -154,16 +132,16 @@ static inline int __udp_lib_port_inuse(unsigned int hash, int port,
* @snum: port number to look up
* @udptable: hash list table, must be of UDP_HTABLE_SIZE
* @port_rover: pointer to record of last unallocated port
- * @ops: AF-dependent address operations
+ * @saddr_comp: AF-dependent comparison of bound local IP addresses
*/
int __udp_lib_get_port(struct sock *sk, unsigned short snum,
struct hlist_head udptable[], int *port_rover,
- const struct udp_get_port_ops *ops)
+ int (*saddr_comp)(const struct sock *sk1,
+ const struct sock *sk2 ) )
{
struct hlist_node *node;
struct hlist_head *head;
struct sock *sk2;
- unsigned int hash;
int error = 1;
write_lock_bh(&udp_hash_lock);
@@ -178,8 +156,7 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum,
for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) {
int size;
- hash = ops->hash_port_and_rcv_saddr(result, sk);
- head = &udptable[hash & (UDP_HTABLE_SIZE - 1)];
+ head = &udptable[result & (UDP_HTABLE_SIZE - 1)];
if (hlist_empty(head)) {
if (result > sysctl_local_port_range[1])
result = sysctl_local_port_range[0] +
@@ -204,16 +181,7 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum,
result = sysctl_local_port_range[0]
+ ((result - sysctl_local_port_range[0]) &
(UDP_HTABLE_SIZE - 1));
- hash = udp_hash_port(result);
- if (__udp_lib_port_inuse(hash, result,
- NULL, udptable, ops))
- continue;
- if (ops->saddr_any(sk))
- break;
-
- hash = ops->hash_port_and_rcv_saddr(result, sk);
- if (! __udp_lib_port_inuse(hash, result,
- sk, udptable, ops))
+ if (! __udp_lib_lport_inuse(result, udptable))
break;
}
if (i >= (1 << 16) / UDP_HTABLE_SIZE)
@@ -221,40 +189,21 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum,
gotit:
*port_rover = snum = result;
} else {
- hash = udp_hash_port(snum);
- head = &udptable[hash & (UDP_HTABLE_SIZE - 1)];
+ head = &udptable[snum & (UDP_HTABLE_SIZE - 1)];
sk_for_each(sk2, node, head)
- if (sk2->sk_hash == hash &&
- sk2 != sk &&
- inet_sk(sk2)->num == snum &&
- (!sk2->sk_reuse || !sk->sk_reuse) &&
- (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if ||
- sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
- ops->saddr_cmp(sk, sk2))
+ if (sk2->sk_hash == snum &&
+ sk2 != sk &&
+ (!sk2->sk_reuse || !sk->sk_reuse) &&
+ (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if
+ || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
+ (*saddr_comp)(sk, sk2) )
goto fail;
-
- if (!ops->saddr_any(sk)) {
- hash = ops->hash_port_and_rcv_saddr(snum, sk);
- head = &udptable[hash & (UDP_HTABLE_SIZE - 1)];
-
- sk_for_each(sk2, node, head)
- if (sk2->sk_hash == hash &&
- sk2 != sk &&
- inet_sk(sk2)->num == snum &&
- (!sk2->sk_reuse || !sk->sk_reuse) &&
- (!sk2->sk_bound_dev_if ||
- !sk->sk_bound_dev_if ||
- sk2->sk_bound_dev_if ==
- sk->sk_bound_dev_if) &&
- ops->saddr_cmp(sk, sk2))
- goto fail;
- }
}
inet_sk(sk)->num = snum;
- sk->sk_hash = hash;
+ sk->sk_hash = snum;
if (sk_unhashed(sk)) {
- head = &udptable[hash & (UDP_HTABLE_SIZE - 1)];
+ head = &udptable[snum & (UDP_HTABLE_SIZE - 1)];
sk_add_node(sk, head);
sock_prot_inc_use(sk->sk_prot);
}
@@ -265,12 +214,12 @@ fail:
}
int udp_get_port(struct sock *sk, unsigned short snum,
- const struct udp_get_port_ops *ops)
+ int (*scmp)(const struct sock *, const struct sock *))
{
- return __udp_lib_get_port(sk, snum, udp_hash, &udp_port_rover, ops);
+ return __udp_lib_get_port(sk, snum, udp_hash, &udp_port_rover, scmp);
}
-static int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2)
+int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2)
{
struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2);
@@ -279,33 +228,9 @@ static int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2)
inet1->rcv_saddr == inet2->rcv_saddr ));
}
-static int ipv4_rcv_saddr_any(const struct sock *sk)
-{
- return !inet_sk(sk)->rcv_saddr;
-}
-
-static inline unsigned int ipv4_hash_port_and_addr(__u16 port, __be32 addr)
-{
- addr ^= addr >> 16;
- addr ^= addr >> 8;
- return port ^ addr;
-}
-
-static unsigned int ipv4_hash_port_and_rcv_saddr(__u16 port,
- const struct sock *sk)
-{
- return ipv4_hash_port_and_addr(port, inet_sk(sk)->rcv_saddr);
-}
-
-const struct udp_get_port_ops udp_ipv4_ops = {
- .saddr_cmp = ipv4_rcv_saddr_equal,
- .saddr_any = ipv4_rcv_saddr_any,
- .hash_port_and_rcv_saddr = ipv4_hash_port_and_rcv_saddr,
-};
-
static inline int udp_v4_get_port(struct sock *sk, unsigned short snum)
{
- return udp_get_port(sk, snum, &udp_ipv4_ops);
+ return udp_get_port(sk, snum, ipv4_rcv_saddr_equal);
}
/* UDP is nearly always wildcards out the wazoo, it makes no sense to try
@@ -317,77 +242,63 @@ static struct sock *__udp4_lib_lookup(__be32 saddr, __be16 sport,
{
struct sock *sk, *result = NULL;
struct hlist_node *node;
- unsigned int hash, hashwild;
- int score, best = -1, hport = ntohs(dport);
-
- hash = ipv4_hash_port_and_addr(hport, daddr);
- hashwild = udp_hash_port(hport);
+ unsigned short hnum = ntohs(dport);
+ int badness = -1;
read_lock(&udp_hash_lock);
-
-lookup:
-
- sk_for_each(sk, node, &udptable[hash & (UDP_HTABLE_SIZE - 1)]) {
+ sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) {
struct inet_sock *inet = inet_sk(sk);
- if (sk->sk_hash != hash || ipv6_only_sock(sk) ||
- inet->num != hport)
- continue;
-
- score = (sk->sk_family == PF_INET ? 1 : 0);
- if (inet->rcv_saddr) {
- if (inet->rcv_saddr != daddr)
- continue;
- score+=2;
- }
- if (inet->daddr) {
- if (inet->daddr != saddr)
- continue;
- score+=2;
- }
- if (inet->dport) {
- if (inet->dport != sport)
- continue;
- score+=2;
- }
- if (sk->sk_bound_dev_if) {
- if (sk->sk_bound_dev_if != dif)
- continue;
- score+=2;
- }
- if (score == 9) {
- result = sk;
- goto found;
- } else if (score > best) {
- result = sk;
- best = score;
+ if (sk->sk_hash == hnum && !ipv6_only_sock(sk)) {
+ int score = (sk->sk_family == PF_INET ? 1 : 0);
+ if (inet->rcv_saddr) {
+ if (inet->rcv_saddr != daddr)
+ continue;
+ score+=2;
+ }
+ if (inet->daddr) {
+ if (inet->daddr != saddr)
+ continue;
+ score+=2;
+ }
+ if (inet->dport) {
+ if (inet->dport != sport)
+ continue;
+ score+=2;
+ }
+ if (sk->sk_bound_dev_if) {
+ if (sk->sk_bound_dev_if != dif)
+ continue;
+ score+=2;
+ }
+ if (score == 9) {
+ result = sk;
+ break;
+ } else if (score > badness) {
+ result = sk;
+ badness = score;
+ }
}
}
-
- if (hash != hashwild) {
- hash = hashwild;
- goto lookup;
- }
-found:
if (result)
sock_hold(result);
read_unlock(&udp_hash_lock);
return result;
}
-static inline struct sock *udp_v4_mcast_next(struct sock *sk, unsigned int hnum,
- int hport, __be32 loc_addr,
+static inline struct sock *udp_v4_mcast_next(struct sock *sk,
+ __be16 loc_port, __be32 loc_addr,
__be16 rmt_port, __be32 rmt_addr,
int dif)
{
struct hlist_node *node;
struct sock *s = sk;
+ unsigned short hnum = ntohs(loc_port);
sk_for_each_from(s, node) {
struct inet_sock *inet = inet_sk(s);
if (s->sk_hash != hnum ||
- inet->num != hport ||
(inet->daddr && inet->daddr != rmt_addr) ||
(inet->dport != rmt_port && inet->dport) ||
(inet->rcv_saddr && inet->rcv_saddr != loc_addr) ||
@@ -1221,45 +1132,29 @@ static int __udp4_lib_mcast_deliver(struct sk_buff *skb,
__be32 saddr, __be32 daddr,
struct hlist_head udptable[])
{
- struct sock *sk, *skw, *sknext;
+ struct sock *sk;
int dif;
- int hport = ntohs(uh->dest);
- unsigned int hash = ipv4_hash_port_and_addr(hport, daddr);
- unsigned int hashwild = udp_hash_port(hport);
-
- dif = skb->dev->ifindex;
read_lock(&udp_hash_lock);
-
- sk = sk_head(&udptable[hash & (UDP_HTABLE_SIZE - 1)]);
- skw = sk_head(&udptable[hashwild & (UDP_HTABLE_SIZE - 1)]);
-
- sk = udp_v4_mcast_next(sk, hash, hport, daddr, uh->source, saddr, dif);
- if (!sk) {
- hash = hashwild;
- sk = udp_v4_mcast_next(skw, hash, hport, daddr, uh->source,
- saddr, dif);
- }
+ sk = sk_head(&udptable[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]);
+ dif = skb->dev->ifindex;
+ sk = udp_v4_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif);
if (sk) {
+ struct sock *sknext = NULL;
+
do {
struct sk_buff *skb1 = skb;
- sknext = udp_v4_mcast_next(sk_next(sk), hash, hport,
- daddr, uh->source, saddr, dif);
- if (!sknext && hash != hashwild) {
- hash = hashwild;
- sknext = udp_v4_mcast_next(skw, hash, hport,
- daddr, uh->source, saddr, dif);
- }
+
+ sknext = udp_v4_mcast_next(sk_next(sk), uh->dest, daddr,
+ uh->source, saddr, dif);
if (sknext)
skb1 = skb_clone(skb, GFP_ATOMIC);
if (skb1) {
int ret = udp_queue_rcv_skb(sk, skb1);
if (ret > 0)
- /*
- * we should probably re-process
- * instead of dropping packets here.
- */
+ /* we should probably re-process instead
+ * of dropping packets here. */
kfree_skb(skb1);
}
sk = sknext;
@@ -1346,7 +1241,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
return __udp4_lib_mcast_deliver(skb, uh, saddr, daddr, udptable);
sk = __udp4_lib_lookup(saddr, uh->source, daddr, uh->dest,
- skb->dev->ifindex, udptable);
+ skb->dev->ifindex, udptable );
if (sk != NULL) {
int ret = udp_queue_rcv_skb(sk, skb);
diff --git a/net/ipv4/udp_impl.h b/net/ipv4/udp_impl.h
index 06d94195e644..820a477cfaa6 100644
--- a/net/ipv4/udp_impl.h
+++ b/net/ipv4/udp_impl.h
@@ -5,14 +5,14 @@
#include <net/protocol.h>
#include <net/inet_common.h>
-extern const struct udp_get_port_ops udp_ipv4_ops;
-
extern int __udp4_lib_rcv(struct sk_buff *, struct hlist_head [], int );
extern void __udp4_lib_err(struct sk_buff *, u32, struct hlist_head []);
extern int __udp_lib_get_port(struct sock *sk, unsigned short snum,
struct hlist_head udptable[], int *port_rover,
- const struct udp_get_port_ops *ops);
+ int (*)(const struct sock*,const struct sock*));
+extern int ipv4_rcv_saddr_equal(const struct sock *, const struct sock *);
+
extern int udp_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, int optlen);
diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c
index 3653b32dce2d..f34fd686a8f1 100644
--- a/net/ipv4/udplite.c
+++ b/net/ipv4/udplite.c
@@ -19,15 +19,14 @@ struct hlist_head udplite_hash[UDP_HTABLE_SIZE];
static int udplite_port_rover;
int udplite_get_port(struct sock *sk, unsigned short p,
- const struct udp_get_port_ops *ops)
+ int (*c)(const struct sock *, const struct sock *))
{
- return __udp_lib_get_port(sk, p, udplite_hash,
- &udplite_port_rover, ops);
+ return __udp_lib_get_port(sk, p, udplite_hash, &udplite_port_rover, c);
}
static int udplite_v4_get_port(struct sock *sk, unsigned short snum)
{
- return udplite_get_port(sk, snum, &udp_ipv4_ops);
+ return udplite_get_port(sk, snum, ipv4_rcv_saddr_equal);
}
static int udplite_rcv(struct sk_buff *skb)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 329de679ac38..5a5f8bd4597a 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -2990,7 +2990,7 @@ static struct in6_addr *extract_addr(struct nlattr *addr, struct nlattr *local)
return pfx;
}
-static struct nla_policy ifa_ipv6_policy[IFA_MAX+1] __read_mostly = {
+static const struct nla_policy ifa_ipv6_policy[IFA_MAX+1] = {
[IFA_ADDRESS] = { .len = sizeof(struct in6_addr) },
[IFA_LOCAL] = { .len = sizeof(struct in6_addr) },
[IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) },
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c
index fc3882c90604..53b3998a486c 100644
--- a/net/ipv6/fib6_rules.c
+++ b/net/ipv6/fib6_rules.c
@@ -157,7 +157,7 @@ static int fib6_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
return 1;
}
-static struct nla_policy fib6_rule_policy[FRA_MAX+1] __read_mostly = {
+static const struct nla_policy fib6_rule_policy[FRA_MAX+1] = {
FRA_GENERIC_POLICY,
};
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index dc442fb791b0..1b1797f1f33d 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -160,6 +160,7 @@ static unsigned int ipv6_confirm(unsigned int hooknum,
{
struct nf_conn *ct;
struct nf_conn_help *help;
+ struct nf_conntrack_helper *helper;
enum ip_conntrack_info ctinfo;
unsigned int ret, protoff;
unsigned int extoff = (u8 *)(ipv6_hdr(*pskb) + 1) - (*pskb)->data;
@@ -172,7 +173,11 @@ static unsigned int ipv6_confirm(unsigned int hooknum,
goto out;
help = nfct_help(ct);
- if (!help || !help->helper)
+ if (!help)
+ goto out;
+ /* rcu_read_lock()ed by nf_hook_slow */
+ helper = rcu_dereference(help->helper);
+ if (!helper)
goto out;
protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum,
@@ -182,7 +187,7 @@ static unsigned int ipv6_confirm(unsigned int hooknum,
return NF_ACCEPT;
}
- ret = help->helper->help(pskb, protoff, ct, ctinfo);
+ ret = helper->help(pskb, protoff, ct, ctinfo);
if (ret != NF_ACCEPT)
return ret;
out:
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 1324b06796c0..fe8d9837f9f8 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1999,7 +1999,7 @@ void rt6_mtu_change(struct net_device *dev, unsigned mtu)
fib6_clean_all(rt6_mtu_change_route, 0, &arg);
}
-static struct nla_policy rtm_ipv6_policy[RTA_MAX+1] __read_mostly = {
+static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
[RTA_GATEWAY] = { .len = sizeof(struct in6_addr) },
[RTA_OIF] = { .type = NLA_U32 },
[RTA_IIF] = { .type = NLA_U32 },
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index d1fbddd172e7..4210951edb6e 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -52,28 +52,9 @@
DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6) __read_mostly;
-static int ipv6_rcv_saddr_any(const struct sock *sk)
-{
- struct ipv6_pinfo *np = inet6_sk(sk);
-
- return ipv6_addr_any(&np->rcv_saddr);
-}
-
-static unsigned int ipv6_hash_port_and_rcv_saddr(__u16 port,
- const struct sock *sk)
-{
- return port;
-}
-
-const struct udp_get_port_ops udp_ipv6_ops = {
- .saddr_cmp = ipv6_rcv_saddr_equal,
- .saddr_any = ipv6_rcv_saddr_any,
- .hash_port_and_rcv_saddr = ipv6_hash_port_and_rcv_saddr,
-};
-
static inline int udp_v6_get_port(struct sock *sk, unsigned short snum)
{
- return udp_get_port(sk, snum, &udp_ipv6_ops);
+ return udp_get_port(sk, snum, ipv6_rcv_saddr_equal);
}
static struct sock *__udp6_lib_lookup(struct in6_addr *saddr, __be16 sport,
diff --git a/net/ipv6/udp_impl.h b/net/ipv6/udp_impl.h
index 36b0c11a28a3..6e252f318f7c 100644
--- a/net/ipv6/udp_impl.h
+++ b/net/ipv6/udp_impl.h
@@ -6,8 +6,6 @@
#include <net/addrconf.h>
#include <net/inet_common.h>
-extern const struct udp_get_port_ops udp_ipv6_ops;
-
extern int __udp6_lib_rcv(struct sk_buff **, struct hlist_head [], int );
extern void __udp6_lib_err(struct sk_buff *, struct inet6_skb_parm *,
int , int , int , __be32 , struct hlist_head []);
diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c
index c40a51362f89..f54016a55004 100644
--- a/net/ipv6/udplite.c
+++ b/net/ipv6/udplite.c
@@ -37,7 +37,7 @@ static struct inet6_protocol udplitev6_protocol = {
static int udplite_v6_get_port(struct sock *sk, unsigned short snum)
{
- return udplite_get_port(sk, snum, &udp_ipv6_ops);
+ return udplite_get_port(sk, snum, ipv6_rcv_saddr_equal);
}
struct proto udplitev6_prot = {
diff --git a/net/irda/irlap_event.c b/net/irda/irlap_event.c
index 0b02073ffdf3..a8b8873aa263 100644
--- a/net/irda/irlap_event.c
+++ b/net/irda/irlap_event.c
@@ -317,23 +317,6 @@ void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event,
}
/*
- * Function irlap_next_state (self, state)
- *
- * Switches state and provides debug information
- *
- */
-static inline void irlap_next_state(struct irlap_cb *self, IRLAP_STATE state)
-{
- /*
- if (!self || self->magic != LAP_MAGIC)
- return;
-
- IRDA_DEBUG(4, "next LAP state = %s\n", irlap_state[state]);
- */
- self->state = state;
-}
-
-/*
* Function irlap_state_ndm (event, skb, frame)
*
* NDM (Normal Disconnected Mode) state
@@ -1086,7 +1069,6 @@ static int irlap_state_xmit_p(struct irlap_cb *self, IRLAP_EVENT event,
} else {
/* Final packet of window */
irlap_send_data_primary_poll(self, skb);
- irlap_next_state(self, LAP_NRM_P);
/*
* Make sure state machine does not try to send
@@ -1436,14 +1418,14 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
*/
self->remote_busy = FALSE;
+ /* Stop final timer */
+ del_timer(&self->final_timer);
+
/*
* Nr as expected?
*/
ret = irlap_validate_nr_received(self, info->nr);
if (ret == NR_EXPECTED) {
- /* Stop final timer */
- del_timer(&self->final_timer);
-
/* Update Nr received */
irlap_update_nr_received(self, info->nr);
@@ -1475,14 +1457,12 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
/* Resend rejected frames */
irlap_resend_rejected_frames(self, CMD_FRAME);
-
- /* Final timer ??? Jean II */
+ irlap_start_final_timer(self, self->final_timeout * 2);
irlap_next_state(self, LAP_NRM_P);
} else if (ret == NR_INVALID) {
IRDA_DEBUG(1, "%s(), Received RR with "
"invalid nr !\n", __FUNCTION__);
- del_timer(&self->final_timer);
irlap_next_state(self, LAP_RESET_WAIT);
diff --git a/net/irda/irlap_frame.c b/net/irda/irlap_frame.c
index 3c5a68e36414..3013c49ab975 100644
--- a/net/irda/irlap_frame.c
+++ b/net/irda/irlap_frame.c
@@ -798,16 +798,19 @@ void irlap_send_data_primary_poll(struct irlap_cb *self, struct sk_buff *skb)
self->vs = (self->vs + 1) % 8;
self->ack_required = FALSE;
+ irlap_next_state(self, LAP_NRM_P);
irlap_send_i_frame(self, tx_skb, CMD_FRAME);
} else {
IRDA_DEBUG(4, "%s(), sending unreliable frame\n", __FUNCTION__);
if (self->ack_required) {
irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME);
+ irlap_next_state(self, LAP_NRM_P);
irlap_send_rr_frame(self, CMD_FRAME);
self->ack_required = FALSE;
} else {
skb->data[1] |= PF_BIT;
+ irlap_next_state(self, LAP_NRM_P);
irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME);
}
}
diff --git a/net/key/af_key.c b/net/key/af_key.c
index d302ddae580c..0f8304b0246b 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -1682,6 +1682,7 @@ static int pfkey_flush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hd
unsigned proto;
struct km_event c;
struct xfrm_audit audit_info;
+ int err;
proto = pfkey_satype2proto(hdr->sadb_msg_satype);
if (proto == 0)
@@ -1689,7 +1690,9 @@ static int pfkey_flush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hd
audit_info.loginuid = audit_get_loginuid(current->audit_context);
audit_info.secid = 0;
- xfrm_state_flush(proto, &audit_info);
+ err = xfrm_state_flush(proto, &audit_info);
+ if (err)
+ return err;
c.data.proto = proto;
c.seq = hdr->sadb_msg_seq;
c.pid = hdr->sadb_msg_pid;
@@ -2683,10 +2686,13 @@ static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, struct sadb_msg
{
struct km_event c;
struct xfrm_audit audit_info;
+ int err;
audit_info.loginuid = audit_get_loginuid(current->audit_context);
audit_info.secid = 0;
- xfrm_policy_flush(XFRM_POLICY_TYPE_MAIN, &audit_info);
+ err = xfrm_policy_flush(XFRM_POLICY_TYPE_MAIN, &audit_info);
+ if (err)
+ return err;
c.data.type = XFRM_POLICY_TYPE_MAIN;
c.event = XFRM_MSG_FLUSHPOLICY;
c.pid = hdr->sadb_msg_pid;
diff --git a/net/netfilter/nf_conntrack_amanda.c b/net/netfilter/nf_conntrack_amanda.c
index b8869eab7650..0568f2e86b59 100644
--- a/net/netfilter/nf_conntrack_amanda.c
+++ b/net/netfilter/nf_conntrack_amanda.c
@@ -208,13 +208,14 @@ static int __init nf_conntrack_amanda_init(void)
{
int ret, i;
- ret = -ENOMEM;
for (i = 0; i < ARRAY_SIZE(search); i++) {
search[i].ts = textsearch_prepare(ts_algo, search[i].string,
search[i].len,
GFP_KERNEL, TS_AUTOLOAD);
- if (search[i].ts == NULL)
+ if (IS_ERR(search[i].ts)) {
+ ret = PTR_ERR(search[i].ts);
goto err1;
+ }
}
ret = nf_conntrack_helper_register(&amanda_helper[0]);
if (ret < 0)
@@ -227,10 +228,9 @@ static int __init nf_conntrack_amanda_init(void)
err2:
nf_conntrack_helper_unregister(&amanda_helper[0]);
err1:
- for (; i >= 0; i--) {
- if (search[i].ts)
- textsearch_destroy(search[i].ts);
- }
+ while (--i >= 0)
+ textsearch_destroy(search[i].ts);
+
return ret;
}
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 483e927a9ca4..7a15e30356f2 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -350,9 +350,15 @@ static void death_by_timeout(unsigned long ul_conntrack)
{
struct nf_conn *ct = (void *)ul_conntrack;
struct nf_conn_help *help = nfct_help(ct);
+ struct nf_conntrack_helper *helper;
- if (help && help->helper && help->helper->destroy)
- help->helper->destroy(ct);
+ if (help) {
+ rcu_read_lock();
+ helper = rcu_dereference(help->helper);
+ if (helper && helper->destroy)
+ helper->destroy(ct);
+ rcu_read_unlock();
+ }
write_lock_bh(&nf_conntrack_lock);
/* Inside lock so preempt is disabled on module removal path.
@@ -661,6 +667,7 @@ init_conntrack(const struct nf_conntrack_tuple *tuple,
unsigned int dataoff)
{
struct nf_conn *conntrack;
+ struct nf_conn_help *help;
struct nf_conntrack_tuple repl_tuple;
struct nf_conntrack_expect *exp;
u_int32_t features = 0;
@@ -691,6 +698,7 @@ init_conntrack(const struct nf_conntrack_tuple *tuple,
write_lock_bh(&nf_conntrack_lock);
exp = find_expectation(tuple);
+ help = nfct_help(conntrack);
if (exp) {
DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n",
conntrack, exp);
@@ -698,7 +706,7 @@ init_conntrack(const struct nf_conntrack_tuple *tuple,
__set_bit(IPS_EXPECTED_BIT, &conntrack->status);
conntrack->master = exp->master;
if (exp->helper)
- nfct_help(conntrack)->helper = exp->helper;
+ rcu_assign_pointer(help->helper, exp->helper);
#ifdef CONFIG_NF_CONNTRACK_MARK
conntrack->mark = exp->master->mark;
#endif
@@ -708,10 +716,11 @@ init_conntrack(const struct nf_conntrack_tuple *tuple,
nf_conntrack_get(&conntrack->master->ct_general);
NF_CT_STAT_INC(expect_new);
} else {
- struct nf_conn_help *help = nfct_help(conntrack);
-
- if (help)
- help->helper = __nf_ct_helper_find(&repl_tuple);
+ if (help) {
+ /* not in hash table yet, so not strictly necessary */
+ rcu_assign_pointer(help->helper,
+ __nf_ct_helper_find(&repl_tuple));
+ }
NF_CT_STAT_INC(new);
}
@@ -893,7 +902,8 @@ void nf_conntrack_alter_reply(struct nf_conn *ct,
helper = __nf_ct_helper_find(newreply);
if (helper)
memset(&help->help, 0, sizeof(help->help));
- help->helper = helper;
+ /* not in hash table yet, so not strictly necessary */
+ rcu_assign_pointer(help->helper, helper);
}
write_unlock_bh(&nf_conntrack_lock);
}
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
index 117cbfdb910c..504fb6c083f9 100644
--- a/net/netfilter/nf_conntrack_expect.c
+++ b/net/netfilter/nf_conntrack_expect.c
@@ -337,6 +337,10 @@ int nf_conntrack_expect_related(struct nf_conntrack_expect *expect)
NF_CT_ASSERT(master_help);
write_lock_bh(&nf_conntrack_lock);
+ if (!master_help->helper) {
+ ret = -ESHUTDOWN;
+ goto out;
+ }
list_for_each_entry(i, &nf_conntrack_expect_list, list) {
if (expect_matches(i, expect)) {
/* Refresh timer: if it's dying, ignore.. */
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
index 0743be4434b0..f868b7fbd9b4 100644
--- a/net/netfilter/nf_conntrack_helper.c
+++ b/net/netfilter/nf_conntrack_helper.c
@@ -93,7 +93,7 @@ static inline int unhelp(struct nf_conntrack_tuple_hash *i,
if (help && help->helper == me) {
nf_conntrack_event(IPCT_HELPER, ct);
- help->helper = NULL;
+ rcu_assign_pointer(help->helper, NULL);
}
return 0;
}
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index d6d39e241327..3f73327794ab 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -171,21 +171,29 @@ ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct nf_conn *ct)
{
struct nfattr *nest_helper;
const struct nf_conn_help *help = nfct_help(ct);
+ struct nf_conntrack_helper *helper;
- if (!help || !help->helper)
+ if (!help)
return 0;
+ rcu_read_lock();
+ helper = rcu_dereference(help->helper);
+ if (!helper)
+ goto out;
+
nest_helper = NFA_NEST(skb, CTA_HELP);
- NFA_PUT(skb, CTA_HELP_NAME, strlen(help->helper->name), help->helper->name);
+ NFA_PUT(skb, CTA_HELP_NAME, strlen(helper->name), helper->name);
- if (help->helper->to_nfattr)
- help->helper->to_nfattr(skb, ct);
+ if (helper->to_nfattr)
+ helper->to_nfattr(skb, ct);
NFA_NEST_END(skb, nest_helper);
-
+out:
+ rcu_read_unlock();
return 0;
nfattr_failure:
+ rcu_read_unlock();
return -1;
}
@@ -842,7 +850,7 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[])
if (help && help->helper) {
/* we had a helper before ... */
nf_ct_remove_expectations(ct);
- help->helper = NULL;
+ rcu_assign_pointer(help->helper, NULL);
}
return 0;
@@ -866,7 +874,7 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[])
/* need to zero data of old helper */
memset(&help->help, 0, sizeof(help->help));
- help->helper = helper;
+ rcu_assign_pointer(help->helper, helper);
return 0;
}
@@ -950,6 +958,7 @@ ctnetlink_create_conntrack(struct nfattr *cda[],
struct nf_conn *ct;
int err = -EINVAL;
struct nf_conn_help *help;
+ struct nf_conntrack_helper *helper = NULL;
ct = nf_conntrack_alloc(otuple, rtuple);
if (ct == NULL || IS_ERR(ct))
@@ -980,14 +989,17 @@ ctnetlink_create_conntrack(struct nfattr *cda[],
#endif
help = nfct_help(ct);
- if (help)
- help->helper = nf_ct_helper_find_get(rtuple);
+ if (help) {
+ helper = nf_ct_helper_find_get(rtuple);
+ /* not in hash table yet so not strictly necessary */
+ rcu_assign_pointer(help->helper, helper);
+ }
add_timer(&ct->timeout);
nf_conntrack_hash_insert(ct);
- if (help && help->helper)
- nf_ct_helper_put(help->helper);
+ if (helper)
+ nf_ct_helper_put(helper);
return 0;
diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c
index 5434472420fe..339c397d1b5f 100644
--- a/net/netfilter/nf_conntrack_proto_gre.c
+++ b/net/netfilter/nf_conntrack_proto_gre.c
@@ -100,7 +100,6 @@ int nf_ct_gre_keymap_add(struct nf_conn *ct, enum ip_conntrack_dir dir,
struct nf_conn_help *help = nfct_help(ct);
struct nf_ct_gre_keymap **kmp, *km;
- BUG_ON(strcmp(help->helper->name, "pptp"));
kmp = &help->help.ct_pptp_info.keymap[dir];
if (*kmp) {
/* check whether it's a retransmission */
@@ -137,7 +136,6 @@ void nf_ct_gre_keymap_destroy(struct nf_conn *ct)
enum ip_conntrack_dir dir;
DEBUGP("entering for ct %p\n", ct);
- BUG_ON(strcmp(help->helper->name, "pptp"));
write_lock_bh(&nf_ct_gre_lock);
for (dir = IP_CT_DIR_ORIGINAL; dir < IP_CT_DIR_MAX; dir++) {
diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c
index 07e47dbcb0a9..24b660f16ce3 100644
--- a/net/netlabel/netlabel_cipso_v4.c
+++ b/net/netlabel/netlabel_cipso_v4.c
@@ -59,7 +59,7 @@ static struct genl_family netlbl_cipsov4_gnl_family = {
};
/* NetLabel Netlink attribute policy */
-static struct nla_policy netlbl_cipsov4_genl_policy[NLBL_CIPSOV4_A_MAX + 1] = {
+static const struct nla_policy netlbl_cipsov4_genl_policy[NLBL_CIPSOV4_A_MAX + 1] = {
[NLBL_CIPSOV4_A_DOI] = { .type = NLA_U32 },
[NLBL_CIPSOV4_A_MTYPE] = { .type = NLA_U32 },
[NLBL_CIPSOV4_A_TAG] = { .type = NLA_U8 },
diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c
index f2535e7f2869..b165712aaa70 100644
--- a/net/netlabel/netlabel_kapi.c
+++ b/net/netlabel/netlabel_kapi.c
@@ -246,19 +246,18 @@ int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap,
/**
* netlbl_socket_setattr - Label a socket using the correct protocol
- * @sock: the socket to label
+ * @sk: the socket to label
* @secattr: the security attributes
*
* Description:
* Attach the correct label to the given socket using the security attributes
- * specified in @secattr. This function requires exclusive access to
- * @sock->sk, which means it either needs to be in the process of being
- * created or locked via lock_sock(sock->sk). Returns zero on success,
- * negative values on failure.
+ * specified in @secattr. This function requires exclusive access to @sk,
+ * which means it either needs to be in the process of being created or locked.
+ * Returns zero on success, negative values on failure.
*
*/
-int netlbl_socket_setattr(const struct socket *sock,
- const struct netlbl_lsm_secattr *secattr)
+int netlbl_sock_setattr(struct sock *sk,
+ const struct netlbl_lsm_secattr *secattr)
{
int ret_val = -ENOENT;
struct netlbl_dom_map *dom_entry;
@@ -269,9 +268,9 @@ int netlbl_socket_setattr(const struct socket *sock,
goto socket_setattr_return;
switch (dom_entry->type) {
case NETLBL_NLTYPE_CIPSOV4:
- ret_val = cipso_v4_socket_setattr(sock,
- dom_entry->type_def.cipsov4,
- secattr);
+ ret_val = cipso_v4_sock_setattr(sk,
+ dom_entry->type_def.cipsov4,
+ secattr);
break;
case NETLBL_NLTYPE_UNLABELED:
ret_val = 0;
@@ -309,30 +308,6 @@ int netlbl_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
}
/**
- * netlbl_socket_getattr - Determine the security attributes of a socket
- * @sock: the socket
- * @secattr: the security attributes
- *
- * Description:
- * Examines the given socket to see any NetLabel style labeling has been
- * applied to the socket, if so it parses the socket label and returns the
- * security attributes in @secattr. Returns zero on success, negative values
- * on failure.
- *
- */
-int netlbl_socket_getattr(const struct socket *sock,
- struct netlbl_lsm_secattr *secattr)
-{
- int ret_val;
-
- ret_val = cipso_v4_socket_getattr(sock, secattr);
- if (ret_val == 0)
- return 0;
-
- return netlbl_unlabel_getattr(secattr);
-}
-
-/**
* netlbl_skbuff_getattr - Determine the security attributes of a packet
* @skb: the packet
* @secattr: the security attributes
diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c
index e8c80f33f3d7..e00fc219c72b 100644
--- a/net/netlabel/netlabel_mgmt.c
+++ b/net/netlabel/netlabel_mgmt.c
@@ -59,7 +59,7 @@ static struct genl_family netlbl_mgmt_gnl_family = {
};
/* NetLabel Netlink attribute policy */
-static struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
+static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
[NLBL_MGMT_A_DOMAIN] = { .type = NLA_NUL_STRING },
[NLBL_MGMT_A_PROTOCOL] = { .type = NLA_U32 },
[NLBL_MGMT_A_VERSION] = { .type = NLA_U32 },
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
index b931edee4b8b..5c303c68af1d 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -61,7 +61,7 @@ static struct genl_family netlbl_unlabel_gnl_family = {
};
/* NetLabel Netlink attribute policy */
-static struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1] = {
+static const struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1] = {
[NLBL_UNLABEL_A_ACPTFLG] = { .type = NLA_U8 },
};
diff --git a/net/netlink/attr.c b/net/netlink/attr.c
index df5f820a4c32..c591212793ee 100644
--- a/net/netlink/attr.c
+++ b/net/netlink/attr.c
@@ -24,9 +24,9 @@ static u16 nla_attr_minlen[NLA_TYPE_MAX+1] __read_mostly = {
};
static int validate_nla(struct nlattr *nla, int maxtype,
- struct nla_policy *policy)
+ const struct nla_policy *policy)
{
- struct nla_policy *pt;
+ const struct nla_policy *pt;
int minlen = 0, attrlen = nla_len(nla);
if (nla->nla_type <= 0 || nla->nla_type > maxtype)
@@ -99,7 +99,7 @@ static int validate_nla(struct nlattr *nla, int maxtype,
* Returns 0 on success or a negative error code.
*/
int nla_validate(struct nlattr *head, int len, int maxtype,
- struct nla_policy *policy)
+ const struct nla_policy *policy)
{
struct nlattr *nla;
int rem, err;
@@ -130,7 +130,7 @@ errout:
* Returns 0 on success or a negative error code.
*/
int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len,
- struct nla_policy *policy)
+ const struct nla_policy *policy)
{
struct nlattr *nla;
int rem, err;
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index 6e31234a4196..b9ab62f938d0 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -472,7 +472,7 @@ static struct sk_buff *ctrl_build_msg(struct genl_family *family, u32 pid,
return skb;
}
-static struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] __read_mostly = {
+static const struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = {
[CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 },
[CTRL_ATTR_FAMILY_NAME] = { .type = NLA_NUL_STRING,
.len = GENL_NAMSIZ - 1 },
diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c
index be7d299acd73..d1c383fca82c 100644
--- a/net/sched/sch_atm.c
+++ b/net/sched/sch_atm.c
@@ -599,6 +599,7 @@ static void atm_tc_destroy(struct Qdisc *sch)
/* races ? */
while ((flow = p->flows)) {
tcf_destroy_chain(flow->filter_list);
+ flow->filter_list = NULL;
if (flow->ref > 1)
printk(KERN_ERR "atm_destroy: %p->ref = %d\n",flow,
flow->ref);
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index a294542cb8e4..ee2d5967d109 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -1748,10 +1748,12 @@ cbq_destroy(struct Qdisc* sch)
* classes from root to leafs which means that filters can still
* be bound to classes which have been destroyed already. --TGR '04
*/
- for (h = 0; h < 16; h++)
- for (cl = q->classes[h]; cl; cl = cl->next)
+ for (h = 0; h < 16; h++) {
+ for (cl = q->classes[h]; cl; cl = cl->next) {
tcf_destroy_chain(cl->filter_list);
-
+ cl->filter_list = NULL;
+ }
+ }
for (h = 0; h < 16; h++) {
struct cbq_class *next;
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 87c794d8fa2d..d70fa30d4294 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1744,20 +1744,23 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
int chunk;
struct sk_buff *skb;
+ unix_state_lock(sk);
skb = skb_dequeue(&sk->sk_receive_queue);
if (skb==NULL)
{
if (copied >= target)
- break;
+ goto unlock;
/*
* POSIX 1003.1g mandates this order.
*/
if ((err = sock_error(sk)) != 0)
- break;
+ goto unlock;
if (sk->sk_shutdown & RCV_SHUTDOWN)
- break;
+ goto unlock;
+
+ unix_state_unlock(sk);
err = -EAGAIN;
if (!timeo)
break;
@@ -1771,7 +1774,11 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
}
mutex_lock(&u->readlock);
continue;
+ unlock:
+ unix_state_unlock(sk);
+ break;
}
+ unix_state_unlock(sk);
if (check_creds) {
/* Never glue messages from different writers */
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 64a375178c5f..157bfbd250ba 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -834,11 +834,67 @@ struct xfrm_policy *xfrm_policy_byid(u8 type, int dir, u32 id, int delete,
}
EXPORT_SYMBOL(xfrm_policy_byid);
-void xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info)
+#ifdef CONFIG_SECURITY_NETWORK_XFRM
+static inline int
+xfrm_policy_flush_secctx_check(u8 type, struct xfrm_audit *audit_info)
{
- int dir;
+ int dir, err = 0;
+
+ for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
+ struct xfrm_policy *pol;
+ struct hlist_node *entry;
+ int i;
+
+ hlist_for_each_entry(pol, entry,
+ &xfrm_policy_inexact[dir], bydst) {
+ if (pol->type != type)
+ continue;
+ err = security_xfrm_policy_delete(pol);
+ if (err) {
+ xfrm_audit_log(audit_info->loginuid,
+ audit_info->secid,
+ AUDIT_MAC_IPSEC_DELSPD, 0,
+ pol, NULL);
+ return err;
+ }
+ }
+ for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) {
+ hlist_for_each_entry(pol, entry,
+ xfrm_policy_bydst[dir].table + i,
+ bydst) {
+ if (pol->type != type)
+ continue;
+ err = security_xfrm_policy_delete(pol);
+ if (err) {
+ xfrm_audit_log(audit_info->loginuid,
+ audit_info->secid,
+ AUDIT_MAC_IPSEC_DELSPD,
+ 0, pol, NULL);
+ return err;
+ }
+ }
+ }
+ }
+ return err;
+}
+#else
+static inline int
+xfrm_policy_flush_secctx_check(u8 type, struct xfrm_audit *audit_info)
+{
+ return 0;
+}
+#endif
+
+int xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info)
+{
+ int dir, err = 0;
write_lock_bh(&xfrm_policy_lock);
+
+ err = xfrm_policy_flush_secctx_check(type, audit_info);
+ if (err)
+ goto out;
+
for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
struct xfrm_policy *pol;
struct hlist_node *entry;
@@ -891,7 +947,9 @@ void xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info)
xfrm_policy_count[dir] -= killed;
}
atomic_inc(&flow_cache_genid);
+out:
write_unlock_bh(&xfrm_policy_lock);
+ return err;
}
EXPORT_SYMBOL(xfrm_policy_flush);
@@ -2583,4 +2641,3 @@ restore_state:
}
EXPORT_SYMBOL(xfrm_migrate);
#endif
-
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 372f06eb8bb7..85f3f43a6cca 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -391,12 +391,48 @@ int xfrm_state_delete(struct xfrm_state *x)
}
EXPORT_SYMBOL(xfrm_state_delete);
-void xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info)
+#ifdef CONFIG_SECURITY_NETWORK_XFRM
+static inline int
+xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info)
{
- int i;
- int err = 0;
+ int i, err = 0;
+
+ for (i = 0; i <= xfrm_state_hmask; i++) {
+ struct hlist_node *entry;
+ struct xfrm_state *x;
+
+ hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) {
+ if (xfrm_id_proto_match(x->id.proto, proto) &&
+ (err = security_xfrm_state_delete(x)) != 0) {
+ xfrm_audit_log(audit_info->loginuid,
+ audit_info->secid,
+ AUDIT_MAC_IPSEC_DELSA,
+ 0, NULL, x);
+
+ return err;
+ }
+ }
+ }
+
+ return err;
+}
+#else
+static inline int
+xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info)
+{
+ return 0;
+}
+#endif
+
+int xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info)
+{
+ int i, err = 0;
spin_lock_bh(&xfrm_state_lock);
+ err = xfrm_state_flush_secctx_check(proto, audit_info);
+ if (err)
+ goto out;
+
for (i = 0; i <= xfrm_state_hmask; i++) {
struct hlist_node *entry;
struct xfrm_state *x;
@@ -419,8 +455,12 @@ restart:
}
}
}
+ err = 0;
+
+out:
spin_unlock_bh(&xfrm_state_lock);
wake_up(&km_waitq);
+ return err;
}
EXPORT_SYMBOL(xfrm_state_flush);
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index b14c7e590c31..c06883bf620e 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -1418,10 +1418,13 @@ static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
struct km_event c;
struct xfrm_usersa_flush *p = NLMSG_DATA(nlh);
struct xfrm_audit audit_info;
+ int err;
audit_info.loginuid = NETLINK_CB(skb).loginuid;
audit_info.secid = NETLINK_CB(skb).sid;
- xfrm_state_flush(p->proto, &audit_info);
+ err = xfrm_state_flush(p->proto, &audit_info);
+ if (err)
+ return err;
c.data.proto = p->proto;
c.event = nlh->nlmsg_type;
c.seq = nlh->nlmsg_seq;
@@ -1582,7 +1585,9 @@ static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
audit_info.loginuid = NETLINK_CB(skb).loginuid;
audit_info.secid = NETLINK_CB(skb).sid;
- xfrm_policy_flush(type, &audit_info);
+ err = xfrm_policy_flush(type, &audit_info);
+ if (err)
+ return err;
c.data.type = type;
c.event = nlh->nlmsg_type;
c.seq = nlh->nlmsg_seq;