@@ -5821,6 +5821,62 @@ iface_get_arptype(int fd, const char *device, char *ebuf)
5821
5821
return ifr .ifr_hwaddr .sa_family ;
5822
5822
}
5823
5823
5824
+ /*
5825
+ * In a DLT_CAN_SOCKETCAN frame the first four bytes are a 32-bit integer
5826
+ * value in host byte order if the filter program is running in the kernel and
5827
+ * in network byte order if in userland. This applies to both CC, FD and XL
5828
+ * frames, see pcap_handle_packet_mmap() for the rationale. Return 1 iff the
5829
+ * [possibly modified] filter program can work correctly in the kernel.
5830
+ */
5831
+ #if __BYTE_ORDER == __LITTLE_ENDIAN
5832
+ static int
5833
+ fix_dlt_can_socketcan (const u_int len , struct bpf_insn insn [])
5834
+ {
5835
+ for (u_int i = 0 ; i < len ; ++ i ) {
5836
+ switch (insn [i ].code ) {
5837
+ case BPF_LD |BPF_B |BPF_ABS : // ldb [k]
5838
+ case BPF_LDX |BPF_MSH |BPF_B : // ldxb 4*([k]&0xf)
5839
+ if (insn [i ].k < 4 )
5840
+ insn [i ].k = 3 - insn [i ].k ; // Fixed now.
5841
+ break ;
5842
+ case BPF_LD |BPF_H |BPF_ABS : // ldh [k]
5843
+ case BPF_LD |BPF_W |BPF_ABS : // ld [k]
5844
+ /*
5845
+ * A halfword or a word load cannot be fixed by just
5846
+ * changing k, even if every required byte is within
5847
+ * the byte-swapped part of the frame, even if the
5848
+ * load is aligned. The fix would require either
5849
+ * rewriting the filter program extensively or
5850
+ * generating it differently in the first place.
5851
+ */
5852
+ case BPF_LD |BPF_B |BPF_IND : // ldb [x + k]
5853
+ case BPF_LD |BPF_H |BPF_IND : // ldh [x + k]
5854
+ case BPF_LD |BPF_W |BPF_IND : // ld [x + k]
5855
+ /*
5856
+ * In addition to the above, a variable offset load
5857
+ * cannot be fixed because x can have any value, thus
5858
+ * x + k can have any value, but only the first four
5859
+ * bytes are swapped. An easy way to demonstrate it
5860
+ * is to compile "link[link[4]] == 0", which will use
5861
+ * "ldb [x + 0]" to access one of the first four bytes
5862
+ * of the frame iff CAN CC/FD payload length is less
5863
+ * than 4.
5864
+ */
5865
+ if (insn [i ].k < 4 )
5866
+ return 0 ; // Userland filtering only.
5867
+ break ;
5868
+ }
5869
+ }
5870
+ return 1 ;
5871
+ }
5872
+ #else
5873
+ static int
5874
+ fix_dlt_can_socketcan (const u_int len _U_ , struct bpf_insn insn [] _U_ )
5875
+ {
5876
+ return 1 ;
5877
+ }
5878
+ #endif // __BYTE_ORDER == __LITTLE_ENDIAN
5879
+
5824
5880
static int
5825
5881
fix_program (pcap_t * handle , struct sock_fprog * fcode )
5826
5882
{
@@ -5847,6 +5903,17 @@ fix_program(pcap_t *handle, struct sock_fprog *fcode)
5847
5903
fcode -> len = len ;
5848
5904
fcode -> filter = (struct sock_filter * ) f ;
5849
5905
5906
+ switch (handle -> linktype ) {
5907
+ case DLT_CAN_SOCKETCAN :
5908
+ /*
5909
+ * If a similar fix needs to be done for CAN frames that
5910
+ * appear on the "any" pseudo-interface, it needs to be done
5911
+ * differently because that would be within DLT_LINUX_SLL or
5912
+ * DLT_LINUX_SLL2.
5913
+ */
5914
+ return fix_dlt_can_socketcan (len , f );
5915
+ }
5916
+
5850
5917
for (i = 0 ; i < len ; ++ i ) {
5851
5918
p = & f [i ];
5852
5919
/*
0 commit comments