@@ -5821,6 +5821,62 @@ iface_get_arptype(int fd, const char *device, char *ebuf)
58215821 return ifr .ifr_hwaddr .sa_family ;
58225822}
58235823
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+
58245880static int
58255881fix_program (pcap_t * handle , struct sock_fprog * fcode )
58265882{
@@ -5847,6 +5903,17 @@ fix_program(pcap_t *handle, struct sock_fprog *fcode)
58475903 fcode -> len = len ;
58485904 fcode -> filter = (struct sock_filter * ) f ;
58495905
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+
58505917 for (i = 0 ; i < len ; ++ i ) {
58515918 p = & f [i ];
58525919 /*
0 commit comments