* Re: [PATCH v5 net-next 0/9] net: dsa: netc: add bridge mode support
From: patchwork-bot+netdevbpf @ 2026-06-15 21:50 UTC (permalink / raw)
To: Wei Fang
Cc: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, chleroy, andrew, olteanv, linux,
wei.fang, imx, netdev, linux-kernel, linuxppc-dev,
linux-arm-kernel
In-Reply-To: <20260611021458.2629145-1-wei.fang@oss.nxp.com>
Hello:
This series was applied to netdev/net-next.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Thu, 11 Jun 2026 10:14:49 +0800 you wrote:
> From: Wei Fang <wei.fang@nxp.com>
>
> This series adds bridge mode support to the NETC DSA switch driver,
> covering both VLAN-aware and VLAN-unaware operation.
>
> The NETC switch manages forwarding through a set of hardware tables
> accessed via NTMP: the FDB table (FDBT), VLAN filter table (VFT), egress
> treatment table (ETT), and egress count table (ECT). The series extends
> the NTMP layer with the operations required for bridging, then builds the
> DSA bridge callbacks on top.
>
> [...]
Here is the summary with links:
- [v5,net-next,1/9] net: enetc: add interfaces to manage dynamic FDB entries
https://git.kernel.org/netdev/net-next/c/ca394837dfdd
- [v5,net-next,2/9] net: enetc: add "Update" and "Delete" operations to VLAN filter table
https://git.kernel.org/netdev/net-next/c/c52b6702a948
- [v5,net-next,3/9] net: enetc: add interfaces to manage egress treatment table
https://git.kernel.org/netdev/net-next/c/3cc291a35939
- [v5,net-next,4/9] net: enetc: add "Update" operation to the egress count table
https://git.kernel.org/netdev/net-next/c/d51f238a154a
- [v5,net-next,5/9] net: dsa: netc: initialize the group bitmap of ETT and ECT
https://git.kernel.org/netdev/net-next/c/1a58ae73dd74
- [v5,net-next,6/9] net: enetc: add helpers to set/clear table bitmap
https://git.kernel.org/netdev/net-next/c/8469b17310d1
- [v5,net-next,7/9] net: dsa: netc: add VLAN filter table and egress treatment management
https://git.kernel.org/netdev/net-next/c/84b4a3b30abd
- [v5,net-next,8/9] net: dsa: netc: add bridge mode support
https://git.kernel.org/netdev/net-next/c/751aa5a5d593
- [v5,net-next,9/9] net: dsa: netc: implement dynamic FDB entry ageing
https://git.kernel.org/netdev/net-next/c/05b5ee610fbb
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH net-next] octeontx2-pf: add page pool ethtool statistics
From: Jakub Kicinski @ 2026-06-15 21:50 UTC (permalink / raw)
To: Ratheesh Kannoth
Cc: linux-kernel, netdev, andrew+netdev, davem, edumazet, pabeni,
sgoutham
In-Reply-To: <20260615032141.521667-1-rkannoth@marvell.com>
On Mon, 15 Jun 2026 08:51:41 +0530 Ratheesh Kannoth wrote:
> Expose page pool allocator statistics through ethtool.
> When the interface is up, aggregate stats from each
> receive queue page pool and append the common page_pool ethtool stat
> block to the driver's private statistics set.
include/net/page_pool/helpers.h :
/* Deprecated driver-facing API, use netlink instead */
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
int page_pool_ethtool_stats_get_count(void);
u8 *page_pool_ethtool_stats_get_strings(u8 *data);
u64 *page_pool_ethtool_stats_get(u64 *data, const void *stats);
Is the page pool in your driver shared by multiple netdevs?
If not just set netdev in page_pool_params
If yes then you need to explain it in the commit msg
Please note that net-next is closed for the next 2 weeks
--
pw-bot: cr
^ permalink raw reply
* Re: [PATCH v18 net-next 00/11] nbl driver for Nebulamatrix NICs
From: Jakub Kicinski @ 2026-06-15 21:54 UTC (permalink / raw)
To: illusion.wang
Cc: dimon.zhao, alvin.wang, sam.chen, netdev, andrew+netdev, corbet,
horms, linux-doc, pabeni, vadim.fedorenko, lukas.bulwahn,
edumazet, enelsonmoore, skhan, hkallweit1, open list
In-Reply-To: <20260611044916.2383-1-illusion.wang@nebula-matrix.com>
On Thu, 11 Jun 2026 12:48:59 +0800 illusion.wang wrote:
> This patch series represents the first phase. We plan to integrate it in
> two phases: the first phase covers mailbox and chip configuration,
> while the second phase involves net dev configuration.
> Together, they will provide basic PF-based Ethernet port transmission and
> reception capabilities.
7.1 has been tagged and the merge window for 7.2 has started.
It's a bit late to be adding drivers, so please repost this
after 7.2-rc1 has been tagged and net-next re-opened:
https://netdev.bots.linux.dev/net-next.html
--
pw-bot: cr
^ permalink raw reply
* Re: [PATCH net-next v3 2/4] udmabuf: emit one sg entry per pinned folio
From: Jakub Kicinski @ 2026-06-15 21:57 UTC (permalink / raw)
To: Bobby Eshleman
Cc: Donald Hunter, David S. Miller, Eric Dumazet, Paolo Abeni,
Simon Horman, Andrew Lunn, Gerd Hoffmann, Vivek Kasireddy,
Sumit Semwal, Christian König, Shuah Khan, netdev,
linux-kernel, dri-devel, linux-media, linaro-mm-sig,
linux-kselftest, sdf, razor, daniel, almasrymina, matttbe,
skhawaja, dw, Bobby Eshleman
In-Reply-To: <20260612-tcpdm-large-niovs-v3-2-a3b693e76fcb@meta.com>
On Fri, 12 Jun 2026 09:25:58 -0700 Bobby Eshleman wrote:
> dma_map_sgtable() does not always merge contiguous pages for us, so we
> do this internally before exporting.
>
> Signed-off-by: Bobby Eshleman <bobbyeshleman@meta.com>
> ---
> drivers/dma-buf/udmabuf.c
This will need at the very least an ack from DMABUF maintainers,
so it's a bit late to consider it for 7.2
--
pw-bot: defer
^ permalink raw reply
* Re: [PATCH net-next 1/5] tls: reject the combination of TLS and sockmap
From: Sabrina Dubroca @ 2026-06-15 22:00 UTC (permalink / raw)
To: Jakub Sitnicki
Cc: Jakub Kicinski, davem, netdev, edumazet, pabeni, andrew+netdev,
horms, bpf, john.fastabend
In-Reply-To: <87tsr3bq2m.fsf@cloudflare.com>
2026-06-15, 20:45:21 +0200, Jakub Sitnicki wrote:
> On Sat, Jun 13, 2026 at 06:40 PM -07, Jakub Kicinski wrote:
> > TLS and sockmap (BPF psock) integration hides a lot of latent bugs.
> > Bugs which may be more or less relevant for real users but they
> > are definitely exploitable.
> >
> > We could not find anyone actively using this integration so let's
> > reject this config. Adding a TLS socket to a sockmap was already
> > rejected by sk_psock_init() through the inet_csk_has_ulp() check.
> > We need to reject the attempts to configure the TLS keys (rather
> > than adding the ULP itself) because checking prior to the ULP
> > installation is tricky without risking a race with sockmap getting
> > added in parallel (sockmap does not hold the socket lock).
> >
> > This patch is a minimal rejection of the feature. Subsequent patch
> > in the series will do a light dead code removal. Full cleanup would
> > require a major rewrite of the Tx path, we don't need skmsg any more.
> >
> > Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> > ---
>
> SGTM until we can come up with a generic way to exclude sockmapped
> sockets from ktls and espintcp.
And possibly ovpn too.
Reviewed-by: Sabrina Dubroca <sd@queasysnail.net>
--
Sabrina
^ permalink raw reply
* Re: [PATCH net-next 2/5] tls: remove dead sockmap (psock) handling from the SW path
From: Sabrina Dubroca @ 2026-06-15 22:20 UTC (permalink / raw)
To: Jakub Kicinski
Cc: davem, netdev, edumazet, pabeni, andrew+netdev, horms, bpf, jakub,
john.fastabend
In-Reply-To: <20260614014102.461064-3-kuba@kernel.org>
2026-06-13, 18:40:57 -0700, Jakub Kicinski wrote:
> TLS and sockmap are now mutually exclusive. Try to delete the code
> from sendmsg and recvmsg path which is now obviously dead.
>
> The main goal is to delete enough code for AI security scanners
> to no longer bother us with sockmap related bugs. At the same
> time retain the code in case someone has the cycles to fix
> all of this and make the integration work, again.
>
> If the integration does not get restored we can wipe the rest
> of the skmsg code from TLS in two or three releases.
>
> The changes on the Tx side are deeper since that's where most
> of the bugs are, Rx side simply takes the data from sockmap
> and gives it to the user. On Tx split record handling and
> rolling back the iterator were the two problem areas.
>
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> ---
> include/linux/skmsg.h | 9 -
> net/core/skmsg.c | 52 +-----
> net/tls/tls_main.c | 8 +-
> net/tls/tls_sw.c | 399 +++---------------------------------------
> 4 files changed, 31 insertions(+), 437 deletions(-)
Reviewed-by: Sabrina Dubroca <sd@queasysnail.net>
> @@ -2417,7 +2088,7 @@ int tls_sw_read_sock(struct sock *sk, read_descriptor_t *desc,
> } else {
> struct tls_decrypt_arg darg;
>
> - err = tls_rx_rec_wait(sk, NULL, true, released, !!copied);
> + err = tls_rx_rec_wait(sk, true, released, !!copied);
nit: There's also a leftover sk_psock_get in that function. We can
clean it up later, let's get this series in.
--
Sabrina
^ permalink raw reply
* Re: [PATCH net-next v2 1/3] docs: net: tls-offload: document tls_dev_del, tls_dev_resync, and rekey
From: Sabrina Dubroca @ 2026-06-15 22:24 UTC (permalink / raw)
To: Jakub Kicinski
Cc: davem, netdev, edumazet, pabeni, andrew+netdev, horms, corbet,
linux-doc, john.fastabend, jiri, skhan
In-Reply-To: <20260613165846.2913092-2-kuba@kernel.org>
2026-06-13, 09:58:44 -0700, Jakub Kicinski wrote:
> Fill in some gaps in the TLS offload doc:
>
> - describe the tls_dev_del and tls_dev_resync callbacks
> - add a mention of rekeying being out of scope for now
>
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> ---
> v2:
> - add mentions of the callback in resync text
Thanks!
> - Stack -> The stack
> v1: https://lore.kernel.org/20260609201224.1191391-1-kuba@kernel.org
Reviewed-by: Sabrina Dubroca <sd@queasysnail.net>
--
Sabrina
^ permalink raw reply
* [PATCH net-next 0/2] appletalk: move the protocol out of tree
From: Jakub Kicinski @ 2026-06-15 22:29 UTC (permalink / raw)
To: davem
Cc: netdev, edumazet, pabeni, andrew+netdev, horms, geert, chleroy,
npiggin, mpe, maddy, linux-mips, linux-m68k, linuxppc-dev,
Jakub Kicinski
This tiny series moves appletalk out of tree, to:
https://github.com/linux-netdev/mod-orphan
Core maintainainers are unable to keep up with the rate of security
bug reports and fixes. Nobody seems to care about appletalk enough
to review the patches.
As Eric pointed out Mac OS dropped AppleTalk over a decade ago.
Jakub Kicinski (2):
appletalk: stop storing per-interface state in struct net_device
appletalk: move the protocol out of tree
MAINTAINERS | 5 +-
Documentation/admin-guide/sysctl/net.rst | 46 +-
.../networking/net_cachelines/net_device.rst | 1 -
net/Kconfig | 1 -
net/appletalk/Kconfig | 30 -
net/802/Makefile | 1 -
net/Makefile | 1 -
net/appletalk/Makefile | 10 -
include/linux/atalk.h | 186 --
include/linux/netdevice.h | 4 -
net/appletalk/aarp.c | 1041 ---------
net/appletalk/atalk_proc.c | 242 --
net/appletalk/ddp.c | 2017 -----------------
net/appletalk/sysctl_net_atalk.c | 58 -
arch/arm/configs/ixp4xx_defconfig | 1 -
arch/m68k/configs/amiga_defconfig | 1 -
arch/m68k/configs/apollo_defconfig | 1 -
arch/m68k/configs/atari_defconfig | 1 -
arch/m68k/configs/bvme6000_defconfig | 1 -
arch/m68k/configs/hp300_defconfig | 1 -
arch/m68k/configs/mac_defconfig | 1 -
arch/m68k/configs/multi_defconfig | 1 -
arch/m68k/configs/mvme147_defconfig | 1 -
arch/m68k/configs/mvme16x_defconfig | 1 -
arch/m68k/configs/q40_defconfig | 1 -
arch/m68k/configs/sun3_defconfig | 1 -
arch/m68k/configs/sun3x_defconfig | 1 -
arch/mips/configs/gpr_defconfig | 1 -
arch/mips/configs/malta_defconfig | 1 -
arch/mips/configs/malta_kvm_defconfig | 1 -
arch/mips/configs/malta_qemu_32r6_defconfig | 1 -
arch/mips/configs/maltaaprp_defconfig | 1 -
arch/mips/configs/maltasmvp_defconfig | 1 -
arch/mips/configs/maltasmvp_eva_defconfig | 1 -
arch/mips/configs/maltaup_defconfig | 1 -
arch/mips/configs/maltaup_xpa_defconfig | 1 -
arch/mips/configs/mtx1_defconfig | 1 -
arch/powerpc/configs/ppc6xx_defconfig | 1 -
arch/sh/configs/landisk_defconfig | 1 -
39 files changed, 3 insertions(+), 3665 deletions(-)
delete mode 100644 net/appletalk/Kconfig
delete mode 100644 net/appletalk/Makefile
delete mode 100644 include/linux/atalk.h
delete mode 100644 net/appletalk/aarp.c
delete mode 100644 net/appletalk/atalk_proc.c
delete mode 100644 net/appletalk/ddp.c
delete mode 100644 net/appletalk/sysctl_net_atalk.c
--
2.54.0
^ permalink raw reply
* [PATCH net-next 1/2] appletalk: stop storing per-interface state in struct net_device
From: Jakub Kicinski @ 2026-06-15 22:29 UTC (permalink / raw)
To: davem
Cc: netdev, edumazet, pabeni, andrew+netdev, horms, geert, chleroy,
npiggin, mpe, maddy, linux-mips, linux-m68k, linuxppc-dev,
Jakub Kicinski
In-Reply-To: <20260615222935.947233-1-kuba@kernel.org>
AppleTalk keeps its per-interface control block (struct atalk_iface)
directly in struct netdevice (dev->atalk_ptr). This is the only thing
tying the protocol into the core net_device layout and is the sole
blocker to moving AppleTalk out of tree.
Replace dev->atalk_ptr with a small ifindex-keyed hashtable internal
to ddp.c. The existing atalk_interfaces list stays the owner of the iface
objects; the hashtable is purely a fast dev->iface index and reuses
the same atalk_interfaces_lock.
AFAICT this patch does not make this code any more racy than it already
is, I'm sure Sashiko will point out some basically existing bugs.
AFAICT atalk_interfaces_lock is the innermost lock already.
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
.../networking/net_cachelines/net_device.rst | 1 -
include/linux/atalk.h | 8 +---
include/linux/netdevice.h | 4 --
net/appletalk/ddp.c | 48 +++++++++++++++++--
4 files changed, 45 insertions(+), 16 deletions(-)
diff --git a/Documentation/networking/net_cachelines/net_device.rst b/Documentation/networking/net_cachelines/net_device.rst
index eb2e6851c6f6..512f6d6fa3d8 100644
--- a/Documentation/networking/net_cachelines/net_device.rst
+++ b/Documentation/networking/net_cachelines/net_device.rst
@@ -90,7 +90,6 @@ struct inet6_dev* ip6_ptr read_mostly
struct vlan_info* vlan_info
struct dsa_port* dsa_ptr
struct tipc_bearer* tipc_ptr
-void* atalk_ptr
struct wireless_dev* ieee80211_ptr
struct wpan_dev* ieee802154_ptr
struct mpls_dev* mpls_ptr
diff --git a/include/linux/atalk.h b/include/linux/atalk.h
index a55bfc6567d0..ce7e6bfa9e2a 100644
--- a/include/linux/atalk.h
+++ b/include/linux/atalk.h
@@ -30,6 +30,7 @@ struct atalk_iface {
#define ATIF_PROBE_FAIL 2 /* Probe collided */
struct atalk_netrange nets;
struct atalk_iface *next;
+ struct hlist_node hash_node; /* keyed on dev->ifindex */
};
struct atalk_sock {
@@ -113,12 +114,7 @@ extern int aarp_proto_init(void);
/* Inter module exports */
/* Give a device find its atif control structure */
-#if IS_ENABLED(CONFIG_ATALK)
-static inline struct atalk_iface *atalk_find_dev(struct net_device *dev)
-{
- return dev->atalk_ptr;
-}
-#endif
+extern struct atalk_iface *atalk_find_dev(struct net_device *dev);
extern struct atalk_addr *atalk_find_dev_addr(struct net_device *dev);
extern struct net_device *atrtr_get_dev(struct atalk_addr *sa);
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 7f4f0837c09f..655564621f28 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1947,7 +1947,6 @@ enum netdev_reg_state {
* @vlan_info: VLAN info
* @dsa_ptr: dsa specific data
* @tipc_ptr: TIPC specific data
- * @atalk_ptr: AppleTalk link
* @ip_ptr: IPv4 specific data
* @ip6_ptr: IPv6 specific data
* @ieee80211_ptr: IEEE 802.11 specific data, assign before registering
@@ -2349,9 +2348,6 @@ struct net_device {
#if IS_ENABLED(CONFIG_TIPC)
struct tipc_bearer __rcu *tipc_ptr;
#endif
-#if IS_ENABLED(CONFIG_ATALK)
- void *atalk_ptr;
-#endif
#if IS_ENABLED(CONFIG_CFG80211)
struct wireless_dev *ieee80211_ptr;
#endif
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index 30a6dc06291c..afb86ce6e644 100644
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -52,6 +52,7 @@
#include <linux/termios.h> /* For TIOCOUTQ/INQ */
#include <linux/compat.h>
#include <linux/slab.h>
+#include <linux/hashtable.h>
#include <net/datalink.h>
#include <net/psnap.h>
#include <net/sock.h>
@@ -204,6 +205,33 @@ DEFINE_RWLOCK(atalk_routes_lock);
struct atalk_iface *atalk_interfaces;
DEFINE_RWLOCK(atalk_interfaces_lock);
+/* Fast dev->iface lookup, keyed on ifindex. Shares atalk_interfaces_lock with
+ * the atalk_interfaces list, which remains the owner of the iface objects.
+ */
+#define ATALK_IFACE_HASH_BITS 8
+static DEFINE_HASHTABLE(atalk_iface_hash, ATALK_IFACE_HASH_BITS);
+
+/* Find the iface for @dev. Caller must hold atalk_interfaces_lock. */
+static struct atalk_iface *__atalk_find_dev(struct net_device *dev)
+{
+ struct atalk_iface *iface;
+
+ hash_for_each_possible(atalk_iface_hash, iface, hash_node, dev->ifindex)
+ if (iface->dev == dev)
+ return iface;
+ return NULL;
+}
+
+struct atalk_iface *atalk_find_dev(struct net_device *dev)
+{
+ struct atalk_iface *iface;
+
+ read_lock_bh(&atalk_interfaces_lock);
+ iface = __atalk_find_dev(dev);
+ read_unlock_bh(&atalk_interfaces_lock);
+ return iface;
+}
+
/* For probing devices or in a routerless network */
struct atalk_route atrtr_default;
@@ -221,9 +249,9 @@ static void atif_drop_device(struct net_device *dev)
while ((tmp = *iface) != NULL) {
if (tmp->dev == dev) {
*iface = tmp->next;
+ hash_del(&tmp->hash_node);
dev_put(dev);
kfree(tmp);
- dev->atalk_ptr = NULL;
} else
iface = &tmp->next;
}
@@ -240,13 +268,13 @@ static struct atalk_iface *atif_add_device(struct net_device *dev,
dev_hold(dev);
iface->dev = dev;
- dev->atalk_ptr = iface;
iface->address = *sa;
iface->status = 0;
write_lock_bh(&atalk_interfaces_lock);
iface->next = atalk_interfaces;
atalk_interfaces = iface;
+ hash_add(atalk_iface_hash, &iface->hash_node, dev->ifindex);
write_unlock_bh(&atalk_interfaces_lock);
out:
return iface;
@@ -347,8 +375,15 @@ static int atif_proxy_probe_device(struct atalk_iface *atif,
struct atalk_addr *atalk_find_dev_addr(struct net_device *dev)
{
- struct atalk_iface *iface = dev->atalk_ptr;
- return iface ? &iface->address : NULL;
+ struct atalk_addr *addr = NULL;
+ struct atalk_iface *iface;
+
+ read_lock_bh(&atalk_interfaces_lock);
+ iface = __atalk_find_dev(dev);
+ if (iface)
+ addr = &iface->address;
+ read_unlock_bh(&atalk_interfaces_lock);
+ return addr;
}
static struct atalk_addr *atalk_find_primary(void)
@@ -388,8 +423,10 @@ static struct atalk_addr *atalk_find_primary(void)
*/
static struct atalk_iface *atalk_find_anynet(int node, struct net_device *dev)
{
- struct atalk_iface *iface = dev->atalk_ptr;
+ struct atalk_iface *iface;
+ read_lock_bh(&atalk_interfaces_lock);
+ iface = __atalk_find_dev(dev);
if (!iface || iface->status & ATIF_PROBE)
goto out_err;
@@ -398,6 +435,7 @@ static struct atalk_iface *atalk_find_anynet(int node, struct net_device *dev)
node != ATADDR_ANYNODE)
goto out_err;
out:
+ read_unlock_bh(&atalk_interfaces_lock);
return iface;
out_err:
iface = NULL;
--
2.54.0
^ permalink raw reply related
* [PATCH net-next 2/2] appletalk: move the protocol out of tree
From: Jakub Kicinski @ 2026-06-15 22:29 UTC (permalink / raw)
To: davem
Cc: netdev, edumazet, pabeni, andrew+netdev, horms, geert, chleroy,
npiggin, mpe, maddy, linux-mips, linux-m68k, linuxppc-dev,
Jakub Kicinski
In-Reply-To: <20260615222935.947233-1-kuba@kernel.org>
AppleTalk has been removed in MacOS X 10.6 (Snow Leopard), in 2009,
according to Wikipedia. We recently got a burst of AI generated
fixes to this protocol which nobody is reviewing.
Let AppleTalk follow AX.25 and hamradio out of the Linux tree.
We we will maintain the code at: github.com/linux-netdev/mod-orphan
for anyone interested in playing with it.
Retain the uAPI for now. No strong reason, simply because I suspect
keeping it will be less controversial.
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
MAINTAINERS | 5 +-
Documentation/admin-guide/sysctl/net.rst | 46 +-
net/Kconfig | 1 -
net/appletalk/Kconfig | 30 -
net/802/Makefile | 1 -
net/Makefile | 1 -
net/appletalk/Makefile | 10 -
include/linux/atalk.h | 182 --
net/appletalk/aarp.c | 1041 ----------
net/appletalk/atalk_proc.c | 242 ---
net/appletalk/ddp.c | 2055 -------------------
net/appletalk/sysctl_net_atalk.c | 58 -
arch/arm/configs/ixp4xx_defconfig | 1 -
arch/m68k/configs/amiga_defconfig | 1 -
arch/m68k/configs/apollo_defconfig | 1 -
arch/m68k/configs/atari_defconfig | 1 -
arch/m68k/configs/bvme6000_defconfig | 1 -
arch/m68k/configs/hp300_defconfig | 1 -
arch/m68k/configs/mac_defconfig | 1 -
arch/m68k/configs/multi_defconfig | 1 -
arch/m68k/configs/mvme147_defconfig | 1 -
arch/m68k/configs/mvme16x_defconfig | 1 -
arch/m68k/configs/q40_defconfig | 1 -
arch/m68k/configs/sun3_defconfig | 1 -
arch/m68k/configs/sun3x_defconfig | 1 -
arch/mips/configs/gpr_defconfig | 1 -
arch/mips/configs/malta_defconfig | 1 -
arch/mips/configs/malta_kvm_defconfig | 1 -
arch/mips/configs/malta_qemu_32r6_defconfig | 1 -
arch/mips/configs/maltaaprp_defconfig | 1 -
arch/mips/configs/maltasmvp_defconfig | 1 -
arch/mips/configs/maltasmvp_eva_defconfig | 1 -
arch/mips/configs/maltaup_defconfig | 1 -
arch/mips/configs/maltaup_xpa_defconfig | 1 -
arch/mips/configs/mtx1_defconfig | 1 -
arch/powerpc/configs/ppc6xx_defconfig | 1 -
arch/sh/configs/landisk_defconfig | 1 -
37 files changed, 3 insertions(+), 3694 deletions(-)
delete mode 100644 net/appletalk/Kconfig
delete mode 100644 net/appletalk/Makefile
delete mode 100644 include/linux/atalk.h
delete mode 100644 net/appletalk/aarp.c
delete mode 100644 net/appletalk/atalk_proc.c
delete mode 100644 net/appletalk/ddp.c
delete mode 100644 net/appletalk/sysctl_net_atalk.c
diff --git a/MAINTAINERS b/MAINTAINERS
index cc1dde0c9067..06df1171f4cf 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1968,10 +1968,9 @@ F: drivers/hwmon/applesmc.c
APPLETALK NETWORK LAYER
L: netdev@vger.kernel.org
-S: Odd fixes
-F: include/linux/atalk.h
+S: Obsolete
F: include/uapi/linux/atalk.h
-F: net/appletalk/
+F: include/uapi/linux/if_ltalk.h
APPLIED MICRO (APM) X-GENE DEVICE TREE SUPPORT
M: Khuong Dinh <khuong@os.amperecomputing.com>
diff --git a/Documentation/admin-guide/sysctl/net.rst b/Documentation/admin-guide/sysctl/net.rst
index 0724a793798f..37c5a0624c5d 100644
--- a/Documentation/admin-guide/sysctl/net.rst
+++ b/Documentation/admin-guide/sysctl/net.rst
@@ -475,51 +475,7 @@ Please see: Documentation/networking/ip-sysctl.rst and
Documentation/admin-guide/sysctl/net.rst for descriptions of these entries.
-4. Appletalk
-------------
-
-The /proc/sys/net/appletalk directory holds the Appletalk configuration data
-when Appletalk is loaded. The configurable parameters are:
-
-aarp-expiry-time
-----------------
-
-The amount of time we keep an ARP entry before expiring it. Used to age out
-old hosts.
-
-aarp-resolve-time
------------------
-
-The amount of time we will spend trying to resolve an Appletalk address.
-
-aarp-retransmit-limit
----------------------
-
-The number of times we will retransmit a query before giving up.
-
-aarp-tick-time
---------------
-
-Controls the rate at which expires are checked.
-
-The directory /proc/net/appletalk holds the list of active Appletalk sockets
-on a machine.
-
-The fields indicate the DDP type, the local address (in network:node format)
-the remote address, the size of the transmit pending queue, the size of the
-received queue (bytes waiting for applications to read) the state and the uid
-owning the socket.
-
-/proc/net/atalk_iface lists all the interfaces configured for appletalk.It
-shows the name of the interface, its Appletalk address, the network range on
-that address (or network number for phase 1 networks), and the status of the
-interface.
-
-/proc/net/atalk_route lists each known network route. It lists the target
-(network) that the route leads to, the router (may be directly connected), the
-route flags, and the device the route is using.
-
-5. TIPC
+4. TIPC
-------
tipc_rmem
diff --git a/net/Kconfig b/net/Kconfig
index bdea8aef7983..e38477393551 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -261,7 +261,6 @@ source "net/bridge/Kconfig"
source "net/dsa/Kconfig"
source "net/8021q/Kconfig"
source "net/llc/Kconfig"
-source "net/appletalk/Kconfig"
source "net/x25/Kconfig"
source "net/lapb/Kconfig"
source "net/phonet/Kconfig"
diff --git a/net/appletalk/Kconfig b/net/appletalk/Kconfig
deleted file mode 100644
index 041141abf925..000000000000
--- a/net/appletalk/Kconfig
+++ /dev/null
@@ -1,30 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Appletalk configuration
-#
-config ATALK
- tristate "Appletalk protocol support"
- select LLC
- help
- AppleTalk is the protocol that Apple computers can use to communicate
- on a network. If your Linux box is connected to such a network and you
- wish to connect to it, say Y. You will need to use the netatalk package
- so that your Linux box can act as a print and file server for Macs as
- well as access AppleTalk printers. Check out
- <http://www.zettabyte.net/netatalk/> on the WWW for details.
- EtherTalk is the name used for AppleTalk over Ethernet and the
- cheaper and slower LocalTalk is AppleTalk over a proprietary Apple
- network using serial links. EtherTalk and LocalTalk are fully
- supported by Linux.
-
- General information about how to connect Linux, Windows machines and
- Macs is on the WWW at <http://www.eats.com/linux_mac_win.html>. The
- NET3-4-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>, contains valuable
- information as well.
-
- To compile this driver as a module, choose M here: the module will be
- called appletalk. You almost certainly want to compile it as a
- module so you can restart your AppleTalk stack without rebooting
- your machine. I hear that the GNU boycott of Apple is over, so
- even politically correct people are allowed to say Y here.
diff --git a/net/802/Makefile b/net/802/Makefile
index 9503ef6b2e06..54784f3cae5a 100644
--- a/net/802/Makefile
+++ b/net/802/Makefile
@@ -6,7 +6,6 @@
obj-$(CONFIG_LLC) += psnap.o
obj-$(CONFIG_NET_FC) += fc.o
obj-$(CONFIG_FDDI) += fddi.o
-obj-$(CONFIG_ATALK) += psnap.o
obj-$(CONFIG_STP) += stp.o
obj-$(CONFIG_GARP) += garp.o
obj-$(CONFIG_MRP) += mrp.o
diff --git a/net/Makefile b/net/Makefile
index d2175fce0406..5b2dd7f07a85 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -25,7 +25,6 @@ obj-$(CONFIG_NET_KEY) += key/
obj-$(CONFIG_BRIDGE) += bridge/
obj-$(CONFIG_NET_DEVLINK) += devlink/
obj-y += dsa/
-obj-$(CONFIG_ATALK) += appletalk/
obj-$(CONFIG_X25) += x25/
obj-$(CONFIG_LAPB) += lapb/
obj-$(CONFIG_CAN) += can/
diff --git a/net/appletalk/Makefile b/net/appletalk/Makefile
deleted file mode 100644
index 152312a15180..000000000000
--- a/net/appletalk/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Makefile for the Linux AppleTalk layer.
-#
-
-obj-$(CONFIG_ATALK) += appletalk.o
-
-appletalk-y := aarp.o ddp.o
-appletalk-$(CONFIG_PROC_FS) += atalk_proc.o
-appletalk-$(CONFIG_SYSCTL) += sysctl_net_atalk.o
diff --git a/include/linux/atalk.h b/include/linux/atalk.h
deleted file mode 100644
index ce7e6bfa9e2a..000000000000
--- a/include/linux/atalk.h
+++ /dev/null
@@ -1,182 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __LINUX_ATALK_H__
-#define __LINUX_ATALK_H__
-
-
-#include <net/sock.h>
-#include <uapi/linux/atalk.h>
-
-struct atalk_route {
- struct net_device *dev;
- struct atalk_addr target;
- struct atalk_addr gateway;
- int flags;
- struct atalk_route *next;
-};
-
-/**
- * struct atalk_iface - AppleTalk Interface
- * @dev - Network device associated with this interface
- * @address - Our address
- * @status - What are we doing?
- * @nets - Associated direct netrange
- * @next - next element in the list of interfaces
- */
-struct atalk_iface {
- struct net_device *dev;
- struct atalk_addr address;
- int status;
-#define ATIF_PROBE 1 /* Probing for an address */
-#define ATIF_PROBE_FAIL 2 /* Probe collided */
- struct atalk_netrange nets;
- struct atalk_iface *next;
- struct hlist_node hash_node; /* keyed on dev->ifindex */
-};
-
-struct atalk_sock {
- /* struct sock has to be the first member of atalk_sock */
- struct sock sk;
- __be16 dest_net;
- __be16 src_net;
- unsigned char dest_node;
- unsigned char src_node;
- unsigned char dest_port;
- unsigned char src_port;
-};
-
-static inline struct atalk_sock *at_sk(struct sock *sk)
-{
- return (struct atalk_sock *)sk;
-}
-
-struct ddpehdr {
- __be16 deh_len_hops; /* lower 10 bits are length, next 4 - hops */
- __be16 deh_sum;
- __be16 deh_dnet;
- __be16 deh_snet;
- __u8 deh_dnode;
- __u8 deh_snode;
- __u8 deh_dport;
- __u8 deh_sport;
- /* And netatalk apps expect to stick the type in themselves */
-};
-
-static __inline__ struct ddpehdr *ddp_hdr(struct sk_buff *skb)
-{
- return (struct ddpehdr *)skb_transport_header(skb);
-}
-
-/* AppleTalk AARP headers */
-struct elapaarp {
- __be16 hw_type;
-#define AARP_HW_TYPE_ETHERNET 1
-#define AARP_HW_TYPE_TOKENRING 2
- __be16 pa_type;
- __u8 hw_len;
- __u8 pa_len;
-#define AARP_PA_ALEN 4
- __be16 function;
-#define AARP_REQUEST 1
-#define AARP_REPLY 2
-#define AARP_PROBE 3
- __u8 hw_src[ETH_ALEN];
- __u8 pa_src_zero;
- __be16 pa_src_net;
- __u8 pa_src_node;
- __u8 hw_dst[ETH_ALEN];
- __u8 pa_dst_zero;
- __be16 pa_dst_net;
- __u8 pa_dst_node;
-} __attribute__ ((packed));
-
-static __inline__ struct elapaarp *aarp_hdr(struct sk_buff *skb)
-{
- return (struct elapaarp *)skb_transport_header(skb);
-}
-
-/* Not specified - how long till we drop a resolved entry */
-#define AARP_EXPIRY_TIME (5 * 60 * HZ)
-/* Size of hash table */
-#define AARP_HASH_SIZE 16
-/* Fast retransmission timer when resolving */
-#define AARP_TICK_TIME (HZ / 5)
-/* Send 10 requests then give up (2 seconds) */
-#define AARP_RETRANSMIT_LIMIT 10
-/*
- * Some value bigger than total retransmit time + a bit for last reply to
- * appear and to stop continual requests
- */
-#define AARP_RESOLVE_TIME (10 * HZ)
-
-extern struct datalink_proto *ddp_dl, *aarp_dl;
-extern int aarp_proto_init(void);
-
-/* Inter module exports */
-
-/* Give a device find its atif control structure */
-extern struct atalk_iface *atalk_find_dev(struct net_device *dev);
-
-extern struct atalk_addr *atalk_find_dev_addr(struct net_device *dev);
-extern struct net_device *atrtr_get_dev(struct atalk_addr *sa);
-extern int aarp_send_ddp(struct net_device *dev,
- struct sk_buff *skb,
- struct atalk_addr *sa, void *hwaddr);
-extern void aarp_device_down(struct net_device *dev);
-extern void aarp_probe_network(struct atalk_iface *atif);
-extern int aarp_proxy_probe_network(struct atalk_iface *atif,
- struct atalk_addr *sa);
-extern void aarp_proxy_remove(struct net_device *dev,
- struct atalk_addr *sa);
-
-extern void aarp_cleanup_module(void);
-
-extern struct hlist_head atalk_sockets;
-extern rwlock_t atalk_sockets_lock;
-
-extern struct atalk_route *atalk_routes;
-extern rwlock_t atalk_routes_lock;
-
-extern struct atalk_iface *atalk_interfaces;
-extern rwlock_t atalk_interfaces_lock;
-
-extern struct atalk_route atrtr_default;
-
-struct aarp_iter_state {
- int bucket;
- struct aarp_entry **table;
-};
-
-extern const struct seq_operations aarp_seq_ops;
-
-extern int sysctl_aarp_expiry_time;
-extern int sysctl_aarp_tick_time;
-extern int sysctl_aarp_retransmit_limit;
-extern int sysctl_aarp_resolve_time;
-
-#ifdef CONFIG_SYSCTL
-extern int atalk_register_sysctl(void);
-extern void atalk_unregister_sysctl(void);
-#else
-static inline int atalk_register_sysctl(void)
-{
- return 0;
-}
-static inline void atalk_unregister_sysctl(void)
-{
-}
-#endif
-
-#ifdef CONFIG_PROC_FS
-extern int atalk_proc_init(void);
-extern void atalk_proc_exit(void);
-#else
-static inline int atalk_proc_init(void)
-{
- return 0;
-}
-static inline void atalk_proc_exit(void)
-{
-}
-#endif /* CONFIG_PROC_FS */
-
-#endif /* __LINUX_ATALK_H__ */
diff --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c
deleted file mode 100644
index 078fb7a6efa5..000000000000
--- a/net/appletalk/aarp.c
+++ /dev/null
@@ -1,1041 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * AARP: An implementation of the AppleTalk AARP protocol for
- * Ethernet 'ELAP'.
- *
- * Alan Cox <Alan.Cox@linux.org>
- *
- * This doesn't fit cleanly with the IP arp. Potentially we can use
- * the generic neighbour discovery code to clean this up.
- *
- * FIXME:
- * We ought to handle the retransmits with a single list and a
- * separate fast timer for when it is needed.
- * Use neighbour discovery code.
- * Token Ring Support.
- *
- * References:
- * Inside AppleTalk (2nd Ed).
- * Fixes:
- * Jaume Grau - flush caches on AARP_PROBE
- * Rob Newberry - Added proxy AARP and AARP proc fs,
- * moved probing from DDP module.
- * Arnaldo C. Melo - don't mangle rx packets
- */
-
-#include <linux/if_arp.h>
-#include <linux/slab.h>
-#include <net/sock.h>
-#include <net/datalink.h>
-#include <net/psnap.h>
-#include <linux/atalk.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/export.h>
-#include <linux/etherdevice.h>
-#include <linux/refcount.h>
-
-int sysctl_aarp_expiry_time = AARP_EXPIRY_TIME;
-int sysctl_aarp_tick_time = AARP_TICK_TIME;
-int sysctl_aarp_retransmit_limit = AARP_RETRANSMIT_LIMIT;
-int sysctl_aarp_resolve_time = AARP_RESOLVE_TIME;
-
-/* Lists of aarp entries */
-/**
- * struct aarp_entry - AARP entry
- * @refcnt: Reference count
- * @last_sent: Last time we xmitted the aarp request
- * @packet_queue: Queue of frames wait for resolution
- * @status: Used for proxy AARP
- * @expires_at: Entry expiry time
- * @target_addr: DDP Address
- * @dev: Device to use
- * @hwaddr: Physical i/f address of target/router
- * @xmit_count: When this hits 10 we give up
- * @next: Next entry in chain
- */
-struct aarp_entry {
- refcount_t refcnt;
- /* These first two are only used for unresolved entries */
- unsigned long last_sent;
- struct sk_buff_head packet_queue;
- int status;
- unsigned long expires_at;
- struct atalk_addr target_addr;
- struct net_device *dev;
- char hwaddr[ETH_ALEN];
- unsigned short xmit_count;
- struct aarp_entry *next;
-};
-
-/* Hashed list of resolved, unresolved and proxy entries */
-static struct aarp_entry *resolved[AARP_HASH_SIZE];
-static struct aarp_entry *unresolved[AARP_HASH_SIZE];
-static struct aarp_entry *proxies[AARP_HASH_SIZE];
-static int unresolved_count;
-
-/* One lock protects it all. */
-static DEFINE_RWLOCK(aarp_lock);
-
-/* Used to walk the list and purge/kick entries. */
-static struct timer_list aarp_timer;
-
-static inline void aarp_entry_get(struct aarp_entry *a)
-{
- refcount_inc(&a->refcnt);
-}
-
-static inline void aarp_entry_put(struct aarp_entry *a)
-{
- if (refcount_dec_and_test(&a->refcnt))
- kfree(a);
-}
-
-/*
- * Delete an aarp queue
- *
- * Must run under aarp_lock.
- */
-static void __aarp_expire(struct aarp_entry *a)
-{
- skb_queue_purge(&a->packet_queue);
- aarp_entry_put(a);
-}
-
-/*
- * Send an aarp queue entry request
- *
- * Must run under aarp_lock.
- */
-static void __aarp_send_query(struct aarp_entry *a)
-{
- static unsigned char aarp_eth_multicast[ETH_ALEN] =
- { 0x09, 0x00, 0x07, 0xFF, 0xFF, 0xFF };
- struct net_device *dev = a->dev;
- struct elapaarp *eah;
- int len = dev->hard_header_len + sizeof(*eah) + aarp_dl->header_length;
- struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC);
- struct atalk_addr *sat = atalk_find_dev_addr(dev);
-
- if (!skb)
- return;
-
- if (!sat) {
- kfree_skb(skb);
- return;
- }
-
- /* Set up the buffer */
- skb_reserve(skb, dev->hard_header_len + aarp_dl->header_length);
- skb_reset_network_header(skb);
- skb_reset_transport_header(skb);
- skb_put(skb, sizeof(*eah));
- skb->protocol = htons(ETH_P_ATALK);
- skb->dev = dev;
- eah = aarp_hdr(skb);
-
- /* Set up the ARP */
- eah->hw_type = htons(AARP_HW_TYPE_ETHERNET);
- eah->pa_type = htons(ETH_P_ATALK);
- eah->hw_len = ETH_ALEN;
- eah->pa_len = AARP_PA_ALEN;
- eah->function = htons(AARP_REQUEST);
-
- ether_addr_copy(eah->hw_src, dev->dev_addr);
-
- eah->pa_src_zero = 0;
- eah->pa_src_net = sat->s_net;
- eah->pa_src_node = sat->s_node;
-
- eth_zero_addr(eah->hw_dst);
-
- eah->pa_dst_zero = 0;
- eah->pa_dst_net = a->target_addr.s_net;
- eah->pa_dst_node = a->target_addr.s_node;
-
- /* Send it */
- aarp_dl->request(aarp_dl, skb, aarp_eth_multicast);
- /* Update the sending count */
- a->xmit_count++;
- a->last_sent = jiffies;
-}
-
-/* This runs under aarp_lock and in softint context, so only atomic memory
- * allocations can be used. */
-static void aarp_send_reply(struct net_device *dev, struct atalk_addr *us,
- struct atalk_addr *them, unsigned char *sha)
-{
- struct elapaarp *eah;
- int len = dev->hard_header_len + sizeof(*eah) + aarp_dl->header_length;
- struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC);
-
- if (!skb)
- return;
-
- /* Set up the buffer */
- skb_reserve(skb, dev->hard_header_len + aarp_dl->header_length);
- skb_reset_network_header(skb);
- skb_reset_transport_header(skb);
- skb_put(skb, sizeof(*eah));
- skb->protocol = htons(ETH_P_ATALK);
- skb->dev = dev;
- eah = aarp_hdr(skb);
-
- /* Set up the ARP */
- eah->hw_type = htons(AARP_HW_TYPE_ETHERNET);
- eah->pa_type = htons(ETH_P_ATALK);
- eah->hw_len = ETH_ALEN;
- eah->pa_len = AARP_PA_ALEN;
- eah->function = htons(AARP_REPLY);
-
- ether_addr_copy(eah->hw_src, dev->dev_addr);
-
- eah->pa_src_zero = 0;
- eah->pa_src_net = us->s_net;
- eah->pa_src_node = us->s_node;
-
- if (!sha)
- eth_zero_addr(eah->hw_dst);
- else
- ether_addr_copy(eah->hw_dst, sha);
-
- eah->pa_dst_zero = 0;
- eah->pa_dst_net = them->s_net;
- eah->pa_dst_node = them->s_node;
-
- /* Send it */
- aarp_dl->request(aarp_dl, skb, sha);
-}
-
-/*
- * Send probe frames. Called from aarp_probe_network and
- * aarp_proxy_probe_network.
- */
-
-static void aarp_send_probe(struct net_device *dev, struct atalk_addr *us)
-{
- struct elapaarp *eah;
- int len = dev->hard_header_len + sizeof(*eah) + aarp_dl->header_length;
- struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC);
- static unsigned char aarp_eth_multicast[ETH_ALEN] =
- { 0x09, 0x00, 0x07, 0xFF, 0xFF, 0xFF };
-
- if (!skb)
- return;
-
- /* Set up the buffer */
- skb_reserve(skb, dev->hard_header_len + aarp_dl->header_length);
- skb_reset_network_header(skb);
- skb_reset_transport_header(skb);
- skb_put(skb, sizeof(*eah));
- skb->protocol = htons(ETH_P_ATALK);
- skb->dev = dev;
- eah = aarp_hdr(skb);
-
- /* Set up the ARP */
- eah->hw_type = htons(AARP_HW_TYPE_ETHERNET);
- eah->pa_type = htons(ETH_P_ATALK);
- eah->hw_len = ETH_ALEN;
- eah->pa_len = AARP_PA_ALEN;
- eah->function = htons(AARP_PROBE);
-
- ether_addr_copy(eah->hw_src, dev->dev_addr);
-
- eah->pa_src_zero = 0;
- eah->pa_src_net = us->s_net;
- eah->pa_src_node = us->s_node;
-
- eth_zero_addr(eah->hw_dst);
-
- eah->pa_dst_zero = 0;
- eah->pa_dst_net = us->s_net;
- eah->pa_dst_node = us->s_node;
-
- /* Send it */
- aarp_dl->request(aarp_dl, skb, aarp_eth_multicast);
-}
-
-/*
- * Handle an aarp timer expire
- *
- * Must run under the aarp_lock.
- */
-
-static void __aarp_expire_timer(struct aarp_entry **n)
-{
- struct aarp_entry *t;
-
- while (*n)
- /* Expired ? */
- if (time_after(jiffies, (*n)->expires_at)) {
- t = *n;
- *n = (*n)->next;
- __aarp_expire(t);
- } else
- n = &((*n)->next);
-}
-
-/*
- * Kick all pending requests 5 times a second.
- *
- * Must run under the aarp_lock.
- */
-static void __aarp_kick(struct aarp_entry **n)
-{
- struct aarp_entry *t;
-
- while (*n)
- /* Expired: if this will be the 11th tx, we delete instead. */
- if ((*n)->xmit_count >= sysctl_aarp_retransmit_limit) {
- t = *n;
- *n = (*n)->next;
- __aarp_expire(t);
- } else {
- __aarp_send_query(*n);
- n = &((*n)->next);
- }
-}
-
-/*
- * A device has gone down. Take all entries referring to the device
- * and remove them.
- *
- * Must run under the aarp_lock.
- */
-static void __aarp_expire_device(struct aarp_entry **n, struct net_device *dev)
-{
- struct aarp_entry *t;
-
- while (*n)
- if ((*n)->dev == dev) {
- t = *n;
- *n = (*n)->next;
- __aarp_expire(t);
- } else
- n = &((*n)->next);
-}
-
-/* Handle the timer event */
-static void aarp_expire_timeout(struct timer_list *unused)
-{
- int ct;
-
- write_lock_bh(&aarp_lock);
-
- for (ct = 0; ct < AARP_HASH_SIZE; ct++) {
- __aarp_expire_timer(&resolved[ct]);
- __aarp_kick(&unresolved[ct]);
- __aarp_expire_timer(&unresolved[ct]);
- __aarp_expire_timer(&proxies[ct]);
- }
-
- write_unlock_bh(&aarp_lock);
- mod_timer(&aarp_timer, jiffies +
- (unresolved_count ? sysctl_aarp_tick_time :
- sysctl_aarp_expiry_time));
-}
-
-/* Network device notifier chain handler. */
-static int aarp_device_event(struct notifier_block *this, unsigned long event,
- void *ptr)
-{
- struct net_device *dev = netdev_notifier_info_to_dev(ptr);
- int ct;
-
- if (!net_eq(dev_net(dev), &init_net))
- return NOTIFY_DONE;
-
- if (event == NETDEV_DOWN) {
- write_lock_bh(&aarp_lock);
-
- for (ct = 0; ct < AARP_HASH_SIZE; ct++) {
- __aarp_expire_device(&resolved[ct], dev);
- __aarp_expire_device(&unresolved[ct], dev);
- __aarp_expire_device(&proxies[ct], dev);
- }
-
- write_unlock_bh(&aarp_lock);
- }
- return NOTIFY_DONE;
-}
-
-/* Expire all entries in a hash chain */
-static void __aarp_expire_all(struct aarp_entry **n)
-{
- struct aarp_entry *t;
-
- while (*n) {
- t = *n;
- *n = (*n)->next;
- __aarp_expire(t);
- }
-}
-
-/* Cleanup all hash chains -- module unloading */
-static void aarp_purge(void)
-{
- int ct;
-
- write_lock_bh(&aarp_lock);
- for (ct = 0; ct < AARP_HASH_SIZE; ct++) {
- __aarp_expire_all(&resolved[ct]);
- __aarp_expire_all(&unresolved[ct]);
- __aarp_expire_all(&proxies[ct]);
- }
- write_unlock_bh(&aarp_lock);
-}
-
-/*
- * Create a new aarp entry. This must use GFP_ATOMIC because it
- * runs while holding spinlocks.
- */
-static struct aarp_entry *aarp_alloc(void)
-{
- struct aarp_entry *a = kzalloc_obj(*a, GFP_ATOMIC);
- if (!a)
- return NULL;
-
- refcount_set(&a->refcnt, 1);
- skb_queue_head_init(&a->packet_queue);
- return a;
-}
-
-/*
- * Find an entry. We might return an expired but not yet purged entry. We
- * don't care as it will do no harm.
- *
- * This must run under the aarp_lock.
- */
-static struct aarp_entry *__aarp_find_entry(struct aarp_entry *list,
- struct net_device *dev,
- struct atalk_addr *sat)
-{
- while (list) {
- if (list->target_addr.s_net == sat->s_net &&
- list->target_addr.s_node == sat->s_node &&
- list->dev == dev)
- break;
- list = list->next;
- }
-
- return list;
-}
-
-/* Called from the DDP code, and thus must be exported. */
-void aarp_proxy_remove(struct net_device *dev, struct atalk_addr *sa)
-{
- int hash = sa->s_node % (AARP_HASH_SIZE - 1);
- struct aarp_entry *a;
-
- write_lock_bh(&aarp_lock);
-
- a = __aarp_find_entry(proxies[hash], dev, sa);
- if (a)
- a->expires_at = jiffies - 1;
-
- write_unlock_bh(&aarp_lock);
-}
-
-/* This must run under aarp_lock. */
-static struct atalk_addr *__aarp_proxy_find(struct net_device *dev,
- struct atalk_addr *sa)
-{
- int hash = sa->s_node % (AARP_HASH_SIZE - 1);
- struct aarp_entry *a = __aarp_find_entry(proxies[hash], dev, sa);
-
- return a ? sa : NULL;
-}
-
-void aarp_probe_network(struct atalk_iface *atif)
-{
- unsigned int count;
-
- for (count = 0; count < AARP_RETRANSMIT_LIMIT; count++) {
- aarp_send_probe(atif->dev, &atif->address);
-
- /* Defer 1/10th */
- msleep(100);
-
- if (atif->status & ATIF_PROBE_FAIL)
- break;
- }
-}
-
-int aarp_proxy_probe_network(struct atalk_iface *atif, struct atalk_addr *sa)
-{
- int hash, retval = -EPROTONOSUPPORT;
- struct aarp_entry *entry;
- unsigned int count;
-
- /*
- * we don't currently support LocalTalk or PPP for proxy AARP;
- * if someone wants to try and add it, have fun
- */
- if (atif->dev->type == ARPHRD_LOCALTLK ||
- atif->dev->type == ARPHRD_PPP)
- goto out;
-
- /*
- * create a new AARP entry with the flags set to be published --
- * we need this one to hang around even if it's in use
- */
- entry = aarp_alloc();
- retval = -ENOMEM;
- if (!entry)
- goto out;
-
- entry->expires_at = -1;
- entry->status = ATIF_PROBE;
- entry->target_addr.s_node = sa->s_node;
- entry->target_addr.s_net = sa->s_net;
- entry->dev = atif->dev;
-
- write_lock_bh(&aarp_lock);
- aarp_entry_get(entry);
-
- hash = sa->s_node % (AARP_HASH_SIZE - 1);
- entry->next = proxies[hash];
- proxies[hash] = entry;
-
- for (count = 0; count < AARP_RETRANSMIT_LIMIT; count++) {
- aarp_send_probe(atif->dev, sa);
-
- /* Defer 1/10th */
- write_unlock_bh(&aarp_lock);
- msleep(100);
- write_lock_bh(&aarp_lock);
-
- if (entry->status & ATIF_PROBE_FAIL)
- break;
- }
-
- if (entry->status & ATIF_PROBE_FAIL) {
- entry->expires_at = jiffies - 1; /* free the entry */
- retval = -EADDRINUSE; /* return network full */
- } else { /* clear the probing flag */
- entry->status &= ~ATIF_PROBE;
- retval = 1;
- }
-
- aarp_entry_put(entry);
- write_unlock_bh(&aarp_lock);
-out:
- return retval;
-}
-
-/* Send a DDP frame */
-int aarp_send_ddp(struct net_device *dev, struct sk_buff *skb,
- struct atalk_addr *sa, void *hwaddr)
-{
- static char ddp_eth_multicast[ETH_ALEN] =
- { 0x09, 0x00, 0x07, 0xFF, 0xFF, 0xFF };
- int hash;
- struct aarp_entry *a;
-
- skb_reset_network_header(skb);
-
- /* Check for LocalTalk first */
- if (dev->type == ARPHRD_LOCALTLK) {
- struct atalk_addr *at = atalk_find_dev_addr(dev);
- struct ddpehdr *ddp = (struct ddpehdr *)skb->data;
- int ft = 2;
-
- if (!at) {
- kfree_skb(skb);
- return NET_XMIT_DROP;
- }
-
- /*
- * Compressible ?
- *
- * IFF: src_net == dest_net == device_net
- * (zero matches anything)
- */
-
- if ((!ddp->deh_snet || at->s_net == ddp->deh_snet) &&
- (!ddp->deh_dnet || at->s_net == ddp->deh_dnet)) {
- skb_pull(skb, sizeof(*ddp) - 4);
-
- /*
- * The upper two remaining bytes are the port
- * numbers we just happen to need. Now put the
- * length in the lower two.
- */
- *((__be16 *)skb->data) = htons(skb->len);
- ft = 1;
- }
- /*
- * Nice and easy. No AARP type protocols occur here so we can
- * just shovel it out with a 3 byte LLAP header
- */
-
- skb_push(skb, 3);
- skb->data[0] = sa->s_node;
- skb->data[1] = at->s_node;
- skb->data[2] = ft;
- skb->dev = dev;
- goto sendit;
- }
-
- /* On a PPP link we neither compress nor aarp. */
- if (dev->type == ARPHRD_PPP) {
- skb->protocol = htons(ETH_P_PPPTALK);
- skb->dev = dev;
- goto sendit;
- }
-
- /* Non ELAP we cannot do. */
- if (dev->type != ARPHRD_ETHER)
- goto free_it;
-
- skb->dev = dev;
- skb->protocol = htons(ETH_P_ATALK);
- hash = sa->s_node % (AARP_HASH_SIZE - 1);
-
- /* Do we have a resolved entry? */
- if (sa->s_node == ATADDR_BCAST) {
- /* Send it */
- ddp_dl->request(ddp_dl, skb, ddp_eth_multicast);
- goto sent;
- }
-
- write_lock_bh(&aarp_lock);
- a = __aarp_find_entry(resolved[hash], dev, sa);
-
- if (a) { /* Return 1 and fill in the address */
- a->expires_at = jiffies + (sysctl_aarp_expiry_time * 10);
- ddp_dl->request(ddp_dl, skb, a->hwaddr);
- write_unlock_bh(&aarp_lock);
- goto sent;
- }
-
- /* Do we have an unresolved entry: This is the less common path */
- a = __aarp_find_entry(unresolved[hash], dev, sa);
- if (a) { /* Queue onto the unresolved queue */
- skb_queue_tail(&a->packet_queue, skb);
- goto out_unlock;
- }
-
- /* Allocate a new entry */
- a = aarp_alloc();
- if (!a) {
- /* Whoops slipped... good job it's an unreliable protocol 8) */
- write_unlock_bh(&aarp_lock);
- goto free_it;
- }
-
- /* Set up the queue */
- skb_queue_tail(&a->packet_queue, skb);
- a->expires_at = jiffies + sysctl_aarp_resolve_time;
- a->dev = dev;
- a->next = unresolved[hash];
- a->target_addr = *sa;
- a->xmit_count = 0;
- unresolved[hash] = a;
- unresolved_count++;
-
- /* Send an initial request for the address */
- __aarp_send_query(a);
-
- /*
- * Switch to fast timer if needed (That is if this is the first
- * unresolved entry to get added)
- */
-
- if (unresolved_count == 1)
- mod_timer(&aarp_timer, jiffies + sysctl_aarp_tick_time);
-
- /* Now finally, it is safe to drop the lock. */
-out_unlock:
- write_unlock_bh(&aarp_lock);
-
- /* Tell the ddp layer we have taken over for this frame. */
- goto sent;
-
-sendit:
- if (skb->sk)
- skb->priority = READ_ONCE(skb->sk->sk_priority);
- if (dev_queue_xmit(skb))
- goto drop;
-sent:
- return NET_XMIT_SUCCESS;
-free_it:
- kfree_skb(skb);
-drop:
- return NET_XMIT_DROP;
-}
-EXPORT_SYMBOL(aarp_send_ddp);
-
-/*
- * An entry in the aarp unresolved queue has become resolved. Send
- * all the frames queued under it.
- *
- * Must run under aarp_lock.
- */
-static void __aarp_resolved(struct aarp_entry **list, struct aarp_entry *a,
- int hash)
-{
- struct sk_buff *skb;
-
- while (*list)
- if (*list == a) {
- unresolved_count--;
- *list = a->next;
-
- /* Move into the resolved list */
- a->next = resolved[hash];
- resolved[hash] = a;
-
- /* Kick frames off */
- while ((skb = skb_dequeue(&a->packet_queue)) != NULL) {
- a->expires_at = jiffies +
- sysctl_aarp_expiry_time * 10;
- ddp_dl->request(ddp_dl, skb, a->hwaddr);
- }
- } else
- list = &((*list)->next);
-}
-
-/*
- * This is called by the SNAP driver whenever we see an AARP SNAP
- * frame. We currently only support Ethernet.
- */
-static int aarp_rcv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *pt, struct net_device *orig_dev)
-{
- struct elapaarp *ea = aarp_hdr(skb);
- int hash, ret = 0;
- __u16 function;
- struct aarp_entry *a;
- struct atalk_addr sa, *ma, da;
- struct atalk_iface *ifa;
-
- if (!net_eq(dev_net(dev), &init_net))
- goto out0;
-
- /* We only do Ethernet SNAP AARP. */
- if (dev->type != ARPHRD_ETHER)
- goto out0;
-
- /* Frame size ok? */
- if (!skb_pull(skb, sizeof(*ea)))
- goto out0;
-
- function = ntohs(ea->function);
-
- /* Sanity check fields. */
- if (function < AARP_REQUEST || function > AARP_PROBE ||
- ea->hw_len != ETH_ALEN || ea->pa_len != AARP_PA_ALEN ||
- ea->pa_src_zero || ea->pa_dst_zero)
- goto out0;
-
- /* Looks good. */
- hash = ea->pa_src_node % (AARP_HASH_SIZE - 1);
-
- /* Build an address. */
- sa.s_node = ea->pa_src_node;
- sa.s_net = ea->pa_src_net;
-
- /* Process the packet. Check for replies of me. */
- ifa = atalk_find_dev(dev);
- if (!ifa)
- goto out1;
-
- if (ifa->status & ATIF_PROBE &&
- ifa->address.s_node == ea->pa_dst_node &&
- ifa->address.s_net == ea->pa_dst_net) {
- ifa->status |= ATIF_PROBE_FAIL; /* Fail the probe (in use) */
- goto out1;
- }
-
- /* Check for replies of proxy AARP entries */
- da.s_node = ea->pa_dst_node;
- da.s_net = ea->pa_dst_net;
-
- write_lock_bh(&aarp_lock);
- a = __aarp_find_entry(proxies[hash], dev, &da);
-
- if (a && a->status & ATIF_PROBE) {
- a->status |= ATIF_PROBE_FAIL;
- /*
- * we do not respond to probe or request packets of
- * this address while we are probing this address
- */
- goto unlock;
- }
-
- switch (function) {
- case AARP_REPLY:
- if (!unresolved_count) /* Speed up */
- break;
-
- /* Find the entry. */
- a = __aarp_find_entry(unresolved[hash], dev, &sa);
- if (!a || dev != a->dev)
- break;
-
- /* We can fill one in - this is good. */
- ether_addr_copy(a->hwaddr, ea->hw_src);
- __aarp_resolved(&unresolved[hash], a, hash);
- if (!unresolved_count)
- mod_timer(&aarp_timer,
- jiffies + sysctl_aarp_expiry_time);
- break;
-
- case AARP_REQUEST:
- case AARP_PROBE:
-
- /*
- * If it is my address set ma to my address and reply.
- * We can treat probe and request the same. Probe
- * simply means we shouldn't cache the querying host,
- * as in a probe they are proposing an address not
- * using one.
- *
- * Support for proxy-AARP added. We check if the
- * address is one of our proxies before we toss the
- * packet out.
- */
-
- sa.s_node = ea->pa_dst_node;
- sa.s_net = ea->pa_dst_net;
-
- /* See if we have a matching proxy. */
- ma = __aarp_proxy_find(dev, &sa);
- if (!ma)
- ma = &ifa->address;
- else { /* We need to make a copy of the entry. */
- da.s_node = sa.s_node;
- da.s_net = sa.s_net;
- ma = &da;
- }
-
- if (function == AARP_PROBE) {
- /*
- * A probe implies someone trying to get an
- * address. So as a precaution flush any
- * entries we have for this address.
- */
- a = __aarp_find_entry(resolved[sa.s_node %
- (AARP_HASH_SIZE - 1)],
- skb->dev, &sa);
-
- /*
- * Make it expire next tick - that avoids us
- * getting into a probe/flush/learn/probe/
- * flush/learn cycle during probing of a slow
- * to respond host addr.
- */
- if (a) {
- a->expires_at = jiffies - 1;
- mod_timer(&aarp_timer, jiffies +
- sysctl_aarp_tick_time);
- }
- }
-
- if (sa.s_node != ma->s_node)
- break;
-
- if (sa.s_net && ma->s_net && sa.s_net != ma->s_net)
- break;
-
- sa.s_node = ea->pa_src_node;
- sa.s_net = ea->pa_src_net;
-
- /* aarp_my_address has found the address to use for us.
- */
- aarp_send_reply(dev, ma, &sa, ea->hw_src);
- break;
- }
-
-unlock:
- write_unlock_bh(&aarp_lock);
-out1:
- ret = 1;
-out0:
- kfree_skb(skb);
- return ret;
-}
-
-static struct notifier_block aarp_notifier = {
- .notifier_call = aarp_device_event,
-};
-
-static unsigned char aarp_snap_id[] = { 0x00, 0x00, 0x00, 0x80, 0xF3 };
-
-int __init aarp_proto_init(void)
-{
- int rc;
-
- aarp_dl = register_snap_client(aarp_snap_id, aarp_rcv);
- if (!aarp_dl) {
- printk(KERN_CRIT "Unable to register AARP with SNAP.\n");
- return -ENOMEM;
- }
- timer_setup(&aarp_timer, aarp_expire_timeout, 0);
- aarp_timer.expires = jiffies + sysctl_aarp_expiry_time;
- add_timer(&aarp_timer);
- rc = register_netdevice_notifier(&aarp_notifier);
- if (rc) {
- timer_delete_sync(&aarp_timer);
- unregister_snap_client(aarp_dl);
- }
- return rc;
-}
-
-/* Remove the AARP entries associated with a device. */
-void aarp_device_down(struct net_device *dev)
-{
- int ct;
-
- write_lock_bh(&aarp_lock);
-
- for (ct = 0; ct < AARP_HASH_SIZE; ct++) {
- __aarp_expire_device(&resolved[ct], dev);
- __aarp_expire_device(&unresolved[ct], dev);
- __aarp_expire_device(&proxies[ct], dev);
- }
-
- write_unlock_bh(&aarp_lock);
-}
-
-#ifdef CONFIG_PROC_FS
-/*
- * Get the aarp entry that is in the chain described
- * by the iterator.
- * If pos is set then skip till that index.
- * pos = 1 is the first entry
- */
-static struct aarp_entry *iter_next(struct aarp_iter_state *iter, loff_t *pos)
-{
- int ct = iter->bucket;
- struct aarp_entry **table = iter->table;
- loff_t off = 0;
- struct aarp_entry *entry;
-
- rescan:
- while (ct < AARP_HASH_SIZE) {
- for (entry = table[ct]; entry; entry = entry->next) {
- if (!pos || ++off == *pos) {
- iter->table = table;
- iter->bucket = ct;
- return entry;
- }
- }
- ++ct;
- }
-
- if (table == resolved) {
- ct = 0;
- table = unresolved;
- goto rescan;
- }
- if (table == unresolved) {
- ct = 0;
- table = proxies;
- goto rescan;
- }
- return NULL;
-}
-
-static void *aarp_seq_start(struct seq_file *seq, loff_t *pos)
- __acquires(aarp_lock)
-{
- struct aarp_iter_state *iter = seq->private;
-
- read_lock_bh(&aarp_lock);
- iter->table = resolved;
- iter->bucket = 0;
-
- return *pos ? iter_next(iter, pos) : SEQ_START_TOKEN;
-}
-
-static void *aarp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
- struct aarp_entry *entry = v;
- struct aarp_iter_state *iter = seq->private;
-
- ++*pos;
-
- /* first line after header */
- if (v == SEQ_START_TOKEN)
- entry = iter_next(iter, NULL);
-
- /* next entry in current bucket */
- else if (entry->next)
- entry = entry->next;
-
- /* next bucket or table */
- else {
- ++iter->bucket;
- entry = iter_next(iter, NULL);
- }
- return entry;
-}
-
-static void aarp_seq_stop(struct seq_file *seq, void *v)
- __releases(aarp_lock)
-{
- read_unlock_bh(&aarp_lock);
-}
-
-static const char *dt2str(unsigned long ticks)
-{
- static char buf[32];
-
- sprintf(buf, "%ld.%02ld", ticks / HZ, ((ticks % HZ) * 100) / HZ);
-
- return buf;
-}
-
-static int aarp_seq_show(struct seq_file *seq, void *v)
-{
- struct aarp_iter_state *iter = seq->private;
- struct aarp_entry *entry = v;
- unsigned long now = jiffies;
-
- if (v == SEQ_START_TOKEN)
- seq_puts(seq,
- "Address Interface Hardware Address"
- " Expires LastSend Retry Status\n");
- else {
- seq_printf(seq, "%04X:%02X %-12s",
- ntohs(entry->target_addr.s_net),
- (unsigned int) entry->target_addr.s_node,
- entry->dev ? entry->dev->name : "????");
- seq_printf(seq, "%pM", entry->hwaddr);
- seq_printf(seq, " %8s",
- dt2str((long)entry->expires_at - (long)now));
- if (iter->table == unresolved)
- seq_printf(seq, " %8s %6hu",
- dt2str(now - entry->last_sent),
- entry->xmit_count);
- else
- seq_puts(seq, " ");
- seq_printf(seq, " %s\n",
- (iter->table == resolved) ? "resolved"
- : (iter->table == unresolved) ? "unresolved"
- : (iter->table == proxies) ? "proxies"
- : "unknown");
- }
- return 0;
-}
-
-const struct seq_operations aarp_seq_ops = {
- .start = aarp_seq_start,
- .next = aarp_seq_next,
- .stop = aarp_seq_stop,
- .show = aarp_seq_show,
-};
-#endif
-
-/* General module cleanup. Called from cleanup_module() in ddp.c. */
-void aarp_cleanup_module(void)
-{
- timer_delete_sync(&aarp_timer);
- unregister_netdevice_notifier(&aarp_notifier);
- unregister_snap_client(aarp_dl);
- aarp_purge();
-}
diff --git a/net/appletalk/atalk_proc.c b/net/appletalk/atalk_proc.c
deleted file mode 100644
index 01787fb6a7bc..000000000000
--- a/net/appletalk/atalk_proc.c
+++ /dev/null
@@ -1,242 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * atalk_proc.c - proc support for Appletalk
- *
- * Copyright(c) Arnaldo Carvalho de Melo <acme@conectiva.com.br>
- */
-
-#include <linux/init.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <net/net_namespace.h>
-#include <net/sock.h>
-#include <linux/atalk.h>
-#include <linux/export.h>
-
-
-static __inline__ struct atalk_iface *atalk_get_interface_idx(loff_t pos)
-{
- struct atalk_iface *i;
-
- for (i = atalk_interfaces; pos && i; i = i->next)
- --pos;
-
- return i;
-}
-
-static void *atalk_seq_interface_start(struct seq_file *seq, loff_t *pos)
- __acquires(atalk_interfaces_lock)
-{
- loff_t l = *pos;
-
- read_lock_bh(&atalk_interfaces_lock);
- return l ? atalk_get_interface_idx(--l) : SEQ_START_TOKEN;
-}
-
-static void *atalk_seq_interface_next(struct seq_file *seq, void *v, loff_t *pos)
-{
- struct atalk_iface *i;
-
- ++*pos;
- if (v == SEQ_START_TOKEN) {
- i = NULL;
- if (atalk_interfaces)
- i = atalk_interfaces;
- goto out;
- }
- i = v;
- i = i->next;
-out:
- return i;
-}
-
-static void atalk_seq_interface_stop(struct seq_file *seq, void *v)
- __releases(atalk_interfaces_lock)
-{
- read_unlock_bh(&atalk_interfaces_lock);
-}
-
-static int atalk_seq_interface_show(struct seq_file *seq, void *v)
-{
- struct atalk_iface *iface;
-
- if (v == SEQ_START_TOKEN) {
- seq_puts(seq, "Interface Address Networks "
- "Status\n");
- goto out;
- }
-
- iface = v;
- seq_printf(seq, "%-16s %04X:%02X %04X-%04X %d\n",
- iface->dev->name, ntohs(iface->address.s_net),
- iface->address.s_node, ntohs(iface->nets.nr_firstnet),
- ntohs(iface->nets.nr_lastnet), iface->status);
-out:
- return 0;
-}
-
-static __inline__ struct atalk_route *atalk_get_route_idx(loff_t pos)
-{
- struct atalk_route *r;
-
- for (r = atalk_routes; pos && r; r = r->next)
- --pos;
-
- return r;
-}
-
-static void *atalk_seq_route_start(struct seq_file *seq, loff_t *pos)
- __acquires(atalk_routes_lock)
-{
- loff_t l = *pos;
-
- read_lock_bh(&atalk_routes_lock);
- return l ? atalk_get_route_idx(--l) : SEQ_START_TOKEN;
-}
-
-static void *atalk_seq_route_next(struct seq_file *seq, void *v, loff_t *pos)
-{
- struct atalk_route *r;
-
- ++*pos;
- if (v == SEQ_START_TOKEN) {
- r = NULL;
- if (atalk_routes)
- r = atalk_routes;
- goto out;
- }
- r = v;
- r = r->next;
-out:
- return r;
-}
-
-static void atalk_seq_route_stop(struct seq_file *seq, void *v)
- __releases(atalk_routes_lock)
-{
- read_unlock_bh(&atalk_routes_lock);
-}
-
-static int atalk_seq_route_show(struct seq_file *seq, void *v)
-{
- struct atalk_route *rt;
-
- if (v == SEQ_START_TOKEN) {
- seq_puts(seq, "Target Router Flags Dev\n");
- goto out;
- }
-
- if (atrtr_default.dev) {
- rt = &atrtr_default;
- seq_printf(seq, "Default %04X:%02X %-4d %s\n",
- ntohs(rt->gateway.s_net), rt->gateway.s_node,
- rt->flags, rt->dev->name);
- }
-
- rt = v;
- seq_printf(seq, "%04X:%02X %04X:%02X %-4d %s\n",
- ntohs(rt->target.s_net), rt->target.s_node,
- ntohs(rt->gateway.s_net), rt->gateway.s_node,
- rt->flags, rt->dev->name);
-out:
- return 0;
-}
-
-static void *atalk_seq_socket_start(struct seq_file *seq, loff_t *pos)
- __acquires(atalk_sockets_lock)
-{
- read_lock_bh(&atalk_sockets_lock);
- return seq_hlist_start_head(&atalk_sockets, *pos);
-}
-
-static void *atalk_seq_socket_next(struct seq_file *seq, void *v, loff_t *pos)
-{
- return seq_hlist_next(v, &atalk_sockets, pos);
-}
-
-static void atalk_seq_socket_stop(struct seq_file *seq, void *v)
- __releases(atalk_sockets_lock)
-{
- read_unlock_bh(&atalk_sockets_lock);
-}
-
-static int atalk_seq_socket_show(struct seq_file *seq, void *v)
-{
- struct sock *s;
- struct atalk_sock *at;
-
- if (v == SEQ_START_TOKEN) {
- seq_printf(seq, "Type Local_addr Remote_addr Tx_queue "
- "Rx_queue St UID\n");
- goto out;
- }
-
- s = sk_entry(v);
- at = at_sk(s);
-
- seq_printf(seq, "%02X %04X:%02X:%02X %04X:%02X:%02X %08X:%08X "
- "%02X %u\n",
- s->sk_type, ntohs(at->src_net), at->src_node, at->src_port,
- ntohs(at->dest_net), at->dest_node, at->dest_port,
- sk_wmem_alloc_get(s),
- sk_rmem_alloc_get(s),
- s->sk_state,
- from_kuid_munged(seq_user_ns(seq), sk_uid(s)));
-out:
- return 0;
-}
-
-static const struct seq_operations atalk_seq_interface_ops = {
- .start = atalk_seq_interface_start,
- .next = atalk_seq_interface_next,
- .stop = atalk_seq_interface_stop,
- .show = atalk_seq_interface_show,
-};
-
-static const struct seq_operations atalk_seq_route_ops = {
- .start = atalk_seq_route_start,
- .next = atalk_seq_route_next,
- .stop = atalk_seq_route_stop,
- .show = atalk_seq_route_show,
-};
-
-static const struct seq_operations atalk_seq_socket_ops = {
- .start = atalk_seq_socket_start,
- .next = atalk_seq_socket_next,
- .stop = atalk_seq_socket_stop,
- .show = atalk_seq_socket_show,
-};
-
-int __init atalk_proc_init(void)
-{
- if (!proc_mkdir("atalk", init_net.proc_net))
- return -ENOMEM;
-
- if (!proc_create_seq("atalk/interface", 0444, init_net.proc_net,
- &atalk_seq_interface_ops))
- goto out;
-
- if (!proc_create_seq("atalk/route", 0444, init_net.proc_net,
- &atalk_seq_route_ops))
- goto out;
-
- if (!proc_create_seq("atalk/socket", 0444, init_net.proc_net,
- &atalk_seq_socket_ops))
- goto out;
-
- if (!proc_create_seq_private("atalk/arp", 0444, init_net.proc_net,
- &aarp_seq_ops,
- sizeof(struct aarp_iter_state), NULL))
- goto out;
-
- return 0;
-
-out:
- remove_proc_subtree("atalk", init_net.proc_net);
- return -ENOMEM;
-}
-
-void atalk_proc_exit(void)
-{
- remove_proc_subtree("atalk", init_net.proc_net);
-}
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
deleted file mode 100644
index afb86ce6e644..000000000000
--- a/net/appletalk/ddp.c
+++ /dev/null
@@ -1,2055 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * DDP: An implementation of the AppleTalk DDP protocol for
- * Ethernet 'ELAP'.
- *
- * Alan Cox <alan@lxorguk.ukuu.org.uk>
- *
- * With more than a little assistance from
- *
- * Wesley Craig <netatalk@umich.edu>
- *
- * Fixes:
- * Neil Horman : Added missing device ioctls
- * Michael Callahan : Made routing work
- * Wesley Craig : Fix probing to listen to a
- * passed node id.
- * Alan Cox : Added send/recvmsg support
- * Alan Cox : Moved at. to protinfo in
- * socket.
- * Alan Cox : Added firewall hooks.
- * Alan Cox : Supports new ARPHRD_LOOPBACK
- * Christer Weinigel : Routing and /proc fixes.
- * Bradford Johnson : LocalTalk.
- * Tom Dyas : Module support.
- * Alan Cox : Hooks for PPP (based on the
- * LocalTalk hook).
- * Alan Cox : Posix bits
- * Alan Cox/Mike Freeman : Possible fix to NBP problems
- * Bradford Johnson : IP-over-DDP (experimental)
- * Jay Schulist : Moved IP-over-DDP to its own
- * driver file. (ipddp.c & ipddp.h)
- * Jay Schulist : Made work as module with
- * AppleTalk drivers, cleaned it.
- * Rob Newberry : Added proxy AARP and AARP
- * procfs, moved probing to AARP
- * module.
- * Adrian Sun/
- * Michael Zuelsdorff : fix for net.0 packets. don't
- * allow illegal ether/tokentalk
- * port assignment. we lose a
- * valid localtalk port as a
- * result.
- * Arnaldo C. de Melo : Cleanup, in preparation for
- * shared skb support 8)
- * Arnaldo C. de Melo : Move proc stuff to atalk_proc.c,
- * use seq_file
- */
-
-#include <linux/capability.h>
-#include <linux/module.h>
-#include <linux/if_arp.h>
-#include <linux/termios.h> /* For TIOCOUTQ/INQ */
-#include <linux/compat.h>
-#include <linux/slab.h>
-#include <linux/hashtable.h>
-#include <net/datalink.h>
-#include <net/psnap.h>
-#include <net/sock.h>
-#include <net/tcp_states.h>
-#include <net/route.h>
-#include <net/compat.h>
-#include <linux/atalk.h>
-#include <linux/highmem.h>
-
-struct datalink_proto *ddp_dl, *aarp_dl;
-static const struct proto_ops atalk_dgram_ops;
-
-/**************************************************************************\
-* *
-* Handlers for the socket list. *
-* *
-\**************************************************************************/
-
-HLIST_HEAD(atalk_sockets);
-DEFINE_RWLOCK(atalk_sockets_lock);
-
-static inline void __atalk_insert_socket(struct sock *sk)
-{
- sk_add_node(sk, &atalk_sockets);
-}
-
-static inline void atalk_remove_socket(struct sock *sk)
-{
- write_lock_bh(&atalk_sockets_lock);
- sk_del_node_init(sk);
- write_unlock_bh(&atalk_sockets_lock);
-}
-
-static struct sock *atalk_search_socket(struct sockaddr_at *to,
- struct atalk_iface *atif)
-{
- struct sock *def_socket = NULL;
- struct sock *s;
-
- read_lock_bh(&atalk_sockets_lock);
- sk_for_each(s, &atalk_sockets) {
- struct atalk_sock *at = at_sk(s);
-
- if (to->sat_port != at->src_port)
- continue;
-
- if (to->sat_addr.s_net == ATADDR_ANYNET &&
- to->sat_addr.s_node == ATADDR_BCAST) {
- if (atif->address.s_node == at->src_node &&
- atif->address.s_net == at->src_net) {
- /* This socket's address matches the address of the interface
- * that received the packet -- use it
- */
- goto found;
- }
-
- /* Continue searching for a socket matching the interface address,
- * but use this socket by default if no other one is found
- */
- def_socket = s;
- }
-
- if (to->sat_addr.s_net == at->src_net &&
- (to->sat_addr.s_node == at->src_node ||
- to->sat_addr.s_node == ATADDR_BCAST ||
- to->sat_addr.s_node == ATADDR_ANYNODE))
- goto found;
-
- /* XXXX.0 -- we got a request for this router. make sure
- * that the node is appropriately set. */
- if (to->sat_addr.s_node == ATADDR_ANYNODE &&
- to->sat_addr.s_net != ATADDR_ANYNET &&
- atif->address.s_node == at->src_node) {
- to->sat_addr.s_node = atif->address.s_node;
- goto found;
- }
- }
- s = def_socket;
-found:
- read_unlock_bh(&atalk_sockets_lock);
- return s;
-}
-
-/**
- * atalk_find_or_insert_socket - Try to find a socket matching ADDR
- * @sk: socket to insert in the list if it is not there already
- * @sat: address to search for
- *
- * Try to find a socket matching ADDR in the socket list, if found then return
- * it. If not, insert SK into the socket list.
- *
- * This entire operation must execute atomically.
- */
-static struct sock *atalk_find_or_insert_socket(struct sock *sk,
- struct sockaddr_at *sat)
-{
- struct sock *s;
- struct atalk_sock *at;
-
- write_lock_bh(&atalk_sockets_lock);
- sk_for_each(s, &atalk_sockets) {
- at = at_sk(s);
-
- if (at->src_net == sat->sat_addr.s_net &&
- at->src_node == sat->sat_addr.s_node &&
- at->src_port == sat->sat_port)
- goto found;
- }
- s = NULL;
- __atalk_insert_socket(sk); /* Wheee, it's free, assign and insert. */
-found:
- write_unlock_bh(&atalk_sockets_lock);
- return s;
-}
-
-static void atalk_destroy_timer(struct timer_list *t)
-{
- struct sock *sk = timer_container_of(sk, t, sk_timer);
-
- if (sk_has_allocations(sk)) {
- sk->sk_timer.expires = jiffies + SOCK_DESTROY_TIME;
- add_timer(&sk->sk_timer);
- } else
- sock_put(sk);
-}
-
-static inline void atalk_destroy_socket(struct sock *sk)
-{
- atalk_remove_socket(sk);
- skb_queue_purge(&sk->sk_receive_queue);
-
- if (sk_has_allocations(sk)) {
- timer_setup(&sk->sk_timer, atalk_destroy_timer, 0);
- sk->sk_timer.expires = jiffies + SOCK_DESTROY_TIME;
- add_timer(&sk->sk_timer);
- } else
- sock_put(sk);
-}
-
-/**************************************************************************\
-* *
-* Routing tables for the AppleTalk socket layer. *
-* *
-\**************************************************************************/
-
-/* Anti-deadlock ordering is atalk_routes_lock --> iface_lock -DaveM */
-struct atalk_route *atalk_routes;
-DEFINE_RWLOCK(atalk_routes_lock);
-
-struct atalk_iface *atalk_interfaces;
-DEFINE_RWLOCK(atalk_interfaces_lock);
-
-/* Fast dev->iface lookup, keyed on ifindex. Shares atalk_interfaces_lock with
- * the atalk_interfaces list, which remains the owner of the iface objects.
- */
-#define ATALK_IFACE_HASH_BITS 8
-static DEFINE_HASHTABLE(atalk_iface_hash, ATALK_IFACE_HASH_BITS);
-
-/* Find the iface for @dev. Caller must hold atalk_interfaces_lock. */
-static struct atalk_iface *__atalk_find_dev(struct net_device *dev)
-{
- struct atalk_iface *iface;
-
- hash_for_each_possible(atalk_iface_hash, iface, hash_node, dev->ifindex)
- if (iface->dev == dev)
- return iface;
- return NULL;
-}
-
-struct atalk_iface *atalk_find_dev(struct net_device *dev)
-{
- struct atalk_iface *iface;
-
- read_lock_bh(&atalk_interfaces_lock);
- iface = __atalk_find_dev(dev);
- read_unlock_bh(&atalk_interfaces_lock);
- return iface;
-}
-
-/* For probing devices or in a routerless network */
-struct atalk_route atrtr_default;
-
-/* AppleTalk interface control */
-/*
- * Drop a device. Doesn't drop any of its routes - that is the caller's
- * problem. Called when we down the interface or delete the address.
- */
-static void atif_drop_device(struct net_device *dev)
-{
- struct atalk_iface **iface = &atalk_interfaces;
- struct atalk_iface *tmp;
-
- write_lock_bh(&atalk_interfaces_lock);
- while ((tmp = *iface) != NULL) {
- if (tmp->dev == dev) {
- *iface = tmp->next;
- hash_del(&tmp->hash_node);
- dev_put(dev);
- kfree(tmp);
- } else
- iface = &tmp->next;
- }
- write_unlock_bh(&atalk_interfaces_lock);
-}
-
-static struct atalk_iface *atif_add_device(struct net_device *dev,
- struct atalk_addr *sa)
-{
- struct atalk_iface *iface = kzalloc_obj(*iface);
-
- if (!iface)
- goto out;
-
- dev_hold(dev);
- iface->dev = dev;
- iface->address = *sa;
- iface->status = 0;
-
- write_lock_bh(&atalk_interfaces_lock);
- iface->next = atalk_interfaces;
- atalk_interfaces = iface;
- hash_add(atalk_iface_hash, &iface->hash_node, dev->ifindex);
- write_unlock_bh(&atalk_interfaces_lock);
-out:
- return iface;
-}
-
-/* Perform phase 2 AARP probing on our tentative address */
-static int atif_probe_device(struct atalk_iface *atif)
-{
- int netrange = ntohs(atif->nets.nr_lastnet) -
- ntohs(atif->nets.nr_firstnet) + 1;
- int probe_net = ntohs(atif->address.s_net);
- int probe_node = atif->address.s_node;
- int netct, nodect;
-
- /* Offset the network we start probing with */
- if (probe_net == ATADDR_ANYNET) {
- probe_net = ntohs(atif->nets.nr_firstnet);
- if (netrange)
- probe_net += jiffies % netrange;
- }
- if (probe_node == ATADDR_ANYNODE)
- probe_node = jiffies & 0xFF;
-
- /* Scan the networks */
- atif->status |= ATIF_PROBE;
- for (netct = 0; netct <= netrange; netct++) {
- /* Sweep the available nodes from a given start */
- atif->address.s_net = htons(probe_net);
- for (nodect = 0; nodect < 256; nodect++) {
- atif->address.s_node = (nodect + probe_node) & 0xFF;
- if (atif->address.s_node > 0 &&
- atif->address.s_node < 254) {
- /* Probe a proposed address */
- aarp_probe_network(atif);
-
- if (!(atif->status & ATIF_PROBE_FAIL)) {
- atif->status &= ~ATIF_PROBE;
- return 0;
- }
- }
- atif->status &= ~ATIF_PROBE_FAIL;
- }
- probe_net++;
- if (probe_net > ntohs(atif->nets.nr_lastnet))
- probe_net = ntohs(atif->nets.nr_firstnet);
- }
- atif->status &= ~ATIF_PROBE;
-
- return -EADDRINUSE; /* Network is full... */
-}
-
-
-/* Perform AARP probing for a proxy address */
-static int atif_proxy_probe_device(struct atalk_iface *atif,
- struct atalk_addr *proxy_addr)
-{
- int netrange = ntohs(atif->nets.nr_lastnet) -
- ntohs(atif->nets.nr_firstnet) + 1;
- /* we probe the interface's network */
- int probe_net = ntohs(atif->address.s_net);
- int probe_node = ATADDR_ANYNODE; /* we'll take anything */
- int netct, nodect;
-
- /* Offset the network we start probing with */
- if (probe_net == ATADDR_ANYNET) {
- probe_net = ntohs(atif->nets.nr_firstnet);
- if (netrange)
- probe_net += jiffies % netrange;
- }
-
- if (probe_node == ATADDR_ANYNODE)
- probe_node = jiffies & 0xFF;
-
- /* Scan the networks */
- for (netct = 0; netct <= netrange; netct++) {
- /* Sweep the available nodes from a given start */
- proxy_addr->s_net = htons(probe_net);
- for (nodect = 0; nodect < 256; nodect++) {
- proxy_addr->s_node = (nodect + probe_node) & 0xFF;
- if (proxy_addr->s_node > 0 &&
- proxy_addr->s_node < 254) {
- /* Tell AARP to probe a proposed address */
- int ret = aarp_proxy_probe_network(atif,
- proxy_addr);
-
- if (ret != -EADDRINUSE)
- return ret;
- }
- }
- probe_net++;
- if (probe_net > ntohs(atif->nets.nr_lastnet))
- probe_net = ntohs(atif->nets.nr_firstnet);
- }
-
- return -EADDRINUSE; /* Network is full... */
-}
-
-
-struct atalk_addr *atalk_find_dev_addr(struct net_device *dev)
-{
- struct atalk_addr *addr = NULL;
- struct atalk_iface *iface;
-
- read_lock_bh(&atalk_interfaces_lock);
- iface = __atalk_find_dev(dev);
- if (iface)
- addr = &iface->address;
- read_unlock_bh(&atalk_interfaces_lock);
- return addr;
-}
-
-static struct atalk_addr *atalk_find_primary(void)
-{
- struct atalk_iface *fiface = NULL;
- struct atalk_addr *retval;
- struct atalk_iface *iface;
-
- /*
- * Return a point-to-point interface only if
- * there is no non-ptp interface available.
- */
- read_lock_bh(&atalk_interfaces_lock);
- for (iface = atalk_interfaces; iface; iface = iface->next) {
- if (!fiface && !(iface->dev->flags & IFF_LOOPBACK))
- fiface = iface;
- if (!(iface->dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT))) {
- retval = &iface->address;
- goto out;
- }
- }
-
- if (fiface)
- retval = &fiface->address;
- else if (atalk_interfaces)
- retval = &atalk_interfaces->address;
- else
- retval = NULL;
-out:
- read_unlock_bh(&atalk_interfaces_lock);
- return retval;
-}
-
-/*
- * Find a match for 'any network' - ie any of our interfaces with that
- * node number will do just nicely.
- */
-static struct atalk_iface *atalk_find_anynet(int node, struct net_device *dev)
-{
- struct atalk_iface *iface;
-
- read_lock_bh(&atalk_interfaces_lock);
- iface = __atalk_find_dev(dev);
- if (!iface || iface->status & ATIF_PROBE)
- goto out_err;
-
- if (node != ATADDR_BCAST &&
- iface->address.s_node != node &&
- node != ATADDR_ANYNODE)
- goto out_err;
-out:
- read_unlock_bh(&atalk_interfaces_lock);
- return iface;
-out_err:
- iface = NULL;
- goto out;
-}
-
-/* Find a match for a specific network:node pair */
-static struct atalk_iface *atalk_find_interface(__be16 net, int node)
-{
- struct atalk_iface *iface;
-
- read_lock_bh(&atalk_interfaces_lock);
- for (iface = atalk_interfaces; iface; iface = iface->next) {
- if ((node == ATADDR_BCAST ||
- node == ATADDR_ANYNODE ||
- iface->address.s_node == node) &&
- iface->address.s_net == net &&
- !(iface->status & ATIF_PROBE))
- break;
-
- /* XXXX.0 -- net.0 returns the iface associated with net */
- if (node == ATADDR_ANYNODE && net != ATADDR_ANYNET &&
- ntohs(iface->nets.nr_firstnet) <= ntohs(net) &&
- ntohs(net) <= ntohs(iface->nets.nr_lastnet))
- break;
- }
- read_unlock_bh(&atalk_interfaces_lock);
- return iface;
-}
-
-
-/*
- * Find a route for an AppleTalk packet. This ought to get cached in
- * the socket (later on...). We know about host routes and the fact
- * that a route must be direct to broadcast.
- */
-static struct atalk_route *atrtr_find(struct atalk_addr *target)
-{
- /*
- * we must search through all routes unless we find a
- * host route, because some host routes might overlap
- * network routes
- */
- struct atalk_route *net_route = NULL;
- struct atalk_route *r;
-
- read_lock_bh(&atalk_routes_lock);
- for (r = atalk_routes; r; r = r->next) {
- if (!(r->flags & RTF_UP))
- continue;
-
- if (r->target.s_net == target->s_net) {
- if (r->flags & RTF_HOST) {
- /*
- * if this host route is for the target,
- * the we're done
- */
- if (r->target.s_node == target->s_node)
- goto out;
- } else
- /*
- * this route will work if there isn't a
- * direct host route, so cache it
- */
- net_route = r;
- }
- }
-
- /*
- * if we found a network route but not a direct host
- * route, then return it
- */
- if (net_route)
- r = net_route;
- else if (atrtr_default.dev)
- r = &atrtr_default;
- else /* No route can be found */
- r = NULL;
-out:
- read_unlock_bh(&atalk_routes_lock);
- return r;
-}
-
-
-/*
- * Given an AppleTalk network, find the device to use. This can be
- * a simple lookup.
- */
-struct net_device *atrtr_get_dev(struct atalk_addr *sa)
-{
- struct atalk_route *atr = atrtr_find(sa);
- return atr ? atr->dev : NULL;
-}
-
-/* Set up a default router */
-static void atrtr_set_default(struct net_device *dev)
-{
- atrtr_default.dev = dev;
- atrtr_default.flags = RTF_UP;
- atrtr_default.gateway.s_net = htons(0);
- atrtr_default.gateway.s_node = 0;
-}
-
-/*
- * Add a router. Basically make sure it looks valid and stuff the
- * entry in the list. While it uses netranges we always set them to one
- * entry to work like netatalk.
- */
-static int atrtr_create(struct rtentry *r, struct net_device *devhint)
-{
- struct sockaddr_at *ta = (struct sockaddr_at *)&r->rt_dst;
- struct sockaddr_at *ga = (struct sockaddr_at *)&r->rt_gateway;
- struct atalk_route *rt;
- struct atalk_iface *iface, *riface;
- int retval = -EINVAL;
-
- /*
- * Fixme: Raise/Lower a routing change semaphore for these
- * operations.
- */
-
- /* Validate the request */
- if (ta->sat_family != AF_APPLETALK ||
- (!devhint && ga->sat_family != AF_APPLETALK))
- goto out;
-
- /* Now walk the routing table and make our decisions */
- write_lock_bh(&atalk_routes_lock);
- for (rt = atalk_routes; rt; rt = rt->next) {
- if (r->rt_flags != rt->flags)
- continue;
-
- if (ta->sat_addr.s_net == rt->target.s_net) {
- if (!(rt->flags & RTF_HOST))
- break;
- if (ta->sat_addr.s_node == rt->target.s_node)
- break;
- }
- }
-
- if (!devhint) {
- riface = NULL;
-
- read_lock_bh(&atalk_interfaces_lock);
- for (iface = atalk_interfaces; iface; iface = iface->next) {
- if (!riface &&
- ntohs(ga->sat_addr.s_net) >=
- ntohs(iface->nets.nr_firstnet) &&
- ntohs(ga->sat_addr.s_net) <=
- ntohs(iface->nets.nr_lastnet))
- riface = iface;
-
- if (ga->sat_addr.s_net == iface->address.s_net &&
- ga->sat_addr.s_node == iface->address.s_node)
- riface = iface;
- }
- read_unlock_bh(&atalk_interfaces_lock);
-
- retval = -ENETUNREACH;
- if (!riface)
- goto out_unlock;
-
- devhint = riface->dev;
- }
-
- if (!rt) {
- rt = kzalloc_obj(*rt, GFP_ATOMIC);
-
- retval = -ENOBUFS;
- if (!rt)
- goto out_unlock;
-
- rt->next = atalk_routes;
- atalk_routes = rt;
- }
-
- /* Fill in the routing entry */
- rt->target = ta->sat_addr;
- dev_put(rt->dev); /* Release old device */
- dev_hold(devhint);
- rt->dev = devhint;
- rt->flags = r->rt_flags;
- rt->gateway = ga->sat_addr;
-
- retval = 0;
-out_unlock:
- write_unlock_bh(&atalk_routes_lock);
-out:
- return retval;
-}
-
-/* Delete a route. Find it and discard it */
-static int atrtr_delete(struct atalk_addr *addr)
-{
- struct atalk_route **r = &atalk_routes;
- int retval = 0;
- struct atalk_route *tmp;
-
- write_lock_bh(&atalk_routes_lock);
- while ((tmp = *r) != NULL) {
- if (tmp->target.s_net == addr->s_net &&
- (!(tmp->flags&RTF_GATEWAY) ||
- tmp->target.s_node == addr->s_node)) {
- *r = tmp->next;
- dev_put(tmp->dev);
- kfree(tmp);
- goto out;
- }
- r = &tmp->next;
- }
- retval = -ENOENT;
-out:
- write_unlock_bh(&atalk_routes_lock);
- return retval;
-}
-
-/*
- * Called when a device is downed. Just throw away any routes
- * via it.
- */
-static void atrtr_device_down(struct net_device *dev)
-{
- struct atalk_route **r = &atalk_routes;
- struct atalk_route *tmp;
-
- write_lock_bh(&atalk_routes_lock);
- while ((tmp = *r) != NULL) {
- if (tmp->dev == dev) {
- *r = tmp->next;
- dev_put(dev);
- kfree(tmp);
- } else
- r = &tmp->next;
- }
- write_unlock_bh(&atalk_routes_lock);
-
- if (atrtr_default.dev == dev)
- atrtr_set_default(NULL);
-}
-
-/* Actually down the interface */
-static inline void atalk_dev_down(struct net_device *dev)
-{
- atrtr_device_down(dev); /* Remove all routes for the device */
- aarp_device_down(dev); /* Remove AARP entries for the device */
- atif_drop_device(dev); /* Remove the device */
-}
-
-/*
- * A device event has occurred. Watch for devices going down and
- * delete our use of them (iface and route).
- */
-static int ddp_device_event(struct notifier_block *this, unsigned long event,
- void *ptr)
-{
- struct net_device *dev = netdev_notifier_info_to_dev(ptr);
-
- if (!net_eq(dev_net(dev), &init_net))
- return NOTIFY_DONE;
-
- if (event == NETDEV_DOWN)
- /* Discard any use of this */
- atalk_dev_down(dev);
-
- return NOTIFY_DONE;
-}
-
-/* ioctl calls. Shouldn't even need touching */
-/* Device configuration ioctl calls */
-static int atif_ioctl(int cmd, void __user *arg)
-{
- static char aarp_mcast[6] = { 0x09, 0x00, 0x00, 0xFF, 0xFF, 0xFF };
- struct ifreq atreq;
- struct atalk_netrange *nr;
- struct sockaddr_at *sa;
- struct net_device *dev;
- struct atalk_iface *atif;
- int ct;
- int limit;
- struct rtentry rtdef;
- int add_route;
-
- if (get_user_ifreq(&atreq, NULL, arg))
- return -EFAULT;
-
- dev = __dev_get_by_name(&init_net, atreq.ifr_name);
- if (!dev)
- return -ENODEV;
-
- sa = (struct sockaddr_at *)&atreq.ifr_addr;
- atif = atalk_find_dev(dev);
-
- switch (cmd) {
- case SIOCSIFADDR:
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- if (sa->sat_family != AF_APPLETALK)
- return -EINVAL;
- if (dev->type != ARPHRD_ETHER &&
- dev->type != ARPHRD_LOOPBACK &&
- dev->type != ARPHRD_LOCALTLK &&
- dev->type != ARPHRD_PPP)
- return -EPROTONOSUPPORT;
-
- nr = (struct atalk_netrange *)&sa->sat_zero[0];
- add_route = 1;
-
- /*
- * if this is a point-to-point iface, and we already
- * have an iface for this AppleTalk address, then we
- * should not add a route
- */
- if ((dev->flags & IFF_POINTOPOINT) &&
- atalk_find_interface(sa->sat_addr.s_net,
- sa->sat_addr.s_node)) {
- printk(KERN_DEBUG "AppleTalk: point-to-point "
- "interface added with "
- "existing address\n");
- add_route = 0;
- }
-
- /*
- * Phase 1 is fine on LocalTalk but we don't do
- * EtherTalk phase 1. Anyone wanting to add it, go ahead.
- */
- if (dev->type == ARPHRD_ETHER && nr->nr_phase != 2)
- return -EPROTONOSUPPORT;
- if (sa->sat_addr.s_node == ATADDR_BCAST ||
- sa->sat_addr.s_node == 254)
- return -EINVAL;
- if (atif) {
- /* Already setting address */
- if (atif->status & ATIF_PROBE)
- return -EBUSY;
-
- atif->address.s_net = sa->sat_addr.s_net;
- atif->address.s_node = sa->sat_addr.s_node;
- atrtr_device_down(dev); /* Flush old routes */
- } else {
- atif = atif_add_device(dev, &sa->sat_addr);
- if (!atif)
- return -ENOMEM;
- }
- atif->nets = *nr;
-
- /*
- * Check if the chosen address is used. If so we
- * error and atalkd will try another.
- */
-
- if (!(dev->flags & IFF_LOOPBACK) &&
- !(dev->flags & IFF_POINTOPOINT) &&
- atif_probe_device(atif) < 0) {
- atif_drop_device(dev);
- return -EADDRINUSE;
- }
-
- /* Hey it worked - add the direct routes */
- sa = (struct sockaddr_at *)&rtdef.rt_gateway;
- sa->sat_family = AF_APPLETALK;
- sa->sat_addr.s_net = atif->address.s_net;
- sa->sat_addr.s_node = atif->address.s_node;
- sa = (struct sockaddr_at *)&rtdef.rt_dst;
- rtdef.rt_flags = RTF_UP;
- sa->sat_family = AF_APPLETALK;
- sa->sat_addr.s_node = ATADDR_ANYNODE;
- if (dev->flags & IFF_LOOPBACK ||
- dev->flags & IFF_POINTOPOINT)
- rtdef.rt_flags |= RTF_HOST;
-
- /* Routerless initial state */
- if (nr->nr_firstnet == htons(0) &&
- nr->nr_lastnet == htons(0xFFFE)) {
- sa->sat_addr.s_net = atif->address.s_net;
- atrtr_create(&rtdef, dev);
- atrtr_set_default(dev);
- } else {
- limit = ntohs(nr->nr_lastnet);
- if (limit - ntohs(nr->nr_firstnet) > 4096) {
- printk(KERN_WARNING "Too many routes/"
- "iface.\n");
- return -EINVAL;
- }
- if (add_route)
- for (ct = ntohs(nr->nr_firstnet);
- ct <= limit; ct++) {
- sa->sat_addr.s_net = htons(ct);
- atrtr_create(&rtdef, dev);
- }
- }
- dev_mc_add_global(dev, aarp_mcast);
- return 0;
-
- case SIOCGIFADDR:
- if (!atif)
- return -EADDRNOTAVAIL;
-
- sa->sat_family = AF_APPLETALK;
- sa->sat_addr = atif->address;
- break;
-
- case SIOCGIFBRDADDR:
- if (!atif)
- return -EADDRNOTAVAIL;
-
- sa->sat_family = AF_APPLETALK;
- sa->sat_addr.s_net = atif->address.s_net;
- sa->sat_addr.s_node = ATADDR_BCAST;
- break;
-
- case SIOCATALKDIFADDR:
- case SIOCDIFADDR:
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- if (sa->sat_family != AF_APPLETALK)
- return -EINVAL;
- atalk_dev_down(dev);
- break;
-
- case SIOCSARP:
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- if (sa->sat_family != AF_APPLETALK)
- return -EINVAL;
- /*
- * for now, we only support proxy AARP on ELAP;
- * we should be able to do it for LocalTalk, too.
- */
- if (dev->type != ARPHRD_ETHER)
- return -EPROTONOSUPPORT;
-
- /*
- * atif points to the current interface on this network;
- * we aren't concerned about its current status (at
- * least for now), but it has all the settings about
- * the network we're going to probe. Consequently, it
- * must exist.
- */
- if (!atif)
- return -EADDRNOTAVAIL;
-
- nr = (struct atalk_netrange *)&(atif->nets);
- /*
- * Phase 1 is fine on Localtalk but we don't do
- * Ethertalk phase 1. Anyone wanting to add it, go ahead.
- */
- if (dev->type == ARPHRD_ETHER && nr->nr_phase != 2)
- return -EPROTONOSUPPORT;
-
- if (sa->sat_addr.s_node == ATADDR_BCAST ||
- sa->sat_addr.s_node == 254)
- return -EINVAL;
-
- /*
- * Check if the chosen address is used. If so we
- * error and ATCP will try another.
- */
- if (atif_proxy_probe_device(atif, &(sa->sat_addr)) < 0)
- return -EADDRINUSE;
-
- /*
- * We now have an address on the local network, and
- * the AARP code will defend it for us until we take it
- * down. We don't set up any routes right now, because
- * ATCP will install them manually via SIOCADDRT.
- */
- break;
-
- case SIOCDARP:
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- if (sa->sat_family != AF_APPLETALK)
- return -EINVAL;
- if (!atif)
- return -EADDRNOTAVAIL;
-
- /* give to aarp module to remove proxy entry */
- aarp_proxy_remove(atif->dev, &(sa->sat_addr));
- return 0;
- }
-
- return put_user_ifreq(&atreq, arg);
-}
-
-static int atrtr_ioctl_addrt(struct rtentry *rt)
-{
- struct net_device *dev = NULL;
-
- if (rt->rt_dev) {
- char name[IFNAMSIZ];
-
- if (copy_from_user(name, rt->rt_dev, IFNAMSIZ-1))
- return -EFAULT;
- name[IFNAMSIZ-1] = '\0';
-
- dev = __dev_get_by_name(&init_net, name);
- if (!dev)
- return -ENODEV;
- }
- return atrtr_create(rt, dev);
-}
-
-/* Routing ioctl() calls */
-static int atrtr_ioctl(unsigned int cmd, void __user *arg)
-{
- struct rtentry rt;
-
- if (copy_from_user(&rt, arg, sizeof(rt)))
- return -EFAULT;
-
- switch (cmd) {
- case SIOCDELRT:
- if (rt.rt_dst.sa_family != AF_APPLETALK)
- return -EINVAL;
- return atrtr_delete(&((struct sockaddr_at *)
- &rt.rt_dst)->sat_addr);
-
- case SIOCADDRT:
- return atrtr_ioctl_addrt(&rt);
- }
- return -EINVAL;
-}
-
-/**************************************************************************\
-* *
-* Handling for system calls applied via the various interfaces to an *
-* AppleTalk socket object. *
-* *
-\**************************************************************************/
-
-/*
- * Checksum: This is 'optional'. It's quite likely also a good
- * candidate for assembler hackery 8)
- */
-static unsigned long atalk_sum_partial(const unsigned char *data,
- int len, unsigned long sum)
-{
- /* This ought to be unwrapped neatly. I'll trust gcc for now */
- while (len--) {
- sum += *data++;
- sum = rol16(sum, 1);
- }
- return sum;
-}
-
-/* Checksum skb data -- similar to skb_checksum */
-static unsigned long atalk_sum_skb(const struct sk_buff *skb, int offset,
- int len, unsigned long sum)
-{
- int start = skb_headlen(skb);
- struct sk_buff *frag_iter;
- int i, copy;
-
- /* checksum stuff in header space */
- if ((copy = start - offset) > 0) {
- if (copy > len)
- copy = len;
- sum = atalk_sum_partial(skb->data + offset, copy, sum);
- if ((len -= copy) == 0)
- return sum;
-
- offset += copy;
- }
-
- /* checksum stuff in frags */
- for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- int end;
- const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- WARN_ON(start > offset + len);
-
- end = start + skb_frag_size(frag);
- if ((copy = end - offset) > 0) {
- u8 *vaddr;
-
- if (copy > len)
- copy = len;
- vaddr = kmap_atomic(skb_frag_page(frag));
- sum = atalk_sum_partial(vaddr + skb_frag_off(frag) +
- offset - start, copy, sum);
- kunmap_atomic(vaddr);
-
- if (!(len -= copy))
- return sum;
- offset += copy;
- }
- start = end;
- }
-
- skb_walk_frags(skb, frag_iter) {
- int end;
-
- WARN_ON(start > offset + len);
-
- end = start + frag_iter->len;
- if ((copy = end - offset) > 0) {
- if (copy > len)
- copy = len;
- sum = atalk_sum_skb(frag_iter, offset - start,
- copy, sum);
- if ((len -= copy) == 0)
- return sum;
- offset += copy;
- }
- start = end;
- }
-
- BUG_ON(len > 0);
-
- return sum;
-}
-
-static __be16 atalk_checksum(const struct sk_buff *skb, int len)
-{
- unsigned long sum;
-
- /* skip header 4 bytes */
- sum = atalk_sum_skb(skb, 4, len-4, 0);
-
- /* Use 0xFFFF for 0. 0 itself means none */
- return sum ? htons((unsigned short)sum) : htons(0xFFFF);
-}
-
-static struct proto ddp_proto = {
- .name = "DDP",
- .owner = THIS_MODULE,
- .obj_size = sizeof(struct atalk_sock),
-};
-
-/*
- * Create a socket. Initialise the socket, blank the addresses
- * set the state.
- */
-static int atalk_create(struct net *net, struct socket *sock, int protocol,
- int kern)
-{
- struct sock *sk;
- int rc = -ESOCKTNOSUPPORT;
-
- if (!net_eq(net, &init_net))
- return -EAFNOSUPPORT;
-
- /*
- * We permit SOCK_DGRAM and RAW is an extension. It is trivial to do
- * and gives you the full ELAP frame. Should be handy for CAP 8)
- */
- if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM)
- goto out;
-
- rc = -EPERM;
- if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW))
- goto out;
-
- rc = -ENOMEM;
- sk = sk_alloc(net, PF_APPLETALK, GFP_KERNEL, &ddp_proto, kern);
- if (!sk)
- goto out;
- rc = 0;
- sock->ops = &atalk_dgram_ops;
- sock_init_data(sock, sk);
-
- /* Checksums on by default */
- sock_set_flag(sk, SOCK_ZAPPED);
-out:
- return rc;
-}
-
-/* Free a socket. No work needed */
-static int atalk_release(struct socket *sock)
-{
- struct sock *sk = sock->sk;
-
- if (sk) {
- sock_hold(sk);
- lock_sock(sk);
-
- sock_orphan(sk);
- sock->sk = NULL;
- atalk_destroy_socket(sk);
-
- release_sock(sk);
- sock_put(sk);
- }
- return 0;
-}
-
-/**
- * atalk_pick_and_bind_port - Pick a source port when one is not given
- * @sk: socket to insert into the tables
- * @sat: address to search for
- *
- * Pick a source port when one is not given. If we can find a suitable free
- * one, we insert the socket into the tables using it.
- *
- * This whole operation must be atomic.
- */
-static int atalk_pick_and_bind_port(struct sock *sk, struct sockaddr_at *sat)
-{
- int retval;
-
- write_lock_bh(&atalk_sockets_lock);
-
- for (sat->sat_port = ATPORT_RESERVED;
- sat->sat_port < ATPORT_LAST;
- sat->sat_port++) {
- struct sock *s;
-
- sk_for_each(s, &atalk_sockets) {
- struct atalk_sock *at = at_sk(s);
-
- if (at->src_net == sat->sat_addr.s_net &&
- at->src_node == sat->sat_addr.s_node &&
- at->src_port == sat->sat_port)
- goto try_next_port;
- }
-
- /* Wheee, it's free, assign and insert. */
- __atalk_insert_socket(sk);
- at_sk(sk)->src_port = sat->sat_port;
- retval = 0;
- goto out;
-
-try_next_port:;
- }
-
- retval = -EBUSY;
-out:
- write_unlock_bh(&atalk_sockets_lock);
- return retval;
-}
-
-static int atalk_autobind(struct sock *sk)
-{
- struct atalk_sock *at = at_sk(sk);
- struct sockaddr_at sat;
- struct atalk_addr *ap = atalk_find_primary();
- int n = -EADDRNOTAVAIL;
-
- if (!ap || ap->s_net == htons(ATADDR_ANYNET))
- goto out;
-
- at->src_net = sat.sat_addr.s_net = ap->s_net;
- at->src_node = sat.sat_addr.s_node = ap->s_node;
-
- n = atalk_pick_and_bind_port(sk, &sat);
- if (!n)
- sock_reset_flag(sk, SOCK_ZAPPED);
-out:
- return n;
-}
-
-/* Set the address 'our end' of the connection */
-static int atalk_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int addr_len)
-{
- struct sockaddr_at *addr = (struct sockaddr_at *)uaddr;
- struct sock *sk = sock->sk;
- struct atalk_sock *at = at_sk(sk);
- int err;
-
- if (!sock_flag(sk, SOCK_ZAPPED) ||
- addr_len != sizeof(struct sockaddr_at))
- return -EINVAL;
-
- if (addr->sat_family != AF_APPLETALK)
- return -EAFNOSUPPORT;
-
- lock_sock(sk);
- if (addr->sat_addr.s_net == htons(ATADDR_ANYNET)) {
- struct atalk_addr *ap = atalk_find_primary();
-
- err = -EADDRNOTAVAIL;
- if (!ap)
- goto out;
-
- at->src_net = addr->sat_addr.s_net = ap->s_net;
- at->src_node = addr->sat_addr.s_node = ap->s_node;
- } else {
- err = -EADDRNOTAVAIL;
- if (!atalk_find_interface(addr->sat_addr.s_net,
- addr->sat_addr.s_node))
- goto out;
-
- at->src_net = addr->sat_addr.s_net;
- at->src_node = addr->sat_addr.s_node;
- }
-
- if (addr->sat_port == ATADDR_ANYPORT) {
- err = atalk_pick_and_bind_port(sk, addr);
-
- if (err < 0)
- goto out;
- } else {
- at->src_port = addr->sat_port;
-
- err = -EADDRINUSE;
- if (atalk_find_or_insert_socket(sk, addr))
- goto out;
- }
-
- sock_reset_flag(sk, SOCK_ZAPPED);
- err = 0;
-out:
- release_sock(sk);
- return err;
-}
-
-/* Set the address we talk to */
-static int atalk_connect(struct socket *sock, struct sockaddr_unsized *uaddr,
- int addr_len, int flags)
-{
- struct sock *sk = sock->sk;
- struct atalk_sock *at = at_sk(sk);
- struct sockaddr_at *addr;
- int err;
-
- sk->sk_state = TCP_CLOSE;
- sock->state = SS_UNCONNECTED;
-
- if (addr_len != sizeof(*addr))
- return -EINVAL;
-
- addr = (struct sockaddr_at *)uaddr;
-
- if (addr->sat_family != AF_APPLETALK)
- return -EAFNOSUPPORT;
-
- if (addr->sat_addr.s_node == ATADDR_BCAST &&
- !sock_flag(sk, SOCK_BROADCAST)) {
-#if 1
- pr_warn("atalk_connect: %s is broken and did not set SO_BROADCAST.\n",
- current->comm);
-#else
- return -EACCES;
-#endif
- }
-
- lock_sock(sk);
- err = -EBUSY;
- if (sock_flag(sk, SOCK_ZAPPED))
- if (atalk_autobind(sk) < 0)
- goto out;
-
- err = -ENETUNREACH;
- if (!atrtr_get_dev(&addr->sat_addr))
- goto out;
-
- at->dest_port = addr->sat_port;
- at->dest_net = addr->sat_addr.s_net;
- at->dest_node = addr->sat_addr.s_node;
-
- sock->state = SS_CONNECTED;
- sk->sk_state = TCP_ESTABLISHED;
- err = 0;
-out:
- release_sock(sk);
- return err;
-}
-
-/*
- * Find the name of an AppleTalk socket. Just copy the right
- * fields into the sockaddr.
- */
-static int atalk_getname(struct socket *sock, struct sockaddr *uaddr,
- int peer)
-{
- struct sockaddr_at sat;
- struct sock *sk = sock->sk;
- struct atalk_sock *at = at_sk(sk);
- int err;
-
- lock_sock(sk);
- err = -ENOBUFS;
- if (sock_flag(sk, SOCK_ZAPPED))
- if (atalk_autobind(sk) < 0)
- goto out;
-
- memset(&sat, 0, sizeof(sat));
-
- if (peer) {
- err = -ENOTCONN;
- if (sk->sk_state != TCP_ESTABLISHED)
- goto out;
-
- sat.sat_addr.s_net = at->dest_net;
- sat.sat_addr.s_node = at->dest_node;
- sat.sat_port = at->dest_port;
- } else {
- sat.sat_addr.s_net = at->src_net;
- sat.sat_addr.s_node = at->src_node;
- sat.sat_port = at->src_port;
- }
-
- sat.sat_family = AF_APPLETALK;
- memcpy(uaddr, &sat, sizeof(sat));
- err = sizeof(struct sockaddr_at);
-
-out:
- release_sock(sk);
- return err;
-}
-
-static int atalk_route_packet(struct sk_buff *skb, struct net_device *dev,
- struct ddpehdr *ddp, __u16 len_hops, int origlen)
-{
- struct atalk_route *rt;
- struct atalk_addr ta;
-
- /*
- * Don't route multicast, etc., packets, or packets sent to "this
- * network"
- */
- if (skb->pkt_type != PACKET_HOST || !ddp->deh_dnet) {
- /*
- * FIXME:
- *
- * Can it ever happen that a packet is from a PPP iface and
- * needs to be broadcast onto the default network?
- */
- if (dev->type == ARPHRD_PPP)
- printk(KERN_DEBUG "AppleTalk: didn't forward broadcast "
- "packet received from PPP iface\n");
- goto free_it;
- }
-
- ta.s_net = ddp->deh_dnet;
- ta.s_node = ddp->deh_dnode;
-
- /* Route the packet */
- rt = atrtr_find(&ta);
- /* increment hops count */
- len_hops += 1 << 10;
- if (!rt || !(len_hops & (15 << 10)))
- goto free_it;
-
- /* FIXME: use skb->cb to be able to use shared skbs */
-
- /*
- * Route goes through another gateway, so set the target to the
- * gateway instead.
- */
-
- if (rt->flags & RTF_GATEWAY) {
- ta.s_net = rt->gateway.s_net;
- ta.s_node = rt->gateway.s_node;
- }
-
- /* Fix up skb->len field */
- skb_trim(skb, min_t(unsigned int, origlen,
- (rt->dev->hard_header_len +
- ddp_dl->header_length + (len_hops & 1023))));
-
- /* FIXME: use skb->cb to be able to use shared skbs */
- ddp->deh_len_hops = htons(len_hops);
-
- /*
- * Send the buffer onwards
- *
- * Now we must always be careful. If it's come from LocalTalk to
- * EtherTalk it might not fit
- *
- * Order matters here: If a packet has to be copied to make a new
- * headroom (rare hopefully) then it won't need unsharing.
- *
- * Note. ddp-> becomes invalid at the realloc.
- */
- if (skb_headroom(skb) < 22) {
- /* 22 bytes - 12 ether, 2 len, 3 802.2 5 snap */
- struct sk_buff *nskb = skb_realloc_headroom(skb, 32);
- kfree_skb(skb);
- skb = nskb;
- } else
- skb = skb_unshare(skb, GFP_ATOMIC);
-
- /*
- * If the buffer didn't vanish into the lack of space bitbucket we can
- * send it.
- */
- if (skb == NULL)
- goto drop;
-
- if (aarp_send_ddp(rt->dev, skb, &ta, NULL) == NET_XMIT_DROP)
- return NET_RX_DROP;
- return NET_RX_SUCCESS;
-free_it:
- kfree_skb(skb);
-drop:
- return NET_RX_DROP;
-}
-
-/**
- * atalk_rcv - Receive a packet (in skb) from device dev
- * @skb: packet received
- * @dev: network device where the packet comes from
- * @pt: packet type
- * @orig_dev: the original receive net device
- *
- * Receive a packet (in skb) from device dev. This has come from the SNAP
- * decoder, and on entry skb->transport_header is the DDP header, skb->len
- * is the DDP header, skb->len is the DDP length. The physical headers
- * have been extracted. PPP should probably pass frames marked as for this
- * layer. [ie ARPHRD_ETHERTALK]
- */
-static int atalk_rcv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *pt, struct net_device *orig_dev)
-{
- struct ddpehdr *ddp;
- struct sock *sock;
- struct atalk_iface *atif;
- struct sockaddr_at tosat;
- int origlen;
- __u16 len_hops;
-
- if (!net_eq(dev_net(dev), &init_net))
- goto drop;
-
- /* Don't mangle buffer if shared */
- if (!(skb = skb_share_check(skb, GFP_ATOMIC)))
- goto out;
-
- /* Size check and make sure header is contiguous */
- if (!pskb_may_pull(skb, sizeof(*ddp)))
- goto drop;
-
- ddp = ddp_hdr(skb);
-
- len_hops = ntohs(ddp->deh_len_hops);
-
- /* Trim buffer in case of stray trailing data */
- origlen = skb->len;
- skb_trim(skb, min_t(unsigned int, skb->len, len_hops & 1023));
-
- /*
- * Size check to see if ddp->deh_len was crap
- * (Otherwise we'll detonate most spectacularly
- * in the middle of atalk_checksum() or recvmsg()).
- */
- if (skb->len < sizeof(*ddp) || skb->len < (len_hops & 1023)) {
- pr_debug("AppleTalk: dropping corrupted frame (deh_len=%u, "
- "skb->len=%u)\n", len_hops & 1023, skb->len);
- goto drop;
- }
-
- /*
- * Any checksums. Note we don't do htons() on this == is assumed to be
- * valid for net byte orders all over the networking code...
- */
- if (ddp->deh_sum &&
- atalk_checksum(skb, len_hops & 1023) != ddp->deh_sum)
- /* Not a valid AppleTalk frame - dustbin time */
- goto drop;
-
- /* Check the packet is aimed at us */
- if (!ddp->deh_dnet) /* Net 0 is 'this network' */
- atif = atalk_find_anynet(ddp->deh_dnode, dev);
- else
- atif = atalk_find_interface(ddp->deh_dnet, ddp->deh_dnode);
-
- if (!atif) {
- /* Not ours, so we route the packet via the correct
- * AppleTalk iface
- */
- return atalk_route_packet(skb, dev, ddp, len_hops, origlen);
- }
-
- /*
- * Which socket - atalk_search_socket() looks for a *full match*
- * of the <net, node, port> tuple.
- */
- tosat.sat_addr.s_net = ddp->deh_dnet;
- tosat.sat_addr.s_node = ddp->deh_dnode;
- tosat.sat_port = ddp->deh_dport;
-
- sock = atalk_search_socket(&tosat, atif);
- if (!sock) /* But not one of our sockets */
- goto drop;
-
- /* Queue packet (standard) */
- if (sock_queue_rcv_skb(sock, skb) < 0)
- goto drop;
-
- return NET_RX_SUCCESS;
-
-drop:
- kfree_skb(skb);
-out:
- return NET_RX_DROP;
-
-}
-
-/*
- * Receive a LocalTalk frame. We make some demands on the caller here.
- * Caller must provide enough headroom on the packet to pull the short
- * header and append a long one.
- */
-static int ltalk_rcv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *pt, struct net_device *orig_dev)
-{
- if (!net_eq(dev_net(dev), &init_net))
- goto freeit;
-
- /* Expand any short form frames */
- if (skb_mac_header(skb)[2] == 1) {
- struct ddpehdr *ddp;
- /* Find our address */
- struct atalk_addr *ap = atalk_find_dev_addr(dev);
-
- if (!ap || skb->len < sizeof(__be16) || skb->len > 1023)
- goto freeit;
-
- /* Don't mangle buffer if shared */
- if (!(skb = skb_share_check(skb, GFP_ATOMIC)))
- return 0;
-
- /*
- * The push leaves us with a ddephdr not an shdr, and
- * handily the port bytes in the right place preset.
- */
- ddp = skb_push(skb, sizeof(*ddp) - 4);
-
- /* Now fill in the long header */
-
- /*
- * These two first. The mac overlays the new source/dest
- * network information so we MUST copy these before
- * we write the network numbers !
- */
-
- ddp->deh_dnode = skb_mac_header(skb)[0]; /* From physical header */
- ddp->deh_snode = skb_mac_header(skb)[1]; /* From physical header */
-
- ddp->deh_dnet = ap->s_net; /* Network number */
- ddp->deh_snet = ap->s_net;
- ddp->deh_sum = 0; /* No checksum */
- /*
- * Not sure about this bit...
- */
- /* Non routable, so force a drop if we slip up later */
- ddp->deh_len_hops = htons(skb->len + (DDP_MAXHOPS << 10));
- }
- skb_reset_transport_header(skb);
-
- return atalk_rcv(skb, dev, pt, orig_dev);
-freeit:
- kfree_skb(skb);
- return 0;
-}
-
-static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
-{
- struct sock *sk = sock->sk;
- struct atalk_sock *at = at_sk(sk);
- DECLARE_SOCKADDR(struct sockaddr_at *, usat, msg->msg_name);
- int flags = msg->msg_flags;
- int loopback = 0;
- struct sockaddr_at local_satalk, gsat;
- struct sk_buff *skb;
- struct net_device *dev;
- struct ddpehdr *ddp;
- int size, hard_header_len;
- struct atalk_route *rt, *rt_lo = NULL;
- int err;
-
- if (flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT))
- return -EINVAL;
-
- if (len > DDP_MAXSZ)
- return -EMSGSIZE;
-
- lock_sock(sk);
- if (usat) {
- err = -EBUSY;
- if (sock_flag(sk, SOCK_ZAPPED))
- if (atalk_autobind(sk) < 0)
- goto out;
-
- err = -EINVAL;
- if (msg->msg_namelen < sizeof(*usat) ||
- usat->sat_family != AF_APPLETALK)
- goto out;
-
- err = -EPERM;
- /* netatalk didn't implement this check */
- if (usat->sat_addr.s_node == ATADDR_BCAST &&
- !sock_flag(sk, SOCK_BROADCAST)) {
- goto out;
- }
- } else {
- err = -ENOTCONN;
- if (sk->sk_state != TCP_ESTABLISHED)
- goto out;
- usat = &local_satalk;
- usat->sat_family = AF_APPLETALK;
- usat->sat_port = at->dest_port;
- usat->sat_addr.s_node = at->dest_node;
- usat->sat_addr.s_net = at->dest_net;
- }
-
- /* Build a packet */
- net_dbg_ratelimited("SK %p: Got address.\n", sk);
-
- /* For headers */
- size = sizeof(struct ddpehdr) + len + ddp_dl->header_length;
-
- if (usat->sat_addr.s_net || usat->sat_addr.s_node == ATADDR_ANYNODE) {
- rt = atrtr_find(&usat->sat_addr);
- } else {
- struct atalk_addr at_hint;
-
- at_hint.s_node = 0;
- at_hint.s_net = at->src_net;
-
- rt = atrtr_find(&at_hint);
- }
- err = -ENETUNREACH;
- if (!rt)
- goto out;
-
- dev = rt->dev;
-
- net_dbg_ratelimited("SK %p: Size needed %d, device %s\n",
- sk, size, dev->name);
-
- hard_header_len = dev->hard_header_len;
- /* Leave room for loopback hardware header if necessary */
- if (usat->sat_addr.s_node == ATADDR_BCAST &&
- (dev->flags & IFF_LOOPBACK || !(rt->flags & RTF_GATEWAY))) {
- struct atalk_addr at_lo;
-
- at_lo.s_node = 0;
- at_lo.s_net = 0;
-
- rt_lo = atrtr_find(&at_lo);
-
- if (rt_lo && rt_lo->dev->hard_header_len > hard_header_len)
- hard_header_len = rt_lo->dev->hard_header_len;
- }
-
- size += hard_header_len;
- release_sock(sk);
- skb = sock_alloc_send_skb(sk, size, (flags & MSG_DONTWAIT), &err);
- lock_sock(sk);
- if (!skb)
- goto out;
-
- skb_reserve(skb, ddp_dl->header_length);
- skb_reserve(skb, hard_header_len);
- skb->dev = dev;
-
- net_dbg_ratelimited("SK %p: Begin build.\n", sk);
-
- ddp = skb_put(skb, sizeof(struct ddpehdr));
- ddp->deh_len_hops = htons(len + sizeof(*ddp));
- ddp->deh_dnet = usat->sat_addr.s_net;
- ddp->deh_snet = at->src_net;
- ddp->deh_dnode = usat->sat_addr.s_node;
- ddp->deh_snode = at->src_node;
- ddp->deh_dport = usat->sat_port;
- ddp->deh_sport = at->src_port;
-
- net_dbg_ratelimited("SK %p: Copy user data (%zd bytes).\n", sk, len);
-
- err = memcpy_from_msg(skb_put(skb, len), msg, len);
- if (err) {
- kfree_skb(skb);
- err = -EFAULT;
- goto out;
- }
-
- if (sk->sk_no_check_tx)
- ddp->deh_sum = 0;
- else
- ddp->deh_sum = atalk_checksum(skb, len + sizeof(*ddp));
-
- /*
- * Loopback broadcast packets to non gateway targets (ie routes
- * to group we are in)
- */
- if (ddp->deh_dnode == ATADDR_BCAST &&
- !(rt->flags & RTF_GATEWAY) && !(dev->flags & IFF_LOOPBACK)) {
- struct sk_buff *skb2 = skb_copy(skb, GFP_KERNEL);
-
- if (skb2) {
- loopback = 1;
- net_dbg_ratelimited("SK %p: send out(copy).\n", sk);
- /*
- * If it fails it is queued/sent above in the aarp queue
- */
- aarp_send_ddp(dev, skb2, &usat->sat_addr, NULL);
- }
- }
-
- if (dev->flags & IFF_LOOPBACK || loopback) {
- net_dbg_ratelimited("SK %p: Loop back.\n", sk);
- /* loop back */
- skb_orphan(skb);
- if (ddp->deh_dnode == ATADDR_BCAST) {
- if (!rt_lo) {
- kfree_skb(skb);
- err = -ENETUNREACH;
- goto out;
- }
- dev = rt_lo->dev;
- skb->dev = dev;
- }
- ddp_dl->request(ddp_dl, skb, dev->dev_addr);
- } else {
- net_dbg_ratelimited("SK %p: send out.\n", sk);
- if (rt->flags & RTF_GATEWAY) {
- gsat.sat_addr = rt->gateway;
- usat = &gsat;
- }
-
- /*
- * If it fails it is queued/sent above in the aarp queue
- */
- aarp_send_ddp(dev, skb, &usat->sat_addr, NULL);
- }
- net_dbg_ratelimited("SK %p: Done write (%zd).\n", sk, len);
-
-out:
- release_sock(sk);
- return err ? : len;
-}
-
-static int atalk_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
- int flags)
-{
- struct sock *sk = sock->sk;
- struct ddpehdr *ddp;
- int copied = 0;
- int offset = 0;
- int err = 0;
- struct sk_buff *skb;
-
- skb = skb_recv_datagram(sk, flags, &err);
- lock_sock(sk);
-
- if (!skb)
- goto out;
-
- /* FIXME: use skb->cb to be able to use shared skbs */
- ddp = ddp_hdr(skb);
- copied = ntohs(ddp->deh_len_hops) & 1023;
-
- if (sk->sk_type != SOCK_RAW) {
- offset = sizeof(*ddp);
- copied -= offset;
- }
-
- if (copied > size) {
- copied = size;
- msg->msg_flags |= MSG_TRUNC;
- }
- err = skb_copy_datagram_msg(skb, offset, msg, copied);
-
- if (!err && msg->msg_name) {
- DECLARE_SOCKADDR(struct sockaddr_at *, sat, msg->msg_name);
- sat->sat_family = AF_APPLETALK;
- sat->sat_port = ddp->deh_sport;
- sat->sat_addr.s_node = ddp->deh_snode;
- sat->sat_addr.s_net = ddp->deh_snet;
- msg->msg_namelen = sizeof(*sat);
- }
-
- skb_free_datagram(sk, skb); /* Free the datagram. */
-
-out:
- release_sock(sk);
- return err ? : copied;
-}
-
-
-/*
- * AppleTalk ioctl calls.
- */
-static int atalk_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- int rc = -ENOIOCTLCMD;
- struct sock *sk = sock->sk;
- void __user *argp = (void __user *)arg;
-
- switch (cmd) {
- /* Protocol layer */
- case TIOCOUTQ: {
- long amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
-
- if (amount < 0)
- amount = 0;
- rc = put_user(amount, (int __user *)argp);
- break;
- }
- case TIOCINQ: {
- struct sk_buff *skb;
- long amount = 0;
-
- spin_lock_irq(&sk->sk_receive_queue.lock);
- skb = skb_peek(&sk->sk_receive_queue);
- if (skb)
- amount = skb->len - sizeof(struct ddpehdr);
- spin_unlock_irq(&sk->sk_receive_queue.lock);
- rc = put_user(amount, (int __user *)argp);
- break;
- }
- /* Routing */
- case SIOCADDRT:
- case SIOCDELRT:
- rc = -EPERM;
- if (capable(CAP_NET_ADMIN))
- rc = atrtr_ioctl(cmd, argp);
- break;
- /* Interface */
- case SIOCGIFADDR:
- case SIOCSIFADDR:
- case SIOCGIFBRDADDR:
- case SIOCATALKDIFADDR:
- case SIOCDIFADDR:
- case SIOCSARP: /* proxy AARP */
- case SIOCDARP: /* proxy AARP */
- rtnl_lock();
- rc = atif_ioctl(cmd, argp);
- rtnl_unlock();
- break;
- }
-
- return rc;
-}
-
-
-#ifdef CONFIG_COMPAT
-static int atalk_compat_routing_ioctl(struct sock *sk, unsigned int cmd,
- struct compat_rtentry __user *ur)
-{
- compat_uptr_t rtdev;
- struct rtentry rt;
-
- if (copy_from_user(&rt.rt_dst, &ur->rt_dst,
- 3 * sizeof(struct sockaddr)) ||
- get_user(rt.rt_flags, &ur->rt_flags) ||
- get_user(rt.rt_metric, &ur->rt_metric) ||
- get_user(rt.rt_mtu, &ur->rt_mtu) ||
- get_user(rt.rt_window, &ur->rt_window) ||
- get_user(rt.rt_irtt, &ur->rt_irtt) ||
- get_user(rtdev, &ur->rt_dev))
- return -EFAULT;
-
- switch (cmd) {
- case SIOCDELRT:
- if (rt.rt_dst.sa_family != AF_APPLETALK)
- return -EINVAL;
- return atrtr_delete(&((struct sockaddr_at *)
- &rt.rt_dst)->sat_addr);
-
- case SIOCADDRT:
- rt.rt_dev = compat_ptr(rtdev);
- return atrtr_ioctl_addrt(&rt);
- default:
- return -EINVAL;
- }
-}
-static int atalk_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- void __user *argp = compat_ptr(arg);
- struct sock *sk = sock->sk;
-
- switch (cmd) {
- case SIOCADDRT:
- case SIOCDELRT:
- return atalk_compat_routing_ioctl(sk, cmd, argp);
- /*
- * SIOCATALKDIFADDR is a SIOCPROTOPRIVATE ioctl number, so we
- * cannot handle it in common code. The data we access if ifreq
- * here is compatible, so we can simply call the native
- * handler.
- */
- case SIOCATALKDIFADDR:
- return atalk_ioctl(sock, cmd, (unsigned long)argp);
- default:
- return -ENOIOCTLCMD;
- }
-}
-#endif /* CONFIG_COMPAT */
-
-
-static const struct net_proto_family atalk_family_ops = {
- .family = PF_APPLETALK,
- .create = atalk_create,
- .owner = THIS_MODULE,
-};
-
-static const struct proto_ops atalk_dgram_ops = {
- .family = PF_APPLETALK,
- .owner = THIS_MODULE,
- .release = atalk_release,
- .bind = atalk_bind,
- .connect = atalk_connect,
- .socketpair = sock_no_socketpair,
- .accept = sock_no_accept,
- .getname = atalk_getname,
- .poll = datagram_poll,
- .ioctl = atalk_ioctl,
- .gettstamp = sock_gettstamp,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = atalk_compat_ioctl,
-#endif
- .listen = sock_no_listen,
- .shutdown = sock_no_shutdown,
- .sendmsg = atalk_sendmsg,
- .recvmsg = atalk_recvmsg,
- .mmap = sock_no_mmap,
-};
-
-static struct notifier_block ddp_notifier = {
- .notifier_call = ddp_device_event,
-};
-
-static struct packet_type ltalk_packet_type __read_mostly = {
- .type = cpu_to_be16(ETH_P_LOCALTALK),
- .func = ltalk_rcv,
-};
-
-static struct packet_type ppptalk_packet_type __read_mostly = {
- .type = cpu_to_be16(ETH_P_PPPTALK),
- .func = atalk_rcv,
-};
-
-static unsigned char ddp_snap_id[] = { 0x08, 0x00, 0x07, 0x80, 0x9B };
-
-/* Export symbols for use by drivers when AppleTalk is a module */
-EXPORT_SYMBOL(atrtr_get_dev);
-EXPORT_SYMBOL(atalk_find_dev_addr);
-
-/* Called by proto.c on kernel start up */
-static int __init atalk_init(void)
-{
- int rc;
-
- rc = proto_register(&ddp_proto, 0);
- if (rc)
- goto out;
-
- rc = sock_register(&atalk_family_ops);
- if (rc)
- goto out_proto;
-
- ddp_dl = register_snap_client(ddp_snap_id, atalk_rcv);
- if (!ddp_dl) {
- pr_crit("Unable to register DDP with SNAP.\n");
- rc = -ENOMEM;
- goto out_sock;
- }
-
- dev_add_pack(<alk_packet_type);
- dev_add_pack(&ppptalk_packet_type);
-
- rc = register_netdevice_notifier(&ddp_notifier);
- if (rc)
- goto out_snap;
-
- rc = aarp_proto_init();
- if (rc)
- goto out_dev;
-
- rc = atalk_proc_init();
- if (rc)
- goto out_aarp;
-
- rc = atalk_register_sysctl();
- if (rc)
- goto out_proc;
-out:
- return rc;
-out_proc:
- atalk_proc_exit();
-out_aarp:
- aarp_cleanup_module();
-out_dev:
- unregister_netdevice_notifier(&ddp_notifier);
-out_snap:
- dev_remove_pack(&ppptalk_packet_type);
- dev_remove_pack(<alk_packet_type);
- unregister_snap_client(ddp_dl);
-out_sock:
- sock_unregister(PF_APPLETALK);
-out_proto:
- proto_unregister(&ddp_proto);
- goto out;
-}
-module_init(atalk_init);
-
-/*
- * No explicit module reference count manipulation is needed in the
- * protocol. Socket layer sets module reference count for us
- * and interfaces reference counting is done
- * by the network device layer.
- *
- * Ergo, before the AppleTalk module can be removed, all AppleTalk
- * sockets should be closed from user space.
- */
-static void __exit atalk_exit(void)
-{
-#ifdef CONFIG_SYSCTL
- atalk_unregister_sysctl();
-#endif /* CONFIG_SYSCTL */
- atalk_proc_exit();
- aarp_cleanup_module(); /* General aarp clean-up. */
- unregister_netdevice_notifier(&ddp_notifier);
- dev_remove_pack(<alk_packet_type);
- dev_remove_pack(&ppptalk_packet_type);
- unregister_snap_client(ddp_dl);
- sock_unregister(PF_APPLETALK);
- proto_unregister(&ddp_proto);
-}
-module_exit(atalk_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Alan Cox <alan@lxorguk.ukuu.org.uk>");
-MODULE_DESCRIPTION("AppleTalk 0.20\n");
-MODULE_ALIAS_NETPROTO(PF_APPLETALK);
diff --git a/net/appletalk/sysctl_net_atalk.c b/net/appletalk/sysctl_net_atalk.c
deleted file mode 100644
index 7aebfe903242..000000000000
--- a/net/appletalk/sysctl_net_atalk.c
+++ /dev/null
@@ -1,58 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * sysctl_net_atalk.c: sysctl interface to net AppleTalk subsystem.
- *
- * Begun April 1, 1996, Mike Shaver.
- * Added /proc/sys/net/atalk directory entry (empty =) ). [MS]
- * Dynamic registration, added aarp entries. (5/30/97 Chris Horn)
- */
-
-#include <linux/sysctl.h>
-#include <net/sock.h>
-#include <linux/atalk.h>
-
-static struct ctl_table atalk_table[] = {
- {
- .procname = "aarp-expiry-time",
- .data = &sysctl_aarp_expiry_time,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_jiffies,
- },
- {
- .procname = "aarp-tick-time",
- .data = &sysctl_aarp_tick_time,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_jiffies,
- },
- {
- .procname = "aarp-retransmit-limit",
- .data = &sysctl_aarp_retransmit_limit,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
- {
- .procname = "aarp-resolve-time",
- .data = &sysctl_aarp_resolve_time,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_jiffies,
- },
-};
-
-static struct ctl_table_header *atalk_table_header;
-
-int __init atalk_register_sysctl(void)
-{
- atalk_table_header = register_net_sysctl(&init_net, "net/appletalk", atalk_table);
- if (!atalk_table_header)
- return -ENOMEM;
- return 0;
-}
-
-void atalk_unregister_sysctl(void)
-{
- unregister_net_sysctl_table(atalk_table_header);
-}
diff --git a/arch/arm/configs/ixp4xx_defconfig b/arch/arm/configs/ixp4xx_defconfig
index 01d72580bcc5..418ef909572b 100644
--- a/arch/arm/configs/ixp4xx_defconfig
+++ b/arch/arm/configs/ixp4xx_defconfig
@@ -55,7 +55,6 @@ CONFIG_ATM=y
CONFIG_ATM_BR2684=m
CONFIG_BRIDGE=m
CONFIG_VLAN_8021Q=m
-CONFIG_ATALK=m
CONFIG_DEV_APPLETALK=m
CONFIG_IPDDP=m
CONFIG_IPDDP_ENCAP=y
diff --git a/arch/m68k/configs/amiga_defconfig b/arch/m68k/configs/amiga_defconfig
index aadff466830f..93b1cb632b19 100644
--- a/arch/m68k/configs/amiga_defconfig
+++ b/arch/m68k/configs/amiga_defconfig
@@ -236,7 +236,6 @@ CONFIG_RDS=m
CONFIG_RDS_TCP=m
CONFIG_L2TP=m
CONFIG_BRIDGE=m
-CONFIG_ATALK=m
CONFIG_DNS_RESOLVER=y
CONFIG_BATMAN_ADV=m
# CONFIG_BATMAN_ADV_BATMAN_V is not set
diff --git a/arch/m68k/configs/apollo_defconfig b/arch/m68k/configs/apollo_defconfig
index ea9487a39884..6edfa55c8b9f 100644
--- a/arch/m68k/configs/apollo_defconfig
+++ b/arch/m68k/configs/apollo_defconfig
@@ -232,7 +232,6 @@ CONFIG_RDS=m
CONFIG_RDS_TCP=m
CONFIG_L2TP=m
CONFIG_BRIDGE=m
-CONFIG_ATALK=m
CONFIG_DNS_RESOLVER=y
CONFIG_BATMAN_ADV=m
# CONFIG_BATMAN_ADV_BATMAN_V is not set
diff --git a/arch/m68k/configs/atari_defconfig b/arch/m68k/configs/atari_defconfig
index a70127ac7a2d..f8808aac9e63 100644
--- a/arch/m68k/configs/atari_defconfig
+++ b/arch/m68k/configs/atari_defconfig
@@ -239,7 +239,6 @@ CONFIG_RDS=m
CONFIG_RDS_TCP=m
CONFIG_L2TP=m
CONFIG_BRIDGE=m
-CONFIG_ATALK=m
CONFIG_DNS_RESOLVER=y
CONFIG_BATMAN_ADV=m
# CONFIG_BATMAN_ADV_BATMAN_V is not set
diff --git a/arch/m68k/configs/bvme6000_defconfig b/arch/m68k/configs/bvme6000_defconfig
index 83da79382538..067ecf850201 100644
--- a/arch/m68k/configs/bvme6000_defconfig
+++ b/arch/m68k/configs/bvme6000_defconfig
@@ -229,7 +229,6 @@ CONFIG_RDS=m
CONFIG_RDS_TCP=m
CONFIG_L2TP=m
CONFIG_BRIDGE=m
-CONFIG_ATALK=m
CONFIG_DNS_RESOLVER=y
CONFIG_BATMAN_ADV=m
# CONFIG_BATMAN_ADV_BATMAN_V is not set
diff --git a/arch/m68k/configs/hp300_defconfig b/arch/m68k/configs/hp300_defconfig
index cea5ab74b3b1..aa93c67caa43 100644
--- a/arch/m68k/configs/hp300_defconfig
+++ b/arch/m68k/configs/hp300_defconfig
@@ -231,7 +231,6 @@ CONFIG_RDS=m
CONFIG_RDS_TCP=m
CONFIG_L2TP=m
CONFIG_BRIDGE=m
-CONFIG_ATALK=m
CONFIG_DNS_RESOLVER=y
CONFIG_BATMAN_ADV=m
# CONFIG_BATMAN_ADV_BATMAN_V is not set
diff --git a/arch/m68k/configs/mac_defconfig b/arch/m68k/configs/mac_defconfig
index 26406777376d..79d2e0383484 100644
--- a/arch/m68k/configs/mac_defconfig
+++ b/arch/m68k/configs/mac_defconfig
@@ -230,7 +230,6 @@ CONFIG_RDS=m
CONFIG_RDS_TCP=m
CONFIG_L2TP=m
CONFIG_BRIDGE=m
-CONFIG_ATALK=m
CONFIG_DNS_RESOLVER=y
CONFIG_BATMAN_ADV=m
# CONFIG_BATMAN_ADV_BATMAN_V is not set
diff --git a/arch/m68k/configs/multi_defconfig b/arch/m68k/configs/multi_defconfig
index 8357491645ad..b13889268ff5 100644
--- a/arch/m68k/configs/multi_defconfig
+++ b/arch/m68k/configs/multi_defconfig
@@ -250,7 +250,6 @@ CONFIG_RDS=m
CONFIG_RDS_TCP=m
CONFIG_L2TP=m
CONFIG_BRIDGE=m
-CONFIG_ATALK=m
CONFIG_DNS_RESOLVER=y
CONFIG_BATMAN_ADV=m
# CONFIG_BATMAN_ADV_BATMAN_V is not set
diff --git a/arch/m68k/configs/mvme147_defconfig b/arch/m68k/configs/mvme147_defconfig
index fe94f95862e7..cd773d2509bb 100644
--- a/arch/m68k/configs/mvme147_defconfig
+++ b/arch/m68k/configs/mvme147_defconfig
@@ -228,7 +228,6 @@ CONFIG_RDS=m
CONFIG_RDS_TCP=m
CONFIG_L2TP=m
CONFIG_BRIDGE=m
-CONFIG_ATALK=m
CONFIG_DNS_RESOLVER=y
CONFIG_BATMAN_ADV=m
# CONFIG_BATMAN_ADV_BATMAN_V is not set
diff --git a/arch/m68k/configs/mvme16x_defconfig b/arch/m68k/configs/mvme16x_defconfig
index ba67cacc079e..af921f24a5c8 100644
--- a/arch/m68k/configs/mvme16x_defconfig
+++ b/arch/m68k/configs/mvme16x_defconfig
@@ -229,7 +229,6 @@ CONFIG_RDS=m
CONFIG_RDS_TCP=m
CONFIG_L2TP=m
CONFIG_BRIDGE=m
-CONFIG_ATALK=m
CONFIG_DNS_RESOLVER=y
CONFIG_BATMAN_ADV=m
# CONFIG_BATMAN_ADV_BATMAN_V is not set
diff --git a/arch/m68k/configs/q40_defconfig b/arch/m68k/configs/q40_defconfig
index 552399979e4b..f2eb67618e97 100644
--- a/arch/m68k/configs/q40_defconfig
+++ b/arch/m68k/configs/q40_defconfig
@@ -230,7 +230,6 @@ CONFIG_RDS=m
CONFIG_RDS_TCP=m
CONFIG_L2TP=m
CONFIG_BRIDGE=m
-CONFIG_ATALK=m
CONFIG_DNS_RESOLVER=y
CONFIG_BATMAN_ADV=m
# CONFIG_BATMAN_ADV_BATMAN_V is not set
diff --git a/arch/m68k/configs/sun3_defconfig b/arch/m68k/configs/sun3_defconfig
index b4f3935d3d18..108dac7ed55e 100644
--- a/arch/m68k/configs/sun3_defconfig
+++ b/arch/m68k/configs/sun3_defconfig
@@ -225,7 +225,6 @@ CONFIG_RDS=m
CONFIG_RDS_TCP=m
CONFIG_L2TP=m
CONFIG_BRIDGE=m
-CONFIG_ATALK=m
CONFIG_DNS_RESOLVER=y
CONFIG_BATMAN_ADV=m
# CONFIG_BATMAN_ADV_BATMAN_V is not set
diff --git a/arch/m68k/configs/sun3x_defconfig b/arch/m68k/configs/sun3x_defconfig
index bb519520ae6e..1e1d946cbe23 100644
--- a/arch/m68k/configs/sun3x_defconfig
+++ b/arch/m68k/configs/sun3x_defconfig
@@ -226,7 +226,6 @@ CONFIG_RDS=m
CONFIG_RDS_TCP=m
CONFIG_L2TP=m
CONFIG_BRIDGE=m
-CONFIG_ATALK=m
CONFIG_DNS_RESOLVER=y
CONFIG_BATMAN_ADV=m
# CONFIG_BATMAN_ADV_BATMAN_V is not set
diff --git a/arch/mips/configs/gpr_defconfig b/arch/mips/configs/gpr_defconfig
index 47016655a089..7834569a8314 100644
--- a/arch/mips/configs/gpr_defconfig
+++ b/arch/mips/configs/gpr_defconfig
@@ -91,7 +91,6 @@ CONFIG_ATM_BR2684=m
CONFIG_BRIDGE=m
CONFIG_VLAN_8021Q=m
CONFIG_LLC2=m
-CONFIG_ATALK=m
CONFIG_DEV_APPLETALK=m
CONFIG_IPDDP=m
CONFIG_IPDDP_ENCAP=y
diff --git a/arch/mips/configs/malta_defconfig b/arch/mips/configs/malta_defconfig
index 61c9d5cd1a75..89d7c47ca7f0 100644
--- a/arch/mips/configs/malta_defconfig
+++ b/arch/mips/configs/malta_defconfig
@@ -170,7 +170,6 @@ CONFIG_IP_SCTP=m
CONFIG_BRIDGE=m
CONFIG_VLAN_8021Q=m
CONFIG_VLAN_8021Q_GVRP=y
-CONFIG_ATALK=m
CONFIG_DEV_APPLETALK=m
CONFIG_IPDDP=m
CONFIG_IPDDP_ENCAP=y
diff --git a/arch/mips/configs/malta_kvm_defconfig b/arch/mips/configs/malta_kvm_defconfig
index f862fbc7fbb7..39c69af12adc 100644
--- a/arch/mips/configs/malta_kvm_defconfig
+++ b/arch/mips/configs/malta_kvm_defconfig
@@ -174,7 +174,6 @@ CONFIG_IP_SCTP=m
CONFIG_BRIDGE=m
CONFIG_VLAN_8021Q=m
CONFIG_VLAN_8021Q_GVRP=y
-CONFIG_ATALK=m
CONFIG_DEV_APPLETALK=m
CONFIG_IPDDP=m
CONFIG_IPDDP_ENCAP=y
diff --git a/arch/mips/configs/malta_qemu_32r6_defconfig b/arch/mips/configs/malta_qemu_32r6_defconfig
index 14cdd23f1acb..5feb1dc43bae 100644
--- a/arch/mips/configs/malta_qemu_32r6_defconfig
+++ b/arch/mips/configs/malta_qemu_32r6_defconfig
@@ -46,7 +46,6 @@ CONFIG_INET6_IPCOMP=m
CONFIG_IPV6_TUNNEL=m
CONFIG_BRIDGE=m
CONFIG_VLAN_8021Q=m
-CONFIG_ATALK=m
CONFIG_DEV_APPLETALK=m
CONFIG_IPDDP=m
CONFIG_IPDDP_ENCAP=y
diff --git a/arch/mips/configs/maltaaprp_defconfig b/arch/mips/configs/maltaaprp_defconfig
index 2943593264b9..a69fb992b82a 100644
--- a/arch/mips/configs/maltaaprp_defconfig
+++ b/arch/mips/configs/maltaaprp_defconfig
@@ -48,7 +48,6 @@ CONFIG_INET6_IPCOMP=m
CONFIG_IPV6_TUNNEL=m
CONFIG_BRIDGE=m
CONFIG_VLAN_8021Q=m
-CONFIG_ATALK=m
CONFIG_DEV_APPLETALK=m
CONFIG_IPDDP=m
CONFIG_IPDDP_ENCAP=y
diff --git a/arch/mips/configs/maltasmvp_defconfig b/arch/mips/configs/maltasmvp_defconfig
index 47226fca0548..689edb56c055 100644
--- a/arch/mips/configs/maltasmvp_defconfig
+++ b/arch/mips/configs/maltasmvp_defconfig
@@ -49,7 +49,6 @@ CONFIG_INET6_IPCOMP=m
CONFIG_IPV6_TUNNEL=m
CONFIG_BRIDGE=m
CONFIG_VLAN_8021Q=m
-CONFIG_ATALK=m
CONFIG_DEV_APPLETALK=m
CONFIG_IPDDP=m
CONFIG_IPDDP_ENCAP=y
diff --git a/arch/mips/configs/maltasmvp_eva_defconfig b/arch/mips/configs/maltasmvp_eva_defconfig
index 09187a78409f..a56db606b2d8 100644
--- a/arch/mips/configs/maltasmvp_eva_defconfig
+++ b/arch/mips/configs/maltasmvp_eva_defconfig
@@ -50,7 +50,6 @@ CONFIG_INET6_IPCOMP=m
CONFIG_IPV6_TUNNEL=m
CONFIG_BRIDGE=m
CONFIG_VLAN_8021Q=m
-CONFIG_ATALK=m
CONFIG_DEV_APPLETALK=m
CONFIG_IPDDP=m
CONFIG_IPDDP_ENCAP=y
diff --git a/arch/mips/configs/maltaup_defconfig b/arch/mips/configs/maltaup_defconfig
index a80783097c1e..ee10762ab593 100644
--- a/arch/mips/configs/maltaup_defconfig
+++ b/arch/mips/configs/maltaup_defconfig
@@ -47,7 +47,6 @@ CONFIG_INET6_IPCOMP=m
CONFIG_IPV6_TUNNEL=m
CONFIG_BRIDGE=m
CONFIG_VLAN_8021Q=m
-CONFIG_ATALK=m
CONFIG_DEV_APPLETALK=m
CONFIG_IPDDP=m
CONFIG_IPDDP_ENCAP=y
diff --git a/arch/mips/configs/maltaup_xpa_defconfig b/arch/mips/configs/maltaup_xpa_defconfig
index e660c503654e..0e207bb0f794 100644
--- a/arch/mips/configs/maltaup_xpa_defconfig
+++ b/arch/mips/configs/maltaup_xpa_defconfig
@@ -171,7 +171,6 @@ CONFIG_IP_SCTP=m
CONFIG_BRIDGE=m
CONFIG_VLAN_8021Q=m
CONFIG_VLAN_8021Q_GVRP=y
-CONFIG_ATALK=m
CONFIG_DEV_APPLETALK=m
CONFIG_IPDDP=m
CONFIG_IPDDP_ENCAP=y
diff --git a/arch/mips/configs/mtx1_defconfig b/arch/mips/configs/mtx1_defconfig
index a1c374bd4785..46b40784a828 100644
--- a/arch/mips/configs/mtx1_defconfig
+++ b/arch/mips/configs/mtx1_defconfig
@@ -136,7 +136,6 @@ CONFIG_ATM_BR2684=m
CONFIG_BRIDGE=m
CONFIG_VLAN_8021Q=m
CONFIG_LLC2=m
-CONFIG_ATALK=m
CONFIG_DEV_APPLETALK=m
CONFIG_IPDDP=m
CONFIG_IPDDP_ENCAP=y
diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig
index c9bdaed06d03..f528cab1c6cf 100644
--- a/arch/powerpc/configs/ppc6xx_defconfig
+++ b/arch/powerpc/configs/ppc6xx_defconfig
@@ -228,7 +228,6 @@ CONFIG_ATM=m
CONFIG_ATM_BR2684=m
CONFIG_BRIDGE=m
CONFIG_VLAN_8021Q=m
-CONFIG_ATALK=m
CONFIG_DEV_APPLETALK=m
CONFIG_IPDDP=m
CONFIG_IPDDP_ENCAP=y
diff --git a/arch/sh/configs/landisk_defconfig b/arch/sh/configs/landisk_defconfig
index 4c39a23e6e0d..2b7e10c9acee 100644
--- a/arch/sh/configs/landisk_defconfig
+++ b/arch/sh/configs/landisk_defconfig
@@ -24,7 +24,6 @@ CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_IP_PNP=y
# CONFIG_IPV6 is not set
CONFIG_NETFILTER=y
-CONFIG_ATALK=m
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_ATA=y
--
2.54.0
^ permalink raw reply related
* [PATCH net] net: dsa: Fix skb ownership in taggers
From: Linus Walleij @ 2026-06-15 22:33 UTC (permalink / raw)
To: Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Florian Fainelli,
Jonas Gorski, Hauke Mehrtens, Kurt Kanzenbach, Woojung Huh,
UNGLinuxDriver, Chester A. Unal, Daniel Golle, Matthias Brugger,
AngeloGioacchino Del Regno, Wei Fang, Clark Wang,
Clément Léger, George McCollister, David Yang
Cc: netdev, Sashiko AI Review, Linus Walleij
The tag_8021q.c tagger calls vlan_insert_tag() in dsa_8021q_xmit().
vlan_insert_tag() will consume the skb with kfree_skb() on failure
and return NULL.
When NULL is returned as error code to ->xmit() in dsa_user_xmit()
it will free the same skb again leading to a double-free.
The idea of dsa_user_xmit() and dsa_switch_rcv() dropping the skb
they held before the call to ->xmit() and ->rcv() is conceptually
wrong: the pattern elsewhere in the networking code is that consumers
drop their skb:s on failure.
Modify the ->xmit() and ->rcv() call sites to not drop the SKB if
the taggers return NULL from any of these calls. Move those drops into
the taggers so every callback error path that retains ownership consumes
the skb before returning NULL.
Keep the existing helper ownership rules: VLAN insertion helpers already
free on failure (this is the case in tag_8021q.c), while deferred
transmit paths either transfer the skb reference to worker context or
hold a worker reference with skb_get() and drop the caller's reference.
For SJA1105 meta RX, transfer the buffered stampable skb under the meta
lock and return NULL while the skb is waiting for its meta frame: the
skb is not dropped in this case.
Reported-by: Sashiko AI Review <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/r/20260610153952.1685895-1-kuba@kernel.org/
Suggested-by: Jakub Kicinski <kuba@kernel.org>
Assisted-by: Codex:gpt-5-5
Signed-off-by: Linus Walleij <linusw@kernel.org>
---
net/dsa/tag.c | 4 +---
net/dsa/tag_ar9331.c | 10 ++++++++--
net/dsa/tag_brcm.c | 46 ++++++++++++++++++++++++++++++++-------------
net/dsa/tag_dsa.c | 15 ++++++++++++---
net/dsa/tag_gswip.c | 8 ++++++--
net/dsa/tag_hellcreek.c | 9 +++++++--
net/dsa/tag_ksz.c | 44 ++++++++++++++++++++++++++++++-------------
net/dsa/tag_lan9303.c | 2 ++
net/dsa/tag_mtk.c | 8 ++++++--
net/dsa/tag_mxl-gsw1xx.c | 3 +++
net/dsa/tag_mxl862xx.c | 3 +++
net/dsa/tag_netc.c | 15 ++++++++++++---
net/dsa/tag_ocelot.c | 4 +++-
net/dsa/tag_ocelot_8021q.c | 20 +++++++++++++-------
net/dsa/tag_qca.c | 14 +++++++++++---
net/dsa/tag_rtl4_a.c | 10 ++++++++--
net/dsa/tag_rtl8_4.c | 24 +++++++++++++++++------
net/dsa/tag_rzn1_a5psw.c | 10 ++++++++--
net/dsa/tag_sja1105.c | 42 ++++++++++++++++++++++++++---------------
net/dsa/tag_trailer.c | 16 ++++++++++++----
net/dsa/tag_vsc73xx_8021q.c | 1 +
net/dsa/tag_xrs700x.c | 12 +++++++++---
net/dsa/tag_yt921x.c | 7 ++++++-
net/dsa/user.c | 7 +++----
24 files changed, 243 insertions(+), 91 deletions(-)
diff --git a/net/dsa/tag.c b/net/dsa/tag.c
index 79ad105902d9..cfc8f5a0cbd9 100644
--- a/net/dsa/tag.c
+++ b/net/dsa/tag.c
@@ -84,10 +84,8 @@ static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev,
nskb = cpu_dp->rcv(skb, dev);
}
- if (!nskb) {
- kfree_skb(skb);
+ if (!nskb)
return 0;
- }
skb = nskb;
skb_push(skb, ETH_HLEN);
diff --git a/net/dsa/tag_ar9331.c b/net/dsa/tag_ar9331.c
index cbb588ca73aa..2e2388143b02 100644
--- a/net/dsa/tag_ar9331.c
+++ b/net/dsa/tag_ar9331.c
@@ -51,8 +51,10 @@ static struct sk_buff *ar9331_tag_rcv(struct sk_buff *skb,
u8 ver, port;
u16 hdr;
- if (unlikely(!pskb_may_pull(skb, AR9331_HDR_LEN)))
+ if (unlikely(!pskb_may_pull(skb, AR9331_HDR_LEN))) {
+ kfree_skb(skb);
return NULL;
+ }
hdr = le16_to_cpu(*(__le16 *)skb_mac_header(skb));
@@ -60,12 +62,14 @@ static struct sk_buff *ar9331_tag_rcv(struct sk_buff *skb,
if (unlikely(ver != AR9331_HDR_VERSION)) {
netdev_warn_once(ndev, "%s:%i wrong header version 0x%2x\n",
__func__, __LINE__, hdr);
+ kfree_skb(skb);
return NULL;
}
if (unlikely(hdr & AR9331_HDR_FROM_CPU)) {
netdev_warn_once(ndev, "%s:%i packet should not be from cpu 0x%2x\n",
__func__, __LINE__, hdr);
+ kfree_skb(skb);
return NULL;
}
@@ -75,8 +79,10 @@ static struct sk_buff *ar9331_tag_rcv(struct sk_buff *skb,
port = FIELD_GET(AR9331_HDR_PORT_NUM_MASK, hdr);
skb->dev = dsa_conduit_find_user(ndev, 0, port);
- if (!skb->dev)
+ if (!skb->dev) {
+ kfree_skb(skb);
return NULL;
+ }
return skb;
}
diff --git a/net/dsa/tag_brcm.c b/net/dsa/tag_brcm.c
index cf9420439054..23f032b76190 100644
--- a/net/dsa/tag_brcm.c
+++ b/net/dsa/tag_brcm.c
@@ -102,10 +102,12 @@ static struct sk_buff *brcm_tag_xmit_ll(struct sk_buff *skb,
* (including FCS and tag) because the length verification is done after
* the Broadcom tag is stripped off the ingress packet.
*
- * Let dsa_user_xmit() free the SKB
+ * Free the SKB on error.
*/
- if (__skb_put_padto(skb, ETH_ZLEN + BRCM_TAG_LEN, false))
+ if (__skb_put_padto(skb, ETH_ZLEN + BRCM_TAG_LEN, false)) {
+ kfree_skb(skb);
return NULL;
+ }
skb_push(skb, BRCM_TAG_LEN);
@@ -151,27 +153,35 @@ static struct sk_buff *brcm_tag_rcv_ll(struct sk_buff *skb,
int source_port;
u8 *brcm_tag;
- if (unlikely(!pskb_may_pull(skb, BRCM_TAG_LEN)))
+ if (unlikely(!pskb_may_pull(skb, BRCM_TAG_LEN))) {
+ kfree_skb(skb);
return NULL;
+ }
brcm_tag = skb->data - offset;
/* The opcode should never be different than 0b000 */
- if (unlikely((brcm_tag[0] >> BRCM_OPCODE_SHIFT) & BRCM_OPCODE_MASK))
+ if (unlikely((brcm_tag[0] >> BRCM_OPCODE_SHIFT) & BRCM_OPCODE_MASK)) {
+ kfree_skb(skb);
return NULL;
+ }
/* We should never see a reserved reason code without knowing how to
* handle it
*/
- if (unlikely(brcm_tag[2] & BRCM_EG_RC_RSVD))
+ if (unlikely(brcm_tag[2] & BRCM_EG_RC_RSVD)) {
+ kfree_skb(skb);
return NULL;
+ }
/* Locate which port this is coming from */
source_port = brcm_tag[3] & BRCM_EG_PID_MASK;
skb->dev = dsa_conduit_find_user(dev, 0, source_port);
- if (!skb->dev)
+ if (!skb->dev) {
+ kfree_skb(skb);
return NULL;
+ }
/* Remove Broadcom tag and update checksum */
skb_pull_rcsum(skb, BRCM_TAG_LEN);
@@ -228,8 +238,10 @@ static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb,
__be16 *proto;
u8 *brcm_tag;
- if (unlikely(!pskb_may_pull(skb, BRCM_LEG_TAG_LEN + VLAN_HLEN)))
+ if (unlikely(!pskb_may_pull(skb, BRCM_LEG_TAG_LEN + VLAN_HLEN))) {
+ kfree_skb(skb);
return NULL;
+ }
brcm_tag = dsa_etype_header_pos_rx(skb);
proto = (__be16 *)(brcm_tag + BRCM_LEG_TAG_LEN);
@@ -237,8 +249,10 @@ static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb,
source_port = brcm_tag[5] & BRCM_LEG_PORT_ID;
skb->dev = dsa_conduit_find_user(dev, 0, source_port);
- if (!skb->dev)
+ if (!skb->dev) {
+ kfree_skb(skb);
return NULL;
+ }
/* The internal switch in BCM63XX SoCs always tags on egress on the CPU
* port. We use VID 0 internally for untagged traffic, so strip the tag
@@ -274,10 +288,12 @@ static struct sk_buff *brcm_leg_tag_xmit(struct sk_buff *skb,
* (including FCS and tag) because the length verification is done after
* the Broadcom tag is stripped off the ingress packet.
*
- * Let dsa_user_xmit() free the SKB
+ * Free the SKB on error.
*/
- if (__skb_put_padto(skb, ETH_ZLEN + BRCM_LEG_TAG_LEN, false))
+ if (__skb_put_padto(skb, ETH_ZLEN + BRCM_LEG_TAG_LEN, false)) {
+ kfree_skb(skb);
return NULL;
+ }
skb_push(skb, BRCM_LEG_TAG_LEN);
@@ -326,10 +342,12 @@ static struct sk_buff *brcm_leg_fcs_tag_xmit(struct sk_buff *skb,
* and tag) because the length verification is done after the Broadcom
* tag is stripped off the ingress packet.
*
- * Let dsa_user_xmit() free the SKB.
+ * Free the SKB on error.
*/
- if (__skb_put_padto(skb, ETH_ZLEN + BRCM_LEG_TAG_LEN, false))
+ if (__skb_put_padto(skb, ETH_ZLEN + BRCM_LEG_TAG_LEN, false)) {
+ kfree_skb(skb);
return NULL;
+ }
fcs_len = skb->len;
fcs_val = cpu_to_le32(crc32_le(~0, skb->data, fcs_len) ^ ~0);
@@ -351,8 +369,10 @@ static struct sk_buff *brcm_leg_fcs_tag_xmit(struct sk_buff *skb,
brcm_tag[5] = dp->index & BRCM_LEG_PORT_ID;
/* Original FCS value */
- if (__skb_pad(skb, ETH_FCS_LEN, false))
+ if (__skb_pad(skb, ETH_FCS_LEN, false)) {
+ kfree_skb(skb);
return NULL;
+ }
skb_put_data(skb, &fcs_val, ETH_FCS_LEN);
return skb;
diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c
index 2a2c4fb61a65..d5ffee35fbb5 100644
--- a/net/dsa/tag_dsa.c
+++ b/net/dsa/tag_dsa.c
@@ -224,6 +224,7 @@ static struct sk_buff *dsa_rcv_ll(struct sk_buff *skb, struct net_device *dev,
/* Remote management is not implemented yet,
* drop.
*/
+ kfree_skb(skb);
return NULL;
case DSA_CODE_ARP_MIRROR:
case DSA_CODE_POLICY_MIRROR:
@@ -244,12 +245,14 @@ static struct sk_buff *dsa_rcv_ll(struct sk_buff *skb, struct net_device *dev,
/* Reserved code, this could be anything. Drop
* seems like the safest option.
*/
+ kfree_skb(skb);
return NULL;
}
break;
default:
+ kfree_skb(skb);
return NULL;
}
@@ -271,8 +274,10 @@ static struct sk_buff *dsa_rcv_ll(struct sk_buff *skb, struct net_device *dev,
source_port);
}
- if (!skb->dev)
+ if (!skb->dev) {
+ kfree_skb(skb);
return NULL;
+ }
/* When using LAG offload, skb->dev is not a DSA user interface,
* so we cannot call dsa_default_offload_fwd_mark and we need to
@@ -335,8 +340,10 @@ static struct sk_buff *dsa_xmit(struct sk_buff *skb, struct net_device *dev)
static struct sk_buff *dsa_rcv(struct sk_buff *skb, struct net_device *dev)
{
- if (unlikely(!pskb_may_pull(skb, DSA_HLEN)))
+ if (unlikely(!pskb_may_pull(skb, DSA_HLEN))) {
+ kfree_skb(skb);
return NULL;
+ }
return dsa_rcv_ll(skb, dev, 0);
}
@@ -375,8 +382,10 @@ static struct sk_buff *edsa_xmit(struct sk_buff *skb, struct net_device *dev)
static struct sk_buff *edsa_rcv(struct sk_buff *skb, struct net_device *dev)
{
- if (unlikely(!pskb_may_pull(skb, EDSA_HLEN)))
+ if (unlikely(!pskb_may_pull(skb, EDSA_HLEN))) {
+ kfree_skb(skb);
return NULL;
+ }
skb_pull_rcsum(skb, EDSA_HLEN - DSA_HLEN);
diff --git a/net/dsa/tag_gswip.c b/net/dsa/tag_gswip.c
index 5fa436121087..5c407d448c9f 100644
--- a/net/dsa/tag_gswip.c
+++ b/net/dsa/tag_gswip.c
@@ -80,16 +80,20 @@ static struct sk_buff *gswip_tag_rcv(struct sk_buff *skb,
int port;
u8 *gswip_tag;
- if (unlikely(!pskb_may_pull(skb, GSWIP_RX_HEADER_LEN)))
+ if (unlikely(!pskb_may_pull(skb, GSWIP_RX_HEADER_LEN))) {
+ kfree_skb(skb);
return NULL;
+ }
gswip_tag = skb->data - ETH_HLEN;
/* Get source port information */
port = (gswip_tag[7] & GSWIP_RX_SPPID_MASK) >> GSWIP_RX_SPPID_SHIFT;
skb->dev = dsa_conduit_find_user(dev, 0, port);
- if (!skb->dev)
+ if (!skb->dev) {
+ kfree_skb(skb);
return NULL;
+ }
/* remove GSWIP tag */
skb_pull_rcsum(skb, GSWIP_RX_HEADER_LEN);
diff --git a/net/dsa/tag_hellcreek.c b/net/dsa/tag_hellcreek.c
index 544ab15685a2..dd9f328f3182 100644
--- a/net/dsa/tag_hellcreek.c
+++ b/net/dsa/tag_hellcreek.c
@@ -27,8 +27,10 @@ static struct sk_buff *hellcreek_xmit(struct sk_buff *skb,
* checksums after the switch strips the tag.
*/
if (skb->ip_summed == CHECKSUM_PARTIAL &&
- skb_checksum_help(skb))
+ skb_checksum_help(skb)) {
+ kfree_skb(skb);
return NULL;
+ }
/* Tag encoding */
tag = skb_put(skb, HELLCREEK_TAG_LEN);
@@ -47,11 +49,14 @@ static struct sk_buff *hellcreek_rcv(struct sk_buff *skb,
skb->dev = dsa_conduit_find_user(dev, 0, port);
if (!skb->dev) {
netdev_warn_once(dev, "Failed to get source port: %d\n", port);
+ kfree_skb(skb);
return NULL;
}
- if (pskb_trim_rcsum(skb, skb->len - HELLCREEK_TAG_LEN))
+ if (pskb_trim_rcsum(skb, skb->len - HELLCREEK_TAG_LEN)) {
+ kfree_skb(skb);
return NULL;
+ }
dsa_default_offload_fwd_mark(skb);
diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c
index d2475c3bbb7d..67fa89f102e0 100644
--- a/net/dsa/tag_ksz.c
+++ b/net/dsa/tag_ksz.c
@@ -88,11 +88,15 @@ static struct sk_buff *ksz_common_rcv(struct sk_buff *skb,
unsigned int port, unsigned int len)
{
skb->dev = dsa_conduit_find_user(dev, 0, port);
- if (!skb->dev)
+ if (!skb->dev) {
+ kfree_skb(skb);
return NULL;
+ }
- if (pskb_trim_rcsum(skb, skb->len - len))
+ if (pskb_trim_rcsum(skb, skb->len - len)) {
+ kfree_skb(skb);
return NULL;
+ }
dsa_default_offload_fwd_mark(skb);
@@ -123,8 +127,10 @@ static struct sk_buff *ksz8795_xmit(struct sk_buff *skb, struct net_device *dev)
struct ethhdr *hdr;
u8 *tag;
- if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb))
+ if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) {
+ kfree_skb(skb);
return NULL;
+ }
/* Tag encoding */
tag = skb_put(skb, KSZ_INGRESS_TAG_LEN);
@@ -141,8 +147,10 @@ static struct sk_buff *ksz8795_rcv(struct sk_buff *skb, struct net_device *dev)
{
u8 *tag;
- if (skb_linearize(skb))
+ if (skb_linearize(skb)) {
+ kfree_skb(skb);
return NULL;
+ }
tag = skb_tail_pointer(skb) - KSZ_EGRESS_TAG_LEN;
@@ -255,22 +263,24 @@ static struct sk_buff *ksz_defer_xmit(struct dsa_port *dp, struct sk_buff *skb)
xmit_work_fn = tagger_data->xmit_work_fn;
xmit_worker = priv->xmit_worker;
- if (!xmit_work_fn || !xmit_worker)
+ if (!xmit_work_fn || !xmit_worker) {
+ kfree_skb(skb);
return NULL;
+ }
xmit_work = kzalloc_obj(*xmit_work, GFP_ATOMIC);
- if (!xmit_work)
+ if (!xmit_work) {
+ kfree_skb(skb);
return NULL;
+ }
kthread_init_work(&xmit_work->work, xmit_work_fn);
- /* Increase refcount so the kfree_skb in dsa_user_xmit
- * won't really free the packet.
- */
xmit_work->dp = dp;
xmit_work->skb = skb_get(skb);
kthread_queue_work(xmit_worker, &xmit_work->work);
+ kfree_skb(skb);
return NULL;
}
@@ -284,8 +294,10 @@ static struct sk_buff *ksz9477_xmit(struct sk_buff *skb,
__be16 *tag;
u16 val;
- if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb))
+ if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) {
+ kfree_skb(skb);
return NULL;
+ }
/* Tag encoding */
ksz_xmit_timestamp(dp, skb);
@@ -310,8 +322,10 @@ static struct sk_buff *ksz9477_rcv(struct sk_buff *skb, struct net_device *dev)
unsigned int port;
u8 *tag;
- if (skb_linearize(skb))
+ if (skb_linearize(skb)) {
+ kfree_skb(skb);
return NULL;
+ }
/* Tag decoding */
tag = skb_tail_pointer(skb) - KSZ_EGRESS_TAG_LEN;
@@ -352,8 +366,10 @@ static struct sk_buff *ksz9893_xmit(struct sk_buff *skb,
struct ethhdr *hdr;
u8 *tag;
- if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb))
+ if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) {
+ kfree_skb(skb);
return NULL;
+ }
/* Tag encoding */
ksz_xmit_timestamp(dp, skb);
@@ -418,8 +434,10 @@ static struct sk_buff *lan937x_xmit(struct sk_buff *skb,
__be16 *tag;
u16 val;
- if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb))
+ if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) {
+ kfree_skb(skb);
return NULL;
+ }
ksz_xmit_timestamp(dp, skb);
diff --git a/net/dsa/tag_lan9303.c b/net/dsa/tag_lan9303.c
index 258e5d7dc5ef..d1194696499a 100644
--- a/net/dsa/tag_lan9303.c
+++ b/net/dsa/tag_lan9303.c
@@ -85,6 +85,7 @@ static struct sk_buff *lan9303_rcv(struct sk_buff *skb, struct net_device *dev)
if (unlikely(!pskb_may_pull(skb, LAN9303_TAG_LEN))) {
dev_warn_ratelimited(&dev->dev,
"Dropping packet, cannot pull\n");
+ kfree_skb(skb);
return NULL;
}
@@ -102,6 +103,7 @@ static struct sk_buff *lan9303_rcv(struct sk_buff *skb, struct net_device *dev)
skb->dev = dsa_conduit_find_user(dev, 0, source_port);
if (!skb->dev) {
dev_warn_ratelimited(&dev->dev, "Dropping packet due to invalid source port\n");
+ kfree_skb(skb);
return NULL;
}
diff --git a/net/dsa/tag_mtk.c b/net/dsa/tag_mtk.c
index dea3eecaf093..c7dc7731675e 100644
--- a/net/dsa/tag_mtk.c
+++ b/net/dsa/tag_mtk.c
@@ -72,8 +72,10 @@ static struct sk_buff *mtk_tag_rcv(struct sk_buff *skb, struct net_device *dev)
int port;
__be16 *phdr;
- if (unlikely(!pskb_may_pull(skb, MTK_HDR_LEN)))
+ if (unlikely(!pskb_may_pull(skb, MTK_HDR_LEN))) {
+ kfree_skb(skb);
return NULL;
+ }
phdr = dsa_etype_header_pos_rx(skb);
hdr = ntohs(*phdr);
@@ -87,8 +89,10 @@ static struct sk_buff *mtk_tag_rcv(struct sk_buff *skb, struct net_device *dev)
port = (hdr & MTK_HDR_RECV_SOURCE_PORT_MASK);
skb->dev = dsa_conduit_find_user(dev, 0, port);
- if (!skb->dev)
+ if (!skb->dev) {
+ kfree_skb(skb);
return NULL;
+ }
dsa_default_offload_fwd_mark(skb);
diff --git a/net/dsa/tag_mxl-gsw1xx.c b/net/dsa/tag_mxl-gsw1xx.c
index 60f7c445e656..4b1b6ef94196 100644
--- a/net/dsa/tag_mxl-gsw1xx.c
+++ b/net/dsa/tag_mxl-gsw1xx.c
@@ -73,6 +73,7 @@ static struct sk_buff *gsw1xx_tag_rcv(struct sk_buff *skb,
if (unlikely(!pskb_may_pull(skb, GSW1XX_HEADER_LEN))) {
dev_warn_ratelimited(&dev->dev, "Dropping packet, cannot pull SKB\n");
+ kfree_skb(skb);
return NULL;
}
@@ -81,6 +82,7 @@ static struct sk_buff *gsw1xx_tag_rcv(struct sk_buff *skb,
if (unlikely(ntohs(gsw1xx_tag[0]) != ETH_P_MXLGSW)) {
dev_warn_ratelimited(&dev->dev, "Dropping packet due to invalid special tag\n");
dev_warn_ratelimited(&dev->dev, "Tag: %8ph\n", gsw1xx_tag);
+ kfree_skb(skb);
return NULL;
}
@@ -90,6 +92,7 @@ static struct sk_buff *gsw1xx_tag_rcv(struct sk_buff *skb,
if (!skb->dev) {
dev_warn_ratelimited(&dev->dev, "Dropping packet due to invalid source port\n");
dev_warn_ratelimited(&dev->dev, "Tag: %8ph\n", gsw1xx_tag);
+ kfree_skb(skb);
return NULL;
}
diff --git a/net/dsa/tag_mxl862xx.c b/net/dsa/tag_mxl862xx.c
index 8daefeb8d49d..87b80ddf0946 100644
--- a/net/dsa/tag_mxl862xx.c
+++ b/net/dsa/tag_mxl862xx.c
@@ -64,6 +64,7 @@ static struct sk_buff *mxl862_tag_rcv(struct sk_buff *skb,
if (unlikely(!pskb_may_pull(skb, MXL862_HEADER_LEN))) {
dev_warn_ratelimited(&dev->dev, "Cannot pull SKB, packet dropped\n");
+ kfree_skb(skb);
return NULL;
}
@@ -73,6 +74,7 @@ static struct sk_buff *mxl862_tag_rcv(struct sk_buff *skb,
dev_warn_ratelimited(&dev->dev,
"Invalid special tag marker, packet dropped, tag: %8ph\n",
mxl862_tag);
+ kfree_skb(skb);
return NULL;
}
@@ -83,6 +85,7 @@ static struct sk_buff *mxl862_tag_rcv(struct sk_buff *skb,
dev_warn_ratelimited(&dev->dev,
"Invalid source port, packet dropped, tag: %8ph\n",
mxl862_tag);
+ kfree_skb(skb);
return NULL;
}
diff --git a/net/dsa/tag_netc.c b/net/dsa/tag_netc.c
index ccedfe3a80b6..b1bc67e28866 100644
--- a/net/dsa/tag_netc.c
+++ b/net/dsa/tag_netc.c
@@ -130,14 +130,17 @@ static struct sk_buff *netc_rcv(struct sk_buff *skb,
int tag_len, sw_id, port;
int type, subtype;
- if (unlikely(!pskb_may_pull(skb, NETC_TAG_MAX_LEN)))
+ if (unlikely(!pskb_may_pull(skb, NETC_TAG_MAX_LEN))) {
+ kfree_skb(skb);
return NULL;
+ }
tag_cmn = dsa_etype_header_pos_rx(skb);
if (ntohs(tag_cmn->tpid) != ETH_P_NXP_NETC) {
dev_warn_ratelimited(&ndev->dev, "Unknown TPID 0x%04x\n",
ntohs(tag_cmn->tpid));
+ kfree_skb(skb);
return NULL;
}
@@ -150,13 +153,16 @@ static struct sk_buff *netc_rcv(struct sk_buff *skb,
dev_warn_ratelimited(&ndev->dev,
"VEPA switch ID is not supported yet\n");
+ kfree_skb(skb);
return NULL;
}
port = FIELD_GET(NETC_TAG_PORT, tag_cmn->switch_port);
skb->dev = dsa_conduit_find_user(ndev, sw_id, port);
- if (!skb->dev)
+ if (!skb->dev) {
+ kfree_skb(skb);
return NULL;
+ }
type = FIELD_GET(NETC_TAG_TYPE, tag_cmn->type);
subtype = FIELD_GET(NETC_TAG_SUBTYPE, tag_cmn->type);
@@ -164,11 +170,14 @@ static struct sk_buff *netc_rcv(struct sk_buff *skb,
dsa_default_offload_fwd_mark(skb);
} else if (type == NETC_TAG_TO_HOST) {
/* Currently only subtype0 supported */
- if (subtype != NETC_TAG_TH_SUBTYPE0)
+ if (subtype != NETC_TAG_TH_SUBTYPE0) {
+ kfree_skb(skb);
return NULL;
+ }
} else {
dev_warn_ratelimited(&ndev->dev,
"Unexpected tag type %d\n", type);
+ kfree_skb(skb);
return NULL;
}
diff --git a/net/dsa/tag_ocelot.c b/net/dsa/tag_ocelot.c
index 3405def79c2d..d208c7322cd6 100644
--- a/net/dsa/tag_ocelot.c
+++ b/net/dsa/tag_ocelot.c
@@ -107,14 +107,16 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb,
ocelot_xfh_get_rew_val(extraction, &rew_val);
skb->dev = dsa_conduit_find_user(netdev, 0, src_port);
- if (!skb->dev)
+ if (!skb->dev) {
/* The switch will reflect back some frames sent through
* sockets opened on the bare DSA conduit. These will come back
* with src_port equal to the index of the CPU port, for which
* there is no user registered. So don't print any error
* message here (ignore and drop those frames).
*/
+ kfree_skb(skb);
return NULL;
+ }
dsa_default_offload_fwd_mark(skb);
skb->priority = qos_class;
diff --git a/net/dsa/tag_ocelot_8021q.c b/net/dsa/tag_ocelot_8021q.c
index e89d9254e90a..f50f1cd83f16 100644
--- a/net/dsa/tag_ocelot_8021q.c
+++ b/net/dsa/tag_ocelot_8021q.c
@@ -33,30 +33,34 @@ static struct sk_buff *ocelot_defer_xmit(struct dsa_port *dp,
xmit_work_fn = data->xmit_work_fn;
xmit_worker = priv->xmit_worker;
- if (!xmit_work_fn || !xmit_worker)
+ if (!xmit_work_fn || !xmit_worker) {
+ kfree_skb(skb);
return NULL;
+ }
/* PTP over IP packets need UDP checksumming. We may have inherited
* NETIF_F_HW_CSUM from the DSA conduit, but these packets are not sent
* through the DSA conduit, so calculate the checksum here.
*/
- if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb))
+ if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) {
+ kfree_skb(skb);
return NULL;
+ }
xmit_work = kzalloc_obj(*xmit_work, GFP_ATOMIC);
- if (!xmit_work)
+ if (!xmit_work) {
+ kfree_skb(skb);
return NULL;
+ }
/* Calls felix_port_deferred_xmit in felix.c */
kthread_init_work(&xmit_work->work, xmit_work_fn);
- /* Increase refcount so the kfree_skb in dsa_user_xmit
- * won't really free the packet.
- */
xmit_work->dp = dp;
xmit_work->skb = skb_get(skb);
kthread_queue_work(xmit_worker, &xmit_work->work);
+ kfree_skb(skb);
return NULL;
}
@@ -84,8 +88,10 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb,
dsa_8021q_rcv(skb, &src_port, &switch_id, NULL, NULL);
skb->dev = dsa_conduit_find_user(netdev, switch_id, src_port);
- if (!skb->dev)
+ if (!skb->dev) {
+ kfree_skb(skb);
return NULL;
+ }
dsa_default_offload_fwd_mark(skb);
diff --git a/net/dsa/tag_qca.c b/net/dsa/tag_qca.c
index 9e3b429e8b36..510792fbfa92 100644
--- a/net/dsa/tag_qca.c
+++ b/net/dsa/tag_qca.c
@@ -46,16 +46,20 @@ static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev)
tagger_data = ds->tagger_data;
- if (unlikely(!pskb_may_pull(skb, QCA_HDR_LEN)))
+ if (unlikely(!pskb_may_pull(skb, QCA_HDR_LEN))) {
+ kfree_skb(skb);
return NULL;
+ }
phdr = dsa_etype_header_pos_rx(skb);
hdr = ntohs(*phdr);
/* Make sure the version is correct */
ver = FIELD_GET(QCA_HDR_RECV_VERSION, hdr);
- if (unlikely(ver != QCA_HDR_VERSION))
+ if (unlikely(ver != QCA_HDR_VERSION)) {
+ kfree_skb(skb);
return NULL;
+ }
/* Get pk type */
pk_type = FIELD_GET(QCA_HDR_RECV_TYPE, hdr);
@@ -64,6 +68,7 @@ static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev)
if (pk_type == QCA_HDR_RECV_TYPE_RW_REG_ACK) {
if (likely(tagger_data->rw_reg_ack_handler))
tagger_data->rw_reg_ack_handler(ds, skb);
+ kfree_skb(skb);
return NULL;
}
@@ -71,6 +76,7 @@ static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev)
if (pk_type == QCA_HDR_RECV_TYPE_MIB) {
if (likely(tagger_data->mib_autocast_handler))
tagger_data->mib_autocast_handler(ds, skb);
+ kfree_skb(skb);
return NULL;
}
@@ -78,8 +84,10 @@ static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev)
port = FIELD_GET(QCA_HDR_RECV_SOURCE_PORT, hdr);
skb->dev = dsa_conduit_find_user(dev, 0, port);
- if (!skb->dev)
+ if (!skb->dev) {
+ kfree_skb(skb);
return NULL;
+ }
/* Remove QCA tag and recalculate checksum */
skb_pull_rcsum(skb, QCA_HDR_LEN);
diff --git a/net/dsa/tag_rtl4_a.c b/net/dsa/tag_rtl4_a.c
index 3cc63eacfa03..9805c56025de 100644
--- a/net/dsa/tag_rtl4_a.c
+++ b/net/dsa/tag_rtl4_a.c
@@ -41,8 +41,10 @@ static struct sk_buff *rtl4a_tag_xmit(struct sk_buff *skb,
u16 out;
/* Pad out to at least 60 bytes */
- if (unlikely(__skb_put_padto(skb, ETH_ZLEN, false)))
+ if (unlikely(__skb_put_padto(skb, ETH_ZLEN, false))) {
+ kfree_skb(skb);
return NULL;
+ }
netdev_dbg(dev, "add realtek tag to package to port %d\n",
dp->index);
@@ -75,8 +77,10 @@ static struct sk_buff *rtl4a_tag_rcv(struct sk_buff *skb,
u8 prot;
u8 port;
- if (unlikely(!pskb_may_pull(skb, RTL4_A_HDR_LEN)))
+ if (unlikely(!pskb_may_pull(skb, RTL4_A_HDR_LEN))) {
+ kfree_skb(skb);
return NULL;
+ }
tag = dsa_etype_header_pos_rx(skb);
p = (__be16 *)tag;
@@ -92,6 +96,7 @@ static struct sk_buff *rtl4a_tag_rcv(struct sk_buff *skb,
prot = (protport >> RTL4_A_PROTOCOL_SHIFT) & 0x0f;
if (prot != RTL4_A_PROTOCOL_RTL8366RB) {
netdev_err(dev, "unknown realtek protocol 0x%01x\n", prot);
+ kfree_skb(skb);
return NULL;
}
port = protport & 0xff;
@@ -99,6 +104,7 @@ static struct sk_buff *rtl4a_tag_rcv(struct sk_buff *skb,
skb->dev = dsa_conduit_find_user(dev, 0, port);
if (!skb->dev) {
netdev_dbg(dev, "could not find user for port %d\n", port);
+ kfree_skb(skb);
return NULL;
}
diff --git a/net/dsa/tag_rtl8_4.c b/net/dsa/tag_rtl8_4.c
index 852c6b88079a..4da3beebef75 100644
--- a/net/dsa/tag_rtl8_4.c
+++ b/net/dsa/tag_rtl8_4.c
@@ -143,8 +143,10 @@ static struct sk_buff *rtl8_4t_tag_xmit(struct sk_buff *skb,
/* Calculate the checksum here if not done yet as trailing tags will
* break either software or hardware based checksum
*/
- if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb))
+ if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) {
+ kfree_skb(skb);
return NULL;
+ }
rtl8_4_write_tag(skb, dev, skb_put(skb, RTL8_4_TAG_LEN));
@@ -201,11 +203,15 @@ static int rtl8_4_read_tag(struct sk_buff *skb, struct net_device *dev,
static struct sk_buff *rtl8_4_tag_rcv(struct sk_buff *skb,
struct net_device *dev)
{
- if (unlikely(!pskb_may_pull(skb, RTL8_4_TAG_LEN)))
+ if (unlikely(!pskb_may_pull(skb, RTL8_4_TAG_LEN))) {
+ kfree_skb(skb);
return NULL;
+ }
- if (unlikely(rtl8_4_read_tag(skb, dev, dsa_etype_header_pos_rx(skb))))
+ if (unlikely(rtl8_4_read_tag(skb, dev, dsa_etype_header_pos_rx(skb)))) {
+ kfree_skb(skb);
return NULL;
+ }
/* Remove tag and recalculate checksum */
skb_pull_rcsum(skb, RTL8_4_TAG_LEN);
@@ -218,14 +224,20 @@ static struct sk_buff *rtl8_4_tag_rcv(struct sk_buff *skb,
static struct sk_buff *rtl8_4t_tag_rcv(struct sk_buff *skb,
struct net_device *dev)
{
- if (skb_linearize(skb))
+ if (skb_linearize(skb)) {
+ kfree_skb(skb);
return NULL;
+ }
- if (unlikely(rtl8_4_read_tag(skb, dev, skb_tail_pointer(skb) - RTL8_4_TAG_LEN)))
+ if (unlikely(rtl8_4_read_tag(skb, dev, skb_tail_pointer(skb) - RTL8_4_TAG_LEN))) {
+ kfree_skb(skb);
return NULL;
+ }
- if (pskb_trim_rcsum(skb, skb->len - RTL8_4_TAG_LEN))
+ if (pskb_trim_rcsum(skb, skb->len - RTL8_4_TAG_LEN)) {
+ kfree_skb(skb);
return NULL;
+ }
return skb;
}
diff --git a/net/dsa/tag_rzn1_a5psw.c b/net/dsa/tag_rzn1_a5psw.c
index 10994b3470f6..f66f52f5d2a5 100644
--- a/net/dsa/tag_rzn1_a5psw.c
+++ b/net/dsa/tag_rzn1_a5psw.c
@@ -48,8 +48,10 @@ static struct sk_buff *a5psw_tag_xmit(struct sk_buff *skb, struct net_device *de
* least 60 bytes otherwise they will be discarded when they enter the
* switch port logic.
*/
- if (__skb_put_padto(skb, ETH_ZLEN, false))
+ if (__skb_put_padto(skb, ETH_ZLEN, false)) {
+ kfree_skb(skb);
return NULL;
+ }
/* provide 'A5PSW_TAG_LEN' bytes additional space */
skb_push(skb, A5PSW_TAG_LEN);
@@ -77,6 +79,7 @@ static struct sk_buff *a5psw_tag_rcv(struct sk_buff *skb,
if (unlikely(!pskb_may_pull(skb, A5PSW_TAG_LEN))) {
dev_warn_ratelimited(&dev->dev,
"Dropping packet, cannot pull\n");
+ kfree_skb(skb);
return NULL;
}
@@ -84,14 +87,17 @@ static struct sk_buff *a5psw_tag_rcv(struct sk_buff *skb,
if (tag->ctrl_tag != htons(ETH_P_DSA_A5PSW)) {
dev_warn_ratelimited(&dev->dev, "Dropping packet due to invalid TAG marker\n");
+ kfree_skb(skb);
return NULL;
}
port = FIELD_GET(A5PSW_CTRL_DATA_PORT, ntohs(tag->ctrl_data));
skb->dev = dsa_conduit_find_user(dev, 0, port);
- if (!skb->dev)
+ if (!skb->dev) {
+ kfree_skb(skb);
return NULL;
+ }
skb_pull_rcsum(skb, A5PSW_TAG_LEN);
dsa_strip_etype_header(skb, A5PSW_TAG_LEN);
diff --git a/net/dsa/tag_sja1105.c b/net/dsa/tag_sja1105.c
index de6d4ce8668b..bfe1f746f55b 100644
--- a/net/dsa/tag_sja1105.c
+++ b/net/dsa/tag_sja1105.c
@@ -149,19 +149,20 @@ static struct sk_buff *sja1105_defer_xmit(struct dsa_port *dp,
xmit_work_fn = tagger_data->xmit_work_fn;
xmit_worker = priv->xmit_worker;
- if (!xmit_work_fn || !xmit_worker)
+ if (!xmit_work_fn || !xmit_worker) {
+ kfree_skb(skb);
return NULL;
+ }
xmit_work = kzalloc_obj(*xmit_work, GFP_ATOMIC);
- if (!xmit_work)
+ if (!xmit_work) {
+ kfree_skb(skb);
return NULL;
+ }
kthread_init_work(&xmit_work->work, xmit_work_fn);
- /* Increase refcount so the kfree_skb in dsa_user_xmit
- * won't really free the packet.
- */
xmit_work->dp = dp;
- xmit_work->skb = skb_get(skb);
+ xmit_work->skb = skb;
kthread_queue_work(xmit_worker, &xmit_work->work);
@@ -401,10 +402,7 @@ static struct sk_buff
kfree_skb(priv->stampable_skb);
}
- /* Hold a reference to avoid dsa_switch_rcv
- * from freeing the skb.
- */
- priv->stampable_skb = skb_get(skb);
+ priv->stampable_skb = skb;
spin_unlock(&priv->meta_lock);
/* Tell DSA we got nothing */
@@ -436,6 +434,7 @@ static struct sk_buff
dev_err_ratelimited(ds->dev,
"Unexpected meta frame\n");
spin_unlock(&priv->meta_lock);
+ kfree_skb(skb);
return NULL;
}
@@ -443,6 +442,7 @@ static struct sk_buff
dev_err_ratelimited(ds->dev,
"Meta frame on wrong port\n");
spin_unlock(&priv->meta_lock);
+ kfree_skb(skb);
return NULL;
}
@@ -501,18 +501,21 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb,
/* Normal data plane traffic and link-local frames are tagged with
* a tag_8021q VLAN which we have to strip
*/
- if (sja1105_skb_has_tag_8021q(skb))
+ if (sja1105_skb_has_tag_8021q(skb)) {
dsa_8021q_rcv(skb, &source_port, &switch_id, &vbid, &vid);
- else if (source_port == -1 && switch_id == -1)
+ } else if (source_port == -1 && switch_id == -1) {
/* Packets with no source information have no chance of
* getting accepted, drop them straight away.
*/
+ kfree_skb(skb);
return NULL;
+ }
skb->dev = dsa_tag_8021q_find_user(netdev, source_port, switch_id,
vid, vbid);
if (!skb->dev) {
netdev_warn(netdev, "Couldn't decode source port\n");
+ kfree_skb(skb);
return NULL;
}
@@ -539,12 +542,15 @@ static struct sk_buff *sja1110_rcv_meta(struct sk_buff *skb, u16 rx_header)
if (!ds) {
net_err_ratelimited("%s: cannot find switch id %d\n",
conduit->name, switch_id);
+ kfree_skb(skb);
return NULL;
}
tagger_data = sja1105_tagger_data(ds);
- if (!tagger_data->meta_tstamp_handler)
+ if (!tagger_data->meta_tstamp_handler) {
+ kfree_skb(skb);
return NULL;
+ }
for (i = 0; i <= n_ts; i++) {
u8 ts_id, source_port, dir;
@@ -562,6 +568,7 @@ static struct sk_buff *sja1110_rcv_meta(struct sk_buff *skb, u16 rx_header)
}
/* Discard the meta frame, we've consumed the timestamps it contained */
+ kfree_skb(skb);
return NULL;
}
@@ -572,8 +579,10 @@ static struct sk_buff *sja1110_rcv_inband_control_extension(struct sk_buff *skb,
{
u16 rx_header;
- if (unlikely(!pskb_may_pull(skb, SJA1110_HEADER_LEN)))
+ if (unlikely(!pskb_may_pull(skb, SJA1110_HEADER_LEN))) {
+ kfree_skb(skb);
return NULL;
+ }
/* skb->data points to skb_mac_header(skb) + ETH_HLEN, which is exactly
* what we need because the caller has checked the EtherType (which is
@@ -609,8 +618,10 @@ static struct sk_buff *sja1110_rcv_inband_control_extension(struct sk_buff *skb,
* padding and trailer we need to account for the fact that
* skb->data points to skb_mac_header(skb) + ETH_HLEN.
*/
- if (pskb_trim_rcsum(skb, start_of_padding - ETH_HLEN))
+ if (pskb_trim_rcsum(skb, start_of_padding - ETH_HLEN)) {
+ kfree_skb(skb);
return NULL;
+ }
/* Trap-to-host frame, no timestamp trailer */
} else {
*source_port = SJA1110_RX_HEADER_SRC_PORT(rx_header);
@@ -653,6 +664,7 @@ static struct sk_buff *sja1110_rcv(struct sk_buff *skb,
if (!skb->dev) {
netdev_warn(netdev, "Couldn't decode source port\n");
+ kfree_skb(skb);
return NULL;
}
diff --git a/net/dsa/tag_trailer.c b/net/dsa/tag_trailer.c
index 4dce24cfe6a7..49c802c10ca6 100644
--- a/net/dsa/tag_trailer.c
+++ b/net/dsa/tag_trailer.c
@@ -30,22 +30,30 @@ static struct sk_buff *trailer_rcv(struct sk_buff *skb, struct net_device *dev)
u8 *trailer;
int source_port;
- if (skb_linearize(skb))
+ if (skb_linearize(skb)) {
+ kfree_skb(skb);
return NULL;
+ }
trailer = skb_tail_pointer(skb) - 4;
if (trailer[0] != 0x80 || (trailer[1] & 0xf8) != 0x00 ||
- (trailer[2] & 0xef) != 0x00 || trailer[3] != 0x00)
+ (trailer[2] & 0xef) != 0x00 || trailer[3] != 0x00) {
+ kfree_skb(skb);
return NULL;
+ }
source_port = trailer[1] & 7;
skb->dev = dsa_conduit_find_user(dev, 0, source_port);
- if (!skb->dev)
+ if (!skb->dev) {
+ kfree_skb(skb);
return NULL;
+ }
- if (pskb_trim_rcsum(skb, skb->len - 4))
+ if (pskb_trim_rcsum(skb, skb->len - 4)) {
+ kfree_skb(skb);
return NULL;
+ }
return skb;
}
diff --git a/net/dsa/tag_vsc73xx_8021q.c b/net/dsa/tag_vsc73xx_8021q.c
index af121a9aff7f..f4736a1a7a0f 100644
--- a/net/dsa/tag_vsc73xx_8021q.c
+++ b/net/dsa/tag_vsc73xx_8021q.c
@@ -44,6 +44,7 @@ vsc73xx_rcv(struct sk_buff *skb, struct net_device *netdev)
if (!skb->dev) {
dev_warn_ratelimited(&netdev->dev,
"Couldn't decode source port\n");
+ kfree_skb(skb);
return NULL;
}
diff --git a/net/dsa/tag_xrs700x.c b/net/dsa/tag_xrs700x.c
index a05219f702c6..bb268020ee86 100644
--- a/net/dsa/tag_xrs700x.c
+++ b/net/dsa/tag_xrs700x.c
@@ -30,15 +30,21 @@ static struct sk_buff *xrs700x_rcv(struct sk_buff *skb, struct net_device *dev)
source_port = ffs((int)trailer[0]) - 1;
- if (source_port < 0)
+ if (source_port < 0) {
+ kfree_skb(skb);
return NULL;
+ }
skb->dev = dsa_conduit_find_user(dev, 0, source_port);
- if (!skb->dev)
+ if (!skb->dev) {
+ kfree_skb(skb);
return NULL;
+ }
- if (pskb_trim_rcsum(skb, skb->len - 1))
+ if (pskb_trim_rcsum(skb, skb->len - 1)) {
+ kfree_skb(skb);
return NULL;
+ }
/* Frame is forwarded by hardware, don't forward in software. */
dsa_default_offload_fwd_mark(skb);
diff --git a/net/dsa/tag_yt921x.c b/net/dsa/tag_yt921x.c
index f3ced99b1c85..294784ab6694 100644
--- a/net/dsa/tag_yt921x.c
+++ b/net/dsa/tag_yt921x.c
@@ -87,8 +87,10 @@ yt921x_tag_rcv(struct sk_buff *skb, struct net_device *netdev)
__be16 *tag;
u16 rx;
- if (unlikely(!pskb_may_pull(skb, YT921X_TAG_LEN)))
+ if (unlikely(!pskb_may_pull(skb, YT921X_TAG_LEN))) {
+ kfree_skb(skb);
return NULL;
+ }
tag = dsa_etype_header_pos_rx(skb);
@@ -96,6 +98,7 @@ yt921x_tag_rcv(struct sk_buff *skb, struct net_device *netdev)
dev_warn_ratelimited(&netdev->dev,
"Unexpected EtherType 0x%04x\n",
ntohs(tag[0]));
+ kfree_skb(skb);
return NULL;
}
@@ -104,6 +107,7 @@ yt921x_tag_rcv(struct sk_buff *skb, struct net_device *netdev)
if (unlikely((rx & YT921X_TAG_PORT_EN) == 0)) {
dev_warn_ratelimited(&netdev->dev,
"Unexpected rx tag 0x%04x\n", rx);
+ kfree_skb(skb);
return NULL;
}
@@ -112,6 +116,7 @@ yt921x_tag_rcv(struct sk_buff *skb, struct net_device *netdev)
if (unlikely(!skb->dev)) {
dev_warn_ratelimited(&netdev->dev,
"Couldn't decode source port %u\n", port);
+ kfree_skb(skb);
return NULL;
}
diff --git a/net/dsa/user.c b/net/dsa/user.c
index 8704c1a3a5b7..072fa76972cc 100644
--- a/net/dsa/user.c
+++ b/net/dsa/user.c
@@ -935,13 +935,12 @@ static netdev_tx_t dsa_user_xmit(struct sk_buff *skb, struct net_device *dev)
eth_skb_pad(skb);
/* Transmit function may have to reallocate the original SKB,
- * in which case it must have freed it. Only free it here on error.
+ * in which case it must have freed it. Taggers will drop the
+ * passed skb on error.
*/
nskb = p->xmit(skb, dev);
- if (!nskb) {
- kfree_skb(skb);
+ if (!nskb)
return NETDEV_TX_OK;
- }
return dsa_enqueue_skb(nskb, dev);
}
---
base-commit: f34c6b3a3c3d98f34918e1d2ea846a5acccac6d1
change-id: 20260616-dsa-fix-free-skb-bb028ce90802
Best regards,
--
Linus Walleij <linusw@kernel.org>
^ permalink raw reply related
* Re: [PATCH net v2] net: airoha: Fix skb->priority underflow in
From: Joe Damato @ 2026-06-15 22:34 UTC (permalink / raw)
To: Wayen Yan; +Cc: netdev, lorenzo, horms, linux-arm-kernel, linux-mediatek
In-Reply-To: <6a2ff493.5934d26d.389ef4.d16d@mx.google.com>
On Mon, Jun 15, 2026 at 08:48:13PM +0800, Wayen Yan wrote:
> From b894fc031e307f1b6756ea9fcac98e82e23815e1 Mon Sep 17 00:00:00 2001
> From: "Wayen.Yan" <win847@gmail.com>
> Date: Sun, 14 Jun 2026 07:30:54 +0800
> Subject: [PATCH net v2] net: airoha: Fix skb->priority underflow in
> airoha_dev_select_queue()
>
> In airoha_dev_select_queue(), the expression:
>
> queue = (skb->priority - 1) % AIROHA_NUM_QOS_QUEUES;
>
> implicitly converts to unsigned arithmetic: when skb->priority is 0
> (the default for unclassified traffic), (0u - 1u) wraps to UINT_MAX,
> and UINT_MAX % 8 = 7, routing default best-effort packets to the
> highest-priority QoS queue. This causes QoS inversion where the
> majority of traffic on a PON gateway starves actual high-priority
> flows (VoIP, gaming, etc.).
>
> Fix by guarding the subtraction: when priority is 0, map to queue 0
> (lowest priority), otherwise apply the original (priority - 1) % 8
> mapping.
>
> Fixes: 2b288b81560b ("net: airoha: Introduce ndo_select_queue callback")
> Acked-by: Lorenzo Bianconi <lorenzo@kernel.org>
> Signed-off-by: Wayen <win847@gmail.com>
> ---
> drivers/net/ethernet/airoha/airoha_eth.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
Hm, I tried to apply this patch to my tree just to see what would happen with
the duplicated SMTP headers and it looks like they just get added to the
commit message.
I think you might need to re-send it (but you'll have to wait 24 hours between
re-sends).
The code looks fine to me, though, so feel free to include my tag:
Reviewed-by: Joe Damato <joe@dama.to>
^ permalink raw reply
* Re: [PATCH] net: airoha: Fix always-true condition in PPE1 queue reservation loop
From: patchwork-bot+netdevbpf @ 2026-06-15 22:50 UTC (permalink / raw)
To: Wayen Yan
Cc: netdev, lorenzo, horms, pabeni, kuba, edumazet, andrew+netdev,
angelogioacchino.delregno, matthias.bgg, linux-arm-kernel,
linux-mediatek
In-Reply-To: <6a2ca3de.ad59c0a6.147df9.2ac1@mx.google.com>
Hello:
This patch was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Sat, 13 Jun 2026 08:23:12 +0800 you wrote:
> In airoha_fe_pse_ports_init(), the inner condition for PPE1 queue
> reservation is identical to the for-loop bound, making it always true
> and the else branch dead code:
>
> for (q = 0; q < pse_port_num_queues[FE_PSE_PORT_PPE1]; q++) {
> if (q < pse_port_num_queues[FE_PSE_PORT_PPE1]) /* always true */
> set RSV_PAGES;
> else
> set 0; /* unreachable */
> }
>
> [...]
Here is the summary with links:
- net: airoha: Fix always-true condition in PPE1 queue reservation loop
https://git.kernel.org/netdev/net/c/c66f8511a810
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH net-next v2 0/3] docs: net: more adjustments to docs
From: patchwork-bot+netdevbpf @ 2026-06-15 22:50 UTC (permalink / raw)
To: Jakub Kicinski
Cc: davem, netdev, edumazet, pabeni, andrew+netdev, horms, corbet,
linux-doc, john.fastabend, sd, jiri
In-Reply-To: <20260613165846.2913092-1-kuba@kernel.org>
Hello:
This series was applied to netdev/net-next.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Sat, 13 Jun 2026 09:58:43 -0700 you wrote:
> A few small updates to the docs.
> This is trying to prepare docs for getting fed directly
> into AI reviews.
>
> v2:
> - fixes in the tls offload patch
> - add the strparser patch in place of the already applied XDP md one
> v1: https://lore.kernel.org/20260609201224.1191391-1-kuba@kernel.org
>
> [...]
Here is the summary with links:
- [net-next,v2,1/3] docs: net: tls-offload: document tls_dev_del, tls_dev_resync, and rekey
https://git.kernel.org/netdev/net-next/c/c8ee634048dd
- [net-next,v2,2/3] docs: net: fix minor issues with devlink docs
https://git.kernel.org/netdev/net-next/c/e504cf18ef47
- [net-next,v2,3/3] docs: net: fix minor issues with strparser docs
https://git.kernel.org/netdev/net-next/c/d9e4dd3c6f1f
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH net-next v5 0/12] net: atlantic: add PTP support for AQC113 (Antigua)
From: patchwork-bot+netdevbpf @ 2026-06-15 22:50 UTC (permalink / raw)
To: Sukhdeep
Cc: netdev, andrew+netdev, davem, edumazet, kuba, pabeni,
linux-kernel, horms, vadim.fedorenko
In-Reply-To: <20260610115448.272-1-sukhdeeps@marvell.com>
Hello:
This series was applied to netdev/net-next.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Wed, 10 Jun 2026 17:24:36 +0530 you wrote:
> From: Sukhdeep Singh <sukhdeeps@marvell.com>
>
> This series adds IEEE 1588 PTP support for the AQC113 (Antigua) network
> controller. AQC113 is the successor to the existing AQC107 (Atlantic)
> chip already supported by the atlantic driver.
>
> AQC113 uses a substantially different hardware architecture for PTP
> compared to AQC107:
>
> [...]
Here is the summary with links:
- [net-next,v5,1/12] net: atlantic: correct L3L4 filter flow_type masking and IPv6 handling
https://git.kernel.org/netdev/net-next/c/9ed479cd9fd3
- [net-next,v5,2/12] net: atlantic: move active_ipv4/ipv6 bitmap updates after HW write
https://git.kernel.org/netdev/net-next/c/dfb7a7468b94
- [net-next,v5,3/12] net: atlantic: decouple aq_set_data_fl3l4() from driver internals
https://git.kernel.org/netdev/net-next/c/7bd18209741f
- [net-next,v5,4/12] net: atlantic: add AQC113 hardware register definitions and accessors
https://git.kernel.org/netdev/net-next/c/228c40913220
- [net-next,v5,5/12] net: atlantic: add AQC113 filter data structures, firmware query and register dump
https://git.kernel.org/netdev/net-next/c/4428d3b99414
- [net-next,v5,6/12] net: atlantic: fix AQC113 HW init: ART, L2 filter slot, MAC address
https://git.kernel.org/netdev/net-next/c/6c1ca112a6e4
- [net-next,v5,7/12] net: atlantic: implement AQC113 L2/L3/L4 RX filter ops
https://git.kernel.org/netdev/net-next/c/ddce0b1bc002
- [net-next,v5,8/12] net: atlantic: add AQC113 PTP traffic class and TX path setup
https://git.kernel.org/netdev/net-next/c/5e7c8f8e96b4
- [net-next,v5,9/12] net: atlantic: extend hw_ops and TX descriptor for AQC113 PTP
https://git.kernel.org/netdev/net-next/c/f4f2bfe2b2ea
- [net-next,v5,10/12] net: atlantic: add AQC113 PTP hardware ops in hw_atl2
https://git.kernel.org/netdev/net-next/c/f6a7a4bcc5d3
- [net-next,v5,11/12] net: atlantic: add AQC113 TX timestamp polling and PTP TX classification
https://git.kernel.org/netdev/net-next/c/da8222888659
- [net-next,v5,12/12] net: atlantic: add AQC113 PTP support in aq_ptp and driver core
https://git.kernel.org/netdev/net-next/c/0384ba231868
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH] net: airoha: Fix typos in comments and Kconfig
From: patchwork-bot+netdevbpf @ 2026-06-15 22:50 UTC (permalink / raw)
To: Wayen Yan
Cc: netdev, lorenzo, horms, pabeni, kuba, edumazet, andrew+netdev,
angelogioacchino.delregno, matthias.bgg, linux-arm-kernel,
linux-mediatek
In-Reply-To: <6a2ca74a.c5b1db4e.21a698.01e7@mx.google.com>
Hello:
This patch was applied to netdev/net-next.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Sat, 13 Jun 2026 08:41:16 +0800 you wrote:
> Fix several typos found during code review:
> - Kconfig: "Aiorha" -> "Airoha" in NET_AIROHA_FLOW_STATS help text
> - Comment: "CMD1" -> "CDM1" (Central DMA, not Command)
> - Comments: "GMD1/2/3/4" -> "GDM1/2/3/4" (Gigabit DMA, not GMD)
>
> These are pure comment and documentation fixes with no functional impact.
>
> [...]
Here is the summary with links:
- net: airoha: Fix typos in comments and Kconfig
https://git.kernel.org/netdev/net-next/c/a061dfb063fa
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH] net: airoha: Fix non-standard return value in airoha_ppe_get_wdma_info()
From: patchwork-bot+netdevbpf @ 2026-06-15 22:50 UTC (permalink / raw)
To: Wayen Yan
Cc: netdev, lorenzo, horms, pabeni, kuba, edumazet, andrew+netdev,
angelogioacchino.delregno, matthias.bgg, linux-arm-kernel,
linux-mediatek
In-Reply-To: <6a2ca3d9.ad59c0a6.147df9.2a62@mx.google.com>
Hello:
This patch was applied to netdev/net-next.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Sat, 13 Jun 2026 08:22:31 +0800 you wrote:
> airoha_ppe_get_wdma_info() returns -1 when the last path in the
> forwarding path stack is not of type DEV_PATH_MTK_WDMA. This is not
> a standard kernel error code. Replace it with -EINVAL since the
> input path type is invalid from the caller's perspective.
>
> Fixes: 23020f049327 ("net: airoha: Introduce ethernet support for EN7581 SoC")
> Signed-off-by: Wayen.Yan <win847@gmail.com>
>
> [...]
Here is the summary with links:
- net: airoha: Fix non-standard return value in airoha_ppe_get_wdma_info()
https://git.kernel.org/netdev/net-next/c/05173fa30add
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH] net/mlx5: HWS: correct CONFIG_MLX5_HW_STEERING macro name in comment
From: patchwork-bot+netdevbpf @ 2026-06-15 22:50 UTC (permalink / raw)
To: Ethan Nelson-Moore
Cc: netdev, linux-rdma, saeedm, leon, tariqt, mbloch, andrew+netdev,
davem, edumazet, kuba, pabeni
In-Reply-To: <20260613225904.140791-1-enelsonmoore@gmail.com>
Hello:
This patch was applied to netdev/net-next.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Sat, 13 Jun 2026 15:59:00 -0700 you wrote:
> A comment in
> drivers/net/ethernet/mellanox/mlx5/core/steering/hws/fs_hws.h
> incorrectly refers to CONFIG_MLX5_HWS_STEERING instead of
> CONFIG_MLX5_HW_STEERING. Correct it.
>
> Discovered while searching for CONFIG_* symbols referenced in code but
> not defined in any Kconfig file.
>
> [...]
Here is the summary with links:
- net/mlx5: HWS: correct CONFIG_MLX5_HW_STEERING macro name in comment
https://git.kernel.org/netdev/net-next/c/952d66f16dcd
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH net-next v2 3/3] docs: net: fix minor issues with strparser docs
From: Sabrina Dubroca @ 2026-06-15 22:51 UTC (permalink / raw)
To: Jakub Kicinski
Cc: davem, netdev, edumazet, pabeni, andrew+netdev, horms, corbet,
linux-doc, john.fastabend, jiri, skhan
In-Reply-To: <20260613165846.2913092-4-kuba@kernel.org>
2026-06-13, 09:58:46 -0700, Jakub Kicinski wrote:
> Not sure if anyone would read this doc, but the API has evolved
> since it was written. Update to:
> - show the int return type for strp_init()
> - refer to strp_data_ready(), not the old strp_tcp_data_ready() name
> - direct users to strp_msg(skb) for strparser metadata instead of
> treating skb->cb as struct strp_msg directly
>
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> ---
> CC: corbet@lwn.net
> CC: skhan@linuxfoundation.org
> CC: linux-doc@vger.kernel.org
> ---
> Documentation/networking/strparser.rst | 22 +++++++++++-----------
> 1 file changed, 11 insertions(+), 11 deletions(-)
Reviewed-by: Sabrina Dubroca <sd@queasysnail.net>
> @@ -123,9 +123,9 @@ Callbacks
> should parse the sk_buff as containing the headers for the
> next application layer message in the stream.
Last time I had a look at strp, I was thinking about removing half of
the callbacks, since they're never used. Not a big simplification, but
it would remove a few indirections when reading the code.
--
Sabrina
^ permalink raw reply
* Re: [PATCH stable 6.6.y v3 0/4] bpf: linked scalar precision fixes
From: Paul Chaignon @ 2026-06-15 22:51 UTC (permalink / raw)
To: Zhenzhong Wu
Cc: bpf, netdev, linux-kernel, ast, daniel, john.fastabend, andrii,
martin.lau, song, yonghong.song, kpsingh, haoluo, jolsa,
menglong8.dong, eddyz87, shung-hsi.yu, stable, mykolal, tamird,
Sasha Levin
In-Reply-To: <cover.1781194510.git.jt26wzz@gmail.com>
On Mon, Jun 15, 2026 at 12:58:37AM +0800, Zhenzhong Wu wrote:
> Hi,
>
> This v3 targets 6.6.y and changes the backport strategy based on review
> feedback on v2.
[...]
> Relevant QEMU selftest results on 6.6.y with this backport:
>
> verifier_scalar_ids passed all 18 subtests, including the newly
> backported linked-scalar precision tests and the related
> check_ids_in_regsafe tests.
The first patch in this backport series is actually breaking the
"precise: test 1" selftest from test_verifier. You can see the full
error at [1]. I haven't yet checked if it's the test or the backport
that needs to be adjusted.
1: https://github.com/shunghsiyu/libbpf/actions/runs/27575831217/job/81523786835
>
> Thanks to Shung-Hsi Yu for reviewing v2 and suggesting the upstream
> linked-scalar precision series as the preferred backport direction.
>
> Eduard Zingerman (4):
> bpf: Track equal scalars history on per-instruction level
> bpf: Remove mark_precise_scalar_ids()
> selftests/bpf: Tests for per-insn sync_linked_regs() precision
> tracking
> selftests/bpf: Update comments find_equal_scalars->sync_linked_regs
>
> include/linux/bpf_verifier.h | 4 +
> kernel/bpf/verifier.c | 367 +++++++++++-------
> .../selftests/bpf/progs/verifier_scalar_ids.c | 253 ++++++++----
> .../selftests/bpf/progs/verifier_spill_fill.c | 4 +-
> .../bpf/progs/verifier_subprog_precision.c | 2 +-
> .../testing/selftests/bpf/verifier/precise.c | 2 +-
> 6 files changed, 417 insertions(+), 215 deletions(-)
>
>
> base-commit: 924b4a879cbb75aef37c160b955b92f6894b11a4
> --
> 2.43.0
^ permalink raw reply
* Re: [PATCH] sctp: correct CONFIG_SCTP_DBG_OBJCNT macro name in comment
From: patchwork-bot+netdevbpf @ 2026-06-15 23:00 UTC (permalink / raw)
To: Ethan Nelson-Moore
Cc: horms, linux-sctp, netdev, marcelo.leitner, lucien.xin, davem,
edumazet, kuba, pabeni
In-Reply-To: <20260613233725.162470-1-enelsonmoore@gmail.com>
Hello:
This patch was applied to netdev/net-next.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Sat, 13 Jun 2026 16:37:25 -0700 you wrote:
> A comment in <net/sctp/sctp.h> incorrectly refers to
> CONFIG_SCTP_DBG_OBJCOUNT instead of CONFIG_SCTP_DBG_OBJCNT. Correct it.
>
> Discovered while searching for CONFIG_* symbols referenced in code but
> not defined in any Kconfig file.
>
> Signed-off-by: Ethan Nelson-Moore <enelsonmoore@gmail.com>
>
> [...]
Here is the summary with links:
- sctp: correct CONFIG_SCTP_DBG_OBJCNT macro name in comment
https://git.kernel.org/netdev/net-next/c/eb82367bca56
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH] net: airoha: Fix MODULE_LICENSE to match SPDX GPL-2.0-only identifier
From: patchwork-bot+netdevbpf @ 2026-06-15 23:00 UTC (permalink / raw)
To: Wayen Yan
Cc: netdev, lorenzo, horms, pabeni, kuba, edumazet, andrew+netdev,
angelogioacchino.delregno, matthias.bgg, linux-arm-kernel,
linux-mediatek
In-Reply-To: <6a2ded59.63d39acb.391892.7632@mx.google.com>
Hello:
This patch was applied to netdev/net-next.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Sun, 14 Jun 2026 07:52:39 +0800 you wrote:
> Both airoha_eth.c and airoha_npu.c declare SPDX-License-Identifier:
> GPL-2.0-only but use MODULE_LICENSE("GPL"), which the kernel module
> loader interprets as GPL-2.0+ (any GPL version). This mismatch causes
> license compliance tools (FOSSology, ScanCode, etc.) to misidentify
> the effective license as more permissive than intended.
>
> Replace MODULE_LICENSE("GPL") with MODULE_LICENSE("GPL v2") to
> align with the GPL-2.0-only SPDX identifier. Per include/linux/module.h,
> "GPL v2" maps to GPL-2.0-only, matching the source files' declared
> license.
>
> [...]
Here is the summary with links:
- net: airoha: Fix MODULE_LICENSE to match SPDX GPL-2.0-only identifier
https://git.kernel.org/netdev/net-next/c/b0d62ed16424
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* [ANNOUNCE] iproute2 7.1 release
From: Stephen Hemminger @ 2026-06-15 23:06 UTC (permalink / raw)
To: netdev
This is the regular release of iproute2 corresponding to the 7.1 kernel.
The main theme this cycle is wider JSON output coverage. Victor
Nogueira added JSON support to the HFSC, QFQ, and multiq
qdiscs. Matthieu Baerts added JSON to the timestamp helper and MPTCP
monitor, and Vitaly Grinberg changed dpll monitor mode to send one
object per event in JSON.
The dpll command saw the most feature work. Petr Oros added
client-side filtering for device and pin show, including filtering
pins by parent-device, parent-pin, direction, and state, and aligned
the help and man page notation with the actual option parsing. Ivan
Vecera fixed several man page correctness issues.
Michael Guralnik added FRMR pools support to rdma, with a show command
and set commands for aging and pinned, aligned to the merged kernel
UAPI. Ioana Lazea enabled 64-bit burst values for tc-tbf and
tc-htb. Eric Dumazet added support for TCP delack timers to ss and
forced a flush in monitor mode.
Smaller changes: Justin Iurman added seg6 tunsrc support in lwtunnel
with updated encap documentation; Matthieu Baerts made MPTCP stream
closure uniform; Hangbin Liu added actor and partner churn state to
bond slave output; Jiri Pirko showed the devlink instance index in dev
output and added an mnl_attr_get_uint() fallback; and the obsolete
hamradio protocols were removed. Kernel headers were refreshed by
David Ahern.
One behavior change worth noting for packagers and scripters:
libnetlink now flushes stdout only in monitor mode, pairing with the ss monitor flush change.
Download:
https://www.kernel.org/pub/linux/utils/net/iproute2/iproute2-7.1.0.tar.gz
Repository for current release:
https://github.com/shemminger/iproute2.git
git://git.kernel.org/pub/scm/network/iproute2/iproute2.git
And future release (net-next):
git://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git
David Ahern (3):
Update kernel headers
Update kernel headers
Update kernel headers
Eric Dumazet (2):
ss: add support for TCP delack timers
ss: force a flush in monitor mode
Hangbin Liu (1):
iplink: bond_slave: print actor and partner churn state
Ioana Lazea (2):
tc/tbf: enable use of 64 bit burst
tc/htb: enable use of 64 bit burst
Ivan Vecera (1):
dpll: fix man page correctness issues
Jiri Pirko (2):
mnl: add fallback implementation for mnl_attr_get_uint()
devlink: show devlink instance index in dev output
Justin Iurman (2):
seg6: add tunsrc support in iproute_lwtunnel
man8: update seg6 encap documentation
Matthieu Baerts (NGI0) (3):
mptcp: uniform stream closure
utils: timestamp: add JSON support
mptcp: monitor: add JSON support
Michael Guralnik (5):
rdma: Update headers
rdma: Add resource FRMR pools show command
rdma: Add FRMR pools set aging command
rdma: Add FRMR pools set pinned command
rdma: Align FRMR pool UAPI names with merged kernel UAPI
Petr Oros (5):
dpll: add client-side filtering for device show
dpll: add client-side filtering for pin show
dpll: add pin filtering by parent-device and parent-pin
dpll: add direction and state filtering for pin show
dpll: align help and man notation with actual option parsing
Stephen Hemminger (4):
uapi: update to 7.1-rc1
remove hamradio protocols
libnetlink: flush stdout only in monitor mode
v7.1.0
Victor Nogueira (3):
tc: Add JSON output support to HFSC
tc: Add JSON output support to QFQ
tc: Add JSON output support to multiq
Vitaly Grinberg (1):
dpll: Send object per event in JSON monitor mode
^ permalink raw reply
* Re: [PATCH net-next v7 1/2] net: ti: icssg-prueth: Add Frame Preemption MAC Merge support
From: Jakub Kicinski @ 2026-06-15 23:10 UTC (permalink / raw)
To: m-malladi
Cc: Jakub Kicinski, elfring, haokexin, vadim.fedorenko, devnexen,
horms, jacob.e.keller, arnd, basharath, afd, parvathi,
vladimir.oltean, rogerq, danishanwar, pabeni, edumazet, davem,
andrew+netdev, linux-arm-kernel, netdev, linux-kernel, srk,
vigneshr
In-Reply-To: <20260610052511.781752-2-m-malladi@ti.com>
This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
---
net: ti: icssg-prueth: Add Frame Preemption MAC Merge support
This patch adds QoS infrastructure for Frame Preemption (FPE) in the
ICSSG Ethernet driver, including a verify state machine driver helper,
mqprio-based preemptible-tc mapping, and a link-state callback. A
follow-up patch in this series wires this up to ethtool's MAC Merge ops.
> diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
> --- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c
> +++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
> @@ -392,6 +392,8 @@ static void emac_adjust_link(struct net_device *ndev)
> } else {
> icssg_set_port_state(emac, ICSSG_EMAC_PORT_DISABLE);
> }
> +
> + icssg_qos_link_state_update(ndev);
> }
[Medium]
emac_adjust_link() sets emac->link = 0 before reaching this call. Inside
icssg_qos_link_state_update() -> icssg_iet_change_preemptible_tcs() ->
icssg_config_ietfpe(), the very first check is:
if (!emac->link) {
netdev_dbg(ndev, "cannot change IET/FPE state ... \n");
return 0;
}
so on a link-down the IET path returns early without clearing
iet->fpe_active or iet->verify_status, even though firmware has already
been told ICSSG_EMAC_PORT_DISABLE just above. After the follow-up patch
adds get_mm(), would ethtool then report stale tx_active=true and a
stale verify_status while the link is down?
The commit message states:
Verify state machine re-triggers on link up/down events based on
fpe_enabled and fpe_active flags
Is the link-down half of that contract implemented anywhere?
[Medium]
A related question on the locking design: emac->link is written here by
emac_adjust_link() without taking iet->fpe_lock, but icssg_config_ietfpe()
reads emac->link inside the fpe_lock-held critical section. The lockset
for writers and readers is disjoint, so fpe_lock does not actually
serialize emac->link.
Can the following interleaving occur?
CPU0 (ndo_setup_tc) CPU1 (emac_adjust_link)
mutex_lock(&iet->fpe_lock);
reads emac->link == 1
emac->link = 0;
icssg_set_port_state(... DISABLE);
proceeds to write FPE regs
and issue PREMPT_TX_ENABLE
mutex_unlock(&iet->fpe_lock);
icssg_qos_link_state_update();
sees emac->link == 0, returns
leaving stale FPE writes on a port the firmware has just disabled? The
commit message says "fpe_lock serializes all FPE state mutations" but
emac->link is one of those mutations and is not covered.
> diff --git a/drivers/net/ethernet/ti/icssg/icssg_qos.c b/drivers/net/ethernet/ti/icssg/icssg_qos.c
> new file mode 100644
> --- /dev/null
> +++ b/drivers/net/ethernet/ti/icssg/icssg_qos.c
> @@ -0,0 +1,282 @@
[ ... ]
> +static int icssg_iet_verify_wait(struct prueth_emac *emac)
> +{
> + void __iomem *config = emac->dram.va + ICSSG_CONFIG_OFFSET;
> + struct prueth_qos_iet *iet = &emac->qos.iet;
> + unsigned long delay_us, timeout_us;
> + u32 status;
> + int ret;
> +
> + delay_us = iet->verify_time_ms * 1000;
> + timeout_us = delay_us * ICSSG_IET_VERIFY_ATTEMPTS;
> +
> + ret = readb_poll_timeout(config + PRE_EMPTION_VERIFY_STATUS,
> + status,
> + status == ICSSG_IETFPE_STATE_SUCCEEDED,
> + delay_us,
> + timeout_us);
> +
> + iet->verify_status = status;
> + return ret;
> +}
[High]
With ICSSG_IET_MAX_VERIFY_TIME = 128 and ICSSG_IET_VERIFY_ATTEMPTS = 3,
this can sleep for up to 384ms while iet->fpe_lock is held. fpe_lock is
acquired by icssg_iet_change_preemptible_tcs() from two paths:
- emac_tc_setup_mqprio() via .ndo_setup_tc, called with RTNL held.
- icssg_qos_link_state_update() from emac_adjust_link(), invoked by
phylib with phydev->lock held (prueth_emac_common_start()
explicitly does mutex_lock(phydev->lock) before calling
emac_adjust_link).
Once the follow-up patch wires set_mm() to write iet->mac_verify_configure,
this sleep becomes reachable from any user with CAP_NET_ADMIN. Should
the verify wait be deferred to a workqueue or a completion driven by a
firmware notification rather than block under RTNL / phydev->lock for
hundreds of milliseconds? Other drivers with MAC Merge support
(e.g. fec, stmmac) take the deferred-work approach for the same reason.
[Low]
The condition only breaks on ICSSG_IETFPE_STATE_SUCCEEDED, but the enum
also defines a distinct ICSSG_IETFPE_STATE_FAILED value reported by
firmware on a definitive verify failure. With the current condition,
would a FAILED state cause the loop to keep polling for the entire
timeout and then surface as:
netdev_err(ndev, "MAC Verification failed with timeout\n");
even though it was not actually a timeout? Could the cond also break on
FAILED so the caller can distinguish the two?
> +int icssg_config_ietfpe(struct net_device *ndev, bool enable)
> +{
> + struct prueth_emac *emac = netdev_priv(ndev);
> + void __iomem *config = emac->dram.va + ICSSG_CONFIG_OFFSET;
> + struct prueth_qos_iet *iet = &emac->qos.iet;
> + int ret;
> + u8 val;
> +
> + lockdep_assert_held(&iet->fpe_lock);
> +
> + if (!emac->link) {
> + netdev_dbg(ndev, "cannot change IET/FPE state when interface is down\n");
> + return 0;
> + }
[ ... ]
> + if (enable && iet->mac_verify_configure) {
> + ret = icssg_iet_verify_wait(emac);
> + if (ret) {
> + netdev_err(ndev, "MAC Verification failed with timeout\n");
> + goto disable_tx;
> + }
> + } else if (enable) {
> + /* Give firmware some time to update
> + * PRE_EMPTION_ACTIVE_TX state
> + */
> + usleep_range(100, 200);
> + }
> +
> + if (enable) {
> + val = readb(config + PRE_EMPTION_ACTIVE_TX);
> + if (val != 1) {
> + netdev_err(ndev,
> + "Firmware fails to activate IET/FPE\n");
> + ret = -EIO;
> + goto disable_tx;
> + }
> + iet->fpe_active = true;
> + } else {
> + iet->fpe_active = false;
> + }
> +
> + icssg_iet_set_preempt_mask(emac);
> + netdev_dbg(ndev, "IET FPE %s successfully\n",
> + str_enable_disable(enable));
> + return 0;
> +
> +disable_tx:
> + icssg_set_port_state(emac, ICSSG_EMAC_PORT_PREMPT_TX_DISABLE);
> +fallback:
> + writeb(0, config + PRE_EMPTION_ENABLE_TX);
> + writeb(0, config + PRE_EMPTION_ENABLE_VERIFY);
> + iet->verify_status = ICSSG_IETFPE_STATE_DISABLED;
> + iet->fpe_active = false;
> + return ret;
> +}
[Medium]
icssg_set_port_state() only synchronizes the R30 command-done handshake;
it does not guarantee firmware has finished updating the
PRE_EMPTION_ACTIVE_TX status byte. Is a 100-200us sleep a documented
worst-case latency for firmware to publish that byte under load
(concurrent Rx, TAS, FDB ageing, link events)?
If the byte has not yet been written, this code returns -EIO,
mischaracterizing it as "Firmware fails to activate IET/FPE", and the
fallback path then writes PRE_EMPTION_ENABLE_TX = 0, defeating the
user's enable. icssg_iet_verify_wait() already uses
readb_poll_timeout() for an analogous status byte; could the same
pattern be applied here with a small millisecond-range timeout?
[Medium]
The success path always calls icssg_iet_set_preempt_mask(), and on
fpe_active=false that helper takes the reset_hw branch and clears all
per-queue BIT(4) preemptive markers. The disable_tx and fallback paths
do not call icssg_iet_set_preempt_mask().
If FPE was previously active (so EXPRESS_PRE_EMPTIVE_Q_MAP[i] = BIT(4)
on some queues) and a subsequent reconfigure fails (verify timeout, or
PRE_EMPTION_ACTIVE_TX != 1), the failure paths only clear
PRE_EMPTION_ENABLE_TX / PRE_EMPTION_ENABLE_VERIFY but leave the
per-queue map and the EXPRESS_PRE_EMPTIVE_Q_MASK with stale preemptive
bits. Should the failure paths also call icssg_iet_set_preempt_mask()
(after iet->fpe_active is set to false) to keep the queue map and the
TX-enable bit consistent?
[ ... ]
> +EXPORT_SYMBOL_GPL(icssg_qos_init);
[ ... ]
> +EXPORT_SYMBOL_GPL(icssg_qos_ndo_setup_tc);
[ ... ]
> +EXPORT_SYMBOL_GPL(icssg_qos_link_state_update);
[Low]
Per the Makefile change in this patch:
icssg-y := icssg/icssg_common.o \
...
icssg/icssg_ethtool.o \
icssg/icssg_qos.o
icssg_qos.o is linked into the same icssg.ko module as the only callers
(icssg_prueth.c and icssg_common.c). Are there cross-module consumers
that need these symbols exported, or can the EXPORT_SYMBOL_GPL lines be
dropped since EXPORT_SYMBOL_GPL is only required for cross-module
linkage?
--
pw-bot: cr
^ permalink raw reply
* Re: [PATCH net-next v7 2/2] net: ti: icssg-prueth: Add ethtool ops for Frame Preemption MAC Merge
From: Jakub Kicinski @ 2026-06-15 23:10 UTC (permalink / raw)
To: m-malladi
Cc: Jakub Kicinski, elfring, haokexin, vadim.fedorenko, devnexen,
horms, jacob.e.keller, arnd, basharath, afd, parvathi,
vladimir.oltean, rogerq, danishanwar, pabeni, edumazet, davem,
andrew+netdev, linux-arm-kernel, netdev, linux-kernel, srk,
vigneshr
In-Reply-To: <20260610052511.781752-3-m-malladi@ti.com>
This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
---
Subject: net: ti: icssg-prueth: Add ethtool ops for Frame Preemption MAC Merge
This patch wires up the ethtool MAC Merge ops (.get_mm, .set_mm,
.get_mm_stats) for the ICSSG PRU Ethernet driver and adds five firmware
preemption counters that feed both the new MM stats and the existing
ethtool -S table.
> diff --git a/drivers/net/ethernet/ti/icssg/icssg_ethtool.c b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c
> index b715af21d23a..0620782318ab 100644
> --- a/drivers/net/ethernet/ti/icssg/icssg_ethtool.c
> +++ b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c
> @@ -294,6 +294,103 @@ static int emac_set_per_queue_coalesce(struct net_device *ndev, u32 queue,
[ ... ]
> +static int emac_set_mm(struct net_device *ndev, struct ethtool_mm_cfg *cfg,
> + struct netlink_ext_ack *extack)
> +{
> + struct prueth_emac *emac = netdev_priv(ndev);
> + struct prueth_qos_iet *iet = &emac->qos.iet;
> + int err;
> +
> + if (emac->is_sr1)
> + return -EOPNOTSUPP;
> +
> + if (!cfg->pmac_enabled) {
> + NL_SET_ERR_MSG_MOD(extack, "preemptible MAC is always enabled");
> + return -EOPNOTSUPP;
> + }
> +
> + mutex_lock(&iet->fpe_lock);
> + iet->verify_time_ms = cfg->verify_time;
> + iet->tx_min_frag_size = cfg->tx_min_frag_size;
> + iet->fpe_enabled = cfg->tx_enabled;
> + iet->mac_verify_configure = cfg->verify_enabled;
> + err = icssg_config_ietfpe(ndev, cfg->tx_enabled);
> + mutex_unlock(&iet->fpe_lock);
> +
> + return err;
> +}
[Medium]
Can the cached software state in iet diverge from the hardware here when
icssg_config_ietfpe() fails?
The new fields (verify_time_ms, tx_min_frag_size, fpe_enabled,
mac_verify_configure) are written to iet before icssg_config_ietfpe() is
called, but the error paths in icssg_config_ietfpe() only roll back a
subset of state:
icssg_qos.c:icssg_config_ietfpe() {
...
disable_tx:
icssg_set_port_state(emac, ICSSG_EMAC_PORT_PREMPT_TX_DISABLE);
fallback:
writeb(0, config + PRE_EMPTION_ENABLE_TX);
writeb(0, config + PRE_EMPTION_ENABLE_VERIFY);
iet->verify_status = ICSSG_IETFPE_STATE_DISABLED;
iet->fpe_active = false;
return ret;
}
iet->fpe_enabled is left set to cfg->tx_enabled even though the hardware
TX preempt path has been disabled.
Two follow-on effects appear to come from this:
emac_get_mm() reports state->tx_enabled = iet->fpe_enabled, so userspace
sees tx_enabled=true after a set_mm that returned an error and left FPE
disabled in hardware.
icssg_qos_link_state_update() drives icssg_iet_change_preemptible_tcs(),
which calls icssg_config_ietfpe(emac->ndev, iet->fpe_enabled) on every
link transition, so the failed configuration is retried each link-up
without further user action.
Would it make sense to stage cfg into local variables, only commit them
to iet after icssg_config_ietfpe() returns success, or otherwise
restore the previous iet fields on the error return?
> +static void emac_get_mm_stats(struct net_device *ndev,
> + struct ethtool_mm_stats *s)
> +{
> + struct prueth_emac *emac = netdev_priv(ndev);
> +
> + if (emac->is_sr1)
> + return;
> +
> + if (!emac->prueth->pa_stats)
> + return;
> +
> + emac_update_hardware_stats(emac);
> +
> + /* MACMergeHoldCount stats is not tracked by the firmware */
> + s->MACMergeFrameAssOkCount = emac_get_stat_by_name(emac, "FW_PREEMPT_ASSEMBLY_OK");
> + s->MACMergeFrameAssErrorCount = emac_get_stat_by_name(emac, "FW_PREEMPT_ASSEMBLY_ERR");
> + s->MACMergeFragCountRx = emac_get_stat_by_name(emac, "FW_PREEMPT_FRAG_CNT_RX");
> + s->MACMergeFragCountTx = emac_get_stat_by_name(emac, "FW_PREEMPT_FRAG_CNT_TX");
> + s->MACMergeFrameSmdErrorCount = emac_get_stat_by_name(emac, "FW_PREEMPT_BAD_FRAG");
> +}
[ ... ]
> diff --git a/drivers/net/ethernet/ti/icssg/icssg_stats.h b/drivers/net/ethernet/ti/icssg/icssg_stats.h
> index 5ec0b38e0c67..8073deac35c3 100644
> --- a/drivers/net/ethernet/ti/icssg/icssg_stats.h
> +++ b/drivers/net/ethernet/ti/icssg/icssg_stats.h
> @@ -189,6 +187,11 @@ static const struct icssg_pa_stats icssg_all_pa_stats[] = {
> ICSSG_PA_STATS(FW_INF_DROP_PRIOTAGGED),
> ICSSG_PA_STATS(FW_INF_DROP_NOTAG),
> ICSSG_PA_STATS(FW_INF_DROP_NOTMEMBER),
> + ICSSG_PA_STATS(FW_PREEMPT_BAD_FRAG),
> + ICSSG_PA_STATS(FW_PREEMPT_ASSEMBLY_ERR),
> + ICSSG_PA_STATS(FW_PREEMPT_FRAG_CNT_TX),
> + ICSSG_PA_STATS(FW_PREEMPT_ASSEMBLY_OK),
> + ICSSG_PA_STATS(FW_PREEMPT_FRAG_CNT_RX),
> ICSSG_PA_STATS(FW_RX_EOF_SHORT_FRMERR),
> ICSSG_PA_STATS(FW_RX_B0_DROP_EARLY_EOF),
> ICSSG_PA_STATS(FW_TX_JUMBO_FRM_CUTOFF),
[Medium]
Are these five new entries duplicating values that already have a
standard uAPI?
The same five firmware counters are exposed through the new
.get_mm_stats callback as the standardized MAC Merge stats
(MACMergeFrameAssOkCount, MACMergeFrameAssErrorCount, MACMergeFragCountRx,
MACMergeFragCountTx, MACMergeFrameSmdErrorCount in struct
ethtool_mm_stats), and adding them to icssg_all_pa_stats[] also
publishes them via emac_get_strings() / emac_get_ethtool_stats() as
ethtool -S strings.
Documentation/networking/statistics.rst describes ethtool -S as the
private-driver-stats interface; counters that have a standard uAPI are
expected to flow only through that uAPI.
Could the firmware-register lookup table used by emac_get_stat_by_name()
be separated from the ethtool -S string table, so the new preemption
counters feed get_mm_stats without also showing up under ethtool -S?
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox