mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-29 23:53:32 +00:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Pull networking fixes from David Miller: 1) Out of bounds array access in 802.11 minstrel code, from Adrien Schildknecht. 2) Don't use skb_get() in IGMP/MLD code paths, as this makes pskb_may_pull() BUG. From Linus Luessing. 3) Fix off by one in ipv4 route dumping code, from Andy Whitcroft. 4) Fix deadlock in reqsk_queue_unlink(), from Eric Dumazet. 5) Fix ppp device deregistration wrt. netns deletion, from Guillaume Nault. 6) Fix deadlock when creating per-cpu ipv6 routes, from Martin KaFai Lau. 7) Fix memory leak in batman-adv code, from Sven Eckelmann. * git://git.kernel.org/pub/scm/linux/kernel/git/davem/net: batman-adv: Fix memory leak on tt add with invalid vlan net: phy: fix semicolon.cocci warnings net: qmi_wwan: add HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module be2net: avoid vxlan offloading on multichannel configs ipv6: Fix a potential deadlock when creating pcpu rt ipv6: Add rt6_make_pcpu_route() ipv6: Remove un-used argument from ip6_dst_alloc() net: phy: workaround for buggy cable detection by LAN8700 after cable plugging net: ethernet: micrel: fix an error code ppp: fix device unregistration upon netns deletion net: phy: fix PHY_RUNNING in phy_state_machine Revert "net: limit tcp/udp rmem/wmem to SOCK_{RCV,SND}BUF_MIN" inet: fix potential deadlock in reqsk_queue_unlink() gianfar: Restore link state settings after MAC reset ipv4: off-by-one in continuation handling in /proc/net/route net: fix wrong skb_get() usage / crash in IGMP/MLD parsing code mac80211: fix invalid read in minstrel_sort_best_tp_rates()
This commit is contained in:
commit
28e55d0723
18 changed files with 212 additions and 146 deletions
|
@ -5174,7 +5174,7 @@ static void be_add_vxlan_port(struct net_device *netdev, sa_family_t sa_family,
|
|||
struct device *dev = &adapter->pdev->dev;
|
||||
int status;
|
||||
|
||||
if (lancer_chip(adapter) || BEx_chip(adapter))
|
||||
if (lancer_chip(adapter) || BEx_chip(adapter) || be_is_mc(adapter))
|
||||
return;
|
||||
|
||||
if (adapter->flags & BE_FLAGS_VXLAN_OFFLOADS) {
|
||||
|
@ -5221,7 +5221,7 @@ static void be_del_vxlan_port(struct net_device *netdev, sa_family_t sa_family,
|
|||
{
|
||||
struct be_adapter *adapter = netdev_priv(netdev);
|
||||
|
||||
if (lancer_chip(adapter) || BEx_chip(adapter))
|
||||
if (lancer_chip(adapter) || BEx_chip(adapter) || be_is_mc(adapter))
|
||||
return;
|
||||
|
||||
if (adapter->vxlan_port != port)
|
||||
|
|
|
@ -2102,6 +2102,11 @@ int startup_gfar(struct net_device *ndev)
|
|||
/* Start Rx/Tx DMA and enable the interrupts */
|
||||
gfar_start(priv);
|
||||
|
||||
/* force link state update after mac reset */
|
||||
priv->oldlink = 0;
|
||||
priv->oldspeed = 0;
|
||||
priv->oldduplex = -1;
|
||||
|
||||
phy_start(priv->phydev);
|
||||
|
||||
enable_napi(priv);
|
||||
|
|
|
@ -952,9 +952,8 @@ static int ks8842_alloc_dma_bufs(struct net_device *netdev)
|
|||
|
||||
sg_dma_address(&tx_ctl->sg) = dma_map_single(adapter->dev,
|
||||
tx_ctl->buf, DMA_BUFFER_SIZE, DMA_TO_DEVICE);
|
||||
err = dma_mapping_error(adapter->dev,
|
||||
sg_dma_address(&tx_ctl->sg));
|
||||
if (err) {
|
||||
if (dma_mapping_error(adapter->dev, sg_dma_address(&tx_ctl->sg))) {
|
||||
err = -ENOMEM;
|
||||
sg_dma_address(&tx_ctl->sg) = 0;
|
||||
goto err;
|
||||
}
|
||||
|
|
|
@ -811,6 +811,7 @@ void phy_state_machine(struct work_struct *work)
|
|||
bool needs_aneg = false, do_suspend = false;
|
||||
enum phy_state old_state;
|
||||
int err = 0;
|
||||
int old_link;
|
||||
|
||||
mutex_lock(&phydev->lock);
|
||||
|
||||
|
@ -896,11 +897,18 @@ void phy_state_machine(struct work_struct *work)
|
|||
phydev->adjust_link(phydev->attached_dev);
|
||||
break;
|
||||
case PHY_RUNNING:
|
||||
/* Only register a CHANGE if we are
|
||||
* polling or ignoring interrupts
|
||||
/* Only register a CHANGE if we are polling or ignoring
|
||||
* interrupts and link changed since latest checking.
|
||||
*/
|
||||
if (!phy_interrupt_is_valid(phydev))
|
||||
phydev->state = PHY_CHANGELINK;
|
||||
if (!phy_interrupt_is_valid(phydev)) {
|
||||
old_link = phydev->link;
|
||||
err = phy_read_status(phydev);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
if (old_link != phydev->link)
|
||||
phydev->state = PHY_CHANGELINK;
|
||||
}
|
||||
break;
|
||||
case PHY_CHANGELINK:
|
||||
err = phy_read_status(phydev);
|
||||
|
|
|
@ -91,19 +91,18 @@ static int lan911x_config_init(struct phy_device *phydev)
|
|||
}
|
||||
|
||||
/*
|
||||
* The LAN8710/LAN8720 requires a minimum of 2 link pulses within 64ms of each
|
||||
* other in order to set the ENERGYON bit and exit EDPD mode. If a link partner
|
||||
* does send the pulses within this interval, the PHY will remained powered
|
||||
* down.
|
||||
*
|
||||
* This workaround will manually toggle the PHY on/off upon calls to read_status
|
||||
* in order to generate link test pulses if the link is down. If a link partner
|
||||
* is present, it will respond to the pulses, which will cause the ENERGYON bit
|
||||
* to be set and will cause the EDPD mode to be exited.
|
||||
* The LAN87xx suffers from rare absence of the ENERGYON-bit when Ethernet cable
|
||||
* plugs in while LAN87xx is in Energy Detect Power-Down mode. This leads to
|
||||
* unstable detection of plugging in Ethernet cable.
|
||||
* This workaround disables Energy Detect Power-Down mode and waiting for
|
||||
* response on link pulses to detect presence of plugged Ethernet cable.
|
||||
* The Energy Detect Power-Down mode is enabled again in the end of procedure to
|
||||
* save approximately 220 mW of power if cable is unplugged.
|
||||
*/
|
||||
static int lan87xx_read_status(struct phy_device *phydev)
|
||||
{
|
||||
int err = genphy_read_status(phydev);
|
||||
int i;
|
||||
|
||||
if (!phydev->link) {
|
||||
/* Disable EDPD to wake up PHY */
|
||||
|
@ -116,8 +115,16 @@ static int lan87xx_read_status(struct phy_device *phydev)
|
|||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* Sleep 64 ms to allow ~5 link test pulses to be sent */
|
||||
msleep(64);
|
||||
/* Wait max 640 ms to detect energy */
|
||||
for (i = 0; i < 64; i++) {
|
||||
/* Sleep to allow link test pulses to be sent */
|
||||
msleep(10);
|
||||
rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
if (rc & MII_LAN83C185_ENERGYON)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Re-enable EDPD */
|
||||
rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
|
||||
|
@ -191,7 +198,7 @@ static struct phy_driver smsc_phy_driver[] = {
|
|||
|
||||
/* basic functions */
|
||||
.config_aneg = genphy_config_aneg,
|
||||
.read_status = genphy_read_status,
|
||||
.read_status = lan87xx_read_status,
|
||||
.config_init = smsc_phy_config_init,
|
||||
.soft_reset = smsc_phy_reset,
|
||||
|
||||
|
|
|
@ -269,9 +269,9 @@ static void ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound);
|
|||
static void ppp_ccp_closed(struct ppp *ppp);
|
||||
static struct compressor *find_compressor(int type);
|
||||
static void ppp_get_stats(struct ppp *ppp, struct ppp_stats *st);
|
||||
static struct ppp *ppp_create_interface(struct net *net, int unit, int *retp);
|
||||
static struct ppp *ppp_create_interface(struct net *net, int unit,
|
||||
struct file *file, int *retp);
|
||||
static void init_ppp_file(struct ppp_file *pf, int kind);
|
||||
static void ppp_shutdown_interface(struct ppp *ppp);
|
||||
static void ppp_destroy_interface(struct ppp *ppp);
|
||||
static struct ppp *ppp_find_unit(struct ppp_net *pn, int unit);
|
||||
static struct channel *ppp_find_channel(struct ppp_net *pn, int unit);
|
||||
|
@ -392,8 +392,10 @@ static int ppp_release(struct inode *unused, struct file *file)
|
|||
file->private_data = NULL;
|
||||
if (pf->kind == INTERFACE) {
|
||||
ppp = PF_TO_PPP(pf);
|
||||
rtnl_lock();
|
||||
if (file == ppp->owner)
|
||||
ppp_shutdown_interface(ppp);
|
||||
unregister_netdevice(ppp->dev);
|
||||
rtnl_unlock();
|
||||
}
|
||||
if (atomic_dec_and_test(&pf->refcnt)) {
|
||||
switch (pf->kind) {
|
||||
|
@ -593,8 +595,10 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||
mutex_lock(&ppp_mutex);
|
||||
if (pf->kind == INTERFACE) {
|
||||
ppp = PF_TO_PPP(pf);
|
||||
rtnl_lock();
|
||||
if (file == ppp->owner)
|
||||
ppp_shutdown_interface(ppp);
|
||||
unregister_netdevice(ppp->dev);
|
||||
rtnl_unlock();
|
||||
}
|
||||
if (atomic_long_read(&file->f_count) < 2) {
|
||||
ppp_release(NULL, file);
|
||||
|
@ -838,11 +842,10 @@ static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf,
|
|||
/* Create a new ppp unit */
|
||||
if (get_user(unit, p))
|
||||
break;
|
||||
ppp = ppp_create_interface(net, unit, &err);
|
||||
ppp = ppp_create_interface(net, unit, file, &err);
|
||||
if (!ppp)
|
||||
break;
|
||||
file->private_data = &ppp->file;
|
||||
ppp->owner = file;
|
||||
err = -EFAULT;
|
||||
if (put_user(ppp->file.index, p))
|
||||
break;
|
||||
|
@ -916,6 +919,16 @@ static __net_init int ppp_init_net(struct net *net)
|
|||
static __net_exit void ppp_exit_net(struct net *net)
|
||||
{
|
||||
struct ppp_net *pn = net_generic(net, ppp_net_id);
|
||||
struct ppp *ppp;
|
||||
LIST_HEAD(list);
|
||||
int id;
|
||||
|
||||
rtnl_lock();
|
||||
idr_for_each_entry(&pn->units_idr, ppp, id)
|
||||
unregister_netdevice_queue(ppp->dev, &list);
|
||||
|
||||
unregister_netdevice_many(&list);
|
||||
rtnl_unlock();
|
||||
|
||||
idr_destroy(&pn->units_idr);
|
||||
}
|
||||
|
@ -1088,8 +1101,28 @@ static int ppp_dev_init(struct net_device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void ppp_dev_uninit(struct net_device *dev)
|
||||
{
|
||||
struct ppp *ppp = netdev_priv(dev);
|
||||
struct ppp_net *pn = ppp_pernet(ppp->ppp_net);
|
||||
|
||||
ppp_lock(ppp);
|
||||
ppp->closing = 1;
|
||||
ppp_unlock(ppp);
|
||||
|
||||
mutex_lock(&pn->all_ppp_mutex);
|
||||
unit_put(&pn->units_idr, ppp->file.index);
|
||||
mutex_unlock(&pn->all_ppp_mutex);
|
||||
|
||||
ppp->owner = NULL;
|
||||
|
||||
ppp->file.dead = 1;
|
||||
wake_up_interruptible(&ppp->file.rwait);
|
||||
}
|
||||
|
||||
static const struct net_device_ops ppp_netdev_ops = {
|
||||
.ndo_init = ppp_dev_init,
|
||||
.ndo_uninit = ppp_dev_uninit,
|
||||
.ndo_start_xmit = ppp_start_xmit,
|
||||
.ndo_do_ioctl = ppp_net_ioctl,
|
||||
.ndo_get_stats64 = ppp_get_stats64,
|
||||
|
@ -2667,8 +2700,8 @@ ppp_get_stats(struct ppp *ppp, struct ppp_stats *st)
|
|||
* or if there is already a unit with the requested number.
|
||||
* unit == -1 means allocate a new number.
|
||||
*/
|
||||
static struct ppp *
|
||||
ppp_create_interface(struct net *net, int unit, int *retp)
|
||||
static struct ppp *ppp_create_interface(struct net *net, int unit,
|
||||
struct file *file, int *retp)
|
||||
{
|
||||
struct ppp *ppp;
|
||||
struct ppp_net *pn;
|
||||
|
@ -2688,6 +2721,7 @@ ppp_create_interface(struct net *net, int unit, int *retp)
|
|||
ppp->mru = PPP_MRU;
|
||||
init_ppp_file(&ppp->file, INTERFACE);
|
||||
ppp->file.hdrlen = PPP_HDRLEN - 2; /* don't count proto bytes */
|
||||
ppp->owner = file;
|
||||
for (i = 0; i < NUM_NP; ++i)
|
||||
ppp->npmode[i] = NPMODE_PASS;
|
||||
INIT_LIST_HEAD(&ppp->channels);
|
||||
|
@ -2775,34 +2809,6 @@ init_ppp_file(struct ppp_file *pf, int kind)
|
|||
init_waitqueue_head(&pf->rwait);
|
||||
}
|
||||
|
||||
/*
|
||||
* Take down a ppp interface unit - called when the owning file
|
||||
* (the one that created the unit) is closed or detached.
|
||||
*/
|
||||
static void ppp_shutdown_interface(struct ppp *ppp)
|
||||
{
|
||||
struct ppp_net *pn;
|
||||
|
||||
pn = ppp_pernet(ppp->ppp_net);
|
||||
mutex_lock(&pn->all_ppp_mutex);
|
||||
|
||||
/* This will call dev_close() for us. */
|
||||
ppp_lock(ppp);
|
||||
if (!ppp->closing) {
|
||||
ppp->closing = 1;
|
||||
ppp_unlock(ppp);
|
||||
unregister_netdev(ppp->dev);
|
||||
unit_put(&pn->units_idr, ppp->file.index);
|
||||
} else
|
||||
ppp_unlock(ppp);
|
||||
|
||||
ppp->file.dead = 1;
|
||||
ppp->owner = NULL;
|
||||
wake_up_interruptible(&ppp->file.rwait);
|
||||
|
||||
mutex_unlock(&pn->all_ppp_mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the memory used by a ppp unit. This is only called once
|
||||
* there are no channels connected to the unit and no file structs
|
||||
|
|
|
@ -785,6 +785,7 @@ static const struct usb_device_id products[] = {
|
|||
{QMI_FIXED_INTF(0x413c, 0x81a4, 8)}, /* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card */
|
||||
{QMI_FIXED_INTF(0x413c, 0x81a8, 8)}, /* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card */
|
||||
{QMI_FIXED_INTF(0x413c, 0x81a9, 8)}, /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */
|
||||
{QMI_FIXED_INTF(0x03f0, 0x4e1d, 8)}, /* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */
|
||||
{QMI_FIXED_INTF(0x03f0, 0x581d, 4)}, /* HP lt4112 LTE/HSPA+ Gobi 4G Module (Huawei me906e) */
|
||||
|
||||
/* 4. Gobi 1000 devices */
|
||||
|
|
|
@ -595,8 +595,11 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
|
|||
/* increase the refcounter of the related vlan */
|
||||
vlan = batadv_softif_vlan_get(bat_priv, vid);
|
||||
if (WARN(!vlan, "adding TT local entry %pM to non-existent VLAN %d",
|
||||
addr, BATADV_PRINT_VID(vid)))
|
||||
addr, BATADV_PRINT_VID(vid))) {
|
||||
kfree(tt_local);
|
||||
tt_local = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
batadv_dbg(BATADV_DBG_TT, bat_priv,
|
||||
"Creating new local tt entry: %pM (vid: %d, ttvn: %d)\n",
|
||||
|
|
|
@ -1591,7 +1591,7 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
|
|||
break;
|
||||
}
|
||||
|
||||
if (skb_trimmed)
|
||||
if (skb_trimmed && skb_trimmed != skb)
|
||||
kfree_skb(skb_trimmed);
|
||||
|
||||
return err;
|
||||
|
@ -1636,7 +1636,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
|
|||
break;
|
||||
}
|
||||
|
||||
if (skb_trimmed)
|
||||
if (skb_trimmed && skb_trimmed != skb)
|
||||
kfree_skb(skb_trimmed);
|
||||
|
||||
return err;
|
||||
|
|
|
@ -4022,8 +4022,8 @@ EXPORT_SYMBOL(skb_checksum_setup);
|
|||
* Otherwise returns the provided skb. Returns NULL in error cases
|
||||
* (e.g. transport_len exceeds skb length or out-of-memory).
|
||||
*
|
||||
* Caller needs to set the skb transport header and release the returned skb.
|
||||
* Provided skb is consumed.
|
||||
* Caller needs to set the skb transport header and free any returned skb if it
|
||||
* differs from the provided skb.
|
||||
*/
|
||||
static struct sk_buff *skb_checksum_maybe_trim(struct sk_buff *skb,
|
||||
unsigned int transport_len)
|
||||
|
@ -4032,16 +4032,12 @@ static struct sk_buff *skb_checksum_maybe_trim(struct sk_buff *skb,
|
|||
unsigned int len = skb_transport_offset(skb) + transport_len;
|
||||
int ret;
|
||||
|
||||
if (skb->len < len) {
|
||||
kfree_skb(skb);
|
||||
if (skb->len < len)
|
||||
return NULL;
|
||||
} else if (skb->len == len) {
|
||||
else if (skb->len == len)
|
||||
return skb;
|
||||
}
|
||||
|
||||
skb_chk = skb_clone(skb, GFP_ATOMIC);
|
||||
kfree_skb(skb);
|
||||
|
||||
if (!skb_chk)
|
||||
return NULL;
|
||||
|
||||
|
@ -4066,8 +4062,8 @@ static struct sk_buff *skb_checksum_maybe_trim(struct sk_buff *skb,
|
|||
* If the skb has data beyond the given transport length, then a
|
||||
* trimmed & cloned skb is checked and returned.
|
||||
*
|
||||
* Caller needs to set the skb transport header and release the returned skb.
|
||||
* Provided skb is consumed.
|
||||
* Caller needs to set the skb transport header and free any returned skb if it
|
||||
* differs from the provided skb.
|
||||
*/
|
||||
struct sk_buff *skb_checksum_trimmed(struct sk_buff *skb,
|
||||
unsigned int transport_len,
|
||||
|
@ -4079,23 +4075,26 @@ struct sk_buff *skb_checksum_trimmed(struct sk_buff *skb,
|
|||
|
||||
skb_chk = skb_checksum_maybe_trim(skb, transport_len);
|
||||
if (!skb_chk)
|
||||
return NULL;
|
||||
goto err;
|
||||
|
||||
if (!pskb_may_pull(skb_chk, offset)) {
|
||||
kfree_skb(skb_chk);
|
||||
return NULL;
|
||||
}
|
||||
if (!pskb_may_pull(skb_chk, offset))
|
||||
goto err;
|
||||
|
||||
__skb_pull(skb_chk, offset);
|
||||
ret = skb_chkf(skb_chk);
|
||||
__skb_push(skb_chk, offset);
|
||||
|
||||
if (ret) {
|
||||
kfree_skb(skb_chk);
|
||||
return NULL;
|
||||
}
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
return skb_chk;
|
||||
|
||||
err:
|
||||
if (skb_chk && skb_chk != skb)
|
||||
kfree_skb(skb_chk);
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL(skb_checksum_trimmed);
|
||||
|
||||
|
|
|
@ -2465,7 +2465,7 @@ static struct key_vector *fib_route_get_idx(struct fib_route_iter *iter,
|
|||
key = l->key + 1;
|
||||
iter->pos++;
|
||||
|
||||
if (pos-- <= 0)
|
||||
if (--pos <= 0)
|
||||
break;
|
||||
|
||||
l = NULL;
|
||||
|
|
|
@ -1435,33 +1435,35 @@ static int __ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed)
|
|||
struct sk_buff *skb_chk;
|
||||
unsigned int transport_len;
|
||||
unsigned int len = skb_transport_offset(skb) + sizeof(struct igmphdr);
|
||||
int ret;
|
||||
int ret = -EINVAL;
|
||||
|
||||
transport_len = ntohs(ip_hdr(skb)->tot_len) - ip_hdrlen(skb);
|
||||
|
||||
skb_get(skb);
|
||||
skb_chk = skb_checksum_trimmed(skb, transport_len,
|
||||
ip_mc_validate_checksum);
|
||||
if (!skb_chk)
|
||||
return -EINVAL;
|
||||
goto err;
|
||||
|
||||
if (!pskb_may_pull(skb_chk, len)) {
|
||||
kfree_skb(skb_chk);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!pskb_may_pull(skb_chk, len))
|
||||
goto err;
|
||||
|
||||
ret = ip_mc_check_igmp_msg(skb_chk);
|
||||
if (ret) {
|
||||
kfree_skb(skb_chk);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
if (skb_trimmed)
|
||||
*skb_trimmed = skb_chk;
|
||||
else
|
||||
/* free now unneeded clone */
|
||||
else if (skb_chk != skb)
|
||||
kfree_skb(skb_chk);
|
||||
|
||||
return 0;
|
||||
ret = 0;
|
||||
|
||||
err:
|
||||
if (ret && skb_chk && skb_chk != skb)
|
||||
kfree_skb(skb_chk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1470,7 +1472,7 @@ static int __ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed)
|
|||
* @skb_trimmed: to store an skb pointer trimmed to IPv4 packet tail (optional)
|
||||
*
|
||||
* Checks whether an IPv4 packet is a valid IGMP packet. If so sets
|
||||
* skb network and transport headers accordingly and returns zero.
|
||||
* skb transport header accordingly and returns zero.
|
||||
*
|
||||
* -EINVAL: A broken packet was detected, i.e. it violates some internet
|
||||
* standard
|
||||
|
@ -1485,7 +1487,8 @@ static int __ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed)
|
|||
* to leave the original skb and its full frame unchanged (which might be
|
||||
* desirable for layer 2 frame jugglers).
|
||||
*
|
||||
* The caller needs to release a reference count from any returned skb_trimmed.
|
||||
* Caller needs to set the skb network header and free any returned skb if it
|
||||
* differs from the provided skb.
|
||||
*/
|
||||
int ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed)
|
||||
{
|
||||
|
|
|
@ -593,7 +593,7 @@ static bool reqsk_queue_unlink(struct request_sock_queue *queue,
|
|||
}
|
||||
|
||||
spin_unlock(&queue->syn_wait_lock);
|
||||
if (del_timer_sync(&req->rsk_timer))
|
||||
if (timer_pending(&req->rsk_timer) && del_timer_sync(&req->rsk_timer))
|
||||
reqsk_put(req);
|
||||
return found;
|
||||
}
|
||||
|
|
|
@ -41,8 +41,6 @@ static int tcp_syn_retries_min = 1;
|
|||
static int tcp_syn_retries_max = MAX_TCP_SYNCNT;
|
||||
static int ip_ping_group_range_min[] = { 0, 0 };
|
||||
static int ip_ping_group_range_max[] = { GID_T_MAX, GID_T_MAX };
|
||||
static int min_sndbuf = SOCK_MIN_SNDBUF;
|
||||
static int min_rcvbuf = SOCK_MIN_RCVBUF;
|
||||
|
||||
/* Update system visible IP port range */
|
||||
static void set_local_port_range(struct net *net, int range[2])
|
||||
|
@ -530,7 +528,7 @@ static struct ctl_table ipv4_table[] = {
|
|||
.maxlen = sizeof(sysctl_tcp_wmem),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec_minmax,
|
||||
.extra1 = &min_sndbuf,
|
||||
.extra1 = &one,
|
||||
},
|
||||
{
|
||||
.procname = "tcp_notsent_lowat",
|
||||
|
@ -545,7 +543,7 @@ static struct ctl_table ipv4_table[] = {
|
|||
.maxlen = sizeof(sysctl_tcp_rmem),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec_minmax,
|
||||
.extra1 = &min_rcvbuf,
|
||||
.extra1 = &one,
|
||||
},
|
||||
{
|
||||
.procname = "tcp_app_win",
|
||||
|
@ -758,7 +756,7 @@ static struct ctl_table ipv4_table[] = {
|
|||
.maxlen = sizeof(sysctl_udp_rmem_min),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec_minmax,
|
||||
.extra1 = &min_rcvbuf,
|
||||
.extra1 = &one
|
||||
},
|
||||
{
|
||||
.procname = "udp_wmem_min",
|
||||
|
@ -766,7 +764,7 @@ static struct ctl_table ipv4_table[] = {
|
|||
.maxlen = sizeof(sysctl_udp_wmem_min),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec_minmax,
|
||||
.extra1 = &min_sndbuf,
|
||||
.extra1 = &one
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
|
|
@ -172,6 +172,8 @@ static void rt6_free_pcpu(struct rt6_info *non_pcpu_rt)
|
|||
*ppcpu_rt = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
non_pcpu_rt->rt6i_pcpu = NULL;
|
||||
}
|
||||
|
||||
static void rt6_release(struct rt6_info *rt)
|
||||
|
|
|
@ -143,34 +143,36 @@ static int __ipv6_mc_check_mld(struct sk_buff *skb,
|
|||
struct sk_buff *skb_chk = NULL;
|
||||
unsigned int transport_len;
|
||||
unsigned int len = skb_transport_offset(skb) + sizeof(struct mld_msg);
|
||||
int ret;
|
||||
int ret = -EINVAL;
|
||||
|
||||
transport_len = ntohs(ipv6_hdr(skb)->payload_len);
|
||||
transport_len -= skb_transport_offset(skb) - sizeof(struct ipv6hdr);
|
||||
|
||||
skb_get(skb);
|
||||
skb_chk = skb_checksum_trimmed(skb, transport_len,
|
||||
ipv6_mc_validate_checksum);
|
||||
if (!skb_chk)
|
||||
return -EINVAL;
|
||||
goto err;
|
||||
|
||||
if (!pskb_may_pull(skb_chk, len)) {
|
||||
kfree_skb(skb_chk);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!pskb_may_pull(skb_chk, len))
|
||||
goto err;
|
||||
|
||||
ret = ipv6_mc_check_mld_msg(skb_chk);
|
||||
if (ret) {
|
||||
kfree_skb(skb_chk);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
if (skb_trimmed)
|
||||
*skb_trimmed = skb_chk;
|
||||
else
|
||||
/* free now unneeded clone */
|
||||
else if (skb_chk != skb)
|
||||
kfree_skb(skb_chk);
|
||||
|
||||
return 0;
|
||||
ret = 0;
|
||||
|
||||
err:
|
||||
if (ret && skb_chk && skb_chk != skb)
|
||||
kfree_skb(skb_chk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -179,7 +181,7 @@ static int __ipv6_mc_check_mld(struct sk_buff *skb,
|
|||
* @skb_trimmed: to store an skb pointer trimmed to IPv6 packet tail (optional)
|
||||
*
|
||||
* Checks whether an IPv6 packet is a valid MLD packet. If so sets
|
||||
* skb network and transport headers accordingly and returns zero.
|
||||
* skb transport header accordingly and returns zero.
|
||||
*
|
||||
* -EINVAL: A broken packet was detected, i.e. it violates some internet
|
||||
* standard
|
||||
|
@ -194,7 +196,8 @@ static int __ipv6_mc_check_mld(struct sk_buff *skb,
|
|||
* to leave the original skb and its full frame unchanged (which might be
|
||||
* desirable for layer 2 frame jugglers).
|
||||
*
|
||||
* The caller needs to release a reference count from any returned skb_trimmed.
|
||||
* Caller needs to set the skb network header and free any returned skb if it
|
||||
* differs from the provided skb.
|
||||
*/
|
||||
int ipv6_mc_check_mld(struct sk_buff *skb, struct sk_buff **skb_trimmed)
|
||||
{
|
||||
|
|
|
@ -318,8 +318,7 @@ static const struct rt6_info ip6_blk_hole_entry_template = {
|
|||
/* allocate dst with ip6_dst_ops */
|
||||
static struct rt6_info *__ip6_dst_alloc(struct net *net,
|
||||
struct net_device *dev,
|
||||
int flags,
|
||||
struct fib6_table *table)
|
||||
int flags)
|
||||
{
|
||||
struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev,
|
||||
0, DST_OBSOLETE_FORCE_CHK, flags);
|
||||
|
@ -336,10 +335,9 @@ static struct rt6_info *__ip6_dst_alloc(struct net *net,
|
|||
|
||||
static struct rt6_info *ip6_dst_alloc(struct net *net,
|
||||
struct net_device *dev,
|
||||
int flags,
|
||||
struct fib6_table *table)
|
||||
int flags)
|
||||
{
|
||||
struct rt6_info *rt = __ip6_dst_alloc(net, dev, flags, table);
|
||||
struct rt6_info *rt = __ip6_dst_alloc(net, dev, flags);
|
||||
|
||||
if (rt) {
|
||||
rt->rt6i_pcpu = alloc_percpu_gfp(struct rt6_info *, GFP_ATOMIC);
|
||||
|
@ -950,8 +948,7 @@ static struct rt6_info *ip6_rt_cache_alloc(struct rt6_info *ort,
|
|||
if (ort->rt6i_flags & (RTF_CACHE | RTF_PCPU))
|
||||
ort = (struct rt6_info *)ort->dst.from;
|
||||
|
||||
rt = __ip6_dst_alloc(dev_net(ort->dst.dev), ort->dst.dev,
|
||||
0, ort->rt6i_table);
|
||||
rt = __ip6_dst_alloc(dev_net(ort->dst.dev), ort->dst.dev, 0);
|
||||
|
||||
if (!rt)
|
||||
return NULL;
|
||||
|
@ -983,8 +980,7 @@ static struct rt6_info *ip6_rt_pcpu_alloc(struct rt6_info *rt)
|
|||
struct rt6_info *pcpu_rt;
|
||||
|
||||
pcpu_rt = __ip6_dst_alloc(dev_net(rt->dst.dev),
|
||||
rt->dst.dev, rt->dst.flags,
|
||||
rt->rt6i_table);
|
||||
rt->dst.dev, rt->dst.flags);
|
||||
|
||||
if (!pcpu_rt)
|
||||
return NULL;
|
||||
|
@ -997,32 +993,53 @@ static struct rt6_info *ip6_rt_pcpu_alloc(struct rt6_info *rt)
|
|||
/* It should be called with read_lock_bh(&tb6_lock) acquired */
|
||||
static struct rt6_info *rt6_get_pcpu_route(struct rt6_info *rt)
|
||||
{
|
||||
struct rt6_info *pcpu_rt, *prev, **p;
|
||||
struct rt6_info *pcpu_rt, **p;
|
||||
|
||||
p = this_cpu_ptr(rt->rt6i_pcpu);
|
||||
pcpu_rt = *p;
|
||||
|
||||
if (pcpu_rt)
|
||||
goto done;
|
||||
if (pcpu_rt) {
|
||||
dst_hold(&pcpu_rt->dst);
|
||||
rt6_dst_from_metrics_check(pcpu_rt);
|
||||
}
|
||||
return pcpu_rt;
|
||||
}
|
||||
|
||||
static struct rt6_info *rt6_make_pcpu_route(struct rt6_info *rt)
|
||||
{
|
||||
struct fib6_table *table = rt->rt6i_table;
|
||||
struct rt6_info *pcpu_rt, *prev, **p;
|
||||
|
||||
pcpu_rt = ip6_rt_pcpu_alloc(rt);
|
||||
if (!pcpu_rt) {
|
||||
struct net *net = dev_net(rt->dst.dev);
|
||||
|
||||
pcpu_rt = net->ipv6.ip6_null_entry;
|
||||
goto done;
|
||||
dst_hold(&net->ipv6.ip6_null_entry->dst);
|
||||
return net->ipv6.ip6_null_entry;
|
||||
}
|
||||
|
||||
prev = cmpxchg(p, NULL, pcpu_rt);
|
||||
if (prev) {
|
||||
/* If someone did it before us, return prev instead */
|
||||
read_lock_bh(&table->tb6_lock);
|
||||
if (rt->rt6i_pcpu) {
|
||||
p = this_cpu_ptr(rt->rt6i_pcpu);
|
||||
prev = cmpxchg(p, NULL, pcpu_rt);
|
||||
if (prev) {
|
||||
/* If someone did it before us, return prev instead */
|
||||
dst_destroy(&pcpu_rt->dst);
|
||||
pcpu_rt = prev;
|
||||
}
|
||||
} else {
|
||||
/* rt has been removed from the fib6 tree
|
||||
* before we have a chance to acquire the read_lock.
|
||||
* In this case, don't brother to create a pcpu rt
|
||||
* since rt is going away anyway. The next
|
||||
* dst_check() will trigger a re-lookup.
|
||||
*/
|
||||
dst_destroy(&pcpu_rt->dst);
|
||||
pcpu_rt = prev;
|
||||
pcpu_rt = rt;
|
||||
}
|
||||
|
||||
done:
|
||||
dst_hold(&pcpu_rt->dst);
|
||||
rt6_dst_from_metrics_check(pcpu_rt);
|
||||
read_unlock_bh(&table->tb6_lock);
|
||||
return pcpu_rt;
|
||||
}
|
||||
|
||||
|
@ -1097,9 +1114,22 @@ static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
|
|||
rt->dst.lastuse = jiffies;
|
||||
rt->dst.__use++;
|
||||
pcpu_rt = rt6_get_pcpu_route(rt);
|
||||
read_unlock_bh(&table->tb6_lock);
|
||||
|
||||
if (pcpu_rt) {
|
||||
read_unlock_bh(&table->tb6_lock);
|
||||
} else {
|
||||
/* We have to do the read_unlock first
|
||||
* because rt6_make_pcpu_route() may trigger
|
||||
* ip6_dst_gc() which will take the write_lock.
|
||||
*/
|
||||
dst_hold(&rt->dst);
|
||||
read_unlock_bh(&table->tb6_lock);
|
||||
pcpu_rt = rt6_make_pcpu_route(rt);
|
||||
dst_release(&rt->dst);
|
||||
}
|
||||
|
||||
return pcpu_rt;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1555,7 +1585,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
|
|||
if (unlikely(!idev))
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
rt = ip6_dst_alloc(net, dev, 0, NULL);
|
||||
rt = ip6_dst_alloc(net, dev, 0);
|
||||
if (unlikely(!rt)) {
|
||||
in6_dev_put(idev);
|
||||
dst = ERR_PTR(-ENOMEM);
|
||||
|
@ -1742,7 +1772,8 @@ int ip6_route_add(struct fib6_config *cfg)
|
|||
if (!table)
|
||||
goto out;
|
||||
|
||||
rt = ip6_dst_alloc(net, NULL, (cfg->fc_flags & RTF_ADDRCONF) ? 0 : DST_NOCOUNT, table);
|
||||
rt = ip6_dst_alloc(net, NULL,
|
||||
(cfg->fc_flags & RTF_ADDRCONF) ? 0 : DST_NOCOUNT);
|
||||
|
||||
if (!rt) {
|
||||
err = -ENOMEM;
|
||||
|
@ -2399,7 +2430,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
|
|||
{
|
||||
struct net *net = dev_net(idev->dev);
|
||||
struct rt6_info *rt = ip6_dst_alloc(net, net->loopback_dev,
|
||||
DST_NOCOUNT, NULL);
|
||||
DST_NOCOUNT);
|
||||
if (!rt)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
|
|
|
@ -92,14 +92,15 @@ int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_ewma)
|
|||
static inline void
|
||||
minstrel_sort_best_tp_rates(struct minstrel_sta_info *mi, int i, u8 *tp_list)
|
||||
{
|
||||
int j = MAX_THR_RATES;
|
||||
struct minstrel_rate_stats *tmp_mrs = &mi->r[j - 1].stats;
|
||||
int j;
|
||||
struct minstrel_rate_stats *tmp_mrs;
|
||||
struct minstrel_rate_stats *cur_mrs = &mi->r[i].stats;
|
||||
|
||||
while (j > 0 && (minstrel_get_tp_avg(&mi->r[i], cur_mrs->prob_ewma) >
|
||||
minstrel_get_tp_avg(&mi->r[tp_list[j - 1]], tmp_mrs->prob_ewma))) {
|
||||
j--;
|
||||
for (j = MAX_THR_RATES; j > 0; --j) {
|
||||
tmp_mrs = &mi->r[tp_list[j - 1]].stats;
|
||||
if (minstrel_get_tp_avg(&mi->r[i], cur_mrs->prob_ewma) <=
|
||||
minstrel_get_tp_avg(&mi->r[tp_list[j - 1]], tmp_mrs->prob_ewma))
|
||||
break;
|
||||
}
|
||||
|
||||
if (j < MAX_THR_RATES - 1)
|
||||
|
|
Loading…
Reference in a new issue