1 /*
2  * PTP 1588 support
3  *
4  * This file implements a BPF that recognizes PTP event messages.
5  *
6  * Copyright (C) 2010 OMICRON electronics GmbH
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */
22 
23 #ifndef _PTP_CLASSIFY_H_
24 #define _PTP_CLASSIFY_H_
25 
26 #include <linux/if_ether.h>
27 #include <linux/if_vlan.h>
28 #include <linux/ip.h>
29 #include <linux/filter.h>
30 #ifdef __KERNEL__
31 #include <linux/in.h>
32 #else
33 #include <netinet/in.h>
34 #endif
35 
36 #define PTP_CLASS_NONE  0x00 /* not a PTP event message */
37 #define PTP_CLASS_V1    0x01 /* protocol version 1 */
38 #define PTP_CLASS_V2    0x02 /* protocol version 2 */
39 #define PTP_CLASS_VMASK 0x0f /* max protocol version is 15 */
40 #define PTP_CLASS_IPV4  0x10 /* event in an IPV4 UDP packet */
41 #define PTP_CLASS_IPV6  0x20 /* event in an IPV6 UDP packet */
42 #define PTP_CLASS_L2    0x30 /* event in a L2 packet */
43 #define PTP_CLASS_VLAN  0x40 /* event in a VLAN tagged L2 packet */
44 #define PTP_CLASS_PMASK 0xf0 /* mask for the packet type field */
45 
46 #define PTP_CLASS_V1_IPV4 (PTP_CLASS_V1 | PTP_CLASS_IPV4)
47 #define PTP_CLASS_V1_IPV6 (PTP_CLASS_V1 | PTP_CLASS_IPV6) /*probably DNE*/
48 #define PTP_CLASS_V2_IPV4 (PTP_CLASS_V2 | PTP_CLASS_IPV4)
49 #define PTP_CLASS_V2_IPV6 (PTP_CLASS_V2 | PTP_CLASS_IPV6)
50 #define PTP_CLASS_V2_L2   (PTP_CLASS_V2 | PTP_CLASS_L2)
51 #define PTP_CLASS_V2_VLAN (PTP_CLASS_V2 | PTP_CLASS_VLAN)
52 
53 #define PTP_EV_PORT 319
54 #define PTP_GEN_BIT 0x08 /* indicates general message, if set in message type */
55 
56 #define OFF_ETYPE	12
57 #define OFF_IHL		14
58 #define OFF_FRAG	20
59 #define OFF_PROTO4	23
60 #define OFF_NEXT	6
61 #define OFF_UDP_DST	2
62 
63 #define OFF_PTP_SOURCE_UUID	22 /* PTPv1 only */
64 #define OFF_PTP_SEQUENCE_ID	30
65 #define OFF_PTP_CONTROL		32 /* PTPv1 only */
66 
67 #define IPV4_HLEN(data) (((struct iphdr *)(data + OFF_IHL))->ihl << 2)
68 
69 #define IP6_HLEN	40
70 #define UDP_HLEN	8
71 
72 #define RELOFF_DST4	(ETH_HLEN + OFF_UDP_DST)
73 #define OFF_DST6	(ETH_HLEN + IP6_HLEN + OFF_UDP_DST)
74 #define OFF_PTP6	(ETH_HLEN + IP6_HLEN + UDP_HLEN)
75 
76 #define OP_AND	(BPF_ALU | BPF_AND  | BPF_K)
77 #define OP_JEQ	(BPF_JMP | BPF_JEQ  | BPF_K)
78 #define OP_JSET	(BPF_JMP | BPF_JSET | BPF_K)
79 #define OP_LDB	(BPF_LD  | BPF_B    | BPF_ABS)
80 #define OP_LDH	(BPF_LD  | BPF_H    | BPF_ABS)
81 #define OP_LDHI	(BPF_LD  | BPF_H    | BPF_IND)
82 #define OP_LDX	(BPF_LDX | BPF_B    | BPF_MSH)
83 #define OP_OR	(BPF_ALU | BPF_OR   | BPF_K)
84 #define OP_RETA	(BPF_RET | BPF_A)
85 #define OP_RETK	(BPF_RET | BPF_K)
86 
ptp_filter_init(struct sock_filter * f,int len)87 static inline int ptp_filter_init(struct sock_filter *f, int len)
88 {
89 	if (OP_LDH == f[0].code)
90 		return sk_chk_filter(f, len);
91 	else
92 		return 0;
93 }
94 
95 #define PTP_FILTER \
96 	{OP_LDH,	0,   0, OFF_ETYPE		}, /*              */ \
97 	{OP_JEQ,	0,  12, ETH_P_IP		}, /* f goto L20   */ \
98 	{OP_LDB,	0,   0, OFF_PROTO4		}, /*              */ \
99 	{OP_JEQ,	0,   9, IPPROTO_UDP		}, /* f goto L10   */ \
100 	{OP_LDH,	0,   0, OFF_FRAG		}, /*              */ \
101 	{OP_JSET,	7,   0, 0x1fff			}, /* t goto L11   */ \
102 	{OP_LDX,	0,   0, OFF_IHL			}, /*              */ \
103 	{OP_LDHI,	0,   0, RELOFF_DST4		}, /*              */ \
104 	{OP_JEQ,	0,   4, PTP_EV_PORT		}, /* f goto L12   */ \
105 	{OP_LDHI,	0,   0, ETH_HLEN + UDP_HLEN	}, /*              */ \
106 	{OP_AND,	0,   0, PTP_CLASS_VMASK		}, /*              */ \
107 	{OP_OR,		0,   0, PTP_CLASS_IPV4		}, /*              */ \
108 	{OP_RETA,	0,   0, 0			}, /*              */ \
109 /*L1x*/	{OP_RETK,	0,   0, PTP_CLASS_NONE		}, /*              */ \
110 /*L20*/	{OP_JEQ,	0,   9, ETH_P_IPV6		}, /* f goto L40   */ \
111 	{OP_LDB,	0,   0, ETH_HLEN + OFF_NEXT	}, /*              */ \
112 	{OP_JEQ,	0,   6, IPPROTO_UDP		}, /* f goto L30   */ \
113 	{OP_LDH,	0,   0, OFF_DST6		}, /*              */ \
114 	{OP_JEQ,	0,   4, PTP_EV_PORT		}, /* f goto L31   */ \
115 	{OP_LDH,	0,   0, OFF_PTP6		}, /*              */ \
116 	{OP_AND,	0,   0, PTP_CLASS_VMASK		}, /*              */ \
117 	{OP_OR,		0,   0, PTP_CLASS_IPV6		}, /*              */ \
118 	{OP_RETA,	0,   0, 0			}, /*              */ \
119 /*L3x*/	{OP_RETK,	0,   0, PTP_CLASS_NONE		}, /*              */ \
120 /*L40*/	{OP_JEQ,	0,   9, ETH_P_8021Q		}, /* f goto L50   */ \
121 	{OP_LDH,	0,   0, OFF_ETYPE + 4		}, /*              */ \
122 	{OP_JEQ,	0,  15, ETH_P_1588		}, /* f goto L60   */ \
123 	{OP_LDB,	0,   0, ETH_HLEN + VLAN_HLEN	}, /*              */ \
124 	{OP_AND,	0,   0, PTP_GEN_BIT		}, /*              */ \
125 	{OP_JEQ,	0,  12, 0			}, /* f goto L6x   */ \
126 	{OP_LDH,	0,   0, ETH_HLEN + VLAN_HLEN	}, /*              */ \
127 	{OP_AND,	0,   0, PTP_CLASS_VMASK		}, /*              */ \
128 	{OP_OR,		0,   0, PTP_CLASS_VLAN		}, /*              */ \
129 	{OP_RETA,	0,   0, 0			}, /*              */ \
130 /*L50*/	{OP_JEQ,	0,   7, ETH_P_1588		}, /* f goto L61   */ \
131 	{OP_LDB,	0,   0, ETH_HLEN		}, /*              */ \
132 	{OP_AND,	0,   0, PTP_GEN_BIT		}, /*              */ \
133 	{OP_JEQ,	0,   4, 0			}, /* f goto L6x   */ \
134 	{OP_LDH,	0,   0, ETH_HLEN		}, /*              */ \
135 	{OP_AND,	0,   0, PTP_CLASS_VMASK		}, /*              */ \
136 	{OP_OR,		0,   0, PTP_CLASS_L2		}, /*              */ \
137 	{OP_RETA,	0,   0, 0			}, /*              */ \
138 /*L6x*/	{OP_RETK,	0,   0, PTP_CLASS_NONE		},
139 
140 #endif
141