]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
ad1ad5c8 SS |
2 | |
3 | #include <linux/filter.h> | |
e306723e | 4 | #include <netinet/if_ether.h> |
ad1ad5c8 | 5 | |
3ffd4af2 | 6 | #include "fd-util.h" |
3ffd4af2 | 7 | #include "lldp-network.h" |
f5947a5e | 8 | #include "missing_network.h" |
3ffd4af2 | 9 | #include "socket-util.h" |
ad1ad5c8 SS |
10 | |
11 | int lldp_network_bind_raw_socket(int ifindex) { | |
ad1ad5c8 | 12 | |
35897745 LP |
13 | static const struct sock_filter filter[] = { |
14 | BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ethhdr, h_dest)), /* A <- 4 bytes of destination MAC */ | |
ad1ad5c8 SS |
15 | BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0180c200, 1, 0), /* A != 01:80:c2:00 */ |
16 | BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */ | |
35897745 | 17 | BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ethhdr, h_dest) + 4), /* A <- remaining 2 bytes of destination MAC */ |
ad1ad5c8 SS |
18 | BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0000, 3, 0), /* A != 00:00 */ |
19 | BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0003, 2, 0), /* A != 00:03 */ | |
20 | BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x000e, 1, 0), /* A != 00:0e */ | |
21 | BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */ | |
35897745 | 22 | BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ethhdr, h_proto)), /* A <- protocol */ |
ad1ad5c8 SS |
23 | BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_LLDP, 1, 0), /* A != ETHERTYPE_LLDP */ |
24 | BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */ | |
25 | BPF_STMT(BPF_RET + BPF_K, (uint32_t) -1), /* accept packet */ | |
26 | }; | |
27 | ||
35897745 | 28 | static const struct sock_fprog fprog = { |
ad1ad5c8 | 29 | .len = ELEMENTSOF(filter), |
35897745 | 30 | .filter = (struct sock_filter*) filter, |
ad1ad5c8 SS |
31 | }; |
32 | ||
6f844e3a MK |
33 | struct packet_mreq mreq = { |
34 | .mr_ifindex = ifindex, | |
35 | .mr_type = PACKET_MR_MULTICAST, | |
36 | .mr_alen = ETH_ALEN, | |
37 | .mr_address = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x00 } | |
38 | }; | |
39 | ||
ad1ad5c8 SS |
40 | union sockaddr_union saddrll = { |
41 | .ll.sll_family = AF_PACKET, | |
42 | .ll.sll_ifindex = ifindex, | |
43 | }; | |
44 | ||
35897745 | 45 | _cleanup_close_ int fd = -1; |
ad1ad5c8 SS |
46 | int r; |
47 | ||
48 | assert(ifindex > 0); | |
49 | ||
8e38570e LP |
50 | fd = socket(PF_PACKET, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, |
51 | htobe16(ETHERTYPE_LLDP)); | |
35897745 | 52 | if (fd < 0) |
ad1ad5c8 SS |
53 | return -errno; |
54 | ||
35897745 | 55 | r = setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)); |
ad1ad5c8 SS |
56 | if (r < 0) |
57 | return -errno; | |
58 | ||
6f844e3a MK |
59 | r = setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); |
60 | if (r < 0) | |
61 | return -errno; | |
62 | ||
63 | mreq.mr_address[ETH_ALEN - 1] = 0x03; | |
64 | r = setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); | |
65 | if (r < 0) | |
66 | return -errno; | |
67 | ||
68 | mreq.mr_address[ETH_ALEN - 1] = 0x0E; | |
69 | r = setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); | |
70 | if (r < 0) | |
71 | return -errno; | |
72 | ||
35897745 | 73 | r = bind(fd, &saddrll.sa, sizeof(saddrll.ll)); |
ad1ad5c8 SS |
74 | if (r < 0) |
75 | return -errno; | |
76 | ||
c10d6bdb | 77 | return TAKE_FD(fd); |
ad1ad5c8 | 78 | } |