]> git.ipfire.org Git - thirdparty/lldpd.git/blame - src/daemon/interfaces-bpf.c
build: run cross-platforms test on ubuntu-latest
[thirdparty/lldpd.git] / src / daemon / interfaces-bpf.c
CommitLineData
c3e340b6
VB
1/* -*- mode: c; c-file-style: "openbsd" -*- */
2/*
3 * Copyright (c) 2013 Vincent Bernat <bernat@luffy.cx>
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include "lldpd.h"
19#include <unistd.h>
92a6138d 20#include <errno.h>
c3e340b6
VB
21#include <net/bpf.h>
22
23struct bpf_buffer {
8b549648 24 size_t len; /* Total length of the buffer */
eeb66a08 25 struct bpf_hdr data[0];
c3e340b6
VB
26};
27
28int
8b549648 29ifbpf_phys_init(struct lldpd *cfg, struct lldpd_hardware *hardware)
c3e340b6
VB
30{
31 struct bpf_buffer *buffer = NULL;
32 int fd = -1;
33
8b549648 34 log_debug("interfaces", "initialize ethernet device %s", hardware->h_ifname);
8b50be7f 35 if ((fd = priv_iface_init(hardware->h_ifindex, hardware->h_ifname)) == -1)
c3e340b6
VB
36 return -1;
37
38 /* Allocate receive buffer */
8b549648
VB
39 hardware->h_data = buffer = malloc(ETHER_MAX_LEN +
40 BPF_WORDALIGN(sizeof(struct bpf_hdr)) + sizeof(struct bpf_buffer));
c3e340b6 41 if (buffer == NULL) {
8b549648 42 log_warn("interfaces", "unable to allocate buffer space for BPF on %s",
c3e340b6
VB
43 hardware->h_ifname);
44 goto end;
45 }
7b4eb194 46 buffer->len = ETHER_MAX_LEN + BPF_WORDALIGN(sizeof(struct bpf_hdr));
c3e340b6
VB
47
48 /* Setup multicast */
49 interfaces_setup_multicast(cfg, hardware->h_ifname, 0);
50
51 hardware->h_sendfd = fd; /* Send */
52
53 levent_hardware_add_fd(hardware, fd); /* Receive */
54 log_debug("interfaces", "interface %s initialized (fd=%d)", hardware->h_ifname,
55 fd);
56 return 0;
57
58end:
59 if (fd >= 0) close(fd);
60 free(buffer);
61 hardware->h_data = NULL;
62 return -1;
63}
64
65/* Ethernet send/receive through BPF */
66static int
8b549648
VB
67ifbpf_eth_send(struct lldpd *cfg, struct lldpd_hardware *hardware, char *buffer,
68 size_t size)
c3e340b6
VB
69{
70 log_debug("interfaces", "send PDU to ethernet device %s (fd=%d)",
71 hardware->h_ifname, hardware->h_sendfd);
8b549648 72 return write(hardware->h_sendfd, buffer, size);
c3e340b6
VB
73}
74
75static int
8b549648
VB
76ifbpf_eth_recv(struct lldpd *cfg, struct lldpd_hardware *hardware, int fd, char *buffer,
77 size_t size)
c3e340b6
VB
78{
79 struct bpf_buffer *bpfbuf = hardware->h_data;
80 struct bpf_hdr *bh;
81 log_debug("interfaces", "receive PDU from ethernet device %s",
82 hardware->h_ifname);
83
84 /* We assume we have only receive one packet (unbuffered mode). Dunno if
85 * this is correct. */
86 if (read(fd, bpfbuf->data, bpfbuf->len) == -1) {
afd49b83 87 if (errno == ENETDOWN) {
8b549648
VB
88 log_debug("interfaces",
89 "error while receiving frame on %s (network down)",
afd49b83
VB
90 hardware->h_ifname);
91 } else {
92 log_warn("interfaces", "error while receiving frame on %s",
93 hardware->h_ifname);
94 hardware->h_rx_discarded_cnt++;
95 }
c3e340b6
VB
96 return -1;
97 }
8b549648
VB
98 bh = (struct bpf_hdr *)bpfbuf->data;
99 if (bh->bh_caplen < size) size = bh->bh_caplen;
eeb66a08 100 memcpy(buffer, (char *)bpfbuf->data + bh->bh_hdrlen, size);
c3e340b6
VB
101
102 return size;
103}
104
105static int
106ifbpf_eth_close(struct lldpd *cfg, struct lldpd_hardware *hardware)
107{
8b549648 108 log_debug("interfaces", "close ethernet device %s", hardware->h_ifname);
c3e340b6
VB
109 interfaces_setup_multicast(cfg, hardware->h_ifname, 1);
110 return 0;
111}
112
113struct lldpd_ops bpf_ops = {
114 .send = ifbpf_eth_send,
115 .recv = ifbpf_eth_recv,
116 .cleanup = ifbpf_eth_close,
117};