]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 27 Jul 2012 01:09:01 +0000 (18:09 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 27 Jul 2012 01:09:01 +0000 (18:09 -0700)
Pull networking updates and fixes from David Miller:

1) Reinstate the no-ref optimization for input route lookups in ipv4 to
   fix some routing cache removal perf regressions.

2) Make TCP socket pre-demux work on ipv6 side too, from Eric Dumazet.

3) Get RX hash value from correct place in be2net driver, from
   Sarveshwar Bandi.

4) Validation of FIB cached routes missing critical check, from Eric
   Dumazet.

5) EEH support in mlx4 driver, from Kleber Sacilotto de Souza.

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net: (23 commits)
  ipv6: Early TCP socket demux
  ipv4: Fix input route performance regression.
  pch_gbe: vlan skb len fix
  pch_gbe: add extra clean tx
  pch_gbe: fix transmit watchdog timeout
  ixgbe: fix panic while dumping packets on Tx hang with IOMMU
  be2net: Fix to parse RSS hash from Receive completions correctly.
  net/mlx4_en: Limit the RFS filter IDs to be < RPS_NO_FILTER
  hyperv: Add error handling to rndis_filter_device_add()
  hyperv: Add a check for ring_size value
  ipv4: rt_cache_valid must check expired routes
  net/pch_gpe: Cannot disable ethernet autonegation
  qeth: repair crash in qeth_l3_vlan_rx_kill_vid()
  netiucv: cleanup attribute usage
  net: wiznet add missing HAS_IOMEM dependency
  be2net: Missing byteswap in be_get_fw_log_level causes oops on PowerPC
  mlx4: Add support for EEH error recovery
  cdc-ncm: tag Ericsson WWAN devices (eg F5521gw) with FLAG_WWAN
  wanmain: comparing array with NULL
  caif: fix NULL pointer check
  ...

32 files changed:
drivers/net/caif/caif_serial.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
drivers/net/ethernet/emulex/benet/be_ethtool.c
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/mellanox/mlx4/catas.c
drivers/net/ethernet/mellanox/mlx4/cmd.c
drivers/net/ethernet/mellanox/mlx4/en_netdev.c
drivers/net/ethernet/mellanox/mlx4/main.c
drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c
drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
drivers/net/ethernet/wiznet/Kconfig
drivers/net/hyperv/netvsc_drv.c
drivers/net/hyperv/rndis_filter.c
drivers/net/team/team.c
drivers/net/usb/cdc_ncm.c
drivers/s390/net/netiucv.c
drivers/s390/net/qeth_l3_main.c
include/net/inet6_hashtables.h
include/net/protocol.h
include/net/route.h
net/ipv4/arp.c
net/ipv4/fib_semantics.c
net/ipv4/ip_fragment.c
net/ipv4/ip_input.c
net/ipv4/route.c
net/ipv4/tcp_ipv4.c
net/ipv4/xfrm4_input.c
net/ipv6/ip6_input.c
net/ipv6/tcp_ipv6.c
net/wanrouter/wanmain.c

index 8a3054b848125f76153d9bb53ccbaf19c1c36b3c..5de74e76202134402420311d1fe824c7ce57055a 100644 (file)
@@ -325,6 +325,9 @@ static int ldisc_open(struct tty_struct *tty)
 
        sprintf(name, "cf%s", tty->name);
        dev = alloc_netdev(sizeof(*ser), name, caifdev_setup);
+       if (!dev)
+               return -ENOMEM;
+
        ser = netdev_priv(dev);
        ser->tty = tty_kref_get(tty);
        ser->dev = dev;
index ec62a5c8bd37c25f0c0ec9a133b4c95339e421dc..28a0bcfe61ff9a4224d5b1f3442400a363bce79b 100644 (file)
  * of counts that the SM entered the EEE LPI state. Clock 25MHz. Read only
  * register. Reset on hard reset. */
 #define MISC_REG_CPMU_LP_SM_ENT_CNT_P0                          0xa8b8
+/* [RW 16] EEE LPI Entry Events Counter. A statistic counter with the number
+ * of counts that the SM entered the EEE LPI state. Clock 25MHz. Read only
+ * register. Reset on hard reset. */
+#define MISC_REG_CPMU_LP_SM_ENT_CNT_P1                          0xa8bc
 /* [RW 32] The following driver registers(1...16) represent 16 drivers and
    32 clients. Each client can be controlled by one driver only. One in each
    bit represent that this driver control the appropriate client (Ex: bit 5
index 667d89042d35b33b2792a9ed9b848aae3db27897..332db64dd5bea11eed0cf878565c5c2e573f5c3e 100644 (file)
@@ -785,9 +785,11 @@ static int bnx2x_hw_stats_update(struct bnx2x *bp)
 
        pstats->host_port_stats_counter++;
 
-       if (CHIP_IS_E3(bp))
-               estats->eee_tx_lpi += REG_RD(bp,
-                                            MISC_REG_CPMU_LP_SM_ENT_CNT_P0);
+       if (CHIP_IS_E3(bp)) {
+               u32 lpi_reg = BP_PORT(bp) ? MISC_REG_CPMU_LP_SM_ENT_CNT_P1
+                                         : MISC_REG_CPMU_LP_SM_ENT_CNT_P0;
+               estats->eee_tx_lpi += REG_RD(bp, lpi_reg);
+       }
 
        if (!BP_NOMCP(bp)) {
                u32 nig_timer_max =
index e34be1c7ae8aa4b3808365b5eee9fb40407e834d..c0e700653f965ef204ba38286b33dae76289d897 100644 (file)
@@ -910,8 +910,9 @@ static void be_set_fw_log_level(struct be_adapter *adapter, u32 level)
        if (!status) {
                cfgs = (struct be_fat_conf_params *)(extfat_cmd.va +
                                        sizeof(struct be_cmd_resp_hdr));
-               for (i = 0; i < cfgs->num_modules; i++) {
-                       for (j = 0; j < cfgs->module[i].num_modes; j++) {
+               for (i = 0; i < le32_to_cpu(cfgs->num_modules); i++) {
+                       u32 num_modes = le32_to_cpu(cfgs->module[i].num_modes);
+                       for (j = 0; j < num_modes; j++) {
                                if (cfgs->module[i].trace_lvl[j].mode ==
                                                                MODE_UART)
                                        cfgs->module[i].trace_lvl[j].dbg_lvl =
index 4d967717449067d2802d09957a48c66f0b4241aa..c60de89b66696759a453ff4d69650c1905209c58 100644 (file)
@@ -1397,7 +1397,7 @@ static void be_parse_rx_compl_v1(struct be_eth_rx_compl *compl,
        rxcp->pkt_type =
                AMAP_GET_BITS(struct amap_eth_rx_compl_v1, cast_enc, compl);
        rxcp->rss_hash =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v1, rsshash, rxcp);
+               AMAP_GET_BITS(struct amap_eth_rx_compl_v1, rsshash, compl);
        if (rxcp->vlanf) {
                rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtm,
                                          compl);
@@ -1429,7 +1429,7 @@ static void be_parse_rx_compl_v0(struct be_eth_rx_compl *compl,
        rxcp->pkt_type =
                AMAP_GET_BITS(struct amap_eth_rx_compl_v0, cast_enc, compl);
        rxcp->rss_hash =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v0, rsshash, rxcp);
+               AMAP_GET_BITS(struct amap_eth_rx_compl_v0, rsshash, compl);
        if (rxcp->vlanf) {
                rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtm,
                                          compl);
@@ -3579,7 +3579,7 @@ u32 be_get_fw_log_level(struct be_adapter *adapter)
        if (!status) {
                cfgs = (struct be_fat_conf_params *)(extfat_cmd.va +
                                                sizeof(struct be_cmd_resp_hdr));
-               for (j = 0; j < cfgs->module[0].num_modes; j++) {
+               for (j = 0; j < le32_to_cpu(cfgs->module[0].num_modes); j++) {
                        if (cfgs->module[0].trace_lvl[j].mode == MODE_UART)
                                level = cfgs->module[0].trace_lvl[j].dbg_lvl;
                }
index 3b6784cf134a8159892f133342f981eb7ad3413f..c709eae58c630a9a1e2c5e5e7539d733cf609e31 100644 (file)
@@ -396,11 +396,10 @@ static void ixgbe_dump(struct ixgbe_adapter *adapter)
                                pr_cont("\n");
 
                        if (netif_msg_pktdata(adapter) &&
-                           dma_unmap_len(tx_buffer, len) != 0)
+                           tx_buffer->skb)
                                print_hex_dump(KERN_INFO, "",
                                        DUMP_PREFIX_ADDRESS, 16, 1,
-                                       phys_to_virt(dma_unmap_addr(tx_buffer,
-                                                                   dma)),
+                                       tx_buffer->skb->data,
                                        dma_unmap_len(tx_buffer, len),
                                        true);
                }
@@ -474,10 +473,12 @@ rx_ring_summary:
                                        (u64)rx_buffer_info->dma,
                                        rx_buffer_info->skb);
 
-                               if (netif_msg_pktdata(adapter)) {
+                               if (netif_msg_pktdata(adapter) &&
+                                   rx_buffer_info->dma) {
                                        print_hex_dump(KERN_INFO, "",
                                           DUMP_PREFIX_ADDRESS, 16, 1,
-                                          phys_to_virt(rx_buffer_info->dma),
+                                          page_address(rx_buffer_info->page) +
+                                                   rx_buffer_info->page_offset,
                                           ixgbe_rx_bufsz(rx_ring), true);
                                }
                        }
index 915e947b422d63888dfd65522b7d14a3fa4162ff..9c656fe4983dda7fbb10dd1b195bf12b2808c8e8 100644 (file)
@@ -69,16 +69,21 @@ static void poll_catas(unsigned long dev_ptr)
        struct mlx4_priv *priv = mlx4_priv(dev);
 
        if (readl(priv->catas_err.map)) {
-               dump_err_buf(dev);
-
-               mlx4_dispatch_event(dev, MLX4_DEV_EVENT_CATASTROPHIC_ERROR, 0);
+               /* If the device is off-line, we cannot try to recover it */
+               if (pci_channel_offline(dev->pdev))
+                       mod_timer(&priv->catas_err.timer,
+                                 round_jiffies(jiffies + MLX4_CATAS_POLL_INTERVAL));
+               else {
+                       dump_err_buf(dev);
+                       mlx4_dispatch_event(dev, MLX4_DEV_EVENT_CATASTROPHIC_ERROR, 0);
 
-               if (internal_err_reset) {
-                       spin_lock(&catas_lock);
-                       list_add(&priv->catas_err.list, &catas_list);
-                       spin_unlock(&catas_lock);
+                       if (internal_err_reset) {
+                               spin_lock(&catas_lock);
+                               list_add(&priv->catas_err.list, &catas_list);
+                               spin_unlock(&catas_lock);
 
-                       queue_work(mlx4_wq, &catas_work);
+                               queue_work(mlx4_wq, &catas_work);
+                       }
                }
        } else
                mod_timer(&priv->catas_err.timer,
@@ -100,6 +105,10 @@ static void catas_reset(struct work_struct *work)
        list_for_each_entry_safe(priv, tmppriv, &tlist, catas_err.list) {
                struct pci_dev *pdev = priv->dev.pdev;
 
+               /* If the device is off-line, we cannot reset it */
+               if (pci_channel_offline(pdev))
+                       continue;
+
                ret = mlx4_restart_one(priv->dev.pdev);
                /* 'priv' now is not valid */
                if (ret)
index 7e94987d030c4da44885c5aa3dd56daf1d022907..c8fef435302155d32aa8236e0118c2406241c48c 100644 (file)
@@ -296,7 +296,12 @@ int mlx4_comm_cmd(struct mlx4_dev *dev, u8 cmd, u16 param,
 
 static int cmd_pending(struct mlx4_dev *dev)
 {
-       u32 status = readl(mlx4_priv(dev)->cmd.hcr + HCR_STATUS_OFFSET);
+       u32 status;
+
+       if (pci_channel_offline(dev->pdev))
+               return -EIO;
+
+       status = readl(mlx4_priv(dev)->cmd.hcr + HCR_STATUS_OFFSET);
 
        return (status & swab32(1 << HCR_GO_BIT)) ||
                (mlx4_priv(dev)->cmd.toggle ==
@@ -314,11 +319,29 @@ static int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param,
 
        mutex_lock(&cmd->hcr_mutex);
 
+       if (pci_channel_offline(dev->pdev)) {
+               /*
+                * Device is going through error recovery
+                * and cannot accept commands.
+                */
+               ret = -EIO;
+               goto out;
+       }
+
        end = jiffies;
        if (event)
                end += msecs_to_jiffies(GO_BIT_TIMEOUT_MSECS);
 
        while (cmd_pending(dev)) {
+               if (pci_channel_offline(dev->pdev)) {
+                       /*
+                        * Device is going through error recovery
+                        * and cannot accept commands.
+                        */
+                       ret = -EIO;
+                       goto out;
+               }
+
                if (time_after_eq(jiffies, end)) {
                        mlx4_err(dev, "%s:cmd_pending failed\n", __func__);
                        goto out;
@@ -431,14 +454,33 @@ static int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
 
        down(&priv->cmd.poll_sem);
 
+       if (pci_channel_offline(dev->pdev)) {
+               /*
+                * Device is going through error recovery
+                * and cannot accept commands.
+                */
+               err = -EIO;
+               goto out;
+       }
+
        err = mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0,
                            in_modifier, op_modifier, op, CMD_POLL_TOKEN, 0);
        if (err)
                goto out;
 
        end = msecs_to_jiffies(timeout) + jiffies;
-       while (cmd_pending(dev) && time_before(jiffies, end))
+       while (cmd_pending(dev) && time_before(jiffies, end)) {
+               if (pci_channel_offline(dev->pdev)) {
+                       /*
+                        * Device is going through error recovery
+                        * and cannot accept commands.
+                        */
+                       err = -EIO;
+                       goto out;
+               }
+
                cond_resched();
+       }
 
        if (cmd_pending(dev)) {
                err = -ETIMEDOUT;
@@ -532,6 +574,9 @@ int __mlx4_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
               int out_is_imm, u32 in_modifier, u8 op_modifier,
               u16 op, unsigned long timeout, int native)
 {
+       if (pci_channel_offline(dev->pdev))
+               return -EIO;
+
        if (!mlx4_is_mfunc(dev) || (native && mlx4_is_master(dev))) {
                if (mlx4_priv(dev)->cmd.use_events)
                        return mlx4_cmd_wait(dev, in_param, out_param,
index 8864d8b5373790de6750089f6bc4f1a4d687651e..edd9cb8d3e1d8f09cc1715ddee967b5fa58181fd 100644 (file)
@@ -201,7 +201,7 @@ mlx4_en_filter_alloc(struct mlx4_en_priv *priv, int rxq_index, __be32 src_ip,
 
        filter->flow_id = flow_id;
 
-       filter->id = priv->last_filter_id++;
+       filter->id = priv->last_filter_id++ % RPS_NO_FILTER;
 
        list_add_tail(&filter->next, &priv->filters);
        hlist_add_head(&filter->filter_chain,
index e8f8ebb4ae65d653befa53f87f3fd319fb3b96ad..48d0e90194cb19d2a322990425b478f9e178b623 100644 (file)
@@ -1817,6 +1817,9 @@ static int mlx4_get_ownership(struct mlx4_dev *dev)
        void __iomem *owner;
        u32 ret;
 
+       if (pci_channel_offline(dev->pdev))
+               return -EIO;
+
        owner = ioremap(pci_resource_start(dev->pdev, 0) + MLX4_OWNER_BASE,
                        MLX4_OWNER_SIZE);
        if (!owner) {
@@ -1833,6 +1836,9 @@ static void mlx4_free_ownership(struct mlx4_dev *dev)
 {
        void __iomem *owner;
 
+       if (pci_channel_offline(dev->pdev))
+               return;
+
        owner = ioremap(pci_resource_start(dev->pdev, 0) + MLX4_OWNER_BASE,
                        MLX4_OWNER_SIZE);
        if (!owner) {
@@ -2279,11 +2285,33 @@ static DEFINE_PCI_DEVICE_TABLE(mlx4_pci_table) = {
 
 MODULE_DEVICE_TABLE(pci, mlx4_pci_table);
 
+static pci_ers_result_t mlx4_pci_err_detected(struct pci_dev *pdev,
+                                             pci_channel_state_t state)
+{
+       mlx4_remove_one(pdev);
+
+       return state == pci_channel_io_perm_failure ?
+               PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_NEED_RESET;
+}
+
+static pci_ers_result_t mlx4_pci_slot_reset(struct pci_dev *pdev)
+{
+       int ret = __mlx4_init_one(pdev, NULL);
+
+       return ret ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
+}
+
+static struct pci_error_handlers mlx4_err_handler = {
+       .error_detected = mlx4_pci_err_detected,
+       .slot_reset     = mlx4_pci_slot_reset,
+};
+
 static struct pci_driver mlx4_driver = {
        .name           = DRV_NAME,
        .id_table       = mlx4_pci_table,
        .probe          = mlx4_init_one,
-       .remove         = __devexit_p(mlx4_remove_one)
+       .remove         = __devexit_p(mlx4_remove_one),
+       .err_handler    = &mlx4_err_handler,
 };
 
 static int __init mlx4_verify_params(void)
index 9dbf38c10a6836a0d98a1f98dad8d7cbd6f04f5c..24b787be6062aed4432f57032193b218e5b936d9 100644 (file)
@@ -129,7 +129,6 @@ static int pch_gbe_set_settings(struct net_device *netdev,
        hw->mac.link_duplex = ecmd->duplex;
        hw->phy.autoneg_advertised = ecmd->advertising;
        hw->mac.autoneg = ecmd->autoneg;
-       pch_gbe_hal_phy_sw_reset(hw);
 
        /* reset the link */
        if (netif_running(adapter->netdev)) {
index b1006563f7363d479daf1109d7a112deec47130e..feb85d56c750c425cb6e5ab9d3cee37b2dfc0251 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/ptp_classify.h>
 #endif
 
-#define DRV_VERSION     "1.00"
+#define DRV_VERSION     "1.01"
 const char pch_driver_version[] = DRV_VERSION;
 
 #define PCI_DEVICE_ID_INTEL_IOH1_GBE   0x8802          /* Pci device ID */
@@ -35,7 +35,7 @@ const char pch_driver_version[] = DRV_VERSION;
 #define DSC_INIT16                     0xC000
 #define PCH_GBE_DMA_ALIGN              0
 #define PCH_GBE_DMA_PADDING            2
-#define PCH_GBE_WATCHDOG_PERIOD                (1 * HZ)        /* watchdog time */
+#define PCH_GBE_WATCHDOG_PERIOD                (5 * HZ)        /* watchdog time */
 #define PCH_GBE_COPYBREAK_DEFAULT      256
 #define PCH_GBE_PCI_BAR                        1
 #define PCH_GBE_RESERVE_MEMORY         0x200000        /* 2MB */
@@ -1579,7 +1579,8 @@ pch_gbe_clean_tx(struct pch_gbe_adapter *adapter,
        struct sk_buff *skb;
        unsigned int i;
        unsigned int cleaned_count = 0;
-       bool cleaned = true;
+       bool cleaned = false;
+       int unused, thresh;
 
        pr_debug("next_to_clean : %d\n", tx_ring->next_to_clean);
 
@@ -1588,10 +1589,36 @@ pch_gbe_clean_tx(struct pch_gbe_adapter *adapter,
        pr_debug("gbec_status:0x%04x  dma_status:0x%04x\n",
                 tx_desc->gbec_status, tx_desc->dma_status);
 
+       unused = PCH_GBE_DESC_UNUSED(tx_ring);
+       thresh = tx_ring->count - PCH_GBE_TX_WEIGHT;
+       if ((tx_desc->gbec_status == DSC_INIT16) && (unused < thresh))
+       {  /* current marked clean, tx queue filling up, do extra clean */
+               int j, k;
+               if (unused < 8) {  /* tx queue nearly full */
+                       pr_debug("clean_tx: transmit queue warning (%x,%x) unused=%d\n",
+                               tx_ring->next_to_clean,tx_ring->next_to_use,unused);
+               }
+
+               /* current marked clean, scan for more that need cleaning. */
+               k = i;
+               for (j = 0; j < PCH_GBE_TX_WEIGHT; j++)
+               {
+                       tx_desc = PCH_GBE_TX_DESC(*tx_ring, k);
+                       if (tx_desc->gbec_status != DSC_INIT16) break; /*found*/
+                       if (++k >= tx_ring->count) k = 0;  /*increment, wrap*/
+               }
+               if (j < PCH_GBE_TX_WEIGHT) {
+                       pr_debug("clean_tx: unused=%d loops=%d found tx_desc[%x,%x:%x].gbec_status=%04x\n",
+                               unused,j, i,k, tx_ring->next_to_use, tx_desc->gbec_status);
+                       i = k;  /*found one to clean, usu gbec_status==2000.*/
+               }
+       }
+
        while ((tx_desc->gbec_status & DSC_INIT16) == 0x0000) {
                pr_debug("gbec_status:0x%04x\n", tx_desc->gbec_status);
                buffer_info = &tx_ring->buffer_info[i];
                skb = buffer_info->skb;
+               cleaned = true;
 
                if ((tx_desc->gbec_status & PCH_GBE_TXD_GMAC_STAT_ABT)) {
                        adapter->stats.tx_aborted_errors++;
@@ -1639,18 +1666,21 @@ pch_gbe_clean_tx(struct pch_gbe_adapter *adapter,
        }
        pr_debug("called pch_gbe_unmap_and_free_tx_resource() %d count\n",
                 cleaned_count);
-       /* Recover from running out of Tx resources in xmit_frame */
-       spin_lock(&tx_ring->tx_lock);
-       if (unlikely(cleaned && (netif_queue_stopped(adapter->netdev)))) {
-               netif_wake_queue(adapter->netdev);
-               adapter->stats.tx_restart_count++;
-               pr_debug("Tx wake queue\n");
-       }
+       if (cleaned_count > 0)  { /*skip this if nothing cleaned*/
+               /* Recover from running out of Tx resources in xmit_frame */
+               spin_lock(&tx_ring->tx_lock);
+               if (unlikely(cleaned && (netif_queue_stopped(adapter->netdev))))
+               {
+                       netif_wake_queue(adapter->netdev);
+                       adapter->stats.tx_restart_count++;
+                       pr_debug("Tx wake queue\n");
+               }
 
-       tx_ring->next_to_clean = i;
+               tx_ring->next_to_clean = i;
 
-       pr_debug("next_to_clean : %d\n", tx_ring->next_to_clean);
-       spin_unlock(&tx_ring->tx_lock);
+               pr_debug("next_to_clean : %d\n", tx_ring->next_to_clean);
+               spin_unlock(&tx_ring->tx_lock);
+       }
        return cleaned;
 }
 
@@ -1988,6 +2018,7 @@ int pch_gbe_up(struct pch_gbe_adapter *adapter)
 void pch_gbe_down(struct pch_gbe_adapter *adapter)
 {
        struct net_device *netdev = adapter->netdev;
+       struct pci_dev *pdev = adapter->pdev;
        struct pch_gbe_rx_ring *rx_ring = adapter->rx_ring;
 
        /* signal that we're down so the interrupt handler does not
@@ -2004,7 +2035,8 @@ void pch_gbe_down(struct pch_gbe_adapter *adapter)
        netif_carrier_off(netdev);
        netif_stop_queue(netdev);
 
-       pch_gbe_reset(adapter);
+       if ((pdev->error_state) && (pdev->error_state != pci_channel_io_normal))
+               pch_gbe_reset(adapter);
        pch_gbe_clean_tx_ring(adapter, adapter->tx_ring);
        pch_gbe_clean_rx_ring(adapter, adapter->rx_ring);
 
@@ -2127,13 +2159,6 @@ static int pch_gbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        struct pch_gbe_tx_ring *tx_ring = adapter->tx_ring;
        unsigned long flags;
 
-       if (unlikely(skb->len > (adapter->hw.mac.max_frame_size - 4))) {
-               pr_err("Transfer length Error: skb len: %d > max: %d\n",
-                      skb->len, adapter->hw.mac.max_frame_size);
-               dev_kfree_skb_any(skb);
-               adapter->stats.tx_length_errors++;
-               return NETDEV_TX_OK;
-       }
        if (!spin_trylock_irqsave(&tx_ring->tx_lock, flags)) {
                /* Collision - tell upper layer to requeue */
                return NETDEV_TX_LOCKED;
@@ -2387,7 +2412,7 @@ static int pch_gbe_napi_poll(struct napi_struct *napi, int budget)
        pch_gbe_clean_rx(adapter, adapter->rx_ring, &work_done, budget);
        cleaned = pch_gbe_clean_tx(adapter, adapter->tx_ring);
 
-       if (!cleaned)
+       if (cleaned)
                work_done = budget;
        /* If no Tx and not enough Rx work done,
         * exit the polling mode
@@ -2793,6 +2818,7 @@ static int __init pch_gbe_init_module(void)
 {
        int ret;
 
+       pr_info("EG20T PCH Gigabit Ethernet Driver - version %s\n",DRV_VERSION);
        ret = pci_register_driver(&pch_gbe_driver);
        if (copybreak != PCH_GBE_COPYBREAK_DEFAULT) {
                if (copybreak == 0) {
index cb18043f5830bbb6414e870455f7c46203a0f6fe..b4d281626fb499d084b49bd8c5a1bd5571751573 100644 (file)
@@ -4,6 +4,7 @@
 
 config NET_VENDOR_WIZNET
        bool "WIZnet devices"
+       depends on HAS_IOMEM
        default y
        ---help---
          If you have a network (Ethernet) card belonging to this class, say Y
index 8e23c084c4a73e32888eee1310f47690d2f6aca2..8c5a1c43c81d257c09a67385e01da93f3c24465f 100644 (file)
@@ -47,7 +47,7 @@ struct net_device_context {
        struct work_struct work;
 };
 
-
+#define RING_SIZE_MIN 64
 static int ring_size = 128;
 module_param(ring_size, int, S_IRUGO);
 MODULE_PARM_DESC(ring_size, "Ring buffer size (# of pages)");
@@ -518,6 +518,11 @@ static void __exit netvsc_drv_exit(void)
 
 static int __init netvsc_drv_init(void)
 {
+       if (ring_size < RING_SIZE_MIN) {
+               ring_size = RING_SIZE_MIN;
+               pr_info("Increased ring_size to %d (min allowed)\n",
+                       ring_size);
+       }
        return vmbus_driver_register(&netvsc_drv);
 }
 
index fbf53946820525c19d6c1b7db46de38a4d6ad85f..e5d6146937fa0aade2476662ce87084b7337187c 100644 (file)
@@ -804,18 +804,15 @@ int rndis_filter_device_add(struct hv_device *dev,
        /* Send the rndis initialization message */
        ret = rndis_filter_init_device(rndis_device);
        if (ret != 0) {
-               /*
-                * TODO: If rndis init failed, we will need to shut down the
-                * channel
-                */
+               rndis_filter_device_remove(dev);
+               return ret;
        }
 
        /* Get the mac address */
        ret = rndis_filter_query_device_mac(rndis_device);
        if (ret != 0) {
-               /*
-                * TODO: shutdown rndis device and the channel
-                */
+               rndis_filter_device_remove(dev);
+               return ret;
        }
 
        memcpy(device_info->mac_adr, rndis_device->hw_mac_adr, ETH_ALEN);
index b104c05225f7ea0964d3065b6789f945451d9c23..87707ab3943084821e1b7e5c5b9a201d51a944ba 100644 (file)
@@ -1447,7 +1447,7 @@ static int team_netpoll_setup(struct net_device *dev,
 {
        struct team *team = netdev_priv(dev);
        struct team_port *port;
-       int err;
+       int err = 0;
 
        mutex_lock(&team->lock);
        list_for_each_entry(port, &team->port_list, list) {
index 4b9513fcf27539953704630475f7754b5e3a7eb4..f4ce5957df326bb94131031fabdb1daf6dcabf42 100644 (file)
@@ -138,20 +138,7 @@ struct cdc_ncm_ctx {
 static void cdc_ncm_txpath_bh(unsigned long param);
 static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx);
 static enum hrtimer_restart cdc_ncm_tx_timer_cb(struct hrtimer *hr_timer);
-static const struct driver_info cdc_ncm_info;
 static struct usb_driver cdc_ncm_driver;
-static const struct ethtool_ops cdc_ncm_ethtool_ops;
-
-static const struct usb_device_id cdc_devs[] = {
-       { USB_INTERFACE_INFO(USB_CLASS_COMM,
-               USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE),
-               .driver_info = (unsigned long)&cdc_ncm_info,
-       },
-       {
-       },
-};
-
-MODULE_DEVICE_TABLE(usb, cdc_devs);
 
 static void
 cdc_ncm_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
@@ -454,6 +441,16 @@ static void cdc_ncm_free(struct cdc_ncm_ctx *ctx)
        kfree(ctx);
 }
 
+static const struct ethtool_ops cdc_ncm_ethtool_ops = {
+       .get_drvinfo = cdc_ncm_get_drvinfo,
+       .get_link = usbnet_get_link,
+       .get_msglevel = usbnet_get_msglevel,
+       .set_msglevel = usbnet_set_msglevel,
+       .get_settings = usbnet_get_settings,
+       .set_settings = usbnet_set_settings,
+       .nway_reset = usbnet_nway_reset,
+};
+
 static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)
 {
        struct cdc_ncm_ctx *ctx;
@@ -1203,6 +1200,41 @@ static const struct driver_info cdc_ncm_info = {
        .tx_fixup = cdc_ncm_tx_fixup,
 };
 
+/* Same as cdc_ncm_info, but with FLAG_WWAN */
+static const struct driver_info wwan_info = {
+       .description = "Mobile Broadband Network Device",
+       .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET
+                       | FLAG_WWAN,
+       .bind = cdc_ncm_bind,
+       .unbind = cdc_ncm_unbind,
+       .check_connect = cdc_ncm_check_connect,
+       .manage_power = cdc_ncm_manage_power,
+       .status = cdc_ncm_status,
+       .rx_fixup = cdc_ncm_rx_fixup,
+       .tx_fixup = cdc_ncm_tx_fixup,
+};
+
+static const struct usb_device_id cdc_devs[] = {
+       /* Ericsson MBM devices like F5521gw */
+       { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
+               | USB_DEVICE_ID_MATCH_VENDOR,
+         .idVendor = 0x0bdb,
+         .bInterfaceClass = USB_CLASS_COMM,
+         .bInterfaceSubClass = USB_CDC_SUBCLASS_NCM,
+         .bInterfaceProtocol = USB_CDC_PROTO_NONE,
+         .driver_info = (unsigned long) &wwan_info,
+       },
+
+       /* Generic CDC-NCM devices */
+       { USB_INTERFACE_INFO(USB_CLASS_COMM,
+               USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE),
+               .driver_info = (unsigned long)&cdc_ncm_info,
+       },
+       {
+       },
+};
+MODULE_DEVICE_TABLE(usb, cdc_devs);
+
 static struct usb_driver cdc_ncm_driver = {
        .name = "cdc_ncm",
        .id_table = cdc_devs,
@@ -1215,16 +1247,6 @@ static struct usb_driver cdc_ncm_driver = {
        .disable_hub_initiated_lpm = 1,
 };
 
-static const struct ethtool_ops cdc_ncm_ethtool_ops = {
-       .get_drvinfo = cdc_ncm_get_drvinfo,
-       .get_link = usbnet_get_link,
-       .get_msglevel = usbnet_get_msglevel,
-       .set_msglevel = usbnet_set_msglevel,
-       .get_settings = usbnet_get_settings,
-       .set_settings = usbnet_set_settings,
-       .nway_reset = usbnet_nway_reset,
-};
-
 module_usb_driver(cdc_ncm_driver);
 
 MODULE_AUTHOR("Hans Petter Selasky");
index 8160591913f95bd7555ac70129bbd06ef9ea0b60..4ffa66c87ea509ebd914938364fb16eb205fde7b 100644 (file)
@@ -1854,26 +1854,11 @@ static struct attribute_group netiucv_stat_attr_group = {
        .attrs = netiucv_stat_attrs,
 };
 
-static int netiucv_add_files(struct device *dev)
-{
-       int ret;
-
-       IUCV_DBF_TEXT(trace, 3, __func__);
-       ret = sysfs_create_group(&dev->kobj, &netiucv_attr_group);
-       if (ret)
-               return ret;
-       ret = sysfs_create_group(&dev->kobj, &netiucv_stat_attr_group);
-       if (ret)
-               sysfs_remove_group(&dev->kobj, &netiucv_attr_group);
-       return ret;
-}
-
-static void netiucv_remove_files(struct device *dev)
-{
-       IUCV_DBF_TEXT(trace, 3, __func__);
-       sysfs_remove_group(&dev->kobj, &netiucv_stat_attr_group);
-       sysfs_remove_group(&dev->kobj, &netiucv_attr_group);
-}
+static const struct attribute_group *netiucv_attr_groups[] = {
+       &netiucv_stat_attr_group,
+       &netiucv_attr_group,
+       NULL,
+};
 
 static int netiucv_register_device(struct net_device *ndev)
 {
@@ -1887,6 +1872,7 @@ static int netiucv_register_device(struct net_device *ndev)
                dev_set_name(dev, "net%s", ndev->name);
                dev->bus = &iucv_bus;
                dev->parent = iucv_root;
+               dev->groups = netiucv_attr_groups;
                /*
                 * The release function could be called after the
                 * module has been unloaded. It's _only_ task is to
@@ -1904,22 +1890,14 @@ static int netiucv_register_device(struct net_device *ndev)
                put_device(dev);
                return ret;
        }
-       ret = netiucv_add_files(dev);
-       if (ret)
-               goto out_unreg;
        priv->dev = dev;
        dev_set_drvdata(dev, priv);
        return 0;
-
-out_unreg:
-       device_unregister(dev);
-       return ret;
 }
 
 static void netiucv_unregister_device(struct device *dev)
 {
        IUCV_DBF_TEXT(trace, 3, __func__);
-       netiucv_remove_files(dev);
        device_unregister(dev);
 }
 
index 0cf706699a043e4d67c52e7dead8a00e7092a4f7..c5f03fa70fbaea0e774da0891a1ba9338c69f88d 100644 (file)
@@ -1758,6 +1758,8 @@ static void qeth_l3_free_vlan_addresses4(struct qeth_card *card,
        QETH_CARD_TEXT(card, 4, "frvaddr4");
 
        netdev = __vlan_find_dev_deep(card->dev, vid);
+       if (!netdev)
+               return;
        in_dev = in_dev_get(netdev);
        if (!in_dev)
                return;
@@ -1786,6 +1788,8 @@ static void qeth_l3_free_vlan_addresses6(struct qeth_card *card,
        QETH_CARD_TEXT(card, 4, "frvaddr6");
 
        netdev = __vlan_find_dev_deep(card->dev, vid);
+       if (!netdev)
+               return;
        in6_dev = in6_dev_get(netdev);
        if (!in6_dev)
                return;
index 00cbb4384c795b470777bd501cb65c914df50f82..9e34c877a77093ff1257e18941949a12391363d6 100644 (file)
@@ -96,14 +96,15 @@ static inline struct sock *__inet6_lookup_skb(struct inet_hashinfo *hashinfo,
                                              const __be16 sport,
                                              const __be16 dport)
 {
-       struct sock *sk;
+       struct sock *sk = skb_steal_sock(skb);
 
-       if (unlikely(sk = skb_steal_sock(skb)))
+       if (sk)
                return sk;
-       else return __inet6_lookup(dev_net(skb_dst(skb)->dev), hashinfo,
-                                  &ipv6_hdr(skb)->saddr, sport,
-                                  &ipv6_hdr(skb)->daddr, ntohs(dport),
-                                  inet6_iif(skb));
+
+       return __inet6_lookup(dev_net(skb_dst(skb)->dev), hashinfo,
+                             &ipv6_hdr(skb)->saddr, sport,
+                             &ipv6_hdr(skb)->daddr, ntohs(dport),
+                             inet6_iif(skb));
 }
 
 extern struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo,
index 057f2d3155673cf302171b2c57dc0366505c524e..929528c73fe8454a1dd34da7efbbc6d1fd8677fd 100644 (file)
@@ -52,6 +52,8 @@ struct net_protocol {
 
 #if IS_ENABLED(CONFIG_IPV6)
 struct inet6_protocol {
+       void    (*early_demux)(struct sk_buff *skb);
+
        int     (*handler)(struct sk_buff *skb);
 
        void    (*err_handler)(struct sk_buff *skb,
index c29ef2733f2d65e179d78a3c3f7268509ce68fae..8c52bc6f1c9027e9330daad6005f8a772e09a191 100644 (file)
@@ -30,6 +30,7 @@
 #include <net/inet_sock.h>
 #include <linux/in_route.h>
 #include <linux/rtnetlink.h>
+#include <linux/rcupdate.h>
 #include <linux/route.h>
 #include <linux/ip.h>
 #include <linux/cache.h>
@@ -157,8 +158,22 @@ static inline struct rtable *ip_route_output_gre(struct net *net, struct flowi4
        return ip_route_output_key(net, fl4);
 }
 
-extern int ip_route_input(struct sk_buff *skb, __be32 dst, __be32 src,
-                         u8 tos, struct net_device *devin);
+extern int ip_route_input_noref(struct sk_buff *skb, __be32 dst, __be32 src,
+                               u8 tos, struct net_device *devin);
+
+static inline int ip_route_input(struct sk_buff *skb, __be32 dst, __be32 src,
+                                u8 tos, struct net_device *devin)
+{
+       int err;
+
+       rcu_read_lock();
+       err = ip_route_input_noref(skb, dst, src, tos, devin);
+       if (!err)
+               skb_dst_force(skb);
+       rcu_read_unlock();
+
+       return err;
+}
 
 extern void ipv4_update_pmtu(struct sk_buff *skb, struct net *net, u32 mtu,
                             int oif, u32 mark, u8 protocol, int flow_flags);
index a0124eb7dbeacf51d617fb51e7c09fc91106f221..77e87aff419ab105ef3ad3b5f852ef676b18a827 100644 (file)
@@ -827,7 +827,7 @@ static int arp_process(struct sk_buff *skb)
        }
 
        if (arp->ar_op == htons(ARPOP_REQUEST) &&
-           ip_route_input(skb, tip, sip, 0, dev) == 0) {
+           ip_route_input_noref(skb, tip, sip, 0, dev) == 0) {
 
                rt = skb_rtable(skb);
                addr_type = rt->rt_type;
index e55171f184f9731274c568345b9b74c14b2e63cc..da0cc2e6b2500f89850642aa8e2d50d26d6a2ae3 100644 (file)
@@ -172,9 +172,9 @@ static void free_fib_info_rcu(struct rcu_head *head)
                if (nexthop_nh->nh_exceptions)
                        free_nh_exceptions(nexthop_nh);
                if (nexthop_nh->nh_rth_output)
-                       dst_release(&nexthop_nh->nh_rth_output->dst);
+                       dst_free(&nexthop_nh->nh_rth_output->dst);
                if (nexthop_nh->nh_rth_input)
-                       dst_release(&nexthop_nh->nh_rth_input->dst);
+                       dst_free(&nexthop_nh->nh_rth_input->dst);
        } endfor_nexthops(fi);
 
        release_net(fi->fib_net);
index 7ad88e5e711020f0d733adafd2a60c9287925dd3..8d07c973409ca3df9d09f8fb6b3a614d304603a8 100644 (file)
@@ -258,8 +258,8 @@ static void ip_expire(unsigned long arg)
                /* skb dst is stale, drop it, and perform route lookup again */
                skb_dst_drop(head);
                iph = ip_hdr(head);
-               err = ip_route_input(head, iph->daddr, iph->saddr,
-                                    iph->tos, head->dev);
+               err = ip_route_input_noref(head, iph->daddr, iph->saddr,
+                                          iph->tos, head->dev);
                if (err)
                        goto out_rcu_unlock;
 
index 4ebc6feee25082db739d876cb98d7a9c93bc6d8c..981ff1eef28cc9a1b24b0b50f58caa32fbcdd0d1 100644 (file)
@@ -314,6 +314,7 @@ drop:
 }
 
 int sysctl_ip_early_demux __read_mostly = 1;
+EXPORT_SYMBOL(sysctl_ip_early_demux);
 
 static int ip_rcv_finish(struct sk_buff *skb)
 {
@@ -326,8 +327,11 @@ static int ip_rcv_finish(struct sk_buff *skb)
 
                rcu_read_lock();
                ipprot = rcu_dereference(inet_protos[protocol]);
-               if (ipprot && ipprot->early_demux)
+               if (ipprot && ipprot->early_demux) {
                        ipprot->early_demux(skb);
+                       /* must reload iph, skb->head might have changed */
+                       iph = ip_hdr(skb);
+               }
                rcu_read_unlock();
        }
 
@@ -336,8 +340,8 @@ static int ip_rcv_finish(struct sk_buff *skb)
         *      how the packet travels inside Linux networking.
         */
        if (!skb_dst(skb)) {
-               int err = ip_route_input(skb, iph->daddr, iph->saddr,
-                                        iph->tos, skb->dev);
+               int err = ip_route_input_noref(skb, iph->daddr, iph->saddr,
+                                              iph->tos, skb->dev);
                if (unlikely(err)) {
                        if (err == -EXDEV)
                                NET_INC_STATS_BH(dev_net(skb->dev),
index 6bcb8fc71cbc77a2f4ce0303b5fcc67481e9e49a..fc1a81ca79a7837d4307cb2a9bb034630c99b1a2 100644 (file)
@@ -444,7 +444,7 @@ static inline int ip_rt_proc_init(void)
 }
 #endif /* CONFIG_PROC_FS */
 
-static inline int rt_is_expired(struct rtable *rth)
+static inline bool rt_is_expired(const struct rtable *rth)
 {
        return rth->rt_genid != rt_genid(dev_net(rth->dst.dev));
 }
@@ -1199,10 +1199,9 @@ restart:
        fnhe->fnhe_stamp = jiffies;
 }
 
-static inline void rt_release_rcu(struct rcu_head *head)
+static inline void rt_free(struct rtable *rt)
 {
-       struct dst_entry *dst = container_of(head, struct dst_entry, rcu_head);
-       dst_release(dst);
+       call_rcu_bh(&rt->dst.rcu_head, dst_rcu_free);
 }
 
 static void rt_cache_route(struct fib_nh *nh, struct rtable *rt)
@@ -1216,15 +1215,23 @@ static void rt_cache_route(struct fib_nh *nh, struct rtable *rt)
 
        prev = cmpxchg(p, orig, rt);
        if (prev == orig) {
-               dst_clone(&rt->dst);
                if (orig)
-                       call_rcu_bh(&orig->dst.rcu_head, rt_release_rcu);
+                       rt_free(orig);
+       } else {
+               /* Routes we intend to cache in the FIB nexthop have
+                * the DST_NOCACHE bit clear.  However, if we are
+                * unsuccessful at storing this route into the cache
+                * we really need to set it.
+                */
+               rt->dst.flags |= DST_NOCACHE;
        }
 }
 
-static bool rt_cache_valid(struct rtable *rt)
+static bool rt_cache_valid(const struct rtable *rt)
 {
-       return (rt && rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK);
+       return  rt &&
+               rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK &&
+               !rt_is_expired(rt);
 }
 
 static void rt_set_nexthop(struct rtable *rt, __be32 daddr,
@@ -1243,7 +1250,7 @@ static void rt_set_nexthop(struct rtable *rt, __be32 daddr,
 #ifdef CONFIG_IP_ROUTE_CLASSID
                rt->dst.tclassid = nh->nh_tclassid;
 #endif
-               if (!(rt->dst.flags & DST_HOST))
+               if (!(rt->dst.flags & DST_NOCACHE))
                        rt_cache_route(nh, rt);
        }
 
@@ -1259,7 +1266,7 @@ static struct rtable *rt_dst_alloc(struct net_device *dev,
                                   bool nopolicy, bool noxfrm, bool will_cache)
 {
        return dst_alloc(&ipv4_dst_ops, dev, 1, DST_OBSOLETE_FORCE_CHK,
-                        (will_cache ? 0 : DST_HOST) | DST_NOCACHE |
+                        (will_cache ? 0 : (DST_HOST | DST_NOCACHE)) |
                         (nopolicy ? DST_NOPOLICY : 0) |
                         (noxfrm ? DST_NOXFRM : 0));
 }
@@ -1364,8 +1371,7 @@ static void ip_handle_martian_source(struct net_device *dev,
 static int __mkroute_input(struct sk_buff *skb,
                           const struct fib_result *res,
                           struct in_device *in_dev,
-                          __be32 daddr, __be32 saddr, u32 tos,
-                          struct rtable **result)
+                          __be32 daddr, __be32 saddr, u32 tos)
 {
        struct rtable *rth;
        int err;
@@ -1416,7 +1422,7 @@ static int __mkroute_input(struct sk_buff *skb,
                if (!itag) {
                        rth = FIB_RES_NH(*res).nh_rth_input;
                        if (rt_cache_valid(rth)) {
-                               dst_hold(&rth->dst);
+                               skb_dst_set_noref(skb, &rth->dst);
                                goto out;
                        }
                        do_cache = true;
@@ -1443,8 +1449,8 @@ static int __mkroute_input(struct sk_buff *skb,
        rth->dst.output = ip_output;
 
        rt_set_nexthop(rth, daddr, res, NULL, res->fi, res->type, itag);
+       skb_dst_set(skb, &rth->dst);
 out:
-       *result = rth;
        err = 0;
  cleanup:
        return err;
@@ -1456,21 +1462,13 @@ static int ip_mkroute_input(struct sk_buff *skb,
                            struct in_device *in_dev,
                            __be32 daddr, __be32 saddr, u32 tos)
 {
-       struct rtable *rth = NULL;
-       int err;
-
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
        if (res->fi && res->fi->fib_nhs > 1)
                fib_select_multipath(res);
 #endif
 
        /* create a routing cache entry */
-       err = __mkroute_input(skb, res, in_dev, daddr, saddr, tos, &rth);
-       if (err)
-               return err;
-
-       skb_dst_set(skb, &rth->dst);
-       return 0;
+       return __mkroute_input(skb, res, in_dev, daddr, saddr, tos);
 }
 
 /*
@@ -1586,8 +1584,9 @@ local_input:
                if (!itag) {
                        rth = FIB_RES_NH(res).nh_rth_input;
                        if (rt_cache_valid(rth)) {
-                               dst_hold(&rth->dst);
-                               goto set_and_out;
+                               skb_dst_set_noref(skb, &rth->dst);
+                               err = 0;
+                               goto out;
                        }
                        do_cache = true;
                }
@@ -1618,7 +1617,6 @@ local_input:
        }
        if (do_cache)
                rt_cache_route(&FIB_RES_NH(res), rth);
-set_and_out:
        skb_dst_set(skb, &rth->dst);
        err = 0;
        goto out;
@@ -1656,8 +1654,8 @@ martian_source_keep_err:
        goto out;
 }
 
-int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr,
-                  u8 tos, struct net_device *dev)
+int ip_route_input_noref(struct sk_buff *skb, __be32 daddr, __be32 saddr,
+                        u8 tos, struct net_device *dev)
 {
        int res;
 
@@ -1700,7 +1698,7 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr,
        rcu_read_unlock();
        return res;
 }
-EXPORT_SYMBOL(ip_route_input);
+EXPORT_SYMBOL(ip_route_input_noref);
 
 /* called with rcu_read_lock() */
 static struct rtable *__mkroute_output(const struct fib_result *res,
index 3e30548ac32a263ddb4f377c09d4b62dbc418f1e..b6b07c93924c37e710b3ccef83f06235160d7588 100644 (file)
@@ -1686,7 +1686,6 @@ void tcp_v4_early_demux(struct sk_buff *skb)
        struct net *net = dev_net(skb->dev);
        const struct iphdr *iph;
        const struct tcphdr *th;
-       struct net_device *dev;
        struct sock *sk;
 
        if (skb->pkt_type != PACKET_HOST)
@@ -1701,14 +1700,10 @@ void tcp_v4_early_demux(struct sk_buff *skb)
        if (th->doff < sizeof(struct tcphdr) / 4)
                return;
 
-       if (!pskb_may_pull(skb, ip_hdrlen(skb) + th->doff * 4))
-               return;
-
-       dev = skb->dev;
        sk = __inet_lookup_established(net, &tcp_hashinfo,
                                       iph->saddr, th->source,
                                       iph->daddr, ntohs(th->dest),
-                                      dev->ifindex);
+                                      skb->skb_iif);
        if (sk) {
                skb->sk = sk;
                skb->destructor = sock_edemux;
@@ -1718,7 +1713,7 @@ void tcp_v4_early_demux(struct sk_buff *skb)
                        if (dst)
                                dst = dst_check(dst, 0);
                        if (dst &&
-                           icsk->rx_dst_ifindex == dev->ifindex)
+                           icsk->rx_dst_ifindex == skb->skb_iif)
                                skb_dst_set_noref(skb, dst);
                }
        }
index 58d23a57250982b7b0f01986c17ff105b0350135..06814b6216dc1bc71fedc9924b23d74b817a38d8 100644 (file)
@@ -27,8 +27,8 @@ static inline int xfrm4_rcv_encap_finish(struct sk_buff *skb)
        if (skb_dst(skb) == NULL) {
                const struct iphdr *iph = ip_hdr(skb);
 
-               if (ip_route_input(skb, iph->daddr, iph->saddr,
-                                  iph->tos, skb->dev))
+               if (ip_route_input_noref(skb, iph->daddr, iph->saddr,
+                                        iph->tos, skb->dev))
                        goto drop;
        }
        return dst_input(skb);
index 5ab923e51af3d4232afe9ea56af0933b7dcb8b9c..47975e363fcdec47ad3c12f5097688e839772167 100644 (file)
 
 
 
-inline int ip6_rcv_finish( struct sk_buff *skb)
+int ip6_rcv_finish(struct sk_buff *skb)
 {
-       if (skb_dst(skb) == NULL)
+       if (sysctl_ip_early_demux && !skb_dst(skb)) {
+               const struct inet6_protocol *ipprot;
+
+               rcu_read_lock();
+               ipprot = rcu_dereference(inet6_protos[ipv6_hdr(skb)->nexthdr]);
+               if (ipprot && ipprot->early_demux)
+                       ipprot->early_demux(skb);
+               rcu_read_unlock();
+       }
+       if (!skb_dst(skb))
                ip6_route_input(skb);
 
        return dst_input(skb);
index f49476e2d8845092d8d0e30dcf6ec9a7db7a6106..221224e72507cf462021c8ff330e355f067e7efb 100644 (file)
@@ -1674,6 +1674,43 @@ do_time_wait:
        goto discard_it;
 }
 
+static void tcp_v6_early_demux(struct sk_buff *skb)
+{
+       const struct ipv6hdr *hdr;
+       const struct tcphdr *th;
+       struct sock *sk;
+
+       if (skb->pkt_type != PACKET_HOST)
+               return;
+
+       if (!pskb_may_pull(skb, skb_transport_offset(skb) + sizeof(struct tcphdr)))
+               return;
+
+       hdr = ipv6_hdr(skb);
+       th = tcp_hdr(skb);
+
+       if (th->doff < sizeof(struct tcphdr) / 4)
+               return;
+
+       sk = __inet6_lookup_established(dev_net(skb->dev), &tcp_hashinfo,
+                                       &hdr->saddr, th->source,
+                                       &hdr->daddr, ntohs(th->dest),
+                                       inet6_iif(skb));
+       if (sk) {
+               skb->sk = sk;
+               skb->destructor = sock_edemux;
+               if (sk->sk_state != TCP_TIME_WAIT) {
+                       struct dst_entry *dst = sk->sk_rx_dst;
+                       struct inet_sock *icsk = inet_sk(sk);
+                       if (dst)
+                               dst = dst_check(dst, 0);
+                       if (dst &&
+                           icsk->rx_dst_ifindex == inet6_iif(skb))
+                               skb_dst_set_noref(skb, dst);
+               }
+       }
+}
+
 static struct timewait_sock_ops tcp6_timewait_sock_ops = {
        .twsk_obj_size  = sizeof(struct tcp6_timewait_sock),
        .twsk_unique    = tcp_twsk_unique,
@@ -1984,6 +2021,7 @@ struct proto tcpv6_prot = {
 };
 
 static const struct inet6_protocol tcpv6_protocol = {
+       .early_demux    =       tcp_v6_early_demux,
        .handler        =       tcp_v6_rcv,
        .err_handler    =       tcp_v6_err,
        .gso_send_check =       tcp_v6_gso_send_check,
index 788a12c1eb5d61c9df0a98d6ca2f5ad8ce7bfeda..2ab785064b7e36da5d0871f2abfd57b5a92f09ee 100644 (file)
@@ -602,36 +602,31 @@ static int wanrouter_device_new_if(struct wan_device *wandev,
                 * successfully, add it to the interface list.
                 */
 
-               if (dev->name == NULL) {
-                       err = -EINVAL;
-               } else {
+#ifdef WANDEBUG
+               printk(KERN_INFO "%s: registering interface %s...\n",
+                      wanrouter_modname, dev->name);
+#endif
 
-                       #ifdef WANDEBUG
-                       printk(KERN_INFO "%s: registering interface %s...\n",
-                               wanrouter_modname, dev->name);
-                       #endif
-
-                       err = register_netdev(dev);
-                       if (!err) {
-                               struct net_device *slave = NULL;
-                               unsigned long smp_flags=0;
-
-                               lock_adapter_irq(&wandev->lock, &smp_flags);
-
-                               if (wandev->dev == NULL) {
-                                       wandev->dev = dev;
-                               } else {
-                                       for (slave=wandev->dev;
-                                            DEV_TO_SLAVE(slave);
-                                            slave = DEV_TO_SLAVE(slave))
-                                               DEV_TO_SLAVE(slave) = dev;
-                               }
-                               ++wandev->ndev;
-
-                               unlock_adapter_irq(&wandev->lock, &smp_flags);
-                               err = 0;        /* done !!! */
-                               goto out;
+               err = register_netdev(dev);
+               if (!err) {
+                       struct net_device *slave = NULL;
+                       unsigned long smp_flags=0;
+
+                       lock_adapter_irq(&wandev->lock, &smp_flags);
+
+                       if (wandev->dev == NULL) {
+                               wandev->dev = dev;
+                       } else {
+                               for (slave=wandev->dev;
+                                    DEV_TO_SLAVE(slave);
+                                    slave = DEV_TO_SLAVE(slave))
+                                       DEV_TO_SLAVE(slave) = dev;
                        }
+                       ++wandev->ndev;
+
+                       unlock_adapter_irq(&wandev->lock, &smp_flags);
+                       err = 0;        /* done !!! */
+                       goto out;
                }
                if (wandev->del_if)
                        wandev->del_if(wandev, dev);