static int lldp_receive_datagram(sd_event_source *s, int fd, uint32_t revents, void *userdata) { _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL; ssize_t space, length; sd_lldp *lldp = userdata; assert(fd >= 0); assert(lldp); space = next_datagram_size_fd(fd); if (space < 0) return log_lldp_errno(space, "Failed to determine datagram size to read: %m"); n = lldp_neighbor_new(space); if (!n) return -ENOMEM; length = recv(fd, LLDP_NEIGHBOR_RAW(n), n->raw_size, MSG_DONTWAIT); if (length < 0) return log_lldp_errno(errno, "Failed to read LLDP datagram: %m"); if ((size_t) length != n->raw_size) { log_lldp("Packet size mismatch."); return -EINVAL; } return lldp_handle_datagram(lldp, n); }
_public_ int sd_lldp_start(sd_lldp *lldp) { int r; assert_return(lldp, -EINVAL); assert_return(lldp->event, -EINVAL); assert_return(lldp->ifindex > 0, -EINVAL); if (lldp->fd >= 0) return 0; assert(!lldp->io_event_source); lldp->fd = lldp_network_bind_raw_socket(lldp->ifindex); if (lldp->fd < 0) return lldp->fd; r = sd_event_add_io(lldp->event, &lldp->io_event_source, lldp->fd, EPOLLIN, lldp_receive_datagram, lldp); if (r < 0) goto fail; r = sd_event_source_set_priority(lldp->io_event_source, lldp->event_priority); if (r < 0) goto fail; (void) sd_event_source_set_description(lldp->io_event_source, "lldp-io"); log_lldp("Started LLDP client"); return 1; fail: lldp_reset(lldp); return r; }
static void lldp_callback(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n) { assert(lldp); log_lldp("Invoking callback for '%c'.", event); if (!lldp->callback) return; lldp->callback(lldp, event, n, lldp->userdata); }
_public_ int sd_lldp_stop(sd_lldp *lldp) { assert_return(lldp, -EINVAL); if (lldp->fd < 0) return 0; log_lldp("Stopping LLDP client"); lldp_reset(lldp); lldp_flush_neighbors(lldp); return 1; }
static int lldp_handle_datagram(sd_lldp *lldp, sd_lldp_neighbor *n) { int r; assert(lldp); assert(n); r = lldp_neighbor_parse(n); if (r == -EBADMSG) /* Ignore bad messages */ return 0; if (r < 0) return r; r = lldp_add_neighbor(lldp, n); if (r < 0) { log_lldp_errno(r, "Failed to add datagram. Ignoring."); return 0; } log_lldp("Successfully processed LLDP datagram."); return 0; }
static int lldp_receive_datagram(sd_event_source *s, int fd, uint32_t revents, void *userdata) { _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL; ssize_t space, length; sd_lldp *lldp = userdata; struct timespec ts; assert(fd >= 0); assert(lldp); space = next_datagram_size_fd(fd); if (space < 0) return log_lldp_errno(space, "Failed to determine datagram size to read: %m"); n = lldp_neighbor_new(space); if (!n) return -ENOMEM; length = recv(fd, LLDP_NEIGHBOR_RAW(n), n->raw_size, MSG_DONTWAIT); if (length < 0) { if (errno == EAGAIN || errno == EINTR) return 0; return log_lldp_errno(errno, "Failed to read LLDP datagram: %m"); } if ((size_t) length != n->raw_size) { log_lldp("Packet size mismatch."); return -EINVAL; } /* Try to get the timestamp of this packet if it is known */ if (ioctl(fd, SIOCGSTAMPNS, &ts) >= 0) triple_timestamp_from_realtime(&n->timestamp, timespec_load(&ts)); else triple_timestamp_get(&n->timestamp); return lldp_handle_datagram(lldp, n); }