Skip to content

Commit 46641a7

Browse files
committed
Add ARP responder to tap_darwin, improve evloop test
1 parent 530f5a5 commit 46641a7

File tree

3 files changed

+154
-8
lines changed

3 files changed

+154
-8
lines changed

src/port/posix/tap_darwin.c

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@
5252
#ifndef ETH_P_IP
5353
#define ETH_P_IP ETHERTYPE_IP
5454
#endif
55+
#ifndef ETHERTYPE_ARP
56+
#define ETHERTYPE_ARP 0x0806
57+
#endif
5558

5659
#define PACKED __attribute__((packed))
5760
#define AF_HDR_SIZE 4
@@ -65,6 +68,34 @@ struct eth_hdr {
6568
static int utun_fd = -1;
6669
static uint8_t peer_mac[6] = {0x06, 0x00, 0x00, 0x00, 0x00, 0x01};
6770
static pthread_mutex_t utun_lock = PTHREAD_MUTEX_INITIALIZER;
71+
static uint8_t pending_frame[LINK_MTU + sizeof(struct eth_hdr)];
72+
static size_t pending_len = 0;
73+
static pthread_mutex_t pending_lock = PTHREAD_MUTEX_INITIALIZER;
74+
static uint32_t host_ip_be;
75+
static uint32_t peer_ip_be;
76+
77+
struct arp_packet {
78+
uint16_t htype;
79+
uint16_t ptype;
80+
uint8_t hlen;
81+
uint8_t plen;
82+
uint16_t opcode;
83+
uint8_t sha[6];
84+
uint32_t spa;
85+
uint8_t tha[6];
86+
uint32_t tpa;
87+
} PACKED;
88+
89+
static int enqueue_frame(const void *frame, size_t len)
90+
{
91+
if (len > sizeof(pending_frame))
92+
return -1;
93+
pthread_mutex_lock(&pending_lock);
94+
memcpy(pending_frame, frame, len);
95+
pending_len = len;
96+
pthread_mutex_unlock(&pending_lock);
97+
return 0;
98+
}
6899

69100
static int tap_poll(struct wolfIP_ll_dev *ll, void *buf, uint32_t len)
70101
{
@@ -77,6 +108,18 @@ static int tap_poll(struct wolfIP_ll_dev *ll, void *buf, uint32_t len)
77108
if (utun_fd < 0)
78109
return -1;
79110

111+
pthread_mutex_lock(&pending_lock);
112+
if (pending_len > 0) {
113+
size_t to_copy = pending_len;
114+
if (to_copy > len)
115+
to_copy = len;
116+
memcpy(buf, pending_frame, to_copy);
117+
pending_len = 0;
118+
pthread_mutex_unlock(&pending_lock);
119+
return (int)to_copy;
120+
}
121+
pthread_mutex_unlock(&pending_lock);
122+
80123
pfd.fd = utun_fd;
81124
pfd.events = POLLIN;
82125

@@ -109,6 +152,7 @@ static int tap_send(struct wolfIP_ll_dev *ll, void *buf, uint32_t len)
109152
uint8_t tmp[LINK_MTU + AF_HDR_SIZE];
110153
struct eth_hdr *eth;
111154
size_t ip_len;
155+
struct arp_packet *arp;
112156
uint32_t af;
113157
(void)ll;
114158

@@ -117,6 +161,35 @@ static int tap_send(struct wolfIP_ll_dev *ll, void *buf, uint32_t len)
117161
if (len < sizeof(struct eth_hdr))
118162
return 0;
119163
eth = (struct eth_hdr *)buf;
164+
if (ntohs(eth->type) == ETHERTYPE_ARP) {
165+
if (len < sizeof(struct eth_hdr) + sizeof(struct arp_packet))
166+
return (int)len;
167+
arp = (struct arp_packet *)(eth + 1);
168+
if (ntohs(arp->opcode) == 1 /* request */ &&
169+
arp->tpa == host_ip_be) {
170+
struct {
171+
struct eth_hdr eth;
172+
struct arp_packet arp;
173+
} PACKED reply;
174+
memset(&reply, 0, sizeof(reply));
175+
memcpy(reply.eth.dst, eth->src, sizeof(reply.eth.dst));
176+
memcpy(reply.eth.src, peer_mac, sizeof(reply.eth.src));
177+
reply.eth.type = htons(ETHERTYPE_ARP);
178+
reply.arp.htype = htons(1);
179+
reply.arp.ptype = htons(ETHERTYPE_IP);
180+
reply.arp.hlen = 6;
181+
reply.arp.plen = 4;
182+
reply.arp.opcode = htons(2);
183+
memcpy(reply.arp.sha, peer_mac, sizeof(reply.arp.sha));
184+
reply.arp.spa = host_ip_be;
185+
memcpy(reply.arp.tha, arp->sha, sizeof(reply.arp.tha));
186+
reply.arp.tpa = arp->spa;
187+
printf("tap_darwin: answering ARP request locally\n");
188+
enqueue_frame(&reply, sizeof(reply));
189+
return (int)len;
190+
}
191+
return (int)len;
192+
}
120193
if (ntohs(eth->type) != ETH_P_IP)
121194
return (int)len;
122195

@@ -155,6 +228,8 @@ static int tap_setup_ipv4(const char *ifname, uint32_t host_ip, uint32_t peer_ip
155228
if (!inet_ntop(AF_INET, &netmask, netmask_str, sizeof(netmask_str)))
156229
return -1;
157230

231+
printf("tap_setup_ipv4: ifname=%s local=%s peer=%s\n", ifname, local_str, peer_str);
232+
158233
snprintf(cmd, sizeof(cmd), "/sbin/ifconfig %s inet %s %s netmask %s up",
159234
ifname, local_str, peer_str, netmask_str);
160235
if (system(cmd) != 0)
@@ -173,7 +248,10 @@ int tap_init(struct wolfIP_ll_dev *ll, const char *requested_ifname, uint32_t ho
173248
struct sockaddr_ctl sc;
174249
char ifname_buf[IFNAMSIZ];
175250
socklen_t optlen;
176-
uint32_t peer_ip = atoip4(WOLFIP_IP);
251+
uint32_t peer_ip = htonl(atoip4(WOLFIP_IP));
252+
host_ip_be = host_ip;
253+
peer_ip_be = peer_ip;
254+
printf("tap_init: host_ip=0x%08x peer_ip=0x%08x\n", host_ip_be, peer_ip_be);
177255
(void)requested_ifname;
178256

179257
utun_fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);

src/test/test_eventloop.c

Lines changed: 72 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@
2525
#include <stdlib.h>
2626
#include <sys/time.h>
2727
#include <unistd.h>
28+
#include <fcntl.h>
2829
#include <string.h>
2930
#include <errno.h>
31+
#include <sys/select.h>
3032
#include <sys/socket.h>
3133
#include <sys/types.h>
3234
#include "config.h"
@@ -209,6 +211,11 @@ void *pt_echoclient(void *arg)
209211
unsigned i;
210212
uint8_t local_buf[BUFFER_SIZE];
211213
uint32_t *srv_addr = (uint32_t *)arg;
214+
int old_flags = -1;
215+
fd_set wfds, rfds;
216+
struct timeval tv;
217+
socklen_t errlen;
218+
int err;
212219
struct sockaddr_in remote_sock = {
213220
.sin_family = AF_INET,
214221
.sin_port = ntohs(8), /* Echo */
@@ -222,20 +229,80 @@ void *pt_echoclient(void *arg)
222229
sleep(1);
223230
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int));
224231
printf("Connecting to echo server\n");
232+
old_flags = fcntl(fd, F_GETFL, 0);
233+
if (old_flags < 0) {
234+
perror("fcntl(F_GETFL)");
235+
close(fd);
236+
return (void *)-1;
237+
}
238+
if (fcntl(fd, F_SETFL, old_flags | O_NONBLOCK) < 0) {
239+
perror("fcntl(F_SETFL)");
240+
close(fd);
241+
return (void *)-1;
242+
}
225243
ret = connect(fd, (struct sockaddr *)&remote_sock, sizeof(remote_sock));
226244
if (ret < 0) {
227-
printf("test client connect: %d\n", ret);
228-
perror("connect");
229-
return (void *)-1;
245+
err = errno;
246+
printf("test client connect returned %d, errno=%d (%s)\n", ret, err, strerror(err));
247+
if (err != EINPROGRESS) {
248+
perror("connect");
249+
close(fd);
250+
return (void *)-1;
251+
}
252+
printf("Waiting for connect to complete...\n");
253+
while (1) {
254+
tv.tv_sec = 5;
255+
tv.tv_usec = 0;
256+
FD_ZERO(&rfds);
257+
FD_ZERO(&wfds);
258+
FD_SET(fd, &rfds);
259+
FD_SET(fd, &wfds);
260+
ret = select(fd + 1, &rfds, &wfds, NULL, &tv);
261+
if (ret <= 0) {
262+
printf("select returned %d (timeout or error)\n", ret);
263+
if (ret < 0) {
264+
perror("select");
265+
close(fd);
266+
return (void *)-1;
267+
}
268+
}
269+
errlen = sizeof(err);
270+
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) < 0) {
271+
perror("getsockopt(SO_ERROR)");
272+
close(fd);
273+
return (void *)-1;
274+
}
275+
if (err == 0) {
276+
printf("connect completed after select()\n");
277+
break;
278+
}
279+
if (ret == 0) {
280+
printf("connect still in progress after timeout\n");
281+
continue;
282+
}
283+
if (err != EINPROGRESS && err != EALREADY && err != EWOULDBLOCK && err != EAGAIN) {
284+
printf("connect completed with error: %d (%s)\n", err, strerror(err));
285+
close(fd);
286+
return (void *)-1;
287+
}
288+
}
289+
} else {
290+
printf("connect returned immediately\n");
230291
}
292+
if (fcntl(fd, F_SETFL, old_flags) < 0)
293+
perror("fcntl(restore)");
294+
printf("test client: connect succeeded\n");
231295
for (i = 0; i < sizeof(local_buf); i += sizeof(test_pattern)) {
232296
memcpy(local_buf + i, test_pattern, sizeof(test_pattern));
233297
}
234298
ret = write(fd, local_buf, sizeof(local_buf));
235299
if (ret < 0) {
236-
printf("test client write: %d\n", ret);
300+
int werr = errno;
301+
printf("test client write: %d (errno=%d: %s)\n", ret, werr, strerror(werr));
302+
perror("write");
237303
return (void *)-1;
238304
}
305+
printf("test client: wrote %d bytes\n", ret);
239306
while (total_r < sizeof(local_buf)) {
240307
ret = read(fd, local_buf + total_r, sizeof(local_buf) - total_r);
241308
if (ret < 0) {
@@ -250,6 +317,7 @@ void *pt_echoclient(void *arg)
250317
return (void *)-1;
251318
}
252319
total_r += ret;
320+
printf("test client: read %d bytes (total %u)\n", ret, total_r);
253321
}
254322
for (i = 0; i < sizeof(local_buf); i += sizeof(test_pattern)) {
255323
if (memcmp(local_buf + i, test_pattern, sizeof(test_pattern))) {

src/wolfip.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2507,9 +2507,9 @@ static void arp_recv(struct wolfIP *s, unsigned int if_idx, void *buf, int len)
25072507
arp->sip = ee32(conf->ip);
25082508
arp_store_neighbor(s, if_idx, ee32(arp->sip), arp->sma);
25092509
eth_output_add_header(s, if_idx, arp->tma, &arp->eth, ETH_TYPE_ARP);
2510-
if (ll->send)
2511-
ll->send(ll, buf, len);
2512-
}
2510+
if (ll->send)
2511+
ll->send(ll, buf, len);
2512+
}
25132513
if (arp->opcode == ee16(ARP_REPLY)) {
25142514
arp_store_neighbor(s, if_idx, ee32(arp->sip), arp->sma);
25152515
}

0 commit comments

Comments
 (0)