Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 20 May 2011 20:43:21 +0000 (13:43 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 20 May 2011 20:43:21 +0000 (13:43 -0700)
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1446 commits)
  macvlan: fix panic if lowerdev in a bond
  tg3: Add braces around 5906 workaround.
  tg3: Fix NETIF_F_LOOPBACK error
  macvlan: remove one synchronize_rcu() call
  networking: NET_CLS_ROUTE4 depends on INET
  irda: Fix error propagation in ircomm_lmp_connect_response()
  irda: Kill set but unused variable 'bytes' in irlan_check_command_param()
  irda: Kill set but unused variable 'clen' in ircomm_connect_indication()
  rxrpc: Fix set but unused variable 'usage' in rxrpc_get_transport()
  be2net: Kill set but unused variable 'req' in lancer_fw_download()
  irda: Kill set but unused vars 'saddr' and 'daddr' in irlan_provider_connect_indication()
  atl1c: atl1c_resume() is only used when CONFIG_PM_SLEEP is defined.
  rxrpc: Fix set but unused variable 'usage' in rxrpc_get_peer().
  rxrpc: Kill set but unused variable 'local' in rxrpc_UDP_error_handler()
  rxrpc: Kill set but unused variable 'sp' in rxrpc_process_connection()
  rxrpc: Kill set but unused variable 'sp' in rxrpc_rotate_tx_window()
  pkt_sched: Kill set but unused variable 'protocol' in tc_classify()
  isdn: capi: Use pr_debug() instead of ifdefs.
  tg3: Update version to 3.119
  tg3: Apply rx_discards fix to 5719/5720
  ...

Fix up trivial conflicts in arch/x86/Kconfig and net/mac80211/agg-tx.c
as per Davem.

40 files changed:
1  2 
Documentation/feature-removal-schedule.txt
MAINTAINERS
arch/x86/Kconfig
drivers/Kconfig
drivers/infiniband/hw/cxgb4/cm.c
drivers/net/acenic.c
drivers/net/arm/etherh.c
drivers/net/ehea/ehea_main.c
drivers/net/fs_enet/fs_enet-main.c
drivers/net/ixgbe/ixgbe_main.c
drivers/net/macvlan.c
drivers/net/sunhme.c
drivers/scsi/bnx2fc/bnx2fc_fcoe.c
drivers/scsi/fcoe/fcoe.c
include/linux/ssb/ssb.h
include/net/sctp/sctp.h
net/9p/client.c
net/batman-adv/gateway_client.c
net/batman-adv/originator.c
net/batman-adv/soft-interface.c
net/core/dst.c
net/core/net-sysfs.c
net/core/net_namespace.c
net/core/pktgen.c
net/core/skbuff.c
net/decnet/dn_dev.c
net/ipv4/fib_trie.c
net/ipv4/igmp.c
net/ipv6/addrconf.c
net/ipv6/mcast.c
net/ipv6/sit.c
net/l2tp/l2tp_ip.c
net/mac80211/agg-tx.c
net/mac80211/work.c
net/phonet/pn_dev.c
net/sctp/bind_addr.c
net/sctp/ipv6.c
net/sctp/protocol.c
net/sctp/ulpevent.c
net/socket.c

@@@ -35,17 -35,6 +35,6 @@@ Who: Luis R. Rodriguez <lrodriguez@athe
  
  ---------------------------
  
- What: AR9170USB
- When: 2.6.40
- Why:  This driver is deprecated and the firmware is no longer
-       maintained. The replacement driver "carl9170" has been
-       around for a while, so the devices are still supported.
- Who:  Christian Lamparter <chunkeey@googlemail.com>
- ---------------------------
  What: IRQF_SAMPLE_RANDOM
  Check:        IRQF_SAMPLE_RANDOM
  When: July 2009
@@@ -387,6 -376,26 +376,6 @@@ Who:      Tejun Heo <tj@kernel.org
  
  ----------------------------
  
 -What: Support for lcd_switch and display_get in asus-laptop driver
 -When: March 2010
 -Why:  These two features use non-standard interfaces. There are the
 -      only features that really need multiple path to guess what's
 -      the right method name on a specific laptop.
 -
 -      Removing them will allow to remove a lot of code an significantly
 -      clean the drivers.
 -
 -      This will affect the backlight code which won't be able to know
 -      if the backlight is on or off. The platform display file will also be
 -      write only (like the one in eeepc-laptop).
 -
 -      This should'nt affect a lot of user because they usually know
 -      when their display is on or off.
 -
 -Who:  Corentin Chary <corentin.chary@gmail.com>
 -
 -----------------------------
 -
  What: sysfs-class-rfkill state file
  When: Feb 2014
  Files:        net/rfkill/core.c
@@@ -405,16 -414,6 +394,6 @@@ Who:      anybody or Florian Mickler <flori
  
  ----------------------------
  
- What: capifs
- When: February 2011
- Files:        drivers/isdn/capi/capifs.*
- Why:  udev fully replaces this special file system that only contains CAPI
-       NCCI TTY device nodes. User space (pppdcapiplugin) works without
-       noticing the difference.
- Who:  Jan Kiszka <jan.kiszka@web.de>
- ----------------------------
  What: KVM paravirt mmu host support
  When: January 2011
  Why:  The paravirt mmu host support is slower than non-paravirt mmu, both
@@@ -460,6 -459,14 +439,6 @@@ Who:      Thomas Gleixner <tglx@linutronix.d
  
  ----------------------------
  
 -What: The acpi_sleep=s4_nonvs command line option
 -When: 2.6.37
 -Files:        arch/x86/kernel/acpi/sleep.c
 -Why:  superseded by acpi_sleep=nonvs
 -Who:  Rafael J. Wysocki <rjw@sisk.pl>
 -
 -----------------------------
 -
  What:         PCI DMA unmap state API
  When: August 2012
  Why:  PCI DMA unmap state API (include/linux/pci-dma.h) was replaced
diff --combined MAINTAINERS
@@@ -185,9 -185,10 +185,9 @@@ F:        Documentation/filesystems/9p.tx
  F:    fs/9p/
  
  A2232 SERIAL BOARD DRIVER
 -M:    Enver Haase <A2232@gmx.net>
  L:    linux-m68k@lists.linux-m68k.org
 -S:    Maintained
 -F:    drivers/char/ser_a2232*
 +S:    Orphan
 +F:    drivers/staging/generic_serial/ser_a2232*
  
  AACRAID SCSI RAID DRIVER
  M:    Adaptec OEM Raid Solutions <aacraid@adaptec.com>
@@@ -405,8 -406,8 +405,8 @@@ S: Maintaine
  F:    sound/oss/aedsp16.c
  
  AFFS FILE SYSTEM
 -M:    Roman Zippel <zippel@linux-m68k.org>
 -S:    Maintained
 +L:    linux-fsdevel@vger.kernel.org
 +S:    Orphan
  F:    Documentation/filesystems/affs.txt
  F:    fs/affs/
  
@@@ -877,13 -878,6 +877,13 @@@ F:       arch/arm/mach-mv78xx0
  F:    arch/arm/mach-orion5x/
  F:    arch/arm/plat-orion/
  
 +ARM/Orion SoC/Technologic Systems TS-78xx platform support
 +M:    Alexander Clouter <alex@digriz.org.uk>
 +L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 +W:    http://www.digriz.org.uk/ts78xx/kernel
 +S:    Maintained
 +F:    arch/arm/mach-orion5x/ts78xx-*
 +
  ARM/MIOA701 MACHINE SUPPORT
  M:    Robert Jarzmik <robert.jarzmik@free.fr>
  L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@@ -1032,13 -1026,12 +1032,13 @@@ W:   http://www.fluff.org/ben/linux
  S:    Maintained
  F:    arch/arm/mach-s3c64xx/
  
 -ARM/S5P ARM ARCHITECTURES
 +ARM/S5P EXYNOS ARM ARCHITECTURES
  M:    Kukjin Kim <kgene.kim@samsung.com>
  L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
  L:    linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
  S:    Maintained
  F:    arch/arm/mach-s5p*/
 +F:    arch/arm/mach-exynos*/
  
  ARM/SAMSUNG MOBILE MACHINE SUPPORT
  M:    Kyungmin Park <kyungmin.park@samsung.com>
@@@ -1071,7 -1064,7 +1071,7 @@@ F:      arch/arm/mach-shmobile
  F:    drivers/sh/
  
  ARM/TELECHIPS ARM ARCHITECTURE
 -M:    "Hans J. Koch" <hjk@linutronix.de>
 +M:    "Hans J. Koch" <hjk@hansjkoch.de>
  L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
  S:    Maintained
  F:    arch/arm/plat-tcc/
@@@ -1232,13 -1225,6 +1232,6 @@@ W:     http://wireless.kernel.org/en/users/
  S:    Supported
  F:    drivers/net/wireless/ath/ath9k/
  
- ATHEROS AR9170 WIRELESS DRIVER
- M:    Christian Lamparter <chunkeey@web.de>
- L:    linux-wireless@vger.kernel.org
- W:    http://wireless.kernel.org/en/users/Drivers/ar9170
- S:    Obsolete
- F:    drivers/net/wireless/ath/ar9170/
  CARL9170 LINUX COMMUNITY WIRELESS DRIVER
  M:    Christian Lamparter <chunkeey@googlemail.com>
  L:    linux-wireless@vger.kernel.org
@@@ -1831,10 -1817,11 +1824,10 @@@ S:   Maintaine
  F:    drivers/platform/x86/compal-laptop.c
  
  COMPUTONE INTELLIPORT MULTIPORT CARD
 -M:    "Michael H. Warfield" <mhw@wittsend.com>
  W:    http://www.wittsend.com/computone.html
 -S:    Maintained
 +S:    Orphan
  F:    Documentation/serial/computone.txt
 -F:    drivers/char/ip2/
 +F:    drivers/staging/tty/ip2/
  
  CONEXANT ACCESSRUNNER USB DRIVER
  M:    Simon Arlott <cxacru@fire.lp0.eu>
@@@ -2017,7 -2004,7 +2010,7 @@@ F:      drivers/net/wan/cycx
  CYCLADES ASYNC MUX DRIVER
  W:    http://www.cyclades.com/
  S:    Orphan
 -F:    drivers/char/cyclades.c
 +F:    drivers/tty/cyclades.c
  F:    include/linux/cyclades.h
  
  CYCLADES PC300 DRIVER
@@@ -2131,8 -2118,8 +2124,8 @@@ L:      Eng.Linux@digi.co
  W:    http://www.digi.com
  S:    Orphan
  F:    Documentation/serial/digiepca.txt
 -F:    drivers/char/epca*
 -F:    drivers/char/digi*
 +F:    drivers/staging/tty/epca*
 +F:    drivers/staging/tty/digi*
  
  DIOLAN U2C-12 I2C DRIVER
  M:    Guenter Roeck <guenter.roeck@ericsson.com>
@@@ -2809,23 -2796,42 +2802,23 @@@ GPIO SUBSYSTE
  M:    Grant Likely <grant.likely@secretlab.ca>
  S:    Maintained
  T:    git git://git.secretlab.ca/git/linux-2.6.git
 -F:    Documentation/gpio/gpio.txt
 +F:    Documentation/gpio.txt
  F:    drivers/gpio/
  F:    include/linux/gpio*
  
 +GRE DEMULTIPLEXER DRIVER
 +M:    Dmitry Kozlov <xeb@mail.ru>
 +L:    netdev@vger.kernel.org
 +S:    Maintained
 +F:    net/ipv4/gre.c
 +F:    include/net/gre.h
 +
  GRETH 10/100/1G Ethernet MAC device driver
  M:    Kristoffer Glembo <kristoffer@gaisler.com>
  L:    netdev@vger.kernel.org
  S:    Maintained
  F:    drivers/net/greth*
  
 -HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER
 -M:    Frank Seidel <frank@f-seidel.de>
 -L:    platform-driver-x86@vger.kernel.org
 -W:    http://www.kernel.org/pub/linux/kernel/people/fseidel/hdaps/
 -S:    Maintained
 -F:    drivers/platform/x86/hdaps.c
 -
 -HWPOISON MEMORY FAILURE HANDLING
 -M:    Andi Kleen <andi@firstfloor.org>
 -L:    linux-mm@kvack.org
 -T:    git git://git.kernel.org/pub/scm/linux/kernel/git/ak/linux-mce-2.6.git hwpoison
 -S:    Maintained
 -F:    mm/memory-failure.c
 -F:    mm/hwpoison-inject.c
 -
 -HYPERVISOR VIRTUAL CONSOLE DRIVER
 -L:    linuxppc-dev@lists.ozlabs.org
 -S:    Odd Fixes
 -F:    drivers/tty/hvc/
 -
 -iSCSI BOOT FIRMWARE TABLE (iBFT) DRIVER
 -M:    Peter Jones <pjones@redhat.com>
 -M:    Konrad Rzeszutek Wilk <konrad@kernel.org>
 -S:    Maintained
 -F:    drivers/firmware/iscsi_ibft*
 -
  GSPCA FINEPIX SUBDRIVER
  M:    Frank Zago <frank@zago.net>
  L:    linux-media@vger.kernel.org
@@@ -2876,26 -2882,6 +2869,26 @@@ T:    git git://git.kernel.org/pub/scm/lin
  S:    Maintained
  F:    drivers/media/video/gspca/
  
 +HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER
 +M:    Frank Seidel <frank@f-seidel.de>
 +L:    platform-driver-x86@vger.kernel.org
 +W:    http://www.kernel.org/pub/linux/kernel/people/fseidel/hdaps/
 +S:    Maintained
 +F:    drivers/platform/x86/hdaps.c
 +
 +HWPOISON MEMORY FAILURE HANDLING
 +M:    Andi Kleen <andi@firstfloor.org>
 +L:    linux-mm@kvack.org
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/ak/linux-mce-2.6.git hwpoison
 +S:    Maintained
 +F:    mm/memory-failure.c
 +F:    mm/hwpoison-inject.c
 +
 +HYPERVISOR VIRTUAL CONSOLE DRIVER
 +L:    linuxppc-dev@lists.ozlabs.org
 +S:    Odd Fixes
 +F:    drivers/tty/hvc/
 +
  HARDWARE MONITORING
  M:    Jean Delvare <khali@linux-fr.org>
  M:    Guenter Roeck <guenter.roeck@ericsson.com>
@@@ -2946,8 -2932,8 +2939,8 @@@ F:      drivers/block/cciss
  F:    include/linux/cciss_ioctl.h
  
  HFS FILESYSTEM
 -M:    Roman Zippel <zippel@linux-m68k.org>
 -S:    Maintained
 +L:    linux-fsdevel@vger.kernel.org
 +S:    Orphan
  F:    Documentation/filesystems/hfs.txt
  F:    fs/hfs/
  
@@@ -3363,6 -3349,12 +3356,12 @@@ F:    Documentation/wimax/README.i2400
  F:    drivers/net/wimax/i2400m/
  F:    include/linux/wimax/i2400m.h
  
+ INTEL WIRELESS 3945ABG/BG, 4965AGN (iwlegacy)
+ M:    Stanislaw Gruszka <sgruszka@redhat.com>
+ L:    linux-wireless@vger.kernel.org
+ S:    Supported
+ F:    drivers/net/wireless/iwlegacy/
  INTEL WIRELESS WIFI LINK (iwlwifi)
  M:    Wey-Yi Guy <wey-yi.w.guy@intel.com>
  M:    Intel Linux Wireless <ilw@linux.intel.com>
@@@ -3479,12 -3471,6 +3478,12 @@@ F:    Documentation/isapnp.tx
  F:    drivers/pnp/isapnp/
  F:    include/linux/isapnp.h
  
 +iSCSI BOOT FIRMWARE TABLE (iBFT) DRIVER
 +M:    Peter Jones <pjones@redhat.com>
 +M:    Konrad Rzeszutek Wilk <konrad@kernel.org>
 +S:    Maintained
 +F:    drivers/firmware/iscsi_ibft*
 +
  ISCSI
  M:    Mike Christie <michaelc@cs.wisc.edu>
  L:    open-iscsi@googlegroups.com
@@@ -3814,7 -3800,7 +3813,7 @@@ M:      Rusty Russell <rusty@rustcorp.com.au
  L:    lguest@lists.ozlabs.org
  W:    http://lguest.ozlabs.org/
  S:    Odd Fixes
 -F:    Documentation/lguest/
 +F:    Documentation/virtual/lguest/
  F:    arch/x86/lguest/
  F:    drivers/lguest/
  F:    include/linux/lguest*.h
@@@ -4001,6 -3987,7 +4000,6 @@@ F:      arch/m32r
  
  M68K ARCHITECTURE
  M:    Geert Uytterhoeven <geert@linux-m68k.org>
 -M:    Roman Zippel <zippel@linux-m68k.org>
  L:    linux-m68k@lists.linux-m68k.org
  W:    http://www.linux-m68k.org/
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/geert/linux-m68k.git
@@@ -4090,7 -4077,7 +4089,7 @@@ F:      drivers/video/matrox/matroxfb_
  F:    include/linux/matroxfb.h
  
  MAX6650 HARDWARE MONITOR AND FAN CONTROLLER DRIVER
 -M:    "Hans J. Koch" <hjk@linutronix.de>
 +M:    "Hans J. Koch" <hjk@hansjkoch.de>
  L:    lm-sensors@lm-sensors.org
  S:    Maintained
  F:    Documentation/hwmon/max6650
@@@ -4205,7 -4192,7 +4204,7 @@@ MOXA SMARTIO/INDUSTIO/INTELLIO SERIAL C
  M:    Jiri Slaby <jirislaby@gmail.com>
  S:    Maintained
  F:    Documentation/serial/moxa-smartio
 -F:    drivers/char/mxser.*
 +F:    drivers/tty/mxser.*
  
  MSI LAPTOP SUPPORT
  M:    "Lee, Chun-Yi" <jlee@novell.com>
@@@ -4247,7 -4234,7 +4246,7 @@@ F:      sound/oss/msnd
  
  MULTITECH MULTIPORT CARD (ISICOM)
  S:    Orphan
 -F:    drivers/char/isicom.c
 +F:    drivers/tty/isicom.c
  F:    include/linux/isicom.h
  
  MUSB MULTIPOINT HIGH SPEED DUAL-ROLE CONTROLLER
@@@ -4385,6 -4372,7 +4384,7 @@@ S:      Maintaine
  F:    net/ipv4/
  F:    net/ipv6/
  F:    include/net/ip*
+ F:    arch/x86/net/*
  
  NETWORKING [LABELED] (NetLabel, CIPSO, Labeled IPsec, SECMARK)
  M:    Paul Moore <paul.moore@hp.com>
@@@ -4995,13 -4983,6 +4995,13 @@@ F:    Documentation/pps
  F:    drivers/pps/
  F:    include/linux/pps*.h
  
 +PPTP DRIVER
 +M:    Dmitry Kozlov <xeb@mail.ru>
 +L:    netdev@vger.kernel.org
 +S:    Maintained
 +F:    drivers/net/pptp.c
 +W:    http://sourceforge.net/projects/accel-pptp
 +
  PREEMPTIBLE KERNEL
  M:    Robert Love <rml@tech9.net>
  L:    kpreempt-tech@lists.sourceforge.net
@@@ -5293,14 -5274,14 +5293,14 @@@ F:   drivers/memstick/host/r592.
  RISCOM8 DRIVER
  S:    Orphan
  F:    Documentation/serial/riscom8.txt
 -F:    drivers/char/riscom8*
 +F:    drivers/staging/tty/riscom8*
  
  ROCKETPORT DRIVER
  P:    Comtrol Corp.
  W:    http://www.comtrol.com
  S:    Maintained
  F:    Documentation/serial/rocket.txt
 -F:    drivers/char/rocket*
 +F:    drivers/tty/rocket*
  
  ROSE NETWORK LAYER
  M:    Ralf Baechle <ralf@linux-mips.org>
@@@ -5410,7 -5391,7 +5410,7 @@@ F:      drivers/media/video/*7146
  F:    include/media/*7146*
  
  SAMSUNG AUDIO (ASoC) DRIVERS
 -M:    Jassi Brar <jassi.brar@samsung.com>
 +M:    Jassi Brar <jassisinghbrar@gmail.com>
  L:    alsa-devel@alsa-project.org (moderated for non-subscribers)
  S:    Supported
  F:    sound/soc/samsung
@@@ -5431,7 -5412,6 +5431,7 @@@ F:      include/linux/timex.
  F:    kernel/time/clocksource.c
  F:    kernel/time/time*.c
  F:    kernel/time/ntp.c
 +F:    drivers/clocksource
  
  TLG2300 VIDEO4LINUX-2 DRIVER
  M:    Huang Shijie <shijie8@gmail.com>
@@@ -5612,9 -5592,9 +5612,9 @@@ F:      include/linux/ata.
  F:    include/linux/libata.h
  
  SERVER ENGINES 10Gbps iSCSI - BladeEngine 2 DRIVER
 -M:    Jayamohan Kallickal <jayamohank@serverengines.com>
 +M:    Jayamohan Kallickal <jayamohan.kallickal@emulex.com>
  L:    linux-scsi@vger.kernel.org
 -W:    http://www.serverengines.com
 +W:    http://www.emulex.com
  S:    Supported
  F:    drivers/scsi/be2iscsi/
  
@@@ -5832,6 -5812,13 +5832,13 @@@ S:    Maintaine
  F:    drivers/ssb/
  F:    include/linux/ssb/
  
+ BROADCOM SPECIFIC AMBA DRIVER (BCMA)
+ M:    RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com>
+ L:    linux-wireless@vger.kernel.org
+ S:    Maintained
+ F:    drivers/bcma/
+ F:    include/linux/bcma/
  SONY VAIO CONTROL DEVICE DRIVER
  M:    Mattia Dongili <malattia@linux.it>
  L:    platform-driver-x86@vger.kernel.org
@@@ -5937,9 -5924,10 +5944,9 @@@ F:     arch/arm/mach-spear6xx/spear600.
  F:    arch/arm/mach-spear6xx/spear600_evb.c
  
  SPECIALIX IO8+ MULTIPORT SERIAL CARD DRIVER
 -M:    Roger Wolff <R.E.Wolff@BitWizard.nl>
 -S:    Supported
 +S:    Orphan
  F:    Documentation/serial/specialix.txt
 -F:    drivers/char/specialix*
 +F:    drivers/staging/tty/specialix*
  
  SPI SUBSYSTEM
  M:    David Brownell <dbrownell@users.sourceforge.net>
@@@ -5984,6 -5972,7 +5991,6 @@@ F:      arch/alpha/kernel/srm_env.
  
  STABLE BRANCH
  M:    Greg Kroah-Hartman <greg@kroah.com>
 -M:    Chris Wright <chrisw@sous-sol.org>
  L:    stable@kernel.org
  S:    Maintained
  
@@@ -6267,8 -6256,7 +6274,8 @@@ M:      Greg Ungerer <gerg@uclinux.org
  W:    http://www.uclinux.org/
  L:    uclinux-dev@uclinux.org  (subscribers-only)
  S:    Maintained
 -F:    arch/m68knommu/
 +F:    arch/m68k/*/*_no.*
 +F:    arch/m68k/include/asm/*_no.*
  
  UCLINUX FOR RENESAS H8/300 (H8300)
  M:    Yoshinori Sato <ysato@users.sourceforge.jp>
@@@ -6632,13 -6620,13 +6639,13 @@@ L:   user-mode-linux-devel@lists.sourcefo
  L:    user-mode-linux-user@lists.sourceforge.net
  W:    http://user-mode-linux.sourceforge.net
  S:    Maintained
 -F:    Documentation/uml/
 +F:    Documentation/virtual/uml/
  F:    arch/um/
  F:    fs/hostfs/
  F:    fs/hppfs/
  
  USERSPACE I/O (UIO)
 -M:    "Hans J. Koch" <hjk@linutronix.de>
 +M:    "Hans J. Koch" <hjk@hansjkoch.de>
  M:    Greg Kroah-Hartman <gregkh@suse.de>
  S:    Maintained
  F:    Documentation/DocBook/uio-howto.tmpl
@@@ -6936,18 -6924,6 +6943,18 @@@ T:    git git://git.kernel.org/pub/scm/lin
  S:    Maintained
  F:    drivers/platform/x86
  
 +XEN HYPERVISOR INTERFACE
 +M:    Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
 +M:    Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
 +L:    xen-devel@lists.xensource.com (moderated for non-subscribers)
 +L:    virtualization@lists.linux-foundation.org
 +S:    Supported
 +F:    arch/x86/xen/
 +F:    drivers/*/xen-*front.c
 +F:    drivers/xen/
 +F:    arch/x86/include/asm/xen/
 +F:    include/xen/
 +
  XEN NETWORK BACKEND DRIVER
  M:    Ian Campbell <ian.campbell@citrix.com>
  L:    xen-devel@lists.xensource.com (moderated for non-subscribers)
@@@ -6969,6 -6945,18 +6976,6 @@@ S:     Supporte
  F:    arch/x86/xen/*swiotlb*
  F:    drivers/xen/*swiotlb*
  
 -XEN HYPERVISOR INTERFACE
 -M:    Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
 -M:    Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
 -L:    xen-devel@lists.xensource.com (moderated for non-subscribers)
 -L:    virtualization@lists.linux-foundation.org
 -S:    Supported
 -F:    arch/x86/xen/
 -F:    drivers/*/xen-*front.c
 -F:    drivers/xen/
 -F:    arch/x86/include/asm/xen/
 -F:    include/xen/
 -
  XFS FILESYSTEM
  P:    Silicon Graphics Inc
  M:    Alex Elder <aelder@sgi.com>
@@@ -7038,6 -7026,20 +7045,6 @@@ M:     "Maciej W. Rozycki" <macro@linux-mip
  S:    Maintained
  F:    drivers/tty/serial/zs.*
  
 -GRE DEMULTIPLEXER DRIVER
 -M:    Dmitry Kozlov <xeb@mail.ru>
 -L:    netdev@vger.kernel.org
 -S:    Maintained
 -F:    net/ipv4/gre.c
 -F:    include/net/gre.h
 -
 -PPTP DRIVER
 -M:    Dmitry Kozlov <xeb@mail.ru>
 -L:    netdev@vger.kernel.org
 -S:    Maintained
 -F:    drivers/net/pptp.c
 -W:    http://sourceforge.net/projects/accel-pptp
 -
  THE REST
  M:    Linus Torvalds <torvalds@linux-foundation.org>
  L:    linux-kernel@vger.kernel.org
diff --combined arch/x86/Kconfig
@@@ -8,7 -8,6 +8,7 @@@ config 64BI
  
  config X86_32
        def_bool !64BIT
 +      select CLKSRC_I8253
  
  config X86_64
        def_bool 64BIT
@@@ -72,6 -71,8 +72,7 @@@ config X8
        select GENERIC_IRQ_SHOW
        select IRQ_FORCED_THREADING
        select USE_GENERIC_SMP_HELPERS if SMP
 -      select ARCH_NO_SYSDEV_OPS
+       select HAVE_BPF_JIT if (X86_64 && NET)
  
  config INSTRUCTION_DECODER
        def_bool (KPROBES || PERF_EVENTS)
@@@ -112,14 -113,7 +113,14 @@@ config MM
        def_bool y
  
  config ZONE_DMA
 -      def_bool y
 +      bool "DMA memory allocation support" if EXPERT
 +      default y
 +      help
 +        DMA memory allocation support allows devices with less than 32-bit
 +        addressing to allocate within the first 16MB of address space.
 +        Disable if no such devices will be used.
 +
 +        If unsure, say Y.
  
  config SBUS
        bool
@@@ -372,6 -366,17 +373,6 @@@ config X86_U
  # Following is an alphabetically sorted list of 32 bit extended platforms
  # Please maintain the alphabetic order if and when there are additions
  
 -config X86_ELAN
 -      bool "AMD Elan"
 -      depends on X86_32
 -      depends on X86_EXTENDED_PLATFORM
 -      ---help---
 -        Select this for an AMD Elan processor.
 -
 -        Do not use this option for K6/Athlon/Opteron processors!
 -
 -        If unsure, choose "PC-compatible" instead.
 -
  config X86_INTEL_CE
        bool "CE4100 TV platform"
        depends on PCI
@@@ -686,7 -691,6 +687,7 @@@ config AMD_IOMM
        bool "AMD IOMMU support"
        select SWIOTLB
        select PCI_MSI
 +      select PCI_IOV
        depends on X86_64 && PCI && ACPI
        ---help---
          With this option you can enable support for AMD IOMMU hardware in
@@@ -1171,7 -1175,7 +1172,7 @@@ comment "NUMA (Summit) requires SMP, 64
  config AMD_NUMA
        def_bool y
        prompt "Old style AMD Opteron NUMA detection"
 -      depends on X86_64 && NUMA && PCI
 +      depends on NUMA && PCI
        ---help---
          Enable AMD NUMA node topology detection.  You should say Y here if
          you have a multi processor AMD system. This uses an old method to
@@@ -1198,7 -1202,7 +1199,7 @@@ config NODES_SPAN_OTHER_NODE
  
  config NUMA_EMU
        bool "NUMA emulation"
 -      depends on X86_64 && NUMA
 +      depends on NUMA
        ---help---
          Enable NUMA emulation. A flat machine will be split
          into virtual nodes when booted with "numa=fake=N", where N is the
@@@ -1220,10 -1224,6 +1221,10 @@@ config HAVE_ARCH_BOOTME
        def_bool y
        depends on X86_32 && NUMA
  
 +config HAVE_ARCH_ALLOC_REMAP
 +      def_bool y
 +      depends on X86_32 && NUMA
 +
  config ARCH_HAVE_MEMORY_PRESENT
        def_bool y
        depends on X86_32 && DISCONTIGMEM
@@@ -1232,9 -1232,13 +1233,9 @@@ config NEED_NODE_MEMMAP_SIZ
        def_bool y
        depends on X86_32 && (DISCONTIGMEM || SPARSEMEM)
  
 -config HAVE_ARCH_ALLOC_REMAP
 -      def_bool y
 -      depends on X86_32 && NUMA
 -
  config ARCH_FLATMEM_ENABLE
        def_bool y
 -      depends on X86_32 && ARCH_SELECT_MEMORY_MODEL && !NUMA
 +      depends on X86_32 && !NUMA
  
  config ARCH_DISCONTIGMEM_ENABLE
        def_bool y
@@@ -1244,16 -1248,20 +1245,16 @@@ config ARCH_DISCONTIGMEM_DEFAUL
        def_bool y
        depends on NUMA && X86_32
  
 -config ARCH_PROC_KCORE_TEXT
 -      def_bool y
 -      depends on X86_64 && PROC_KCORE
 -
 -config ARCH_SPARSEMEM_DEFAULT
 -      def_bool y
 -      depends on X86_64
 -
  config ARCH_SPARSEMEM_ENABLE
        def_bool y
        depends on X86_64 || NUMA || (EXPERIMENTAL && X86_32) || X86_32_NON_STANDARD
        select SPARSEMEM_STATIC if X86_32
        select SPARSEMEM_VMEMMAP_ENABLE if X86_64
  
 +config ARCH_SPARSEMEM_DEFAULT
 +      def_bool y
 +      depends on X86_64
 +
  config ARCH_SELECT_MEMORY_MODEL
        def_bool y
        depends on ARCH_SPARSEMEM_ENABLE
@@@ -1262,10 -1270,6 +1263,10 @@@ config ARCH_MEMORY_PROB
        def_bool X86_64
        depends on MEMORY_HOTPLUG
  
 +config ARCH_PROC_KCORE_TEXT
 +      def_bool y
 +      depends on X86_64 && PROC_KCORE
 +
  config ILLEGAL_POINTER_VALUE
         hex
         default 0 if X86_32
@@@ -1700,6 -1704,10 +1701,6 @@@ config ARCH_ENABLE_MEMORY_HOTREMOV
        def_bool y
        depends on MEMORY_HOTPLUG
  
 -config HAVE_ARCH_EARLY_PFN_TO_NID
 -      def_bool X86_64
 -      depends on NUMA
 -
  config USE_PERCPU_NUMA_NODE_ID
        def_bool y
        depends on NUMA
@@@ -1841,7 -1849,7 +1842,7 @@@ config APM_ALLOW_INT
  
  endif # APM
  
 -source "arch/x86/kernel/cpu/cpufreq/Kconfig"
 +source "drivers/cpufreq/Kconfig"
  
  source "drivers/cpuidle/Kconfig"
  
@@@ -2069,7 -2077,7 +2070,7 @@@ config OLP
        depends on !X86_PAE
        select GPIOLIB
        select OF
 -      select OF_PROMTREE if PROC_DEVICETREE
 +      select OF_PROMTREE
        ---help---
          Add support for detecting the unique features of the OLPC
          XO hardware.
diff --combined drivers/Kconfig
@@@ -68,6 -68,8 +68,8 @@@ source "drivers/watchdog/Kconfig
  
  source "drivers/ssb/Kconfig"
  
+ source "drivers/bcma/Kconfig"
  source "drivers/mfd/Kconfig"
  
  source "drivers/regulator/Kconfig"
@@@ -119,7 -121,4 +121,7 @@@ source "drivers/platform/Kconfig
  source "drivers/clk/Kconfig"
  
  source "drivers/hwspinlock/Kconfig"
 +
 +source "drivers/clocksource/Kconfig"
 +
  endmenu
@@@ -315,8 -315,9 +315,9 @@@ static struct rtable *find_route(struc
                                 __be16 peer_port, u8 tos)
  {
        struct rtable *rt;
+       struct flowi4 fl4;
  
-       rt = ip_route_output_ports(&init_net, NULL, peer_ip, local_ip,
+       rt = ip_route_output_ports(&init_net, &fl4, NULL, peer_ip, local_ip,
                                   peer_port, local_port, IPPROTO_TCP,
                                   tos, 0);
        if (IS_ERR(rt))
@@@ -1198,7 -1199,9 +1199,7 @@@ static int pass_open_rpl(struct c4iw_de
        }
        PDBG("%s ep %p status %d error %d\n", __func__, ep,
             rpl->status, status2errno(rpl->status));
 -      ep->com.wr_wait.ret = status2errno(rpl->status);
 -      ep->com.wr_wait.done = 1;
 -      wake_up(&ep->com.wr_wait.wait);
 +      c4iw_wake_up(&ep->com.wr_wait, status2errno(rpl->status));
  
        return 0;
  }
@@@ -1232,7 -1235,9 +1233,7 @@@ static int close_listsrv_rpl(struct c4i
        struct c4iw_listen_ep *ep = lookup_stid(t, stid);
  
        PDBG("%s ep %p\n", __func__, ep);
 -      ep->com.wr_wait.ret = status2errno(rpl->status);
 -      ep->com.wr_wait.done = 1;
 -      wake_up(&ep->com.wr_wait.wait);
 +      c4iw_wake_up(&ep->com.wr_wait, status2errno(rpl->status));
        return 0;
  }
  
@@@ -1462,7 -1467,7 +1463,7 @@@ static int peer_close(struct c4iw_dev *
        struct c4iw_qp_attributes attrs;
        int disconnect = 1;
        int release = 0;
 -      int closing = 0;
 +      int abort = 0;
        struct tid_info *t = dev->rdev.lldi.tids;
        unsigned int tid = GET_TID(hdr);
  
                 * in rdma connection migration (see c4iw_accept_cr()).
                 */
                __state_set(&ep->com, CLOSING);
 -              ep->com.wr_wait.done = 1;
 -              ep->com.wr_wait.ret = -ECONNRESET;
                PDBG("waking up ep %p tid %u\n", ep, ep->hwtid);
 -              wake_up(&ep->com.wr_wait.wait);
 +              c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET);
                break;
        case MPA_REP_SENT:
                __state_set(&ep->com, CLOSING);
 -              ep->com.wr_wait.done = 1;
 -              ep->com.wr_wait.ret = -ECONNRESET;
                PDBG("waking up ep %p tid %u\n", ep, ep->hwtid);
 -              wake_up(&ep->com.wr_wait.wait);
 +              c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET);
                break;
        case FPDU_MODE:
                start_ep_timer(ep);
                __state_set(&ep->com, CLOSING);
 -              closing = 1;
 +              attrs.next_state = C4IW_QP_STATE_CLOSING;
 +              abort = c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
 +                                     C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
                peer_close_upcall(ep);
 +              disconnect = 1;
                break;
        case ABORTING:
                disconnect = 0;
                BUG_ON(1);
        }
        mutex_unlock(&ep->com.mutex);
 -      if (closing) {
 -              attrs.next_state = C4IW_QP_STATE_CLOSING;
 -              c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
 -                             C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
 -      }
        if (disconnect)
                c4iw_ep_disconnect(ep, 0, GFP_KERNEL);
        if (release)
@@@ -1571,7 -1582,9 +1572,7 @@@ static int peer_abort(struct c4iw_dev *
        /*
         * Wake up any threads in rdma_init() or rdma_fini().
         */
 -      ep->com.wr_wait.done = 1;
 -      ep->com.wr_wait.ret = -ECONNRESET;
 -      wake_up(&ep->com.wr_wait.wait);
 +      c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET);
  
        mutex_lock(&ep->com.mutex);
        switch (ep->com.state) {
@@@ -1698,14 -1711,14 +1699,14 @@@ static int terminate(struct c4iw_dev *d
        ep = lookup_tid(t, tid);
        BUG_ON(!ep);
  
 -      if (ep->com.qp) {
 +      if (ep && ep->com.qp) {
                printk(KERN_WARNING MOD "TERM received tid %u qpid %u\n", tid,
                       ep->com.qp->wq.sq.qid);
                attrs.next_state = C4IW_QP_STATE_TERMINATE;
                c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
                               C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
        } else
 -              printk(KERN_WARNING MOD "TERM received tid %u no qp\n", tid);
 +              printk(KERN_WARNING MOD "TERM received tid %u no ep/qp\n", tid);
  
        return 0;
  }
@@@ -2284,8 -2297,14 +2285,8 @@@ static int fw6_msg(struct c4iw_dev *dev
                ret = (int)((be64_to_cpu(rpl->data[0]) >> 8) & 0xff);
                wr_waitp = (struct c4iw_wr_wait *)(__force unsigned long) rpl->data[1];
                PDBG("%s wr_waitp %p ret %u\n", __func__, wr_waitp, ret);
 -              if (wr_waitp) {
 -                      if (ret)
 -                              wr_waitp->ret = -ret;
 -                      else
 -                              wr_waitp->ret = 0;
 -                      wr_waitp->done = 1;
 -                      wake_up(&wr_waitp->wait);
 -              }
 +              if (wr_waitp)
 +                      c4iw_wake_up(wr_waitp, ret ? -ret : 0);
                kfree_skb(skb);
                break;
        case 2:
diff --combined drivers/net/acenic.c
@@@ -68,7 -68,6 +68,7 @@@
  #include <linux/sockios.h>
  #include <linux/firmware.h>
  #include <linux/slab.h>
 +#include <linux/prefetch.h>
  
  #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
  #include <linux/if_vlan.h>
@@@ -2659,15 -2658,15 +2659,15 @@@ static int ace_get_settings(struct net_
  
        link = readl(&regs->GigLnkState);
        if (link & LNK_1000MB)
-               ecmd->speed = SPEED_1000;
+               ethtool_cmd_speed_set(ecmd, SPEED_1000);
        else {
                link = readl(&regs->FastLnkState);
                if (link & LNK_100MB)
-                       ecmd->speed = SPEED_100;
+                       ethtool_cmd_speed_set(ecmd, SPEED_100);
                else if (link & LNK_10MB)
-                       ecmd->speed = SPEED_10;
+                       ethtool_cmd_speed_set(ecmd, SPEED_10);
                else
-                       ecmd->speed = 0;
+                       ethtool_cmd_speed_set(ecmd, 0);
        }
        if (link & LNK_FULL_DUPLEX)
                ecmd->duplex = DUPLEX_FULL;
@@@ -2719,9 -2718,9 +2719,9 @@@ static int ace_set_settings(struct net_
                link |= LNK_TX_FLOW_CTL_Y;
        if (ecmd->autoneg == AUTONEG_ENABLE)
                link |= LNK_NEGOTIATE;
-       if (ecmd->speed != speed) {
+       if (ethtool_cmd_speed(ecmd) != speed) {
                link &= ~(LNK_1000MB | LNK_100MB | LNK_10MB);
-               switch (speed) {
+               switch (ethtool_cmd_speed(ecmd)) {
                case SPEED_1000:
                        link |= LNK_1000MB;
                        break;
diff --combined drivers/net/arm/etherh.c
@@@ -527,7 -527,7 +527,7 @@@ static void __init etherh_banner(void
   * Read the ethernet address string from the on board rom.
   * This is an ascii string...
   */
 -static int __init etherh_addr(char *addr, struct expansion_card *ec)
 +static int __devinit etherh_addr(char *addr, struct expansion_card *ec)
  {
        struct in_chunk_dir cd;
        char *s;
@@@ -591,10 -591,11 +591,11 @@@ static void etherh_get_drvinfo(struct n
  static int etherh_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
  {
        cmd->supported  = etherh_priv(dev)->supported;
-       cmd->speed      = SPEED_10;
+       ethtool_cmd_speed_set(cmd, SPEED_10);
        cmd->duplex     = DUPLEX_HALF;
        cmd->port       = dev->if_port == IF_PORT_10BASET ? PORT_TP : PORT_BNC;
-       cmd->autoneg    = dev->flags & IFF_AUTOMEDIA ? AUTONEG_ENABLE : AUTONEG_DISABLE;
+       cmd->autoneg    = (dev->flags & IFF_AUTOMEDIA ?
+                          AUTONEG_ENABLE : AUTONEG_DISABLE);
        return 0;
  }
  
@@@ -655,7 -656,7 +656,7 @@@ static const struct net_device_ops ethe
  static u32 etherh_regoffsets[16];
  static u32 etherm_regoffsets[16];
  
 -static int __init
 +static int __devinit
  etherh_probe(struct expansion_card *ec, const struct ecard_id *id)
  {
        const struct etherh_data *data = id->data;
@@@ -41,7 -41,6 +41,7 @@@
  #include <linux/memory.h>
  #include <asm/kexec.h>
  #include <linux/mutex.h>
 +#include <linux/prefetch.h>
  
  #include <net/ip.h>
  
@@@ -3263,10 -3262,12 +3263,12 @@@ struct ehea_port *ehea_setup_single_por
        dev->netdev_ops = &ehea_netdev_ops;
        ehea_set_ethtool_ops(dev);
  
+       dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO
+                     | NETIF_F_IP_CSUM | NETIF_F_HW_VLAN_TX | NETIF_F_LRO;
        dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO
                      | NETIF_F_HIGHDMA | NETIF_F_IP_CSUM | NETIF_F_HW_VLAN_TX
                      | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER
-                     | NETIF_F_LLTX;
+                     | NETIF_F_LLTX | NETIF_F_RXCSUM;
        dev->watchdog_timeo = EHEA_WATCH_DOG_TIMEOUT;
  
        if (use_lro)
@@@ -956,8 -956,6 +956,6 @@@ static const struct ethtool_ops fs_etht
        .get_link = ethtool_op_get_link,
        .get_msglevel = fs_get_msglevel,
        .set_msglevel = fs_set_msglevel,
-       .set_tx_csum = ethtool_op_set_tx_csum,  /* local! */
-       .set_sg = ethtool_op_set_sg,
        .get_regs = fs_get_regs,
  };
  
@@@ -998,10 -996,8 +996,10 @@@ static const struct net_device_ops fs_e
  #endif
  };
  
 +static struct of_device_id fs_enet_match[];
  static int __devinit fs_enet_probe(struct platform_device *ofdev)
  {
 +      const struct of_device_id *match;
        struct net_device *ndev;
        struct fs_enet_private *fep;
        struct fs_platform_info *fpi;
        const u8 *mac_addr;
        int privsize, len, ret = -ENODEV;
  
 -      if (!ofdev->dev.of_match)
 +      match = of_match_device(fs_enet_match, &ofdev->dev);
 +      if (!match)
                return -EINVAL;
  
        fpi = kzalloc(sizeof(*fpi), GFP_KERNEL);
        if (!fpi)
                return -ENOMEM;
  
 -      if (!IS_FEC(ofdev->dev.of_match)) {
 +      if (!IS_FEC(match)) {
                data = of_get_property(ofdev->dev.of_node, "fsl,cpm-command", &len);
                if (!data || len != 4)
                        goto out_free_fpi;
        fep->dev = &ofdev->dev;
        fep->ndev = ndev;
        fep->fpi = fpi;
 -      fep->ops = ofdev->dev.of_match->data;
 +      fep->ops = match->data;
  
        ret = fep->ops->setup_data(ndev);
        if (ret)
  char ixgbe_driver_name[] = "ixgbe";
  static const char ixgbe_driver_string[] =
                              "Intel(R) 10 Gigabit PCI Express Network Driver";
- #define DRV_VERSION "3.2.9-k2"
+ #define MAJ 3
+ #define MIN 3
+ #define BUILD 8
+ #define KFIX 2
+ #define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \
+       __stringify(BUILD) "-k" __stringify(KFIX)
  const char ixgbe_driver_version[] = DRV_VERSION;
  static const char ixgbe_copyright[] =
                                "Copyright (c) 1999-2011 Intel Corporation.";
@@@ -120,6 -124,10 +124,10 @@@ static DEFINE_PCI_DEVICE_TABLE(ixgbe_pc
         board_82599 },
        {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540T),
         board_X540 },
+       {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_SF2),
+        board_82599 },
+       {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_LS),
+        board_82599 },
  
        /* required last entry */
        {0, }
@@@ -185,6 -193,22 +193,22 @@@ static inline void ixgbe_disable_sriov(
        adapter->flags &= ~IXGBE_FLAG_SRIOV_ENABLED;
  }
  
+ static void ixgbe_service_event_schedule(struct ixgbe_adapter *adapter)
+ {
+       if (!test_bit(__IXGBE_DOWN, &adapter->state) &&
+           !test_and_set_bit(__IXGBE_SERVICE_SCHED, &adapter->state))
+               schedule_work(&adapter->service_task);
+ }
+ static void ixgbe_service_event_complete(struct ixgbe_adapter *adapter)
+ {
+       BUG_ON(!test_bit(__IXGBE_SERVICE_SCHED, &adapter->state));
+       /* flush memory to make sure state is correct before next watchog */
+       smp_mb__before_clear_bit();
+       clear_bit(__IXGBE_SERVICE_SCHED, &adapter->state);
+ }
  struct ixgbe_reg_info {
        u32 ofs;
        char *name;
@@@ -811,7 -835,19 +835,19 @@@ static inline bool ixgbe_check_tx_hang(
  #define DESC_NEEDED (TXD_USE_COUNT(IXGBE_MAX_DATA_PER_TXD) /* skb->data */ + \
        MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1) /* for context */
  
- static void ixgbe_tx_timeout(struct net_device *netdev);
+ /**
+  * ixgbe_tx_timeout_reset - initiate reset due to Tx timeout
+  * @adapter: driver private struct
+  **/
+ static void ixgbe_tx_timeout_reset(struct ixgbe_adapter *adapter)
+ {
+       /* Do the reset outside of interrupt context */
+       if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
+               adapter->flags2 |= IXGBE_FLAG2_RESET_REQUESTED;
+               ixgbe_service_event_schedule(adapter);
+       }
+ }
  
  /**
   * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
@@@ -893,7 -929,7 +929,7 @@@ static bool ixgbe_clean_tx_irq(struct i
                        adapter->tx_timeout_count + 1, tx_ring->queue_index);
  
                /* schedule immediate reset if we believe we hung */
-               ixgbe_tx_timeout(adapter->netdev);
+               ixgbe_tx_timeout_reset(adapter);
  
                /* the adapter is about to reset, no point in enabling stuff */
                return true;
@@@ -943,8 -979,6 +979,6 @@@ static void ixgbe_update_rx_dca(struct 
        rxctrl |= IXGBE_DCA_RXCTRL_DESC_DCA_EN;
        rxctrl |= IXGBE_DCA_RXCTRL_HEAD_DCA_EN;
        rxctrl &= ~(IXGBE_DCA_RXCTRL_DESC_RRO_EN);
-       rxctrl &= ~(IXGBE_DCA_RXCTRL_DESC_WRO_EN |
-                   IXGBE_DCA_RXCTRL_DESC_HSRO_EN);
        IXGBE_WRITE_REG(hw, IXGBE_DCA_RXCTRL(reg_idx), rxctrl);
  }
  
@@@ -962,7 -996,6 +996,6 @@@ static void ixgbe_update_tx_dca(struct 
                txctrl &= ~IXGBE_DCA_TXCTRL_CPUID_MASK;
                txctrl |= dca3_get_tag(&adapter->pdev->dev, cpu);
                txctrl |= IXGBE_DCA_TXCTRL_DESC_DCA_EN;
-               txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN;
                IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(reg_idx), txctrl);
                break;
        case ixgbe_mac_82599EB:
                txctrl |= (dca3_get_tag(&adapter->pdev->dev, cpu) <<
                           IXGBE_DCA_TXCTRL_CPUID_SHIFT_82599);
                txctrl |= IXGBE_DCA_TXCTRL_DESC_DCA_EN;
-               txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN;
                IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(reg_idx), txctrl);
                break;
        default:
@@@ -1061,8 -1093,14 +1093,14 @@@ static int __ixgbe_notify_dca(struct de
  
        return 0;
  }
  #endif /* CONFIG_IXGBE_DCA */
+ static inline void ixgbe_rx_hash(union ixgbe_adv_rx_desc *rx_desc,
+                                struct sk_buff *skb)
+ {
+       skb->rxhash = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss);
+ }
  /**
   * ixgbe_receive_skb - Send a completed packet up the stack
   * @adapter: board private structure
@@@ -1454,6 -1492,8 +1492,8 @@@ static void ixgbe_clean_rx_irq(struct i
                }
  
                ixgbe_rx_checksum(adapter, rx_desc, skb);
+               if (adapter->netdev->features & NETIF_F_RXHASH)
+                       ixgbe_rx_hash(rx_desc, skb);
  
                /* probably a little skewed due to removing CRC */
                total_rx_bytes += skb->len;
@@@ -1787,35 -1827,51 +1827,51 @@@ static void ixgbe_set_itr_msix(struct i
  }
  
  /**
-  * ixgbe_check_overtemp_task - worker thread to check over tempurature
-  * @work: pointer to work_struct containing our data
+  * ixgbe_check_overtemp_subtask - check for over tempurature
+  * @adapter: pointer to adapter
   **/
- static void ixgbe_check_overtemp_task(struct work_struct *work)
+ static void ixgbe_check_overtemp_subtask(struct ixgbe_adapter *adapter)
  {
-       struct ixgbe_adapter *adapter = container_of(work,
-                                                    struct ixgbe_adapter,
-                                                    check_overtemp_task);
        struct ixgbe_hw *hw = &adapter->hw;
        u32 eicr = adapter->interrupt_event;
  
-       if (!(adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE))
+       if (test_bit(__IXGBE_DOWN, &adapter->state))
                return;
  
+       if (!(adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) &&
+           !(adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_EVENT))
+               return;
+       adapter->flags2 &= ~IXGBE_FLAG2_TEMP_SENSOR_EVENT;
        switch (hw->device_id) {
-       case IXGBE_DEV_ID_82599_T3_LOM: {
-               u32 autoneg;
-               bool link_up = false;
+       case IXGBE_DEV_ID_82599_T3_LOM:
+               /*
+                * Since the warning interrupt is for both ports
+                * we don't have to check if:
+                *  - This interrupt wasn't for our port.
+                *  - We may have missed the interrupt so always have to
+                *    check if we  got a LSC
+                */
+               if (!(eicr & IXGBE_EICR_GPI_SDP0) &&
+                   !(eicr & IXGBE_EICR_LSC))
+                       return;
+               if (!(eicr & IXGBE_EICR_LSC) && hw->mac.ops.check_link) {
+                       u32 autoneg;
+                       bool link_up = false;
  
-               if (hw->mac.ops.check_link)
                        hw->mac.ops.check_link(hw, &autoneg, &link_up, false);
  
-               if (((eicr & IXGBE_EICR_GPI_SDP0) && (!link_up)) ||
-                   (eicr & IXGBE_EICR_LSC))
-                       /* Check if this is due to overtemp */
-                       if (hw->phy.ops.check_overtemp(hw) == IXGBE_ERR_OVERTEMP)
-                               break;
-               return;
-       }
+                       if (link_up)
+                               return;
+               }
+               /* Check if this is not due to overtemp */
+               if (hw->phy.ops.check_overtemp(hw) != IXGBE_ERR_OVERTEMP)
+                       return;
+               break;
        default:
                if (!(eicr & IXGBE_EICR_GPI_SDP0))
                        return;
               "Network adapter has been stopped because it has over heated. "
               "Restart the computer. If the problem persists, "
               "power off the system and replace the adapter\n");
-       /* write to clear the interrupt */
-       IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP0);
+       adapter->interrupt_event = 0;
  }
  
  static void ixgbe_check_fan_failure(struct ixgbe_adapter *adapter, u32 eicr)
@@@ -1848,15 -1904,19 +1904,19 @@@ static void ixgbe_check_sfp_event(struc
        if (eicr & IXGBE_EICR_GPI_SDP2) {
                /* Clear the interrupt */
                IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2);
-               if (!test_bit(__IXGBE_DOWN, &adapter->state))
-                       schedule_work(&adapter->sfp_config_module_task);
+               if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
+                       adapter->flags2 |= IXGBE_FLAG2_SFP_NEEDS_RESET;
+                       ixgbe_service_event_schedule(adapter);
+               }
        }
  
        if (eicr & IXGBE_EICR_GPI_SDP1) {
                /* Clear the interrupt */
                IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1);
-               if (!test_bit(__IXGBE_DOWN, &adapter->state))
-                       schedule_work(&adapter->multispeed_fiber_task);
+               if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
+                       adapter->flags |= IXGBE_FLAG_NEED_LINK_CONFIG;
+                       ixgbe_service_event_schedule(adapter);
+               }
        }
  }
  
@@@ -1870,7 -1930,7 +1930,7 @@@ static void ixgbe_check_lsc(struct ixgb
        if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
                IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_LSC);
                IXGBE_WRITE_FLUSH(hw);
-               schedule_work(&adapter->watchdog_task);
+               ixgbe_service_event_schedule(adapter);
        }
  }
  
@@@ -1898,26 -1958,32 +1958,32 @@@ static irqreturn_t ixgbe_msix_lsc(int i
  
        switch (hw->mac.type) {
        case ixgbe_mac_82599EB:
-               ixgbe_check_sfp_event(adapter, eicr);
-               if ((adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) &&
-                   ((eicr & IXGBE_EICR_GPI_SDP0) || (eicr & IXGBE_EICR_LSC))) {
-                       adapter->interrupt_event = eicr;
-                       schedule_work(&adapter->check_overtemp_task);
-               }
-               /* now fallthrough to handle Flow Director */
        case ixgbe_mac_X540:
                /* Handle Flow Director Full threshold interrupt */
                if (eicr & IXGBE_EICR_FLOW_DIR) {
+                       int reinit_count = 0;
                        int i;
-                       IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_FLOW_DIR);
-                       /* Disable transmits before FDIR Re-initialization */
-                       netif_tx_stop_all_queues(netdev);
                        for (i = 0; i < adapter->num_tx_queues; i++) {
-                               struct ixgbe_ring *tx_ring =
-                                                           adapter->tx_ring[i];
+                               struct ixgbe_ring *ring = adapter->tx_ring[i];
                                if (test_and_clear_bit(__IXGBE_TX_FDIR_INIT_DONE,
-                                                      &tx_ring->state))
-                                       schedule_work(&adapter->fdir_reinit_task);
+                                                      &ring->state))
+                                       reinit_count++;
+                       }
+                       if (reinit_count) {
+                               /* no more flow director interrupts until after init */
+                               IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_FLOW_DIR);
+                               eicr &= ~IXGBE_EICR_FLOW_DIR;
+                               adapter->flags2 |= IXGBE_FLAG2_FDIR_REQUIRES_REINIT;
+                               ixgbe_service_event_schedule(adapter);
+                       }
+               }
+               ixgbe_check_sfp_event(adapter, eicr);
+               if ((adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) &&
+                   ((eicr & IXGBE_EICR_GPI_SDP0) || (eicr & IXGBE_EICR_LSC))) {
+                       if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
+                               adapter->interrupt_event = eicr;
+                               adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_EVENT;
+                               ixgbe_service_event_schedule(adapter);
                        }
                }
                break;
  
        ixgbe_check_fan_failure(adapter, eicr);
  
+       /* re-enable the original interrupt state, no lsc, no queues */
        if (!test_bit(__IXGBE_DOWN, &adapter->state))
-               IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_OTHER);
+               IXGBE_WRITE_REG(hw, IXGBE_EIMS, eicr &
+                               ~(IXGBE_EIMS_LSC | IXGBE_EIMS_RTX_QUEUE));
  
        return IRQ_HANDLED;
  }
@@@ -2513,8 -2581,11 +2581,11 @@@ static irqreturn_t ixgbe_intr(int irq, 
                ixgbe_check_sfp_event(adapter, eicr);
                if ((adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) &&
                    ((eicr & IXGBE_EICR_GPI_SDP0) || (eicr & IXGBE_EICR_LSC))) {
-                       adapter->interrupt_event = eicr;
-                       schedule_work(&adapter->check_overtemp_task);
+                       if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
+                               adapter->interrupt_event = eicr;
+                               adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_EVENT;
+                               ixgbe_service_event_schedule(adapter);
+                       }
                }
                break;
        default:
@@@ -2731,7 -2802,7 +2802,7 @@@ void ixgbe_configure_tx_ring(struct ixg
  
        /* poll to verify queue is enabled */
        do {
-               msleep(1);
+               usleep_range(1000, 2000);
                txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(reg_idx));
        } while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
        if (!wait_loop)
@@@ -3023,7 -3094,7 +3094,7 @@@ static void ixgbe_rx_desc_queue_enable(
                return;
  
        do {
-               msleep(1);
+               usleep_range(1000, 2000);
                rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(reg_idx));
        } while (--wait_loop && !(rxdctl & IXGBE_RXDCTL_ENABLE));
  
@@@ -3178,7 -3249,9 +3249,9 @@@ static void ixgbe_configure_virtualizat
        /* enable Tx loopback for VF/PF communication */
        IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, IXGBE_PFDTXGSWC_VT_LBEN);
        /* Enable MAC Anti-Spoofing */
-       hw->mac.ops.set_mac_anti_spoofing(hw, (adapter->num_vfs != 0),
+       hw->mac.ops.set_mac_anti_spoofing(hw,
+                                         (adapter->antispoofing_enabled =
+                                          (adapter->num_vfs != 0)),
                                          adapter->num_vfs);
  }
  
@@@ -3487,7 -3560,7 +3560,7 @@@ static int ixgbe_write_uc_addr_list(str
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        struct ixgbe_hw *hw = &adapter->hw;
        unsigned int vfn = adapter->num_vfs;
-       unsigned int rar_entries = hw->mac.num_rar_entries - (vfn + 1);
+       unsigned int rar_entries = IXGBE_MAX_PF_MACVLANS;
        int count = 0;
  
        /* return ENOMEM indicating insufficient memory for addresses */
@@@ -3760,31 -3833,16 +3833,16 @@@ static inline bool ixgbe_is_sfp(struct 
   **/
  static void ixgbe_sfp_link_config(struct ixgbe_adapter *adapter)
  {
-       struct ixgbe_hw *hw = &adapter->hw;
+       /*
+        * We are assuming the worst case scenerio here, and that
+        * is that an SFP was inserted/removed after the reset
+        * but before SFP detection was enabled.  As such the best
+        * solution is to just start searching as soon as we start
+        */
+       if (adapter->hw.mac.type == ixgbe_mac_82598EB)
+               adapter->flags2 |= IXGBE_FLAG2_SEARCH_FOR_SFP;
  
-               if (hw->phy.multispeed_fiber) {
-                       /*
-                        * In multispeed fiber setups, the device may not have
-                        * had a physical connection when the driver loaded.
-                        * If that's the case, the initial link configuration
-                        * couldn't get the MAC into 10G or 1G mode, so we'll
-                        * never have a link status change interrupt fire.
-                        * We need to try and force an autonegotiation
-                        * session, then bring up link.
-                        */
-                       if (hw->mac.ops.setup_sfp)
-                               hw->mac.ops.setup_sfp(hw);
-                       if (!(adapter->flags & IXGBE_FLAG_IN_SFP_LINK_TASK))
-                               schedule_work(&adapter->multispeed_fiber_task);
-               } else {
-                       /*
-                        * Direct Attach Cu and non-multispeed fiber modules
-                        * still need to be configured properly prior to
-                        * attempting link.
-                        */
-                       if (!(adapter->flags & IXGBE_FLAG_IN_SFP_MOD_TASK))
-                               schedule_work(&adapter->sfp_config_module_task);
-               }
+       adapter->flags2 |= IXGBE_FLAG2_SFP_NEEDS_RESET;
  }
  
  /**
@@@ -3860,9 -3918,10 +3918,10 @@@ static void ixgbe_setup_gpie(struct ixg
        if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE)
                gpie |= IXGBE_SDP1_GPIEN;
  
-       if (hw->mac.type == ixgbe_mac_82599EB)
+       if (hw->mac.type == ixgbe_mac_82599EB) {
                gpie |= IXGBE_SDP1_GPIEN;
                gpie |= IXGBE_SDP2_GPIEN;
+       }
  
        IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
  }
@@@ -3913,17 -3972,6 +3972,6 @@@ static int ixgbe_up_complete(struct ixg
                        e_crit(drv, "Fan has stopped, replace the adapter\n");
        }
  
-       /*
-        * For hot-pluggable SFP+ devices, a new SFP+ module may have
-        * arrived before interrupts were enabled but after probe.  Such
-        * devices wouldn't have their type identified yet. We need to
-        * kick off the SFP+ module setup first, then try to bring up link.
-        * If we're not hot-pluggable SFP+, we just need to configure link
-        * and bring it up.
-        */
-       if (hw->phy.type == ixgbe_phy_none)
-               schedule_work(&adapter->sfp_config_module_task);
        /* enable transmits */
        netif_tx_start_all_queues(adapter->netdev);
  
         * link up interrupt but shouldn't be a problem */
        adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
        adapter->link_check_timeout = jiffies;
-       mod_timer(&adapter->watchdog_timer, jiffies);
+       mod_timer(&adapter->service_timer, jiffies);
  
        /* Set PF Reset Done bit so PF/VF Mail Ops can work */
        ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
  void ixgbe_reinit_locked(struct ixgbe_adapter *adapter)
  {
        WARN_ON(in_interrupt());
+       /* put off any impending NetWatchDogTimeout */
+       adapter->netdev->trans_start = jiffies;
        while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state))
-               msleep(1);
+               usleep_range(1000, 2000);
        ixgbe_down(adapter);
        /*
         * If SR-IOV enabled then wait a bit before bringing the adapter
@@@ -3972,10 -4023,20 +4023,20 @@@ void ixgbe_reset(struct ixgbe_adapter *
        struct ixgbe_hw *hw = &adapter->hw;
        int err;
  
+       /* lock SFP init bit to prevent race conditions with the watchdog */
+       while (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
+               usleep_range(1000, 2000);
+       /* clear all SFP and link config related flags while holding SFP_INIT */
+       adapter->flags2 &= ~(IXGBE_FLAG2_SEARCH_FOR_SFP |
+                            IXGBE_FLAG2_SFP_NEEDS_RESET);
+       adapter->flags &= ~IXGBE_FLAG_NEED_LINK_CONFIG;
        err = hw->mac.ops.init_hw(hw);
        switch (err) {
        case 0:
        case IXGBE_ERR_SFP_NOT_PRESENT:
+       case IXGBE_ERR_SFP_NOT_SUPPORTED:
                break;
        case IXGBE_ERR_MASTER_REQUESTS_PENDING:
                e_dev_err("master disable timed out\n");
                e_dev_err("Hardware Error: %d\n", err);
        }
  
+       clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state);
        /* reprogram the RAR[0] in case user changed it. */
        hw->mac.ops.set_rar(hw, 0, hw->mac.addr, adapter->num_vfs,
                            IXGBE_RAH_AV);
@@@ -4121,26 -4184,12 +4184,12 @@@ void ixgbe_down(struct ixgbe_adapter *a
        struct net_device *netdev = adapter->netdev;
        struct ixgbe_hw *hw = &adapter->hw;
        u32 rxctrl;
-       u32 txdctl;
        int i;
        int num_q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
  
        /* signal that we are down to the interrupt handler */
        set_bit(__IXGBE_DOWN, &adapter->state);
  
-       /* disable receive for all VFs and wait one second */
-       if (adapter->num_vfs) {
-               /* ping all the active vfs to let them know we are going down */
-               ixgbe_ping_all_vfs(adapter);
-               /* Disable all VFTE/VFRE TX/RX */
-               ixgbe_disable_tx_rx(adapter);
-               /* Mark all the VFs as inactive */
-               for (i = 0 ; i < adapter->num_vfs; i++)
-                       adapter->vfinfo[i].clear_to_send = 0;
-       }
        /* disable receives */
        rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
        IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl & ~IXGBE_RXCTRL_RXEN);
                /* this call also flushes the previous write */
                ixgbe_disable_rx_queue(adapter, adapter->rx_ring[i]);
  
-       msleep(10);
+       usleep_range(10000, 20000);
  
        netif_tx_stop_all_queues(netdev);
  
-       clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
-       del_timer_sync(&adapter->sfp_timer);
-       del_timer_sync(&adapter->watchdog_timer);
-       cancel_work_sync(&adapter->watchdog_task);
+       /* call carrier off first to avoid false dev_watchdog timeouts */
        netif_carrier_off(netdev);
        netif_tx_disable(netdev);
  
  
        ixgbe_napi_disable_all(adapter);
  
+       adapter->flags2 &= ~(IXGBE_FLAG2_FDIR_REQUIRES_REINIT |
+                            IXGBE_FLAG2_RESET_REQUESTED);
+       adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE;
+       del_timer_sync(&adapter->service_timer);
+       /* disable receive for all VFs and wait one second */
+       if (adapter->num_vfs) {
+               /* ping all the active vfs to let them know we are going down */
+               ixgbe_ping_all_vfs(adapter);
+               /* Disable all VFTE/VFRE TX/RX */
+               ixgbe_disable_tx_rx(adapter);
+               /* Mark all the VFs as inactive */
+               for (i = 0 ; i < adapter->num_vfs; i++)
+                       adapter->vfinfo[i].clear_to_send = 0;
+       }
        /* Cleanup the affinity_hint CPU mask memory and callback */
        for (i = 0; i < num_q_vectors; i++) {
                struct ixgbe_q_vector *q_vector = adapter->q_vector[i];
                free_cpumask_var(q_vector->affinity_mask);
        }
  
-       if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE ||
-           adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)
-               cancel_work_sync(&adapter->fdir_reinit_task);
-       if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE)
-               cancel_work_sync(&adapter->check_overtemp_task);
        /* disable transmits in the hardware now that interrupts are off */
        for (i = 0; i < adapter->num_tx_queues; i++) {
                u8 reg_idx = adapter->tx_ring[i]->reg_idx;
-               txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(reg_idx));
-               IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx),
-                               (txdctl & ~IXGBE_TXDCTL_ENABLE));
+               IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), IXGBE_TXDCTL_SWFLSH);
        }
-       /* Disable the Tx DMA engine on 82599 */
+       /* Disable the Tx DMA engine on 82599 and X540 */
        switch (hw->mac.type) {
        case ixgbe_mac_82599EB:
        case ixgbe_mac_X540:
                break;
        }
  
-       /* clear n-tuple filters that are cached */
-       ethtool_ntuple_flush(netdev);
        if (!pci_channel_offline(adapter->pdev))
                ixgbe_reset(adapter);
  
@@@ -4267,25 -4320,8 +4320,8 @@@ static void ixgbe_tx_timeout(struct net
  {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
  
-       adapter->tx_timeout_count++;
        /* Do the reset outside of interrupt context */
-       schedule_work(&adapter->reset_task);
- }
- static void ixgbe_reset_task(struct work_struct *work)
- {
-       struct ixgbe_adapter *adapter;
-       adapter = container_of(work, struct ixgbe_adapter, reset_task);
-       /* If we're already down or resetting, just bail */
-       if (test_bit(__IXGBE_DOWN, &adapter->state) ||
-           test_bit(__IXGBE_RESETTING, &adapter->state))
-               return;
-       ixgbe_dump(adapter);
-       netdev_err(adapter->netdev, "Reset adapter\n");
-       ixgbe_reinit_locked(adapter);
+       ixgbe_tx_timeout_reset(adapter);
  }
  
  /**
@@@ -4567,8 -4603,8 +4603,8 @@@ static inline bool ixgbe_cache_ring_rss
  #ifdef CONFIG_IXGBE_DCB
  
  /* ixgbe_get_first_reg_idx - Return first register index associated with ring */
- void ixgbe_get_first_reg_idx(struct ixgbe_adapter *adapter, u8 tc,
-                            unsigned int *tx, unsigned int *rx)
static void ixgbe_get_first_reg_idx(struct ixgbe_adapter *adapter, u8 tc,
+                                   unsigned int *tx, unsigned int *rx)
  {
        struct net_device *dev = adapter->netdev;
        struct ixgbe_hw *hw = &adapter->hw;
@@@ -5100,6 -5136,11 +5136,6 @@@ err_set_interrupt
        return err;
  }
  
 -static void ring_free_rcu(struct rcu_head *head)
 -{
 -      kfree(container_of(head, struct ixgbe_ring, rcu));
 -}
 -
  /**
   * ixgbe_clear_interrupt_scheme - Clear the current interrupt scheme settings
   * @adapter: board private structure to clear interrupt scheme on
@@@ -5121,7 -5162,7 +5157,7 @@@ void ixgbe_clear_interrupt_scheme(struc
                /* ixgbe_get_stats64() might access this ring, we must wait
                 * a grace period before freeing it.
                 */
 -              call_rcu(&ring->rcu, ring_free_rcu);
 +              kfree_rcu(ring, rcu);
                adapter->rx_ring[i] = NULL;
        }
  
        ixgbe_reset_interrupt_capability(adapter);
  }
  
- /**
-  * ixgbe_sfp_timer - worker thread to find a missing module
-  * @data: pointer to our adapter struct
-  **/
- static void ixgbe_sfp_timer(unsigned long data)
- {
-       struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data;
-       /*
-        * Do the sfp_timer outside of interrupt context due to the
-        * delays that sfp+ detection requires
-        */
-       schedule_work(&adapter->sfp_task);
- }
- /**
-  * ixgbe_sfp_task - worker thread to find a missing module
-  * @work: pointer to work_struct containing our data
-  **/
- static void ixgbe_sfp_task(struct work_struct *work)
- {
-       struct ixgbe_adapter *adapter = container_of(work,
-                                                    struct ixgbe_adapter,
-                                                    sfp_task);
-       struct ixgbe_hw *hw = &adapter->hw;
-       if ((hw->phy.type == ixgbe_phy_nl) &&
-           (hw->phy.sfp_type == ixgbe_sfp_type_not_present)) {
-               s32 ret = hw->phy.ops.identify_sfp(hw);
-               if (ret == IXGBE_ERR_SFP_NOT_PRESENT)
-                       goto reschedule;
-               ret = hw->phy.ops.reset(hw);
-               if (ret == IXGBE_ERR_SFP_NOT_SUPPORTED) {
-                       e_dev_err("failed to initialize because an unsupported "
-                                 "SFP+ module type was detected.\n");
-                       e_dev_err("Reload the driver after installing a "
-                                 "supported module.\n");
-                       unregister_netdev(adapter->netdev);
-               } else {
-                       e_info(probe, "detected SFP+: %d\n", hw->phy.sfp_type);
-               }
-               /* don't need this routine any more */
-               clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
-       }
-       return;
- reschedule:
-       if (test_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state))
-               mod_timer(&adapter->sfp_timer,
-                         round_jiffies(jiffies + (2 * HZ)));
- }
  /**
   * ixgbe_sw_init - Initialize general software structures (struct ixgbe_adapter)
   * @adapter: board private structure to initialize
@@@ -5899,8 -5889,13 +5884,13 @@@ void ixgbe_update_stats(struct ixgbe_ad
                hwstats->gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH);
                hwstats->tor += IXGBE_READ_REG(hw, IXGBE_TORH);
                break;
-       case ixgbe_mac_82599EB:
        case ixgbe_mac_X540:
+               /* OS2BMC stats are X540 only*/
+               hwstats->o2bgptc += IXGBE_READ_REG(hw, IXGBE_O2BGPTC);
+               hwstats->o2bspc += IXGBE_READ_REG(hw, IXGBE_O2BSPC);
+               hwstats->b2ospc += IXGBE_READ_REG(hw, IXGBE_B2OSPC);
+               hwstats->b2ogprc += IXGBE_READ_REG(hw, IXGBE_B2OGPRC);
+       case ixgbe_mac_82599EB:
                hwstats->gorc += IXGBE_READ_REG(hw, IXGBE_GORCL);
                IXGBE_READ_REG(hw, IXGBE_GORCH); /* to clear */
                hwstats->gotc += IXGBE_READ_REG(hw, IXGBE_GOTCL);
  }
  
  /**
-  * ixgbe_watchdog - Timer Call-back
-  * @data: pointer to adapter cast into an unsigned long
+  * ixgbe_fdir_reinit_subtask - worker thread to reinit FDIR filter table
+  * @adapter - pointer to the device adapter structure
   **/
- static void ixgbe_watchdog(unsigned long data)
+ static void ixgbe_fdir_reinit_subtask(struct ixgbe_adapter *adapter)
  {
-       struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data;
        struct ixgbe_hw *hw = &adapter->hw;
-       u64 eics = 0;
        int i;
  
-       /*
-        *  Do the watchdog outside of interrupt context due to the lovely
-        * delays that some of the newer hardware requires
-        */
+       if (!(adapter->flags2 & IXGBE_FLAG2_FDIR_REQUIRES_REINIT))
+               return;
+       adapter->flags2 &= ~IXGBE_FLAG2_FDIR_REQUIRES_REINIT;
  
+       /* if interface is down do nothing */
        if (test_bit(__IXGBE_DOWN, &adapter->state))
-               goto watchdog_short_circuit;
+               return;
+       /* do nothing if we are not using signature filters */
+       if (!(adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE))
+               return;
+       adapter->fdir_overflow++;
+       if (ixgbe_reinit_fdir_tables_82599(hw) == 0) {
+               for (i = 0; i < adapter->num_tx_queues; i++)
+                       set_bit(__IXGBE_TX_FDIR_INIT_DONE,
+                               &(adapter->tx_ring[i]->state));
+               /* re-enable flow director interrupts */
+               IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_FLOW_DIR);
+       } else {
+               e_err(probe, "failed to finish FDIR re-initialization, "
+                     "ignored adding FDIR ATR filters\n");
+       }
+ }
+ /**
+  * ixgbe_check_hang_subtask - check for hung queues and dropped interrupts
+  * @adapter - pointer to the device adapter structure
+  *
+  * This function serves two purposes.  First it strobes the interrupt lines
+  * in order to make certain interrupts are occuring.  Secondly it sets the
+  * bits needed to check for TX hangs.  As a result we should immediately
+  * determine if a hang has occured.
+  */
+ static void ixgbe_check_hang_subtask(struct ixgbe_adapter *adapter)
+ {
+       struct ixgbe_hw *hw = &adapter->hw;
+       u64 eics = 0;
+       int i;
+       /* If we're down or resetting, just bail */
+       if (test_bit(__IXGBE_DOWN, &adapter->state) ||
+           test_bit(__IXGBE_RESETTING, &adapter->state))
+               return;
+       /* Force detection of hung controller */
+       if (netif_carrier_ok(adapter->netdev)) {
+               for (i = 0; i < adapter->num_tx_queues; i++)
+                       set_check_for_tx_hang(adapter->tx_ring[i]);
+       }
  
        if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED)) {
                /*
                 */
                IXGBE_WRITE_REG(hw, IXGBE_EICS,
                        (IXGBE_EICS_TCP_TIMER | IXGBE_EICS_OTHER));
-               goto watchdog_reschedule;
-       }
-       /* get one bit for every active tx/rx interrupt vector */
-       for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) {
-               struct ixgbe_q_vector *qv = adapter->q_vector[i];
-               if (qv->rxr_count || qv->txr_count)
-                       eics |= ((u64)1 << i);
+       } else {
+               /* get one bit for every active tx/rx interrupt vector */
+               for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) {
+                       struct ixgbe_q_vector *qv = adapter->q_vector[i];
+                       if (qv->rxr_count || qv->txr_count)
+                               eics |= ((u64)1 << i);
+               }
        }
  
-       /* Cause software interrupt to ensure rx rings are cleaned */
+       /* Cause software interrupt to ensure rings are cleaned */
        ixgbe_irq_rearm_queues(adapter, eics);
  
- watchdog_reschedule:
-       /* Reset the timer */
-       mod_timer(&adapter->watchdog_timer, round_jiffies(jiffies + 2 * HZ));
- watchdog_short_circuit:
-       schedule_work(&adapter->watchdog_task);
  }
  
  /**
-  * ixgbe_multispeed_fiber_task - worker thread to configure multispeed fiber
-  * @work: pointer to work_struct containing our data
+  * ixgbe_watchdog_update_link - update the link status
+  * @adapter - pointer to the device adapter structure
+  * @link_speed - pointer to a u32 to store the link_speed
   **/
- static void ixgbe_multispeed_fiber_task(struct work_struct *work)
+ static void ixgbe_watchdog_update_link(struct ixgbe_adapter *adapter)
  {
-       struct ixgbe_adapter *adapter = container_of(work,
-                                                    struct ixgbe_adapter,
-                                                    multispeed_fiber_task);
        struct ixgbe_hw *hw = &adapter->hw;
-       u32 autoneg;
-       bool negotiation;
+       u32 link_speed = adapter->link_speed;
+       bool link_up = adapter->link_up;
+       int i;
  
-       adapter->flags |= IXGBE_FLAG_IN_SFP_LINK_TASK;
-       autoneg = hw->phy.autoneg_advertised;
-       if ((!autoneg) && (hw->mac.ops.get_link_capabilities))
-               hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiation);
-       hw->mac.autotry_restart = false;
-       if (hw->mac.ops.setup_link)
-               hw->mac.ops.setup_link(hw, autoneg, negotiation, true);
-       adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
-       adapter->flags &= ~IXGBE_FLAG_IN_SFP_LINK_TASK;
+       if (!(adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE))
+               return;
+       if (hw->mac.ops.check_link) {
+               hw->mac.ops.check_link(hw, &link_speed, &link_up, false);
+       } else {
+               /* always assume link is up, if no check link function */
+               link_speed = IXGBE_LINK_SPEED_10GB_FULL;
+               link_up = true;
+       }
+       if (link_up) {
+               if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
+                       for (i = 0; i < MAX_TRAFFIC_CLASS; i++)
+                               hw->mac.ops.fc_enable(hw, i);
+               } else {
+                       hw->mac.ops.fc_enable(hw, 0);
+               }
+       }
+       if (link_up ||
+           time_after(jiffies, (adapter->link_check_timeout +
+                                IXGBE_TRY_LINK_TIMEOUT))) {
+               adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE;
+               IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMC_LSC);
+               IXGBE_WRITE_FLUSH(hw);
+       }
+       adapter->link_up = link_up;
+       adapter->link_speed = link_speed;
  }
  
  /**
-  * ixgbe_sfp_config_module_task - worker thread to configure a new SFP+ module
-  * @work: pointer to work_struct containing our data
+  * ixgbe_watchdog_link_is_up - update netif_carrier status and
+  *                             print link up message
+  * @adapter - pointer to the device adapter structure
   **/
- static void ixgbe_sfp_config_module_task(struct work_struct *work)
+ static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *adapter)
  {
-       struct ixgbe_adapter *adapter = container_of(work,
-                                                    struct ixgbe_adapter,
-                                                    sfp_config_module_task);
+       struct net_device *netdev = adapter->netdev;
        struct ixgbe_hw *hw = &adapter->hw;
-       u32 err;
+       u32 link_speed = adapter->link_speed;
+       bool flow_rx, flow_tx;
  
-       adapter->flags |= IXGBE_FLAG_IN_SFP_MOD_TASK;
+       /* only continue if link was previously down */
+       if (netif_carrier_ok(netdev))
+               return;
  
-       /* Time for electrical oscillations to settle down */
-       msleep(100);
-       err = hw->phy.ops.identify_sfp(hw);
+       adapter->flags2 &= ~IXGBE_FLAG2_SEARCH_FOR_SFP;
  
-       if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
-               e_dev_err("failed to initialize because an unsupported SFP+ "
-                         "module type was detected.\n");
-               e_dev_err("Reload the driver after installing a supported "
-                         "module.\n");
-               unregister_netdev(adapter->netdev);
-               return;
+       switch (hw->mac.type) {
+       case ixgbe_mac_82598EB: {
+               u32 frctl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
+               u32 rmcs = IXGBE_READ_REG(hw, IXGBE_RMCS);
+               flow_rx = !!(frctl & IXGBE_FCTRL_RFCE);
+               flow_tx = !!(rmcs & IXGBE_RMCS_TFCE_802_3X);
+       }
+               break;
+       case ixgbe_mac_X540:
+       case ixgbe_mac_82599EB: {
+               u32 mflcn = IXGBE_READ_REG(hw, IXGBE_MFLCN);
+               u32 fccfg = IXGBE_READ_REG(hw, IXGBE_FCCFG);
+               flow_rx = !!(mflcn & IXGBE_MFLCN_RFCE);
+               flow_tx = !!(fccfg & IXGBE_FCCFG_TFCE_802_3X);
+       }
+               break;
+       default:
+               flow_tx = false;
+               flow_rx = false;
+               break;
        }
-       if (hw->mac.ops.setup_sfp)
-               hw->mac.ops.setup_sfp(hw);
+       e_info(drv, "NIC Link is Up %s, Flow Control: %s\n",
+              (link_speed == IXGBE_LINK_SPEED_10GB_FULL ?
+              "10 Gbps" :
+              (link_speed == IXGBE_LINK_SPEED_1GB_FULL ?
+              "1 Gbps" :
+              (link_speed == IXGBE_LINK_SPEED_100_FULL ?
+              "100 Mbps" :
+              "unknown speed"))),
+              ((flow_rx && flow_tx) ? "RX/TX" :
+              (flow_rx ? "RX" :
+              (flow_tx ? "TX" : "None"))));
  
-       if (!(adapter->flags & IXGBE_FLAG_IN_SFP_LINK_TASK))
-               /* This will also work for DA Twinax connections */
-               schedule_work(&adapter->multispeed_fiber_task);
-       adapter->flags &= ~IXGBE_FLAG_IN_SFP_MOD_TASK;
+       netif_carrier_on(netdev);
+ #ifdef HAVE_IPLINK_VF_CONFIG
+       ixgbe_check_vf_rate_limit(adapter);
+ #endif /* HAVE_IPLINK_VF_CONFIG */
  }
  
  /**
-  * ixgbe_fdir_reinit_task - worker thread to reinit FDIR filter table
-  * @work: pointer to work_struct containing our data
+  * ixgbe_watchdog_link_is_down - update netif_carrier status and
+  *                               print link down message
+  * @adapter - pointer to the adapter structure
   **/
- static void ixgbe_fdir_reinit_task(struct work_struct *work)
+ static void ixgbe_watchdog_link_is_down(struct ixgbe_adapter* adapter)
  {
-       struct ixgbe_adapter *adapter = container_of(work,
-                                                    struct ixgbe_adapter,
-                                                    fdir_reinit_task);
+       struct net_device *netdev = adapter->netdev;
        struct ixgbe_hw *hw = &adapter->hw;
+       adapter->link_up = false;
+       adapter->link_speed = 0;
+       /* only continue if link was up previously */
+       if (!netif_carrier_ok(netdev))
+               return;
+       /* poll for SFP+ cable when link is down */
+       if (ixgbe_is_sfp(hw) && hw->mac.type == ixgbe_mac_82598EB)
+               adapter->flags2 |= IXGBE_FLAG2_SEARCH_FOR_SFP;
+       e_info(drv, "NIC Link is Down\n");
+       netif_carrier_off(netdev);
+ }
+ /**
+  * ixgbe_watchdog_flush_tx - flush queues on link down
+  * @adapter - pointer to the device adapter structure
+  **/
+ static void ixgbe_watchdog_flush_tx(struct ixgbe_adapter *adapter)
+ {
        int i;
+       int some_tx_pending = 0;
  
-       if (ixgbe_reinit_fdir_tables_82599(hw) == 0) {
-               for (i = 0; i < adapter->num_tx_queues; i++)
-                       set_bit(__IXGBE_TX_FDIR_INIT_DONE,
-                               &(adapter->tx_ring[i]->state));
-       } else {
-               e_err(probe, "failed to finish FDIR re-initialization, "
-                     "ignored adding FDIR ATR filters\n");
+       if (!netif_carrier_ok(adapter->netdev)) {
+               for (i = 0; i < adapter->num_tx_queues; i++) {
+                       struct ixgbe_ring *tx_ring = adapter->tx_ring[i];
+                       if (tx_ring->next_to_use != tx_ring->next_to_clean) {
+                               some_tx_pending = 1;
+                               break;
+                       }
+               }
+               if (some_tx_pending) {
+                       /* We've lost link, so the controller stops DMA,
+                        * but we've got queued Tx work that's never going
+                        * to get done, so reset controller to flush Tx.
+                        * (Do the reset outside of interrupt context).
+                        */
+                       adapter->flags2 |= IXGBE_FLAG2_RESET_REQUESTED;
+               }
        }
-       /* Done FDIR Re-initialization, enable transmits */
-       netif_tx_start_all_queues(adapter->netdev);
  }
  
  static void ixgbe_spoof_check(struct ixgbe_adapter *adapter)
        e_warn(drv, "%d Spoofed packets detected\n", ssvpc);
  }
  
- static DEFINE_MUTEX(ixgbe_watchdog_lock);
+ /**
+  * ixgbe_watchdog_subtask - check and bring link up
+  * @adapter - pointer to the device adapter structure
+  **/
+ static void ixgbe_watchdog_subtask(struct ixgbe_adapter *adapter)
+ {
+       /* if interface is down do nothing */
+       if (test_bit(__IXGBE_DOWN, &adapter->state))
+               return;
+       ixgbe_watchdog_update_link(adapter);
+       if (adapter->link_up)
+               ixgbe_watchdog_link_is_up(adapter);
+       else
+               ixgbe_watchdog_link_is_down(adapter);
+       ixgbe_spoof_check(adapter);
+       ixgbe_update_stats(adapter);
+       ixgbe_watchdog_flush_tx(adapter);
+ }
  
  /**
-  * ixgbe_watchdog_task - worker thread to bring link up
-  * @work: pointer to work_struct containing our data
+  * ixgbe_sfp_detection_subtask - poll for SFP+ cable
+  * @adapter - the ixgbe adapter structure
   **/
- static void ixgbe_watchdog_task(struct work_struct *work)
+ static void ixgbe_sfp_detection_subtask(struct ixgbe_adapter *adapter)
  {
-       struct ixgbe_adapter *adapter = container_of(work,
-                                                    struct ixgbe_adapter,
-                                                    watchdog_task);
-       struct net_device *netdev = adapter->netdev;
        struct ixgbe_hw *hw = &adapter->hw;
-       u32 link_speed;
-       bool link_up;
-       int i;
-       struct ixgbe_ring *tx_ring;
-       int some_tx_pending = 0;
+       s32 err;
  
-       mutex_lock(&ixgbe_watchdog_lock);
+       /* not searching for SFP so there is nothing to do here */
+       if (!(adapter->flags2 & IXGBE_FLAG2_SEARCH_FOR_SFP) &&
+           !(adapter->flags2 & IXGBE_FLAG2_SFP_NEEDS_RESET))
+               return;
  
-       link_up = adapter->link_up;
-       link_speed = adapter->link_speed;
+       /* someone else is in init, wait until next service event */
+       if (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
+               return;
  
-       if (adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE) {
-               hw->mac.ops.check_link(hw, &link_speed, &link_up, false);
-               if (link_up) {
- #ifdef CONFIG_DCB
-                       if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
-                               for (i = 0; i < MAX_TRAFFIC_CLASS; i++)
-                                       hw->mac.ops.fc_enable(hw, i);
-                       } else {
-                               hw->mac.ops.fc_enable(hw, 0);
-                       }
- #else
-                       hw->mac.ops.fc_enable(hw, 0);
- #endif
-               }
+       err = hw->phy.ops.identify_sfp(hw);
+       if (err == IXGBE_ERR_SFP_NOT_SUPPORTED)
+               goto sfp_out;
  
-               if (link_up ||
-                   time_after(jiffies, (adapter->link_check_timeout +
-                                        IXGBE_TRY_LINK_TIMEOUT))) {
-                       adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE;
-                       IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMC_LSC);
-               }
-               adapter->link_up = link_up;
-               adapter->link_speed = link_speed;
+       if (err == IXGBE_ERR_SFP_NOT_PRESENT) {
+               /* If no cable is present, then we need to reset
+                * the next time we find a good cable. */
+               adapter->flags2 |= IXGBE_FLAG2_SFP_NEEDS_RESET;
        }
  
-       if (link_up) {
-               if (!netif_carrier_ok(netdev)) {
-                       bool flow_rx, flow_tx;
-                       switch (hw->mac.type) {
-                       case ixgbe_mac_82598EB: {
-                               u32 frctl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
-                               u32 rmcs = IXGBE_READ_REG(hw, IXGBE_RMCS);
-                               flow_rx = !!(frctl & IXGBE_FCTRL_RFCE);
-                               flow_tx = !!(rmcs & IXGBE_RMCS_TFCE_802_3X);
-                       }
-                               break;
-                       case ixgbe_mac_82599EB:
-                       case ixgbe_mac_X540: {
-                               u32 mflcn = IXGBE_READ_REG(hw, IXGBE_MFLCN);
-                               u32 fccfg = IXGBE_READ_REG(hw, IXGBE_FCCFG);
-                               flow_rx = !!(mflcn & IXGBE_MFLCN_RFCE);
-                               flow_tx = !!(fccfg & IXGBE_FCCFG_TFCE_802_3X);
-                       }
-                               break;
-                       default:
-                               flow_tx = false;
-                               flow_rx = false;
-                               break;
-                       }
+       /* exit on error */
+       if (err)
+               goto sfp_out;
  
-                       e_info(drv, "NIC Link is Up %s, Flow Control: %s\n",
-                              (link_speed == IXGBE_LINK_SPEED_10GB_FULL ?
-                              "10 Gbps" :
-                              (link_speed == IXGBE_LINK_SPEED_1GB_FULL ?
-                              "1 Gbps" :
-                              (link_speed == IXGBE_LINK_SPEED_100_FULL ?
-                              "100 Mbps" :
-                              "unknown speed"))),
-                              ((flow_rx && flow_tx) ? "RX/TX" :
-                              (flow_rx ? "RX" :
-                              (flow_tx ? "TX" : "None"))));
-                       netif_carrier_on(netdev);
-                       ixgbe_check_vf_rate_limit(adapter);
-               } else {
-                       /* Force detection of hung controller */
-                       for (i = 0; i < adapter->num_tx_queues; i++) {
-                               tx_ring = adapter->tx_ring[i];
-                               set_check_for_tx_hang(tx_ring);
-                       }
-               }
-       } else {
-               adapter->link_up = false;
-               adapter->link_speed = 0;
-               if (netif_carrier_ok(netdev)) {
-                       e_info(drv, "NIC Link is Down\n");
-                       netif_carrier_off(netdev);
-               }
-       }
+       /* exit if reset not needed */
+       if (!(adapter->flags2 & IXGBE_FLAG2_SFP_NEEDS_RESET))
+               goto sfp_out;
  
-       if (!netif_carrier_ok(netdev)) {
-               for (i = 0; i < adapter->num_tx_queues; i++) {
-                       tx_ring = adapter->tx_ring[i];
-                       if (tx_ring->next_to_use != tx_ring->next_to_clean) {
-                               some_tx_pending = 1;
-                               break;
-                       }
-               }
+       adapter->flags2 &= ~IXGBE_FLAG2_SFP_NEEDS_RESET;
  
-               if (some_tx_pending) {
-                       /* We've lost link, so the controller stops DMA,
-                        * but we've got queued Tx work that's never going
-                        * to get done, so reset controller to flush Tx.
-                        * (Do the reset outside of interrupt context).
-                        */
-                        schedule_work(&adapter->reset_task);
-               }
+       /*
+        * A module may be identified correctly, but the EEPROM may not have
+        * support for that module.  setup_sfp() will fail in that case, so
+        * we should not allow that module to load.
+        */
+       if (hw->mac.type == ixgbe_mac_82598EB)
+               err = hw->phy.ops.reset(hw);
+       else
+               err = hw->mac.ops.setup_sfp(hw);
+       if (err == IXGBE_ERR_SFP_NOT_SUPPORTED)
+               goto sfp_out;
+       adapter->flags |= IXGBE_FLAG_NEED_LINK_CONFIG;
+       e_info(probe, "detected SFP+: %d\n", hw->phy.sfp_type);
+ sfp_out:
+       clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state);
+       if ((err == IXGBE_ERR_SFP_NOT_SUPPORTED) &&
+           (adapter->netdev->reg_state == NETREG_REGISTERED)) {
+               e_dev_err("failed to initialize because an unsupported "
+                         "SFP+ module type was detected.\n");
+               e_dev_err("Reload the driver after installing a "
+                         "supported module.\n");
+               unregister_netdev(adapter->netdev);
        }
+ }
  
-       ixgbe_spoof_check(adapter);
-       ixgbe_update_stats(adapter);
-       mutex_unlock(&ixgbe_watchdog_lock);
+ /**
+  * ixgbe_sfp_link_config_subtask - set up link SFP after module install
+  * @adapter - the ixgbe adapter structure
+  **/
+ static void ixgbe_sfp_link_config_subtask(struct ixgbe_adapter *adapter)
+ {
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 autoneg;
+       bool negotiation;
+       if (!(adapter->flags & IXGBE_FLAG_NEED_LINK_CONFIG))
+               return;
+       /* someone else is in init, wait until next service event */
+       if (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
+               return;
+       adapter->flags &= ~IXGBE_FLAG_NEED_LINK_CONFIG;
+       autoneg = hw->phy.autoneg_advertised;
+       if ((!autoneg) && (hw->mac.ops.get_link_capabilities))
+               hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiation);
+       hw->mac.autotry_restart = false;
+       if (hw->mac.ops.setup_link)
+               hw->mac.ops.setup_link(hw, autoneg, negotiation, true);
+       adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
+       adapter->link_check_timeout = jiffies;
+       clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state);
+ }
+ /**
+  * ixgbe_service_timer - Timer Call-back
+  * @data: pointer to adapter cast into an unsigned long
+  **/
+ static void ixgbe_service_timer(unsigned long data)
+ {
+       struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data;
+       unsigned long next_event_offset;
+       /* poll faster when waiting for link */
+       if (adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE)
+               next_event_offset = HZ / 10;
+       else
+               next_event_offset = HZ * 2;
+       /* Reset the timer */
+       mod_timer(&adapter->service_timer, next_event_offset + jiffies);
+       ixgbe_service_event_schedule(adapter);
+ }
+ static void ixgbe_reset_subtask(struct ixgbe_adapter *adapter)
+ {
+       if (!(adapter->flags2 & IXGBE_FLAG2_RESET_REQUESTED))
+               return;
+       adapter->flags2 &= ~IXGBE_FLAG2_RESET_REQUESTED;
+       /* If we're already down or resetting, just bail */
+       if (test_bit(__IXGBE_DOWN, &adapter->state) ||
+           test_bit(__IXGBE_RESETTING, &adapter->state))
+               return;
+       ixgbe_dump(adapter);
+       netdev_err(adapter->netdev, "Reset adapter\n");
+       adapter->tx_timeout_count++;
+       ixgbe_reinit_locked(adapter);
+ }
+ /**
+  * ixgbe_service_task - manages and runs subtasks
+  * @work: pointer to work_struct containing our data
+  **/
+ static void ixgbe_service_task(struct work_struct *work)
+ {
+       struct ixgbe_adapter *adapter = container_of(work,
+                                                    struct ixgbe_adapter,
+                                                    service_task);
+       ixgbe_reset_subtask(adapter);
+       ixgbe_sfp_detection_subtask(adapter);
+       ixgbe_sfp_link_config_subtask(adapter);
+       ixgbe_check_overtemp_subtask(adapter);
+       ixgbe_watchdog_subtask(adapter);
+       ixgbe_fdir_reinit_subtask(adapter);
+       ixgbe_check_hang_subtask(adapter);
+       ixgbe_service_event_complete(adapter);
  }
  
  static int ixgbe_tso(struct ixgbe_adapter *adapter,
@@@ -7089,6 -7244,8 +7239,8 @@@ static void __devinit ixgbe_probe_vf(st
  #ifdef CONFIG_PCI_IOV
        struct ixgbe_hw *hw = &adapter->hw;
        int err;
+       int num_vf_macvlans, i;
+       struct vf_macvlans *mv_list;
  
        if (hw->mac.type == ixgbe_mac_82598EB || !max_vfs)
                return;
                e_err(probe, "Failed to enable PCI sriov: %d\n", err);
                goto err_novfs;
        }
+       num_vf_macvlans = hw->mac.num_rar_entries -
+               (IXGBE_MAX_PF_MACVLANS + 1 + adapter->num_vfs);
+       adapter->mv_list = mv_list = kcalloc(num_vf_macvlans,
+                                            sizeof(struct vf_macvlans),
+                                            GFP_KERNEL);
+       if (mv_list) {
+               /* Initialize list of VF macvlans */
+               INIT_LIST_HEAD(&adapter->vf_mvs.l);
+               for (i = 0; i < num_vf_macvlans; i++) {
+                       mv_list->vf = -1;
+                       mv_list->free = true;
+                       mv_list->rar_entry = hw->mac.num_rar_entries -
+                               (i + adapter->num_vfs + 1);
+                       list_add(&mv_list->l, &adapter->vf_mvs.l);
+                       mv_list++;
+               }
+       }
        /* If call to enable VFs succeeded then allocate memory
         * for per VF control structures.
         */
@@@ -7275,22 -7452,6 +7447,6 @@@ static int __devinit ixgbe_probe(struc
        hw->phy.mdio.mdio_read = ixgbe_mdio_read;
        hw->phy.mdio.mdio_write = ixgbe_mdio_write;
  
-       /* set up this timer and work struct before calling get_invariants
-        * which might start the timer
-        */
-       init_timer(&adapter->sfp_timer);
-       adapter->sfp_timer.function = ixgbe_sfp_timer;
-       adapter->sfp_timer.data = (unsigned long) adapter;
-       INIT_WORK(&adapter->sfp_task, ixgbe_sfp_task);
-       /* multispeed fiber has its own tasklet, called from GPI SDP1 context */
-       INIT_WORK(&adapter->multispeed_fiber_task, ixgbe_multispeed_fiber_task);
-       /* a new SFP+ module arrival, called from GPI SDP2 context */
-       INIT_WORK(&adapter->sfp_config_module_task,
-                 ixgbe_sfp_config_module_task);
        ii->get_invariants(hw);
  
        /* setup the private structure */
        hw->phy.reset_if_overtemp = false;
        if (err == IXGBE_ERR_SFP_NOT_PRESENT &&
            hw->mac.type == ixgbe_mac_82598EB) {
-               /*
-                * Start a kernel thread to watch for a module to arrive.
-                * Only do this for 82598, since 82599 will generate
-                * interrupts on module arrival.
-                */
-               set_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
-               mod_timer(&adapter->sfp_timer,
-                         round_jiffies(jiffies + (2 * HZ)));
                err = 0;
        } else if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
-               e_dev_err("failed to initialize because an unsupported SFP+ "
+               e_dev_err("failed to load because an unsupported SFP+ "
                          "module type was detected.\n");
                e_dev_err("Reload the driver after installing a supported "
                          "module.\n");
        netdev->features |= NETIF_F_TSO;
        netdev->features |= NETIF_F_TSO6;
        netdev->features |= NETIF_F_GRO;
+       netdev->features |= NETIF_F_RXHASH;
  
-       if (adapter->hw.mac.type == ixgbe_mac_82599EB)
+       switch (adapter->hw.mac.type) {
+       case ixgbe_mac_82599EB:
+       case ixgbe_mac_X540:
                netdev->features |= NETIF_F_SCTP_CSUM;
+               break;
+       default:
+               break;
+       }
  
        netdev->vlan_features |= NETIF_F_TSO;
        netdev->vlan_features |= NETIF_F_TSO6;
              (hw->mac.type == ixgbe_mac_82599EB))))
                hw->mac.ops.disable_tx_laser(hw);
  
-       init_timer(&adapter->watchdog_timer);
-       adapter->watchdog_timer.function = ixgbe_watchdog;
-       adapter->watchdog_timer.data = (unsigned long)adapter;
+       setup_timer(&adapter->service_timer, &ixgbe_service_timer,
+                   (unsigned long) adapter);
  
-       INIT_WORK(&adapter->reset_task, ixgbe_reset_task);
-       INIT_WORK(&adapter->watchdog_task, ixgbe_watchdog_task);
+       INIT_WORK(&adapter->service_task, ixgbe_service_task);
+       clear_bit(__IXGBE_SERVICE_SCHED, &adapter->state);
  
        err = ixgbe_init_interrupt_scheme(adapter);
        if (err)
                goto err_sw_init;
  
+       if (!(adapter->flags & IXGBE_FLAG_RSS_ENABLED))
+               netdev->features &= ~NETIF_F_RXHASH;
        switch (pdev->device) {
        case IXGBE_DEV_ID_82599_SFP:
                /* Only this subdevice supports WOL */
  
        /* print bus type/speed/width info */
        e_dev_info("(PCI Express:%s:%s) %pM\n",
-                  (hw->bus.speed == ixgbe_bus_speed_5000 ? "5.0Gb/s" :
-                   hw->bus.speed == ixgbe_bus_speed_2500 ? "2.5Gb/s" :
+                  (hw->bus.speed == ixgbe_bus_speed_5000 ? "5.0GT/s" :
+                   hw->bus.speed == ixgbe_bus_speed_2500 ? "2.5GT/s" :
                    "Unknown"),
                   (hw->bus.width == ixgbe_bus_width_pcie_x8 ? "Width x8" :
                    hw->bus.width == ixgbe_bus_width_pcie_x4 ? "Width x4" :
        /* carrier off reporting is important to ethtool even BEFORE open */
        netif_carrier_off(netdev);
  
-       if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE ||
-           adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)
-               INIT_WORK(&adapter->fdir_reinit_task, ixgbe_fdir_reinit_task);
-       if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE)
-               INIT_WORK(&adapter->check_overtemp_task,
-                         ixgbe_check_overtemp_task);
  #ifdef CONFIG_IXGBE_DCA
        if (dca_add_requester(&pdev->dev) == 0) {
                adapter->flags |= IXGBE_FLAG_DCA_ENABLED;
@@@ -7541,11 -7696,7 +7691,7 @@@ err_sw_init
  err_eeprom:
        if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
                ixgbe_disable_sriov(adapter);
-       clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
-       del_timer_sync(&adapter->sfp_timer);
-       cancel_work_sync(&adapter->sfp_task);
-       cancel_work_sync(&adapter->multispeed_fiber_task);
-       cancel_work_sync(&adapter->sfp_config_module_task);
+       adapter->flags2 &= ~IXGBE_FLAG2_SEARCH_FOR_SFP;
        iounmap(hw->hw_addr);
  err_ioremap:
        free_netdev(netdev);
@@@ -7573,24 -7724,7 +7719,7 @@@ static void __devexit ixgbe_remove(stru
        struct net_device *netdev = adapter->netdev;
  
        set_bit(__IXGBE_DOWN, &adapter->state);
-       /*
-        * The timers may be rescheduled, so explicitly disable them
-        * from being rescheduled.
-        */
-       clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
-       del_timer_sync(&adapter->watchdog_timer);
-       del_timer_sync(&adapter->sfp_timer);
-       cancel_work_sync(&adapter->watchdog_task);
-       cancel_work_sync(&adapter->sfp_task);
-       cancel_work_sync(&adapter->multispeed_fiber_task);
-       cancel_work_sync(&adapter->sfp_config_module_task);
-       if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE ||
-           adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)
-               cancel_work_sync(&adapter->fdir_reinit_task);
-       if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE)
-               cancel_work_sync(&adapter->check_overtemp_task);
+       cancel_work_sync(&adapter->service_task);
  
  #ifdef CONFIG_IXGBE_DCA
        if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) {
diff --combined drivers/net/macvlan.c
@@@ -70,16 -70,17 +70,17 @@@ static void macvlan_hash_add(struct mac
        hlist_add_head_rcu(&vlan->hlist, &port->vlan_hash[addr[5]]);
  }
  
- static void macvlan_hash_del(struct macvlan_dev *vlan)
+ static void macvlan_hash_del(struct macvlan_dev *vlan, bool sync)
  {
        hlist_del_rcu(&vlan->hlist);
-       synchronize_rcu();
+       if (sync)
+               synchronize_rcu();
  }
  
  static void macvlan_hash_change_addr(struct macvlan_dev *vlan,
                                        const unsigned char *addr)
  {
-       macvlan_hash_del(vlan);
+       macvlan_hash_del(vlan, true);
        /* Now that we are unhashed it is safe to change the device
         * address without confusing packet delivery.
         */
@@@ -345,7 -346,7 +346,7 @@@ static int macvlan_stop(struct net_devi
        dev_uc_del(lowerdev, dev->dev_addr);
  
  hash_del:
-       macvlan_hash_del(vlan);
+       macvlan_hash_del(vlan, !dev->dismantle);
        return 0;
  }
  
@@@ -415,7 -416,7 +416,7 @@@ static struct lock_class_key macvlan_ne
  #define MACVLAN_FEATURES \
        (NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \
         NETIF_F_GSO | NETIF_F_TSO | NETIF_F_UFO | NETIF_F_GSO_ROBUST | \
-        NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_GRO)
+        NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_GRO | NETIF_F_RXCSUM)
  
  #define MACVLAN_STATE_MASK \
        ((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT))
@@@ -517,12 -518,6 +518,6 @@@ static void macvlan_ethtool_get_drvinfo
        snprintf(drvinfo->version, 32, "0.1");
  }
  
- static u32 macvlan_ethtool_get_rx_csum(struct net_device *dev)
- {
-       const struct macvlan_dev *vlan = netdev_priv(dev);
-       return dev_ethtool_get_rx_csum(vlan->lowerdev);
- }
  static int macvlan_ethtool_get_settings(struct net_device *dev,
                                        struct ethtool_cmd *cmd)
  {
        return dev_ethtool_get_settings(vlan->lowerdev, cmd);
  }
  
- static u32 macvlan_ethtool_get_flags(struct net_device *dev)
- {
-       const struct macvlan_dev *vlan = netdev_priv(dev);
-       return dev_ethtool_get_flags(vlan->lowerdev);
- }
  static const struct ethtool_ops macvlan_ethtool_ops = {
        .get_link               = ethtool_op_get_link,
        .get_settings           = macvlan_ethtool_get_settings,
-       .get_rx_csum            = macvlan_ethtool_get_rx_csum,
        .get_drvinfo            = macvlan_ethtool_get_drvinfo,
-       .get_flags              = macvlan_ethtool_get_flags,
  };
  
  static const struct net_device_ops macvlan_netdev_ops = {
@@@ -598,18 -585,26 +585,18 @@@ static int macvlan_port_create(struct n
        err = netdev_rx_handler_register(dev, macvlan_handle_frame, port);
        if (err)
                kfree(port);
-       dev->priv_flags |= IFF_MACVLAN_PORT;
+       else
+               dev->priv_flags |= IFF_MACVLAN_PORT;
        return err;
  }
  
 -static void macvlan_port_rcu_free(struct rcu_head *head)
 -{
 -      struct macvlan_port *port;
 -
 -      port = container_of(head, struct macvlan_port, rcu);
 -      kfree(port);
 -}
 -
  static void macvlan_port_destroy(struct net_device *dev)
  {
        struct macvlan_port *port = macvlan_port_get(dev);
  
        dev->priv_flags &= ~IFF_MACVLAN_PORT;
        netdev_rx_handler_unregister(dev);
 -      call_rcu(&port->rcu, macvlan_port_rcu_free);
 +      kfree_rcu(port, rcu);
  }
  
  static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[])
@@@ -791,6 -786,7 +778,7 @@@ static int macvlan_device_event(struct 
        struct net_device *dev = ptr;
        struct macvlan_dev *vlan, *next;
        struct macvlan_port *port;
+       LIST_HEAD(list_kill);
  
        if (!macvlan_port_exists(dev))
                return NOTIFY_DONE;
                        break;
  
                list_for_each_entry_safe(vlan, next, &port->vlans, list)
-                       vlan->dev->rtnl_link_ops->dellink(vlan->dev, NULL);
+                       vlan->dev->rtnl_link_ops->dellink(vlan->dev, &list_kill);
+               unregister_netdevice_many(&list_kill);
+               list_del(&list_kill);
                break;
        case NETDEV_PRE_TYPE_CHANGE:
                /* Forbid underlaying device to change its type. */
diff --combined drivers/net/sunhme.c
@@@ -1383,7 -1383,7 +1383,7 @@@ force_link
                if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) {
                        hp->sw_bmcr = BMCR_SPEED100;
                } else {
-                       if (ep->speed == SPEED_100)
+                       if (ethtool_cmd_speed(ep) == SPEED_100)
                                hp->sw_bmcr = BMCR_SPEED100;
                        else
                                hp->sw_bmcr = 0;
@@@ -2401,6 -2401,7 +2401,7 @@@ static void happy_meal_set_multicast(st
  static int hme_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
  {
        struct happy_meal *hp = netdev_priv(dev);
+       u32 speed;
  
        cmd->supported =
                (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
  
        if (hp->sw_bmcr & BMCR_ANENABLE) {
                cmd->autoneg = AUTONEG_ENABLE;
-               cmd->speed =
-                       (hp->sw_lpa & (LPA_100HALF | LPA_100FULL)) ?
-                       SPEED_100 : SPEED_10;
-               if (cmd->speed == SPEED_100)
+               speed = ((hp->sw_lpa & (LPA_100HALF | LPA_100FULL)) ?
+                        SPEED_100 : SPEED_10);
+               if (speed == SPEED_100)
                        cmd->duplex =
                                (hp->sw_lpa & (LPA_100FULL)) ?
                                DUPLEX_FULL : DUPLEX_HALF;
                                DUPLEX_FULL : DUPLEX_HALF;
        } else {
                cmd->autoneg = AUTONEG_DISABLE;
-               cmd->speed =
-                       (hp->sw_bmcr & BMCR_SPEED100) ?
-                       SPEED_100 : SPEED_10;
+               speed = (hp->sw_bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10;
                cmd->duplex =
                        (hp->sw_bmcr & BMCR_FULLDPLX) ?
                        DUPLEX_FULL : DUPLEX_HALF;
        }
+       ethtool_cmd_speed_set(cmd, speed);
        return 0;
  }
  
@@@ -2452,8 -2451,8 +2451,8 @@@ static int hme_set_settings(struct net_
            cmd->autoneg != AUTONEG_DISABLE)
                return -EINVAL;
        if (cmd->autoneg == AUTONEG_DISABLE &&
-           ((cmd->speed != SPEED_100 &&
-             cmd->speed != SPEED_10) ||
+           ((ethtool_cmd_speed(cmd) != SPEED_100 &&
+             ethtool_cmd_speed(cmd) != SPEED_10) ||
             (cmd->duplex != DUPLEX_HALF &&
              cmd->duplex != DUPLEX_FULL)))
                return -EINVAL;
@@@ -2788,7 -2787,8 +2787,8 @@@ static int __devinit happy_meal_sbus_pr
        dev->ethtool_ops = &hme_ethtool_ops;
  
        /* Happy Meal can do it all... */
-       dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
+       dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM;
+       dev->features |= dev->hw_features | NETIF_F_RXCSUM;
  
        dev->irq = op->archdata.irqs[0];
  
@@@ -3113,7 -3113,8 +3113,8 @@@ static int __devinit happy_meal_pci_pro
        dev->dma = 0;
  
        /* Happy Meal can do it all... */
-       dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
+       dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM;
+       dev->features |= dev->hw_features | NETIF_F_RXCSUM;
  
  #if defined(CONFIG_SBUS) && defined(CONFIG_PCI)
        /* Hook up PCI register/descriptor accessors. */
@@@ -3237,18 -3238,15 +3238,18 @@@ static void happy_meal_pci_exit(void
  #endif
  
  #ifdef CONFIG_SBUS
 +static const struct of_device_id hme_sbus_match[];
  static int __devinit hme_sbus_probe(struct platform_device *op)
  {
 +      const struct of_device_id *match;
        struct device_node *dp = op->dev.of_node;
        const char *model = of_get_property(dp, "model", NULL);
        int is_qfe;
  
 -      if (!op->dev.of_match)
 +      match = of_match_device(hme_sbus_match, &op->dev);
 +      if (!match)
                return -EINVAL;
 -      is_qfe = (op->dev.of_match->data != NULL);
 +      is_qfe = (match->data != NULL);
  
        if (!is_qfe && model && !strcmp(model, "SUNW,sbus-qfe"))
                is_qfe = 1;
@@@ -664,7 -664,7 +664,7 @@@ static void bnx2fc_link_speed_update(st
        struct fcoe_port *port = lport_priv(lport);
        struct bnx2fc_hba *hba = port->priv;
        struct net_device *netdev = hba->netdev;
-       struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+       struct ethtool_cmd ecmd;
  
        if (!dev_ethtool_get_settings(netdev, &ecmd)) {
                lport->link_supported_speeds &=
                if (ecmd.supported & SUPPORTED_10000baseT_Full)
                        lport->link_supported_speeds |= FC_PORTSPEED_10GBIT;
  
-               if (ecmd.speed == SPEED_1000)
+               switch (ethtool_cmd_speed(&ecmd)) {
+               case SPEED_1000:
                        lport->link_speed = FC_PORTSPEED_1GBIT;
-               if (ecmd.speed == SPEED_10000)
+                       break;
+               case SPEED_10000:
                        lport->link_speed = FC_PORTSPEED_10GBIT;
+                       break;
+               }
        }
-       return;
  }
  static int bnx2fc_link_ok(struct fc_lport *lport)
  {
@@@ -1130,7 -1133,7 +1133,7 @@@ static void bnx2fc_interface_release(st
        struct net_device *phys_dev;
  
        hba = container_of(kref, struct bnx2fc_hba, kref);
 -      BNX2FC_HBA_DBG(hba->ctlr.lp, "Interface is being released\n");
 +      BNX2FC_MISC_DBG("Interface is being released\n");
  
        netdev = hba->netdev;
        phys_dev = hba->phys_dev;
@@@ -1254,17 -1257,20 +1257,17 @@@ setup_err
  static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba,
                                  struct device *parent, int npiv)
  {
 -      struct fc_lport         *lport = NULL;
 +      struct fc_lport         *lport, *n_port;
        struct fcoe_port        *port;
        struct Scsi_Host        *shost;
        struct fc_vport         *vport = dev_to_vport(parent);
        int                     rc = 0;
  
        /* Allocate Scsi_Host structure */
 -      if (!npiv) {
 -              lport = libfc_host_alloc(&bnx2fc_shost_template,
 -                                        sizeof(struct fcoe_port));
 -      } else {
 -              lport = libfc_vport_create(vport,
 -                                         sizeof(struct fcoe_port));
 -      }
 +      if (!npiv)
 +              lport = libfc_host_alloc(&bnx2fc_shost_template, sizeof(*port));
 +      else
 +              lport = libfc_vport_create(vport, sizeof(*port));
  
        if (!lport) {
                printk(KERN_ERR PFX "could not allocate scsi host structure\n");
                goto lp_config_err;
  
        if (npiv) {
 -              vport = dev_to_vport(parent);
                printk(KERN_ERR PFX "Setting vport names, 0x%llX 0x%llX\n",
                        vport->node_name, vport->port_name);
                fc_set_wwnn(lport, vport->node_name);
        fc_host_port_type(lport->host) = FC_PORTTYPE_UNKNOWN;
  
        /* Allocate exchange manager */
 -      if (!npiv) {
 +      if (!npiv)
                rc = bnx2fc_em_config(lport);
 -              if (rc) {
 -                      printk(KERN_ERR PFX "Error on bnx2fc_em_config\n");
 -                      goto shost_err;
 -              }
 +      else {
 +              shost = vport_to_shost(vport);
 +              n_port = shost_priv(shost);
 +              rc = fc_exch_mgr_list_clone(n_port, lport);
 +      }
 +
 +      if (rc) {
 +              printk(KERN_ERR PFX "Error on bnx2fc_em_config\n");
 +              goto shost_err;
        }
  
        bnx2fc_interface_get(hba);
@@@ -1353,6 -1355,8 +1356,6 @@@ static void bnx2fc_if_destroy(struct fc
        /* Free existing transmit skbs */
        fcoe_clean_pending_queue(lport);
  
 -      bnx2fc_interface_put(hba);
 -
        /* Free queued packets for the receive thread */
        bnx2fc_clean_rx_queue(lport);
  
  
        /* Release Scsi_Host */
        scsi_host_put(lport->host);
 +
 +      bnx2fc_interface_put(hba);
  }
  
  /**
diff --combined drivers/scsi/fcoe/fcoe.c
@@@ -380,42 -380,6 +380,42 @@@ out
        return fcoe;
  }
  
 +/**
 + * fcoe_interface_release() - fcoe_port kref release function
 + * @kref: Embedded reference count in an fcoe_interface struct
 + */
 +static void fcoe_interface_release(struct kref *kref)
 +{
 +      struct fcoe_interface *fcoe;
 +      struct net_device *netdev;
 +
 +      fcoe = container_of(kref, struct fcoe_interface, kref);
 +      netdev = fcoe->netdev;
 +      /* tear-down the FCoE controller */
 +      fcoe_ctlr_destroy(&fcoe->ctlr);
 +      kfree(fcoe);
 +      dev_put(netdev);
 +      module_put(THIS_MODULE);
 +}
 +
 +/**
 + * fcoe_interface_get() - Get a reference to a FCoE interface
 + * @fcoe: The FCoE interface to be held
 + */
 +static inline void fcoe_interface_get(struct fcoe_interface *fcoe)
 +{
 +      kref_get(&fcoe->kref);
 +}
 +
 +/**
 + * fcoe_interface_put() - Put a reference to a FCoE interface
 + * @fcoe: The FCoE interface to be released
 + */
 +static inline void fcoe_interface_put(struct fcoe_interface *fcoe)
 +{
 +      kref_put(&fcoe->kref, fcoe_interface_release);
 +}
 +
  /**
   * fcoe_interface_cleanup() - Clean up a FCoE interface
   * @fcoe: The FCoE interface to be cleaned up
@@@ -428,21 -392,6 +428,21 @@@ void fcoe_interface_cleanup(struct fcoe
        struct fcoe_ctlr *fip = &fcoe->ctlr;
        u8 flogi_maddr[ETH_ALEN];
        const struct net_device_ops *ops;
 +      struct fcoe_port *port = lport_priv(fcoe->ctlr.lp);
 +
 +      FCOE_NETDEV_DBG(netdev, "Destroying interface\n");
 +
 +      /* Logout of the fabric */
 +      fc_fabric_logoff(fcoe->ctlr.lp);
 +
 +      /* Cleanup the fc_lport */
 +      fc_lport_destroy(fcoe->ctlr.lp);
 +
 +      /* Stop the transmit retry timer */
 +      del_timer_sync(&port->timer);
 +
 +      /* Free existing transmit skbs */
 +      fcoe_clean_pending_queue(fcoe->ctlr.lp);
  
        /*
         * Don't listen for Ethernet packets anymore.
        } else
                dev_mc_del(netdev, FIP_ALL_ENODE_MACS);
  
 +      if (!is_zero_ether_addr(port->data_src_addr))
 +              dev_uc_del(netdev, port->data_src_addr);
 +
        /* Tell the LLD we are done w/ FCoE */
        ops = netdev->netdev_ops;
        if (ops->ndo_fcoe_disable) {
                        FCOE_NETDEV_DBG(netdev, "Failed to disable FCoE"
                                        " specific feature for LLD.\n");
        }
 -}
 -
 -/**
 - * fcoe_interface_release() - fcoe_port kref release function
 - * @kref: Embedded reference count in an fcoe_interface struct
 - */
 -static void fcoe_interface_release(struct kref *kref)
 -{
 -      struct fcoe_interface *fcoe;
 -      struct net_device *netdev;
 -
 -      fcoe = container_of(kref, struct fcoe_interface, kref);
 -      netdev = fcoe->netdev;
 -      /* tear-down the FCoE controller */
 -      fcoe_ctlr_destroy(&fcoe->ctlr);
 -      kfree(fcoe);
 -      dev_put(netdev);
 -      module_put(THIS_MODULE);
 -}
 -
 -/**
 - * fcoe_interface_get() - Get a reference to a FCoE interface
 - * @fcoe: The FCoE interface to be held
 - */
 -static inline void fcoe_interface_get(struct fcoe_interface *fcoe)
 -{
 -      kref_get(&fcoe->kref);
 -}
 -
 -/**
 - * fcoe_interface_put() - Put a reference to a FCoE interface
 - * @fcoe: The FCoE interface to be released
 - */
 -static inline void fcoe_interface_put(struct fcoe_interface *fcoe)
 -{
 -      kref_put(&fcoe->kref, fcoe_interface_release);
 +      fcoe_interface_put(fcoe);
  }
  
  /**
@@@ -840,9 -821,39 +840,9 @@@ skip_oem
   * fcoe_if_destroy() - Tear down a SW FCoE instance
   * @lport: The local port to be destroyed
   *
 - * Locking: must be called with the RTNL mutex held and RTNL mutex
 - * needed to be dropped by this function since not dropping RTNL
 - * would cause circular locking warning on synchronous fip worker
 - * cancelling thru fcoe_interface_put invoked by this function.
 - *
   */
  static void fcoe_if_destroy(struct fc_lport *lport)
  {
 -      struct fcoe_port *port = lport_priv(lport);
 -      struct fcoe_interface *fcoe = port->priv;
 -      struct net_device *netdev = fcoe->netdev;
 -
 -      FCOE_NETDEV_DBG(netdev, "Destroying interface\n");
 -
 -      /* Logout of the fabric */
 -      fc_fabric_logoff(lport);
 -
 -      /* Cleanup the fc_lport */
 -      fc_lport_destroy(lport);
 -
 -      /* Stop the transmit retry timer */
 -      del_timer_sync(&port->timer);
 -
 -      /* Free existing transmit skbs */
 -      fcoe_clean_pending_queue(lport);
 -
 -      if (!is_zero_ether_addr(port->data_src_addr))
 -              dev_uc_del(netdev, port->data_src_addr);
 -      rtnl_unlock();
 -
 -      /* receives may not be stopped until after this */
 -      fcoe_interface_put(fcoe);
 -
        /* Free queued packets for the per-CPU receive threads */
        fcoe_percpu_clean(lport);
  
@@@ -1772,8 -1783,23 +1772,8 @@@ static int fcoe_disable(struct net_devi
        int rc = 0;
  
        mutex_lock(&fcoe_config_mutex);
 -#ifdef CONFIG_FCOE_MODULE
 -      /*
 -       * Make sure the module has been initialized, and is not about to be
 -       * removed.  Module paramter sysfs files are writable before the
 -       * module_init function is called and after module_exit.
 -       */
 -      if (THIS_MODULE->state != MODULE_STATE_LIVE) {
 -              rc = -ENODEV;
 -              goto out_nodev;
 -      }
 -#endif
 -
 -      if (!rtnl_trylock()) {
 -              mutex_unlock(&fcoe_config_mutex);
 -              return -ERESTARTSYS;
 -      }
  
 +      rtnl_lock();
        fcoe = fcoe_hostlist_lookup_port(netdev);
        rtnl_unlock();
  
        } else
                rc = -ENODEV;
  
 -out_nodev:
        mutex_unlock(&fcoe_config_mutex);
        return rc;
  }
@@@ -1801,7 -1828,22 +1801,7 @@@ static int fcoe_enable(struct net_devic
        int rc = 0;
  
        mutex_lock(&fcoe_config_mutex);
 -#ifdef CONFIG_FCOE_MODULE
 -      /*
 -       * Make sure the module has been initialized, and is not about to be
 -       * removed.  Module paramter sysfs files are writable before the
 -       * module_init function is called and after module_exit.
 -       */
 -      if (THIS_MODULE->state != MODULE_STATE_LIVE) {
 -              rc = -ENODEV;
 -              goto out_nodev;
 -      }
 -#endif
 -      if (!rtnl_trylock()) {
 -              mutex_unlock(&fcoe_config_mutex);
 -              return -ERESTARTSYS;
 -      }
 -
 +      rtnl_lock();
        fcoe = fcoe_hostlist_lookup_port(netdev);
        rtnl_unlock();
  
        else if (!fcoe_link_ok(fcoe->ctlr.lp))
                fcoe_ctlr_link_up(&fcoe->ctlr);
  
 -out_nodev:
        mutex_unlock(&fcoe_config_mutex);
        return rc;
  }
  static int fcoe_destroy(struct net_device *netdev)
  {
        struct fcoe_interface *fcoe;
 +      struct fc_lport *lport;
        int rc = 0;
  
        mutex_lock(&fcoe_config_mutex);
 -#ifdef CONFIG_FCOE_MODULE
 -      /*
 -       * Make sure the module has been initialized, and is not about to be
 -       * removed.  Module paramter sysfs files are writable before the
 -       * module_init function is called and after module_exit.
 -       */
 -      if (THIS_MODULE->state != MODULE_STATE_LIVE) {
 -              rc = -ENODEV;
 -              goto out_nodev;
 -      }
 -#endif
 -      if (!rtnl_trylock()) {
 -              mutex_unlock(&fcoe_config_mutex);
 -              return -ERESTARTSYS;
 -      }
 -
 +      rtnl_lock();
        fcoe = fcoe_hostlist_lookup_port(netdev);
        if (!fcoe) {
                rtnl_unlock();
                rc = -ENODEV;
                goto out_nodev;
        }
 -      fcoe_interface_cleanup(fcoe);
 +      lport = fcoe->ctlr.lp;
        list_del(&fcoe->list);
 -      /* RTNL mutex is dropped by fcoe_if_destroy */
 -      fcoe_if_destroy(fcoe->ctlr.lp);
 +      fcoe_interface_cleanup(fcoe);
 +      rtnl_unlock();
 +      fcoe_if_destroy(lport);
  out_nodev:
        mutex_unlock(&fcoe_config_mutex);
        return rc;
@@@ -1856,6 -1912,8 +1856,6 @@@ static void fcoe_destroy_work(struct wo
  
        port = container_of(work, struct fcoe_port, destroy_work);
        mutex_lock(&fcoe_config_mutex);
 -      rtnl_lock();
 -      /* RTNL mutex is dropped by fcoe_if_destroy */
        fcoe_if_destroy(port->lport);
        mutex_unlock(&fcoe_config_mutex);
  }
@@@ -1890,7 -1948,23 +1890,7 @@@ static int fcoe_create(struct net_devic
        struct fc_lport *lport;
  
        mutex_lock(&fcoe_config_mutex);
 -
 -      if (!rtnl_trylock()) {
 -              mutex_unlock(&fcoe_config_mutex);
 -              return -ERESTARTSYS;
 -      }
 -
 -#ifdef CONFIG_FCOE_MODULE
 -      /*
 -       * Make sure the module has been initialized, and is not about to be
 -       * removed.  Module paramter sysfs files are writable before the
 -       * module_init function is called and after module_exit.
 -       */
 -      if (THIS_MODULE->state != MODULE_STATE_LIVE) {
 -              rc = -ENODEV;
 -              goto out_nodev;
 -      }
 -#endif
 +      rtnl_lock();
  
        /* look for existing lport */
        if (fcoe_hostlist_lookup(netdev)) {
@@@ -1952,7 -2026,7 +1952,7 @@@ out_nodev
  int fcoe_link_speed_update(struct fc_lport *lport)
  {
        struct net_device *netdev = fcoe_netdev(lport);
-       struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+       struct ethtool_cmd ecmd;
  
        if (!dev_ethtool_get_settings(netdev, &ecmd)) {
                lport->link_supported_speeds &=
                if (ecmd.supported & SUPPORTED_10000baseT_Full)
                        lport->link_supported_speeds |=
                                FC_PORTSPEED_10GBIT;
-               if (ecmd.speed == SPEED_1000)
+               switch (ethtool_cmd_speed(&ecmd)) {
+               case SPEED_1000:
                        lport->link_speed = FC_PORTSPEED_1GBIT;
-               if (ecmd.speed == SPEED_10000)
+                       break;
+               case SPEED_10000:
                        lport->link_speed = FC_PORTSPEED_10GBIT;
+                       break;
+               }
                return 0;
        }
        return -1;
diff --combined include/linux/ssb/ssb.h
@@@ -308,7 -308,7 +308,7 @@@ struct ssb_bus 
  
        /* ID information about the Chip. */
        u16 chip_id;
-       u16 chip_rev;
+       u8 chip_rev;
        u16 sprom_offset;
        u16 sprom_size;         /* number of words in sprom */
        u8 chip_package;
@@@ -404,9 -404,7 +404,9 @@@ extern bool ssb_is_sprom_available(stru
  
  /* Set a fallback SPROM.
   * See kdoc at the function definition for complete documentation. */
 -extern int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom);
 +extern int ssb_arch_register_fallback_sprom(
 +              int (*sprom_callback)(struct ssb_bus *bus,
 +              struct ssb_sprom *out));
  
  /* Suspend a SSB bus.
   * Call this from the parent bus suspend routine. */
@@@ -520,6 -518,7 +520,7 @@@ extern int ssb_bus_may_powerdown(struc
   * Otherwise static always-on powercontrol will be used. */
  extern int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl);
  
+ extern void ssb_commit_settings(struct ssb_bus *bus);
  
  /* Various helper functions */
  extern u32 ssb_admatch_base(u32 adm);
diff --combined include/net/sctp/sctp.h
   * sctp/protocol.c
   */
  extern struct sock *sctp_get_ctl_sock(void);
 -extern void sctp_local_addr_free(struct rcu_head *head);
  extern int sctp_copy_local_addr_list(struct sctp_bind_addr *,
                                     sctp_scope_t, gfp_t gfp,
                                     int flags);
@@@ -530,7 -531,6 +530,6 @@@ _sctp_walk_params((pos), (chunk), ntohs
  
  #define _sctp_walk_params(pos, chunk, end, member)\
  for (pos.v = chunk->member;\
-      pos.v <= (void *)chunk + end - sizeof(sctp_paramhdr_t) &&\
       pos.v <= (void *)chunk + end - ntohs(pos.p->length) &&\
       ntohs(pos.p->length) >= sizeof(sctp_paramhdr_t);\
       pos.v += WORD_ROUND(ntohs(pos.p->length)))
@@@ -541,7 -541,6 +540,6 @@@ _sctp_walk_errors((err), (chunk_hdr), n
  #define _sctp_walk_errors(err, chunk_hdr, end)\
  for (err = (sctp_errhdr_t *)((void *)chunk_hdr + \
            sizeof(sctp_chunkhdr_t));\
-      (void *)err <= (void *)chunk_hdr + end - sizeof(sctp_errhdr_t) &&\
       (void *)err <= (void *)chunk_hdr + end - ntohs(err->length) &&\
       ntohs(err->length) >= sizeof(sctp_errhdr_t); \
       err = (sctp_errhdr_t *)((void *)err + WORD_ROUND(ntohs(err->length))))
diff --combined net/9p/client.c
@@@ -614,7 -614,7 +614,7 @@@ p9_client_rpc(struct p9_client *c, int8
  
        err = c->trans_mod->request(c, req);
        if (err < 0) {
 -              if (err != -ERESTARTSYS)
 +              if (err != -ERESTARTSYS && err != -EFAULT)
                        c->status = Disconnected;
                goto reterr;
        }
@@@ -929,15 -929,15 +929,15 @@@ error
  }
  EXPORT_SYMBOL(p9_client_attach);
  
 -struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
 -      int clone)
 +struct p9_fid *p9_client_walk(struct p9_fid *oldfid, uint16_t nwname,
 +              char **wnames, int clone)
  {
        int err;
        struct p9_client *clnt;
        struct p9_fid *fid;
        struct p9_qid *wqids;
        struct p9_req_t *req;
 -      int16_t nwqids, count;
 +      uint16_t nwqids, count;
  
        err = 0;
        wqids = NULL;
                fid = oldfid;
  
  
 -      P9_DPRINTK(P9_DEBUG_9P, ">>> TWALK fids %d,%d nwname %d wname[0] %s\n",
 +      P9_DPRINTK(P9_DEBUG_9P, ">>> TWALK fids %d,%d nwname %ud wname[0] %s\n",
                oldfid->fid, fid->fid, nwname, wnames ? wnames[0] : NULL);
  
        req = p9_client_rpc(clnt, P9_TWALK, "ddT", oldfid->fid, fid->fid,
@@@ -1220,6 -1220,27 +1220,6 @@@ error
  }
  EXPORT_SYMBOL(p9_client_fsync);
  
 -int p9_client_sync_fs(struct p9_fid *fid)
 -{
 -      int err = 0;
 -      struct p9_req_t *req;
 -      struct p9_client *clnt;
 -
 -      P9_DPRINTK(P9_DEBUG_9P, ">>> TSYNC_FS fid %d\n", fid->fid);
 -
 -      clnt = fid->clnt;
 -      req = p9_client_rpc(clnt, P9_TSYNCFS, "d", fid->fid);
 -      if (IS_ERR(req)) {
 -              err = PTR_ERR(req);
 -              goto error;
 -      }
 -      P9_DPRINTK(P9_DEBUG_9P, "<<< RSYNCFS fid %d\n", fid->fid);
 -      p9_free_req(clnt, req);
 -error:
 -      return err;
 -}
 -EXPORT_SYMBOL(p9_client_sync_fs);
 -
  int p9_client_clunk(struct p9_fid *fid)
  {
        int err;
@@@ -1281,7 -1302,7 +1281,7 @@@ in
  p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset,
                                                                u32 count)
  {
-       int err, rsize, total;
+       int err, rsize;
        struct p9_client *clnt;
        struct p9_req_t *req;
        char *dataptr;
                                        (long long unsigned) offset, count);
        err = 0;
        clnt = fid->clnt;
-       total = 0;
  
        rsize = fid->iounit;
        if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
@@@ -1346,7 -1366,7 +1345,7 @@@ in
  p9_client_write(struct p9_fid *fid, char *data, const char __user *udata,
                                                        u64 offset, u32 count)
  {
-       int err, rsize, total;
+       int err, rsize;
        struct p9_client *clnt;
        struct p9_req_t *req;
  
                                fid->fid, (long long unsigned) offset, count);
        err = 0;
        clnt = fid->clnt;
-       total = 0;
  
        rsize = fid->iounit;
        if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
@@@ -1745,7 -1764,7 +1743,7 @@@ EXPORT_SYMBOL_GPL(p9_client_xattrcreate
  
  int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset)
  {
-       int err, rsize, total;
+       int err, rsize;
        struct p9_client *clnt;
        struct p9_req_t *req;
        char *dataptr;
  
        err = 0;
        clnt = fid->clnt;
-       total = 0;
  
        rsize = fid->iounit;
        if (!rsize || rsize > clnt->msize-P9_READDIRHDRSZ)
  #include "gateway_client.h"
  #include "gateway_common.h"
  #include "hard-interface.h"
+ #include "originator.h"
  #include <linux/ip.h>
  #include <linux/ipv6.h>
  #include <linux/udp.h>
  #include <linux/if_vlan.h>
  
 -static void gw_node_free_rcu(struct rcu_head *rcu)
 -{
 -      struct gw_node *gw_node;
 -
 -      gw_node = container_of(rcu, struct gw_node, rcu);
 -      kfree(gw_node);
 -}
 -
  static void gw_node_free_ref(struct gw_node *gw_node)
  {
        if (atomic_dec_and_test(&gw_node->refcount))
 -              call_rcu(&gw_node->rcu, gw_node_free_rcu);
 +              kfree_rcu(gw_node, rcu);
  }
  
void *gw_get_selected(struct bat_priv *bat_priv)
static struct gw_node *gw_get_selected_gw_node(struct bat_priv *bat_priv)
  {
-       struct gw_node *curr_gateway_tmp;
-       struct orig_node *orig_node = NULL;
+       struct gw_node *gw_node;
  
        rcu_read_lock();
-       curr_gateway_tmp = rcu_dereference(bat_priv->curr_gw);
-       if (!curr_gateway_tmp)
-               goto out;
-       orig_node = curr_gateway_tmp->orig_node;
-       if (!orig_node)
+       gw_node = rcu_dereference(bat_priv->curr_gw);
+       if (!gw_node)
                goto out;
  
-       if (!atomic_inc_not_zero(&orig_node->refcount))
-               orig_node = NULL;
+       if (!atomic_inc_not_zero(&gw_node->refcount))
+               gw_node = NULL;
  
  out:
        rcu_read_unlock();
-       return orig_node;
+       return gw_node;
  }
  
void gw_deselect(struct bat_priv *bat_priv)
struct orig_node *gw_get_selected_orig(struct bat_priv *bat_priv)
  {
        struct gw_node *gw_node;
+       struct orig_node *orig_node = NULL;
  
-       spin_lock_bh(&bat_priv->gw_list_lock);
-       gw_node = rcu_dereference(bat_priv->curr_gw);
-       rcu_assign_pointer(bat_priv->curr_gw, NULL);
-       spin_unlock_bh(&bat_priv->gw_list_lock);
+       gw_node = gw_get_selected_gw_node(bat_priv);
+       if (!gw_node)
+               goto out;
+       rcu_read_lock();
+       orig_node = gw_node->orig_node;
+       if (!orig_node)
+               goto unlock;
+       if (!atomic_inc_not_zero(&orig_node->refcount))
+               orig_node = NULL;
  
+ unlock:
+       rcu_read_unlock();
+ out:
        if (gw_node)
                gw_node_free_ref(gw_node);
+       return orig_node;
  }
  
  static void gw_select(struct bat_priv *bat_priv, struct gw_node *new_gw_node)
  {
        struct gw_node *curr_gw_node;
  
+       spin_lock_bh(&bat_priv->gw_list_lock);
        if (new_gw_node && !atomic_inc_not_zero(&new_gw_node->refcount))
                new_gw_node = NULL;
  
-       spin_lock_bh(&bat_priv->gw_list_lock);
-       curr_gw_node = rcu_dereference(bat_priv->curr_gw);
+       curr_gw_node = bat_priv->curr_gw;
        rcu_assign_pointer(bat_priv->curr_gw, new_gw_node);
-       spin_unlock_bh(&bat_priv->gw_list_lock);
  
        if (curr_gw_node)
                gw_node_free_ref(curr_gw_node);
+       spin_unlock_bh(&bat_priv->gw_list_lock);
+ }
+ void gw_deselect(struct bat_priv *bat_priv)
+ {
+       gw_select(bat_priv, NULL);
  }
  
  void gw_election(struct bat_priv *bat_priv)
  {
        struct hlist_node *node;
-       struct gw_node *gw_node, *curr_gw, *curr_gw_tmp = NULL;
+       struct gw_node *gw_node, *curr_gw = NULL, *curr_gw_tmp = NULL;
+       struct neigh_node *router;
        uint8_t max_tq = 0;
        uint32_t max_gw_factor = 0, tmp_gw_factor = 0;
        int down, up;
        if (atomic_read(&bat_priv->gw_mode) != GW_MODE_CLIENT)
                return;
  
-       rcu_read_lock();
-       curr_gw = rcu_dereference(bat_priv->curr_gw);
-       if (curr_gw) {
-               rcu_read_unlock();
-               return;
-       }
+       curr_gw = gw_get_selected_gw_node(bat_priv);
+       if (curr_gw)
+               goto out;
  
+       rcu_read_lock();
        if (hlist_empty(&bat_priv->gw_list)) {
-               if (curr_gw) {
-                       rcu_read_unlock();
-                       bat_dbg(DBG_BATMAN, bat_priv,
-                               "Removing selected gateway - "
-                               "no gateway in range\n");
-                       gw_deselect(bat_priv);
-               } else
-                       rcu_read_unlock();
-               return;
+               bat_dbg(DBG_BATMAN, bat_priv,
+                       "Removing selected gateway - "
+                       "no gateway in range\n");
+               gw_deselect(bat_priv);
+               goto unlock;
        }
  
        hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
-               if (!gw_node->orig_node->router)
+               if (gw_node->deleted)
                        continue;
  
-               if (gw_node->deleted)
+               router = orig_node_get_router(gw_node->orig_node);
+               if (!router)
                        continue;
  
                switch (atomic_read(&bat_priv->gw_sel_class)) {
                        gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags,
                                             &down, &up);
  
-                       tmp_gw_factor = (gw_node->orig_node->router->tq_avg *
-                                        gw_node->orig_node->router->tq_avg *
+                       tmp_gw_factor = (router->tq_avg * router->tq_avg *
                                         down * 100 * 100) /
                                         (TQ_LOCAL_WINDOW_SIZE *
                                         TQ_LOCAL_WINDOW_SIZE * 64);
  
                        if ((tmp_gw_factor > max_gw_factor) ||
                            ((tmp_gw_factor == max_gw_factor) &&
-                            (gw_node->orig_node->router->tq_avg > max_tq)))
+                            (router->tq_avg > max_tq)))
                                curr_gw_tmp = gw_node;
                        break;
  
                          *     soon as a better gateway appears which has
                          *     $routing_class more tq points)
                          **/
-                       if (gw_node->orig_node->router->tq_avg > max_tq)
+                       if (router->tq_avg > max_tq)
                                curr_gw_tmp = gw_node;
                        break;
                }
  
-               if (gw_node->orig_node->router->tq_avg > max_tq)
-                       max_tq = gw_node->orig_node->router->tq_avg;
+               if (router->tq_avg > max_tq)
+                       max_tq = router->tq_avg;
  
                if (tmp_gw_factor > max_gw_factor)
                        max_gw_factor = tmp_gw_factor;
+               neigh_node_free_ref(router);
        }
  
        if (curr_gw != curr_gw_tmp) {
+               router = orig_node_get_router(curr_gw_tmp->orig_node);
+               if (!router)
+                       goto unlock;
                if ((curr_gw) && (!curr_gw_tmp))
                        bat_dbg(DBG_BATMAN, bat_priv,
                                "Removing selected gateway - "
                                "(gw_flags: %i, tq: %i)\n",
                                curr_gw_tmp->orig_node->orig,
                                curr_gw_tmp->orig_node->gw_flags,
-                               curr_gw_tmp->orig_node->router->tq_avg);
+                               router->tq_avg);
                else
                        bat_dbg(DBG_BATMAN, bat_priv,
                                "Changing route to gateway %pM "
                                "(gw_flags: %i, tq: %i)\n",
                                curr_gw_tmp->orig_node->orig,
                                curr_gw_tmp->orig_node->gw_flags,
-                               curr_gw_tmp->orig_node->router->tq_avg);
+                               router->tq_avg);
  
+               neigh_node_free_ref(router);
                gw_select(bat_priv, curr_gw_tmp);
        }
  
+ unlock:
        rcu_read_unlock();
+ out:
+       if (curr_gw)
+               gw_node_free_ref(curr_gw);
  }
  
  void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node)
  {
-       struct gw_node *curr_gateway_tmp;
+       struct orig_node *curr_gw_orig;
+       struct neigh_node *router_gw = NULL, *router_orig = NULL;
        uint8_t gw_tq_avg, orig_tq_avg;
  
-       rcu_read_lock();
-       curr_gateway_tmp = rcu_dereference(bat_priv->curr_gw);
-       if (!curr_gateway_tmp)
-               goto out_rcu;
-       if (!curr_gateway_tmp->orig_node)
-               goto deselect_rcu;
+       curr_gw_orig = gw_get_selected_orig(bat_priv);
+       if (!curr_gw_orig)
+               goto deselect;
  
-       if (!curr_gateway_tmp->orig_node->router)
-               goto deselect_rcu;
+       router_gw = orig_node_get_router(curr_gw_orig);
+       if (!router_gw)
+               goto deselect;
  
        /* this node already is the gateway */
-       if (curr_gateway_tmp->orig_node == orig_node)
-               goto out_rcu;
-       if (!orig_node->router)
-               goto out_rcu;
+       if (curr_gw_orig == orig_node)
+               goto out;
  
-       gw_tq_avg = curr_gateway_tmp->orig_node->router->tq_avg;
-       rcu_read_unlock();
+       router_orig = orig_node_get_router(orig_node);
+       if (!router_orig)
+               goto out;
  
-       orig_tq_avg = orig_node->router->tq_avg;
+       gw_tq_avg = router_gw->tq_avg;
+       orig_tq_avg = router_orig->tq_avg;
  
        /* the TQ value has to be better */
        if (orig_tq_avg < gw_tq_avg)
                "Restarting gateway selection: better gateway found (tq curr: "
                "%i, tq new: %i)\n",
                gw_tq_avg, orig_tq_avg);
-       goto deselect;
  
- out_rcu:
-       rcu_read_unlock();
-       goto out;
- deselect_rcu:
-       rcu_read_unlock();
  deselect:
        gw_deselect(bat_priv);
  out:
+       if (curr_gw_orig)
+               orig_node_free_ref(curr_gw_orig);
+       if (router_gw)
+               neigh_node_free_ref(router_gw);
+       if (router_orig)
+               neigh_node_free_ref(router_orig);
        return;
  }
  
@@@ -283,7 -308,15 +300,15 @@@ void gw_node_update(struct bat_priv *ba
                    struct orig_node *orig_node, uint8_t new_gwflags)
  {
        struct hlist_node *node;
-       struct gw_node *gw_node;
+       struct gw_node *gw_node, *curr_gw;
+       /**
+        * Note: We don't need a NULL check here, since curr_gw never gets
+        * dereferenced. If curr_gw is NULL we also should not exit as we may
+        * have this gateway in our list (duplication check!) even though we
+        * have no currently selected gateway.
+        */
+       curr_gw = gw_get_selected_gw_node(bat_priv);
  
        rcu_read_lock();
        hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
                                "Gateway %pM removed from gateway list\n",
                                orig_node->orig);
  
-                       if (gw_node == rcu_dereference(bat_priv->curr_gw)) {
-                               rcu_read_unlock();
-                               gw_deselect(bat_priv);
-                               return;
-                       }
+                       if (gw_node == curr_gw)
+                               goto deselect;
                }
  
-               rcu_read_unlock();
-               return;
+               goto unlock;
        }
-       rcu_read_unlock();
  
        if (new_gwflags == 0)
-               return;
+               goto unlock;
  
        gw_node_add(bat_priv, orig_node, new_gwflags);
+       goto unlock;
+ deselect:
+       gw_deselect(bat_priv);
+ unlock:
+       rcu_read_unlock();
+       if (curr_gw)
+               gw_node_free_ref(curr_gw);
  }
  
  void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node)
  
  void gw_node_purge(struct bat_priv *bat_priv)
  {
-       struct gw_node *gw_node;
+       struct gw_node *gw_node, *curr_gw;
        struct hlist_node *node, *node_tmp;
        unsigned long timeout = 2 * PURGE_TIMEOUT * HZ;
+       char do_deselect = 0;
+       curr_gw = gw_get_selected_gw_node(bat_priv);
  
        spin_lock_bh(&bat_priv->gw_list_lock);
  
                    atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE)
                        continue;
  
-               if (rcu_dereference(bat_priv->curr_gw) == gw_node)
-                       gw_deselect(bat_priv);
+               if (curr_gw == gw_node)
+                       do_deselect = 1;
  
                hlist_del_rcu(&gw_node->list);
                gw_node_free_ref(gw_node);
        }
  
        spin_unlock_bh(&bat_priv->gw_list_lock);
+       /* gw_deselect() needs to acquire the gw_list_lock */
+       if (do_deselect)
+               gw_deselect(bat_priv);
+       if (curr_gw)
+               gw_node_free_ref(curr_gw);
  }
  
+ /**
+  * fails if orig_node has no router
+  */
  static int _write_buffer_text(struct bat_priv *bat_priv,
                              struct seq_file *seq, struct gw_node *gw_node)
  {
        struct gw_node *curr_gw;
-       int down, up, ret;
+       struct neigh_node *router;
+       int down, up, ret = -1;
  
        gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, &down, &up);
  
-       rcu_read_lock();
-       curr_gw = rcu_dereference(bat_priv->curr_gw);
+       router = orig_node_get_router(gw_node->orig_node);
+       if (!router)
+               goto out;
  
-       ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n",
-                      (curr_gw == gw_node ? "=>" : "  "),
-                      gw_node->orig_node->orig,
-                      gw_node->orig_node->router->tq_avg,
-                      gw_node->orig_node->router->addr,
-                      gw_node->orig_node->router->if_incoming->net_dev->name,
-                      gw_node->orig_node->gw_flags,
-                      (down > 2048 ? down / 1024 : down),
-                      (down > 2048 ? "MBit" : "KBit"),
-                      (up > 2048 ? up / 1024 : up),
-                      (up > 2048 ? "MBit" : "KBit"));
+       curr_gw = gw_get_selected_gw_node(bat_priv);
  
-       rcu_read_unlock();
+       ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n",
+                        (curr_gw == gw_node ? "=>" : "  "),
+                        gw_node->orig_node->orig,
+                        router->tq_avg, router->addr,
+                        router->if_incoming->net_dev->name,
+                        gw_node->orig_node->gw_flags,
+                        (down > 2048 ? down / 1024 : down),
+                        (down > 2048 ? "MBit" : "KBit"),
+                        (up > 2048 ? up / 1024 : up),
+                        (up > 2048 ? "MBit" : "KBit"));
+       neigh_node_free_ref(router);
+       if (curr_gw)
+               gw_node_free_ref(curr_gw);
+ out:
        return ret;
  }
  
@@@ -384,40 -439,42 +431,42 @@@ int gw_client_seq_print_text(struct seq
  {
        struct net_device *net_dev = (struct net_device *)seq->private;
        struct bat_priv *bat_priv = netdev_priv(net_dev);
+       struct hard_iface *primary_if;
        struct gw_node *gw_node;
        struct hlist_node *node;
-       int gw_count = 0;
-       if (!bat_priv->primary_if) {
+       int gw_count = 0, ret = 0;
  
-               return seq_printf(seq, "BATMAN mesh %s disabled - please "
-                                 "specify interfaces to enable it\n",
-                                 net_dev->name);
+       primary_if = primary_if_get_selected(bat_priv);
+       if (!primary_if) {
+               ret = seq_printf(seq, "BATMAN mesh %s disabled - please "
+                                "specify interfaces to enable it\n",
+                                net_dev->name);
+               goto out;
        }
  
-       if (bat_priv->primary_if->if_status != IF_ACTIVE) {
-               return seq_printf(seq, "BATMAN mesh %s disabled - "
-                                      "primary interface not active\n",
-                                      net_dev->name);
+       if (primary_if->if_status != IF_ACTIVE) {
+               ret = seq_printf(seq, "BATMAN mesh %s disabled - "
+                                "primary interface not active\n",
+                                net_dev->name);
+               goto out;
        }
  
        seq_printf(seq, "      %-12s (%s/%i) %17s [%10s]: gw_class ... "
                   "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n",
                   "Gateway", "#", TQ_MAX_VALUE, "Nexthop",
                   "outgoingIF", SOURCE_VERSION, REVISION_VERSION_STR,
-                  bat_priv->primary_if->net_dev->name,
-                  bat_priv->primary_if->net_dev->dev_addr, net_dev->name);
+                  primary_if->net_dev->name,
+                  primary_if->net_dev->dev_addr, net_dev->name);
  
        rcu_read_lock();
        hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
                if (gw_node->deleted)
                        continue;
  
-               if (!gw_node->orig_node->router)
+               /* fails if orig_node has no router */
+               if (_write_buffer_text(bat_priv, seq, gw_node) < 0)
                        continue;
  
-               _write_buffer_text(bat_priv, seq, gw_node);
                gw_count++;
        }
        rcu_read_unlock();
        if (gw_count == 0)
                seq_printf(seq, "No gateways in range ...\n");
  
-       return 0;
+ out:
+       if (primary_if)
+               hardif_free_ref(primary_if);
+       return ret;
  }
  
  int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
        struct iphdr *iphdr;
        struct ipv6hdr *ipv6hdr;
        struct udphdr *udphdr;
+       struct gw_node *curr_gw;
        unsigned int header_len = 0;
  
        if (atomic_read(&bat_priv->gw_mode) == GW_MODE_OFF)
        if (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER)
                return -1;
  
-       rcu_read_lock();
-       if (!rcu_dereference(bat_priv->curr_gw)) {
-               rcu_read_unlock();
+       curr_gw = gw_get_selected_gw_node(bat_priv);
+       if (!curr_gw)
                return 0;
-       }
-       rcu_read_unlock();
  
+       if (curr_gw)
+               gw_node_free_ref(curr_gw);
        return 1;
  }
@@@ -19,8 -19,6 +19,6 @@@
   *
   */
  
- /* increase the reference counter for this originator */
  #include "main.h"
  #include "originator.h"
  #include "hash.h"
@@@ -56,12 -54,35 +54,27 @@@ err
        return 0;
  }
  
 -static void neigh_node_free_rcu(struct rcu_head *rcu)
 -{
 -      struct neigh_node *neigh_node;
 -
 -      neigh_node = container_of(rcu, struct neigh_node, rcu);
 -      kfree(neigh_node);
 -}
 -
  void neigh_node_free_ref(struct neigh_node *neigh_node)
  {
        if (atomic_dec_and_test(&neigh_node->refcount))
 -              call_rcu(&neigh_node->rcu, neigh_node_free_rcu);
 +              kfree_rcu(neigh_node, rcu);
  }
  
+ /* increases the refcounter of a found router */
+ struct neigh_node *orig_node_get_router(struct orig_node *orig_node)
+ {
+       struct neigh_node *router;
+       rcu_read_lock();
+       router = rcu_dereference(orig_node->router);
+       if (router && !atomic_inc_not_zero(&router->refcount))
+               router = NULL;
+       rcu_read_unlock();
+       return router;
+ }
  struct neigh_node *create_neighbor(struct orig_node *orig_node,
                                   struct orig_node *orig_neigh_node,
                                   uint8_t *neigh,
  
        INIT_HLIST_NODE(&neigh_node->list);
        INIT_LIST_HEAD(&neigh_node->bonding_list);
+       spin_lock_init(&neigh_node->tq_lock);
  
        memcpy(neigh_node->addr, neigh, ETH_ALEN);
        neigh_node->orig_node = orig_neigh_node;
@@@ -120,7 -142,7 +134,7 @@@ static void orig_node_free_rcu(struct r
        spin_unlock_bh(&orig_node->neigh_list_lock);
  
        frag_list_free(&orig_node->frag_list);
-       hna_global_del_orig(orig_node->bat_priv, orig_node,
+       tt_global_del_orig(orig_node->bat_priv, orig_node,
                            "originator timed out");
  
        kfree(orig_node->bcast_own);
@@@ -198,7 -220,7 +212,7 @@@ struct orig_node *get_orig_node(struct 
        orig_node->bat_priv = bat_priv;
        memcpy(orig_node->orig, addr, ETH_ALEN);
        orig_node->router = NULL;
-       orig_node->hna_buff = NULL;
+       orig_node->tt_buff = NULL;
        orig_node->bcast_seqno_reset = jiffies - 1
                                        - msecs_to_jiffies(RESET_PROTECTION_MS);
        orig_node->batman_seqno_reset = jiffies - 1
@@@ -309,8 -331,8 +323,8 @@@ static bool purge_orig_node(struct bat_
                                                        &best_neigh_node)) {
                        update_routes(bat_priv, orig_node,
                                      best_neigh_node,
-                                     orig_node->hna_buff,
-                                     orig_node->hna_buff_len);
+                                     orig_node->tt_buff,
+                                     orig_node->tt_buff_len);
                }
        }
  
@@@ -381,29 -403,34 +395,34 @@@ int orig_seq_print_text(struct seq_fil
        struct hashtable_t *hash = bat_priv->orig_hash;
        struct hlist_node *node, *node_tmp;
        struct hlist_head *head;
+       struct hard_iface *primary_if;
        struct orig_node *orig_node;
-       struct neigh_node *neigh_node;
+       struct neigh_node *neigh_node, *neigh_node_tmp;
        int batman_count = 0;
        int last_seen_secs;
        int last_seen_msecs;
-       int i;
+       int i, ret = 0;
+       primary_if = primary_if_get_selected(bat_priv);
  
-       if ((!bat_priv->primary_if) ||
-           (bat_priv->primary_if->if_status != IF_ACTIVE)) {
-               if (!bat_priv->primary_if)
-                       return seq_printf(seq, "BATMAN mesh %s disabled - "
-                                    "please specify interfaces to enable it\n",
-                                    net_dev->name);
+       if (!primary_if) {
+               ret = seq_printf(seq, "BATMAN mesh %s disabled - "
+                                "please specify interfaces to enable it\n",
+                                net_dev->name);
+               goto out;
+       }
  
-               return seq_printf(seq, "BATMAN mesh %s "
-                                 "disabled - primary interface not active\n",
-                                 net_dev->name);
+       if (primary_if->if_status != IF_ACTIVE) {
+               ret = seq_printf(seq, "BATMAN mesh %s "
+                                "disabled - primary interface not active\n",
+                                net_dev->name);
+               goto out;
        }
  
        seq_printf(seq, "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n",
                   SOURCE_VERSION, REVISION_VERSION_STR,
-                  bat_priv->primary_if->net_dev->name,
-                  bat_priv->primary_if->net_dev->dev_addr, net_dev->name);
+                  primary_if->net_dev->name,
+                  primary_if->net_dev->dev_addr, net_dev->name);
        seq_printf(seq, "  %-15s %s (%s/%i) %17s [%10s]: %20s ...\n",
                   "Originator", "last-seen", "#", TQ_MAX_VALUE, "Nexthop",
                   "outgoingIF", "Potential nexthops");
  
                rcu_read_lock();
                hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) {
-                       if (!orig_node->router)
+                       neigh_node = orig_node_get_router(orig_node);
+                       if (!neigh_node)
                                continue;
  
-                       if (orig_node->router->tq_avg == 0)
-                               continue;
+                       if (neigh_node->tq_avg == 0)
+                               goto next;
  
                        last_seen_secs = jiffies_to_msecs(jiffies -
                                                orig_node->last_valid) / 1000;
                        last_seen_msecs = jiffies_to_msecs(jiffies -
                                                orig_node->last_valid) % 1000;
  
-                       neigh_node = orig_node->router;
                        seq_printf(seq, "%pM %4i.%03is   (%3i) %pM [%10s]:",
                                   orig_node->orig, last_seen_secs,
                                   last_seen_msecs, neigh_node->tq_avg,
                                   neigh_node->addr,
                                   neigh_node->if_incoming->net_dev->name);
  
-                       hlist_for_each_entry_rcu(neigh_node, node_tmp,
+                       hlist_for_each_entry_rcu(neigh_node_tmp, node_tmp,
                                                 &orig_node->neigh_list, list) {
-                               seq_printf(seq, " %pM (%3i)", neigh_node->addr,
-                                               neigh_node->tq_avg);
+                               seq_printf(seq, " %pM (%3i)",
+                                          neigh_node_tmp->addr,
+                                          neigh_node_tmp->tq_avg);
                        }
  
                        seq_printf(seq, "\n");
                        batman_count++;
+ next:
+                       neigh_node_free_ref(neigh_node);
                }
                rcu_read_unlock();
        }
  
-       if ((batman_count == 0))
+       if (batman_count == 0)
                seq_printf(seq, "No batman nodes in range ...\n");
  
-       return 0;
+ out:
+       if (primary_if)
+               hardif_free_ref(primary_if);
+       return ret;
  }
  
  static int orig_node_add_if(struct orig_node *orig_node, int max_if_num)
@@@ -43,8 -43,6 +43,6 @@@ static void bat_get_drvinfo(struct net_
  static u32 bat_get_msglevel(struct net_device *dev);
  static void bat_set_msglevel(struct net_device *dev, u32 value);
  static u32 bat_get_link(struct net_device *dev);
- static u32 bat_get_rx_csum(struct net_device *dev);
- static int bat_set_rx_csum(struct net_device *dev, u32 data);
  
  static const struct ethtool_ops bat_ethtool_ops = {
        .get_settings = bat_get_settings,
@@@ -52,8 -50,6 +50,6 @@@
        .get_msglevel = bat_get_msglevel,
        .set_msglevel = bat_set_msglevel,
        .get_link = bat_get_link,
-       .get_rx_csum = bat_get_rx_csum,
-       .set_rx_csum = bat_set_rx_csum
  };
  
  int my_skb_head_push(struct sk_buff *skb, unsigned int len)
        return 0;
  }
  
 -static void softif_neigh_free_rcu(struct rcu_head *rcu)
 -{
 -      struct softif_neigh *softif_neigh;
 -
 -      softif_neigh = container_of(rcu, struct softif_neigh, rcu);
 -      kfree(softif_neigh);
 -}
 -
  static void softif_neigh_free_ref(struct softif_neigh *softif_neigh)
  {
        if (atomic_dec_and_test(&softif_neigh->refcount))
 -              call_rcu(&softif_neigh->rcu, softif_neigh_free_rcu);
 +              kfree_rcu(softif_neigh, rcu);
  }
  
void softif_neigh_purge(struct bat_priv *bat_priv)
static void softif_neigh_vid_free_rcu(struct rcu_head *rcu)
  {
-       struct softif_neigh *softif_neigh, *softif_neigh_tmp;
+       struct softif_neigh_vid *softif_neigh_vid;
+       struct softif_neigh *softif_neigh;
        struct hlist_node *node, *node_tmp;
+       struct bat_priv *bat_priv;
  
-       spin_lock_bh(&bat_priv->softif_neigh_lock);
+       softif_neigh_vid = container_of(rcu, struct softif_neigh_vid, rcu);
+       bat_priv = softif_neigh_vid->bat_priv;
  
+       spin_lock_bh(&bat_priv->softif_neigh_lock);
        hlist_for_each_entry_safe(softif_neigh, node, node_tmp,
-                                 &bat_priv->softif_neigh_list, list) {
+                                 &softif_neigh_vid->softif_neigh_list, list) {
+               hlist_del_rcu(&softif_neigh->list);
+               softif_neigh_free_ref(softif_neigh);
+       }
+       spin_unlock_bh(&bat_priv->softif_neigh_lock);
  
-               if ((!time_after(jiffies, softif_neigh->last_seen +
-                               msecs_to_jiffies(SOFTIF_NEIGH_TIMEOUT))) &&
-                   (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE))
-                       continue;
+       kfree(softif_neigh_vid);
+ }
  
-               hlist_del_rcu(&softif_neigh->list);
+ static void softif_neigh_vid_free_ref(struct softif_neigh_vid *softif_neigh_vid)
+ {
+       if (atomic_dec_and_test(&softif_neigh_vid->refcount))
+               call_rcu(&softif_neigh_vid->rcu, softif_neigh_vid_free_rcu);
+ }
  
-               if (bat_priv->softif_neigh == softif_neigh) {
-                       bat_dbg(DBG_ROUTES, bat_priv,
-                                "Current mesh exit point '%pM' vanished "
-                                "(vid: %d).\n",
-                                softif_neigh->addr, softif_neigh->vid);
-                       softif_neigh_tmp = bat_priv->softif_neigh;
-                       bat_priv->softif_neigh = NULL;
-                       softif_neigh_free_ref(softif_neigh_tmp);
-               }
+ static struct softif_neigh_vid *softif_neigh_vid_get(struct bat_priv *bat_priv,
+                                                    short vid)
+ {
+       struct softif_neigh_vid *softif_neigh_vid;
+       struct hlist_node *node;
  
-               softif_neigh_free_ref(softif_neigh);
+       rcu_read_lock();
+       hlist_for_each_entry_rcu(softif_neigh_vid, node,
+                                &bat_priv->softif_neigh_vids, list) {
+               if (softif_neigh_vid->vid != vid)
+                       continue;
+               if (!atomic_inc_not_zero(&softif_neigh_vid->refcount))
+                       continue;
+               goto out;
        }
  
-       spin_unlock_bh(&bat_priv->softif_neigh_lock);
+       softif_neigh_vid = kzalloc(sizeof(struct softif_neigh_vid),
+                                  GFP_ATOMIC);
+       if (!softif_neigh_vid)
+               goto out;
+       softif_neigh_vid->vid = vid;
+       softif_neigh_vid->bat_priv = bat_priv;
+       /* initialize with 2 - caller decrements counter by one */
+       atomic_set(&softif_neigh_vid->refcount, 2);
+       INIT_HLIST_HEAD(&softif_neigh_vid->softif_neigh_list);
+       INIT_HLIST_NODE(&softif_neigh_vid->list);
+       spin_lock_bh(&bat_priv->softif_neigh_vid_lock);
+       hlist_add_head_rcu(&softif_neigh_vid->list,
+                          &bat_priv->softif_neigh_vids);
+       spin_unlock_bh(&bat_priv->softif_neigh_vid_lock);
+ out:
+       rcu_read_unlock();
+       return softif_neigh_vid;
  }
  
  static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv,
                                             uint8_t *addr, short vid)
  {
-       struct softif_neigh *softif_neigh;
+       struct softif_neigh_vid *softif_neigh_vid;
+       struct softif_neigh *softif_neigh = NULL;
        struct hlist_node *node;
  
+       softif_neigh_vid = softif_neigh_vid_get(bat_priv, vid);
+       if (!softif_neigh_vid)
+               goto out;
        rcu_read_lock();
        hlist_for_each_entry_rcu(softif_neigh, node,
-                                &bat_priv->softif_neigh_list, list) {
+                                &softif_neigh_vid->softif_neigh_list,
+                                list) {
                if (!compare_eth(softif_neigh->addr, addr))
                        continue;
  
-               if (softif_neigh->vid != vid)
-                       continue;
                if (!atomic_inc_not_zero(&softif_neigh->refcount))
                        continue;
  
                softif_neigh->last_seen = jiffies;
-               goto out;
+               goto unlock;
        }
  
        softif_neigh = kzalloc(sizeof(struct softif_neigh), GFP_ATOMIC);
        if (!softif_neigh)
-               goto out;
+               goto unlock;
  
        memcpy(softif_neigh->addr, addr, ETH_ALEN);
-       softif_neigh->vid = vid;
        softif_neigh->last_seen = jiffies;
        /* initialize with 2 - caller decrements counter by one */
        atomic_set(&softif_neigh->refcount, 2);
  
        INIT_HLIST_NODE(&softif_neigh->list);
        spin_lock_bh(&bat_priv->softif_neigh_lock);
-       hlist_add_head_rcu(&softif_neigh->list, &bat_priv->softif_neigh_list);
+       hlist_add_head_rcu(&softif_neigh->list,
+                          &softif_neigh_vid->softif_neigh_list);
        spin_unlock_bh(&bat_priv->softif_neigh_lock);
  
+ unlock:
+       rcu_read_unlock();
  out:
+       if (softif_neigh_vid)
+               softif_neigh_vid_free_ref(softif_neigh_vid);
+       return softif_neigh;
+ }
+ static struct softif_neigh *softif_neigh_get_selected(
+                               struct softif_neigh_vid *softif_neigh_vid)
+ {
+       struct softif_neigh *softif_neigh;
+       rcu_read_lock();
+       softif_neigh = rcu_dereference(softif_neigh_vid->softif_neigh);
+       if (softif_neigh && !atomic_inc_not_zero(&softif_neigh->refcount))
+               softif_neigh = NULL;
        rcu_read_unlock();
        return softif_neigh;
  }
  
+ static struct softif_neigh *softif_neigh_vid_get_selected(
+                                               struct bat_priv *bat_priv,
+                                               short vid)
+ {
+       struct softif_neigh_vid *softif_neigh_vid;
+       struct softif_neigh *softif_neigh = NULL;
+       softif_neigh_vid = softif_neigh_vid_get(bat_priv, vid);
+       if (!softif_neigh_vid)
+               goto out;
+       softif_neigh = softif_neigh_get_selected(softif_neigh_vid);
+ out:
+       if (softif_neigh_vid)
+               softif_neigh_vid_free_ref(softif_neigh_vid);
+       return softif_neigh;
+ }
+ static void softif_neigh_vid_select(struct bat_priv *bat_priv,
+                                   struct softif_neigh *new_neigh,
+                                   short vid)
+ {
+       struct softif_neigh_vid *softif_neigh_vid;
+       struct softif_neigh *curr_neigh;
+       softif_neigh_vid = softif_neigh_vid_get(bat_priv, vid);
+       if (!softif_neigh_vid)
+               goto out;
+       spin_lock_bh(&bat_priv->softif_neigh_lock);
+       if (new_neigh && !atomic_inc_not_zero(&new_neigh->refcount))
+               new_neigh = NULL;
+       curr_neigh = softif_neigh_vid->softif_neigh;
+       rcu_assign_pointer(softif_neigh_vid->softif_neigh, new_neigh);
+       if ((curr_neigh) && (!new_neigh))
+               bat_dbg(DBG_ROUTES, bat_priv,
+                       "Removing mesh exit point on vid: %d (prev: %pM).\n",
+                       vid, curr_neigh->addr);
+       else if ((curr_neigh) && (new_neigh))
+               bat_dbg(DBG_ROUTES, bat_priv,
+                       "Changing mesh exit point on vid: %d from %pM "
+                       "to %pM.\n", vid, curr_neigh->addr, new_neigh->addr);
+       else if ((!curr_neigh) && (new_neigh))
+               bat_dbg(DBG_ROUTES, bat_priv,
+                       "Setting mesh exit point on vid: %d to %pM.\n",
+                       vid, new_neigh->addr);
+       if (curr_neigh)
+               softif_neigh_free_ref(curr_neigh);
+       spin_unlock_bh(&bat_priv->softif_neigh_lock);
+ out:
+       if (softif_neigh_vid)
+               softif_neigh_vid_free_ref(softif_neigh_vid);
+ }
+ static void softif_neigh_vid_deselect(struct bat_priv *bat_priv,
+                                     struct softif_neigh_vid *softif_neigh_vid)
+ {
+       struct softif_neigh *curr_neigh;
+       struct softif_neigh *softif_neigh = NULL, *softif_neigh_tmp;
+       struct hard_iface *primary_if = NULL;
+       struct hlist_node *node;
+       primary_if = primary_if_get_selected(bat_priv);
+       if (!primary_if)
+               goto out;
+       /* find new softif_neigh immediately to avoid temporary loops */
+       rcu_read_lock();
+       curr_neigh = rcu_dereference(softif_neigh_vid->softif_neigh);
+       hlist_for_each_entry_rcu(softif_neigh_tmp, node,
+                                &softif_neigh_vid->softif_neigh_list,
+                                list) {
+               if (softif_neigh_tmp == curr_neigh)
+                       continue;
+               /* we got a neighbor but its mac is 'bigger' than ours  */
+               if (memcmp(primary_if->net_dev->dev_addr,
+                          softif_neigh_tmp->addr, ETH_ALEN) < 0)
+                       continue;
+               if (!atomic_inc_not_zero(&softif_neigh_tmp->refcount))
+                       continue;
+               softif_neigh = softif_neigh_tmp;
+               goto unlock;
+       }
+ unlock:
+       rcu_read_unlock();
+ out:
+       softif_neigh_vid_select(bat_priv, softif_neigh, softif_neigh_vid->vid);
+       if (primary_if)
+               hardif_free_ref(primary_if);
+       if (softif_neigh)
+               softif_neigh_free_ref(softif_neigh);
+ }
  int softif_neigh_seq_print_text(struct seq_file *seq, void *offset)
  {
        struct net_device *net_dev = (struct net_device *)seq->private;
        struct bat_priv *bat_priv = netdev_priv(net_dev);
+       struct softif_neigh_vid *softif_neigh_vid;
        struct softif_neigh *softif_neigh;
-       struct hlist_node *node;
+       struct hard_iface *primary_if;
+       struct hlist_node *node, *node_tmp;
+       struct softif_neigh *curr_softif_neigh;
+       int ret = 0, last_seen_secs, last_seen_msecs;
+       primary_if = primary_if_get_selected(bat_priv);
+       if (!primary_if) {
+               ret = seq_printf(seq, "BATMAN mesh %s disabled - "
+                                "please specify interfaces to enable it\n",
+                                net_dev->name);
+               goto out;
+       }
  
-       if (!bat_priv->primary_if) {
-               return seq_printf(seq, "BATMAN mesh %s disabled - "
-                              "please specify interfaces to enable it\n",
-                              net_dev->name);
+       if (primary_if->if_status != IF_ACTIVE) {
+               ret = seq_printf(seq, "BATMAN mesh %s "
+                                "disabled - primary interface not active\n",
+                                net_dev->name);
+               goto out;
        }
  
        seq_printf(seq, "Softif neighbor list (%s)\n", net_dev->name);
  
        rcu_read_lock();
-       hlist_for_each_entry_rcu(softif_neigh, node,
-                                &bat_priv->softif_neigh_list, list)
-               seq_printf(seq, "%s %pM (vid: %d)\n",
-                               bat_priv->softif_neigh == softif_neigh
-                               ? "=>" : "  ", softif_neigh->addr,
-                               softif_neigh->vid);
+       hlist_for_each_entry_rcu(softif_neigh_vid, node,
+                                &bat_priv->softif_neigh_vids, list) {
+               seq_printf(seq, "     %-15s %s on vid: %d\n",
+                          "Originator", "last-seen", softif_neigh_vid->vid);
+               curr_softif_neigh = softif_neigh_get_selected(softif_neigh_vid);
+               hlist_for_each_entry_rcu(softif_neigh, node_tmp,
+                                        &softif_neigh_vid->softif_neigh_list,
+                                        list) {
+                       last_seen_secs = jiffies_to_msecs(jiffies -
+                                               softif_neigh->last_seen) / 1000;
+                       last_seen_msecs = jiffies_to_msecs(jiffies -
+                                               softif_neigh->last_seen) % 1000;
+                       seq_printf(seq, "%s %pM  %3i.%03is\n",
+                                  curr_softif_neigh == softif_neigh
+                                  ? "=>" : "  ", softif_neigh->addr,
+                                  last_seen_secs, last_seen_msecs);
+               }
+               if (curr_softif_neigh)
+                       softif_neigh_free_ref(curr_softif_neigh);
+               seq_printf(seq, "\n");
+       }
        rcu_read_unlock();
  
-       return 0;
+ out:
+       if (primary_if)
+               hardif_free_ref(primary_if);
+       return ret;
+ }
+ void softif_neigh_purge(struct bat_priv *bat_priv)
+ {
+       struct softif_neigh *softif_neigh, *curr_softif_neigh;
+       struct softif_neigh_vid *softif_neigh_vid;
+       struct hlist_node *node, *node_tmp, *node_tmp2;
+       char do_deselect;
+       rcu_read_lock();
+       hlist_for_each_entry_rcu(softif_neigh_vid, node,
+                                &bat_priv->softif_neigh_vids, list) {
+               if (!atomic_inc_not_zero(&softif_neigh_vid->refcount))
+                       continue;
+               curr_softif_neigh = softif_neigh_get_selected(softif_neigh_vid);
+               do_deselect = 0;
+               spin_lock_bh(&bat_priv->softif_neigh_lock);
+               hlist_for_each_entry_safe(softif_neigh, node_tmp, node_tmp2,
+                                         &softif_neigh_vid->softif_neigh_list,
+                                         list) {
+                       if ((!time_after(jiffies, softif_neigh->last_seen +
+                               msecs_to_jiffies(SOFTIF_NEIGH_TIMEOUT))) &&
+                           (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE))
+                               continue;
+                       if (curr_softif_neigh == softif_neigh) {
+                               bat_dbg(DBG_ROUTES, bat_priv,
+                                       "Current mesh exit point on vid: %d "
+                                       "'%pM' vanished.\n",
+                                       softif_neigh_vid->vid,
+                                       softif_neigh->addr);
+                               do_deselect = 1;
+                       }
+                       hlist_del_rcu(&softif_neigh->list);
+                       softif_neigh_free_ref(softif_neigh);
+               }
+               spin_unlock_bh(&bat_priv->softif_neigh_lock);
+               /* soft_neigh_vid_deselect() needs to acquire the
+                * softif_neigh_lock */
+               if (do_deselect)
+                       softif_neigh_vid_deselect(bat_priv, softif_neigh_vid);
+               if (curr_softif_neigh)
+                       softif_neigh_free_ref(curr_softif_neigh);
+               softif_neigh_vid_free_ref(softif_neigh_vid);
+       }
+       rcu_read_unlock();
+       spin_lock_bh(&bat_priv->softif_neigh_vid_lock);
+       hlist_for_each_entry_safe(softif_neigh_vid, node, node_tmp,
+                                 &bat_priv->softif_neigh_vids, list) {
+               if (!hlist_empty(&softif_neigh_vid->softif_neigh_list))
+                       continue;
+               hlist_del_rcu(&softif_neigh_vid->list);
+               softif_neigh_vid_free_ref(softif_neigh_vid);
+       }
+       spin_unlock_bh(&bat_priv->softif_neigh_vid_lock);
  }
  
  static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev,
        struct bat_priv *bat_priv = netdev_priv(dev);
        struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
        struct batman_packet *batman_packet;
-       struct softif_neigh *softif_neigh, *softif_neigh_tmp;
+       struct softif_neigh *softif_neigh = NULL;
+       struct hard_iface *primary_if = NULL;
+       struct softif_neigh *curr_softif_neigh = NULL;
  
        if (ntohs(ethhdr->h_proto) == ETH_P_8021Q)
                batman_packet = (struct batman_packet *)
                batman_packet = (struct batman_packet *)(skb->data + ETH_HLEN);
  
        if (batman_packet->version != COMPAT_VERSION)
-               goto err;
+               goto out;
  
        if (batman_packet->packet_type != BAT_PACKET)
-               goto err;
+               goto out;
  
        if (!(batman_packet->flags & PRIMARIES_FIRST_HOP))
-               goto err;
+               goto out;
  
        if (is_my_mac(batman_packet->orig))
-               goto err;
+               goto out;
  
        softif_neigh = softif_neigh_get(bat_priv, batman_packet->orig, vid);
        if (!softif_neigh)
-               goto err;
+               goto out;
  
-       if (bat_priv->softif_neigh == softif_neigh)
+       curr_softif_neigh = softif_neigh_vid_get_selected(bat_priv, vid);
+       if (curr_softif_neigh == softif_neigh)
+               goto out;
+       primary_if = primary_if_get_selected(bat_priv);
+       if (!primary_if)
                goto out;
  
        /* we got a neighbor but its mac is 'bigger' than ours  */
-       if (memcmp(bat_priv->primary_if->net_dev->dev_addr,
+       if (memcmp(primary_if->net_dev->dev_addr,
                   softif_neigh->addr, ETH_ALEN) < 0)
                goto out;
  
-       /* switch to new 'smallest neighbor' */
-       if ((bat_priv->softif_neigh) &&
-           (memcmp(softif_neigh->addr, bat_priv->softif_neigh->addr,
-                                                       ETH_ALEN) < 0)) {
-               bat_dbg(DBG_ROUTES, bat_priv,
-                       "Changing mesh exit point from %pM (vid: %d) "
-                       "to %pM (vid: %d).\n",
-                        bat_priv->softif_neigh->addr,
-                        bat_priv->softif_neigh->vid,
-                        softif_neigh->addr, softif_neigh->vid);
-               softif_neigh_tmp = bat_priv->softif_neigh;
-               bat_priv->softif_neigh = softif_neigh;
-               softif_neigh_free_ref(softif_neigh_tmp);
-               /* we need to hold the additional reference */
-               goto err;
-       }
        /* close own batX device and use softif_neigh as exit node */
-       if ((!bat_priv->softif_neigh) &&
-           (memcmp(softif_neigh->addr,
-                   bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN) < 0)) {
-               bat_dbg(DBG_ROUTES, bat_priv,
-                       "Setting mesh exit point to %pM (vid: %d).\n",
-                       softif_neigh->addr, softif_neigh->vid);
-               bat_priv->softif_neigh = softif_neigh;
-               /* we need to hold the additional reference */
-               goto err;
+       if (!curr_softif_neigh) {
+               softif_neigh_vid_select(bat_priv, softif_neigh, vid);
+               goto out;
        }
  
+       /* switch to new 'smallest neighbor' */
+       if (memcmp(softif_neigh->addr, curr_softif_neigh->addr, ETH_ALEN) < 0)
+               softif_neigh_vid_select(bat_priv, softif_neigh, vid);
  out:
-       softif_neigh_free_ref(softif_neigh);
- err:
        kfree_skb(skb);
+       if (softif_neigh)
+               softif_neigh_free_ref(softif_neigh);
+       if (curr_softif_neigh)
+               softif_neigh_free_ref(curr_softif_neigh);
+       if (primary_if)
+               hardif_free_ref(primary_if);
        return;
  }
  
@@@ -285,11 -539,11 +531,11 @@@ static int interface_set_mac_addr(struc
        if (!is_valid_ether_addr(addr->sa_data))
                return -EADDRNOTAVAIL;
  
-       /* only modify hna-table if it has been initialised before */
+       /* only modify transtable if it has been initialised before */
        if (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) {
-               hna_local_remove(bat_priv, dev->dev_addr,
+               tt_local_remove(bat_priv, dev->dev_addr,
                                 "mac address changed");
-               hna_local_add(dev, addr->sa_data);
+               tt_local_add(dev, addr->sa_data);
        }
  
        memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
@@@ -311,8 -565,10 +557,10 @@@ int interface_tx(struct sk_buff *skb, s
  {
        struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
        struct bat_priv *bat_priv = netdev_priv(soft_iface);
+       struct hard_iface *primary_if = NULL;
        struct bcast_packet *bcast_packet;
        struct vlan_ethhdr *vhdr;
+       struct softif_neigh *curr_softif_neigh = NULL;
        int data_len = skb->len, ret;
        short vid = -1;
        bool do_bcast = false;
         * if we have a another chosen mesh exit node in range
         * it will transport the packets to the mesh
         */
-       if ((bat_priv->softif_neigh) && (bat_priv->softif_neigh->vid == vid))
+       curr_softif_neigh = softif_neigh_vid_get_selected(bat_priv, vid);
+       if (curr_softif_neigh)
                goto dropped;
  
        /* TODO: check this for locks */
-       hna_local_add(soft_iface, ethhdr->h_source);
+       tt_local_add(soft_iface, ethhdr->h_source);
  
        if (is_multicast_ether_addr(ethhdr->h_dest)) {
                ret = gw_is_target(bat_priv, skb);
  
        /* ethernet packet should be broadcasted */
        if (do_bcast) {
-               if (!bat_priv->primary_if)
+               primary_if = primary_if_get_selected(bat_priv);
+               if (!primary_if)
                        goto dropped;
  
                if (my_skb_head_push(skb, sizeof(struct bcast_packet)) < 0)
                /* hw address of first interface is the orig mac because only
                 * this mac is known throughout the mesh */
                memcpy(bcast_packet->orig,
-                      bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
+                      primary_if->net_dev->dev_addr, ETH_ALEN);
  
                /* set broadcast sequence number */
                bcast_packet->seqno =
@@@ -402,6 -660,10 +652,10 @@@ dropped
  dropped_freed:
        bat_priv->stats.tx_dropped++;
  end:
+       if (curr_softif_neigh)
+               softif_neigh_free_ref(curr_softif_neigh);
+       if (primary_if)
+               hardif_free_ref(primary_if);
        return NETDEV_TX_OK;
  }
  
@@@ -413,6 -675,7 +667,7 @@@ void interface_rx(struct net_device *so
        struct unicast_packet *unicast_packet;
        struct ethhdr *ethhdr;
        struct vlan_ethhdr *vhdr;
+       struct softif_neigh *curr_softif_neigh = NULL;
        short vid = -1;
        int ret;
  
         * if we have a another chosen mesh exit node in range
         * it will transport the packets to the non-mesh network
         */
-       if ((bat_priv->softif_neigh) && (bat_priv->softif_neigh->vid == vid)) {
+       curr_softif_neigh = softif_neigh_vid_get_selected(bat_priv, vid);
+       if (curr_softif_neigh) {
                skb_push(skb, hdr_size);
                unicast_packet = (struct unicast_packet *)skb->data;
  
                skb_reset_mac_header(skb);
  
                memcpy(unicast_packet->dest,
-                      bat_priv->softif_neigh->addr, ETH_ALEN);
+                      curr_softif_neigh->addr, ETH_ALEN);
                ret = route_unicast_packet(skb, recv_if);
                if (ret == NET_RX_DROP)
                        goto dropped;
        soft_iface->last_rx = jiffies;
  
        netif_rx(skb);
-       return;
+       goto out;
  
  dropped:
        kfree_skb(skb);
  out:
+       if (curr_softif_neigh)
+               softif_neigh_free_ref(curr_softif_neigh);
        return;
  }
  
@@@ -516,14 -782,15 +774,15 @@@ static void interface_setup(struct net_
        dev->hard_start_xmit = interface_tx;
  #endif
        dev->destructor = free_netdev;
+       dev->tx_queue_len = 0;
  
        /**
         * can't call min_mtu, because the needed variables
         * have not been initialized yet
         */
        dev->mtu = ETH_DATA_LEN;
-       dev->hard_header_len = BAT_HEADER_LEN; /* reserve more space in the
-                                               * skbuff for our header */
+       /* reserve more space in the skbuff for our header */
+       dev->hard_header_len = BAT_HEADER_LEN;
  
        /* generate random address */
        random_ether_addr(dev_addr);
@@@ -548,7 -815,7 +807,7 @@@ struct net_device *softif_create(char *
                goto out;
        }
  
-       ret = register_netdev(soft_iface);
+       ret = register_netdevice(soft_iface);
        if (ret < 0) {
                pr_err("Unable to register the batman interface '%s': %i\n",
                       name, ret);
  
        atomic_set(&bat_priv->mesh_state, MESH_INACTIVE);
        atomic_set(&bat_priv->bcast_seqno, 1);
-       atomic_set(&bat_priv->hna_local_changed, 0);
+       atomic_set(&bat_priv->tt_local_changed, 0);
  
        bat_priv->primary_if = NULL;
        bat_priv->num_ifaces = 0;
-       bat_priv->softif_neigh = NULL;
  
        ret = sysfs_add_meshif(soft_iface);
        if (ret < 0)
@@@ -632,7 -898,7 +890,7 @@@ static int bat_get_settings(struct net_
  {
        cmd->supported = 0;
        cmd->advertising = 0;
-       cmd->speed = SPEED_10;
+       ethtool_cmd_speed_set(cmd, SPEED_10);
        cmd->duplex = DUPLEX_FULL;
        cmd->port = PORT_TP;
        cmd->phy_address = 0;
@@@ -667,12 -933,3 +925,3 @@@ static u32 bat_get_link(struct net_devi
        return 1;
  }
  
- static u32 bat_get_rx_csum(struct net_device *dev)
- {
-       return 0;
- }
- static int bat_set_rx_csum(struct net_device *dev, u32 data)
- {
-       return -EOPNOTSUPP;
- }
diff --combined net/core/dst.c
@@@ -19,7 -19,6 +19,7 @@@
  #include <linux/types.h>
  #include <net/net_namespace.h>
  #include <linux/sched.h>
 +#include <linux/prefetch.h>
  
  #include <net/dst.h>
  
@@@ -34,9 -33,6 +34,6 @@@
   * 3) This list is guarded by a mutex,
   *    so that the gc_task and dst_dev_event() can be synchronized.
   */
- #if RT_CACHE_DEBUG >= 2
- static atomic_t                        dst_total = ATOMIC_INIT(0);
- #endif
  
  /*
   * We want to keep lock & list close together
@@@ -70,10 -66,6 +67,6 @@@ static void dst_gc_task(struct work_str
        unsigned long expires = ~0L;
        struct dst_entry *dst, *next, head;
        struct dst_entry *last = &head;
- #if RT_CACHE_DEBUG >= 2
-       ktime_t time_start = ktime_get();
-       struct timespec elapsed;
- #endif
  
        mutex_lock(&dst_gc_mutex);
        next = dst_busy_list;
@@@ -147,15 -139,6 +140,6 @@@ loop
  
        spin_unlock_bh(&dst_garbage.lock);
        mutex_unlock(&dst_gc_mutex);
- #if RT_CACHE_DEBUG >= 2
-       elapsed = ktime_to_timespec(ktime_sub(ktime_get(), time_start));
-       printk(KERN_DEBUG "dst_total: %d delayed: %d work_perf: %d"
-               " expires: %lu elapsed: %lu us\n",
-               atomic_read(&dst_total), delayed, work_performed,
-               expires,
-               elapsed.tv_sec * USEC_PER_SEC +
-                 elapsed.tv_nsec / NSEC_PER_USEC);
- #endif
  }
  
  int dst_discard(struct sk_buff *skb)
@@@ -167,7 -150,8 +151,8 @@@ EXPORT_SYMBOL(dst_discard)
  
  const u32 dst_default_metrics[RTAX_MAX];
  
- void *dst_alloc(struct dst_ops *ops, int initial_ref)
+ void *dst_alloc(struct dst_ops *ops, struct net_device *dev,
+               int initial_ref, int initial_obsolete, int flags)
  {
        struct dst_entry *dst;
  
                if (ops->gc(ops))
                        return NULL;
        }
-       dst = kmem_cache_zalloc(ops->kmem_cachep, GFP_ATOMIC);
+       dst = kmem_cache_alloc(ops->kmem_cachep, GFP_ATOMIC);
        if (!dst)
                return NULL;
-       atomic_set(&dst->__refcnt, initial_ref);
+       dst->child = NULL;
+       dst->dev = dev;
+       if (dev)
+               dev_hold(dev);
        dst->ops = ops;
-       dst->lastuse = jiffies;
-       dst->path = dst;
-       dst->input = dst->output = dst_discard;
        dst_init_metrics(dst, dst_default_metrics, true);
- #if RT_CACHE_DEBUG >= 2
-       atomic_inc(&dst_total);
+       dst->expires = 0UL;
+       dst->path = dst;
+       dst->neighbour = NULL;
+       dst->hh = NULL;
+ #ifdef CONFIG_XFRM
+       dst->xfrm = NULL;
+ #endif
+       dst->input = dst_discard;
+       dst->output = dst_discard;
+       dst->error = 0;
+       dst->obsolete = initial_obsolete;
+       dst->header_len = 0;
+       dst->trailer_len = 0;
+ #ifdef CONFIG_IP_ROUTE_CLASSID
+       dst->tclassid = 0;
  #endif
+       atomic_set(&dst->__refcnt, initial_ref);
+       dst->__use = 0;
+       dst->lastuse = jiffies;
+       dst->flags = flags;
+       dst->next = NULL;
        dst_entries_add(ops, 1);
        return dst;
  }
@@@ -246,9 -248,6 +249,6 @@@ again
                dst->ops->destroy(dst);
        if (dst->dev)
                dev_put(dst->dev);
- #if RT_CACHE_DEBUG >= 2
-       atomic_dec(&dst_total);
- #endif
        kmem_cache_free(dst->ops->kmem_cachep, dst);
  
        dst = child;
diff --combined net/core/net-sysfs.c
@@@ -28,6 -28,7 +28,7 @@@
  static const char fmt_hex[] = "%#x\n";
  static const char fmt_long_hex[] = "%#lx\n";
  static const char fmt_dec[] = "%d\n";
+ static const char fmt_udec[] = "%u\n";
  static const char fmt_ulong[] = "%lu\n";
  static const char fmt_u64[] = "%llu\n";
  
@@@ -145,13 -146,10 +146,10 @@@ static ssize_t show_speed(struct devic
        if (!rtnl_trylock())
                return restart_syscall();
  
-       if (netif_running(netdev) &&
-           netdev->ethtool_ops &&
-           netdev->ethtool_ops->get_settings) {
-               struct ethtool_cmd cmd = { ETHTOOL_GSET };
-               if (!netdev->ethtool_ops->get_settings(netdev, &cmd))
-                       ret = sprintf(buf, fmt_dec, ethtool_cmd_speed(&cmd));
+       if (netif_running(netdev)) {
+               struct ethtool_cmd cmd;
+               if (!dev_ethtool_get_settings(netdev, &cmd))
+                       ret = sprintf(buf, fmt_udec, ethtool_cmd_speed(&cmd));
        }
        rtnl_unlock();
        return ret;
@@@ -166,13 -164,11 +164,11 @@@ static ssize_t show_duplex(struct devic
        if (!rtnl_trylock())
                return restart_syscall();
  
-       if (netif_running(netdev) &&
-           netdev->ethtool_ops &&
-           netdev->ethtool_ops->get_settings) {
-               struct ethtool_cmd cmd = { ETHTOOL_GSET };
-               if (!netdev->ethtool_ops->get_settings(netdev, &cmd))
-                       ret = sprintf(buf, "%s\n", cmd.duplex ? "full" : "half");
+       if (netif_running(netdev)) {
+               struct ethtool_cmd cmd;
+               if (!dev_ethtool_get_settings(netdev, &cmd))
+                       ret = sprintf(buf, "%s\n",
+                                     cmd.duplex ? "full" : "half");
        }
        rtnl_unlock();
        return ret;
@@@ -565,6 -561,13 +561,6 @@@ static ssize_t show_rps_map(struct netd
        return len;
  }
  
 -static void rps_map_release(struct rcu_head *rcu)
 -{
 -      struct rps_map *map = container_of(rcu, struct rps_map, rcu);
 -
 -      kfree(map);
 -}
 -
  static ssize_t store_rps_map(struct netdev_rx_queue *queue,
                      struct rx_queue_attribute *attribute,
                      const char *buf, size_t len)
        spin_unlock(&rps_map_lock);
  
        if (old_map)
 -              call_rcu(&old_map->rcu, rps_map_release);
 +              kfree_rcu(old_map, rcu);
  
        free_cpumask_var(mask);
        return len;
@@@ -721,7 -724,7 +717,7 @@@ static void rx_queue_release(struct kob
        map = rcu_dereference_raw(queue->rps_map);
        if (map) {
                RCU_INIT_POINTER(queue->rps_map, NULL);
 -              call_rcu(&map->rcu, rps_map_release);
 +              kfree_rcu(map, rcu);
        }
  
        flow_table = rcu_dereference_raw(queue->rps_flow_table);
@@@ -891,6 -894,21 +887,6 @@@ static ssize_t show_xps_map(struct netd
        return len;
  }
  
 -static void xps_map_release(struct rcu_head *rcu)
 -{
 -      struct xps_map *map = container_of(rcu, struct xps_map, rcu);
 -
 -      kfree(map);
 -}
 -
 -static void xps_dev_maps_release(struct rcu_head *rcu)
 -{
 -      struct xps_dev_maps *dev_maps =
 -          container_of(rcu, struct xps_dev_maps, rcu);
 -
 -      kfree(dev_maps);
 -}
 -
  static DEFINE_MUTEX(xps_map_mutex);
  #define xmap_dereference(P)           \
        rcu_dereference_protected((P), lockdep_is_held(&xps_map_mutex))
@@@ -946,7 -964,7 +942,7 @@@ static ssize_t store_xps_map(struct net
                } else
                        pos = map_len = alloc_len = 0;
  
-               need_set = cpu_isset(cpu, *mask) && cpu_online(cpu);
+               need_set = cpumask_test_cpu(cpu, mask) && cpu_online(cpu);
  #ifdef CONFIG_NUMA
                if (need_set) {
                        if (numa_node == -2)
                map = dev_maps ?
                        xmap_dereference(dev_maps->cpu_map[cpu]) : NULL;
                if (map && xmap_dereference(new_dev_maps->cpu_map[cpu]) != map)
 -                      call_rcu(&map->rcu, xps_map_release);
 +                      kfree_rcu(map, rcu);
                if (new_dev_maps->cpu_map[cpu])
                        nonempty = 1;
        }
        }
  
        if (dev_maps)
 -              call_rcu(&dev_maps->rcu, xps_dev_maps_release);
 +              kfree_rcu(dev_maps, rcu);
  
        netdev_queue_numa_node_write(queue, (numa_node >= 0) ? numa_node :
                                            NUMA_NO_NODE);
@@@ -1062,7 -1080,7 +1058,7 @@@ static void netdev_queue_release(struc
                                else {
                                        RCU_INIT_POINTER(dev_maps->cpu_map[i],
                                            NULL);
 -                                      call_rcu(&map->rcu, xps_map_release);
 +                                      kfree_rcu(map, rcu);
                                        map = NULL;
                                }
                        }
  
                if (!nonempty) {
                        RCU_INIT_POINTER(dev->xps_maps, NULL);
 -                      call_rcu(&dev_maps->rcu, xps_dev_maps_release);
 +                      kfree_rcu(dev_maps, rcu);
                }
        }
  
diff --combined net/core/net_namespace.c
@@@ -27,6 -27,14 +27,6 @@@ EXPORT_SYMBOL(init_net)
  
  #define INITIAL_NET_GEN_PTRS  13 /* +1 for len +2 for rcu_head */
  
 -static void net_generic_release(struct rcu_head *rcu)
 -{
 -      struct net_generic *ng;
 -
 -      ng = container_of(rcu, struct net_generic, rcu);
 -      kfree(ng);
 -}
 -
  static int net_assign_generic(struct net *net, int id, void *data)
  {
        struct net_generic *ng, *old_ng;
@@@ -60,7 -68,7 +60,7 @@@
        memcpy(&ng->ptr, &old_ng->ptr, old_ng->len * sizeof(void*));
  
        rcu_assign_pointer(net->gen, ng);
 -      call_rcu(&old_ng->rcu, net_generic_release);
 +      kfree_rcu(old_ng, rcu);
  assign:
        ng->ptr[id - 1] = data;
        return 0;
@@@ -208,11 -216,14 +208,14 @@@ static void net_free(struct net *net
        kmem_cache_free(net_cachep, net);
  }
  
- static struct net *net_create(void)
+ struct net *copy_net_ns(unsigned long flags, struct net *old_net)
  {
        struct net *net;
        int rv;
  
+       if (!(flags & CLONE_NEWNET))
+               return get_net(old_net);
        net = net_alloc();
        if (!net)
                return ERR_PTR(-ENOMEM);
        return net;
  }
  
- struct net *copy_net_ns(unsigned long flags, struct net *old_net)
- {
-       if (!(flags & CLONE_NEWNET))
-               return get_net(old_net);
-       return net_create();
- }
  static DEFINE_SPINLOCK(cleanup_list_lock);
  static LIST_HEAD(cleanup_list);  /* Must hold cleanup_list_lock to touch */
  
diff --combined net/core/pktgen.c
  #include <linux/wait.h>
  #include <linux/etherdevice.h>
  #include <linux/kthread.h>
 +#include <linux/prefetch.h>
  #include <net/net_namespace.h>
  #include <net/checksum.h>
  #include <net/ipv6.h>
@@@ -450,7 -449,6 +450,6 @@@ static void pktgen_stop(struct pktgen_t
  static void pktgen_clear_counters(struct pktgen_dev *pkt_dev);
  
  static unsigned int scan_ip6(const char *s, char ip[16]);
- static unsigned int fmt_ip6(char *s, const char ip[16]);
  
  /* Module parameters, defaults. */
  static int pg_count_d __read_mostly = 1000;
@@@ -557,21 -555,13 +556,13 @@@ static int pktgen_if_show(struct seq_fi
                           pkt_dev->skb_priority);
  
        if (pkt_dev->flags & F_IPV6) {
-               char b1[128], b2[128], b3[128];
-               fmt_ip6(b1, pkt_dev->in6_saddr.s6_addr);
-               fmt_ip6(b2, pkt_dev->min_in6_saddr.s6_addr);
-               fmt_ip6(b3, pkt_dev->max_in6_saddr.s6_addr);
                seq_printf(seq,
-                          "     saddr: %s  min_saddr: %s  max_saddr: %s\n", b1,
-                          b2, b3);
-               fmt_ip6(b1, pkt_dev->in6_daddr.s6_addr);
-               fmt_ip6(b2, pkt_dev->min_in6_daddr.s6_addr);
-               fmt_ip6(b3, pkt_dev->max_in6_daddr.s6_addr);
-               seq_printf(seq,
-                          "     daddr: %s  min_daddr: %s  max_daddr: %s\n", b1,
-                          b2, b3);
+                          "     saddr: %pI6c  min_saddr: %pI6c  max_saddr: %pI6c\n"
+                          "     daddr: %pI6c  min_daddr: %pI6c  max_daddr: %pI6c\n",
+                          &pkt_dev->in6_saddr,
+                          &pkt_dev->min_in6_saddr, &pkt_dev->max_in6_saddr,
+                          &pkt_dev->in6_daddr,
+                          &pkt_dev->min_in6_daddr, &pkt_dev->max_in6_daddr);
        } else {
                seq_printf(seq,
                           "     dst_min: %s  dst_max: %s\n",
                   pkt_dev->cur_src_mac_offset);
  
        if (pkt_dev->flags & F_IPV6) {
-               char b1[128], b2[128];
-               fmt_ip6(b1, pkt_dev->cur_in6_daddr.s6_addr);
-               fmt_ip6(b2, pkt_dev->cur_in6_saddr.s6_addr);
-               seq_printf(seq, "     cur_saddr: %s  cur_daddr: %s\n", b2, b1);
+               seq_printf(seq, "     cur_saddr: %pI6c  cur_daddr: %pI6c\n",
+                               &pkt_dev->cur_in6_saddr,
+                               &pkt_dev->cur_in6_daddr);
        } else
                seq_printf(seq, "     cur_saddr: 0x%x  cur_daddr: 0x%x\n",
                           pkt_dev->cur_saddr, pkt_dev->cur_daddr);
@@@ -1310,7 -1299,7 +1300,7 @@@ static ssize_t pktgen_if_write(struct f
                buf[len] = 0;
  
                scan_ip6(buf, pkt_dev->in6_daddr.s6_addr);
-               fmt_ip6(buf, pkt_dev->in6_daddr.s6_addr);
+               snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->in6_daddr);
  
                ipv6_addr_copy(&pkt_dev->cur_in6_daddr, &pkt_dev->in6_daddr);
  
                buf[len] = 0;
  
                scan_ip6(buf, pkt_dev->min_in6_daddr.s6_addr);
-               fmt_ip6(buf, pkt_dev->min_in6_daddr.s6_addr);
+               snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->min_in6_daddr);
  
                ipv6_addr_copy(&pkt_dev->cur_in6_daddr,
                               &pkt_dev->min_in6_daddr);
                buf[len] = 0;
  
                scan_ip6(buf, pkt_dev->max_in6_daddr.s6_addr);
-               fmt_ip6(buf, pkt_dev->max_in6_daddr.s6_addr);
+               snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->max_in6_daddr);
  
                if (debug)
                        printk(KERN_DEBUG "pktgen: dst6_max set to: %s\n", buf);
                buf[len] = 0;
  
                scan_ip6(buf, pkt_dev->in6_saddr.s6_addr);
-               fmt_ip6(buf, pkt_dev->in6_saddr.s6_addr);
+               snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->in6_saddr);
  
                ipv6_addr_copy(&pkt_dev->cur_in6_saddr, &pkt_dev->in6_saddr);
  
                return count;
        }
        if (!strcmp(name, "dst_mac")) {
-               char *v = valstr;
-               unsigned char old_dmac[ETH_ALEN];
-               unsigned char *m = pkt_dev->dst_mac;
-               memcpy(old_dmac, pkt_dev->dst_mac, ETH_ALEN);
                len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
                if (len < 0)
                        return len;
                memset(valstr, 0, sizeof(valstr));
                if (copy_from_user(valstr, &user_buffer[i], len))
                        return -EFAULT;
-               i += len;
-               for (*m = 0; *v && m < pkt_dev->dst_mac + 6; v++) {
-                       int value;
-                       value = hex_to_bin(*v);
-                       if (value >= 0)
-                               *m = *m * 16 + value;
-                       if (*v == ':') {
-                               m++;
-                               *m = 0;
-                       }
-               }
  
+               if (!mac_pton(valstr, pkt_dev->dst_mac))
+                       return -EINVAL;
                /* Set up Dest MAC */
-               if (compare_ether_addr(old_dmac, pkt_dev->dst_mac))
-                       memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, ETH_ALEN);
+               memcpy(&pkt_dev->hh[0], pkt_dev->dst_mac, ETH_ALEN);
  
-               sprintf(pg_result, "OK: dstmac");
+               sprintf(pg_result, "OK: dstmac %pM", pkt_dev->dst_mac);
                return count;
        }
        if (!strcmp(name, "src_mac")) {
-               char *v = valstr;
-               unsigned char old_smac[ETH_ALEN];
-               unsigned char *m = pkt_dev->src_mac;
-               memcpy(old_smac, pkt_dev->src_mac, ETH_ALEN);
                len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
                if (len < 0)
                        return len;
                memset(valstr, 0, sizeof(valstr));
                if (copy_from_user(valstr, &user_buffer[i], len))
                        return -EFAULT;
-               i += len;
-               for (*m = 0; *v && m < pkt_dev->src_mac + 6; v++) {
-                       int value;
-                       value = hex_to_bin(*v);
-                       if (value >= 0)
-                               *m = *m * 16 + value;
-                       if (*v == ':') {
-                               m++;
-                               *m = 0;
-                       }
-               }
  
+               if (!mac_pton(valstr, pkt_dev->src_mac))
+                       return -EINVAL;
                /* Set up Src MAC */
-               if (compare_ether_addr(old_smac, pkt_dev->src_mac))
-                       memcpy(&(pkt_dev->hh[6]), pkt_dev->src_mac, ETH_ALEN);
+               memcpy(&pkt_dev->hh[6], pkt_dev->src_mac, ETH_ALEN);
  
-               sprintf(pg_result, "OK: srcmac");
+               sprintf(pg_result, "OK: srcmac %pM", pkt_dev->src_mac);
                return count;
        }
  
@@@ -2515,7 -2467,6 +2468,6 @@@ static int pktgen_output_ipsec(struct s
  {
        struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x;
        int err = 0;
-       struct iphdr *iph;
  
        if (!x)
                return 0;
                return 0;
  
        spin_lock(&x->lock);
-       iph = ip_hdr(skb);
  
        err = x->outer_mode->output(x, skb);
        if (err)
@@@ -2625,6 -2575,7 +2576,7 @@@ static void pktgen_finalize_skb(struct 
        } else {
                int frags = pkt_dev->nfrags;
                int i, len;
+               int frag_len;
  
  
                if (frags > MAX_SKB_FRAGS)
                }
  
                i = 0;
+               frag_len = (datalen/frags) < PAGE_SIZE ?
+                          (datalen/frags) : PAGE_SIZE;
                while (datalen > 0) {
                        if (unlikely(!pkt_dev->page)) {
                                int node = numa_node_id();
                        skb_shinfo(skb)->frags[i].page = pkt_dev->page;
                        get_page(pkt_dev->page);
                        skb_shinfo(skb)->frags[i].page_offset = 0;
-                       skb_shinfo(skb)->frags[i].size =
-                           (datalen < PAGE_SIZE ? datalen : PAGE_SIZE);
+                       /*last fragment, fill rest of data*/
+                       if (i == (frags - 1))
+                               skb_shinfo(skb)->frags[i].size =
+                                   (datalen < PAGE_SIZE ? datalen : PAGE_SIZE);
+                       else
+                               skb_shinfo(skb)->frags[i].size = frag_len;
                        datalen -= skb_shinfo(skb)->frags[i].size;
                        skb->len += skb_shinfo(skb)->frags[i].size;
                        skb->data_len += skb_shinfo(skb)->frags[i].size;
                        i++;
                        skb_shinfo(skb)->nr_frags = i;
                }
-               while (i < frags) {
-                       int rem;
-                       if (i == 0)
-                               break;
-                       rem = skb_shinfo(skb)->frags[i - 1].size / 2;
-                       if (rem == 0)
-                               break;
-                       skb_shinfo(skb)->frags[i - 1].size -= rem;
-                       skb_shinfo(skb)->frags[i] =
-                           skb_shinfo(skb)->frags[i - 1];
-                       get_page(skb_shinfo(skb)->frags[i].page);
-                       skb_shinfo(skb)->frags[i].page =
-                           skb_shinfo(skb)->frags[i - 1].page;
-                       skb_shinfo(skb)->frags[i].page_offset +=
-                           skb_shinfo(skb)->frags[i - 1].size;
-                       skb_shinfo(skb)->frags[i].size = rem;
-                       i++;
-                       skb_shinfo(skb)->nr_frags = i;
-               }
        }
  
        /* Stamp the time, and sequence number,
@@@ -2918,79 -2851,6 +2852,6 @@@ static unsigned int scan_ip6(const cha
        return len;
  }
  
- static char tohex(char hexdigit)
- {
-       return hexdigit > 9 ? hexdigit + 'a' - 10 : hexdigit + '0';
- }
- static int fmt_xlong(char *s, unsigned int i)
- {
-       char *bak = s;
-       *s = tohex((i >> 12) & 0xf);
-       if (s != bak || *s != '0')
-               ++s;
-       *s = tohex((i >> 8) & 0xf);
-       if (s != bak || *s != '0')
-               ++s;
-       *s = tohex((i >> 4) & 0xf);
-       if (s != bak || *s != '0')
-               ++s;
-       *s = tohex(i & 0xf);
-       return s - bak + 1;
- }
- static unsigned int fmt_ip6(char *s, const char ip[16])
- {
-       unsigned int len;
-       unsigned int i;
-       unsigned int temp;
-       unsigned int compressing;
-       int j;
-       len = 0;
-       compressing = 0;
-       for (j = 0; j < 16; j += 2) {
- #ifdef V4MAPPEDPREFIX
-               if (j == 12 && !memcmp(ip, V4mappedprefix, 12)) {
-                       inet_ntoa_r(*(struct in_addr *)(ip + 12), s);
-                       temp = strlen(s);
-                       return len + temp;
-               }
- #endif
-               temp = ((unsigned long)(unsigned char)ip[j] << 8) +
-                   (unsigned long)(unsigned char)ip[j + 1];
-               if (temp == 0) {
-                       if (!compressing) {
-                               compressing = 1;
-                               if (j == 0) {
-                                       *s++ = ':';
-                                       ++len;
-                               }
-                       }
-               } else {
-                       if (compressing) {
-                               compressing = 0;
-                               *s++ = ':';
-                               ++len;
-                       }
-                       i = fmt_xlong(s, temp);
-                       len += i;
-                       s += i;
-                       if (j < 14) {
-                               *s++ = ':';
-                               ++len;
-                       }
-               }
-       }
-       if (compressing) {
-               *s++ = ':';
-               ++len;
-       }
-       *s = 0;
-       return len;
- }
  static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
                                        struct pktgen_dev *pkt_dev)
  {
diff --combined net/core/skbuff.c
@@@ -57,7 -57,6 +57,7 @@@
  #include <linux/init.h>
  #include <linux/scatterlist.h>
  #include <linux/errqueue.h>
 +#include <linux/prefetch.h>
  
  #include <net/protocol.h>
  #include <net/dst.h>
@@@ -2994,6 -2993,9 +2994,9 @@@ int sock_queue_err_skb(struct sock *sk
        skb->destructor = sock_rmem_free;
        atomic_add(skb->truesize, &sk->sk_rmem_alloc);
  
+       /* before exiting rcu section, make sure dst is refcounted */
+       skb_dst_force(skb);
        skb_queue_tail(&sk->sk_error_queue, skb);
        if (!sock_flag(sk, SOCK_DEAD))
                sk->sk_data_ready(sk, skb->len);
diff --combined net/decnet/dn_dev.c
@@@ -332,9 -332,14 +332,9 @@@ static struct dn_ifaddr *dn_dev_alloc_i
        return ifa;
  }
  
 -static void dn_dev_free_ifa_rcu(struct rcu_head *head)
 -{
 -      kfree(container_of(head, struct dn_ifaddr, rcu));
 -}
 -
  static void dn_dev_free_ifa(struct dn_ifaddr *ifa)
  {
 -      call_rcu(&ifa->rcu, dn_dev_free_ifa_rcu);
 +      kfree_rcu(ifa, rcu);
  }
  
  static void dn_dev_del_ifa(struct dn_dev *dn_db, struct dn_ifaddr __rcu **ifap, int destroy)
@@@ -747,7 -752,8 +747,8 @@@ static int dn_nl_dump_ifaddr(struct sk_
        skip_naddr = cb->args[1];
  
        idx = 0;
-       for_each_netdev(&init_net, dev) {
+       rcu_read_lock();
+       for_each_netdev_rcu(&init_net, dev) {
                if (idx < skip_ndevs)
                        goto cont;
                else if (idx > skip_ndevs) {
                        skip_naddr = 0;
                }
  
-               if ((dn_db = rtnl_dereference(dev->dn_ptr)) == NULL)
+               if ((dn_db = rcu_dereference(dev->dn_ptr)) == NULL)
                        goto cont;
  
-               for (ifa = rtnl_dereference(dn_db->ifa_list), dn_idx = 0; ifa;
-                    ifa = rtnl_dereference(ifa->ifa_next), dn_idx++) {
+               for (ifa = rcu_dereference(dn_db->ifa_list), dn_idx = 0; ifa;
+                    ifa = rcu_dereference(ifa->ifa_next), dn_idx++) {
                        if (dn_idx < skip_naddr)
                                continue;
  
@@@ -773,6 -779,7 +774,7 @@@ cont
                idx++;
        }
  done:
+       rcu_read_unlock();
        cb->args[0] = idx;
        cb->args[1] = dn_idx;
  
diff --combined net/ipv4/fib_trie.c
@@@ -126,7 -126,7 +126,7 @@@ struct tnode 
                struct work_struct work;
                struct tnode *tnode_free;
        };
-       struct rt_trie_node *child[0];
+       struct rt_trie_node __rcu *child[0];
  };
  
  #ifdef CONFIG_IP_FIB_TRIE_STATS
@@@ -151,7 -151,7 +151,7 @@@ struct trie_stat 
  };
  
  struct trie {
-       struct rt_trie_node *trie;
+       struct rt_trie_node __rcu *trie;
  #ifdef CONFIG_IP_FIB_TRIE_STATS
        struct trie_use_stats stats;
  #endif
@@@ -177,16 -177,29 +177,29 @@@ static const int sync_pages = 128
  static struct kmem_cache *fn_alias_kmem __read_mostly;
  static struct kmem_cache *trie_leaf_kmem __read_mostly;
  
- static inline struct tnode *node_parent(struct rt_trie_node *node)
+ /*
+  * caller must hold RTNL
+  */
+ static inline struct tnode *node_parent(const struct rt_trie_node *node)
  {
-       return (struct tnode *)(node->parent & ~NODE_TYPE_MASK);
+       unsigned long parent;
+       parent = rcu_dereference_index_check(node->parent, lockdep_rtnl_is_held());
+       return (struct tnode *)(parent & ~NODE_TYPE_MASK);
  }
  
- static inline struct tnode *node_parent_rcu(struct rt_trie_node *node)
+ /*
+  * caller must hold RCU read lock or RTNL
+  */
+ static inline struct tnode *node_parent_rcu(const struct rt_trie_node *node)
  {
-       struct tnode *ret = node_parent(node);
+       unsigned long parent;
+       parent = rcu_dereference_index_check(node->parent, rcu_read_lock_held() ||
+                                                          lockdep_rtnl_is_held());
  
-       return rcu_dereference_rtnl(ret);
+       return (struct tnode *)(parent & ~NODE_TYPE_MASK);
  }
  
  /* Same as rcu_assign_pointer
@@@ -198,18 -211,24 +211,24 @@@ static inline void node_set_parent(stru
        node->parent = (unsigned long)ptr | NODE_TYPE(node);
  }
  
- static inline struct rt_trie_node *tnode_get_child(struct tnode *tn, unsigned int i)
+ /*
+  * caller must hold RTNL
+  */
+ static inline struct rt_trie_node *tnode_get_child(const struct tnode *tn, unsigned int i)
  {
        BUG_ON(i >= 1U << tn->bits);
  
-       return tn->child[i];
+       return rtnl_dereference(tn->child[i]);
  }
  
- static inline struct rt_trie_node *tnode_get_child_rcu(struct tnode *tn, unsigned int i)
+ /*
+  * caller must hold RCU read lock or RTNL
+  */
+ static inline struct rt_trie_node *tnode_get_child_rcu(const struct tnode *tn, unsigned int i)
  {
-       struct rt_trie_node *ret = tnode_get_child(tn, i);
+       BUG_ON(i >= 1U << tn->bits);
  
-       return rcu_dereference_rtnl(ret);
+       return rcu_dereference_rtnl(tn->child[i]);
  }
  
  static inline int tnode_child_length(const struct tnode *tn)
@@@ -350,9 -369,14 +369,9 @@@ static inline void free_leaf(struct lea
        call_rcu_bh(&l->rcu, __leaf_free_rcu);
  }
  
 -static void __leaf_info_free_rcu(struct rcu_head *head)
 -{
 -      kfree(container_of(head, struct leaf_info, rcu));
 -}
 -
  static inline void free_leaf_info(struct leaf_info *leaf)
  {
 -      call_rcu(&leaf->rcu, __leaf_info_free_rcu);
 +      kfree_rcu(leaf, rcu);
  }
  
  static struct tnode *tnode_alloc(size_t size)
@@@ -482,7 -506,7 +501,7 @@@ static inline void put_child(struct tri
  static void tnode_put_child_reorg(struct tnode *tn, int i, struct rt_trie_node *n,
                                  int wasfull)
  {
-       struct rt_trie_node *chi = tn->child[i];
+       struct rt_trie_node *chi = rtnl_dereference(tn->child[i]);
        int isfull;
  
        BUG_ON(i >= 1<<tn->bits);
@@@ -660,7 -684,7 +679,7 @@@ one_child
                for (i = 0; i < tnode_child_length(tn); i++) {
                        struct rt_trie_node *n;
  
-                       n = tn->child[i];
+                       n = rtnl_dereference(tn->child[i]);
                        if (!n)
                                continue;
  
        return (struct rt_trie_node *) tn;
  }
  
+ static void tnode_clean_free(struct tnode *tn)
+ {
+       int i;
+       struct tnode *tofree;
+       for (i = 0; i < tnode_child_length(tn); i++) {
+               tofree = (struct tnode *)rtnl_dereference(tn->child[i]);
+               if (tofree)
+                       tnode_free(tofree);
+       }
+       tnode_free(tn);
+ }
  static struct tnode *inflate(struct trie *t, struct tnode *tn)
  {
        struct tnode *oldtnode = tn;
                inode = (struct tnode *) node;
  
                if (inode->bits == 1) {
-                       put_child(t, tn, 2*i, inode->child[0]);
-                       put_child(t, tn, 2*i+1, inode->child[1]);
+                       put_child(t, tn, 2*i, rtnl_dereference(inode->child[0]));
+                       put_child(t, tn, 2*i+1, rtnl_dereference(inode->child[1]));
  
                        tnode_free_safe(inode);
                        continue;
  
                size = tnode_child_length(left);
                for (j = 0; j < size; j++) {
-                       put_child(t, left, j, inode->child[j]);
-                       put_child(t, right, j, inode->child[j + size]);
+                       put_child(t, left, j, rtnl_dereference(inode->child[j]));
+                       put_child(t, right, j, rtnl_dereference(inode->child[j + size]));
                }
                put_child(t, tn, 2*i, resize(t, left));
                put_child(t, tn, 2*i+1, resize(t, right));
        tnode_free_safe(oldtnode);
        return tn;
  nomem:
-       {
-               int size = tnode_child_length(tn);
-               int j;
-               for (j = 0; j < size; j++)
-                       if (tn->child[j])
-                               tnode_free((struct tnode *)tn->child[j]);
-               tnode_free(tn);
-               return ERR_PTR(-ENOMEM);
-       }
+       tnode_clean_free(tn);
+       return ERR_PTR(-ENOMEM);
  }
  
  static struct tnode *halve(struct trie *t, struct tnode *tn)
        tnode_free_safe(oldtnode);
        return tn;
  nomem:
-       {
-               int size = tnode_child_length(tn);
-               int j;
-               for (j = 0; j < size; j++)
-                       if (tn->child[j])
-                               tnode_free((struct tnode *)tn->child[j]);
-               tnode_free(tn);
-               return ERR_PTR(-ENOMEM);
-       }
+       tnode_clean_free(tn);
+       return ERR_PTR(-ENOMEM);
  }
  
  /* readside must use rcu_read_lock currently dump routines
@@@ -1028,7 -1046,7 +1041,7 @@@ static struct list_head *fib_insert_nod
        t_key cindex;
  
        pos = 0;
-       n = t->trie;
+       n = rtnl_dereference(t->trie);
  
        /* If we point to NULL, stop. Either the tree is empty and we should
         * just put a new leaf in if, or we have reached an empty child slot,
@@@ -1314,6 -1332,9 +1327,9 @@@ int fib_table_insert(struct fib_table *
                }
        }
  
+       if (!plen)
+               tb->tb_num_default++;
        list_add_tail_rcu(&new_fa->fa_list,
                          (fa ? &fa->fa_list : fa_head));
  
@@@ -1679,6 -1700,9 +1695,9 @@@ int fib_table_delete(struct fib_table *
  
        list_del_rcu(&fa->fa_list);
  
+       if (!plen)
+               tb->tb_num_default--;
        if (list_empty(fa_head)) {
                hlist_del_rcu(&li->hlist);
                free_leaf_info(li);
@@@ -1751,7 -1775,7 +1770,7 @@@ static struct leaf *leaf_walk_rcu(struc
                                continue;
  
                        if (IS_LEAF(c)) {
-                               prefetch(p->child[idx]);
+                               prefetch(rcu_dereference_rtnl(p->child[idx]));
                                return (struct leaf *) c;
                        }
  
@@@ -1969,6 -1993,7 +1988,7 @@@ struct fib_table *fib_trie_table(u32 id
  
        tb->tb_id = id;
        tb->tb_default = -1;
+       tb->tb_num_default = 0;
  
        t = (struct trie *) tb->tb_data;
        memset(t, 0, sizeof(*t));
@@@ -2264,7 -2289,7 +2284,7 @@@ static void *fib_trie_seq_next(struct s
  
        /* walk rest of this hash chain */
        h = tb->tb_id & (FIB_TABLE_HASHSZ - 1);
-       while ( (tb_node = rcu_dereference(tb->tb_hlist.next)) ) {
+       while ((tb_node = rcu_dereference(hlist_next_rcu(&tb->tb_hlist)))) {
                tb = hlist_entry(tb_node, struct fib_table, tb_hlist);
                n = fib_trie_get_first(iter, (struct trie *) tb->tb_data);
                if (n)
diff --combined net/ipv4/igmp.c
@@@ -149,11 -149,17 +149,11 @@@ static void ip_mc_clear_src(struct ip_m
  static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
                         int sfcount, __be32 *psfsrc, int delta);
  
 -
 -static void ip_mc_list_reclaim(struct rcu_head *head)
 -{
 -      kfree(container_of(head, struct ip_mc_list, rcu));
 -}
 -
  static void ip_ma_put(struct ip_mc_list *im)
  {
        if (atomic_dec_and_test(&im->refcnt)) {
                in_dev_put(im->interface);
 -              call_rcu(&im->rcu, ip_mc_list_reclaim);
 +              kfree_rcu(im, rcu);
        }
  }
  
@@@ -303,6 -309,7 +303,7 @@@ static struct sk_buff *igmpv3_newpack(s
        struct iphdr *pip;
        struct igmpv3_report *pig;
        struct net *net = dev_net(dev);
+       struct flowi4 fl4;
  
        while (1) {
                skb = alloc_skb(size + LL_ALLOCATED_SPACE(dev),
        }
        igmp_skb_size(skb) = size;
  
-       rt = ip_route_output_ports(net, NULL, IGMPV3_ALL_MCR, 0,
+       rt = ip_route_output_ports(net, &fl4, NULL, IGMPV3_ALL_MCR, 0,
                                   0, 0,
                                   IPPROTO_IGMP, 0, dev->ifindex);
        if (IS_ERR(rt)) {
                kfree_skb(skb);
                return NULL;
        }
-       if (rt->rt_src == 0) {
-               kfree_skb(skb);
-               ip_rt_put(rt);
-               return NULL;
-       }
  
        skb_dst_set(skb, &rt->dst);
        skb->dev = dev;
        pip->tos      = 0xc0;
        pip->frag_off = htons(IP_DF);
        pip->ttl      = 1;
-       pip->daddr    = rt->rt_dst;
-       pip->saddr    = rt->rt_src;
+       pip->daddr    = fl4.daddr;
+       pip->saddr    = fl4.saddr;
        pip->protocol = IPPROTO_IGMP;
        pip->tot_len  = 0;      /* filled in later */
        ip_select_ident(pip, &rt->dst, NULL);
@@@ -649,6 -651,7 +645,7 @@@ static int igmp_send_report(struct in_d
        struct net_device *dev = in_dev->dev;
        struct net *net = dev_net(dev);
        __be32  group = pmc ? pmc->multiaddr : 0;
+       struct flowi4 fl4;
        __be32  dst;
  
        if (type == IGMPV3_HOST_MEMBERSHIP_REPORT)
        else
                dst = group;
  
-       rt = ip_route_output_ports(net, NULL, dst, 0,
+       rt = ip_route_output_ports(net, &fl4, NULL, dst, 0,
                                   0, 0,
                                   IPPROTO_IGMP, 0, dev->ifindex);
        if (IS_ERR(rt))
                return -1;
  
-       if (rt->rt_src == 0) {
-               ip_rt_put(rt);
-               return -1;
-       }
        skb = alloc_skb(IGMP_SIZE+LL_ALLOCATED_SPACE(dev), GFP_ATOMIC);
        if (skb == NULL) {
                ip_rt_put(rt);
        iph->frag_off = htons(IP_DF);
        iph->ttl      = 1;
        iph->daddr    = dst;
-       iph->saddr    = rt->rt_src;
+       iph->saddr    = fl4.saddr;
        iph->protocol = IPPROTO_IGMP;
        ip_select_ident(iph, &rt->dst, NULL);
        ((u8*)&iph[1])[0] = IPOPT_RA;
@@@ -1830,6 -1828,12 +1822,6 @@@ done
  }
  EXPORT_SYMBOL(ip_mc_join_group);
  
 -static void ip_sf_socklist_reclaim(struct rcu_head *rp)
 -{
 -      kfree(container_of(rp, struct ip_sf_socklist, rcu));
 -      /* sk_omem_alloc should have been decreased by the caller*/
 -}
 -
  static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml,
                           struct in_device *in_dev)
  {
        rcu_assign_pointer(iml->sflist, NULL);
        /* decrease mem now to avoid the memleak warning */
        atomic_sub(IP_SFLSIZE(psf->sl_max), &sk->sk_omem_alloc);
 -      call_rcu(&psf->rcu, ip_sf_socklist_reclaim);
 +      kfree_rcu(psf, rcu);
        return err;
  }
  
 -
 -static void ip_mc_socklist_reclaim(struct rcu_head *rp)
 -{
 -      kfree(container_of(rp, struct ip_mc_socklist, rcu));
 -      /* sk_omem_alloc should have been decreased by the caller*/
 -}
 -
 -
  /*
   *    Ask a socket to leave a group.
   */
@@@ -1889,7 -1901,7 +1881,7 @@@ int ip_mc_leave_group(struct sock *sk, 
                rtnl_unlock();
                /* decrease mem now to avoid the memleak warning */
                atomic_sub(sizeof(*iml), &sk->sk_omem_alloc);
 -              call_rcu(&iml->rcu, ip_mc_socklist_reclaim);
 +              kfree_rcu(iml, rcu);
                return 0;
        }
        if (!in_dev)
@@@ -2006,7 -2018,7 +1998,7 @@@ int ip_mc_source(int add, int omode, st
                                newpsl->sl_addr[i] = psl->sl_addr[i];
                        /* decrease mem now to avoid the memleak warning */
                        atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc);
 -                      call_rcu(&psl->rcu, ip_sf_socklist_reclaim);
 +                      kfree_rcu(psl, rcu);
                }
                rcu_assign_pointer(pmc->sflist, newpsl);
                psl = newpsl;
@@@ -2107,7 -2119,7 +2099,7 @@@ int ip_mc_msfilter(struct sock *sk, str
                        psl->sl_count, psl->sl_addr, 0);
                /* decrease mem now to avoid the memleak warning */
                atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc);
 -              call_rcu(&psl->rcu, ip_sf_socklist_reclaim);
 +              kfree_rcu(psl, rcu);
        } else
                (void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode,
                        0, NULL, 0);
@@@ -2304,7 -2316,7 +2296,7 @@@ void ip_mc_drop_socket(struct sock *sk
                        ip_mc_dec_group(in_dev, iml->multi.imr_multiaddr.s_addr);
                /* decrease mem now to avoid the memleak warning */
                atomic_sub(sizeof(*iml), &sk->sk_omem_alloc);
 -              call_rcu(&iml->rcu, ip_mc_socklist_reclaim);
 +              kfree_rcu(iml, rcu);
        }
        rtnl_unlock();
  }
diff --combined net/ipv6/addrconf.c
@@@ -289,19 -289,19 +289,19 @@@ static int snmp6_alloc_dev(struct inet6
                          sizeof(struct ipstats_mib),
                          __alignof__(struct ipstats_mib)) < 0)
                goto err_ip;
-       if (snmp_mib_init((void __percpu **)idev->stats.icmpv6,
-                         sizeof(struct icmpv6_mib),
-                         __alignof__(struct icmpv6_mib)) < 0)
+       idev->stats.icmpv6dev = kzalloc(sizeof(struct icmpv6_mib_device),
+                                       GFP_KERNEL);
+       if (!idev->stats.icmpv6dev)
                goto err_icmp;
-       if (snmp_mib_init((void __percpu **)idev->stats.icmpv6msg,
-                         sizeof(struct icmpv6msg_mib),
-                         __alignof__(struct icmpv6msg_mib)) < 0)
+       idev->stats.icmpv6msgdev = kzalloc(sizeof(struct icmpv6msg_mib_device),
+                                          GFP_KERNEL);
+       if (!idev->stats.icmpv6msgdev)
                goto err_icmpmsg;
  
        return 0;
  
  err_icmpmsg:
-       snmp_mib_free((void __percpu **)idev->stats.icmpv6);
+       kfree(idev->stats.icmpv6dev);
  err_icmp:
        snmp_mib_free((void __percpu **)idev->stats.ipv6);
  err_ip:
  
  static void snmp6_free_dev(struct inet6_dev *idev)
  {
-       snmp_mib_free((void __percpu **)idev->stats.icmpv6msg);
-       snmp_mib_free((void __percpu **)idev->stats.icmpv6);
+       kfree(idev->stats.icmpv6msgdev);
+       kfree(idev->stats.icmpv6dev);
        snmp_mib_free((void __percpu **)idev->stats.ipv6);
  }
  
  /* Nobody refers to this device, we may destroy it. */
  
 -static void in6_dev_finish_destroy_rcu(struct rcu_head *head)
 -{
 -      struct inet6_dev *idev = container_of(head, struct inet6_dev, rcu);
 -      kfree(idev);
 -}
 -
  void in6_dev_finish_destroy(struct inet6_dev *idev)
  {
        struct net_device *dev = idev->dev;
                return;
        }
        snmp6_free_dev(idev);
 -      call_rcu(&idev->rcu, in6_dev_finish_destroy_rcu);
 +      kfree_rcu(idev, rcu);
  }
  
  EXPORT_SYMBOL(in6_dev_finish_destroy);
@@@ -529,6 -535,12 +529,6 @@@ static int addrconf_fixup_forwarding(st
  }
  #endif
  
 -static void inet6_ifa_finish_destroy_rcu(struct rcu_head *head)
 -{
 -      struct inet6_ifaddr *ifp = container_of(head, struct inet6_ifaddr, rcu);
 -      kfree(ifp);
 -}
 -
  /* Nobody refers to this ifaddr, destroy it */
  void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp)
  {
        }
        dst_release(&ifp->rt->dst);
  
 -      call_rcu(&ifp->rcu, inet6_ifa_finish_destroy_rcu);
 +      kfree_rcu(ifp, rcu);
  }
  
  static void
@@@ -813,6 -825,8 +813,8 @@@ static void ipv6_del_addr(struct inet6_
                dst_release(&rt->dst);
        }
  
+       /* clean up prefsrc entries */
+       rt6_remove_prefsrc(ifp);
  out:
        in6_ifa_put(ifp);
  }
@@@ -1269,7 -1283,7 +1271,7 @@@ static int ipv6_count_addresses(struct 
        return cnt;
  }
  
- int ipv6_chk_addr(struct net *net, struct in6_addr *addr,
+ int ipv6_chk_addr(struct net *net, const struct in6_addr *addr,
                  struct net_device *dev, int strict)
  {
        struct inet6_ifaddr *ifp;
@@@ -1312,7 -1326,7 +1314,7 @@@ static bool ipv6_chk_same_addr(struct n
        return false;
  }
  
- int ipv6_chk_prefix(struct in6_addr *addr, struct net_device *dev)
+ int ipv6_chk_prefix(const struct in6_addr *addr, struct net_device *dev)
  {
        struct inet6_dev *idev;
        struct inet6_ifaddr *ifa;
@@@ -1443,7 -1457,7 +1445,7 @@@ void addrconf_dad_failure(struct inet6_
  
  /* Join to solicited addr multicast group. */
  
- void addrconf_join_solict(struct net_device *dev, struct in6_addr *addr)
+ void addrconf_join_solict(struct net_device *dev, const struct in6_addr *addr)
  {
        struct in6_addr maddr;
  
        ipv6_dev_mc_inc(dev, &maddr);
  }
  
- void addrconf_leave_solict(struct inet6_dev *idev, struct in6_addr *addr)
+ void addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr)
  {
        struct in6_addr maddr;
  
@@@ -2099,7 -2113,7 +2101,7 @@@ err_exit
  /*
   *    Manual configuration of address on an interface
   */
- static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx,
+ static int inet6_addr_add(struct net *net, int ifindex, const struct in6_addr *pfx,
                          unsigned int plen, __u8 ifa_flags, __u32 prefered_lft,
                          __u32 valid_lft)
  {
        return PTR_ERR(ifp);
  }
  
- static int inet6_addr_del(struct net *net, int ifindex, struct in6_addr *pfx,
+ static int inet6_addr_del(struct net *net, int ifindex, const struct in6_addr *pfx,
                          unsigned int plen)
  {
        struct inet6_ifaddr *ifp;
@@@ -2336,7 -2350,7 +2338,7 @@@ static void init_loopback(struct net_de
        add_addr(idev, &in6addr_loopback, 128, IFA_HOST);
  }
  
- static void addrconf_add_linklocal(struct inet6_dev *idev, struct in6_addr *addr)
+ static void addrconf_add_linklocal(struct inet6_dev *idev, const struct in6_addr *addr)
  {
        struct inet6_ifaddr * ifp;
        u32 addr_flags = IFA_F_PERMANENT;
@@@ -3107,7 -3121,7 +3109,7 @@@ void if6_proc_exit(void
  
  #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
  /* Check if address is a home address configured on any interface. */
- int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr)
+ int ipv6_chk_home_addr(struct net *net, const struct in6_addr *addr)
  {
        int ret = 0;
        struct inet6_ifaddr *ifp = NULL;
@@@ -3824,7 -3838,7 +3826,7 @@@ static inline size_t inet6_if_nlmsg_siz
               + nla_total_size(inet6_ifla6_size()); /* IFLA_PROTINFO */
  }
  
- static inline void __snmp6_fill_stats(u64 *stats, void __percpu **mib,
+ static inline void __snmp6_fill_statsdev(u64 *stats, atomic_long_t *mib,
                                      int items, int bytes)
  {
        int i;
        /* Use put_unaligned() because stats may not be aligned for u64. */
        put_unaligned(items, &stats[0]);
        for (i = 1; i < items; i++)
-               put_unaligned(snmp_fold_field(mib, i), &stats[i]);
+               put_unaligned(atomic_long_read(&mib[i]), &stats[i]);
  
        memset(&stats[items], 0, pad);
  }
@@@ -3863,7 -3877,7 +3865,7 @@@ static void snmp6_fill_stats(u64 *stats
                                     IPSTATS_MIB_MAX, bytes, offsetof(struct ipstats_mib, syncp));
                break;
        case IFLA_INET6_ICMP6STATS:
-               __snmp6_fill_stats(stats, (void __percpu **)idev->stats.icmpv6, ICMP6_MIB_MAX, bytes);
+               __snmp6_fill_statsdev(stats, idev->stats.icmpv6dev->mibs, ICMP6_MIB_MAX, bytes);
                break;
        }
  }
diff --combined net/ipv6/mcast.c
@@@ -92,16 -92,16 +92,16 @@@ static void mld_gq_timer_expire(unsigne
  static void mld_ifc_timer_expire(unsigned long data);
  static void mld_ifc_event(struct inet6_dev *idev);
  static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *pmc);
- static void mld_del_delrec(struct inet6_dev *idev, struct in6_addr *addr);
+ static void mld_del_delrec(struct inet6_dev *idev, const struct in6_addr *addr);
  static void mld_clear_delrec(struct inet6_dev *idev);
  static int sf_setstate(struct ifmcaddr6 *pmc);
  static void sf_markstate(struct ifmcaddr6 *pmc);
  static void ip6_mc_clear_src(struct ifmcaddr6 *pmc);
- static int ip6_mc_del_src(struct inet6_dev *idev, struct in6_addr *pmca,
-                         int sfmode, int sfcount, struct in6_addr *psfsrc,
+ static int ip6_mc_del_src(struct inet6_dev *idev, const struct in6_addr *pmca,
+                         int sfmode, int sfcount, const struct in6_addr *psfsrc,
                          int delta);
- static int ip6_mc_add_src(struct inet6_dev *idev, struct in6_addr *pmca,
-                         int sfmode, int sfcount, struct in6_addr *psfsrc,
+ static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca,
+                         int sfmode, int sfcount, const struct in6_addr *psfsrc,
                          int delta);
  static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml,
                            struct inet6_dev *idev);
@@@ -201,6 -201,10 +201,6 @@@ int ipv6_sock_mc_join(struct sock *sk, 
        return 0;
  }
  
 -static void ipv6_mc_socklist_reclaim(struct rcu_head *head)
 -{
 -      kfree(container_of(head, struct ipv6_mc_socklist, rcu));
 -}
  /*
   *    socket leave on multicast group
   */
@@@ -235,7 -239,7 +235,7 @@@ int ipv6_sock_mc_drop(struct sock *sk, 
                                (void) ip6_mc_leave_src(sk, mc_lst, NULL);
                        rcu_read_unlock();
                        atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc);
 -                      call_rcu(&mc_lst->rcu, ipv6_mc_socklist_reclaim);
 +                      kfree_rcu(mc_lst, rcu);
                        return 0;
                }
        }
  
  /* called with rcu_read_lock() */
  static struct inet6_dev *ip6_mc_find_dev_rcu(struct net *net,
-                                            struct in6_addr *group,
+                                            const struct in6_addr *group,
                                             int ifindex)
  {
        struct net_device *dev = NULL;
@@@ -303,7 -307,7 +303,7 @@@ void ipv6_sock_mc_close(struct sock *sk
                rcu_read_unlock();
  
                atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc);
 -              call_rcu(&mc_lst->rcu, ipv6_mc_socklist_reclaim);
 +              kfree_rcu(mc_lst, rcu);
  
                spin_lock(&ipv6_sk_mc_lock);
        }
@@@ -447,7 -451,7 +447,7 @@@ done
  
  int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf)
  {
-       struct in6_addr *group;
+       const struct in6_addr *group;
        struct ipv6_mc_socklist *pmc;
        struct inet6_dev *idev;
        struct ipv6_pinfo *inet6 = inet6_sk(sk);
@@@ -538,7 -542,7 +538,7 @@@ int ip6_mc_msfget(struct sock *sk, stru
        struct group_filter __user *optval, int __user *optlen)
  {
        int err, i, count, copycount;
-       struct in6_addr *group;
+       const struct in6_addr *group;
        struct ipv6_mc_socklist *pmc;
        struct inet6_dev *idev;
        struct ipv6_pinfo *inet6 = inet6_sk(sk);
@@@ -748,7 -752,7 +748,7 @@@ static void mld_add_delrec(struct inet6
        spin_unlock_bh(&idev->mc_lock);
  }
  
- static void mld_del_delrec(struct inet6_dev *idev, struct in6_addr *pmca)
+ static void mld_del_delrec(struct inet6_dev *idev, const struct in6_addr *pmca)
  {
        struct ifmcaddr6 *pmc, *pmc_prev;
        struct ip6_sf_list *psf, *psf_next;
@@@ -1048,7 -1052,7 +1048,7 @@@ static void igmp6_group_queried(struct 
  
  /* mark EXCLUDE-mode sources */
  static int mld_xmarksources(struct ifmcaddr6 *pmc, int nsrcs,
-       struct in6_addr *srcs)
+       const struct in6_addr *srcs)
  {
        struct ip6_sf_list *psf;
        int i, scount;
  }
  
  static int mld_marksources(struct ifmcaddr6 *pmc, int nsrcs,
-       struct in6_addr *srcs)
+       const struct in6_addr *srcs)
  {
        struct ip6_sf_list *psf;
        int i, scount;
@@@ -1111,7 -1115,7 +1111,7 @@@ int igmp6_event_query(struct sk_buff *s
  {
        struct mld2_query *mlh2 = NULL;
        struct ifmcaddr6 *ma;
-       struct in6_addr *group;
+       const struct in6_addr *group;
        unsigned long max_delay;
        struct inet6_dev *idev;
        struct mld_msg *mld;
@@@ -1817,7 -1821,7 +1817,7 @@@ err_out
  }
  
  static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode,
-       struct in6_addr *psfsrc)
+       const struct in6_addr *psfsrc)
  {
        struct ip6_sf_list *psf, *psf_prev;
        int rv = 0;
        return rv;
  }
  
- static int ip6_mc_del_src(struct inet6_dev *idev, struct in6_addr *pmca,
-                         int sfmode, int sfcount, struct in6_addr *psfsrc,
+ static int ip6_mc_del_src(struct inet6_dev *idev, const struct in6_addr *pmca,
+                         int sfmode, int sfcount, const struct in6_addr *psfsrc,
                          int delta)
  {
        struct ifmcaddr6 *pmc;
   * Add multicast single-source filter to the interface list
   */
  static int ip6_mc_add1_src(struct ifmcaddr6 *pmc, int sfmode,
-       struct in6_addr *psfsrc, int delta)
+       const struct in6_addr *psfsrc, int delta)
  {
        struct ip6_sf_list *psf, *psf_prev;
  
@@@ -2017,8 -2021,8 +2017,8 @@@ static int sf_setstate(struct ifmcaddr
  /*
   * Add multicast source filter list to the interface list
   */
- static int ip6_mc_add_src(struct inet6_dev *idev, struct in6_addr *pmca,
-                         int sfmode, int sfcount, struct in6_addr *psfsrc,
+ static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca,
+                         int sfmode, int sfcount, const struct in6_addr *psfsrc,
                          int delta)
  {
        struct ifmcaddr6 *pmc;
diff --combined net/ipv6/sit.c
@@@ -250,11 -250,6 +250,6 @@@ static struct ip_tunnel *ipip6_tunnel_l
  
        dev_net_set(dev, net);
  
-       if (strchr(name, '%')) {
-               if (dev_alloc_name(dev, name) < 0)
-                       goto failed_free;
-       }
        nt = netdev_priv(dev);
  
        nt->parms = *parms;
@@@ -401,6 -396,11 +396,6 @@@ out
        return err;
  }
  
 -static void prl_entry_destroy_rcu(struct rcu_head *head)
 -{
 -      kfree(container_of(head, struct ip_tunnel_prl_entry, rcu_head));
 -}
 -
  static void prl_list_destroy_rcu(struct rcu_head *head)
  {
        struct ip_tunnel_prl_entry *p, *n;
@@@ -428,7 -428,7 +423,7 @@@ ipip6_tunnel_del_prl(struct ip_tunnel *
                     p = &x->next) {
                        if (x->addr == a->addr) {
                                *p = x->next;
 -                              call_rcu(&x->rcu_head, prl_entry_destroy_rcu);
 +                              kfree_rcu(x, rcu_head);
                                t->prl_count--;
                                goto out;
                        }
@@@ -447,7 -447,7 +442,7 @@@ out
  }
  
  static int
- isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t)
+ isatap_chksrc(struct sk_buff *skb, const struct iphdr *iph, struct ip_tunnel *t)
  {
        struct ip_tunnel_prl_entry *p;
        int ok = 1;
                else
                        skb->ndisc_nodetype = NDISC_NODETYPE_NODEFAULT;
        } else {
-               struct in6_addr *addr6 = &ipv6_hdr(skb)->saddr;
+               const struct in6_addr *addr6 = &ipv6_hdr(skb)->saddr;
                if (ipv6_addr_is_isatap(addr6) &&
                    (addr6->s6_addr32[3] == iph->saddr) &&
                    ipv6_chk_prefix(addr6, t->dev))
@@@ -494,7 -495,7 +490,7 @@@ static int ipip6_err(struct sk_buff *sk
     8 bytes of packet payload. It means, that precise relaying of
     ICMP in the real Internet is absolutely infeasible.
   */
-       struct iphdr *iph = (struct iphdr*)skb->data;
+       const struct iphdr *iph = (const struct iphdr *)skb->data;
        const int type = icmp_hdr(skb)->type;
        const int code = icmp_hdr(skb)->code;
        struct ip_tunnel *t;
@@@ -552,7 -553,7 +548,7 @@@ out
        return err;
  }
  
- static inline void ipip6_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb)
+ static inline void ipip6_ecn_decapsulate(const struct iphdr *iph, struct sk_buff *skb)
  {
        if (INET_ECN_is_ce(iph->tos))
                IP6_ECN_set_ce(ipv6_hdr(skb));
  
  static int ipip6_rcv(struct sk_buff *skb)
  {
-       struct iphdr *iph;
+       const struct iphdr *iph;
        struct ip_tunnel *tunnel;
  
        if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
@@@ -616,7 -617,7 +612,7 @@@ out
   * comes from 6rd / 6to4 (RFC 3056) addr space.
   */
  static inline
- __be32 try_6rd(struct in6_addr *v6dst, struct ip_tunnel *tunnel)
+ __be32 try_6rd(const struct in6_addr *v6dst, struct ip_tunnel *tunnel)
  {
        __be32 dst = 0;
  
@@@ -659,8 -660,8 +655,8 @@@ static netdev_tx_t ipip6_tunnel_xmit(st
  {
        struct ip_tunnel *tunnel = netdev_priv(dev);
        struct pcpu_tstats *tstats;
-       struct iphdr  *tiph = &tunnel->parms.iph;
-       struct ipv6hdr *iph6 = ipv6_hdr(skb);
+       const struct iphdr  *tiph = &tunnel->parms.iph;
+       const struct ipv6hdr *iph6 = ipv6_hdr(skb);
        u8     tos = tunnel->parms.iph.tos;
        __be16 df = tiph->frag_off;
        struct rtable *rt;                      /* Route to the other host */
        struct iphdr  *iph;                     /* Our new IP header */
        unsigned int max_headroom;              /* The extra header space needed */
        __be32 dst = tiph->daddr;
+       struct flowi4 fl4;
        int    mtu;
-       struct in6_addr *addr6;
+       const struct in6_addr *addr6;
        int addr_type;
  
        if (skb->protocol != htons(ETH_P_IPV6))
                        goto tx_error;
                }
  
-               addr6 = (struct in6_addr*)&neigh->primary_key;
+               addr6 = (const struct in6_addr*)&neigh->primary_key;
                addr_type = ipv6_addr_type(addr6);
  
                if ((addr_type & IPV6_ADDR_UNICAST) &&
                        goto tx_error;
                }
  
-               addr6 = (struct in6_addr*)&neigh->primary_key;
+               addr6 = (const struct in6_addr*)&neigh->primary_key;
                addr_type = ipv6_addr_type(addr6);
  
                if (addr_type == IPV6_ADDR_ANY) {
                dst = addr6->s6_addr32[3];
        }
  
-       rt = ip_route_output_ports(dev_net(dev), NULL,
+       rt = ip_route_output_ports(dev_net(dev), &fl4, NULL,
                                   dst, tiph->saddr,
                                   0, 0,
                                   IPPROTO_IPV6, RT_TOS(tos),
        iph->frag_off           =       df;
        iph->protocol           =       IPPROTO_IPV6;
        iph->tos                =       INET_ECN_encapsulate(tos, ipv6_get_dsfield(iph6));
-       iph->daddr              =       rt->rt_dst;
-       iph->saddr              =       rt->rt_src;
+       iph->daddr              =       fl4.daddr;
+       iph->saddr              =       fl4.saddr;
  
        if ((iph->ttl = tiph->ttl) == 0)
                iph->ttl        =       iph6->hop_limit;
@@@ -844,13 -846,14 +841,14 @@@ static void ipip6_tunnel_bind_dev(struc
  {
        struct net_device *tdev = NULL;
        struct ip_tunnel *tunnel;
-       struct iphdr *iph;
+       const struct iphdr *iph;
+       struct flowi4 fl4;
  
        tunnel = netdev_priv(dev);
        iph = &tunnel->parms.iph;
  
        if (iph->daddr) {
-               struct rtable *rt = ip_route_output_ports(dev_net(dev), NULL,
+               struct rtable *rt = ip_route_output_ports(dev_net(dev), &fl4, NULL,
                                                          iph->daddr, iph->saddr,
                                                          0, 0,
                                                          IPPROTO_IPV6,
diff --combined net/l2tp/l2tp_ip.c
@@@ -296,12 -296,12 +296,12 @@@ out_in_use
  
  static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
  {
-       int rc;
-       struct inet_sock *inet = inet_sk(sk);
        struct sockaddr_l2tpip *lsa = (struct sockaddr_l2tpip *) uaddr;
+       struct inet_sock *inet = inet_sk(sk);
+       struct flowi4 *fl4;
        struct rtable *rt;
        __be32 saddr;
-       int oif;
+       int oif, rc;
  
        rc = -EINVAL;
        if (addr_len < sizeof(*lsa))
        if (lsa->l2tp_family != AF_INET)
                goto out;
  
+       lock_sock(sk);
        sk_dst_reset(sk);
  
        oif = sk->sk_bound_dev_if;
        if (ipv4_is_multicast(lsa->l2tp_addr.s_addr))
                goto out;
  
-       rt = ip_route_connect(lsa->l2tp_addr.s_addr, saddr,
+       fl4 = &inet->cork.fl.u.ip4;
+       rt = ip_route_connect(fl4, lsa->l2tp_addr.s_addr, saddr,
                              RT_CONN_FLAGS(sk), oif,
                              IPPROTO_L2TP,
                              0, 0, sk, true);
        l2tp_ip_sk(sk)->peer_conn_id = lsa->l2tp_conn_id;
  
        if (!inet->inet_saddr)
-               inet->inet_saddr = rt->rt_src;
+               inet->inet_saddr = fl4->saddr;
        if (!inet->inet_rcv_saddr)
-               inet->inet_rcv_saddr = rt->rt_src;
-       inet->inet_daddr = rt->rt_dst;
+               inet->inet_rcv_saddr = fl4->saddr;
+       inet->inet_daddr = fl4->daddr;
        sk->sk_state = TCP_ESTABLISHED;
        inet->inet_id = jiffies;
  
  
        rc = 0;
  out:
+       release_sock(sk);
        return rc;
  }
  
@@@ -416,23 -420,28 +420,28 @@@ static int l2tp_ip_sendmsg(struct kioc
        int rc;
        struct l2tp_ip_sock *lsa = l2tp_ip_sk(sk);
        struct inet_sock *inet = inet_sk(sk);
-       struct ip_options *opt = inet->opt;
        struct rtable *rt = NULL;
+       struct flowi4 *fl4;
        int connected = 0;
        __be32 daddr;
  
+       lock_sock(sk);
+       rc = -ENOTCONN;
        if (sock_flag(sk, SOCK_DEAD))
-               return -ENOTCONN;
+               goto out;
  
        /* Get and verify the address. */
        if (msg->msg_name) {
                struct sockaddr_l2tpip *lip = (struct sockaddr_l2tpip *) msg->msg_name;
+               rc = -EINVAL;
                if (msg->msg_namelen < sizeof(*lip))
-                       return -EINVAL;
+                       goto out;
  
                if (lip->l2tp_family != AF_INET) {
+                       rc = -EAFNOSUPPORT;
                        if (lip->l2tp_family != AF_UNSPEC)
-                               return -EAFNOSUPPORT;
+                               goto out;
                }
  
                daddr = lip->l2tp_addr.s_addr;
                goto error;
        }
  
+       fl4 = &inet->cork.fl.u.ip4;
        if (connected)
                rt = (struct rtable *) __sk_dst_check(sk, 0);
  
        if (rt == NULL) {
+               struct ip_options_rcu *inet_opt;
+               rcu_read_lock();
+               inet_opt = rcu_dereference(inet->inet_opt);
                /* Use correct destination address if we have options. */
-               if (opt && opt->srr)
-                       daddr = opt->faddr;
+               if (inet_opt && inet_opt->opt.srr)
+                       daddr = inet_opt->opt.faddr;
+               rcu_read_unlock();
  
                /* If this fails, retransmit mechanism of transport layer will
                 * keep trying until route appears or the connection times
                 * itself out.
                 */
-               rt = ip_route_output_ports(sock_net(sk), sk,
+               rt = ip_route_output_ports(sock_net(sk), fl4, sk,
                                           daddr, inet->inet_saddr,
                                           inet->inet_dport, inet->inet_sport,
                                           sk->sk_protocol, RT_CONN_FLAGS(sk),
        skb_dst_set(skb, dst_clone(&rt->dst));
  
        /* Queue the packet to IP for output */
-       rc = ip_queue_xmit(skb);
+       rc = ip_queue_xmit(skb, &inet->cork.fl);
  
  error:
        /* Update stats */
                lsa->tx_errors++;
        }
  
+ out:
+       release_sock(sk);
        return rc;
  
  no_route:
        IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES);
        kfree_skb(skb);
-       return -EHOSTUNREACH;
+       rc = -EHOSTUNREACH;
+       goto out;
  }
  
  static int l2tp_ip_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
@@@ -667,7 -687,7 +687,7 @@@ MODULE_AUTHOR("James Chapman <jchapman@
  MODULE_DESCRIPTION("L2TP over IP");
  MODULE_VERSION("1.0");
  
 -/* Use the value of SOCK_DGRAM (2) directory, because __stringify does't like
 +/* Use the value of SOCK_DGRAM (2) directory, because __stringify doesn't like
   * enums
   */
  MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, 2, IPPROTO_L2TP);
diff --combined net/mac80211/agg-tx.c
@@@ -136,26 -136,45 +136,37 @@@ void ieee80211_send_bar(struct ieee8021
        ieee80211_tx_skb(sdata, skb);
  }
  
 -static void kfree_tid_tx(struct rcu_head *rcu_head)
 -{
 -      struct tid_ampdu_tx *tid_tx =
 -          container_of(rcu_head, struct tid_ampdu_tx, rcu_head);
 -
 -      kfree(tid_tx);
 -}
 -
+ void ieee80211_assign_tid_tx(struct sta_info *sta, int tid,
+                            struct tid_ampdu_tx *tid_tx)
+ {
+       lockdep_assert_held(&sta->ampdu_mlme.mtx);
+       lockdep_assert_held(&sta->lock);
+       rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx);
+ }
  int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
                                    enum ieee80211_back_parties initiator,
                                    bool tx)
  {
        struct ieee80211_local *local = sta->local;
-       struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid];
+       struct tid_ampdu_tx *tid_tx;
        int ret;
  
        lockdep_assert_held(&sta->ampdu_mlme.mtx);
  
-       if (!tid_tx)
-               return -ENOENT;
        spin_lock_bh(&sta->lock);
  
+       tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
+       if (!tid_tx) {
+               spin_unlock_bh(&sta->lock);
+               return -ENOENT;
+       }
        if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) {
                /* not even started yet! */
-               rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL);
+               ieee80211_assign_tid_tx(sta, tid, NULL);
                spin_unlock_bh(&sta->lock);
 -              call_rcu(&tid_tx->rcu_head, kfree_tid_tx);
 +              kfree_rcu(tid_tx, rcu_head);
                return 0;
        }
  
@@@ -275,13 -294,13 +286,13 @@@ ieee80211_wake_queue_agg(struct ieee802
  
  void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
  {
-       struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid];
+       struct tid_ampdu_tx *tid_tx;
        struct ieee80211_local *local = sta->local;
        struct ieee80211_sub_if_data *sdata = sta->sdata;
        u16 start_seq_num;
        int ret;
  
-       lockdep_assert_held(&sta->ampdu_mlme.mtx);
+       tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
  
        /*
         * While we're asking the driver about the aggregation,
                                        " tid %d\n", tid);
  #endif
                spin_lock_bh(&sta->lock);
-               rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL);
+               ieee80211_assign_tid_tx(sta, tid, NULL);
                spin_unlock_bh(&sta->lock);
  
                ieee80211_wake_queue_agg(local, tid);
 -              call_rcu(&tid_tx->rcu_head, kfree_tid_tx);
 +              kfree_rcu(tid_tx, rcu_head);
                return;
        }
  
@@@ -388,9 -407,9 +399,9 @@@ int ieee80211_start_tx_ba_session(struc
                goto err_unlock_sta;
        }
  
-       tid_tx = sta->ampdu_mlme.tid_tx[tid];
+       tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
        /* check if the TID is not in aggregation flow already */
-       if (tid_tx) {
+       if (tid_tx || sta->ampdu_mlme.tid_start_tx[tid]) {
  #ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "BA request denied - session is not "
                                 "idle on tid %u\n", tid);
        sta->ampdu_mlme.dialog_token_allocator++;
        tid_tx->dialog_token = sta->ampdu_mlme.dialog_token_allocator;
  
-       /* finally, assign it to the array */
-       rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx);
+       /*
+        * Finally, assign it to the start array; the work item will
+        * collect it and move it to the normal array.
+        */
+       sta->ampdu_mlme.tid_start_tx[tid] = tid_tx;
  
        ieee80211_queue_work(&local->hw, &sta->ampdu_mlme.work);
  
@@@ -472,16 -494,19 +486,19 @@@ ieee80211_agg_splice_finish(struct ieee
  static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
                                         struct sta_info *sta, u16 tid)
  {
+       struct tid_ampdu_tx *tid_tx;
        lockdep_assert_held(&sta->ampdu_mlme.mtx);
  
+       tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
  #ifdef CONFIG_MAC80211_HT_DEBUG
        printk(KERN_DEBUG "Aggregation is on for tid %d\n", tid);
  #endif
  
        drv_ampdu_action(local, sta->sdata,
                         IEEE80211_AMPDU_TX_OPERATIONAL,
-                        &sta->sta, tid, NULL,
-                        sta->ampdu_mlme.tid_tx[tid]->buf_size);
+                        &sta->sta, tid, NULL, tid_tx->buf_size);
  
        /*
         * synchronize with TX path, while splicing the TX path
         */
        spin_lock_bh(&sta->lock);
  
-       ieee80211_agg_splice_packets(local, sta->ampdu_mlme.tid_tx[tid], tid);
+       ieee80211_agg_splice_packets(local, tid_tx, tid);
        /*
         * Now mark as operational. This will be visible
         * in the TX path, and lets it go lock-free in
         * the common case.
         */
-       set_bit(HT_AGG_STATE_OPERATIONAL, &sta->ampdu_mlme.tid_tx[tid]->state);
+       set_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state);
        ieee80211_agg_splice_finish(local, tid);
  
        spin_unlock_bh(&sta->lock);
@@@ -529,7 -554,7 +546,7 @@@ void ieee80211_start_tx_ba_cb(struct ie
        }
  
        mutex_lock(&sta->ampdu_mlme.mtx);
-       tid_tx = sta->ampdu_mlme.tid_tx[tid];
+       tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
  
        if (WARN_ON(!tid_tx)) {
  #ifdef CONFIG_MAC80211_HT_DEBUG
@@@ -607,7 -632,7 +624,7 @@@ int ieee80211_stop_tx_ba_session(struc
                return -EINVAL;
  
        spin_lock_bh(&sta->lock);
-       tid_tx = sta->ampdu_mlme.tid_tx[tid];
+       tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
  
        if (!tid_tx) {
                ret = -ENOENT;
@@@ -663,7 -688,7 +680,7 @@@ void ieee80211_stop_tx_ba_cb(struct iee
  
        mutex_lock(&sta->ampdu_mlme.mtx);
        spin_lock_bh(&sta->lock);
-       tid_tx = sta->ampdu_mlme.tid_tx[tid];
+       tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
  
        if (!tid_tx || !test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
  #ifdef CONFIG_MAC80211_HT_DEBUG
        ieee80211_agg_splice_packets(local, tid_tx, tid);
  
        /* future packets must not find the tid_tx struct any more */
-       rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL);
+       ieee80211_assign_tid_tx(sta, tid, NULL);
  
        ieee80211_agg_splice_finish(local, tid);
  
 -      call_rcu(&tid_tx->rcu_head, kfree_tid_tx);
 +      kfree_rcu(tid_tx, rcu_head);
  
   unlock_sta:
        spin_unlock_bh(&sta->lock);
@@@ -744,7 -769,7 +761,7 @@@ void ieee80211_process_addba_resp(struc
  
        mutex_lock(&sta->ampdu_mlme.mtx);
  
-       tid_tx = sta->ampdu_mlme.tid_tx[tid];
+       tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
        if (!tid_tx)
                goto out;
  
diff --combined net/mac80211/work.c
@@@ -65,9 -65,17 +65,9 @@@ static void run_again(struct ieee80211_
                mod_timer(&local->work_timer, timeout);
  }
  
 -static void work_free_rcu(struct rcu_head *head)
 -{
 -      struct ieee80211_work *wk =
 -              container_of(head, struct ieee80211_work, rcu_head);
 -
 -      kfree(wk);
 -}
 -
  void free_work(struct ieee80211_work *wk)
  {
 -      call_rcu(&wk->rcu_head, work_free_rcu);
 +      kfree_rcu(wk, rcu_head);
  }
  
  static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len,
@@@ -190,9 -198,8 +190,8 @@@ static void ieee80211_send_assoc(struc
        struct sk_buff *skb;
        struct ieee80211_mgmt *mgmt;
        u8 *pos, qos_info;
-       const u8 *ies;
        size_t offset = 0, noffset;
-       int i, len, count, rates_len, supp_rates_len;
+       int i, count, rates_len, supp_rates_len;
        u16 capab;
        struct ieee80211_supported_band *sband;
        u32 rates = 0;
        }
  
        /* SSID */
-       ies = pos = skb_put(skb, 2 + wk->assoc.ssid_len);
+       pos = skb_put(skb, 2 + wk->assoc.ssid_len);
        *pos++ = WLAN_EID_SSID;
        *pos++ = wk->assoc.ssid_len;
        memcpy(pos, wk->assoc.ssid, wk->assoc.ssid_len);
        if (supp_rates_len > 8)
                supp_rates_len = 8;
  
-       len = sband->n_bitrates;
        pos = skb_put(skb, supp_rates_len + 2);
        *pos++ = WLAN_EID_SUPP_RATES;
        *pos++ = supp_rates_len;
diff --combined net/phonet/pn_dev.c
@@@ -162,6 -162,14 +162,6 @@@ int phonet_address_add(struct net_devic
        return err;
  }
  
 -static void phonet_device_rcu_free(struct rcu_head *head)
 -{
 -      struct phonet_device *pnd;
 -
 -      pnd = container_of(head, struct phonet_device, rcu);
 -      kfree(pnd);
 -}
 -
  int phonet_address_del(struct net_device *dev, u8 addr)
  {
        struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev));
        mutex_unlock(&pndevs->lock);
  
        if (pnd)
 -              call_rcu(&pnd->rcu, phonet_device_rcu_free);
 +              kfree_rcu(pnd, rcu);
  
        return err;
  }
@@@ -418,18 -426,14 +418,14 @@@ int phonet_route_del(struct net_device 
        return 0;
  }
  
- struct net_device *phonet_route_get(struct net *net, u8 daddr)
+ struct net_device *phonet_route_get_rcu(struct net *net, u8 daddr)
  {
        struct phonet_net *pnn = phonet_pernet(net);
        struct phonet_routes *routes = &pnn->routes;
        struct net_device *dev;
  
-       ASSERT_RTNL(); /* no need to hold the device */
        daddr >>= 2;
-       rcu_read_lock();
        dev = rcu_dereference(routes->table[daddr]);
-       rcu_read_unlock();
        return dev;
  }
  
diff --combined net/sctp/bind_addr.c
@@@ -140,14 -140,12 +140,12 @@@ void sctp_bind_addr_init(struct sctp_bi
  /* Dispose of the address list. */
  static void sctp_bind_addr_clean(struct sctp_bind_addr *bp)
  {
-       struct sctp_sockaddr_entry *addr;
-       struct list_head *pos, *temp;
+       struct sctp_sockaddr_entry *addr, *temp;
  
        /* Empty the bind address list. */
-       list_for_each_safe(pos, temp, &bp->address_list) {
-               addr = list_entry(pos, struct sctp_sockaddr_entry, list);
-               list_del(pos);
-               kfree(addr);
+       list_for_each_entry_safe(addr, temp, &bp->address_list, list) {
+               list_del_rcu(&addr->list);
+               call_rcu(&addr->rcu, sctp_local_addr_free);
                SCTP_DBG_OBJCNT_DEC(addr);
        }
  }
@@@ -219,7 -217,7 +217,7 @@@ int sctp_del_bind_addr(struct sctp_bind
        }
  
        if (found) {
 -              call_rcu(&addr->rcu, sctp_local_addr_free);
 +              kfree_rcu(addr, rcu);
                SCTP_DBG_OBJCNT_DEC(addr);
                return 0;
        }
diff --combined net/sctp/ipv6.c
  
  #include <asm/uaccess.h>
  
+ static inline int sctp_v6_addr_match_len(union sctp_addr *s1,
+                                        union sctp_addr *s2);
+ static void sctp_v6_to_addr(union sctp_addr *addr, struct in6_addr *saddr,
+                             __be16 port);
+ static int sctp_v6_cmp_addr(const union sctp_addr *addr1,
+                           const union sctp_addr *addr2);
  /* Event handler for inet6 address addition/deletion events.
   * The sctp_local_addr_list needs to be protocted by a spin lock since
   * multiple notifiers (say IPv4 and IPv6) may be running at the same
@@@ -123,7 -130,7 +130,7 @@@ static int sctp_inet6addr_event(struct 
                }
                spin_unlock_bh(&sctp_local_addr_lock);
                if (found)
 -                      call_rcu(&addr->rcu, sctp_local_addr_free);
 +                      kfree_rcu(addr, rcu);
                break;
        }
  
@@@ -240,37 -247,107 +247,107 @@@ static int sctp_v6_xmit(struct sk_buff 
  /* Returns the dst cache entry for the given source and destination ip
   * addresses.
   */
- static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
-                                        union sctp_addr *daddr,
-                                        union sctp_addr *saddr)
+ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
+                           struct flowi *fl, struct sock *sk)
  {
-       struct dst_entry *dst;
-       struct flowi6 fl6;
+       struct sctp_association *asoc = t->asoc;
+       struct dst_entry *dst = NULL;
+       struct flowi6 *fl6 = &fl->u.ip6;
+       struct sctp_bind_addr *bp;
+       struct sctp_sockaddr_entry *laddr;
+       union sctp_addr *baddr = NULL;
+       union sctp_addr *daddr = &t->ipaddr;
+       union sctp_addr dst_saddr;
+       __u8 matchlen = 0;
+       __u8 bmatchlen;
+       sctp_scope_t scope;
  
-       memset(&fl6, 0, sizeof(fl6));
-       ipv6_addr_copy(&fl6.daddr, &daddr->v6.sin6_addr);
+       memset(fl6, 0, sizeof(struct flowi6));
+       ipv6_addr_copy(&fl6->daddr, &daddr->v6.sin6_addr);
+       fl6->fl6_dport = daddr->v6.sin6_port;
+       fl6->flowi6_proto = IPPROTO_SCTP;
        if (ipv6_addr_type(&daddr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL)
-               fl6.flowi6_oif = daddr->v6.sin6_scope_id;
+               fl6->flowi6_oif = daddr->v6.sin6_scope_id;
  
+       SCTP_DEBUG_PRINTK("%s: DST=%pI6 ", __func__, &fl6->daddr);
  
-       SCTP_DEBUG_PRINTK("%s: DST=%pI6 ", __func__, &fl6.daddr);
+       if (asoc)
+               fl6->fl6_sport = htons(asoc->base.bind_addr.port);
  
        if (saddr) {
-               ipv6_addr_copy(&fl6.saddr, &saddr->v6.sin6_addr);
-               SCTP_DEBUG_PRINTK("SRC=%pI6 - ", &fl6.saddr);
+               ipv6_addr_copy(&fl6->saddr, &saddr->v6.sin6_addr);
+               fl6->fl6_sport = saddr->v6.sin6_port;
+               SCTP_DEBUG_PRINTK("SRC=%pI6 - ", &fl6->saddr);
+       }
+       dst = ip6_dst_lookup_flow(sk, fl6, NULL, false);
+       if (!asoc || saddr)
+               goto out;
+       bp = &asoc->base.bind_addr;
+       scope = sctp_scope(daddr);
+       /* ip6_dst_lookup has filled in the fl6->saddr for us.  Check
+        * to see if we can use it.
+        */
+       if (!IS_ERR(dst)) {
+               /* Walk through the bind address list and look for a bind
+                * address that matches the source address of the returned dst.
+                */
+               sctp_v6_to_addr(&dst_saddr, &fl6->saddr, htons(bp->port));
+               rcu_read_lock();
+               list_for_each_entry_rcu(laddr, &bp->address_list, list) {
+                       if (!laddr->valid || (laddr->state != SCTP_ADDR_SRC))
+                               continue;
+                       /* Do not compare against v4 addrs */
+                       if ((laddr->a.sa.sa_family == AF_INET6) &&
+                           (sctp_v6_cmp_addr(&dst_saddr, &laddr->a))) {
+                               rcu_read_unlock();
+                               goto out;
+                       }
+               }
+               rcu_read_unlock();
+               /* None of the bound addresses match the source address of the
+                * dst. So release it.
+                */
+               dst_release(dst);
+               dst = NULL;
        }
  
-       dst = ip6_route_output(&init_net, NULL, &fl6);
-       if (!dst->error) {
+       /* Walk through the bind address list and try to get the
+        * best source address for a given destination.
+        */
+       rcu_read_lock();
+       list_for_each_entry_rcu(laddr, &bp->address_list, list) {
+               if (!laddr->valid && laddr->state != SCTP_ADDR_SRC)
+                       continue;
+               if ((laddr->a.sa.sa_family == AF_INET6) &&
+                   (scope <= sctp_scope(&laddr->a))) {
+                       bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a);
+                       if (!baddr || (matchlen < bmatchlen)) {
+                               baddr = &laddr->a;
+                               matchlen = bmatchlen;
+                       }
+               }
+       }
+       rcu_read_unlock();
+       if (baddr) {
+               ipv6_addr_copy(&fl6->saddr, &baddr->v6.sin6_addr);
+               fl6->fl6_sport = baddr->v6.sin6_port;
+               dst = ip6_dst_lookup_flow(sk, fl6, NULL, false);
+       }
+ out:
+       if (!IS_ERR(dst)) {
                struct rt6_info *rt;
                rt = (struct rt6_info *)dst;
+               t->dst = dst;
                SCTP_DEBUG_PRINTK("rt6_dst:%pI6 rt6_src:%pI6\n",
-                       &rt->rt6i_dst.addr, &rt->rt6i_src.addr);
-               return dst;
+                       &rt->rt6i_dst.addr, &fl6->saddr);
+       } else {
+               t->dst = NULL;
+               SCTP_DEBUG_PRINTK("NO ROUTE\n");
        }
-       SCTP_DEBUG_PRINTK("NO ROUTE\n");
-       dst_release(dst);
-       return NULL;
  }
  
  /* Returns the number of consecutive initial bits that match in the 2 ipv6
@@@ -286,64 -363,18 +363,18 @@@ static inline int sctp_v6_addr_match_le
   * and asoc's bind address list.
   */
  static void sctp_v6_get_saddr(struct sctp_sock *sk,
-                             struct sctp_association *asoc,
-                             struct dst_entry *dst,
-                             union sctp_addr *daddr,
-                             union sctp_addr *saddr)
+                             struct sctp_transport *t,
+                             struct flowi *fl)
  {
-       struct sctp_bind_addr *bp;
-       struct sctp_sockaddr_entry *laddr;
-       sctp_scope_t scope;
-       union sctp_addr *baddr = NULL;
-       __u8 matchlen = 0;
-       __u8 bmatchlen;
+       struct flowi6 *fl6 = &fl->u.ip6;
+       union sctp_addr *saddr = &t->saddr;
  
-       SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p daddr:%pI6 ",
-                         __func__, asoc, dst, &daddr->v6.sin6_addr);
-       if (!asoc) {
-               ipv6_dev_get_saddr(sock_net(sctp_opt2sk(sk)),
-                                  dst ? ip6_dst_idev(dst)->dev : NULL,
-                                  &daddr->v6.sin6_addr,
-                                  inet6_sk(&sk->inet.sk)->srcprefs,
-                                  &saddr->v6.sin6_addr);
-               SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: %pI6\n",
-                                 &saddr->v6.sin6_addr);
-               return;
-       }
-       scope = sctp_scope(daddr);
-       bp = &asoc->base.bind_addr;
+       SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p\n", __func__, t->asoc, t->dst);
  
-       /* Go through the bind address list and find the best source address
-        * that matches the scope of the destination address.
-        */
-       rcu_read_lock();
-       list_for_each_entry_rcu(laddr, &bp->address_list, list) {
-               if (!laddr->valid)
-                       continue;
-               if ((laddr->state == SCTP_ADDR_SRC) &&
-                   (laddr->a.sa.sa_family == AF_INET6) &&
-                   (scope <= sctp_scope(&laddr->a))) {
-                       bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a);
-                       if (!baddr || (matchlen < bmatchlen)) {
-                               baddr = &laddr->a;
-                               matchlen = bmatchlen;
-                       }
-               }
-       }
-       if (baddr) {
-               memcpy(saddr, baddr, sizeof(union sctp_addr));
-               SCTP_DEBUG_PRINTK("saddr: %pI6\n", &saddr->v6.sin6_addr);
-       } else {
-               pr_err("%s: asoc:%p Could not find a valid source "
-                      "address for the dest:%pI6\n",
-                      __func__, asoc, &daddr->v6.sin6_addr);
+       if (t->dst) {
+               saddr->v6.sin6_family = AF_INET6;
+               ipv6_addr_copy(&saddr->v6.sin6_addr, &fl6->saddr);
        }
-       rcu_read_unlock();
  }
  
  /* Make a copy of all potential local addresses. */
@@@ -465,14 -496,13 +496,13 @@@ static int sctp_v6_to_addr_param(const 
        return length;
  }
  
- /* Initialize a sctp_addr from a dst_entry. */
- static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst,
+ /* Initialize a sctp_addr from struct in6_addr. */
+ static void sctp_v6_to_addr(union sctp_addr *addr, struct in6_addr *saddr,
                              __be16 port)
  {
-       struct rt6_info *rt = (struct rt6_info *)dst;
        addr->sa.sa_family = AF_INET6;
        addr->v6.sin6_port = port;
-       ipv6_addr_copy(&addr->v6.sin6_addr, &rt->rt6i_src.addr);
+       ipv6_addr_copy(&addr->v6.sin6_addr, saddr);
  }
  
  /* Compare addresses exactly.
@@@ -531,7 -561,7 +561,7 @@@ static int sctp_v6_is_any(const union s
  static int sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp)
  {
        int type;
-       struct in6_addr *in6 = (struct in6_addr *)&addr->v6.sin6_addr;
+       const struct in6_addr *in6 = (const struct in6_addr *)&addr->v6.sin6_addr;
  
        type = ipv6_addr_type(in6);
        if (IPV6_ADDR_ANY == type)
@@@ -959,7 -989,6 +989,6 @@@ static struct sctp_af sctp_af_inet6 = 
        .to_sk_daddr       = sctp_v6_to_sk_daddr,
        .from_addr_param   = sctp_v6_from_addr_param,
        .to_addr_param     = sctp_v6_to_addr_param,
-       .dst_saddr         = sctp_v6_dst_saddr,
        .cmp_addr          = sctp_v6_cmp_addr,
        .scope             = sctp_v6_scope,
        .addr_valid        = sctp_v6_addr_valid,
diff --combined net/sctp/protocol.c
@@@ -230,6 -230,13 +230,6 @@@ static void sctp_free_local_addr_list(v
        }
  }
  
 -void sctp_local_addr_free(struct rcu_head *head)
 -{
 -      struct sctp_sockaddr_entry *e = container_of(head,
 -                              struct sctp_sockaddr_entry, rcu);
 -      kfree(e);
 -}
 -
  /* Copy the local addresses which are valid for 'scope' into 'bp'.  */
  int sctp_copy_local_addr_list(struct sctp_bind_addr *bp, sctp_scope_t scope,
                              gfp_t gfp, int copy_flags)
@@@ -332,13 -339,12 +332,12 @@@ static int sctp_v4_to_addr_param(const 
  }
  
  /* Initialize a sctp_addr from a dst_entry. */
- static void sctp_v4_dst_saddr(union sctp_addr *saddr, struct dst_entry *dst,
+ static void sctp_v4_dst_saddr(union sctp_addr *saddr, struct flowi4 *fl4,
                              __be16 port)
  {
-       struct rtable *rt = (struct rtable *)dst;
        saddr->v4.sin_family = AF_INET;
        saddr->v4.sin_port = port;
-       saddr->v4.sin_addr.s_addr = rt->rt_src;
+       saddr->v4.sin_addr.s_addr = fl4->saddr;
  }
  
  /* Compare two addresses exactly. */
@@@ -456,35 -462,36 +455,36 @@@ static sctp_scope_t sctp_v4_scope(unio
   * addresses. If an association is passed, trys to get a dst entry with a
   * source address that matches an address in the bind address list.
   */
- static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
-                                        union sctp_addr *daddr,
-                                        union sctp_addr *saddr)
+ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
+                               struct flowi *fl, struct sock *sk)
  {
+       struct sctp_association *asoc = t->asoc;
        struct rtable *rt;
-       struct flowi4 fl4;
+       struct flowi4 *fl4 = &fl->u.ip4;
        struct sctp_bind_addr *bp;
        struct sctp_sockaddr_entry *laddr;
        struct dst_entry *dst = NULL;
+       union sctp_addr *daddr = &t->ipaddr;
        union sctp_addr dst_saddr;
  
-       memset(&fl4, 0x0, sizeof(struct flowi4));
-       fl4.daddr  = daddr->v4.sin_addr.s_addr;
-       fl4.fl4_dport = daddr->v4.sin_port;
-       fl4.flowi4_proto = IPPROTO_SCTP;
+       memset(fl4, 0x0, sizeof(struct flowi4));
+       fl4->daddr  = daddr->v4.sin_addr.s_addr;
+       fl4->fl4_dport = daddr->v4.sin_port;
+       fl4->flowi4_proto = IPPROTO_SCTP;
        if (asoc) {
-               fl4.flowi4_tos = RT_CONN_FLAGS(asoc->base.sk);
-               fl4.flowi4_oif = asoc->base.sk->sk_bound_dev_if;
-               fl4.fl4_sport = htons(asoc->base.bind_addr.port);
+               fl4->flowi4_tos = RT_CONN_FLAGS(asoc->base.sk);
+               fl4->flowi4_oif = asoc->base.sk->sk_bound_dev_if;
+               fl4->fl4_sport = htons(asoc->base.bind_addr.port);
        }
        if (saddr) {
-               fl4.saddr = saddr->v4.sin_addr.s_addr;
-               fl4.fl4_sport = saddr->v4.sin_port;
+               fl4->saddr = saddr->v4.sin_addr.s_addr;
+               fl4->fl4_sport = saddr->v4.sin_port;
        }
  
        SCTP_DEBUG_PRINTK("%s: DST:%pI4, SRC:%pI4 - ",
-                         __func__, &fl4.daddr, &fl4.saddr);
+                         __func__, &fl4->daddr, &fl4->saddr);
  
-       rt = ip_route_output_key(&init_net, &fl4);
+       rt = ip_route_output_key(&init_net, fl4);
        if (!IS_ERR(rt))
                dst = &rt->dst;
  
                /* Walk through the bind address list and look for a bind
                 * address that matches the source address of the returned dst.
                 */
-               sctp_v4_dst_saddr(&dst_saddr, dst, htons(bp->port));
+               sctp_v4_dst_saddr(&dst_saddr, fl4, htons(bp->port));
                rcu_read_lock();
                list_for_each_entry_rcu(laddr, &bp->address_list, list) {
                        if (!laddr->valid || (laddr->state != SCTP_ADDR_SRC))
                        continue;
                if ((laddr->state == SCTP_ADDR_SRC) &&
                    (AF_INET == laddr->a.sa.sa_family)) {
-                       fl4.saddr = laddr->a.v4.sin_addr.s_addr;
-                       fl4.fl4_sport = laddr->a.v4.sin_port;
-                       rt = ip_route_output_key(&init_net, &fl4);
+                       fl4->saddr = laddr->a.v4.sin_addr.s_addr;
+                       fl4->fl4_sport = laddr->a.v4.sin_port;
+                       rt = ip_route_output_key(&init_net, fl4);
                        if (!IS_ERR(rt)) {
                                dst = &rt->dst;
                                goto out_unlock;
  out_unlock:
        rcu_read_unlock();
  out:
+       t->dst = dst;
        if (dst)
                SCTP_DEBUG_PRINTK("rt_dst:%pI4, rt_src:%pI4\n",
-                                 &rt->rt_dst, &rt->rt_src);
+                                 &fl4->daddr, &fl4->saddr);
        else
                SCTP_DEBUG_PRINTK("NO ROUTE\n");
-       return dst;
  }
  
  /* For v4, the source address is cached in the route entry(dst). So no need
   * to cache it separately and hence this is an empty routine.
   */
  static void sctp_v4_get_saddr(struct sctp_sock *sk,
-                             struct sctp_association *asoc,
-                             struct dst_entry *dst,
-                             union sctp_addr *daddr,
-                             union sctp_addr *saddr)
+                             struct sctp_transport *t,
+                             struct flowi *fl)
  {
-       struct rtable *rt = (struct rtable *)dst;
-       if (!asoc)
-               return;
+       union sctp_addr *saddr = &t->saddr;
+       struct rtable *rt = (struct rtable *)t->dst;
  
        if (rt) {
                saddr->v4.sin_family = AF_INET;
-               saddr->v4.sin_port = htons(asoc->base.bind_addr.port);
-               saddr->v4.sin_addr.s_addr = rt->rt_src;
+               saddr->v4.sin_addr.s_addr = fl->u.ip4.saddr;
        }
  }
  
@@@ -674,7 -675,7 +668,7 @@@ static int sctp_inetaddr_event(struct n
                }
                spin_unlock_bh(&sctp_local_addr_lock);
                if (found)
 -                      call_rcu(&addr->rcu, sctp_local_addr_free);
 +                      kfree_rcu(addr, rcu);
                break;
        }
  
@@@ -847,14 -848,14 +841,14 @@@ static inline int sctp_v4_xmit(struct s
  
        SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, src:%pI4, dst:%pI4\n",
                          __func__, skb, skb->len,
-                         &skb_rtable(skb)->rt_src,
-                         &skb_rtable(skb)->rt_dst);
+                         &transport->fl.u.ip4.saddr,
+                         &transport->fl.u.ip4.daddr);
  
        inet->pmtudisc = transport->param_flags & SPP_PMTUD_ENABLE ?
                         IP_PMTUDISC_DO : IP_PMTUDISC_DONT;
  
        SCTP_INC_STATS(SCTP_MIB_OUTSCTPPACKS);
-       return ip_queue_xmit(skb);
+       return ip_queue_xmit(skb, &transport->fl);
  }
  
  static struct sctp_af sctp_af_inet;
@@@ -943,7 -944,6 +937,6 @@@ static struct sctp_af sctp_af_inet = 
        .to_sk_daddr       = sctp_v4_to_sk_daddr,
        .from_addr_param   = sctp_v4_from_addr_param,
        .to_addr_param     = sctp_v4_to_addr_param,
-       .dst_saddr         = sctp_v4_dst_saddr,
        .cmp_addr          = sctp_v4_cmp_addr,
        .addr_valid        = sctp_v4_addr_valid,
        .inaddr_any        = sctp_v4_inaddr_any,
diff --combined net/sctp/ulpevent.c
@@@ -554,7 -554,7 +554,7 @@@ struct sctp_ulpevent *sctp_ulpevent_mak
        memcpy(&ssf->ssf_info, &chunk->sinfo, sizeof(struct sctp_sndrcvinfo));
  
        /* Per TSVWG discussion with Randy. Allow the application to
 -       * resemble a fragmented message.
 +       * reassemble a fragmented message.
         */
        ssf->ssf_info.sinfo_flags = chunk->chunk_hdr->flags;
  
@@@ -843,7 -843,7 +843,7 @@@ struct sctp_ulpevent *sctp_ulpevent_mak
        ak = (struct sctp_authkey_event *)
                skb_put(skb, sizeof(struct sctp_authkey_event));
  
-       ak->auth_type = SCTP_AUTHENTICATION_INDICATION;
+       ak->auth_type = SCTP_AUTHENTICATION_EVENT;
        ak->auth_flags = 0;
        ak->auth_length = sizeof(struct sctp_authkey_event);
  
@@@ -862,6 -862,34 +862,34 @@@ fail
        return NULL;
  }
  
+ /*
+  * Socket Extensions for SCTP
+  * 6.3.10. SCTP_SENDER_DRY_EVENT
+  */
+ struct sctp_ulpevent *sctp_ulpevent_make_sender_dry_event(
+       const struct sctp_association *asoc, gfp_t gfp)
+ {
+       struct sctp_ulpevent *event;
+       struct sctp_sender_dry_event *sdry;
+       struct sk_buff *skb;
+       event = sctp_ulpevent_new(sizeof(struct sctp_sender_dry_event),
+                                 MSG_NOTIFICATION, gfp);
+       if (!event)
+               return NULL;
+       skb = sctp_event2skb(event);
+       sdry = (struct sctp_sender_dry_event *)
+               skb_put(skb, sizeof(struct sctp_sender_dry_event));
+       sdry->sender_dry_type = SCTP_SENDER_DRY_EVENT;
+       sdry->sender_dry_flags = 0;
+       sdry->sender_dry_length = sizeof(struct sctp_sender_dry_event);
+       sctp_ulpevent_set_owner(event, asoc);
+       sdry->sender_dry_assoc_id = sctp_assoc2id(asoc);
+       return event;
+ }
  
  /* Return the notification type, assuming this is a notification
   * event.
diff --combined net/socket.c
@@@ -263,6 -263,15 +263,6 @@@ static struct inode *sock_alloc_inode(s
        return &ei->vfs_inode;
  }
  
 -
 -
 -static void wq_free_rcu(struct rcu_head *head)
 -{
 -      struct socket_wq *wq = container_of(head, struct socket_wq, rcu);
 -
 -      kfree(wq);
 -}
 -
  static void sock_destroy_inode(struct inode *inode)
  {
        struct socket_alloc *ei;
  
        ei = container_of(inode, struct socket_alloc, vfs_inode);
        wq = rcu_dereference_protected(ei->socket.wq, 1);
 -      call_rcu(&wq->rcu, wq_free_rcu);
 +      kfree_rcu(wq, rcu);
        kmem_cache_free(sock_inode_cachep, ei);
  }
  
@@@ -542,11 -551,10 +542,10 @@@ int sock_tx_timestamp(struct sock *sk, 
  }
  EXPORT_SYMBOL(sock_tx_timestamp);
  
- static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock,
-                                struct msghdr *msg, size_t size)
+ static inline int __sock_sendmsg_nosec(struct kiocb *iocb, struct socket *sock,
+                                      struct msghdr *msg, size_t size)
  {
        struct sock_iocb *si = kiocb_to_siocb(iocb);
-       int err;
  
        sock_update_classid(sock->sk);
  
        si->msg = msg;
        si->size = size;
  
-       err = security_socket_sendmsg(sock, msg, size);
-       if (err)
-               return err;
        return sock->ops->sendmsg(iocb, sock, msg, size);
  }
  
+ static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock,
+                                struct msghdr *msg, size_t size)
+ {
+       int err = security_socket_sendmsg(sock, msg, size);
+       return err ?: __sock_sendmsg_nosec(iocb, sock, msg, size);
+ }
  int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
  {
        struct kiocb iocb;
  }
  EXPORT_SYMBOL(sock_sendmsg);
  
+ int sock_sendmsg_nosec(struct socket *sock, struct msghdr *msg, size_t size)
+ {
+       struct kiocb iocb;
+       struct sock_iocb siocb;
+       int ret;
+       init_sync_kiocb(&iocb, NULL);
+       iocb.private = &siocb;
+       ret = __sock_sendmsg_nosec(&iocb, sock, msg, size);
+       if (-EIOCBQUEUED == ret)
+               ret = wait_on_sync_kiocb(&iocb);
+       return ret;
+ }
  int kernel_sendmsg(struct socket *sock, struct msghdr *msg,
                   struct kvec *vec, size_t num, size_t size)
  {
@@@ -1854,57 -1880,47 +1871,47 @@@ SYSCALL_DEFINE2(shutdown, int, fd, int
  #define COMPAT_NAMELEN(msg)   COMPAT_MSG(msg, msg_namelen)
  #define COMPAT_FLAGS(msg)     COMPAT_MSG(msg, msg_flags)
  
- /*
-  *    BSD sendmsg interface
-  */
- SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned, flags)
+ static int __sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
+                        struct msghdr *msg_sys, unsigned flags, int nosec)
  {
        struct compat_msghdr __user *msg_compat =
            (struct compat_msghdr __user *)msg;
-       struct socket *sock;
        struct sockaddr_storage address;
        struct iovec iovstack[UIO_FASTIOV], *iov = iovstack;
        unsigned char ctl[sizeof(struct cmsghdr) + 20]
            __attribute__ ((aligned(sizeof(__kernel_size_t))));
        /* 20 is size of ipv6_pktinfo */
        unsigned char *ctl_buf = ctl;
-       struct msghdr msg_sys;
        int err, ctl_len, iov_size, total_len;
-       int fput_needed;
  
        err = -EFAULT;
        if (MSG_CMSG_COMPAT & flags) {
-               if (get_compat_msghdr(&msg_sys, msg_compat))
+               if (get_compat_msghdr(msg_sys, msg_compat))
                        return -EFAULT;
-       } else if (copy_from_user(&msg_sys, msg, sizeof(struct msghdr)))
+       } else if (copy_from_user(msg_sys, msg, sizeof(struct msghdr)))
                return -EFAULT;
  
-       sock = sockfd_lookup_light(fd, &err, &fput_needed);
-       if (!sock)
-               goto out;
        /* do not move before msg_sys is valid */
        err = -EMSGSIZE;
-       if (msg_sys.msg_iovlen > UIO_MAXIOV)
-               goto out_put;
+       if (msg_sys->msg_iovlen > UIO_MAXIOV)
+               goto out;
  
        /* Check whether to allocate the iovec area */
        err = -ENOMEM;
-       iov_size = msg_sys.msg_iovlen * sizeof(struct iovec);
-       if (msg_sys.msg_iovlen > UIO_FASTIOV) {
+       iov_size = msg_sys->msg_iovlen * sizeof(struct iovec);
+       if (msg_sys->msg_iovlen > UIO_FASTIOV) {
                iov = sock_kmalloc(sock->sk, iov_size, GFP_KERNEL);
                if (!iov)
-                       goto out_put;
+                       goto out;
        }
  
        /* This will also move the address data into kernel space */
        if (MSG_CMSG_COMPAT & flags) {
-               err = verify_compat_iovec(&msg_sys, iov,
+               err = verify_compat_iovec(msg_sys, iov,
                                          (struct sockaddr *)&address,
                                          VERIFY_READ);
        } else
-               err = verify_iovec(&msg_sys, iov,
+               err = verify_iovec(msg_sys, iov,
                                   (struct sockaddr *)&address,
                                   VERIFY_READ);
        if (err < 0)
  
        err = -ENOBUFS;
  
-       if (msg_sys.msg_controllen > INT_MAX)
+       if (msg_sys->msg_controllen > INT_MAX)
                goto out_freeiov;
-       ctl_len = msg_sys.msg_controllen;
+       ctl_len = msg_sys->msg_controllen;
        if ((MSG_CMSG_COMPAT & flags) && ctl_len) {
                err =
-                   cmsghdr_from_user_compat_to_kern(&msg_sys, sock->sk, ctl,
+                   cmsghdr_from_user_compat_to_kern(msg_sys, sock->sk, ctl,
                                                     sizeof(ctl));
                if (err)
                        goto out_freeiov;
-               ctl_buf = msg_sys.msg_control;
-               ctl_len = msg_sys.msg_controllen;
+               ctl_buf = msg_sys->msg_control;
+               ctl_len = msg_sys->msg_controllen;
        } else if (ctl_len) {
                if (ctl_len > sizeof(ctl)) {
                        ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL);
                }
                err = -EFAULT;
                /*
-                * Careful! Before this, msg_sys.msg_control contains a user pointer.
+                * Careful! Before this, msg_sys->msg_control contains a user pointer.
                 * Afterwards, it will be a kernel pointer. Thus the compiler-assisted
                 * checking falls down on this.
                 */
                if (copy_from_user(ctl_buf,
-                                  (void __user __force *)msg_sys.msg_control,
+                                  (void __user __force *)msg_sys->msg_control,
                                   ctl_len))
                        goto out_freectl;
-               msg_sys.msg_control = ctl_buf;
+               msg_sys->msg_control = ctl_buf;
        }
-       msg_sys.msg_flags = flags;
+       msg_sys->msg_flags = flags;
  
        if (sock->file->f_flags & O_NONBLOCK)
-               msg_sys.msg_flags |= MSG_DONTWAIT;
-       err = sock_sendmsg(sock, &msg_sys, total_len);
+               msg_sys->msg_flags |= MSG_DONTWAIT;
+       err = (nosec ? sock_sendmsg_nosec : sock_sendmsg)(sock, msg_sys,
+                                                         total_len);
  
  out_freectl:
        if (ctl_buf != ctl)
  out_freeiov:
        if (iov != iovstack)
                sock_kfree_s(sock->sk, iov, iov_size);
- out_put:
+ out:
+       return err;
+ }
+ /*
+  *    BSD sendmsg interface
+  */
+ SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned, flags)
+ {
+       int fput_needed, err;
+       struct msghdr msg_sys;
+       struct socket *sock = sockfd_lookup_light(fd, &err, &fput_needed);
+       if (!sock)
+               goto out;
+       err = __sys_sendmsg(sock, msg, &msg_sys, flags, 0);
        fput_light(sock->file, fput_needed);
  out:
        return err;
  }
  
+ /*
+  *    Linux sendmmsg interface
+  */
+ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
+                  unsigned int flags)
+ {
+       int fput_needed, err, datagrams;
+       struct socket *sock;
+       struct mmsghdr __user *entry;
+       struct compat_mmsghdr __user *compat_entry;
+       struct msghdr msg_sys;
+       datagrams = 0;
+       sock = sockfd_lookup_light(fd, &err, &fput_needed);
+       if (!sock)
+               return err;
+       err = sock_error(sock->sk);
+       if (err)
+               goto out_put;
+       entry = mmsg;
+       compat_entry = (struct compat_mmsghdr __user *)mmsg;
+       while (datagrams < vlen) {
+               /*
+                * No need to ask LSM for more than the first datagram.
+                */
+               if (MSG_CMSG_COMPAT & flags) {
+                       err = __sys_sendmsg(sock, (struct msghdr __user *)compat_entry,
+                                           &msg_sys, flags, datagrams);
+                       if (err < 0)
+                               break;
+                       err = __put_user(err, &compat_entry->msg_len);
+                       ++compat_entry;
+               } else {
+                       err = __sys_sendmsg(sock, (struct msghdr __user *)entry,
+                                           &msg_sys, flags, datagrams);
+                       if (err < 0)
+                               break;
+                       err = put_user(err, &entry->msg_len);
+                       ++entry;
+               }
+               if (err)
+                       break;
+               ++datagrams;
+       }
+ out_put:
+       fput_light(sock->file, fput_needed);
+       if (err == 0)
+               return datagrams;
+       if (datagrams != 0) {
+               /*
+                * We may send less entries than requested (vlen) if the
+                * sock is non blocking...
+                */
+               if (err != -EAGAIN) {
+                       /*
+                        * ... or if sendmsg returns an error after we
+                        * send some datagrams, where we record the
+                        * error to return on the next call or if the
+                        * app asks about it using getsockopt(SO_ERROR).
+                        */
+                       sock->sk->sk_err = -err;
+               }
+               return datagrams;
+       }
+       return err;
+ }
+ SYSCALL_DEFINE4(sendmmsg, int, fd, struct mmsghdr __user *, mmsg,
+               unsigned int, vlen, unsigned int, flags)
+ {
+       return __sys_sendmmsg(fd, mmsg, vlen, flags);
+ }
  static int __sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
                         struct msghdr *msg_sys, unsigned flags, int nosec)
  {
@@@ -2113,14 -2232,16 +2223,16 @@@ int __sys_recvmmsg(int fd, struct mmsgh
                 */
                if (MSG_CMSG_COMPAT & flags) {
                        err = __sys_recvmsg(sock, (struct msghdr __user *)compat_entry,
-                                           &msg_sys, flags, datagrams);
+                                           &msg_sys, flags & ~MSG_WAITFORONE,
+                                           datagrams);
                        if (err < 0)
                                break;
                        err = __put_user(err, &compat_entry->msg_len);
                        ++compat_entry;
                } else {
                        err = __sys_recvmsg(sock, (struct msghdr __user *)entry,
-                                           &msg_sys, flags, datagrams);
+                                           &msg_sys, flags & ~MSG_WAITFORONE,
+                                           datagrams);
                        if (err < 0)
                                break;
                        err = put_user(err, &entry->msg_len);
@@@ -2205,11 -2326,11 +2317,11 @@@ SYSCALL_DEFINE5(recvmmsg, int, fd, stru
  #ifdef __ARCH_WANT_SYS_SOCKETCALL
  /* Argument list sizes for sys_socketcall */
  #define AL(x) ((x) * sizeof(unsigned long))
- static const unsigned char nargs[20] = {
+ static const unsigned char nargs[21] = {
        AL(0), AL(3), AL(3), AL(3), AL(2), AL(3),
        AL(3), AL(3), AL(4), AL(4), AL(4), AL(6),
        AL(6), AL(2), AL(5), AL(5), AL(3), AL(3),
-       AL(4), AL(5)
+       AL(4), AL(5), AL(4)
  };
  
  #undef AL
@@@ -2229,7 -2350,7 +2341,7 @@@ SYSCALL_DEFINE2(socketcall, int, call, 
        int err;
        unsigned int len;
  
-       if (call < 1 || call > SYS_RECVMMSG)
+       if (call < 1 || call > SYS_SENDMMSG)
                return -EINVAL;
  
        len = nargs[call];
        case SYS_SENDMSG:
                err = sys_sendmsg(a0, (struct msghdr __user *)a1, a[2]);
                break;
+       case SYS_SENDMMSG:
+               err = sys_sendmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3]);
+               break;
        case SYS_RECVMSG:
                err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]);
                break;
@@@ -2634,13 -2758,13 +2749,13 @@@ static int ethtool_ioctl(struct net *ne
                return -EFAULT;
  
        if (convert_in) {
-               /* We expect there to be holes between fs.m_u and
+               /* We expect there to be holes between fs.m_ext and
                 * fs.ring_cookie and at the end of fs, but nowhere else.
                 */
-               BUILD_BUG_ON(offsetof(struct compat_ethtool_rxnfc, fs.m_u) +
-                            sizeof(compat_rxnfc->fs.m_u) !=
-                            offsetof(struct ethtool_rxnfc, fs.m_u) +
-                            sizeof(rxnfc->fs.m_u));
+               BUILD_BUG_ON(offsetof(struct compat_ethtool_rxnfc, fs.m_ext) +
+                            sizeof(compat_rxnfc->fs.m_ext) !=
+                            offsetof(struct ethtool_rxnfc, fs.m_ext) +
+                            sizeof(rxnfc->fs.m_ext));
                BUILD_BUG_ON(
                        offsetof(struct compat_ethtool_rxnfc, fs.location) -
                        offsetof(struct compat_ethtool_rxnfc, fs.ring_cookie) !=
                        offsetof(struct ethtool_rxnfc, fs.ring_cookie));
  
                if (copy_in_user(rxnfc, compat_rxnfc,
-                                (void *)(&rxnfc->fs.m_u + 1) -
+                                (void *)(&rxnfc->fs.m_ext + 1) -
                                 (void *)rxnfc) ||
                    copy_in_user(&rxnfc->fs.ring_cookie,
                                 &compat_rxnfc->fs.ring_cookie,
  
        if (convert_out) {
                if (copy_in_user(compat_rxnfc, rxnfc,
-                                (const void *)(&rxnfc->fs.m_u + 1) -
+                                (const void *)(&rxnfc->fs.m_ext + 1) -
                                 (const void *)rxnfc) ||
                    copy_in_user(&compat_rxnfc->fs.ring_cookie,
                                 &rxnfc->fs.ring_cookie,