]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/lldp-network.c
tree-wide: htonl() is weird, let's use htobe32() instead (#3538)
[thirdparty/systemd.git] / src / libsystemd-network / lldp-network.c
CommitLineData
ad1ad5c8
SS
1/***
2 This file is part of systemd.
3
4 Copyright (C) 2014 Tom Gundersen
5 Copyright (C) 2014 Susant Sahani
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
21#include <linux/filter.h>
e306723e 22#include <netinet/if_ether.h>
ad1ad5c8 23
3ffd4af2 24#include "fd-util.h"
3ffd4af2 25#include "lldp-network.h"
3ffd4af2 26#include "socket-util.h"
ad1ad5c8
SS
27
28int lldp_network_bind_raw_socket(int ifindex) {
ad1ad5c8 29
35897745
LP
30 static const struct sock_filter filter[] = {
31 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ethhdr, h_dest)), /* A <- 4 bytes of destination MAC */
ad1ad5c8
SS
32 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0180c200, 1, 0), /* A != 01:80:c2:00 */
33 BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */
35897745 34 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ethhdr, h_dest) + 4), /* A <- remaining 2 bytes of destination MAC */
ad1ad5c8
SS
35 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0000, 3, 0), /* A != 00:00 */
36 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0003, 2, 0), /* A != 00:03 */
37 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x000e, 1, 0), /* A != 00:0e */
38 BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */
35897745 39 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ethhdr, h_proto)), /* A <- protocol */
ad1ad5c8
SS
40 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_LLDP, 1, 0), /* A != ETHERTYPE_LLDP */
41 BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */
42 BPF_STMT(BPF_RET + BPF_K, (uint32_t) -1), /* accept packet */
43 };
44
35897745 45 static const struct sock_fprog fprog = {
ad1ad5c8 46 .len = ELEMENTSOF(filter),
35897745 47 .filter = (struct sock_filter*) filter,
ad1ad5c8
SS
48 };
49
ad1ad5c8
SS
50 union sockaddr_union saddrll = {
51 .ll.sll_family = AF_PACKET,
52 .ll.sll_ifindex = ifindex,
53 };
54
35897745 55 _cleanup_close_ int fd = -1;
ad1ad5c8
SS
56 int r;
57
58 assert(ifindex > 0);
59
8e38570e
LP
60 fd = socket(PF_PACKET, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK,
61 htobe16(ETHERTYPE_LLDP));
35897745 62 if (fd < 0)
ad1ad5c8
SS
63 return -errno;
64
35897745 65 r = setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog));
ad1ad5c8
SS
66 if (r < 0)
67 return -errno;
68
35897745 69 r = bind(fd, &saddrll.sa, sizeof(saddrll.ll));
ad1ad5c8
SS
70 if (r < 0)
71 return -errno;
72
35897745
LP
73 r = fd;
74 fd = -1;
ad1ad5c8
SS
75
76 return r;
77}