diff options
Diffstat (limited to 'net')
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; |