#include <string.h>
#include <stdlib.h>
#include <stdio.h>
+#include <fcntl.h>
#include "nmrpd.h"
#if defined(NMRPFLASH_WINDOWS)
pcap_t *pcap;
#ifndef NMRPFLASH_WINDOWS
int fd;
+#ifdef NMRPFLASH_LINUX
+ bool stp;
+#endif
#else
HANDLE handle;
DWORD index;
return true;
}
+#ifdef NMRPFLASH_LINUX
+static int open_stp_state(const char *intf)
+{
+ char name[256];
+ snprintf(name, sizeof(name), "/sys/class/net/%s/bridge/stp_state", intf);
+ return open(name, O_RDWR, 0644);
+}
+
+static bool is_stp_enabled(const char *intf)
+{
+ char c;
+ int fd = open_stp_state(intf);
+ if (fd == -1) {
+ return false;
+ }
+
+ if (read(fd, &c, 1) != 1) {
+ c = '0';
+ }
+
+ close(fd);
+ return c == '1';
+}
+
+static bool set_stp_enabled(const char *intf, bool enabled)
+{
+ bool ret;
+ const char *s = enabled ? "1\n" : "0\n";
+ int fd = open_stp_state(intf);
+ if (fd == -1) {
+ return false;
+ }
+
+ ret = (write(fd, s, 2) == 2);
+ close(fd);
+
+ return ret;
+}
+#endif
+
static bool get_intf_info(const char *intf, uint8_t *hwaddr, void *dummy)
{
struct ifaddrs *ifas, *ifa;
sock->pcap = pcap_open_live(sock->intf, BUFSIZ, 1, 1, buf);
if (!sock->pcap) {
fprintf(stderr, "%s.\n", buf);
- goto cleanup_malloc;
+ goto cleanup;
}
if (*buf) {
if (pcap_datalink(sock->pcap) != DLT_EN10MB) {
fprintf(stderr, "%s is not an ethernet interface.\n",
intf);
- goto cleanup_pcap;
+ goto cleanup;
}
#ifndef NMRPFLASH_WINDOWS
#endif
if (err) {
fprintf(stderr, "Failed to get interface info.\n");
- goto cleanup_malloc;
+ goto cleanup;
}
#ifndef NMRPFLASH_WINDOWS
sock->fd = pcap_get_selectable_fd(sock->pcap);
if (sock->fd == -1) {
pcap_perror(sock->pcap, "pcap_get_selectable_fd");
- goto cleanup_pcap;
+ goto cleanup;
}
#else
sock->handle = pcap_getevent(sock->pcap);
if (!sock->handle) {
pcap_perror(sock->pcap, "pcap_getevent");
- goto cleanup_pcap;
+ goto cleanup;
}
err = pcap_setmintocopy(sock->pcap, 1);
if (err) {
pcap_perror(sock->pcap, "pcap_setmintocopy");
- goto cleanup_pcap;
+ goto cleanup;
}
#endif
err = pcap_compile(sock->pcap, &fp, buf, 0, 0);
if (err) {
pcap_perror(sock->pcap, "pcap_compile");
- goto cleanup_pcap;
+ goto cleanup;
}
err = pcap_setfilter(sock->pcap, &fp);
if (err) {
pcap_perror(sock->pcap, "pcap_setfilter");
- goto cleanup_pcap;
+ goto cleanup;
}
+#ifdef NMRPFLASH_LINUX
+ // nmrpflash does not work on bridge interfaces with STP enabled
+ if ((sock->stp = is_stp_enabled(intf))) {
+ if (!set_stp_enabled(intf, false)) {
+ fprintf(stderr, "Warning: failed to disable STP on %s.\n", intf);
+ }
+ }
+#endif
+
return sock;
-cleanup_pcap:
- pcap_close(sock->pcap);
-cleanup_malloc:
- free(sock);
+cleanup:
+ ethsock_close(sock);
return NULL;
}
int ethsock_close(struct ethsock *sock)
{
- pcap_close(sock->pcap);
+ if (!sock) {
+ return 0;
+ }
+
+#ifdef NMRPFLASH_LINUX
+ if (sock->stp) {
+ set_stp_enabled(sock->intf, true);
+ }
+#endif
+ if (sock->pcap) {
+ pcap_close(sock->pcap);
+ }
+
free(sock);
return 0;
}