summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/802/psnap.c2
-rw-r--r--net/Kconfig7
-rw-r--r--net/bridge/br_if.c21
-rw-r--r--net/bridge/br_private.h1
-rw-r--r--net/bridge/netfilter/ebt_ulog.c10
-rw-r--r--net/bridge/netfilter/ebtables.c7
-rw-r--r--net/core/dev.c7
-rw-r--r--net/core/filter.c6
-rw-r--r--net/core/skbuff.c8
-rw-r--r--net/core/utils.c4
-rw-r--r--net/dccp/ipv4.c3
-rw-r--r--net/dccp/ipv6.c1
-rw-r--r--net/ieee80211/ieee80211_rx.c26
-rw-r--r--net/ieee80211/ieee80211_wx.c12
-rw-r--r--net/ipv4/icmp.c5
-rw-r--r--net/ipv4/igmp.c2
-rw-r--r--net/ipv4/multipath_wrandom.c8
-rw-r--r--net/ipv4/netfilter/arp_tables.c7
-rw-r--r--net/ipv4/netfilter/ip_conntrack_netlink.c3
-rw-r--r--net/ipv4/netfilter/ip_conntrack_tftp.c1
-rw-r--r--net/ipv4/netfilter/ip_nat_standalone.c4
-rw-r--r--net/ipv4/netfilter/ip_tables.c7
-rw-r--r--net/ipv4/netfilter/ipt_ULOG.c26
-rw-r--r--net/ipv4/netfilter/ipt_policy.c11
-rw-r--r--net/ipv4/proc.c2
-rw-r--r--net/ipv4/tcp_htcp.c1
-rw-r--r--net/ipv4/tcp_ipv4.c3
-rw-r--r--net/ipv6/addrconf.c6
-rw-r--r--net/ipv6/af_inet6.c6
-rw-r--r--net/ipv6/mcast.c56
-rw-r--r--net/ipv6/netfilter/ip6_tables.c7
-rw-r--r--net/ipv6/netfilter/ip6t_policy.c7
-rw-r--r--net/ipv6/proc.c2
-rw-r--r--net/ipv6/tcp_ipv6.c1
-rw-r--r--net/key/af_key.c2
-rw-r--r--net/netfilter/nf_conntrack_core.c2
-rw-r--r--net/netfilter/nf_conntrack_ftp.c2
-rw-r--r--net/netfilter/nf_conntrack_netlink.c3
-rw-r--r--net/netfilter/nfnetlink_log.c20
-rw-r--r--net/netfilter/nfnetlink_queue.c3
-rw-r--r--net/packet/af_packet.c16
-rw-r--r--net/sctp/input.c75
-rw-r--r--net/sctp/inqueue.c4
-rw-r--r--net/sctp/output.c2
-rw-r--r--net/sctp/outqueue.c12
-rw-r--r--net/sctp/proc.c32
-rw-r--r--net/sctp/sm_make_chunk.c16
-rw-r--r--net/sctp/sm_sideeffect.c4
-rw-r--r--net/sctp/sm_statefuns.c10
-rw-r--r--net/sctp/socket.c8
-rw-r--r--net/sctp/sysctl.c7
-rw-r--r--net/sctp/transport.c2
-rw-r--r--net/socket.c2
-rw-r--r--net/sunrpc/auth.c25
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c40
-rw-r--r--net/sunrpc/auth_unix.c6
-rw-r--r--net/sunrpc/rpc_pipe.c102
-rw-r--r--net/sunrpc/sched.c9
58 files changed, 456 insertions, 228 deletions
diff --git a/net/802/psnap.c b/net/802/psnap.c
index 4d638944d933..34e42968b477 100644
--- a/net/802/psnap.c
+++ b/net/802/psnap.c
@@ -59,8 +59,10 @@ static int snap_rcv(struct sk_buff *skb, struct net_device *dev,
proto = find_snap_client(skb->h.raw);
if (proto) {
/* Pass the frame on. */
+ u8 *hdr = skb->data;
skb->h.raw += 5;
skb_pull(skb, 5);
+ skb_postpull_rcsum(skb, hdr, 5);
rc = proto->rcvfunc(skb, dev, &snap_packet_type, orig_dev);
} else {
skb->sk = NULL;
diff --git a/net/Kconfig b/net/Kconfig
index bc603d9aea56..5126f58d9c44 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -27,6 +27,13 @@ if NET
menu "Networking options"
+config NETDEBUG
+ bool "Network packet debugging"
+ help
+ You can say Y here if you want to get additional messages useful in
+ debugging bad packets, but can overwhelm logs under denial of service
+ attacks.
+
source "net/packet/Kconfig"
source "net/unix/Kconfig"
source "net/xfrm/Kconfig"
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index ba442883e877..da687c8dc6ff 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -104,6 +104,7 @@ static void destroy_nbp(struct net_bridge_port *p)
{
struct net_device *dev = p->dev;
+ dev->br_port = NULL;
p->br = NULL;
p->dev = NULL;
dev_put(dev);
@@ -118,13 +119,24 @@ static void destroy_nbp_rcu(struct rcu_head *head)
destroy_nbp(p);
}
-/* called with RTNL */
+/* Delete port(interface) from bridge is done in two steps.
+ * via RCU. First step, marks device as down. That deletes
+ * all the timers and stops new packets from flowing through.
+ *
+ * Final cleanup doesn't occur until after all CPU's finished
+ * processing packets.
+ *
+ * Protected from multiple admin operations by RTNL mutex
+ */
static void del_nbp(struct net_bridge_port *p)
{
struct net_bridge *br = p->br;
struct net_device *dev = p->dev;
- dev->br_port = NULL;
+ /* Race between RTNL notify and RCU callback */
+ if (p->deleted)
+ return;
+
dev_set_promiscuity(dev, -1);
cancel_delayed_work(&p->carrier_check);
@@ -132,16 +144,13 @@ static void del_nbp(struct net_bridge_port *p)
spin_lock_bh(&br->lock);
br_stp_disable_port(p);
+ p->deleted = 1;
spin_unlock_bh(&br->lock);
br_fdb_delete_by_port(br, p);
list_del_rcu(&p->list);
- del_timer_sync(&p->message_age_timer);
- del_timer_sync(&p->forward_delay_timer);
- del_timer_sync(&p->hold_timer);
-
call_rcu(&p->rcu, destroy_nbp_rcu);
}
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index c5bd631ffcd5..e330b17b6d81 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -68,6 +68,7 @@ struct net_bridge_port
/* STP */
u8 priority;
u8 state;
+ u8 deleted;
u16 port_no;
unsigned char topology_change_ack;
unsigned char config_pending;
diff --git a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c
index ce617b3dbbb8..802baf755ef4 100644
--- a/net/bridge/netfilter/ebt_ulog.c
+++ b/net/bridge/netfilter/ebt_ulog.c
@@ -46,7 +46,7 @@
#define PRINTR(format, args...) do { if (net_ratelimit()) \
printk(format , ## args); } while (0)
-static unsigned int nlbufsiz = 4096;
+static unsigned int nlbufsiz = NLMSG_GOODSIZE;
module_param(nlbufsiz, uint, 0600);
MODULE_PARM_DESC(nlbufsiz, "netlink buffer size (number of bytes) "
"(defaults to 4096)");
@@ -98,12 +98,14 @@ static void ulog_timer(unsigned long data)
static struct sk_buff *ulog_alloc_skb(unsigned int size)
{
struct sk_buff *skb;
+ unsigned int n;
- skb = alloc_skb(nlbufsiz, GFP_ATOMIC);
+ n = max(size, nlbufsiz);
+ skb = alloc_skb(n, GFP_ATOMIC);
if (!skb) {
PRINTR(KERN_ERR "ebt_ulog: can't alloc whole buffer "
- "of size %ub!\n", nlbufsiz);
- if (size < nlbufsiz) {
+ "of size %ub!\n", n);
+ if (n > size) {
/* try to allocate only as much as we need for
* current packet */
skb = alloc_skb(size, GFP_ATOMIC);
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index 00729b3604f8..cbd4020cc84d 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -934,6 +934,13 @@ static int do_replace(void __user *user, unsigned int len)
BUGPRINT("Entries_size never zero\n");
return -EINVAL;
}
+ /* overflow check */
+ if (tmp.nentries >= ((INT_MAX - sizeof(struct ebt_table_info)) / NR_CPUS -
+ SMP_CACHE_BYTES) / sizeof(struct ebt_counter))
+ return -ENOMEM;
+ if (tmp.num_counters >= INT_MAX / sizeof(struct ebt_counter))
+ return -ENOMEM;
+
countersize = COUNTER_OFFSET(tmp.nentries) *
(highest_possible_processor_id()+1);
newinfo = (struct ebt_table_info *)
diff --git a/net/core/dev.c b/net/core/dev.c
index fd070a098f20..2afb0de95329 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2543,13 +2543,14 @@ int dev_ioctl(unsigned int cmd, void __user *arg)
case SIOCBONDENSLAVE:
case SIOCBONDRELEASE:
case SIOCBONDSETHWADDR:
- case SIOCBONDSLAVEINFOQUERY:
- case SIOCBONDINFOQUERY:
case SIOCBONDCHANGEACTIVE:
case SIOCBRADDIF:
case SIOCBRDELIF:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
+ /* fall through */
+ case SIOCBONDSLAVEINFOQUERY:
+ case SIOCBONDINFOQUERY:
dev_load(ifr.ifr_name);
rtnl_lock();
ret = dev_ifsioc(&ifr, cmd);
@@ -3236,7 +3237,7 @@ static int __init net_dev_init(void)
* Initialise the packet receive queues.
*/
- for (i = 0; i < NR_CPUS; i++) {
+ for_each_cpu(i) {
struct softnet_data *queue;
queue = &per_cpu(softnet_data, i);
diff --git a/net/core/filter.c b/net/core/filter.c
index 9540946a48f3..93fbd01d2259 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -64,7 +64,7 @@ static inline void *load_pointer(struct sk_buff *skb, int k,
}
/**
- * sk_run_filter - run a filter on a socket
+ * sk_run_filter - run a filter on a socket
* @skb: buffer to run the filter on
* @filter: filter to apply
* @flen: length of filter
@@ -78,8 +78,8 @@ unsigned int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int
{
struct sock_filter *fentry; /* We walk down these */
void *ptr;
- u32 A = 0; /* Accumulator */
- u32 X = 0; /* Index Register */
+ u32 A = 0; /* Accumulator */
+ u32 X = 0; /* Index Register */
u32 mem[BPF_MEMWORDS]; /* Scratch Memory Store */
u32 tmp;
int k;
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index d0732e9c8560..6766f118f070 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -135,13 +135,15 @@ void skb_under_panic(struct sk_buff *skb, int sz, void *here)
struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
int fclone)
{
+ kmem_cache_t *cache;
struct skb_shared_info *shinfo;
struct sk_buff *skb;
u8 *data;
+ cache = fclone ? skbuff_fclone_cache : skbuff_head_cache;
+
/* Get the HEAD */
- skb = kmem_cache_alloc(fclone ? skbuff_fclone_cache : skbuff_head_cache,
- gfp_mask & ~__GFP_DMA);
+ skb = kmem_cache_alloc(cache, gfp_mask & ~__GFP_DMA);
if (!skb)
goto out;
@@ -180,7 +182,7 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
out:
return skb;
nodata:
- kmem_cache_free(skbuff_head_cache, skb);
+ kmem_cache_free(cache, skb);
skb = NULL;
goto out;
}
diff --git a/net/core/utils.c b/net/core/utils.c
index ac1d1fcf8673..fdc4f38bc46c 100644
--- a/net/core/utils.c
+++ b/net/core/utils.c
@@ -121,7 +121,7 @@ void __init net_random_init(void)
{
int i;
- for (i = 0; i < NR_CPUS; i++) {
+ for_each_cpu(i) {
struct nrnd_state *state = &per_cpu(net_rand_state,i);
__net_srandom(state, i+jiffies);
}
@@ -133,7 +133,7 @@ static int net_random_reseed(void)
unsigned long seed[NR_CPUS];
get_random_bytes(seed, sizeof(seed));
- for (i = 0; i < NR_CPUS; i++) {
+ for_each_cpu(i) {
struct nrnd_state *state = &per_cpu(net_rand_state,i);
__net_srandom(state, seed[i]);
}
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 00f983226672..dc0487b5bace 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -119,7 +119,8 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
if (err != 0)
goto failure;
- err = ip_route_newports(&rt, inet->sport, inet->dport, sk);
+ err = ip_route_newports(&rt, IPPROTO_DCCP, inet->sport, inet->dport,
+ sk);
if (err != 0)
goto failure;
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index df074259f9c3..80c4d048869e 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -468,6 +468,7 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
done:
if (opt && opt != np->opt)
sock_kfree_s(sk, opt, opt->tot_len);
+ dst_release(dst);
return err;
}
diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c
index 7a121802faa9..960aa78cdb97 100644
--- a/net/ieee80211/ieee80211_rx.c
+++ b/net/ieee80211/ieee80211_rx.c
@@ -350,6 +350,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
u8 src[ETH_ALEN];
struct ieee80211_crypt_data *crypt = NULL;
int keyidx = 0;
+ int can_be_decrypted = 0;
hdr = (struct ieee80211_hdr_4addr *)skb->data;
stats = &ieee->stats;
@@ -410,12 +411,23 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
return 1;
}
- if (is_multicast_ether_addr(hdr->addr1)
- ? ieee->host_mc_decrypt : ieee->host_decrypt) {
+ can_be_decrypted = (is_multicast_ether_addr(hdr->addr1) ||
+ is_broadcast_ether_addr(hdr->addr2)) ?
+ ieee->host_mc_decrypt : ieee->host_decrypt;
+
+ if (can_be_decrypted) {
int idx = 0;
- if (skb->len >= hdrlen + 3)
+ if (skb->len >= hdrlen + 3) {
+ /* Top two-bits of byte 3 are the key index */
idx = skb->data[hdrlen + 3] >> 6;
+ }
+
+ /* ieee->crypt[] is WEP_KEY (4) in length. Given that idx
+ * is only allowed 2-bits of storage, no value of idx can
+ * be provided via above code that would result in idx
+ * being out of range */
crypt = ieee->crypt[idx];
+
#ifdef NOT_YET
sta = NULL;
@@ -553,7 +565,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
/* skb: hdr + (possibly fragmented, possibly encrypted) payload */
- if (ieee->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
+ if ((fc & IEEE80211_FCTL_PROTECTED) && can_be_decrypted &&
(keyidx = ieee80211_rx_frame_decrypt(ieee, skb, crypt)) < 0)
goto rx_dropped;
@@ -617,7 +629,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
/* skb: hdr + (possible reassembled) full MSDU payload; possibly still
* encrypted/authenticated */
- if (ieee->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
+ if ((fc & IEEE80211_FCTL_PROTECTED) && can_be_decrypted &&
ieee80211_rx_frame_decrypt_msdu(ieee, skb, keyidx, crypt))
goto rx_dropped;
@@ -1439,7 +1451,7 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee,
break;
case IEEE80211_STYPE_PROBE_REQ:
- IEEE80211_DEBUG_MGMT("recieved auth (%d)\n",
+ IEEE80211_DEBUG_MGMT("received auth (%d)\n",
WLAN_FC_GET_STYPE(le16_to_cpu
(header->frame_ctl)));
@@ -1473,7 +1485,7 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee,
break;
case IEEE80211_STYPE_AUTH:
- IEEE80211_DEBUG_MGMT("recieved auth (%d)\n",
+ IEEE80211_DEBUG_MGMT("received auth (%d)\n",
WLAN_FC_GET_STYPE(le16_to_cpu
(header->frame_ctl)));
diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c
index 23e1630f50b7..f87c6b89f845 100644
--- a/net/ieee80211/ieee80211_wx.c
+++ b/net/ieee80211/ieee80211_wx.c
@@ -232,15 +232,18 @@ static char *ipw2100_translate_scan(struct ieee80211_device *ieee,
return start;
}
+#define SCAN_ITEM_SIZE 128
+
int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct ieee80211_network *network;
unsigned long flags;
+ int err = 0;
char *ev = extra;
- char *stop = ev + IW_SCAN_MAX_DATA;
+ char *stop = ev + wrqu->data.length;
int i = 0;
IEEE80211_DEBUG_WX("Getting scan\n");
@@ -249,6 +252,11 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
list_for_each_entry(network, &ieee->network_list, list) {
i++;
+ if (stop - ev < SCAN_ITEM_SIZE) {
+ err = -E2BIG;
+ break;
+ }
+
if (ieee->scan_age == 0 ||
time_after(network->last_scanned + ieee->scan_age, jiffies))
ev = ipw2100_translate_scan(ieee, ev, stop, network);
@@ -270,7 +278,7 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
- return 0;
+ return err;
}
int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 105039eb7629..4d1c40972a4b 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -385,7 +385,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
u32 daddr;
if (ip_options_echo(&icmp_param->replyopts, skb))
- goto out;
+ return;
if (icmp_xmit_lock())
return;
@@ -416,7 +416,6 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
ip_rt_put(rt);
out_unlock:
icmp_xmit_unlock();
-out:;
}
@@ -525,7 +524,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info)
iph->tos;
if (ip_options_echo(&icmp_param.replyopts, skb_in))
- goto ende;
+ goto out_unlock;
/*
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index d8ce7133cd8f..0b4e95f93dad 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -970,7 +970,7 @@ int igmp_rcv(struct sk_buff *skb)
case IGMP_MTRACE_RESP:
break;
default:
- NETDEBUG(KERN_DEBUG "New IGMP type=%d, why we do not know about it?\n", ih->type);
+ break;
}
drop:
diff --git a/net/ipv4/multipath_wrandom.c b/net/ipv4/multipath_wrandom.c
index d34a9fa608e0..342d0b9098f5 100644
--- a/net/ipv4/multipath_wrandom.c
+++ b/net/ipv4/multipath_wrandom.c
@@ -228,7 +228,7 @@ static void wrandom_set_nhinfo(__u32 network,
struct multipath_dest *d, *target_dest = NULL;
/* store the weight information for a certain route */
- spin_lock(&state[state_idx].lock);
+ spin_lock_bh(&state[state_idx].lock);
/* find state entry for gateway or add one if necessary */
list_for_each_entry_rcu(r, &state[state_idx].head, list) {
@@ -276,7 +276,7 @@ static void wrandom_set_nhinfo(__u32 network,
* we are finished
*/
- spin_unlock(&state[state_idx].lock);
+ spin_unlock_bh(&state[state_idx].lock);
}
static void __multipath_free(struct rcu_head *head)
@@ -302,7 +302,7 @@ static void wrandom_flush(void)
for (i = 0; i < MULTIPATH_STATE_SIZE; ++i) {
struct multipath_route *r;
- spin_lock(&state[i].lock);
+ spin_lock_bh(&state[i].lock);
list_for_each_entry_rcu(r, &state[i].head, list) {
struct multipath_dest *d;
list_for_each_entry_rcu(d, &r->dests, list) {
@@ -315,7 +315,7 @@ static void wrandom_flush(void)
__multipath_free);
}
- spin_unlock(&state[i].lock);
+ spin_unlock_bh(&state[i].lock);
}
}
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index afe3d8f8177d..dd1048be8a01 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -807,6 +807,13 @@ static int do_replace(void __user *user, unsigned int len)
if (len != sizeof(tmp) + tmp.size)
return -ENOPROTOOPT;
+ /* overflow check */
+ if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
+ SMP_CACHE_BYTES)
+ return -ENOMEM;
+ if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
+ return -ENOMEM;
+
newinfo = xt_alloc_table_info(tmp.size);
if (!newinfo)
return -ENOMEM;
diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c
index c9ebbe0d2d9c..e0b5926c76f9 100644
--- a/net/ipv4/netfilter/ip_conntrack_netlink.c
+++ b/net/ipv4/netfilter/ip_conntrack_netlink.c
@@ -1216,7 +1216,7 @@ static int ctnetlink_expect_event(struct notifier_block *this,
b = skb->tail;
- type |= NFNL_SUBSYS_CTNETLINK << 8;
+ type |= NFNL_SUBSYS_CTNETLINK_EXP << 8;
nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg));
nfmsg = NLMSG_DATA(nlh);
@@ -1567,6 +1567,7 @@ static struct nfnetlink_subsystem ctnl_exp_subsys = {
};
MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK);
+MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK_EXP);
static int __init ctnetlink_init(void)
{
diff --git a/net/ipv4/netfilter/ip_conntrack_tftp.c b/net/ipv4/netfilter/ip_conntrack_tftp.c
index d3c5a371f993..4ba4463cec28 100644
--- a/net/ipv4/netfilter/ip_conntrack_tftp.c
+++ b/net/ipv4/netfilter/ip_conntrack_tftp.c
@@ -71,6 +71,7 @@ static int tftp_help(struct sk_buff **pskb,
exp->tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
exp->mask.src.ip = 0xffffffff;
+ exp->mask.src.u.udp.port = 0;
exp->mask.dst.ip = 0xffffffff;
exp->mask.dst.u.udp.port = 0xffff;
exp->mask.dst.protonum = 0xff;
diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c
index ad438fb185b8..92c54999a19d 100644
--- a/net/ipv4/netfilter/ip_nat_standalone.c
+++ b/net/ipv4/netfilter/ip_nat_standalone.c
@@ -209,8 +209,8 @@ ip_nat_in(unsigned int hooknum,
&& (ct = ip_conntrack_get(*pskb, &ctinfo)) != NULL) {
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
- if (ct->tuplehash[dir].tuple.src.ip !=
- ct->tuplehash[!dir].tuple.dst.ip) {
+ if (ct->tuplehash[dir].tuple.dst.ip !=
+ ct->tuplehash[!dir].tuple.src.ip) {
dst_release((*pskb)->dst);
(*pskb)->dst = NULL;
}
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 2371b2062c2d..16f47c675fef 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -921,6 +921,13 @@ do_replace(void __user *user, unsigned int len)
if (len != sizeof(tmp) + tmp.size)
return -ENOPROTOOPT;
+ /* overflow check */
+ if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
+ SMP_CACHE_BYTES)
+ return -ENOMEM;
+ if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
+ return -ENOMEM;
+
newinfo = xt_alloc_table_info(tmp.size);
if (!newinfo)
return -ENOMEM;
diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c
index 641dbc477650..180a9ea57b69 100644
--- a/net/ipv4/netfilter/ipt_ULOG.c
+++ b/net/ipv4/netfilter/ipt_ULOG.c
@@ -35,6 +35,10 @@
* each nlgroup you are using, so the total kernel memory usage increases
* by that factor.
*
+ * Actually you should use nlbufsiz a bit smaller than PAGE_SIZE, since
+ * nlbufsiz is used with alloc_skb, which adds another
+ * sizeof(struct skb_shared_info). Use NLMSG_GOODSIZE instead.
+ *
* flushtimeout:
* Specify, after how many hundredths of a second the queue should be
* flushed even if it is not full yet.
@@ -76,7 +80,7 @@ MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NFLOG);
#define PRINTR(format, args...) do { if (net_ratelimit()) printk(format , ## args); } while (0)
-static unsigned int nlbufsiz = 4096;
+static unsigned int nlbufsiz = NLMSG_GOODSIZE;
module_param(nlbufsiz, uint, 0400);
MODULE_PARM_DESC(nlbufsiz, "netlink buffer size");
@@ -143,22 +147,26 @@ static void ulog_timer(unsigned long data)
static struct sk_buff *ulog_alloc_skb(unsigned int size)
{
struct sk_buff *skb;
+ unsigned int n;
/* alloc skb which should be big enough for a whole
* multipart message. WARNING: has to be <= 131000
* due to slab allocator restrictions */
- skb = alloc_skb(nlbufsiz, GFP_ATOMIC);
+ n = max(size, nlbufsiz);
+ skb = alloc_skb(n, GFP_ATOMIC);
if (!skb) {
- PRINTR("ipt_ULOG: can't alloc whole buffer %ub!\n",
- nlbufsiz);
+ PRINTR("ipt_ULOG: can't alloc whole buffer %ub!\n", n);
- /* try to allocate only as much as we need for
- * current packet */
+ if (n > size) {
+ /* try to allocate only as much as we need for
+ * current packet */
- skb = alloc_skb(size, GFP_ATOMIC);
- if (!skb)
- PRINTR("ipt_ULOG: can't even allocate %ub\n", size);
+ skb = alloc_skb(size, GFP_ATOMIC);
+ if (!skb)
+ PRINTR("ipt_ULOG: can't even allocate %ub\n",
+ size);
+ }
}
return skb;
diff --git a/net/ipv4/netfilter/ipt_policy.c b/net/ipv4/netfilter/ipt_policy.c
index 18ca8258a1c5..5a7a265280f9 100644
--- a/net/ipv4/netfilter/ipt_policy.c
+++ b/net/ipv4/netfilter/ipt_policy.c
@@ -26,10 +26,13 @@ MODULE_LICENSE("GPL");
static inline int
match_xfrm_state(struct xfrm_state *x, const struct ipt_policy_elem *e)
{
-#define MATCH(x,y) (!e->match.x || ((e->x == (y)) ^ e->invert.x))
+#define MATCH_ADDR(x,y,z) (!e->match.x || \
+ ((e->x.a4.s_addr == (e->y.a4.s_addr & (z))) \
+ ^ e->invert.x))
+#define MATCH(x,y) (!e->match.x || ((e->x == (y)) ^ e->invert.x))
- return MATCH(saddr, x->props.saddr.a4 & e->smask) &&
- MATCH(daddr, x->id.daddr.a4 & e->dmask) &&
+ return MATCH_ADDR(saddr, smask, x->props.saddr.a4) &&
+ MATCH_ADDR(daddr, dmask, x->id.daddr.a4) &&
MATCH(proto, x->id.proto) &&
MATCH(mode, x->props.mode) &&
MATCH(spi, x->id.spi) &&
@@ -89,7 +92,7 @@ match_policy_out(const struct sk_buff *skb, const struct ipt_policy_info *info)
return 0;
}
- return strict ? 1 : 0;
+ return strict ? i == info->len : 0;
}
static int match(const struct sk_buff *skb,
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c
index 39d49dc333a7..1b167c4bb3be 100644
--- a/net/ipv4/proc.c
+++ b/net/ipv4/proc.c
@@ -49,7 +49,7 @@ static int fold_prot_inuse(struct proto *proto)
int res = 0;
int cpu;
- for (cpu = 0; cpu < NR_CPUS; cpu++)
+ for_each_cpu(cpu)
res += proto->stats[cpu].inuse;
return res;
diff --git a/net/ipv4/tcp_htcp.c b/net/ipv4/tcp_htcp.c
index 3284cfb993e6..128de4d7c0b7 100644
--- a/net/ipv4/tcp_htcp.c
+++ b/net/ipv4/tcp_htcp.c
@@ -230,7 +230,6 @@ static void htcp_cong_avoid(struct sock *sk, u32 ack, u32 rtt,
if (tp->snd_cwnd < tp->snd_cwnd_clamp)
tp->snd_cwnd++;
tp->snd_cwnd_cnt = 0;
- ca->ccount++;
}
}
}
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 6ea353907af5..233bdf259965 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -236,7 +236,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
if (err)
goto failure;
- err = ip_route_newports(&rt, inet->sport, inet->dport, sk);
+ err = ip_route_newports(&rt, IPPROTO_TCP, inet->sport, inet->dport, sk);
if (err)
goto failure;
@@ -1845,7 +1845,6 @@ void __init tcp_v4_init(struct net_proto_family *ops)
}
EXPORT_SYMBOL(ipv4_specific);
-EXPORT_SYMBOL(inet_bind_bucket_create);
EXPORT_SYMBOL(tcp_hashinfo);
EXPORT_SYMBOL(tcp_prot);
EXPORT_SYMBOL(tcp_unhash);
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index d328d5986143..1db50487916b 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -3321,9 +3321,7 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
switch (event) {
case RTM_NEWADDR:
- dst_hold(&ifp->rt->u.dst);
- if (ip6_ins_rt(ifp->rt, NULL, NULL, NULL))
- dst_release(&ifp->rt->u.dst);
+ ip6_ins_rt(ifp->rt, NULL, NULL, NULL);
if (ifp->idev->cnf.forwarding)
addrconf_join_anycast(ifp);
break;
@@ -3334,8 +3332,6 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
dst_hold(&ifp->rt->u.dst);
if (ip6_del_rt(ifp->rt, NULL, NULL, NULL))
dst_free(&ifp->rt->u.dst);
- else
- dst_release(&ifp->rt->u.dst);
break;
}
}
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 064ffab82a9f..6c9711ac1c03 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -369,12 +369,6 @@ int inet6_destroy_sock(struct sock *sk)
struct sk_buff *skb;
struct ipv6_txoptions *opt;
- /*
- * Release destination entry
- */
-
- sk_dst_reset(sk);
-
/* Release rx options */
if ((skb = xchg(&np->pktoptions, NULL)) != NULL)
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 6c05c7978bef..4420948a1bfe 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -1252,8 +1252,7 @@ int igmp6_event_query(struct sk_buff *skb)
}
} else {
for (ma = idev->mc_list; ma; ma=ma->next) {
- if (group_type != IPV6_ADDR_ANY &&
- !ipv6_addr_equal(group, &ma->mca_addr))
+ if (!ipv6_addr_equal(group, &ma->mca_addr))
continue;
spin_lock_bh(&ma->mca_lock);
if (ma->mca_flags & MAF_TIMER_RUNNING) {
@@ -1268,11 +1267,10 @@ int igmp6_event_query(struct sk_buff *skb)
ma->mca_flags &= ~MAF_GSQUERY;
}
if (!(ma->mca_flags & MAF_GSQUERY) ||
- mld_marksources(ma, ntohs(mlh2->nsrcs), mlh2->srcs))
+ mld_marksources(ma, ntohs(mlh2->nsrcs), mlh2->srcs))
igmp6_group_queried(ma, max_delay);
spin_unlock_bh(&ma->mca_lock);
- if (group_type != IPV6_ADDR_ANY)
- break;
+ break;
}
}
read_unlock_bh(&idev->lock);
@@ -1351,7 +1349,7 @@ static int is_in(struct ifmcaddr6 *pmc, struct ip6_sf_list *psf, int type,
* in all filters
*/
if (psf->sf_count[MCAST_INCLUDE])
- return 0;
+ return type == MLD2_MODE_IS_INCLUDE;
return pmc->mca_sfcount[MCAST_EXCLUDE] ==
psf->sf_count[MCAST_EXCLUDE];
}
@@ -1966,7 +1964,7 @@ static void sf_markstate(struct ifmcaddr6 *pmc)
static int sf_setstate(struct ifmcaddr6 *pmc)
{
- struct ip6_sf_list *psf;
+ struct ip6_sf_list *psf, *dpsf;
int mca_xcount = pmc->mca_sfcount[MCAST_EXCLUDE];
int qrv = pmc->idev->mc_qrv;
int new_in, rv;
@@ -1978,8 +1976,48 @@ static int sf_setstate(struct ifmcaddr6 *pmc)
!psf->sf_count[MCAST_INCLUDE];
} else
new_in = psf->sf_count[MCAST_INCLUDE] != 0;
- if (new_in != psf->sf_oldin) {
- psf->sf_crcount = qrv;
+ if (new_in) {
+ if (!psf->sf_oldin) {
+ struct ip6_sf_list *prev = 0;
+
+ for (dpsf=pmc->mca_tomb; dpsf;
+ dpsf=dpsf->sf_next) {
+ if (ipv6_addr_equal(&dpsf->sf_addr,
+ &psf->sf_addr))
+ break;
+ prev = dpsf;
+ }
+ if (dpsf) {
+ if (prev)
+ prev->sf_next = dpsf->sf_next;
+ else
+ pmc->mca_tomb = dpsf->sf_next;
+ kfree(dpsf);
+ }
+ psf->sf_crcount = qrv;
+ rv++;
+ }
+ } else if (psf->sf_oldin) {
+ psf->sf_crcount = 0;
+ /*
+ * add or update "delete" records if an active filter
+ * is now inactive
+ */
+ for (dpsf=pmc->mca_tomb; dpsf; dpsf=dpsf->sf_next)
+ if (ipv6_addr_equal(&dpsf->sf_addr,
+ &psf->sf_addr))
+ break;
+ if (!dpsf) {
+ dpsf = (struct ip6_sf_list *)
+ kmalloc(sizeof(*dpsf), GFP_ATOMIC);
+ if (!dpsf)
+ continue;
+ *dpsf = *psf;
+ /* pmc->mca_lock held by callers */
+ dpsf->sf_next = pmc->mca_tomb;
+ pmc->mca_tomb = dpsf;
+ }
+ dpsf->sf_crcount = qrv;
rv++;
}
}
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 847068fd3367..74ff56c322f4 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -978,6 +978,13 @@ do_replace(void __user *user, unsigned int len)
if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
return -EFAULT;
+ /* overflow check */
+ if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
+ SMP_CACHE_BYTES)
+ return -ENOMEM;
+ if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
+ return -ENOMEM;
+
newinfo = xt_alloc_table_info(tmp.size);
if (!newinfo)
return -ENOMEM;
diff --git a/net/ipv6/netfilter/ip6t_policy.c b/net/ipv6/netfilter/ip6t_policy.c
index afe1cc4c18a5..3d39ec924041 100644
--- a/net/ipv6/netfilter/ip6t_policy.c
+++ b/net/ipv6/netfilter/ip6t_policy.c
@@ -26,8 +26,9 @@ MODULE_LICENSE("GPL");
static inline int
match_xfrm_state(struct xfrm_state *x, const struct ip6t_policy_elem *e)
{
-#define MATCH_ADDR(x,y,z) (!e->match.x || \
- ((ip6_masked_addrcmp((z), &e->x, &e->y)) == 0) ^ e->invert.x)
+#define MATCH_ADDR(x,y,z) (!e->match.x || \
+ ((!ip6_masked_addrcmp(&e->x.a6, &e->y.a6, z)) \
+ ^ e->invert.x))
#define MATCH(x,y) (!e->match.x || ((e->x == (y)) ^ e->invert.x))
return MATCH_ADDR(saddr, smask, (struct in6_addr *)&x->props.saddr.a6) &&
@@ -91,7 +92,7 @@ match_policy_out(const struct sk_buff *skb, const struct ip6t_policy_info *info)
return 0;
}
- return strict ? 1 : 0;
+ return strict ? i == info->len : 0;
}
static int match(const struct sk_buff *skb,
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c
index 50a13e75d70e..4238b1ed8860 100644
--- a/net/ipv6/proc.c
+++ b/net/ipv6/proc.c
@@ -38,7 +38,7 @@ static int fold_prot_inuse(struct proto *proto)
int res = 0;
int cpu;
- for (cpu=0; cpu<NR_CPUS; cpu++)
+ for_each_cpu(cpu)
res += proto->stats[cpu].inuse;
return res;
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 66d04004afda..ca9cf6853755 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -515,6 +515,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
done:
if (opt && opt != np->opt)
sock_kfree_s(sk, opt, opt->tot_len);
+ dst_release(dst);
return err;
}
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 43f1ce74187d..ae86d237a456 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -1620,6 +1620,7 @@ static int key_notify_sa_flush(struct km_event *c)
return -ENOBUFS;
hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg));
hdr->sadb_msg_satype = pfkey_proto2satype(c->data.proto);
+ hdr->sadb_msg_type = SADB_FLUSH;
hdr->sadb_msg_seq = c->seq;
hdr->sadb_msg_pid = c->pid;
hdr->sadb_msg_version = PF_KEY_V2;
@@ -2385,6 +2386,7 @@ static int key_notify_policy_flush(struct km_event *c)
if (!skb_out)
return -ENOBUFS;
hdr = (struct sadb_msg *) skb_put(skb_out, sizeof(struct sadb_msg));
+ hdr->sadb_msg_type = SADB_X_SPDFLUSH;
hdr->sadb_msg_seq = c->seq;
hdr->sadb_msg_pid = c->pid;
hdr->sadb_msg_version = PF_KEY_V2;
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 62bb509f05d4..0ce337a1d974 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -188,7 +188,7 @@ extern struct nf_conntrack_protocol nf_conntrack_generic_protocol;
struct nf_conntrack_protocol *
__nf_ct_proto_find(u_int16_t l3proto, u_int8_t protocol)
{
- if (unlikely(nf_ct_protos[l3proto] == NULL))
+ if (unlikely(l3proto >= AF_MAX || nf_ct_protos[l3proto] == NULL))
return &nf_conntrack_generic_protocol;
return nf_ct_protos[l3proto][protocol];
diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c
index ab0c920f0d30..6f210f399762 100644
--- a/net/netfilter/nf_conntrack_ftp.c
+++ b/net/netfilter/nf_conntrack_ftp.c
@@ -657,8 +657,6 @@ static int __init init(void)
/* FIXME should be configurable whether IPv4 and IPv6 FTP connections
are tracked or not - YK */
for (i = 0; i < ports_c; i++) {
- memset(&ftp[i], 0, sizeof(struct nf_conntrack_helper));
-
ftp[i][0].tuple.src.l3num = PF_INET;
ftp[i][1].tuple.src.l3num = PF_INET6;
for (j = 0; j < 2; j++) {
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 73ab16bc7d40..9ff3463037e1 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -1232,7 +1232,7 @@ static int ctnetlink_expect_event(struct notifier_block *this,
b = skb->tail;
- type |= NFNL_SUBSYS_CTNETLINK << 8;
+ type |= NFNL_SUBSYS_CTNETLINK_EXP << 8;
nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg));
nfmsg = NLMSG_DATA(nlh);
@@ -1589,6 +1589,7 @@ static struct nfnetlink_subsystem ctnl_exp_subsys = {
};
MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK);
+MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK_EXP);
static int __init ctnetlink_init(void)
{
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index e10512e229b6..3b3c781b40c0 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -37,7 +37,7 @@
#include "../bridge/br_private.h"
#endif
-#define NFULNL_NLBUFSIZ_DEFAULT 4096
+#define NFULNL_NLBUFSIZ_DEFAULT NLMSG_GOODSIZE
#define NFULNL_TIMEOUT_DEFAULT 100 /* every second */
#define NFULNL_QTHRESH_DEFAULT 100 /* 100 packets */
@@ -314,24 +314,28 @@ static struct sk_buff *nfulnl_alloc_skb(unsigned int inst_size,
unsigned int pkt_size)
{
struct sk_buff *skb;
+ unsigned int n;
UDEBUG("entered (%u, %u)\n", inst_size, pkt_size);
/* alloc skb which should be big enough for a whole multipart
* message. WARNING: has to be <= 128k due to slab restrictions */
- skb = alloc_skb(inst_size, GFP_ATOMIC);
+ n = max(inst_size, pkt_size);
+ skb = alloc_skb(n, GFP_ATOMIC);
if (!skb) {
PRINTR("nfnetlink_log: can't alloc whole buffer (%u bytes)\n",
inst_size);
- /* try to allocate only as much as we need for current
- * packet */
+ if (n > pkt_size) {
+ /* try to allocate only as much as we need for current
+ * packet */
- skb = alloc_skb(pkt_size, GFP_ATOMIC);
- if (!skb)
- PRINTR("nfnetlink_log: can't even alloc %u bytes\n",
- pkt_size);
+ skb = alloc_skb(pkt_size, GFP_ATOMIC);
+ if (!skb)
+ PRINTR("nfnetlink_log: can't even alloc %u "
+ "bytes\n", pkt_size);
+ }
}
return skb;
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index 18ed9c5d209c..cac38b2e147a 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -825,7 +825,8 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
}
if (nfqa[NFQA_MARK-1])
- skb->nfmark = ntohl(*(u_int32_t *)NFA_DATA(nfqa[NFQA_MARK-1]));
+ entry->skb->nfmark = ntohl(*(u_int32_t *)
+ NFA_DATA(nfqa[NFQA_MARK-1]));
issue_verdict(entry, verdict);
instance_put(queue);
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index ee93abc71cb8..9db7dbdb16e6 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -365,7 +365,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock,
*/
err = -EMSGSIZE;
- if(len>dev->mtu+dev->hard_header_len)
+ if (len > dev->mtu + dev->hard_header_len)
goto out_unlock;
err = -ENOBUFS;
@@ -935,7 +935,7 @@ static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr, int add
* Check legality
*/
- if(addr_len!=sizeof(struct sockaddr))
+ if (addr_len != sizeof(struct sockaddr))
return -EINVAL;
strlcpy(name,uaddr->sa_data,sizeof(name));
@@ -1092,7 +1092,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
* retries.
*/
- if(skb==NULL)
+ if (skb == NULL)
goto out;
/*
@@ -1392,8 +1392,8 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
if (level != SOL_PACKET)
return -ENOPROTOOPT;
- if (get_user(len,optlen))
- return -EFAULT;
+ if (get_user(len, optlen))
+ return -EFAULT;
if (len < 0)
return -EINVAL;
@@ -1419,9 +1419,9 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
return -ENOPROTOOPT;
}
- if (put_user(len, optlen))
- return -EFAULT;
- return 0;
+ if (put_user(len, optlen))
+ return -EFAULT;
+ return 0;
}
diff --git a/net/sctp/input.c b/net/sctp/input.c
index 4aa6fc60357c..cb78b50868ee 100644
--- a/net/sctp/input.c
+++ b/net/sctp/input.c
@@ -257,20 +257,26 @@ int sctp_rcv(struct sk_buff *skb)
*/
sctp_bh_lock_sock(sk);
+ /* It is possible that the association could have moved to a different
+ * socket if it is peeled off. If so, update the sk.
+ */
+ if (sk != rcvr->sk) {
+ sctp_bh_lock_sock(rcvr->sk);
+ sctp_bh_unlock_sock(sk);
+ sk = rcvr->sk;
+ }
+
if (sock_owned_by_user(sk))
sk_add_backlog(sk, skb);
else
sctp_backlog_rcv(sk, skb);
- /* Release the sock and any reference counts we took in the
- * lookup calls.
+ /* Release the sock and the sock ref we took in the lookup calls.
+ * The asoc/ep ref will be released in sctp_backlog_rcv.
*/
sctp_bh_unlock_sock(sk);
- if (asoc)
- sctp_association_put(asoc);
- else
- sctp_endpoint_put(ep);
sock_put(sk);
+
return ret;
discard_it:
@@ -296,12 +302,50 @@ discard_release:
int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
{
struct sctp_chunk *chunk = SCTP_INPUT_CB(skb)->chunk;
- struct sctp_inq *inqueue = &chunk->rcvr->inqueue;
-
- sctp_inq_push(inqueue, chunk);
+ struct sctp_inq *inqueue = NULL;
+ struct sctp_ep_common *rcvr = NULL;
+
+ rcvr = chunk->rcvr;
+
+ BUG_TRAP(rcvr->sk == sk);
+
+ if (rcvr->dead) {
+ sctp_chunk_free(chunk);
+ } else {
+ inqueue = &chunk->rcvr->inqueue;
+ sctp_inq_push(inqueue, chunk);
+ }
+
+ /* Release the asoc/ep ref we took in the lookup calls in sctp_rcv. */
+ if (SCTP_EP_TYPE_ASSOCIATION == rcvr->type)
+ sctp_association_put(sctp_assoc(rcvr));
+ else
+ sctp_endpoint_put(sctp_ep(rcvr));
+
return 0;
}
+void sctp_backlog_migrate(struct sctp_association *assoc,
+ struct sock *oldsk, struct sock *newsk)
+{
+ struct sk_buff *skb;
+ struct sctp_chunk *chunk;
+
+ skb = oldsk->sk_backlog.head;
+ oldsk->sk_backlog.head = oldsk->sk_backlog.tail = NULL;
+ while (skb != NULL) {
+ struct sk_buff *next = skb->next;
+
+ chunk = SCTP_INPUT_CB(skb)->chunk;
+ skb->next = NULL;
+ if (&assoc->base == chunk->rcvr)
+ sk_add_backlog(newsk, skb);
+ else
+ sk_add_backlog(oldsk, skb);
+ skb = next;
+ }
+}
+
/* Handle icmp frag needed error. */
void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc,
struct sctp_transport *t, __u32 pmtu)
@@ -544,10 +588,16 @@ int sctp_rcv_ootb(struct sk_buff *skb)
sctp_errhdr_t *err;
ch = (sctp_chunkhdr_t *) skb->data;
- ch_end = ((__u8 *) ch) + WORD_ROUND(ntohs(ch->length));
/* Scan through all the chunks in the packet. */
- while (ch_end > (__u8 *)ch && ch_end < skb->tail) {
+ do {
+ /* Break out if chunk length is less then minimal. */
+ if (ntohs(ch->length) < sizeof(sctp_chunkhdr_t))
+ break;
+
+ ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length));
+ if (ch_end > skb->tail)
+ break;
/* RFC 8.4, 2) If the OOTB packet contains an ABORT chunk, the
* receiver MUST silently discard the OOTB packet and take no
@@ -578,8 +628,7 @@ int sctp_rcv_ootb(struct sk_buff *skb)
}
ch = (sctp_chunkhdr_t *) ch_end;
- ch_end = ((__u8 *) ch) + WORD_ROUND(ntohs(ch->length));
- }
+ } while (ch_end < skb->tail);
return 0;
diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c
index 2d33922c044b..297b8951463e 100644
--- a/net/sctp/inqueue.c
+++ b/net/sctp/inqueue.c
@@ -73,8 +73,10 @@ void sctp_inq_free(struct sctp_inq *queue)
/* If there is a packet which is currently being worked on,
* free it as well.
*/
- if (queue->in_progress)
+ if (queue->in_progress) {
sctp_chunk_free(queue->in_progress);
+ queue->in_progress = NULL;
+ }
if (queue->malloced) {
/* Dump the master memory segment. */
diff --git a/net/sctp/output.c b/net/sctp/output.c
index a40991ef72c9..437cba7260a4 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -608,7 +608,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
* When a Fast Retransmit is being performed the sender SHOULD
* ignore the value of cwnd and SHOULD NOT delay retransmission.
*/
- if (!chunk->fast_retransmit)
+ if (chunk->fast_retransmit <= 0)
if (transport->flight_size >= transport->cwnd) {
retval = SCTP_XMIT_RWND_FULL;
goto finish;
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index efb72faba20c..f148f9576dd2 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -406,7 +406,7 @@ void sctp_retransmit_mark(struct sctp_outq *q,
* chunks that are not yet acked should be added to the
* retransmit queue.
*/
- if ((fast_retransmit && chunk->fast_retransmit) ||
+ if ((fast_retransmit && (chunk->fast_retransmit > 0)) ||
(!fast_retransmit && !chunk->tsn_gap_acked)) {
/* RFC 2960 6.2.1 Processing a Received SACK
*
@@ -603,7 +603,8 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
/* Mark the chunk as ineligible for fast retransmit
* after it is retransmitted.
*/
- chunk->fast_retransmit = 0;
+ if (chunk->fast_retransmit > 0)
+ chunk->fast_retransmit = -1;
*start_timer = 1;
q->empty = 0;
@@ -621,7 +622,8 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
list_for_each(lchunk1, lqueue) {
chunk1 = list_entry(lchunk1, struct sctp_chunk,
transmitted_list);
- chunk1->fast_retransmit = 0;
+ if (chunk1->fast_retransmit > 0)
+ chunk1->fast_retransmit = -1;
}
}
}
@@ -1562,11 +1564,11 @@ static void sctp_mark_missing(struct sctp_outq *q,
/*
* M4) If any DATA chunk is found to have a
* 'TSN.Missing.Report'
- * value larger than or equal to 4, mark that chunk for
+ * value larger than or equal to 3, mark that chunk for
* retransmission and start the fast retransmit procedure.
*/
- if (chunk->tsn_missing_report >= 4) {
+ if (chunk->tsn_missing_report >= 3) {
chunk->fast_retransmit = 1;
do_fast_retransmit = 1;
}
diff --git a/net/sctp/proc.c b/net/sctp/proc.c
index 6e4dc28874d7..d47a52c303a8 100644
--- a/net/sctp/proc.c
+++ b/net/sctp/proc.c
@@ -176,7 +176,7 @@ static void sctp_seq_dump_remote_addrs(struct seq_file *seq, struct sctp_associa
static void * sctp_eps_seq_start(struct seq_file *seq, loff_t *pos)
{
- if (*pos > sctp_ep_hashsize)
+ if (*pos >= sctp_ep_hashsize)
return NULL;
if (*pos < 0)
@@ -185,8 +185,6 @@ static void * sctp_eps_seq_start(struct seq_file *seq, loff_t *pos)
if (*pos == 0)
seq_printf(seq, " ENDPT SOCK STY SST HBKT LPORT UID INODE LADDRS\n");
- ++*pos;
-
return (void *)pos;
}
@@ -198,11 +196,9 @@ static void sctp_eps_seq_stop(struct seq_file *seq, void *v)
static void * sctp_eps_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
- if (*pos > sctp_ep_hashsize)
+ if (++*pos >= sctp_ep_hashsize)
return NULL;
- ++*pos;
-
return pos;
}
@@ -214,19 +210,19 @@ static int sctp_eps_seq_show(struct seq_file *seq, void *v)
struct sctp_ep_common *epb;
struct sctp_endpoint *ep;
struct sock *sk;
- int hash = *(int *)v;
+ int hash = *(loff_t *)v;
- if (hash > sctp_ep_hashsize)
+ if (hash >= sctp_ep_hashsize)
return -ENOMEM;
- head = &sctp_ep_hashtable[hash-1];
+ head = &sctp_ep_hashtable[hash];
sctp_local_bh_disable();
read_lock(&head->lock);
for (epb = head->chain; epb; epb = epb->next) {
ep = sctp_ep(epb);
sk = epb->sk;
seq_printf(seq, "%8p %8p %-3d %-3d %-4d %-5d %5d %5lu ", ep, sk,
- sctp_sk(sk)->type, sk->sk_state, hash-1,
+ sctp_sk(sk)->type, sk->sk_state, hash,
epb->bind_addr.port,
sock_i_uid(sk), sock_i_ino(sk));
@@ -283,7 +279,7 @@ void sctp_eps_proc_exit(void)
static void * sctp_assocs_seq_start(struct seq_file *seq, loff_t *pos)
{
- if (*pos > sctp_assoc_hashsize)
+ if (*pos >= sctp_assoc_hashsize)
return NULL;
if (*pos < 0)
@@ -293,8 +289,6 @@ static void * sctp_assocs_seq_start(struct seq_file *seq, loff_t *pos)
seq_printf(seq, " ASSOC SOCK STY SST ST HBKT ASSOC-ID TX_QUEUE RX_QUEUE UID INODE LPORT "
"RPORT LADDRS <-> RADDRS\n");
- ++*pos;
-
return (void *)pos;
}
@@ -306,11 +300,9 @@ static void sctp_assocs_seq_stop(struct seq_file *seq, void *v)
static void * sctp_assocs_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
- if (*pos > sctp_assoc_hashsize)
+ if (++*pos >= sctp_assoc_hashsize)
return NULL;
- ++*pos;
-
return pos;
}
@@ -321,12 +313,12 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v)
struct sctp_ep_common *epb;
struct sctp_association *assoc;
struct sock *sk;
- int hash = *(int *)v;
+ int hash = *(loff_t *)v;
- if (hash > sctp_assoc_hashsize)
+ if (hash >= sctp_assoc_hashsize)
return -ENOMEM;
- head = &sctp_assoc_hashtable[hash-1];
+ head = &sctp_assoc_hashtable[hash];
sctp_local_bh_disable();
read_lock(&head->lock);
for (epb = head->chain; epb; epb = epb->next) {
@@ -335,7 +327,7 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v)
seq_printf(seq,
"%8p %8p %-3d %-3d %-2d %-4d %4d %8d %8d %7d %5lu %-5d %5d ",
assoc, sk, sctp_sk(sk)->type, sk->sk_state,
- assoc->state, hash-1, assoc->assoc_id,
+ assoc->state, hash, assoc->assoc_id,
(sk->sk_rcvbuf - assoc->rwnd),
assoc->sndbuf_used,
sock_i_uid(sk), sock_i_ino(sk),
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index 556c495c6922..5e0de3c0eead 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -1275,7 +1275,12 @@ static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
unsigned int keylen;
char *key;
- headersize = sizeof(sctp_paramhdr_t) + SCTP_SECRET_SIZE;
+ /* Header size is static data prior to the actual cookie, including
+ * any padding.
+ */
+ headersize = sizeof(sctp_paramhdr_t) +
+ (sizeof(struct sctp_signed_cookie) -
+ sizeof(struct sctp_cookie));
bodysize = sizeof(struct sctp_cookie)
+ ntohs(init_chunk->chunk_hdr->length) + addrs_len;
@@ -1354,7 +1359,7 @@ struct sctp_association *sctp_unpack_cookie(
struct sctp_signed_cookie *cookie;
struct sctp_cookie *bear_cookie;
int headersize, bodysize, fixed_size;
- __u8 digest[SCTP_SIGNATURE_SIZE];
+ __u8 *digest = ep->digest;
struct scatterlist sg;
unsigned int keylen, len;
char *key;
@@ -1362,7 +1367,12 @@ struct sctp_association *sctp_unpack_cookie(
struct sk_buff *skb = chunk->skb;
struct timeval tv;
- headersize = sizeof(sctp_chunkhdr_t) + SCTP_SECRET_SIZE;
+ /* Header size is static data prior to the actual cookie, including
+ * any padding.
+ */
+ headersize = sizeof(sctp_chunkhdr_t) +
+ (sizeof(struct sctp_signed_cookie) -
+ sizeof(struct sctp_cookie));
bodysize = ntohs(chunk->chunk_hdr->length) - headersize;
fixed_size = headersize + sizeof(struct sctp_cookie);
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index b8b38aba92b3..8d1dc24bab4c 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -1300,7 +1300,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
"T1 INIT Timeout adjustment"
" init_err_counter: %d"
" cycle: %d"
- " timeout: %d\n",
+ " timeout: %ld\n",
asoc->init_err_counter,
asoc->init_cycle,
asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT]);
@@ -1328,7 +1328,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
SCTP_DEBUG_PRINTK(
"T1 COOKIE Timeout adjustment"
" init_err_counter: %d"
- " timeout: %d\n",
+ " timeout: %ld\n",
asoc->init_err_counter,
asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE]);
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 477d7f80dba6..2b9a832b29a7 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -884,7 +884,7 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const struct sctp_endpoint *ep,
{
struct sctp_transport *transport = (struct sctp_transport *) arg;
- if (asoc->overall_error_count > asoc->max_retrans) {
+ if (asoc->overall_error_count >= asoc->max_retrans) {
/* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
SCTP_U32(SCTP_ERROR_NO_ERROR));
@@ -2122,7 +2122,7 @@ static sctp_disposition_t sctp_sf_do_5_2_6_stale(const struct sctp_endpoint *ep,
struct sctp_bind_addr *bp;
int attempts = asoc->init_err_counter + 1;
- if (attempts >= asoc->max_init_attempts) {
+ if (attempts > asoc->max_init_attempts) {
sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
SCTP_U32(SCTP_ERROR_STALE_COOKIE));
return SCTP_DISPOSITION_DELETE_TCB;
@@ -3090,6 +3090,8 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep,
break;
ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length));
+ if (ch_end > skb->tail)
+ break;
if (SCTP_CID_SHUTDOWN_ACK == ch->type)
ootb_shut_ack = 1;
@@ -4638,7 +4640,7 @@ sctp_disposition_t sctp_sf_t1_init_timer_expire(const struct sctp_endpoint *ep,
SCTP_DEBUG_PRINTK("Timer T1 expired (INIT).\n");
- if (attempts < asoc->max_init_attempts) {
+ if (attempts <= asoc->max_init_attempts) {
bp = (struct sctp_bind_addr *) &asoc->base.bind_addr;
repl = sctp_make_init(asoc, bp, GFP_ATOMIC, 0);
if (!repl)
@@ -4695,7 +4697,7 @@ sctp_disposition_t sctp_sf_t1_cookie_timer_expire(const struct sctp_endpoint *ep
SCTP_DEBUG_PRINTK("Timer T1 expired (COOKIE-ECHO).\n");
- if (attempts < asoc->max_init_attempts) {
+ if (attempts <= asoc->max_init_attempts) {
repl = sctp_make_cookie_echo(asoc, NULL);
if (!repl)
return SCTP_DISPOSITION_NOMEM;
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index c98ee375ba5e..0ea947eb6813 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -2995,7 +2995,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
sp->hbinterval = jiffies_to_msecs(sctp_hb_interval);
sp->pathmaxrxt = sctp_max_retrans_path;
sp->pathmtu = 0; // allow default discovery
- sp->sackdelay = sctp_sack_timeout;
+ sp->sackdelay = jiffies_to_msecs(sctp_sack_timeout);
sp->param_flags = SPP_HB_ENABLE |
SPP_PMTUD_ENABLE |
SPP_SACKDELAY_ENABLE;
@@ -5426,7 +5426,7 @@ out:
return err;
do_error:
- if (asoc->init_err_counter + 1 >= asoc->max_init_attempts)
+ if (asoc->init_err_counter + 1 > asoc->max_init_attempts)
err = -ETIMEDOUT;
else
err = -ECONNREFUSED;
@@ -5602,8 +5602,12 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
*/
newsp->type = type;
+ spin_lock_bh(&oldsk->sk_lock.slock);
+ /* Migrate the backlog from oldsk to newsk. */
+ sctp_backlog_migrate(assoc, oldsk, newsk);
/* Migrate the association to the new socket. */
sctp_assoc_migrate(assoc, newsk);
+ spin_unlock_bh(&oldsk->sk_lock.slock);
/* If the association on the newsk is already closed before accept()
* is called, set RCV_SHUTDOWN flag.
diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c
index fcd7096c953d..dc6f3ff32358 100644
--- a/net/sctp/sysctl.c
+++ b/net/sctp/sysctl.c
@@ -159,12 +159,9 @@ static ctl_table sctp_table[] = {
.ctl_name = NET_SCTP_PRESERVE_ENABLE,
.procname = "cookie_preserve_enable",
.data = &sctp_cookie_preserve_enable,
- .maxlen = sizeof(long),
+ .maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_doulongvec_ms_jiffies_minmax,
- .strategy = &sctp_sysctl_jiffies_ms,
- .extra1 = &rto_timer_min,
- .extra2 = &rto_timer_max
+ .proc_handler = &proc_dointvec
},
{
.ctl_name = NET_SCTP_RTO_ALPHA,
diff --git a/net/sctp/transport.c b/net/sctp/transport.c
index 68d73e2dd155..160f62ad1cc5 100644
--- a/net/sctp/transport.c
+++ b/net/sctp/transport.c
@@ -350,7 +350,7 @@ void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt)
tp->rto_pending = 0;
SCTP_DEBUG_PRINTK("%s: transport: %p, rtt: %d, srtt: %d "
- "rttvar: %d, rto: %d\n", __FUNCTION__,
+ "rttvar: %d, rto: %ld\n", __FUNCTION__,
tp, rtt, tp->srtt, tp->rttvar, tp->rto);
}
diff --git a/net/socket.c b/net/socket.c
index b38a263853c3..a00851f981db 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -2078,7 +2078,7 @@ void socket_seq_show(struct seq_file *seq)
int cpu;
int counter = 0;
- for (cpu = 0; cpu < NR_CPUS; cpu++)
+ for_each_cpu(cpu)
counter += per_cpu(sockets_in_use, cpu);
/* It can be negative, by the way. 8) */
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
index 9ac1b8c26c01..8d6f1a176b15 100644
--- a/net/sunrpc/auth.c
+++ b/net/sunrpc/auth.c
@@ -184,7 +184,7 @@ rpcauth_gc_credcache(struct rpc_auth *auth, struct hlist_head *free)
*/
struct rpc_cred *
rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred,
- int taskflags)
+ int flags)
{
struct rpc_cred_cache *cache = auth->au_credcache;
HLIST_HEAD(free);
@@ -193,7 +193,7 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred,
*cred = NULL;
int nr = 0;
- if (!(taskflags & RPC_TASK_ROOTCREDS))
+ if (!(flags & RPCAUTH_LOOKUP_ROOTCREDS))
nr = acred->uid & RPC_CREDCACHE_MASK;
retry:
spin_lock(&rpc_credcache_lock);
@@ -202,7 +202,7 @@ retry:
hlist_for_each_safe(pos, next, &cache->hashtable[nr]) {
struct rpc_cred *entry;
entry = hlist_entry(pos, struct rpc_cred, cr_hash);
- if (entry->cr_ops->crmatch(acred, entry, taskflags)) {
+ if (entry->cr_ops->crmatch(acred, entry, flags)) {
hlist_del(&entry->cr_hash);
cred = entry;
break;
@@ -224,7 +224,7 @@ retry:
rpcauth_destroy_credlist(&free);
if (!cred) {
- new = auth->au_ops->crcreate(auth, acred, taskflags);
+ new = auth->au_ops->crcreate(auth, acred, flags);
if (!IS_ERR(new)) {
#ifdef RPC_DEBUG
new->cr_magic = RPCAUTH_CRED_MAGIC;
@@ -232,13 +232,21 @@ retry:
goto retry;
} else
cred = new;
+ } else if ((cred->cr_flags & RPCAUTH_CRED_NEW)
+ && cred->cr_ops->cr_init != NULL
+ && !(flags & RPCAUTH_LOOKUP_NEW)) {
+ int res = cred->cr_ops->cr_init(auth, cred);
+ if (res < 0) {
+ put_rpccred(cred);
+ cred = ERR_PTR(res);
+ }
}
return (struct rpc_cred *) cred;
}
struct rpc_cred *
-rpcauth_lookupcred(struct rpc_auth *auth, int taskflags)
+rpcauth_lookupcred(struct rpc_auth *auth, int flags)
{
struct auth_cred acred = {
.uid = current->fsuid,
@@ -250,7 +258,7 @@ rpcauth_lookupcred(struct rpc_auth *auth, int taskflags)
dprintk("RPC: looking up %s cred\n",
auth->au_ops->au_name);
get_group_info(acred.group_info);
- ret = auth->au_ops->lookup_cred(auth, &acred, taskflags);
+ ret = auth->au_ops->lookup_cred(auth, &acred, flags);
put_group_info(acred.group_info);
return ret;
}
@@ -265,11 +273,14 @@ rpcauth_bindcred(struct rpc_task *task)
.group_info = current->group_info,
};
struct rpc_cred *ret;
+ int flags = 0;
dprintk("RPC: %4d looking up %s cred\n",
task->tk_pid, task->tk_auth->au_ops->au_name);
get_group_info(acred.group_info);
- ret = auth->au_ops->lookup_cred(auth, &acred, task->tk_flags);
+ if (task->tk_flags & RPC_TASK_ROOTCREDS)
+ flags |= RPCAUTH_LOOKUP_ROOTCREDS;
+ ret = auth->au_ops->lookup_cred(auth, &acred, flags);
if (!IS_ERR(ret))
task->tk_msg.rpc_cred = ret;
else
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index 8d782282ec19..bb46efd92e57 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -158,6 +158,7 @@ gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx)
old = gss_cred->gc_ctx;
gss_cred->gc_ctx = ctx;
cred->cr_flags |= RPCAUTH_CRED_UPTODATE;
+ cred->cr_flags &= ~RPCAUTH_CRED_NEW;
write_unlock(&gss_ctx_lock);
if (old)
gss_put_ctx(old);
@@ -580,7 +581,7 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
} else {
struct auth_cred acred = { .uid = uid };
spin_unlock(&gss_auth->lock);
- cred = rpcauth_lookup_credcache(clnt->cl_auth, &acred, 0);
+ cred = rpcauth_lookup_credcache(clnt->cl_auth, &acred, RPCAUTH_LOOKUP_NEW);
if (IS_ERR(cred)) {
err = PTR_ERR(cred);
goto err_put_ctx;
@@ -758,13 +759,13 @@ gss_destroy_cred(struct rpc_cred *rc)
* Lookup RPCSEC_GSS cred for the current process
*/
static struct rpc_cred *
-gss_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int taskflags)
+gss_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
{
- return rpcauth_lookup_credcache(auth, acred, taskflags);
+ return rpcauth_lookup_credcache(auth, acred, flags);
}
static struct rpc_cred *
-gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int taskflags)
+gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
{
struct gss_auth *gss_auth = container_of(auth, struct gss_auth, rpc_auth);
struct gss_cred *cred = NULL;
@@ -785,13 +786,8 @@ gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int taskflags)
*/
cred->gc_flags = 0;
cred->gc_base.cr_ops = &gss_credops;
+ cred->gc_base.cr_flags = RPCAUTH_CRED_NEW;
cred->gc_service = gss_auth->service;
- do {
- err = gss_create_upcall(gss_auth, cred);
- } while (err == -EAGAIN);
- if (err < 0)
- goto out_err;
-
return &cred->gc_base;
out_err:
@@ -801,13 +797,34 @@ out_err:
}
static int
-gss_match(struct auth_cred *acred, struct rpc_cred *rc, int taskflags)
+gss_cred_init(struct rpc_auth *auth, struct rpc_cred *cred)
+{
+ struct gss_auth *gss_auth = container_of(auth, struct gss_auth, rpc_auth);
+ struct gss_cred *gss_cred = container_of(cred,struct gss_cred, gc_base);
+ int err;
+
+ do {
+ err = gss_create_upcall(gss_auth, gss_cred);
+ } while (err == -EAGAIN);
+ return err;
+}
+
+static int
+gss_match(struct auth_cred *acred, struct rpc_cred *rc, int flags)
{
struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base);
+ /*
+ * If the searchflags have set RPCAUTH_LOOKUP_NEW, then
+ * we don't really care if the credential has expired or not,
+ * since the caller should be prepared to reinitialise it.
+ */
+ if ((flags & RPCAUTH_LOOKUP_NEW) && (rc->cr_flags & RPCAUTH_CRED_NEW))
+ goto out;
/* Don't match with creds that have expired. */
if (gss_cred->gc_ctx && time_after(jiffies, gss_cred->gc_ctx->gc_expiry))
return 0;
+out:
return (rc->cr_uid == acred->uid);
}
@@ -1241,6 +1258,7 @@ static struct rpc_authops authgss_ops = {
static struct rpc_credops gss_credops = {
.cr_name = "AUTH_GSS",
.crdestroy = gss_destroy_cred,
+ .cr_init = gss_cred_init,
.crmatch = gss_match,
.crmarshal = gss_marshal,
.crrefresh = gss_refresh,
diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c
index 1b3ed4fd1987..df14b6bfbf10 100644
--- a/net/sunrpc/auth_unix.c
+++ b/net/sunrpc/auth_unix.c
@@ -75,7 +75,7 @@ unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
atomic_set(&cred->uc_count, 1);
cred->uc_flags = RPCAUTH_CRED_UPTODATE;
- if (flags & RPC_TASK_ROOTCREDS) {
+ if (flags & RPCAUTH_LOOKUP_ROOTCREDS) {
cred->uc_uid = 0;
cred->uc_gid = 0;
cred->uc_gids[0] = NOGROUP;
@@ -108,12 +108,12 @@ unx_destroy_cred(struct rpc_cred *cred)
* request root creds (e.g. for NFS swapping).
*/
static int
-unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int taskflags)
+unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int flags)
{
struct unx_cred *cred = (struct unx_cred *) rcred;
int i;
- if (!(taskflags & RPC_TASK_ROOTCREDS)) {
+ if (!(flags & RPCAUTH_LOOKUP_ROOTCREDS)) {
int groups;
if (cred->uc_uid != acred->uid
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 9764c80ab0b2..a5c0c7b6e151 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -38,44 +38,42 @@ static kmem_cache_t *rpc_inode_cachep __read_mostly;
#define RPC_UPCALL_TIMEOUT (30*HZ)
-static void
-__rpc_purge_list(struct rpc_inode *rpci, struct list_head *head, int err)
+static void rpc_purge_list(struct rpc_inode *rpci, struct list_head *head,
+ void (*destroy_msg)(struct rpc_pipe_msg *), int err)
{
struct rpc_pipe_msg *msg;
- void (*destroy_msg)(struct rpc_pipe_msg *);
- destroy_msg = rpci->ops->destroy_msg;
- while (!list_empty(head)) {
+ if (list_empty(head))
+ return;
+ do {
msg = list_entry(head->next, struct rpc_pipe_msg, list);
- list_del_init(&msg->list);
+ list_del(&msg->list);
msg->errno = err;
destroy_msg(msg);
- }
-}
-
-static void
-__rpc_purge_upcall(struct inode *inode, int err)
-{
- struct rpc_inode *rpci = RPC_I(inode);
-
- __rpc_purge_list(rpci, &rpci->pipe, err);
- rpci->pipelen = 0;
+ } while (!list_empty(head));
wake_up(&rpci->waitq);
}
static void
rpc_timeout_upcall_queue(void *data)
{
+ LIST_HEAD(free_list);
struct rpc_inode *rpci = (struct rpc_inode *)data;
struct inode *inode = &rpci->vfs_inode;
+ void (*destroy_msg)(struct rpc_pipe_msg *);
- mutex_lock(&inode->i_mutex);
- if (rpci->ops == NULL)
- goto out;
- if (rpci->nreaders == 0 && !list_empty(&rpci->pipe))
- __rpc_purge_upcall(inode, -ETIMEDOUT);
-out:
- mutex_unlock(&inode->i_mutex);
+ spin_lock(&inode->i_lock);
+ if (rpci->ops == NULL) {
+ spin_unlock(&inode->i_lock);
+ return;
+ }
+ destroy_msg = rpci->ops->destroy_msg;
+ if (rpci->nreaders == 0) {
+ list_splice_init(&rpci->pipe, &free_list);
+ rpci->pipelen = 0;
+ }
+ spin_unlock(&inode->i_lock);
+ rpc_purge_list(rpci, &free_list, destroy_msg, -ETIMEDOUT);
}
int
@@ -84,7 +82,7 @@ rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg)
struct rpc_inode *rpci = RPC_I(inode);
int res = -EPIPE;
- mutex_lock(&inode->i_mutex);
+ spin_lock(&inode->i_lock);
if (rpci->ops == NULL)
goto out;
if (rpci->nreaders) {
@@ -100,7 +98,7 @@ rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg)
res = 0;
}
out:
- mutex_unlock(&inode->i_mutex);
+ spin_unlock(&inode->i_lock);
wake_up(&rpci->waitq);
return res;
}
@@ -115,21 +113,29 @@ static void
rpc_close_pipes(struct inode *inode)
{
struct rpc_inode *rpci = RPC_I(inode);
+ struct rpc_pipe_ops *ops;
mutex_lock(&inode->i_mutex);
- if (rpci->ops != NULL) {
+ ops = rpci->ops;
+ if (ops != NULL) {
+ LIST_HEAD(free_list);
+
+ spin_lock(&inode->i_lock);
rpci->nreaders = 0;
- __rpc_purge_list(rpci, &rpci->in_upcall, -EPIPE);
- __rpc_purge_upcall(inode, -EPIPE);
- rpci->nwriters = 0;
- if (rpci->ops->release_pipe)
- rpci->ops->release_pipe(inode);
+ list_splice_init(&rpci->in_upcall, &free_list);
+ list_splice_init(&rpci->pipe, &free_list);
+ rpci->pipelen = 0;
rpci->ops = NULL;
+ spin_unlock(&inode->i_lock);
+ rpc_purge_list(rpci, &free_list, ops->destroy_msg, -EPIPE);
+ rpci->nwriters = 0;
+ if (ops->release_pipe)
+ ops->release_pipe(inode);
+ cancel_delayed_work(&rpci->queue_timeout);
+ flush_scheduled_work();
}
rpc_inode_setowner(inode, NULL);
mutex_unlock(&inode->i_mutex);
- cancel_delayed_work(&rpci->queue_timeout);
- flush_scheduled_work();
}
static struct inode *
@@ -177,16 +183,26 @@ rpc_pipe_release(struct inode *inode, struct file *filp)
goto out;
msg = (struct rpc_pipe_msg *)filp->private_data;
if (msg != NULL) {
+ spin_lock(&inode->i_lock);
msg->errno = -EAGAIN;
- list_del_init(&msg->list);
+ list_del(&msg->list);
+ spin_unlock(&inode->i_lock);
rpci->ops->destroy_msg(msg);
}
if (filp->f_mode & FMODE_WRITE)
rpci->nwriters --;
- if (filp->f_mode & FMODE_READ)
+ if (filp->f_mode & FMODE_READ) {
rpci->nreaders --;
- if (!rpci->nreaders)
- __rpc_purge_upcall(inode, -EAGAIN);
+ if (rpci->nreaders == 0) {
+ LIST_HEAD(free_list);
+ spin_lock(&inode->i_lock);
+ list_splice_init(&rpci->pipe, &free_list);
+ rpci->pipelen = 0;
+ spin_unlock(&inode->i_lock);
+ rpc_purge_list(rpci, &free_list,
+ rpci->ops->destroy_msg, -EAGAIN);
+ }
+ }
if (rpci->ops->release_pipe)
rpci->ops->release_pipe(inode);
out:
@@ -209,6 +225,7 @@ rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset)
}
msg = filp->private_data;
if (msg == NULL) {
+ spin_lock(&inode->i_lock);
if (!list_empty(&rpci->pipe)) {
msg = list_entry(rpci->pipe.next,
struct rpc_pipe_msg,
@@ -218,6 +235,7 @@ rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset)
filp->private_data = msg;
msg->copied = 0;
}
+ spin_unlock(&inode->i_lock);
if (msg == NULL)
goto out_unlock;
}
@@ -225,7 +243,9 @@ rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset)
res = rpci->ops->upcall(filp, msg, buf, len);
if (res < 0 || msg->len == msg->copied) {
filp->private_data = NULL;
- list_del_init(&msg->list);
+ spin_lock(&inode->i_lock);
+ list_del(&msg->list);
+ spin_unlock(&inode->i_lock);
rpci->ops->destroy_msg(msg);
}
out_unlock:
@@ -610,7 +630,7 @@ rpc_lookup_negative(char *path, struct nameidata *nd)
return ERR_PTR(error);
dir = nd->dentry->d_inode;
mutex_lock(&dir->i_mutex);
- dentry = lookup_hash(nd);
+ dentry = lookup_one_len(nd->last.name, nd->dentry, nd->last.len);
if (IS_ERR(dentry))
goto out_err;
if (dentry->d_inode) {
@@ -672,7 +692,7 @@ rpc_rmdir(char *path)
return error;
dir = nd.dentry->d_inode;
mutex_lock(&dir->i_mutex);
- dentry = lookup_hash(&nd);
+ dentry = lookup_one_len(nd.last.name, nd.dentry, nd.last.len);
if (IS_ERR(dentry)) {
error = PTR_ERR(dentry);
goto out_release;
@@ -733,7 +753,7 @@ rpc_unlink(char *path)
return error;
dir = nd.dentry->d_inode;
mutex_lock(&dir->i_mutex);
- dentry = lookup_hash(&nd);
+ dentry = lookup_one_len(nd.last.name, nd.dentry, nd.last.len);
if (IS_ERR(dentry)) {
error = PTR_ERR(dentry);
goto out_release;
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index 7415406aa1ae..802d4fe0f55c 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -908,10 +908,10 @@ void rpc_release_task(struct rpc_task *task)
/**
* rpc_run_task - Allocate a new RPC task, then run rpc_execute against it
- * @clnt - pointer to RPC client
- * @flags - RPC flags
- * @ops - RPC call ops
- * @data - user call data
+ * @clnt: pointer to RPC client
+ * @flags: RPC flags
+ * @ops: RPC call ops
+ * @data: user call data
*/
struct rpc_task *rpc_run_task(struct rpc_clnt *clnt, int flags,
const struct rpc_call_ops *ops,
@@ -930,6 +930,7 @@ EXPORT_SYMBOL(rpc_run_task);
/**
* rpc_find_parent - find the parent of a child task.
* @child: child task
+ * @parent: parent task
*
* Checks that the parent task is still sleeping on the
* queue 'childq'. If so returns a pointer to the parent.