summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/bridge/br_netlink.c2
-rw-r--r--net/core/Makefile2
-rw-r--r--net/core/dev.c19
-rw-r--r--net/core/neighbour.c14
-rw-r--r--net/core/netevent.c69
-rw-r--r--net/core/skbuff.c45
-rw-r--r--net/dccp/ipv6.c4
-rw-r--r--net/decnet/dn_route.c9
-rw-r--r--net/ipv4/ip_output.c7
-rw-r--r--net/ipv4/ip_sockglue.c9
-rw-r--r--net/ipv4/netfilter/ip_conntrack_sip.c2
-rw-r--r--net/ipv4/netfilter/ipt_hashlimit.c3
-rw-r--r--net/ipv4/route.c8
-rw-r--r--net/ipv4/tcp.c5
-rw-r--r--net/ipv4/tcp_input.c3
-rw-r--r--net/ipv4/tcp_ipv4.c2
-rw-r--r--net/ipv4/tcp_minisocks.c4
-rw-r--r--net/ipv4/tcp_probe.c2
-rw-r--r--net/ipv6/addrconf.c174
-rw-r--r--net/ipv6/af_inet6.c2
-rw-r--r--net/ipv6/inet6_connection_sock.c2
-rw-r--r--net/ipv6/ip6_output.c129
-rw-r--r--net/ipv6/route.c7
-rw-r--r--net/ipv6/tcp_ipv6.c6
-rw-r--r--net/ipv6/udp.c2
-rw-r--r--net/ipv6/xfrm6_output.c2
-rw-r--r--net/lapb/lapb_iface.c12
-rw-r--r--net/llc/af_llc.c20
-rw-r--r--net/llc/llc_sap.c4
-rw-r--r--net/netfilter/xt_SECMARK.c2
-rw-r--r--net/netfilter/xt_string.c5
-rw-r--r--net/sched/sch_api.c2
-rw-r--r--net/sunrpc/cache.c6
-rw-r--r--net/sunrpc/clnt.c52
-rw-r--r--net/sunrpc/rpc_pipe.c6
-rw-r--r--net/sunrpc/xprt.c21
-rw-r--r--net/sunrpc/xprtsock.c29
-rw-r--r--net/unix/af_unix.c17
38 files changed, 520 insertions, 189 deletions
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index 06abb6634f5b..53086fb75089 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -85,7 +85,7 @@ void br_ifinfo_notify(int event, struct net_bridge_port *port)
goto err_out;
err = br_fill_ifinfo(skb, port, current->pid, 0, event, 0);
- if (err)
+ if (err < 0)
goto err_kfree;
NETLINK_CB(skb).dst_group = RTNLGRP_LINK;
diff --git a/net/core/Makefile b/net/core/Makefile
index e9bd2467d5a9..2645ba428d48 100644
--- a/net/core/Makefile
+++ b/net/core/Makefile
@@ -7,7 +7,7 @@ obj-y := sock.o request_sock.o skbuff.o iovec.o datagram.o stream.o scm.o \
obj-$(CONFIG_SYSCTL) += sysctl_net_core.o
-obj-y += dev.o ethtool.o dev_mcast.o dst.o \
+obj-y += dev.o ethtool.o dev_mcast.o dst.o netevent.o \
neighbour.o rtnetlink.o utils.o link_watch.o filter.o
obj-$(CONFIG_XFRM) += flow.o
diff --git a/net/core/dev.c b/net/core/dev.c
index 4d2b5167d7f5..d95e2626d944 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1166,11 +1166,6 @@ int skb_checksum_help(struct sk_buff *skb, int inward)
goto out_set_summed;
if (unlikely(skb_shinfo(skb)->gso_size)) {
- static int warned;
-
- WARN_ON(!warned);
- warned = 1;
-
/* Let GSO fix up the checksum. */
goto out_set_summed;
}
@@ -1220,11 +1215,6 @@ struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features)
__skb_pull(skb, skb->mac_len);
if (unlikely(skb->ip_summed != CHECKSUM_HW)) {
- static int warned;
-
- WARN_ON(!warned);
- warned = 1;
-
if (skb_header_cloned(skb) &&
(err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
return ERR_PTR(err);
@@ -3429,12 +3419,9 @@ static void net_dma_rebalance(void)
unsigned int cpu, i, n;
struct dma_chan *chan;
- lock_cpu_hotplug();
-
if (net_dma_count == 0) {
for_each_online_cpu(cpu)
- rcu_assign_pointer(per_cpu(softnet_data.net_dma, cpu), NULL);
- unlock_cpu_hotplug();
+ rcu_assign_pointer(per_cpu(softnet_data, cpu).net_dma, NULL);
return;
}
@@ -3447,15 +3434,13 @@ static void net_dma_rebalance(void)
+ (i < (num_online_cpus() % net_dma_count) ? 1 : 0));
while(n) {
- per_cpu(softnet_data.net_dma, cpu) = chan;
+ per_cpu(softnet_data, cpu).net_dma = chan;
cpu = next_cpu(cpu, cpu_online_map);
n--;
}
i++;
}
rcu_read_unlock();
-
- unlock_cpu_hotplug();
}
/**
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 7ad681f5e712..5130d2efdbbe 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -29,6 +29,7 @@
#include <net/neighbour.h>
#include <net/dst.h>
#include <net/sock.h>
+#include <net/netevent.h>
#include <linux/rtnetlink.h>
#include <linux/random.h>
#include <linux/string.h>
@@ -754,6 +755,7 @@ static void neigh_timer_handler(unsigned long arg)
neigh->nud_state = NUD_STALE;
neigh->updated = jiffies;
neigh_suspect(neigh);
+ notify = 1;
}
} else if (state & NUD_DELAY) {
if (time_before_eq(now,
@@ -762,6 +764,7 @@ static void neigh_timer_handler(unsigned long arg)
neigh->nud_state = NUD_REACHABLE;
neigh->updated = jiffies;
neigh_connect(neigh);
+ notify = 1;
next = neigh->confirmed + neigh->parms->reachable_time;
} else {
NEIGH_PRINTK2("neigh %p is probed.\n", neigh);
@@ -819,6 +822,8 @@ static void neigh_timer_handler(unsigned long arg)
out:
write_unlock(&neigh->lock);
}
+ if (notify)
+ call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
#ifdef CONFIG_ARPD
if (notify && neigh->parms->app_probes)
@@ -926,9 +931,7 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
{
u8 old;
int err;
-#ifdef CONFIG_ARPD
int notify = 0;
-#endif
struct net_device *dev;
int update_isrouter = 0;
@@ -948,9 +951,7 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
neigh_suspect(neigh);
neigh->nud_state = new;
err = 0;
-#ifdef CONFIG_ARPD
notify = old & NUD_VALID;
-#endif
goto out;
}
@@ -1022,9 +1023,7 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
if (!(new & NUD_CONNECTED))
neigh->confirmed = jiffies -
(neigh->parms->base_reachable_time << 1);
-#ifdef CONFIG_ARPD
notify = 1;
-#endif
}
if (new == old)
goto out;
@@ -1056,6 +1055,9 @@ out:
(neigh->flags & ~NTF_ROUTER);
}
write_unlock_bh(&neigh->lock);
+
+ if (notify)
+ call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
#ifdef CONFIG_ARPD
if (notify && neigh->parms->app_probes)
neigh_app_notify(neigh);
diff --git a/net/core/netevent.c b/net/core/netevent.c
new file mode 100644
index 000000000000..35d02c38554e
--- /dev/null
+++ b/net/core/netevent.c
@@ -0,0 +1,69 @@
+/*
+ * Network event notifiers
+ *
+ * Authors:
+ * Tom Tucker <tom@opengridcomputing.com>
+ * Steve Wise <swise@opengridcomputing.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Fixes:
+ */
+
+#include <linux/rtnetlink.h>
+#include <linux/notifier.h>
+
+static ATOMIC_NOTIFIER_HEAD(netevent_notif_chain);
+
+/**
+ * register_netevent_notifier - register a netevent notifier block
+ * @nb: notifier
+ *
+ * Register a notifier to be called when a netevent occurs.
+ * The notifier passed is linked into the kernel structures and must
+ * not be reused until it has been unregistered. A negative errno code
+ * is returned on a failure.
+ */
+int register_netevent_notifier(struct notifier_block *nb)
+{
+ int err;
+
+ err = atomic_notifier_chain_register(&netevent_notif_chain, nb);
+ return err;
+}
+
+/**
+ * netevent_unregister_notifier - unregister a netevent notifier block
+ * @nb: notifier
+ *
+ * Unregister a notifier previously registered by
+ * register_neigh_notifier(). The notifier is unlinked into the
+ * kernel structures and may then be reused. A negative errno code
+ * is returned on a failure.
+ */
+
+int unregister_netevent_notifier(struct notifier_block *nb)
+{
+ return atomic_notifier_chain_unregister(&netevent_notif_chain, nb);
+}
+
+/**
+ * call_netevent_notifiers - call all netevent notifier blocks
+ * @val: value passed unmodified to notifier function
+ * @v: pointer passed unmodified to notifier function
+ *
+ * Call all neighbour notifier blocks. Parameters and return value
+ * are as for notifier_call_chain().
+ */
+
+int call_netevent_notifiers(unsigned long val, void *v)
+{
+ return atomic_notifier_call_chain(&netevent_notif_chain, val, v);
+}
+
+EXPORT_SYMBOL_GPL(register_netevent_notifier);
+EXPORT_SYMBOL_GPL(unregister_netevent_notifier);
+EXPORT_SYMBOL_GPL(call_netevent_notifiers);
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 476aa3978504..022d8894c11d 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -71,13 +71,6 @@ static kmem_cache_t *skbuff_head_cache __read_mostly;
static kmem_cache_t *skbuff_fclone_cache __read_mostly;
/*
- * lockdep: lock class key used by skb_queue_head_init():
- */
-struct lock_class_key skb_queue_lock_key;
-
-EXPORT_SYMBOL(skb_queue_lock_key);
-
-/*
* Keep out-of-line to prevent kernel bloat.
* __builtin_return_address is not used because it is not always
* reliable.
@@ -256,6 +249,29 @@ nodata:
goto out;
}
+/**
+ * __netdev_alloc_skb - allocate an skbuff for rx on a specific device
+ * @dev: network device to receive on
+ * @length: length to allocate
+ * @gfp_mask: get_free_pages mask, passed to alloc_skb
+ *
+ * Allocate a new &sk_buff and assign it a usage count of one. The
+ * buffer has unspecified headroom built in. Users should allocate
+ * the headroom they think they need without accounting for the
+ * built in space. The built in space is used for optimisations.
+ *
+ * %NULL is returned if there is no free memory.
+ */
+struct sk_buff *__netdev_alloc_skb(struct net_device *dev,
+ unsigned int length, gfp_t gfp_mask)
+{
+ struct sk_buff *skb;
+
+ skb = alloc_skb(length + NET_SKB_PAD, gfp_mask);
+ if (likely(skb))
+ skb_reserve(skb, NET_SKB_PAD);
+ return skb;
+}
static void skb_drop_list(struct sk_buff **listp)
{
@@ -846,7 +862,11 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len)
unlikely((err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC))))
return err;
- for (i = 0; i < nfrags; i++) {
+ i = 0;
+ if (offset >= len)
+ goto drop_pages;
+
+ for (; i < nfrags; i++) {
int end = offset + skb_shinfo(skb)->frags[i].size;
if (end < len) {
@@ -854,9 +874,9 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len)
continue;
}
- if (len > offset)
- skb_shinfo(skb)->frags[i++].size = len - offset;
+ skb_shinfo(skb)->frags[i++].size = len - offset;
+drop_pages:
skb_shinfo(skb)->nr_frags = i;
for (; i < nfrags; i++)
@@ -864,7 +884,7 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len)
if (skb_shinfo(skb)->frag_list)
skb_drop_fraglist(skb);
- break;
+ goto done;
}
for (fragp = &skb_shinfo(skb)->frag_list; (frag = *fragp);
@@ -879,6 +899,7 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len)
return -ENOMEM;
nfrag->next = frag->next;
+ kfree_skb(frag);
frag = nfrag;
*fragp = frag;
}
@@ -897,6 +918,7 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len)
break;
}
+done:
if (len > skb_headlen(skb)) {
skb->data_len -= skb->len - len;
skb->len = len;
@@ -2042,6 +2064,7 @@ EXPORT_SYMBOL(__kfree_skb);
EXPORT_SYMBOL(kfree_skb);
EXPORT_SYMBOL(__pskb_pull_tail);
EXPORT_SYMBOL(__alloc_skb);
+EXPORT_SYMBOL(__netdev_alloc_skb);
EXPORT_SYMBOL(pskb_copy);
EXPORT_SYMBOL(pskb_expand_head);
EXPORT_SYMBOL(skb_checksum);
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 9f3d4d7cd0bf..610c722ac27f 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -230,7 +230,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
ipv6_addr_copy(&np->saddr, saddr);
inet->rcv_saddr = LOOPBACK4_IPV6;
- ip6_dst_store(sk, dst, NULL);
+ __ip6_dst_store(sk, dst, NULL);
icsk->icsk_ext_hdr_len = 0;
if (np->opt != NULL)
@@ -863,7 +863,7 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
* comment in that function for the gory details. -acme
*/
- ip6_dst_store(newsk, dst, NULL);
+ __ip6_dst_store(newsk, dst, NULL);
newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM |
NETIF_F_TSO);
newdp6 = (struct dccp6_sock *)newsk;
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index 1355614ec11b..743e9fcf7c5a 100644
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -925,8 +925,13 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old
for(dev_out = dev_base; dev_out; dev_out = dev_out->next) {
if (!dev_out->dn_ptr)
continue;
- if (dn_dev_islocal(dev_out, oldflp->fld_src))
- break;
+ if (!dn_dev_islocal(dev_out, oldflp->fld_src))
+ continue;
+ if ((dev_out->flags & IFF_LOOPBACK) &&
+ oldflp->fld_dst &&
+ !dn_dev_islocal(dev_out, oldflp->fld_dst))
+ continue;
+ break;
}
read_unlock(&dev_base_lock);
if (dev_out == NULL)
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 7c9f9a6421b8..9bf307a29783 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -526,6 +526,8 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
err = output(skb);
+ if (!err)
+ IP_INC_STATS(IPSTATS_MIB_FRAGCREATES);
if (err || !frag)
break;
@@ -649,9 +651,6 @@ slow_path:
/*
* Put this fragment into the sending queue.
*/
-
- IP_INC_STATS(IPSTATS_MIB_FRAGCREATES);
-
iph->tot_len = htons(len + hlen);
ip_send_check(iph);
@@ -659,6 +658,8 @@ slow_path:
err = output(skb2);
if (err)
goto fail;
+
+ IP_INC_STATS(IPSTATS_MIB_FRAGCREATES);
}
kfree_skb(skb);
IP_INC_STATS(IPSTATS_MIB_FRAGOKS);
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 84f43a3c9098..2d05c4133d3e 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -112,14 +112,19 @@ static void ip_cmsg_recv_retopts(struct msghdr *msg, struct sk_buff *skb)
static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb)
{
char *secdata;
- u32 seclen;
+ u32 seclen, secid;
int err;
- err = security_socket_getpeersec_dgram(skb, &secdata, &seclen);
+ err = security_socket_getpeersec_dgram(NULL, skb, &secid);
+ if (err)
+ return;
+
+ err = security_secid_to_secctx(secid, &secdata, &seclen);
if (err)
return;
put_cmsg(msg, SOL_IP, SCM_SECURITY, seclen, secdata);
+ security_release_secctx(secdata, seclen);
}
diff --git a/net/ipv4/netfilter/ip_conntrack_sip.c b/net/ipv4/netfilter/ip_conntrack_sip.c
index fc87ce0da40d..4f222d6be009 100644
--- a/net/ipv4/netfilter/ip_conntrack_sip.c
+++ b/net/ipv4/netfilter/ip_conntrack_sip.c
@@ -442,7 +442,7 @@ static int __init init(void)
sip[i].tuple.src.u.udp.port = htons(ports[i]);
sip[i].mask.src.u.udp.port = 0xFFFF;
sip[i].mask.dst.protonum = 0xFF;
- sip[i].max_expected = 1;
+ sip[i].max_expected = 2;
sip[i].timeout = 3 * 60; /* 3 minutes */
sip[i].me = THIS_MODULE;
sip[i].help = sip_help;
diff --git a/net/ipv4/netfilter/ipt_hashlimit.c b/net/ipv4/netfilter/ipt_hashlimit.c
index 92980ab8ce48..6b662449e825 100644
--- a/net/ipv4/netfilter/ipt_hashlimit.c
+++ b/net/ipv4/netfilter/ipt_hashlimit.c
@@ -508,6 +508,9 @@ hashlimit_checkentry(const char *tablename,
if (!r->cfg.expire)
return 0;
+ if (r->name[sizeof(r->name) - 1] != '\0')
+ return 0;
+
/* This is the best we've got: We cannot release and re-grab lock,
* since checkentry() is called before ip_tables.c grabs ipt_mutex.
* We also cannot grab the hashtable spinlock, since htable_create will
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 2dc6dbb28467..19bd49d69d9f 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -104,6 +104,7 @@
#include <net/icmp.h>
#include <net/xfrm.h>
#include <net/ip_mp_alg.h>
+#include <net/netevent.h>
#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h>
#endif
@@ -1125,6 +1126,7 @@ void ip_rt_redirect(u32 old_gw, u32 daddr, u32 new_gw,
struct rtable *rth, **rthp;
u32 skeys[2] = { saddr, 0 };
int ikeys[2] = { dev->ifindex, 0 };
+ struct netevent_redirect netevent;
if (!in_dev)
return;
@@ -1216,6 +1218,11 @@ void ip_rt_redirect(u32 old_gw, u32 daddr, u32 new_gw,
rt_drop(rt);
goto do_next;
}
+
+ netevent.old = &rth->u.dst;
+ netevent.new = &rt->u.dst;
+ call_netevent_notifiers(NETEVENT_REDIRECT,
+ &netevent);
rt_del(hash, rth);
if (!rt_intern_hash(hash, rt, &rt))
@@ -1452,6 +1459,7 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu)
}
dst->metrics[RTAX_MTU-1] = mtu;
dst_set_expires(dst, ip_rt_mtu_expires);
+ call_netevent_notifiers(NETEVENT_PMTU_UPDATE, dst);
}
}
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index f6a2d9223d07..934396bb1376 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -1132,7 +1132,7 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
tp->ucopy.dma_chan = NULL;
preempt_disable();
if ((len > sysctl_tcp_dma_copybreak) && !(flags & MSG_PEEK) &&
- !sysctl_tcp_low_latency && __get_cpu_var(softnet_data.net_dma)) {
+ !sysctl_tcp_low_latency && __get_cpu_var(softnet_data).net_dma) {
preempt_enable_no_resched();
tp->ucopy.pinned_list = dma_pin_iovec_pages(msg->msg_iov, len);
} else
@@ -1659,7 +1659,8 @@ adjudge_to_death:
const int tmo = tcp_fin_time(sk);
if (tmo > TCP_TIMEWAIT_LEN) {
- inet_csk_reset_keepalive_timer(sk, tcp_fin_time(sk));
+ inet_csk_reset_keepalive_timer(sk,
+ tmo - TCP_TIMEWAIT_LEN);
} else {
tcp_time_wait(sk, TCP_FIN_WAIT2, tmo);
goto out;
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 738dad9f7d49..104af5d5bcbc 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -3541,7 +3541,8 @@ void tcp_cwnd_application_limited(struct sock *sk)
if (inet_csk(sk)->icsk_ca_state == TCP_CA_Open &&
sk->sk_socket && !test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) {
/* Limited by application or receiver window. */
- u32 win_used = max(tp->snd_cwnd_used, 2U);
+ u32 init_win = tcp_init_cwnd(tp, __sk_dst_get(sk));
+ u32 win_used = max(tp->snd_cwnd_used, init_win);
if (win_used < tp->snd_cwnd) {
tp->snd_ssthresh = tcp_current_ssthresh(sk);
tp->snd_cwnd = (tp->snd_cwnd + win_used) >> 1;
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index f6f39e814291..4b04c3edd4a9 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -438,7 +438,6 @@ void tcp_v4_err(struct sk_buff *skb, u32 info)
It can f.e. if SYNs crossed.
*/
if (!sock_owned_by_user(sk)) {
- TCP_INC_STATS_BH(TCP_MIB_ATTEMPTFAILS);
sk->sk_err = err;
sk->sk_error_report(sk);
@@ -874,7 +873,6 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
drop_and_free:
reqsk_free(req);
drop:
- TCP_INC_STATS_BH(TCP_MIB_ATTEMPTFAILS);
return 0;
}
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 0ccb7cb22b15..624e2b2c7f53 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -589,8 +589,10 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb,
/* RFC793: "second check the RST bit" and
* "fourth, check the SYN bit"
*/
- if (flg & (TCP_FLAG_RST|TCP_FLAG_SYN))
+ if (flg & (TCP_FLAG_RST|TCP_FLAG_SYN)) {
+ TCP_INC_STATS_BH(TCP_MIB_ATTEMPTFAILS);
goto embryonic_reset;
+ }
/* ACK sequence verified above, just make sure ACK is
* set. If ACK not set, just silently drop the packet.
diff --git a/net/ipv4/tcp_probe.c b/net/ipv4/tcp_probe.c
index d7d517a3a238..b3435324b573 100644
--- a/net/ipv4/tcp_probe.c
+++ b/net/ipv4/tcp_probe.c
@@ -114,7 +114,7 @@ static int tcpprobe_open(struct inode * inode, struct file * file)
static ssize_t tcpprobe_read(struct file *file, char __user *buf,
size_t len, loff_t *ppos)
{
- int error = 0, cnt;
+ int error = 0, cnt = 0;
unsigned char *tbuf;
if (!buf || len < 0)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 2316a4315a18..8ea1e36bf8eb 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -1869,15 +1869,21 @@ err_exit:
/*
* Manual configuration of address on an interface
*/
-static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen)
+static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen,
+ __u32 prefered_lft, __u32 valid_lft)
{
struct inet6_ifaddr *ifp;
struct inet6_dev *idev;
struct net_device *dev;
+ __u8 ifa_flags = 0;
int scope;
ASSERT_RTNL();
+ /* check the lifetime */
+ if (!valid_lft || prefered_lft > valid_lft)
+ return -EINVAL;
+
if ((dev = __dev_get_by_index(ifindex)) == NULL)
return -ENODEV;
@@ -1889,10 +1895,29 @@ static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen)
scope = ipv6_addr_scope(pfx);
- ifp = ipv6_add_addr(idev, pfx, plen, scope, IFA_F_PERMANENT);
+ if (valid_lft == INFINITY_LIFE_TIME)
+ ifa_flags |= IFA_F_PERMANENT;
+ else if (valid_lft >= 0x7FFFFFFF/HZ)
+ valid_lft = 0x7FFFFFFF/HZ;
+
+ if (prefered_lft == 0)
+ ifa_flags |= IFA_F_DEPRECATED;
+ else if ((prefered_lft >= 0x7FFFFFFF/HZ) &&
+ (prefered_lft != INFINITY_LIFE_TIME))
+ prefered_lft = 0x7FFFFFFF/HZ;
+
+ ifp = ipv6_add_addr(idev, pfx, plen, scope, ifa_flags);
+
if (!IS_ERR(ifp)) {
+ spin_lock(&ifp->lock);
+ ifp->valid_lft = valid_lft;
+ ifp->prefered_lft = prefered_lft;
+ ifp->tstamp = jiffies;
+ spin_unlock(&ifp->lock);
+
addrconf_dad_start(ifp, 0);
in6_ifa_put(ifp);
+ addrconf_verify(0);
return 0;
}
@@ -1945,7 +1970,8 @@ int addrconf_add_ifaddr(void __user *arg)
return -EFAULT;
rtnl_lock();
- err = inet6_addr_add(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen);
+ err = inet6_addr_add(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen,
+ INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
rtnl_unlock();
return err;
}
@@ -2771,12 +2797,16 @@ restart:
ifp->idev->nd_parms->retrans_time / HZ;
#endif
- if (age >= ifp->valid_lft) {
+ if (ifp->valid_lft != INFINITY_LIFE_TIME &&
+ age >= ifp->valid_lft) {
spin_unlock(&ifp->lock);
in6_ifa_hold(ifp);
read_unlock(&addrconf_hash_lock);
ipv6_del_addr(ifp);
goto restart;
+ } else if (ifp->prefered_lft == INFINITY_LIFE_TIME) {
+ spin_unlock(&ifp->lock);
+ continue;
} else if (age >= ifp->prefered_lft) {
/* jiffies - ifp->tsamp > age >= ifp->prefered_lft */
int deprecate = 0;
@@ -2853,7 +2883,8 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
pfx = RTA_DATA(rta[IFA_ADDRESS-1]);
}
if (rta[IFA_LOCAL-1]) {
- if (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx)))
+ if (RTA_PAYLOAD(rta[IFA_LOCAL-1]) < sizeof(*pfx) ||
+ (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx))))
return -EINVAL;
pfx = RTA_DATA(rta[IFA_LOCAL-1]);
}
@@ -2864,11 +2895,61 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
}
static int
+inet6_addr_modify(int ifindex, struct in6_addr *pfx,
+ __u32 prefered_lft, __u32 valid_lft)
+{
+ struct inet6_ifaddr *ifp = NULL;
+ struct net_device *dev;
+ int ifa_flags = 0;
+
+ if ((dev = __dev_get_by_index(ifindex)) == NULL)
+ return -ENODEV;
+
+ if (!(dev->flags&IFF_UP))
+ return -ENETDOWN;
+
+ if (!valid_lft || (prefered_lft > valid_lft))
+ return -EINVAL;
+
+ ifp = ipv6_get_ifaddr(pfx, dev, 1);
+ if (ifp == NULL)
+ return -ENOENT;
+
+ if (valid_lft == INFINITY_LIFE_TIME)
+ ifa_flags = IFA_F_PERMANENT;
+ else if (valid_lft >= 0x7FFFFFFF/HZ)
+ valid_lft = 0x7FFFFFFF/HZ;
+
+ if (prefered_lft == 0)
+ ifa_flags = IFA_F_DEPRECATED;
+ else if ((prefered_lft >= 0x7FFFFFFF/HZ) &&
+ (prefered_lft != INFINITY_LIFE_TIME))
+ prefered_lft = 0x7FFFFFFF/HZ;
+
+ spin_lock_bh(&ifp->lock);
+ ifp->flags = (ifp->flags & ~(IFA_F_DEPRECATED|IFA_F_PERMANENT)) | ifa_flags;
+
+ ifp->tstamp = jiffies;
+ ifp->valid_lft = valid_lft;
+ ifp->prefered_lft = prefered_lft;
+
+ spin_unlock_bh(&ifp->lock);
+ if (!(ifp->flags&IFA_F_TENTATIVE))
+ ipv6_ifa_notify(0, ifp);
+ in6_ifa_put(ifp);
+
+ addrconf_verify(0);
+
+ return 0;
+}
+
+static int
inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
{
struct rtattr **rta = arg;
struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
struct in6_addr *pfx;
+ __u32 valid_lft = INFINITY_LIFE_TIME, prefered_lft = INFINITY_LIFE_TIME;
pfx = NULL;
if (rta[IFA_ADDRESS-1]) {
@@ -2877,14 +2958,34 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
pfx = RTA_DATA(rta[IFA_ADDRESS-1]);
}
if (rta[IFA_LOCAL-1]) {
- if (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx)))
+ if (RTA_PAYLOAD(rta[IFA_LOCAL-1]) < sizeof(*pfx) ||
+ (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx))))
return -EINVAL;
pfx = RTA_DATA(rta[IFA_LOCAL-1]);
}
if (pfx == NULL)
return -EINVAL;
- return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen);
+ if (rta[IFA_CACHEINFO-1]) {
+ struct ifa_cacheinfo *ci;
+ if (RTA_PAYLOAD(rta[IFA_CACHEINFO-1]) < sizeof(*ci))
+ return -EINVAL;
+ ci = RTA_DATA(rta[IFA_CACHEINFO-1]);
+ valid_lft = ci->ifa_valid;
+ prefered_lft = ci->ifa_prefered;
+ }
+
+ if (nlh->nlmsg_flags & NLM_F_REPLACE) {
+ int ret;
+ ret = inet6_addr_modify(ifm->ifa_index, pfx,
+ prefered_lft, valid_lft);
+ if (ret == 0 || !(nlh->nlmsg_flags & NLM_F_CREATE))
+ return ret;
+ }
+
+ return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen,
+ prefered_lft, valid_lft);
+
}
/* Maximum length of ifa_cacheinfo attributes */
@@ -3121,6 +3222,62 @@ static int inet6_dump_ifacaddr(struct sk_buff *skb, struct netlink_callback *cb)
return inet6_dump_addr(skb, cb, type);
}
+static int inet6_rtm_getaddr(struct sk_buff *in_skb,
+ struct nlmsghdr* nlh, void *arg)
+{
+ struct rtattr **rta = arg;
+ struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
+ struct in6_addr *addr = NULL;
+ struct net_device *dev = NULL;
+ struct inet6_ifaddr *ifa;
+ struct sk_buff *skb;
+ int size = NLMSG_SPACE(sizeof(struct ifaddrmsg) + INET6_IFADDR_RTA_SPACE);
+ int err;
+
+ if (rta[IFA_ADDRESS-1]) {
+ if (RTA_PAYLOAD(rta[IFA_ADDRESS-1]) < sizeof(*addr))
+ return -EINVAL;
+ addr = RTA_DATA(rta[IFA_ADDRESS-1]);
+ }
+ if (rta[IFA_LOCAL-1]) {
+ if (RTA_PAYLOAD(rta[IFA_LOCAL-1]) < sizeof(*addr) ||
+ (addr && memcmp(addr, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*addr))))
+ return -EINVAL;
+ addr = RTA_DATA(rta[IFA_LOCAL-1]);
+ }
+ if (addr == NULL)
+ return -EINVAL;
+
+ if (ifm->ifa_index)
+ dev = __dev_get_by_index(ifm->ifa_index);
+
+ if ((ifa = ipv6_get_ifaddr(addr, dev, 1)) == NULL)
+ return -EADDRNOTAVAIL;
+
+ if ((skb = alloc_skb(size, GFP_KERNEL)) == NULL) {
+ err = -ENOBUFS;
+ goto out;
+ }
+
+ NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid;
+ err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(in_skb).pid,
+ nlh->nlmsg_seq, RTM_NEWADDR, 0);
+ if (err < 0) {
+ err = -EMSGSIZE;
+ goto out_free;
+ }
+
+ err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
+ if (err > 0)
+ err = 0;
+out:
+ in6_ifa_put(ifa);
+ return err;
+out_free:
+ kfree_skb(skb);
+ goto out;
+}
+
static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa)
{
struct sk_buff *skb;
@@ -3363,7 +3520,8 @@ static struct rtnetlink_link inet6_rtnetlink_table[RTM_NR_MSGTYPES] = {
[RTM_GETLINK - RTM_BASE] = { .dumpit = inet6_dump_ifinfo, },
[RTM_NEWADDR - RTM_BASE] = { .doit = inet6_rtm_newaddr, },
[RTM_DELADDR - RTM_BASE] = { .doit = inet6_rtm_deladdr, },
- [RTM_GETADDR - RTM_BASE] = { .dumpit = inet6_dump_ifaddr, },
+ [RTM_GETADDR - RTM_BASE] = { .doit = inet6_rtm_getaddr,
+ .dumpit = inet6_dump_ifaddr, },
[RTM_GETMULTICAST - RTM_BASE] = { .dumpit = inet6_dump_ifmcaddr, },
[RTM_GETANYCAST - RTM_BASE] = { .dumpit = inet6_dump_ifacaddr, },
[RTM_NEWROUTE - RTM_BASE] = { .doit = inet6_rtm_newroute, },
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 5a0ba58b86cc..ac85e9c532c2 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -658,7 +658,7 @@ int inet6_sk_rebuild_header(struct sock *sk)
return err;
}
- ip6_dst_store(sk, dst, NULL);
+ __ip6_dst_store(sk, dst, NULL);
}
return 0;
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
index 5c950cc79d80..bf491077b822 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -185,7 +185,7 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok)
return err;
}
- ip6_dst_store(sk, dst, NULL);
+ __ip6_dst_store(sk, dst, NULL);
}
skb->dst = dst_clone(dst);
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 3bc74ce78800..69451af6abe7 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -356,6 +356,7 @@ int ip6_forward(struct sk_buff *skb)
skb->dev = dst->dev;
icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
0, skb->dev);
+ IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
kfree_skb(skb);
return -ETIMEDOUT;
@@ -595,6 +596,9 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
}
err = output(skb);
+ if(!err)
+ IP6_INC_STATS(IPSTATS_MIB_FRAGCREATES);
+
if (err || !frag)
break;
@@ -706,12 +710,11 @@ slow_path:
/*
* Put this fragment into the sending queue.
*/
-
- IP6_INC_STATS(IPSTATS_MIB_FRAGCREATES);
-
err = output(frag);
if (err)
goto fail;
+
+ IP6_INC_STATS(IPSTATS_MIB_FRAGCREATES);
}
kfree_skb(skb);
IP6_INC_STATS(IPSTATS_MIB_FRAGOKS);
@@ -723,48 +726,51 @@ fail:
return err;
}
-int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl)
+static struct dst_entry *ip6_sk_dst_check(struct sock *sk,
+ struct dst_entry *dst,
+ struct flowi *fl)
{
- int err = 0;
+ struct ipv6_pinfo *np = inet6_sk(sk);
+ struct rt6_info *rt = (struct rt6_info *)dst;
- *dst = NULL;
- if (sk) {
- struct ipv6_pinfo *np = inet6_sk(sk);
-
- *dst = sk_dst_check(sk, np->dst_cookie);
- if (*dst) {
- struct rt6_info *rt = (struct rt6_info*)*dst;
-
- /* Yes, checking route validity in not connected
- * case is not very simple. Take into account,
- * that we do not support routing by source, TOS,
- * and MSG_DONTROUTE --ANK (980726)
- *
- * 1. If route was host route, check that
- * cached destination is current.
- * If it is network route, we still may
- * check its validity using saved pointer
- * to the last used address: daddr_cache.
- * We do not want to save whole address now,
- * (because main consumer of this service
- * is tcp, which has not this problem),
- * so that the last trick works only on connected
- * sockets.
- * 2. oif also should be the same.
- */
- if (((rt->rt6i_dst.plen != 128 ||
- !ipv6_addr_equal(&fl->fl6_dst,
- &rt->rt6i_dst.addr))
- && (np->daddr_cache == NULL ||
- !ipv6_addr_equal(&fl->fl6_dst,
- np->daddr_cache)))
- || (fl->oif && fl->oif != (*dst)->dev->ifindex)) {
- dst_release(*dst);
- *dst = NULL;
- }
- }
+ if (!dst)
+ goto out;
+
+ /* Yes, checking route validity in not connected
+ * case is not very simple. Take into account,
+ * that we do not support routing by source, TOS,
+ * and MSG_DONTROUTE --ANK (980726)
+ *
+ * 1. If route was host route, check that
+ * cached destination is current.
+ * If it is network route, we still may
+ * check its validity using saved pointer
+ * to the last used address: daddr_cache.
+ * We do not want to save whole address now,
+ * (because main consumer of this service
+ * is tcp, which has not this problem),
+ * so that the last trick works only on connected
+ * sockets.
+ * 2. oif also should be the same.
+ */
+ if (((rt->rt6i_dst.plen != 128 ||
+ !ipv6_addr_equal(&fl->fl6_dst, &rt->rt6i_dst.addr))
+ && (np->daddr_cache == NULL ||
+ !ipv6_addr_equal(&fl->fl6_dst, np->daddr_cache)))
+ || (fl->oif && fl->oif != dst->dev->ifindex)) {
+ dst_release(dst);
+ dst = NULL;
}
+out:
+ return dst;
+}
+
+static int ip6_dst_lookup_tail(struct sock *sk,
+ struct dst_entry **dst, struct flowi *fl)
+{
+ int err;
+
if (*dst == NULL)
*dst = ip6_route_output(sk, fl);
@@ -773,7 +779,6 @@ int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl)
if (ipv6_addr_any(&fl->fl6_src)) {
err = ipv6_get_saddr(*dst, &fl->fl6_dst, &fl->fl6_src);
-
if (err)
goto out_err_release;
}
@@ -786,8 +791,48 @@ out_err_release:
return err;
}
+/**
+ * ip6_dst_lookup - perform route lookup on flow
+ * @sk: socket which provides route info
+ * @dst: pointer to dst_entry * for result
+ * @fl: flow to lookup
+ *
+ * This function performs a route lookup on the given flow.
+ *
+ * It returns zero on success, or a standard errno code on error.
+ */
+int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl)
+{
+ *dst = NULL;
+ return ip6_dst_lookup_tail(sk, dst, fl);
+}
EXPORT_SYMBOL_GPL(ip6_dst_lookup);
+/**
+ * ip6_sk_dst_lookup - perform socket cached route lookup on flow
+ * @sk: socket which provides the dst cache and route info
+ * @dst: pointer to dst_entry * for result
+ * @fl: flow to lookup
+ *
+ * This function performs a route lookup on the given flow with the
+ * possibility of using the cached route in the socket if it is valid.
+ * It will take the socket dst lock when operating on the dst cache.
+ * As a result, this function can only be used in process context.
+ *
+ * It returns zero on success, or a standard errno code on error.
+ */
+int ip6_sk_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl)
+{
+ *dst = NULL;
+ if (sk) {
+ *dst = sk_dst_check(sk, inet6_sk(sk)->dst_cookie);
+ *dst = ip6_sk_dst_check(sk, *dst, fl);
+ }
+
+ return ip6_dst_lookup_tail(sk, dst, fl);
+}
+EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup);
+
static inline int ip6_ufo_append_data(struct sock *sk,
int getfrag(void *from, char *to, int offset, int len,
int odd, struct sk_buff *skb),
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 87c39c978cd0..4b163711f3a8 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -53,6 +53,7 @@
#include <linux/rtnetlink.h>
#include <net/dst.h>
#include <net/xfrm.h>
+#include <net/netevent.h>
#include <asm/uaccess.h>
@@ -742,6 +743,7 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu)
dst->metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG;
}
dst->metrics[RTAX_MTU-1] = mtu;
+ call_netevent_notifiers(NETEVENT_PMTU_UPDATE, dst);
}
}
@@ -1155,6 +1157,7 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *saddr,
struct rt6_info *rt, *nrt = NULL;
int strict;
struct fib6_node *fn;
+ struct netevent_redirect netevent;
/*
* Get the "current" route for this destination and
@@ -1252,6 +1255,10 @@ restart:
if (ip6_ins_rt(nrt, NULL, NULL, NULL))
goto out;
+ netevent.old = &rt->u.dst;
+ netevent.new = &nrt->u.dst;
+ call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
+
if (rt->rt6i_flags&RTF_CACHE) {
ip6_del_rt(rt, NULL, NULL, NULL);
return;
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 923989d0520d..b843a650be71 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -270,7 +270,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
inet->rcv_saddr = LOOPBACK4_IPV6;
sk->sk_gso_type = SKB_GSO_TCPV6;
- ip6_dst_store(sk, dst, NULL);
+ __ip6_dst_store(sk, dst, NULL);
icsk->icsk_ext_hdr_len = 0;
if (np->opt)
@@ -427,7 +427,6 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
case TCP_SYN_RECV: /* Cannot happen.
It can, it SYNs are crossed. --ANK */
if (!sock_owned_by_user(sk)) {
- TCP_INC_STATS_BH(TCP_MIB_ATTEMPTFAILS);
sk->sk_err = err;
sk->sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */
@@ -831,7 +830,6 @@ drop:
if (req)
reqsk_free(req);
- TCP_INC_STATS_BH(TCP_MIB_ATTEMPTFAILS);
return 0; /* don't send reset */
}
@@ -947,7 +945,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
*/
sk->sk_gso_type = SKB_GSO_TCPV6;
- ip6_dst_store(newsk, dst, NULL);
+ __ip6_dst_store(newsk, dst, NULL);
newtcp6sk = (struct tcp6_sock *)newsk;
inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index ccc57f434cd3..3d54f246411e 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -782,7 +782,7 @@ do_udp_sendmsg:
connected = 0;
}
- err = ip6_dst_lookup(sk, &dst, fl);
+ err = ip6_sk_dst_lookup(sk, &dst, fl);
if (err)
goto out;
if (final_p)
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
index 0eea60ea9ebc..c8c8b44a0f58 100644
--- a/net/ipv6/xfrm6_output.c
+++ b/net/ipv6/xfrm6_output.c
@@ -125,7 +125,7 @@ static int xfrm6_output_finish(struct sk_buff *skb)
if (!skb_is_gso(skb))
return xfrm6_output_finish2(skb);
- skb->protocol = htons(ETH_P_IP);
+ skb->protocol = htons(ETH_P_IPV6);
segs = skb_gso_segment(skb, 0);
kfree_skb(skb);
if (unlikely(IS_ERR(segs)))
diff --git a/net/lapb/lapb_iface.c b/net/lapb/lapb_iface.c
index d504eed416f6..7e6bc41eeb21 100644
--- a/net/lapb/lapb_iface.c
+++ b/net/lapb/lapb_iface.c
@@ -238,11 +238,13 @@ int lapb_setparms(struct net_device *dev, struct lapb_parms_struct *parms)
goto out_put;
if (lapb->state == LAPB_STATE_0) {
- if (((parms->mode & LAPB_EXTENDED) &&
- (parms->window < 1 || parms->window > 127)) ||
- (parms->window < 1 || parms->window > 7))
- goto out_put;
-
+ if (parms->mode & LAPB_EXTENDED) {
+ if (parms->window < 1 || parms->window > 127)
+ goto out_put;
+ } else {
+ if (parms->window < 1 || parms->window > 7)
+ goto out_put;
+ }
lapb->mode = parms->mode;
lapb->window = parms->window;
}
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
index d6cfe84d521b..2652ead96c64 100644
--- a/net/llc/af_llc.c
+++ b/net/llc/af_llc.c
@@ -784,24 +784,20 @@ static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock,
copied += used;
len -= used;
- if (used + offset < skb->len)
- continue;
-
if (!(flags & MSG_PEEK)) {
sk_eat_skb(sk, skb, 0);
*seq = 0;
}
+
+ /* For non stream protcols we get one packet per recvmsg call */
+ if (sk->sk_type != SOCK_STREAM)
+ goto copy_uaddr;
+
+ /* Partial read */
+ if (used + offset < skb->len)
+ continue;
} while (len > 0);
- /*
- * According to UNIX98, msg_name/msg_namelen are ignored
- * on connected socket. -ANK
- * But... af_llc still doesn't have separate sets of methods for
- * SOCK_DGRAM and SOCK_STREAM :-( So we have to do this test, will
- * eventually fix this tho :-) -acme
- */
- if (sk->sk_type == SOCK_DGRAM)
- goto copy_uaddr;
out:
release_sock(sk);
return copied;
diff --git a/net/llc/llc_sap.c b/net/llc/llc_sap.c
index 20c4eb5c1ac6..42eb0c3a9780 100644
--- a/net/llc/llc_sap.c
+++ b/net/llc/llc_sap.c
@@ -51,10 +51,10 @@ void llc_save_primitive(struct sock *sk, struct sk_buff* skb, u8 prim)
{
struct sockaddr_llc *addr;
- if (skb->sk->sk_type == SOCK_STREAM) /* See UNIX98 */
- return;
/* save primitive for use by the user. */
addr = llc_ui_skb_cb(skb);
+
+ memset(addr, 0, sizeof(*addr));
addr->sllc_family = sk->sk_family;
addr->sllc_arphrd = skb->dev->type;
addr->sllc_test = prim == LLC_TEST_PRIM;
diff --git a/net/netfilter/xt_SECMARK.c b/net/netfilter/xt_SECMARK.c
index c2ce9c4011cc..de9537ad9a7c 100644
--- a/net/netfilter/xt_SECMARK.c
+++ b/net/netfilter/xt_SECMARK.c
@@ -57,6 +57,8 @@ static int checkentry_selinux(struct xt_secmark_target_info *info)
{
int err;
struct xt_secmark_target_selinux_info *sel = &info->u.sel;
+
+ sel->selctx[SECMARK_SELCTX_MAX - 1] = '\0';
err = selinux_string_to_sid(sel->selctx, &sel->selsid);
if (err) {
diff --git a/net/netfilter/xt_string.c b/net/netfilter/xt_string.c
index 0ebb6ac2c8c7..d8e3891b5f8b 100644
--- a/net/netfilter/xt_string.c
+++ b/net/netfilter/xt_string.c
@@ -55,7 +55,10 @@ static int checkentry(const char *tablename,
/* Damn, can't handle this case properly with iptables... */
if (conf->from_offset > conf->to_offset)
return 0;
-
+ if (conf->algo[XT_STRING_MAX_ALGO_NAME_SIZE - 1] != '\0')
+ return 0;
+ if (conf->patlen > XT_STRING_MAX_PATTERN_SIZE)
+ return 0;
ts_conf = textsearch_prepare(conf->algo, conf->pattern, conf->patlen,
GFP_KERNEL, TS_AUTOLOAD);
if (IS_ERR(ts_conf))
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index c7844bacbbcb..a19eff12cf78 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -430,7 +430,7 @@ qdisc_create(struct net_device *dev, u32 handle, struct rtattr **tca, int *errp)
}
#endif
- err = -EINVAL;
+ err = -ENOENT;
if (ops == NULL)
goto err_out;
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index 7026b0866b7b..00cb388ece03 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -71,7 +71,12 @@ struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail,
new = detail->alloc();
if (!new)
return NULL;
+ /* must fully initialise 'new', else
+ * we might get lose if we need to
+ * cache_put it soon.
+ */
cache_init(new);
+ detail->init(new, key);
write_lock(&detail->hash_lock);
@@ -85,7 +90,6 @@ struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail,
return tmp;
}
}
- detail->init(new, key);
new->next = *head;
*head = new;
detail->entries++;
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 4ba271f892c8..d6409e757219 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -921,26 +921,43 @@ call_transmit(struct rpc_task *task)
task->tk_status = xprt_prepare_transmit(task);
if (task->tk_status != 0)
return;
+ task->tk_action = call_transmit_status;
/* Encode here so that rpcsec_gss can use correct sequence number. */
if (rpc_task_need_encode(task)) {
- task->tk_rqstp->rq_bytes_sent = 0;
+ BUG_ON(task->tk_rqstp->rq_bytes_sent != 0);
call_encode(task);
/* Did the encode result in an error condition? */
if (task->tk_status != 0)
- goto out_nosend;
+ return;
}
- task->tk_action = call_transmit_status;
xprt_transmit(task);
if (task->tk_status < 0)
return;
- if (!task->tk_msg.rpc_proc->p_decode) {
- task->tk_action = rpc_exit_task;
- rpc_wake_up_task(task);
- }
- return;
-out_nosend:
- /* release socket write lock before attempting to handle error */
- xprt_abort_transmit(task);
+ /*
+ * On success, ensure that we call xprt_end_transmit() before sleeping
+ * in order to allow access to the socket to other RPC requests.
+ */
+ call_transmit_status(task);
+ if (task->tk_msg.rpc_proc->p_decode != NULL)
+ return;
+ task->tk_action = rpc_exit_task;
+ rpc_wake_up_task(task);
+}
+
+/*
+ * 5a. Handle cleanup after a transmission
+ */
+static void
+call_transmit_status(struct rpc_task *task)
+{
+ task->tk_action = call_status;
+ /*
+ * Special case: if we've been waiting on the socket's write_space()
+ * callback, then don't call xprt_end_transmit().
+ */
+ if (task->tk_status == -EAGAIN)
+ return;
+ xprt_end_transmit(task);
rpc_task_force_reencode(task);
}
@@ -992,18 +1009,7 @@ call_status(struct rpc_task *task)
}
/*
- * 6a. Handle transmission errors.
- */
-static void
-call_transmit_status(struct rpc_task *task)
-{
- if (task->tk_status != -EAGAIN)
- rpc_task_force_reencode(task);
- call_status(task);
-}
-
-/*
- * 6b. Handle RPC timeout
+ * 6a. Handle RPC timeout
* We do not release the request slot, so we keep using the
* same XID for all retransmits.
*/
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index dc6cb93c8830..a3bd2db2e024 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -667,10 +667,11 @@ rpc_mkdir(char *path, struct rpc_clnt *rpc_client)
RPCAUTH_info, RPCAUTH_EOF);
if (error)
goto err_depopulate;
+ dget(dentry);
out:
mutex_unlock(&dir->i_mutex);
rpc_release_path(&nd);
- return dget(dentry);
+ return dentry;
err_depopulate:
rpc_depopulate(dentry);
__rpc_rmdir(dir, dentry);
@@ -731,10 +732,11 @@ rpc_mkpipe(char *path, void *private, struct rpc_pipe_ops *ops, int flags)
rpci->flags = flags;
rpci->ops = ops;
inode_dir_notify(dir, DN_CREATE);
+ dget(dentry);
out:
mutex_unlock(&dir->i_mutex);
rpc_release_path(&nd);
- return dget(dentry);
+ return dentry;
err_dput:
dput(dentry);
dentry = ERR_PTR(-ENOMEM);
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 313b68d892c6..e8c2bc4977f3 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -707,12 +707,9 @@ out_unlock:
return err;
}
-void
-xprt_abort_transmit(struct rpc_task *task)
+void xprt_end_transmit(struct rpc_task *task)
{
- struct rpc_xprt *xprt = task->tk_xprt;
-
- xprt_release_write(xprt, task);
+ xprt_release_write(task->tk_xprt, task);
}
/**
@@ -761,8 +758,6 @@ void xprt_transmit(struct rpc_task *task)
task->tk_status = -ENOTCONN;
else if (!req->rq_received)
rpc_sleep_on(&xprt->pending, task, NULL, xprt_timer);
-
- xprt->ops->release_xprt(xprt, task);
spin_unlock_bh(&xprt->transport_lock);
return;
}
@@ -772,18 +767,8 @@ void xprt_transmit(struct rpc_task *task)
* schedq, and being picked up by a parallel run of rpciod().
*/
task->tk_status = status;
-
- switch (status) {
- case -ECONNREFUSED:
+ if (status == -ECONNREFUSED)
rpc_sleep_on(&xprt->sending, task, NULL, NULL);
- case -EAGAIN:
- case -ENOTCONN:
- return;
- default:
- break;
- }
- xprt_release_write(xprt, task);
- return;
}
static inline void do_xprt_reserve(struct rpc_task *task)
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index ee678ed13b6f..441bd53f5eca 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -414,6 +414,33 @@ static int xs_tcp_send_request(struct rpc_task *task)
}
/**
+ * xs_tcp_release_xprt - clean up after a tcp transmission
+ * @xprt: transport
+ * @task: rpc task
+ *
+ * This cleans up if an error causes us to abort the transmission of a request.
+ * In this case, the socket may need to be reset in order to avoid confusing
+ * the server.
+ */
+static void xs_tcp_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task)
+{
+ struct rpc_rqst *req;
+
+ if (task != xprt->snd_task)
+ return;
+ if (task == NULL)
+ goto out_release;
+ req = task->tk_rqstp;
+ if (req->rq_bytes_sent == 0)
+ goto out_release;
+ if (req->rq_bytes_sent == req->rq_snd_buf.len)
+ goto out_release;
+ set_bit(XPRT_CLOSE_WAIT, &task->tk_xprt->state);
+out_release:
+ xprt_release_xprt(xprt, task);
+}
+
+/**
* xs_close - close a socket
* @xprt: transport
*
@@ -1250,7 +1277,7 @@ static struct rpc_xprt_ops xs_udp_ops = {
static struct rpc_xprt_ops xs_tcp_ops = {
.reserve_xprt = xprt_reserve_xprt,
- .release_xprt = xprt_release_xprt,
+ .release_xprt = xs_tcp_release_xprt,
.set_port = xs_set_port,
.connect = xs_connect,
.buf_alloc = rpc_malloc,
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 6f2909279268..de6ec519272e 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -128,23 +128,17 @@ static atomic_t unix_nr_socks = ATOMIC_INIT(0);
#define UNIX_ABSTRACT(sk) (unix_sk(sk)->addr->hash != UNIX_HASH_SIZE)
#ifdef CONFIG_SECURITY_NETWORK
-static void unix_get_peersec_dgram(struct sk_buff *skb)
+static void unix_get_secdata(struct scm_cookie *scm, struct sk_buff *skb)
{
- int err;
-
- err = security_socket_getpeersec_dgram(skb, UNIXSECDATA(skb),
- UNIXSECLEN(skb));
- if (err)
- *(UNIXSECDATA(skb)) = NULL;
+ memcpy(UNIXSID(skb), &scm->secid, sizeof(u32));
}
static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb)
{
- scm->secdata = *UNIXSECDATA(skb);
- scm->seclen = *UNIXSECLEN(skb);
+ scm->secid = *UNIXSID(skb);
}
#else
-static inline void unix_get_peersec_dgram(struct sk_buff *skb)
+static inline void unix_get_secdata(struct scm_cookie *scm, struct sk_buff *skb)
{ }
static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb)
@@ -1322,8 +1316,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred));
if (siocb->scm->fp)
unix_attach_fds(siocb->scm, skb);
-
- unix_get_peersec_dgram(skb);
+ unix_get_secdata(siocb->scm, skb);
skb->h.raw = skb->data;
err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);