18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* PTP classifier 38c2ecf20Sopenharmony_ci */ 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci/* The below program is the bpf_asm (tools/net/) representation of 68c2ecf20Sopenharmony_ci * the opcode array in the ptp_filter structure. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * For convenience, this can easily be altered and reviewed with 98c2ecf20Sopenharmony_ci * bpf_asm and bpf_dbg, e.g. `./bpf_asm -c prog` where prog is a 108c2ecf20Sopenharmony_ci * simple file containing the below program: 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * ldh [12] ; load ethertype 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * ; PTP over UDP over IPv4 over Ethernet 158c2ecf20Sopenharmony_ci * test_ipv4: 168c2ecf20Sopenharmony_ci * jneq #0x800, test_ipv6 ; ETH_P_IP ? 178c2ecf20Sopenharmony_ci * ldb [23] ; load proto 188c2ecf20Sopenharmony_ci * jneq #17, drop_ipv4 ; IPPROTO_UDP ? 198c2ecf20Sopenharmony_ci * ldh [20] ; load frag offset field 208c2ecf20Sopenharmony_ci * jset #0x1fff, drop_ipv4 ; don't allow fragments 218c2ecf20Sopenharmony_ci * ldxb 4*([14]&0xf) ; load IP header len 228c2ecf20Sopenharmony_ci * ldh [x + 16] ; load UDP dst port 238c2ecf20Sopenharmony_ci * jneq #319, drop_ipv4 ; is port PTP_EV_PORT ? 248c2ecf20Sopenharmony_ci * ldh [x + 22] ; load payload 258c2ecf20Sopenharmony_ci * and #0xf ; mask PTP_CLASS_VMASK 268c2ecf20Sopenharmony_ci * or #0x10 ; PTP_CLASS_IPV4 278c2ecf20Sopenharmony_ci * ret a ; return PTP class 288c2ecf20Sopenharmony_ci * drop_ipv4: ret #0x0 ; PTP_CLASS_NONE 298c2ecf20Sopenharmony_ci * 308c2ecf20Sopenharmony_ci * ; PTP over UDP over IPv6 over Ethernet 318c2ecf20Sopenharmony_ci * test_ipv6: 328c2ecf20Sopenharmony_ci * jneq #0x86dd, test_8021q ; ETH_P_IPV6 ? 338c2ecf20Sopenharmony_ci * ldb [20] ; load proto 348c2ecf20Sopenharmony_ci * jneq #17, drop_ipv6 ; IPPROTO_UDP ? 358c2ecf20Sopenharmony_ci * ldh [56] ; load UDP dst port 368c2ecf20Sopenharmony_ci * jneq #319, drop_ipv6 ; is port PTP_EV_PORT ? 378c2ecf20Sopenharmony_ci * ldh [62] ; load payload 388c2ecf20Sopenharmony_ci * and #0xf ; mask PTP_CLASS_VMASK 398c2ecf20Sopenharmony_ci * or #0x20 ; PTP_CLASS_IPV6 408c2ecf20Sopenharmony_ci * ret a ; return PTP class 418c2ecf20Sopenharmony_ci * drop_ipv6: ret #0x0 ; PTP_CLASS_NONE 428c2ecf20Sopenharmony_ci * 438c2ecf20Sopenharmony_ci * ; PTP over 802.1Q over Ethernet 448c2ecf20Sopenharmony_ci * test_8021q: 458c2ecf20Sopenharmony_ci * jneq #0x8100, test_ieee1588 ; ETH_P_8021Q ? 468c2ecf20Sopenharmony_ci * ldh [16] ; load inner type 478c2ecf20Sopenharmony_ci * jneq #0x88f7, test_8021q_ipv4 ; ETH_P_1588 ? 488c2ecf20Sopenharmony_ci * ldb [18] ; load payload 498c2ecf20Sopenharmony_ci * and #0x8 ; as we don't have ports here, test 508c2ecf20Sopenharmony_ci * jneq #0x0, drop_ieee1588 ; for PTP_GEN_BIT and drop these 518c2ecf20Sopenharmony_ci * ldh [18] ; reload payload 528c2ecf20Sopenharmony_ci * and #0xf ; mask PTP_CLASS_VMASK 538c2ecf20Sopenharmony_ci * or #0xc0 ; PTP_CLASS_VLAN|PTP_CLASS_L2 548c2ecf20Sopenharmony_ci * ret a ; return PTP class 558c2ecf20Sopenharmony_ci * 568c2ecf20Sopenharmony_ci * ; PTP over UDP over IPv4 over 802.1Q over Ethernet 578c2ecf20Sopenharmony_ci * test_8021q_ipv4: 588c2ecf20Sopenharmony_ci * jneq #0x800, test_8021q_ipv6 ; ETH_P_IP ? 598c2ecf20Sopenharmony_ci * ldb [27] ; load proto 608c2ecf20Sopenharmony_ci * jneq #17, drop_8021q_ipv4 ; IPPROTO_UDP ? 618c2ecf20Sopenharmony_ci * ldh [24] ; load frag offset field 628c2ecf20Sopenharmony_ci * jset #0x1fff, drop_8021q_ipv4; don't allow fragments 638c2ecf20Sopenharmony_ci * ldxb 4*([18]&0xf) ; load IP header len 648c2ecf20Sopenharmony_ci * ldh [x + 20] ; load UDP dst port 658c2ecf20Sopenharmony_ci * jneq #319, drop_8021q_ipv4 ; is port PTP_EV_PORT ? 668c2ecf20Sopenharmony_ci * ldh [x + 26] ; load payload 678c2ecf20Sopenharmony_ci * and #0xf ; mask PTP_CLASS_VMASK 688c2ecf20Sopenharmony_ci * or #0x90 ; PTP_CLASS_VLAN|PTP_CLASS_IPV4 698c2ecf20Sopenharmony_ci * ret a ; return PTP class 708c2ecf20Sopenharmony_ci * drop_8021q_ipv4: ret #0x0 ; PTP_CLASS_NONE 718c2ecf20Sopenharmony_ci * 728c2ecf20Sopenharmony_ci * ; PTP over UDP over IPv6 over 802.1Q over Ethernet 738c2ecf20Sopenharmony_ci * test_8021q_ipv6: 748c2ecf20Sopenharmony_ci * jneq #0x86dd, drop_8021q_ipv6 ; ETH_P_IPV6 ? 758c2ecf20Sopenharmony_ci * ldb [24] ; load proto 768c2ecf20Sopenharmony_ci * jneq #17, drop_8021q_ipv6 ; IPPROTO_UDP ? 778c2ecf20Sopenharmony_ci * ldh [60] ; load UDP dst port 788c2ecf20Sopenharmony_ci * jneq #319, drop_8021q_ipv6 ; is port PTP_EV_PORT ? 798c2ecf20Sopenharmony_ci * ldh [66] ; load payload 808c2ecf20Sopenharmony_ci * and #0xf ; mask PTP_CLASS_VMASK 818c2ecf20Sopenharmony_ci * or #0xa0 ; PTP_CLASS_VLAN|PTP_CLASS_IPV6 828c2ecf20Sopenharmony_ci * ret a ; return PTP class 838c2ecf20Sopenharmony_ci * drop_8021q_ipv6: ret #0x0 ; PTP_CLASS_NONE 848c2ecf20Sopenharmony_ci * 858c2ecf20Sopenharmony_ci * ; PTP over Ethernet 868c2ecf20Sopenharmony_ci * test_ieee1588: 878c2ecf20Sopenharmony_ci * jneq #0x88f7, drop_ieee1588 ; ETH_P_1588 ? 888c2ecf20Sopenharmony_ci * ldb [14] ; load payload 898c2ecf20Sopenharmony_ci * and #0x8 ; as we don't have ports here, test 908c2ecf20Sopenharmony_ci * jneq #0x0, drop_ieee1588 ; for PTP_GEN_BIT and drop these 918c2ecf20Sopenharmony_ci * ldh [14] ; reload payload 928c2ecf20Sopenharmony_ci * and #0xf ; mask PTP_CLASS_VMASK 938c2ecf20Sopenharmony_ci * or #0x40 ; PTP_CLASS_L2 948c2ecf20Sopenharmony_ci * ret a ; return PTP class 958c2ecf20Sopenharmony_ci * drop_ieee1588: ret #0x0 ; PTP_CLASS_NONE 968c2ecf20Sopenharmony_ci */ 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 998c2ecf20Sopenharmony_ci#include <linux/filter.h> 1008c2ecf20Sopenharmony_ci#include <linux/ptp_classify.h> 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic struct bpf_prog *ptp_insns __read_mostly; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ciunsigned int ptp_classify_raw(const struct sk_buff *skb) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci return BPF_PROG_RUN(ptp_insns, skb); 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ptp_classify_raw); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistruct ptp_header *ptp_parse_header(struct sk_buff *skb, unsigned int type) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci u8 *ptr = skb_mac_header(skb); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci if (type & PTP_CLASS_VLAN) 1158c2ecf20Sopenharmony_ci ptr += VLAN_HLEN; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci switch (type & PTP_CLASS_PMASK) { 1188c2ecf20Sopenharmony_ci case PTP_CLASS_IPV4: 1198c2ecf20Sopenharmony_ci ptr += IPV4_HLEN(ptr) + UDP_HLEN; 1208c2ecf20Sopenharmony_ci break; 1218c2ecf20Sopenharmony_ci case PTP_CLASS_IPV6: 1228c2ecf20Sopenharmony_ci ptr += IP6_HLEN + UDP_HLEN; 1238c2ecf20Sopenharmony_ci break; 1248c2ecf20Sopenharmony_ci case PTP_CLASS_L2: 1258c2ecf20Sopenharmony_ci break; 1268c2ecf20Sopenharmony_ci default: 1278c2ecf20Sopenharmony_ci return NULL; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci ptr += ETH_HLEN; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci /* Ensure that the entire header is present in this packet. */ 1338c2ecf20Sopenharmony_ci if (ptr + sizeof(struct ptp_header) > skb->data + skb->len) 1348c2ecf20Sopenharmony_ci return NULL; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci return (struct ptp_header *)ptr; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ptp_parse_header); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_civoid __init ptp_classifier_init(void) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci static struct sock_filter ptp_filter[] __initdata = { 1438c2ecf20Sopenharmony_ci { 0x28, 0, 0, 0x0000000c }, 1448c2ecf20Sopenharmony_ci { 0x15, 0, 12, 0x00000800 }, 1458c2ecf20Sopenharmony_ci { 0x30, 0, 0, 0x00000017 }, 1468c2ecf20Sopenharmony_ci { 0x15, 0, 9, 0x00000011 }, 1478c2ecf20Sopenharmony_ci { 0x28, 0, 0, 0x00000014 }, 1488c2ecf20Sopenharmony_ci { 0x45, 7, 0, 0x00001fff }, 1498c2ecf20Sopenharmony_ci { 0xb1, 0, 0, 0x0000000e }, 1508c2ecf20Sopenharmony_ci { 0x48, 0, 0, 0x00000010 }, 1518c2ecf20Sopenharmony_ci { 0x15, 0, 4, 0x0000013f }, 1528c2ecf20Sopenharmony_ci { 0x48, 0, 0, 0x00000016 }, 1538c2ecf20Sopenharmony_ci { 0x54, 0, 0, 0x0000000f }, 1548c2ecf20Sopenharmony_ci { 0x44, 0, 0, 0x00000010 }, 1558c2ecf20Sopenharmony_ci { 0x16, 0, 0, 0x00000000 }, 1568c2ecf20Sopenharmony_ci { 0x06, 0, 0, 0x00000000 }, 1578c2ecf20Sopenharmony_ci { 0x15, 0, 9, 0x000086dd }, 1588c2ecf20Sopenharmony_ci { 0x30, 0, 0, 0x00000014 }, 1598c2ecf20Sopenharmony_ci { 0x15, 0, 6, 0x00000011 }, 1608c2ecf20Sopenharmony_ci { 0x28, 0, 0, 0x00000038 }, 1618c2ecf20Sopenharmony_ci { 0x15, 0, 4, 0x0000013f }, 1628c2ecf20Sopenharmony_ci { 0x28, 0, 0, 0x0000003e }, 1638c2ecf20Sopenharmony_ci { 0x54, 0, 0, 0x0000000f }, 1648c2ecf20Sopenharmony_ci { 0x44, 0, 0, 0x00000020 }, 1658c2ecf20Sopenharmony_ci { 0x16, 0, 0, 0x00000000 }, 1668c2ecf20Sopenharmony_ci { 0x06, 0, 0, 0x00000000 }, 1678c2ecf20Sopenharmony_ci { 0x15, 0, 32, 0x00008100 }, 1688c2ecf20Sopenharmony_ci { 0x28, 0, 0, 0x00000010 }, 1698c2ecf20Sopenharmony_ci { 0x15, 0, 7, 0x000088f7 }, 1708c2ecf20Sopenharmony_ci { 0x30, 0, 0, 0x00000012 }, 1718c2ecf20Sopenharmony_ci { 0x54, 0, 0, 0x00000008 }, 1728c2ecf20Sopenharmony_ci { 0x15, 0, 35, 0x00000000 }, 1738c2ecf20Sopenharmony_ci { 0x28, 0, 0, 0x00000012 }, 1748c2ecf20Sopenharmony_ci { 0x54, 0, 0, 0x0000000f }, 1758c2ecf20Sopenharmony_ci { 0x44, 0, 0, 0x000000c0 }, 1768c2ecf20Sopenharmony_ci { 0x16, 0, 0, 0x00000000 }, 1778c2ecf20Sopenharmony_ci { 0x15, 0, 12, 0x00000800 }, 1788c2ecf20Sopenharmony_ci { 0x30, 0, 0, 0x0000001b }, 1798c2ecf20Sopenharmony_ci { 0x15, 0, 9, 0x00000011 }, 1808c2ecf20Sopenharmony_ci { 0x28, 0, 0, 0x00000018 }, 1818c2ecf20Sopenharmony_ci { 0x45, 7, 0, 0x00001fff }, 1828c2ecf20Sopenharmony_ci { 0xb1, 0, 0, 0x00000012 }, 1838c2ecf20Sopenharmony_ci { 0x48, 0, 0, 0x00000014 }, 1848c2ecf20Sopenharmony_ci { 0x15, 0, 4, 0x0000013f }, 1858c2ecf20Sopenharmony_ci { 0x48, 0, 0, 0x0000001a }, 1868c2ecf20Sopenharmony_ci { 0x54, 0, 0, 0x0000000f }, 1878c2ecf20Sopenharmony_ci { 0x44, 0, 0, 0x00000090 }, 1888c2ecf20Sopenharmony_ci { 0x16, 0, 0, 0x00000000 }, 1898c2ecf20Sopenharmony_ci { 0x06, 0, 0, 0x00000000 }, 1908c2ecf20Sopenharmony_ci { 0x15, 0, 8, 0x000086dd }, 1918c2ecf20Sopenharmony_ci { 0x30, 0, 0, 0x00000018 }, 1928c2ecf20Sopenharmony_ci { 0x15, 0, 6, 0x00000011 }, 1938c2ecf20Sopenharmony_ci { 0x28, 0, 0, 0x0000003c }, 1948c2ecf20Sopenharmony_ci { 0x15, 0, 4, 0x0000013f }, 1958c2ecf20Sopenharmony_ci { 0x28, 0, 0, 0x00000042 }, 1968c2ecf20Sopenharmony_ci { 0x54, 0, 0, 0x0000000f }, 1978c2ecf20Sopenharmony_ci { 0x44, 0, 0, 0x000000a0 }, 1988c2ecf20Sopenharmony_ci { 0x16, 0, 0, 0x00000000 }, 1998c2ecf20Sopenharmony_ci { 0x06, 0, 0, 0x00000000 }, 2008c2ecf20Sopenharmony_ci { 0x15, 0, 7, 0x000088f7 }, 2018c2ecf20Sopenharmony_ci { 0x30, 0, 0, 0x0000000e }, 2028c2ecf20Sopenharmony_ci { 0x54, 0, 0, 0x00000008 }, 2038c2ecf20Sopenharmony_ci { 0x15, 0, 4, 0x00000000 }, 2048c2ecf20Sopenharmony_ci { 0x28, 0, 0, 0x0000000e }, 2058c2ecf20Sopenharmony_ci { 0x54, 0, 0, 0x0000000f }, 2068c2ecf20Sopenharmony_ci { 0x44, 0, 0, 0x00000040 }, 2078c2ecf20Sopenharmony_ci { 0x16, 0, 0, 0x00000000 }, 2088c2ecf20Sopenharmony_ci { 0x06, 0, 0, 0x00000000 }, 2098c2ecf20Sopenharmony_ci }; 2108c2ecf20Sopenharmony_ci struct sock_fprog_kern ptp_prog; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci ptp_prog.len = ARRAY_SIZE(ptp_filter); 2138c2ecf20Sopenharmony_ci ptp_prog.filter = ptp_filter; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci BUG_ON(bpf_prog_create(&ptp_insns, &ptp_prog)); 2168c2ecf20Sopenharmony_ci} 217