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);
80 fprintf(stderr, "Failed to get MAC address of interface %s.\n", interface);
87 static bool get_hwaddr(uint8_t *hwaddr, const char *interface)
89 PIP_ADAPTER_INFO adapters, adapter;
94 if ((ret = GetAdaptersInfo(NULL, &bufLen)) != ERROR_BUFFER_OVERFLOW) {
95 fprintf(stderr, "GetAdaptersInfo: error %d.\n", ret);
99 adapters = malloc(bufLen);
105 if ((ret = GetAdaptersInfo(adapters, bufLen) == NO_ERROR)) {
106 for (adapter = adapters; adapter; adapter = adapter->Next) {
107 if (adapter->Type != MIB_IF_TYPE_ETHERNET) {
111 if (!strcmp(adapter->AdapterName, interface)) {
112 for (i = 0; i != MIN(adapter->AddressLength, 6); ++i) {
113 hwaddr[i] = adapter->Address[i];
121 fprintf(stderr, "GetAdaptersInfo: error %d.\n", ret);
130 inline uint8_t *ethsock_get_hwaddr(struct ethsock *sock)
135 struct ethsock *ethsock_create(const char *interface, uint16_t protocol)
137 char buf[PCAP_ERRBUF_SIZE];
138 struct bpf_program fp;
139 struct ethsock *sock;
142 sock = malloc(sizeof(struct ethsock));
148 if (!get_hwaddr(sock->hwaddr, interface)) {
154 sock->pcap = pcap_open_live(interface, BUFSIZ, 1, 1, buf);
156 fprintf(stderr, "%s.\n", buf);
161 fprintf(stderr, "Warning: %s.\n", buf);
164 if (pcap_datalink(sock->pcap) != DLT_EN10MB) {
165 fprintf(stderr, "Interface %s not supported.\n", interface);
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 int ethsock_list_all(void)
267 pcap_if_t *devs, *dev;
269 char errbuf[PCAP_ERRBUF_SIZE];
271 if (pcap_findalldevs(&devs, errbuf) != 0) {
272 fprintf(stderr, "%s.\n", errbuf);
276 for (dev = devs; dev; dev = dev->next) {
277 get_hwaddr(hwaddr, dev->name);
278 printf("%02x:%02x:%02x:%02x:%02x:%02x %s",
279 hwaddr[0], hwaddr[1], hwaddr[2],
280 hwaddr[3], hwaddr[4], hwaddr[5],
283 if (dev->description) {
284 printf(" (%s)\n", dev->description);