1
0
mirror of https://git.openwrt.org/openwrt/openwrt.git synced 2024-06-20 23:58:27 +02:00

realtek: correct egress frame port verification

Destination switch ports for outgoing frame can range from 0 to
CPU_PORT-1.

Refactor the code to only generate egress frame CPU headers when a valid
destination port number is available, and make the code a bit more
consistent between different switch generations. Change the dest_port
argument's type to 'unsigned int', since only positive values are valid.

This fixes the issue where egress frames on switch port 0 did not
receive a VLAN tag, because they are sent out without a CPU header.
Also fixes a potential issue with invalid (negative) egress port numbers
on RTL93xx switches.

Reported-by: Arınç ÜNAL <arinc.unal@xeront.com>
Suggested-by: Birger Koblitz <mail@birger-koblitz.de>
Tested-by: Luiz Angelo Daros de Luca <luizluca@gmail.com>
Signed-off-by: Sander Vanheule <sander@svanheule.net>
This commit is contained in:
Sander Vanheule 2022-06-19 10:29:35 +02:00
parent 0b35a08a05
commit 1773264a0c
2 changed files with 38 additions and 41 deletions

View File

@ -92,47 +92,42 @@ struct notify_b {
u32 reserved2[8];
};
static void rtl838x_create_tx_header(struct p_hdr *h, int dest_port, int prio)
static void rtl838x_create_tx_header(struct p_hdr *h, unsigned int dest_port, int prio)
{
if (dest_port > 0) {
// cpu_tag[0] is reserved on the RTL83XX SoCs
h->cpu_tag[1] = 0x0401; // BIT 10: RTL8380_CPU_TAG, BIT0: L2LEARNING on
h->cpu_tag[2] = 0x0200; // Set only AS_DPM, to enable DPM settings below
h->cpu_tag[3] = 0x0000;
// cpu_tag[0] is reserved on the RTL83XX SoCs
h->cpu_tag[1] = 0x0401; // BIT 10: RTL8380_CPU_TAG, BIT0: L2LEARNING on
h->cpu_tag[2] = 0x0200; // Set only AS_DPM, to enable DPM settings below
h->cpu_tag[3] = 0x0000;
h->cpu_tag[4] = BIT(dest_port) >> 16;
h->cpu_tag[5] = BIT(dest_port) & 0xffff;
/* Set internal priority (PRI) and enable (AS_PRI) */
if (prio >= 0)
h->cpu_tag[2] |= ((prio & 0x7) | BIT(3)) << 12;
}
static void rtl839x_create_tx_header(struct p_hdr *h, unsigned int dest_port, int prio)
{
// cpu_tag[0] is reserved on the RTL83XX SoCs
h->cpu_tag[1] = 0x0100; // RTL8390_CPU_TAG marker
h->cpu_tag[2] = BIT(4) | BIT(7); /* AS_DPM (4) and L2LEARNING (7) flags */
h->cpu_tag[3] = h->cpu_tag[4] = h->cpu_tag[5] = 0;
// h->cpu_tag[1] |= BIT(1) | BIT(0); // Bypass filter 1/2
if (dest_port >= 32) {
dest_port -= 32;
h->cpu_tag[2] = BIT(dest_port) >> 16;
h->cpu_tag[3] = BIT(dest_port) & 0xffff;
} else {
h->cpu_tag[4] = BIT(dest_port) >> 16;
h->cpu_tag[5] = BIT(dest_port) & 0xffff;
/* Set internal priority (PRI) and enable (AS_PRI) */
if (prio >= 0)
h->cpu_tag[2] |= ((prio & 0x7) | BIT(3)) << 12;
}
/* Set internal priority (PRI) and enable (AS_PRI) */
if (prio >= 0)
h->cpu_tag[2] |= ((prio & 0x7) | BIT(3)) << 8;
}
static void rtl839x_create_tx_header(struct p_hdr *h, int dest_port, int prio)
{
if (dest_port > 0) {
// cpu_tag[0] is reserved on the RTL83XX SoCs
h->cpu_tag[1] = 0x0100; // RTL8390_CPU_TAG marker
h->cpu_tag[2] = h->cpu_tag[3] = h->cpu_tag[4] = h->cpu_tag[5] = 0;
// h->cpu_tag[1] |= BIT(1) | BIT(0); // Bypass filter 1/2
if (dest_port >= 32) {
dest_port -= 32;
h->cpu_tag[2] = BIT(dest_port) >> 16;
h->cpu_tag[3] = BIT(dest_port) & 0xffff;
} else {
h->cpu_tag[4] = BIT(dest_port) >> 16;
h->cpu_tag[5] = BIT(dest_port) & 0xffff;
}
h->cpu_tag[2] |= BIT(4); // Enable destination port mask use
h->cpu_tag[2] |= BIT(7); // Enable L2 Learning
/* Set internal priority (PRI) and enable (AS_PRI) */
if (prio >= 0)
h->cpu_tag[2] |= ((prio & 0x7) | BIT(3)) << 8;
}
}
static void rtl930x_create_tx_header(struct p_hdr *h, int dest_port, int prio)
static void rtl930x_create_tx_header(struct p_hdr *h, unsigned int dest_port, int prio)
{
h->cpu_tag[0] = 0x8000; // CPU tag marker
h->cpu_tag[1] = h->cpu_tag[2] = 0;
@ -147,7 +142,7 @@ static void rtl930x_create_tx_header(struct p_hdr *h, int dest_port, int prio)
h->cpu_tag[2] = (BIT(5) | (prio & 0x1f)) << 8;
}
static void rtl931x_create_tx_header(struct p_hdr *h, int dest_port, int prio)
static void rtl931x_create_tx_header(struct p_hdr *h, unsigned int dest_port, int prio)
{
h->cpu_tag[0] = 0x8000; // CPU tag marker
h->cpu_tag[1] = h->cpu_tag[2] = 0;
@ -1144,9 +1139,10 @@ static int rtl838x_eth_tx(struct sk_buff *skb, struct net_device *dev)
len = skb->len;
/* Check for DSA tagging at the end of the buffer */
if (netdev_uses_dsa(dev) && skb->data[len-4] == 0x80 && skb->data[len-3] > 0
&& skb->data[len-3] < priv->cpu_port && skb->data[len-2] == 0x10
&& skb->data[len-1] == 0x00) {
if (netdev_uses_dsa(dev) && skb->data[len-4] == 0x80
&& skb->data[len-3] < priv->cpu_port
&& skb->data[len-2] == 0x10
&& skb->data[len-1] == 0x00) {
/* Reuse tag space for CRC if possible */
dest_port = skb->data[len-3];
skb->data[len-4] = skb->data[len-3] = skb->data[len-2] = skb->data[len-1] = 0x00;
@ -1173,7 +1169,8 @@ static int rtl838x_eth_tx(struct sk_buff *skb, struct net_device *dev)
h->len -= 4;
}
priv->r->create_tx_header(h, dest_port, skb->priority >> 1);
if (dest_port >= 0)
priv->r->create_tx_header(h, dest_port, skb->priority >> 1);
/* Copy packet data to tx buffer */
memcpy((void *)KSEG1ADDR(h->buf), skb->data, len);

View File

@ -436,7 +436,7 @@ struct rtl838x_eth_reg {
int mac;
int l2_tbl_flush_ctrl;
void (*update_cntr)(int r, int work_done);
void (*create_tx_header)(struct p_hdr *h, int dest_port, int prio);
void (*create_tx_header)(struct p_hdr *h, unsigned int dest_port, int prio);
bool (*decode_tag)(struct p_hdr *h, struct dsa_tag *tag);
};