1 #include <netinet/if_ether.h>
2 #include <sys/socket.h>
11 #if defined(_WIN32) || defined(_WIN64)
12 #define NMRPFLASH_WINDOWS
13 #elif defined(__linux__)
14 #define NMRPFLASH_LINUX
15 #elif defined(__APPLE__) && defined(__MACH__)
17 #elif defined(__unix__)
18 #define NMRPFLASH_UNIX
19 #warning "nmrp-flash is not fully supported on your operating system"
22 #if defined(NMRPFLASH_WINDOWS)
27 #if defined(NMRPFLASH_LINUX)
28 #include <linux/if_packet.h>
29 #elif defined (NMRPFLASH_OSX)
30 #include <net/if_dl.h>
35 #define MIN(a, b) ((a) < (b) ? (a) : (b))
41 struct timeval timeout;
46 #ifndef NMRPFLASH_WINDOWS
47 static bool get_hwaddr(uint8_t *hwaddr, const char *interface)
49 struct ifaddrs *ifas, *ifa;
53 if (getifaddrs(&ifas) != 0) {
60 for (ifa = ifas; ifa; ifa = ifa->ifa_next) {
61 if (!strcmp(ifa->ifa_name, interface)) {
62 #ifdef NMRPFLASH_LINUX
63 if (ifa->ifa_addr->sa_family != AF_PACKET) {
66 src = ((struct sockaddr_ll*)ifa->ifa_addr)->sll_addr;
68 if (ifa->ifa_addr->sa_family != AF_LINK) {
71 src = LLADDR((struct sockaddr_dl*)ifa->ifa_addr);
73 memcpy(hwaddr, src, 6);
83 static bool get_hwaddr(uint8_t *hwaddr, const char *interface)
85 PIP_ADAPTER_INFO adapters, adapter;
90 if ((ret = GetAdaptersInfo(NULL, &bufLen)) != ERROR_BUFFER_OVERFLOW) {
91 fprintf(stderr, "GetAdaptersInfo: error %d.\n", ret);
95 adapters = malloc(bufLen);
101 if ((ret = GetAdaptersInfo(adapters, bufLen) == NO_ERROR)) {
102 for (adapter = adapters; adapter; adapter = adapter->Next) {
103 if (adapter->Type != MIB_IF_TYPE_ETHERNET) {
107 if (!strcmp(adapter->AdapterName, interface)) {
108 if (adapter->AddressLength == 6) {
109 for (i = 0; i != 6; ++i) {
110 hwaddr[i] = adapter->Address[i];
119 fprintf(stderr, "GetAdaptersInfo: error %d.\n", ret);
128 inline uint8_t *ethsock_get_hwaddr(struct ethsock *sock)
133 struct ethsock *ethsock_create(const char *interface, uint16_t protocol)
135 char buf[PCAP_ERRBUF_SIZE];
136 struct bpf_program fp;
137 struct ethsock *sock;
140 sock = malloc(sizeof(struct ethsock));
148 sock->pcap = pcap_open_live(interface, BUFSIZ, 1, 1, buf);
150 fprintf(stderr, "%s.\n", buf);
155 fprintf(stderr, "Warning: %s.\n", buf);
158 if (pcap_datalink(sock->pcap) != DLT_EN10MB) {
159 fprintf(stderr, "Interface %s is not an ethernet interface.\n",
164 if (!get_hwaddr(sock->hwaddr, interface)) {
165 fprintf(stderr, "Failed to get MAC address of interface.\n");
169 sock->fd = pcap_get_selectable_fd(sock->pcap);
170 if (sock->fd == -1) {
171 fprintf(stderr, "No selectable file descriptor available.\n");
175 snprintf(buf, sizeof(buf), "ether proto %04x", protocol);
176 err = pcap_compile(sock->pcap, &fp, buf, 0, PCAP_NETMASK_UNKNOWN);
178 pcap_perror(sock->pcap, "pcap_compile");
182 if ((err = pcap_setfilter(sock->pcap, &fp))) {
183 pcap_perror(sock->pcap, "pcap_setfilter");
190 pcap_close(sock->pcap);
196 ssize_t ethsock_recv(struct ethsock *sock, void *buf, size_t len)
198 struct pcap_pkthdr* hdr;
199 const u_char *capbuf;
203 if (sock->timeout.tv_sec || sock->timeout.tv_usec) {
205 FD_SET(sock->fd, &fds);
207 status = select(sock->fd + 1, &fds, NULL, NULL, &sock->timeout);
211 } else if (status == 0) {
216 status = pcap_next_ex(sock->pcap, &hdr, &capbuf);
219 memcpy(buf, capbuf, MIN(len, hdr->caplen));
224 pcap_perror(sock->pcap, "pcap_next_ex");
227 fprintf(stderr, "pcap_next_ex: returned %d.\n", status);
232 int ethsock_send(struct ethsock *sock, void *buf, size_t len)
234 #ifdef NMRPFLASH_WINDOWS
235 if (pcap_sendpacket(sock->pcap, buf, len) == 0) {
238 pcap_perror(sock->pcap, "pcap_sendpacket");
242 if (pcap_inject(sock->pcap, buf, len) == len) {
245 pcap_perror(sock->pcap, "pcap_inject");
251 int ethsock_close(struct ethsock *sock)
253 pcap_close(sock->pcap);
258 int ethsock_set_timeout(struct ethsock *sock, unsigned msec)
260 sock->timeout.tv_sec = msec / 1000;
261 sock->timeout.tv_usec = (msec % 1000) * 1000;
265 static bool is_ethernet(const char *interface)
268 char errbuf[PCAP_ERRBUF_SIZE];
271 if ((pcap = pcap_create(interface, errbuf))) {
272 if (pcap_activate(pcap) == 0) {
273 ret = (pcap_datalink(pcap) == DLT_EN10MB);
281 int ethsock_list_all(void)
283 pcap_if_t *devs, *dev;
285 char errbuf[PCAP_ERRBUF_SIZE];
287 if (pcap_findalldevs(&devs, errbuf) != 0) {
288 fprintf(stderr, "%s.\n", errbuf);
292 memset(hwaddr, 0, 6);
294 for (dev = devs; dev; dev = dev->next) {
295 if (dev->flags & PCAP_IF_LOOPBACK) {
299 if (!is_ethernet(dev->name)) {
303 if (!get_hwaddr(hwaddr, dev->name)) {
307 printf("%s %02x:%02x:%02x:%02x:%02x:%02x", dev->name, hwaddr[0],
308 hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);
310 if (dev->description) {
311 printf(" (%s)\n", dev->description);