net: hdlc_fr: Add support for any Ethertype
Change the fr_rx function to make this driver support any Ethertype when receiving skbs on normal (non-Ethernet-emulating) PVC devices. (This driver is already able to handle any Ethertype when sending.) Originally in the fr_rx function, the code that parses the long (10-byte) header only recognizes a few Ethertype values and drops frames with other Ethertype values. This patch replaces this code to make fr_rx support any Ethertype. This patch also creates a new function fr_snap_parse as part of the new code. Cc: Krzysztof Halasa <khc@pm.waw.pl> Signed-off-by: Xie He <xie.he.0141@gmail.com> Acked-by: Willem de Bruijn <willemb@google.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
77124c4463
commit
54b77a77e3
1 changed files with 49 additions and 26 deletions
|
@ -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)
|
||||
{
|
||||
|
@ -945,35 +984,19 @@ static int fr_rx(struct sk_buff *skb)
|
|||
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:
|
||||
if (!pvc->main)
|
||||
} 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;
|
||||
skb->dev = pvc->main;
|
||||
skb->protocol = htons(pid);
|
||||
skb_reset_mac_header(skb);
|
||||
break;
|
||||
|
||||
case 0x80C20007: /* bridged Ethernet frame */
|
||||
if (!pvc->ether)
|
||||
goto rx_drop;
|
||||
skb->protocol = eth_type_trans(skb, pvc->ether);
|
||||
break;
|
||||
|
||||
default:
|
||||
netdev_info(frad, "Unsupported protocol, OUI=%x PID=%x\n",
|
||||
oui, pid);
|
||||
} else {
|
||||
goto rx_drop;
|
||||
}
|
||||
|
||||
} else {
|
||||
netdev_info(frad, "Unsupported protocol, NLPID=%x length=%i\n",
|
||||
data[3], skb->len);
|
||||
|
|
Loading…
Add table
Reference in a new issue