summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-04-05 14:04:10 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2013-04-05 14:04:10 -0700
commit53f63189b1110559dce8c1ee29e8abc3e31f7630 (patch)
tree5f9850243be2ab26d4ad3ad6829eaa93d90f188f
parent6cfa92382e5f11be0bdb5ced62ed249004708f6c (diff)
parent124dff01afbdbff251f0385beca84ba1b9adda68 (diff)
downloadlinux-3.10-53f63189b1110559dce8c1ee29e8abc3e31f7630.tar.gz
linux-3.10-53f63189b1110559dce8c1ee29e8abc3e31f7630.tar.bz2
linux-3.10-53f63189b1110559dce8c1ee29e8abc3e31f7630.zip
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Pull networking fixes from David Miller: 1) Fix erroneous sock_orphan() leading to crashes and double kfree_skb() in NFC protocol. From Thierry Escande and Samuel Ortiz. 2) Fix use after free in remain-on-channel mac80211 code, from Johannes Berg. 3) nf_reset() needs to reset the NF tracing cookie, otherwise we can leak it from one namespace into another. Fix from Gao Feng and Patrick McHardy. 4) Fix overflow in channel scanning array of mwifiex driver, from Stone Piao. 5) Fix loss of link after suspend/shutdown in r8169, from Hayes Wang. 6) Synchronization of unicast address lists to the undelying device doesn't work because whether to sync is maintained as a boolean rather than a true count. Fix from Vlad Yasevich. 7) Fix corruption of TSO packets in atl1e by limiting the segmented packet length. From Hannes Frederic Sowa. 8) Revert bogus AF_UNIX credential passing change and fix the coalescing issue properly, from Eric W Biederman. 9) Changes of ipv4 address lifetime settings needs to generate a notification, from Jiri Pirko. * git://git.kernel.org/pub/scm/linux/kernel/git/davem/net: (22 commits) netfilter: don't reset nf_trace in nf_reset() net: ipv4: notify when address lifetime changes ixgbe: fix registration order of driver and DCA nofitication af_unix: If we don't care about credentials coallesce all messages Revert "af_unix: dont send SCM_CREDENTIAL when dest socket is NULL" bonding: remove sysfs before removing devices atl1e: limit gso segment size to prevent generation of wrong ip length fields net: count hw_addr syncs so that unsync works properly. r8169: fix auto speed down issue netfilter: ip6t_NPT: Fix translation for non-multiple of 32 prefix lengths mwifiex: limit channel number not to overflow memory NFC: microread: Fix build failure due to a new MEI bus API iwlwifi: dvm: fix the passive-no-RX workaround netfilter: nf_conntrack: fix error return code NFC: llcp: Keep the connected socket parent pointer alive mac80211: fix idle handling sequence netfilter: nfnetlink_acct: return -EINVAL if object name is empty netfilter: nfnetlink_queue: fix error return code in nfnetlink_queue_init() netfilter: reset nf_trace in nf_reset mac80211: fix remain-on-channel cancel crash ...
-rw-r--r--drivers/net/bonding/bond_main.c2
-rw-r--r--drivers/net/ethernet/atheros/atl1e/atl1e.h2
-rw-r--r--drivers/net/ethernet/atheros/atl1e/atl1e_main.c1
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_main.c11
-rw-r--r--drivers/net/ethernet/realtek/r8169.c28
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/rxon.c18
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/tx.c2
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.c3
-rw-r--r--drivers/nfc/microread/mei.c38
-rw-r--r--include/linux/netdevice.h2
-rw-r--r--include/linux/skbuff.h7
-rw-r--r--net/core/dev.c1
-rw-r--r--net/core/dev_addr_lists.c6
-rw-r--r--net/ipv4/devinet.c6
-rw-r--r--net/ipv6/netfilter/ip6t_NPT.c2
-rw-r--r--net/mac80211/cfg.c6
-rw-r--r--net/mac80211/chan.c17
-rw-r--r--net/mac80211/ieee80211_i.h4
-rw-r--r--net/mac80211/iface.c2
-rw-r--r--net/mac80211/offchannel.c23
-rw-r--r--net/netfilter/nf_conntrack_standalone.c1
-rw-r--r--net/netfilter/nfnetlink_acct.c2
-rw-r--r--net/netfilter/nfnetlink_queue_core.c4
-rw-r--r--net/nfc/llcp/llcp.c8
-rw-r--r--net/nfc/llcp/sock.c6
-rw-r--r--net/unix/af_unix.c6
26 files changed, 133 insertions, 75 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index a51241b2e62..171b10f167a 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -4902,8 +4902,8 @@ static void __exit bonding_exit(void)
bond_destroy_debugfs();
- rtnl_link_unregister(&bond_link_ops);
unregister_pernet_subsys(&bond_net_ops);
+ rtnl_link_unregister(&bond_link_ops);
#ifdef CONFIG_NET_POLL_CONTROLLER
/*
diff --git a/drivers/net/ethernet/atheros/atl1e/atl1e.h b/drivers/net/ethernet/atheros/atl1e/atl1e.h
index edfdf6b950e..b5fd934585e 100644
--- a/drivers/net/ethernet/atheros/atl1e/atl1e.h
+++ b/drivers/net/ethernet/atheros/atl1e/atl1e.h
@@ -186,7 +186,7 @@ struct atl1e_tpd_desc {
/* how about 0x2000 */
#define MAX_TX_BUF_LEN 0x2000
#define MAX_TX_BUF_SHIFT 13
-/*#define MAX_TX_BUF_LEN 0x3000 */
+#define MAX_TSO_SEG_SIZE 0x3c00
/* rrs word 1 bit 0:31 */
#define RRS_RX_CSUM_MASK 0xFFFF
diff --git a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
index f73d5609439..ac25f05ff68 100644
--- a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
+++ b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
@@ -2329,6 +2329,7 @@ static int atl1e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
INIT_WORK(&adapter->reset_task, atl1e_reset_task);
INIT_WORK(&adapter->link_chg_task, atl1e_link_chg_task);
+ netif_set_gso_max_size(netdev, MAX_TSO_SEG_SIZE);
err = register_netdev(netdev);
if (err) {
netdev_err(netdev, "register netdevice failed\n");
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index db5611ae407..79f4a26ea6c 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -7922,12 +7922,19 @@ static int __init ixgbe_init_module(void)
ixgbe_dbg_init();
#endif /* CONFIG_DEBUG_FS */
+ ret = pci_register_driver(&ixgbe_driver);
+ if (ret) {
+#ifdef CONFIG_DEBUG_FS
+ ixgbe_dbg_exit();
+#endif /* CONFIG_DEBUG_FS */
+ return ret;
+ }
+
#ifdef CONFIG_IXGBE_DCA
dca_register_notify(&dca_notifier);
#endif
- ret = pci_register_driver(&ixgbe_driver);
- return ret;
+ return 0;
}
module_init(ixgbe_init_module);
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 28fb50a1e9c..4ecbe64a758 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -3818,6 +3818,30 @@ static void rtl_init_mdio_ops(struct rtl8169_private *tp)
}
}
+static void rtl_speed_down(struct rtl8169_private *tp)
+{
+ u32 adv;
+ int lpa;
+
+ rtl_writephy(tp, 0x1f, 0x0000);
+ lpa = rtl_readphy(tp, MII_LPA);
+
+ if (lpa & (LPA_10HALF | LPA_10FULL))
+ adv = ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full;
+ else if (lpa & (LPA_100HALF | LPA_100FULL))
+ adv = ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full;
+ else
+ adv = ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full |
+ (tp->mii.supports_gmii ?
+ ADVERTISED_1000baseT_Half |
+ ADVERTISED_1000baseT_Full : 0);
+
+ rtl8169_set_speed(tp->dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL,
+ adv);
+}
+
static void rtl_wol_suspend_quirk(struct rtl8169_private *tp)
{
void __iomem *ioaddr = tp->mmio_addr;
@@ -3848,9 +3872,7 @@ static bool rtl_wol_pll_power_down(struct rtl8169_private *tp)
if (!(__rtl8169_get_wol(tp) & WAKE_ANY))
return false;
- rtl_writephy(tp, 0x1f, 0x0000);
- rtl_writephy(tp, MII_BMCR, 0x0000);
-
+ rtl_speed_down(tp);
rtl_wol_suspend_quirk(tp);
return true;
diff --git a/drivers/net/wireless/iwlwifi/dvm/rxon.c b/drivers/net/wireless/iwlwifi/dvm/rxon.c
index 23be948cf16..a82b6b39d4f 100644
--- a/drivers/net/wireless/iwlwifi/dvm/rxon.c
+++ b/drivers/net/wireless/iwlwifi/dvm/rxon.c
@@ -1419,6 +1419,14 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
mutex_lock(&priv->mutex);
+ if (changes & BSS_CHANGED_IDLE && bss_conf->idle) {
+ /*
+ * If we go idle, then clearly no "passive-no-rx"
+ * workaround is needed any more, this is a reset.
+ */
+ iwlagn_lift_passive_no_rx(priv);
+ }
+
if (unlikely(!iwl_is_ready(priv))) {
IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
mutex_unlock(&priv->mutex);
@@ -1450,16 +1458,6 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
priv->timestamp = bss_conf->sync_tsf;
ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
} else {
- /*
- * If we disassociate while there are pending
- * frames, just wake up the queues and let the
- * frames "escape" ... This shouldn't really
- * be happening to start with, but we should
- * not get stuck in this case either since it
- * can happen if userspace gets confused.
- */
- iwlagn_lift_passive_no_rx(priv);
-
ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
if (ctx->ctxid == IWL_RXON_CTX_BSS)
diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c
index 6aec2df3bb2..d1a670d7b10 100644
--- a/drivers/net/wireless/iwlwifi/dvm/tx.c
+++ b/drivers/net/wireless/iwlwifi/dvm/tx.c
@@ -1192,7 +1192,7 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
memset(&info->status, 0, sizeof(info->status));
if (status == TX_STATUS_FAIL_PASSIVE_NO_RX &&
- iwl_is_associated_ctx(ctx) && ctx->vif &&
+ ctx->vif &&
ctx->vif->type == NL80211_IFTYPE_STATION) {
/* block and stop all queues */
priv->passive_no_rx = true;
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index a44023a7bd5..8aaf56ade4d 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -1892,7 +1892,8 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
}
}
- for (i = 0; i < request->n_channels; i++) {
+ for (i = 0; i < min_t(u32, request->n_channels,
+ MWIFIEX_USER_SCAN_CHAN_MAX); i++) {
chan = request->channels[i];
priv->user_scan_cfg->chan_list[i].chan_number = chan->hw_value;
priv->user_scan_cfg->chan_list[i].radio_type = chan->band;
diff --git a/drivers/nfc/microread/mei.c b/drivers/nfc/microread/mei.c
index eef38cfd812..ca33ae19393 100644
--- a/drivers/nfc/microread/mei.c
+++ b/drivers/nfc/microread/mei.c
@@ -22,7 +22,7 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
-#include <linux/mei_bus.h>
+#include <linux/mei_cl_bus.h>
#include <linux/nfc.h>
#include <net/nfc/hci.h>
@@ -32,9 +32,6 @@
#define MICROREAD_DRIVER_NAME "microread"
-#define MICROREAD_UUID UUID_LE(0x0bb17a78, 0x2a8e, 0x4c50, 0x94, \
- 0xd4, 0x50, 0x26, 0x67, 0x23, 0x77, 0x5c)
-
struct mei_nfc_hdr {
u8 cmd;
u8 status;
@@ -48,7 +45,7 @@ struct mei_nfc_hdr {
#define MEI_NFC_MAX_READ (MEI_NFC_HEADER_SIZE + MEI_NFC_MAX_HCI_PAYLOAD)
struct microread_mei_phy {
- struct mei_device *mei_device;
+ struct mei_cl_device *device;
struct nfc_hci_dev *hdev;
int powered;
@@ -105,14 +102,14 @@ static int microread_mei_write(void *phy_id, struct sk_buff *skb)
MEI_DUMP_SKB_OUT("mei frame sent", skb);
- r = mei_send(phy->device, skb->data, skb->len);
+ r = mei_cl_send(phy->device, skb->data, skb->len);
if (r > 0)
r = 0;
return r;
}
-static void microread_event_cb(struct mei_device *device, u32 events,
+static void microread_event_cb(struct mei_cl_device *device, u32 events,
void *context)
{
struct microread_mei_phy *phy = context;
@@ -120,7 +117,7 @@ static void microread_event_cb(struct mei_device *device, u32 events,
if (phy->hard_fault != 0)
return;
- if (events & BIT(MEI_EVENT_RX)) {
+ if (events & BIT(MEI_CL_EVENT_RX)) {
struct sk_buff *skb;
int reply_size;
@@ -128,7 +125,7 @@ static void microread_event_cb(struct mei_device *device, u32 events,
if (!skb)
return;
- reply_size = mei_recv(device, skb->data, MEI_NFC_MAX_READ);
+ reply_size = mei_cl_recv(device, skb->data, MEI_NFC_MAX_READ);
if (reply_size < MEI_NFC_HEADER_SIZE) {
kfree(skb);
return;
@@ -149,8 +146,8 @@ static struct nfc_phy_ops mei_phy_ops = {
.disable = microread_mei_disable,
};
-static int microread_mei_probe(struct mei_device *device,
- const struct mei_id *id)
+static int microread_mei_probe(struct mei_cl_device *device,
+ const struct mei_cl_device_id *id)
{
struct microread_mei_phy *phy;
int r;
@@ -164,9 +161,9 @@ static int microread_mei_probe(struct mei_device *device,
}
phy->device = device;
- mei_set_clientdata(device, phy);
+ mei_cl_set_drvdata(device, phy);
- r = mei_register_event_cb(device, microread_event_cb, phy);
+ r = mei_cl_register_event_cb(device, microread_event_cb, phy);
if (r) {
pr_err(MICROREAD_DRIVER_NAME ": event cb registration failed\n");
goto err_out;
@@ -186,9 +183,9 @@ err_out:
return r;
}
-static int microread_mei_remove(struct mei_device *device)
+static int microread_mei_remove(struct mei_cl_device *device)
{
- struct microread_mei_phy *phy = mei_get_clientdata(device);
+ struct microread_mei_phy *phy = mei_cl_get_drvdata(device);
pr_info("Removing microread\n");
@@ -202,16 +199,15 @@ static int microread_mei_remove(struct mei_device *device)
return 0;
}
-static struct mei_id microread_mei_tbl[] = {
- { MICROREAD_DRIVER_NAME, MICROREAD_UUID },
+static struct mei_cl_device_id microread_mei_tbl[] = {
+ { MICROREAD_DRIVER_NAME },
/* required last entry */
{ }
};
-
MODULE_DEVICE_TABLE(mei, microread_mei_tbl);
-static struct mei_driver microread_driver = {
+static struct mei_cl_driver microread_driver = {
.id_table = microread_mei_tbl,
.name = MICROREAD_DRIVER_NAME,
@@ -225,7 +221,7 @@ static int microread_mei_init(void)
pr_debug(DRIVER_DESC ": %s\n", __func__);
- r = mei_driver_register(&microread_driver);
+ r = mei_cl_driver_register(&microread_driver);
if (r) {
pr_err(MICROREAD_DRIVER_NAME ": driver registration failed\n");
return r;
@@ -236,7 +232,7 @@ static int microread_mei_init(void)
static void microread_mei_exit(void)
{
- mei_driver_unregister(&microread_driver);
+ mei_cl_driver_unregister(&microread_driver);
}
module_init(microread_mei_init);
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 8bfa95600e4..6151e903eef 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -210,9 +210,9 @@ struct netdev_hw_addr {
#define NETDEV_HW_ADDR_T_SLAVE 3
#define NETDEV_HW_ADDR_T_UNICAST 4
#define NETDEV_HW_ADDR_T_MULTICAST 5
- bool synced;
bool global_use;
int refcount;
+ int synced;
struct rcu_head rcu_head;
};
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 441f5bfdab8..b8292d8cc9f 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -2643,6 +2643,13 @@ static inline void nf_reset(struct sk_buff *skb)
#endif
}
+static inline void nf_reset_trace(struct sk_buff *skb)
+{
+#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
+ skb->nf_trace = 0;
+#endif
+}
+
/* Note: This doesn't put any conntrack and bridge info in dst. */
static inline void __nf_copy(struct sk_buff *dst, const struct sk_buff *src)
{
diff --git a/net/core/dev.c b/net/core/dev.c
index 13e6447f039..e7d68ed8aaf 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1639,6 +1639,7 @@ int dev_forward_skb(struct net_device *dev, struct sk_buff *skb)
skb->mark = 0;
secpath_reset(skb);
nf_reset(skb);
+ nf_reset_trace(skb);
return netif_rx(skb);
}
EXPORT_SYMBOL_GPL(dev_forward_skb);
diff --git a/net/core/dev_addr_lists.c b/net/core/dev_addr_lists.c
index bd2eb9d3e36..abdc9e6ef33 100644
--- a/net/core/dev_addr_lists.c
+++ b/net/core/dev_addr_lists.c
@@ -37,7 +37,7 @@ static int __hw_addr_create_ex(struct netdev_hw_addr_list *list,
ha->type = addr_type;
ha->refcount = 1;
ha->global_use = global;
- ha->synced = false;
+ ha->synced = 0;
list_add_tail_rcu(&ha->list, &list->list);
list->count++;
@@ -165,7 +165,7 @@ int __hw_addr_sync(struct netdev_hw_addr_list *to_list,
addr_len, ha->type);
if (err)
break;
- ha->synced = true;
+ ha->synced++;
ha->refcount++;
} else if (ha->refcount == 1) {
__hw_addr_del(to_list, ha->addr, addr_len, ha->type);
@@ -186,7 +186,7 @@ void __hw_addr_unsync(struct netdev_hw_addr_list *to_list,
if (ha->synced) {
__hw_addr_del(to_list, ha->addr,
addr_len, ha->type);
- ha->synced = false;
+ ha->synced--;
__hw_addr_del(from_list, ha->addr,
addr_len, ha->type);
}
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index f678507bc82..96083b7a436 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -802,8 +802,10 @@ static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg
if (nlh->nlmsg_flags & NLM_F_EXCL ||
!(nlh->nlmsg_flags & NLM_F_REPLACE))
return -EEXIST;
-
- set_ifa_lifetime(ifa_existing, valid_lft, prefered_lft);
+ ifa = ifa_existing;
+ set_ifa_lifetime(ifa, valid_lft, prefered_lft);
+ rtmsg_ifa(RTM_NEWADDR, ifa, nlh, NETLINK_CB(skb).portid);
+ blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
}
return 0;
}
diff --git a/net/ipv6/netfilter/ip6t_NPT.c b/net/ipv6/netfilter/ip6t_NPT.c
index 33608c61027..cb631143721 100644
--- a/net/ipv6/netfilter/ip6t_NPT.c
+++ b/net/ipv6/netfilter/ip6t_NPT.c
@@ -57,7 +57,7 @@ static bool ip6t_npt_map_pfx(const struct ip6t_npt_tginfo *npt,
if (pfx_len - i >= 32)
mask = 0;
else
- mask = htonl(~((1 << (pfx_len - i)) - 1));
+ mask = htonl((1 << (i - pfx_len + 32)) - 1);
idx = i / 32;
addr->s6_addr32[idx] &= mask;
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index fb306814576..a6893602f87 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2582,7 +2582,7 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local,
list_del(&dep->list);
mutex_unlock(&local->mtx);
- ieee80211_roc_notify_destroy(dep);
+ ieee80211_roc_notify_destroy(dep, true);
return 0;
}
@@ -2622,7 +2622,7 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local,
ieee80211_start_next_roc(local);
mutex_unlock(&local->mtx);
- ieee80211_roc_notify_destroy(found);
+ ieee80211_roc_notify_destroy(found, true);
} else {
/* work may be pending so use it all the time */
found->abort = true;
@@ -2632,6 +2632,8 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local,
/* work will clean up etc */
flush_delayed_work(&found->work);
+ WARN_ON(!found->to_be_freed);
+ kfree(found);
}
return 0;
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 78c0d90dd64..931be419ab5 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -63,6 +63,7 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
enum ieee80211_chanctx_mode mode)
{
struct ieee80211_chanctx *ctx;
+ u32 changed;
int err;
lockdep_assert_held(&local->chanctx_mtx);
@@ -76,6 +77,13 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
ctx->conf.rx_chains_dynamic = 1;
ctx->mode = mode;
+ /* acquire mutex to prevent idle from changing */
+ mutex_lock(&local->mtx);
+ /* turn idle off *before* setting channel -- some drivers need that */
+ changed = ieee80211_idle_off(local);
+ if (changed)
+ ieee80211_hw_config(local, changed);
+
if (!local->use_chanctx) {
local->_oper_channel_type =
cfg80211_get_chandef_type(chandef);
@@ -85,14 +93,17 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
err = drv_add_chanctx(local, ctx);
if (err) {
kfree(ctx);
- return ERR_PTR(err);
+ ctx = ERR_PTR(err);
+
+ ieee80211_recalc_idle(local);
+ goto out;
}
}
+ /* and keep the mutex held until the new chanctx is on the list */
list_add_rcu(&ctx->list, &local->chanctx_list);
- mutex_lock(&local->mtx);
- ieee80211_recalc_idle(local);
+ out:
mutex_unlock(&local->mtx);
return ctx;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 388580a1bad..5672533a083 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -309,6 +309,7 @@ struct ieee80211_roc_work {
struct ieee80211_channel *chan;
bool started, abort, hw_begun, notified;
+ bool to_be_freed;
unsigned long hw_start_time;
@@ -1347,7 +1348,7 @@ void ieee80211_offchannel_return(struct ieee80211_local *local);
void ieee80211_roc_setup(struct ieee80211_local *local);
void ieee80211_start_next_roc(struct ieee80211_local *local);
void ieee80211_roc_purge(struct ieee80211_sub_if_data *sdata);
-void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc);
+void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc, bool free);
void ieee80211_sw_roc_work(struct work_struct *work);
void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc);
@@ -1361,6 +1362,7 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
enum nl80211_iftype type);
void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata);
void ieee80211_remove_interfaces(struct ieee80211_local *local);
+u32 ieee80211_idle_off(struct ieee80211_local *local);
void ieee80211_recalc_idle(struct ieee80211_local *local);
void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata,
const int offset);
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 3bfe2612c8c..58150f877ec 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -78,7 +78,7 @@ void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_TXPOWER);
}
-static u32 ieee80211_idle_off(struct ieee80211_local *local)
+u32 ieee80211_idle_off(struct ieee80211_local *local)
{
if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE))
return 0;
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c
index cc79b4a2e82..430bd254e49 100644
--- a/net/mac80211/offchannel.c
+++ b/net/mac80211/offchannel.c
@@ -297,10 +297,13 @@ void ieee80211_start_next_roc(struct ieee80211_local *local)
}
}
-void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc)
+void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc, bool free)
{
struct ieee80211_roc_work *dep, *tmp;
+ if (WARN_ON(roc->to_be_freed))
+ return;
+
/* was never transmitted */
if (roc->frame) {
cfg80211_mgmt_tx_status(&roc->sdata->wdev,
@@ -316,9 +319,12 @@ void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc)
GFP_KERNEL);
list_for_each_entry_safe(dep, tmp, &roc->dependents, list)
- ieee80211_roc_notify_destroy(dep);
+ ieee80211_roc_notify_destroy(dep, true);
- kfree(roc);
+ if (free)
+ kfree(roc);
+ else
+ roc->to_be_freed = true;
}
void ieee80211_sw_roc_work(struct work_struct *work)
@@ -331,6 +337,9 @@ void ieee80211_sw_roc_work(struct work_struct *work)
mutex_lock(&local->mtx);
+ if (roc->to_be_freed)
+ goto out_unlock;
+
if (roc->abort)
goto finish;
@@ -370,7 +379,7 @@ void ieee80211_sw_roc_work(struct work_struct *work)
finish:
list_del(&roc->list);
started = roc->started;
- ieee80211_roc_notify_destroy(roc);
+ ieee80211_roc_notify_destroy(roc, !roc->abort);
if (started) {
drv_flush(local, false);
@@ -410,7 +419,7 @@ static void ieee80211_hw_roc_done(struct work_struct *work)
list_del(&roc->list);
- ieee80211_roc_notify_destroy(roc);
+ ieee80211_roc_notify_destroy(roc, true);
/* if there's another roc, start it now */
ieee80211_start_next_roc(local);
@@ -460,12 +469,14 @@ void ieee80211_roc_purge(struct ieee80211_sub_if_data *sdata)
list_for_each_entry_safe(roc, tmp, &tmp_list, list) {
if (local->ops->remain_on_channel) {
list_del(&roc->list);
- ieee80211_roc_notify_destroy(roc);
+ ieee80211_roc_notify_destroy(roc, true);
} else {
ieee80211_queue_delayed_work(&local->hw, &roc->work, 0);
/* work will clean up etc */
flush_delayed_work(&roc->work);
+ WARN_ON(!roc->to_be_freed);
+ kfree(roc);
}
}
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index 6bcce401fd1..fedee394366 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -568,6 +568,7 @@ static int __init nf_conntrack_standalone_init(void)
register_net_sysctl(&init_net, "net", nf_ct_netfilter_table);
if (!nf_ct_netfilter_header) {
pr_err("nf_conntrack: can't register to sysctl.\n");
+ ret = -ENOMEM;
goto out_sysctl;
}
#endif
diff --git a/net/netfilter/nfnetlink_acct.c b/net/netfilter/nfnetlink_acct.c
index 589d686f0b4..dc3fd5d4446 100644
--- a/net/netfilter/nfnetlink_acct.c
+++ b/net/netfilter/nfnetlink_acct.c
@@ -49,6 +49,8 @@ nfnl_acct_new(struct sock *nfnl, struct sk_buff *skb,
return -EINVAL;
acct_name = nla_data(tb[NFACCT_NAME]);
+ if (strlen(acct_name) == 0)
+ return -EINVAL;
list_for_each_entry(nfacct, &nfnl_acct_list, head) {
if (strncmp(nfacct->name, acct_name, NFACCT_NAME_MAX) != 0)
diff --git a/net/netfilter/nfnetlink_queue_core.c b/net/netfilter/nfnetlink_queue_core.c
index 1cb48540f86..42680b2baa1 100644
--- a/net/netfilter/nfnetlink_queue_core.c
+++ b/net/netfilter/nfnetlink_queue_core.c
@@ -1062,8 +1062,10 @@ static int __init nfnetlink_queue_init(void)
#ifdef CONFIG_PROC_FS
if (!proc_create("nfnetlink_queue", 0440,
- proc_net_netfilter, &nfqnl_file_ops))
+ proc_net_netfilter, &nfqnl_file_ops)) {
+ status = -ENOMEM;
goto cleanup_subsys;
+ }
#endif
register_netdevice_notifier(&nfqnl_dev_notifier);
diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c
index b530afadd76..ee25f25f0cd 100644
--- a/net/nfc/llcp/llcp.c
+++ b/net/nfc/llcp/llcp.c
@@ -107,8 +107,6 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen,
accept_sk->sk_state_change(sk);
bh_unlock_sock(accept_sk);
-
- sock_orphan(accept_sk);
}
if (listen == true) {
@@ -134,8 +132,6 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen,
bh_unlock_sock(sk);
- sock_orphan(sk);
-
sk_del_node_init(sk);
}
@@ -164,8 +160,6 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen,
bh_unlock_sock(sk);
- sock_orphan(sk);
-
sk_del_node_init(sk);
}
@@ -827,7 +821,6 @@ static void nfc_llcp_recv_ui(struct nfc_llcp_local *local,
skb_get(skb);
} else {
pr_err("Receive queue is full\n");
- kfree_skb(skb);
}
nfc_llcp_sock_put(llcp_sock);
@@ -1028,7 +1021,6 @@ static void nfc_llcp_recv_hdlc(struct nfc_llcp_local *local,
skb_get(skb);
} else {
pr_err("Receive queue is full\n");
- kfree_skb(skb);
}
}
diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c
index 5c7cdf3f2a8..8f025746f33 100644
--- a/net/nfc/llcp/sock.c
+++ b/net/nfc/llcp/sock.c
@@ -270,7 +270,9 @@ struct sock *nfc_llcp_accept_dequeue(struct sock *parent,
}
if (sk->sk_state == LLCP_CONNECTED || !newsock) {
- nfc_llcp_accept_unlink(sk);
+ list_del_init(&lsk->accept_queue);
+ sock_put(sk);
+
if (newsock)
sock_graft(sk, newsock);
@@ -464,8 +466,6 @@ static int llcp_sock_release(struct socket *sock)
nfc_llcp_accept_unlink(accept_sk);
release_sock(accept_sk);
-
- sock_orphan(accept_sk);
}
}
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 971282b6f6a..2db702d82e7 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1412,8 +1412,8 @@ static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock,
if (UNIXCB(skb).cred)
return;
if (test_bit(SOCK_PASSCRED, &sock->flags) ||
- (other->sk_socket &&
- test_bit(SOCK_PASSCRED, &other->sk_socket->flags))) {
+ !other->sk_socket ||
+ test_bit(SOCK_PASSCRED, &other->sk_socket->flags)) {
UNIXCB(skb).pid = get_pid(task_tgid(current));
UNIXCB(skb).cred = get_current_cred();
}
@@ -1993,7 +1993,7 @@ again:
if ((UNIXCB(skb).pid != siocb->scm->pid) ||
(UNIXCB(skb).cred != siocb->scm->cred))
break;
- } else {
+ } else if (test_bit(SOCK_PASSCRED, &sock->flags)) {
/* Copy credentials */
scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).cred);
check_creds = 1;