#define WPCAP
#include <pcap.h>
#else
-#include <pcap.h>
+#include <sys/ioctl.h>
#include <ifaddrs.h>
+#include <unistd.h>
+#include <net/if.h>
+#include <pcap.h>
#if defined(NMRPFLASH_LINUX)
#define NMRPFLASH_AF_PACKET AF_PACKET
#include <linux/if_packet.h>
int fd;
#else
HANDLE handle;
+ DWORD index;
#endif
unsigned timeout;
uint8_t hwaddr[6];
};
+struct ethsock_ip_undo
+{
+#ifndef NMRPFLASH_WINDOWS
+ uint32_t ip[2];
+#else
+ ULONG context;
+#endif
+};
+
const char *mac_to_str(uint8_t *mac)
{
static char buf[18];
return true;
}
-static bool get_hwaddr_from_intf(const char *intf, uint8_t *hwaddr)
+static bool get_intf_info(const char *intf, uint8_t *hwaddr, void *dummy)
{
struct ifaddrs *ifas, *ifa;
bool found;
}
}
-static bool get_hwaddr_from_intf(const char *intf, uint8_t *hwaddr)
+static bool get_intf_info(const char *intf, uint8_t *hwaddr, DWORD *index)
{
PIP_ADAPTER_INFO adapters, adapter;
DWORD ret;
if ((ret = GetAdaptersInfo(adapters, &bufLen) == NO_ERROR)) {
for (adapter = adapters; adapter; adapter = adapter->Next) {
- if (adapter->Type != MIB_IF_TYPE_ETHERNET) {
+ if (adapter->Type != MIB_IF_TYPE_ETHERNET && adapter->Type != IF_TYPE_IEEE80211) {
continue;
}
* AdapterName from GetAdaptersInfo is just "{GUID}".*/
if (strstr(intf, adapter->AdapterName)) {
if (adapter->AddressLength == 6) {
- for (i = 0; i != 6; ++i) {
- hwaddr[i] = adapter->Address[i];
+ memcpy(hwaddr, adapter->Address, 6);
+ if (index) {
+ *index = adapter->Index;
}
-
found = true;
break;
}
goto cleanup_pcap;
}
- if (!get_hwaddr_from_intf(intf, sock->hwaddr)) {
- fprintf(stderr, "Failed to get MAC address of interface.\n");
+#ifndef NMRPFLASH_WINDOWS
+ err = !get_intf_info(intf, sock->hwaddr, NULL);
+#else
+ err = !get_intf_info(intf, sock->hwaddr, &sock->index);
+#endif
+ if (err) {
+ fprintf(stderr, "Failed to get interface info.\n");
goto cleanup_malloc;
}
#ifndef NMRPFLASH_WINDOWS
sock->fd = pcap_get_selectable_fd(sock->pcap);
if (sock->fd == -1) {
- fprintf(stderr, "No selectable file descriptor available.\n");
+ pcap_perror(sock->pcap, "pcap_get_selectable_fd");
goto cleanup_pcap;
}
#else
sock->handle = pcap_getevent(sock->pcap);
if (!sock->handle) {
- fprintf(stderr, "No event handle available.\n");
+ pcap_perror(sock->pcap, "pcap_getevent");
goto cleanup_pcap;
}
return 0;
}
+#ifndef NMRPFLASH_WINDOWS
+int ethsock_arp_add(struct ethsock *sock, uint8_t *hwaddr, struct in_addr *ipaddr)
+{
+ return 0;
+}
+
+int ethsock_arp_del(struct ethsock *sock, uint8_t *hwaddr, struct in_addr *ipaddr)
+{
+ return 0;
+}
+#else
+static int ethsock_arp(struct ethsock *sock, uint8_t *hwaddr, struct in_addr *ipaddr, int add)
+{
+ DWORD ret;
+ MIB_IPNETROW arp = {
+ .dwIndex = sock->index,
+ .dwPhysAddrLen = 6,
+ .dwAddr = ipaddr->s_addr,
+ .dwType = MIB_IPNET_TYPE_STATIC
+ };
+
+ memcpy(arp.bPhysAddr, hwaddr, 6);
+
+ if (add) {
+ ret = CreateIpNetEntry(&arp);
+ if (ret != NO_ERROR) {
+ win_perror2("CreateIpNetEntry", ret);
+ return -1;
+ }
+ } else {
+ DeleteIpNetEntry(&arp);
+ }
+
+ return 0;
+}
+
+int ethsock_arp_add(struct ethsock *sock, uint8_t *hwaddr, struct in_addr *ipaddr)
+{
+ ethsock_arp_del(sock, hwaddr, ipaddr);
+ return ethsock_arp(sock, hwaddr, ipaddr, 1);
+}
+
+int ethsock_arp_del(struct ethsock *sock, uint8_t *hwaddr, struct in_addr *ipaddr)
+{
+ return ethsock_arp(sock, hwaddr, ipaddr, 0);
+}
+#endif
+
static bool get_hwaddr_from_pcap(const pcap_if_t *dev, uint8_t *hwaddr)
{
#ifndef NMRPFLASH_WINDOWS
}
#endif
- return get_hwaddr_from_intf(dev->name, hwaddr);
+ return get_intf_info(dev->name, hwaddr, NULL);
}
int ethsock_list_all(void)
return status <= 0 ? status : 0;
}
+
+#ifndef NMRPFLASH_WINDOWS
+static inline void set_addr(void *p, uint32_t addr)
+{
+ struct sockaddr_in* sin = p;
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = addr;
+}
+
+static bool set_interface_up(int fd, const char *intf, bool up)
+{
+ struct ifreq ifr;
+ strncpy(ifr.ifr_name, intf, IFNAMSIZ);
+
+ if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) {
+ perror("ioctl(SIOCGIFFLAGS)");
+ return false;
+ }
+
+ if (!up) {
+ ifr.ifr_flags &= ~(IFF_UP | IFF_RUNNING);
+ } else {
+ ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
+ }
+
+ if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) {
+ perror("ioctl(SIOCSIFFLAGS)");
+ return false;
+ }
+
+ return true;
+}
+
+#endif
+
+int ethsock_ip_add(struct ethsock *sock, uint32_t ipaddr, uint32_t ipmask, struct ethsock_ip_undo **undo)
+{
+ if (undo && !(*undo = malloc(sizeof(struct ethsock_ip_undo)))) {
+ perror("malloc");
+ return -1;
+ }
+
+#ifndef NMRPFLASH_WINDOWS
+ int ret = -1;
+ int fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (!fd) {
+ perror("socket");
+ return -1;
+ }
+
+#ifdef NMRPFLASH_LINUX
+ struct ifreq ifr;
+ strncpy(ifr.ifr_name, sock->intf, IFNAMSIZ);
+ // FIXME: automatically determine the next free alias
+ strcat(ifr.ifr_name, ":42");
+
+ // XXX: undo is non-zero only if we're actually adding an ip
+ if (undo) {
+ set_addr(&ifr.ifr_addr, ipaddr);
+ if (ioctl(fd, SIOCSIFADDR, &ifr) != 0) {
+ perror("ioctl(SIOSIFADDR)");
+ goto out;
+ }
+
+ set_addr(&ifr.ifr_netmask, ipmask);
+ if (ioctl(fd, SIOCSIFNETMASK, &ifr) != 0) {
+ perror("ioctl(SIOCSIFNETMASK)");
+ goto out;
+ }
+
+ (*undo)->ip[0] = ipaddr;
+ (*undo)->ip[1] = ipmask;
+ }
+
+ if (!set_interface_up(fd, ifr.ifr_name, undo ? true : false)) {
+ goto out;
+ }
+#else // NMRPFLASH_OSX (or any other BSD)
+ struct ifaliasreq ifra;
+ strncpy(ifra.ifra_name, sock->intf, IFNAMSIZ);
+
+ set_addr(&ifra.ifra_addr, ipaddr);
+ set_addr(&ifra.ifra_mask, ipmask);
+ //set_addr(&ifra.ifra_broadaddr, (ipaddr & ipmask) | ~ipmask);
+ memset(&ifra.ifra_broadaddr, 0, sizeof(ifra.ifra_broadaddr));
+
+ // XXX: undo is non-zero only if we're actually adding an ip
+
+ if (ioctl(fd, undo ? SIOCAIFADDR : SIOCDIFADDR, &ifra) != 0) {
+ perror("ioctl(SIOCAIFADDR)");
+ goto out;
+ }
+
+ if (undo) {
+ (*undo)->ip[0] = ipaddr;
+ (*undo)->ip[1] = ipmask;
+ set_interface_up(fd, ifra.ifra_name, true);
+ }
+
+#endif
+ ret = 0;
+
+out:
+ close(fd);
+ return ret;
+#else // NMRPFLASH_WINDOWS
+ ULONG instance;
+
+ (*undo)->context = 0;
+
+ DWORD ret = AddIPAddress(ipaddr, ipmask, sock->index, &(*undo)->context, &instance);
+ if (ret != NO_ERROR && ret != ERROR_DUP_DOMAINNAME && ret != ERROR_OBJECT_ALREADY_EXISTS) {
+ win_perror2("AddIPAddress", ret);
+ return -1;
+ }
+
+ return 0;
+#endif
+}
+
+int ethsock_ip_del(struct ethsock *sock, struct ethsock_ip_undo **undo)
+{
+ if (!*undo) {
+ return 0;
+ }
+
+ int ret;
+
+#ifndef NMRPFLASH_WINDOWS
+ if ((*undo)->ip[0] != INADDR_NONE) {
+ ret = ethsock_ip_add(sock, (*undo)->ip[0], (*undo)->ip[1], NULL);
+ } else {
+ ret = 0;
+ }
+#else
+ DeleteIPAddress((*undo)->context);
+ ret = 0;
+#endif
+
+ free(*undo);
+ *undo = NULL;
+ return ret;
+}