Linux USB
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Birger Koblitz" <mail@birger-koblitz.de>
Cc: linux-usb@vger.kernel.org
Subject: Re: [PATCH net-next v20 07/13] ax88179_178a: Add VLAN offload support for AX88179A
Date: Sat, 07 Nov 2026 07:21:53 +0000	[thread overview]
Message-ID: <sashiko-outbox-202697@kernel.org> (raw)
In-Reply-To: <20261106-ax88179a-v20-7-37b5a1189983@birger-koblitz.de>

Thank you for your contribution! Sashiko AI review found 5 potential
issues to consider:
- [Medium] net: usb: ax88179: unchecked USB writes in
  ax88179a_set_features() loop
- [Medium] net: usb: ax88179: uninitialized stack read on short USB read
- [Medium] net: usb: ax88179_178a: unchecked writes and partial state in
  ax88179a_set_features()
- [Medium] net: usb: ax88179_178a: TX VLAN tag drop race in
  ax88179a_tx_fixup()
- [Low] net: usb: ax88179_178a: duplicated VLAN filter update logic in
  add/kill vid
--

commit 6bf60c56c4445f3486e6c4282f90f25fbd952f48
Author: Birger Koblitz <mail@birger-koblitz.de>

ax88179_178a: Add VLAN offload support for AX88179A

This commit adds TX VLAN tagging, RX VLAN stripping, and RX VLAN filter
offload configuration for AX88179A-based USB network devices.

> diff --git a/drivers/net/usb/ax88179a_devices.c b/drivers/net/usb/ax88179a_devices.c
> index 272e923656832..4207d2cc2b865 100644
> --- a/drivers/net/usb/ax88179a_devices.c
> +++ b/drivers/net/usb/ax88179a_devices.c
> @@ -258,6 +258,88 @@ static const struct ethtool_ops ax88179a_ethtool_ops = {
>  	.get_ts_info		= ethtool_op_get_ts_info,
>  };
>  
> +static int ax88179a_vlan_rx_kill_vid(struct net_device *net, __be16 proto, u16 vid)
> +{
> +	struct usbnet *dev = netdev_priv(net);
> +	u16 reg16 = 0;
> +	u8 vlan_ctrl;
> +	int ret = 0;
> +	u8 reg8 = 0;
> +
> +	ret = ax88179_read_cmd(dev, AX_ACCESS_MAC, AX88179A_VLAN_ID_CONTROL, 1, 1, &reg8);
> +	if (ret < 0)
> +		return ret;
> +	vlan_ctrl = reg8;
> +
> +	/* Address */
> +	reg8 = (vid / 16);
> +	ret = ax88179_write_cmd(dev, AX_ACCESS_MAC, AX88179A_VLAN_ID_ADDRESS, 1, 1, &reg8);
> +	if (ret < 0)
> +		return ret;
> +
> +	/* Data */
> +	reg8 = vlan_ctrl | AX_VLAN_CONTROL_RD;
> +	ret = ax88179_write_cmd(dev, AX_ACCESS_MAC, AX88179A_VLAN_ID_CONTROL, 1, 1, &reg8);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = ax88179_read_cmd(dev, AX_ACCESS_MAC, AX88179A_VLAN_ID_DATA0, 2, 2, &reg16);
> +	if (ret < 0)
> +		return ret;
> +	reg16 &= ~(1 << (vid % 16));
> +	ret = ax88179_write_cmd(dev, AX_ACCESS_MAC, AX88179A_VLAN_ID_DATA0, 2, 2, &reg16);
> +	if (ret < 0)
> +		return ret;
> +
> +	reg8 = vlan_ctrl | AX_VLAN_CONTROL_WE;
> +	ret = ax88179_write_cmd(dev, AX_ACCESS_MAC, AX88179A_VLAN_ID_CONTROL, 1, 1, &reg8);
> +	if (ret < 0)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int ax88179a_vlan_rx_add_vid(struct net_device *net, __be16 proto, u16 vid)
> +{
> +	struct usbnet *dev = netdev_priv(net);
> +	u8 vlan_ctrl;
> +	int ret = 0;
> +	u16 reg16;
> +	u8 reg8;
> +
> +	ret = ax88179_read_cmd(dev, AX_ACCESS_MAC, AX88179A_VLAN_ID_CONTROL, 1, 1, &reg8);
> +	if (ret < 0)
> +		return ret;
> +	vlan_ctrl = reg8;

[Severity: Medium]
Can ax88179a_vlan_rx_add_vid() and ax88179a_set_features() read
uninitialized stack memory from reg8 and tmp when a 1-byte
ax88179_read_cmd() returns 0?

Unlike the size == 2 and size == 4 cases in ax88179_read_cmd(), a 1-byte
read passes the caller's pointer directly to __usbnet_read_cmd(), which
only copies into data when usb_control_msg() returns err > 0.  If a short
transfer returns 0, reg8 here and tmp in the NETIF_F_HW_VLAN_CTAG_FILTER
disable and NETIF_F_HW_VLAN_CTAG_RX paths of ax88179a_set_features() are
left uninitialized and then written back to AX88179A_VLAN_ID_CONTROL,
corrupting the register and leaking a stack byte over USB.

> +
> +	/* Address */
> +	reg8 = (vid / 16);
> +	ret = ax88179_write_cmd(dev, AX_ACCESS_MAC, AX88179A_VLAN_ID_ADDRESS, 1, 1, &reg8);
> +	if (ret < 0)
> +		return ret;
> +
> +	/* Data */
> +	reg8 = vlan_ctrl | AX_VLAN_CONTROL_RD;
> +	ret = ax88179_write_cmd(dev, AX_ACCESS_MAC, AX88179A_VLAN_ID_CONTROL, 1, 1, &reg8);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = ax88179_read_cmd(dev, AX_ACCESS_MAC, AX88179A_VLAN_ID_DATA0, 2, 2, &reg16);
> +	if (ret < 0)
> +		return ret;
> +	reg16 |= (1 << (vid % 16));
> +	ret = ax88179_write_cmd(dev, AX_ACCESS_MAC, AX88179A_VLAN_ID_DATA0, 2, 2, &reg16);
> +	if (ret < 0)
> +		return ret;
> +
> +	reg8 = vlan_ctrl | AX_VLAN_CONTROL_WE;
> +	ret = ax88179_write_cmd(dev, AX_ACCESS_MAC, AX88179A_VLAN_ID_CONTROL, 1, 1, &reg8);
> +	if (ret < 0)
> +		return ret;
> +
> +	return 0;
> +}

[Severity: Low]
This isn't a bug, but ax88179a_vlan_rx_kill_vid() and
ax88179a_vlan_rx_add_vid() duplicate the same five-step register sequence
and only differ in whether they clear or set the bit in reg16 (and the two
copies have already diverged in how reg8 and reg16 are initialized).  A
shared helper taking a boolean flag would avoid the duplication.

> @@ -517,6 +599,75 @@ static int ax88179a_mii_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
>  	return phylink_mii_ioctl(data->phylink, rq, cmd);
>  }
>  
> +static int ax88179a_set_features(struct net_device *net, netdev_features_t features)
> +{
> +	struct usbnet *dev = netdev_priv(net);
> +	netdev_features_t changed;
> +	int ret;
> +	u8 tmp;
> +
> +	changed = net->features ^ features;
> +
> +	ret = ax88179_set_features(net, features);
> +	if (ret)
> +		return ret;
> +
> +	if (changed & NETIF_F_HW_VLAN_CTAG_FILTER) {
> +		if (features & NETIF_F_HW_VLAN_CTAG_FILTER) {
> +			u8 vlan_state = 0;
> +
> +			ret = ax88179_read_cmd(dev, AX_ACCESS_MAC,
> +					       AX88179A_VLAN_ID_CONTROL, 1, 1, &vlan_state);
> +			if (ret < 0)
> +				return ret;
> +
> +			for (int i = 0; i < 256; i++) {
> +				/* Address */
> +				tmp = i;
> +				ax88179_write_cmd(dev, AX_ACCESS_MAC, AX88179A_VLAN_ID_ADDRESS,
> +						  1, 1, &tmp);
> +				/* Data */
> +				ax88179_write_u16(dev, AX_ACCESS_MAC, AX88179A_VLAN_ID_DATA0,
> +						  2, 0);
> +				/* Write-Execute */
> +				ax88179_write_u8(dev, AX_ACCESS_MAC, AX88179A_VLAN_ID_CONTROL,
> +						 1, vlan_state | AX_VLAN_CONTROL_WE);\n> +			}

[Severity: Medium]
Should the three USB writes inside this loop check for errors and break out
early?

If a write fails transiently and the final AX_VLAN_CONTROL_VFE write
succeeds, hardware VLAN filtering is enabled with stale entries left in the
filter table.  On a persistent USB error or timeout, the loop runs all 768
synchronous control transfers under rtnl_lock, stalling for up to 768 *
USB_CTRL_SET_TIMEOUT and logging a warning on each failed transfer.

> +			vlan_state |= AX_VLAN_CONTROL_VFE;
> +			ret = ax88179_write_cmd(dev, AX_ACCESS_MAC,
> +						AX88179A_VLAN_ID_CONTROL, 1, 1, &vlan_state);
> +			if (ret < 0)
> +				return ret;
> +		} else {
> +			ret = ax88179_read_cmd(dev, AX_ACCESS_MAC,
> +					       AX88179A_VLAN_ID_CONTROL, 1, 1, &tmp);
> +			if (ret < 0)
> +				return ret;
> +			tmp &= ~AX_VLAN_CONTROL_VFE;
> +			ret = ax88179_write_cmd(dev, AX_ACCESS_MAC,
> +						AX88179A_VLAN_ID_CONTROL, 1, 1, &tmp);
> +			if (ret < 0)
> +				return ret;
> +		}
> +	}
> +
> +	if (changed & NETIF_F_HW_VLAN_CTAG_RX) {
> +		ret = ax88179_read_cmd(dev, AX_ACCESS_MAC, AX88179A_VLAN_ID_CONTROL,
> +				       1, 1, &tmp);
> +		if (ret < 0)
> +			return ret;
> +		if (features & NETIF_F_HW_VLAN_CTAG_RX)
> +			tmp |= AX_VLAN_CONTROL_VSO;
> +		else
> +			tmp &= ~AX_VLAN_CONTROL_VSO;
> +		ret = ax88179_write_cmd(dev, AX_ACCESS_MAC, AX88179A_VLAN_ID_CONTROL,
> +					1, 1, &tmp);
> +		if (ret < 0)
> +			return ret;
> +	}
> +	return 0;
> +}

[Severity: Medium]
Can a failure partway through ax88179a_set_features() leave hardware
offload state out of sync with net->features?

When multiple features change in one call (for example, enabling both
NETIF_F_HW_VLAN_CTAG_FILTER and NETIF_F_HW_VLAN_CTAG_RX) and the later
step fails, returning a negative error causes __netdev_update_features() to
leave dev->features unchanged and skip vlan_get_rx_ctag_filter_info().
AX_VLAN_CONTROL_VFE (or checksum offload changes from
ax88179_set_features()) then stays active in hardware with an all-zero
filter table while dev->features still reports the feature as disabled.

[ ... ]

> @@ -612,9 +766,11 @@ static int ax88179a_bind(struct usbnet *dev, struct usb_interface *intf)
>  		dev->mii.supports_gmii = 1;
>  
>  	dev->net->features |= NETIF_F_SG | NETIF_F_IP_CSUM |
> -			      NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM | NETIF_F_TSO;
> +			      NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM | NETIF_F_TSO |
> +			      NETIF_F_HW_VLAN_CTAG_TX;
>  
>  	dev->net->hw_features |= dev->net->features;
> +	dev->net->hw_features |= NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_FILTER;

[Severity: Medium]
Does enabling NETIF_F_HW_VLAN_CTAG_TX here expose a race in
ax88179a_tx_fixup() that drops VLAN tags when the feature is toggled?

drivers/net/usb/ax88179a_devices.c:ax88179a_tx_fixup() {
    ...
	if ((dev->net->features & NETIF_F_HW_VLAN_CTAG_TX) && (vlan_get_tag(skb, &tci) >= 0)) {
		tx_desc |= AX179A_TX_DESC_VLAN;
		tx_desc |= FIELD_PREP(AX179A_TX_DESC_VLAN_ID, (u64)tci);
	}
    ...
}

CPU0                                  CPU1
validate_xmit_skb()
  validate_xmit_vlan()
    /* NETIF_F_HW_VLAN_CTAG_TX set:
     * tag stays in skb->vlan_tci
     */
                                      __netdev_update_features()
                                        dev->features &=
                                          ~NETIF_F_HW_VLAN_CTAG_TX;
ax88179a_tx_fixup()
  if (dev->net->features &
      NETIF_F_HW_VLAN_CTAG_TX)
    <-- false, frame sent untagged

ax88179a_tx_fixup() (added in commit "ax88179_178a: Add HW support for
AX179A-based chips") checks dev->net->features & NETIF_F_HW_VLAN_CTAG_TX
and calls vlan_get_tag() instead of checking skb_vlan_tag_present(skb) and
skb_vlan_tag_get(skb).  If NETIF_F_HW_VLAN_CTAG_TX is cleared after
validate_xmit_vlan() has already left the tag out-of-band in skb->vlan_tci,
the frame is transmitted without its VLAN tag.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261106-ax88179a-v20-0-37b5a1189983@birger-koblitz.de?part=7

  reply	other threads:[~2026-11-07  7:21 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-06  7:21 [PATCH net-next v20 00/13] ax88179_178a: Add support for AX88179A-based chips Birger Koblitz
2026-11-06  7:21 ` [PATCH net-next v20 01/13] phylink: Add phylink_mac_interrupt Birger Koblitz
2026-11-06 10:11   ` Maxime Chevallier
2026-11-06 15:32     ` Birger Koblitz
2026-11-06 15:55       ` Andrew Lunn
2026-11-07  7:21   ` sashiko-bot
2026-11-06  7:21 ` [PATCH net-next v20 02/13] phylib: Add support for PHYs with broken forced mode Birger Koblitz
2026-11-07  7:21   ` sashiko-bot
2026-11-06  7:21 ` [PATCH net-next v20 03/13] ax88179_178a: Split driver into library and device specific code Birger Koblitz
2026-11-07  7:21   ` sashiko-bot
2026-11-06  7:21 ` [PATCH net-next v20 04/13] ax88179_178a: Add HW support for AX179A-based chips Birger Koblitz
2026-11-07  7:21   ` sashiko-bot
2026-11-06  7:21 ` [PATCH net-next v20 05/13] ax88179_178a: Add EEE configuration support for AX88179A MACs Birger Koblitz
2026-11-07  7:21   ` sashiko-bot
2026-11-06  7:21 ` [PATCH net-next v20 06/13] ax88179_178a: Add EEE configuration support for AX88179A PHYs Birger Koblitz
2026-11-07  7:21   ` sashiko-bot
2026-11-06  7:21 ` [PATCH net-next v20 07/13] ax88179_178a: Add VLAN offload support for AX88179A Birger Koblitz
2026-11-07  7:21   ` sashiko-bot [this message]
2026-11-06  7:21 ` [PATCH net-next v20 08/13] ax88179_178a: Add AX179A/AX279 multicast configuration Birger Koblitz
2026-11-07  7:21   ` sashiko-bot
2026-11-06  7:21 ` [PATCH net-next v20 09/13] ax88179_178a: Add Suspend/resume support for AX88179A/772D/279 Birger Koblitz
2026-11-07  7:21   ` sashiko-bot
2026-11-06  7:21 ` [PATCH net-next v20 10/13] ax88179_178a: Add ethtool get_drvinfo Birger Koblitz
2026-11-07  7:21   ` sashiko-bot
2026-11-06  7:21 ` [PATCH net-next v20 11/13] ax88179_178a: Update driver name and information Birger Koblitz
2026-11-07  7:21   ` sashiko-bot
2026-11-06  7:21 ` [PATCH net-next v20 12/13] ax88179_178a: Add support for AX88179A/772D/279 EEPROM access Birger Koblitz
2026-11-07  7:21   ` sashiko-bot
2026-11-06  7:21 ` [PATCH net-next v20 13/13] ax88796b: Add support for AX88772D, AX88179A and AX88279 Birger Koblitz
2026-11-07  7:21   ` sashiko-bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=sashiko-outbox-202697@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=mail@birger-koblitz.de \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox