Commit 1ee18329 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull networking fixes from David Miller:

 1) If the timing is wrong we can indefinitely stop generating new ipv6
    temporary addresses, from Marcus Huewe.

 2) Don't double free per-cpu stats in ipv6 SIT tunnel driver, from Cong
    Wang.

 3) Put protections in place so that AF_PACKET is not able to submit
    packets which don't even have a link level header to drivers. From
    Willem de Bruijn.

 4) Fix memory leaks in ipv4 and ipv6 multicast code, from Hangbin Liu.

 5) Don't use udp_ioctl() in l2tp code, UDP version expects a UDP socket
    and that doesn't go over very well when it is passed an L2TP one.
    Fix from Eric Dumazet.

 6) Don't crash on NULL pointer in phy_attach_direct(), from Florian
    Fainelli.

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net:
  l2tp: do not use udp_ioctl()
  xen-netfront: Delete rx_refill_timer in xennet_disconnect_backend()
  NET: mkiss: Fix panic
  net: hns: Fix the device being used for dma mapping during TX
  net: phy: Initialize mdio clock at probe function
  igmp, mld: Fix memory leak in igmpv3/mld_del_delrec()
  xen-netfront: Improve error handling during initialization
  sierra_net: Skip validating irrelevant fields for IDLE LSIs
  sierra_net: Add support for IPv6 and Dual-Stack Link Sense Indications
  kcm: fix 0-length case for kcm_sendmsg()
  xen-netfront: Rework the fix for Rx stall during OOM and network stress
  net: phy: Fix PHY module checks and NULL deref in phy_attach_direct()
  net: thunderx: Fix PHY autoneg for SGMII QLM mode
  net: dsa: Do not destroy invalid network devices
  ping: fix a null pointer dereference
  packet: round up linear to header len
  net: introduce device min_header_len
  sit: fix a double free on error path
  lwtunnel: valid encap attr check should return 0 when lwtunnel is disabled
  ipv6: addrconf: fix generation of new temporary addresses
parents a9dbf5c8 72fb96e7
...@@ -31,6 +31,7 @@ struct lmac { ...@@ -31,6 +31,7 @@ struct lmac {
u8 lmac_type; u8 lmac_type;
u8 lane_to_sds; u8 lane_to_sds;
bool use_training; bool use_training;
bool autoneg;
bool link_up; bool link_up;
int lmacid; /* ID within BGX */ int lmacid; /* ID within BGX */
int lmacid_bd; /* ID on board */ int lmacid_bd; /* ID on board */
...@@ -461,7 +462,17 @@ static int bgx_lmac_sgmii_init(struct bgx *bgx, struct lmac *lmac) ...@@ -461,7 +462,17 @@ static int bgx_lmac_sgmii_init(struct bgx *bgx, struct lmac *lmac)
/* power down, reset autoneg, autoneg enable */ /* power down, reset autoneg, autoneg enable */
cfg = bgx_reg_read(bgx, lmacid, BGX_GMP_PCS_MRX_CTL); cfg = bgx_reg_read(bgx, lmacid, BGX_GMP_PCS_MRX_CTL);
cfg &= ~PCS_MRX_CTL_PWR_DN; cfg &= ~PCS_MRX_CTL_PWR_DN;
cfg |= (PCS_MRX_CTL_RST_AN | PCS_MRX_CTL_AN_EN); cfg |= PCS_MRX_CTL_RST_AN;
if (lmac->phydev) {
cfg |= PCS_MRX_CTL_AN_EN;
} else {
/* In scenarios where PHY driver is not present or it's a
* non-standard PHY, FW sets AN_EN to inform Linux driver
* to do auto-neg and link polling or not.
*/
if (cfg & PCS_MRX_CTL_AN_EN)
lmac->autoneg = true;
}
bgx_reg_write(bgx, lmacid, BGX_GMP_PCS_MRX_CTL, cfg); bgx_reg_write(bgx, lmacid, BGX_GMP_PCS_MRX_CTL, cfg);
if (lmac->lmac_type == BGX_MODE_QSGMII) { if (lmac->lmac_type == BGX_MODE_QSGMII) {
...@@ -472,7 +483,7 @@ static int bgx_lmac_sgmii_init(struct bgx *bgx, struct lmac *lmac) ...@@ -472,7 +483,7 @@ static int bgx_lmac_sgmii_init(struct bgx *bgx, struct lmac *lmac)
return 0; return 0;
} }
if (lmac->lmac_type == BGX_MODE_SGMII) { if ((lmac->lmac_type == BGX_MODE_SGMII) && lmac->phydev) {
if (bgx_poll_reg(bgx, lmacid, BGX_GMP_PCS_MRX_STATUS, if (bgx_poll_reg(bgx, lmacid, BGX_GMP_PCS_MRX_STATUS,
PCS_MRX_STATUS_AN_CPT, false)) { PCS_MRX_STATUS_AN_CPT, false)) {
dev_err(&bgx->pdev->dev, "BGX AN_CPT not completed\n"); dev_err(&bgx->pdev->dev, "BGX AN_CPT not completed\n");
...@@ -678,12 +689,71 @@ static int bgx_xaui_check_link(struct lmac *lmac) ...@@ -678,12 +689,71 @@ static int bgx_xaui_check_link(struct lmac *lmac)
return -1; return -1;
} }
static void bgx_poll_for_sgmii_link(struct lmac *lmac)
{
u64 pcs_link, an_result;
u8 speed;
pcs_link = bgx_reg_read(lmac->bgx, lmac->lmacid,
BGX_GMP_PCS_MRX_STATUS);
/*Link state bit is sticky, read it again*/
if (!(pcs_link & PCS_MRX_STATUS_LINK))
pcs_link = bgx_reg_read(lmac->bgx, lmac->lmacid,
BGX_GMP_PCS_MRX_STATUS);
if (bgx_poll_reg(lmac->bgx, lmac->lmacid, BGX_GMP_PCS_MRX_STATUS,
PCS_MRX_STATUS_AN_CPT, false)) {
lmac->link_up = false;
lmac->last_speed = SPEED_UNKNOWN;
lmac->last_duplex = DUPLEX_UNKNOWN;
goto next_poll;
}
lmac->link_up = ((pcs_link & PCS_MRX_STATUS_LINK) != 0) ? true : false;
an_result = bgx_reg_read(lmac->bgx, lmac->lmacid,
BGX_GMP_PCS_ANX_AN_RESULTS);
speed = (an_result >> 3) & 0x3;
lmac->last_duplex = (an_result >> 1) & 0x1;
switch (speed) {
case 0:
lmac->last_speed = 10;
break;
case 1:
lmac->last_speed = 100;
break;
case 2:
lmac->last_speed = 1000;
break;
default:
lmac->link_up = false;
lmac->last_speed = SPEED_UNKNOWN;
lmac->last_duplex = DUPLEX_UNKNOWN;
break;
}
next_poll:
if (lmac->last_link != lmac->link_up) {
if (lmac->link_up)
bgx_sgmii_change_link_state(lmac);
lmac->last_link = lmac->link_up;
}
queue_delayed_work(lmac->check_link, &lmac->dwork, HZ * 3);
}
static void bgx_poll_for_link(struct work_struct *work) static void bgx_poll_for_link(struct work_struct *work)
{ {
struct lmac *lmac; struct lmac *lmac;
u64 spu_link, smu_link; u64 spu_link, smu_link;
lmac = container_of(work, struct lmac, dwork.work); lmac = container_of(work, struct lmac, dwork.work);
if (lmac->is_sgmii) {
bgx_poll_for_sgmii_link(lmac);
return;
}
/* Receive link is latching low. Force it high and verify it */ /* Receive link is latching low. Force it high and verify it */
bgx_reg_modify(lmac->bgx, lmac->lmacid, bgx_reg_modify(lmac->bgx, lmac->lmacid,
...@@ -775,9 +845,21 @@ static int bgx_lmac_enable(struct bgx *bgx, u8 lmacid) ...@@ -775,9 +845,21 @@ static int bgx_lmac_enable(struct bgx *bgx, u8 lmacid)
(lmac->lmac_type != BGX_MODE_XLAUI) && (lmac->lmac_type != BGX_MODE_XLAUI) &&
(lmac->lmac_type != BGX_MODE_40G_KR) && (lmac->lmac_type != BGX_MODE_40G_KR) &&
(lmac->lmac_type != BGX_MODE_10G_KR)) { (lmac->lmac_type != BGX_MODE_10G_KR)) {
if (!lmac->phydev) if (!lmac->phydev) {
return -ENODEV; if (lmac->autoneg) {
bgx_reg_write(bgx, lmacid,
BGX_GMP_PCS_LINKX_TIMER,
PCS_LINKX_TIMER_COUNT);
goto poll;
} else {
/* Default to below link speed and duplex */
lmac->link_up = true;
lmac->last_speed = 1000;
lmac->last_duplex = 1;
bgx_sgmii_change_link_state(lmac);
return 0;
}
}
lmac->phydev->dev_flags = 0; lmac->phydev->dev_flags = 0;
if (phy_connect_direct(&lmac->netdev, lmac->phydev, if (phy_connect_direct(&lmac->netdev, lmac->phydev,
...@@ -786,15 +868,17 @@ static int bgx_lmac_enable(struct bgx *bgx, u8 lmacid) ...@@ -786,15 +868,17 @@ static int bgx_lmac_enable(struct bgx *bgx, u8 lmacid)
return -ENODEV; return -ENODEV;
phy_start_aneg(lmac->phydev); phy_start_aneg(lmac->phydev);
} else { return 0;
lmac->check_link = alloc_workqueue("check_link", WQ_UNBOUND |
WQ_MEM_RECLAIM, 1);
if (!lmac->check_link)
return -ENOMEM;
INIT_DELAYED_WORK(&lmac->dwork, bgx_poll_for_link);
queue_delayed_work(lmac->check_link, &lmac->dwork, 0);
} }
poll:
lmac->check_link = alloc_workqueue("check_link", WQ_UNBOUND |
WQ_MEM_RECLAIM, 1);
if (!lmac->check_link)
return -ENOMEM;
INIT_DELAYED_WORK(&lmac->dwork, bgx_poll_for_link);
queue_delayed_work(lmac->check_link, &lmac->dwork, 0);
return 0; return 0;
} }
......
...@@ -153,10 +153,15 @@ ...@@ -153,10 +153,15 @@
#define PCS_MRX_CTL_LOOPBACK1 BIT_ULL(14) #define PCS_MRX_CTL_LOOPBACK1 BIT_ULL(14)
#define PCS_MRX_CTL_RESET BIT_ULL(15) #define PCS_MRX_CTL_RESET BIT_ULL(15)
#define BGX_GMP_PCS_MRX_STATUS 0x30008 #define BGX_GMP_PCS_MRX_STATUS 0x30008
#define PCS_MRX_STATUS_LINK BIT_ULL(2)
#define PCS_MRX_STATUS_AN_CPT BIT_ULL(5) #define PCS_MRX_STATUS_AN_CPT BIT_ULL(5)
#define BGX_GMP_PCS_ANX_ADV 0x30010
#define BGX_GMP_PCS_ANX_AN_RESULTS 0x30020 #define BGX_GMP_PCS_ANX_AN_RESULTS 0x30020
#define BGX_GMP_PCS_LINKX_TIMER 0x30040
#define PCS_LINKX_TIMER_COUNT 0x1E84
#define BGX_GMP_PCS_SGM_AN_ADV 0x30068 #define BGX_GMP_PCS_SGM_AN_ADV 0x30068
#define BGX_GMP_PCS_MISCX_CTL 0x30078 #define BGX_GMP_PCS_MISCX_CTL 0x30078
#define PCS_MISC_CTL_MODE BIT_ULL(8)
#define PCS_MISC_CTL_DISP_EN BIT_ULL(13) #define PCS_MISC_CTL_DISP_EN BIT_ULL(13)
#define PCS_MISC_CTL_GMX_ENO BIT_ULL(11) #define PCS_MISC_CTL_GMX_ENO BIT_ULL(11)
#define PCS_MISC_CTL_SAMP_PT_MASK 0x7Full #define PCS_MISC_CTL_SAMP_PT_MASK 0x7Full
......
...@@ -305,8 +305,8 @@ int hns_nic_net_xmit_hw(struct net_device *ndev, ...@@ -305,8 +305,8 @@ int hns_nic_net_xmit_hw(struct net_device *ndev,
struct hns_nic_ring_data *ring_data) struct hns_nic_ring_data *ring_data)
{ {
struct hns_nic_priv *priv = netdev_priv(ndev); struct hns_nic_priv *priv = netdev_priv(ndev);
struct device *dev = priv->dev;
struct hnae_ring *ring = ring_data->ring; struct hnae_ring *ring = ring_data->ring;
struct device *dev = ring_to_dev(ring);
struct netdev_queue *dev_queue; struct netdev_queue *dev_queue;
struct skb_frag_struct *frag; struct skb_frag_struct *frag;
int buf_num; int buf_num;
......
...@@ -648,8 +648,8 @@ static void ax_setup(struct net_device *dev) ...@@ -648,8 +648,8 @@ static void ax_setup(struct net_device *dev)
{ {
/* Finish setting up the DEVICE info. */ /* Finish setting up the DEVICE info. */
dev->mtu = AX_MTU; dev->mtu = AX_MTU;
dev->hard_header_len = 0; dev->hard_header_len = AX25_MAX_HEADER_LEN;
dev->addr_len = 0; dev->addr_len = AX25_ADDR_LEN;
dev->type = ARPHRD_AX25; dev->type = ARPHRD_AX25;
dev->tx_queue_len = 10; dev->tx_queue_len = 10;
dev->header_ops = &ax25_header_ops; dev->header_ops = &ax25_header_ops;
......
...@@ -164,6 +164,7 @@ static void loopback_setup(struct net_device *dev) ...@@ -164,6 +164,7 @@ static void loopback_setup(struct net_device *dev)
{ {
dev->mtu = 64 * 1024; dev->mtu = 64 * 1024;
dev->hard_header_len = ETH_HLEN; /* 14 */ dev->hard_header_len = ETH_HLEN; /* 14 */
dev->min_header_len = ETH_HLEN; /* 14 */
dev->addr_len = ETH_ALEN; /* 6 */ dev->addr_len = ETH_ALEN; /* 6 */
dev->type = ARPHRD_LOOPBACK; /* 0x0001*/ dev->type = ARPHRD_LOOPBACK; /* 0x0001*/
dev->flags = IFF_LOOPBACK; dev->flags = IFF_LOOPBACK;
......
...@@ -81,8 +81,6 @@ static int iproc_mdio_read(struct mii_bus *bus, int phy_id, int reg) ...@@ -81,8 +81,6 @@ static int iproc_mdio_read(struct mii_bus *bus, int phy_id, int reg)
if (rc) if (rc)
return rc; return rc;
iproc_mdio_config_clk(priv->base);
/* Prepare the read operation */ /* Prepare the read operation */
cmd = (MII_DATA_TA_VAL << MII_DATA_TA_SHIFT) | cmd = (MII_DATA_TA_VAL << MII_DATA_TA_SHIFT) |
(reg << MII_DATA_RA_SHIFT) | (reg << MII_DATA_RA_SHIFT) |
...@@ -112,8 +110,6 @@ static int iproc_mdio_write(struct mii_bus *bus, int phy_id, ...@@ -112,8 +110,6 @@ static int iproc_mdio_write(struct mii_bus *bus, int phy_id,
if (rc) if (rc)
return rc; return rc;
iproc_mdio_config_clk(priv->base);
/* Prepare the write operation */ /* Prepare the write operation */
cmd = (MII_DATA_TA_VAL << MII_DATA_TA_SHIFT) | cmd = (MII_DATA_TA_VAL << MII_DATA_TA_SHIFT) |
(reg << MII_DATA_RA_SHIFT) | (reg << MII_DATA_RA_SHIFT) |
...@@ -163,6 +159,8 @@ static int iproc_mdio_probe(struct platform_device *pdev) ...@@ -163,6 +159,8 @@ static int iproc_mdio_probe(struct platform_device *pdev)
bus->read = iproc_mdio_read; bus->read = iproc_mdio_read;
bus->write = iproc_mdio_write; bus->write = iproc_mdio_write;
iproc_mdio_config_clk(priv->base);
rc = of_mdiobus_register(bus, pdev->dev.of_node); rc = of_mdiobus_register(bus, pdev->dev.of_node);
if (rc) { if (rc) {
dev_err(&pdev->dev, "MDIO bus registration failed\n"); dev_err(&pdev->dev, "MDIO bus registration failed\n");
......
...@@ -908,6 +908,7 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, ...@@ -908,6 +908,7 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
struct module *ndev_owner = dev->dev.parent->driver->owner; struct module *ndev_owner = dev->dev.parent->driver->owner;
struct mii_bus *bus = phydev->mdio.bus; struct mii_bus *bus = phydev->mdio.bus;
struct device *d = &phydev->mdio.dev; struct device *d = &phydev->mdio.dev;
bool using_genphy = false;
int err; int err;
/* For Ethernet device drivers that register their own MDIO bus, we /* For Ethernet device drivers that register their own MDIO bus, we
...@@ -920,11 +921,6 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, ...@@ -920,11 +921,6 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
return -EIO; return -EIO;
} }
if (!try_module_get(d->driver->owner)) {
dev_err(&dev->dev, "failed to get the device driver module\n");
return -EIO;
}
get_device(d); get_device(d);
/* Assume that if there is no driver, that it doesn't /* Assume that if there is no driver, that it doesn't
...@@ -938,12 +934,22 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, ...@@ -938,12 +934,22 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
d->driver = d->driver =
&genphy_driver[GENPHY_DRV_1G].mdiodrv.driver; &genphy_driver[GENPHY_DRV_1G].mdiodrv.driver;
using_genphy = true;
}
if (!try_module_get(d->driver->owner)) {
dev_err(&dev->dev, "failed to get the device driver module\n");
err = -EIO;
goto error_put_device;
}
if (using_genphy) {
err = d->driver->probe(d); err = d->driver->probe(d);
if (err >= 0) if (err >= 0)
err = device_bind_driver(d); err = device_bind_driver(d);
if (err) if (err)
goto error; goto error_module_put;
} }
if (phydev->attached_dev) { if (phydev->attached_dev) {
...@@ -980,9 +986,14 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, ...@@ -980,9 +986,14 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
return err; return err;
error: error:
/* phy_detach() does all of the cleanup below */
phy_detach(phydev); phy_detach(phydev);
put_device(d); return err;
error_module_put:
module_put(d->driver->owner); module_put(d->driver->owner);
error_put_device:
put_device(d);
if (ndev_owner != bus->owner) if (ndev_owner != bus->owner)
module_put(bus->owner); module_put(bus->owner);
return err; return err;
...@@ -1045,6 +1056,8 @@ void phy_detach(struct phy_device *phydev) ...@@ -1045,6 +1056,8 @@ void phy_detach(struct phy_device *phydev)
phy_led_triggers_unregister(phydev); phy_led_triggers_unregister(phydev);
module_put(phydev->mdio.dev.driver->owner);
/* If the device had no specific driver before (i.e. - it /* If the device had no specific driver before (i.e. - it
* was using the generic driver), we unbind the device * was using the generic driver), we unbind the device
* from the generic driver so that there's a chance a * from the generic driver so that there's a chance a
...@@ -1065,7 +1078,6 @@ void phy_detach(struct phy_device *phydev) ...@@ -1065,7 +1078,6 @@ void phy_detach(struct phy_device *phydev)
bus = phydev->mdio.bus; bus = phydev->mdio.bus;
put_device(&phydev->mdio.dev); put_device(&phydev->mdio.dev);
module_put(phydev->mdio.dev.driver->owner);
if (ndev_owner != bus->owner) if (ndev_owner != bus->owner)
module_put(bus->owner); module_put(bus->owner);
} }
......
...@@ -73,8 +73,6 @@ static atomic_t iface_counter = ATOMIC_INIT(0); ...@@ -73,8 +73,6 @@ static atomic_t iface_counter = ATOMIC_INIT(0);
/* Private data structure */ /* Private data structure */
struct sierra_net_data { struct sierra_net_data {
u8 ethr_hdr_tmpl[ETH_HLEN]; /* ethernet header template for rx'd pkts */
u16 link_up; /* air link up or down */ u16 link_up; /* air link up or down */
u8 tx_hdr_template[4]; /* part of HIP hdr for tx'd packets */ u8 tx_hdr_template[4]; /* part of HIP hdr for tx'd packets */
...@@ -122,6 +120,7 @@ struct param { ...@@ -122,6 +120,7 @@ struct param {
/* LSI Protocol types */ /* LSI Protocol types */
#define SIERRA_NET_PROTOCOL_UMTS 0x01 #define SIERRA_NET_PROTOCOL_UMTS 0x01
#define SIERRA_NET_PROTOCOL_UMTS_DS 0x04
/* LSI Coverage */ /* LSI Coverage */
#define SIERRA_NET_COVERAGE_NONE 0x00 #define SIERRA_NET_COVERAGE_NONE 0x00
#define SIERRA_NET_COVERAGE_NOPACKET 0x01 #define SIERRA_NET_COVERAGE_NOPACKET 0x01
...@@ -129,7 +128,8 @@ struct param { ...@@ -129,7 +128,8 @@ struct param {
/* LSI Session */ /* LSI Session */
#define SIERRA_NET_SESSION_IDLE 0x00 #define SIERRA_NET_SESSION_IDLE 0x00
/* LSI Link types */ /* LSI Link types */
#define SIERRA_NET_AS_LINK_TYPE_IPv4 0x00 #define SIERRA_NET_AS_LINK_TYPE_IPV4 0x00
#define SIERRA_NET_AS_LINK_TYPE_IPV6 0x02
struct lsi_umts { struct lsi_umts {
u8 protocol; u8 protocol;
...@@ -137,9 +137,14 @@ struct lsi_umts { ...@@ -137,9 +137,14 @@ struct lsi_umts {
__be16 length; __be16 length;
/* eventually use a union for the rest - assume umts for now */ /* eventually use a union for the rest - assume umts for now */
u8 coverage; u8 coverage;
u8 unused2[41]; u8 network_len; /* network name len */
u8 network[40]; /* network name (UCS2, bigendian) */
u8 session_state; u8 session_state;
u8 unused3[33]; u8 unused3[33];
} __packed;
struct lsi_umts_single {
struct lsi_umts lsi;
u8 link_type; u8 link_type;
u8 pdp_addr_len; /* NW-supplied PDP address len */ u8 pdp_addr_len; /* NW-supplied PDP address len */
u8 pdp_addr[16]; /* NW-supplied PDP address (bigendian)) */ u8 pdp_addr[16]; /* NW-supplied PDP address (bigendian)) */
...@@ -158,10 +163,31 @@ struct lsi_umts { ...@@ -158,10 +163,31 @@ struct lsi_umts {
u8 reserved[8]; u8 reserved[8];
} __packed; } __packed;
struct lsi_umts_dual {
struct lsi_umts lsi;
u8 pdp_addr4_len; /* NW-supplied PDP IPv4 address len */
u8 pdp_addr4[4]; /* NW-supplied PDP IPv4 address (bigendian)) */
u8 pdp_addr6_len; /* NW-supplied PDP IPv6 address len */
u8 pdp_addr6[16]; /* NW-supplied PDP IPv6 address (bigendian)) */
u8 unused4[23];
u8 dns1_addr4_len; /* NW-supplied 1st DNS v4 address len (bigendian) */
u8 dns1_addr4[4]; /* NW-supplied 1st DNS v4 address */
u8 dns1_addr6_len; /* NW-supplied 1st DNS v6 address len */
u8 dns1_addr6[16]; /* NW-supplied 1st DNS v6 address (bigendian)*/
u8 dns2_addr4_len; /* NW-supplied 2nd DNS v4 address len (bigendian) */
u8 dns2_addr4[4]; /* NW-supplied 2nd DNS v4 address */
u8 dns2_addr6_len; /* NW-supplied 2nd DNS v6 address len */
u8 dns2_addr6[16]; /* NW-supplied 2nd DNS v6 address (bigendian)*/
u8 unused5[68];
} __packed;
#define SIERRA_NET_LSI_COMMON_LEN 4 #define SIERRA_NET_LSI_COMMON_LEN 4
#define SIERRA_NET_LSI_UMTS_LEN (sizeof(struct lsi_umts)) #define SIERRA_NET_LSI_UMTS_LEN (sizeof(struct lsi_umts_single))
#define SIERRA_NET_LSI_UMTS_STATUS_LEN \ #define SIERRA_NET_LSI_UMTS_STATUS_LEN \
(SIERRA_NET_LSI_UMTS_LEN - SIERRA_NET_LSI_COMMON_LEN) (SIERRA_NET_LSI_UMTS_LEN - SIERRA_NET_LSI_COMMON_LEN)
#define SIERRA_NET_LSI_UMTS_DS_LEN (sizeof(struct lsi_umts_dual))
#define SIERRA_NET_LSI_UMTS_DS_STATUS_LEN \
(SIERRA_NET_LSI_UMTS_DS_LEN - SIERRA_NET_LSI_COMMON_LEN)
/* Forward definitions */ /* Forward definitions */
static void sierra_sync_timer(unsigned long syncdata); static void sierra_sync_timer(unsigned long syncdata);
...@@ -190,10 +216,11 @@ static inline void sierra_net_set_private(struct usbnet *dev, ...@@ -190,10 +216,11 @@ static inline void sierra_net_set_private(struct usbnet *dev,
dev->data[0] = (unsigned long)priv; dev->data[0] = (unsigned long)priv;
} }
/* is packet IPv4 */ /* is packet IPv4/IPv6 */
static inline int is_ip(struct sk_buff *skb) static inline int is_ip(struct sk_buff *skb)
{ {
return skb->protocol == cpu_to_be16(ETH_P_IP); return skb->protocol == cpu_to_be16(ETH_P_IP) ||
skb->protocol == cpu_to_be16(ETH_P_IPV6);
} }
/* /*
...@@ -349,49 +376,54 @@ static inline int sierra_net_is_valid_addrlen(u8 len) ...@@ -349,49 +376,54 @@ static inline int sierra_net_is_valid_addrlen(u8 len)
static int sierra_net_parse_lsi(struct usbnet *dev, char *data, int datalen) static int sierra_net_parse_lsi(struct usbnet *dev, char *data, int datalen)
{ {
struct lsi_umts *lsi = (struct lsi_umts *)data; struct lsi_umts *lsi = (struct lsi_umts *)data;
u32 expected_length;
if (datalen < sizeof(struct lsi_umts)) { if (datalen < sizeof(struct lsi_umts_single)) {
netdev_err(dev->net, "%s: Data length %d, exp %Zu\n", netdev_err(dev->net, "%s: Data length %d, exp >= %Zu\n",
__func__, datalen, __func__, datalen, sizeof(struct lsi_umts_single));
sizeof(struct lsi_umts));
return -1; return -1;
} }
if (lsi->length != cpu_to_be16(SIERRA_NET_LSI_UMTS_STATUS_LEN)) { /* Validate the session state */
netdev_err(dev->net, "%s: LSI_UMTS_STATUS_LEN %d, exp %u\n", if (lsi->session_state == SIERRA_NET_SESSION_IDLE) {
__func__, be16_to_cpu(lsi->length), netdev_err(dev->net, "Session idle, 0x%02x\n",
(u32)SIERRA_NET_LSI_UMTS_STATUS_LEN); lsi->session_state);
return -1; return 0;
} }
/* Validate the protocol - only support UMTS for now */ /* Validate the protocol - only support UMTS for now */
if (lsi->protocol != SIERRA_NET_PROTOCOL_UMTS) { if (lsi->protocol == SIERRA_NET_PROTOCOL_UMTS) {
struct lsi_umts_single *single = (struct lsi_umts_single *)lsi;
/* Validate the link type */
if (single->link_type != SIERRA_NET_AS_LINK_TYPE_IPV4 &&
single->link_type != SIERRA_NET_AS_LINK_TYPE_IPV6) {
netdev_err(dev->net, "Link type unsupported: 0x%02x\n",
single->link_type);
return -1;
}
expected_length = SIERRA_NET_LSI_UMTS_STATUS_LEN;
} else if (lsi->protocol == SIERRA_NET_PROTOCOL_UMTS_DS) {
expected_length = SIERRA_NET_LSI_UMTS_DS_STATUS_LEN;
} else {
netdev_err(dev->net, "Protocol unsupported, 0x%02x\n", netdev_err(dev->net, "Protocol unsupported, 0x%02x\n",
lsi->protocol); lsi->protocol);
return -1; return -1;
} }
/* Validate the link type */ if (be16_to_cpu(lsi->length) != expected_length) {
if (lsi->link_type != SIERRA_NET_AS_LINK_TYPE_IPv4) { netdev_err(dev->net, "%s: LSI_UMTS_STATUS_LEN %d, exp %u\n",
netdev_err(dev->net, "Link type unsupported: 0x%02x\n", __func__, be16_to_cpu(lsi->length), expected_length);
lsi->link_type);
return -1; return -1;
} }
/* Validate the coverage */ /* Validate the coverage */
if (lsi->coverage == SIERRA_NET_COVERAGE_NONE if (lsi->coverage == SIERRA_NET_COVERAGE_NONE ||
|| lsi->coverage == SIERRA_NET_COVERAGE_NOPACKET) { lsi->coverage == SIERRA_NET_COVERAGE_NOPACKET) {
netdev_err(dev->net, "No coverage, 0x%02x\n", lsi->coverage); netdev_err(dev->net, "No coverage, 0x%02x\n", lsi->coverage);
return 0; return 0;
} }
/* Validate the session state */
if (lsi->session_state == SIERRA_NET_SESSION_IDLE) {
netdev_err(dev->net, "Session idle, 0x%02x\n",
lsi->session_state);
return 0;
}
/* Set link_sense true */ /* Set link_sense true */
return 1; return 1;
} }
...@@ -652,7 +684,6 @@ static int sierra_net_bind(struct usbnet *dev, struct usb_interface *intf) ...@@ -652,7 +684,6 @@ static int sierra_net_bind(struct usbnet *dev, struct usb_interface *intf)
u8 numendpoints; u8 numendpoints;
u16 fwattr = 0; u16 fwattr = 0;
int status; int status;
struct ethhdr *eth;
struct sierra_net_data *priv; struct sierra_net_data *priv;
static const u8 sync_tmplate[sizeof(priv->sync_msg)] = { static const u8 sync_tmplate[sizeof(priv->sync_msg)] = {
0x00, 0x00, SIERRA_NET_HIP_MSYNC_ID, 0x00}; 0x00, 0x00, SIERRA_NET_HIP_MSYNC_ID, 0x00};
...@@ -690,11 +721,6 @@ static int sierra_net_bind(struct usbnet *dev, struct usb_interface *intf) ...@@ -690,11 +721,6 @@ static int sierra_net_bind(struct usbnet *dev, struct usb_interface *intf)
dev->net->dev_addr[ETH_ALEN-2] = atomic_inc_return(&iface_counter); dev->net->dev_addr[ETH_ALEN-2] = atomic_inc_return(&iface_counter);
dev->net->dev_addr[ETH_ALEN-1] = ifacenum; dev->net->dev_addr[ETH_ALEN-1] = ifacenum;
/* we will have to manufacture ethernet headers, prepare template */
eth = (struct ethhdr *)priv->ethr_hdr_tmpl;
memcpy(&eth->h_dest, dev->net->dev_addr, ETH_ALEN);
eth->h_proto = cpu_to_be16(ETH_P_IP);
/* prepare shutdown message template */ /* prepare shutdown message template */
memcpy(priv->shdwn_msg, shdwn_tmplate, sizeof(priv->shdwn_msg)); memcpy(priv->shdwn_msg, shdwn_tmplate, sizeof(priv->shdwn_msg));
/* set context index initially to 0 - prepares tx hdr template */ /* set context index initially to 0 - prepares tx hdr template */
...@@ -824,9 +850,14 @@ static int sierra_net_rx_fixup(struct usbnet *dev, struct sk_buff *skb) ...@@ -824,9 +850,14 @@ static int sierra_net_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
skb_pull(skb, hh.hdrlen); skb_pull(skb, hh.hdrlen);
/* We are going to accept this packet, prepare it */ /* We are going to accept this packet, prepare it.
memcpy(skb->data, sierra_net_get_private(dev)->ethr_hdr_tmpl, * In case protocol is IPv6, keep it, otherwise force IPv4.
ETH_HLEN); */
skb_reset_mac_header(skb);
if (eth_hdr(skb)->h_proto != cpu_to_be16(ETH_P_IPV6))
eth_hdr(skb)->h_proto = cpu_to_be16(ETH_P_IP);
eth_zero_addr(eth_hdr(skb)->h_source);
memcpy(eth_hdr(skb)->h_dest, dev->net->dev_addr, ETH_ALEN);
/* Last packet in batch handled by usbnet */ /* Last packet in batch handled by usbnet */
if (hh.payload_len.word == skb->len) if (hh.payload_len.word == skb->len)
......
...@@ -281,6 +281,7 @@ static void xennet_alloc_rx_buffers(struct netfront_queue *queue) ...@@ -281,6 +281,7 @@ static void xennet_alloc_rx_buffers(struct netfront_queue *queue)
{ {
RING_IDX req_prod = queue->rx.req_prod_pvt; RING_IDX req_prod = queue->rx.req_prod_pvt;
int notify; int notify;
int err = 0;
if (unlikely(!netif_carrier_ok(queue->info->netdev))) if (unlikely(!netif_carrier_ok(queue->info->netdev)))
return; return;
...@@ -295,8 +296,10 @@ static void xennet_alloc_rx_buffers(struct netfront_queue *queue) ...@@ -295,8 +296,10 @@ static void xennet_alloc_rx_buffers(struct netfront_queue *queue)
struct xen_netif_rx_request *req; struct xen_netif_rx_request *req;
skb = xennet_alloc_one_rx_buffer(queue); skb = xennet_alloc_one_rx_buffer(queue);
if (!skb) if (!skb) {
err = -ENOMEM;
break; break;
}
id = xennet_rxidx(req_prod); id = xennet_rxidx(req_prod);
...@@ -320,8 +323,13 @@ static void xennet_alloc_rx_buffers(struct netfront_queue *queue) ...@@ -320,8 +323,13 @@ static void xennet_alloc_rx_buffers(struct netfront_queue *queue)
queue->rx.req_prod_pvt = req_prod; queue->rx.req_prod_pvt = req_prod;
/* Not enough requests? Try again later. */ /* Try again later if there are not enough requests or skb allocation
if (req_prod - queue->rx.sring->req_prod < NET_RX_SLOTS_MIN) { * failed.
* Enough requests is quantified as the sum of newly created slots and
* the unconsumed slots at the backend.
*/
if (req_prod - queue->rx.rsp_cons < NET_RX_SLOTS_MIN ||
unlikely(err)) {
mod_timer(&queue->rx_refill_timer, jiffies + (HZ/10)); mod_timer(&queue->rx_refill_timer, jiffies + (HZ/10));
return; return;
} }
...@@ -1379,6 +1387,8 @@ static void xennet_disconnect_backend(struct netfront_info *info) ...@@ -1379,6 +1387,8 @@ static void xennet_disconnect_backend(struct netfront_info *info)
for (i = 0; i < num_queues && info->queues; ++i) { for (i = 0; i < num_queues && info->queues; ++i) {
struct netfront_queue *queue = &info->queues[i]; struct netfront_queue *queue = &info->queues[i];
del_timer_sync(&queue->rx_refill_timer);
if (queue->tx_irq && (queue->tx_irq == queue->rx_irq)) if (queue->tx_irq && (queue->tx_irq == queue->rx_irq))
unbind_from_irqhandler(queue->tx_irq, queue); unbind_from_irqhandler(queue->tx_irq, queue);
if (queue->tx_irq && (queue->tx_irq != queue->rx_irq)) { if (queue->tx_irq && (queue->tx_irq != queue->rx_irq)) {
...@@ -1733,7 +1743,6 @@ static void xennet_destroy_queues(struct netfront_info *info) ...@@ -1733,7 +1743,6 @@ static void xennet_destroy_queues(struct netfront_info *info)
if (netif_running(info->netdev)) if (netif_running(info->netdev))
napi_disable(&queue->napi); napi_disable(&queue->napi);
del_timer_sync(&queue->rx_refill_timer);
netif_napi_del(&queue->napi); netif_napi_del(&queue->napi);
} }
...@@ -1822,27 +1831,19 @@ static int talk_to_netback(struct xenbus_device *dev, ...@@ -1822,27 +1831,19 @@ static int talk_to_netback(struct xenbus_device *dev,
xennet_destroy_queues(info); xennet_destroy_queues(info);
err = xennet_create_queues(info, &num_queues); err = xennet_create_queues(info, &num_queues);
if (err < 0) if (err < 0) {
goto destroy_ring; xenbus_dev_fatal(dev, err, "creating queues");
kfree(info->queues);
info->queues = NULL;
goto out;
}
/* Create shared ring, alloc event channel -- for each queue */ /* Create shared ring, alloc event channel -- for each queue */
for (i = 0; i < num_queues; ++i) { for (i = 0; i < num_queues; ++i) {
queue = &info->queues[i]; queue = &info->queues[i];
err = setup_netfront(dev, queue, feature_split_evtchn); err = setup_netfront(dev, queue, feature_split_evtchn);
if (err) { if (err)
/* setup_netfront() will tidy up the current goto destroy_ring;
* queue on error, but we need to clean up
* those already allocated.
*/
if (i > 0) {
rtnl_lock();
netif_set_real_num_tx_queues(info->netdev, i);
rtnl_unlock();
goto destroy_ring;
} else {
goto out;
}
}
} }
again: again:
...@@ -1932,9 +1933,10 @@ static int talk_to_netback(struct xenbus_device *dev, ...@@ -1932,9 +1933,10 @@ static int talk_to_netback(struct xenbus_device *dev,
xenbus_transaction_end(xbt, 1); xenbus_transaction_end(xbt, 1);
destroy_ring: destroy_ring:
xennet_disconnect_backend(info); xennet_disconnect_backend(info);
kfree(info->queues); xennet_destroy_queues(info);
info->queues = NULL;
out: out:
unregister_netdev(info->netdev);
xennet_free_netdev(info->netdev);
return err; return err;
} }
......
...@@ -1511,6 +1511,7 @@ enum netdev_priv_flags { ...@@ -1511,6 +1511,7 @@ enum netdev_priv_flags {
* @max_mtu: Interface Maximum MTU value * @max_mtu: Interface Maximum MTU value
* @type: Interface hardware type * @type: Interface hardware type
* @hard_header_len: Maximum hardware header length. * @hard_header_len: Maximum hardware header length.
* @min_header_len: Minimum hardware header length
* *
* @needed_headroom: Extra headroom the hardware may need, but not in all * @needed_headroom: Extra headroom the hardware may need, but not in all
* cases can this be guaranteed * cases can this be guaranteed
...@@ -1728,6 +1729,7 @@ struct net_device { ...@@ -1728,6 +1729,7 @@ struct net_device {
unsigned int max_mtu; unsigned int max_mtu;
unsigned short type; unsigned short type;
unsigned short hard_header_len; unsigned short hard_header_len;
unsigned short min_header_len;
unsigned short needed_headroom; unsigned short needed_headroom;
unsigned short needed_tailroom; unsigned short needed_tailroom;
...@@ -2694,6 +2696,8 @@ static inline bool dev_validate_header(const struct net_device *dev, ...@@ -2694,6 +2696,8 @@ static inline bool dev_validate_header(const struct net_device *dev,
{ {
if (likely(len >= dev->hard_header_len)) if (likely(len >= dev->hard_header_len))
return true; return true;
if (len < dev->min_header_len)
return false;
if (capable(CAP_SYS_RAWIO)) { if (capable(CAP_SYS_RAWIO)) {
memset(ll_header + len, 0, dev->hard_header_len - len); memset(ll_header + len, 0, dev->hard_header_len - len);
......
...@@ -178,7 +178,10 @@ static inline int lwtunnel_valid_encap_type(u16 encap_type) ...@@ -178,7 +178,10 @@ static inline int lwtunnel_valid_encap_type(u16 encap_type)
} }
static inline int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int len) static inline int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int len)
{ {
return -EOPNOTSUPP; /* return 0 since we are not walking attr looking for
* RTA_ENCAP_TYPE attribute on nexthops.
*/
return 0;
} }
static inline int lwtunnel_build_state(struct net_device *dev, u16 encap_type, static inline int lwtunnel_build_state(struct net_device *dev, u16 encap_type,
......
...@@ -273,6 +273,7 @@ static int dsa_user_port_apply(struct device_node *port, u32 index, ...@@ -273,6 +273,7 @@ static int dsa_user_port_apply(struct device_node *port, u32 index,
if (err) { if (err) {
dev_warn(ds->dev, "Failed to create slave %d: %d\n", dev_warn(ds->dev, "Failed to create slave %d: %d\n",
index, err); index, err);
ds->ports[index].netdev = NULL;
return err; return err;
} }
......
...@@ -356,6 +356,7 @@ void ether_setup(struct net_device *dev) ...@@ -356,6 +356,7 @@ void ether_setup(struct net_device *dev)
dev->header_ops = &eth_header_ops; dev->header_ops = &eth_header_ops;
dev->type = ARPHRD_ETHER; dev->type = ARPHRD_ETHER;
dev->hard_header_len = ETH_HLEN; dev->hard_header_len = ETH_HLEN;
dev->min_header_len = ETH_HLEN;
dev->mtu = ETH_DATA_LEN; dev->mtu = ETH_DATA_LEN;
dev->min_mtu = ETH_MIN_MTU; dev->min_mtu = ETH_MIN_MTU;
dev->max_mtu = ETH_DATA_LEN; dev->max_mtu = ETH_DATA_LEN;
......
...@@ -1172,6 +1172,7 @@ static void igmpv3_del_delrec(struct in_device *in_dev, struct ip_mc_list *im) ...@@ -1172,6 +1172,7 @@ static void igmpv3_del_delrec(struct in_device *in_dev, struct ip_mc_list *im)
psf->sf_crcount = im->crcount; psf->sf_crcount = im->crcount;
} }
in_dev_put(pmc->interface); in_dev_put(pmc->interface);
kfree(pmc);
} }
spin_unlock_bh(&im->lock); spin_unlock_bh(&im->lock);
} }
......
...@@ -642,6 +642,8 @@ static int ping_v4_push_pending_frames(struct sock *sk, struct pingfakehdr *pfh, ...@@ -642,6 +642,8 @@ static int ping_v4_push_pending_frames(struct sock *sk, struct pingfakehdr *pfh,
{ {
struct sk_buff *skb = skb_peek(&sk->sk_write_queue); struct sk_buff *skb = skb_peek(&sk->sk_write_queue);
if (!skb)
return 0;
pfh->wcheck = csum_partial((char *)&pfh->icmph, pfh->wcheck = csum_partial((char *)&pfh->icmph,
sizeof(struct icmphdr), pfh->wcheck); sizeof(struct icmphdr), pfh->wcheck);
pfh->icmph.checksum = csum_fold(pfh->wcheck); pfh->icmph.checksum = csum_fold(pfh->wcheck);
......
...@@ -4015,6 +4015,12 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp, bool bump_id) ...@@ -4015,6 +4015,12 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp, bool bump_id)
if (bump_id) if (bump_id)
rt_genid_bump_ipv6(dev_net(dev)); rt_genid_bump_ipv6(dev_net(dev));
/* Make sure that a new temporary address will be created
* before this temporary address becomes deprecated.
*/
if (ifp->flags & IFA_F_TEMPORARY)
addrconf_verify_rtnl();
} }
static void addrconf_dad_run(struct inet6_dev *idev) static void addrconf_dad_run(struct inet6_dev *idev)
......
...@@ -779,6 +779,7 @@ static void mld_del_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im) ...@@ -779,6 +779,7 @@ static void mld_del_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im)
psf->sf_crcount = im->mca_crcount; psf->sf_crcount = im->mca_crcount;
} }
in6_dev_put(pmc->idev); in6_dev_put(pmc->idev);
kfree(pmc);
} }
spin_unlock_bh(&im->mca_lock); spin_unlock_bh(&im->mca_lock);
} }
......
...@@ -1380,6 +1380,7 @@ static int ipip6_tunnel_init(struct net_device *dev) ...@@ -1380,6 +1380,7 @@ static int ipip6_tunnel_init(struct net_device *dev)
err = dst_cache_init(&tunnel->dst_cache, GFP_KERNEL); err = dst_cache_init(&tunnel->dst_cache, GFP_KERNEL);
if (err) { if (err) {
free_percpu(dev->tstats); free_percpu(dev->tstats);
dev->tstats = NULL;
return err; return err;
} }
......
...@@ -929,23 +929,25 @@ static int kcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) ...@@ -929,23 +929,25 @@ static int kcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
goto out_error; goto out_error;
} }
/* New message, alloc head skb */ if (msg_data_left(msg)) {
head = alloc_skb(0, sk->sk_allocation); /* New message, alloc head skb */
while (!head) {
kcm_push(kcm);
err = sk_stream_wait_memory(sk, &timeo);
if (err)
goto out_error;
head = alloc_skb(0, sk->sk_allocation); head = alloc_skb(0, sk->sk_allocation);
} while (!head) {
kcm_push(kcm);
err = sk_stream_wait_memory(sk, &timeo);
if (err)
goto out_error;
skb = head; head = alloc_skb(0, sk->sk_allocation);
}
/* Set ip_summed to CHECKSUM_UNNECESSARY to avoid calling skb = head;
* csum_and_copy_from_iter from skb_do_copy_data_nocache.
*/ /* Set ip_summed to CHECKSUM_UNNECESSARY to avoid calling
skb->ip_summed = CHECKSUM_UNNECESSARY; * csum_and_copy_from_iter from skb_do_copy_data_nocache.
*/
skb->ip_summed = CHECKSUM_UNNECESSARY;
}
start: start:
while (msg_data_left(msg)) { while (msg_data_left(msg)) {
...@@ -1018,10 +1020,12 @@ static int kcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) ...@@ -1018,10 +1020,12 @@ static int kcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
if (eor) { if (eor) {
bool not_busy = skb_queue_empty(&sk->sk_write_queue); bool not_busy = skb_queue_empty(&sk->sk_write_queue);
/* Message complete, queue it on send buffer */ if (head) {
__skb_queue_tail(&sk->sk_write_queue, head); /* Message complete, queue it on send buffer */
kcm->seq_skb = NULL; __skb_queue_tail(&sk->sk_write_queue, head);
KCM_STATS_INCR(kcm->stats.tx_msgs); kcm->seq_skb = NULL;
KCM_STATS_INCR(kcm->stats.tx_msgs);
}
if (msg->msg_flags & MSG_BATCH) { if (msg->msg_flags & MSG_BATCH) {
kcm->tx_wait_more = true; kcm->tx_wait_more = true;
......
...@@ -263,6 +263,7 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, ...@@ -263,6 +263,7 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb,
int l2tp_nl_register_ops(enum l2tp_pwtype pw_type, int l2tp_nl_register_ops(enum l2tp_pwtype pw_type,
const struct l2tp_nl_cmd_ops *ops); const struct l2tp_nl_cmd_ops *ops);
void l2tp_nl_unregister_ops(enum l2tp_pwtype pw_type); void l2tp_nl_unregister_ops(enum l2tp_pwtype pw_type);
int l2tp_ioctl(struct sock *sk, int cmd, unsigned long arg);
/* Session reference counts. Incremented when code obtains a reference /* Session reference counts. Incremented when code obtains a reference
* to a session. * to a session.
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <asm/ioctls.h>
#include <linux/icmp.h> #include <linux/icmp.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
...@@ -553,6 +554,30 @@ static int l2tp_ip_recvmsg(struct sock *sk, struct msghdr *msg, ...@@ -553,6 +554,30 @@ static int l2tp_ip_recvmsg(struct sock *sk, struct msghdr *msg,
return err ? err : copied; return err ? err : copied;
} }
int l2tp_ioctl(struct sock *sk, int cmd, unsigned long arg)
{
struct sk_buff *skb;
int amount;
switch (cmd) {
case SIOCOUTQ:
amount = sk_wmem_alloc_get(sk);
break;
case SIOCINQ:
spin_lock_bh(&sk->sk_receive_queue.lock);
skb = skb_peek(&sk->sk_receive_queue);
amount = skb ? skb->len : 0;
spin_unlock_bh(&sk->sk_receive_queue.lock);
break;
default:
return -ENOIOCTLCMD;
}
return put_user(amount, (int __user *)arg);
}
EXPORT_SYMBOL(l2tp_ioctl);
static struct proto l2tp_ip_prot = { static struct proto l2tp_ip_prot = {
.name = "L2TP/IP", .name = "L2TP/IP",
.owner = THIS_MODULE, .owner = THIS_MODULE,
...@@ -561,7 +586,7 @@ static struct proto l2tp_ip_prot = { ...@@ -561,7 +586,7 @@ static struct proto l2tp_ip_prot = {
.bind = l2tp_ip_bind, .bind = l2tp_ip_bind,
.connect = l2tp_ip_connect, .connect = l2tp_ip_connect,
.disconnect = l2tp_ip_disconnect, .disconnect = l2tp_ip_disconnect,
.ioctl = udp_ioctl, .ioctl = l2tp_ioctl,
.destroy = l2tp_ip_destroy_sock, .destroy = l2tp_ip_destroy_sock,
.setsockopt = ip_setsockopt, .setsockopt = ip_setsockopt,
.getsockopt = ip_getsockopt, .getsockopt = ip_getsockopt,
......
...@@ -722,7 +722,7 @@ static struct proto l2tp_ip6_prot = { ...@@ -722,7 +722,7 @@ static struct proto l2tp_ip6_prot = {
.bind = l2tp_ip6_bind, .bind = l2tp_ip6_bind,
.connect = l2tp_ip6_connect, .connect = l2tp_ip6_connect,
.disconnect = l2tp_ip6_disconnect, .disconnect = l2tp_ip6_disconnect,
.ioctl = udp_ioctl, .ioctl = l2tp_ioctl,
.destroy = l2tp_ip6_destroy_sock, .destroy = l2tp_ip6_destroy_sock,
.setsockopt = ipv6_setsockopt, .setsockopt = ipv6_setsockopt,
.getsockopt = ipv6_getsockopt, .getsockopt = ipv6_getsockopt,
......
...@@ -2755,7 +2755,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) ...@@ -2755,7 +2755,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
struct virtio_net_hdr vnet_hdr = { 0 }; struct virtio_net_hdr vnet_hdr = { 0 };
int offset = 0; int offset = 0;
struct packet_sock *po = pkt_sk(sk); struct packet_sock *po = pkt_sk(sk);
int hlen, tlen; int hlen, tlen, linear;
int extra_len = 0; int extra_len = 0;
/* /*
...@@ -2816,8 +2816,9 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) ...@@ -2816,8 +2816,9 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
err = -ENOBUFS; err = -ENOBUFS;
hlen = LL_RESERVED_SPACE(dev); hlen = LL_RESERVED_SPACE(dev);
tlen = dev->needed_tailroom; tlen = dev->needed_tailroom;
skb = packet_alloc_skb(sk, hlen + tlen, hlen, len, linear = __virtio16_to_cpu(vio_le(), vnet_hdr.hdr_len);
__virtio16_to_cpu(vio_le(), vnet_hdr.hdr_len), linear = max(linear, min_t(int, len, dev->hard_header_len));
skb = packet_alloc_skb(sk, hlen + tlen, hlen, len, linear,
msg->msg_flags & MSG_DONTWAIT, &err); msg->msg_flags & MSG_DONTWAIT, &err);
if (skb == NULL) if (skb == NULL)
goto out_unlock; goto out_unlock;
......
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