Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Xie He and committed by
Jakub Kicinski
54b77a77 77124c44

+49 -26
+49 -26
drivers/net/wan/hdlc_fr.c
··· 871 871 return 0; 872 872 } 873 873 874 + static int fr_snap_parse(struct sk_buff *skb, struct pvc_device *pvc) 875 + { 876 + /* OUI 00-00-00 indicates an Ethertype follows */ 877 + if (skb->data[0] == 0x00 && 878 + skb->data[1] == 0x00 && 879 + skb->data[2] == 0x00) { 880 + if (!pvc->main) 881 + return -1; 882 + skb->dev = pvc->main; 883 + skb->protocol = *(__be16 *)(skb->data + 3); /* Ethertype */ 884 + skb_pull(skb, 5); 885 + skb_reset_mac_header(skb); 886 + return 0; 887 + 888 + /* OUI 00-80-C2 stands for the 802.1 organization */ 889 + } else if (skb->data[0] == 0x00 && 890 + skb->data[1] == 0x80 && 891 + skb->data[2] == 0xC2) { 892 + /* PID 00-07 stands for Ethernet frames without FCS */ 893 + if (skb->data[3] == 0x00 && 894 + skb->data[4] == 0x07) { 895 + if (!pvc->ether) 896 + return -1; 897 + skb_pull(skb, 5); 898 + if (skb->len < ETH_HLEN) 899 + return -1; 900 + skb->protocol = eth_type_trans(skb, pvc->ether); 901 + return 0; 902 + 903 + /* PID unsupported */ 904 + } else { 905 + return -1; 906 + } 907 + 908 + /* OUI unsupported */ 909 + } else { 910 + return -1; 911 + } 912 + } 874 913 875 914 static int fr_rx(struct sk_buff *skb) 876 915 { ··· 984 945 skb->protocol = htons(ETH_P_IPV6); 985 946 skb_reset_mac_header(skb); 986 947 987 - } else if (skb->len > 10 && data[3] == FR_PAD && 988 - data[4] == NLPID_SNAP && data[5] == FR_PAD) { 989 - u16 oui = ntohs(*(__be16*)(data + 6)); 990 - u16 pid = ntohs(*(__be16*)(data + 8)); 991 - skb_pull(skb, 10); 992 - 993 - switch ((((u32)oui) << 16) | pid) { 994 - case ETH_P_ARP: /* routed frame with SNAP */ 995 - case ETH_P_IPX: 996 - case ETH_P_IP: /* a long variant */ 997 - case ETH_P_IPV6: 998 - if (!pvc->main) 948 + } else if (data[3] == FR_PAD) { 949 + if (skb->len < 5) 950 + goto rx_error; 951 + if (data[4] == NLPID_SNAP) { /* A SNAP header follows */ 952 + skb_pull(skb, 5); 953 + if (skb->len < 5) /* Incomplete SNAP header */ 954 + goto rx_error; 955 + if (fr_snap_parse(skb, pvc)) 999 956 goto rx_drop; 1000 - skb->dev = pvc->main; 1001 - skb->protocol = htons(pid); 1002 - skb_reset_mac_header(skb); 1003 - break; 1004 - 1005 - case 0x80C20007: /* bridged Ethernet frame */ 1006 - if (!pvc->ether) 1007 - goto rx_drop; 1008 - skb->protocol = eth_type_trans(skb, pvc->ether); 1009 - break; 1010 - 1011 - default: 1012 - netdev_info(frad, "Unsupported protocol, OUI=%x PID=%x\n", 1013 - oui, pid); 957 + } else { 1014 958 goto rx_drop; 1015 959 } 960 + 1016 961 } else { 1017 962 netdev_info(frad, "Unsupported protocol, NLPID=%x length=%i\n", 1018 963 data[3], skb->len);