Commit 12c9ee3c authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'net-hdlc_fr-improve-fr_rx-and-add-support-for-any-ethertype'

Xie He says:

====================
net: hdlc_fr: Improve fr_rx and add support for any Ethertype

The main purpose of this series is the last patch. The previous 4 patches
are just code clean-ups so that the last patch will not make the code too
messy. The patches must be applied in sequence.

The receiving code of this driver doesn't support arbitrary Ethertype
values. It only recognizes a few known Ethertypes when receiving and drops
skbs with other Ethertypes.

However, the standard document RFC 2427 allows Frame Relay to support any
Ethertype values. This series adds support for this.

Change from v6:
Remove the explanation about why only a 2-byte address field is accepted
because I think it is inadequate and unnecessary.

Change from v5:
Small fix to the commit messages.

Change from v4:
Drop the change related to the stats.rx_dropped count.
Improve the commit message by stating why only a 2-byte address field
is accepted.

Change from v3:
Split the last patch into 2 patches.
Improve the commit message about the stats.rx_dropped count.

Change from v2:
Small fix to the commit messages.

Change from v1:
Small fix to the commit messages.
====================

Link: https://lore.kernel.org/r/20201031181043.805329-1-xie.he.0141@gmail.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 16b5f5ce 54b77a77
......@@ -871,6 +871,45 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
return 0;
}
static int fr_snap_parse(struct sk_buff *skb, struct pvc_device *pvc)
{
/* OUI 00-00-00 indicates an Ethertype follows */
if (skb->data[0] == 0x00 &&
skb->data[1] == 0x00 &&
skb->data[2] == 0x00) {
if (!pvc->main)
return -1;
skb->dev = pvc->main;
skb->protocol = *(__be16 *)(skb->data + 3); /* Ethertype */
skb_pull(skb, 5);
skb_reset_mac_header(skb);
return 0;
/* OUI 00-80-C2 stands for the 802.1 organization */
} else if (skb->data[0] == 0x00 &&
skb->data[1] == 0x80 &&
skb->data[2] == 0xC2) {
/* PID 00-07 stands for Ethernet frames without FCS */
if (skb->data[3] == 0x00 &&
skb->data[4] == 0x07) {
if (!pvc->ether)
return -1;
skb_pull(skb, 5);
if (skb->len < ETH_HLEN)
return -1;
skb->protocol = eth_type_trans(skb, pvc->ether);
return 0;
/* PID unsupported */
} else {
return -1;
}
/* OUI unsupported */
} else {
return -1;
}
}
static int fr_rx(struct sk_buff *skb)
{
......@@ -880,9 +919,9 @@ static int fr_rx(struct sk_buff *skb)
u8 *data = skb->data;
u16 dlci;
struct pvc_device *pvc;
struct net_device *dev = NULL;
struct net_device *dev;
if (skb->len <= 4 || fh->ea1 || data[2] != FR_UI)
if (skb->len < 4 || fh->ea1 || !fh->ea2 || data[2] != FR_UI)
goto rx_error;
dlci = q922_to_dlci(skb->data);
......@@ -904,8 +943,7 @@ static int fr_rx(struct sk_buff *skb)
netdev_info(frad, "No PVC for received frame's DLCI %d\n",
dlci);
#endif
dev_kfree_skb_any(skb);
return NET_RX_DROP;
goto rx_drop;
}
if (pvc->state.fecn != fh->fecn) {
......@@ -931,63 +969,51 @@ static int fr_rx(struct sk_buff *skb)
}
if (data[3] == NLPID_IP) {
if (!pvc->main)
goto rx_drop;
skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */
dev = pvc->main;
skb->dev = pvc->main;
skb->protocol = htons(ETH_P_IP);
skb_reset_mac_header(skb);
} else if (data[3] == NLPID_IPV6) {
if (!pvc->main)
goto rx_drop;
skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */
dev = pvc->main;
skb->dev = pvc->main;
skb->protocol = htons(ETH_P_IPV6);
skb_reset_mac_header(skb);
} else if (skb->len > 10 && data[3] == FR_PAD &&
data[4] == NLPID_SNAP && data[5] == FR_PAD) {
u16 oui = ntohs(*(__be16*)(data + 6));
u16 pid = ntohs(*(__be16*)(data + 8));
skb_pull(skb, 10);
switch ((((u32)oui) << 16) | pid) {
case ETH_P_ARP: /* routed frame with SNAP */
case ETH_P_IPX:
case ETH_P_IP: /* a long variant */
case ETH_P_IPV6:
dev = pvc->main;
skb->protocol = htons(pid);
break;
case 0x80C20007: /* bridged Ethernet frame */
if ((dev = pvc->ether) != NULL)
skb->protocol = eth_type_trans(skb, dev);
break;
default:
netdev_info(frad, "Unsupported protocol, OUI=%x PID=%x\n",
oui, pid);
dev_kfree_skb_any(skb);
return NET_RX_DROP;
} else if (data[3] == FR_PAD) {
if (skb->len < 5)
goto rx_error;
if (data[4] == NLPID_SNAP) { /* A SNAP header follows */
skb_pull(skb, 5);
if (skb->len < 5) /* Incomplete SNAP header */
goto rx_error;
if (fr_snap_parse(skb, pvc))
goto rx_drop;
} else {
goto rx_drop;
}
} else {
netdev_info(frad, "Unsupported protocol, NLPID=%x length=%i\n",
data[3], skb->len);
dev_kfree_skb_any(skb);
return NET_RX_DROP;
goto rx_drop;
}
if (dev) {
dev->stats.rx_packets++; /* PVC traffic */
dev->stats.rx_bytes += skb->len;
if (pvc->state.becn)
dev->stats.rx_compressed++;
skb->dev = dev;
netif_rx(skb);
return NET_RX_SUCCESS;
} else {
dev_kfree_skb_any(skb);
return NET_RX_DROP;
}
dev = skb->dev;
dev->stats.rx_packets++; /* PVC traffic */
dev->stats.rx_bytes += skb->len;
if (pvc->state.becn)
dev->stats.rx_compressed++;
netif_rx(skb);
return NET_RX_SUCCESS;
rx_error:
rx_error:
frad->stats.rx_errors++; /* Mark error */
rx_drop:
dev_kfree_skb_any(skb);
return NET_RX_DROP;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment