The following commit has been merged in the master branch: commit 7f1adb0db4f6130f42f408e21d3241cc67fe70e1 Merge: e5b381acc3da755a56df131e5522420e9e6de9b4 6686c459e1449a3ee5f3fd313b0a559ace7a700e Author: Stephen Rothwell sfr@canb.auug.org.au Date: Fri Mar 23 11:08:39 2018 +1100
Merge remote-tracking branch 'net-next/master'
diff --combined Documentation/devicetree/bindings/net/dsa/marvell.txt index 8c033d48e2ba,caf71e2fe24a..60d50a2b0323 --- a/Documentation/devicetree/bindings/net/dsa/marvell.txt +++ b/Documentation/devicetree/bindings/net/dsa/marvell.txt @@@ -13,9 -13,18 +13,18 @@@ placed as a child node of an mdio devic The properties described here are those specific to Marvell devices. Additional required and optional properties can be found in dsa.txt.
+ The compatibility string is used only to find an identification register, + which is at a different MDIO base address in different switch families. + - "marvell,mv88e6085" : Switch has base address 0x10. Use with models: + 6085, 6095, 6097, 6123, 6131, 6141, 6161, 6165, + 6171, 6172, 6175, 6176, 6185, 6240, 6320, 6321, + 6341, 6350, 6351, 6352 + - "marvell,mv88e6190" : Switch has base address 0x00. Use with models: + 6190, 6190X, 6191, 6290, 6390, 6390X + Required properties: - compatible : Should be one of "marvell,mv88e6085" or - "marvell,mv88e6190" + "marvell,mv88e6190" as indicated above - reg : Address on the MII bus for the switch.
Optional properties: @@@ -50,15 -59,14 +59,15 @@@ Example compatible = "marvell,mv88e6085"; reg = <0>; reset-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>; - }; - mdio { - #address-cells = <1>; - #size-cells = <0>; - switch1phy0: switch1phy0@0 { - reg = <0>; - interrupt-parent = <&switch0>; - interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + switch1phy0: switch1phy0@0 { + reg = <0>; + interrupt-parent = <&switch0>; + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + }; }; }; }; @@@ -75,24 -83,23 +84,24 @@@ compatible = "marvell,mv88e6390"; reg = <0>; reset-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>; - }; - mdio { - #address-cells = <1>; - #size-cells = <0>; - switch1phy0: switch1phy0@0 { - reg = <0>; - interrupt-parent = <&switch0>; - interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + switch1phy0: switch1phy0@0 { + reg = <0>; + interrupt-parent = <&switch0>; + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + }; }; - };
- mdio1 { - compatible = "marvell,mv88e6xxx-mdio-external"; - #address-cells = <1>; - #size-cells = <0>; - switch1phy9: switch1phy0@9 { - reg = <9>; + mdio1 { + compatible = "marvell,mv88e6xxx-mdio-external"; + #address-cells = <1>; + #size-cells = <0>; + switch1phy9: switch1phy0@9 { + reg = <9>; + }; }; }; }; diff --combined MAINTAINERS index e6f48305c70c,214c9bca232a..a63244b31f58 --- a/MAINTAINERS +++ b/MAINTAINERS @@@ -866,17 -866,7 +866,17 @@@ F: drivers/iio/*/ad F: drivers/iio/adc/ltc2497* X: drivers/iio/*/adjd* F: drivers/staging/iio/*/ad* -F: drivers/staging/iio/trigger/iio-trig-bfin-timer.c + +ANDES ARCHITECTURE +M: Greentime Hu green.hu@gmail.com +M: Vincent Chen deanbo422@gmail.com +T: git https://github.com/andestech/linux.git +S: Supported +F: arch/nds32/ +F: Documentation/devicetree/bindings/interrupt-controller/andestech,ativic32.txt +F: Documentation/devicetree/bindings/nds32/ +K: nds32 +N: nds32
ANDROID CONFIG FRAGMENTS M: Rob Herring robh@kernel.org @@@ -1162,7 -1152,7 +1162,7 @@@ S: Maintaine F: drivers/clk/sunxi/
ARM/Allwinner sunXi SoC support -M: Maxime Ripard maxime.ripard@free-electrons.com +M: Maxime Ripard maxime.ripard@bootlin.com M: Chen-Yu Tsai wens@csie.org L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained @@@ -1246,6 -1236,27 +1246,6 @@@ M: Boris Brezillon <boris.brezillon@fre S: Maintained F: drivers/clk/at91
-ARM/ATMEL AT91RM9200, AT91SAM9 AND SAMA5 SOC SUPPORT -M: Nicolas Ferre nicolas.ferre@microchip.com -M: Alexandre Belloni alexandre.belloni@bootlin.com -L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -W: http://www.linux4sam.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/nferre/linux-at91.git -S: Supported -N: at91 -N: atmel -F: arch/arm/mach-at91/ -F: include/soc/at91/ -F: arch/arm/boot/dts/at91*.dts -F: arch/arm/boot/dts/at91*.dtsi -F: arch/arm/boot/dts/sama*.dts -F: arch/arm/boot/dts/sama*.dtsi -F: arch/arm/include/debug/at91.S -F: drivers/memory/atmel* -F: drivers/watchdog/sama5d4_wdt.c -X: drivers/input/touchscreen/atmel_mxt_ts.c -X: drivers/net/wireless/atmel/ - ARM/CALXEDA HIGHBANK ARCHITECTURE M: Rob Herring robh@kernel.org L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) @@@ -1645,27 -1656,6 +1645,27 @@@ L: linux-arm-kernel@lists.infradead.or F: arch/arm/mach-ks8695/ S: Odd Fixes
+ARM/Microchip (AT91) SoC support +M: Nicolas Ferre nicolas.ferre@microchip.com +M: Alexandre Belloni alexandre.belloni@bootlin.com +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) +W: http://www.linux4sam.org +T: git git://git.kernel.org/pub/scm/linux/kernel/git/nferre/linux-at91.git +S: Supported +N: at91 +N: atmel +F: arch/arm/mach-at91/ +F: include/soc/at91/ +F: arch/arm/boot/dts/at91*.dts +F: arch/arm/boot/dts/at91*.dtsi +F: arch/arm/boot/dts/sama*.dts +F: arch/arm/boot/dts/sama*.dtsi +F: arch/arm/include/debug/at91.S +F: drivers/memory/atmel* +F: drivers/watchdog/sama5d4_wdt.c +X: drivers/input/touchscreen/atmel_mxt_ts.c +X: drivers/net/wireless/atmel/ + ARM/MIOA701 MACHINE SUPPORT M: Robert Jarzmik robert.jarzmik@free.fr L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) @@@ -1710,20 -1700,6 +1710,20 @@@ F: Documentation/devicetree/bindings/ar F: Documentation/devicetree/bindings/arm/ux500/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-nomadik.git
+ARM/NUVOTON NPCM ARCHITECTURE +M: Avi Fishman avifishman70@gmail.com +M: Tomer Maimon tmaimon77@gmail.com +R: Patrick Venture venture@google.com +R: Nancy Yuen yuenn@google.com +R: Brendan Higgins brendanhiggins@google.com +L: openbmc@lists.ozlabs.org (moderated for non-subscribers) +S: Supported +F: arch/arm/mach-npcm/ +F: arch/arm/boot/dts/nuvoton-npcm* +F: include/dt-bindings/clock/nuvoton,npcm7xx-clks.h +F: drivers/*/*npcm* +F: Documentation/*/*npcm* + ARM/NUVOTON W90X900 ARM ARCHITECTURE M: Wan ZongShun mcuos.com@gmail.com L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) @@@ -1887,6 -1863,7 +1887,6 @@@ Q: https://patchwork.kernel.org/project S: Maintained F: arch/arm/boot/dts/s3c* F: arch/arm/boot/dts/s5p* -F: arch/arm/boot/dts/samsung* F: arch/arm/boot/dts/exynos* F: arch/arm64/boot/dts/exynos/ F: arch/arm/plat-samsung/ @@@ -1986,14 -1963,6 +1986,14 @@@ M: Thor Thayer <thor.thayer@linux.intel S: Maintained F: drivers/edac/altera_edac.
+ARM/SPREADTRUM SoC SUPPORT +M: Orson Zhai orsonzhai@gmail.com +M: Baolin Wang baolin.wang@linaro.org +M: Chunyan Zhang zhang.lyra@gmail.com +S: Maintained +F: arch/arm64/boot/dts/sprd +N: sprd + ARM/STI ARCHITECTURE M: Patrice Chotard patrice.chotard@st.com L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) @@@ -2660,6 -2629,51 +2660,6 @@@ F: Documentation/filesystems/bfs.tx F: fs/bfs/ F: include/uapi/linux/bfs_fs.h
-BLACKFIN ARCHITECTURE -L: adi-buildroot-devel@lists.sourceforge.net (moderated for non-subscribers) -T: git git://git.code.sf.net/p/adi-linux/code -W: http://blackfin.uclinux.org -S: Orphan -F: arch/blackfin/ - -BLACKFIN EMAC DRIVER -L: adi-buildroot-devel@lists.sourceforge.net (moderated for non-subscribers) -W: http://blackfin.uclinux.org -S: Orphan -F: drivers/net/ethernet/adi/ - -BLACKFIN MEDIA DRIVER -L: adi-buildroot-devel@lists.sourceforge.net (moderated for non-subscribers) -W: http://blackfin.uclinux.org/ -S: Orphan -F: drivers/media/platform/blackfin/ -F: drivers/media/i2c/adv7183* -F: drivers/media/i2c/vs6624* - -BLACKFIN RTC DRIVER -L: adi-buildroot-devel@lists.sourceforge.net (moderated for non-subscribers) -W: http://blackfin.uclinux.org -S: Orphan -F: drivers/rtc/rtc-bfin.c - -BLACKFIN SDH DRIVER -L: adi-buildroot-devel@lists.sourceforge.net (moderated for non-subscribers) -W: http://blackfin.uclinux.org -S: Orphan -F: drivers/mmc/host/bfin_sdh.c - -BLACKFIN SERIAL DRIVER -L: adi-buildroot-devel@lists.sourceforge.net (moderated for non-subscribers) -W: http://blackfin.uclinux.org -S: Orphan -F: drivers/tty/serial/bfin_uart.c - -BLACKFIN WATCHDOG DRIVER -L: adi-buildroot-devel@lists.sourceforge.net (moderated for non-subscribers) -W: http://blackfin.uclinux.org -S: Orphan -F: drivers/watchdog/bfin_wdt.c - BLINKM RGB LED DRIVER M: Jan-Simon Moeller jansimon.moeller@gmx.de S: Maintained @@@ -3293,7 -3307,6 +3293,7 @@@ F: include/media/cec-notifier. F: include/uapi/linux/cec.h F: include/uapi/linux/cec-funcs.h F: Documentation/devicetree/bindings/media/cec.txt +F: Documentation/ABI/testing/debugfs-cec-error-inj
CEC GPIO DRIVER M: Hans Verkuil hans.verkuil@cisco.com @@@ -3736,6 -3749,16 +3736,6 @@@ S: Maintaine F: Documentation/filesystems/cramfs.txt F: fs/cramfs/
-CRIS PORT -M: Mikael Starvik starvik@axis.com -M: Jesper Nilsson jesper.nilsson@axis.com -L: linux-cris-kernel@axis.com -W: http://developer.axis.com -T: git git://git.kernel.org/pub/scm/linux/kernel/git/jesper/cris.git -S: Maintained -F: arch/cris/ -F: drivers/tty/serial/crisv10.* - CRYPTO API M: Herbert Xu herbert@gondor.apana.org.au M: "David S. Miller" davem@davemloft.net @@@ -4603,7 -4626,7 +4603,7 @@@ F: include/uapi/drm/drm F: include/linux/vga*
DRM DRIVERS FOR ALLWINNER A10 -M: Maxime Ripard maxime.ripard@free-electrons.com +M: Maxime Ripard maxime.ripard@bootlin.com L: dri-devel@lists.freedesktop.org S: Supported F: drivers/gpu/drm/sun4i/ @@@ -5776,6 -5799,10 +5776,6 @@@ F: fs/crypto F: include/linux/fscrypt*.h F: Documentation/filesystems/fscrypt.rst
-FUJITSU FR-V (FRV) PORT -S: Orphan -F: arch/frv/ - FUJITSU LAPTOP EXTRAS M: Jonathan Woithe jwoithe@just42.net L: platform-driver-x86@vger.kernel.org @@@ -6547,7 -6574,7 +6547,7 @@@ F: drivers/i2c/muxes F: include/linux/i2c-mux.h
I2C MV64XXX MARVELL AND ALLWINNER DRIVER -M: Gregory CLEMENT gregory.clement@free-electrons.com +M: Gregory CLEMENT gregory.clement@bootlin.com L: linux-i2c@vger.kernel.org S: Maintained F: drivers/i2c/busses/i2c-mv64xxx.c @@@ -6876,13 -6903,6 +6876,13 @@@ M: James Hogan <jhogan@kernel.org S: Maintained F: drivers/media/rc/img-ir/
+IMON SOUNDGRAPH USB IR RECEIVER +M: Sean Young sean@mess.org +L: linux-media@vger.kernel.org +S: Maintained +F: drivers/media/rc/imon_raw.c +F: drivers/media/rc/imon.c + IMS TWINTURBO FRAMEBUFFER DRIVER L: linux-fbdev@vger.kernel.org S: Orphan @@@ -7208,7 -7228,6 +7208,7 @@@ M: Shiraz Saleem <shiraz.saleem@intel.c L: linux-rdma@vger.kernel.org S: Supported F: drivers/infiniband/hw/i40iw/ +F: include/uapi/rdma/i40iw-abi.h
INTEL TELEMETRY DRIVER M: Souvik Kumar Chakravarty souvik.k.chakravarty@intel.com @@@ -8293,6 -8312,11 +8293,6 @@@ W: http://linux-test-project.github.io T: git git://github.com/linux-test-project/ltp.git S: Maintained
-M32R ARCHITECTURE -W: http://www.linux-m32r.org/ -S: Orphan -F: arch/m32r/ - M68K ARCHITECTURE M: Geert Uytterhoeven geert@linux-m68k.org L: linux-m68k@lists.linux-m68k.org @@@ -8572,6 -8596,15 +8572,15 @@@ S: Maintaine F: Documentation/ABI/testing/sysfs-bus-iio-potentiometer-mcp4531 F: drivers/iio/potentiometer/mcp4531.c
+ MCR20A IEEE-802.15.4 RADIO DRIVER + M: Xue Liu liuxuenetmail@gmail.com + L: linux-wpan@vger.kernel.org + W: https://github.com/xueliu/mcr20a-linux + S: Maintained + F: drivers/net/ieee802154/mcr20a.c + F: drivers/net/ieee802154/mcr20a.h + F: Documentation/devicetree/bindings/net/ieee802154/mcr20a.txt + MEASUREMENT COMPUTING CIO-DAC IIO DRIVER M: William Breathitt Gray vilhelm.gray@gmail.com L: linux-iio@vger.kernel.org @@@ -8588,14 -8621,6 +8597,14 @@@ T: git git://linuxtv.org/media_tree.gi S: Supported F: drivers/media/dvb-frontends/ascot2e*
+MEDIA DRIVERS FOR CXD2099AR CI CONTROLLERS +M: Jasmin Jessich jasmin@anw.at +L: linux-media@vger.kernel.org +W: https://linuxtv.org +T: git git://linuxtv.org/media_tree.git +S: Maintained +F: drivers/media/dvb-frontends/cxd2099* + MEDIA DRIVERS FOR CXD2841ER M: Sergey Kozlov serjk@netup.ru M: Abylay Ospan aospan@netup.ru @@@ -8606,15 -8631,6 +8615,15 @@@ T: git git://linuxtv.org/media_tree.gi S: Supported F: drivers/media/dvb-frontends/cxd2841er*
+MEDIA DRIVERS FOR CXD2880 +M: Yasunari Takiguchi Yasunari.Takiguchi@sony.com +L: linux-media@vger.kernel.org +W: http://linuxtv.org/ +T: git git://linuxtv.org/media_tree.git +S: Supported +F: drivers/media/dvb-frontends/cxd2880/* +F: drivers/media/spi/cxd2880* + MEDIA DRIVERS FOR DIGITAL DEVICES PCIE DEVICES M: Daniel Scheller d.scheller.oss@gmail.com L: linux-media@vger.kernel.org @@@ -8682,16 -8698,6 +8691,16 @@@ T: git git://linuxtv.org/media_tree.gi S: Supported F: drivers/media/pci/netup_unidvb/*
+MEDIA DRIVERS FOR RENESAS - CEU +M: Jacopo Mondi jacopo@jmondi.org +L: linux-media@vger.kernel.org +L: linux-renesas-soc@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +S: Supported +F: Documentation/devicetree/bindings/media/renesas,ceu.txt +F: drivers/media/platform/renesas-ceu.c +F: include/media/drv-intf/renesas-ceu.h + MEDIA DRIVERS FOR RENESAS - DRIF M: Ramesh Shanmugasundaram ramesh.shanmugasundaram@bp.renesas.com L: linux-media@vger.kernel.org @@@ -9087,6 -9093,20 +9096,6 @@@ F: drivers/media/platform/meson/ao-cec. F: Documentation/devicetree/bindings/media/meson-ao-cec.txt T: git git://linuxtv.org/media_tree.git
-METAG ARCHITECTURE -M: James Hogan jhogan@kernel.org -L: linux-metag@vger.kernel.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/jhogan/metag.git -S: Odd Fixes -F: arch/metag/ -F: Documentation/metag/ -F: Documentation/devicetree/bindings/metag/ -F: Documentation/devicetree/bindings/interrupt-controller/img,* -F: drivers/clocksource/metag_generic.c -F: drivers/irqchip/irq-metag.c -F: drivers/irqchip/irq-metag-ext.c -F: drivers/tty/metag_da.c - MICROBLAZE ARCHITECTURE M: Michal Simek monstr@monstr.eu W: http://www.monstr.eu/fdt/ @@@ -9141,6 -9161,13 +9150,13 @@@ F: drivers/net/dsa/microchip/ F: include/linux/platform_data/microchip-ksz.h F: Documentation/devicetree/bindings/net/dsa/ksz.txt
+ MICROCHIP LAN743X ETHERNET DRIVER + M: Bryan Whitehead bryan.whitehead@microchip.com + M: Microchip Linux Driver Support UNGLinuxDriver@microchip.com + L: netdev@vger.kernel.org + S: Maintained + F: drivers/net/ethernet/microchip/lan743x_* + MICROCHIP USB251XB DRIVER M: Richard Leitner richard.leitner@skidata.com L: linux-usb@vger.kernel.org @@@ -9148,15 -9175,6 +9164,15 @@@ S: Maintaine F: drivers/usb/misc/usb251xb.c F: Documentation/devicetree/bindings/usb/usb251xb.txt
+MICROSEMI MIPS SOCS +M: Alexandre Belloni alexandre.belloni@bootlin.com +L: linux-mips@linux-mips.org +S: Maintained +F: arch/mips/generic/board-ocelot.c +F: arch/mips/configs/generic/board-ocelot.config +F: arch/mips/boot/dts/mscc/ +F: Documentation/devicetree/bindings/mips/mscc.txt + MICROSEMI SMART ARRAY SMARTPQI DRIVER (smartpqi) M: Don Brace don.brace@microsemi.com L: esc.storagedev@microsemi.com @@@ -9377,14 -9395,6 +9393,14 @@@ S: Maintaine F: drivers/media/i2c/mt9t001.c F: include/media/i2c/mt9t001.h
+MT9T112 APTINA CAMERA SENSOR +M: Jacopo Mondi jacopo@jmondi.org +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +S: Odd Fixes +F: drivers/media/i2c/mt9t112.c +F: include/media/i2c/mt9t112.h + MT9V032 APTINA CAMERA SENSOR M: Laurent Pinchart laurent.pinchart@ideasonboard.com L: linux-media@vger.kernel.org @@@ -9931,13 -9941,6 +9947,13 @@@ F: Documentation/ABI/stable/sysfs-bus-n F: include/linux/nvmem-consumer.h F: include/linux/nvmem-provider.h
+NXP SGTL5000 DRIVER +M: Fabio Estevam fabio.estevam@nxp.com +L: alsa-devel@alsa-project.org (moderated for non-subscribers) +S: Maintained +F: Documentation/devicetree/bindings/sound/sgtl5000.txt +F: sound/soc/codecs/sgtl5000* + NXP TDA998X DRM DRIVER M: Russell King linux@armlinux.org.uk S: Supported @@@ -10190,13 -10193,6 +10206,13 @@@ T: git git://linuxtv.org/media_tree.gi S: Maintained F: drivers/media/i2c/ov13858.c
+OMNIVISION OV2685 SENSOR DRIVER +M: Shunqian Zheng zhengsq@rock-chips.com +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +S: Maintained +F: drivers/media/i2c/ov2685.c + OMNIVISION OV5640 SENSOR DRIVER M: Steve Longerbeam slongerbeam@gmail.com L: linux-media@vger.kernel.org @@@ -10211,13 -10207,6 +10227,13 @@@ T: git git://linuxtv.org/media_tree.gi S: Maintained F: drivers/media/i2c/ov5647.c
+OMNIVISION OV5695 SENSOR DRIVER +M: Shunqian Zheng zhengsq@rock-chips.com +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +S: Maintained +F: drivers/media/i2c/ov5695.c + OMNIVISION OV7670 SENSOR DRIVER M: Jonathan Corbet corbet@lwn.net L: linux-media@vger.kernel.org @@@ -10226,14 -10215,6 +10242,14 @@@ S: Maintaine F: drivers/media/i2c/ov7670.c F: Documentation/devicetree/bindings/media/i2c/ov7670.txt
+OMNIVISION OV772x SENSOR DRIVER +M: Jacopo Mondi jacopo@jmondi.org +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +S: Odd fixes +F: drivers/media/i2c/ov772x.c +F: include/media/i2c/ov772x.h + OMNIVISION OV7740 SENSOR DRIVER M: Wenyou Yang wenyou.yang@microchip.com L: linux-media@vger.kernel.org @@@ -10242,16 -10223,6 +10258,16 @@@ S: Maintaine F: drivers/media/i2c/ov7740.c F: Documentation/devicetree/bindings/media/i2c/ov7740.txt
+OMNIVISION OV9650 SENSOR DRIVER +M: Sakari Ailus sakari.ailus@linux.intel.com +R: Akinobu Mita akinobu.mita@gmail.com +R: Sylwester Nawrocki s.nawrocki@samsung.com +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +S: Maintained +F: drivers/media/i2c/ov9650.c +F: Documentation/devicetree/bindings/media/i2c/ov9650.txt + ONENAND FLASH DRIVER M: Kyungmin Park kyungmin.park@samsung.com L: linux-mtd@lists.infradead.org @@@ -10453,6 -10424,14 +10469,6 @@@ L: platform-driver-x86@vger.kernel.or S: Maintained F: drivers/platform/x86/panasonic-laptop.c
-PANASONIC MN10300/AM33/AM34 PORT -M: David Howells dhowells@redhat.com -L: linux-am33-list@redhat.com (moderated for non-subscribers) -W: ftp://ftp.redhat.com/pub/redhat/gnupro/AM33/ -S: Maintained -F: Documentation/mn10300/ -F: arch/mn10300/ - PARALLEL LCD/KEYPAD PANEL DRIVER M: Willy Tarreau willy@haproxy.com M: Ksenija Stanojevic ksenija.stanojevic@gmail.com @@@ -10874,7 -10853,6 +10890,7 @@@ F: drivers/platform/x86/peaq-wmi. PER-CPU MEMORY ALLOCATOR M: Tejun Heo tj@kernel.org M: Christoph Lameter cl@linux.com +M: Dennis Zhou dennisszhou@gmail.com T: git git://git.kernel.org/pub/scm/linux/kernel/git/tj/percpu.git S: Maintained F: include/linux/percpu*.h @@@ -11381,6 -11359,12 +11397,6 @@@ F: include/sound/pxa2xx-lib. F: sound/arm/pxa* F: sound/soc/pxa/
-PXA3xx NAND FLASH DRIVER -M: Ezequiel Garcia ezequiel.garcia@free-electrons.com -L: linux-mtd@lists.infradead.org -S: Maintained -F: drivers/mtd/nand/pxa3xx_nand.c - QAT DRIVER M: Giovanni Cabiddu giovanni.cabiddu@intel.com L: qat-linux@intel.com @@@ -12139,7 -12123,6 +12155,7 @@@ M: Sylwester Nawrocki <s.nawrocki@samsu L: alsa-devel@alsa-project.org (moderated for non-subscribers) S: Supported F: sound/soc/samsung/ +F: Documentation/devicetree/bindings/sound/samsung*
SAMSUNG EXYNOS PSEUDO RANDOM NUMBER GENERATOR (RNG) DRIVER M: Krzysztof Kozlowski krzk@kernel.org @@@ -12238,7 -12221,6 +12254,7 @@@ M: Tomasz Figa <tomasz.figa@gmail.com M: Chanwoo Choi cw00.choi@samsung.com S: Supported L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers) +T: git git://git.kernel.org/pub/scm/linux/kernel/git/snawrocki/clk.git F: drivers/clk/samsung/ F: include/dt-bindings/clock/exynos*.h F: Documentation/devicetree/bindings/clock/exynos*.txt @@@ -12300,6 -12282,13 +12316,6 @@@ F: include/linux/sched. F: include/uapi/linux/sched.h F: include/linux/wait.h
-SCORE ARCHITECTURE -M: Chen Liqin liqin.linux@gmail.com -M: Lennox Wu lennox.wu@gmail.com -W: http://www.sunplus.com -S: Supported -F: arch/score/ - SCR24X CHIP CARD INTERFACE DRIVER M: Lubomir Rintel lkundrak@v3.sk S: Supported @@@ -12827,9 -12816,10 +12843,9 @@@ S: Maintaine F: drivers/net/ethernet/smsc/smsc9420.*
SOC-CAMERA V4L2 SUBSYSTEM -M: Guennadi Liakhovetski g.liakhovetski@gmx.de L: linux-media@vger.kernel.org T: git git://linuxtv.org/media_tree.git -S: Maintained +S: Orphan F: include/media/soc* F: drivers/media/i2c/soc_camera/ F: drivers/media/platform/soc_camera/ @@@ -13421,16 -13411,15 +13437,16 @@@ T: git git://git.kernel.org/pub/scm/lin S: Supported F: drivers/mfd/syscon.c
-SYSTEM CONTROL & POWER INTERFACE (SCPI) Message Protocol drivers +SYSTEM CONTROL & POWER/MANAGEMENT INTERFACE (SCPI/SCMI) Message Protocol drivers M: Sudeep Holla sudeep.holla@arm.com L: linux-arm-kernel@lists.infradead.org S: Maintained -F: Documentation/devicetree/bindings/arm/arm,scpi.txt -F: drivers/clk/clk-scpi.c -F: drivers/cpufreq/scpi-cpufreq.c +F: Documentation/devicetree/bindings/arm/arm,sc[mp]i.txt +F: drivers/clk/clk-sc[mp]i.c +F: drivers/cpufreq/sc[mp]i-cpufreq.c F: drivers/firmware/arm_scpi.c -F: include/linux/scpi_protocol.h +F: drivers/firmware/arm_scmi/ +F: include/linux/sc[mp]i_protocol.h
SYSTEM RESET/SHUTDOWN DRIVERS M: Sebastian Reichel sre@kernel.org @@@ -13546,14 -13535,6 +13562,14 @@@ T: git git://linuxtv.org/mkrufky/tuners S: Maintained F: drivers/media/tuners/tda18271*
+TDA1997x MEDIA DRIVER +M: Tim Harvey tharvey@gateworks.com +L: linux-media@vger.kernel.org +W: https://linuxtv.org +Q: http://patchwork.linuxtv.org/project/linux-media/list/ +S: Maintained +F: drivers/media/i2c/tda1997x.* + TDA827x MEDIA DRIVER M: Michael Krufky mkrufky@linuxtv.org L: linux-media@vger.kernel.org @@@ -13635,12 -13616,6 +13651,12 @@@ L: linux-media@vger.kernel.or S: Maintained F: drivers/media/rc/ttusbir.c
+TECHWELL TW9910 VIDEO DECODER +L: linux-media@vger.kernel.org +S: Orphan +F: drivers/media/i2c/tw9910.c +F: include/media/i2c/tw9910.h + TEE SUBSYSTEM M: Jens Wiklander jens.wiklander@linaro.org S: Maintained @@@ -13676,8 -13651,7 +13692,8 @@@ S: Supporte F: drivers/i2c/busses/i2c-tegra.c
TEGRA IOMMU DRIVERS -M: Hiroshi Doyu hdoyu@nvidia.com +M: Thierry Reding thierry.reding@gmail.com +L: linux-tegra@vger.kernel.org S: Supported F: drivers/iommu/tegra*
@@@ -13850,13 -13824,6 +13866,13 @@@ F: arch/arm/mach-davinci F: drivers/i2c/busses/i2c-davinci.c F: arch/arm/boot/dts/da850*
+TI DAVINCI SERIES CLOCK DRIVER +M: David Lechner david@lechnology.com +R: Sekhar Nori nsekhar@ti.com +S: Maintained +F: Documentation/devicetree/bindings/clock/ti/davinci/ +F: drivers/clk/davinci/ + TI DAVINCI SERIES GPIO DRIVER M: Keerthy j-keerthy@ti.com L: linux-gpio@vger.kernel.org @@@ -13972,6 -13939,19 +13988,6 @@@ S: Orpha F: drivers/net/wireless/ti/ F: include/linux/wl12xx.h
-TILE ARCHITECTURE -W: http://www.mellanox.com/repository/solutions/tile-scm/ -S: Orphan -F: arch/tile/ -F: drivers/char/tile-srom.c -F: drivers/edac/tile_edac.c -F: drivers/net/ethernet/tile/ -F: drivers/rtc/rtc-tile.c -F: drivers/tty/hvc/hvc_tile.c -F: drivers/tty/serial/tilegx.c -F: drivers/usb/host/*-tilegx.c -F: include/linux/usb/tilegx.h - TIMEKEEPING, CLOCKSOURCE CORE, NTP, ALARMTIMER M: John Stultz john.stultz@linaro.org M: Thomas Gleixner tglx@linutronix.de diff --combined arch/arm/boot/dts/armada-370-rd.dts index 54ee9fa6b58e,c28afb242393..cc2f774eb267 --- a/arch/arm/boot/dts/armada-370-rd.dts +++ b/arch/arm/boot/dts/armada-370-rd.dts @@@ -1,4 -1,3 +1,4 @@@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) /* * Device Tree file for Marvell Armada 370 Reference Design board * (RD-88F6710-A1) @@@ -7,6 -6,44 +7,6 @@@ * * Copyright (C) 2013 Florian Fainelli florian@openwrt.org * - * This file is dual-licensed: you can use it either under the terms - * of the GPL or the X11 license, at your option. Note that this dual - * licensing only applies to this file, and not this project as a - * whole. - * - * a) This file is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This file is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Or, alternatively, - * - * b) Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * * Note: this Device Tree assumes that the bootloader has remapped the * internal registers to 0xf1000000 (instead of the default * 0xd0000000). The 0xf1000000 is the default used by the recent, @@@ -19,6 -56,7 +19,7 @@@
/dts-v1/; #include <dt-bindings/input/input.h> + #include <dt-bindings/interrupt-controller/irq.h> #include <dt-bindings/gpio/gpio.h> #include "armada-370.dtsi"
@@@ -206,6 -244,8 +207,8 @@@ #address-cells = <1>; #size-cells = <0>; reg = <0x10>; + interrupt-controller; + #interrupt-cells = <2>;
ports { #address-cells = <1>; @@@ -241,6 -281,35 +244,35 @@@ }; }; }; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + switchphy0: switchphy@0 { + reg = <0>; + interrupt-parent = <&switch>; + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + }; + + switchphy1: switchphy@1 { + reg = <1>; + interrupt-parent = <&switch>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH>; + }; + + switchphy2: switchphy@2 { + reg = <2>; + interrupt-parent = <&switch>; + interrupts = <2 IRQ_TYPE_LEVEL_HIGH>; + }; + + switchphy3: switchphy@3 { + reg = <3>; + interrupt-parent = <&switch>; + interrupts = <3 IRQ_TYPE_LEVEL_HIGH>; + }; + }; }; };
diff --combined arch/m68k/mac/config.c index 36086cceb537,c73eb8209555..0c3275aa0197 --- a/arch/m68k/mac/config.c +++ b/arch/m68k/mac/config.c @@@ -26,7 -26,6 +26,7 @@@ #include <linux/platform_device.h> #include <linux/adb.h> #include <linux/cuda.h> +#include <linux/pmu.h> #include <linux/rtc.h>
#include <asm/setup.h> @@@ -700,7 -699,7 +700,7 @@@ static struct mac_model mac_data_table[ .name = "PowerBook 190", .adb_type = MAC_ADB_PB2, .via_type = MAC_VIA_QUADRA, - .scsi_type = MAC_SCSI_LATE, + .scsi_type = MAC_SCSI_OLD, .ide_type = MAC_IDE_BABOON, .scc_type = MAC_SCC_QUADRA, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@@ -891,9 -890,6 +891,9 @@@ static void __init mac_identify(void #ifdef CONFIG_ADB_CUDA find_via_cuda(); #endif +#ifdef CONFIG_ADB_PMU68K + find_via_pmu(); +#endif }
static void __init mac_report_hardware(void) @@@ -1065,7 -1061,9 +1065,7 @@@ int __init mac_platform_init(void mac_scsi_old_rsrc, ARRAY_SIZE(mac_scsi_old_rsrc)); break; case MAC_SCSI_LATE: - /* PDMA logic in 68040 PowerBooks is somehow different to - * '030 models. It's probably more like Quadras (see mac_esp). - */ + /* XXX PDMA support for PowerBook 500 series needs testing */ platform_device_register_simple("mac_scsi", 0, mac_scsi_late_rsrc, ARRAY_SIZE(mac_scsi_late_rsrc)); break; @@@ -1090,6 -1088,10 +1090,10 @@@ macintosh_config->expansion_type == MAC_EXP_PDS_COMM) platform_device_register_simple("macsonic", -1, NULL, 0);
+ if (macintosh_config->expansion_type == MAC_EXP_PDS || + macintosh_config->expansion_type == MAC_EXP_PDS_COMM) + platform_device_register_simple("mac89x0", -1, NULL, 0); + if (macintosh_config->ether_type == MAC_ETHER_MACE) platform_device_register_simple("macmace", -1, NULL, 0);
diff --combined arch/x86/net/bpf_jit_comp.c index ce5b2ebd5701,eb661fff94d7..b725154182cc --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@@ -11,10 -11,10 +11,10 @@@ #include <linux/netdevice.h> #include <linux/filter.h> #include <linux/if_vlan.h> - #include <asm/cacheflush.h> + #include <linux/bpf.h> + #include <asm/set_memory.h> #include <asm/nospec-branch.h> - #include <linux/bpf.h>
/* * assembly code in arch/x86/net/bpf_jit.S @@@ -61,7 -61,12 +61,12 @@@ static bool is_imm8(int value
static bool is_simm32(s64 value) { - return value == (s64) (s32) value; + return value == (s64)(s32)value; + } + + static bool is_uimm32(u64 value) + { + return value == (u64)(u32)value; }
/* mov dst, src */ @@@ -98,16 -103,6 +103,6 @@@ static int bpf_size_to_x86_bytes(int bp #define X86_JLE 0x7E #define X86_JG 0x7F
- static void bpf_flush_icache(void *start, void *end) - { - mm_segment_t old_fs = get_fs(); - - set_fs(KERNEL_DS); - smp_wmb(); - flush_icache_range((unsigned long)start, (unsigned long)end); - set_fs(old_fs); - } - #define CHOOSE_LOAD_FUNC(K, func) \ ((int)K < 0 ? ((int)K >= SKF_LL_OFF ? func##_negative_offset : func) : func##_positive_offset)
@@@ -212,7 -207,7 +207,7 @@@ struct jit_context /* emit x64 prologue code for BPF program and check it's size. * bpf_tail_call helper will skip it while jumping into another program */ - static void emit_prologue(u8 **pprog, u32 stack_depth) + static void emit_prologue(u8 **pprog, u32 stack_depth, bool ebpf_from_cbpf) { u8 *prog = *pprog; int cnt = 0; @@@ -247,18 -242,21 +242,21 @@@ /* mov qword ptr [rbp+24],r15 */ EMIT4(0x4C, 0x89, 0x7D, 24);
- /* Clear the tail call counter (tail_call_cnt): for eBPF tail calls - * we need to reset the counter to 0. It's done in two instructions, - * resetting rax register to 0 (xor on eax gets 0 extended), and - * moving it to the counter location. - */ + if (!ebpf_from_cbpf) { + /* Clear the tail call counter (tail_call_cnt): for eBPF tail + * calls we need to reset the counter to 0. It's done in two + * instructions, resetting rax register to 0, and moving it + * to the counter location. + */
- /* xor eax, eax */ - EMIT2(0x31, 0xc0); - /* mov qword ptr [rbp+32], rax */ - EMIT4(0x48, 0x89, 0x45, 32); + /* xor eax, eax */ + EMIT2(0x31, 0xc0); + /* mov qword ptr [rbp+32], rax */ + EMIT4(0x48, 0x89, 0x45, 32); + + BUILD_BUG_ON(cnt != PROLOGUE_SIZE); + }
- BUILD_BUG_ON(cnt != PROLOGUE_SIZE); *pprog = prog; }
@@@ -356,6 -354,86 +354,86 @@@ static void emit_load_skb_data_hlen(u8 *pprog = prog; }
+ static void emit_mov_imm32(u8 **pprog, bool sign_propagate, + u32 dst_reg, const u32 imm32) + { + u8 *prog = *pprog; + u8 b1, b2, b3; + int cnt = 0; + + /* optimization: if imm32 is positive, use 'mov %eax, imm32' + * (which zero-extends imm32) to save 2 bytes. + */ + if (sign_propagate && (s32)imm32 < 0) { + /* 'mov %rax, imm32' sign extends imm32 */ + b1 = add_1mod(0x48, dst_reg); + b2 = 0xC7; + b3 = 0xC0; + EMIT3_off32(b1, b2, add_1reg(b3, dst_reg), imm32); + goto done; + } + + /* optimization: if imm32 is zero, use 'xor %eax, %eax' + * to save 3 bytes. + */ + if (imm32 == 0) { + if (is_ereg(dst_reg)) + EMIT1(add_2mod(0x40, dst_reg, dst_reg)); + b2 = 0x31; /* xor */ + b3 = 0xC0; + EMIT2(b2, add_2reg(b3, dst_reg, dst_reg)); + goto done; + } + + /* mov %eax, imm32 */ + if (is_ereg(dst_reg)) + EMIT1(add_1mod(0x40, dst_reg)); + EMIT1_off32(add_1reg(0xB8, dst_reg), imm32); + done: + *pprog = prog; + } + + static void emit_mov_imm64(u8 **pprog, u32 dst_reg, + const u32 imm32_hi, const u32 imm32_lo) + { + u8 *prog = *pprog; + int cnt = 0; + + if (is_uimm32(((u64)imm32_hi << 32) | (u32)imm32_lo)) { + /* For emitting plain u32, where sign bit must not be + * propagated LLVM tends to load imm64 over mov32 + * directly, so save couple of bytes by just doing + * 'mov %eax, imm32' instead. + */ + emit_mov_imm32(&prog, false, dst_reg, imm32_lo); + } else { + /* movabsq %rax, imm64 */ + EMIT2(add_1mod(0x48, dst_reg), add_1reg(0xB8, dst_reg)); + EMIT(imm32_lo, 4); + EMIT(imm32_hi, 4); + } + + *pprog = prog; + } + + static void emit_mov_reg(u8 **pprog, bool is64, u32 dst_reg, u32 src_reg) + { + u8 *prog = *pprog; + int cnt = 0; + + if (is64) { + /* mov dst, src */ + EMIT_mov(dst_reg, src_reg); + } else { + /* mov32 dst, src */ + if (is_ereg(dst_reg) || is_ereg(src_reg)) + EMIT1(add_2mod(0x40, dst_reg, src_reg)); + EMIT2(0x89, add_2reg(0xC0, dst_reg, src_reg)); + } + + *pprog = prog; + } + static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, int oldproglen, struct jit_context *ctx) { @@@ -369,7 -447,8 +447,8 @@@ int proglen = 0; u8 *prog = temp;
- emit_prologue(&prog, bpf_prog->aux->stack_depth); + emit_prologue(&prog, bpf_prog->aux->stack_depth, + bpf_prog_was_classic(bpf_prog));
if (seen_ld_abs) emit_load_skb_data_hlen(&prog); @@@ -378,7 -457,7 +457,7 @@@ const s32 imm32 = insn->imm; u32 dst_reg = insn->dst_reg; u32 src_reg = insn->src_reg; - u8 b1 = 0, b2 = 0, b3 = 0; + u8 b2 = 0, b3 = 0; s64 jmp_offset; u8 jmp_cond; bool reload_skb_data; @@@ -414,16 -493,11 +493,11 @@@ EMIT2(b2, add_2reg(0xC0, dst_reg, src_reg)); break;
- /* mov dst, src */ case BPF_ALU64 | BPF_MOV | BPF_X: - EMIT_mov(dst_reg, src_reg); - break; - - /* mov32 dst, src */ case BPF_ALU | BPF_MOV | BPF_X: - if (is_ereg(dst_reg) || is_ereg(src_reg)) - EMIT1(add_2mod(0x40, dst_reg, src_reg)); - EMIT2(0x89, add_2reg(0xC0, dst_reg, src_reg)); + emit_mov_reg(&prog, + BPF_CLASS(insn->code) == BPF_ALU64, + dst_reg, src_reg); break;
/* neg dst */ @@@ -486,58 -560,13 +560,13 @@@ break;
case BPF_ALU64 | BPF_MOV | BPF_K: - /* optimization: if imm32 is positive, - * use 'mov eax, imm32' (which zero-extends imm32) - * to save 2 bytes - */ - if (imm32 < 0) { - /* 'mov rax, imm32' sign extends imm32 */ - b1 = add_1mod(0x48, dst_reg); - b2 = 0xC7; - b3 = 0xC0; - EMIT3_off32(b1, b2, add_1reg(b3, dst_reg), imm32); - break; - } - case BPF_ALU | BPF_MOV | BPF_K: - /* optimization: if imm32 is zero, use 'xor <dst>,<dst>' - * to save 3 bytes. - */ - if (imm32 == 0) { - if (is_ereg(dst_reg)) - EMIT1(add_2mod(0x40, dst_reg, dst_reg)); - b2 = 0x31; /* xor */ - b3 = 0xC0; - EMIT2(b2, add_2reg(b3, dst_reg, dst_reg)); - break; - } - - /* mov %eax, imm32 */ - if (is_ereg(dst_reg)) - EMIT1(add_1mod(0x40, dst_reg)); - EMIT1_off32(add_1reg(0xB8, dst_reg), imm32); + emit_mov_imm32(&prog, BPF_CLASS(insn->code) == BPF_ALU64, + dst_reg, imm32); break;
case BPF_LD | BPF_IMM | BPF_DW: - /* optimization: if imm64 is zero, use 'xor <dst>,<dst>' - * to save 7 bytes. - */ - if (insn[0].imm == 0 && insn[1].imm == 0) { - b1 = add_2mod(0x48, dst_reg, dst_reg); - b2 = 0x31; /* xor */ - b3 = 0xC0; - EMIT3(b1, b2, add_2reg(b3, dst_reg, dst_reg)); - - insn++; - i++; - break; - } - - /* movabsq %rax, imm64 */ - EMIT2(add_1mod(0x48, dst_reg), add_1reg(0xB8, dst_reg)); - EMIT(insn[0].imm, 4); - EMIT(insn[1].imm, 4); - + emit_mov_imm64(&prog, dst_reg, insn[1].imm, insn[0].imm); insn++; i++; break; @@@ -594,36 -623,38 +623,38 @@@ case BPF_ALU | BPF_MUL | BPF_X: case BPF_ALU64 | BPF_MUL | BPF_K: case BPF_ALU64 | BPF_MUL | BPF_X: - EMIT1(0x50); /* push rax */ - EMIT1(0x52); /* push rdx */ + { + bool is64 = BPF_CLASS(insn->code) == BPF_ALU64; + + if (dst_reg != BPF_REG_0) + EMIT1(0x50); /* push rax */ + if (dst_reg != BPF_REG_3) + EMIT1(0x52); /* push rdx */
/* mov r11, dst_reg */ EMIT_mov(AUX_REG, dst_reg);
if (BPF_SRC(insn->code) == BPF_X) - /* mov rax, src_reg */ - EMIT_mov(BPF_REG_0, src_reg); + emit_mov_reg(&prog, is64, BPF_REG_0, src_reg); else - /* mov rax, imm32 */ - EMIT3_off32(0x48, 0xC7, 0xC0, imm32); + emit_mov_imm32(&prog, is64, BPF_REG_0, imm32);
- if (BPF_CLASS(insn->code) == BPF_ALU64) + if (is64) EMIT1(add_1mod(0x48, AUX_REG)); else if (is_ereg(AUX_REG)) EMIT1(add_1mod(0x40, AUX_REG)); /* mul(q) r11 */ EMIT2(0xF7, add_1reg(0xE0, AUX_REG));
- /* mov r11, rax */ - EMIT_mov(AUX_REG, BPF_REG_0); - - EMIT1(0x5A); /* pop rdx */ - EMIT1(0x58); /* pop rax */ - - /* mov dst_reg, r11 */ - EMIT_mov(dst_reg, AUX_REG); + if (dst_reg != BPF_REG_3) + EMIT1(0x5A); /* pop rdx */ + if (dst_reg != BPF_REG_0) { + /* mov dst_reg, rax */ + EMIT_mov(dst_reg, BPF_REG_0); + EMIT1(0x58); /* pop rax */ + } break; - + } /* shifts */ case BPF_ALU | BPF_LSH | BPF_K: case BPF_ALU | BPF_RSH | BPF_K: @@@ -641,7 -672,11 +672,11 @@@ case BPF_RSH: b3 = 0xE8; break; case BPF_ARSH: b3 = 0xF8; break; } - EMIT3(0xC1, add_1reg(b3, dst_reg), imm32); + + if (imm32 == 1) + EMIT2(0xD1, add_1reg(b3, dst_reg)); + else + EMIT3(0xC1, add_1reg(b3, dst_reg), imm32); break;
case BPF_ALU | BPF_LSH | BPF_X: @@@ -1188,7 -1223,7 +1223,7 @@@ skip_init_addrs * may converge on the last pass. In such case do one more * pass to emit the final image */ - for (pass = 0; pass < 10 || image; pass++) { + for (pass = 0; pass < 20 || image; pass++) { proglen = do_jit(prog, addrs, image, oldproglen, &ctx); if (proglen <= 0) { image = NULL; @@@ -1215,14 -1250,12 +1250,13 @@@ } } oldproglen = proglen; + cond_resched(); }
if (bpf_jit_enable > 1) bpf_jit_dump(prog->len, proglen, pass + 1, image);
if (image) { - bpf_flush_icache(header, image + proglen); if (!prog->is_func || extra_pass) { bpf_jit_binary_lock_ro(header); } else { diff --combined drivers/bluetooth/btusb.c index 366a49c7c08f,fa4ce83893bb..5cd868ea28ed --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@@ -231,6 -231,7 +231,6 @@@ static const struct usb_device_id black { USB_DEVICE(0x0930, 0x0227), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311e), .driver_info = BTUSB_ATH3012 }, @@@ -263,7 -264,6 +263,7 @@@ { USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 },
/* QCA ROME chipset */ + { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x0cf3, 0xe007), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x0cf3, 0xe009), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x0cf3, 0xe010), .driver_info = BTUSB_QCA_ROME }, @@@ -340,6 -340,7 +340,7 @@@
/* Intel Bluetooth devices */ { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_NEW }, + { USB_DEVICE(0x8087, 0x0026), .driver_info = BTUSB_INTEL_NEW }, { USB_DEVICE(0x8087, 0x07da), .driver_info = BTUSB_CSR }, { USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL }, { USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL }, @@@ -374,6 -375,9 +375,9 @@@ { USB_DEVICE(0x13d3, 0x3461), .driver_info = BTUSB_REALTEK }, { USB_DEVICE(0x13d3, 0x3462), .driver_info = BTUSB_REALTEK },
+ /* Additional Realtek 8822BE Bluetooth devices */ + { USB_DEVICE(0x0b05, 0x185c), .driver_info = BTUSB_REALTEK }, + /* Silicon Wave based devices */ { USB_DEVICE(0x0c10, 0x0000), .driver_info = BTUSB_SWAVE },
@@@ -386,10 -390,10 +390,10 @@@ */ static const struct dmi_system_id btusb_needs_reset_resume_table[] = { { - /* Lenovo Yoga 920 (QCA Rome device 0cf3:e300) */ + /* Dell OptiPlex 3060 (QCA ROME device 0cf3:e007) */ .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 920"), + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 3060"), }, }, {} @@@ -2073,6 -2077,8 +2077,8 @@@ static int btusb_setup_intel_new(struc case 0x0c: /* WsP */ case 0x11: /* JfP */ case 0x12: /* ThP */ + case 0x13: /* HrP */ + case 0x14: /* QnJ, IcP */ break; default: BT_ERR("%s: Unsupported Intel hardware variant (%u)", @@@ -2165,6 -2171,8 +2171,8 @@@ break; case 0x11: /* JfP */ case 0x12: /* ThP */ + case 0x13: /* HrP */ + case 0x14: /* QnJ, IcP */ snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u-%u.sfi", le16_to_cpu(ver.hw_variant), le16_to_cpu(ver.hw_revision), @@@ -2196,6 -2204,8 +2204,8 @@@ break; case 0x11: /* JfP */ case 0x12: /* ThP */ + case 0x13: /* HrP */ + case 0x14: /* QnJ, IcP */ snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u-%u.ddc", le16_to_cpu(ver.hw_variant), le16_to_cpu(ver.hw_revision), diff --combined drivers/infiniband/core/cma.c index 34fa0507ed4f,915bbd867b61..ecacd71babf2 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@@ -62,7 -62,6 +62,7 @@@ #include <rdma/iw_cm.h>
#include "core_priv.h" +#include "cma_priv.h"
MODULE_AUTHOR("Sean Hefty"); MODULE_DESCRIPTION("Generic RDMA CM Agent"); @@@ -328,6 -327,46 +328,6 @@@ struct ib_device *cma_get_ib_dev(struc * We do this by disabling removal notification while a callback is in process, * and reporting it after the callback completes. */ -struct rdma_id_private { - struct rdma_cm_id id; - - struct rdma_bind_list *bind_list; - struct hlist_node node; - struct list_head list; /* listen_any_list or cma_device.list */ - struct list_head listen_list; /* per device listens */ - struct cma_device *cma_dev; - struct list_head mc_list; - - int internal_id; - enum rdma_cm_state state; - spinlock_t lock; - struct mutex qp_mutex; - - struct completion comp; - atomic_t refcount; - struct mutex handler_mutex; - - int backlog; - int timeout_ms; - struct ib_sa_query *query; - int query_id; - union { - struct ib_cm_id *ib; - struct iw_cm_id *iw; - } cm_id; - - u32 seq_num; - u32 qkey; - u32 qp_num; - pid_t owner; - u32 options; - u8 srq; - u8 tos; - bool tos_set; - u8 reuseaddr; - u8 afonly; - enum ib_gid_type gid_type; -};
struct cma_multicast { struct rdma_id_private *id_priv; @@@ -466,8 -505,6 +466,8 @@@ static void _cma_attach_to_dev(struct r id_priv->id.route.addr.dev_addr.transport = rdma_node_get_transport(cma_dev->device->node_type); list_add_tail(&id_priv->list, &cma_dev->id_list); + id_priv->res.type = RDMA_RESTRACK_CM_ID; + rdma_restrack_add(&id_priv->res); }
static void cma_attach_to_dev(struct rdma_id_private *id_priv, @@@ -740,10 -777,10 +740,10 @@@ static void cma_deref_id(struct rdma_id complete(&id_priv->comp); }
-struct rdma_cm_id *rdma_create_id(struct net *net, - rdma_cm_event_handler event_handler, - void *context, enum rdma_port_space ps, - enum ib_qp_type qp_type) +struct rdma_cm_id *__rdma_create_id(struct net *net, + rdma_cm_event_handler event_handler, + void *context, enum rdma_port_space ps, + enum ib_qp_type qp_type, const char *caller) { struct rdma_id_private *id_priv;
@@@ -751,10 -788,7 +751,10 @@@ if (!id_priv) return ERR_PTR(-ENOMEM);
- id_priv->owner = task_pid_nr(current); + if (caller) + id_priv->res.kern_name = caller; + else + rdma_restrack_set_task(&id_priv->res, current); id_priv->state = RDMA_CM_IDLE; id_priv->id.context = context; id_priv->id.event_handler = event_handler; @@@ -774,7 -808,7 +774,7 @@@
return &id_priv->id; } -EXPORT_SYMBOL(rdma_create_id); +EXPORT_SYMBOL(__rdma_create_id);
static int cma_init_ud_qp(struct rdma_id_private *id_priv, struct ib_qp *qp) { @@@ -1300,7 -1334,7 +1300,7 @@@ static bool validate_ipv6_net_dev(struc IPV6_ADDR_LINKLOCAL; struct rt6_info *rt = rt6_lookup(dev_net(net_dev), &dst_addr->sin6_addr, &src_addr->sin6_addr, net_dev->ifindex, - strict); + NULL, strict); bool ret;
if (!rt) @@@ -1407,12 -1441,21 +1407,12 @@@ static bool cma_match_private_data(stru return true; }
-static bool cma_protocol_roce_dev_port(struct ib_device *device, int port_num) -{ - enum rdma_link_layer ll = rdma_port_get_link_layer(device, port_num); - enum rdma_transport_type transport = - rdma_node_get_transport(device->node_type); - - return ll == IB_LINK_LAYER_ETHERNET && transport == RDMA_TRANSPORT_IB; -} - static bool cma_protocol_roce(const struct rdma_cm_id *id) { struct ib_device *device = id->device; const int port_num = id->port_num ?: rdma_start_port(device);
- return cma_protocol_roce_dev_port(device, port_num); + return rdma_protocol_roce(device, port_num); }
static bool cma_match_net_dev(const struct rdma_cm_id *id, @@@ -1425,7 -1468,7 +1425,7 @@@ /* This request is an AF_IB request or a RoCE request */ return (!id->port_num || id->port_num == port_num) && (addr->src_addr.ss_family == AF_IB || - cma_protocol_roce_dev_port(id->device, port_num)); + rdma_protocol_roce(id->device, port_num));
return !addr->dev_addr.bound_dev_if || (net_eq(dev_net(net_dev), addr->dev_addr.net) && @@@ -1480,7 -1523,7 +1480,7 @@@ static struct rdma_id_private *cma_id_f if (PTR_ERR(*net_dev) == -EAFNOSUPPORT) { /* Assuming the protocol is AF_IB */ *net_dev = NULL; - } else if (cma_protocol_roce_dev_port(req.device, req.port)) { + } else if (rdma_protocol_roce(req.device, req.port)) { /* TODO find the net dev matching the request parameters * through the RoCE GID table */ *net_dev = NULL; @@@ -1625,7 -1668,6 +1625,7 @@@ void rdma_destroy_id(struct rdma_cm_id mutex_unlock(&id_priv->handler_mutex);
if (id_priv->cma_dev) { + rdma_restrack_del(&id_priv->res); if (rdma_cap_ib_cm(id_priv->id.device, 1)) { if (id_priv->cm_id.ib) ib_destroy_cm_id(id_priv->cm_id.ib); @@@ -1775,7 -1817,6 +1775,7 @@@ static struct rdma_id_private *cma_new_ struct ib_cm_event *ib_event, struct net_device *net_dev) { + struct rdma_id_private *listen_id_priv; struct rdma_id_private *id_priv; struct rdma_cm_id *id; struct rdma_route *rt; @@@ -1785,11 -1826,9 +1785,11 @@@ ib_event->param.req_rcvd.primary_path->service_id; int ret;
- id = rdma_create_id(listen_id->route.addr.dev_addr.net, + listen_id_priv = container_of(listen_id, struct rdma_id_private, id); + id = __rdma_create_id(listen_id->route.addr.dev_addr.net, listen_id->event_handler, listen_id->context, - listen_id->ps, ib_event->param.req_rcvd.qp_type); + listen_id->ps, ib_event->param.req_rcvd.qp_type, + listen_id_priv->res.kern_name); if (IS_ERR(id)) return NULL;
@@@ -1838,17 -1877,14 +1838,17 @@@ static struct rdma_id_private *cma_new_ struct ib_cm_event *ib_event, struct net_device *net_dev) { + struct rdma_id_private *listen_id_priv; struct rdma_id_private *id_priv; struct rdma_cm_id *id; const sa_family_t ss_family = listen_id->route.addr.src_addr.ss_family; struct net *net = listen_id->route.addr.dev_addr.net; int ret;
- id = rdma_create_id(net, listen_id->event_handler, listen_id->context, - listen_id->ps, IB_QPT_UD); + listen_id_priv = container_of(listen_id, struct rdma_id_private, id); + id = __rdma_create_id(net, listen_id->event_handler, listen_id->context, + listen_id->ps, IB_QPT_UD, + listen_id_priv->res.kern_name); if (IS_ERR(id)) return NULL;
@@@ -2114,11 -2150,10 +2114,11 @@@ static int iw_conn_req_handler(struct i goto out;
/* Create a new RDMA id for the new IW CM ID */ - new_cm_id = rdma_create_id(listen_id->id.route.addr.dev_addr.net, - listen_id->id.event_handler, - listen_id->id.context, - RDMA_PS_TCP, IB_QPT_RC); + new_cm_id = __rdma_create_id(listen_id->id.route.addr.dev_addr.net, + listen_id->id.event_handler, + listen_id->id.context, + RDMA_PS_TCP, IB_QPT_RC, + listen_id->res.kern_name); if (IS_ERR(new_cm_id)) { ret = -ENOMEM; goto out; @@@ -2243,8 -2278,8 +2243,8 @@@ static void cma_listen_on_dev(struct rd if (cma_family(id_priv) == AF_IB && !rdma_cap_ib_cm(cma_dev->device, 1)) return;
- id = rdma_create_id(net, cma_listen_handler, id_priv, id_priv->id.ps, - id_priv->id.qp_type); + id = __rdma_create_id(net, cma_listen_handler, id_priv, id_priv->id.ps, + id_priv->id.qp_type, id_priv->res.kern_name); if (IS_ERR(id)) return;
@@@ -3034,8 -3069,7 +3034,8 @@@ static int cma_port_is_unique(struct rd continue;
/* different dest port -> unique */ - if (!cma_any_port(cur_daddr) && + if (!cma_any_port(daddr) && + !cma_any_port(cur_daddr) && (dport != cur_dport)) continue;
@@@ -3046,8 -3080,7 +3046,8 @@@ continue;
/* different dst address -> unique */ - if (!cma_any_addr(cur_daddr) && + if (!cma_any_addr(daddr) && + !cma_any_addr(cur_daddr) && cma_addr_cmp(daddr, cur_daddr)) continue;
@@@ -3345,19 -3378,17 +3345,19 @@@ int rdma_bind_addr(struct rdma_cm_id *i } #endif } + daddr = cma_dst_addr(id_priv); + daddr->sa_family = addr->sa_family; + ret = cma_get_port(id_priv); if (ret) goto err2;
- daddr = cma_dst_addr(id_priv); - daddr->sa_family = addr->sa_family; - return 0; err2: - if (id_priv->cma_dev) + if (id_priv->cma_dev) { + rdma_restrack_del(&id_priv->res); cma_release_dev(id_priv); + } err1: cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_IDLE); return ret; @@@ -3740,18 -3771,14 +3740,18 @@@ static int cma_send_sidr_rep(struct rdm return ib_send_cm_sidr_rep(id_priv->cm_id.ib, &rep); }
-int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) +int __rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param, + const char *caller) { struct rdma_id_private *id_priv; int ret;
id_priv = container_of(id, struct rdma_id_private, id);
- id_priv->owner = task_pid_nr(current); + if (caller) + id_priv->res.kern_name = caller; + else + rdma_restrack_set_task(&id_priv->res, current);
if (!cma_comp(id_priv, RDMA_CM_CONNECT)) return -EINVAL; @@@ -3791,7 -3818,7 +3791,7 @@@ reject rdma_reject(id, NULL, 0); return ret; } -EXPORT_SYMBOL(rdma_accept); +EXPORT_SYMBOL(__rdma_accept);
int rdma_notify(struct rdma_cm_id *id, enum ib_event_type event) { @@@ -3909,14 -3936,10 +3909,14 @@@ static int cma_ib_mc_handler(int status rdma_start_port(id_priv->cma_dev->device)];
event.event = RDMA_CM_EVENT_MULTICAST_JOIN; - ib_init_ah_from_mcmember(id_priv->id.device, - id_priv->id.port_num, &multicast->rec, - ndev, gid_type, - &event.param.ud.ah_attr); + ret = ib_init_ah_from_mcmember(id_priv->id.device, + id_priv->id.port_num, + &multicast->rec, + ndev, gid_type, + &event.param.ud.ah_attr); + if (ret) + event.event = RDMA_CM_EVENT_MULTICAST_ERROR; + event.param.ud.qp_num = 0xFFFFFF; event.param.ud.qkey = be32_to_cpu(multicast->rec.qkey); if (ndev) @@@ -4150,9 -4173,6 +4150,9 @@@ int rdma_join_multicast(struct rdma_cm_ struct cma_multicast *mc; int ret;
+ if (!id->device) + return -EINVAL; + id_priv = container_of(id, struct rdma_id_private, id); if (!cma_comp(id_priv, RDMA_CM_ADDR_BOUND) && !cma_comp(id_priv, RDMA_CM_ADDR_RESOLVED)) @@@ -4476,7 -4496,7 +4476,7 @@@ static int cma_get_id_stats(struct sk_b RDMA_NL_RDMA_CM_ATTR_DST_ADDR)) goto out;
- id_stats->pid = id_priv->owner; + id_stats->pid = task_pid_vnr(id_priv->res.task); id_stats->port_space = id->ps; id_stats->cm_state = id_priv->state; id_stats->qp_num = id_priv->qp_num; @@@ -4529,6 -4549,7 +4529,7 @@@ static struct pernet_operations cma_per .exit = cma_exit_net, .id = &cma_pernet_id, .size = sizeof(struct cma_pernet), + .async = true, };
static int __init cma_init(void) diff --combined drivers/infiniband/hw/usnic/usnic_transport.c index 2e9bba52a686,67de94343cb4..e0a95538c364 --- a/drivers/infiniband/hw/usnic/usnic_transport.c +++ b/drivers/infiniband/hw/usnic/usnic_transport.c @@@ -174,14 -174,13 +174,13 @@@ void usnic_transport_put_socket(struct int usnic_transport_sock_get_addr(struct socket *sock, int *proto, uint32_t *addr, uint16_t *port) { - int len; int err; struct sockaddr_in sock_addr;
err = sock->ops->getname(sock, (struct sockaddr *)&sock_addr, - &len, 0); - if (err) + 0); + if (err < 0) return err;
if (sock_addr.sin_family != AF_INET) @@@ -201,8 -200,10 +200,8 @@@ int usnic_transport_init(void) { roce_bitmap = kzalloc(ROCE_BITMAP_SZ, GFP_KERNEL); - if (!roce_bitmap) { - usnic_err("Failed to allocate bit map"); + if (!roce_bitmap) return -ENOMEM; - }
/* Do not ever allocate bit 0, hence set it here */ bitmap_set(roce_bitmap, 0, 1); diff --combined drivers/net/dsa/b53/b53_common.c index 63e02a54d537,cd16067265dd..78616787f2a3 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@@ -814,8 -814,8 +814,8 @@@ void b53_get_strings(struct dsa_switch unsigned int i;
for (i = 0; i < mib_size; i++) - memcpy(data + i * ETH_GSTRING_LEN, - mibs[i].name, ETH_GSTRING_LEN); + strlcpy(data + i * ETH_GSTRING_LEN, + mibs[i].name, ETH_GSTRING_LEN); } EXPORT_SYMBOL(b53_get_strings);
@@@ -852,7 -852,7 +852,7 @@@ void b53_get_ethtool_stats(struct dsa_s } EXPORT_SYMBOL(b53_get_ethtool_stats);
- int b53_get_sset_count(struct dsa_switch *ds) + int b53_get_sset_count(struct dsa_switch *ds, int port) { struct b53_device *dev = ds->priv;
diff --combined drivers/net/ethernet/8390/ne.c index 4e05953c4fbc,4cdff6e6af89..44a084b41bf0 --- a/drivers/net/ethernet/8390/ne.c +++ b/drivers/net/ethernet/8390/ne.c @@@ -99,7 -99,7 +99,7 @@@ MODULE_LICENSE("GPL") that the ne2k probe is the last 8390 based probe to take place (as it is at boot) and so the probe will get confused by any other 8390 cards. ISA device autoprobes on a running machine are not recommended anyway. */ -#if !defined(MODULE) && (defined(CONFIG_ISA) || defined(CONFIG_M32R)) +#if !defined(MODULE) && defined(CONFIG_ISA) /* Do we need a portlist for the ISA auto-probe ? */ #define NEEDS_PORTLIST #endif @@@ -164,7 -164,12 +164,7 @@@ bad_clone_list[] __initdata = #define NESM_START_PG 0x40 /* First page of TX buffer */ #define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */
-#if defined(CONFIG_PLAT_MAPPI) -# define DCR_VAL 0x4b -#elif defined(CONFIG_PLAT_OAKS32R) || \ - defined(CONFIG_MACH_TX49XX) -# define DCR_VAL 0x48 /* 8-bit mode */ -#elif defined(CONFIG_ATARI) /* 8-bit mode on Atari, normal on Q40 */ +#if defined(CONFIG_ATARI) /* 8-bit mode on Atari, normal on Q40 */ # define DCR_VAL (MACH_IS_ATARI ? 0x48 : 0x49) #else # define DCR_VAL 0x49 @@@ -417,7 -422,12 +417,7 @@@ static int __init ne_probe1(struct net_ stop_page = NE1SM_STOP_PG; }
-#if defined(CONFIG_PLAT_MAPPI) || defined(CONFIG_PLAT_OAKS32R) - neX000 = ((SA_prom[14] == 0x57 && SA_prom[15] == 0x57) - || (SA_prom[14] == 0x42 && SA_prom[15] == 0x42)); -#else neX000 = (SA_prom[14] == 0x57 && SA_prom[15] == 0x57); -#endif ctron = (SA_prom[0] == 0x00 && SA_prom[1] == 0x00 && SA_prom[2] == 0x1d); copam = (SA_prom[14] == 0x49 && SA_prom[15] == 0x00);
@@@ -475,7 -485,7 +475,7 @@@ mdelay(10); /* wait 10ms for interrupt to propagate */ outb_p(0x00, ioaddr + EN0_IMR); /* Mask it again. */ dev->irq = probe_irq_off(cookie); - if (netif_msg_probe(ei_local)) + if (ne_msg_enable & NETIF_MSG_PROBE) pr_cont(" autoirq is %d", dev->irq); } else if (dev->irq == 2) /* Fixup for users that don't know that IRQ 2 is really IRQ 9, @@@ -498,9 -508,18 +498,9 @@@
dev->base_addr = ioaddr;
-#ifdef CONFIG_PLAT_MAPPI - outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, - ioaddr + E8390_CMD); /* 0x61 */ - for (i = 0; i < ETH_ALEN; i++) { - dev->dev_addr[i] = SA_prom[i] - = inb_p(ioaddr + EN1_PHYS_SHIFT(i)); - } -#else for (i = 0; i < ETH_ALEN; i++) { dev->dev_addr[i] = SA_prom[i]; } -#endif
pr_cont("%pM\n", dev->dev_addr);
diff --combined drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 61022b5f6743,99c9b88d6d34..e880be8e3c45 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@@ -75,6 -75,7 +75,7 @@@ #include "t4fw_api.h" #include "t4fw_version.h" #include "cxgb4_dcb.h" + #include "srq.h" #include "cxgb4_debugfs.h" #include "clip_tbl.h" #include "l2t.h" @@@ -210,6 -211,9 +211,9 @@@ static void link_report(struct net_devi case 40000: s = "40Gbps"; break; + case 50000: + s = "50Gbps"; + break; case 100000: s = "100Gbps"; break; @@@ -583,6 -587,10 +587,10 @@@ static int fwevtq_handler(struct sge_rs const struct cpl_abort_rpl_rss *p = (void *)rsp;
hash_del_filter_rpl(q->adap, p); + } else if (opcode == CPL_SRQ_TABLE_RPL) { + const struct cpl_srq_table_rpl *p = (void *)rsp; + + do_srq_table_rpl(q->adap, p); } else dev_err(q->adap->pdev_dev, "unexpected CPL %#x on FW event queue\n", opcode); @@@ -1733,10 -1741,11 +1741,11 @@@ EXPORT_SYMBOL(cxgb4_sync_txq_pidx)
int cxgb4_read_tpte(struct net_device *dev, u32 stag, __be32 *tpte) { - struct adapter *adap; - u32 offset, memtype, memaddr; u32 edc0_size, edc1_size, mc0_size, mc1_size, size; u32 edc0_end, edc1_end, mc0_end, mc1_end; + u32 offset, memtype, memaddr; + struct adapter *adap; + u32 hma_size = 0; int ret;
adap = netdev2adap(dev); @@@ -1756,6 -1765,10 +1765,10 @@@ size = t4_read_reg(adap, MA_EXT_MEMORY0_BAR_A); mc0_size = EXT_MEM0_SIZE_G(size) << 20;
+ if (t4_read_reg(adap, MA_TARGET_MEM_ENABLE_A) & HMA_MUX_F) { + size = t4_read_reg(adap, MA_EXT_MEMORY1_BAR_A); + hma_size = EXT_MEM1_SIZE_G(size) << 20; + } edc0_end = edc0_size; edc1_end = edc0_end + edc1_size; mc0_end = edc1_end + mc0_size; @@@ -1767,7 -1780,10 +1780,10 @@@ memtype = MEM_EDC1; memaddr = offset - edc0_end; } else { - if (offset < mc0_end) { + if (hma_size && (offset < (edc1_end + hma_size))) { + memtype = MEM_HMA; + memaddr = offset - edc1_end; + } else if (offset < mc0_end) { memtype = MEM_MC0; memaddr = offset - edc1_end; } else if (is_t5(adap->params.chip)) { @@@ -2870,11 -2886,11 +2886,11 @@@ static int cxgb_set_tx_maxrate(struct n /* Convert from Mbps to Kbps */ req_rate = rate << 10;
- /* Max rate is 10 Gbps */ + /* Max rate is 100 Gbps */ if (req_rate >= SCHED_MAX_RATE_KBPS) { dev_err(adap->pdev_dev, - "Invalid rate %u Mbps, Max rate is %u Gbps\n", - rate, SCHED_MAX_RATE_KBPS); + "Invalid rate %u Mbps, Max rate is %u Mbps\n", + rate, SCHED_MAX_RATE_KBPS >> 10); return -ERANGE; }
@@@ -3244,6 -3260,14 +3260,14 @@@ static const struct ethtool_ops cxgb4_m .get_drvinfo = cxgb4_mgmt_get_drvinfo, };
+ static void notify_fatal_err(struct work_struct *work) + { + struct adapter *adap; + + adap = container_of(work, struct adapter, fatal_err_notify_task); + notify_ulds(adap, CXGB4_STATE_FATAL_ERROR); + } + void t4_fatal_err(struct adapter *adap) { int port; @@@ -3268,6 -3292,7 +3292,7 @@@ netif_carrier_off(dev); } dev_alert(adap->pdev_dev, "encountered fatal error, adapter stopped\n"); + queue_work(adap->workq, &adap->fatal_err_notify_task); }
static void setup_memwin(struct adapter *adap) @@@ -3298,6 -3323,206 +3323,206 @@@ static void setup_memwin_rdma(struct ad } }
+ /* HMA Definitions */ + + /* The maximum number of address that can be send in a single FW cmd */ + #define HMA_MAX_ADDR_IN_CMD 5 + + #define HMA_PAGE_SIZE PAGE_SIZE + + #define HMA_MAX_NO_FW_ADDRESS (16 << 10) /* FW supports 16K addresses */ + + #define HMA_PAGE_ORDER \ + ((HMA_PAGE_SIZE < HMA_MAX_NO_FW_ADDRESS) ? \ + ilog2(HMA_MAX_NO_FW_ADDRESS / HMA_PAGE_SIZE) : 0) + + /* The minimum and maximum possible HMA sizes that can be specified in the FW + * configuration(in units of MB). + */ + #define HMA_MIN_TOTAL_SIZE 1 + #define HMA_MAX_TOTAL_SIZE \ + (((HMA_PAGE_SIZE << HMA_PAGE_ORDER) * \ + HMA_MAX_NO_FW_ADDRESS) >> 20) + + static void adap_free_hma_mem(struct adapter *adapter) + { + struct scatterlist *iter; + struct page *page; + int i; + + if (!adapter->hma.sgt) + return; + + if (adapter->hma.flags & HMA_DMA_MAPPED_FLAG) { + dma_unmap_sg(adapter->pdev_dev, adapter->hma.sgt->sgl, + adapter->hma.sgt->nents, PCI_DMA_BIDIRECTIONAL); + adapter->hma.flags &= ~HMA_DMA_MAPPED_FLAG; + } + + for_each_sg(adapter->hma.sgt->sgl, iter, + adapter->hma.sgt->orig_nents, i) { + page = sg_page(iter); + if (page) + __free_pages(page, HMA_PAGE_ORDER); + } + + kfree(adapter->hma.phy_addr); + sg_free_table(adapter->hma.sgt); + kfree(adapter->hma.sgt); + adapter->hma.sgt = NULL; + } + + static int adap_config_hma(struct adapter *adapter) + { + struct scatterlist *sgl, *iter; + struct sg_table *sgt; + struct page *newpage; + unsigned int i, j, k; + u32 param, hma_size; + unsigned int ncmds; + size_t page_size; + u32 page_order; + int node, ret; + + /* HMA is supported only for T6+ cards. + * Avoid initializing HMA in kdump kernels. + */ + if (is_kdump_kernel() || + CHELSIO_CHIP_VERSION(adapter->params.chip) < CHELSIO_T6) + return 0; + + /* Get the HMA region size required by fw */ + param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | + FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_HMA_SIZE)); + ret = t4_query_params(adapter, adapter->mbox, adapter->pf, 0, + 1, ¶m, &hma_size); + /* An error means card has its own memory or HMA is not supported by + * the firmware. Return without any errors. + */ + if (ret || !hma_size) + return 0; + + if (hma_size < HMA_MIN_TOTAL_SIZE || + hma_size > HMA_MAX_TOTAL_SIZE) { + dev_err(adapter->pdev_dev, + "HMA size %uMB beyond bounds(%u-%lu)MB\n", + hma_size, HMA_MIN_TOTAL_SIZE, HMA_MAX_TOTAL_SIZE); + return -EINVAL; + } + + page_size = HMA_PAGE_SIZE; + page_order = HMA_PAGE_ORDER; + adapter->hma.sgt = kzalloc(sizeof(*adapter->hma.sgt), GFP_KERNEL); + if (unlikely(!adapter->hma.sgt)) { + dev_err(adapter->pdev_dev, "HMA SG table allocation failed\n"); + return -ENOMEM; + } + sgt = adapter->hma.sgt; + /* FW returned value will be in MB's + */ + sgt->orig_nents = (hma_size << 20) / (page_size << page_order); + if (sg_alloc_table(sgt, sgt->orig_nents, GFP_KERNEL)) { + dev_err(adapter->pdev_dev, "HMA SGL allocation failed\n"); + kfree(adapter->hma.sgt); + adapter->hma.sgt = NULL; + return -ENOMEM; + } + + sgl = adapter->hma.sgt->sgl; + node = dev_to_node(adapter->pdev_dev); + for_each_sg(sgl, iter, sgt->orig_nents, i) { + newpage = alloc_pages_node(node, __GFP_NOWARN | GFP_KERNEL, + page_order); + if (!newpage) { + dev_err(adapter->pdev_dev, + "Not enough memory for HMA page allocation\n"); + ret = -ENOMEM; + goto free_hma; + } + sg_set_page(iter, newpage, page_size << page_order, 0); + } + + sgt->nents = dma_map_sg(adapter->pdev_dev, sgl, sgt->orig_nents, + DMA_BIDIRECTIONAL); + if (!sgt->nents) { + dev_err(adapter->pdev_dev, + "Not enough memory for HMA DMA mapping"); + ret = -ENOMEM; + goto free_hma; + } + adapter->hma.flags |= HMA_DMA_MAPPED_FLAG; + + adapter->hma.phy_addr = kcalloc(sgt->nents, sizeof(dma_addr_t), + GFP_KERNEL); + if (unlikely(!adapter->hma.phy_addr)) + goto free_hma; + + for_each_sg(sgl, iter, sgt->nents, i) { + newpage = sg_page(iter); + adapter->hma.phy_addr[i] = sg_dma_address(iter); + } + + ncmds = DIV_ROUND_UP(sgt->nents, HMA_MAX_ADDR_IN_CMD); + /* Pass on the addresses to firmware */ + for (i = 0, k = 0; i < ncmds; i++, k += HMA_MAX_ADDR_IN_CMD) { + struct fw_hma_cmd hma_cmd; + u8 naddr = HMA_MAX_ADDR_IN_CMD; + u8 soc = 0, eoc = 0; + u8 hma_mode = 1; /* Presently we support only Page table mode */ + + soc = (i == 0) ? 1 : 0; + eoc = (i == ncmds - 1) ? 1 : 0; + + /* For last cmd, set naddr corresponding to remaining + * addresses + */ + if (i == ncmds - 1) { + naddr = sgt->nents % HMA_MAX_ADDR_IN_CMD; + naddr = naddr ? naddr : HMA_MAX_ADDR_IN_CMD; + } + memset(&hma_cmd, 0, sizeof(hma_cmd)); + hma_cmd.op_pkd = htonl(FW_CMD_OP_V(FW_HMA_CMD) | + FW_CMD_REQUEST_F | FW_CMD_WRITE_F); + hma_cmd.retval_len16 = htonl(FW_LEN16(hma_cmd)); + + hma_cmd.mode_to_pcie_params = + htonl(FW_HMA_CMD_MODE_V(hma_mode) | + FW_HMA_CMD_SOC_V(soc) | FW_HMA_CMD_EOC_V(eoc)); + + /* HMA cmd size specified in MB's */ + hma_cmd.naddr_size = + htonl(FW_HMA_CMD_SIZE_V(hma_size) | + FW_HMA_CMD_NADDR_V(naddr)); + + /* Total Page size specified in units of 4K */ + hma_cmd.addr_size_pkd = + htonl(FW_HMA_CMD_ADDR_SIZE_V + ((page_size << page_order) >> 12)); + + /* Fill the 5 addresses */ + for (j = 0; j < naddr; j++) { + hma_cmd.phy_address[j] = + cpu_to_be64(adapter->hma.phy_addr[j + k]); + } + ret = t4_wr_mbox(adapter, adapter->mbox, &hma_cmd, + sizeof(hma_cmd), &hma_cmd); + if (ret) { + dev_err(adapter->pdev_dev, + "HMA FW command failed with err %d\n", ret); + goto free_hma; + } + } + + if (!ret) + dev_info(adapter->pdev_dev, + "Reserved %uMB host memory for HMA\n", hma_size); + return ret; + + free_hma: + adap_free_hma_mem(adapter); + return ret; + } + static int adap_init1(struct adapter *adap, struct fw_caps_config_cmd *c) { u32 v; @@@ -3751,6 -3976,12 +3976,12 @@@ static int adap_init0_config(struct ada if (ret < 0) goto bye;
+ /* We will proceed even if HMA init fails. */ + ret = adap_config_hma(adapter); + if (ret) + dev_err(adapter->pdev_dev, + "HMA configuration failed with error %d\n", ret); + /* * And finally tell the firmware to initialize itself using the * parameters from the Configuration File. @@@ -3957,6 -4188,11 +4188,11 @@@ static int adap_init0(struct adapter *a * effect. Otherwise, it's time to try initializing the adapter. */ if (state == DEV_STATE_INIT) { + ret = adap_config_hma(adap); + if (ret) + dev_err(adap->pdev_dev, + "HMA configuration failed with error %d\n", + ret); dev_info(adap->pdev_dev, "Coming up as %s: "\ "Adapter already initialized\n", adap->flags & MASTER_PF ? "MASTER" : "SLAVE"); @@@ -4236,6 -4472,20 +4472,20 @@@ adap->vres.pbl.start = val[4]; adap->vres.pbl.size = val[5] - val[4] + 1;
+ params[0] = FW_PARAM_PFVF(SRQ_START); + params[1] = FW_PARAM_PFVF(SRQ_END); + ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2, + params, val); + if (!ret) { + adap->vres.srq.start = val[0]; + adap->vres.srq.size = val[1] - val[0] + 1; + } + if (adap->vres.srq.size) { + adap->srq = t4_init_srq(adap->vres.srq.size); + if (!adap->srq) + dev_warn(&adap->pdev->dev, "could not allocate SRQ, continuing\n"); + } + params[0] = FW_PARAM_PFVF(SQRQ_START); params[1] = FW_PARAM_PFVF(SQRQ_END); params[2] = FW_PARAM_PFVF(CQ_START); @@@ -4269,6 -4519,18 +4519,18 @@@ "max_ordird_qp %d max_ird_adapter %d\n", adap->params.max_ordird_qp, adap->params.max_ird_adapter); + + /* Enable write_with_immediate if FW supports it */ + params[0] = FW_PARAM_DEV(RDMA_WRITE_WITH_IMM); + ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1, params, + val); + adap->params.write_w_imm_support = (ret == 0 && val[0] != 0); + + /* Enable write_cmpl if FW supports it */ + params[0] = FW_PARAM_DEV(RI_WRITE_CMPL_WR); + ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1, params, + val); + adap->params.write_cmpl_support = (ret == 0 && val[0] != 0); adap->num_ofld_uld += 2; } if (caps_cmd.iscsicaps) { @@@ -4346,6 -4608,7 +4608,7 @@@ * happened to HW/FW, stop issuing commands. */ bye: + adap_free_hma_mem(adap); kfree(adap->sge.egr_map); kfree(adap->sge.ingr_map); kfree(adap->sge.starving_fl); @@@ -4903,6 -5166,7 +5166,7 @@@ static void free_some_resources(struct
kvfree(adapter->smt); kvfree(adapter->l2t); + kvfree(adapter->srq); t4_cleanup_sched(adapter); kvfree(adapter->tids.tid_tab); cxgb4_cleanup_tc_flower(adapter); @@@ -4970,6 -5234,7 +5234,6 @@@ static void cxgb4_mgmt_setup(struct net /* Initialize the device structure. */ dev->netdev_ops = &cxgb4_mgmt_netdev_ops; dev->ethtool_ops = &cxgb4_mgmt_ethtool_ops; - dev->needs_free_netdev = true; }
static int cxgb4_iov_configure(struct pci_dev *pdev, int num_vfs) @@@ -5180,8 -5445,6 +5444,8 @@@ static int init_one(struct pci_dev *pde adapter->name = pci_name(pdev); adapter->mbox = func; adapter->pf = func; + adapter->params.chip = chip; + adapter->adap_idx = adap_idx; adapter->msg_enable = DFLT_MSG_ENABLE; adapter->mbox_log = kzalloc(sizeof(*adapter->mbox_log) + (sizeof(struct mbox_cmd) * @@@ -5257,6 -5520,7 +5521,7 @@@ INIT_WORK(&adapter->tid_release_task, process_tid_release_list); INIT_WORK(&adapter->db_full_task, process_db_full); INIT_WORK(&adapter->db_drop_task, process_db_drop); + INIT_WORK(&adapter->fatal_err_notify_task, notify_fatal_err);
err = t4_prep_adapter(adapter); if (err) @@@ -5574,6 -5838,8 +5839,8 @@@ static void remove_one(struct pci_dev * t4_uld_clean_up(adapter); }
+ adap_free_hma_mem(adapter); + disable_interrupts(adapter);
for_each_port(adapter, i) diff --combined drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index e4ec32a9ca15,159dc2df878d..fd43f98ddbe7 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@@ -454,6 -454,16 +454,16 @@@ static void dpaa_set_rx_mode(struct net err); }
+ if (!!(net_dev->flags & IFF_ALLMULTI) != priv->mac_dev->allmulti) { + priv->mac_dev->allmulti = !priv->mac_dev->allmulti; + err = priv->mac_dev->set_allmulti(priv->mac_dev->fman_mac, + priv->mac_dev->allmulti); + if (err < 0) + netif_err(priv, drv, net_dev, + "mac_dev->set_allmulti() = %d\n", + err); + } + err = priv->mac_dev->set_multi(net_dev, priv->mac_dev); if (err < 0) netif_err(priv, drv, net_dev, "mac_dev->set_multi() = %d\n", @@@ -1916,8 -1926,10 +1926,10 @@@ static int skb_to_sg_fd(struct dpaa_pri goto csum_failed; }
+ /* SGT[0] is used by the linear part */ sgt = (struct qm_sg_entry *)(sgt_buf + priv->tx_headroom); - qm_sg_entry_set_len(&sgt[0], skb_headlen(skb)); + frag_len = skb_headlen(skb); + qm_sg_entry_set_len(&sgt[0], frag_len); sgt[0].bpid = FSL_DPAA_BPID_INV; sgt[0].offset = 0; addr = dma_map_single(dev, skb->data, @@@ -1930,9 -1942,9 +1942,9 @@@ qm_sg_entry_set64(&sgt[0], addr);
/* populate the rest of SGT entries */ - frag = &skb_shinfo(skb)->frags[0]; - frag_len = frag->size; - for (i = 1; i <= nr_frags; i++, frag++) { + for (i = 0; i < nr_frags; i++) { + frag = &skb_shinfo(skb)->frags[i]; + frag_len = frag->size; WARN_ON(!skb_frag_page(frag)); addr = skb_frag_dma_map(dev, frag, 0, frag_len, dma_dir); @@@ -1942,15 -1954,16 +1954,16 @@@ goto sg_map_failed; }
- qm_sg_entry_set_len(&sgt[i], frag_len); - sgt[i].bpid = FSL_DPAA_BPID_INV; - sgt[i].offset = 0; + qm_sg_entry_set_len(&sgt[i + 1], frag_len); + sgt[i + 1].bpid = FSL_DPAA_BPID_INV; + sgt[i + 1].offset = 0;
/* keep the offset in the address */ - qm_sg_entry_set64(&sgt[i], addr); - frag_len = frag->size; + qm_sg_entry_set64(&sgt[i + 1], addr); } - qm_sg_entry_set_f(&sgt[i - 1], frag_len); + + /* Set the final bit in the last used entry of the SGT */ + qm_sg_entry_set_f(&sgt[nr_frags], frag_len);
qm_fd_set_sg(fd, priv->tx_headroom, skb->len);
@@@ -2008,6 -2021,7 +2021,6 @@@ static inline int dpaa_xmit(struct dpaa }
if (unlikely(err < 0)) { - percpu_stats->tx_errors++; percpu_stats->tx_fifo_errors++; return err; } @@@ -2051,19 -2065,23 +2064,23 @@@ static int dpaa_start_xmit(struct sk_bu /* MAX_SKB_FRAGS is equal or larger than our dpaa_SGT_MAX_ENTRIES; * make sure we don't feed FMan with more fragments than it supports. */ - if (nonlinear && - likely(skb_shinfo(skb)->nr_frags < DPAA_SGT_MAX_ENTRIES)) { - /* Just create a S/G fd based on the skb */ - err = skb_to_sg_fd(priv, skb, &fd); - percpu_priv->tx_frag_skbuffs++; - } else { + if (unlikely(nonlinear && + (skb_shinfo(skb)->nr_frags >= DPAA_SGT_MAX_ENTRIES))) { /* If the egress skb contains more fragments than we support * we have no choice but to linearize it ourselves. */ - if (unlikely(nonlinear) && __skb_linearize(skb)) + if (__skb_linearize(skb)) goto enomem;
- /* Finally, create a contig FD from this skb */ + nonlinear = skb_is_nonlinear(skb); + } + + if (nonlinear) { + /* Just create a S/G fd based on the skb */ + err = skb_to_sg_fd(priv, skb, &fd); + percpu_priv->tx_frag_skbuffs++; + } else { + /* Create a contig FD from this skb */ err = skb_to_contig_fd(priv, skb, &fd, &offset); } if (unlikely(err < 0)) @@@ -2200,14 -2218,8 +2217,8 @@@ static enum qman_cb_dqrr_result rx_erro if (dpaa_eth_napi_schedule(percpu_priv, portal)) return qman_cb_dqrr_stop;
- if (dpaa_eth_refill_bpools(priv)) - /* Unable to refill the buffer pool due to insufficient - * system memory. Just release the frame back into the pool, - * otherwise we'll soon end up with an empty buffer pool. - */ - dpaa_fd_release(net_dev, &dq->fd); - else - dpaa_rx_error(net_dev, priv, percpu_priv, &dq->fd, fq->fqid); + dpaa_eth_refill_bpools(priv); + dpaa_rx_error(net_dev, priv, percpu_priv, &dq->fd, fq->fqid);
return qman_cb_dqrr_consume; } @@@ -2277,6 -2289,7 +2288,6 @@@ static enum qman_cb_dqrr_result rx_defa vaddr = phys_to_virt(addr); prefetch(vaddr + qm_fd_get_offset(fd));
- fd_format = qm_fd_get_format(fd); /* The only FD types that we may receive are contig and S/G */ WARN_ON((fd_format != qm_fd_contig) && (fd_format != qm_fd_sg));
@@@ -2309,10 -2322,8 +2320,10 @@@
skb_len = skb->len;
- if (unlikely(netif_receive_skb(skb) == NET_RX_DROP)) + if (unlikely(netif_receive_skb(skb) == NET_RX_DROP)) { + percpu_stats->rx_dropped++; return qman_cb_dqrr_consume; + }
percpu_stats->rx_packets++; percpu_stats->rx_bytes += skb_len; @@@ -2766,7 -2777,7 +2777,7 @@@ static int dpaa_eth_probe(struct platfo
priv->channel = (u16)channel;
- /* Start a thread that will walk the CPUs with affine portals + /* Walk the CPUs with affine portals * and add this pool channel to each's dequeue mask. */ dpaa_eth_add_channel(priv->channel); @@@ -2860,7 -2871,7 +2871,7 @@@ static int dpaa_remove(struct platform_ struct device *dev; int err;
- dev = &pdev->dev; + dev = pdev->dev.parent; net_dev = dev_get_drvdata(dev);
priv = netdev_priv(net_dev); diff --combined drivers/net/ethernet/freescale/fman/fman_dtsec.c index 7af31ddd093f,9a581faaa742..57b1e2b47c0a --- a/drivers/net/ethernet/freescale/fman/fman_dtsec.c +++ b/drivers/net/ethernet/freescale/fman/fman_dtsec.c @@@ -1100,7 -1100,7 +1100,7 @@@ int dtsec_add_hash_mac_address(struct f set_bucket(dtsec->regs, bucket, true);
/* Create element to be added to the driver hash table */ - hash_entry = kmalloc(sizeof(*hash_entry), GFP_KERNEL); + hash_entry = kmalloc(sizeof(*hash_entry), GFP_ATOMIC); if (!hash_entry) return -ENOMEM; hash_entry->addr = addr; @@@ -1117,6 -1117,25 +1117,25 @@@ return 0; }
+ int dtsec_set_allmulti(struct fman_mac *dtsec, bool enable) + { + u32 tmp; + struct dtsec_regs __iomem *regs = dtsec->regs; + + if (!is_init_done(dtsec->dtsec_drv_param)) + return -EINVAL; + + tmp = ioread32be(®s->rctrl); + if (enable) + tmp |= RCTRL_MPROM; + else + tmp &= ~RCTRL_MPROM; + + iowrite32be(tmp, ®s->rctrl); + + return 0; + } + int dtsec_del_hash_mac_address(struct fman_mac *dtsec, enet_addr_t *eth_addr) { struct dtsec_regs __iomem *regs = dtsec->regs; diff --combined drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c index 996dc099cd58,ba338428ffd1..3c0d882ba183 --- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c @@@ -1,6 -1,6 +1,6 @@@ /* * drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c - * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * Copyright (c) 2017, 2018 Mellanox Technologies. All rights reserved. * Copyright (c) 2017 Jiri Pirko jiri@mellanox.com * * Redistribution and use in source and binary forms, with or without @@@ -443,17 -443,6 +443,17 @@@ int mlxsw_afa_block_jump(struct mlxsw_a } EXPORT_SYMBOL(mlxsw_afa_block_jump);
+int mlxsw_afa_block_terminate(struct mlxsw_afa_block *block) +{ + if (block->finished) + return -EINVAL; + mlxsw_afa_set_goto_set(block->cur_set, + MLXSW_AFA_SET_GOTO_BINDING_CMD_TERM, 0); + block->finished = true; + return 0; +} +EXPORT_SYMBOL(mlxsw_afa_block_terminate); + static struct mlxsw_afa_fwd_entry * mlxsw_afa_fwd_entry_create(struct mlxsw_afa *mlxsw_afa, u8 local_port) { @@@ -849,7 -838,6 +849,6 @@@ struct mlxsw_afa_mirror struct mlxsw_afa_resource resource; int span_id; u8 local_in_port; - u8 local_out_port; bool ingress; };
@@@ -859,7 -847,7 +858,7 @@@ mlxsw_afa_mirror_destroy(struct mlxsw_a { block->afa->ops->mirror_del(block->afa->ops_priv, mirror->local_in_port, - mirror->local_out_port, + mirror->span_id, mirror->ingress); kfree(mirror); } @@@ -875,9 -863,8 +874,8 @@@ mlxsw_afa_mirror_destructor(struct mlxs }
static struct mlxsw_afa_mirror * - mlxsw_afa_mirror_create(struct mlxsw_afa_block *block, - u8 local_in_port, u8 local_out_port, - bool ingress) + mlxsw_afa_mirror_create(struct mlxsw_afa_block *block, u8 local_in_port, + const struct net_device *out_dev, bool ingress) { struct mlxsw_afa_mirror *mirror; int err; @@@ -887,13 -874,12 +885,12 @@@ return ERR_PTR(-ENOMEM);
err = block->afa->ops->mirror_add(block->afa->ops_priv, - local_in_port, local_out_port, + local_in_port, out_dev, ingress, &mirror->span_id); if (err) goto err_mirror_add;
mirror->ingress = ingress; - mirror->local_out_port = local_out_port; mirror->local_in_port = local_in_port; mirror->resource.destructor = mlxsw_afa_mirror_destructor; mlxsw_afa_resource_add(block, &mirror->resource); @@@ -920,13 -906,13 +917,13 @@@ mlxsw_afa_block_append_allocated_mirror }
int - mlxsw_afa_block_append_mirror(struct mlxsw_afa_block *block, - u8 local_in_port, u8 local_out_port, bool ingress) + mlxsw_afa_block_append_mirror(struct mlxsw_afa_block *block, u8 local_in_port, + const struct net_device *out_dev, bool ingress) { struct mlxsw_afa_mirror *mirror; int err;
- mirror = mlxsw_afa_mirror_create(block, local_in_port, local_out_port, + mirror = mlxsw_afa_mirror_create(block, local_in_port, out_dev, ingress); if (IS_ERR(mirror)) return PTR_ERR(mirror); diff --combined drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h index b91f2b0829b0,6dd601703c99..3a155d104384 --- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h +++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h @@@ -36,6 -36,7 +36,7 @@@ #define _MLXSW_CORE_ACL_FLEX_ACTIONS_H
#include <linux/types.h> + #include <linux/netdevice.h>
struct mlxsw_afa; struct mlxsw_afa_block; @@@ -48,9 -49,10 +49,10 @@@ struct mlxsw_afa_ops void (*kvdl_fwd_entry_del)(void *priv, u32 kvdl_index); int (*counter_index_get)(void *priv, unsigned int *p_counter_index); void (*counter_index_put)(void *priv, unsigned int counter_index); - int (*mirror_add)(void *priv, u8 locol_in_port, u8 local_out_port, + int (*mirror_add)(void *priv, u8 local_in_port, + const struct net_device *out_dev, bool ingress, int *p_span_id); - void (*mirror_del)(void *priv, u8 locol_in_port, u8 local_out_port, + void (*mirror_del)(void *priv, u8 local_in_port, int span_id, bool ingress); };
@@@ -65,13 -67,13 +67,14 @@@ char *mlxsw_afa_block_first_set(struct u32 mlxsw_afa_block_first_set_kvdl_index(struct mlxsw_afa_block *block); int mlxsw_afa_block_continue(struct mlxsw_afa_block *block); int mlxsw_afa_block_jump(struct mlxsw_afa_block *block, u16 group_id); +int mlxsw_afa_block_terminate(struct mlxsw_afa_block *block); int mlxsw_afa_block_append_drop(struct mlxsw_afa_block *block); int mlxsw_afa_block_append_trap(struct mlxsw_afa_block *block, u16 trap_id); int mlxsw_afa_block_append_trap_and_forward(struct mlxsw_afa_block *block, u16 trap_id); int mlxsw_afa_block_append_mirror(struct mlxsw_afa_block *block, - u8 local_in_port, u8 local_out_port, + u8 local_in_port, + const struct net_device *out_dev, bool ingress); int mlxsw_afa_block_append_fwd(struct mlxsw_afa_block *block, u8 local_port, bool in_port); diff --combined drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 92064db2ae44,92194a9b2caf..21bee8f19894 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@@ -70,16 -70,23 +70,23 @@@ #define MLXSW_SP_RESOURCE_NAME_KVD_LINEAR "linear" #define MLXSW_SP_RESOURCE_NAME_KVD_HASH_SINGLE "hash_single" #define MLXSW_SP_RESOURCE_NAME_KVD_HASH_DOUBLE "hash_double" + #define MLXSW_SP_RESOURCE_NAME_KVD_LINEAR_SINGLES "singles" + #define MLXSW_SP_RESOURCE_NAME_KVD_LINEAR_CHUNKS "chunks" + #define MLXSW_SP_RESOURCE_NAME_KVD_LINEAR_LARGE_CHUNKS "large_chunks"
enum mlxsw_sp_resource_id { MLXSW_SP_RESOURCE_KVD, MLXSW_SP_RESOURCE_KVD_LINEAR, MLXSW_SP_RESOURCE_KVD_HASH_SINGLE, MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE, + MLXSW_SP_RESOURCE_KVD_LINEAR_SINGLE, + MLXSW_SP_RESOURCE_KVD_LINEAR_CHUNKS, + MLXSW_SP_RESOURCE_KVD_LINEAR_LARGE_CHUNKS, };
struct mlxsw_sp_port; struct mlxsw_sp_rif; + struct mlxsw_sp_span_entry;
struct mlxsw_sp_upper { struct net_device *dev; @@@ -111,35 -118,13 +118,13 @@@ struct mlxsw_sp_mid unsigned long *ports_in_mid; /* bits array */ };
- enum mlxsw_sp_span_type { - MLXSW_SP_SPAN_EGRESS, - MLXSW_SP_SPAN_INGRESS - }; - - struct mlxsw_sp_span_inspected_port { - struct list_head list; - enum mlxsw_sp_span_type type; - u8 local_port; - - /* Whether this is a directly bound mirror (port-to-port) or an ACL. */ - bool bound; - }; - - struct mlxsw_sp_span_entry { - u8 local_port; - bool used; - struct list_head bound_ports_list; - int ref_count; - int id; - }; - enum mlxsw_sp_port_mall_action_type { MLXSW_SP_PORT_MALL_MIRROR, MLXSW_SP_PORT_MALL_SAMPLE, };
struct mlxsw_sp_port_mall_mirror_tc_entry { - u8 to_local_port; + int span_id; bool ingress; };
@@@ -226,6 -211,8 +211,8 @@@ struct mlxsw_sp_port_xstats u64 wred_drop[TC_MAX_QUEUE]; u64 tail_drop[TC_MAX_QUEUE]; u64 backlog[TC_MAX_QUEUE]; + u64 tx_bytes[IEEE_8021QAZ_MAX_TCS]; + u64 tx_packets[IEEE_8021QAZ_MAX_TCS]; };
struct mlxsw_sp_port { @@@ -263,6 -250,7 +250,7 @@@ struct mlxsw_sp_port_sample *sample; struct list_head vlans_list; struct mlxsw_sp_qdisc *root_qdisc; + struct mlxsw_sp_qdisc *tclass_qdiscs; unsigned acl_rule_count; struct mlxsw_sp_acl_block *ing_acl_block; struct mlxsw_sp_acl_block *eg_acl_block; @@@ -400,16 -388,6 +388,6 @@@ struct mlxsw_sp_port *mlxsw_sp_port_dev struct mlxsw_sp_port *mlxsw_sp_port_lower_dev_hold(struct net_device *dev); void mlxsw_sp_port_dev_put(struct mlxsw_sp_port *mlxsw_sp_port); struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find_rcu(struct net_device *dev); - int mlxsw_sp_span_mirror_add(struct mlxsw_sp_port *from, - struct mlxsw_sp_port *to, - enum mlxsw_sp_span_type type, - bool bind); - void mlxsw_sp_span_mirror_del(struct mlxsw_sp_port *from, - u8 destination_port, - enum mlxsw_sp_span_type type, - bool bind); - struct mlxsw_sp_span_entry * - mlxsw_sp_span_entry_find(struct mlxsw_sp *mlxsw_sp, u8 local_port);
/* spectrum_dcb.c */ #ifdef CONFIG_MLXSW_SPECTRUM_DCB @@@ -465,6 -443,7 +443,7 @@@ int mlxsw_sp_kvdl_alloc_size_query(stru unsigned int entry_count, unsigned int *p_alloc_size); u64 mlxsw_sp_kvdl_occ_get(const struct mlxsw_sp *mlxsw_sp); + int mlxsw_sp_kvdl_resources_register(struct devlink *devlink);
struct mlxsw_sp_acl_rule_info { unsigned int priority; @@@ -556,7 -535,6 +535,7 @@@ void mlxsw_sp_acl_rulei_keymask_buf(str int mlxsw_sp_acl_rulei_act_continue(struct mlxsw_sp_acl_rule_info *rulei); int mlxsw_sp_acl_rulei_act_jump(struct mlxsw_sp_acl_rule_info *rulei, u16 group_id); +int mlxsw_sp_acl_rulei_act_terminate(struct mlxsw_sp_acl_rule_info *rulei); int mlxsw_sp_acl_rulei_act_drop(struct mlxsw_sp_acl_rule_info *rulei); int mlxsw_sp_acl_rulei_act_trap(struct mlxsw_sp_acl_rule_info *rulei); int mlxsw_sp_acl_rulei_act_mirror(struct mlxsw_sp *mlxsw_sp, diff --combined drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c index 92d90ed7207e,1c1601a43978..79b1fa27a9a4 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c @@@ -160,6 -160,13 +160,13 @@@ bool mlxsw_sp_acl_block_disabled(struc return block->disable_count; }
+ static bool + mlxsw_sp_acl_ruleset_is_singular(const struct mlxsw_sp_acl_ruleset *ruleset) + { + /* We hold a reference on ruleset ourselves */ + return ruleset->ref_count == 2; + } + static int mlxsw_sp_acl_ruleset_bind(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_block *block, @@@ -341,21 -348,8 +348,8 @@@ mlxsw_sp_acl_ruleset_create(struct mlxs if (err) goto err_ht_insert;
- if (!chain_index) { - /* We only need ruleset with chain index 0, the implicit one, - * to be directly bound to device. The rest of the rulesets - * are bound by "Goto action set". - */ - err = mlxsw_sp_acl_ruleset_block_bind(mlxsw_sp, ruleset, block); - if (err) - goto err_ruleset_bind; - } - return ruleset;
- err_ruleset_bind: - rhashtable_remove_fast(&acl->ruleset_ht, &ruleset->ht_node, - mlxsw_sp_acl_ruleset_ht_params); err_ht_insert: ops->ruleset_del(mlxsw_sp, ruleset->priv); err_ops_ruleset_add: @@@ -369,12 -363,8 +363,8 @@@ static void mlxsw_sp_acl_ruleset_destro struct mlxsw_sp_acl_ruleset *ruleset) { const struct mlxsw_sp_acl_profile_ops *ops = ruleset->ht_key.ops; - struct mlxsw_sp_acl_block *block = ruleset->ht_key.block; - u32 chain_index = ruleset->ht_key.chain_index; struct mlxsw_sp_acl *acl = mlxsw_sp->acl;
- if (!chain_index) - mlxsw_sp_acl_ruleset_block_unbind(mlxsw_sp, ruleset, block); rhashtable_remove_fast(&acl->ruleset_ht, &ruleset->ht_node, mlxsw_sp_acl_ruleset_ht_params); ops->ruleset_del(mlxsw_sp, ruleset->priv); @@@ -528,11 -518,6 +518,11 @@@ int mlxsw_sp_acl_rulei_act_jump(struct return mlxsw_afa_block_jump(rulei->act_block, group_id); }
+int mlxsw_sp_acl_rulei_act_terminate(struct mlxsw_sp_acl_rule_info *rulei) +{ + return mlxsw_afa_block_terminate(rulei->act_block); +} + int mlxsw_sp_acl_rulei_act_drop(struct mlxsw_sp_acl_rule_info *rulei) { return mlxsw_afa_block_append_drop(rulei->act_block); @@@ -577,7 -562,6 +567,6 @@@ int mlxsw_sp_acl_rulei_act_mirror(struc struct net_device *out_dev) { struct mlxsw_sp_acl_block_binding *binding; - struct mlxsw_sp_port *out_port; struct mlxsw_sp_port *in_port;
if (!list_is_singular(&block->binding_list)) @@@ -586,16 -570,10 +575,10 @@@ binding = list_first_entry(&block->binding_list, struct mlxsw_sp_acl_block_binding, list); in_port = binding->mlxsw_sp_port; - if (!mlxsw_sp_port_dev_check(out_dev)) - return -EINVAL; - - out_port = netdev_priv(out_dev); - if (out_port->mlxsw_sp != mlxsw_sp) - return -EINVAL;
return mlxsw_afa_block_append_mirror(rulei->act_block, in_port->local_port, - out_port->local_port, + out_dev, binding->ingress); }
@@@ -700,10 -678,25 +683,25 @@@ int mlxsw_sp_acl_rule_add(struct mlxsw_ if (err) goto err_rhashtable_insert;
+ if (!ruleset->ht_key.chain_index && + mlxsw_sp_acl_ruleset_is_singular(ruleset)) { + /* We only need ruleset with chain index 0, the implicit + * one, to be directly bound to device. The rest of the + * rulesets are bound by "Goto action set". + */ + err = mlxsw_sp_acl_ruleset_block_bind(mlxsw_sp, ruleset, + ruleset->ht_key.block); + if (err) + goto err_ruleset_block_bind; + } + list_add_tail(&rule->list, &mlxsw_sp->acl->rules); ruleset->ht_key.block->rule_count++; return 0;
+ err_ruleset_block_bind: + rhashtable_remove_fast(&ruleset->rule_ht, &rule->ht_node, + mlxsw_sp_acl_rule_ht_params); err_rhashtable_insert: ops->rule_del(mlxsw_sp, rule->priv); return err; @@@ -717,6 -710,10 +715,10 @@@ void mlxsw_sp_acl_rule_del(struct mlxsw
ruleset->ht_key.block->rule_count--; list_del(&rule->list); + if (!ruleset->ht_key.chain_index && + mlxsw_sp_acl_ruleset_is_singular(ruleset)) + mlxsw_sp_acl_ruleset_block_unbind(mlxsw_sp, ruleset, + ruleset->ht_key.block); rhashtable_remove_fast(&ruleset->rule_ht, &rule->ht_node, mlxsw_sp_acl_rule_ht_params); ops->rule_del(mlxsw_sp, rule->priv); diff --combined drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c index 000000000000,ae22a3daffbf..4d6ed207b4af mode 000000,100644..100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c @@@ -1,0 -1,804 +1,824 @@@ + /* + * drivers/net/ethernet/mellanox/mlxsw/mlxsw_span.c + * Copyright (c) 2018 Mellanox Technologies. All rights reserved. + * Copyright (c) 2018 Petr Machata petrm@mellanox.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + #include <linux/list.h> + #include <net/arp.h> + #include <net/gre.h> + #include <net/ndisc.h> + #include <net/ip6_tunnel.h> + + #include "spectrum.h" + #include "spectrum_span.h" + #include "spectrum_ipip.h" + + int mlxsw_sp_span_init(struct mlxsw_sp *mlxsw_sp) + { + int i; + + if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_SPAN)) + return -EIO; + + mlxsw_sp->span.entries_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, + MAX_SPAN); + mlxsw_sp->span.entries = kcalloc(mlxsw_sp->span.entries_count, + sizeof(struct mlxsw_sp_span_entry), + GFP_KERNEL); + if (!mlxsw_sp->span.entries) + return -ENOMEM; + + for (i = 0; i < mlxsw_sp->span.entries_count; i++) { + struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i]; + + INIT_LIST_HEAD(&curr->bound_ports_list); + curr->id = i; + } + + return 0; + } + + void mlxsw_sp_span_fini(struct mlxsw_sp *mlxsw_sp) + { + int i; + + for (i = 0; i < mlxsw_sp->span.entries_count; i++) { + struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i]; + + WARN_ON_ONCE(!list_empty(&curr->bound_ports_list)); + } + kfree(mlxsw_sp->span.entries); + } + + static int + mlxsw_sp_span_entry_phys_parms(const struct net_device *to_dev, + struct mlxsw_sp_span_parms *sparmsp) + { + sparmsp->dest_port = netdev_priv(to_dev); + return 0; + } + + static int + mlxsw_sp_span_entry_phys_configure(struct mlxsw_sp_span_entry *span_entry, + struct mlxsw_sp_span_parms sparms) + { + struct mlxsw_sp_port *dest_port = sparms.dest_port; + struct mlxsw_sp *mlxsw_sp = dest_port->mlxsw_sp; + u8 local_port = dest_port->local_port; + char mpat_pl[MLXSW_REG_MPAT_LEN]; + int pa_id = span_entry->id; + + /* Create a new port analayzer entry for local_port. */ + mlxsw_reg_mpat_pack(mpat_pl, pa_id, local_port, true, + MLXSW_REG_MPAT_SPAN_TYPE_LOCAL_ETH); + + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl); + } + + static void + mlxsw_sp_span_entry_deconfigure_common(struct mlxsw_sp_span_entry *span_entry, + enum mlxsw_reg_mpat_span_type span_type) + { + struct mlxsw_sp_port *dest_port = span_entry->parms.dest_port; + struct mlxsw_sp *mlxsw_sp = dest_port->mlxsw_sp; + u8 local_port = dest_port->local_port; + char mpat_pl[MLXSW_REG_MPAT_LEN]; + int pa_id = span_entry->id; + + mlxsw_reg_mpat_pack(mpat_pl, pa_id, local_port, false, span_type); + mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl); + } + + static void + mlxsw_sp_span_entry_phys_deconfigure(struct mlxsw_sp_span_entry *span_entry) + { + mlxsw_sp_span_entry_deconfigure_common(span_entry, + MLXSW_REG_MPAT_SPAN_TYPE_LOCAL_ETH); + } + + static const + struct mlxsw_sp_span_entry_ops mlxsw_sp_span_entry_ops_phys = { + .can_handle = mlxsw_sp_port_dev_check, + .parms = mlxsw_sp_span_entry_phys_parms, + .configure = mlxsw_sp_span_entry_phys_configure, + .deconfigure = mlxsw_sp_span_entry_phys_deconfigure, + }; + + static int mlxsw_sp_span_dmac(struct neigh_table *tbl, + const void *pkey, + struct net_device *l3edev, + unsigned char dmac[ETH_ALEN]) + { + struct neighbour *neigh = neigh_lookup(tbl, pkey, l3edev); + int err = 0; + + if (!neigh) { + neigh = neigh_create(tbl, pkey, l3edev); + if (IS_ERR(neigh)) + return PTR_ERR(neigh); + } + + neigh_event_send(neigh, NULL); + + read_lock_bh(&neigh->lock); + if ((neigh->nud_state & NUD_VALID) && !neigh->dead) + memcpy(dmac, neigh->ha, ETH_ALEN); + else + err = -ENOENT; + read_unlock_bh(&neigh->lock); + + neigh_release(neigh); + return err; + } + + static int + mlxsw_sp_span_entry_unoffloadable(struct mlxsw_sp_span_parms *sparmsp) + { + sparmsp->dest_port = NULL; + return 0; + } + + static __maybe_unused int + mlxsw_sp_span_entry_tunnel_parms_common(struct net_device *l3edev, + union mlxsw_sp_l3addr saddr, + union mlxsw_sp_l3addr daddr, + union mlxsw_sp_l3addr gw, + __u8 ttl, + struct neigh_table *tbl, + struct mlxsw_sp_span_parms *sparmsp) + { + unsigned char dmac[ETH_ALEN]; + + if (mlxsw_sp_l3addr_is_zero(gw)) + gw = daddr; + + if (!l3edev || !mlxsw_sp_port_dev_check(l3edev) || + mlxsw_sp_span_dmac(tbl, &gw, l3edev, dmac)) + return mlxsw_sp_span_entry_unoffloadable(sparmsp); + + sparmsp->dest_port = netdev_priv(l3edev); + sparmsp->ttl = ttl; + memcpy(sparmsp->dmac, dmac, ETH_ALEN); + memcpy(sparmsp->smac, l3edev->dev_addr, ETH_ALEN); + sparmsp->saddr = saddr; + sparmsp->daddr = daddr; + return 0; + } + + #if IS_ENABLED(CONFIG_NET_IPGRE) + static struct net_device * + mlxsw_sp_span_gretap4_route(const struct net_device *to_dev, + __be32 *saddrp, __be32 *daddrp) + { + struct ip_tunnel *tun = netdev_priv(to_dev); + struct net_device *dev = NULL; + struct ip_tunnel_parm parms; + struct rtable *rt = NULL; + struct flowi4 fl4; + + /* We assume "dev" stays valid after rt is put. */ + ASSERT_RTNL(); + + parms = mlxsw_sp_ipip_netdev_parms4(to_dev); + ip_tunnel_init_flow(&fl4, parms.iph.protocol, *daddrp, *saddrp, + 0, 0, parms.link, tun->fwmark); + + rt = ip_route_output_key(tun->net, &fl4); + if (IS_ERR(rt)) + return NULL; + + if (rt->rt_type != RTN_UNICAST) + goto out; + + dev = rt->dst.dev; + *saddrp = fl4.saddr; + *daddrp = rt->rt_gateway; + + out: + ip_rt_put(rt); + return dev; + } + + static int + mlxsw_sp_span_entry_gretap4_parms(const struct net_device *to_dev, + struct mlxsw_sp_span_parms *sparmsp) + { + struct ip_tunnel_parm tparm = mlxsw_sp_ipip_netdev_parms4(to_dev); + union mlxsw_sp_l3addr saddr = { .addr4 = tparm.iph.saddr }; + union mlxsw_sp_l3addr daddr = { .addr4 = tparm.iph.daddr }; + bool inherit_tos = tparm.iph.tos & 0x1; + bool inherit_ttl = !tparm.iph.ttl; + union mlxsw_sp_l3addr gw = daddr; + struct net_device *l3edev; + + if (!(to_dev->flags & IFF_UP) || + /* Reject tunnels with GRE keys, checksums, etc. */ + tparm.i_flags || tparm.o_flags || + /* Require a fixed TTL and a TOS copied from the mirrored packet. */ + inherit_ttl || !inherit_tos || + /* A destination address may not be "any". */ + mlxsw_sp_l3addr_is_zero(daddr)) + return mlxsw_sp_span_entry_unoffloadable(sparmsp); + + l3edev = mlxsw_sp_span_gretap4_route(to_dev, &saddr.addr4, &gw.addr4); + return mlxsw_sp_span_entry_tunnel_parms_common(l3edev, saddr, daddr, gw, + tparm.iph.ttl, + &arp_tbl, sparmsp); + } + + static int + mlxsw_sp_span_entry_gretap4_configure(struct mlxsw_sp_span_entry *span_entry, + struct mlxsw_sp_span_parms sparms) + { + struct mlxsw_sp_port *dest_port = sparms.dest_port; + struct mlxsw_sp *mlxsw_sp = dest_port->mlxsw_sp; + u8 local_port = dest_port->local_port; + char mpat_pl[MLXSW_REG_MPAT_LEN]; + int pa_id = span_entry->id; + + /* Create a new port analayzer entry for local_port. */ + mlxsw_reg_mpat_pack(mpat_pl, pa_id, local_port, true, + MLXSW_REG_MPAT_SPAN_TYPE_REMOTE_ETH_L3); + mlxsw_reg_mpat_eth_rspan_l2_pack(mpat_pl, + MLXSW_REG_MPAT_ETH_RSPAN_VERSION_NO_HEADER, + sparms.dmac, false); + mlxsw_reg_mpat_eth_rspan_l3_ipv4_pack(mpat_pl, + sparms.ttl, sparms.smac, + be32_to_cpu(sparms.saddr.addr4), + be32_to_cpu(sparms.daddr.addr4)); + + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl); + } + + static void + mlxsw_sp_span_entry_gretap4_deconfigure(struct mlxsw_sp_span_entry *span_entry) + { + mlxsw_sp_span_entry_deconfigure_common(span_entry, + MLXSW_REG_MPAT_SPAN_TYPE_REMOTE_ETH_L3); + } + + static const struct mlxsw_sp_span_entry_ops mlxsw_sp_span_entry_ops_gretap4 = { + .can_handle = is_gretap_dev, + .parms = mlxsw_sp_span_entry_gretap4_parms, + .configure = mlxsw_sp_span_entry_gretap4_configure, + .deconfigure = mlxsw_sp_span_entry_gretap4_deconfigure, + }; + #endif + + #if IS_ENABLED(CONFIG_IPV6_GRE) + static struct net_device * + mlxsw_sp_span_gretap6_route(const struct net_device *to_dev, + struct in6_addr *saddrp, + struct in6_addr *daddrp) + { + struct ip6_tnl *t = netdev_priv(to_dev); + struct flowi6 fl6 = t->fl.u.ip6; + struct net_device *dev = NULL; + struct dst_entry *dst; + struct rt6_info *rt6; + + /* We assume "dev" stays valid after dst is released. */ + ASSERT_RTNL(); + + fl6.flowi6_mark = t->parms.fwmark; + if (!ip6_tnl_xmit_ctl(t, &fl6.saddr, &fl6.daddr)) + return NULL; + + dst = ip6_route_output(t->net, NULL, &fl6); + if (!dst || dst->error) + goto out; + + rt6 = container_of(dst, struct rt6_info, dst); + + dev = dst->dev; + *saddrp = fl6.saddr; + *daddrp = rt6->rt6i_gateway; + + out: + dst_release(dst); + return dev; + } + + static int + mlxsw_sp_span_entry_gretap6_parms(const struct net_device *to_dev, + struct mlxsw_sp_span_parms *sparmsp) + { + struct __ip6_tnl_parm tparm = mlxsw_sp_ipip_netdev_parms6(to_dev); + bool inherit_tos = tparm.flags & IP6_TNL_F_USE_ORIG_TCLASS; + union mlxsw_sp_l3addr saddr = { .addr6 = tparm.laddr }; + union mlxsw_sp_l3addr daddr = { .addr6 = tparm.raddr }; + bool inherit_ttl = !tparm.hop_limit; + union mlxsw_sp_l3addr gw = daddr; + struct net_device *l3edev; + + if (!(to_dev->flags & IFF_UP) || + /* Reject tunnels with GRE keys, checksums, etc. */ + tparm.i_flags || tparm.o_flags || + /* Require a fixed TTL and a TOS copied from the mirrored packet. */ + inherit_ttl || !inherit_tos || + /* A destination address may not be "any". */ + mlxsw_sp_l3addr_is_zero(daddr)) + return mlxsw_sp_span_entry_unoffloadable(sparmsp); + + l3edev = mlxsw_sp_span_gretap6_route(to_dev, &saddr.addr6, &gw.addr6); + return mlxsw_sp_span_entry_tunnel_parms_common(l3edev, saddr, daddr, gw, + tparm.hop_limit, + &nd_tbl, sparmsp); + } + + static int + mlxsw_sp_span_entry_gretap6_configure(struct mlxsw_sp_span_entry *span_entry, + struct mlxsw_sp_span_parms sparms) + { + struct mlxsw_sp_port *dest_port = sparms.dest_port; + struct mlxsw_sp *mlxsw_sp = dest_port->mlxsw_sp; + u8 local_port = dest_port->local_port; + char mpat_pl[MLXSW_REG_MPAT_LEN]; + int pa_id = span_entry->id; + + /* Create a new port analayzer entry for local_port. */ + mlxsw_reg_mpat_pack(mpat_pl, pa_id, local_port, true, + MLXSW_REG_MPAT_SPAN_TYPE_REMOTE_ETH_L3); + mlxsw_reg_mpat_eth_rspan_l2_pack(mpat_pl, + MLXSW_REG_MPAT_ETH_RSPAN_VERSION_NO_HEADER, + sparms.dmac, false); + mlxsw_reg_mpat_eth_rspan_l3_ipv6_pack(mpat_pl, sparms.ttl, sparms.smac, + sparms.saddr.addr6, + sparms.daddr.addr6); + + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl); + } + + static void + mlxsw_sp_span_entry_gretap6_deconfigure(struct mlxsw_sp_span_entry *span_entry) + { + mlxsw_sp_span_entry_deconfigure_common(span_entry, + MLXSW_REG_MPAT_SPAN_TYPE_REMOTE_ETH_L3); + } + + static const + struct mlxsw_sp_span_entry_ops mlxsw_sp_span_entry_ops_gretap6 = { + .can_handle = is_ip6gretap_dev, + .parms = mlxsw_sp_span_entry_gretap6_parms, + .configure = mlxsw_sp_span_entry_gretap6_configure, + .deconfigure = mlxsw_sp_span_entry_gretap6_deconfigure, + }; + #endif + + static const + struct mlxsw_sp_span_entry_ops *const mlxsw_sp_span_entry_types[] = { + &mlxsw_sp_span_entry_ops_phys, + #if IS_ENABLED(CONFIG_NET_IPGRE) + &mlxsw_sp_span_entry_ops_gretap4, + #endif + #if IS_ENABLED(CONFIG_IPV6_GRE) + &mlxsw_sp_span_entry_ops_gretap6, + #endif + }; + + static int + mlxsw_sp_span_entry_nop_parms(const struct net_device *to_dev, + struct mlxsw_sp_span_parms *sparmsp) + { + return mlxsw_sp_span_entry_unoffloadable(sparmsp); + } + + static int + mlxsw_sp_span_entry_nop_configure(struct mlxsw_sp_span_entry *span_entry, + struct mlxsw_sp_span_parms sparms) + { + return 0; + } + + static void + mlxsw_sp_span_entry_nop_deconfigure(struct mlxsw_sp_span_entry *span_entry) + { + } + + static const struct mlxsw_sp_span_entry_ops mlxsw_sp_span_entry_ops_nop = { + .parms = mlxsw_sp_span_entry_nop_parms, + .configure = mlxsw_sp_span_entry_nop_configure, + .deconfigure = mlxsw_sp_span_entry_nop_deconfigure, + }; + + static void + mlxsw_sp_span_entry_configure(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_span_entry *span_entry, + struct mlxsw_sp_span_parms sparms) + { + if (sparms.dest_port) { + if (sparms.dest_port->mlxsw_sp != mlxsw_sp) { + netdev_err(span_entry->to_dev, "Cannot mirror to %s, which belongs to a different mlxsw instance", + sparms.dest_port->dev->name); + sparms.dest_port = NULL; + } else if (span_entry->ops->configure(span_entry, sparms)) { + netdev_err(span_entry->to_dev, "Failed to offload mirror to %s", + sparms.dest_port->dev->name); + sparms.dest_port = NULL; + } + } + + span_entry->parms = sparms; + } + + static void + mlxsw_sp_span_entry_deconfigure(struct mlxsw_sp_span_entry *span_entry) + { + if (span_entry->parms.dest_port) + span_entry->ops->deconfigure(span_entry); + } + + static struct mlxsw_sp_span_entry * + mlxsw_sp_span_entry_create(struct mlxsw_sp *mlxsw_sp, + const struct net_device *to_dev, + const struct mlxsw_sp_span_entry_ops *ops, + struct mlxsw_sp_span_parms sparms) + { + struct mlxsw_sp_span_entry *span_entry = NULL; + int i; + + /* find a free entry to use */ + for (i = 0; i < mlxsw_sp->span.entries_count; i++) { + if (!mlxsw_sp->span.entries[i].ref_count) { + span_entry = &mlxsw_sp->span.entries[i]; + break; + } + } + if (!span_entry) + return NULL; + + span_entry->ops = ops; + span_entry->ref_count = 1; + span_entry->to_dev = to_dev; + mlxsw_sp_span_entry_configure(mlxsw_sp, span_entry, sparms); + + return span_entry; + } + + static void mlxsw_sp_span_entry_destroy(struct mlxsw_sp_span_entry *span_entry) + { + mlxsw_sp_span_entry_deconfigure(span_entry); + } + + struct mlxsw_sp_span_entry * + mlxsw_sp_span_entry_find_by_port(struct mlxsw_sp *mlxsw_sp, + const struct net_device *to_dev) + { + int i; + + for (i = 0; i < mlxsw_sp->span.entries_count; i++) { + struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i]; + + if (curr->ref_count && curr->to_dev == to_dev) + return curr; + } + return NULL; + } + + void mlxsw_sp_span_entry_invalidate(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_span_entry *span_entry) + { + mlxsw_sp_span_entry_deconfigure(span_entry); + span_entry->ops = &mlxsw_sp_span_entry_ops_nop; + } + + static struct mlxsw_sp_span_entry * + mlxsw_sp_span_entry_find_by_id(struct mlxsw_sp *mlxsw_sp, int span_id) + { + int i; + + for (i = 0; i < mlxsw_sp->span.entries_count; i++) { + struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i]; + + if (curr->ref_count && curr->id == span_id) + return curr; + } + return NULL; + } + + static struct mlxsw_sp_span_entry * + mlxsw_sp_span_entry_get(struct mlxsw_sp *mlxsw_sp, + const struct net_device *to_dev, + const struct mlxsw_sp_span_entry_ops *ops, + struct mlxsw_sp_span_parms sparms) + { + struct mlxsw_sp_span_entry *span_entry; + + span_entry = mlxsw_sp_span_entry_find_by_port(mlxsw_sp, to_dev); + if (span_entry) { + /* Already exists, just take a reference */ + span_entry->ref_count++; + return span_entry; + } + + return mlxsw_sp_span_entry_create(mlxsw_sp, to_dev, ops, sparms); + } + + static int mlxsw_sp_span_entry_put(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_span_entry *span_entry) + { + WARN_ON(!span_entry->ref_count); + if (--span_entry->ref_count == 0) + mlxsw_sp_span_entry_destroy(span_entry); + return 0; + } + + static bool mlxsw_sp_span_is_egress_mirror(struct mlxsw_sp_port *port) + { + struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp; + struct mlxsw_sp_span_inspected_port *p; + int i; + + for (i = 0; i < mlxsw_sp->span.entries_count; i++) { + struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i]; + + list_for_each_entry(p, &curr->bound_ports_list, list) + if (p->local_port == port->local_port && + p->type == MLXSW_SP_SPAN_EGRESS) + return true; + } + + return false; + } + + static int mlxsw_sp_span_mtu_to_buffsize(const struct mlxsw_sp *mlxsw_sp, + int mtu) + { + return mlxsw_sp_bytes_cells(mlxsw_sp, mtu * 5 / 2) + 1; + } + + int mlxsw_sp_span_port_mtu_update(struct mlxsw_sp_port *port, u16 mtu) + { + struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp; + char sbib_pl[MLXSW_REG_SBIB_LEN]; + int err; + + /* If port is egress mirrored, the shared buffer size should be + * updated according to the mtu value + */ + if (mlxsw_sp_span_is_egress_mirror(port)) { + u32 buffsize = mlxsw_sp_span_mtu_to_buffsize(mlxsw_sp, mtu); + + mlxsw_reg_sbib_pack(sbib_pl, port->local_port, buffsize); + err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbib), sbib_pl); + if (err) { + netdev_err(port->dev, "Could not update shared buffer for mirroring\n"); + return err; + } + } + + return 0; + } + + static struct mlxsw_sp_span_inspected_port * -mlxsw_sp_span_entry_bound_port_find(struct mlxsw_sp_port *port, - struct mlxsw_sp_span_entry *span_entry) ++mlxsw_sp_span_entry_bound_port_find(struct mlxsw_sp_span_entry *span_entry, ++ enum mlxsw_sp_span_type type, ++ struct mlxsw_sp_port *port, ++ bool bind) + { + struct mlxsw_sp_span_inspected_port *p; + + list_for_each_entry(p, &span_entry->bound_ports_list, list) - if (port->local_port == p->local_port) ++ if (type == p->type && ++ port->local_port == p->local_port && ++ bind == p->bound) + return p; + return NULL; + } + + static int + mlxsw_sp_span_inspected_port_bind(struct mlxsw_sp_port *port, + struct mlxsw_sp_span_entry *span_entry, + enum mlxsw_sp_span_type type, + bool bind) + { + struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp; + char mpar_pl[MLXSW_REG_MPAR_LEN]; + int pa_id = span_entry->id; + + /* bind the port to the SPAN entry */ + mlxsw_reg_mpar_pack(mpar_pl, port->local_port, + (enum mlxsw_reg_mpar_i_e)type, bind, pa_id); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpar), mpar_pl); + } + + static int + mlxsw_sp_span_inspected_port_add(struct mlxsw_sp_port *port, + struct mlxsw_sp_span_entry *span_entry, + enum mlxsw_sp_span_type type, + bool bind) + { + struct mlxsw_sp_span_inspected_port *inspected_port; + struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp; + char sbib_pl[MLXSW_REG_SBIB_LEN]; ++ int i; + int err; + ++ /* A given (source port, direction) can only be bound to one analyzer, ++ * so if a binding is requested, check for conflicts. ++ */ ++ if (bind) ++ for (i = 0; i < mlxsw_sp->span.entries_count; i++) { ++ struct mlxsw_sp_span_entry *curr = ++ &mlxsw_sp->span.entries[i]; ++ ++ if (mlxsw_sp_span_entry_bound_port_find(curr, type, ++ port, bind)) ++ return -EEXIST; ++ } ++ + /* if it is an egress SPAN, bind a shared buffer to it */ + if (type == MLXSW_SP_SPAN_EGRESS) { + u32 buffsize = mlxsw_sp_span_mtu_to_buffsize(mlxsw_sp, + port->dev->mtu); + + mlxsw_reg_sbib_pack(sbib_pl, port->local_port, buffsize); + err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbib), sbib_pl); + if (err) { + netdev_err(port->dev, "Could not create shared buffer for mirroring\n"); + return err; + } + } + + if (bind) { + err = mlxsw_sp_span_inspected_port_bind(port, span_entry, type, + true); + if (err) + goto err_port_bind; + } + + inspected_port = kzalloc(sizeof(*inspected_port), GFP_KERNEL); + if (!inspected_port) { + err = -ENOMEM; + goto err_inspected_port_alloc; + } + inspected_port->local_port = port->local_port; + inspected_port->type = type; ++ inspected_port->bound = bind; + list_add_tail(&inspected_port->list, &span_entry->bound_ports_list); + + return 0; + + err_inspected_port_alloc: + if (bind) + mlxsw_sp_span_inspected_port_bind(port, span_entry, type, + false); + err_port_bind: + if (type == MLXSW_SP_SPAN_EGRESS) { + mlxsw_reg_sbib_pack(sbib_pl, port->local_port, 0); + mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbib), sbib_pl); + } + return err; + } + + static void + mlxsw_sp_span_inspected_port_del(struct mlxsw_sp_port *port, + struct mlxsw_sp_span_entry *span_entry, + enum mlxsw_sp_span_type type, + bool bind) + { + struct mlxsw_sp_span_inspected_port *inspected_port; + struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp; + char sbib_pl[MLXSW_REG_SBIB_LEN]; + - inspected_port = mlxsw_sp_span_entry_bound_port_find(port, span_entry); ++ inspected_port = mlxsw_sp_span_entry_bound_port_find(span_entry, type, ++ port, bind); + if (!inspected_port) + return; + + if (bind) + mlxsw_sp_span_inspected_port_bind(port, span_entry, type, + false); + /* remove the SBIB buffer if it was egress SPAN */ + if (type == MLXSW_SP_SPAN_EGRESS) { + mlxsw_reg_sbib_pack(sbib_pl, port->local_port, 0); + mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbib), sbib_pl); + } + + mlxsw_sp_span_entry_put(mlxsw_sp, span_entry); + + list_del(&inspected_port->list); + kfree(inspected_port); + } + + static const struct mlxsw_sp_span_entry_ops * + mlxsw_sp_span_entry_ops(struct mlxsw_sp *mlxsw_sp, + const struct net_device *to_dev) + { + size_t i; + + for (i = 0; i < ARRAY_SIZE(mlxsw_sp_span_entry_types); ++i) + if (mlxsw_sp_span_entry_types[i]->can_handle(to_dev)) + return mlxsw_sp_span_entry_types[i]; + + return NULL; + } + + int mlxsw_sp_span_mirror_add(struct mlxsw_sp_port *from, + const struct net_device *to_dev, + enum mlxsw_sp_span_type type, bool bind, + int *p_span_id) + { + struct mlxsw_sp *mlxsw_sp = from->mlxsw_sp; + const struct mlxsw_sp_span_entry_ops *ops; + struct mlxsw_sp_span_parms sparms = {0}; + struct mlxsw_sp_span_entry *span_entry; + int err; + + ops = mlxsw_sp_span_entry_ops(mlxsw_sp, to_dev); + if (!ops) { + netdev_err(to_dev, "Cannot mirror to %s", to_dev->name); + return -EOPNOTSUPP; + } + + err = ops->parms(to_dev, &sparms); + if (err) + return err; + + span_entry = mlxsw_sp_span_entry_get(mlxsw_sp, to_dev, ops, sparms); + if (!span_entry) + return -ENOENT; + + netdev_dbg(from->dev, "Adding inspected port to SPAN entry %d\n", + span_entry->id); + + err = mlxsw_sp_span_inspected_port_add(from, span_entry, type, bind); + if (err) + goto err_port_bind; + + *p_span_id = span_entry->id; + return 0; + + err_port_bind: + mlxsw_sp_span_entry_put(mlxsw_sp, span_entry); + return err; + } + + void mlxsw_sp_span_mirror_del(struct mlxsw_sp_port *from, int span_id, + enum mlxsw_sp_span_type type, bool bind) + { + struct mlxsw_sp_span_entry *span_entry; + + span_entry = mlxsw_sp_span_entry_find_by_id(from->mlxsw_sp, span_id); + if (!span_entry) { + netdev_err(from->dev, "no span entry found\n"); + return; + } + + netdev_dbg(from->dev, "removing inspected port from SPAN entry %d\n", + span_entry->id); + mlxsw_sp_span_inspected_port_del(from, span_entry, type, bind); + } + + void mlxsw_sp_span_respin(struct mlxsw_sp *mlxsw_sp) + { + int i; + int err; + + ASSERT_RTNL(); + for (i = 0; i < mlxsw_sp->span.entries_count; i++) { + struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i]; + struct mlxsw_sp_span_parms sparms = {0}; + + if (!curr->ref_count) + continue; + + err = curr->ops->parms(curr->to_dev, &sparms); + if (err) + continue; + + if (memcmp(&sparms, &curr->parms, sizeof(sparms))) { + mlxsw_sp_span_entry_deconfigure(curr); + mlxsw_sp_span_entry_configure(mlxsw_sp, curr, sparms); + } + } + } diff --combined drivers/net/ethernet/mellanox/mlxsw/spectrum_span.h index 000000000000,948aceb512c5..4b87ec20e658 mode 000000,100644..100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.h @@@ -1,0 -1,104 +1,107 @@@ + /* + * drivers/net/ethernet/mellanox/mlxsw/mlxsw_span.h + * Copyright (c) 2018 Mellanox Technologies. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + #ifndef _MLXSW_SPECTRUM_SPAN_H + #define _MLXSW_SPECTRUM_SPAN_H + + #include <linux/types.h> + #include <linux/if_ether.h> + + #include "spectrum_router.h" + + struct mlxsw_sp; + struct mlxsw_sp_port; + + enum mlxsw_sp_span_type { + MLXSW_SP_SPAN_EGRESS, + MLXSW_SP_SPAN_INGRESS + }; + + struct mlxsw_sp_span_inspected_port { + struct list_head list; + enum mlxsw_sp_span_type type; + u8 local_port; ++ ++ /* Whether this is a directly bound mirror (port-to-port) or an ACL. */ ++ bool bound; + }; + + struct mlxsw_sp_span_parms { + struct mlxsw_sp_port *dest_port; /* NULL for unoffloaded SPAN. */ + unsigned int ttl; + unsigned char dmac[ETH_ALEN]; + unsigned char smac[ETH_ALEN]; + union mlxsw_sp_l3addr daddr; + union mlxsw_sp_l3addr saddr; + }; + + struct mlxsw_sp_span_entry_ops; + + struct mlxsw_sp_span_entry { + const struct net_device *to_dev; + const struct mlxsw_sp_span_entry_ops *ops; + struct mlxsw_sp_span_parms parms; + struct list_head bound_ports_list; + int ref_count; + int id; + }; + + struct mlxsw_sp_span_entry_ops { + bool (*can_handle)(const struct net_device *to_dev); + int (*parms)(const struct net_device *to_dev, + struct mlxsw_sp_span_parms *sparmsp); + int (*configure)(struct mlxsw_sp_span_entry *span_entry, + struct mlxsw_sp_span_parms sparms); + void (*deconfigure)(struct mlxsw_sp_span_entry *span_entry); + }; + + int mlxsw_sp_span_init(struct mlxsw_sp *mlxsw_sp); + void mlxsw_sp_span_fini(struct mlxsw_sp *mlxsw_sp); + void mlxsw_sp_span_respin(struct mlxsw_sp *mlxsw_sp); + + int mlxsw_sp_span_mirror_add(struct mlxsw_sp_port *from, + const struct net_device *to_dev, + enum mlxsw_sp_span_type type, + bool bind, int *p_span_id); + void mlxsw_sp_span_mirror_del(struct mlxsw_sp_port *from, int span_id, + enum mlxsw_sp_span_type type, bool bind); + struct mlxsw_sp_span_entry * + mlxsw_sp_span_entry_find_by_port(struct mlxsw_sp *mlxsw_sp, + const struct net_device *to_dev); + + void mlxsw_sp_span_entry_invalidate(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_span_entry *span_entry); + + int mlxsw_sp_span_port_mtu_update(struct mlxsw_sp_port *port, u16 mtu); + + #endif diff --combined drivers/net/ethernet/qlogic/qed/qed_iwarp.c index d5d02be72947,03ad4eeac7f8..69051e98aff9 --- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c +++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c @@@ -1703,13 -1703,6 +1703,13 @@@ qed_iwarp_parse_rx_pkt(struct qed_hwfn iph = (struct iphdr *)((u8 *)(ethh) + eth_hlen);
if (eth_type == ETH_P_IP) { + if (iph->protocol != IPPROTO_TCP) { + DP_NOTICE(p_hwfn, + "Unexpected ip protocol on ll2 %x\n", + iph->protocol); + return -EINVAL; + } + cm_info->local_ip[0] = ntohl(iph->daddr); cm_info->remote_ip[0] = ntohl(iph->saddr); cm_info->ip_version = TCP_IPV4; @@@ -1718,14 -1711,6 +1718,14 @@@ *payload_len = ntohs(iph->tot_len) - ip_hlen; } else if (eth_type == ETH_P_IPV6) { ip6h = (struct ipv6hdr *)iph; + + if (ip6h->nexthdr != IPPROTO_TCP) { + DP_NOTICE(p_hwfn, + "Unexpected ip protocol on ll2 %x\n", + iph->protocol); + return -EINVAL; + } + for (i = 0; i < 4; i++) { cm_info->local_ip[i] = ntohl(ip6h->daddr.in6_u.u6_addr32[i]); @@@ -1799,7 -1784,7 +1799,7 @@@ enum qed_iwarp_mpa_pkt_type /* fpdu can be fragmented over maximum 3 bds: header, partial mpa, unaligned */ #define QED_IWARP_MAX_BDS_PER_FPDU 3
- char *pkt_type_str[] = { + static const char * const pkt_type_str[] = { "QED_IWARP_MPA_PKT_PACKED", "QED_IWARP_MPA_PKT_PARTIAL", "QED_IWARP_MPA_PKT_UNALIGNED" @@@ -1943,8 -1928,8 +1943,8 @@@ qed_iwarp_update_fpdu_length(struct qed /* Missing lower byte is now available */ mpa_len = fpdu->fpdu_length | *mpa_data; fpdu->fpdu_length = QED_IWARP_FPDU_LEN_WITH_PAD(mpa_len); - fpdu->mpa_frag_len = fpdu->fpdu_length; /* one byte of hdr */ + fpdu->mpa_frag_len = 1; fpdu->incomplete_bytes = fpdu->fpdu_length - 1; DP_VERBOSE(p_hwfn, QED_MSG_RDMA, diff --combined drivers/net/ethernet/ti/cpsw.c index b2b30c9df037,8af8891078e2..1b4af54a4968 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@@ -120,14 -120,18 +120,18 @@@ do { #define CPDMA_RXCP 0x60
#define CPSW_POLL_WEIGHT 64 + #define CPSW_RX_VLAN_ENCAP_HDR_SIZE 4 #define CPSW_MIN_PACKET_SIZE (VLAN_ETH_ZLEN) - #define CPSW_MAX_PACKET_SIZE (VLAN_ETH_FRAME_LEN + ETH_FCS_LEN) + #define CPSW_MAX_PACKET_SIZE (VLAN_ETH_FRAME_LEN +\ + ETH_FCS_LEN +\ + CPSW_RX_VLAN_ENCAP_HDR_SIZE)
#define RX_PRIORITY_MAPPING 0x76543210 #define TX_PRIORITY_MAPPING 0x33221100 #define CPDMA_TX_PRIORITY_MAP 0x01234567
#define CPSW_VLAN_AWARE BIT(1) + #define CPSW_RX_VLAN_ENCAP BIT(2) #define CPSW_ALE_VLAN_AWARE 1
#define CPSW_FIFO_NORMAL_MODE (0 << 16) @@@ -148,6 -152,18 +152,18 @@@ #define CPSW_MAX_QUEUES 8 #define CPSW_CPDMA_DESCS_POOL_SIZE_DEFAULT 256
+ #define CPSW_RX_VLAN_ENCAP_HDR_PRIO_SHIFT 29 + #define CPSW_RX_VLAN_ENCAP_HDR_PRIO_MSK GENMASK(2, 0) + #define CPSW_RX_VLAN_ENCAP_HDR_VID_SHIFT 16 + #define CPSW_RX_VLAN_ENCAP_HDR_PKT_TYPE_SHIFT 8 + #define CPSW_RX_VLAN_ENCAP_HDR_PKT_TYPE_MSK GENMASK(1, 0) + enum { + CPSW_RX_VLAN_ENCAP_HDR_PKT_VLAN_TAG = 0, + CPSW_RX_VLAN_ENCAP_HDR_PKT_RESERV, + CPSW_RX_VLAN_ENCAP_HDR_PKT_PRIO_TAG, + CPSW_RX_VLAN_ENCAP_HDR_PKT_UNTAG, + }; + static int debug_level; module_param(debug_level, int, 0); MODULE_PARM_DESC(debug_level, "cpsw debug level (NETIF_MSG bits)"); @@@ -718,6 -734,49 +734,49 @@@ static void cpsw_tx_handler(void *token dev_kfree_skb_any(skb); }
+ static void cpsw_rx_vlan_encap(struct sk_buff *skb) + { + struct cpsw_priv *priv = netdev_priv(skb->dev); + struct cpsw_common *cpsw = priv->cpsw; + u32 rx_vlan_encap_hdr = *((u32 *)skb->data); + u16 vtag, vid, prio, pkt_type; + + /* Remove VLAN header encapsulation word */ + skb_pull(skb, CPSW_RX_VLAN_ENCAP_HDR_SIZE); + + pkt_type = (rx_vlan_encap_hdr >> + CPSW_RX_VLAN_ENCAP_HDR_PKT_TYPE_SHIFT) & + CPSW_RX_VLAN_ENCAP_HDR_PKT_TYPE_MSK; + /* Ignore unknown & Priority-tagged packets*/ + if (pkt_type == CPSW_RX_VLAN_ENCAP_HDR_PKT_RESERV || + pkt_type == CPSW_RX_VLAN_ENCAP_HDR_PKT_PRIO_TAG) + return; + + vid = (rx_vlan_encap_hdr >> + CPSW_RX_VLAN_ENCAP_HDR_VID_SHIFT) & + VLAN_VID_MASK; + /* Ignore vid 0 and pass packet as is */ + if (!vid) + return; + /* Ignore default vlans in dual mac mode */ + if (cpsw->data.dual_emac && + vid == cpsw->slaves[priv->emac_port].port_vlan) + return; + + prio = (rx_vlan_encap_hdr >> + CPSW_RX_VLAN_ENCAP_HDR_PRIO_SHIFT) & + CPSW_RX_VLAN_ENCAP_HDR_PRIO_MSK; + + vtag = (prio << VLAN_PRIO_SHIFT) | vid; + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vtag); + + /* strip vlan tag for VLAN-tagged packet */ + if (pkt_type == CPSW_RX_VLAN_ENCAP_HDR_PKT_VLAN_TAG) { + memmove(skb->data + VLAN_HLEN, skb->data, 2 * ETH_ALEN); + skb_pull(skb, VLAN_HLEN); + } + } + static void cpsw_rx_handler(void *token, int len, int status) { struct cpdma_chan *ch; @@@ -752,6 -811,8 +811,8 @@@ if (new_skb) { skb_copy_queue_mapping(new_skb, skb); skb_put(skb, len); + if (status & CPDMA_RX_VLAN_ENCAP) + cpsw_rx_vlan_encap(skb); cpts_rx_timestamp(cpsw->cpts, skb); skb->protocol = eth_type_trans(skb, ndev); netif_receive_skb(skb); @@@ -1014,8 -1075,7 +1075,8 @@@ static void _cpsw_adjust_link(struct cp /* set speed_in input in case RMII mode is used in 100Mbps */ if (phy->speed == 100) mac_control |= BIT(15); - else if (phy->speed == 10) + /* in band mode only works in 10Mbps RGMII mode */ + else if ((phy->speed == 10) && phy_interface_is_rgmii(phy)) mac_control |= BIT(18); /* In Band mode */
if (priv->rx_pause) @@@ -1407,7 -1467,7 +1468,7 @@@ static void cpsw_init_host_port(struct cpsw_ale_control_set(cpsw->ale, HOST_PORT_NUM, ALE_VLAN_AWARE, CPSW_ALE_VLAN_AWARE); control_reg = readl(&cpsw->regs->control); - control_reg |= CPSW_VLAN_AWARE; + control_reg |= CPSW_VLAN_AWARE | CPSW_RX_VLAN_ENCAP; writel(control_reg, &cpsw->regs->control); fifo_mode = (cpsw->data.dual_emac) ? CPSW_FIFO_DUAL_MAC_MODE : CPSW_FIFO_NORMAL_MODE; @@@ -3123,7 -3183,7 +3184,7 @@@ static int cpsw_probe(struct platform_d cpsw->quirk_irq = true; }
- ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; + ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_VLAN_CTAG_RX;
ndev->netdev_ops = &cpsw_netdev_ops; ndev->ethtool_ops = &cpsw_ethtool_ops; diff --combined drivers/net/hyperv/netvsc.c index 7472172823f3,aa95e81af6e5..4123d081b1c7 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@@ -36,6 -36,7 +36,7 @@@ #include <asm/sync_bitops.h>
#include "hyperv_net.h" + #include "netvsc_trace.h"
/* * Switch the data path from the synthetic interface to the VF @@@ -57,6 -58,8 +58,8 @@@ void netvsc_switch_datapath(struct net_ init_pkt->msg.v4_msg.active_dp.active_datapath = NVSP_DATAPATH_SYNTHETIC;
+ trace_nvsp_send(ndev, init_pkt); + vmbus_sendpacket(dev->channel, init_pkt, sizeof(struct nvsp_message), (unsigned long)init_pkt, @@@ -90,11 -93,6 +93,11 @@@ static void free_netvsc_device(struct r = container_of(head, struct netvsc_device, rcu); int i;
+ kfree(nvdev->extension); + vfree(nvdev->recv_buf); + vfree(nvdev->send_buf); + kfree(nvdev->send_section_map); + for (i = 0; i < VRSS_CHANNEL_MAX; i++) vfree(nvdev->chan_table[i].mrc.slots);
@@@ -129,6 -127,8 +132,8 @@@ static void netvsc_revoke_buf(struct hv revoke_packet->msg.v1_msg. revoke_recv_buf.id = NETVSC_RECEIVE_BUFFER_ID;
+ trace_nvsp_send(ndev, revoke_packet); + ret = vmbus_sendpacket(device->channel, revoke_packet, sizeof(struct nvsp_message), @@@ -169,6 -169,8 +174,8 @@@ revoke_packet->msg.v1_msg.revoke_send_buf.id = NETVSC_SEND_BUFFER_ID;
+ trace_nvsp_send(ndev, revoke_packet); + ret = vmbus_sendpacket(device->channel, revoke_packet, sizeof(struct nvsp_message), @@@ -216,6 -218,12 +223,6 @@@ static void netvsc_teardown_gpadl(struc net_device->recv_buf_gpadl_handle = 0; }
- if (net_device->recv_buf) { - /* Free up the receive buffer */ - vfree(net_device->recv_buf); - net_device->recv_buf = NULL; - } - if (net_device->send_buf_gpadl_handle) { ret = vmbus_teardown_gpadl(device->channel, net_device->send_buf_gpadl_handle); @@@ -230,6 -238,12 +237,6 @@@ } net_device->send_buf_gpadl_handle = 0; } - if (net_device->send_buf) { - /* Free up the send buffer */ - vfree(net_device->send_buf); - net_device->send_buf = NULL; - } - kfree(net_device->send_section_map); }
int netvsc_alloc_recv_comp_ring(struct netvsc_device *net_device, u32 q_idx) @@@ -298,6 -312,8 +305,8 @@@ static int netvsc_init_buf(struct hv_de init_packet->msg.v1_msg. send_recv_buf.id = NETVSC_RECEIVE_BUFFER_ID;
+ trace_nvsp_send(ndev, init_packet); + /* Send the gpadl notification request */ ret = vmbus_sendpacket(device->channel, init_packet, sizeof(struct nvsp_message), @@@ -377,6 -393,8 +386,8 @@@ net_device->send_buf_gpadl_handle; init_packet->msg.v1_msg.send_send_buf.id = NETVSC_SEND_BUFFER_ID;
+ trace_nvsp_send(ndev, init_packet); + /* Send the gpadl notification request */ ret = vmbus_sendpacket(device->channel, init_packet, sizeof(struct nvsp_message), @@@ -445,6 -463,8 +456,8 @@@ static int negotiate_nvsp_ver(struct hv init_packet->msg.init_msg.init.min_protocol_ver = nvsp_ver; init_packet->msg.init_msg.init.max_protocol_ver = nvsp_ver;
+ trace_nvsp_send(ndev, init_packet); + /* Send the init request */ ret = vmbus_sendpacket(device->channel, init_packet, sizeof(struct nvsp_message), @@@ -477,6 -497,8 +490,8 @@@ init_packet->msg.v2_msg.send_ndis_config.capability.teaming = 1; }
+ trace_nvsp_send(ndev, init_packet); + ret = vmbus_sendpacket(device->channel, init_packet, sizeof(struct nvsp_message), (unsigned long)init_packet, @@@ -489,6 -511,7 +504,7 @@@ static int netvsc_connect_vsp(struct hv struct netvsc_device *net_device, const struct netvsc_device_info *device_info) { + struct net_device *ndev = hv_get_drvdata(device); static const u32 ver_list[] = { NVSP_PROTOCOL_VERSION_1, NVSP_PROTOCOL_VERSION_2, NVSP_PROTOCOL_VERSION_4, NVSP_PROTOCOL_VERSION_5 @@@ -529,6 -552,8 +545,8 @@@ send_ndis_ver.ndis_minor_ver = ndis_version & 0xFFFF;
+ trace_nvsp_send(ndev, init_packet); + /* Send the init request */ ret = vmbus_sendpacket(device->channel, init_packet, sizeof(struct nvsp_message), @@@ -555,29 -580,26 +573,29 @@@ void netvsc_device_remove(struct hv_dev = rtnl_dereference(net_device_ctx->nvdev); int i;
- cancel_work_sync(&net_device->subchan_work); - netvsc_revoke_buf(device, net_device);
RCU_INIT_POINTER(net_device_ctx->nvdev, NULL);
+ /* And disassociate NAPI context from device */ + for (i = 0; i < net_device->num_chn; i++) + netif_napi_del(&net_device->chan_table[i].napi); + /* * At this point, no one should be accessing net_device * except in here */ netdev_dbg(ndev, "net device safe to remove\n");
+ /* older versions require that buffer be revoked before close */ + if (net_device->nvsp_version < NVSP_PROTOCOL_VERSION_4) + netvsc_teardown_gpadl(device, net_device); + /* Now, we can close the channel safely */ vmbus_close(device->channel);
- netvsc_teardown_gpadl(device, net_device); - - /* And dissassociate NAPI context from device */ - for (i = 0; i < net_device->num_chn; i++) - netif_napi_del(&net_device->chan_table[i].napi); + if (net_device->nvsp_version >= NVSP_PROTOCOL_VERSION_4) + netvsc_teardown_gpadl(device, net_device);
/* Release all resources */ free_netvsc_device_rcu(net_device); @@@ -641,18 -663,14 +659,18 @@@ static void netvsc_send_tx_complete(str queue_sends = atomic_dec_return(&net_device->chan_table[q_idx].queue_sends);
- if (net_device->destroy && queue_sends == 0) - wake_up(&net_device->wait_drain); - - if (netif_tx_queue_stopped(netdev_get_tx_queue(ndev, q_idx)) && - (hv_ringbuf_avail_percent(&channel->outbound) > RING_AVAIL_PERCENT_HIWATER || - queue_sends < 1)) { - netif_tx_wake_queue(netdev_get_tx_queue(ndev, q_idx)); - ndev_ctx->eth_stats.wake_queue++; + if (unlikely(net_device->destroy)) { + if (queue_sends == 0) + wake_up(&net_device->wait_drain); + } else { + struct netdev_queue *txq = netdev_get_tx_queue(ndev, q_idx); + + if (netif_tx_queue_stopped(txq) && + (hv_ringbuf_avail_percent(&channel->outbound) > RING_AVAIL_PERCENT_HIWATER || + queue_sends < 1)) { + netif_tx_wake_queue(txq); + ndev_ctx->eth_stats.wake_queue++; + } } }
@@@ -747,7 -765,7 +765,7 @@@ static inline int netvsc_send_pkt struct sk_buff *skb) { struct nvsp_message nvmsg; - struct nvsp_1_message_send_rndis_packet * const rpkt = + struct nvsp_1_message_send_rndis_packet *rpkt = &nvmsg.msg.v1_msg.send_rndis_pkt; struct netvsc_channel * const nvchan = &net_device->chan_table[packet->q_idx]; @@@ -776,6 -794,8 +794,8 @@@ if (out_channel->rescind) return -ENODEV;
+ trace_nvsp_send_pkt(ndev, out_channel, rpkt); + if (packet->page_buf_cnt) { if (packet->cp_partial) pb += packet->rmsg_pgcnt; @@@ -1079,6 -1099,8 +1099,8 @@@ static int netvsc_receive(struct net_de + vmxferpage_packet->ranges[i].byte_offset; u32 buflen = vmxferpage_packet->ranges[i].byte_count;
+ trace_rndis_recv(ndev, q_idx, data); + /* Pass it to the upper layer */ status = rndis_filter_receive(ndev, net_device, channel, data, buflen); @@@ -1143,6 -1165,8 +1165,8 @@@ static int netvsc_process_raw_pkt(struc struct net_device_context *net_device_ctx = netdev_priv(ndev); struct nvsp_message *nvmsg = hv_pkt_data(desc);
+ trace_nvsp_recv(ndev, channel, nvmsg); + switch (desc->type) { case VM_PKT_COMP: netvsc_send_completion(net_device, channel, device, diff --combined drivers/net/hyperv/rndis_filter.c index a6ec41c399d6,2dc00f714482..020f8bc54386 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@@ -31,6 -31,7 +31,7 @@@ #include <linux/rtnetlink.h>
#include "hyperv_net.h" + #include "netvsc_trace.h"
static void rndis_set_multicast(struct work_struct *w);
@@@ -241,6 -242,8 +242,8 @@@ static int rndis_filter_send_request(st pb[0].len; }
+ trace_rndis_send(dev->ndev, 0, &req->request_msg); + rcu_read_lock_bh(); ret = netvsc_send(dev->ndev, packet, NULL, pb, NULL); rcu_read_unlock_bh(); @@@ -264,23 -267,13 +267,23 @@@ static void rndis_set_link_state(struc } }
-static void rndis_filter_receive_response(struct rndis_device *dev, - struct rndis_message *resp) +static void rndis_filter_receive_response(struct net_device *ndev, + struct netvsc_device *nvdev, + const struct rndis_message *resp) { + struct rndis_device *dev = nvdev->extension; struct rndis_request *request = NULL; bool found = false; unsigned long flags; - struct net_device *ndev = dev->ndev; + + /* This should never happen, it means control message + * response received after device removed. + */ + if (dev->state == RNDIS_DEV_UNINITIALIZED) { + netdev_err(ndev, + "got rndis message uninitialized\n"); + return; + }
spin_lock_irqsave(&dev->request_lock, flags); list_for_each_entry(request, &dev->req_list, list_ent) { @@@ -362,6 -355,7 +365,6 @@@ static inline void *rndis_get_ppi(struc
static int rndis_filter_receive_data(struct net_device *ndev, struct netvsc_device *nvdev, - struct rndis_device *dev, struct rndis_message *msg, struct vmbus_channel *channel, void *data, u32 data_buflen) @@@ -381,7 -375,7 +384,7 @@@ * should be the data packet size plus the trailer padding size */ if (unlikely(data_buflen < rndis_pkt->data_len)) { - netdev_err(dev->ndev, "rndis message buffer " + netdev_err(ndev, "rndis message buffer " "overflow detected (got %u, min %u)" "...dropping this message!\n", data_buflen, rndis_pkt->data_len); @@@ -409,20 -403,35 +412,20 @@@ int rndis_filter_receive(struct net_dev void *data, u32 buflen) { struct net_device_context *net_device_ctx = netdev_priv(ndev); - struct rndis_device *rndis_dev = net_dev->extension; struct rndis_message *rndis_msg = data;
- /* Make sure the rndis device state is initialized */ - if (unlikely(!rndis_dev)) { - netif_dbg(net_device_ctx, rx_err, ndev, - "got rndis message but no rndis device!\n"); - return NVSP_STAT_FAIL; - } - - if (unlikely(rndis_dev->state == RNDIS_DEV_UNINITIALIZED)) { - netif_dbg(net_device_ctx, rx_err, ndev, - "got rndis message uninitialized\n"); - return NVSP_STAT_FAIL; - } - if (netif_msg_rx_status(net_device_ctx)) dump_rndis_message(ndev, rndis_msg);
switch (rndis_msg->ndis_msg_type) { case RNDIS_MSG_PACKET: - return rndis_filter_receive_data(ndev, net_dev, - rndis_dev, rndis_msg, + return rndis_filter_receive_data(ndev, net_dev, rndis_msg, channel, data, buflen); case RNDIS_MSG_INIT_C: case RNDIS_MSG_QUERY_C: case RNDIS_MSG_SET_C: /* completion msgs */ - rndis_filter_receive_response(rndis_dev, rndis_msg); + rndis_filter_receive_response(ndev, net_dev, rndis_msg); break;
case RNDIS_MSG_INDICATE: @@@ -819,15 -828,13 +822,15 @@@ static int rndis_filter_set_packet_filt struct rndis_set_request *set; int ret;
+ if (dev->filter == new_filter) + return 0; + request = get_rndis_request(dev, RNDIS_MSG_SET, RNDIS_MESSAGE_SIZE(struct rndis_set_request) + sizeof(u32)); if (!request) return -ENOMEM;
- /* Setup the rndis set */ set = &request->request_msg.msg.set_req; set->oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER; @@@ -838,10 -845,8 +841,10 @@@ &new_filter, sizeof(u32));
ret = rndis_filter_send_request(dev, request); - if (ret == 0) + if (ret == 0) { wait_for_completion(&request->wait_event); + dev->filter = new_filter; + }
put_rndis_request(dev, request);
@@@ -859,9 -864,9 +862,9 @@@ static void rndis_set_multicast(struct filter = NDIS_PACKET_TYPE_PROMISCUOUS; } else { if (flags & IFF_ALLMULTI) - flags |= NDIS_PACKET_TYPE_ALL_MULTICAST; + filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; if (flags & IFF_BROADCAST) - flags |= NDIS_PACKET_TYPE_BROADCAST; + filter |= NDIS_PACKET_TYPE_BROADCAST; }
rndis_filter_set_packet_filter(rdev, filter); @@@ -942,12 -947,11 +945,11 @@@ static bool netvsc_device_idle(const st return true; }
- static void rndis_filter_halt_device(struct rndis_device *dev) + static void rndis_filter_halt_device(struct netvsc_device *nvdev, + struct rndis_device *dev) { struct rndis_request *request; struct rndis_halt_request *halt; - struct net_device_context *net_device_ctx = netdev_priv(dev->ndev); - struct netvsc_device *nvdev = rtnl_dereference(net_device_ctx->nvdev);
/* Attempt to do a rndis device halt */ request = get_rndis_request(dev, RNDIS_MSG_HALT, @@@ -1086,6 -1090,8 +1088,8 @@@ void rndis_set_subchannel(struct work_s init_packet->msg.v5_msg.subchn_req.op = NVSP_SUBCHANNEL_ALLOCATE; init_packet->msg.v5_msg.subchn_req.num_subchannels = nvdev->num_chn - 1; + trace_nvsp_send(ndev, init_packet); + ret = vmbus_sendpacket(hv_dev->channel, init_packet, sizeof(struct nvsp_message), (unsigned long)init_packet, @@@ -1118,7 -1124,6 +1122,7 @@@ for (i = 0; i < VRSS_SEND_TAB_SIZE; i++) ndev_ctx->tx_table[i] = i % nvdev->num_chn;
+ netif_device_attach(ndev); rtnl_unlock(); return;
@@@ -1129,8 -1134,6 +1133,8 @@@ failed
nvdev->max_chn = 1; nvdev->num_chn = 1; + + netif_device_attach(ndev); unlock: rtnl_unlock(); } @@@ -1333,10 -1336,6 +1337,10 @@@ out net_device->num_chn = 1; }
+ /* No sub channels, device is ready */ + if (net_device->num_chn == 1) + netif_device_attach(net); + return net_device;
err_dev_remv: @@@ -1349,12 -1348,16 +1353,12 @@@ void rndis_filter_device_remove(struct { struct rndis_device *rndis_dev = net_dev->extension;
- /* Don't try and setup sub channels if about to halt */ - cancel_work_sync(&net_dev->subchan_work); - /* Halt and release the rndis device */ - rndis_filter_halt_device(rndis_dev); + rndis_filter_halt_device(net_dev, rndis_dev);
net_dev->extension = NULL;
netvsc_device_remove(dev); - kfree(rndis_dev); }
int rndis_filter_open(struct netvsc_device *nvdev) @@@ -1372,3 -1375,10 +1376,3 @@@ int rndis_filter_close(struct netvsc_de
return rndis_filter_close_device(nvdev->extension); } - -bool rndis_filter_opened(const struct netvsc_device *nvdev) -{ - const struct rndis_device *dev = nvdev->extension; - - return dev->state == RNDIS_DEV_DATAINITIALIZED; -} diff --combined drivers/net/phy/marvell.c index 0e0978d8a0eb,98fd6b7ceeec..a75c511950c3 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@@ -860,7 -860,7 +860,7 @@@ static int m88e1510_config_init(struct return err;
/* There appears to be a bug in the 88e1512 when used in - * SGMII to copper mode, where the AN advertisment register + * SGMII to copper mode, where the AN advertisement register * clears the pause bits each time a negotiation occurs. * This means we can never be truely sure what was advertised, * so disable Pause support. @@@ -1452,8 -1452,8 +1452,8 @@@ static void marvell_get_strings(struct int i;
for (i = 0; i < ARRAY_SIZE(marvell_hw_stats); i++) { - memcpy(data + i * ETH_GSTRING_LEN, - marvell_hw_stats[i].string, ETH_GSTRING_LEN); + strlcpy(data + i * ETH_GSTRING_LEN, + marvell_hw_stats[i].string, ETH_GSTRING_LEN); } }
diff --combined drivers/net/phy/phy.c index 9aabfa1a455a,c2d9027be863..05c1e8ef15e6 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@@ -618,77 -618,6 +618,68 @@@ static void phy_error(struct phy_devic }
/** + * phy_disable_interrupts - Disable the PHY interrupts from the PHY side + * @phydev: target phy_device struct + */ +static int phy_disable_interrupts(struct phy_device *phydev) +{ + int err; + + /* Disable PHY interrupts */ + err = phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED); + if (err) - goto phy_err; ++ return err; + + /* Clear the interrupt */ - err = phy_clear_interrupt(phydev); - if (err) - goto phy_err; - - return 0; - - phy_err: - phy_error(phydev); - - return err; ++ return phy_clear_interrupt(phydev); +} + +/** + * phy_change - Called by the phy_interrupt to handle PHY changes + * @phydev: phy_device struct that interrupted + */ +static irqreturn_t phy_change(struct phy_device *phydev) +{ + if (phy_interrupt_is_valid(phydev)) { + if (phydev->drv->did_interrupt && + !phydev->drv->did_interrupt(phydev)) + return IRQ_NONE; + + if (phydev->state == PHY_HALTED) + if (phy_disable_interrupts(phydev)) + goto phy_err; + } + + mutex_lock(&phydev->lock); + if ((PHY_RUNNING == phydev->state) || (PHY_NOLINK == phydev->state)) + phydev->state = PHY_CHANGELINK; + mutex_unlock(&phydev->lock); + + /* reschedule state queue work to run as soon as possible */ + phy_trigger_machine(phydev, true); + + if (phy_interrupt_is_valid(phydev) && phy_clear_interrupt(phydev)) + goto phy_err; + return IRQ_HANDLED; + +phy_err: + phy_error(phydev); + return IRQ_NONE; +} + +/** + * phy_change_work - Scheduled by the phy_mac_interrupt to handle PHY changes + * @work: work_struct that describes the work to be done + */ +void phy_change_work(struct work_struct *work) +{ + struct phy_device *phydev = + container_of(work, struct phy_device, phy_queue); + + phy_change(phydev); +} + +/** * phy_interrupt - PHY interrupt handler * @irq: interrupt line * @phy_dat: phy_device pointer @@@ -703,7 -632,9 +694,7 @@@ static irqreturn_t phy_interrupt(int ir if (PHY_HALTED == phydev->state) return IRQ_NONE; /* It can't be ours. */
- phy_change(phydev); - - return IRQ_HANDLED; + return phy_change(phydev); }
/** @@@ -721,6 -652,23 +712,6 @@@ static int phy_enable_interrupts(struc }
/** - * phy_disable_interrupts - Disable the PHY interrupts from the PHY side - * @phydev: target phy_device struct - */ -static int phy_disable_interrupts(struct phy_device *phydev) -{ - int err; - - /* Disable PHY interrupts */ - err = phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED); - if (err) - return err; - - /* Clear the interrupt */ - return phy_clear_interrupt(phydev); -} - -/** * phy_start_interrupts - request and enable interrupts for a PHY device * @phydev: target phy_device struct * @@@ -763,6 -711,50 +754,6 @@@ int phy_stop_interrupts(struct phy_devi EXPORT_SYMBOL(phy_stop_interrupts);
/** - * phy_change - Called by the phy_interrupt to handle PHY changes - * @phydev: phy_device struct that interrupted - */ -void phy_change(struct phy_device *phydev) -{ - if (phy_interrupt_is_valid(phydev)) { - if (phydev->drv->did_interrupt && - !phydev->drv->did_interrupt(phydev)) - return; - - if (phydev->state == PHY_HALTED) - if (phy_disable_interrupts(phydev)) - goto phy_err; - } - - mutex_lock(&phydev->lock); - if ((PHY_RUNNING == phydev->state) || (PHY_NOLINK == phydev->state)) - phydev->state = PHY_CHANGELINK; - mutex_unlock(&phydev->lock); - - /* reschedule state queue work to run as soon as possible */ - phy_trigger_machine(phydev, true); - - if (phy_interrupt_is_valid(phydev) && phy_clear_interrupt(phydev)) - goto phy_err; - return; - -phy_err: - phy_error(phydev); -} - -/** - * phy_change_work - Scheduled by the phy_mac_interrupt to handle PHY changes - * @work: work_struct that describes the work to be done - */ -void phy_change_work(struct work_struct *work) -{ - struct phy_device *phydev = - container_of(work, struct phy_device, phy_queue); - - phy_change(phydev); -} - -/** * phy_stop - Bring down the PHY link, and stop checking the status * @phydev: target phy_device struct */ @@@ -773,13 -765,8 +764,8 @@@ void phy_stop(struct phy_device *phydev if (PHY_HALTED == phydev->state) goto out_unlock;
- if (phy_interrupt_is_valid(phydev)) { - /* Disable PHY Interrupts */ - phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED); - - /* Clear any pending interrupts */ - phy_clear_interrupt(phydev); - } + if (phy_interrupt_is_valid(phydev)) + phy_disable_interrupts(phydev);
phydev->state = PHY_HALTED;
diff --combined drivers/net/phy/phy_device.c index 74664a6c0cdc,b285323327c4..ac23322a32e1 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@@ -374,7 -374,7 +374,7 @@@ struct phy_device *phy_device_create(st dev->duplex = -1; dev->pause = 0; dev->asym_pause = 0; - dev->link = 1; + dev->link = 0; dev->interface = PHY_INTERFACE_MODE_GMII;
dev->autoneg = AUTONEG_ENABLE; @@@ -1012,17 -1012,10 +1012,17 @@@ int phy_attach_direct(struct net_devic err = sysfs_create_link(&phydev->mdio.dev.kobj, &dev->dev.kobj, "attached_dev"); if (!err) { - err = sysfs_create_link(&dev->dev.kobj, &phydev->mdio.dev.kobj, - "phydev"); - if (err) - goto error; + err = sysfs_create_link_nowarn(&dev->dev.kobj, + &phydev->mdio.dev.kobj, + "phydev"); + if (err) { + dev_err(&dev->dev, "could not add device link to %s err %d\n", + kobject_name(&phydev->mdio.dev.kobj), + err); + /* non-fatal - some net drivers can use one netdevice + * with more then one phy + */ + }
phydev->sysfs_links = true; } @@@ -1673,23 -1666,6 +1673,23 @@@ int genphy_config_init(struct phy_devic } EXPORT_SYMBOL(genphy_config_init);
+/* This is used for the phy device which doesn't support the MMD extended + * register access, but it does have side effect when we are trying to access + * the MMD register via indirect method. + */ +int genphy_read_mmd_unsupported(struct phy_device *phdev, int devad, u16 regnum) +{ + return -EOPNOTSUPP; +} +EXPORT_SYMBOL(genphy_read_mmd_unsupported); + +int genphy_write_mmd_unsupported(struct phy_device *phdev, int devnum, + u16 regnum, u16 val) +{ + return -EOPNOTSUPP; +} +EXPORT_SYMBOL(genphy_write_mmd_unsupported); + int genphy_suspend(struct phy_device *phydev) { return phy_set_bits(phydev, MII_BMCR, BMCR_PDOWN); diff --combined drivers/net/ppp/ppp_generic.c index da1937832c99,7dc2f34e7229..926c2c322d43 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@@ -257,7 -257,7 +257,7 @@@ struct ppp_net /* Prototypes. */ static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf, struct file *file, unsigned int cmd, unsigned long arg); -static void ppp_xmit_process(struct ppp *ppp); +static void ppp_xmit_process(struct ppp *ppp, struct sk_buff *skb); static void ppp_send_frame(struct ppp *ppp, struct sk_buff *skb); static void ppp_push(struct ppp *ppp); static void ppp_channel_push(struct channel *pch); @@@ -513,12 -513,13 +513,12 @@@ static ssize_t ppp_write(struct file *f goto out; }
- skb_queue_tail(&pf->xq, skb); - switch (pf->kind) { case INTERFACE: - ppp_xmit_process(PF_TO_PPP(pf)); + ppp_xmit_process(PF_TO_PPP(pf), skb); break; case CHANNEL: + skb_queue_tail(&pf->xq, skb); ppp_channel_push(PF_TO_CHANNEL(pf)); break; } @@@ -970,6 -971,7 +970,7 @@@ static struct pernet_operations ppp_net .exit = ppp_exit_net, .id = &ppp_net_id, .size = sizeof(struct ppp_net), + .async = true, };
static int ppp_unit_register(struct ppp *ppp, int unit, bool ifname_is_set) @@@ -1266,8 -1268,8 +1267,8 @@@ ppp_start_xmit(struct sk_buff *skb, str put_unaligned_be16(proto, pp);
skb_scrub_packet(skb, !net_eq(ppp->ppp_net, dev_net(dev))); - skb_queue_tail(&ppp->file.xq, skb); - ppp_xmit_process(ppp); + ppp_xmit_process(ppp, skb); + return NETDEV_TX_OK;
outf: @@@ -1419,14 -1421,13 +1420,14 @@@ static void ppp_setup(struct net_devic */
/* Called to do any work queued up on the transmit side that can now be done */ -static void __ppp_xmit_process(struct ppp *ppp) +static void __ppp_xmit_process(struct ppp *ppp, struct sk_buff *skb) { - struct sk_buff *skb; - ppp_xmit_lock(ppp); if (!ppp->closing) { ppp_push(ppp); + + if (skb) + skb_queue_tail(&ppp->file.xq, skb); while (!ppp->xmit_pending && (skb = skb_dequeue(&ppp->file.xq))) ppp_send_frame(ppp, skb); @@@ -1440,7 -1441,7 +1441,7 @@@ ppp_xmit_unlock(ppp); }
-static void ppp_xmit_process(struct ppp *ppp) +static void ppp_xmit_process(struct ppp *ppp, struct sk_buff *skb) { local_bh_disable();
@@@ -1448,7 -1449,7 +1449,7 @@@ goto err;
(*this_cpu_ptr(ppp->xmit_recursion))++; - __ppp_xmit_process(ppp); + __ppp_xmit_process(ppp, skb); (*this_cpu_ptr(ppp->xmit_recursion))--;
local_bh_enable(); @@@ -1458,8 -1459,6 +1459,8 @@@ err: local_bh_enable();
+ kfree_skb(skb); + if (net_ratelimit()) netdev_err(ppp->dev, "recursion detected\n"); } @@@ -1944,7 -1943,7 +1945,7 @@@ static void __ppp_channel_push(struct c if (skb_queue_empty(&pch->file.xq)) { ppp = pch->ppp; if (ppp) - __ppp_xmit_process(ppp); + __ppp_xmit_process(ppp, NULL); } }
diff --combined drivers/net/team/team.c index 56c701b73c12,5dd781e65958..222093e878a8 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@@ -1105,14 -1105,15 +1105,15 @@@ static void team_port_disable_netpoll(s } #endif
- static int team_upper_dev_link(struct team *team, struct team_port *port) + static int team_upper_dev_link(struct team *team, struct team_port *port, + struct netlink_ext_ack *extack) { struct netdev_lag_upper_info lag_upper_info; int err;
lag_upper_info.tx_type = team->mode->lag_tx_type; err = netdev_master_upper_dev_link(port->dev, team->dev, NULL, - &lag_upper_info, NULL); + &lag_upper_info, extack); if (err) return err; port->dev->priv_flags |= IFF_TEAM_PORT; @@@ -1129,7 -1130,8 +1130,8 @@@ static void __team_port_change_port_add static int team_dev_type_check_change(struct net_device *dev, struct net_device *port_dev);
- static int team_port_add(struct team *team, struct net_device *port_dev) + static int team_port_add(struct team *team, struct net_device *port_dev, + struct netlink_ext_ack *extack) { struct net_device *dev = team->dev; struct team_port *port; @@@ -1137,12 -1139,14 +1139,14 @@@ int err;
if (port_dev->flags & IFF_LOOPBACK) { + NL_SET_ERR_MSG(extack, "Loopback device can't be added as a team port"); netdev_err(dev, "Device %s is loopback device. Loopback devices can't be added as a team port\n", portname); return -EINVAL; }
if (team_port_exists(port_dev)) { + NL_SET_ERR_MSG(extack, "Device is already a port of a team device"); netdev_err(dev, "Device %s is already a port " "of a team device\n", portname); return -EBUSY; @@@ -1150,6 -1154,7 +1154,7 @@@
if (port_dev->features & NETIF_F_VLAN_CHALLENGED && vlan_uses_dev(dev)) { + NL_SET_ERR_MSG(extack, "Device is VLAN challenged and team device has VLAN set up"); netdev_err(dev, "Device %s is VLAN challenged and team device has VLAN set up\n", portname); return -EPERM; @@@ -1160,6 -1165,7 +1165,7 @@@ return err;
if (port_dev->flags & IFF_UP) { + NL_SET_ERR_MSG(extack, "Device is up. Set it down before adding it as a team port"); netdev_err(dev, "Device %s is up. Set it down before adding it as a team port\n", portname); return -EBUSY; @@@ -1227,7 -1233,7 +1233,7 @@@ goto err_handler_register; }
- err = team_upper_dev_link(team, port); + err = team_upper_dev_link(team, port, extack); if (err) { netdev_err(dev, "Device %s failed to set upper link\n", portname); @@@ -1921,7 -1927,7 +1927,7 @@@ static int team_add_slave(struct net_de int err;
mutex_lock(&team->lock); - err = team_port_add(team, port_dev); + err = team_port_add(team, port_dev, extack); mutex_unlock(&team->lock);
if (!err) @@@ -2395,7 -2401,7 +2401,7 @@@ send_done if (!nlh) { err = __send_and_alloc_skb(&skb, team, portid, send_func); if (err) - goto errout; + return err; goto send_done; }
@@@ -2681,7 -2687,7 +2687,7 @@@ send_done if (!nlh) { err = __send_and_alloc_skb(&skb, team, portid, send_func); if (err) - goto errout; + return err; goto send_done; }
diff --combined drivers/net/tun.c index 28cfa642e39a,baeafa004463..a1ba262f40ad --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@@ -78,6 -78,7 +78,7 @@@ #include <linux/mutex.h>
#include <linux/uaccess.h> + #include <linux/proc_fs.h>
/* Uncomment to enable debugging */ /* #define TUN_DEBUG 1 */ @@@ -655,7 -656,7 +656,7 @@@ static struct tun_struct *tun_enable_qu return tun; }
-static void tun_ptr_free(void *ptr) +void tun_ptr_free(void *ptr) { if (!ptr) return; @@@ -667,7 -668,6 +668,7 @@@ __skb_array_destroy_skb(ptr); } } +EXPORT_SYMBOL_GPL(tun_ptr_free);
static void tun_queue_purge(struct tun_file *tfile) { @@@ -1613,7 -1613,6 +1614,6 @@@ static struct sk_buff *tun_build_skb(st unsigned int delta = 0; char *buf; size_t copied; - bool xdp_xmit = false; int err, pad = TUN_RX_PAD;
rcu_read_lock(); @@@ -1671,8 -1670,14 +1671,14 @@@ preempt_enable(); return NULL; case XDP_TX: - xdp_xmit = true; - /* fall through */ + get_page(alloc_frag->page); + alloc_frag->offset += buflen; + if (tun_xdp_xmit(tun->dev, &xdp)) + goto err_redirect; + tun_xdp_flush(tun->dev); + rcu_read_unlock(); + preempt_enable(); + return NULL; case XDP_PASS: delta = orig_data - xdp.data; break; @@@ -1699,14 -1704,6 +1705,6 @@@ get_page(alloc_frag->page); alloc_frag->offset += buflen;
- if (xdp_xmit) { - skb->dev = tun->dev; - generic_xdp_tx(skb, xdp_prog); - rcu_read_unlock(); - preempt_enable(); - return NULL; - } - rcu_read_unlock(); preempt_enable();
@@@ -2287,11 -2284,67 +2285,67 @@@ static int tun_validate(struct nlattr * return -EINVAL; }
+ static size_t tun_get_size(const struct net_device *dev) + { + BUILD_BUG_ON(sizeof(u32) != sizeof(uid_t)); + BUILD_BUG_ON(sizeof(u32) != sizeof(gid_t)); + + return nla_total_size(sizeof(uid_t)) + /* OWNER */ + nla_total_size(sizeof(gid_t)) + /* GROUP */ + nla_total_size(sizeof(u8)) + /* TYPE */ + nla_total_size(sizeof(u8)) + /* PI */ + nla_total_size(sizeof(u8)) + /* VNET_HDR */ + nla_total_size(sizeof(u8)) + /* PERSIST */ + nla_total_size(sizeof(u8)) + /* MULTI_QUEUE */ + nla_total_size(sizeof(u32)) + /* NUM_QUEUES */ + nla_total_size(sizeof(u32)) + /* NUM_DISABLED_QUEUES */ + 0; + } + + static int tun_fill_info(struct sk_buff *skb, const struct net_device *dev) + { + struct tun_struct *tun = netdev_priv(dev); + + if (nla_put_u8(skb, IFLA_TUN_TYPE, tun->flags & TUN_TYPE_MASK)) + goto nla_put_failure; + if (uid_valid(tun->owner) && + nla_put_u32(skb, IFLA_TUN_OWNER, + from_kuid_munged(current_user_ns(), tun->owner))) + goto nla_put_failure; + if (gid_valid(tun->group) && + nla_put_u32(skb, IFLA_TUN_GROUP, + from_kgid_munged(current_user_ns(), tun->group))) + goto nla_put_failure; + if (nla_put_u8(skb, IFLA_TUN_PI, !(tun->flags & IFF_NO_PI))) + goto nla_put_failure; + if (nla_put_u8(skb, IFLA_TUN_VNET_HDR, !!(tun->flags & IFF_VNET_HDR))) + goto nla_put_failure; + if (nla_put_u8(skb, IFLA_TUN_PERSIST, !!(tun->flags & IFF_PERSIST))) + goto nla_put_failure; + if (nla_put_u8(skb, IFLA_TUN_MULTI_QUEUE, + !!(tun->flags & IFF_MULTI_QUEUE))) + goto nla_put_failure; + if (tun->flags & IFF_MULTI_QUEUE) { + if (nla_put_u32(skb, IFLA_TUN_NUM_QUEUES, tun->numqueues)) + goto nla_put_failure; + if (nla_put_u32(skb, IFLA_TUN_NUM_DISABLED_QUEUES, + tun->numdisabled)) + goto nla_put_failure; + } + + return 0; + + nla_put_failure: + return -EMSGSIZE; + } + static struct rtnl_link_ops tun_link_ops __read_mostly = { .kind = DRV_NAME, .priv_size = sizeof(struct tun_struct), .setup = tun_setup, .validate = tun_validate, + .get_size = tun_get_size, + .fill_info = tun_fill_info, };
static void tun_sock_write_space(struct sock *sk) @@@ -2783,6 -2836,7 +2837,7 @@@ static long __tun_chr_ioctl(struct fil struct tun_struct *tun; void __user* argp = (void __user*)arg; struct ifreq ifr; + struct net *net; kuid_t owner; kgid_t group; int sndbuf; @@@ -2791,7 -2845,8 +2846,8 @@@ int le; int ret;
- if (cmd == TUNSETIFF || cmd == TUNSETQUEUE || _IOC_TYPE(cmd) == SOCK_IOC_TYPE) { + if (cmd == TUNSETIFF || cmd == TUNSETQUEUE || + (_IOC_TYPE(cmd) == SOCK_IOC_TYPE && cmd != SIOCGSKNS)) { if (copy_from_user(&ifr, argp, ifreq_len)) return -EFAULT; } else { @@@ -2811,6 -2866,7 +2867,7 @@@ rtnl_lock();
tun = tun_get(tfile); + net = sock_net(&tfile->sk); if (cmd == TUNSETIFF) { ret = -EEXIST; if (tun) @@@ -2818,7 -2874,7 +2875,7 @@@
ifr.ifr_name[IFNAMSIZ-1] = '\0';
- ret = tun_set_iff(sock_net(&tfile->sk), file, &ifr); + ret = tun_set_iff(net, file, &ifr);
if (ret) goto unlock; @@@ -2840,6 -2896,14 +2897,14 @@@ tfile->ifindex = ifindex; goto unlock; } + if (cmd == SIOCGSKNS) { + ret = -EPERM; + if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) + goto unlock; + + ret = open_related_ns(&net->ns, get_net_ns); + goto unlock; + }
ret = -EBADFD; if (!tun) diff --combined drivers/net/wireless/mac80211_hwsim.c index 35b21f8152bb,7b6c3640a94f..100cf42db65d --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@@ -253,7 -253,7 +253,7 @@@ static inline void hwsim_clear_chanctx_
static unsigned int hwsim_net_id;
- static int hwsim_netgroup; + static struct ida hwsim_netgroup_ida = IDA_INIT;
struct hwsim_net { int netgroup; @@@ -267,11 -267,13 +267,13 @@@ static inline int hwsim_net_get_netgrou return hwsim_net->netgroup; }
- static inline void hwsim_net_set_netgroup(struct net *net) + static inline int hwsim_net_set_netgroup(struct net *net) { struct hwsim_net *hwsim_net = net_generic(net, hwsim_net_id);
- hwsim_net->netgroup = hwsim_netgroup++; + hwsim_net->netgroup = ida_simple_get(&hwsim_netgroup_ida, + 0, 0, GFP_KERNEL); + return hwsim_net->netgroup >= 0 ? 0 : -ENOMEM; }
static inline u32 hwsim_net_get_wmediumd(struct net *net) @@@ -493,6 -495,7 +495,7 @@@ static LIST_HEAD(hwsim_radios) static struct workqueue_struct *hwsim_wq; static struct rhashtable hwsim_radios_rht; static int hwsim_radio_idx; + static int hwsim_radios_generation = 1;
static struct platform_driver mac80211_hwsim_driver = { .driver = { @@@ -637,6 -640,7 +640,7 @@@ static const struct nla_policy hwsim_ge [HWSIM_ATTR_RADIO_NAME] = { .type = NLA_STRING }, [HWSIM_ATTR_NO_VIF] = { .type = NLA_FLAG }, [HWSIM_ATTR_FREQ] = { .type = NLA_U32 }, + [HWSIM_ATTR_PERM_ADDR] = { .type = NLA_UNSPEC, .len = ETH_ALEN }, };
static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, @@@ -2408,6 -2412,7 +2412,7 @@@ struct hwsim_new_radio_params bool destroy_on_close; const char *hwname; bool no_vif; + const u8 *perm_addr; };
static void hwsim_mcast_config_msg(struct sk_buff *mcast_skb, @@@ -2572,15 -2577,25 +2577,25 @@@ static int mac80211_hwsim_new_radio(str skb_queue_head_init(&data->pending);
SET_IEEE80211_DEV(hw, data->dev); - eth_zero_addr(addr); - addr[0] = 0x02; - addr[3] = idx >> 8; - addr[4] = idx; - memcpy(data->addresses[0].addr, addr, ETH_ALEN); - memcpy(data->addresses[1].addr, addr, ETH_ALEN); - data->addresses[1].addr[0] |= 0x40; - hw->wiphy->n_addresses = 2; - hw->wiphy->addresses = data->addresses; + if (!param->perm_addr) { + eth_zero_addr(addr); + addr[0] = 0x02; + addr[3] = idx >> 8; + addr[4] = idx; + memcpy(data->addresses[0].addr, addr, ETH_ALEN); + /* Why need here second address ? */ + data->addresses[1].addr[0] |= 0x40; + memcpy(data->addresses[1].addr, addr, ETH_ALEN); + hw->wiphy->n_addresses = 2; + hw->wiphy->addresses = data->addresses; + /* possible address clash is checked at hash table insertion */ + } else { + memcpy(data->addresses[0].addr, param->perm_addr, ETH_ALEN); + /* compatibility with automatically generated mac addr */ + memcpy(data->addresses[1].addr, param->perm_addr, ETH_ALEN); + hw->wiphy->n_addresses = 2; + hw->wiphy->addresses = data->addresses; + }
data->channels = param->channels; data->use_chanctx = param->use_chanctx; @@@ -2727,7 -2742,6 +2742,7 @@@ mutex_init(&data->mutex);
data->netgroup = hwsim_net_get_netgroup(net); + data->wmediumd = hwsim_net_get_wmediumd(net);
/* Enable frame retransmissions for lossy channels */ hw->max_rates = 4; @@@ -2786,13 -2800,17 +2801,17 @@@ err = rhashtable_insert_fast(&hwsim_radios_rht, &data->rht, hwsim_rht_params); if (err < 0) { - pr_debug("mac80211_hwsim: radio index %d already present\n", - idx); + if (info) { + GENL_SET_ERR_MSG(info, "perm addr already present"); + NL_SET_BAD_ATTR(info->extack, + info->attrs[HWSIM_ATTR_PERM_ADDR]); + } spin_unlock_bh(&hwsim_radio_lock); goto failed_final_insert; }
list_add_tail(&data->list, &hwsim_radios); + hwsim_radios_generation++; spin_unlock_bh(&hwsim_radio_lock);
if (idx > 0) @@@ -3211,6 -3229,19 +3230,19 @@@ static int hwsim_new_radio_nl(struct sk param.regd = hwsim_world_regdom_custom[idx]; }
+ if (info->attrs[HWSIM_ATTR_PERM_ADDR]) { + if (!is_valid_ether_addr( + nla_data(info->attrs[HWSIM_ATTR_PERM_ADDR]))) { + GENL_SET_ERR_MSG(info,"MAC is no valid source addr"); + NL_SET_BAD_ATTR(info->extack, + info->attrs[HWSIM_ATTR_PERM_ADDR]); + return -EINVAL; + } + + + param.perm_addr = nla_data(info->attrs[HWSIM_ATTR_PERM_ADDR]); + } + ret = mac80211_hwsim_new_radio(info, ¶m); kfree(hwname); return ret; @@@ -3250,6 -3281,7 +3282,7 @@@ static int hwsim_del_radio_nl(struct sk list_del(&data->list); rhashtable_remove_fast(&hwsim_radios_rht, &data->rht, hwsim_rht_params); + hwsim_radios_generation++; spin_unlock_bh(&hwsim_radio_lock); mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy), info); @@@ -3306,17 -3338,19 +3339,19 @@@ out_err static int hwsim_dump_radio_nl(struct sk_buff *skb, struct netlink_callback *cb) { - int idx = cb->args[0]; + int last_idx = cb->args[0]; struct mac80211_hwsim_data *data = NULL; - int res; + int res = 0; + void *hdr;
spin_lock_bh(&hwsim_radio_lock); + cb->seq = hwsim_radios_generation;
- if (idx == hwsim_radio_idx) + if (last_idx >= hwsim_radio_idx-1) goto done;
list_for_each_entry(data, &hwsim_radios, list) { - if (data->idx < idx) + if (data->idx <= last_idx) continue;
if (!net_eq(wiphy_net(data->hw->wiphy), sock_net(skb->sk))) @@@ -3329,14 -3363,25 +3364,25 @@@ if (res < 0) break;
- idx = data->idx + 1; + last_idx = data->idx; }
- cb->args[0] = idx; + cb->args[0] = last_idx; + + /* list changed, but no new element sent, set interrupted flag */ + if (skb->len == 0 && cb->prev_seq && cb->seq != cb->prev_seq) { + hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, + cb->nlh->nlmsg_seq, &hwsim_genl_family, + NLM_F_MULTI, HWSIM_CMD_GET_RADIO); + if (!hdr) + res = -EMSGSIZE; + genl_dump_check_consistent(cb, hdr); + genlmsg_end(skb, hdr); + }
done: spin_unlock_bh(&hwsim_radio_lock); - return skb->len; + return res ?: skb->len; }
/* Generic Netlink operations array */ @@@ -3394,6 -3439,7 +3440,7 @@@ static void destroy_radio(struct work_s struct mac80211_hwsim_data *data = container_of(work, struct mac80211_hwsim_data, destroy_work);
+ hwsim_radios_generation++; mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy), NULL); }
@@@ -3463,9 -3509,7 +3510,7 @@@ failure
static __net_init int hwsim_init_net(struct net *net) { - hwsim_net_set_netgroup(net); - - return 0; + return hwsim_net_set_netgroup(net); }
static void __net_exit hwsim_exit_net(struct net *net) @@@ -3488,6 -3532,8 +3533,8 @@@ queue_work(hwsim_wq, &data->destroy_work); } spin_unlock_bh(&hwsim_radio_lock); + + ida_simple_remove(&hwsim_netgroup_ida, hwsim_net_get_netgroup(net)); }
static struct pernet_operations hwsim_net_ops = { @@@ -3495,6 -3541,7 +3542,7 @@@ .exit = hwsim_exit_net, .id = &hwsim_net_id, .size = sizeof(struct hwsim_net), + .async = true, };
static void hwsim_exit_netlink(void) diff --combined drivers/s390/net/qeth_core_main.c index 3653bea38470,8c97ce2516bb..19203340f879 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@@ -527,7 -527,8 +527,7 @@@ static inline int qeth_is_cq(struct qet queue == card->qdio.no_in_queues - 1; }
- -static int qeth_issue_next_read(struct qeth_card *card) +static int __qeth_issue_next_read(struct qeth_card *card) { int rc; struct qeth_cmd_buffer *iob; @@@ -558,17 -559,6 +558,17 @@@ return rc; }
+static int qeth_issue_next_read(struct qeth_card *card) +{ + int ret; + + spin_lock_irq(get_ccwdev_lock(CARD_RDEV(card))); + ret = __qeth_issue_next_read(card); + spin_unlock_irq(get_ccwdev_lock(CARD_RDEV(card))); + + return ret; +} + static struct qeth_reply *qeth_alloc_reply(struct qeth_card *card) { struct qeth_reply *reply; @@@ -718,11 -708,8 +718,8 @@@ static int qeth_check_idx_response(stru
QETH_DBF_HEX(CTRL, 2, buffer, QETH_DBF_CTRL_LEN); if ((buffer[2] & 0xc0) == 0xc0) { - QETH_DBF_MESSAGE(2, "received an IDX TERMINATE " - "with cause code 0x%02x%s\n", - buffer[4], - ((buffer[4] == 0x22) ? - " -- try another portname" : "")); + QETH_DBF_MESSAGE(2, "received an IDX TERMINATE with cause code %#02x\n", + buffer[4]); QETH_CARD_TEXT(card, 2, "ckidxres"); QETH_CARD_TEXT(card, 2, " idxterm"); QETH_CARD_TEXT_(card, 2, " rc%d", -EIO); @@@ -970,7 -957,7 +967,7 @@@ void qeth_clear_thread_running_bit(stru spin_lock_irqsave(&card->thread_mask_lock, flags); card->thread_running_mask &= ~thread; spin_unlock_irqrestore(&card->thread_mask_lock, flags); - wake_up(&card->wait_q); + wake_up_all(&card->wait_q); } EXPORT_SYMBOL_GPL(qeth_clear_thread_running_bit);
@@@ -1174,7 -1161,6 +1171,7 @@@ static void qeth_irq(struct ccw_device } rc = qeth_get_problem(cdev, irb); if (rc) { + card->read_or_write_problem = 1; qeth_clear_ipacmd_list(card); qeth_schedule_recovery(card); goto out; @@@ -1193,7 -1179,7 +1190,7 @@@ return; if (channel == &card->read && channel->state == CH_STATE_UP) - qeth_issue_next_read(card); + __qeth_issue_next_read(card);
iob = channel->iob; index = channel->buf_no; @@@ -2849,7 -2835,8 +2846,8 @@@ static int qeth_init_input_buffer(struc int i;
if ((card->options.cq == QETH_CQ_ENABLED) && (!buf->rx_skb)) { - buf->rx_skb = dev_alloc_skb(QETH_RX_PULL_LEN + ETH_HLEN); + buf->rx_skb = netdev_alloc_skb(card->dev, + QETH_RX_PULL_LEN + ETH_HLEN); if (!buf->rx_skb) return 1; } @@@ -2886,8 -2873,8 +2884,8 @@@ int qeth_init_qdio_queues(struct qeth_c QETH_DBF_TEXT(SETUP, 2, "initqdqs");
/* inbound queue */ - qdio_reset_buffers(card->qdio.in_q->qdio_bufs, - QDIO_MAX_BUFFERS_PER_Q); + qdio_reset_buffers(card->qdio.in_q->qdio_bufs, QDIO_MAX_BUFFERS_PER_Q); + memset(&card->rx, 0, sizeof(struct qeth_rx)); qeth_initialize_working_pool_list(card); /*give only as many buffers to hardware as we have buffer pool entries*/ for (i = 0; i < card->qdio.in_buf_pool.buf_count - 1; ++i) @@@ -2962,12 -2949,10 +2960,10 @@@ struct qeth_cmd_buffer *qeth_get_ipacmd enum qeth_ipa_cmds ipacmd, enum qeth_prot_versions prot) { struct qeth_cmd_buffer *iob; - struct qeth_ipa_cmd *cmd;
iob = qeth_get_buffer(&card->write); if (iob) { - cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); - qeth_fill_ipacmd_header(card, cmd, ipacmd, prot); + qeth_fill_ipacmd_header(card, __ipa_cmd(iob), ipacmd, prot); } else { dev_warn(&card->gdev->dev, "The qeth driver ran out of channel command buffers\n"); @@@ -3078,7 -3063,7 +3074,7 @@@ static struct qeth_cmd_buffer *qeth_get iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETADAPTERPARMS, QETH_PROT_IPV4); if (iob) { - cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + cmd = __ipa_cmd(iob); cmd->data.setadapterparms.hdr.cmdlength = cmdlen; cmd->data.setadapterparms.hdr.command_code = command; cmd->data.setadapterparms.hdr.used_total = 1; @@@ -3220,7 -3205,7 +3216,7 @@@ static int qeth_query_setdiagass(struc iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SET_DIAG_ASS, 0); if (!iob) return -ENOMEM; - cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + cmd = __ipa_cmd(iob); cmd->data.diagass.subcmd_len = 16; cmd->data.diagass.subcmd = QETH_DIAGS_CMD_QUERY; return qeth_send_ipa_cmd(card, iob, qeth_query_setdiagass_cb, NULL); @@@ -3273,7 -3258,7 +3269,7 @@@ int qeth_hw_trap(struct qeth_card *card iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SET_DIAG_ASS, 0); if (!iob) return -ENOMEM; - cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + cmd = __ipa_cmd(iob); cmd->data.diagass.subcmd_len = 80; cmd->data.diagass.subcmd = QETH_DIAGS_CMD_TRAP; cmd->data.diagass.type = 1; @@@ -4251,7 -4236,7 +4247,7 @@@ void qeth_setadp_promisc_mode(struct qe sizeof(struct qeth_ipacmd_setadpparms_hdr) + 8); if (!iob) return; - cmd = (struct qeth_ipa_cmd *)(iob->data + IPA_PDU_HEADER_SIZE); + cmd = __ipa_cmd(iob); cmd->data.setadapterparms.data.mode = mode; qeth_send_ipa_cmd(card, iob, qeth_setadp_promisc_mode_cb, NULL); } @@@ -4318,7 -4303,7 +4314,7 @@@ int qeth_setadpparms_change_macaddr(str sizeof(struct qeth_change_addr)); if (!iob) return -ENOMEM; - cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + cmd = __ipa_cmd(iob); cmd->data.setadapterparms.data.change_addr.cmd = CHANGE_ADDR_READ_MAC; cmd->data.setadapterparms.data.change_addr.addr_size = ETH_ALEN; ether_addr_copy(cmd->data.setadapterparms.data.change_addr.addr, @@@ -4433,7 -4418,7 +4429,7 @@@ static int qeth_setadpparms_set_access_ sizeof(struct qeth_set_access_ctrl)); if (!iob) return -ENOMEM; - cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + cmd = __ipa_cmd(iob); access_ctrl_req = &cmd->data.setadapterparms.data.set_access_ctrl; access_ctrl_req->subcmd_code = isolation;
@@@ -4679,7 -4664,7 +4675,7 @@@ static int qeth_snmp_command(struct qet rc = -ENOMEM; goto out; } - cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + cmd = __ipa_cmd(iob); memcpy(&cmd->data.setadapterparms.data.snmp, &ureq->cmd, req_len); rc = qeth_send_ipa_snmp_cmd(card, iob, QETH_SETADP_BASE_LEN + req_len, qeth_snmp_command_cb, (void *)&qinfo); @@@ -4764,7 -4749,7 +4760,7 @@@ static int qeth_query_oat_command(struc rc = -ENOMEM; goto out_free; } - cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + cmd = __ipa_cmd(iob); oat_req = &cmd->data.setadapterparms.data.query_oat; oat_req->subcmd_code = oat_data.command;
@@@ -5098,6 -5083,8 +5094,6 @@@ static void qeth_core_free_card(struct QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); qeth_clean_channel(&card->read); qeth_clean_channel(&card->write); - if (card->dev) - free_netdev(card->dev); qeth_free_qdio_buffers(card); unregister_service_level(&card->qeth_service_level); kfree(card); @@@ -5339,7 -5326,7 +5335,7 @@@ struct sk_buff *qeth_core_get_next_skb( } else { unsigned int linear = (use_rx_sg) ? QETH_RX_PULL_LEN : skb_len;
- skb = dev_alloc_skb(linear + headroom); + skb = napi_alloc_skb(&card->napi, linear + headroom); } if (!skb) goto no_mem; @@@ -5503,7 -5490,7 +5499,7 @@@ struct qeth_cmd_buffer *qeth_get_setass iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETASSPARMS, prot);
if (iob) { - cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + cmd = __ipa_cmd(iob); cmd->data.setassparms.hdr.assist_no = ipa_func; cmd->data.setassparms.hdr.length = 8 + len; cmd->data.setassparms.hdr.command_code = cmd_code; @@@ -5526,7 -5513,7 +5522,7 @@@ int qeth_send_setassparms(struct qeth_c
QETH_CARD_TEXT(card, 4, "sendassp");
- cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + cmd = __ipa_cmd(iob); if (len <= sizeof(__u32)) cmd->data.setassparms.data.flags_32bit = (__u32) data; else /* (len > sizeof(__u32)) */ diff --combined drivers/s390/net/qeth_l2_main.c index 5ef4c978ad19,8f5babdccb42..50a313806dde --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@@ -108,7 -108,7 +108,7 @@@ static int qeth_l2_send_setdelmac(struc iob = qeth_get_ipacmd_buffer(card, ipacmd, QETH_PROT_IPV4); if (!iob) return -ENOMEM; - cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + cmd = __ipa_cmd(iob); cmd->data.setdelmac.mac_length = ETH_ALEN; ether_addr_copy(cmd->data.setdelmac.mac, mac); return qeth_setdelmac_makerc(card, qeth_send_ipa_cmd(card, iob, @@@ -305,7 -305,7 +305,7 @@@ static int qeth_l2_send_setdelvlan(stru iob = qeth_get_ipacmd_buffer(card, ipacmd, QETH_PROT_IPV4); if (!iob) return -ENOMEM; - cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + cmd = __ipa_cmd(iob); cmd->data.setdelvlan.vlan_id = i; return qeth_setdelvlan_makerc(card, qeth_send_ipa_cmd(card, iob, qeth_l2_send_setdelvlan_cb, NULL)); @@@ -437,10 -437,8 +437,8 @@@ static int qeth_l2_process_inbound_buff *done = 1; break; } - skb->dev = card->dev; switch (hdr->hdr.l2.id) { case QETH_HEADER_TYPE_LAYER2: - skb->pkt_type = PACKET_HOST; skb->protocol = eth_type_trans(skb, skb->dev); if ((card->dev->features & NETIF_F_RXCSUM) && ((hdr->hdr.l2.flags[1] & @@@ -915,8 -913,8 +913,8 @@@ static void qeth_l2_remove_device(struc qeth_l2_set_offline(cgdev);
if (card->dev) { - netif_napi_del(&card->napi); unregister_netdev(card->dev); + free_netdev(card->dev); card->dev = NULL; } return; @@@ -975,6 -973,7 +973,7 @@@ static int qeth_l2_setup_netdev(struct return -ENODEV;
card->dev->ml_priv = card; + card->dev->priv_flags |= IFF_UNICAST_FLT; card->dev->watchdog_timeo = QETH_TX_TIMEOUT; card->dev->mtu = card->info.initial_mtu; card->dev->min_mtu = 64; @@@ -991,9 -990,16 +990,16 @@@ card->dev->features |= NETIF_F_VLAN_CHALLENGED; else card->dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; + + if (card->info.type != QETH_CARD_TYPE_OSN && + card->info.type != QETH_CARD_TYPE_IQD) { + card->dev->priv_flags &= ~IFF_TX_SKB_SHARING; + card->dev->needed_headroom = sizeof(struct qeth_hdr); + card->dev->hw_features |= NETIF_F_SG; + card->dev->vlan_features |= NETIF_F_SG; + } + if (card->info.type == QETH_CARD_TYPE_OSD && !card->info.guestlan) { - card->dev->hw_features = NETIF_F_SG; - card->dev->vlan_features = NETIF_F_SG; card->dev->features |= NETIF_F_SG; /* OSA 3S and earlier has no RX/TX support */ if (qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM)) { @@@ -1005,11 -1011,6 +1011,6 @@@ card->dev->vlan_features |= NETIF_F_RXCSUM; } } - if (card->info.type != QETH_CARD_TYPE_OSN && - card->info.type != QETH_CARD_TYPE_IQD) { - card->dev->priv_flags &= ~IFF_TX_SKB_SHARING; - card->dev->needed_headroom = sizeof(struct qeth_hdr); - }
card->info.broadcast_capable = 1; qeth_l2_request_initial_mac(card); @@@ -1086,7 -1087,6 +1087,6 @@@ static int __qeth_l2_set_online(struct qeth_l2_setup_bridgeport_attrs(card);
card->state = CARD_STATE_HARDSETUP; - memset(&card->rx, 0, sizeof(struct qeth_rx)); qeth_print_status_message(card);
/* softsetup */ @@@ -1374,7 -1374,6 +1374,6 @@@ int qeth_osn_assist(struct net_device * { struct qeth_cmd_buffer *iob; struct qeth_card *card; - int rc;
if (!dev) return -ENODEV; @@@ -1385,9 -1384,8 +1384,8 @@@ if (!qeth_card_hw_is_reachable(card)) return -ENODEV; iob = qeth_wait_for_buffer(&card->write); - memcpy(iob->data+IPA_PDU_HEADER_SIZE, data, data_len); - rc = qeth_osn_send_ipa_cmd(card, iob, data_len); - return rc; + memcpy(__ipa_cmd(iob), data, data_len); + return qeth_osn_send_ipa_cmd(card, iob, data_len); } EXPORT_SYMBOL(qeth_osn_assist);
@@@ -1764,7 -1762,7 +1762,7 @@@ static struct qeth_cmd_buffer *qeth_sbp iob = qeth_get_ipacmd_buffer(card, ipa_cmd, 0); if (!iob) return iob; - cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + cmd = __ipa_cmd(iob); cmd->data.sbp.hdr.cmdlength = sizeof(struct qeth_ipacmd_sbp_hdr) + cmd_length; cmd->data.sbp.hdr.command_code = sbp_cmd; @@@ -2129,7 -2127,7 +2127,7 @@@ static int qeth_l2_vnicc_request(struc return -ENOMEM;
/* create header for request */ - cmd = (struct qeth_ipa_cmd *)(iob->data + IPA_PDU_HEADER_SIZE); + cmd = __ipa_cmd(iob); req = &cmd->data.vnicc;
/* create sub command header for request */ diff --combined drivers/s390/net/qeth_l3_main.c index b6b12220da71,ef3f548b7d35..c1a16a74aa83 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@@ -67,6 -67,15 +67,15 @@@ void qeth_l3_ipaddr_to_string(enum qeth qeth_l3_ipaddr6_to_string(addr, buf); }
+ static struct qeth_ipaddr *qeth_l3_get_addr_buffer(enum qeth_prot_versions prot) + { + struct qeth_ipaddr *addr = kmalloc(sizeof(*addr), GFP_ATOMIC); + + if (addr) + qeth_l3_init_ipaddr(addr, QETH_IP_TYPE_NORMAL, prot); + return addr; + } + static struct qeth_ipaddr *qeth_l3_find_addr_by_ip(struct qeth_card *card, struct qeth_ipaddr *query) { @@@ -138,12 -147,18 +147,18 @@@ static bool qeth_l3_is_addr_covered_by_ return rc; }
- int qeth_l3_delete_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) + static int qeth_l3_delete_ip(struct qeth_card *card, + struct qeth_ipaddr *tmp_addr) { int rc = 0; struct qeth_ipaddr *addr;
- QETH_CARD_TEXT(card, 4, "delip"); + if (tmp_addr->type == QETH_IP_TYPE_RXIP) + QETH_CARD_TEXT(card, 2, "delrxip"); + else if (tmp_addr->type == QETH_IP_TYPE_VIPA) + QETH_CARD_TEXT(card, 2, "delvipa"); + else + QETH_CARD_TEXT(card, 2, "delip");
if (tmp_addr->proto == QETH_PROT_IPV4) QETH_CARD_HEX(card, 4, &tmp_addr->u.a4.addr, 4); @@@ -171,13 -186,18 +186,18 @@@ return rc; }
- int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) + static int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) { int rc = 0; struct qeth_ipaddr *addr; char buf[40];
- QETH_CARD_TEXT(card, 4, "addip"); + if (tmp_addr->type == QETH_IP_TYPE_RXIP) + QETH_CARD_TEXT(card, 2, "addrxip"); + else if (tmp_addr->type == QETH_IP_TYPE_VIPA) + QETH_CARD_TEXT(card, 2, "addvipa"); + else + QETH_CARD_TEXT(card, 2, "addip");
if (tmp_addr->proto == QETH_PROT_IPV4) QETH_CARD_HEX(card, 4, &tmp_addr->u.a4.addr, 4); @@@ -209,7 -229,7 +229,7 @@@
if (qeth_l3_is_addr_covered_by_ipato(card, addr)) { QETH_CARD_TEXT(card, 2, "tkovaddr"); - addr->set_flags |= QETH_IPA_SETIP_TAKEOVER_FLAG; + addr->ipato = 1; } hash_add(card->ip_htable, &addr->hnode, qeth_l3_ipaddr_hash(addr)); @@@ -251,23 -271,6 +271,6 @@@ return rc; }
- - struct qeth_ipaddr *qeth_l3_get_addr_buffer( - enum qeth_prot_versions prot) - { - struct qeth_ipaddr *addr; - - addr = kzalloc(sizeof(struct qeth_ipaddr), GFP_ATOMIC); - if (!addr) - return NULL; - - addr->type = QETH_IP_TYPE_NORMAL; - addr->disp_flag = QETH_DISP_ADDR_DO_NOTHING; - addr->proto = prot; - - return addr; - } - static void qeth_l3_clear_ip_htable(struct qeth_card *card, int recover) { struct qeth_ipaddr *addr; @@@ -352,7 -355,7 +355,7 @@@ static int qeth_l3_send_setdelmc(struc iob = qeth_get_ipacmd_buffer(card, ipacmd, addr->proto); if (!iob) return -ENOMEM; - cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + cmd = __ipa_cmd(iob); ether_addr_copy(cmd->data.setdelipm.mac, addr->mac); if (addr->proto == QETH_PROT_IPV6) memcpy(cmd->data.setdelipm.ip6, &addr->u.a6.addr, @@@ -379,21 -382,38 +382,38 @@@ static void qeth_l3_fill_netmask(u8 *ne } }
+ static u32 qeth_l3_get_setdelip_flags(struct qeth_ipaddr *addr, bool set) + { + switch (addr->type) { + case QETH_IP_TYPE_RXIP: + return (set) ? QETH_IPA_SETIP_TAKEOVER_FLAG : 0; + case QETH_IP_TYPE_VIPA: + return (set) ? QETH_IPA_SETIP_VIPA_FLAG : + QETH_IPA_DELIP_VIPA_FLAG; + default: + return (set && addr->ipato) ? QETH_IPA_SETIP_TAKEOVER_FLAG : 0; + } + } + static int qeth_l3_send_setdelip(struct qeth_card *card, - struct qeth_ipaddr *addr, int ipacmd, unsigned int flags) + struct qeth_ipaddr *addr, + enum qeth_ipa_cmds ipacmd) { - int rc; struct qeth_cmd_buffer *iob; struct qeth_ipa_cmd *cmd; __u8 netmask[16]; + u32 flags;
QETH_CARD_TEXT(card, 4, "setdelip"); - QETH_CARD_TEXT_(card, 4, "flags%02X", flags);
iob = qeth_get_ipacmd_buffer(card, ipacmd, addr->proto); if (!iob) return -ENOMEM; - cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + cmd = __ipa_cmd(iob); + + flags = qeth_l3_get_setdelip_flags(addr, ipacmd == IPA_CMD_SETIP); + QETH_CARD_TEXT_(card, 4, "flags%02X", flags); + if (addr->proto == QETH_PROT_IPV6) { memcpy(cmd->data.setdelip6.ip_addr, &addr->u.a6.addr, sizeof(struct in6_addr)); @@@ -407,9 -427,7 +427,7 @@@ cmd->data.setdelip4.flags = flags; }
- rc = qeth_send_ipa_cmd(card, iob, NULL, NULL); - - return rc; + return qeth_send_ipa_cmd(card, iob, NULL, NULL); }
static int qeth_l3_send_setrouting(struct qeth_card *card, @@@ -423,7 -441,7 +441,7 @@@ iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETRTG, prot); if (!iob) return -ENOMEM; - cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + cmd = __ipa_cmd(iob); cmd->data.setrtg.type = (type); rc = qeth_send_ipa_cmd(card, iob, NULL, NULL);
@@@ -525,10 -543,7 +543,7 @@@ void qeth_l3_update_ipato(struct qeth_c hash_for_each(card->ip_htable, i, addr, hnode) { if (addr->type != QETH_IP_TYPE_NORMAL) continue; - if (qeth_l3_is_addr_covered_by_ipato(card, addr)) - addr->set_flags |= QETH_IPA_SETIP_TAKEOVER_FLAG; - else - addr->set_flags &= ~QETH_IPA_SETIP_TAKEOVER_FLAG; + addr->ipato = qeth_l3_is_addr_covered_by_ipato(card, addr); } }
@@@ -606,132 -621,39 +621,39 @@@ int qeth_l3_del_ipato_entry(struct qeth return rc; }
- /* - * VIPA related functions - */ - int qeth_l3_add_vipa(struct qeth_card *card, enum qeth_prot_versions proto, - const u8 *addr) - { - struct qeth_ipaddr *ipaddr; - int rc; - - ipaddr = qeth_l3_get_addr_buffer(proto); - if (ipaddr) { - if (proto == QETH_PROT_IPV4) { - QETH_CARD_TEXT(card, 2, "addvipa4"); - memcpy(&ipaddr->u.a4.addr, addr, 4); - ipaddr->u.a4.mask = 0; - } else if (proto == QETH_PROT_IPV6) { - QETH_CARD_TEXT(card, 2, "addvipa6"); - memcpy(&ipaddr->u.a6.addr, addr, 16); - ipaddr->u.a6.pfxlen = 0; - } - ipaddr->type = QETH_IP_TYPE_VIPA; - ipaddr->set_flags = QETH_IPA_SETIP_VIPA_FLAG; - ipaddr->del_flags = QETH_IPA_DELIP_VIPA_FLAG; - } else - return -ENOMEM; - - spin_lock_bh(&card->ip_lock); - rc = qeth_l3_add_ip(card, ipaddr); - spin_unlock_bh(&card->ip_lock); - - kfree(ipaddr); - - return rc; - } - - int qeth_l3_del_vipa(struct qeth_card *card, enum qeth_prot_versions proto, - const u8 *addr) - { - struct qeth_ipaddr *ipaddr; - int rc; - - ipaddr = qeth_l3_get_addr_buffer(proto); - if (ipaddr) { - if (proto == QETH_PROT_IPV4) { - QETH_CARD_TEXT(card, 2, "delvipa4"); - memcpy(&ipaddr->u.a4.addr, addr, 4); - ipaddr->u.a4.mask = 0; - } else if (proto == QETH_PROT_IPV6) { - QETH_CARD_TEXT(card, 2, "delvipa6"); - memcpy(&ipaddr->u.a6.addr, addr, 16); - ipaddr->u.a6.pfxlen = 0; - } - ipaddr->type = QETH_IP_TYPE_VIPA; - } else - return -ENOMEM; - - spin_lock_bh(&card->ip_lock); - rc = qeth_l3_delete_ip(card, ipaddr); - spin_unlock_bh(&card->ip_lock); - - kfree(ipaddr); - return rc; - } - - /* - * proxy ARP related functions - */ - int qeth_l3_add_rxip(struct qeth_card *card, enum qeth_prot_versions proto, - const u8 *addr) + int qeth_l3_modify_rxip_vipa(struct qeth_card *card, bool add, const u8 *ip, + enum qeth_ip_types type, + enum qeth_prot_versions proto) { - struct qeth_ipaddr *ipaddr; + struct qeth_ipaddr addr; int rc;
- ipaddr = qeth_l3_get_addr_buffer(proto); - if (ipaddr) { - if (proto == QETH_PROT_IPV4) { - QETH_CARD_TEXT(card, 2, "addrxip4"); - memcpy(&ipaddr->u.a4.addr, addr, 4); - ipaddr->u.a4.mask = 0; - } else if (proto == QETH_PROT_IPV6) { - QETH_CARD_TEXT(card, 2, "addrxip6"); - memcpy(&ipaddr->u.a6.addr, addr, 16); - ipaddr->u.a6.pfxlen = 0; - } - - ipaddr->type = QETH_IP_TYPE_RXIP; - ipaddr->set_flags = QETH_IPA_SETIP_TAKEOVER_FLAG; - ipaddr->del_flags = 0; - } else - return -ENOMEM; + qeth_l3_init_ipaddr(&addr, type, proto); + if (proto == QETH_PROT_IPV4) + memcpy(&addr.u.a4.addr, ip, 4); + else + memcpy(&addr.u.a6.addr, ip, 16);
spin_lock_bh(&card->ip_lock); - rc = qeth_l3_add_ip(card, ipaddr); + rc = add ? qeth_l3_add_ip(card, &addr) : qeth_l3_delete_ip(card, &addr); spin_unlock_bh(&card->ip_lock); - - kfree(ipaddr); - return rc; }
- int qeth_l3_del_rxip(struct qeth_card *card, enum qeth_prot_versions proto, - const u8 *addr) + int qeth_l3_modify_hsuid(struct qeth_card *card, bool add) { - struct qeth_ipaddr *ipaddr; - int rc; + struct qeth_ipaddr addr; + int rc, i;
- ipaddr = qeth_l3_get_addr_buffer(proto); - if (ipaddr) { - if (proto == QETH_PROT_IPV4) { - QETH_CARD_TEXT(card, 2, "delrxip4"); - memcpy(&ipaddr->u.a4.addr, addr, 4); - ipaddr->u.a4.mask = 0; - } else if (proto == QETH_PROT_IPV6) { - QETH_CARD_TEXT(card, 2, "delrxip6"); - memcpy(&ipaddr->u.a6.addr, addr, 16); - ipaddr->u.a6.pfxlen = 0; - } - ipaddr->type = QETH_IP_TYPE_RXIP; - } else - return -ENOMEM; + qeth_l3_init_ipaddr(&addr, QETH_IP_TYPE_NORMAL, QETH_PROT_IPV6); + addr.u.a6.addr.s6_addr[0] = 0xfe; + addr.u.a6.addr.s6_addr[1] = 0x80; + for (i = 0; i < 8; i++) + addr.u.a6.addr.s6_addr[8+i] = card->options.hsuid[i];
spin_lock_bh(&card->ip_lock); - rc = qeth_l3_delete_ip(card, ipaddr); + rc = add ? qeth_l3_add_ip(card, &addr) : qeth_l3_delete_ip(card, &addr); spin_unlock_bh(&card->ip_lock); - - kfree(ipaddr); return rc; }
@@@ -758,8 -680,7 +680,7 @@@ static int qeth_l3_register_addr_entry( if (addr->is_multicast) rc = qeth_l3_send_setdelmc(card, addr, IPA_CMD_SETIPM); else - rc = qeth_l3_send_setdelip(card, addr, IPA_CMD_SETIP, - addr->set_flags); + rc = qeth_l3_send_setdelip(card, addr, IPA_CMD_SETIP); if (rc) QETH_CARD_TEXT(card, 2, "failed"); } while ((--cnt > 0) && rc); @@@ -791,8 -712,7 +712,7 @@@ static int qeth_l3_deregister_addr_entr if (addr->is_multicast) rc = qeth_l3_send_setdelmc(card, addr, IPA_CMD_DELIPM); else - rc = qeth_l3_send_setdelip(card, addr, IPA_CMD_DELIP, - addr->del_flags); + rc = qeth_l3_send_setdelip(card, addr, IPA_CMD_DELIP); if (rc) QETH_CARD_TEXT(card, 2, "failed");
@@@ -1072,7 -992,7 +992,7 @@@ static int qeth_l3_iqd_read_initial_mac QETH_PROT_IPV6); if (!iob) return -ENOMEM; - cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + cmd = __ipa_cmd(iob); *((__u16 *) &cmd->data.create_destroy_addr.unique_id[6]) = card->info.unique_id;
@@@ -1117,7 -1037,7 +1037,7 @@@ static int qeth_l3_get_unique_id(struc QETH_PROT_IPV6); if (!iob) return -ENOMEM; - cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + cmd = __ipa_cmd(iob); *((__u16 *) &cmd->data.create_destroy_addr.unique_id[6]) = card->info.unique_id;
@@@ -1193,7 -1113,7 +1113,7 @@@ qeth_diags_trace(struct qeth_card *card iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SET_DIAG_ASS, 0); if (!iob) return -ENOMEM; - cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + cmd = __ipa_cmd(iob); cmd->data.diagass.subcmd_len = 16; cmd->data.diagass.subcmd = QETH_DIAGS_CMD_TRACE; cmd->data.diagass.type = QETH_DIAGS_TYPE_HIPERSOCKET; @@@ -1502,30 -1422,24 +1422,24 @@@ static void qeth_l3_rebuild_skb(struct ipv6_eth_mc_map(&ipv6_hdr(skb)->daddr, tg_addr);
card->stats.multicast++; - skb->pkt_type = PACKET_MULTICAST; break; case QETH_CAST_BROADCAST: ether_addr_copy(tg_addr, card->dev->broadcast); card->stats.multicast++; - skb->pkt_type = PACKET_BROADCAST; break; - case QETH_CAST_UNICAST: - case QETH_CAST_ANYCAST: - case QETH_CAST_NOCAST: default: if (card->options.sniffer) skb->pkt_type = PACKET_OTHERHOST; - else - skb->pkt_type = PACKET_HOST; ether_addr_copy(tg_addr, card->dev->dev_addr); } + if (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_SRC_MAC_ADDR) card->dev->header_ops->create(skb, card->dev, prot, tg_addr, &hdr->hdr.l3.next_hop.rx.src_mac, - card->dev->addr_len); + skb->len); else card->dev->header_ops->create(skb, card->dev, prot, - tg_addr, "FAKELL", card->dev->addr_len); + tg_addr, "FAKELL", skb->len); }
skb->protocol = eth_type_trans(skb, card->dev); @@@ -1572,20 -1486,16 +1486,16 @@@ static int qeth_l3_process_inbound_buff *done = 1; break; } - skb->dev = card->dev; switch (hdr->hdr.l3.id) { case QETH_HEADER_TYPE_LAYER3: magic = *(__u16 *)skb->data; if ((card->info.type == QETH_CARD_TYPE_IQD) && (magic == ETH_P_AF_IUCV)) { skb->protocol = cpu_to_be16(ETH_P_AF_IUCV); - skb->pkt_type = PACKET_HOST; - skb->mac_header = NET_SKB_PAD; - skb->dev = card->dev; len = skb->len; card->dev->header_ops->create(skb, card->dev, 0, - card->dev->dev_addr, "FAKELL", - card->dev->addr_len); + card->dev->dev_addr, "FAKELL", len); + skb_reset_mac_header(skb); netif_receive_skb(skb); } else { qeth_l3_rebuild_skb(card, skb, hdr); @@@ -1594,7 -1504,6 +1504,6 @@@ } break; case QETH_HEADER_TYPE_LAYER2: /* for HiperSockets sniffer */ - skb->pkt_type = PACKET_HOST; skb->protocol = eth_type_trans(skb, skb->dev); len = skb->len; netif_receive_skb(skb); @@@ -1613,69 -1522,6 +1522,6 @@@ return work_done; }
- static int qeth_l3_verify_vlan_dev(struct net_device *dev, - struct qeth_card *card) - { - int rc = 0; - u16 vid; - - for_each_set_bit(vid, card->active_vlans, VLAN_N_VID) { - struct net_device *netdev; - - rcu_read_lock(); - netdev = __vlan_find_dev_deep_rcu(card->dev, htons(ETH_P_8021Q), - vid); - rcu_read_unlock(); - if (netdev == dev) { - rc = QETH_VLAN_CARD; - break; - } - } - - if (rc && !(vlan_dev_real_dev(dev)->ml_priv == (void *)card)) - return 0; - - return rc; - } - - static int qeth_l3_verify_dev(struct net_device *dev) - { - struct qeth_card *card; - int rc = 0; - unsigned long flags; - - read_lock_irqsave(&qeth_core_card_list.rwlock, flags); - list_for_each_entry(card, &qeth_core_card_list.list, list) { - if (card->dev == dev) { - rc = QETH_REAL_CARD; - break; - } - rc = qeth_l3_verify_vlan_dev(dev, card); - if (rc) - break; - } - read_unlock_irqrestore(&qeth_core_card_list.rwlock, flags); - - return rc; - } - - static struct qeth_card *qeth_l3_get_card_from_dev(struct net_device *dev) - { - struct qeth_card *card = NULL; - int rc; - - rc = qeth_l3_verify_dev(dev); - if (rc == QETH_REAL_CARD) - card = dev->ml_priv; - else if (rc == QETH_VLAN_CARD) - card = vlan_dev_real_dev(dev)->ml_priv; - if (card && card->options.layer2) - card = NULL; - if (card) - QETH_CARD_TEXT_(card, 4, "%d", rc); - return card ; - } - static void qeth_l3_stop_card(struct qeth_card *card, int recovery_mode) { QETH_DBF_TEXT(SETUP, 2, "stopcard"); @@@ -2004,7 -1850,7 +1850,7 @@@ static int qeth_l3_query_arp_cache_info prot); if (!iob) return -ENOMEM; - cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + cmd = __ipa_cmd(iob); cmd->data.setassparms.data.query_arp.request_bits = 0x000F; cmd->data.setassparms.data.query_arp.reply_bits = 0; cmd->data.setassparms.data.query_arp.no_entries = 0; @@@ -2785,14 -2631,16 +2631,16 @@@ static int qeth_l3_setup_netdev(struct if (!(card->info.unique_id & UNIQUE_ID_NOT_BY_CARD)) card->dev->dev_id = card->info.unique_id & 0xffff; + + card->dev->hw_features |= NETIF_F_SG; + card->dev->vlan_features |= NETIF_F_SG; + if (!card->info.guestlan) { - card->dev->hw_features = NETIF_F_SG | - NETIF_F_RXCSUM | NETIF_F_IP_CSUM | - NETIF_F_TSO; - card->dev->vlan_features = NETIF_F_SG | - NETIF_F_RXCSUM | NETIF_F_IP_CSUM | - NETIF_F_TSO; card->dev->features |= NETIF_F_SG; + card->dev->hw_features |= NETIF_F_TSO | + NETIF_F_RXCSUM | NETIF_F_IP_CSUM; + card->dev->vlan_features |= NETIF_F_TSO | + NETIF_F_RXCSUM | NETIF_F_IP_CSUM; } } } else if (card->info.type == QETH_CARD_TYPE_IQD) { @@@ -2865,8 -2713,8 +2713,8 @@@ static void qeth_l3_remove_device(struc qeth_l3_set_offline(cgdev);
if (card->dev) { - netif_napi_del(&card->napi); unregister_netdev(card->dev); + free_netdev(card->dev); card->dev = NULL; }
@@@ -2907,7 -2755,6 +2755,6 @@@ static int __qeth_l3_set_online(struct card->info.hwtrap = 0;
card->state = CARD_STATE_HARDSETUP; - memset(&card->rx, 0, sizeof(struct qeth_rx)); qeth_print_status_message(card);
/* softsetup */ @@@ -3130,13 -2977,43 +2977,43 @@@ struct qeth_discipline qeth_l3_discipli }; EXPORT_SYMBOL_GPL(qeth_l3_discipline);
+ static int qeth_l3_handle_ip_event(struct qeth_card *card, + struct qeth_ipaddr *addr, + unsigned long event) + { + switch (event) { + case NETDEV_UP: + spin_lock_bh(&card->ip_lock); + qeth_l3_add_ip(card, addr); + spin_unlock_bh(&card->ip_lock); + return NOTIFY_OK; + case NETDEV_DOWN: + spin_lock_bh(&card->ip_lock); + qeth_l3_delete_ip(card, addr); + spin_unlock_bh(&card->ip_lock); + return NOTIFY_OK; + default: + return NOTIFY_DONE; + } + } + + static struct qeth_card *qeth_l3_get_card_from_dev(struct net_device *dev) + { + if (is_vlan_dev(dev)) + dev = vlan_dev_real_dev(dev); + if (dev->netdev_ops == &qeth_l3_osa_netdev_ops || + dev->netdev_ops == &qeth_l3_netdev_ops) + return (struct qeth_card *) dev->ml_priv; + return NULL; + } + static int qeth_l3_ip_event(struct notifier_block *this, unsigned long event, void *ptr) {
struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; - struct net_device *dev = (struct net_device *)ifa->ifa_dev->dev; - struct qeth_ipaddr *addr; + struct net_device *dev = ifa->ifa_dev->dev; + struct qeth_ipaddr addr; struct qeth_card *card;
if (dev_net(dev) != &init_net) @@@ -3147,29 -3024,11 +3024,11 @@@ return NOTIFY_DONE; QETH_CARD_TEXT(card, 3, "ipevent");
- addr = qeth_l3_get_addr_buffer(QETH_PROT_IPV4); - if (addr) { - addr->u.a4.addr = be32_to_cpu(ifa->ifa_address); - addr->u.a4.mask = be32_to_cpu(ifa->ifa_mask); - addr->type = QETH_IP_TYPE_NORMAL; - } else - return NOTIFY_DONE; - - switch (event) { - case NETDEV_UP: - spin_lock_bh(&card->ip_lock); - qeth_l3_add_ip(card, addr); - spin_unlock_bh(&card->ip_lock); - break; - case NETDEV_DOWN: - spin_lock_bh(&card->ip_lock); - qeth_l3_delete_ip(card, addr); - spin_unlock_bh(&card->ip_lock); - break; - } + qeth_l3_init_ipaddr(&addr, QETH_IP_TYPE_NORMAL, QETH_PROT_IPV4); + addr.u.a4.addr = be32_to_cpu(ifa->ifa_address); + addr.u.a4.mask = be32_to_cpu(ifa->ifa_mask);
- kfree(addr); - return NOTIFY_DONE; + return qeth_l3_handle_ip_event(card, &addr, event); }
static struct notifier_block qeth_l3_ip_notifier = { @@@ -3181,8 -3040,8 +3040,8 @@@ static int qeth_l3_ip6_event(struct not unsigned long event, void *ptr) { struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr; - struct net_device *dev = (struct net_device *)ifa->idev->dev; - struct qeth_ipaddr *addr; + struct net_device *dev = ifa->idev->dev; + struct qeth_ipaddr addr; struct qeth_card *card;
card = qeth_l3_get_card_from_dev(dev); @@@ -3192,29 -3051,11 +3051,11 @@@ if (!qeth_is_supported(card, IPA_IPV6)) return NOTIFY_DONE;
- addr = qeth_l3_get_addr_buffer(QETH_PROT_IPV6); - if (addr) { - memcpy(&addr->u.a6.addr, &ifa->addr, sizeof(struct in6_addr)); - addr->u.a6.pfxlen = ifa->prefix_len; - addr->type = QETH_IP_TYPE_NORMAL; - } else - return NOTIFY_DONE; - - switch (event) { - case NETDEV_UP: - spin_lock_bh(&card->ip_lock); - qeth_l3_add_ip(card, addr); - spin_unlock_bh(&card->ip_lock); - break; - case NETDEV_DOWN: - spin_lock_bh(&card->ip_lock); - qeth_l3_delete_ip(card, addr); - spin_unlock_bh(&card->ip_lock); - break; - } + qeth_l3_init_ipaddr(&addr, QETH_IP_TYPE_NORMAL, QETH_PROT_IPV6); + addr.u.a6.addr = ifa->addr; + addr.u.a6.pfxlen = ifa->prefix_len;
- kfree(addr); - return NOTIFY_DONE; + return qeth_l3_handle_ip_event(card, &addr, event); }
static struct notifier_block qeth_l3_ip6_notifier = { diff --combined drivers/vhost/net.c index 8139bc70ad7d,b5fb56b822fd..a31d9b240af8 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@@ -170,7 -170,7 +170,7 @@@ static void vhost_net_buf_unproduce(str if (nvq->rx_ring && !vhost_net_buf_is_empty(rxq)) { ptr_ring_unconsume(nvq->rx_ring, rxq->queue + rxq->head, vhost_net_buf_get_size(rxq), - __skb_array_destroy_skb); + tun_ptr_free); rxq->head = rxq->tail = 0; } } @@@ -948,7 -948,6 +948,7 @@@ static int vhost_net_open(struct inode n->vqs[i].done_idx = 0; n->vqs[i].vhost_hlen = 0; n->vqs[i].sock_hlen = 0; + n->vqs[i].rx_ring = NULL; vhost_net_buf_init(&n->vqs[i].rxq); } vhost_dev_init(dev, vqs, VHOST_NET_VQ_MAX); @@@ -973,7 -972,6 +973,7 @@@ static struct socket *vhost_net_stop_vq vhost_net_disable_vq(n, vq); vq->private_data = NULL; vhost_net_buf_unproduce(nvq); + nvq->rx_ring = NULL; mutex_unlock(&vq->mutex); return sock; } @@@ -1040,7 -1038,7 +1040,7 @@@ static struct socket *get_raw_socket(in struct sockaddr_ll sa; char buf[MAX_ADDR_LEN]; } uaddr; - int uaddr_len = sizeof uaddr, r; + int r; struct socket *sock = sockfd_lookup(fd, &r);
if (!sock) @@@ -1052,9 -1050,8 +1052,8 @@@ goto err; }
- r = sock->ops->getname(sock, (struct sockaddr *)&uaddr.sa, - &uaddr_len, 0); - if (r) + r = sock->ops->getname(sock, (struct sockaddr *)&uaddr.sa, 0); + if (r < 0) goto err;
if (uaddr.sa.sll_family != AF_PACKET) { @@@ -1163,14 -1160,14 +1162,14 @@@ static long vhost_net_set_backend(struc vhost_net_disable_vq(n, vq); vq->private_data = sock; vhost_net_buf_unproduce(nvq); - if (index == VHOST_NET_VQ_RX) - nvq->rx_ring = get_tap_ptr_ring(fd); r = vhost_vq_init_access(vq); if (r) goto err_used; r = vhost_net_enable_vq(n, vq); if (r) goto err_used; + if (index == VHOST_NET_VQ_RX) + nvq->rx_ring = get_tap_ptr_ring(fd);
oldubufs = nvq->ubufs; nvq->ubufs = ubufs; diff --combined fs/lockd/svc.c index 346ed161756d,2dee4e03ff1c..3a4f1a1f48e4 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@@ -57,8 -57,8 +57,8 @@@ static struct task_struct *nlmsvc_task static struct svc_rqst *nlmsvc_rqst; unsigned long nlmsvc_timeout;
-atomic_t nlm_ntf_refcnt = ATOMIC_INIT(0); -DECLARE_WAIT_QUEUE_HEAD(nlm_ntf_wq); +static atomic_t nlm_ntf_refcnt = ATOMIC_INIT(0); +static DECLARE_WAIT_QUEUE_HEAD(nlm_ntf_wq);
unsigned int lockd_net_id;
@@@ -709,6 -709,7 +709,7 @@@ static struct pernet_operations lockd_n .exit = lockd_exit_net, .id = &lockd_net_id, .size = sizeof(struct lockd_net), + .async = true, };
diff --combined include/linux/net.h index 2a0391eea05c,000d1aada74f..2248a052061d --- a/include/linux/net.h +++ b/include/linux/net.h @@@ -146,7 -146,7 +146,7 @@@ struct proto_ops struct socket *newsock, int flags, bool kern); int (*getname) (struct socket *sock, struct sockaddr *addr, - int *sockaddr_len, int peer); + int peer); __poll_t (*poll) (struct file *file, struct socket *sock, struct poll_table_struct *wait); int (*ioctl) (struct socket *sock, unsigned int cmd, @@@ -222,7 -222,6 +222,7 @@@ enum int sock_wake_async(struct socket_wq *sk_wq, int how, int band); int sock_register(const struct net_proto_family *fam); void sock_unregister(int family); +bool sock_is_registered(int family); int __sock_create(struct net *net, int family, int type, int proto, struct socket **res, int kern); int sock_create(int family, int type, int proto, struct socket **res); @@@ -295,10 -294,8 +295,8 @@@ int kernel_listen(struct socket *sock, int kernel_accept(struct socket *sock, struct socket **newsock, int flags); int kernel_connect(struct socket *sock, struct sockaddr *addr, int addrlen, int flags); - int kernel_getsockname(struct socket *sock, struct sockaddr *addr, - int *addrlen); - int kernel_getpeername(struct socket *sock, struct sockaddr *addr, - int *addrlen); + int kernel_getsockname(struct socket *sock, struct sockaddr *addr); + int kernel_getpeername(struct socket *sock, struct sockaddr *addr); int kernel_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen); int kernel_setsockopt(struct socket *sock, int level, int optname, char *optval, diff --combined include/linux/phy.h index 7c4c2379e010,5a9b1753fdc5..f0b5870a6d40 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@@ -984,10 -984,6 +984,10 @@@ static inline int genphy_no_soft_reset( { return 0; } +int genphy_read_mmd_unsupported(struct phy_device *phdev, int devad, + u16 regnum); +int genphy_write_mmd_unsupported(struct phy_device *phdev, int devnum, + u16 regnum, u16 val);
/* Clause 45 PHY */ int genphy_c45_restart_aneg(struct phy_device *phydev); @@@ -999,6 -995,14 +999,14 @@@ int genphy_c45_pma_setup_forced(struct int genphy_c45_an_disable_aneg(struct phy_device *phydev); int genphy_c45_read_mdix(struct phy_device *phydev);
+ /* The gen10g_* functions are the old Clause 45 stub */ + int gen10g_config_aneg(struct phy_device *phydev); + int gen10g_read_status(struct phy_device *phydev); + int gen10g_no_soft_reset(struct phy_device *phydev); + int gen10g_config_init(struct phy_device *phydev); + int gen10g_suspend(struct phy_device *phydev); + int gen10g_resume(struct phy_device *phydev); + static inline int phy_read_status(struct phy_device *phydev) { if (!phydev->drv) @@@ -1016,6 -1020,7 +1024,6 @@@ int phy_driver_register(struct phy_driv int phy_drivers_register(struct phy_driver *new_driver, int n, struct module *owner); void phy_state_machine(struct work_struct *work); -void phy_change(struct phy_device *phydev); void phy_change_work(struct work_struct *work); void phy_mac_interrupt(struct phy_device *phydev); void phy_start_machine(struct phy_device *phydev); diff --combined include/linux/skbuff.h index 99df17109e1b,d8340e6e8814..47082f54ec1f --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@@ -466,6 -466,9 +466,9 @@@ struct ubuf_info
#define skb_uarg(SKB) ((struct ubuf_info *)(skb_shinfo(SKB)->destructor_arg))
+ int mm_account_pinned_pages(struct mmpin *mmp, size_t size); + void mm_unaccount_pinned_pages(struct mmpin *mmp); + struct ubuf_info *sock_zerocopy_alloc(struct sock *sk, size_t size); struct ubuf_info *sock_zerocopy_realloc(struct sock *sk, size_t size, struct ubuf_info *uarg); @@@ -4037,12 -4040,6 +4040,12 @@@ static inline bool skb_is_gso_v6(const return skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6; }
+/* Note: Should be called only if skb_is_gso(skb) is true */ +static inline bool skb_is_gso_sctp(const struct sk_buff *skb) +{ + return skb_shinfo(skb)->gso_type & SKB_GSO_SCTP; +} + static inline void skb_gso_reset(struct sk_buff *skb) { skb_shinfo(skb)->gso_size = 0; @@@ -4050,22 -4047,6 +4053,22 @@@ skb_shinfo(skb)->gso_type = 0; }
+static inline void skb_increase_gso_size(struct skb_shared_info *shinfo, + u16 increment) +{ + if (WARN_ON_ONCE(shinfo->gso_size == GSO_BY_FRAGS)) + return; + shinfo->gso_size += increment; +} + +static inline void skb_decrease_gso_size(struct skb_shared_info *shinfo, + u16 decrement) +{ + if (WARN_ON_ONCE(shinfo->gso_size == GSO_BY_FRAGS)) + return; + shinfo->gso_size -= decrement; +} + void __skb_warn_lro_forwarding(const struct sk_buff *skb);
static inline bool skb_warn_if_lro(const struct sk_buff *skb) diff --combined include/linux/socket.h index e2b6bd4fe977,60e01482a9c4..1acf827850cc --- a/include/linux/socket.h +++ b/include/linux/socket.h @@@ -287,6 -287,7 +287,7 @@@ struct ucred #define MSG_SENDPAGE_NOTLAST 0x20000 /* sendpage() internal : not the last page */ #define MSG_BATCH 0x40000 /* sendmmsg(): more messages coming */ #define MSG_EOF MSG_FIN + #define MSG_NO_SHARED_FRAGS 0x80000 /* sendpage() internal : page frags are not shared */
#define MSG_ZEROCOPY 0x4000000 /* Use user data in kernel path */ #define MSG_FASTOPEN 0x20000000 /* Send data in TCP SYN */ @@@ -346,40 -347,13 +347,41 @@@ extern int put_cmsg(struct msghdr*, in
struct timespec;
-/* The __sys_...msg variants allow MSG_CMSG_COMPAT */ -extern long __sys_recvmsg(int fd, struct user_msghdr __user *msg, unsigned flags); -extern long __sys_sendmsg(int fd, struct user_msghdr __user *msg, unsigned flags); +/* The __sys_...msg variants allow MSG_CMSG_COMPAT iff + * forbid_cmsg_compat==false + */ +extern long __sys_recvmsg(int fd, struct user_msghdr __user *msg, + unsigned int flags, bool forbid_cmsg_compat); +extern long __sys_sendmsg(int fd, struct user_msghdr __user *msg, + unsigned int flags, bool forbid_cmsg_compat); extern int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, unsigned int flags, struct timespec *timeout); extern int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, - unsigned int vlen, unsigned int flags); + unsigned int vlen, unsigned int flags, + bool forbid_cmsg_compat); + +/* helpers which do the actual work for syscalls */ +extern int __sys_recvfrom(int fd, void __user *ubuf, size_t size, + unsigned int flags, struct sockaddr __user *addr, + int __user *addr_len); +extern int __sys_sendto(int fd, void __user *buff, size_t len, + unsigned int flags, struct sockaddr __user *addr, + int addr_len); +extern int __sys_accept4(int fd, struct sockaddr __user *upeer_sockaddr, + int __user *upeer_addrlen, int flags); +extern int __sys_socket(int family, int type, int protocol); +extern int __sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen); +extern int __sys_connect(int fd, struct sockaddr __user *uservaddr, + int addrlen); +extern int __sys_listen(int fd, int backlog); +extern int __sys_getsockname(int fd, struct sockaddr __user *usockaddr, + int __user *usockaddr_len); +extern int __sys_getpeername(int fd, struct sockaddr __user *usockaddr, + int __user *usockaddr_len); +extern int __sys_socketpair(int family, int type, int protocol, + int __user *usockvec); +extern int __sys_shutdown(int fd, int how); +
+ extern struct ns_common *get_net_ns(struct ns_common *ns); #endif /* _LINUX_SOCKET_H */ diff --combined include/net/ip.h index f49b3a576bec,d53b5a9eae34..36f8f7811093 --- a/include/net/ip.h +++ b/include/net/ip.h @@@ -91,6 -91,17 +91,17 @@@ static inline int inet_sdif(struct sk_b return 0; }
+ /* Special input handler for packets caught by router alert option. + They are selected only by protocol field, and then processed likely + local ones; but only if someone wants them! Otherwise, router + not running rsvpd will kill RSVP. + + It is user level problem, what it will make with them. + I have no idea, how it will masquearde or NAT them (it is joke, joke :-)), + but receiver should be enough clever f.e. to forward mtrace requests, + sent to multicast group to reach destination designated router. + */ + struct ip_ra_chain { struct ip_ra_chain __rcu *next; struct sock *sk; @@@ -101,8 -112,6 +112,6 @@@ struct rcu_head rcu; };
- extern struct ip_ra_chain __rcu *ip_ra_chain; - /* IP flags. */ #define IP_CE 0x8000 /* Flag: "Congestion" */ #define IP_DF 0x4000 /* Flag: "Don't Fragment" */ @@@ -186,15 -195,15 +195,15 @@@ int ip4_datagram_connect(struct sock *s void ip4_datagram_release_cb(struct sock *sk);
struct ip_reply_arg { - struct kvec iov[1]; + struct kvec iov[1]; int flags; __wsum csum; int csumoffset; /* u16 offset of csum in iov[0].iov_base */ - /* -1 if not needed */ + /* -1 if not needed */ int bound_dev_if; u8 tos; kuid_t uid; - }; + };
#define IP_REPLY_ARG_NOSRCCHECK 1
@@@ -328,13 -337,6 +337,13 @@@ int ip_decrease_ttl(struct iphdr *iph return --iph->ttl; }
+static inline int ip_mtu_locked(const struct dst_entry *dst) +{ + const struct rtable *rt = (const struct rtable *)dst; + + return rt->rt_mtu_locked || dst_metric_locked(dst, RTAX_MTU); +} + static inline int ip_dont_fragment(const struct sock *sk, const struct dst_entry *dst) { @@@ -342,7 -344,7 +351,7 @@@
return pmtudisc == IP_PMTUDISC_DO || (pmtudisc == IP_PMTUDISC_WANT && - !(dst_metric_locked(dst, RTAX_MTU))); + !ip_mtu_locked(dst)); }
static inline bool ip_sk_accept_pmtu(const struct sock *sk) @@@ -368,7 -370,7 +377,7 @@@ static inline unsigned int ip_dst_mtu_m struct net *net = dev_net(dst->dev);
if (net->ipv4.sysctl_ip_fwd_use_pmtu || - dst_metric_locked(dst, RTAX_MTU) || + ip_mtu_locked(dst) || !forwarding) return dst_mtu(dst);
@@@ -584,13 -586,13 +593,13 @@@ int ip_frag_mem(struct net *net) /* * Functions provided by ip_forward.c */ - + int ip_forward(struct sk_buff *skb); - + /* * Functions provided by ip_options.c */ - + void ip_options_build(struct sk_buff *skb, struct ip_options *opt, __be32 daddr, struct rtable *rt, int is_frag);
diff --combined include/net/ip6_route.h index ac0866bb9e93,ce2abc0ff102..0084013d6bed --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@@ -75,7 -75,8 +75,8 @@@ static inline bool rt6_qualify_for_ecmp void ip6_route_input(struct sk_buff *skb); struct dst_entry *ip6_route_input_lookup(struct net *net, struct net_device *dev, - struct flowi6 *fl6, int flags); + struct flowi6 *fl6, + const struct sk_buff *skb, int flags);
struct dst_entry *ip6_route_output_flags(struct net *net, const struct sock *sk, struct flowi6 *fl6, int flags); @@@ -88,9 -89,10 +89,10 @@@ static inline struct dst_entry *ip6_rou }
struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6, - int flags); + const struct sk_buff *skb, int flags); struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, - int ifindex, struct flowi6 *fl6, int flags); + int ifindex, struct flowi6 *fl6, + const struct sk_buff *skb, int flags);
void ip6_route_init_special_entries(void); int ip6_route_init(void); @@@ -126,8 -128,10 +128,10 @@@ static inline int ip6_route_get_saddr(s }
struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr, - const struct in6_addr *saddr, int oif, int flags); - u32 rt6_multipath_hash(const struct flowi6 *fl6, const struct sk_buff *skb); + const struct in6_addr *saddr, int oif, + const struct sk_buff *skb, int flags); + u32 rt6_multipath_hash(const struct net *net, const struct flowi6 *fl6, + const struct sk_buff *skb, struct flow_keys *hkeys);
struct dst_entry *icmp6_dst_alloc(struct net_device *dev, struct flowi6 *fl6);
@@@ -179,9 -183,6 +183,9 @@@ void rt6_disable_ip(struct net_device * void rt6_sync_down_dev(struct net_device *dev, unsigned long event); void rt6_multipath_rebalance(struct rt6_info *rt);
+void rt6_uncached_list_add(struct rt6_info *rt); +void rt6_uncached_list_del(struct rt6_info *rt); + static inline const struct rt6_info *skb_rt6_info(const struct sk_buff *skb) { const struct dst_entry *dst = skb_dst(skb); @@@ -269,4 -270,5 +273,5 @@@ static inline bool rt6_duplicate_nextho ipv6_addr_equal(&a->rt6i_gateway, &b->rt6i_gateway) && !lwtunnel_cmp_encap(a->dst.lwtstate, b->dst.lwtstate); } + #endif diff --combined include/net/ip_fib.h index 77d0a78cf7d2,7c7522e8585b..81d0f2107ff1 --- a/include/net/ip_fib.h +++ b/include/net/ip_fib.h @@@ -59,7 -59,6 +59,7 @@@ struct fib_nh_exception int fnhe_genid; __be32 fnhe_daddr; u32 fnhe_pmtu; + bool fnhe_mtu_locked; __be32 fnhe_gw; unsigned long fnhe_expires; struct rtable __rcu *fnhe_rth_input; @@@ -158,7 -157,7 +158,7 @@@ struct fib_result_nl unsigned char nh_sel; unsigned char type; unsigned char scope; - int err; + int err; };
#ifdef CONFIG_IP_ROUTE_MULTIPATH @@@ -294,6 -293,13 +294,13 @@@ static inline unsigned int fib4_rules_s return 0; }
+ static inline bool fib4_rules_early_flow_dissect(struct net *net, + struct sk_buff *skb, + struct flowi4 *fl4, + struct flow_keys *flkeys) + { + return false; + } #else /* CONFIG_IP_MULTIPLE_TABLES */ int __net_init fib4_rules_init(struct net *net); void __net_exit fib4_rules_exit(struct net *net); @@@ -342,6 -348,24 +349,24 @@@ bool fib4_rule_default(const struct fib int fib4_rules_dump(struct net *net, struct notifier_block *nb); unsigned int fib4_rules_seq_read(struct net *net);
+ static inline bool fib4_rules_early_flow_dissect(struct net *net, + struct sk_buff *skb, + struct flowi4 *fl4, + struct flow_keys *flkeys) + { + unsigned int flag = FLOW_DISSECTOR_F_STOP_AT_ENCAP; + + if (!net->ipv4.fib_rules_require_fldissect) + return false; + + skb_flow_dissect_flow_keys(skb, flkeys, flag); + fl4->fl4_sport = flkeys->ports.src; + fl4->fl4_dport = flkeys->ports.dst; + fl4->flowi4_proto = flkeys->basic.ip_proto; + + return true; + } + #endif /* CONFIG_IP_MULTIPLE_TABLES */
/* Exported by fib_frontend.c */ @@@ -371,8 -395,8 +396,8 @@@ int fib_sync_down_addr(struct net_devic int fib_sync_up(struct net_device *dev, unsigned int nh_flags);
#ifdef CONFIG_IP_ROUTE_MULTIPATH - int fib_multipath_hash(const struct fib_info *fi, const struct flowi4 *fl4, - const struct sk_buff *skb); + int fib_multipath_hash(const struct net *net, const struct flowi4 *fl4, + const struct sk_buff *skb, struct flow_keys *flkeys); #endif void fib_select_multipath(struct fib_result *res, int hash); void fib_select_path(struct net *net, struct fib_result *res, diff --combined include/net/mac80211.h index 2b581bd93812,2fd59ed3be00..385c41c5ce95 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@@ -6,6 -6,7 +6,7 @@@ * Copyright 2007-2010 Johannes Berg johannes@sipsolutions.net * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015 - 2017 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@@ -934,6 -935,7 +935,7 @@@ struct ieee80211_tx_info u8 ampdu_len; u8 antenna; u16 tx_time; + bool is_valid_ack_signal; void *status_driver_data[19 / sizeof(void *)]; } status; struct { @@@ -1098,6 -1100,9 +1100,9 @@@ ieee80211_tx_info_clear_status(struct i * the first subframe. * @RX_FLAG_ICV_STRIPPED: The ICV is stripped from this frame. CRC checking must * be done in the hardware. + * @RX_FLAG_AMPDU_EOF_BIT: Value of the EOF bit in the A-MPDU delimiter for this + * frame + * @RX_FLAG_AMPDU_EOF_BIT_KNOWN: The EOF value is known */ enum mac80211_rx_flags { RX_FLAG_MMIC_ERROR = BIT(0), @@@ -1124,6 -1129,8 +1129,8 @@@ RX_FLAG_MIC_STRIPPED = BIT(21), RX_FLAG_ALLOW_SAME_PN = BIT(22), RX_FLAG_ICV_STRIPPED = BIT(23), + RX_FLAG_AMPDU_EOF_BIT = BIT(24), + RX_FLAG_AMPDU_EOF_BIT_KNOWN = BIT(25), };
/** @@@ -2063,9 -2070,14 +2070,17 @@@ struct ieee80211_txq * @IEEE80211_HW_SUPPORTS_TDLS_BUFFER_STA: Hardware supports buffer STA on * TDLS links. * + * @IEEE80211_HW_DOESNT_SUPPORT_QOS_NDP: The driver (or firmware) doesn't + * support QoS NDP for AP probing - that's most likely a driver bug. + * + * @IEEE80211_HW_DEAUTH_NEED_MGD_TX_PREP: The driver requires the + * mgd_prepare_tx() callback to be called before transmission of a + * deauthentication frame in case the association was completed but no + * beacon was heard. This is required in multi-channel scenarios, where the + * virtual interface might not be given air time for the transmission of + * the frame, as it is not synced with the AP/P2P GO yet, and thus the + * deauthentication frame might not be transmitted. + * * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays */ enum ieee80211_hw_flags { @@@ -2109,7 -2121,7 +2124,8 @@@ IEEE80211_HW_REPORTS_LOW_ACK, IEEE80211_HW_SUPPORTS_TX_FRAG, IEEE80211_HW_SUPPORTS_TDLS_BUFFER_STA, + IEEE80211_HW_DOESNT_SUPPORT_QOS_NDP, + IEEE80211_HW_DEAUTH_NEED_MGD_TX_PREP,
/* keep last, obviously */ NUM_IEEE80211_HW_FLAGS @@@ -3354,6 -3366,9 +3370,9 @@@ enum ieee80211_reconfig_type * management frame prior to having successfully associated to allow the * driver to give it channel time for the transmission, to get a response * and to be able to synchronize with the GO. + * For drivers that set %IEEE80211_HW_DEAUTH_NEED_MGD_TX_PREP, mac80211 + * would also call this function before transmitting a deauthentication + * frame in case that no beacon was heard from the AP/P2P GO. * The callback will be called before each transmission and upon return * mac80211 will transmit the frame right away. * The callback is optional and can (should!) sleep. diff --combined include/net/route.h index 20a92ca9e115,158833ea7988..dbb032d5921b --- a/include/net/route.h +++ b/include/net/route.h @@@ -63,11 -63,8 +63,9 @@@ struct rtable __be32 rt_gateway;
/* Miscellaneous cached information */ - u32 rt_pmtu; + u32 rt_mtu_locked:1, + rt_pmtu:31;
- u32 rt_table_id; - struct list_head rt_uncached; struct uncached_list *rt_uncached_list; }; @@@ -228,9 -225,6 +226,9 @@@ struct in_ifaddr void fib_add_ifaddr(struct in_ifaddr *); void fib_del_ifaddr(struct in_ifaddr *, struct in_ifaddr *);
+void rt_add_uncached_list(struct rtable *rt); +void rt_del_uncached_list(struct rtable *rt); + static inline void ip_rt_put(struct rtable *rt) { /* dst_release() accepts a NULL parameter. diff --combined include/net/sch_generic.h index 2092d33194dd,d4907b584b38..493e311bbe93 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@@ -540,7 -540,7 +540,7 @@@ static inline bool skb_skip_tc_classify return false; }
- /* Reset all TX qdiscs greater then index of a device. */ + /* Reset all TX qdiscs greater than index of a device. */ static inline void qdisc_reset_all_tx_gt(struct net_device *dev, unsigned int i) { struct Qdisc *qdisc; @@@ -824,16 -824,6 +824,16 @@@ static inline void __qdisc_drop(struct *to_free = skb; }
+static inline void __qdisc_drop_all(struct sk_buff *skb, + struct sk_buff **to_free) +{ + if (skb->prev) + skb->prev->next = *to_free; + else + skb->next = *to_free; + *to_free = skb; +} + static inline unsigned int __qdisc_queue_drop_head(struct Qdisc *sch, struct qdisc_skb_head *qh, struct sk_buff **to_free) @@@ -966,15 -956,6 +966,15 @@@ static inline int qdisc_drop(struct sk_ return NET_XMIT_DROP; }
+static inline int qdisc_drop_all(struct sk_buff *skb, struct Qdisc *sch, + struct sk_buff **to_free) +{ + __qdisc_drop_all(skb, to_free); + qdisc_qstats_drop(sch); + + return NET_XMIT_DROP; +} + /* Length to Time (L2T) lookup in a qdisc_rate_table, to determine how long it will take to send a packet given its size. */ diff --combined include/net/sock.h index ae23f3b389ca,b7c75e024e37..709311132d4c --- a/include/net/sock.h +++ b/include/net/sock.h @@@ -417,6 -417,7 +417,7 @@@ struct sock struct page_frag sk_frag; netdev_features_t sk_route_caps; netdev_features_t sk_route_nocaps; + netdev_features_t sk_route_forced_caps; int sk_gso_type; unsigned int sk_gso_max_size; gfp_t sk_allocation; @@@ -1137,7 -1138,6 +1138,7 @@@ struct proto
int proto_register(struct proto *prot, int alloc_slab); void proto_unregister(struct proto *prot); +int sock_load_diag_module(int family, int protocol);
#ifdef SOCK_REFCNT_DEBUG static inline void sk_refcnt_debug_inc(struct sock *sk) @@@ -1585,7 -1585,7 +1586,7 @@@ int sock_no_bind(struct socket *, struc int sock_no_connect(struct socket *, struct sockaddr *, int, int); int sock_no_socketpair(struct socket *, struct socket *); int sock_no_accept(struct socket *, struct socket *, int, bool); - int sock_no_getname(struct socket *, struct sockaddr *, int *, int); + int sock_no_getname(struct socket *, struct sockaddr *, int); __poll_t sock_no_poll(struct file *, struct socket *, struct poll_table_struct *); int sock_no_ioctl(struct socket *, unsigned int, unsigned long); @@@ -1863,15 -1863,6 +1864,6 @@@ static inline void sk_nocaps_add(struc sk->sk_route_caps &= ~flags; }
- static inline bool sk_check_csum_caps(struct sock *sk) - { - return (sk->sk_route_caps & NETIF_F_HW_CSUM) || - (sk->sk_family == PF_INET && - (sk->sk_route_caps & NETIF_F_IP_CSUM)) || - (sk->sk_family == PF_INET6 && - (sk->sk_route_caps & NETIF_F_IPV6_CSUM)); - } - static inline int skb_do_copy_data_nocache(struct sock *sk, struct sk_buff *skb, struct iov_iter *from, char *to, int copy, int offset) @@@ -2150,6 -2141,10 +2142,10 @@@ static inline struct page_frag *sk_page
bool sk_page_frag_refill(struct sock *sk, struct page_frag *pfrag);
+ int sk_alloc_sg(struct sock *sk, int len, struct scatterlist *sg, + int sg_start, int *sg_curr, unsigned int *sg_size, + int first_coalesce); + /* * Default write policy as shown to user space via poll/select/SIGIO */ diff --combined include/uapi/linux/if_ether.h index 820de5d222d2,2e4a6c1accaa..3a45b4ad71a3 --- a/include/uapi/linux/if_ether.h +++ b/include/uapi/linux/if_ether.h @@@ -30,7 -30,6 +30,7 @@@ */
#define ETH_ALEN 6 /* Octets in one ethernet addr */ +#define ETH_TLEN 2 /* Octets in ethernet type field */ #define ETH_HLEN 14 /* Total octets in header. */ #define ETH_ZLEN 60 /* Min. octets in frame sans FCS */ #define ETH_DATA_LEN 1500 /* Max. octets in payload */ @@@ -89,6 -88,7 +89,7 @@@ #define ETH_P_AOE 0x88A2 /* ATA over Ethernet */ #define ETH_P_8021AD 0x88A8 /* 802.1ad Service VLAN */ #define ETH_P_802_EX1 0x88B5 /* 802.1 Local Experimental 1. */ + #define ETH_P_PREAUTH 0x88C7 /* 802.11 Preauthentication */ #define ETH_P_TIPC 0x88CA /* TIPC */ #define ETH_P_MACSEC 0x88E5 /* 802.1ae MACsec */ #define ETH_P_8021AH 0x88E7 /* 802.1ah Backbone Service Tag */ diff --combined kernel/bpf/syscall.c index 0295c95eb2f6,3aeb4ea2a93a..2f0c569fccb2 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@@ -1315,7 -1315,8 +1315,8 @@@ static int bpf_obj_get(const union bpf_
#define BPF_PROG_ATTACH_LAST_FIELD attach_flags
- static int sockmap_get_from_fd(const union bpf_attr *attr, bool attach) + static int sockmap_get_from_fd(const union bpf_attr *attr, + int type, bool attach) { struct bpf_prog *prog = NULL; int ufd = attr->target_fd; @@@ -1329,8 -1330,7 +1330,7 @@@ return PTR_ERR(map);
if (attach) { - prog = bpf_prog_get_type(attr->attach_bpf_fd, - BPF_PROG_TYPE_SK_SKB); + prog = bpf_prog_get_type(attr->attach_bpf_fd, type); if (IS_ERR(prog)) { fdput(f); return PTR_ERR(prog); @@@ -1382,9 -1382,11 +1382,11 @@@ static int bpf_prog_attach(const union case BPF_CGROUP_DEVICE: ptype = BPF_PROG_TYPE_CGROUP_DEVICE; break; + case BPF_SK_MSG_VERDICT: + return sockmap_get_from_fd(attr, BPF_PROG_TYPE_SK_MSG, true); case BPF_SK_SKB_STREAM_PARSER: case BPF_SK_SKB_STREAM_VERDICT: - return sockmap_get_from_fd(attr, true); + return sockmap_get_from_fd(attr, BPF_PROG_TYPE_SK_SKB, true); default: return -EINVAL; } @@@ -1437,9 -1439,11 +1439,11 @@@ static int bpf_prog_detach(const union case BPF_CGROUP_DEVICE: ptype = BPF_PROG_TYPE_CGROUP_DEVICE; break; + case BPF_SK_MSG_VERDICT: + return sockmap_get_from_fd(attr, BPF_PROG_TYPE_SK_MSG, false); case BPF_SK_SKB_STREAM_PARSER: case BPF_SK_SKB_STREAM_VERDICT: - return sockmap_get_from_fd(attr, false); + return sockmap_get_from_fd(attr, BPF_PROG_TYPE_SK_SKB, false); default: return -EINVAL; } @@@ -1845,10 -1849,7 +1849,10 @@@ SYSCALL_DEFINE3(bpf, int, cmd, union bp union bpf_attr attr = {}; int err;
- if (!capable(CAP_SYS_ADMIN) && sysctl_unprivileged_bpf_disabled) + if (sysctl_unprivileged_bpf_disabled && !capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (kernel_is_locked_down("BPF")) return -EPERM;
err = check_uarg_tail_zero(uattr, sizeof(attr), size); diff --combined kernel/trace/bpf_trace.c index 01e6b3a38871,c634e093951f..7f9691c86b6e --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@@ -661,41 -661,7 +661,41 @@@ static const struct bpf_func_proto bpf_ .arg3_type = ARG_ANYTHING, };
-BPF_CALL_3(bpf_perf_prog_read_value_tp, struct bpf_perf_event_data_kern *, ctx, +static const struct bpf_func_proto *tp_prog_func_proto(enum bpf_func_id func_id) +{ + switch (func_id) { + case BPF_FUNC_perf_event_output: + return &bpf_perf_event_output_proto_tp; + case BPF_FUNC_get_stackid: + return &bpf_get_stackid_proto_tp; + default: + return tracing_func_proto(func_id); + } +} + +static bool tp_prog_is_valid_access(int off, int size, enum bpf_access_type type, + struct bpf_insn_access_aux *info) +{ + if (off < sizeof(void *) || off >= PERF_MAX_TRACE_SIZE) + return false; + if (type != BPF_READ) + return false; + if (off % size != 0) + return false; + + BUILD_BUG_ON(PERF_MAX_TRACE_SIZE % sizeof(__u64)); + return true; +} + +const struct bpf_verifier_ops tracepoint_verifier_ops = { + .get_func_proto = tp_prog_func_proto, + .is_valid_access = tp_prog_is_valid_access, +}; + +const struct bpf_prog_ops tracepoint_prog_ops = { +}; + +BPF_CALL_3(bpf_perf_prog_read_value, struct bpf_perf_event_data_kern *, ctx, struct bpf_perf_event_value *, buf, u32, size) { int err = -EINVAL; @@@ -712,8 -678,8 +712,8 @@@ clear return err; }
-static const struct bpf_func_proto bpf_perf_prog_read_value_proto_tp = { - .func = bpf_perf_prog_read_value_tp, +static const struct bpf_func_proto bpf_perf_prog_read_value_proto = { + .func = bpf_perf_prog_read_value, .gpl_only = true, .ret_type = RET_INTEGER, .arg1_type = ARG_PTR_TO_CTX, @@@ -721,7 -687,7 +721,7 @@@ .arg3_type = ARG_CONST_SIZE, };
-static const struct bpf_func_proto *tp_prog_func_proto(enum bpf_func_id func_id) +static const struct bpf_func_proto *pe_prog_func_proto(enum bpf_func_id func_id) { switch (func_id) { case BPF_FUNC_perf_event_output: @@@ -729,17 -695,38 +729,16 @@@ case BPF_FUNC_get_stackid: return &bpf_get_stackid_proto_tp; case BPF_FUNC_perf_prog_read_value: - return &bpf_perf_prog_read_value_proto_tp; + return &bpf_perf_prog_read_value_proto; default: return tracing_func_proto(func_id); } }
-static bool tp_prog_is_valid_access(int off, int size, enum bpf_access_type type, - struct bpf_insn_access_aux *info) -{ - if (off < sizeof(void *) || off >= PERF_MAX_TRACE_SIZE) - return false; - if (type != BPF_READ) - return false; - if (off % size != 0) - return false; - - BUILD_BUG_ON(PERF_MAX_TRACE_SIZE % sizeof(__u64)); - return true; -} - -const struct bpf_verifier_ops tracepoint_verifier_ops = { - .get_func_proto = tp_prog_func_proto, - .is_valid_access = tp_prog_is_valid_access, -}; - -const struct bpf_prog_ops tracepoint_prog_ops = { -}; - static bool pe_prog_is_valid_access(int off, int size, enum bpf_access_type type, struct bpf_insn_access_aux *info) { - const int size_sp = FIELD_SIZEOF(struct bpf_perf_event_data, - sample_period); + const int size_u64 = sizeof(u64);
if (off < 0 || off >= sizeof(struct bpf_perf_event_data)) return false; @@@ -750,8 -737,13 +749,13 @@@
switch (off) { case bpf_ctx_range(struct bpf_perf_event_data, sample_period): - bpf_ctx_record_field_size(info, size_sp); - if (!bpf_ctx_narrow_access_ok(off, size, size_sp)) + bpf_ctx_record_field_size(info, size_u64); + if (!bpf_ctx_narrow_access_ok(off, size, size_u64)) + return false; + break; + case bpf_ctx_range(struct bpf_perf_event_data, addr): + bpf_ctx_record_field_size(info, size_u64); + if (!bpf_ctx_narrow_access_ok(off, size, size_u64)) return false; break; default: @@@ -778,6 -770,14 +782,14 @@@ static u32 pe_prog_convert_ctx_access(e bpf_target_off(struct perf_sample_data, period, 8, target_size)); break; + case offsetof(struct bpf_perf_event_data, addr): + *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct bpf_perf_event_data_kern, + data), si->dst_reg, si->src_reg, + offsetof(struct bpf_perf_event_data_kern, data)); + *insn++ = BPF_LDX_MEM(BPF_DW, si->dst_reg, si->dst_reg, + bpf_target_off(struct perf_sample_data, addr, 8, + target_size)); + break; default: *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct bpf_perf_event_data_kern, regs), si->dst_reg, si->src_reg, @@@ -791,7 -791,7 +803,7 @@@ }
const struct bpf_verifier_ops perf_event_verifier_ops = { - .get_func_proto = tp_prog_func_proto, + .get_func_proto = pe_prog_func_proto, .is_valid_access = pe_prog_is_valid_access, .convert_ctx_access = pe_prog_convert_ctx_access, }; diff --combined net/batman-adv/distributed-arp-table.c index 87cd962d28d5,75dda9454ccf..a60bacf7120b --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c @@@ -1,5 -1,5 +1,5 @@@ // SPDX-License-Identifier: GPL-2.0 - /* Copyright (C) 2011-2017 B.A.T.M.A.N. contributors: + /* Copyright (C) 2011-2018 B.A.T.M.A.N. contributors: * * Antonio Quartulli * @@@ -33,6 -33,7 +33,7 @@@ #include <linux/kernel.h> #include <linux/kref.h> #include <linux/list.h> + #include <linux/netlink.h> #include <linux/rculist.h> #include <linux/rcupdate.h> #include <linux/seq_file.h> @@@ -43,13 -44,19 +44,19 @@@ #include <linux/string.h> #include <linux/workqueue.h> #include <net/arp.h> + #include <net/genetlink.h> + #include <net/netlink.h> + #include <net/sock.h> + #include <uapi/linux/batman_adv.h>
#include "bridge_loop_avoidance.h" #include "hard-interface.h" #include "hash.h" #include "log.h" + #include "netlink.h" #include "originator.h" #include "send.h" + #include "soft-interface.h" #include "translation-table.h" #include "tvlv.h"
@@@ -393,7 -400,7 +400,7 @@@ static void batadv_dbg_arp(struct batad batadv_arp_hw_src(skb, hdr_size), &ip_src, batadv_arp_hw_dst(skb, hdr_size), &ip_dst);
- if (hdr_size == 0) + if (hdr_size < sizeof(struct batadv_unicast_packet)) return;
unicast_4addr_packet = (struct batadv_unicast_4addr_packet *)skb->data; @@@ -495,7 -502,7 +502,7 @@@ static bool batadv_is_orig_node_eligibl * the one with the lowest address */ if (tmp_max == max && max_orig_node && - batadv_compare_eth(candidate->orig, max_orig_node->orig) > 0) + batadv_compare_eth(candidate->orig, max_orig_node->orig)) goto out;
ret = true; @@@ -852,6 -859,151 +859,151 @@@ out #endif
/** + * batadv_dat_cache_dump_entry() - dump one entry of the DAT cache table to a + * netlink socket + * @msg: buffer for the message + * @portid: netlink port + * @seq: Sequence number of netlink message + * @dat_entry: entry to dump + * + * Return: 0 or error code. + */ + static int + batadv_dat_cache_dump_entry(struct sk_buff *msg, u32 portid, u32 seq, + struct batadv_dat_entry *dat_entry) + { + int msecs; + void *hdr; + + hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, + NLM_F_MULTI, BATADV_CMD_GET_DAT_CACHE); + if (!hdr) + return -ENOBUFS; + + msecs = jiffies_to_msecs(jiffies - dat_entry->last_update); + + if (nla_put_in_addr(msg, BATADV_ATTR_DAT_CACHE_IP4ADDRESS, + dat_entry->ip) || + nla_put(msg, BATADV_ATTR_DAT_CACHE_HWADDRESS, ETH_ALEN, + dat_entry->mac_addr) || + nla_put_u16(msg, BATADV_ATTR_DAT_CACHE_VID, dat_entry->vid) || + nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS, msecs)) { + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; + } + + genlmsg_end(msg, hdr); + return 0; + } + + /** + * batadv_dat_cache_dump_bucket() - dump one bucket of the DAT cache table to + * a netlink socket + * @msg: buffer for the message + * @portid: netlink port + * @seq: Sequence number of netlink message + * @head: bucket to dump + * @idx_skip: How many entries to skip + * + * Return: 0 or error code. + */ + static int + batadv_dat_cache_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq, + struct hlist_head *head, int *idx_skip) + { + struct batadv_dat_entry *dat_entry; + int idx = 0; + + rcu_read_lock(); + hlist_for_each_entry_rcu(dat_entry, head, hash_entry) { + if (idx < *idx_skip) + goto skip; + + if (batadv_dat_cache_dump_entry(msg, portid, seq, + dat_entry)) { + rcu_read_unlock(); + *idx_skip = idx; + + return -EMSGSIZE; + } + + skip: + idx++; + } + rcu_read_unlock(); + + return 0; + } + + /** + * batadv_dat_cache_dump() - dump DAT cache table to a netlink socket + * @msg: buffer for the message + * @cb: callback structure containing arguments + * + * Return: message length. + */ + int batadv_dat_cache_dump(struct sk_buff *msg, struct netlink_callback *cb) + { + struct batadv_hard_iface *primary_if = NULL; + int portid = NETLINK_CB(cb->skb).portid; + struct net *net = sock_net(cb->skb->sk); + struct net_device *soft_iface; + struct batadv_hashtable *hash; + struct batadv_priv *bat_priv; + int bucket = cb->args[0]; + struct hlist_head *head; + int idx = cb->args[1]; + int ifindex; + int ret = 0; + + ifindex = batadv_netlink_get_ifindex(cb->nlh, + BATADV_ATTR_MESH_IFINDEX); + if (!ifindex) + return -EINVAL; + + soft_iface = dev_get_by_index(net, ifindex); + if (!soft_iface || !batadv_softif_is_valid(soft_iface)) { + ret = -ENODEV; + goto out; + } + + bat_priv = netdev_priv(soft_iface); + hash = bat_priv->dat.hash; + + primary_if = batadv_primary_if_get_selected(bat_priv); + if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) { + ret = -ENOENT; + goto out; + } + + while (bucket < hash->size) { + head = &hash->table[bucket]; + + if (batadv_dat_cache_dump_bucket(msg, portid, + cb->nlh->nlmsg_seq, head, + &idx)) + break; + + bucket++; + idx = 0; + } + + cb->args[0] = bucket; + cb->args[1] = idx; + + ret = msg->len; + + out: + if (primary_if) + batadv_hardif_put(primary_if); + + if (soft_iface) + dev_put(soft_iface); + + return ret; + } + + /** * batadv_arp_get_type() - parse an ARP packet and gets the type * @bat_priv: the bat priv with all the soft interface information * @skb: packet to analyse diff --combined net/batman-adv/icmp_socket.c index 5daa3d50da17,7d5e9abb7a65..55c358ad3331 --- a/net/batman-adv/icmp_socket.c +++ b/net/batman-adv/icmp_socket.c @@@ -1,5 -1,5 +1,5 @@@ // SPDX-License-Identifier: GPL-2.0 - /* Copyright (C) 2007-2017 B.A.T.M.A.N. contributors: + /* Copyright (C) 2007-2018 B.A.T.M.A.N. contributors: * * Marek Lindner * @@@ -24,7 -24,6 +24,7 @@@ #include <linux/debugfs.h> #include <linux/errno.h> #include <linux/etherdevice.h> +#include <linux/eventpoll.h> #include <linux/export.h> #include <linux/fcntl.h> #include <linux/fs.h> diff --combined net/batman-adv/log.c index cdbe0e5e208b,52d8a4b848c0..853773e45f79 --- a/net/batman-adv/log.c +++ b/net/batman-adv/log.c @@@ -1,5 -1,5 +1,5 @@@ // SPDX-License-Identifier: GPL-2.0 - /* Copyright (C) 2010-2017 B.A.T.M.A.N. contributors: + /* Copyright (C) 2010-2018 B.A.T.M.A.N. contributors: * * Marek Lindner * @@@ -22,7 -22,6 +22,7 @@@ #include <linux/compiler.h> #include <linux/debugfs.h> #include <linux/errno.h> +#include <linux/eventpoll.h> #include <linux/export.h> #include <linux/fcntl.h> #include <linux/fs.h> diff --combined net/batman-adv/multicast.c index d70640135e3a,5615b6abea6f..de3a055f7dd8 --- a/net/batman-adv/multicast.c +++ b/net/batman-adv/multicast.c @@@ -1,5 -1,5 +1,5 @@@ // SPDX-License-Identifier: GPL-2.0 - /* Copyright (C) 2014-2017 B.A.T.M.A.N. contributors: + /* Copyright (C) 2014-2018 B.A.T.M.A.N. contributors: * * Linus Lüssing * @@@ -40,6 -40,7 +40,7 @@@ #include <linux/list.h> #include <linux/lockdep.h> #include <linux/netdevice.h> + #include <linux/netlink.h> #include <linux/printk.h> #include <linux/rculist.h> #include <linux/rcupdate.h> @@@ -52,14 -53,20 +53,20 @@@ #include <linux/types.h> #include <linux/workqueue.h> #include <net/addrconf.h> + #include <net/genetlink.h> #include <net/if_inet6.h> #include <net/ip.h> #include <net/ipv6.h> + #include <net/netlink.h> + #include <net/sock.h> #include <uapi/linux/batadv_packet.h> + #include <uapi/linux/batman_adv.h>
#include "hard-interface.h" #include "hash.h" #include "log.h" + #include "netlink.h" + #include "soft-interface.h" #include "translation-table.h" #include "tvlv.h"
@@@ -102,7 -109,36 +109,36 @@@ static struct net_device *batadv_mcast_ }
/** + * batadv_mcast_addr_is_ipv4() - check if multicast MAC is IPv4 + * @addr: the MAC address to check + * + * Return: True, if MAC address is one reserved for IPv4 multicast, false + * otherwise. + */ + static bool batadv_mcast_addr_is_ipv4(const u8 *addr) + { + static const u8 prefix[] = {0x01, 0x00, 0x5E}; + + return memcmp(prefix, addr, sizeof(prefix)) == 0; + } + + /** + * batadv_mcast_addr_is_ipv6() - check if multicast MAC is IPv6 + * @addr: the MAC address to check + * + * Return: True, if MAC address is one reserved for IPv6 multicast, false + * otherwise. + */ + static bool batadv_mcast_addr_is_ipv6(const u8 *addr) + { + static const u8 prefix[] = {0x33, 0x33}; + + return memcmp(prefix, addr, sizeof(prefix)) == 0; + } + + /** * batadv_mcast_mla_softif_get() - get softif multicast listeners + * @bat_priv: the bat priv with all the soft interface information * @dev: the device to collect multicast addresses from * @mcast_list: a list to put found addresses into * @@@ -119,9 -155,12 +155,12 @@@ * Return: -ENOMEM on memory allocation error or the number of * items added to the mcast_list otherwise. */ - static int batadv_mcast_mla_softif_get(struct net_device *dev, + static int batadv_mcast_mla_softif_get(struct batadv_priv *bat_priv, + struct net_device *dev, struct hlist_head *mcast_list) { + bool all_ipv4 = bat_priv->mcast.flags & BATADV_MCAST_WANT_ALL_IPV4; + bool all_ipv6 = bat_priv->mcast.flags & BATADV_MCAST_WANT_ALL_IPV6; struct net_device *bridge = batadv_mcast_get_bridge(dev); struct netdev_hw_addr *mc_list_entry; struct batadv_hw_addr *new; @@@ -129,6 -168,12 +168,12 @@@
netif_addr_lock_bh(bridge ? bridge : dev); netdev_for_each_mc_addr(mc_list_entry, bridge ? bridge : dev) { + if (all_ipv4 && batadv_mcast_addr_is_ipv4(mc_list_entry->addr)) + continue; + + if (all_ipv6 && batadv_mcast_addr_is_ipv6(mc_list_entry->addr)) + continue; + new = kmalloc(sizeof(*new), GFP_ATOMIC); if (!new) { ret = -ENOMEM; @@@ -193,6 -238,7 +238,7 @@@ static void batadv_mcast_mla_br_addr_cp
/** * batadv_mcast_mla_bridge_get() - get bridged-in multicast listeners + * @bat_priv: the bat priv with all the soft interface information * @dev: a bridge slave whose bridge to collect multicast addresses from * @mcast_list: a list to put found addresses into * @@@ -204,10 -250,13 +250,13 @@@ * Return: -ENOMEM on memory allocation error or the number of * items added to the mcast_list otherwise. */ - static int batadv_mcast_mla_bridge_get(struct net_device *dev, + static int batadv_mcast_mla_bridge_get(struct batadv_priv *bat_priv, + struct net_device *dev, struct hlist_head *mcast_list) { struct list_head bridge_mcast_list = LIST_HEAD_INIT(bridge_mcast_list); + bool all_ipv4 = bat_priv->mcast.flags & BATADV_MCAST_WANT_ALL_IPV4; + bool all_ipv6 = bat_priv->mcast.flags & BATADV_MCAST_WANT_ALL_IPV6; struct br_ip_list *br_ip_entry, *tmp; struct batadv_hw_addr *new; u8 mcast_addr[ETH_ALEN]; @@@ -221,6 -270,12 +270,12 @@@ goto out;
list_for_each_entry(br_ip_entry, &bridge_mcast_list, list) { + if (all_ipv4 && br_ip_entry->addr.proto == htons(ETH_P_IP)) + continue; + + if (all_ipv6 && br_ip_entry->addr.proto == htons(ETH_P_IPV6)) + continue; + batadv_mcast_mla_br_addr_cpy(mcast_addr, &br_ip_entry->addr); if (batadv_mcast_mla_is_duplicate(mcast_addr, mcast_list)) continue; @@@ -543,8 -598,8 +598,8 @@@ update bat_priv->mcast.enabled = true; }
- return !(mcast_data.flags & - (BATADV_MCAST_WANT_ALL_IPV4 | BATADV_MCAST_WANT_ALL_IPV6)); + return !(mcast_data.flags & BATADV_MCAST_WANT_ALL_IPV4 && + mcast_data.flags & BATADV_MCAST_WANT_ALL_IPV6); }
/** @@@ -568,11 -623,11 +623,11 @@@ static void __batadv_mcast_mla_update(s if (!batadv_mcast_mla_tvlv_update(bat_priv)) goto update;
- ret = batadv_mcast_mla_softif_get(soft_iface, &mcast_list); + ret = batadv_mcast_mla_softif_get(bat_priv, soft_iface, &mcast_list); if (ret < 0) goto out;
- ret = batadv_mcast_mla_bridge_get(soft_iface, &mcast_list); + ret = batadv_mcast_mla_bridge_get(bat_priv, soft_iface, &mcast_list); if (ret < 0) goto out;
@@@ -1286,6 -1341,236 +1341,236 @@@ int batadv_mcast_flags_seq_print_text(s #endif
/** + * batadv_mcast_mesh_info_put() - put multicast info into a netlink message + * @msg: buffer for the message + * @bat_priv: the bat priv with all the soft interface information + * + * Return: 0 or error code. + */ + int batadv_mcast_mesh_info_put(struct sk_buff *msg, + struct batadv_priv *bat_priv) + { + u32 flags = bat_priv->mcast.flags; + u32 flags_priv = BATADV_NO_FLAGS; + + if (bat_priv->mcast.bridged) { + flags_priv |= BATADV_MCAST_FLAGS_BRIDGED; + + if (bat_priv->mcast.querier_ipv4.exists) + flags_priv |= BATADV_MCAST_FLAGS_QUERIER_IPV4_EXISTS; + if (bat_priv->mcast.querier_ipv6.exists) + flags_priv |= BATADV_MCAST_FLAGS_QUERIER_IPV6_EXISTS; + if (bat_priv->mcast.querier_ipv4.shadowing) + flags_priv |= BATADV_MCAST_FLAGS_QUERIER_IPV4_SHADOWING; + if (bat_priv->mcast.querier_ipv6.shadowing) + flags_priv |= BATADV_MCAST_FLAGS_QUERIER_IPV6_SHADOWING; + } + + if (nla_put_u32(msg, BATADV_ATTR_MCAST_FLAGS, flags) || + nla_put_u32(msg, BATADV_ATTR_MCAST_FLAGS_PRIV, flags_priv)) + return -EMSGSIZE; + + return 0; + } + + /** + * batadv_mcast_flags_dump_entry() - dump one entry of the multicast flags table + * to a netlink socket + * @msg: buffer for the message + * @portid: netlink port + * @seq: Sequence number of netlink message + * @orig_node: originator to dump the multicast flags of + * + * Return: 0 or error code. + */ + static int + batadv_mcast_flags_dump_entry(struct sk_buff *msg, u32 portid, u32 seq, + struct batadv_orig_node *orig_node) + { + void *hdr; + + hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, + NLM_F_MULTI, BATADV_CMD_GET_MCAST_FLAGS); + if (!hdr) + return -ENOBUFS; + + if (nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN, + orig_node->orig)) { + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; + } + + if (test_bit(BATADV_ORIG_CAPA_HAS_MCAST, + &orig_node->capabilities)) { + if (nla_put_u32(msg, BATADV_ATTR_MCAST_FLAGS, + orig_node->mcast_flags)) { + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; + } + } + + genlmsg_end(msg, hdr); + return 0; + } + + /** + * batadv_mcast_flags_dump_bucket() - dump one bucket of the multicast flags + * table to a netlink socket + * @msg: buffer for the message + * @portid: netlink port + * @seq: Sequence number of netlink message + * @head: bucket to dump + * @idx_skip: How many entries to skip + * + * Return: 0 or error code. + */ + static int + batadv_mcast_flags_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq, + struct hlist_head *head, long *idx_skip) + { + struct batadv_orig_node *orig_node; + long idx = 0; + + rcu_read_lock(); + hlist_for_each_entry_rcu(orig_node, head, hash_entry) { + if (!test_bit(BATADV_ORIG_CAPA_HAS_MCAST, + &orig_node->capa_initialized)) + continue; + + if (idx < *idx_skip) + goto skip; + + if (batadv_mcast_flags_dump_entry(msg, portid, seq, + orig_node)) { + rcu_read_unlock(); + *idx_skip = idx; + + return -EMSGSIZE; + } + + skip: + idx++; + } + rcu_read_unlock(); + + return 0; + } + + /** + * __batadv_mcast_flags_dump() - dump multicast flags table to a netlink socket + * @msg: buffer for the message + * @portid: netlink port + * @seq: Sequence number of netlink message + * @bat_priv: the bat priv with all the soft interface information + * @bucket: current bucket to dump + * @idx: index in current bucket to the next entry to dump + * + * Return: 0 or error code. + */ + static int + __batadv_mcast_flags_dump(struct sk_buff *msg, u32 portid, u32 seq, + struct batadv_priv *bat_priv, long *bucket, long *idx) + { + struct batadv_hashtable *hash = bat_priv->orig_hash; + long bucket_tmp = *bucket; + struct hlist_head *head; + long idx_tmp = *idx; + + while (bucket_tmp < hash->size) { + head = &hash->table[bucket_tmp]; + + if (batadv_mcast_flags_dump_bucket(msg, portid, seq, head, + &idx_tmp)) + break; + + bucket_tmp++; + idx_tmp = 0; + } + + *bucket = bucket_tmp; + *idx = idx_tmp; + + return msg->len; + } + + /** + * batadv_mcast_netlink_get_primary() - get primary interface from netlink + * callback + * @cb: netlink callback structure + * @primary_if: the primary interface pointer to return the result in + * + * Return: 0 or error code. + */ + static int + batadv_mcast_netlink_get_primary(struct netlink_callback *cb, + struct batadv_hard_iface **primary_if) + { + struct batadv_hard_iface *hard_iface = NULL; + struct net *net = sock_net(cb->skb->sk); + struct net_device *soft_iface; + struct batadv_priv *bat_priv; + int ifindex; + int ret = 0; + + ifindex = batadv_netlink_get_ifindex(cb->nlh, BATADV_ATTR_MESH_IFINDEX); + if (!ifindex) + return -EINVAL; + + soft_iface = dev_get_by_index(net, ifindex); + if (!soft_iface || !batadv_softif_is_valid(soft_iface)) { + ret = -ENODEV; + goto out; + } + + bat_priv = netdev_priv(soft_iface); + + hard_iface = batadv_primary_if_get_selected(bat_priv); + if (!hard_iface || hard_iface->if_status != BATADV_IF_ACTIVE) { + ret = -ENOENT; + goto out; + } + + out: + if (soft_iface) + dev_put(soft_iface); + + if (!ret && primary_if) + *primary_if = hard_iface; + else + batadv_hardif_put(hard_iface); + + return ret; + } + + /** + * batadv_mcast_flags_dump() - dump multicast flags table to a netlink socket + * @msg: buffer for the message + * @cb: callback structure containing arguments + * + * Return: message length. + */ + int batadv_mcast_flags_dump(struct sk_buff *msg, struct netlink_callback *cb) + { + struct batadv_hard_iface *primary_if = NULL; + int portid = NETLINK_CB(cb->skb).portid; + struct batadv_priv *bat_priv; + long *bucket = &cb->args[0]; + long *idx = &cb->args[1]; + int ret; + + ret = batadv_mcast_netlink_get_primary(cb, &primary_if); + if (ret) + return ret; + + bat_priv = netdev_priv(primary_if->soft_iface); + ret = __batadv_mcast_flags_dump(msg, portid, cb->nlh->nlmsg_seq, + bat_priv, bucket, idx); + + batadv_hardif_put(primary_if); + return ret; + } + + /** * batadv_mcast_free() - free the multicast optimizations structures * @bat_priv: the bat priv with all the soft interface information */ diff --combined net/batman-adv/routing.c index e61dc1293bb5,289df027ecdd..cc3ed93a6d51 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@@ -1,5 -1,5 +1,5 @@@ // SPDX-License-Identifier: GPL-2.0 - /* Copyright (C) 2007-2017 B.A.T.M.A.N. contributors: + /* Copyright (C) 2007-2018 B.A.T.M.A.N. contributors: * * Marek Lindner, Simon Wunderlich * @@@ -759,7 -759,6 +759,7 @@@ free_skb /** * batadv_reroute_unicast_packet() - update the unicast header for re-routing * @bat_priv: the bat priv with all the soft interface information + * @skb: unicast packet to process * @unicast_packet: the unicast header to be updated * @dst_addr: the payload destination * @vid: VLAN identifier @@@ -771,7 -770,7 +771,7 @@@ * Return: true if the packet header has been updated, false otherwise */ static bool -batadv_reroute_unicast_packet(struct batadv_priv *bat_priv, +batadv_reroute_unicast_packet(struct batadv_priv *bat_priv, struct sk_buff *skb, struct batadv_unicast_packet *unicast_packet, u8 *dst_addr, unsigned short vid) { @@@ -800,10 -799,8 +800,10 @@@ }
/* update the packet header */ + skb_postpull_rcsum(skb, unicast_packet, sizeof(*unicast_packet)); ether_addr_copy(unicast_packet->dest, orig_addr); unicast_packet->ttvn = orig_ttvn; + skb_postpush_rcsum(skb, unicast_packet, sizeof(*unicast_packet));
ret = true; out: @@@ -844,7 -841,7 +844,7 @@@ static bool batadv_check_unicast_ttvn(s * the packet to */ if (batadv_tt_local_client_is_roaming(bat_priv, ethhdr->h_dest, vid)) { - if (batadv_reroute_unicast_packet(bat_priv, unicast_packet, + if (batadv_reroute_unicast_packet(bat_priv, skb, unicast_packet, ethhdr->h_dest, vid)) batadv_dbg_ratelimited(BATADV_DBG_TT, bat_priv, @@@ -890,7 -887,7 +890,7 @@@ * destination can possibly be updated and forwarded towards the new * target host */ - if (batadv_reroute_unicast_packet(bat_priv, unicast_packet, + if (batadv_reroute_unicast_packet(bat_priv, skb, unicast_packet, ethhdr->h_dest, vid)) { batadv_dbg_ratelimited(BATADV_DBG_TT, bat_priv, "Rerouting unicast packet to %pM (dst=%pM): TTVN mismatch old_ttvn=%u new_ttvn=%u\n", @@@ -913,14 -910,12 +913,14 @@@ if (!primary_if) return false;
+ /* update the packet header */ + skb_postpull_rcsum(skb, unicast_packet, sizeof(*unicast_packet)); ether_addr_copy(unicast_packet->dest, primary_if->net_dev->dev_addr); + unicast_packet->ttvn = curr_ttvn; + skb_postpush_rcsum(skb, unicast_packet, sizeof(*unicast_packet));
batadv_hardif_put(primary_if);
- unicast_packet->ttvn = curr_ttvn; - return true; }
@@@ -973,10 -968,14 +973,10 @@@ int batadv_recv_unicast_packet(struct s struct batadv_orig_node *orig_node = NULL, *orig_node_gw = NULL; int check, hdr_size = sizeof(*unicast_packet); enum batadv_subtype subtype; - struct ethhdr *ethhdr; int ret = NET_RX_DROP; bool is4addr, is_gw;
unicast_packet = (struct batadv_unicast_packet *)skb->data; - unicast_4addr_packet = (struct batadv_unicast_4addr_packet *)skb->data; - ethhdr = eth_hdr(skb); - is4addr = unicast_packet->packet_type == BATADV_UNICAST_4ADDR; /* the caller function should have already pulled 2 bytes */ if (is4addr) @@@ -996,14 -995,12 +996,14 @@@ if (!batadv_check_unicast_ttvn(bat_priv, skb, hdr_size)) goto free_skb;
+ unicast_packet = (struct batadv_unicast_packet *)skb->data; + /* packet for me */ if (batadv_is_my_mac(bat_priv, unicast_packet->dest)) { /* If this is a unicast packet from another backgone gw, * drop it. */ - orig_addr_gw = ethhdr->h_source; + orig_addr_gw = eth_hdr(skb)->h_source; orig_node_gw = batadv_orig_hash_find(bat_priv, orig_addr_gw); if (orig_node_gw) { is_gw = batadv_bla_is_backbone_gw(skb, orig_node_gw, @@@ -1018,8 -1015,6 +1018,8 @@@ }
if (is4addr) { + unicast_4addr_packet = + (struct batadv_unicast_4addr_packet *)skb->data; subtype = unicast_4addr_packet->subtype; batadv_dat_inc_counter(bat_priv, subtype);
diff --combined net/core/dev.c index 12be20535714,d8887cc38e7b..f9c28f44286c --- a/net/core/dev.c +++ b/net/core/dev.c @@@ -2378,7 -2378,7 +2378,7 @@@ EXPORT_SYMBOL(netdev_set_num_tc)
/* * Routine to help set real_num_tx_queues. To avoid skbs mapped to queues - * greater then real_num_tx_queues stale skbs on the qdisc must be flushed. + * greater than real_num_tx_queues stale skbs on the qdisc must be flushed. */ int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq) { @@@ -3278,23 -3278,15 +3278,23 @@@ static inline int __dev_xmit_skb(struc #if IS_ENABLED(CONFIG_CGROUP_NET_PRIO) static void skb_update_prio(struct sk_buff *skb) { - struct netprio_map *map = rcu_dereference_bh(skb->dev->priomap); + const struct netprio_map *map; + const struct sock *sk; + unsigned int prioidx;
- if (!skb->priority && skb->sk && map) { - unsigned int prioidx = - sock_cgroup_prioidx(&skb->sk->sk_cgrp_data); + if (skb->priority) + return; + map = rcu_dereference_bh(skb->dev->priomap); + if (!map) + return; + sk = skb_to_full_sk(skb); + if (!sk) + return;
- if (prioidx < map->priomap_len) - skb->priority = map->priomap[prioidx]; - } + prioidx = sock_cgroup_prioidx(&sk->sk_cgrp_data); + + if (prioidx < map->priomap_len) + skb->priority = map->priomap[prioidx]; } #else #define skb_update_prio(skb) @@@ -4359,6 -4351,9 +4359,9 @@@ int netdev_rx_handler_register(struct n if (netdev_is_rx_handler_busy(dev)) return -EBUSY;
+ if (dev->priv_flags & IFF_NO_RX_HANDLER) + return -EINVAL; + /* Note: rx_handler_data must be set before rx_handler */ rcu_assign_pointer(dev->rx_handler_data, rx_handler_data); rcu_assign_pointer(dev->rx_handler, rx_handler); @@@ -7554,6 -7549,19 +7557,19 @@@ static netdev_features_t netdev_fix_fea } }
+ /* LRO/HW-GRO features cannot be combined with RX-FCS */ + if (features & NETIF_F_RXFCS) { + if (features & NETIF_F_LRO) { + netdev_dbg(dev, "Dropping LRO feature since RX-FCS is requested.\n"); + features &= ~NETIF_F_LRO; + } + + if (features & NETIF_F_GRO_HW) { + netdev_dbg(dev, "Dropping HW-GRO feature since RX-FCS is requested.\n"); + features &= ~NETIF_F_GRO_HW; + } + } + return features; }
@@@ -8010,7 -8018,8 +8026,8 @@@ int register_netdev(struct net_device * { int err;
- rtnl_lock(); + if (rtnl_lock_killable()) + return -EINTR; err = register_netdevice(dev); rtnl_unlock(); return err; @@@ -8153,8 -8162,9 +8170,9 @@@ void netdev_run_todo(void BUG_ON(!list_empty(&dev->ptype_specific)); WARN_ON(rcu_access_pointer(dev->ip_ptr)); WARN_ON(rcu_access_pointer(dev->ip6_ptr)); + #if IS_ENABLED(CONFIG_DECNET) WARN_ON(dev->dn_ptr); - + #endif if (dev->priv_destructor) dev->priv_destructor(dev); if (dev->needs_free_netdev) @@@ -8852,6 -8862,7 +8870,7 @@@ static void __net_exit netdev_exit(stru static struct pernet_operations __net_initdata netdev_net_ops = { .init = netdev_init, .exit = netdev_exit, + .async = true, };
static void __net_exit default_device_exit(struct net *net) @@@ -8952,6 -8963,7 +8971,7 @@@ static void __net_exit default_device_e static struct pernet_operations __net_initdata default_device_ops = { .exit = default_device_exit, .exit_batch = default_device_exit_batch, + .async = true, };
/* diff --combined net/core/devlink.c index effd4848c2b4,d03b96f87c25..9236e421bd62 --- a/net/core/devlink.c +++ b/net/core/devlink.c @@@ -1798,7 -1798,7 +1798,7 @@@ send_done if (!nlh) { err = devlink_dpipe_send_and_alloc_skb(&skb, info); if (err) - goto err_skb_send_alloc; + return err; goto send_done; }
@@@ -1807,6 -1807,7 +1807,6 @@@ nla_put_failure: err = -EMSGSIZE; err_table_put: -err_skb_send_alloc: genlmsg_cancel(skb, hdr); nlmsg_free(skb); return err; @@@ -2072,7 -2073,7 +2072,7 @@@ static int devlink_dpipe_entries_fill(s table->counters_enabled, &dump_ctx); if (err) - goto err_entries_dump; + return err;
send_done: nlh = nlmsg_put(dump_ctx.skb, info->snd_portid, info->snd_seq, @@@ -2080,10 -2081,16 +2080,10 @@@ if (!nlh) { err = devlink_dpipe_send_and_alloc_skb(&dump_ctx.skb, info); if (err) - goto err_skb_send_alloc; + return err; goto send_done; } return genlmsg_reply(dump_ctx.skb, info); - -err_entries_dump: -err_skb_send_alloc: - genlmsg_cancel(dump_ctx.skb, dump_ctx.hdr); - nlmsg_free(dump_ctx.skb); - return err; }
static int devlink_nl_cmd_dpipe_entries_get(struct sk_buff *skb, @@@ -2222,7 -2229,7 +2222,7 @@@ send_done if (!nlh) { err = devlink_dpipe_send_and_alloc_skb(&skb, info); if (err) - goto err_skb_send_alloc; + return err; goto send_done; } return genlmsg_reply(skb, info); @@@ -2230,6 -2237,7 +2230,6 @@@ nla_put_failure: err = -EMSGSIZE; err_table_put: -err_skb_send_alloc: genlmsg_cancel(skb, hdr); nlmsg_free(skb); return err; @@@ -2331,6 -2339,32 +2331,32 @@@ out resource->size_valid = size_valid; }
+ static int + devlink_resource_validate_size(struct devlink_resource *resource, u64 size, + struct netlink_ext_ack *extack) + { + u64 reminder; + int err = 0; + + if (size > resource->size_params.size_max) { + NL_SET_ERR_MSG_MOD(extack, "Size larger than maximum"); + err = -EINVAL; + } + + if (size < resource->size_params.size_min) { + NL_SET_ERR_MSG_MOD(extack, "Size smaller than minimum"); + err = -EINVAL; + } + + div64_u64_rem(size, resource->size_params.size_granularity, &reminder); + if (reminder) { + NL_SET_ERR_MSG_MOD(extack, "Wrong granularity"); + err = -EINVAL; + } + + return err; + } + static int devlink_nl_cmd_resource_set(struct sk_buff *skb, struct genl_info *info) { @@@ -2349,12 -2383,8 +2375,8 @@@ if (!resource) return -EINVAL;
- if (!resource->resource_ops->size_validate) - return -EINVAL; - size = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_SIZE]); - err = resource->resource_ops->size_validate(devlink, size, - info->extack); + err = devlink_resource_validate_size(resource, size, info->extack); if (err) return err;
@@@ -2714,22 -2744,22 +2736,22 @@@ static const struct genl_ops devlink_nl .cmd = DEVLINK_CMD_DPIPE_TABLE_GET, .doit = devlink_nl_cmd_dpipe_table_get, .policy = devlink_nl_policy, - .flags = GENL_ADMIN_PERM, .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK, + /* can be retrieved by unprivileged users */ }, { .cmd = DEVLINK_CMD_DPIPE_ENTRIES_GET, .doit = devlink_nl_cmd_dpipe_entries_get, .policy = devlink_nl_policy, - .flags = GENL_ADMIN_PERM, .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK, + /* can be retrieved by unprivileged users */ }, { .cmd = DEVLINK_CMD_DPIPE_HEADERS_GET, .doit = devlink_nl_cmd_dpipe_headers_get, .policy = devlink_nl_policy, - .flags = GENL_ADMIN_PERM, .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK, + /* can be retrieved by unprivileged users */ }, { .cmd = DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET, @@@ -2749,8 -2779,8 +2771,8 @@@ .cmd = DEVLINK_CMD_RESOURCE_DUMP, .doit = devlink_nl_cmd_resource_dump, .policy = devlink_nl_policy, - .flags = GENL_ADMIN_PERM, .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK, + /* can be retrieved by unprivileged users */ }, { .cmd = DEVLINK_CMD_RELOAD, @@@ -3144,7 -3174,6 +3166,6 @@@ EXPORT_SYMBOL_GPL(devlink_dpipe_table_u */ int devlink_resource_register(struct devlink *devlink, const char *resource_name, - bool top_hierarchy, u64 resource_size, u64 resource_id, u64 parent_resource_id, @@@ -3153,8 -3182,11 +3174,11 @@@ { struct devlink_resource *resource; struct list_head *resource_list; + bool top_hierarchy; int err = 0;
+ top_hierarchy = parent_resource_id == DEVLINK_RESOURCE_ID_PARENT_TOP; + mutex_lock(&devlink->lock); resource = devlink_resource_find(devlink, NULL, resource_id); if (resource) { diff --combined net/core/filter.c index 48aa7c7320db,c86f03fd9ea5..00c711c5f1a2 --- a/net/core/filter.c +++ b/net/core/filter.c @@@ -1890,6 -1890,202 +1890,202 @@@ static const struct bpf_func_proto bpf_ .arg4_type = ARG_ANYTHING, };
+ BPF_CALL_4(bpf_msg_redirect_map, struct sk_msg_buff *, msg, + struct bpf_map *, map, u32, key, u64, flags) + { + /* If user passes invalid input drop the packet. */ + if (unlikely(flags)) + return SK_DROP; + + msg->key = key; + msg->flags = flags; + msg->map = map; + + return SK_PASS; + } + + struct sock *do_msg_redirect_map(struct sk_msg_buff *msg) + { + struct sock *sk = NULL; + + if (msg->map) { + sk = __sock_map_lookup_elem(msg->map, msg->key); + + msg->key = 0; + msg->map = NULL; + } + + return sk; + } + + static const struct bpf_func_proto bpf_msg_redirect_map_proto = { + .func = bpf_msg_redirect_map, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, + .arg2_type = ARG_CONST_MAP_PTR, + .arg3_type = ARG_ANYTHING, + .arg4_type = ARG_ANYTHING, + }; + + BPF_CALL_2(bpf_msg_apply_bytes, struct sk_msg_buff *, msg, u32, bytes) + { + msg->apply_bytes = bytes; + return 0; + } + + static const struct bpf_func_proto bpf_msg_apply_bytes_proto = { + .func = bpf_msg_apply_bytes, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, + .arg2_type = ARG_ANYTHING, + }; + + BPF_CALL_2(bpf_msg_cork_bytes, struct sk_msg_buff *, msg, u32, bytes) + { + msg->cork_bytes = bytes; + return 0; + } + + static const struct bpf_func_proto bpf_msg_cork_bytes_proto = { + .func = bpf_msg_cork_bytes, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, + .arg2_type = ARG_ANYTHING, + }; + + BPF_CALL_4(bpf_msg_pull_data, + struct sk_msg_buff *, msg, u32, start, u32, end, u64, flags) + { + unsigned int len = 0, offset = 0, copy = 0; + struct scatterlist *sg = msg->sg_data; + int first_sg, last_sg, i, shift; + unsigned char *p, *to, *from; + int bytes = end - start; + struct page *page; + + if (unlikely(flags || end <= start)) + return -EINVAL; + + /* First find the starting scatterlist element */ + i = msg->sg_start; + do { + len = sg[i].length; + offset += len; + if (start < offset + len) + break; + i++; + if (i == MAX_SKB_FRAGS) + i = 0; + } while (i != msg->sg_end); + + if (unlikely(start >= offset + len)) + return -EINVAL; + + if (!msg->sg_copy[i] && bytes <= len) + goto out; + + first_sg = i; + + /* At this point we need to linearize multiple scatterlist + * elements or a single shared page. Either way we need to + * copy into a linear buffer exclusively owned by BPF. Then + * place the buffer in the scatterlist and fixup the original + * entries by removing the entries now in the linear buffer + * and shifting the remaining entries. For now we do not try + * to copy partial entries to avoid complexity of running out + * of sg_entry slots. The downside is reading a single byte + * will copy the entire sg entry. + */ + do { + copy += sg[i].length; + i++; + if (i == MAX_SKB_FRAGS) + i = 0; + if (bytes < copy) + break; + } while (i != msg->sg_end); + last_sg = i; + + if (unlikely(copy < end - start)) + return -EINVAL; + + page = alloc_pages(__GFP_NOWARN | GFP_ATOMIC, get_order(copy)); + if (unlikely(!page)) + return -ENOMEM; + p = page_address(page); + offset = 0; + + i = first_sg; + do { + from = sg_virt(&sg[i]); + len = sg[i].length; + to = p + offset; + + memcpy(to, from, len); + offset += len; + sg[i].length = 0; + put_page(sg_page(&sg[i])); + + i++; + if (i == MAX_SKB_FRAGS) + i = 0; + } while (i != last_sg); + + sg[first_sg].length = copy; + sg_set_page(&sg[first_sg], page, copy, 0); + + /* To repair sg ring we need to shift entries. If we only + * had a single entry though we can just replace it and + * be done. Otherwise walk the ring and shift the entries. + */ + shift = last_sg - first_sg - 1; + if (!shift) + goto out; + + i = first_sg + 1; + do { + int move_from; + + if (i + shift >= MAX_SKB_FRAGS) + move_from = i + shift - MAX_SKB_FRAGS; + else + move_from = i + shift; + + if (move_from == msg->sg_end) + break; + + sg[i] = sg[move_from]; + sg[move_from].length = 0; + sg[move_from].page_link = 0; + sg[move_from].offset = 0; + + i++; + if (i == MAX_SKB_FRAGS) + i = 0; + } while (1); + msg->sg_end -= shift; + if (msg->sg_end < 0) + msg->sg_end += MAX_SKB_FRAGS; + out: + msg->data = sg_virt(&sg[i]) + start - offset; + msg->data_end = msg->data + bytes; + + return 0; + } + + static const struct bpf_func_proto bpf_msg_pull_data_proto = { + .func = bpf_msg_pull_data, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, + .arg2_type = ARG_ANYTHING, + .arg3_type = ARG_ANYTHING, + .arg4_type = ARG_ANYTHING, + }; + BPF_CALL_1(bpf_get_cgroup_classid, const struct sk_buff *, skb) { return task_get_classid(skb); @@@ -2087,10 -2283,6 +2283,10 @@@ static int bpf_skb_proto_4_to_6(struct u32 off = skb_mac_header_len(skb); int ret;
+ /* SCTP uses GSO_BY_FRAGS, thus cannot adjust it. */ + if (skb_is_gso(skb) && unlikely(skb_is_gso_sctp(skb))) + return -ENOTSUPP; + ret = skb_cow(skb, len_diff); if (unlikely(ret < 0)) return ret; @@@ -2100,21 -2292,19 +2296,21 @@@ return ret;
if (skb_is_gso(skb)) { + struct skb_shared_info *shinfo = skb_shinfo(skb); + /* SKB_GSO_TCPV4 needs to be changed into * SKB_GSO_TCPV6. */ - if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) { - skb_shinfo(skb)->gso_type &= ~SKB_GSO_TCPV4; - skb_shinfo(skb)->gso_type |= SKB_GSO_TCPV6; + if (shinfo->gso_type & SKB_GSO_TCPV4) { + shinfo->gso_type &= ~SKB_GSO_TCPV4; + shinfo->gso_type |= SKB_GSO_TCPV6; }
/* Due to IPv6 header, MSS needs to be downgraded. */ - skb_shinfo(skb)->gso_size -= len_diff; + skb_decrease_gso_size(shinfo, len_diff); /* Header must be checked, and gso_segs recomputed. */ - skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY; - skb_shinfo(skb)->gso_segs = 0; + shinfo->gso_type |= SKB_GSO_DODGY; + shinfo->gso_segs = 0; }
skb->protocol = htons(ETH_P_IPV6); @@@ -2129,10 -2319,6 +2325,10 @@@ static int bpf_skb_proto_6_to_4(struct u32 off = skb_mac_header_len(skb); int ret;
+ /* SCTP uses GSO_BY_FRAGS, thus cannot adjust it. */ + if (skb_is_gso(skb) && unlikely(skb_is_gso_sctp(skb))) + return -ENOTSUPP; + ret = skb_unclone(skb, GFP_ATOMIC); if (unlikely(ret < 0)) return ret; @@@ -2142,21 -2328,19 +2338,21 @@@ return ret;
if (skb_is_gso(skb)) { + struct skb_shared_info *shinfo = skb_shinfo(skb); + /* SKB_GSO_TCPV6 needs to be changed into * SKB_GSO_TCPV4. */ - if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) { - skb_shinfo(skb)->gso_type &= ~SKB_GSO_TCPV6; - skb_shinfo(skb)->gso_type |= SKB_GSO_TCPV4; + if (shinfo->gso_type & SKB_GSO_TCPV6) { + shinfo->gso_type &= ~SKB_GSO_TCPV6; + shinfo->gso_type |= SKB_GSO_TCPV4; }
/* Due to IPv4 header, MSS can be upgraded. */ - skb_shinfo(skb)->gso_size += len_diff; + skb_increase_gso_size(shinfo, len_diff); /* Header must be checked, and gso_segs recomputed. */ - skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY; - skb_shinfo(skb)->gso_segs = 0; + shinfo->gso_type |= SKB_GSO_DODGY; + shinfo->gso_segs = 0; }
skb->protocol = htons(ETH_P_IP); @@@ -2255,10 -2439,6 +2451,10 @@@ static int bpf_skb_net_grow(struct sk_b u32 off = skb_mac_header_len(skb) + bpf_skb_net_base_len(skb); int ret;
+ /* SCTP uses GSO_BY_FRAGS, thus cannot adjust it. */ + if (skb_is_gso(skb) && unlikely(skb_is_gso_sctp(skb))) + return -ENOTSUPP; + ret = skb_cow(skb, len_diff); if (unlikely(ret < 0)) return ret; @@@ -2268,13 -2448,11 +2464,13 @@@ return ret;
if (skb_is_gso(skb)) { + struct skb_shared_info *shinfo = skb_shinfo(skb); + /* Due to header grow, MSS needs to be downgraded. */ - skb_shinfo(skb)->gso_size -= len_diff; + skb_decrease_gso_size(shinfo, len_diff); /* Header must be checked, and gso_segs recomputed. */ - skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY; - skb_shinfo(skb)->gso_segs = 0; + shinfo->gso_type |= SKB_GSO_DODGY; + shinfo->gso_segs = 0; }
return 0; @@@ -2285,10 -2463,6 +2481,10 @@@ static int bpf_skb_net_shrink(struct sk u32 off = skb_mac_header_len(skb) + bpf_skb_net_base_len(skb); int ret;
+ /* SCTP uses GSO_BY_FRAGS, thus cannot adjust it. */ + if (skb_is_gso(skb) && unlikely(skb_is_gso_sctp(skb))) + return -ENOTSUPP; + ret = skb_unclone(skb, GFP_ATOMIC); if (unlikely(ret < 0)) return ret; @@@ -2298,13 -2472,11 +2494,13 @@@ return ret;
if (skb_is_gso(skb)) { + struct skb_shared_info *shinfo = skb_shinfo(skb); + /* Due to header shrink, MSS can be upgraded. */ - skb_shinfo(skb)->gso_size += len_diff; + skb_increase_gso_size(shinfo, len_diff); /* Header must be checked, and gso_segs recomputed. */ - skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY; - skb_shinfo(skb)->gso_segs = 0; + shinfo->gso_type |= SKB_GSO_DODGY; + shinfo->gso_segs = 0; }
return 0; @@@ -2855,7 -3027,8 +3051,8 @@@ bool bpf_helper_changes_pkt_data(void * func == bpf_l3_csum_replace || func == bpf_l4_csum_replace || func == bpf_xdp_adjust_head || - func == bpf_xdp_adjust_meta) + func == bpf_xdp_adjust_meta || + func == bpf_msg_pull_data) return true;
return false; @@@ -3015,7 -3188,7 +3212,7 @@@ BPF_CALL_4(bpf_skb_set_tunnel_key, stru struct ip_tunnel_info *info;
if (unlikely(flags & ~(BPF_F_TUNINFO_IPV6 | BPF_F_ZERO_CSUM_TX | - BPF_F_DONT_FRAGMENT))) + BPF_F_DONT_FRAGMENT | BPF_F_SEQ_NUMBER))) return -EINVAL; if (unlikely(size != sizeof(struct bpf_tunnel_key))) { switch (size) { @@@ -3049,6 -3222,8 +3246,8 @@@ info->key.tun_flags |= TUNNEL_DONT_FRAGMENT; if (flags & BPF_F_ZERO_CSUM_TX) info->key.tun_flags &= ~TUNNEL_CSUM; + if (flags & BPF_F_SEQ_NUMBER) + info->key.tun_flags |= TUNNEL_SEQ;
info->key.tun_id = cpu_to_be64(from->tunnel_id); info->key.tos = from->tunnel_tos; @@@ -3613,6 -3788,22 +3812,22 @@@ static const struct bpf_func_proto } }
+ static const struct bpf_func_proto *sk_msg_func_proto(enum bpf_func_id func_id) + { + switch (func_id) { + case BPF_FUNC_msg_redirect_map: + return &bpf_msg_redirect_map_proto; + case BPF_FUNC_msg_apply_bytes: + return &bpf_msg_apply_bytes_proto; + case BPF_FUNC_msg_cork_bytes: + return &bpf_msg_cork_bytes_proto; + case BPF_FUNC_msg_pull_data: + return &bpf_msg_pull_data_proto; + default: + return bpf_base_func_proto(func_id); + } + } + static const struct bpf_func_proto *sk_skb_func_proto(enum bpf_func_id func_id) { switch (func_id) { @@@ -4002,6 -4193,32 +4217,32 @@@ static bool sk_skb_is_valid_access(int return bpf_skb_is_valid_access(off, size, type, info); }
+ static bool sk_msg_is_valid_access(int off, int size, + enum bpf_access_type type, + struct bpf_insn_access_aux *info) + { + if (type == BPF_WRITE) + return false; + + switch (off) { + case offsetof(struct sk_msg_md, data): + info->reg_type = PTR_TO_PACKET; + break; + case offsetof(struct sk_msg_md, data_end): + info->reg_type = PTR_TO_PACKET_END; + break; + } + + if (off < 0 || off >= sizeof(struct sk_msg_md)) + return false; + if (off % size != 0) + return false; + if (size != sizeof(__u64)) + return false; + + return true; + } + static u32 bpf_convert_ctx_access(enum bpf_access_type type, const struct bpf_insn *si, struct bpf_insn *insn_buf, @@@ -4800,6 -5017,29 +5041,29 @@@ static u32 sk_skb_convert_ctx_access(en return insn - insn_buf; }
+ static u32 sk_msg_convert_ctx_access(enum bpf_access_type type, + const struct bpf_insn *si, + struct bpf_insn *insn_buf, + struct bpf_prog *prog, u32 *target_size) + { + struct bpf_insn *insn = insn_buf; + + switch (si->off) { + case offsetof(struct sk_msg_md, data): + *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_msg_buff, data), + si->dst_reg, si->src_reg, + offsetof(struct sk_msg_buff, data)); + break; + case offsetof(struct sk_msg_md, data_end): + *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_msg_buff, data_end), + si->dst_reg, si->src_reg, + offsetof(struct sk_msg_buff, data_end)); + break; + } + + return insn - insn_buf; + } + const struct bpf_verifier_ops sk_filter_verifier_ops = { .get_func_proto = sk_filter_func_proto, .is_valid_access = sk_filter_is_valid_access, @@@ -4890,6 -5130,15 +5154,15 @@@ const struct bpf_verifier_ops sk_skb_ve const struct bpf_prog_ops sk_skb_prog_ops = { };
+ const struct bpf_verifier_ops sk_msg_verifier_ops = { + .get_func_proto = sk_msg_func_proto, + .is_valid_access = sk_msg_is_valid_access, + .convert_ctx_access = sk_msg_convert_ctx_access, + }; + + const struct bpf_prog_ops sk_msg_prog_ops = { + }; + int sk_detach_filter(struct sock *sk) { int ret = -ENOENT; diff --combined net/core/skbuff.c index 1e7acdc30732,715c13495ba6..46cb22215ff4 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@@ -77,8 -77,8 +77,8 @@@ #include <linux/capability.h> #include <linux/user_namespace.h>
- struct kmem_cache *skbuff_head_cache __read_mostly; - static struct kmem_cache *skbuff_fclone_cache __read_mostly; + struct kmem_cache *skbuff_head_cache __ro_after_init; + static struct kmem_cache *skbuff_fclone_cache __ro_after_init; int sysctl_max_skb_frags __read_mostly = MAX_SKB_FRAGS; EXPORT_SYMBOL(sysctl_max_skb_frags);
@@@ -890,7 -890,7 +890,7 @@@ struct sk_buff *skb_morph(struct sk_buf } EXPORT_SYMBOL_GPL(skb_morph);
- static int mm_account_pinned_pages(struct mmpin *mmp, size_t size) + int mm_account_pinned_pages(struct mmpin *mmp, size_t size) { unsigned long max_pg, num_pg, new_pg, old_pg; struct user_struct *user; @@@ -919,14 -919,16 +919,16 @@@
return 0; } + EXPORT_SYMBOL_GPL(mm_account_pinned_pages);
- static void mm_unaccount_pinned_pages(struct mmpin *mmp) + void mm_unaccount_pinned_pages(struct mmpin *mmp) { if (mmp->user) { atomic_long_sub(mmp->num_pg, &mmp->user->locked_vm); free_uid(mmp->user); } } + EXPORT_SYMBOL_GPL(mm_unaccount_pinned_pages);
struct ubuf_info *sock_zerocopy_alloc(struct sock *sk, size_t size) { @@@ -4179,7 -4181,7 +4181,7 @@@ int sock_queue_err_skb(struct sock *sk
skb_queue_tail(&sk->sk_error_queue, skb); if (!sock_flag(sk, SOCK_DEAD)) - sk->sk_data_ready(sk); + sk->sk_error_report(sk); return 0; } EXPORT_SYMBOL(sock_queue_err_skb); @@@ -4904,7 -4906,7 +4906,7 @@@ static unsigned int skb_gso_transport_s thlen += inner_tcp_hdrlen(skb); } else if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) { thlen = tcp_hdrlen(skb); - } else if (unlikely(shinfo->gso_type & SKB_GSO_SCTP)) { + } else if (unlikely(skb_is_gso_sctp(skb))) { thlen = sizeof(struct sctphdr); } /* UFO sets gso_size to the size of the fragmentation @@@ -5020,16 -5022,13 +5022,16 @@@ EXPORT_SYMBOL_GPL(skb_gso_validate_mac_
static struct sk_buff *skb_reorder_vlan_header(struct sk_buff *skb) { + int mac_len; + if (skb_cow(skb, skb_headroom(skb)) < 0) { kfree_skb(skb); return NULL; }
- memmove(skb->data - ETH_HLEN, skb->data - skb->mac_len - VLAN_HLEN, - 2 * ETH_ALEN); + mac_len = skb->data - skb_mac_header(skb); + memmove(skb_mac_header(skb) + VLAN_HLEN, skb_mac_header(skb), + mac_len - VLAN_HLEN - ETH_TLEN); skb->mac_header += VLAN_HLEN; return skb; } diff --combined net/core/sock.c index 85b0b64e7f9d,f704324d1219..e689496dfd8a --- a/net/core/sock.c +++ b/net/core/sock.c @@@ -1049,16 -1049,18 +1049,18 @@@ set_rcvbuf break;
case SO_ZEROCOPY: - if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6) + if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6) { + if (sk->sk_protocol != IPPROTO_TCP) + ret = -ENOTSUPP; + } else if (sk->sk_family != PF_RDS) { ret = -ENOTSUPP; - else if (sk->sk_protocol != IPPROTO_TCP) - ret = -ENOTSUPP; - else if (sk->sk_state != TCP_CLOSE) - ret = -EBUSY; - else if (val < 0 || val > 1) - ret = -EINVAL; - else - sock_valbool_flag(sk, SOCK_ZEROCOPY, valbool); + } + if (!ret) { + if (val < 0 || val > 1) + ret = -EINVAL; + else + sock_valbool_flag(sk, SOCK_ZEROCOPY, valbool); + } break;
default: @@@ -1274,7 -1276,8 +1276,8 @@@ int sock_getsockopt(struct socket *sock { char address[128];
- if (sock->ops->getname(sock, (struct sockaddr *)address, &lv, 2)) + lv = sock->ops->getname(sock, (struct sockaddr *)address, 2); + if (lv < 0) return -ENOTCONN; if (lv < len) return -EINVAL; @@@ -1773,7 -1776,7 +1776,7 @@@ void sk_setup_caps(struct sock *sk, str u32 max_segs = 1;
sk_dst_set(sk, dst); - sk->sk_route_caps = dst->dev->features; + sk->sk_route_caps = dst->dev->features | sk->sk_route_forced_caps; if (sk->sk_route_caps & NETIF_F_GSO) sk->sk_route_caps |= NETIF_F_GSO_SOFTWARE; sk->sk_route_caps &= ~sk->sk_route_nocaps; @@@ -2234,6 -2237,67 +2237,67 @@@ bool sk_page_frag_refill(struct sock *s } EXPORT_SYMBOL(sk_page_frag_refill);
+ int sk_alloc_sg(struct sock *sk, int len, struct scatterlist *sg, + int sg_start, int *sg_curr_index, unsigned int *sg_curr_size, + int first_coalesce) + { + int sg_curr = *sg_curr_index, use = 0, rc = 0; + unsigned int size = *sg_curr_size; + struct page_frag *pfrag; + struct scatterlist *sge; + + len -= size; + pfrag = sk_page_frag(sk); + + while (len > 0) { + unsigned int orig_offset; + + if (!sk_page_frag_refill(sk, pfrag)) { + rc = -ENOMEM; + goto out; + } + + use = min_t(int, len, pfrag->size - pfrag->offset); + + if (!sk_wmem_schedule(sk, use)) { + rc = -ENOMEM; + goto out; + } + + sk_mem_charge(sk, use); + size += use; + orig_offset = pfrag->offset; + pfrag->offset += use; + + sge = sg + sg_curr - 1; + if (sg_curr > first_coalesce && sg_page(sg) == pfrag->page && + sg->offset + sg->length == orig_offset) { + sg->length += use; + } else { + sge = sg + sg_curr; + sg_unmark_end(sge); + sg_set_page(sge, pfrag->page, use, orig_offset); + get_page(pfrag->page); + sg_curr++; + + if (sg_curr == MAX_SKB_FRAGS) + sg_curr = 0; + + if (sg_curr == sg_start) { + rc = -ENOSPC; + break; + } + } + + len -= use; + } + out: + *sg_curr_size = size; + *sg_curr_index = sg_curr; + return rc; + } + EXPORT_SYMBOL(sk_alloc_sg); + static void __lock_sock(struct sock *sk) __releases(&sk->sk_lock.slock) __acquires(&sk->sk_lock.slock) @@@ -2497,7 -2561,7 +2561,7 @@@ int sock_no_accept(struct socket *sock EXPORT_SYMBOL(sock_no_accept);
int sock_no_getname(struct socket *sock, struct sockaddr *saddr, - int *len, int peer) + int peer) { return -EOPNOTSUPP; } @@@ -3111,6 -3175,7 +3175,7 @@@ static void __net_exit sock_inuse_exit_ static struct pernet_operations net_inuse_ops = { .init = sock_inuse_init_net, .exit = sock_inuse_exit_net, + .async = true, };
static __init int net_inuse_init(void) @@@ -3261,27 -3326,6 +3326,27 @@@ void proto_unregister(struct proto *pro } EXPORT_SYMBOL(proto_unregister);
+int sock_load_diag_module(int family, int protocol) +{ + if (!protocol) { + if (!sock_is_registered(family)) + return -ENOENT; + + return request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK, + NETLINK_SOCK_DIAG, family); + } + +#ifdef CONFIG_INET + if (family == AF_INET && + !rcu_access_pointer(inet_protos[protocol])) + return -ENOENT; +#endif + + return request_module("net-pf-%d-proto-%d-type-%d-%d", PF_NETLINK, + NETLINK_SOCK_DIAG, family, protocol); +} +EXPORT_SYMBOL(sock_load_diag_module); + #ifdef CONFIG_PROC_FS static void *proto_seq_start(struct seq_file *seq, loff_t *pos) __acquires(proto_list_mutex) @@@ -3405,6 -3449,7 +3470,7 @@@ static __net_exit void proto_exit_net(s static __net_initdata struct pernet_operations proto_net_ops = { .init = proto_init_net, .exit = proto_exit_net, + .async = true, };
static int __init proto_init(void) diff --combined net/core/sock_diag.c index c37b5be7c5e4,aee5642affd9..a3392a8f9276 --- a/net/core/sock_diag.c +++ b/net/core/sock_diag.c @@@ -220,7 -220,8 +220,7 @@@ static int __sock_diag_cmd(struct sk_bu return -EINVAL;
if (sock_diag_handlers[req->sdiag_family] == NULL) - request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK, - NETLINK_SOCK_DIAG, req->sdiag_family); + sock_load_diag_module(req->sdiag_family, 0);
mutex_lock(&sock_diag_table_mutex); hndl = sock_diag_handlers[req->sdiag_family]; @@@ -246,7 -247,8 +246,7 @@@ static int sock_diag_rcv_msg(struct sk_ case TCPDIAG_GETSOCK: case DCCPDIAG_GETSOCK: if (inet_rcv_compat == NULL) - request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK, - NETLINK_SOCK_DIAG, AF_INET); + sock_load_diag_module(AF_INET, 0);
mutex_lock(&sock_diag_table_mutex); if (inet_rcv_compat != NULL) @@@ -279,12 -281,14 +279,12 @@@ static int sock_diag_bind(struct net *n case SKNLGRP_INET_TCP_DESTROY: case SKNLGRP_INET_UDP_DESTROY: if (!sock_diag_handlers[AF_INET]) - request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK, - NETLINK_SOCK_DIAG, AF_INET); + sock_load_diag_module(AF_INET, 0); break; case SKNLGRP_INET6_TCP_DESTROY: case SKNLGRP_INET6_UDP_DESTROY: if (!sock_diag_handlers[AF_INET6]) - request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK, - NETLINK_SOCK_DIAG, AF_INET6); + sock_load_diag_module(AF_INET6, 0); break; } return 0; @@@ -324,6 -328,7 +324,7 @@@ static void __net_exit diag_net_exit(st static struct pernet_operations diag_net_ops = { .init = diag_net_init, .exit = diag_net_exit, + .async = true, };
static int __init sock_diag_init(void) diff --combined net/ieee802154/6lowpan/core.c index e9f0489e4229,e4f305320519..275449b0d633 --- a/net/ieee802154/6lowpan/core.c +++ b/net/ieee802154/6lowpan/core.c @@@ -104,6 -104,7 +104,7 @@@ static void lowpan_setup(struct net_dev /* We need an ipv6hdr as minimum len when calling xmit */ ldev->hard_header_len = sizeof(struct ipv6hdr); ldev->flags = IFF_BROADCAST | IFF_MULTICAST; + ldev->priv_flags |= IFF_NO_QUEUE;
ldev->netdev_ops = &lowpan_netdev_ops; ldev->header_ops = &lowpan_header_ops; @@@ -206,13 -207,9 +207,13 @@@ static inline void lowpan_netlink_fini( static int lowpan_device_event(struct notifier_block *unused, unsigned long event, void *ptr) { - struct net_device *wdev = netdev_notifier_info_to_dev(ptr); + struct net_device *ndev = netdev_notifier_info_to_dev(ptr); + struct wpan_dev *wpan_dev;
- if (wdev->type != ARPHRD_IEEE802154) + if (ndev->type != ARPHRD_IEEE802154) + return NOTIFY_DONE; + wpan_dev = ndev->ieee802154_ptr; + if (!wpan_dev) return NOTIFY_DONE;
switch (event) { @@@ -221,8 -218,8 +222,8 @@@ * also delete possible lowpan interfaces which belongs * to the wpan interface. */ - if (wdev->ieee802154_ptr->lowpan_dev) - lowpan_dellink(wdev->ieee802154_ptr->lowpan_dev, NULL); + if (wpan_dev->lowpan_dev) + lowpan_dellink(wpan_dev->lowpan_dev, NULL); break; default: return NOTIFY_DONE; diff --combined net/ipv4/ip_tunnel.c index 7c76dd17b6b9,5fcb17cb426b..c809dbefa9f0 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c @@@ -290,22 -290,6 +290,6 @@@ failed return ERR_PTR(err); }
- static inline void init_tunnel_flow(struct flowi4 *fl4, - int proto, - __be32 daddr, __be32 saddr, - __be32 key, __u8 tos, int oif, - __u32 mark) - { - memset(fl4, 0, sizeof(*fl4)); - fl4->flowi4_oif = oif; - fl4->daddr = daddr; - fl4->saddr = saddr; - fl4->flowi4_tos = tos; - fl4->flowi4_proto = proto; - fl4->fl4_gre_key = key; - fl4->flowi4_mark = mark; - } - static int ip_tunnel_bind_dev(struct net_device *dev) { struct net_device *tdev = NULL; @@@ -322,10 -306,10 +306,10 @@@ struct flowi4 fl4; struct rtable *rt;
- init_tunnel_flow(&fl4, iph->protocol, iph->daddr, - iph->saddr, tunnel->parms.o_key, - RT_TOS(iph->tos), tunnel->parms.link, - tunnel->fwmark); + ip_tunnel_init_flow(&fl4, iph->protocol, iph->daddr, + iph->saddr, tunnel->parms.o_key, + RT_TOS(iph->tos), tunnel->parms.link, + tunnel->fwmark); rt = ip_route_output_key(tunnel->net, &fl4);
if (!IS_ERR(rt)) { @@@ -363,8 -347,7 +347,7 @@@ static struct ip_tunnel *ip_tunnel_crea struct net_device *dev; int t_hlen;
- BUG_ON(!itn->fb_tunnel_dev); - dev = __ip_tunnel_create(net, itn->fb_tunnel_dev->rtnl_link_ops, parms); + dev = __ip_tunnel_create(net, itn->rtnl_link_ops, parms); if (IS_ERR(dev)) return ERR_CAST(dev);
@@@ -581,8 -564,8 +564,8 @@@ void ip_md_tunnel_xmit(struct sk_buff * else if (skb->protocol == htons(ETH_P_IPV6)) tos = ipv6_get_dsfield((const struct ipv6hdr *)inner_iph); } - init_tunnel_flow(&fl4, proto, key->u.ipv4.dst, key->u.ipv4.src, 0, - RT_TOS(tos), tunnel->parms.link, tunnel->fwmark); + ip_tunnel_init_flow(&fl4, proto, key->u.ipv4.dst, key->u.ipv4.src, 0, + RT_TOS(tos), tunnel->parms.link, tunnel->fwmark); if (tunnel->encap.type != TUNNEL_ENCAP_NONE) goto tx_error; rt = ip_route_output_key(tunnel->net, &fl4); @@@ -710,9 -693,9 +693,9 @@@ void ip_tunnel_xmit(struct sk_buff *skb } }
- init_tunnel_flow(&fl4, protocol, dst, tnl_params->saddr, - tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link, - tunnel->fwmark); + ip_tunnel_init_flow(&fl4, protocol, dst, tnl_params->saddr, + tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link, + tunnel->fwmark);
if (ip_tunnel_encap(skb, tunnel, &protocol, &fl4) < 0) goto tx_error; @@@ -838,7 -821,6 +821,6 @@@ int ip_tunnel_ioctl(struct net_device * struct net *net = t->net; struct ip_tunnel_net *itn = net_generic(net, t->ip_tnl_net_id);
- BUG_ON(!itn->fb_tunnel_dev); switch (cmd) { case SIOCGETTUNNEL: if (dev == itn->fb_tunnel_dev) { @@@ -863,7 -845,7 +845,7 @@@ p->o_key = 0; }
- t = ip_tunnel_find(itn, p, itn->fb_tunnel_dev->type); + t = ip_tunnel_find(itn, p, itn->type);
if (cmd == SIOCADDTUNNEL) { if (!t) { @@@ -1007,10 -989,15 +989,15 @@@ int ip_tunnel_init_net(struct net *net struct ip_tunnel_parm parms; unsigned int i;
+ itn->rtnl_link_ops = ops; for (i = 0; i < IP_TNL_HASH_SIZE; i++) INIT_HLIST_HEAD(&itn->tunnels[i]);
- if (!ops) { + if (!ops || !net_has_fallback_tunnels(net)) { + struct ip_tunnel_net *it_init_net; + + it_init_net = net_generic(&init_net, ip_tnl_net_id); + itn->type = it_init_net->type; itn->fb_tunnel_dev = NULL; return 0; } @@@ -1028,6 -1015,7 +1015,7 @@@ itn->fb_tunnel_dev->features |= NETIF_F_NETNS_LOCAL; itn->fb_tunnel_dev->mtu = ip_tunnel_bind_dev(itn->fb_tunnel_dev); ip_tunnel_add(itn, netdev_priv(itn->fb_tunnel_dev)); + itn->type = itn->fb_tunnel_dev->type; } rtnl_unlock();
@@@ -1035,10 -1023,10 +1023,10 @@@ } EXPORT_SYMBOL_GPL(ip_tunnel_init_net);
- static void ip_tunnel_destroy(struct ip_tunnel_net *itn, struct list_head *head, + static void ip_tunnel_destroy(struct net *net, struct ip_tunnel_net *itn, + struct list_head *head, struct rtnl_link_ops *ops) { - struct net *net = dev_net(itn->fb_tunnel_dev); struct net_device *dev, *aux; int h;
@@@ -1070,7 -1058,7 +1058,7 @@@ void ip_tunnel_delete_nets(struct list_ rtnl_lock(); list_for_each_entry(net, net_list, exit_list) { itn = net_generic(net, id); - ip_tunnel_destroy(itn, &list, ops); + ip_tunnel_destroy(net, itn, &list, ops); } unregister_netdevice_many(&list); rtnl_unlock(); @@@ -1108,14 -1096,8 +1096,14 @@@ int ip_tunnel_newlink(struct net_devic eth_hw_addr_random(dev);
mtu = ip_tunnel_bind_dev(dev); - if (!tb[IFLA_MTU]) + if (tb[IFLA_MTU]) { + unsigned int max = 0xfff8 - dev->hard_header_len - nt->hlen; + + dev->mtu = clamp(dev->mtu, (unsigned int)ETH_MIN_MTU, + (unsigned int)(max - sizeof(struct iphdr))); + } else { dev->mtu = mtu; + }
ip_tunnel_add(itn, nt); out: diff --combined net/ipv4/ip_vti.c index 3f091ccad9af,b10bf563afd9..68e367eeee06 --- a/net/ipv4/ip_vti.c +++ b/net/ipv4/ip_vti.c @@@ -387,6 -387,8 +387,6 @@@ static int vti_tunnel_init(struct net_d memcpy(dev->dev_addr, &iph->saddr, 4); memcpy(dev->broadcast, &iph->daddr, 4);
- dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr); - dev->mtu = ETH_DATA_LEN; dev->flags = IFF_NOARP; dev->addr_len = 4; dev->features |= NETIF_F_LLTX; @@@ -452,6 -454,7 +452,7 @@@ static struct pernet_operations vti_net .exit_batch = vti_exit_batch_net, .id = &vti_net_id, .size = sizeof(struct ip_tunnel_net), + .async = true, };
static int vti_tunnel_validate(struct nlattr *tb[], struct nlattr *data[], diff --combined net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 9db988f9a4d7,6531f69db010..51e89247c621 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@@ -154,20 -154,8 +154,20 @@@ static unsigned int ipv4_conntrack_loca struct sk_buff *skb, const struct nf_hook_state *state) { - if (ip_is_fragment(ip_hdr(skb))) /* IP_NODEFRAG setsockopt set */ + if (ip_is_fragment(ip_hdr(skb))) { /* IP_NODEFRAG setsockopt set */ + enum ip_conntrack_info ctinfo; + struct nf_conn *tmpl; + + tmpl = nf_ct_get(skb, &ctinfo); + if (tmpl && nf_ct_is_template(tmpl)) { + /* when skipping ct, clear templates to avoid fooling + * later targets/matches + */ + skb->_nfct = 0; + nf_ct_put(tmpl); + } return NF_ACCEPT; + }
return nf_conntrack_in(state->net, PF_INET, state->hook, skb); } @@@ -411,6 -399,7 +411,7 @@@ static struct pernet_operations ipv4_ne .exit = ipv4_net_exit, .id = &conntrack4_net_id, .size = sizeof(struct conntrack4_net), + .async = true, };
static int __init nf_conntrack_l3proto_ipv4_init(void) diff --combined net/ipv4/route.c index 299e247b2032,e74ee837b300..4ac5728689f5 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@@ -418,6 -418,7 +418,7 @@@ static void __net_exit ip_rt_do_proc_ex static struct pernet_operations ip_rt_proc_ops __net_initdata = { .init = ip_rt_do_proc_init, .exit = ip_rt_do_proc_exit, + .async = true, };
static int __init ip_rt_proc_init(void) @@@ -634,7 -635,6 +635,7 @@@ static inline u32 fnhe_hashfun(__be32 d static void fill_route_from_fnhe(struct rtable *rt, struct fib_nh_exception *fnhe) { rt->rt_pmtu = fnhe->fnhe_pmtu; + rt->rt_mtu_locked = fnhe->fnhe_mtu_locked; rt->dst.expires = fnhe->fnhe_expires;
if (fnhe->fnhe_gw) { @@@ -645,7 -645,7 +646,7 @@@ }
static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw, - u32 pmtu, unsigned long expires) + u32 pmtu, bool lock, unsigned long expires) { struct fnhe_hash_bucket *hash; struct fib_nh_exception *fnhe; @@@ -682,10 -682,8 +683,10 @@@ fnhe->fnhe_genid = genid; if (gw) fnhe->fnhe_gw = gw; - if (pmtu) + if (pmtu) { fnhe->fnhe_pmtu = pmtu; + fnhe->fnhe_mtu_locked = lock; + } fnhe->fnhe_expires = max(1UL, expires); /* Update all cached dsts too */ rt = rcu_dereference(fnhe->fnhe_rth_input); @@@ -709,7 -707,6 +710,7 @@@ fnhe->fnhe_daddr = daddr; fnhe->fnhe_gw = gw; fnhe->fnhe_pmtu = pmtu; + fnhe->fnhe_mtu_locked = lock; fnhe->fnhe_expires = expires;
/* Exception created; mark the cached routes for the nexthop @@@ -791,8 -788,7 +792,8 @@@ static void __ip_do_redirect(struct rta struct fib_nh *nh = &FIB_RES_NH(res);
update_or_create_fnhe(nh, fl4->daddr, new_gw, - 0, jiffies + ip_rt_gc_timeout); + 0, false, + jiffies + ip_rt_gc_timeout); } if (kill_route) rt->dst.obsolete = DST_OBSOLETE_KILL; @@@ -1014,18 -1010,15 +1015,18 @@@ static void __ip_rt_update_pmtu(struct { struct dst_entry *dst = &rt->dst; struct fib_result res; + bool lock = false;
- if (dst_metric_locked(dst, RTAX_MTU)) + if (ip_mtu_locked(dst)) return;
if (ipv4_mtu(dst) < mtu) return;
- if (mtu < ip_rt_min_pmtu) + if (mtu < ip_rt_min_pmtu) { + lock = true; mtu = ip_rt_min_pmtu; + }
if (rt->rt_pmtu == mtu && time_before(jiffies, dst->expires - ip_rt_mtu_expires / 2)) @@@ -1035,7 -1028,7 +1036,7 @@@ if (fib_lookup(dev_net(dst->dev), fl4, &res, 0) == 0) { struct fib_nh *nh = &FIB_RES_NH(res);
- update_or_create_fnhe(nh, fl4->daddr, 0, mtu, + update_or_create_fnhe(nh, fl4->daddr, 0, mtu, lock, jiffies + ip_rt_mtu_expires); } rcu_read_unlock(); @@@ -1288,7 -1281,7 +1289,7 @@@ static unsigned int ipv4_mtu(const stru
mtu = READ_ONCE(dst->dev->mtu);
- if (unlikely(dst_metric_locked(dst, RTAX_MTU))) { + if (unlikely(ip_mtu_locked(dst))) { if (rt->rt_uses_gateway && mtu > 576) mtu = 576; } @@@ -1401,7 -1394,7 +1402,7 @@@ struct uncached_list
static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt_uncached_list);
-static void rt_add_uncached_list(struct rtable *rt) +void rt_add_uncached_list(struct rtable *rt) { struct uncached_list *ul = raw_cpu_ptr(&rt_uncached_list);
@@@ -1412,8 -1405,14 +1413,8 @@@ spin_unlock_bh(&ul->lock); }
-static void ipv4_dst_destroy(struct dst_entry *dst) +void rt_del_uncached_list(struct rtable *rt) { - struct dst_metrics *p = (struct dst_metrics *)DST_METRICS_PTR(dst); - struct rtable *rt = (struct rtable *) dst; - - if (p != &dst_default_metrics && refcount_dec_and_test(&p->refcnt)) - kfree(p); - if (!list_empty(&rt->rt_uncached)) { struct uncached_list *ul = rt->rt_uncached_list;
@@@ -1423,17 -1422,6 +1424,17 @@@ } }
+static void ipv4_dst_destroy(struct dst_entry *dst) +{ + struct dst_metrics *p = (struct dst_metrics *)DST_METRICS_PTR(dst); + struct rtable *rt = (struct rtable *)dst; + + if (p != &dst_default_metrics && refcount_dec_and_test(&p->refcnt)) + kfree(p); + + rt_del_uncached_list(rt); +} + void rt_flush_dev(struct net_device *dev) { struct net *net = dev_net(dev); @@@ -1529,10 -1517,8 +1530,9 @@@ struct rtable *rt_dst_alloc(struct net_ rt->rt_is_input = 0; rt->rt_iif = 0; rt->rt_pmtu = 0; + rt->rt_mtu_locked = 0; rt->rt_gateway = 0; rt->rt_uses_gateway = 0; - rt->rt_table_id = 0; INIT_LIST_HEAD(&rt->rt_uncached);
rt->dst.output = ip_output; @@@ -1668,19 -1654,6 +1668,6 @@@ static void ip_del_fnhe(struct fib_nh * spin_unlock_bh(&fnhe_lock); }
- static void set_lwt_redirect(struct rtable *rth) - { - if (lwtunnel_output_redirect(rth->dst.lwtstate)) { - rth->dst.lwtstate->orig_output = rth->dst.output; - rth->dst.output = lwtunnel_output; - } - - if (lwtunnel_input_redirect(rth->dst.lwtstate)) { - rth->dst.lwtstate->orig_input = rth->dst.input; - rth->dst.input = lwtunnel_input; - } - } - /* called in rcu_read_lock() section */ static int __mkroute_input(struct sk_buff *skb, const struct fib_result *res, @@@ -1763,15 -1736,13 +1750,13 @@@ rt_cache }
rth->rt_is_input = 1; - if (res->table) - rth->rt_table_id = res->table->tb_id; RT_CACHE_STAT_INC(in_slow_tot);
rth->dst.input = ip_forward;
rt_set_nexthop(rth, daddr, res, fnhe, res->fi, res->type, itag, do_cache); - set_lwt_redirect(rth); + lwtunnel_set_redirect(&rth->dst); skb_dst_set(skb, &rth->dst); out: err = 0; @@@ -1787,44 -1758,45 +1772,45 @@@ static void ip_multipath_l3_keys(const struct flow_keys *hash_keys) { const struct iphdr *outer_iph = ip_hdr(skb); + const struct iphdr *key_iph = outer_iph; const struct iphdr *inner_iph; const struct icmphdr *icmph; struct iphdr _inner_iph; struct icmphdr _icmph;
- hash_keys->addrs.v4addrs.src = outer_iph->saddr; - hash_keys->addrs.v4addrs.dst = outer_iph->daddr; if (likely(outer_iph->protocol != IPPROTO_ICMP)) - return; + goto out;
if (unlikely((outer_iph->frag_off & htons(IP_OFFSET)) != 0)) - return; + goto out;
icmph = skb_header_pointer(skb, outer_iph->ihl * 4, sizeof(_icmph), &_icmph); if (!icmph) - return; + goto out;
if (icmph->type != ICMP_DEST_UNREACH && icmph->type != ICMP_REDIRECT && icmph->type != ICMP_TIME_EXCEEDED && icmph->type != ICMP_PARAMETERPROB) - return; + goto out;
inner_iph = skb_header_pointer(skb, outer_iph->ihl * 4 + sizeof(_icmph), sizeof(_inner_iph), &_inner_iph); if (!inner_iph) - return; - hash_keys->addrs.v4addrs.src = inner_iph->saddr; - hash_keys->addrs.v4addrs.dst = inner_iph->daddr; + goto out; + + key_iph = inner_iph; + out: + hash_keys->addrs.v4addrs.src = key_iph->saddr; + hash_keys->addrs.v4addrs.dst = key_iph->daddr; }
/* if skb is set it will be used and fl4 can be NULL */ - int fib_multipath_hash(const struct fib_info *fi, const struct flowi4 *fl4, - const struct sk_buff *skb) + int fib_multipath_hash(const struct net *net, const struct flowi4 *fl4, + const struct sk_buff *skb, struct flow_keys *flkeys) { - struct net *net = fi->fib_net; struct flow_keys hash_keys; u32 mhash;
@@@ -1848,15 -1820,20 +1834,20 @@@ /* short-circuit if we already have L4 hash present */ if (skb->l4_hash) return skb_get_hash_raw(skb) >> 1; + memset(&hash_keys, 0, sizeof(hash_keys)); - skb_flow_dissect_flow_keys(skb, &keys, flag); + + if (!flkeys) { + skb_flow_dissect_flow_keys(skb, &keys, flag); + flkeys = &keys; + }
hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; - hash_keys.addrs.v4addrs.src = keys.addrs.v4addrs.src; - hash_keys.addrs.v4addrs.dst = keys.addrs.v4addrs.dst; - hash_keys.ports.src = keys.ports.src; - hash_keys.ports.dst = keys.ports.dst; - hash_keys.basic.ip_proto = keys.basic.ip_proto; + hash_keys.addrs.v4addrs.src = flkeys->addrs.v4addrs.src; + hash_keys.addrs.v4addrs.dst = flkeys->addrs.v4addrs.dst; + hash_keys.ports.src = flkeys->ports.src; + hash_keys.ports.dst = flkeys->ports.dst; + hash_keys.basic.ip_proto = flkeys->basic.ip_proto; } else { memset(&hash_keys, 0, sizeof(hash_keys)); hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; @@@ -1872,17 -1849,17 +1863,17 @@@
return mhash >> 1; } - EXPORT_SYMBOL_GPL(fib_multipath_hash); #endif /* CONFIG_IP_ROUTE_MULTIPATH */
static int ip_mkroute_input(struct sk_buff *skb, struct fib_result *res, struct in_device *in_dev, - __be32 daddr, __be32 saddr, u32 tos) + __be32 daddr, __be32 saddr, u32 tos, + struct flow_keys *hkeys) { #ifdef CONFIG_IP_ROUTE_MULTIPATH if (res->fi && res->fi->fib_nhs > 1) { - int h = fib_multipath_hash(res->fi, NULL, skb); + int h = fib_multipath_hash(res->fi->fib_net, NULL, skb, hkeys);
fib_select_multipath(res, h); } @@@ -1908,13 -1885,14 +1899,14 @@@ static int ip_route_input_slow(struct s struct fib_result *res) { struct in_device *in_dev = __in_dev_get_rcu(dev); + struct flow_keys *flkeys = NULL, _flkeys; + struct net *net = dev_net(dev); struct ip_tunnel_info *tun_info; - struct flowi4 fl4; + int err = -EINVAL; unsigned int flags = 0; u32 itag = 0; struct rtable *rth; - int err = -EINVAL; - struct net *net = dev_net(dev); + struct flowi4 fl4; bool do_cache;
/* IP on this device is disabled. */ @@@ -1973,6 -1951,10 +1965,10 @@@ fl4.daddr = daddr; fl4.saddr = saddr; fl4.flowi4_uid = sock_net_uid(net, NULL); + + if (fib4_rules_early_flow_dissect(net, skb, &fl4, &_flkeys)) + flkeys = &_flkeys; + err = fib_lookup(net, &fl4, res, 0); if (err != 0) { if (!IN_DEV_FORWARD(in_dev)) @@@ -1998,7 -1980,7 +1994,7 @@@ if (res->type != RTN_UNICAST) goto martian_destination;
- err = ip_mkroute_input(skb, res, in_dev, daddr, saddr, tos); + err = ip_mkroute_input(skb, res, in_dev, daddr, saddr, tos, flkeys); out: return err;
brd_input: @@@ -2040,8 -2022,6 +2036,6 @@@ local_input rth->dst.tclassid = itag; #endif rth->rt_is_input = 1; - if (res->table) - rth->rt_table_id = res->table->tb_id;
RT_CACHE_STAT_INC(in_slow_tot); if (res->type == RTN_UNREACHABLE) { @@@ -2270,8 -2250,6 +2264,6 @@@ add return ERR_PTR(-ENOBUFS);
rth->rt_iif = orig_oif; - if (res->table) - rth->rt_table_id = res->table->tb_id;
RT_CACHE_STAT_INC(out_slow_tot);
@@@ -2293,7 -2271,7 +2285,7 @@@ }
rt_set_nexthop(rth, fl4->daddr, res, fnhe, fi, type, 0, do_cache); - set_lwt_redirect(rth); + lwtunnel_set_redirect(&rth->dst);
return rth; } @@@ -2555,7 -2533,6 +2547,7 @@@ struct dst_entry *ipv4_blackhole_route( rt->rt_is_input = ort->rt_is_input; rt->rt_iif = ort->rt_iif; rt->rt_pmtu = ort->rt_pmtu; + rt->rt_mtu_locked = ort->rt_mtu_locked;
rt->rt_genid = rt_genid_ipv4(net); rt->rt_flags = ort->rt_flags; @@@ -2658,8 -2635,6 +2650,8 @@@ static int rt_fill_info(struct net *net memcpy(metrics, dst_metrics_ptr(&rt->dst), sizeof(metrics)); if (rt->rt_pmtu && expires) metrics[RTAX_MTU - 1] = rt->rt_pmtu; + if (rt->rt_mtu_locked && expires) + metrics[RTAX_LOCK - 1] |= BIT(RTAX_MTU); if (rtnetlink_put_metrics(skb, metrics) < 0) goto nla_put_failure;
@@@ -2804,7 -2779,7 +2796,7 @@@ static int inet_rtm_getroute(struct sk_ rt->rt_flags |= RTCF_NOTIFY;
if (rtm->rtm_flags & RTM_F_LOOKUP_TABLE) - table_id = rt->rt_table_id; + table_id = res.table ? res.table->tb_id : 0;
if (rtm->rtm_flags & RTM_F_FIB_MATCH) { if (!res.fi) { @@@ -3025,6 -3000,7 +3017,7 @@@ static __net_exit void sysctl_route_net static __net_initdata struct pernet_operations sysctl_route_ops = { .init = sysctl_route_net_init, .exit = sysctl_route_net_exit, + .async = true, }; #endif
@@@ -3038,6 -3014,7 +3031,7 @@@ static __net_init int rt_genid_init(str
static __net_initdata struct pernet_operations rt_genid_ops = { .init = rt_genid_init, + .async = true, };
static int __net_init ipv4_inetpeer_init(struct net *net) @@@ -3063,6 -3040,7 +3057,7 @@@ static void __net_exit ipv4_inetpeer_ex static __net_initdata struct pernet_operations ipv4_inetpeer_ops = { .init = ipv4_inetpeer_init, .exit = ipv4_inetpeer_exit, + .async = true, };
#ifdef CONFIG_IP_ROUTE_CLASSID diff --combined net/ipv4/tcp.c index 8b8059b7af4d,d763fae1b574..0c31be306572 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@@ -453,6 -453,7 +453,7 @@@ void tcp_init_sock(struct sock *sk sk->sk_rcvbuf = sock_net(sk)->ipv4.sysctl_tcp_rmem[1];
sk_sockets_allocated_inc(sk); + sk->sk_route_forced_caps = NETIF_F_GSO; } EXPORT_SYMBOL(tcp_init_sock);
@@@ -897,7 -898,7 +898,7 @@@ static unsigned int tcp_xmit_size_goal( struct tcp_sock *tp = tcp_sk(sk); u32 new_size_goal, size_goal;
- if (!large_allowed || !sk_can_gso(sk)) + if (!large_allowed) return mss_now;
/* Note : tcp_tso_autosize() will eventually split this later */ @@@ -993,7 -994,9 +994,9 @@@ new_segment get_page(page); skb_fill_page_desc(skb, i, page, offset, copy); } - skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG; + + if (!(flags & MSG_NO_SHARED_FRAGS)) + skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
skb->len += copy; skb->data_len += copy; @@@ -1062,8 -1065,7 +1065,7 @@@ EXPORT_SYMBOL_GPL(do_tcp_sendpages) int tcp_sendpage_locked(struct sock *sk, struct page *page, int offset, size_t size, int flags) { - if (!(sk->sk_route_caps & NETIF_F_SG) || - !sk_check_csum_caps(sk)) + if (!(sk->sk_route_caps & NETIF_F_SG)) return sock_no_sendpage_locked(sk, page, offset, size, flags);
tcp_rate_check_app_limited(sk); /* is sending application-limited? */ @@@ -1102,27 -1104,11 +1104,11 @@@ static int linear_payload_sz(bool first return 0; }
- static int select_size(const struct sock *sk, bool sg, bool first_skb, bool zc) + static int select_size(bool first_skb, bool zc) { - const struct tcp_sock *tp = tcp_sk(sk); - int tmp = tp->mss_cache; - - if (sg) { - if (zc) - return 0; - - if (sk_can_gso(sk)) { - tmp = linear_payload_sz(first_skb); - } else { - int pgbreak = SKB_MAX_HEAD(MAX_TCP_HEADER); - - if (tmp >= pgbreak && - tmp <= pgbreak + (MAX_SKB_FRAGS - 1) * PAGE_SIZE) - tmp = pgbreak; - } - } - - return tmp; + if (zc) + return 0; + return linear_payload_sz(first_skb); }
void tcp_free_fastopen_req(struct tcp_sock *tp) @@@ -1187,7 -1173,7 +1173,7 @@@ int tcp_sendmsg_locked(struct sock *sk int flags, err, copied = 0; int mss_now = 0, size_goal, copied_syn = 0; bool process_backlog = false; - bool sg, zc = false; + bool zc = false; long timeo;
flags = msg->msg_flags; @@@ -1205,7 -1191,7 +1191,7 @@@ goto out_err; }
- zc = sk_check_csum_caps(sk) && sk->sk_route_caps & NETIF_F_SG; + zc = sk->sk_route_caps & NETIF_F_SG; if (!zc) uarg->zerocopy = 0; } @@@ -1268,18 -1254,12 +1254,12 @@@ restart if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN)) goto do_error;
- sg = !!(sk->sk_route_caps & NETIF_F_SG); - while (msg_data_left(msg)) { int copy = 0; - int max = size_goal;
skb = tcp_write_queue_tail(sk); - if (skb) { - if (skb->ip_summed == CHECKSUM_NONE) - max = mss_now; - copy = max - skb->len; - } + if (skb) + copy = size_goal - skb->len;
if (copy <= 0 || !tcp_skb_can_collapse_to(skb)) { bool first_skb; @@@ -1297,22 -1277,17 +1277,17 @@@ new_segment goto restart; } first_skb = tcp_rtx_and_write_queues_empty(sk); - linear = select_size(sk, sg, first_skb, zc); + linear = select_size(first_skb, zc); skb = sk_stream_alloc_skb(sk, linear, sk->sk_allocation, first_skb); if (!skb) goto wait_for_memory;
process_backlog = true; - /* - * Check whether we can use HW checksum. - */ - if (sk_check_csum_caps(sk)) - skb->ip_summed = CHECKSUM_PARTIAL; + skb->ip_summed = CHECKSUM_PARTIAL;
skb_entail(sk, skb); copy = size_goal; - max = size_goal;
/* All packets are restored as if they have * already been sent. skb_mstamp isn't set to @@@ -1343,7 -1318,7 +1318,7 @@@
if (!skb_can_coalesce(skb, i, pfrag->page, pfrag->offset)) { - if (i >= sysctl_max_skb_frags || !sg) { + if (i >= sysctl_max_skb_frags) { tcp_mark_push(tp, skb); goto new_segment; } @@@ -1396,7 -1371,7 +1371,7 @@@ goto out; }
- if (skb->len < max || (flags & MSG_OOB) || unlikely(tp->repair)) + if (skb->len < size_goal || (flags & MSG_OOB) || unlikely(tp->repair)) continue;
if (forced_push(tp)) { @@@ -3058,8 -3033,8 +3033,8 @@@ struct sk_buff *tcp_get_timestamping_op u32 rate;
stats = alloc_skb(7 * nla_total_size_64bit(sizeof(u64)) + - 3 * nla_total_size(sizeof(u32)) + - 2 * nla_total_size(sizeof(u8)), GFP_ATOMIC); + 5 * nla_total_size(sizeof(u32)) + + 3 * nla_total_size(sizeof(u8)), GFP_ATOMIC); if (!stats) return NULL;
@@@ -3088,6 -3063,10 +3063,10 @@@
nla_put_u8(stats, TCP_NLA_RECUR_RETRANS, inet_csk(sk)->icsk_retransmits); nla_put_u8(stats, TCP_NLA_DELIVERY_RATE_APP_LMT, !!tp->rate_app_limited); + nla_put_u32(stats, TCP_NLA_SND_SSTHRESH, tp->snd_ssthresh); + + nla_put_u32(stats, TCP_NLA_SNDQ_SIZE, tp->write_seq - tp->snd_una); + nla_put_u8(stats, TCP_NLA_CA_STATE, inet_csk(sk)->icsk_ca_state); return stats; }
@@@ -3566,7 -3545,6 +3545,7 @@@ int tcp_abort(struct sock *sk, int err
bh_unlock_sock(sk); local_bh_enable(); + tcp_write_queue_purge(sk); release_sock(sk); return 0; } diff --combined net/ipv4/xfrm4_policy.c index fbebda67ac1b,0c752dc3f93b..6c76a757fa4a --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@@ -100,10 -100,7 +100,9 @@@ static int xfrm4_fill_dst(struct xfrm_d xdst->u.rt.rt_gateway = rt->rt_gateway; xdst->u.rt.rt_uses_gateway = rt->rt_uses_gateway; xdst->u.rt.rt_pmtu = rt->rt_pmtu; + xdst->u.rt.rt_mtu_locked = rt->rt_mtu_locked; - xdst->u.rt.rt_table_id = rt->rt_table_id; INIT_LIST_HEAD(&xdst->u.rt.rt_uncached); + rt_add_uncached_list(&xdst->u.rt);
return 0; } @@@ -243,8 -240,7 +242,8 @@@ static void xfrm4_dst_destroy(struct ds struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
dst_destroy_metrics_generic(dst); - + if (xdst->u.rt.rt_uncached_list) + rt_del_uncached_list(&xdst->u.rt); xfrm_dst_destroy(xdst); }
@@@ -368,6 -364,7 +367,7 @@@ static void __net_exit xfrm4_net_exit(s static struct pernet_operations __net_initdata xfrm4_net_ops = { .init = xfrm4_net_init, .exit = xfrm4_net_exit, + .async = true, };
static void __init xfrm4_policy_init(void) @@@ -382,4 -379,3 +382,3 @@@ void __init xfrm4_init(void xfrm4_protocol_init(); register_pernet_subsys(&xfrm4_net_ops); } - diff --combined net/ipv6/datagram.c index a9f7eca0b6a3,b27333d7b099..88bc2ef7c7a8 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@@ -146,12 -146,10 +146,12 @@@ int __ip6_datagram_connect(struct sock struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr; struct inet_sock *inet = inet_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk); - struct in6_addr *daddr; + struct in6_addr *daddr, old_daddr; + __be32 fl6_flowlabel = 0; + __be32 old_fl6_flowlabel; + __be16 old_dport; int addr_type; int err; - __be32 fl6_flowlabel = 0;
if (usin->sin6_family == AF_INET) { if (__ipv6_only_sock(sk)) @@@ -240,13 -238,9 +240,13 @@@ ipv4_connected } }
+ /* save the current peer information before updating it */ + old_daddr = sk->sk_v6_daddr; + old_fl6_flowlabel = np->flow_label; + old_dport = inet->inet_dport; + sk->sk_v6_daddr = *daddr; np->flow_label = fl6_flowlabel; - inet->inet_dport = usin->sin6_port;
/* @@@ -256,12 -250,11 +256,12 @@@
err = ip6_datagram_dst_update(sk, true); if (err) { - /* Reset daddr and dport so that udp_v6_early_demux() - * fails to find this socket + /* Restore the socket peer info, to keep it consistent with + * the old socket state */ - memset(&sk->sk_v6_daddr, 0, sizeof(sk->sk_v6_daddr)); - inet->inet_dport = 0; + sk->sk_v6_daddr = old_daddr; + np->flow_label = old_fl6_flowlabel; + inet->inet_dport = old_dport; goto out; }
@@@ -808,8 -801,9 +808,9 @@@ int ip6_datagram_send_ctl(struct net *n if (addr_type != IPV6_ADDR_ANY) { int strict = __ipv6_addr_src_scope(addr_type) <= IPV6_ADDR_SCOPE_LINKLOCAL; if (!(inet_sk(sk)->freebind || inet_sk(sk)->transparent) && - !ipv6_chk_addr(net, &src_info->ipi6_addr, - strict ? dev : NULL, 0) && + !ipv6_chk_addr_and_flags(net, &src_info->ipi6_addr, + dev, !strict, 0, + IFA_F_TENTATIVE) && !ipv6_chk_acast_addr_src(net, dev, &src_info->ipi6_addr)) err = -EINVAL; diff --combined net/ipv6/ip6_gre.c index 1bbd0930063e,6adbcf40cf8c..3a98c694da5f --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@@ -126,8 -126,7 +126,8 @@@ static struct ip6_tnl *ip6gre_tunnel_lo struct ip6_tnl *t, *cand = NULL; struct ip6gre_net *ign = net_generic(net, ip6gre_net_id); int dev_type = (gre_proto == htons(ETH_P_TEB) || - gre_proto == htons(ETH_P_ERSPAN)) ? + gre_proto == htons(ETH_P_ERSPAN) || + gre_proto == htons(ETH_P_ERSPAN2)) ? ARPHRD_ETHER : ARPHRD_IP6GRE; int score, cand_score = 4;
@@@ -237,7 -236,7 +237,7 @@@ return t;
dev = ign->fb_tunnel_dev; - if (dev->flags & IFF_UP) + if (dev && dev->flags & IFF_UP) return netdev_priv(dev);
return NULL; @@@ -696,9 -695,6 +696,6 @@@ static netdev_tx_t __gre6_xmit(struct s else fl6->daddr = tunnel->parms.raddr;
- if (tunnel->parms.o_flags & TUNNEL_SEQ) - tunnel->o_seqno++; - /* Push GRE header. */ protocol = (dev->type == ARPHRD_ETHER) ? htons(ETH_P_TEB) : proto;
@@@ -721,14 -717,20 +718,20 @@@ fl6->flowi6_uid = sock_net_uid(dev_net(dev), NULL);
dsfield = key->tos; - flags = key->tun_flags & (TUNNEL_CSUM | TUNNEL_KEY); + flags = key->tun_flags & + (TUNNEL_CSUM | TUNNEL_KEY | TUNNEL_SEQ); tunnel->tun_hlen = gre_calc_hlen(flags);
gre_build_header(skb, tunnel->tun_hlen, flags, protocol, - tunnel_id_to_key32(tun_info->key.tun_id), 0); + tunnel_id_to_key32(tun_info->key.tun_id), + (flags & TUNNEL_SEQ) ? htonl(tunnel->o_seqno++) + : 0);
} else { + if (tunnel->parms.o_flags & TUNNEL_SEQ) + tunnel->o_seqno++; + gre_build_header(skb, tunnel->tun_hlen, tunnel->parms.o_flags, protocol, tunnel->parms.o_key, htonl(tunnel->o_seqno)); @@@ -903,9 -905,6 +906,9 @@@ static netdev_tx_t ip6erspan_tunnel_xmi truncate = true; }
+ if (skb_cow_head(skb, dev->needed_headroom)) + goto tx_err; + t->parms.o_flags &= ~TUNNEL_KEY; IPCB(skb)->flags = 0;
@@@ -948,8 -947,6 +951,8 @@@ md->u.md2.dir, get_hwid(&md->u.md2), truncate, false); + } else { + goto tx_err; } } else { switch (skb->protocol) { @@@ -1059,7 -1056,7 +1062,7 @@@ static void ip6gre_tnl_link_config(stru
struct rt6_info *rt = rt6_lookup(t->net, &p->raddr, &p->laddr, - p->link, strict); + p->link, NULL, strict);
if (!rt) return; @@@ -1475,6 -1472,8 +1478,8 @@@ static int __net_init ip6gre_init_net(s struct ip6gre_net *ign = net_generic(net, ip6gre_net_id); int err;
+ if (!net_has_fallback_tunnels(net)) + return 0; ign->fb_tunnel_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6gre0", NET_NAME_UNKNOWN, ip6gre_tunnel_setup); @@@ -1523,6 -1522,7 +1528,7 @@@ static struct pernet_operations ip6gre_ .exit_batch = ip6gre_exit_batch_net, .id = &ip6gre_net_id, .size = sizeof(struct ip6gre_net), + .async = true, };
static int ip6gre_tunnel_validate(struct nlattr *tb[], struct nlattr *data[], @@@ -1790,6 -1790,12 +1796,12 @@@ static void ip6gre_tap_setup(struct net netif_keep_dst(dev); }
+ bool is_ip6gretap_dev(const struct net_device *dev) + { + return dev->netdev_ops == &ip6gre_tap_netdev_ops; + } + EXPORT_SYMBOL_GPL(is_ip6gretap_dev); + static bool ip6gre_netlink_encap_parms(struct nlattr *data[], struct ip_tunnel_encap *ipencap) { diff --combined net/ipv6/ip6_vti.c index ce18cd20389d,a482b854eeea..67aa9e22e706 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c @@@ -622,12 -622,11 +622,12 @@@ static int vti6_err(struct sk_buff *skb return 0; }
-static void vti6_link_config(struct ip6_tnl *t) +static void vti6_link_config(struct ip6_tnl *t, bool keep_mtu) { struct net_device *dev = t->dev; struct __ip6_tnl_parm *p = &t->parms; struct net_device *tdev = NULL; + int mtu;
memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr)); memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr)); @@@ -641,17 -640,12 +641,17 @@@ else dev->flags &= ~IFF_POINTOPOINT;
+ if (keep_mtu && dev->mtu) { + dev->mtu = clamp(dev->mtu, dev->min_mtu, dev->max_mtu); + return; + } + if (p->flags & IP6_TNL_F_CAP_XMIT) { int strict = (ipv6_addr_type(&p->raddr) & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL)); struct rt6_info *rt = rt6_lookup(t->net, &p->raddr, &p->laddr, - p->link, strict); + p->link, NULL, strict);
if (rt) tdev = rt->dst.dev; @@@ -662,25 -656,20 +662,25 @@@ tdev = __dev_get_by_index(t->net, p->link);
if (tdev) - dev->mtu = max_t(int, tdev->mtu - dev->hard_header_len, - IPV6_MIN_MTU); + mtu = tdev->mtu - sizeof(struct ipv6hdr); + else + mtu = ETH_DATA_LEN - LL_MAX_HEADER - sizeof(struct ipv6hdr); + + dev->mtu = max_t(int, mtu, IPV6_MIN_MTU); }
/** * vti6_tnl_change - update the tunnel parameters * @t: tunnel to be changed * @p: tunnel configuration parameters + * @keep_mtu: MTU was set from userspace, don't re-compute it * * Description: * vti6_tnl_change() updates the tunnel parameters **/ static int -vti6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p) +vti6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p, + bool keep_mtu) { t->parms.laddr = p->laddr; t->parms.raddr = p->raddr; @@@ -690,12 -679,11 +690,12 @@@ t->parms.proto = p->proto; t->parms.fwmark = p->fwmark; dst_cache_reset(&t->dst_cache); - vti6_link_config(t); + vti6_link_config(t, keep_mtu); return 0; }
-static int vti6_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p) +static int vti6_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p, + bool keep_mtu) { struct net *net = dev_net(t->dev); struct vti6_net *ip6n = net_generic(net, vti6_net_id); @@@ -703,7 -691,7 +703,7 @@@
vti6_tnl_unlink(ip6n, t); synchronize_net(); - err = vti6_tnl_change(t, p); + err = vti6_tnl_change(t, p, keep_mtu); vti6_tnl_link(ip6n, t); netdev_state_change(t->dev); return err; @@@ -816,7 -804,7 +816,7 @@@ vti6_ioctl(struct net_device *dev, stru } else t = netdev_priv(dev);
- err = vti6_update(t, &p1); + err = vti6_update(t, &p1, false); } if (t) { err = 0; @@@ -878,8 -866,10 +878,8 @@@ static void vti6_dev_setup(struct net_d dev->priv_destructor = vti6_dev_free;
dev->type = ARPHRD_TUNNEL6; - dev->hard_header_len = LL_MAX_HEADER + sizeof(struct ipv6hdr); - dev->mtu = ETH_DATA_LEN; dev->min_mtu = IPV6_MIN_MTU; - dev->max_mtu = IP_MAX_MTU; + dev->max_mtu = IP_MAX_MTU - sizeof(struct ipv6hdr); dev->flags |= IFF_NOARP; dev->addr_len = sizeof(struct in6_addr); netif_keep_dst(dev); @@@ -915,7 -905,7 +915,7 @@@ static int vti6_dev_init(struct net_dev
if (err) return err; - vti6_link_config(t); + vti6_link_config(t, true); return 0; }
@@@ -1020,7 -1010,7 +1020,7 @@@ static int vti6_changelink(struct net_d } else t = netdev_priv(dev);
- return vti6_update(t, &p); + return vti6_update(t, &p, tb && tb[IFLA_MTU]); }
static size_t vti6_get_size(const struct net_device *dev) @@@ -1158,6 -1148,7 +1158,7 @@@ static struct pernet_operations vti6_ne .exit_batch = vti6_exit_batch_net, .id = &vti6_net_id, .size = sizeof(struct vti6_net), + .async = true, };
static struct xfrm6_protocol vti_esp6_protocol __read_mostly = { diff --combined net/ipv6/ndisc.c index ba5e04c6ae17,10024eb0c521..d1d0b2fa7a07 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@@ -527,7 -527,7 +527,7 @@@ void ndisc_send_na(struct net_device *d }
if (!dev->addr_len) - inc_opt = 0; + inc_opt = false; if (inc_opt) optlen += ndisc_opt_addr_space(dev, NDISC_NEIGHBOUR_ADVERTISEMENT); @@@ -707,7 -707,7 +707,7 @@@ static void ndisc_solicit(struct neighb int probes = atomic_read(&neigh->probes);
if (skb && ipv6_chk_addr_and_flags(dev_net(dev), &ipv6_hdr(skb)->saddr, - dev, 1, + dev, false, 1, IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) saddr = &ipv6_hdr(skb)->saddr; probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES); @@@ -1554,8 -1554,7 +1554,8 @@@ static void ndisc_fill_redirect_hdr_opt *(opt++) = (rd_len >> 3); opt += 6;
- memcpy(opt, ipv6_hdr(orig_skb), rd_len - 8); + skb_copy_bits(orig_skb, skb_network_offset(orig_skb), opt, + rd_len - 8); }
void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) @@@ -1883,6 -1882,7 +1883,7 @@@ static void __net_exit ndisc_net_exit(s static struct pernet_operations ndisc_net_ops = { .init = ndisc_net_init, .exit = ndisc_net_exit, + .async = true, };
int __init ndisc_init(void) diff --combined net/ipv6/route.c index b0d5c64e1978,939d122e71b4..a2ed9fdd58d4 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@@ -128,7 -128,7 +128,7 @@@ struct uncached_list
static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt6_uncached_list);
-static void rt6_uncached_list_add(struct rt6_info *rt) +void rt6_uncached_list_add(struct rt6_info *rt) { struct uncached_list *ul = raw_cpu_ptr(&rt6_uncached_list);
@@@ -139,7 -139,7 +139,7 @@@ spin_unlock_bh(&ul->lock); }
-static void rt6_uncached_list_del(struct rt6_info *rt) +void rt6_uncached_list_del(struct rt6_info *rt) { if (!list_empty(&rt->rt6i_uncached)) { struct uncached_list *ul = rt->rt6i_uncached_list; @@@ -450,8 -450,10 +450,10 @@@ static bool rt6_check_expired(const str return false; }
- static struct rt6_info *rt6_multipath_select(struct rt6_info *match, + static struct rt6_info *rt6_multipath_select(const struct net *net, + struct rt6_info *match, struct flowi6 *fl6, int oif, + const struct sk_buff *skb, int strict) { struct rt6_info *sibling, *next_sibling; @@@ -460,7 -462,7 +462,7 @@@ * case it will always be non-zero. Otherwise now is the time to do it. */ if (!fl6->mp_hash) - fl6->mp_hash = rt6_multipath_hash(fl6, NULL); + fl6->mp_hash = rt6_multipath_hash(net, fl6, skb, NULL);
if (fl6->mp_hash <= atomic_read(&match->rt6i_nh_upper_bound)) return match; @@@ -914,7 -916,9 +916,9 @@@ static bool ip6_hold_safe(struct net *n
static struct rt6_info *ip6_pol_route_lookup(struct net *net, struct fib6_table *table, - struct flowi6 *fl6, int flags) + struct flowi6 *fl6, + const struct sk_buff *skb, + int flags) { struct rt6_info *rt, *rt_cache; struct fib6_node *fn; @@@ -929,8 -933,8 +933,8 @@@ restart rt = rt6_device_match(net, rt, &fl6->saddr, fl6->flowi6_oif, flags); if (rt->rt6i_nsiblings && fl6->flowi6_oif == 0) - rt = rt6_multipath_select(rt, fl6, - fl6->flowi6_oif, flags); + rt = rt6_multipath_select(net, rt, fl6, fl6->flowi6_oif, + skb, flags); } if (rt == net->ipv6.ip6_null_entry) { fn = fib6_backtrack(fn, &fl6->saddr); @@@ -954,14 -958,15 +958,15 @@@ }
struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6, - int flags) + const struct sk_buff *skb, int flags) { - return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_lookup); + return fib6_rule_lookup(net, fl6, skb, flags, ip6_pol_route_lookup); } EXPORT_SYMBOL_GPL(ip6_route_lookup);
struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr, - const struct in6_addr *saddr, int oif, int strict) + const struct in6_addr *saddr, int oif, + const struct sk_buff *skb, int strict) { struct flowi6 fl6 = { .flowi6_oif = oif, @@@ -975,7 -980,7 +980,7 @@@ flags |= RT6_LOOKUP_F_HAS_SADDR; }
- dst = fib6_rule_lookup(net, &fl6, flags, ip6_pol_route_lookup); + dst = fib6_rule_lookup(net, &fl6, skb, flags, ip6_pol_route_lookup); if (dst->error == 0) return (struct rt6_info *) dst;
@@@ -1509,30 -1514,7 +1514,30 @@@ static void rt6_exceptions_remove_prefs } }
-static void rt6_exceptions_update_pmtu(struct rt6_info *rt, int mtu) +static bool rt6_mtu_change_route_allowed(struct inet6_dev *idev, + struct rt6_info *rt, int mtu) +{ + /* If the new MTU is lower than the route PMTU, this new MTU will be the + * lowest MTU in the path: always allow updating the route PMTU to + * reflect PMTU decreases. + * + * If the new MTU is higher, and the route PMTU is equal to the local + * MTU, this means the old MTU is the lowest in the path, so allow + * updating it: if other nodes now have lower MTUs, PMTU discovery will + * handle this. + */ + + if (dst_mtu(&rt->dst) >= mtu) + return true; + + if (dst_mtu(&rt->dst) == idev->cnf.mtu6) + return true; + + return false; +} + +static void rt6_exceptions_update_pmtu(struct inet6_dev *idev, + struct rt6_info *rt, int mtu) { struct rt6_exception_bucket *bucket; struct rt6_exception *rt6_ex; @@@ -1541,22 -1523,20 +1546,22 @@@ bucket = rcu_dereference_protected(rt->rt6i_exception_bucket, lockdep_is_held(&rt6_exception_lock));
- if (bucket) { - for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) { - hlist_for_each_entry(rt6_ex, &bucket->chain, hlist) { - struct rt6_info *entry = rt6_ex->rt6i; - /* For RTF_CACHE with rt6i_pmtu == 0 - * (i.e. a redirected route), - * the metrics of its rt->dst.from has already - * been updated. - */ - if (entry->rt6i_pmtu && entry->rt6i_pmtu > mtu) - entry->rt6i_pmtu = mtu; - } - bucket++; + if (!bucket) + return; + + for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) { + hlist_for_each_entry(rt6_ex, &bucket->chain, hlist) { + struct rt6_info *entry = rt6_ex->rt6i; + + /* For RTF_CACHE with rt6i_pmtu == 0 (i.e. a redirected + * route), the metrics of its rt->dst.from have already + * been updated. + */ + if (entry->rt6i_pmtu && + rt6_mtu_change_route_allowed(idev, entry, mtu)) + entry->rt6i_pmtu = mtu; } + bucket++; } }
@@@ -1672,7 -1652,8 +1677,8 @@@ void rt6_age_exceptions(struct rt6_inf }
struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, - int oif, struct flowi6 *fl6, int flags) + int oif, struct flowi6 *fl6, + const struct sk_buff *skb, int flags) { struct fib6_node *fn, *saved_fn; struct rt6_info *rt, *rt_cache; @@@ -1694,7 -1675,7 +1700,7 @@@ redo_rt6_select: rt = rt6_select(net, fn, oif, strict); if (rt->rt6i_nsiblings) - rt = rt6_multipath_select(rt, fl6, oif, strict); + rt = rt6_multipath_select(net, rt, fl6, oif, skb, strict); if (rt == net->ipv6.ip6_null_entry) { fn = fib6_backtrack(fn, &fl6->saddr); if (fn) @@@ -1793,28 -1774,35 +1799,35 @@@ uncached_rt_out } EXPORT_SYMBOL_GPL(ip6_pol_route);
- static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table, - struct flowi6 *fl6, int flags) + static struct rt6_info *ip6_pol_route_input(struct net *net, + struct fib6_table *table, + struct flowi6 *fl6, + const struct sk_buff *skb, + int flags) { - return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, flags); + return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, skb, flags); }
struct dst_entry *ip6_route_input_lookup(struct net *net, struct net_device *dev, - struct flowi6 *fl6, int flags) + struct flowi6 *fl6, + const struct sk_buff *skb, + int flags) { if (rt6_need_strict(&fl6->daddr) && dev->type != ARPHRD_PIMREG) flags |= RT6_LOOKUP_F_IFACE;
- return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_input); + return fib6_rule_lookup(net, fl6, skb, flags, ip6_pol_route_input); } EXPORT_SYMBOL_GPL(ip6_route_input_lookup);
static void ip6_multipath_l3_keys(const struct sk_buff *skb, - struct flow_keys *keys) + struct flow_keys *keys, + struct flow_keys *flkeys) { const struct ipv6hdr *outer_iph = ipv6_hdr(skb); const struct ipv6hdr *key_iph = outer_iph; + struct flow_keys *_flkeys = flkeys; const struct ipv6hdr *inner_iph; const struct icmp6hdr *icmph; struct ipv6hdr _inner_iph; @@@ -1836,26 -1824,76 +1849,76 @@@ goto out;
key_iph = inner_iph; + _flkeys = NULL; out: - memset(keys, 0, sizeof(*keys)); - keys->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; - keys->addrs.v6addrs.src = key_iph->saddr; - keys->addrs.v6addrs.dst = key_iph->daddr; - keys->tags.flow_label = ip6_flowinfo(key_iph); - keys->basic.ip_proto = key_iph->nexthdr; + if (_flkeys) { + keys->addrs.v6addrs.src = _flkeys->addrs.v6addrs.src; + keys->addrs.v6addrs.dst = _flkeys->addrs.v6addrs.dst; + keys->tags.flow_label = _flkeys->tags.flow_label; + keys->basic.ip_proto = _flkeys->basic.ip_proto; + } else { + keys->addrs.v6addrs.src = key_iph->saddr; + keys->addrs.v6addrs.dst = key_iph->daddr; + keys->tags.flow_label = ip6_flowinfo(key_iph); + keys->basic.ip_proto = key_iph->nexthdr; + } }
/* if skb is set it will be used and fl6 can be NULL */ - u32 rt6_multipath_hash(const struct flowi6 *fl6, const struct sk_buff *skb) + u32 rt6_multipath_hash(const struct net *net, const struct flowi6 *fl6, + const struct sk_buff *skb, struct flow_keys *flkeys) { struct flow_keys hash_keys; + u32 mhash;
- if (skb) { - ip6_multipath_l3_keys(skb, &hash_keys); - return flow_hash_from_keys(&hash_keys) >> 1; + switch (ip6_multipath_hash_policy(net)) { + case 0: + memset(&hash_keys, 0, sizeof(hash_keys)); + hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; + if (skb) { + ip6_multipath_l3_keys(skb, &hash_keys, flkeys); + } else { + hash_keys.addrs.v6addrs.src = fl6->saddr; + hash_keys.addrs.v6addrs.dst = fl6->daddr; + hash_keys.tags.flow_label = (__force u32)fl6->flowlabel; + hash_keys.basic.ip_proto = fl6->flowi6_proto; + } + break; + case 1: + if (skb) { + unsigned int flag = FLOW_DISSECTOR_F_STOP_AT_ENCAP; + struct flow_keys keys; + + /* short-circuit if we already have L4 hash present */ + if (skb->l4_hash) + return skb_get_hash_raw(skb) >> 1; + + memset(&hash_keys, 0, sizeof(hash_keys)); + + if (!flkeys) { + skb_flow_dissect_flow_keys(skb, &keys, flag); + flkeys = &keys; + } + hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; + hash_keys.addrs.v6addrs.src = flkeys->addrs.v6addrs.src; + hash_keys.addrs.v6addrs.dst = flkeys->addrs.v6addrs.dst; + hash_keys.ports.src = flkeys->ports.src; + hash_keys.ports.dst = flkeys->ports.dst; + hash_keys.basic.ip_proto = flkeys->basic.ip_proto; + } else { + memset(&hash_keys, 0, sizeof(hash_keys)); + hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; + hash_keys.addrs.v6addrs.src = fl6->saddr; + hash_keys.addrs.v6addrs.dst = fl6->daddr; + hash_keys.ports.src = fl6->fl6_sport; + hash_keys.ports.dst = fl6->fl6_dport; + hash_keys.basic.ip_proto = fl6->flowi6_proto; + } + break; } + mhash = flow_hash_from_keys(&hash_keys);
- return get_hash_from_flowi6(fl6) >> 1; + return mhash >> 1; }
void ip6_route_input(struct sk_buff *skb) @@@ -1872,20 -1910,29 +1935,29 @@@ .flowi6_mark = skb->mark, .flowi6_proto = iph->nexthdr, }; + struct flow_keys *flkeys = NULL, _flkeys;
tun_info = skb_tunnel_info(skb); if (tun_info && !(tun_info->mode & IP_TUNNEL_INFO_TX)) fl6.flowi6_tun_key.tun_id = tun_info->key.tun_id; + + if (fib6_rules_early_flow_dissect(net, skb, &fl6, &_flkeys)) + flkeys = &_flkeys; + if (unlikely(fl6.flowi6_proto == IPPROTO_ICMPV6)) - fl6.mp_hash = rt6_multipath_hash(&fl6, skb); + fl6.mp_hash = rt6_multipath_hash(net, &fl6, skb, flkeys); skb_dst_drop(skb); - skb_dst_set(skb, ip6_route_input_lookup(net, skb->dev, &fl6, flags)); + skb_dst_set(skb, + ip6_route_input_lookup(net, skb->dev, &fl6, skb, flags)); }
- static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table, - struct flowi6 *fl6, int flags) + static struct rt6_info *ip6_pol_route_output(struct net *net, + struct fib6_table *table, + struct flowi6 *fl6, + const struct sk_buff *skb, + int flags) { - return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, flags); + return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, skb, flags); }
struct dst_entry *ip6_route_output_flags(struct net *net, const struct sock *sk, @@@ -1913,7 -1960,7 +1985,7 @@@ else if (sk) flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs);
- return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_output); + return fib6_rule_lookup(net, fl6, NULL, flags, ip6_pol_route_output); } EXPORT_SYMBOL_GPL(ip6_route_output_flags);
@@@ -2162,6 -2209,7 +2234,7 @@@ struct ip6rd_flowi static struct rt6_info *__ip6_route_redirect(struct net *net, struct fib6_table *table, struct flowi6 *fl6, + const struct sk_buff *skb, int flags) { struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl6; @@@ -2235,8 -2283,9 +2308,9 @@@ out };
static struct dst_entry *ip6_route_redirect(struct net *net, - const struct flowi6 *fl6, - const struct in6_addr *gateway) + const struct flowi6 *fl6, + const struct sk_buff *skb, + const struct in6_addr *gateway) { int flags = RT6_LOOKUP_F_HAS_SADDR; struct ip6rd_flowi rdfl; @@@ -2244,7 -2293,7 +2318,7 @@@ rdfl.fl6 = *fl6; rdfl.gateway = *gateway;
- return fib6_rule_lookup(net, &rdfl.fl6, + return fib6_rule_lookup(net, &rdfl.fl6, skb, flags, __ip6_route_redirect); }
@@@ -2264,7 -2313,7 +2338,7 @@@ void ip6_redirect(struct sk_buff *skb, fl6.flowlabel = ip6_flowinfo(iph); fl6.flowi6_uid = uid;
- dst = ip6_route_redirect(net, &fl6, &ipv6_hdr(skb)->saddr); + dst = ip6_route_redirect(net, &fl6, skb, &ipv6_hdr(skb)->saddr); rt6_do_redirect(dst, NULL, skb); dst_release(dst); } @@@ -2286,7 -2335,7 +2360,7 @@@ void ip6_redirect_no_header(struct sk_b fl6.saddr = iph->daddr; fl6.flowi6_uid = sock_net_uid(net, NULL);
- dst = ip6_route_redirect(net, &fl6, &iph->saddr); + dst = ip6_route_redirect(net, &fl6, skb, &iph->saddr); rt6_do_redirect(dst, NULL, skb); dst_release(dst); } @@@ -2488,7 -2537,7 +2562,7 @@@ static struct rt6_info *ip6_nh_lookup_t flags |= RT6_LOOKUP_F_HAS_SADDR;
flags |= RT6_LOOKUP_F_IGNORE_LINKSTATE; - rt = ip6_pol_route(net, table, cfg->fc_ifindex, &fl6, flags); + rt = ip6_pol_route(net, table, cfg->fc_ifindex, &fl6, NULL, flags);
/* if table lookup failed, fall back to full lookup */ if (rt == net->ipv6.ip6_null_entry) { @@@ -2501,7 -2550,7 +2575,7 @@@
static int ip6_route_check_nh_onlink(struct net *net, struct fib6_config *cfg, - struct net_device *dev, + const struct net_device *dev, struct netlink_ext_ack *extack) { u32 tbid = l3mdev_fib_table(dev) ? : RT_TABLE_MAIN; @@@ -2551,7 -2600,7 +2625,7 @@@ static int ip6_route_check_nh(struct ne }
if (!grt) - grt = rt6_lookup(net, gw_addr, NULL, cfg->fc_ifindex, 1); + grt = rt6_lookup(net, gw_addr, NULL, cfg->fc_ifindex, NULL, 1);
if (!grt) goto out; @@@ -2577,6 -2626,79 +2651,79 @@@ out return err; }
+ static int ip6_validate_gw(struct net *net, struct fib6_config *cfg, + struct net_device **_dev, struct inet6_dev **idev, + struct netlink_ext_ack *extack) + { + const struct in6_addr *gw_addr = &cfg->fc_gateway; + int gwa_type = ipv6_addr_type(gw_addr); + bool skip_dev = gwa_type & IPV6_ADDR_LINKLOCAL ? false : true; + const struct net_device *dev = *_dev; + bool need_addr_check = !dev; + int err = -EINVAL; + + /* if gw_addr is local we will fail to detect this in case + * address is still TENTATIVE (DAD in progress). rt6_lookup() + * will return already-added prefix route via interface that + * prefix route was assigned to, which might be non-loopback. + */ + if (dev && + ipv6_chk_addr_and_flags(net, gw_addr, dev, skip_dev, 0, 0)) { + NL_SET_ERR_MSG(extack, "Gateway can not be a local address"); + goto out; + } + + if (gwa_type != (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST)) { + /* IPv6 strictly inhibits using not link-local + * addresses as nexthop address. + * Otherwise, router will not able to send redirects. + * It is very good, but in some (rare!) circumstances + * (SIT, PtP, NBMA NOARP links) it is handy to allow + * some exceptions. --ANK + * We allow IPv4-mapped nexthops to support RFC4798-type + * addressing + */ + if (!(gwa_type & (IPV6_ADDR_UNICAST | IPV6_ADDR_MAPPED))) { + NL_SET_ERR_MSG(extack, "Invalid gateway address"); + goto out; + } + + if (cfg->fc_flags & RTNH_F_ONLINK) + err = ip6_route_check_nh_onlink(net, cfg, dev, extack); + else + err = ip6_route_check_nh(net, cfg, _dev, idev); + + if (err) + goto out; + } + + /* reload in case device was changed */ + dev = *_dev; + + err = -EINVAL; + if (!dev) { + NL_SET_ERR_MSG(extack, "Egress device not specified"); + goto out; + } else if (dev->flags & IFF_LOOPBACK) { + NL_SET_ERR_MSG(extack, + "Egress device can not be loopback device for this route"); + goto out; + } + + /* if we did not check gw_addr above, do so now that the + * egress device has been resolved. + */ + if (need_addr_check && + ipv6_chk_addr_and_flags(net, gw_addr, dev, skip_dev, 0, 0)) { + NL_SET_ERR_MSG(extack, "Gateway can not be a local address"); + goto out; + } + + err = 0; + out: + return err; + } + static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg, struct netlink_ext_ack *extack) { @@@ -2696,14 -2818,7 +2843,7 @@@ if (err) goto out; rt->dst.lwtstate = lwtstate_get(lwtstate); - if (lwtunnel_output_redirect(rt->dst.lwtstate)) { - rt->dst.lwtstate->orig_output = rt->dst.output; - rt->dst.output = lwtunnel_output; - } - if (lwtunnel_input_redirect(rt->dst.lwtstate)) { - rt->dst.lwtstate->orig_input = rt->dst.input; - rt->dst.input = lwtunnel_input; - } + lwtunnel_set_redirect(&rt->dst); }
ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len); @@@ -2766,61 -2881,11 +2906,11 @@@ }
if (cfg->fc_flags & RTF_GATEWAY) { - const struct in6_addr *gw_addr; - int gwa_type; - - gw_addr = &cfg->fc_gateway; - gwa_type = ipv6_addr_type(gw_addr); - - /* if gw_addr is local we will fail to detect this in case - * address is still TENTATIVE (DAD in progress). rt6_lookup() - * will return already-added prefix route via interface that - * prefix route was assigned to, which might be non-loopback. - */ - err = -EINVAL; - if (ipv6_chk_addr_and_flags(net, gw_addr, - gwa_type & IPV6_ADDR_LINKLOCAL ? - dev : NULL, 0, 0)) { - NL_SET_ERR_MSG(extack, "Invalid gateway address"); + err = ip6_validate_gw(net, cfg, &dev, &idev, extack); + if (err) goto out; - } - rt->rt6i_gateway = *gw_addr; - - if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) { - /* IPv6 strictly inhibits using not link-local - addresses as nexthop address. - Otherwise, router will not able to send redirects. - It is very good, but in some (rare!) circumstances - (SIT, PtP, NBMA NOARP links) it is handy to allow - some exceptions. --ANK - We allow IPv4-mapped nexthops to support RFC4798-type - addressing - */ - if (!(gwa_type & (IPV6_ADDR_UNICAST | - IPV6_ADDR_MAPPED))) { - NL_SET_ERR_MSG(extack, - "Invalid gateway address"); - goto out; - }
- if (cfg->fc_flags & RTNH_F_ONLINK) { - err = ip6_route_check_nh_onlink(net, cfg, dev, - extack); - } else { - err = ip6_route_check_nh(net, cfg, &dev, &idev); - } - if (err) - goto out; - } - err = -EINVAL; - if (!dev) { - NL_SET_ERR_MSG(extack, "Egress device not specified"); - goto out; - } else if (dev->flags & IFF_LOOPBACK) { - NL_SET_ERR_MSG(extack, - "Egress device can not be loopback device for this route"); - goto out; - } + rt->rt6i_gateway = cfg->fc_gateway; }
err = -ENODEV; @@@ -3834,13 -3899,25 +3924,13 @@@ static int rt6_mtu_change_route(struct Since RFC 1981 doesn't include administrative MTU increase update PMTU increase is a MUST. (i.e. jumbo frame) */ - /* - If new MTU is less than route PMTU, this new MTU will be the - lowest MTU in the path, update the route PMTU to reflect PMTU - decreases; if new MTU is greater than route PMTU, and the - old MTU is the lowest MTU in the path, update the route PMTU - to reflect the increase. In this case if the other nodes' MTU - also have the lowest MTU, TOO BIG MESSAGE will be lead to - PMTU discovery. - */ if (rt->dst.dev == arg->dev && - dst_metric_raw(&rt->dst, RTAX_MTU) && !dst_metric_locked(&rt->dst, RTAX_MTU)) { spin_lock_bh(&rt6_exception_lock); - if (dst_mtu(&rt->dst) >= arg->mtu || - (dst_mtu(&rt->dst) < arg->mtu && - dst_mtu(&rt->dst) == idev->cnf.mtu6)) { + if (dst_metric_raw(&rt->dst, RTAX_MTU) && + rt6_mtu_change_route_allowed(idev, rt, arg->mtu)) dst_metric_set(&rt->dst, RTAX_MTU, arg->mtu); - } - rt6_exceptions_update_pmtu(rt, arg->mtu); + rt6_exceptions_update_pmtu(idev, rt, arg->mtu); spin_unlock_bh(&rt6_exception_lock); } return 0; @@@ -4112,7 -4189,6 +4202,7 @@@ static int ip6_route_multipath_add(stru r_cfg.fc_encap_type = nla_get_u16(nla); }
+ r_cfg.fc_flags |= (rtnh->rtnh_flags & RTNH_F_ONLINK); rt = ip6_route_info_create(&r_cfg, extack); if (IS_ERR(rt)) { err = PTR_ERR(rt); @@@ -4612,7 -4688,7 +4702,7 @@@ static int inet6_rtm_getroute(struct sk if (!ipv6_addr_any(&fl6.saddr)) flags |= RT6_LOOKUP_F_HAS_SADDR;
- dst = ip6_route_input_lookup(net, dev, &fl6, flags); + dst = ip6_route_input_lookup(net, dev, &fl6, NULL, flags);
rcu_read_unlock(); } else { @@@ -4993,6 -5069,7 +5083,7 @@@ static void __net_exit ip6_route_net_ex static struct pernet_operations ip6_route_net_ops = { .init = ip6_route_net_init, .exit = ip6_route_net_exit, + .async = true, };
static int __net_init ipv6_inetpeer_init(struct net *net) @@@ -5018,11 -5095,13 +5109,13 @@@ static void __net_exit ipv6_inetpeer_ex static struct pernet_operations ipv6_inetpeer_ops = { .init = ipv6_inetpeer_init, .exit = ipv6_inetpeer_exit, + .async = true, };
static struct pernet_operations ip6_route_net_late_ops = { .init = ip6_route_net_init_late, .exit = ip6_route_net_exit_late, + .async = true, };
static struct notifier_block ip6_route_dev_notifier = { diff --combined net/ipv6/xfrm6_policy.c index 416fe67271a9,88cd0c90fa81..cbb270bd81b0 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@@ -113,9 -113,6 +113,9 @@@ static int xfrm6_fill_dst(struct xfrm_d xdst->u.rt6.rt6i_gateway = rt->rt6i_gateway; xdst->u.rt6.rt6i_dst = rt->rt6i_dst; xdst->u.rt6.rt6i_src = rt->rt6i_src; + INIT_LIST_HEAD(&xdst->u.rt6.rt6i_uncached); + rt6_uncached_list_add(&xdst->u.rt6); + atomic_inc(&dev_net(dev)->ipv6.rt6_stats->fib_rt_uncache);
return 0; } @@@ -247,8 -244,6 +247,8 @@@ static void xfrm6_dst_destroy(struct ds if (likely(xdst->u.rt6.rt6i_idev)) in6_dev_put(xdst->u.rt6.rt6i_idev); dst_destroy_metrics_generic(dst); + if (xdst->u.rt6.rt6i_uncached_list) + rt6_uncached_list_del(&xdst->u.rt6); xfrm_dst_destroy(xdst); }
@@@ -400,6 -395,7 +400,7 @@@ static void __net_exit xfrm6_net_exit(s static struct pernet_operations xfrm6_net_ops = { .init = xfrm6_net_init, .exit = xfrm6_net_exit, + .async = true, };
int __init xfrm6_init(void) diff --combined net/iucv/af_iucv.c index 9e2643ab4ccb,81ce15ffb878..893a022f9620 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@@ -989,14 -989,13 +989,13 @@@ done }
static int iucv_sock_getname(struct socket *sock, struct sockaddr *addr, - int *len, int peer) + int peer) { struct sockaddr_iucv *siucv = (struct sockaddr_iucv *) addr; struct sock *sk = sock->sk; struct iucv_sock *iucv = iucv_sk(sk);
addr->sa_family = AF_IUCV; - *len = sizeof(struct sockaddr_iucv);
if (peer) { memcpy(siucv->siucv_user_id, iucv->dst_user_id, 8); @@@ -1009,7 -1008,7 +1008,7 @@@ memset(&siucv->siucv_addr, 0, sizeof(siucv->siucv_addr)); memset(&siucv->siucv_nodeid, 0, sizeof(siucv->siucv_nodeid));
- return 0; + return sizeof(struct sockaddr_iucv); }
/** @@@ -2433,11 -2432,9 +2432,11 @@@ static int afiucv_iucv_init(void af_iucv_dev->driver = &af_iucv_driver; err = device_register(af_iucv_dev); if (err) - goto out_driver; + goto out_iucv_dev; return 0;
+out_iucv_dev: + put_device(af_iucv_dev); out_driver: driver_unregister(&af_iucv_driver); out_iucv: diff --combined net/kcm/kcmsock.c index 34355fd19f27,a6cd0712e063..516cfad71b85 --- a/net/kcm/kcmsock.c +++ b/net/kcm/kcmsock.c @@@ -1381,32 -1381,24 +1381,32 @@@ static int kcm_attach(struct socket *so .parse_msg = kcm_parse_func_strparser, .read_sock_done = kcm_read_sock_done, }; - int err; + int err = 0;
csk = csock->sk; if (!csk) return -EINVAL;
+ lock_sock(csk); + /* Only allow TCP sockets to be attached for now */ if ((csk->sk_family != AF_INET && csk->sk_family != AF_INET6) || - csk->sk_protocol != IPPROTO_TCP) - return -EOPNOTSUPP; + csk->sk_protocol != IPPROTO_TCP) { + err = -EOPNOTSUPP; + goto out; + }
/* Don't allow listeners or closed sockets */ - if (csk->sk_state == TCP_LISTEN || csk->sk_state == TCP_CLOSE) - return -EOPNOTSUPP; + if (csk->sk_state == TCP_LISTEN || csk->sk_state == TCP_CLOSE) { + err = -EOPNOTSUPP; + goto out; + }
psock = kmem_cache_zalloc(kcm_psockp, GFP_KERNEL); - if (!psock) - return -ENOMEM; + if (!psock) { + err = -ENOMEM; + goto out; + }
psock->mux = mux; psock->sk = csk; @@@ -1415,7 -1407,7 +1415,7 @@@ err = strp_init(&psock->strp, csk, &cb); if (err) { kmem_cache_free(kcm_psockp, psock); - return err; + goto out; }
write_lock_bh(&csk->sk_callback_lock); @@@ -1425,10 -1417,10 +1425,11 @@@ */ if (csk->sk_user_data) { write_unlock_bh(&csk->sk_callback_lock); + strp_stop(&psock->strp); strp_done(&psock->strp); kmem_cache_free(kcm_psockp, psock); - return -EALREADY; + err = -EALREADY; + goto out; }
psock->save_data_ready = csk->sk_data_ready; @@@ -1464,10 -1456,7 +1465,10 @@@ /* Schedule RX work in case there are already bytes queued */ strp_check_rcv(&psock->strp);
- return 0; +out: + release_sock(csk); + + return err; }
static int kcm_attach_ioctl(struct socket *sock, struct kcm_attach *info) @@@ -1519,7 -1508,6 +1520,7 @@@ static void kcm_unattach(struct kcm_pso
if (WARN_ON(psock->rx_kcm)) { write_unlock_bh(&csk->sk_callback_lock); + release_sock(csk); return; }
@@@ -2027,6 -2015,7 +2028,7 @@@ static struct pernet_operations kcm_net .exit = kcm_exit_net, .id = &kcm_net_id, .size = sizeof(struct kcm_net), + .async = true, };
static int __init kcm_init(void) diff --combined net/l2tp/l2tp_core.c index 14b67dfacc4b,189a12a5e4ac..b86868da50d4 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@@ -111,13 -111,6 +111,13 @@@ struct l2tp_net spinlock_t l2tp_session_hlist_lock; };
+#if IS_ENABLED(CONFIG_IPV6) +static bool l2tp_sk_is_v6(struct sock *sk) +{ + return sk->sk_family == PF_INET6 && + !ipv6_addr_v4mapped(&sk->sk_v6_daddr); +} +#endif
static inline struct l2tp_tunnel *l2tp_tunnel(struct sock *sk) { @@@ -1056,7 -1049,7 +1056,7 @@@ static int l2tp_xmit_core(struct l2tp_s /* Queue the packet to IP for output */ skb->ignore_df = 1; #if IS_ENABLED(CONFIG_IPV6) - if (tunnel->sock->sk_family == PF_INET6 && !tunnel->v4mapped) + if (l2tp_sk_is_v6(tunnel->sock)) error = inet6_csk_xmit(tunnel->sock, skb, NULL); else #endif @@@ -1119,15 -1112,6 +1119,15 @@@ int l2tp_xmit_skb(struct l2tp_session * goto out_unlock; }
+ /* The user-space may change the connection status for the user-space + * provided socket at run time: we must check it under the socket lock + */ + if (tunnel->fd >= 0 && sk->sk_state != TCP_ESTABLISHED) { + kfree_skb(skb); + ret = NET_XMIT_DROP; + goto out_unlock; + } + /* Get routing info from the tunnel socket */ skb_dst_drop(skb); skb_dst_set(skb, dst_clone(__sk_dst_check(sk, 0))); @@@ -1147,7 -1131,7 +1147,7 @@@
/* Calculate UDP checksum if configured to do so */ #if IS_ENABLED(CONFIG_IPV6) - if (sk->sk_family == PF_INET6 && !tunnel->v4mapped) + if (l2tp_sk_is_v6(sk)) udp6_set_csum(udp_get_no_check6_tx(sk), skb, &inet6_sk(sk)->saddr, &sk->sk_v6_daddr, udp_len); @@@ -1473,14 -1457,9 +1473,14 @@@ int l2tp_tunnel_create(struct net *net encap = cfg->encap;
/* Quick sanity checks */ + err = -EPROTONOSUPPORT; + if (sk->sk_type != SOCK_DGRAM) { + pr_debug("tunl %hu: fd %d wrong socket type\n", + tunnel_id, fd); + goto err; + } switch (encap) { case L2TP_ENCAPTYPE_UDP: - err = -EPROTONOSUPPORT; if (sk->sk_protocol != IPPROTO_UDP) { pr_err("tunl %hu: fd %d wrong protocol, got %d, expected %d\n", tunnel_id, fd, sk->sk_protocol, IPPROTO_UDP); @@@ -1488,6 -1467,7 +1488,6 @@@ } break; case L2TP_ENCAPTYPE_IP: - err = -EPROTONOSUPPORT; if (sk->sk_protocol != IPPROTO_L2TP) { pr_err("tunl %hu: fd %d wrong protocol, got %d, expected %d\n", tunnel_id, fd, sk->sk_protocol, IPPROTO_L2TP); @@@ -1527,6 -1507,24 +1527,6 @@@ if (cfg != NULL) tunnel->debug = cfg->debug;
-#if IS_ENABLED(CONFIG_IPV6) - if (sk->sk_family == PF_INET6) { - struct ipv6_pinfo *np = inet6_sk(sk); - - if (ipv6_addr_v4mapped(&np->saddr) && - ipv6_addr_v4mapped(&sk->sk_v6_daddr)) { - struct inet_sock *inet = inet_sk(sk); - - tunnel->v4mapped = true; - inet->inet_saddr = np->saddr.s6_addr32[3]; - inet->inet_rcv_saddr = sk->sk_v6_rcv_saddr.s6_addr32[3]; - inet->inet_daddr = sk->sk_v6_daddr.s6_addr32[3]; - } else { - tunnel->v4mapped = false; - } - } -#endif - /* Mark socket as an encapsulation socket. See net/ipv4/udp.c */ tunnel->encap = encap; if (encap == L2TP_ENCAPTYPE_UDP) { @@@ -1789,6 -1787,7 +1789,7 @@@ static struct pernet_operations l2tp_ne .exit = l2tp_exit_net, .id = &l2tp_net_id, .size = sizeof(struct l2tp_net), + .async = true, };
static int __init l2tp_init(void) diff --combined net/mac80211/debugfs.c index 94c7ee9df33b,a75653affbf7..4a91fbe71f03 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@@ -212,7 -212,7 +212,8 @@@ static const char *hw_flag_names[] = FLAG(REPORTS_LOW_ACK), FLAG(SUPPORTS_TX_FRAG), FLAG(SUPPORTS_TDLS_BUFFER_STA), + FLAG(DOESNT_SUPPORT_QOS_NDP), + FLAG(DEAUTH_NEED_MGD_TX_PREP), #undef FLAG };
diff --combined net/mac80211/mlme.c index 5f303abac5ad,0024eff9bb84..fe4aefb06d9f --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@@ -7,6 -7,7 +7,7 @@@ * Copyright 2007, Michael Wu flamingice@sourmilk.net * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015 - 2017 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@@ -896,8 -897,7 +897,8 @@@ void ieee80211_send_nullfunc(struct iee struct ieee80211_hdr_3addr *nullfunc; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
- skb = ieee80211_nullfunc_get(&local->hw, &sdata->vif, true); + skb = ieee80211_nullfunc_get(&local->hw, &sdata->vif, + !ieee80211_hw_check(&local->hw, DOESNT_SUPPORT_QOS_NDP)); if (!skb) return;
@@@ -2009,9 -2009,22 +2010,22 @@@ static void ieee80211_set_disassoc(stru ieee80211_flush_queues(local, sdata, true);
/* deauthenticate/disassociate now */ - if (tx || frame_buf) + if (tx || frame_buf) { + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + + /* + * In multi channel scenarios guarantee that the virtual + * interface is granted immediate airtime to transmit the + * deauthentication frame by calling mgd_prepare_tx, if the + * driver requested so. + */ + if (ieee80211_hw_check(&local->hw, DEAUTH_NEED_MGD_TX_PREP) && + !ifmgd->have_beacon) + drv_mgd_prepare_tx(sdata->local, sdata); + ieee80211_send_deauth_disassoc(sdata, ifmgd->bssid, stype, reason, tx, frame_buf); + }
/* flush out frame - make sure the deauth was actually sent */ if (tx) @@@ -2152,7 -2165,7 +2166,7 @@@ static void ieee80211_sta_tx_wmm_ac_not u16 tx_time) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - u16 tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; + u16 tid = ieee80211_get_tid(hdr); int ac = ieee80211_ac_from_tid(tid); struct ieee80211_sta_tx_tspec *tx_tspec = &ifmgd->tx_tspec[ac]; unsigned long now = jiffies; diff --combined net/netfilter/nf_tables_api.c index 14777c404071,8e19c86d1aa6..83c138edc984 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@@ -74,77 -74,15 +74,77 @@@ static void nft_trans_destroy(struct nf kfree(trans); }
+/* removal requests are queued in the commit_list, but not acted upon + * until after all new rules are in place. + * + * Therefore, nf_register_net_hook(net, &nat_hook) runs before pending + * nf_unregister_net_hook(). + * + * nf_register_net_hook thus fails if a nat hook is already in place + * even if the conflicting hook is about to be removed. + * + * If collision is detected, search commit_log for DELCHAIN matching + * the new nat hooknum; if we find one collision is temporary: + * + * Either transaction is aborted (new/colliding hook is removed), or + * transaction is committed (old hook is removed). + */ +static bool nf_tables_allow_nat_conflict(const struct net *net, + const struct nf_hook_ops *ops) +{ + const struct nft_trans *trans; + bool ret = false; + + if (!ops->nat_hook) + return false; + + list_for_each_entry(trans, &net->nft.commit_list, list) { + const struct nf_hook_ops *pending_ops; + const struct nft_chain *pending; + + if (trans->msg_type != NFT_MSG_NEWCHAIN && + trans->msg_type != NFT_MSG_DELCHAIN) + continue; + + pending = trans->ctx.chain; + if (!nft_is_base_chain(pending)) + continue; + + pending_ops = &nft_base_chain(pending)->ops; + if (pending_ops->nat_hook && + pending_ops->pf == ops->pf && + pending_ops->hooknum == ops->hooknum) { + /* other hook registration already pending? */ + if (trans->msg_type == NFT_MSG_NEWCHAIN) + return false; + + ret = true; + } + } + + return ret; +} + static int nf_tables_register_hook(struct net *net, const struct nft_table *table, struct nft_chain *chain) { + struct nf_hook_ops *ops; + int ret; + if (table->flags & NFT_TABLE_F_DORMANT || !nft_is_base_chain(chain)) return 0;
- return nf_register_net_hook(net, &nft_base_chain(chain)->ops); + ops = &nft_base_chain(chain)->ops; + ret = nf_register_net_hook(net, ops); + if (ret == -EBUSY && nf_tables_allow_nat_conflict(net, ops)) { + ops->nat_hook = false; + ret = nf_register_net_hook(net, ops); + ops->nat_hook = true; + } + + return ret; }
static void nf_tables_unregister_hook(struct net *net, @@@ -1973,7 -1911,6 +1973,7 @@@ static const struct nla_policy nft_rule [NFTA_RULE_POSITION] = { .type = NLA_U64 }, [NFTA_RULE_USERDATA] = { .type = NLA_BINARY, .len = NFT_USERDATA_MAXLEN }, + [NFTA_RULE_ID] = { .type = NLA_U32 }, };
static int nf_tables_fill_rule_info(struct sk_buff *skb, struct net *net, @@@ -2509,9 -2446,6 +2509,9 @@@ EXPORT_SYMBOL_GPL(nft_unregister_set)
static bool nft_set_ops_candidate(const struct nft_set_ops *ops, u32 flags) { + if ((flags & NFT_SET_EVAL) && !ops->update) + return false; + return (flags & ops->features) == (flags & NFT_SET_FEATURES); }
@@@ -2576,7 -2510,7 +2576,7 @@@ nft_select_set_ops(const struct nft_ct if (est.space == best.space && est.lookup < best.lookup) break; - } else if (est.size < best.size) { + } else if (est.size < best.size || !bops) { break; } continue; @@@ -3381,8 -3315,6 +3381,8 @@@ static const struct nla_policy nft_set_ [NFTA_SET_ELEM_TIMEOUT] = { .type = NLA_U64 }, [NFTA_SET_ELEM_USERDATA] = { .type = NLA_BINARY, .len = NFT_USERDATA_MAXLEN }, + [NFTA_SET_ELEM_EXPR] = { .type = NLA_NESTED }, + [NFTA_SET_ELEM_OBJREF] = { .type = NLA_STRING }, };
static const struct nla_policy nft_set_elem_list_policy[NFTA_SET_ELEM_LIST_MAX + 1] = { @@@ -5491,7 -5423,6 +5491,7 @@@ err static void nf_tables_flowtable_destroy(struct nft_flowtable *flowtable) { cancel_delayed_work_sync(&flowtable->data.gc_work); + kfree(flowtable->ops); kfree(flowtable->name); flowtable->data.type->free(&flowtable->data); rhashtable_destroy(&flowtable->data.rhashtable); @@@ -6665,6 -6596,7 +6665,7 @@@ static void __net_exit nf_tables_exit_n static struct pernet_operations nf_tables_net_ops = { .init = nf_tables_init_net, .exit = nf_tables_exit_net, + .async = true, };
static int __init nf_tables_module_init(void) diff --combined net/netfilter/x_tables.c index 4aa01c90e9d1,d9deebe599ec..6de1f6a4cb80 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@@ -423,36 -423,6 +423,36 @@@ textify_hooks(char *buf, size_t size, u return buf; }
+/** + * xt_check_proc_name - check that name is suitable for /proc file creation + * + * @name: file name candidate + * @size: length of buffer + * + * some x_tables modules wish to create a file in /proc. + * This function makes sure that the name is suitable for this + * purpose, it checks that name is NUL terminated and isn't a 'special' + * name, like "..". + * + * returns negative number on error or 0 if name is useable. + */ +int xt_check_proc_name(const char *name, unsigned int size) +{ + if (name[0] == '\0') + return -EINVAL; + + if (strnlen(name, size) == size) + return -ENAMETOOLONG; + + if (strcmp(name, ".") == 0 || + strcmp(name, "..") == 0 || + strchr(name, '/')) + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL(xt_check_proc_name); + int xt_check_match(struct xt_mtchk_param *par, unsigned int size, u_int8_t proto, bool inv_proto) { @@@ -1789,6 -1759,7 +1789,7 @@@ static void __net_exit xt_net_exit(stru static struct pernet_operations xt_net_ops = { .init = xt_net_init, .exit = xt_net_exit, + .async = true, };
static int __init xt_init(void) diff --combined net/netfilter/xt_hashlimit.c index 3360f13dc208,db2fe0911740..ef65b7a9173e --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c @@@ -917,9 -917,8 +917,9 @@@ static int hashlimit_mt_check_v1(const struct hashlimit_cfg3 cfg = {}; int ret;
- if (info->name[sizeof(info->name) - 1] != '\0') - return -EINVAL; + ret = xt_check_proc_name(info->name, sizeof(info->name)); + if (ret) + return ret;
ret = cfg_copy(&cfg, (void *)&info->cfg, 1);
@@@ -936,9 -935,8 +936,9 @@@ static int hashlimit_mt_check_v2(const struct hashlimit_cfg3 cfg = {}; int ret;
- if (info->name[sizeof(info->name) - 1] != '\0') - return -EINVAL; + ret = xt_check_proc_name(info->name, sizeof(info->name)); + if (ret) + return ret;
ret = cfg_copy(&cfg, (void *)&info->cfg, 2);
@@@ -952,11 -950,9 +952,11 @@@ static int hashlimit_mt_check(const struct xt_mtchk_param *par) { struct xt_hashlimit_mtinfo3 *info = par->matchinfo; + int ret;
- if (info->name[sizeof(info->name) - 1] != '\0') - return -EINVAL; + ret = xt_check_proc_name(info->name, sizeof(info->name)); + if (ret) + return ret;
return hashlimit_mt_check_common(par, &info->hinfo, &info->cfg, info->name, 3); @@@ -1349,6 -1345,7 +1349,7 @@@ static struct pernet_operations hashlim .exit = hashlimit_net_exit, .id = &hashlimit_net_id, .size = sizeof(struct hashlimit_net), + .async = true, };
static int __init hashlimit_mt_init(void) diff --combined net/netfilter/xt_recent.c index 81ee1d6543b2,19efdb757944..486dd24da78b --- a/net/netfilter/xt_recent.c +++ b/net/netfilter/xt_recent.c @@@ -361,9 -361,9 +361,9 @@@ static int recent_mt_check(const struc info->hit_count, XT_RECENT_MAX_NSTAMPS - 1); return -EINVAL; } - if (info->name[0] == '\0' || - strnlen(info->name, XT_RECENT_NAME_LEN) == XT_RECENT_NAME_LEN) - return -EINVAL; + ret = xt_check_proc_name(info->name, sizeof(info->name)); + if (ret) + return ret;
if (ip_pkt_list_tot && info->hit_count < ip_pkt_list_tot) nstamp_mask = roundup_pow_of_two(ip_pkt_list_tot) - 1; @@@ -687,6 -687,7 +687,7 @@@ static struct pernet_operations recent_ .exit = recent_net_exit, .id = &recent_net_id, .size = sizeof(struct recent_net), + .async = true, };
static struct xt_match recent_mt_reg[] __read_mostly = { diff --combined net/netlink/genetlink.c index b9ce82c9440f,a6f63a5faee7..af51b8c0a2cb --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@@ -1035,6 -1035,7 +1035,7 @@@ static void __net_exit genl_pernet_exit static struct pernet_operations genl_pernet_ops = { .init = genl_pernet_init, .exit = genl_pernet_exit, + .async = true, };
static int __init genl_init(void) @@@ -1106,7 -1107,7 +1107,7 @@@ static int genlmsg_mcast(struct sk_buf if (!err) delivered = true; else if (err != -ESRCH) - goto error; + return err; return delivered ? 0 : -ESRCH; error: kfree_skb(skb); diff --combined net/sched/act_bpf.c index 9d2cabf1dc7e,da72e0cf2b1f..5cb9b268e8ff --- a/net/sched/act_bpf.c +++ b/net/sched/act_bpf.c @@@ -272,7 -272,7 +272,7 @@@ static void tcf_bpf_prog_fill_cfg(cons
static int tcf_bpf_init(struct net *net, struct nlattr *nla, struct nlattr *est, struct tc_action **act, - int replace, int bind) + int replace, int bind, struct netlink_ext_ack *extack) { struct tc_action_net *tn = net_generic(net, bpf_net_id); struct nlattr *tb[TCA_ACT_BPF_MAX + 1]; @@@ -352,7 -352,7 +352,7 @@@ return res; out: if (res == ACT_P_CREATED) - tcf_idr_cleanup(*act, est); + tcf_idr_release(*act, bind);
return ret; } @@@ -367,14 -367,16 +367,16 @@@ static void tcf_bpf_cleanup(struct tc_a
static int tcf_bpf_walker(struct net *net, struct sk_buff *skb, struct netlink_callback *cb, int type, - const struct tc_action_ops *ops) + const struct tc_action_ops *ops, + struct netlink_ext_ack *extack) { struct tc_action_net *tn = net_generic(net, bpf_net_id);
- return tcf_generic_walker(tn, skb, cb, type, ops); + return tcf_generic_walker(tn, skb, cb, type, ops, extack); }
- static int tcf_bpf_search(struct net *net, struct tc_action **a, u32 index) + static int tcf_bpf_search(struct net *net, struct tc_action **a, u32 index, + struct netlink_ext_ack *extack) { struct tc_action_net *tn = net_generic(net, bpf_net_id);
@@@ -411,6 -413,7 +413,7 @@@ static struct pernet_operations bpf_net .exit_batch = bpf_exit_net, .id = &bpf_net_id, .size = sizeof(struct tc_action_net), + .async = true, };
static int __init bpf_init_module(void) diff --combined net/sched/act_csum.c index 2a5c8fd860cf,1fb1f1f6a555..a527e287c086 --- a/net/sched/act_csum.c +++ b/net/sched/act_csum.c @@@ -46,7 -46,7 +46,7 @@@ static struct tc_action_ops act_csum_op
static int tcf_csum_init(struct net *net, struct nlattr *nla, struct nlattr *est, struct tc_action **a, int ovr, - int bind) + int bind, struct netlink_ext_ack *extack) { struct tc_action_net *tn = net_generic(net, csum_net_id); struct tcf_csum_params *params_old, *params_new; @@@ -350,7 -350,7 +350,7 @@@ static int tcf_csum_sctp(struct sk_buf { struct sctphdr *sctph;
- if (skb_is_gso(skb) && skb_shinfo(skb)->gso_type & SKB_GSO_SCTP) + if (skb_is_gso(skb) && skb_is_gso_sctp(skb)) return 1;
sctph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*sctph)); @@@ -626,20 -626,21 +626,22 @@@ static void tcf_csum_cleanup(struct tc_ struct tcf_csum_params *params;
params = rcu_dereference_protected(p->params, 1); - kfree_rcu(params, rcu); + if (params) + kfree_rcu(params, rcu); }
static int tcf_csum_walker(struct net *net, struct sk_buff *skb, struct netlink_callback *cb, int type, - const struct tc_action_ops *ops) + const struct tc_action_ops *ops, + struct netlink_ext_ack *extack) { struct tc_action_net *tn = net_generic(net, csum_net_id);
- return tcf_generic_walker(tn, skb, cb, type, ops); + return tcf_generic_walker(tn, skb, cb, type, ops, extack); }
- static int tcf_csum_search(struct net *net, struct tc_action **a, u32 index) + static int tcf_csum_search(struct net *net, struct tc_action **a, u32 index, + struct netlink_ext_ack *extack) { struct tc_action_net *tn = net_generic(net, csum_net_id);
@@@ -676,6 -677,7 +678,7 @@@ static struct pernet_operations csum_ne .exit_batch = csum_exit_net, .id = &csum_net_id, .size = sizeof(struct tc_action_net), + .async = true, };
MODULE_DESCRIPTION("Checksum updating actions"); diff --combined net/sched/act_ipt.c index 7e06b9b62613,10866717f88e..b5e8565b89c7 --- a/net/sched/act_ipt.c +++ b/net/sched/act_ipt.c @@@ -80,12 -80,9 +80,12 @@@ static void ipt_destroy_target(struct x static void tcf_ipt_release(struct tc_action *a) { struct tcf_ipt *ipt = to_ipt(a); - ipt_destroy_target(ipt->tcfi_t); + + if (ipt->tcfi_t) { + ipt_destroy_target(ipt->tcfi_t); + kfree(ipt->tcfi_t); + } kfree(ipt->tcfi_tname); - kfree(ipt->tcfi_t); }
static const struct nla_policy ipt_policy[TCA_IPT_MAX + 1] = { @@@ -190,13 -187,13 +190,13 @@@ err2 kfree(tname); err1: if (ret == ACT_P_CREATED) - tcf_idr_cleanup(*a, est); + tcf_idr_release(*a, bind); return err; }
static int tcf_ipt_init(struct net *net, struct nlattr *nla, struct nlattr *est, struct tc_action **a, int ovr, - int bind) + int bind, struct netlink_ext_ack *extack) { return __tcf_ipt_init(net, ipt_net_id, nla, est, a, &act_ipt_ops, ovr, bind); @@@ -204,7 -201,7 +204,7 @@@
static int tcf_xt_init(struct net *net, struct nlattr *nla, struct nlattr *est, struct tc_action **a, int ovr, - int bind) + int bind, struct netlink_ext_ack *extack) { return __tcf_ipt_init(net, xt_net_id, nla, est, a, &act_xt_ops, ovr, bind); @@@ -306,14 -303,16 +306,16 @@@ nla_put_failure
static int tcf_ipt_walker(struct net *net, struct sk_buff *skb, struct netlink_callback *cb, int type, - const struct tc_action_ops *ops) + const struct tc_action_ops *ops, + struct netlink_ext_ack *extack) { struct tc_action_net *tn = net_generic(net, ipt_net_id);
- return tcf_generic_walker(tn, skb, cb, type, ops); + return tcf_generic_walker(tn, skb, cb, type, ops, extack); }
- static int tcf_ipt_search(struct net *net, struct tc_action **a, u32 index) + static int tcf_ipt_search(struct net *net, struct tc_action **a, u32 index, + struct netlink_ext_ack *extack) { struct tc_action_net *tn = net_generic(net, ipt_net_id);
@@@ -350,18 -349,21 +352,21 @@@ static struct pernet_operations ipt_net .exit_batch = ipt_exit_net, .id = &ipt_net_id, .size = sizeof(struct tc_action_net), + .async = true, };
static int tcf_xt_walker(struct net *net, struct sk_buff *skb, struct netlink_callback *cb, int type, - const struct tc_action_ops *ops) + const struct tc_action_ops *ops, + struct netlink_ext_ack *extack) { struct tc_action_net *tn = net_generic(net, xt_net_id);
- return tcf_generic_walker(tn, skb, cb, type, ops); + return tcf_generic_walker(tn, skb, cb, type, ops, extack); }
- static int tcf_xt_search(struct net *net, struct tc_action **a, u32 index) + static int tcf_xt_search(struct net *net, struct tc_action **a, u32 index, + struct netlink_ext_ack *extack) { struct tc_action_net *tn = net_generic(net, xt_net_id);
@@@ -398,6 -400,7 +403,7 @@@ static struct pernet_operations xt_net_ .exit_batch = xt_exit_net, .id = &xt_net_id, .size = sizeof(struct tc_action_net), + .async = true, };
MODULE_AUTHOR("Jamal Hadi Salim(2002-13)"); diff --combined net/sched/act_pedit.c index fef08835f26d,5e8cc8f63acd..f392ccaaa0d8 --- a/net/sched/act_pedit.c +++ b/net/sched/act_pedit.c @@@ -132,7 -132,7 +132,7 @@@ static int tcf_pedit_key_ex_dump(struc
static int tcf_pedit_init(struct net *net, struct nlattr *nla, struct nlattr *est, struct tc_action **a, - int ovr, int bind) + int ovr, int bind, struct netlink_ext_ack *extack) { struct tc_action_net *tn = net_generic(net, pedit_net_id); struct nlattr *tb[TCA_PEDIT_MAX + 1]; @@@ -176,7 -176,7 +176,7 @@@ p = to_pedit(*a); keys = kmalloc(ksize, GFP_KERNEL); if (keys == NULL) { - tcf_idr_cleanup(*a, est); + tcf_idr_release(*a, bind); kfree(keys_ex); return -ENOMEM; } @@@ -419,14 -419,16 +419,16 @@@ nla_put_failure
static int tcf_pedit_walker(struct net *net, struct sk_buff *skb, struct netlink_callback *cb, int type, - const struct tc_action_ops *ops) + const struct tc_action_ops *ops, + struct netlink_ext_ack *extack) { struct tc_action_net *tn = net_generic(net, pedit_net_id);
- return tcf_generic_walker(tn, skb, cb, type, ops); + return tcf_generic_walker(tn, skb, cb, type, ops, extack); }
- static int tcf_pedit_search(struct net *net, struct tc_action **a, u32 index) + static int tcf_pedit_search(struct net *net, struct tc_action **a, u32 index, + struct netlink_ext_ack *extack) { struct tc_action_net *tn = net_generic(net, pedit_net_id);
@@@ -463,6 -465,7 +465,7 @@@ static struct pernet_operations pedit_n .exit_batch = pedit_exit_net, .id = &pedit_net_id, .size = sizeof(struct tc_action_net), + .async = true, };
MODULE_AUTHOR("Jamal Hadi Salim(2002-4)"); diff --combined net/sched/act_police.c index faebf82b99f1,51fe4fe343f7..7081ec75e696 --- a/net/sched/act_police.c +++ b/net/sched/act_police.c @@@ -58,11 -58,12 +58,12 @@@ static struct tc_action_ops act_police_
static int tcf_act_police_walker(struct net *net, struct sk_buff *skb, struct netlink_callback *cb, int type, - const struct tc_action_ops *ops) + const struct tc_action_ops *ops, + struct netlink_ext_ack *extack) { struct tc_action_net *tn = net_generic(net, police_net_id);
- return tcf_generic_walker(tn, skb, cb, type, ops); + return tcf_generic_walker(tn, skb, cb, type, ops, extack); }
static const struct nla_policy police_policy[TCA_POLICE_MAX + 1] = { @@@ -74,7 -75,8 +75,8 @@@
static int tcf_act_police_init(struct net *net, struct nlattr *nla, struct nlattr *est, struct tc_action **a, - int ovr, int bind) + int ovr, int bind, + struct netlink_ext_ack *extack) { int ret = 0, err; struct nlattr *tb[TCA_POLICE_MAX + 1]; @@@ -194,7 -196,7 +196,7 @@@ failure qdisc_put_rtab(P_tab); qdisc_put_rtab(R_tab); if (ret == ACT_P_CREATED) - tcf_idr_cleanup(*a, est); + tcf_idr_release(*a, bind); return err; }
@@@ -304,7 -306,8 +306,8 @@@ nla_put_failure return -1; }
- static int tcf_police_search(struct net *net, struct tc_action **a, u32 index) + static int tcf_police_search(struct net *net, struct tc_action **a, u32 index, + struct netlink_ext_ack *extack) { struct tc_action_net *tn = net_generic(net, police_net_id);
@@@ -344,6 -347,7 +347,7 @@@ static struct pernet_operations police_ .exit_batch = police_exit_net, .id = &police_net_id, .size = sizeof(struct tc_action_net), + .async = true, };
static int __init police_init_module(void) diff --combined net/sched/act_sample.c index 74c5d7e6a0fa,238dfd27e995..3a89f98f17e6 --- a/net/sched/act_sample.c +++ b/net/sched/act_sample.c @@@ -37,7 -37,7 +37,7 @@@ static const struct nla_policy sample_p
static int tcf_sample_init(struct net *net, struct nlattr *nla, struct nlattr *est, struct tc_action **a, int ovr, - int bind) + int bind, struct netlink_ext_ack *extack) { struct tc_action_net *tn = net_generic(net, sample_net_id); struct nlattr *tb[TCA_SAMPLE_MAX + 1]; @@@ -103,8 -103,7 +103,8 @@@ static void tcf_sample_cleanup(struct t
psample_group = rtnl_dereference(s->psample_group); RCU_INIT_POINTER(s->psample_group, NULL); - psample_group_put(psample_group); + if (psample_group) + psample_group_put(psample_group); }
static bool tcf_sample_dev_ok_push(struct net_device *dev) @@@ -203,14 -202,16 +203,16 @@@ nla_put_failure
static int tcf_sample_walker(struct net *net, struct sk_buff *skb, struct netlink_callback *cb, int type, - const struct tc_action_ops *ops) + const struct tc_action_ops *ops, + struct netlink_ext_ack *extack) { struct tc_action_net *tn = net_generic(net, sample_net_id);
- return tcf_generic_walker(tn, skb, cb, type, ops); + return tcf_generic_walker(tn, skb, cb, type, ops, extack); }
- static int tcf_sample_search(struct net *net, struct tc_action **a, u32 index) + static int tcf_sample_search(struct net *net, struct tc_action **a, u32 index, + struct netlink_ext_ack *extack) { struct tc_action_net *tn = net_generic(net, sample_net_id);
@@@ -247,6 -248,7 +249,7 @@@ static struct pernet_operations sample_ .exit_batch = sample_exit_net, .id = &sample_net_id, .size = sizeof(struct tc_action_net), + .async = true, };
static int __init sample_init_module(void) diff --combined net/sched/act_simple.c index b1f38063ada0,91816d73f3f3..e84768ae610a --- a/net/sched/act_simple.c +++ b/net/sched/act_simple.c @@@ -79,7 -79,7 +79,7 @@@ static const struct nla_policy simple_p
static int tcf_simp_init(struct net *net, struct nlattr *nla, struct nlattr *est, struct tc_action **a, - int ovr, int bind) + int ovr, int bind, struct netlink_ext_ack *extack) { struct tc_action_net *tn = net_generic(net, simp_net_id); struct nlattr *tb[TCA_DEF_MAX + 1]; @@@ -121,7 -121,7 +121,7 @@@ d = to_defact(*a); ret = alloc_defdata(d, defdata); if (ret < 0) { - tcf_idr_cleanup(*a, est); + tcf_idr_release(*a, bind); return ret; } d->tcf_action = parm->action; @@@ -170,14 -170,16 +170,16 @@@ nla_put_failure
static int tcf_simp_walker(struct net *net, struct sk_buff *skb, struct netlink_callback *cb, int type, - const struct tc_action_ops *ops) + const struct tc_action_ops *ops, + struct netlink_ext_ack *extack) { struct tc_action_net *tn = net_generic(net, simp_net_id);
- return tcf_generic_walker(tn, skb, cb, type, ops); + return tcf_generic_walker(tn, skb, cb, type, ops, extack); }
- static int tcf_simp_search(struct net *net, struct tc_action **a, u32 index) + static int tcf_simp_search(struct net *net, struct tc_action **a, u32 index, + struct netlink_ext_ack *extack) { struct tc_action_net *tn = net_generic(net, simp_net_id);
@@@ -214,6 -216,7 +216,7 @@@ static struct pernet_operations simp_ne .exit_batch = simp_exit_net, .id = &simp_net_id, .size = sizeof(struct tc_action_net), + .async = true, };
MODULE_AUTHOR("Jamal Hadi Salim(2005)"); diff --combined net/sched/act_skbmod.c index 7b0700f52b50,febec75f4f7a..142a996ac776 --- a/net/sched/act_skbmod.c +++ b/net/sched/act_skbmod.c @@@ -84,7 -84,7 +84,7 @@@ static const struct nla_policy skbmod_p
static int tcf_skbmod_init(struct net *net, struct nlattr *nla, struct nlattr *est, struct tc_action **a, - int ovr, int bind) + int ovr, int bind, struct netlink_ext_ack *extack) { struct tc_action_net *tn = net_generic(net, skbmod_net_id); struct nlattr *tb[TCA_SKBMOD_MAX + 1]; @@@ -152,7 -152,7 +152,7 @@@ ASSERT_RTNL(); p = kzalloc(sizeof(struct tcf_skbmod_params), GFP_KERNEL); if (unlikely(!p)) { - if (ovr) + if (ret == ACT_P_CREATED) tcf_idr_release(*a, bind); return -ENOMEM; } @@@ -190,8 -190,7 +190,8 @@@ static void tcf_skbmod_cleanup(struct t struct tcf_skbmod_params *p;
p = rcu_dereference_protected(d->skbmod_p, 1); - kfree_rcu(p, rcu); + if (p) + kfree_rcu(p, rcu); }
static int tcf_skbmod_dump(struct sk_buff *skb, struct tc_action *a, @@@ -233,14 -232,16 +233,16 @@@ nla_put_failure
static int tcf_skbmod_walker(struct net *net, struct sk_buff *skb, struct netlink_callback *cb, int type, - const struct tc_action_ops *ops) + const struct tc_action_ops *ops, + struct netlink_ext_ack *extack) { struct tc_action_net *tn = net_generic(net, skbmod_net_id);
- return tcf_generic_walker(tn, skb, cb, type, ops); + return tcf_generic_walker(tn, skb, cb, type, ops, extack); }
- static int tcf_skbmod_search(struct net *net, struct tc_action **a, u32 index) + static int tcf_skbmod_search(struct net *net, struct tc_action **a, u32 index, + struct netlink_ext_ack *extack) { struct tc_action_net *tn = net_generic(net, skbmod_net_id);
@@@ -277,6 -278,7 +279,7 @@@ static struct pernet_operations skbmod_ .exit_batch = skbmod_exit_net, .id = &skbmod_net_id, .size = sizeof(struct tc_action_net), + .async = true, };
MODULE_AUTHOR("Jamal Hadi Salim, jhs@mojatatu.com"); diff --combined net/sched/act_tunnel_key.c index 1281ca463727,9169b7e78ada..a1c8dd406a04 --- a/net/sched/act_tunnel_key.c +++ b/net/sched/act_tunnel_key.c @@@ -70,7 -70,7 +70,7 @@@ static const struct nla_policy tunnel_k
static int tunnel_key_init(struct net *net, struct nlattr *nla, struct nlattr *est, struct tc_action **a, - int ovr, int bind) + int ovr, int bind, struct netlink_ext_ack *extack) { struct tc_action_net *tn = net_generic(net, tunnel_key_net_id); struct nlattr *tb[TCA_TUNNEL_KEY_MAX + 1]; @@@ -153,7 -153,6 +153,7 @@@ metadata->u.tun_info.mode |= IP_TUNNEL_INFO_TX; break; default: + ret = -EINVAL; goto err_out; }
@@@ -208,12 -207,11 +208,12 @@@ static void tunnel_key_release(struct t struct tcf_tunnel_key_params *params;
params = rcu_dereference_protected(t->params, 1); + if (params) { + if (params->tcft_action == TCA_TUNNEL_KEY_ACT_SET) + dst_release(¶ms->tcft_enc_metadata->dst);
- if (params->tcft_action == TCA_TUNNEL_KEY_ACT_SET) - dst_release(¶ms->tcft_enc_metadata->dst); - - kfree_rcu(params, rcu); + kfree_rcu(params, rcu); + } }
static int tunnel_key_dump_addresses(struct sk_buff *skb, @@@ -293,14 -291,16 +293,16 @@@ nla_put_failure
static int tunnel_key_walker(struct net *net, struct sk_buff *skb, struct netlink_callback *cb, int type, - const struct tc_action_ops *ops) + const struct tc_action_ops *ops, + struct netlink_ext_ack *extack) { struct tc_action_net *tn = net_generic(net, tunnel_key_net_id);
- return tcf_generic_walker(tn, skb, cb, type, ops); + return tcf_generic_walker(tn, skb, cb, type, ops, extack); }
- static int tunnel_key_search(struct net *net, struct tc_action **a, u32 index) + static int tunnel_key_search(struct net *net, struct tc_action **a, u32 index, + struct netlink_ext_ack *extack) { struct tc_action_net *tn = net_generic(net, tunnel_key_net_id);
@@@ -337,6 -337,7 +339,7 @@@ static struct pernet_operations tunnel_ .exit_batch = tunnel_key_exit_net, .id = &tunnel_key_net_id, .size = sizeof(struct tc_action_net), + .async = true, };
static int __init tunnel_key_init_module(void) diff --combined net/sched/act_vlan.c index c49cb61adedf,c2ee7fd51cc9..4595391c2129 --- a/net/sched/act_vlan.c +++ b/net/sched/act_vlan.c @@@ -109,7 -109,7 +109,7 @@@ static const struct nla_policy vlan_pol
static int tcf_vlan_init(struct net *net, struct nlattr *nla, struct nlattr *est, struct tc_action **a, - int ovr, int bind) + int ovr, int bind, struct netlink_ext_ack *extack) { struct tc_action_net *tn = net_generic(net, vlan_net_id); struct nlattr *tb[TCA_VLAN_MAX + 1]; @@@ -195,7 -195,7 +195,7 @@@ ASSERT_RTNL(); p = kzalloc(sizeof(*p), GFP_KERNEL); if (!p) { - if (ovr) + if (ret == ACT_P_CREATED) tcf_idr_release(*a, bind); return -ENOMEM; } @@@ -225,8 -225,7 +225,8 @@@ static void tcf_vlan_cleanup(struct tc_ struct tcf_vlan_params *p;
p = rcu_dereference_protected(v->vlan_p, 1); - kfree_rcu(p, rcu); + if (p) + kfree_rcu(p, rcu); }
static int tcf_vlan_dump(struct sk_buff *skb, struct tc_action *a, @@@ -268,14 -267,16 +268,16 @@@ nla_put_failure
static int tcf_vlan_walker(struct net *net, struct sk_buff *skb, struct netlink_callback *cb, int type, - const struct tc_action_ops *ops) + const struct tc_action_ops *ops, + struct netlink_ext_ack *extack) { struct tc_action_net *tn = net_generic(net, vlan_net_id);
- return tcf_generic_walker(tn, skb, cb, type, ops); + return tcf_generic_walker(tn, skb, cb, type, ops, extack); }
- static int tcf_vlan_search(struct net *net, struct tc_action **a, u32 index) + static int tcf_vlan_search(struct net *net, struct tc_action **a, u32 index, + struct netlink_ext_ack *extack) { struct tc_action_net *tn = net_generic(net, vlan_net_id);
@@@ -312,6 -313,7 +314,7 @@@ static struct pernet_operations vlan_ne .exit_batch = vlan_exit_net, .id = &vlan_net_id, .size = sizeof(struct tc_action_net), + .async = true, };
static int __init vlan_init_module(void) diff --combined net/smc/af_smc.c index 1e0d780855c3,86913eb5cfa0..5f8046c62d90 --- a/net/smc/af_smc.c +++ b/net/smc/af_smc.c @@@ -7,13 -7,11 +7,11 @@@ * applicable with RoCE-cards only * * Initial restrictions: - * - non-blocking connect postponed - * - IPv6 support postponed * - support for alternate links postponed * - partial support for non-blocking sockets only * - support for urgent data postponed * - * Copyright IBM Corp. 2016 + * Copyright IBM Corp. 2016, 2018 * * Author(s): Ursula Braun ubraun@linux.vnet.ibm.com * based on prototype from Frank Blaschka @@@ -24,7 -22,6 +22,6 @@@
#include <linux/module.h> #include <linux/socket.h> - #include <linux/inetdevice.h> #include <linux/workqueue.h> #include <linux/in.h> #include <linux/sched/signal.h> @@@ -66,6 -63,10 +63,10 @@@ static struct smc_hashinfo smc_v4_hashi .lock = __RW_LOCK_UNLOCKED(smc_v4_hashinfo.lock), };
+ static struct smc_hashinfo smc_v6_hashinfo = { + .lock = __RW_LOCK_UNLOCKED(smc_v6_hashinfo.lock), + }; + int smc_hash_sk(struct sock *sk) { struct smc_hashinfo *h = sk->sk_prot->h.smc_hash; @@@ -105,6 -106,18 +106,18 @@@ struct proto smc_proto = }; EXPORT_SYMBOL_GPL(smc_proto);
+ struct proto smc_proto6 = { + .name = "SMC6", + .owner = THIS_MODULE, + .keepalive = smc_set_keepalive, + .hash = smc_hash_sk, + .unhash = smc_unhash_sk, + .obj_size = sizeof(struct smc_sock), + .h.smc_hash = &smc_v6_hashinfo, + .slab_flags = SLAB_TYPESAFE_BY_RCU, + }; + EXPORT_SYMBOL_GPL(smc_proto6); + static int smc_release(struct socket *sock) { struct sock *sk = sock->sk; @@@ -161,19 -174,22 +174,22 @@@ static void smc_destruct(struct sock *s sk_refcnt_debug_dec(sk); }
- static struct sock *smc_sock_alloc(struct net *net, struct socket *sock) + static struct sock *smc_sock_alloc(struct net *net, struct socket *sock, + int protocol) { struct smc_sock *smc; + struct proto *prot; struct sock *sk;
- sk = sk_alloc(net, PF_SMC, GFP_KERNEL, &smc_proto, 0); + prot = (protocol == SMCPROTO_SMC6) ? &smc_proto6 : &smc_proto; + sk = sk_alloc(net, PF_SMC, GFP_KERNEL, prot, 0); if (!sk) return NULL;
sock_init_data(sock, sk); /* sets sk_refcnt to 1 */ sk->sk_state = SMC_INIT; sk->sk_destruct = smc_destruct; - sk->sk_protocol = SMCPROTO_SMC; + sk->sk_protocol = protocol; smc = smc_sk(sk); INIT_WORK(&smc->tcp_listen_work, smc_tcp_listen_work); INIT_LIST_HEAD(&smc->accept_q); @@@ -200,10 -216,13 +216,13 @@@ static int smc_bind(struct socket *sock goto out;
rc = -EAFNOSUPPORT; + if (addr->sin_family != AF_INET && + addr->sin_family != AF_INET6 && + addr->sin_family != AF_UNSPEC) + goto out; /* accept AF_UNSPEC (mapped to AF_INET) only if s_addr is INADDR_ANY */ - if ((addr->sin_family != AF_INET) && - ((addr->sin_family != AF_UNSPEC) || - (addr->sin_addr.s_addr != htonl(INADDR_ANY)))) + if (addr->sin_family == AF_UNSPEC && + addr->sin_addr.s_addr != htonl(INADDR_ANY)) goto out;
lock_sock(sk); @@@ -273,47 -292,7 +292,7 @@@ static void smc_copy_sock_settings_to_s smc_copy_sock_settings(&smc->sk, smc->clcsock->sk, SK_FLAGS_CLC_TO_SMC); }
- /* determine subnet and mask of internal TCP socket */ - int smc_netinfo_by_tcpsk(struct socket *clcsock, - __be32 *subnet, u8 *prefix_len) - { - struct dst_entry *dst = sk_dst_get(clcsock->sk); - struct in_device *in_dev; - struct sockaddr_in addr; - int rc = -ENOENT; - int len; - - if (!dst) { - rc = -ENOTCONN; - goto out; - } - if (!dst->dev) { - rc = -ENODEV; - goto out_rel; - } - - /* get address to which the internal TCP socket is bound */ - kernel_getsockname(clcsock, (struct sockaddr *)&addr, &len); - /* analyze IPv4 specific data of net_device belonging to TCP socket */ - rcu_read_lock(); - in_dev = __in_dev_get_rcu(dst->dev); - for_ifa(in_dev) { - if (!inet_ifa_match(addr.sin_addr.s_addr, ifa)) - continue; - *prefix_len = inet_mask_len(ifa->ifa_mask); - *subnet = ifa->ifa_address & ifa->ifa_mask; - rc = 0; - break; - } endfor_ifa(in_dev); - rcu_read_unlock(); - - out_rel: - dst_release(dst); - out: - return rc; - } - - static int smc_clnt_conf_first_link(struct smc_sock *smc, union ib_gid *gid) + static int smc_clnt_conf_first_link(struct smc_sock *smc) { struct smc_link_group *lgr = smc->conn.lgr; struct smc_link *link; @@@ -333,6 -312,9 +312,9 @@@ return rc; }
+ if (link->llc_confirm_rc) + return SMC_CLC_DECL_RMBE_EC; + rc = smc_ib_modify_qp_rts(link); if (rc) return SMC_CLC_DECL_INTERR; @@@ -347,11 -329,33 +329,33 @@@ /* send CONFIRM LINK response over RoCE fabric */ rc = smc_llc_send_confirm_link(link, link->smcibdev->mac[link->ibport - 1], - gid, SMC_LLC_RESP); + &link->smcibdev->gid[link->ibport - 1], + SMC_LLC_RESP); if (rc < 0) return SMC_CLC_DECL_TCL;
- return rc; + /* receive ADD LINK request from server over RoCE fabric */ + rest = wait_for_completion_interruptible_timeout(&link->llc_add, + SMC_LLC_WAIT_TIME); + if (rest <= 0) { + struct smc_clc_msg_decline dclc; + + rc = smc_clc_wait_msg(smc, &dclc, sizeof(dclc), + SMC_CLC_DECLINE); + return rc; + } + + /* send add link reject message, only one link supported for now */ + rc = smc_llc_send_add_link(link, + link->smcibdev->mac[link->ibport - 1], + &link->smcibdev->gid[link->ibport - 1], + SMC_LLC_RESP); + if (rc < 0) + return SMC_CLC_DECL_TCL; + + link->state = SMC_LNK_ACTIVE; + + return 0; }
static void smc_conn_save_peer_info(struct smc_sock *smc, @@@ -373,19 -377,9 +377,9 @@@ static void smc_link_save_peer_info(str link->peer_mtu = clc->qp_mtu; }
- static void smc_lgr_forget(struct smc_link_group *lgr) - { - spin_lock_bh(&smc_lgr_list.lock); - /* do not use this link group for new connections */ - if (!list_empty(&lgr->list)) - list_del_init(&lgr->list); - spin_unlock_bh(&smc_lgr_list.lock); - } - /* setup for RDMA connection of client */ static int smc_connect_rdma(struct smc_sock *smc) { - struct sockaddr_in *inaddr = (struct sockaddr_in *)smc->addr; struct smc_clc_msg_accept_confirm aclc; int local_contact = SMC_FIRST_CONTACT; struct smc_ib_device *smcibdev; @@@ -439,8 -433,8 +433,8 @@@
srv_first_contact = aclc.hdr.flag; mutex_lock(&smc_create_lgr_pending); - local_contact = smc_conn_create(smc, inaddr->sin_addr.s_addr, smcibdev, - ibport, &aclc.lcl, srv_first_contact); + local_contact = smc_conn_create(smc, smcibdev, ibport, &aclc.lcl, + srv_first_contact); if (local_contact < 0) { rc = local_contact; if (rc == -ENOMEM) @@@ -499,8 -493,7 +493,7 @@@
if (local_contact == SMC_FIRST_CONTACT) { /* QP confirmation over RoCE fabric */ - reason_code = smc_clnt_conf_first_link( - smc, &smcibdev->gid[ibport - 1]); + reason_code = smc_clnt_conf_first_link(smc); if (reason_code < 0) { rc = reason_code; goto out_err_unlock; @@@ -557,9 -550,8 +550,8 @@@ static int smc_connect(struct socket *s /* separate smc parameter checking to be safe */ if (alen < sizeof(addr->sa_family)) goto out_err; - if (addr->sa_family != AF_INET) + if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6) goto out_err; - smc->addr = addr; /* needed for nonblocking connect */
lock_sock(sk); switch (sk->sk_state) { @@@ -600,7 -592,7 +592,7 @@@ static int smc_clcsock_accept(struct sm int rc;
release_sock(lsk); - new_sk = smc_sock_alloc(sock_net(lsk), NULL); + new_sk = smc_sock_alloc(sock_net(lsk), NULL, lsk->sk_protocol); if (!new_sk) { rc = -ENOMEM; lsk->sk_err = ENOMEM; @@@ -749,9 -741,34 +741,34 @@@ static int smc_serv_conf_first_link(str
rc = smc_clc_wait_msg(smc, &dclc, sizeof(dclc), SMC_CLC_DECLINE); + return rc; }
- return rc; + if (link->llc_confirm_resp_rc) + return SMC_CLC_DECL_RMBE_EC; + + /* send ADD LINK request to client over the RoCE fabric */ + rc = smc_llc_send_add_link(link, + link->smcibdev->mac[link->ibport - 1], + &link->smcibdev->gid[link->ibport - 1], + SMC_LLC_REQ); + if (rc < 0) + return SMC_CLC_DECL_TCL; + + /* receive ADD LINK response from client over the RoCE fabric */ + rest = wait_for_completion_interruptible_timeout(&link->llc_add_resp, + SMC_LLC_WAIT_TIME); + if (rest <= 0) { + struct smc_clc_msg_decline dclc; + + rc = smc_clc_wait_msg(smc, &dclc, sizeof(dclc), + SMC_CLC_DECLINE); + return rc; + } + + link->state = SMC_LNK_ACTIVE; + + return 0; }
/* setup for RDMA connection of server */ @@@ -767,13 -784,10 +784,10 @@@ static void smc_listen_work(struct work struct sock *newsmcsk = &new_smc->sk; struct smc_clc_msg_proposal *pclc; struct smc_ib_device *smcibdev; - struct sockaddr_in peeraddr; u8 buf[SMC_CLC_MAX_LEN]; struct smc_link *link; int reason_code = 0; - int rc = 0, len; - __be32 subnet; - u8 prefix_len; + int rc = 0; u8 ibport;
/* check if peer is smc capable */ @@@ -808,28 -822,19 +822,19 @@@ goto decline_rdma; }
- /* determine subnet and mask from internal TCP socket */ - rc = smc_netinfo_by_tcpsk(newclcsock, &subnet, &prefix_len); - if (rc) { - reason_code = SMC_CLC_DECL_CNFERR; /* configuration error */ - goto decline_rdma; - } - pclc = (struct smc_clc_msg_proposal *)&buf; pclc_prfx = smc_clc_proposal_get_prefix(pclc); - if (pclc_prfx->outgoing_subnet != subnet || - pclc_prfx->prefix_len != prefix_len) { + + rc = smc_clc_prfx_match(newclcsock, pclc_prfx); + if (rc) { reason_code = SMC_CLC_DECL_CNFERR; /* configuration error */ goto decline_rdma; }
- /* get address of the peer connected to the internal TCP socket */ - kernel_getpeername(newclcsock, (struct sockaddr *)&peeraddr, &len); - /* allocate connection / link group */ mutex_lock(&smc_create_lgr_pending); - local_contact = smc_conn_create(new_smc, peeraddr.sin_addr.s_addr, - smcibdev, ibport, &pclc->lcl, 0); + local_contact = smc_conn_create(new_smc, smcibdev, ibport, &pclc->lcl, + 0); if (local_contact < 0) { rc = local_contact; if (rc == -ENOMEM) @@@ -978,6 -983,10 +983,6 @@@ out lsmc->clcsock = NULL; } release_sock(lsk); - /* no more listening, wake up smc_close_wait_listen_clcsock and - * accept - */ - lsk->sk_state_change(lsk); sock_put(&lsmc->sk); /* sock_hold in smc_listen */ }
@@@ -1071,7 -1080,7 +1076,7 @@@ out }
static int smc_getname(struct socket *sock, struct sockaddr *addr, - int *len, int peer) + int peer) { struct smc_sock *smc;
@@@ -1081,7 -1090,7 +1086,7 @@@
smc = smc_sk(sock->sk);
- return smc->clcsock->ops->getname(smc->clcsock, addr, len, peer); + return smc->clcsock->ops->getname(smc->clcsock, addr, peer); }
static int smc_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) @@@ -1379,6 -1388,7 +1384,7 @@@ static const struct proto_ops smc_sock_ static int smc_create(struct net *net, struct socket *sock, int protocol, int kern) { + int family = (protocol == SMCPROTO_SMC6) ? PF_INET6 : PF_INET; struct smc_sock *smc; struct sock *sk; int rc; @@@ -1388,20 -1398,20 +1394,20 @@@ goto out;
rc = -EPROTONOSUPPORT; - if ((protocol != IPPROTO_IP) && (protocol != IPPROTO_TCP)) + if (protocol != SMCPROTO_SMC && protocol != SMCPROTO_SMC6) goto out;
rc = -ENOBUFS; sock->ops = &smc_sock_ops; - sk = smc_sock_alloc(net, sock); + sk = smc_sock_alloc(net, sock, protocol); if (!sk) goto out;
/* create internal TCP socket for CLC handshake and fallback */ smc = smc_sk(sk); smc->use_fallback = false; /* assume rdma capability first */ - rc = sock_create_kern(net, PF_INET, SOCK_STREAM, - IPPROTO_TCP, &smc->clcsock); + rc = sock_create_kern(net, family, SOCK_STREAM, IPPROTO_TCP, + &smc->clcsock); if (rc) { sk_common_release(sk); goto out; @@@ -1441,16 -1451,23 +1447,23 @@@ static int __init smc_init(void
rc = proto_register(&smc_proto, 1); if (rc) { - pr_err("%s: proto_register fails with %d\n", __func__, rc); + pr_err("%s: proto_register(v4) fails with %d\n", __func__, rc); goto out_pnet; }
+ rc = proto_register(&smc_proto6, 1); + if (rc) { + pr_err("%s: proto_register(v6) fails with %d\n", __func__, rc); + goto out_proto; + } + rc = sock_register(&smc_sock_family_ops); if (rc) { pr_err("%s: sock_register fails with %d\n", __func__, rc); - goto out_proto; + goto out_proto6; } INIT_HLIST_HEAD(&smc_v4_hashinfo.ht); + INIT_HLIST_HEAD(&smc_v6_hashinfo.ht);
rc = smc_ib_register_client(); if (rc) { @@@ -1463,6 -1480,8 +1476,8 @@@
out_sock: sock_unregister(PF_SMC); + out_proto6: + proto_unregister(&smc_proto6); out_proto: proto_unregister(&smc_proto); out_pnet: @@@ -1481,11 -1500,13 +1496,13 @@@ static void __exit smc_exit(void spin_unlock_bh(&smc_lgr_list.lock); list_for_each_entry_safe(lgr, lg, &lgr_freeing_list, list) { list_del_init(&lgr->list); + cancel_delayed_work_sync(&lgr->free_work); smc_lgr_free(lgr); /* free link group */ } static_branch_disable(&tcp_have_smc); smc_ib_unregister_client(); sock_unregister(PF_SMC); + proto_unregister(&smc_proto6); proto_unregister(&smc_proto); smc_pnet_exit(); } diff --combined net/socket.c index 4ba9fc631c43,d9a1ac233b35..54dcb43e25a1 --- a/net/socket.c +++ b/net/socket.c @@@ -104,7 -104,6 +104,6 @@@ #include <linux/ipv6_route.h> #include <linux/route.h> #include <linux/sockios.h> - #include <linux/atalk.h> #include <net/busy_poll.h> #include <linux/errqueue.h>
@@@ -234,7 -233,7 +233,7 @@@ static int move_addr_to_user(struct soc return __put_user(klen, ulen); }
- static struct kmem_cache *sock_inode_cachep __read_mostly; + static struct kmem_cache *sock_inode_cachep __ro_after_init;
static struct inode *sock_alloc_inode(struct super_block *sb) { @@@ -991,10 -990,11 +990,11 @@@ static long sock_do_ioctl(struct net *n * what to do with it - that's up to the protocol still. */
- static struct ns_common *get_net_ns(struct ns_common *ns) + struct ns_common *get_net_ns(struct ns_common *ns) { return &get_net(container_of(ns, struct net, ns))->ns; } + EXPORT_SYMBOL_GPL(get_net_ns);
static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) { @@@ -1332,7 -1332,7 +1332,7 @@@ int sock_create_kern(struct net *net, i } EXPORT_SYMBOL(sock_create_kern);
-SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol) +int __sys_socket(int family, int type, int protocol) { int retval; struct socket *sock; @@@ -1359,16 -1359,12 +1359,16 @@@ return sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK)); }
+SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol) +{ + return __sys_socket(family, type, protocol); +} + /* * Create a pair of connected sockets. */
-SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol, - int __user *, usockvec) +int __sys_socketpair(int family, int type, int protocol, int __user *usockvec) { struct socket *sock1, *sock2; int fd1, fd2, err; @@@ -1453,12 -1449,6 +1453,12 @@@ out return err; }
+SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol, + int __user *, usockvec) +{ + return __sys_socketpair(family, type, protocol, usockvec); +} + /* * Bind a name to a socket. Nothing much to do here since it's * the protocol's responsibility to handle the local address. @@@ -1467,7 -1457,7 +1467,7 @@@ * the protocol layer (having also checked the address is ok). */
-SYSCALL_DEFINE3(bind, int, fd, struct sockaddr __user *, umyaddr, int, addrlen) +int __sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen) { struct socket *sock; struct sockaddr_storage address; @@@ -1490,18 -1480,13 +1490,18 @@@ return err; }
+SYSCALL_DEFINE3(bind, int, fd, struct sockaddr __user *, umyaddr, int, addrlen) +{ + return __sys_bind(fd, umyaddr, addrlen); +} + /* * Perform a listen. Basically, we allow the protocol to do anything * necessary for a listen, and if that works, we mark the socket as * ready for listening. */
-SYSCALL_DEFINE2(listen, int, fd, int, backlog) +int __sys_listen(int fd, int backlog) { struct socket *sock; int err, fput_needed; @@@ -1522,11 -1507,6 +1522,11 @@@ return err; }
+SYSCALL_DEFINE2(listen, int, fd, int, backlog) +{ + return __sys_listen(fd, backlog); +} + /* * For accept, we attempt to create a new socket, set up the link * with the client, wake up the client, then return the new @@@ -1539,8 -1519,8 +1539,8 @@@ * clean when we restucture accept also. */
-SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr, - int __user *, upeer_addrlen, int, flags) +int __sys_accept4(int fd, struct sockaddr __user *upeer_sockaddr, + int __user *upeer_addrlen, int flags) { struct socket *sock, *newsock; struct file *newfile; @@@ -1593,8 -1573,9 +1593,9 @@@ goto out_fd;
if (upeer_sockaddr) { - if (newsock->ops->getname(newsock, (struct sockaddr *)&address, - &len, 2) < 0) { + len = newsock->ops->getname(newsock, + (struct sockaddr *)&address, 2); + if (len < 0) { err = -ECONNABORTED; goto out_fd; } @@@ -1619,16 -1600,10 +1620,16 @@@ out_fd goto out_put; }
+SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr, + int __user *, upeer_addrlen, int, flags) +{ + return __sys_accept4(fd, upeer_sockaddr, upeer_addrlen, flags); +} + SYSCALL_DEFINE3(accept, int, fd, struct sockaddr __user *, upeer_sockaddr, int __user *, upeer_addrlen) { - return sys_accept4(fd, upeer_sockaddr, upeer_addrlen, 0); + return __sys_accept4(fd, upeer_sockaddr, upeer_addrlen, 0); }
/* @@@ -1643,7 -1618,8 +1644,7 @@@ * include the -EINPROGRESS status for such sockets. */
-SYSCALL_DEFINE3(connect, int, fd, struct sockaddr __user *, uservaddr, - int, addrlen) +int __sys_connect(int fd, struct sockaddr __user *uservaddr, int addrlen) { struct socket *sock; struct sockaddr_storage address; @@@ -1669,23 -1645,17 +1670,23 @@@ out return err; }
+SYSCALL_DEFINE3(connect, int, fd, struct sockaddr __user *, uservaddr, + int, addrlen) +{ + return __sys_connect(fd, uservaddr, addrlen); +} + /* * Get the local address ('name') of a socket object. Move the obtained * name to user space. */
-SYSCALL_DEFINE3(getsockname, int, fd, struct sockaddr __user *, usockaddr, - int __user *, usockaddr_len) +int __sys_getsockname(int fd, struct sockaddr __user *usockaddr, + int __user *usockaddr_len) { struct socket *sock; struct sockaddr_storage address; - int len, err, fput_needed; + int err, fput_needed;
sock = sockfd_lookup_light(fd, &err, &fput_needed); if (!sock) @@@ -1695,10 -1665,11 +1696,11 @@@ if (err) goto out_put;
- err = sock->ops->getname(sock, (struct sockaddr *)&address, &len, 0); - if (err) + err = sock->ops->getname(sock, (struct sockaddr *)&address, 0); + if (err < 0) goto out_put; - err = move_addr_to_user(&address, len, usockaddr, usockaddr_len); + /* "err" is actually length in this case */ + err = move_addr_to_user(&address, err, usockaddr, usockaddr_len);
out_put: fput_light(sock->file, fput_needed); @@@ -1706,23 -1677,17 +1708,23 @@@ out return err; }
+SYSCALL_DEFINE3(getsockname, int, fd, struct sockaddr __user *, usockaddr, + int __user *, usockaddr_len) +{ + return __sys_getsockname(fd, usockaddr, usockaddr_len); +} + /* * Get the remote address ('name') of a socket object. Move the obtained * name to user space. */
-SYSCALL_DEFINE3(getpeername, int, fd, struct sockaddr __user *, usockaddr, - int __user *, usockaddr_len) +int __sys_getpeername(int fd, struct sockaddr __user *usockaddr, + int __user *usockaddr_len) { struct socket *sock; struct sockaddr_storage address; - int len, err, fput_needed; + int err, fput_needed;
sock = sockfd_lookup_light(fd, &err, &fput_needed); if (sock != NULL) { @@@ -1732,30 -1697,25 +1734,29 @@@ return err; }
- err = - sock->ops->getname(sock, (struct sockaddr *)&address, &len, - 1); - if (!err) - err = move_addr_to_user(&address, len, usockaddr, + err = sock->ops->getname(sock, (struct sockaddr *)&address, 1); + if (err >= 0) + /* "err" is actually length in this case */ + err = move_addr_to_user(&address, err, usockaddr, usockaddr_len); fput_light(sock->file, fput_needed); } return err; }
+SYSCALL_DEFINE3(getpeername, int, fd, struct sockaddr __user *, usockaddr, + int __user *, usockaddr_len) +{ + return __sys_getpeername(fd, usockaddr, usockaddr_len); +} + /* * Send a datagram to a given address. We move the address into kernel * space and check the user space data area is readable before invoking * the protocol. */ - -SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len, - unsigned int, flags, struct sockaddr __user *, addr, - int, addr_len) +int __sys_sendto(int fd, void __user *buff, size_t len, unsigned int flags, + struct sockaddr __user *addr, int addr_len) { struct socket *sock; struct sockaddr_storage address; @@@ -1793,13 -1753,6 +1794,13 @@@ out return err; }
+SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len, + unsigned int, flags, struct sockaddr __user *, addr, + int, addr_len) +{ + return __sys_sendto(fd, buff, len, flags, addr, addr_len); +} + /* * Send a datagram down a socket. */ @@@ -1807,7 -1760,7 +1808,7 @@@ SYSCALL_DEFINE4(send, int, fd, void __user *, buff, size_t, len, unsigned int, flags) { - return sys_sendto(fd, buff, len, flags, NULL, 0); + return __sys_sendto(fd, buff, len, flags, NULL, 0); }
/* @@@ -1815,8 -1768,10 +1816,8 @@@ * sender. We verify the buffers are writable and if needed move the * sender address from kernel to user space. */ - -SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size, - unsigned int, flags, struct sockaddr __user *, addr, - int __user *, addr_len) +int __sys_recvfrom(int fd, void __user *ubuf, size_t size, unsigned int flags, + struct sockaddr __user *addr, int __user *addr_len) { struct socket *sock; struct iovec iov; @@@ -1856,13 -1811,6 +1857,13 @@@ out return err; }
+SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size, + unsigned int, flags, struct sockaddr __user *, addr, + int __user *, addr_len) +{ + return __sys_recvfrom(fd, ubuf, size, flags, addr, addr_len); +} + /* * Receive a datagram from a socket. */ @@@ -1870,7 -1818,7 +1871,7 @@@ SYSCALL_DEFINE4(recv, int, fd, void __user *, ubuf, size_t, size, unsigned int, flags) { - return sys_recvfrom(fd, ubuf, size, flags, NULL, NULL); + return __sys_recvfrom(fd, ubuf, size, flags, NULL, NULL); }
/* @@@ -1878,8 -1826,8 +1879,8 @@@ * to pass the user mode parameter for the protocols to sort out. */
-SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname, - char __user *, optval, int, optlen) +static int __sys_setsockopt(int fd, int level, int optname, + char __user *optval, int optlen) { int err, fput_needed; struct socket *sock; @@@ -1907,19 -1855,13 +1908,19 @@@ out_put return err; }
+SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname, + char __user *, optval, int, optlen) +{ + return __sys_setsockopt(fd, level, optname, optval, optlen); +} + /* * Get a socket option. Because we don't know the option lengths we have * to pass a user mode parameter for the protocols to sort out. */
-SYSCALL_DEFINE5(getsockopt, int, fd, int, level, int, optname, - char __user *, optval, int __user *, optlen) +static int __sys_getsockopt(int fd, int level, int optname, + char __user *optval, int __user *optlen) { int err, fput_needed; struct socket *sock; @@@ -1944,17 -1886,11 +1945,17 @@@ out_put return err; }
+SYSCALL_DEFINE5(getsockopt, int, fd, int, level, int, optname, + char __user *, optval, int __user *, optlen) +{ + return __sys_getsockopt(fd, level, optname, optval, optlen); +} + /* * Shutdown a socket. */
-SYSCALL_DEFINE2(shutdown, int, fd, int, how) +int __sys_shutdown(int fd, int how) { int err, fput_needed; struct socket *sock; @@@ -1969,11 -1905,6 +1970,11 @@@ return err; }
+SYSCALL_DEFINE2(shutdown, int, fd, int, how) +{ + return __sys_shutdown(fd, how); +} + /* A couple of helpful macros for getting the address of the 32/64 bit * fields which are the same type (int / unsigned) on our platforms. */ @@@ -2137,16 -2068,12 +2138,16 @@@ out_freeiov * BSD sendmsg interface */
-long __sys_sendmsg(int fd, struct user_msghdr __user *msg, unsigned flags) +long __sys_sendmsg(int fd, struct user_msghdr __user *msg, unsigned int flags, + bool forbid_cmsg_compat) { int fput_needed, err; struct msghdr msg_sys; struct socket *sock;
+ if (forbid_cmsg_compat && (flags & MSG_CMSG_COMPAT)) + return -EINVAL; + sock = sockfd_lookup_light(fd, &err, &fput_needed); if (!sock) goto out; @@@ -2160,7 -2087,9 +2161,7 @@@ out
SYSCALL_DEFINE3(sendmsg, int, fd, struct user_msghdr __user *, msg, unsigned int, flags) { - if (flags & MSG_CMSG_COMPAT) - return -EINVAL; - return __sys_sendmsg(fd, msg, flags); + return __sys_sendmsg(fd, msg, flags, true); }
/* @@@ -2168,7 -2097,7 +2169,7 @@@ */
int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, - unsigned int flags) + unsigned int flags, bool forbid_cmsg_compat) { int fput_needed, err, datagrams; struct socket *sock; @@@ -2178,9 -2107,6 +2179,9 @@@ struct used_address used_address; unsigned int oflags = flags;
+ if (forbid_cmsg_compat && (flags & MSG_CMSG_COMPAT)) + return -EINVAL; + if (vlen > UIO_MAXIOV) vlen = UIO_MAXIOV;
@@@ -2237,7 -2163,9 +2238,7 @@@ SYSCALL_DEFINE4(sendmmsg, int, fd, struct mmsghdr __user *, mmsg, unsigned int, vlen, unsigned int, flags) { - if (flags & MSG_CMSG_COMPAT) - return -EINVAL; - return __sys_sendmmsg(fd, mmsg, vlen, flags); + return __sys_sendmmsg(fd, mmsg, vlen, flags, true); }
static int ___sys_recvmsg(struct socket *sock, struct user_msghdr __user *msg, @@@ -2310,16 -2238,12 +2311,16 @@@ out_freeiov * BSD recvmsg interface */
-long __sys_recvmsg(int fd, struct user_msghdr __user *msg, unsigned flags) +long __sys_recvmsg(int fd, struct user_msghdr __user *msg, unsigned int flags, + bool forbid_cmsg_compat) { int fput_needed, err; struct msghdr msg_sys; struct socket *sock;
+ if (forbid_cmsg_compat && (flags & MSG_CMSG_COMPAT)) + return -EINVAL; + sock = sockfd_lookup_light(fd, &err, &fput_needed); if (!sock) goto out; @@@ -2334,7 -2258,9 +2335,7 @@@ out SYSCALL_DEFINE3(recvmsg, int, fd, struct user_msghdr __user *, msg, unsigned int, flags) { - if (flags & MSG_CMSG_COMPAT) - return -EINVAL; - return __sys_recvmsg(fd, msg, flags); + return __sys_recvmsg(fd, msg, flags, true); }
/* @@@ -2363,10 -2289,12 +2364,12 @@@ int __sys_recvmmsg(int fd, struct mmsgh if (!sock) return err;
- err = sock_error(sock->sk); - if (err) { - datagrams = err; - goto out_put; + if (likely(!(flags & MSG_ERRQUEUE))) { + err = sock_error(sock->sk); + if (err) { + datagrams = err; + goto out_put; + } }
entry = mmsg; @@@ -2450,9 -2378,9 +2453,9 @@@ out_put return datagrams; }
-SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr __user *, mmsg, - unsigned int, vlen, unsigned int, flags, - struct timespec __user *, timeout) +static int do_sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, + unsigned int vlen, unsigned int flags, + struct timespec __user *timeout) { int datagrams; struct timespec timeout_sys; @@@ -2475,13 -2403,6 +2478,13 @@@ return datagrams; }
+SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr __user *, mmsg, + unsigned int, vlen, unsigned int, flags, + struct timespec __user *, timeout) +{ + return do_sys_recvmmsg(fd, mmsg, vlen, flags, timeout); +} + #ifdef __ARCH_WANT_SYS_SOCKETCALL /* Argument list sizes for sys_socketcall */ #define AL(x) ((x) * sizeof(unsigned long)) @@@ -2529,82 -2450,76 +2532,82 @@@ SYSCALL_DEFINE2(socketcall, int, call,
switch (call) { case SYS_SOCKET: - err = sys_socket(a0, a1, a[2]); + err = __sys_socket(a0, a1, a[2]); break; case SYS_BIND: - err = sys_bind(a0, (struct sockaddr __user *)a1, a[2]); + err = __sys_bind(a0, (struct sockaddr __user *)a1, a[2]); break; case SYS_CONNECT: - err = sys_connect(a0, (struct sockaddr __user *)a1, a[2]); + err = __sys_connect(a0, (struct sockaddr __user *)a1, a[2]); break; case SYS_LISTEN: - err = sys_listen(a0, a1); + err = __sys_listen(a0, a1); break; case SYS_ACCEPT: - err = sys_accept4(a0, (struct sockaddr __user *)a1, - (int __user *)a[2], 0); + err = __sys_accept4(a0, (struct sockaddr __user *)a1, + (int __user *)a[2], 0); break; case SYS_GETSOCKNAME: err = - sys_getsockname(a0, (struct sockaddr __user *)a1, - (int __user *)a[2]); + __sys_getsockname(a0, (struct sockaddr __user *)a1, + (int __user *)a[2]); break; case SYS_GETPEERNAME: err = - sys_getpeername(a0, (struct sockaddr __user *)a1, - (int __user *)a[2]); + __sys_getpeername(a0, (struct sockaddr __user *)a1, + (int __user *)a[2]); break; case SYS_SOCKETPAIR: - err = sys_socketpair(a0, a1, a[2], (int __user *)a[3]); + err = __sys_socketpair(a0, a1, a[2], (int __user *)a[3]); break; case SYS_SEND: - err = sys_send(a0, (void __user *)a1, a[2], a[3]); + err = __sys_sendto(a0, (void __user *)a1, a[2], a[3], + NULL, 0); break; case SYS_SENDTO: - err = sys_sendto(a0, (void __user *)a1, a[2], a[3], - (struct sockaddr __user *)a[4], a[5]); + err = __sys_sendto(a0, (void __user *)a1, a[2], a[3], + (struct sockaddr __user *)a[4], a[5]); break; case SYS_RECV: - err = sys_recv(a0, (void __user *)a1, a[2], a[3]); + err = __sys_recvfrom(a0, (void __user *)a1, a[2], a[3], + NULL, NULL); break; case SYS_RECVFROM: - err = sys_recvfrom(a0, (void __user *)a1, a[2], a[3], - (struct sockaddr __user *)a[4], - (int __user *)a[5]); + err = __sys_recvfrom(a0, (void __user *)a1, a[2], a[3], + (struct sockaddr __user *)a[4], + (int __user *)a[5]); break; case SYS_SHUTDOWN: - err = sys_shutdown(a0, a1); + err = __sys_shutdown(a0, a1); break; case SYS_SETSOCKOPT: - err = sys_setsockopt(a0, a1, a[2], (char __user *)a[3], a[4]); + err = __sys_setsockopt(a0, a1, a[2], (char __user *)a[3], + a[4]); break; case SYS_GETSOCKOPT: err = - sys_getsockopt(a0, a1, a[2], (char __user *)a[3], - (int __user *)a[4]); + __sys_getsockopt(a0, a1, a[2], (char __user *)a[3], + (int __user *)a[4]); break; case SYS_SENDMSG: - err = sys_sendmsg(a0, (struct user_msghdr __user *)a1, a[2]); + err = __sys_sendmsg(a0, (struct user_msghdr __user *)a1, + a[2], true); break; case SYS_SENDMMSG: - err = sys_sendmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3]); + err = __sys_sendmmsg(a0, (struct mmsghdr __user *)a1, a[2], + a[3], true); break; case SYS_RECVMSG: - err = sys_recvmsg(a0, (struct user_msghdr __user *)a1, a[2]); + err = __sys_recvmsg(a0, (struct user_msghdr __user *)a1, + a[2], true); break; case SYS_RECVMMSG: - err = sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3], - (struct timespec __user *)a[4]); + err = do_sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2], + a[3], (struct timespec __user *)a[4]); break; case SYS_ACCEPT4: - err = sys_accept4(a0, (struct sockaddr __user *)a1, - (int __user *)a[2], a[3]); + err = __sys_accept4(a0, (struct sockaddr __user *)a1, + (int __user *)a[2], a[3]); break; default: err = -EINVAL; @@@ -2675,11 -2590,6 +2678,11 @@@ void sock_unregister(int family } EXPORT_SYMBOL(sock_unregister);
+bool sock_is_registered(int family) +{ + return family < NPROTO && rcu_access_pointer(net_families[family]); +} + static int __init sock_init(void) { int err; @@@ -3259,17 -3169,15 +3262,15 @@@ int kernel_connect(struct socket *sock } EXPORT_SYMBOL(kernel_connect);
- int kernel_getsockname(struct socket *sock, struct sockaddr *addr, - int *addrlen) + int kernel_getsockname(struct socket *sock, struct sockaddr *addr) { - return sock->ops->getname(sock, addr, addrlen, 0); + return sock->ops->getname(sock, addr, 0); } EXPORT_SYMBOL(kernel_getsockname);
- int kernel_getpeername(struct socket *sock, struct sockaddr *addr, - int *addrlen) + int kernel_getpeername(struct socket *sock, struct sockaddr *addr) { - return sock->ops->getname(sock, addr, addrlen, 1); + return sock->ops->getname(sock, addr, 1); } EXPORT_SYMBOL(kernel_getpeername);
diff --combined net/sunrpc/clnt.c index eb1a81895397,806395687bb6..d839c33ae7d9 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@@ -1231,7 -1231,7 +1231,7 @@@ static const struct sockaddr_in6 rpc_in * negative errno is returned. */ static int rpc_sockname(struct net *net, struct sockaddr *sap, size_t salen, - struct sockaddr *buf, int buflen) + struct sockaddr *buf) { struct socket *sock; int err; @@@ -1269,7 -1269,7 +1269,7 @@@ goto out_release; }
- err = kernel_getsockname(sock, buf, &buflen); + err = kernel_getsockname(sock, buf); if (err < 0) { dprintk("RPC: getsockname failed (%d)\n", err); goto out_release; @@@ -1353,7 -1353,7 +1353,7 @@@ int rpc_localaddr(struct rpc_clnt *clnt rcu_read_unlock();
rpc_set_port(sap, 0); - err = rpc_sockname(net, sap, salen, buf, buflen); + err = rpc_sockname(net, sap, salen, buf); put_net(net); if (err != 0) /* Couldn't discover local address, return ANYADDR */ @@@ -1546,7 -1546,6 +1546,7 @@@ call_reserveresult(struct rpc_task *tas task->tk_status = 0; if (status >= 0) { if (task->tk_rqstp) { + xprt_request_init(task); task->tk_action = call_refresh; return; } @@@ -1888,7 -1887,7 +1888,7 @@@ call_connect_status(struct rpc_task *ta
dprint_status(task);
- trace_rpc_connect_status(task, status); + trace_rpc_connect_status(task); task->tk_status = 0; switch (status) { case -ECONNREFUSED: @@@ -2015,9 -2014,6 +2015,9 @@@ call_transmit_status(struct rpc_task *t case -EPERM: if (RPC_IS_SOFTCONN(task)) { xprt_end_transmit(task); + if (!task->tk_msg.rpc_proc->p_proc) + trace_xprt_ping(task->tk_xprt, + task->tk_status); rpc_exit(task, task->tk_status); break; } @@@ -2116,9 -2112,6 +2116,9 @@@ call_status(struct rpc_task *task struct rpc_rqst *req = task->tk_rqstp; int status;
+ if (!task->tk_msg.rpc_proc->p_proc) + trace_xprt_ping(task->tk_xprt, task->tk_status); + if (req->rq_reply_bytes_recvd > 0 && !req->rq_bytes_sent) task->tk_status = req->rq_reply_bytes_recvd;
diff --combined net/sunrpc/xprtsock.c index 2511c21ef114,956e29c1438d..9e1c5024aba9 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@@ -527,7 -527,6 +527,7 @@@ static int xs_local_send_request(struc xs_pktdump("packet data:", req->rq_svec->iov_base, req->rq_svec->iov_len);
+ req->rq_xtime = ktime_get(); status = xs_sendpages(transport->sock, NULL, 0, xdr, req->rq_bytes_sent, true, &sent); dprintk("RPC: %s(%u) = %d\n", @@@ -590,7 -589,6 +590,7 @@@ static int xs_udp_send_request(struct r
if (!xprt_bound(xprt)) return -ENOTCONN; + req->rq_xtime = ktime_get(); status = xs_sendpages(transport->sock, xs_addr(xprt), xprt->addrlen, xdr, req->rq_bytes_sent, true, &sent);
@@@ -680,7 -678,6 +680,7 @@@ static int xs_tcp_send_request(struct r /* Continue transmitting the packet/record. We must be careful * to cope with writespace callbacks arriving _after_ we have * called sendmsg(). */ + req->rq_xtime = ktime_get(); while (1) { sent = 0; status = xs_sendpages(transport->sock, NULL, 0, xdr, @@@ -1063,7 -1060,6 +1063,7 @@@ static void xs_udp_data_read_skb(struc if (!rovr) goto out_unlock; xprt_pin_rqst(rovr); + xprt_update_rtt(rovr->rq_task); spin_unlock(&xprt->recv_lock); task = rovr->rq_task;
@@@ -1798,10 -1794,9 +1798,9 @@@ static void xs_sock_set_reuseport(struc static unsigned short xs_sock_getport(struct socket *sock) { struct sockaddr_storage buf; - int buflen; unsigned short port = 0;
- if (kernel_getsockname(sock, (struct sockaddr *)&buf, &buflen) < 0) + if (kernel_getsockname(sock, (struct sockaddr *)&buf) < 0) goto out; switch (buf.ss_family) { case AF_INET6: @@@ -2764,7 -2759,6 +2763,7 @@@ static const struct rpc_xprt_ops xs_loc .reserve_xprt = xprt_reserve_xprt, .release_xprt = xs_tcp_release_xprt, .alloc_slot = xprt_alloc_slot, + .free_slot = xprt_free_slot, .rpcbind = xs_local_rpcbind, .set_port = xs_local_set_port, .connect = xs_local_connect, @@@ -2784,7 -2778,6 +2783,7 @@@ static const struct rpc_xprt_ops xs_udp .reserve_xprt = xprt_reserve_xprt_cong, .release_xprt = xprt_release_xprt_cong, .alloc_slot = xprt_alloc_slot, + .free_slot = xprt_free_slot, .rpcbind = rpcb_getport_async, .set_port = xs_set_port, .connect = xs_connect, @@@ -2806,7 -2799,6 +2805,7 @@@ static const struct rpc_xprt_ops xs_tcp .reserve_xprt = xprt_reserve_xprt, .release_xprt = xs_tcp_release_xprt, .alloc_slot = xprt_lock_and_alloc_slot, + .free_slot = xprt_free_slot, .rpcbind = rpcb_getport_async, .set_port = xs_set_port, .connect = xs_connect, @@@ -2838,7 -2830,6 +2837,7 @@@ static const struct rpc_xprt_ops bc_tcp .reserve_xprt = xprt_reserve_xprt, .release_xprt = xprt_release_xprt, .alloc_slot = xprt_alloc_slot, + .free_slot = xprt_free_slot, .buf_alloc = bc_malloc, .buf_free = bc_free, .send_request = bc_send_request, diff --combined net/xfrm/xfrm_policy.c index 625b3fca5704,77d9d1ab05ce..cb3bb9ae4407 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@@ -1458,13 -1458,10 +1458,13 @@@ xfrm_tmpl_resolve(struct xfrm_policy ** static int xfrm_get_tos(const struct flowi *fl, int family) { const struct xfrm_policy_afinfo *afinfo; - int tos = 0; + int tos;
afinfo = xfrm_policy_get_afinfo(family); - tos = afinfo ? afinfo->get_tos(fl) : 0; + if (!afinfo) + return 0; + + tos = afinfo->get_tos(fl);
rcu_read_unlock();
@@@ -1894,7 -1891,7 +1894,7 @@@ static void xfrm_policy_queue_process(s spin_unlock(&pq->hold_queue.lock);
dst_hold(xfrm_dst_path(dst)); - dst = xfrm_lookup(net, xfrm_dst_path(dst), &fl, sk, 0); + dst = xfrm_lookup(net, xfrm_dst_path(dst), &fl, sk, XFRM_LOOKUP_QUEUE); if (IS_ERR(dst)) goto purge_queue;
@@@ -2732,14 -2729,14 +2732,14 @@@ static const void *xfrm_get_dst_nexthop while (dst->xfrm) { const struct xfrm_state *xfrm = dst->xfrm;
+ dst = xfrm_dst_child(dst); + if (xfrm->props.mode == XFRM_MODE_TRANSPORT) continue; if (xfrm->type->flags & XFRM_TYPE_REMOTE_COADDR) daddr = xfrm->coaddr; else if (!(xfrm->type->flags & XFRM_TYPE_LOCAL_COADDR)) daddr = &xfrm->id.daddr; - - dst = xfrm_dst_child(dst); } return daddr; } @@@ -2985,6 -2982,7 +2985,7 @@@ static void __net_exit xfrm_net_exit(st static struct pernet_operations __net_initdata xfrm_net_ops = { .init = xfrm_net_init, .exit = xfrm_net_exit, + .async = true, };
void __init xfrm_init(void) diff --combined net/xfrm/xfrm_user.c index 080035f056d9,aff2e84ec761..e92b8c019c88 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@@ -121,17 -121,22 +121,17 @@@ static inline int verify_replay(struct struct nlattr *rt = attrs[XFRMA_REPLAY_ESN_VAL]; struct xfrm_replay_state_esn *rs;
- if (p->flags & XFRM_STATE_ESN) { - if (!rt) - return -EINVAL; - - rs = nla_data(rt); + if (!rt) + return (p->flags & XFRM_STATE_ESN) ? -EINVAL : 0;
- if (rs->bmp_len > XFRMA_REPLAY_ESN_MAX / sizeof(rs->bmp[0]) / 8) - return -EINVAL; + rs = nla_data(rt);
- if (nla_len(rt) < (int)xfrm_replay_state_esn_len(rs) && - nla_len(rt) != sizeof(*rs)) - return -EINVAL; - } + if (rs->bmp_len > XFRMA_REPLAY_ESN_MAX / sizeof(rs->bmp[0]) / 8) + return -EINVAL;
- if (!rt) - return 0; + if (nla_len(rt) < (int)xfrm_replay_state_esn_len(rs) && + nla_len(rt) != sizeof(*rs)) + return -EINVAL;
/* As only ESP and AH support ESN feature. */ if ((p->id.proto != IPPROTO_ESP) && (p->id.proto != IPPROTO_AH)) @@@ -3253,6 -3258,7 +3253,7 @@@ static void __net_exit xfrm_user_net_ex static struct pernet_operations xfrm_user_net_ops = { .init = xfrm_user_net_init, .exit_batch = xfrm_user_net_exit, + .async = true, };
static int __init xfrm_user_init(void)