Commit 505f48b5 authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net:
  fib_rules: fix unresolved_rules counting
  r8169: fix wrong eee setting for rlt8111evl
  r8169: fix driver shutdown WoL regression.
  ehea: Change maintainer to me
  pptp: pptp_rcv_core() misses pskb_may_pull() call
  tproxy: copy transparent flag when creating a time wait
  pptp: fix skb leak in pptp_xmit()
  bonding: use local function pointer of bond->recv_probe in bond_handle_frame
  smsc911x: Add support for SMSC LAN89218
  tg3: negate USE_PHYLIB flag check
  netconsole: enable netconsole can make net_device refcnt incorrent
  bluetooth: Properly clone LSM attributes to newly created child connections
  l2tp: fix a potential skb leak in l2tp_xmit_skb()
  bridge: fix hang on removal of bridge via netlink
  x25: Prevent skb overreads when checking call user data
  x25: Handle undersized/fragmented skbs
  x25: Validate incoming call user data lengths
  udplite: fast-path computation of checksum coverage
  IPVS netns shutdown/startup dead-lock
  netfilter: nf_conntrack: fix event flooding in GRE protocol tracker
parents 486cf46f afaef734
...@@ -2460,7 +2460,7 @@ S: Supported ...@@ -2460,7 +2460,7 @@ S: Supported
F: drivers/infiniband/hw/ehca/ F: drivers/infiniband/hw/ehca/
EHEA (IBM pSeries eHEA 10Gb ethernet adapter) DRIVER EHEA (IBM pSeries eHEA 10Gb ethernet adapter) DRIVER
M: Breno Leitao <leitao@linux.vnet.ibm.com> M: Thadeu Lima de Souza Cascardo <cascardo@linux.vnet.ibm.com>
L: netdev@vger.kernel.org L: netdev@vger.kernel.org
S: Maintained S: Maintained
F: drivers/net/ehea/ F: drivers/net/ehea/
......
...@@ -1435,6 +1435,8 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb) ...@@ -1435,6 +1435,8 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
struct sk_buff *skb = *pskb; struct sk_buff *skb = *pskb;
struct slave *slave; struct slave *slave;
struct bonding *bond; struct bonding *bond;
void (*recv_probe)(struct sk_buff *, struct bonding *,
struct slave *);
skb = skb_share_check(skb, GFP_ATOMIC); skb = skb_share_check(skb, GFP_ATOMIC);
if (unlikely(!skb)) if (unlikely(!skb))
...@@ -1448,11 +1450,12 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb) ...@@ -1448,11 +1450,12 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
if (bond->params.arp_interval) if (bond->params.arp_interval)
slave->dev->last_rx = jiffies; slave->dev->last_rx = jiffies;
if (bond->recv_probe) { recv_probe = ACCESS_ONCE(bond->recv_probe);
if (recv_probe) {
struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC); struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC);
if (likely(nskb)) { if (likely(nskb)) {
bond->recv_probe(nskb, bond, slave); recv_probe(nskb, bond, slave);
dev_kfree_skb(nskb); dev_kfree_skb(nskb);
} }
} }
......
...@@ -307,6 +307,11 @@ static ssize_t store_enabled(struct netconsole_target *nt, ...@@ -307,6 +307,11 @@ static ssize_t store_enabled(struct netconsole_target *nt,
return err; return err;
if (enabled < 0 || enabled > 1) if (enabled < 0 || enabled > 1)
return -EINVAL; return -EINVAL;
if (enabled == nt->enabled) {
printk(KERN_INFO "netconsole: network logging has already %s\n",
nt->enabled ? "started" : "stopped");
return -EINVAL;
}
if (enabled) { /* 1 */ if (enabled) { /* 1 */
......
...@@ -285,8 +285,10 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb) ...@@ -285,8 +285,10 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
ip_send_check(iph); ip_send_check(iph);
ip_local_out(skb); ip_local_out(skb);
return 1;
tx_error: tx_error:
kfree_skb(skb);
return 1; return 1;
} }
...@@ -305,11 +307,18 @@ static int pptp_rcv_core(struct sock *sk, struct sk_buff *skb) ...@@ -305,11 +307,18 @@ static int pptp_rcv_core(struct sock *sk, struct sk_buff *skb)
} }
header = (struct pptp_gre_header *)(skb->data); header = (struct pptp_gre_header *)(skb->data);
headersize = sizeof(*header);
/* test if acknowledgement present */ /* test if acknowledgement present */
if (PPTP_GRE_IS_A(header->ver)) { if (PPTP_GRE_IS_A(header->ver)) {
__u32 ack = (PPTP_GRE_IS_S(header->flags)) ? __u32 ack;
header->ack : header->seq; /* ack in different place if S = 0 */
if (!pskb_may_pull(skb, headersize))
goto drop;
header = (struct pptp_gre_header *)(skb->data);
/* ack in different place if S = 0 */
ack = PPTP_GRE_IS_S(header->flags) ? header->ack : header->seq;
ack = ntohl(ack); ack = ntohl(ack);
...@@ -318,21 +327,18 @@ static int pptp_rcv_core(struct sock *sk, struct sk_buff *skb) ...@@ -318,21 +327,18 @@ static int pptp_rcv_core(struct sock *sk, struct sk_buff *skb)
/* also handle sequence number wrap-around */ /* also handle sequence number wrap-around */
if (WRAPPED(ack, opt->ack_recv)) if (WRAPPED(ack, opt->ack_recv))
opt->ack_recv = ack; opt->ack_recv = ack;
} else {
headersize -= sizeof(header->ack);
} }
/* test if payload present */ /* test if payload present */
if (!PPTP_GRE_IS_S(header->flags)) if (!PPTP_GRE_IS_S(header->flags))
goto drop; goto drop;
headersize = sizeof(*header);
payload_len = ntohs(header->payload_len); payload_len = ntohs(header->payload_len);
seq = ntohl(header->seq); seq = ntohl(header->seq);
/* no ack present? */
if (!PPTP_GRE_IS_A(header->ver))
headersize -= sizeof(header->ack);
/* check for incomplete packet (length smaller than expected) */ /* check for incomplete packet (length smaller than expected) */
if (skb->len - headersize < payload_len) if (!pskb_may_pull(skb, headersize + payload_len))
goto drop; goto drop;
payload = skb->data + headersize; payload = skb->data + headersize;
......
...@@ -2859,7 +2859,7 @@ static void rtl8168e_2_hw_phy_config(struct rtl8169_private *tp) ...@@ -2859,7 +2859,7 @@ static void rtl8168e_2_hw_phy_config(struct rtl8169_private *tp)
rtl_writephy(tp, 0x1f, 0x0004); rtl_writephy(tp, 0x1f, 0x0004);
rtl_writephy(tp, 0x1f, 0x0007); rtl_writephy(tp, 0x1f, 0x0007);
rtl_writephy(tp, 0x1e, 0x0020); rtl_writephy(tp, 0x1e, 0x0020);
rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0100); rtl_w1w0_phy(tp, 0x15, 0x0000, 0x0100);
rtl_writephy(tp, 0x1f, 0x0002); rtl_writephy(tp, 0x1f, 0x0002);
rtl_writephy(tp, 0x1f, 0x0000); rtl_writephy(tp, 0x1f, 0x0000);
rtl_writephy(tp, 0x0d, 0x0007); rtl_writephy(tp, 0x0d, 0x0007);
...@@ -3316,6 +3316,37 @@ static void __devinit rtl_init_mdio_ops(struct rtl8169_private *tp) ...@@ -3316,6 +3316,37 @@ static void __devinit rtl_init_mdio_ops(struct rtl8169_private *tp)
} }
} }
static void rtl_wol_suspend_quirk(struct rtl8169_private *tp)
{
void __iomem *ioaddr = tp->mmio_addr;
switch (tp->mac_version) {
case RTL_GIGA_MAC_VER_29:
case RTL_GIGA_MAC_VER_30:
case RTL_GIGA_MAC_VER_32:
case RTL_GIGA_MAC_VER_33:
case RTL_GIGA_MAC_VER_34:
RTL_W32(RxConfig, RTL_R32(RxConfig) |
AcceptBroadcast | AcceptMulticast | AcceptMyPhys);
break;
default:
break;
}
}
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_wol_suspend_quirk(tp);
return true;
}
static void r810x_phy_power_down(struct rtl8169_private *tp) static void r810x_phy_power_down(struct rtl8169_private *tp)
{ {
rtl_writephy(tp, 0x1f, 0x0000); rtl_writephy(tp, 0x1f, 0x0000);
...@@ -3330,18 +3361,8 @@ static void r810x_phy_power_up(struct rtl8169_private *tp) ...@@ -3330,18 +3361,8 @@ static void r810x_phy_power_up(struct rtl8169_private *tp)
static void r810x_pll_power_down(struct rtl8169_private *tp) static void r810x_pll_power_down(struct rtl8169_private *tp)
{ {
void __iomem *ioaddr = tp->mmio_addr; if (rtl_wol_pll_power_down(tp))
if (__rtl8169_get_wol(tp) & WAKE_ANY) {
rtl_writephy(tp, 0x1f, 0x0000);
rtl_writephy(tp, MII_BMCR, 0x0000);
if (tp->mac_version == RTL_GIGA_MAC_VER_29 ||
tp->mac_version == RTL_GIGA_MAC_VER_30)
RTL_W32(RxConfig, RTL_R32(RxConfig) | AcceptBroadcast |
AcceptMulticast | AcceptMyPhys);
return; return;
}
r810x_phy_power_down(tp); r810x_phy_power_down(tp);
} }
...@@ -3430,17 +3451,8 @@ static void r8168_pll_power_down(struct rtl8169_private *tp) ...@@ -3430,17 +3451,8 @@ static void r8168_pll_power_down(struct rtl8169_private *tp)
tp->mac_version == RTL_GIGA_MAC_VER_33) tp->mac_version == RTL_GIGA_MAC_VER_33)
rtl_ephy_write(ioaddr, 0x19, 0xff64); rtl_ephy_write(ioaddr, 0x19, 0xff64);
if (__rtl8169_get_wol(tp) & WAKE_ANY) { if (rtl_wol_pll_power_down(tp))
rtl_writephy(tp, 0x1f, 0x0000);
rtl_writephy(tp, MII_BMCR, 0x0000);
if (tp->mac_version == RTL_GIGA_MAC_VER_32 ||
tp->mac_version == RTL_GIGA_MAC_VER_33 ||
tp->mac_version == RTL_GIGA_MAC_VER_34)
RTL_W32(RxConfig, RTL_R32(RxConfig) | AcceptBroadcast |
AcceptMulticast | AcceptMyPhys);
return; return;
}
r8168_phy_power_down(tp); r8168_phy_power_down(tp);
...@@ -5788,11 +5800,30 @@ static const struct dev_pm_ops rtl8169_pm_ops = { ...@@ -5788,11 +5800,30 @@ static const struct dev_pm_ops rtl8169_pm_ops = {
#endif /* !CONFIG_PM */ #endif /* !CONFIG_PM */
static void rtl_wol_shutdown_quirk(struct rtl8169_private *tp)
{
void __iomem *ioaddr = tp->mmio_addr;
/* WoL fails with 8168b when the receiver is disabled. */
switch (tp->mac_version) {
case RTL_GIGA_MAC_VER_11:
case RTL_GIGA_MAC_VER_12:
case RTL_GIGA_MAC_VER_17:
pci_clear_master(tp->pci_dev);
RTL_W8(ChipCmd, CmdRxEnb);
/* PCI commit */
RTL_R8(ChipCmd);
break;
default:
break;
}
}
static void rtl_shutdown(struct pci_dev *pdev) static void rtl_shutdown(struct pci_dev *pdev)
{ {
struct net_device *dev = pci_get_drvdata(pdev); struct net_device *dev = pci_get_drvdata(pdev);
struct rtl8169_private *tp = netdev_priv(dev); struct rtl8169_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->mmio_addr;
rtl8169_net_suspend(dev); rtl8169_net_suspend(dev);
...@@ -5806,16 +5837,9 @@ static void rtl_shutdown(struct pci_dev *pdev) ...@@ -5806,16 +5837,9 @@ static void rtl_shutdown(struct pci_dev *pdev)
spin_unlock_irq(&tp->lock); spin_unlock_irq(&tp->lock);
if (system_state == SYSTEM_POWER_OFF) { if (system_state == SYSTEM_POWER_OFF) {
/* WoL fails with 8168b when the receiver is disabled. */ if (__rtl8169_get_wol(tp) & WAKE_ANY) {
if ((tp->mac_version == RTL_GIGA_MAC_VER_11 || rtl_wol_suspend_quirk(tp);
tp->mac_version == RTL_GIGA_MAC_VER_12 || rtl_wol_shutdown_quirk(tp);
tp->mac_version == RTL_GIGA_MAC_VER_17) &&
(tp->features & RTL_FEATURE_WOL)) {
pci_clear_master(pdev);
RTL_W8(ChipCmd, CmdRxEnb);
/* PCI commit */
RTL_R8(ChipCmd);
} }
pci_wake_from_d3(pdev, true); pci_wake_from_d3(pdev, true);
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
* LAN9215, LAN9216, LAN9217, LAN9218 * LAN9215, LAN9216, LAN9217, LAN9218
* LAN9210, LAN9211 * LAN9210, LAN9211
* LAN9220, LAN9221 * LAN9220, LAN9221
* LAN89218
* *
*/ */
...@@ -1983,6 +1984,7 @@ static int __devinit smsc911x_init(struct net_device *dev) ...@@ -1983,6 +1984,7 @@ static int __devinit smsc911x_init(struct net_device *dev)
case 0x01170000: case 0x01170000:
case 0x01160000: case 0x01160000:
case 0x01150000: case 0x01150000:
case 0x218A0000:
/* LAN911[5678] family */ /* LAN911[5678] family */
pdata->generation = pdata->idrev & 0x0000FFFF; pdata->generation = pdata->idrev & 0x0000FFFF;
break; break;
......
...@@ -15577,7 +15577,7 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev) ...@@ -15577,7 +15577,7 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev)
cancel_work_sync(&tp->reset_task); cancel_work_sync(&tp->reset_task);
if (!tg3_flag(tp, USE_PHYLIB)) { if (tg3_flag(tp, USE_PHYLIB)) {
tg3_phy_fini(tp); tg3_phy_fini(tp);
tg3_mdio_fini(tp); tg3_mdio_fini(tp);
} }
......
...@@ -900,6 +900,7 @@ struct netns_ipvs { ...@@ -900,6 +900,7 @@ struct netns_ipvs {
volatile int sync_state; volatile int sync_state;
volatile int master_syncid; volatile int master_syncid;
volatile int backup_syncid; volatile int backup_syncid;
struct mutex sync_mutex;
/* multicast interface name */ /* multicast interface name */
char master_mcast_ifn[IP_VS_IFNAME_MAXLEN]; char master_mcast_ifn[IP_VS_IFNAME_MAXLEN];
char backup_mcast_ifn[IP_VS_IFNAME_MAXLEN]; char backup_mcast_ifn[IP_VS_IFNAME_MAXLEN];
......
...@@ -66,40 +66,34 @@ static inline int udplite_checksum_init(struct sk_buff *skb, struct udphdr *uh) ...@@ -66,40 +66,34 @@ static inline int udplite_checksum_init(struct sk_buff *skb, struct udphdr *uh)
return 0; return 0;
} }
static inline int udplite_sender_cscov(struct udp_sock *up, struct udphdr *uh) /* Slow-path computation of checksum. Socket is locked. */
static inline __wsum udplite_csum_outgoing(struct sock *sk, struct sk_buff *skb)
{ {
const struct udp_sock *up = udp_sk(skb->sk);
int cscov = up->len; int cscov = up->len;
__wsum csum = 0;
/* if (up->pcflag & UDPLITE_SEND_CC) {
* Sender has set `partial coverage' option on UDP-Lite socket /*
*/ * Sender has set `partial coverage' option on UDP-Lite socket.
if (up->pcflag & UDPLITE_SEND_CC) { * The special case "up->pcslen == 0" signifies full coverage.
*/
if (up->pcslen < up->len) { if (up->pcslen < up->len) {
/* up->pcslen == 0 means that full coverage is required, if (0 < up->pcslen)
* partial coverage only if 0 < up->pcslen < up->len */ cscov = up->pcslen;
if (0 < up->pcslen) { udp_hdr(skb)->len = htons(up->pcslen);
cscov = up->pcslen;
}
uh->len = htons(up->pcslen);
} }
/* /*
* NOTE: Causes for the error case `up->pcslen > up->len': * NOTE: Causes for the error case `up->pcslen > up->len':
* (i) Application error (will not be penalized). * (i) Application error (will not be penalized).
* (ii) Payload too big for send buffer: data is split * (ii) Payload too big for send buffer: data is split
* into several packets, each with its own header. * into several packets, each with its own header.
* In this case (e.g. last segment), coverage may * In this case (e.g. last segment), coverage may
* exceed packet length. * exceed packet length.
* Since packets with coverage length > packet length are * Since packets with coverage length > packet length are
* illegal, we fall back to the defaults here. * illegal, we fall back to the defaults here.
*/ */
} }
return cscov;
}
static inline __wsum udplite_csum_outgoing(struct sock *sk, struct sk_buff *skb)
{
int cscov = udplite_sender_cscov(udp_sk(sk), udp_hdr(skb));
__wsum csum = 0;
skb->ip_summed = CHECKSUM_NONE; /* no HW support for checksumming */ skb->ip_summed = CHECKSUM_NONE; /* no HW support for checksumming */
...@@ -115,16 +109,21 @@ static inline __wsum udplite_csum_outgoing(struct sock *sk, struct sk_buff *skb) ...@@ -115,16 +109,21 @@ static inline __wsum udplite_csum_outgoing(struct sock *sk, struct sk_buff *skb)
return csum; return csum;
} }
/* Fast-path computation of checksum. Socket may not be locked. */
static inline __wsum udplite_csum(struct sk_buff *skb) static inline __wsum udplite_csum(struct sk_buff *skb)
{ {
struct sock *sk = skb->sk; const struct udp_sock *up = udp_sk(skb->sk);
int cscov = udplite_sender_cscov(udp_sk(sk), udp_hdr(skb));
const int off = skb_transport_offset(skb); const int off = skb_transport_offset(skb);
const int len = skb->len - off; int len = skb->len - off;
if ((up->pcflag & UDPLITE_SEND_CC) && up->pcslen < len) {
if (0 < up->pcslen)
len = up->pcslen;
udp_hdr(skb)->len = htons(up->pcslen);
}
skb->ip_summed = CHECKSUM_NONE; /* no HW support for checksumming */ skb->ip_summed = CHECKSUM_NONE; /* no HW support for checksumming */
return skb_checksum(skb, off, min(cscov, len), 0); return skb_checksum(skb, off, len, 0);
} }
extern void udplite4_register(void); extern void udplite4_register(void);
......
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
/* Bluetooth L2CAP sockets. */ /* Bluetooth L2CAP sockets. */
#include <linux/security.h>
#include <net/bluetooth/bluetooth.h> #include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h> #include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h> #include <net/bluetooth/l2cap.h>
...@@ -933,6 +935,8 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) ...@@ -933,6 +935,8 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
chan->force_reliable = pchan->force_reliable; chan->force_reliable = pchan->force_reliable;
chan->flushable = pchan->flushable; chan->flushable = pchan->flushable;
chan->force_active = pchan->force_active; chan->force_active = pchan->force_active;
security_sk_clone(parent, sk);
} else { } else {
switch (sk->sk_type) { switch (sk->sk_type) {
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/security.h>
#include <net/sock.h> #include <net/sock.h>
#include <asm/system.h> #include <asm/system.h>
...@@ -264,6 +265,8 @@ static void rfcomm_sock_init(struct sock *sk, struct sock *parent) ...@@ -264,6 +265,8 @@ static void rfcomm_sock_init(struct sock *sk, struct sock *parent)
pi->sec_level = rfcomm_pi(parent)->sec_level; pi->sec_level = rfcomm_pi(parent)->sec_level;
pi->role_switch = rfcomm_pi(parent)->role_switch; pi->role_switch = rfcomm_pi(parent)->role_switch;
security_sk_clone(parent, sk);
} else { } else {
pi->dlc->defer_setup = 0; pi->dlc->defer_setup = 0;
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/security.h>
#include <net/sock.h> #include <net/sock.h>
#include <asm/system.h> #include <asm/system.h>
...@@ -403,8 +404,10 @@ static void sco_sock_init(struct sock *sk, struct sock *parent) ...@@ -403,8 +404,10 @@ static void sco_sock_init(struct sock *sk, struct sock *parent)
{ {
BT_DBG("sk %p", sk); BT_DBG("sk %p", sk);
if (parent) if (parent) {
sk->sk_type = parent->sk_type; sk->sk_type = parent->sk_type;
security_sk_clone(parent, sk);
}
} }
static struct proto sco_proto = { static struct proto sco_proto = {
......
...@@ -161,9 +161,10 @@ static void del_nbp(struct net_bridge_port *p) ...@@ -161,9 +161,10 @@ static void del_nbp(struct net_bridge_port *p)
call_rcu(&p->rcu, destroy_nbp_rcu); call_rcu(&p->rcu, destroy_nbp_rcu);
} }
/* called with RTNL */ /* Delete bridge device */
static void del_br(struct net_bridge *br, struct list_head *head) void br_dev_delete(struct net_device *dev, struct list_head *head)
{ {
struct net_bridge *br = netdev_priv(dev);
struct net_bridge_port *p, *n; struct net_bridge_port *p, *n;
list_for_each_entry_safe(p, n, &br->port_list, list) { list_for_each_entry_safe(p, n, &br->port_list, list) {
...@@ -268,7 +269,7 @@ int br_del_bridge(struct net *net, const char *name) ...@@ -268,7 +269,7 @@ int br_del_bridge(struct net *net, const char *name)
} }
else else
del_br(netdev_priv(dev), NULL); br_dev_delete(dev, NULL);
rtnl_unlock(); rtnl_unlock();
return ret; return ret;
...@@ -449,7 +450,7 @@ void __net_exit br_net_exit(struct net *net) ...@@ -449,7 +450,7 @@ void __net_exit br_net_exit(struct net *net)
rtnl_lock(); rtnl_lock();
for_each_netdev(net, dev) for_each_netdev(net, dev)
if (dev->priv_flags & IFF_EBRIDGE) if (dev->priv_flags & IFF_EBRIDGE)
del_br(netdev_priv(dev), &list); br_dev_delete(dev, &list);
unregister_netdevice_many(&list); unregister_netdevice_many(&list);
rtnl_unlock(); rtnl_unlock();
......
...@@ -210,6 +210,7 @@ static struct rtnl_link_ops br_link_ops __read_mostly = { ...@@ -210,6 +210,7 @@ static struct rtnl_link_ops br_link_ops __read_mostly = {
.priv_size = sizeof(struct net_bridge), .priv_size = sizeof(struct net_bridge),
.setup = br_dev_setup, .setup = br_dev_setup,
.validate = br_validate, .validate = br_validate,
.dellink = br_dev_delete,
}; };
int __init br_netlink_init(void) int __init br_netlink_init(void)
......
...@@ -294,6 +294,7 @@ static inline int br_is_root_bridge(const struct net_bridge *br) ...@@ -294,6 +294,7 @@ static inline int br_is_root_bridge(const struct net_bridge *br)
/* br_device.c */ /* br_device.c */
extern void br_dev_setup(struct net_device *dev); extern void br_dev_setup(struct net_device *dev);
extern void br_dev_delete(struct net_device *dev, struct list_head *list);
extern netdev_tx_t br_dev_xmit(struct sk_buff *skb, extern netdev_tx_t br_dev_xmit(struct sk_buff *skb,
struct net_device *dev); struct net_device *dev);
#ifdef CONFIG_NET_POLL_CONTROLLER #ifdef CONFIG_NET_POLL_CONTROLLER
......
...@@ -475,8 +475,11 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) ...@@ -475,8 +475,11 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
list_del_rcu(&rule->list); list_del_rcu(&rule->list);
if (rule->action == FR_ACT_GOTO) if (rule->action == FR_ACT_GOTO) {
ops->nr_goto_rules--; ops->nr_goto_rules--;
if (rtnl_dereference(rule->ctarget) == NULL)
ops->unresolved_rules--;
}
/* /*
* Check if this rule is a target to any of them. If so, * Check if this rule is a target to any of them. If so,
......
...@@ -328,6 +328,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo) ...@@ -328,6 +328,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw); struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw);
const int rto = (icsk->icsk_rto << 2) - (icsk->icsk_rto >> 1); const int rto = (icsk->icsk_rto << 2) - (icsk->icsk_rto >> 1);
tw->tw_transparent = inet_sk(sk)->transparent;
tw->tw_rcv_wscale = tp->rx_opt.rcv_wscale; tw->tw_rcv_wscale = tp->rx_opt.rcv_wscale;
tcptw->tw_rcv_nxt = tp->rcv_nxt; tcptw->tw_rcv_nxt = tp->rcv_nxt;
tcptw->tw_snd_nxt = tp->snd_nxt; tcptw->tw_snd_nxt = tp->snd_nxt;
......
...@@ -1045,8 +1045,10 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len ...@@ -1045,8 +1045,10 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len
headroom = NET_SKB_PAD + sizeof(struct iphdr) + headroom = NET_SKB_PAD + sizeof(struct iphdr) +
uhlen + hdr_len; uhlen + hdr_len;
old_headroom = skb_headroom(skb); old_headroom = skb_headroom(skb);
if (skb_cow_head(skb, headroom)) if (skb_cow_head(skb, headroom)) {
dev_kfree_skb(skb);
goto abort; goto abort;
}
new_headroom = skb_headroom(skb); new_headroom = skb_headroom(skb);
skb_orphan(skb); skb_orphan(skb);
......
...@@ -2283,6 +2283,7 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) ...@@ -2283,6 +2283,7 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
struct ip_vs_service *svc; struct ip_vs_service *svc;
struct ip_vs_dest_user *udest_compat; struct ip_vs_dest_user *udest_compat;
struct ip_vs_dest_user_kern udest; struct ip_vs_dest_user_kern udest;
struct netns_ipvs *ipvs = net_ipvs(net);
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN))
return -EPERM; return -EPERM;
...@@ -2303,6 +2304,24 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) ...@@ -2303,6 +2304,24 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
/* increase the module use count */ /* increase the module use count */
ip_vs_use_count_inc(); ip_vs_use_count_inc();
/* Handle daemons since they have another lock */
if (cmd == IP_VS_SO_SET_STARTDAEMON ||
cmd == IP_VS_SO_SET_STOPDAEMON) {
struct ip_vs_daemon_user *dm = (struct ip_vs_daemon_user *)arg;
if (mutex_lock_interruptible(&ipvs->sync_mutex)) {
ret = -ERESTARTSYS;
goto out_dec;
}
if (cmd == IP_VS_SO_SET_STARTDAEMON)
ret = start_sync_thread(net, dm->state, dm->mcast_ifn,
dm->syncid);
else
ret = stop_sync_thread(net, dm->state);
mutex_unlock(&ipvs->sync_mutex);
goto out_dec;
}
if (mutex_lock_interruptible(&__ip_vs_mutex)) { if (mutex_lock_interruptible(&__ip_vs_mutex)) {
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
goto out_dec; goto out_dec;
...@@ -2316,15 +2335,6 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) ...@@ -2316,15 +2335,6 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
/* Set timeout values for (tcp tcpfin udp) */ /* Set timeout values for (tcp tcpfin udp) */
ret = ip_vs_set_timeout(net, (struct ip_vs_timeout_user *)arg); ret = ip_vs_set_timeout(net, (struct ip_vs_timeout_user *)arg);
goto out_unlock; goto out_unlock;
} else if (cmd == IP_VS_SO_SET_STARTDAEMON) {
struct ip_vs_daemon_user *dm = (struct ip_vs_daemon_user *)arg;
ret = start_sync_thread(net, dm->state, dm->mcast_ifn,
dm->syncid);
goto out_unlock;
} else if (cmd == IP_VS_SO_SET_STOPDAEMON) {
struct ip_vs_daemon_user *dm = (struct ip_vs_daemon_user *)arg;
ret = stop_sync_thread(net, dm->state);
goto out_unlock;
} }
usvc_compat = (struct ip_vs_service_user *)arg; usvc_compat = (struct ip_vs_service_user *)arg;
...@@ -2584,6 +2594,33 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) ...@@ -2584,6 +2594,33 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
if (copy_from_user(arg, user, copylen) != 0) if (copy_from_user(arg, user, copylen) != 0)
return -EFAULT; return -EFAULT;
/*
* Handle daemons first since it has its own locking
*/
if (cmd == IP_VS_SO_GET_DAEMON) {
struct ip_vs_daemon_user d[2];
memset(&d, 0, sizeof(d));
if (mutex_lock_interruptible(&ipvs->sync_mutex))
return -ERESTARTSYS;
if (ipvs->sync_state & IP_VS_STATE_MASTER) {
d[0].state = IP_VS_STATE_MASTER;
strlcpy(d[0].mcast_ifn, ipvs->master_mcast_ifn,
sizeof(d[0].mcast_ifn));
d[0].syncid = ipvs->master_syncid;
}
if (ipvs->sync_state & IP_VS_STATE_BACKUP) {
d[1].state = IP_VS_STATE_BACKUP;
strlcpy(d[1].mcast_ifn, ipvs->backup_mcast_ifn,
sizeof(d[1].mcast_ifn));
d[1].syncid = ipvs->backup_syncid;
}
if (copy_to_user(user, &d, sizeof(d)) != 0)
ret = -EFAULT;
mutex_unlock(&ipvs->sync_mutex);
return ret;
}
if (mutex_lock_interruptible(&__ip_vs_mutex)) if (mutex_lock_interruptible(&__ip_vs_mutex))
return -ERESTARTSYS; return -ERESTARTSYS;
...@@ -2681,28 +2718,6 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) ...@@ -2681,28 +2718,6 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
} }
break; break;
case IP_VS_SO_GET_DAEMON:
{
struct ip_vs_daemon_user d[2];
memset(&d, 0, sizeof(d));
if (ipvs->sync_state & IP_VS_STATE_MASTER) {
d[0].state = IP_VS_STATE_MASTER;
strlcpy(d[0].mcast_ifn, ipvs->master_mcast_ifn,
sizeof(d[0].mcast_ifn));
d[0].syncid = ipvs->master_syncid;
}
if (ipvs->sync_state & IP_VS_STATE_BACKUP) {
d[1].state = IP_VS_STATE_BACKUP;
strlcpy(d[1].mcast_ifn, ipvs->backup_mcast_ifn,
sizeof(d[1].mcast_ifn));
d[1].syncid = ipvs->backup_syncid;
}
if (copy_to_user(user, &d, sizeof(d)) != 0)
ret = -EFAULT;
}
break;
default: default:
ret = -EINVAL; ret = -EINVAL;
} }
...@@ -3205,7 +3220,7 @@ static int ip_vs_genl_dump_daemons(struct sk_buff *skb, ...@@ -3205,7 +3220,7 @@ static int ip_vs_genl_dump_daemons(struct sk_buff *skb,
struct net *net = skb_sknet(skb); struct net *net = skb_sknet(skb);
struct netns_ipvs *ipvs = net_ipvs(net); struct netns_ipvs *ipvs = net_ipvs(net);
mutex_lock(&__ip_vs_mutex); mutex_lock(&ipvs->sync_mutex);
if ((ipvs->sync_state & IP_VS_STATE_MASTER) && !cb->args[0]) { if ((ipvs->sync_state & IP_VS_STATE_MASTER) && !cb->args[0]) {
if (ip_vs_genl_dump_daemon(skb, IP_VS_STATE_MASTER, if (ip_vs_genl_dump_daemon(skb, IP_VS_STATE_MASTER,
ipvs->master_mcast_ifn, ipvs->master_mcast_ifn,
...@@ -3225,7 +3240,7 @@ static int ip_vs_genl_dump_daemons(struct sk_buff *skb, ...@@ -3225,7 +3240,7 @@ static int ip_vs_genl_dump_daemons(struct sk_buff *skb,
} }
nla_put_failure: nla_put_failure:
mutex_unlock(&__ip_vs_mutex); mutex_unlock(&ipvs->sync_mutex);
return skb->len; return skb->len;
} }
...@@ -3271,13 +3286,9 @@ static int ip_vs_genl_set_config(struct net *net, struct nlattr **attrs) ...@@ -3271,13 +3286,9 @@ static int ip_vs_genl_set_config(struct net *net, struct nlattr **attrs)
return ip_vs_set_timeout(net, &t); return ip_vs_set_timeout(net, &t);
} }
static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info) static int ip_vs_genl_set_daemon(struct sk_buff *skb, struct genl_info *info)
{ {
struct ip_vs_service *svc = NULL;
struct ip_vs_service_user_kern usvc;
struct ip_vs_dest_user_kern udest;
int ret = 0, cmd; int ret = 0, cmd;
int need_full_svc = 0, need_full_dest = 0;
struct net *net; struct net *net;
struct netns_ipvs *ipvs; struct netns_ipvs *ipvs;
...@@ -3285,19 +3296,10 @@ static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info) ...@@ -3285,19 +3296,10 @@ static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info)
ipvs = net_ipvs(net); ipvs = net_ipvs(net);
cmd = info->genlhdr->cmd; cmd = info->genlhdr->cmd;
mutex_lock(&__ip_vs_mutex); if (cmd == IPVS_CMD_NEW_DAEMON || cmd == IPVS_CMD_DEL_DAEMON) {
if (cmd == IPVS_CMD_FLUSH) {
ret = ip_vs_flush(net);
goto out;
} else if (cmd == IPVS_CMD_SET_CONFIG) {
ret = ip_vs_genl_set_config(net, info->attrs);
goto out;
} else if (cmd == IPVS_CMD_NEW_DAEMON ||
cmd == IPVS_CMD_DEL_DAEMON) {
struct nlattr *daemon_attrs[IPVS_DAEMON_ATTR_MAX + 1]; struct nlattr *daemon_attrs[IPVS_DAEMON_ATTR_MAX + 1];
mutex_lock(&ipvs->sync_mutex);
if (!info->attrs[IPVS_CMD_ATTR_DAEMON] || if (!info->attrs[IPVS_CMD_ATTR_DAEMON] ||
nla_parse_nested(daemon_attrs, IPVS_DAEMON_ATTR_MAX, nla_parse_nested(daemon_attrs, IPVS_DAEMON_ATTR_MAX,
info->attrs[IPVS_CMD_ATTR_DAEMON], info->attrs[IPVS_CMD_ATTR_DAEMON],
...@@ -3310,6 +3312,33 @@ static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info) ...@@ -3310,6 +3312,33 @@ static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info)
ret = ip_vs_genl_new_daemon(net, daemon_attrs); ret = ip_vs_genl_new_daemon(net, daemon_attrs);
else else
ret = ip_vs_genl_del_daemon(net, daemon_attrs); ret = ip_vs_genl_del_daemon(net, daemon_attrs);
out:
mutex_unlock(&ipvs->sync_mutex);
}
return ret;
}
static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info)
{
struct ip_vs_service *svc = NULL;
struct ip_vs_service_user_kern usvc;
struct ip_vs_dest_user_kern udest;
int ret = 0, cmd;
int need_full_svc = 0, need_full_dest = 0;
struct net *net;
struct netns_ipvs *ipvs;
net = skb_sknet(skb);
ipvs = net_ipvs(net);
cmd = info->genlhdr->cmd;
mutex_lock(&__ip_vs_mutex);
if (cmd == IPVS_CMD_FLUSH) {
ret = ip_vs_flush(net);
goto out;
} else if (cmd == IPVS_CMD_SET_CONFIG) {
ret = ip_vs_genl_set_config(net, info->attrs);
goto out; goto out;
} else if (cmd == IPVS_CMD_ZERO && } else if (cmd == IPVS_CMD_ZERO &&
!info->attrs[IPVS_CMD_ATTR_SERVICE]) { !info->attrs[IPVS_CMD_ATTR_SERVICE]) {
...@@ -3536,13 +3565,13 @@ static struct genl_ops ip_vs_genl_ops[] __read_mostly = { ...@@ -3536,13 +3565,13 @@ static struct genl_ops ip_vs_genl_ops[] __read_mostly = {
.cmd = IPVS_CMD_NEW_DAEMON, .cmd = IPVS_CMD_NEW_DAEMON,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.policy = ip_vs_cmd_policy, .policy = ip_vs_cmd_policy,
.doit = ip_vs_genl_set_cmd, .doit = ip_vs_genl_set_daemon,
}, },
{ {
.cmd = IPVS_CMD_DEL_DAEMON, .cmd = IPVS_CMD_DEL_DAEMON,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.policy = ip_vs_cmd_policy, .policy = ip_vs_cmd_policy,
.doit = ip_vs_genl_set_cmd, .doit = ip_vs_genl_set_daemon,
}, },
{ {
.cmd = IPVS_CMD_GET_DAEMON, .cmd = IPVS_CMD_GET_DAEMON,
......
...@@ -61,6 +61,7 @@ ...@@ -61,6 +61,7 @@
#define SYNC_PROTO_VER 1 /* Protocol version in header */ #define SYNC_PROTO_VER 1 /* Protocol version in header */
static struct lock_class_key __ipvs_sync_key;
/* /*
* IPVS sync connection entry * IPVS sync connection entry
* Version 0, i.e. original version. * Version 0, i.e. original version.
...@@ -1545,6 +1546,7 @@ int start_sync_thread(struct net *net, int state, char *mcast_ifn, __u8 syncid) ...@@ -1545,6 +1546,7 @@ int start_sync_thread(struct net *net, int state, char *mcast_ifn, __u8 syncid)
IP_VS_DBG(7, "Each ip_vs_sync_conn entry needs %Zd bytes\n", IP_VS_DBG(7, "Each ip_vs_sync_conn entry needs %Zd bytes\n",
sizeof(struct ip_vs_sync_conn_v0)); sizeof(struct ip_vs_sync_conn_v0));
if (state == IP_VS_STATE_MASTER) { if (state == IP_VS_STATE_MASTER) {
if (ipvs->master_thread) if (ipvs->master_thread)
return -EEXIST; return -EEXIST;
...@@ -1667,6 +1669,7 @@ int __net_init ip_vs_sync_net_init(struct net *net) ...@@ -1667,6 +1669,7 @@ int __net_init ip_vs_sync_net_init(struct net *net)
{ {
struct netns_ipvs *ipvs = net_ipvs(net); struct netns_ipvs *ipvs = net_ipvs(net);
__mutex_init(&ipvs->sync_mutex, "ipvs->sync_mutex", &__ipvs_sync_key);
INIT_LIST_HEAD(&ipvs->sync_queue); INIT_LIST_HEAD(&ipvs->sync_queue);
spin_lock_init(&ipvs->sync_lock); spin_lock_init(&ipvs->sync_lock);
spin_lock_init(&ipvs->sync_buff_lock); spin_lock_init(&ipvs->sync_buff_lock);
...@@ -1680,7 +1683,9 @@ int __net_init ip_vs_sync_net_init(struct net *net) ...@@ -1680,7 +1683,9 @@ int __net_init ip_vs_sync_net_init(struct net *net)
void ip_vs_sync_net_cleanup(struct net *net) void ip_vs_sync_net_cleanup(struct net *net)
{ {
int retc; int retc;
struct netns_ipvs *ipvs = net_ipvs(net);
mutex_lock(&ipvs->sync_mutex);
retc = stop_sync_thread(net, IP_VS_STATE_MASTER); retc = stop_sync_thread(net, IP_VS_STATE_MASTER);
if (retc && retc != -ESRCH) if (retc && retc != -ESRCH)
pr_err("Failed to stop Master Daemon\n"); pr_err("Failed to stop Master Daemon\n");
...@@ -1688,4 +1693,5 @@ void ip_vs_sync_net_cleanup(struct net *net) ...@@ -1688,4 +1693,5 @@ void ip_vs_sync_net_cleanup(struct net *net)
retc = stop_sync_thread(net, IP_VS_STATE_BACKUP); retc = stop_sync_thread(net, IP_VS_STATE_BACKUP);
if (retc && retc != -ESRCH) if (retc && retc != -ESRCH)
pr_err("Failed to stop Backup Daemon\n"); pr_err("Failed to stop Backup Daemon\n");
mutex_unlock(&ipvs->sync_mutex);
} }
...@@ -241,8 +241,8 @@ static int gre_packet(struct nf_conn *ct, ...@@ -241,8 +241,8 @@ static int gre_packet(struct nf_conn *ct,
nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_refresh_acct(ct, ctinfo, skb,
ct->proto.gre.stream_timeout); ct->proto.gre.stream_timeout);
/* Also, more likely to be important, and not a probe. */ /* Also, more likely to be important, and not a probe. */
set_bit(IPS_ASSURED_BIT, &ct->status); if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status))
nf_conntrack_event_cache(IPCT_ASSURED, ct); nf_conntrack_event_cache(IPCT_ASSURED, ct);
} else } else
nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_refresh_acct(ct, ctinfo, skb,
ct->proto.gre.timeout); ct->proto.gre.timeout);
......
...@@ -91,7 +91,7 @@ int x25_parse_address_block(struct sk_buff *skb, ...@@ -91,7 +91,7 @@ int x25_parse_address_block(struct sk_buff *skb,
int needed; int needed;
int rc; int rc;
if (skb->len < 1) { if (!pskb_may_pull(skb, 1)) {
/* packet has no address block */ /* packet has no address block */
rc = 0; rc = 0;
goto empty; goto empty;
...@@ -100,7 +100,7 @@ int x25_parse_address_block(struct sk_buff *skb, ...@@ -100,7 +100,7 @@ int x25_parse_address_block(struct sk_buff *skb,
len = *skb->data; len = *skb->data;
needed = 1 + (len >> 4) + (len & 0x0f); needed = 1 + (len >> 4) + (len & 0x0f);
if (skb->len < needed) { if (!pskb_may_pull(skb, needed)) {
/* packet is too short to hold the addresses it claims /* packet is too short to hold the addresses it claims
to hold */ to hold */
rc = -1; rc = -1;
...@@ -295,7 +295,8 @@ static struct sock *x25_find_listener(struct x25_address *addr, ...@@ -295,7 +295,8 @@ static struct sock *x25_find_listener(struct x25_address *addr,
* Found a listening socket, now check the incoming * Found a listening socket, now check the incoming
* call user data vs this sockets call user data * call user data vs this sockets call user data
*/ */
if(skb->len > 0 && x25_sk(s)->cudmatchlength > 0) { if (x25_sk(s)->cudmatchlength > 0 &&
skb->len >= x25_sk(s)->cudmatchlength) {
if((memcmp(x25_sk(s)->calluserdata.cuddata, if((memcmp(x25_sk(s)->calluserdata.cuddata,
skb->data, skb->data,
x25_sk(s)->cudmatchlength)) == 0) { x25_sk(s)->cudmatchlength)) == 0) {
...@@ -951,13 +952,26 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb, ...@@ -951,13 +952,26 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
* *
* Facilities length is mandatory in call request packets * Facilities length is mandatory in call request packets
*/ */
if (skb->len < 1) if (!pskb_may_pull(skb, 1))
goto out_clear_request; goto out_clear_request;
len = skb->data[0] + 1; len = skb->data[0] + 1;
if (skb->len < len) if (!pskb_may_pull(skb, len))
goto out_clear_request; goto out_clear_request;
skb_pull(skb,len); skb_pull(skb,len);
/*
* Ensure that the amount of call user data is valid.
*/
if (skb->len > X25_MAX_CUD_LEN)
goto out_clear_request;
/*
* Get all the call user data so it can be used in
* x25_find_listener and skb_copy_from_linear_data up ahead.
*/
if (!pskb_may_pull(skb, skb->len))
goto out_clear_request;
/* /*
* Find a listener for the particular address/cud pair. * Find a listener for the particular address/cud pair.
*/ */
...@@ -1166,6 +1180,9 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock, ...@@ -1166,6 +1180,9 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock,
* byte of the user data is the logical value of the Q Bit. * byte of the user data is the logical value of the Q Bit.
*/ */
if (test_bit(X25_Q_BIT_FLAG, &x25->flags)) { if (test_bit(X25_Q_BIT_FLAG, &x25->flags)) {
if (!pskb_may_pull(skb, 1))
goto out_kfree_skb;
qbit = skb->data[0]; qbit = skb->data[0];
skb_pull(skb, 1); skb_pull(skb, 1);
} }
...@@ -1244,7 +1261,9 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock, ...@@ -1244,7 +1261,9 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,
struct x25_sock *x25 = x25_sk(sk); struct x25_sock *x25 = x25_sk(sk);
struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)msg->msg_name; struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)msg->msg_name;
size_t copied; size_t copied;
int qbit; int qbit, header_len = x25->neighbour->extended ?
X25_EXT_MIN_LEN : X25_STD_MIN_LEN;
struct sk_buff *skb; struct sk_buff *skb;
unsigned char *asmptr; unsigned char *asmptr;
int rc = -ENOTCONN; int rc = -ENOTCONN;
...@@ -1265,6 +1284,9 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock, ...@@ -1265,6 +1284,9 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,
skb = skb_dequeue(&x25->interrupt_in_queue); skb = skb_dequeue(&x25->interrupt_in_queue);
if (!pskb_may_pull(skb, X25_STD_MIN_LEN))
goto out_free_dgram;
skb_pull(skb, X25_STD_MIN_LEN); skb_pull(skb, X25_STD_MIN_LEN);
/* /*
...@@ -1285,10 +1307,12 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock, ...@@ -1285,10 +1307,12 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,
if (!skb) if (!skb)
goto out; goto out;
if (!pskb_may_pull(skb, header_len))
goto out_free_dgram;
qbit = (skb->data[0] & X25_Q_BIT) == X25_Q_BIT; qbit = (skb->data[0] & X25_Q_BIT) == X25_Q_BIT;
skb_pull(skb, x25->neighbour->extended ? skb_pull(skb, header_len);
X25_EXT_MIN_LEN : X25_STD_MIN_LEN);
if (test_bit(X25_Q_BIT_FLAG, &x25->flags)) { if (test_bit(X25_Q_BIT_FLAG, &x25->flags)) {
asmptr = skb_push(skb, 1); asmptr = skb_push(skb, 1);
......
...@@ -32,6 +32,9 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *nb) ...@@ -32,6 +32,9 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *nb)
unsigned short frametype; unsigned short frametype;
unsigned int lci; unsigned int lci;
if (!pskb_may_pull(skb, X25_STD_MIN_LEN))
return 0;
frametype = skb->data[2]; frametype = skb->data[2];
lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF); lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF);
...@@ -115,6 +118,9 @@ int x25_lapb_receive_frame(struct sk_buff *skb, struct net_device *dev, ...@@ -115,6 +118,9 @@ int x25_lapb_receive_frame(struct sk_buff *skb, struct net_device *dev,
goto drop; goto drop;
} }
if (!pskb_may_pull(skb, 1))
return 0;
switch (skb->data[0]) { switch (skb->data[0]) {
case X25_IFACE_DATA: case X25_IFACE_DATA:
......
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities, int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
struct x25_dte_facilities *dte_facs, unsigned long *vc_fac_mask) struct x25_dte_facilities *dte_facs, unsigned long *vc_fac_mask)
{ {
unsigned char *p = skb->data; unsigned char *p;
unsigned int len; unsigned int len;
*vc_fac_mask = 0; *vc_fac_mask = 0;
...@@ -60,14 +60,16 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities, ...@@ -60,14 +60,16 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
memset(dte_facs->called_ae, '\0', sizeof(dte_facs->called_ae)); memset(dte_facs->called_ae, '\0', sizeof(dte_facs->called_ae));
memset(dte_facs->calling_ae, '\0', sizeof(dte_facs->calling_ae)); memset(dte_facs->calling_ae, '\0', sizeof(dte_facs->calling_ae));
if (skb->len < 1) if (!pskb_may_pull(skb, 1))
return 0; return 0;
len = *p++; len = skb->data[0];
if (len >= skb->len) if (!pskb_may_pull(skb, 1 + len))
return -1; return -1;
p = skb->data + 1;
while (len > 0) { while (len > 0) {
switch (*p & X25_FAC_CLASS_MASK) { switch (*p & X25_FAC_CLASS_MASK) {
case X25_FAC_CLASS_A: case X25_FAC_CLASS_A:
......
...@@ -107,6 +107,8 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp ...@@ -107,6 +107,8 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp
/* /*
* Parse the data in the frame. * Parse the data in the frame.
*/ */
if (!pskb_may_pull(skb, X25_STD_MIN_LEN))
goto out_clear;
skb_pull(skb, X25_STD_MIN_LEN); skb_pull(skb, X25_STD_MIN_LEN);
len = x25_parse_address_block(skb, &source_addr, len = x25_parse_address_block(skb, &source_addr,
...@@ -127,9 +129,11 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp ...@@ -127,9 +129,11 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp
* Copy any Call User Data. * Copy any Call User Data.
*/ */
if (skb->len > 0) { if (skb->len > 0) {
skb_copy_from_linear_data(skb, if (skb->len > X25_MAX_CUD_LEN)
x25->calluserdata.cuddata, goto out_clear;
skb->len);
skb_copy_bits(skb, 0, x25->calluserdata.cuddata,
skb->len);
x25->calluserdata.cudlength = skb->len; x25->calluserdata.cudlength = skb->len;
} }
if (!sock_flag(sk, SOCK_DEAD)) if (!sock_flag(sk, SOCK_DEAD))
...@@ -137,6 +141,9 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp ...@@ -137,6 +141,9 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp
break; break;
} }
case X25_CLEAR_REQUEST: case X25_CLEAR_REQUEST:
if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2))
goto out_clear;
x25_write_internal(sk, X25_CLEAR_CONFIRMATION); x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
x25_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]); x25_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]);
break; break;
...@@ -164,6 +171,9 @@ static int x25_state2_machine(struct sock *sk, struct sk_buff *skb, int frametyp ...@@ -164,6 +171,9 @@ static int x25_state2_machine(struct sock *sk, struct sk_buff *skb, int frametyp
switch (frametype) { switch (frametype) {
case X25_CLEAR_REQUEST: case X25_CLEAR_REQUEST:
if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2))
goto out_clear;
x25_write_internal(sk, X25_CLEAR_CONFIRMATION); x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
x25_disconnect(sk, 0, skb->data[3], skb->data[4]); x25_disconnect(sk, 0, skb->data[3], skb->data[4]);
break; break;
...@@ -177,6 +187,11 @@ static int x25_state2_machine(struct sock *sk, struct sk_buff *skb, int frametyp ...@@ -177,6 +187,11 @@ static int x25_state2_machine(struct sock *sk, struct sk_buff *skb, int frametyp
} }
return 0; return 0;
out_clear:
x25_write_internal(sk, X25_CLEAR_REQUEST);
x25_start_t23timer(sk);
return 0;
} }
/* /*
...@@ -206,6 +221,9 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp ...@@ -206,6 +221,9 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
break; break;
case X25_CLEAR_REQUEST: case X25_CLEAR_REQUEST:
if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2))
goto out_clear;
x25_write_internal(sk, X25_CLEAR_CONFIRMATION); x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
x25_disconnect(sk, 0, skb->data[3], skb->data[4]); x25_disconnect(sk, 0, skb->data[3], skb->data[4]);
break; break;
...@@ -304,6 +322,12 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp ...@@ -304,6 +322,12 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
} }
return queued; return queued;
out_clear:
x25_write_internal(sk, X25_CLEAR_REQUEST);
x25->state = X25_STATE_2;
x25_start_t23timer(sk);
return 0;
} }
/* /*
...@@ -313,13 +337,13 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp ...@@ -313,13 +337,13 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
*/ */
static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametype) static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametype)
{ {
struct x25_sock *x25 = x25_sk(sk);
switch (frametype) { switch (frametype) {
case X25_RESET_REQUEST: case X25_RESET_REQUEST:
x25_write_internal(sk, X25_RESET_CONFIRMATION); x25_write_internal(sk, X25_RESET_CONFIRMATION);
case X25_RESET_CONFIRMATION: { case X25_RESET_CONFIRMATION: {
struct x25_sock *x25 = x25_sk(sk);
x25_stop_timer(sk); x25_stop_timer(sk);
x25->condition = 0x00; x25->condition = 0x00;
x25->va = 0; x25->va = 0;
...@@ -331,6 +355,9 @@ static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametyp ...@@ -331,6 +355,9 @@ static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametyp
break; break;
} }
case X25_CLEAR_REQUEST: case X25_CLEAR_REQUEST:
if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2))
goto out_clear;
x25_write_internal(sk, X25_CLEAR_CONFIRMATION); x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
x25_disconnect(sk, 0, skb->data[3], skb->data[4]); x25_disconnect(sk, 0, skb->data[3], skb->data[4]);
break; break;
...@@ -340,6 +367,12 @@ static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametyp ...@@ -340,6 +367,12 @@ static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametyp
} }
return 0; return 0;
out_clear:
x25_write_internal(sk, X25_CLEAR_REQUEST);
x25->state = X25_STATE_2;
x25_start_t23timer(sk);
return 0;
} }
/* Higher level upcall for a LAPB frame */ /* Higher level upcall for a LAPB frame */
......
...@@ -90,6 +90,9 @@ void x25_link_control(struct sk_buff *skb, struct x25_neigh *nb, ...@@ -90,6 +90,9 @@ void x25_link_control(struct sk_buff *skb, struct x25_neigh *nb,
break; break;
case X25_DIAGNOSTIC: case X25_DIAGNOSTIC:
if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 4))
break;
printk(KERN_WARNING "x25: diagnostic #%d - %02X %02X %02X\n", printk(KERN_WARNING "x25: diagnostic #%d - %02X %02X %02X\n",
skb->data[3], skb->data[4], skb->data[3], skb->data[4],
skb->data[5], skb->data[6]); skb->data[5], skb->data[6]);
......
...@@ -269,7 +269,11 @@ int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q, ...@@ -269,7 +269,11 @@ int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q,
int *d, int *m) int *d, int *m)
{ {
struct x25_sock *x25 = x25_sk(sk); struct x25_sock *x25 = x25_sk(sk);
unsigned char *frame = skb->data; unsigned char *frame;
if (!pskb_may_pull(skb, X25_STD_MIN_LEN))
return X25_ILLEGAL;
frame = skb->data;
*ns = *nr = *q = *d = *m = 0; *ns = *nr = *q = *d = *m = 0;
...@@ -294,6 +298,10 @@ int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q, ...@@ -294,6 +298,10 @@ int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q,
if (frame[2] == X25_RR || if (frame[2] == X25_RR ||
frame[2] == X25_RNR || frame[2] == X25_RNR ||
frame[2] == X25_REJ) { frame[2] == X25_REJ) {
if (!pskb_may_pull(skb, X25_EXT_MIN_LEN))
return X25_ILLEGAL;
frame = skb->data;
*nr = (frame[3] >> 1) & 0x7F; *nr = (frame[3] >> 1) & 0x7F;
return frame[2]; return frame[2];
} }
...@@ -308,6 +316,10 @@ int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q, ...@@ -308,6 +316,10 @@ int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q,
if (x25->neighbour->extended) { if (x25->neighbour->extended) {
if ((frame[2] & 0x01) == X25_DATA) { if ((frame[2] & 0x01) == X25_DATA) {
if (!pskb_may_pull(skb, X25_EXT_MIN_LEN))
return X25_ILLEGAL;
frame = skb->data;
*q = (frame[0] & X25_Q_BIT) == X25_Q_BIT; *q = (frame[0] & X25_Q_BIT) == X25_Q_BIT;
*d = (frame[0] & X25_D_BIT) == X25_D_BIT; *d = (frame[0] & X25_D_BIT) == X25_D_BIT;
*m = (frame[3] & X25_EXT_M_BIT) == X25_EXT_M_BIT; *m = (frame[3] & X25_EXT_M_BIT) == X25_EXT_M_BIT;
......
...@@ -1097,6 +1097,7 @@ void security_sk_clone(const struct sock *sk, struct sock *newsk) ...@@ -1097,6 +1097,7 @@ void security_sk_clone(const struct sock *sk, struct sock *newsk)
{ {
security_ops->sk_clone_security(sk, newsk); security_ops->sk_clone_security(sk, newsk);
} }
EXPORT_SYMBOL(security_sk_clone);
void security_sk_classify_flow(struct sock *sk, struct flowi *fl) void security_sk_classify_flow(struct sock *sk, struct flowi *fl)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment