sim: Add a netdev backed by VPNKit

This commit is contained in:
YAMAMOTO Takashi 2020-03-18 21:12:26 +09:00 committed by Xiang Xiao
parent 124c00b661
commit a5f8b20fcd
4 changed files with 307 additions and 5 deletions

View File

@ -117,15 +117,35 @@ config SIM_NETDEV
select ARCH_HAVE_NETDEV_STATISTICS
select SCHED_LPWORK
select SIM_WALLTIME
---help---
Build in support for a simulated network device.
if SIM_NETDEV
choice
prompt "Simulated Network Device Type"
default SIM_NETDEV_TAP
config SIM_NETDEV_TAP
bool "Simulated Network Device with TAP/WPCAP"
---help---
Build in support for a simulated network device using a TAP device on Linux or
WPCAP on Windows.
config SIM_NETDEV_VPNKIT
bool "Simulated Network Device with VPNKit"
---help---
Build in support for a simulated network device using VPNKit.
endchoice
endif
if HOST_LINUX
choice
prompt "Simulation Network Type"
default SIM_NET_HOST_ROUTE
depends on SIM_NETDEV
depends on SIM_NETDEV_TAP
config SIM_NET_HOST_ROUTE
bool "Use local host route"

View File

@ -157,7 +157,7 @@ ifeq ($(CONFIG_ARCH_ROMGETC),y)
CSRCS += up_romgetc.c
endif
ifeq ($(CONFIG_SIM_NETDEV),y)
ifeq ($(CONFIG_SIM_NETDEV_TAP),y)
CSRCS += up_netdriver.c
HOSTCFLAGS += -DNETDEV_BUFSIZE=$(CONFIG_NET_ETH_PKTSIZE)
ifneq ($(HOSTOS),Cygwin)
@ -173,7 +173,12 @@ else # HOSTOS != Cygwin
HOSTSRCS += up_wpcap.c
DRVLIB = /lib/w32api/libws2_32.a /lib/w32api/libiphlpapi.a
endif # HOSTOS != Cygwin
endif # CONFIG_SIM_NETDEV
else ifeq ($(CONFIG_SIM_NETDEV_VPNKIT),y)
CSRCS += up_netdriver.c
HOSTSRCS += up_vpnkit.c
VPATH += :sim/vpnkit
HOSTSRCS += protocol.c negotiate.c
endif
ifeq ($(CONFIG_RPTUN),y)
CSRCS += up_rptun.c

View File

@ -314,7 +314,7 @@ FAR struct ioexpander_dev_s *sim_ioexpander_initialize(void);
/* up_tapdev.c **************************************************************/
#if defined(CONFIG_SIM_NETDEV) && !defined(__CYGWIN__)
#if defined(CONFIG_SIM_NETDEV_TAP) && !defined(__CYGWIN__)
void tapdev_init(void);
int tapdev_avail(void);
unsigned int tapdev_read(unsigned char *buf, unsigned int buflen);
@ -332,7 +332,7 @@ void tapdev_ifdown(void);
/* up_wpcap.c ***************************************************************/
#if defined(CONFIG_SIM_NETDEV) && defined(__CYGWIN__)
#if defined(CONFIG_SIM_NETDEV_TAP) && defined(__CYGWIN__)
void wpcap_init(void);
unsigned int wpcap_read(unsigned char *buf, unsigned int buflen);
void wpcap_send(unsigned char *buf, unsigned int buflen);
@ -345,6 +345,24 @@ void wpcap_send(unsigned char *buf, unsigned int buflen);
# define netdev_ifdown() {}
#endif
/* up_vpnkit.c **************************************************************/
#if defined(CONFIG_SIM_NETDEV_VPNKIT)
void vpnkit_init(void);
int vpnkit_avail(void);
unsigned int vpnkit_read(unsigned char *buf, unsigned int buflen);
void vpnkit_send(unsigned char *buf, unsigned int buflen);
void vpnkit_ifup(in_addr_t ifaddr);
void vpnkit_ifdown(void);
# define netdev_init() vpnkit_init()
# define netdev_avail() vpnkit_avail()
# define netdev_read(buf,buflen) vpnkit_read(buf,buflen)
# define netdev_send(buf,buflen) vpnkit_send(buf,buflen)
# define netdev_ifup(ifaddr) vpnkit_ifup(ifaddr)
# define netdev_ifdown() vpnkit_ifdown()
#endif
/* up_netdriver.c ***********************************************************/
#ifdef CONFIG_SIM_NETDEV

View File

@ -0,0 +1,259 @@
/****************************************************************************
* arch/sim/src/sim/up_vpnkit.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <sys/types.h>
#include <sys/un.h>
/* XXX broken api: mixing nuttx and host in_addr_t */
#include <netinet/in.h>
#include <poll.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "vpnkit/protocol.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define ERROR(fmt, ...) \
fprintf(stderr, "up_vpnkit: " fmt "\r\n", ##__VA_ARGS__)
#define INFO(fmt, ...) \
fprintf(stderr, "up_vpnkit: " fmt "\r\n", ##__VA_ARGS__)
#define DEBUG(fmt, ...)
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
static const char *g_vpnkit_socket_path = "/tmp/vpnkit-nuttx"; /* XXX config */
static struct vif_info g_vifinfo;
static int g_vpnkit_fd = -1;
/****************************************************************************
* Private Functions
****************************************************************************/
int negotiate(int fd, struct vif_info *vif);
void netdriver_setmacaddr(unsigned char *macaddr);
static void vpnkit_connect()
{
struct sockaddr_un sun;
int fd;
if (g_vpnkit_fd != -1)
{
return;
}
fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd == -1)
{
ERROR("failed to create a socket");
return;
}
memset(&sun, 0, sizeof(sun));
sun.sun_family = AF_UNIX;
strncpy(sun.sun_path, g_vpnkit_socket_path, sizeof(sun.sun_path) - 1);
if (connect(fd, (const struct sockaddr *)&sun, sizeof(sun)) == -1)
{
ERROR("failed to connect to the vpnkit socket %s",
g_vpnkit_socket_path);
close(fd);
return;
}
if (negotiate(fd, &g_vifinfo))
{
ERROR("failed to negotiate with vpnkit");
close(fd);
return;
}
INFO("Successfully negotiated with vpnkit");
g_vpnkit_fd = fd;
}
static void vpnkit_disconnect()
{
if (g_vpnkit_fd == -1)
{
return;
}
INFO("disconnecting from vpnkit");
close(g_vpnkit_fd);
g_vpnkit_fd = -1;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: vpnkit_init
*
****************************************************************************/
void vpnkit_init(void)
{
vpnkit_connect();
netdriver_setmacaddr(g_vifinfo.mac);
}
/****************************************************************************
* Name: vpnkit_avail
*
****************************************************************************/
int vpnkit_avail(void)
{
struct pollfd pfd;
int ret;
vpnkit_connect();
memset(&pfd, 0, sizeof(pfd));
pfd.fd = g_vpnkit_fd;
pfd.events = POLLIN;
ret = poll(&pfd, 1, 0);
if (ret == -1)
{
ERROR("poll failed on vpnkit socket");
vpnkit_disconnect();
return 0;
}
else if (ret != 0)
{
DEBUG("vpnkit_avail is returning 1");
}
return ret != 0;
}
/****************************************************************************
* Name: vpnkit_read
*
****************************************************************************/
unsigned int vpnkit_read(unsigned char *buf, unsigned int buflen)
{
uint8_t header[2]; /* 16-bit payload length in little endian */
size_t packet_len;
ssize_t ret;
DEBUG("vpnkit_read called");
vpnkit_connect();
ret = really_read(g_vpnkit_fd, header, sizeof(header));
if (ret == -1)
{
ERROR("failed to read packet header");
vpnkit_disconnect();
return 0;
}
packet_len = (header[1] << 8) | header[0];
if (packet_len > buflen)
{
INFO("packet larger (%zu) than buffer size (%u)", packet_len, buflen);
/* XXX it's better to drop this particular packet it. */
vpnkit_disconnect();
return 0;
}
ret = really_read(g_vpnkit_fd, buf, packet_len);
if (ret == -1)
{
ERROR("failed to read packet");
vpnkit_disconnect();
return 0;
}
DEBUG("a packet received (size %zu)", packet_len);
return packet_len;
}
/****************************************************************************
* Name: vpnkit_send
*
****************************************************************************/
void vpnkit_send(unsigned char *buf, unsigned int buflen)
{
uint8_t header[2]; /* 16-bit payload length in little endian */
ssize_t ret;
DEBUG("vpnkit_send called");
vpnkit_connect();
header[0] = buflen & 0xff;
header[1] = (buflen >> 8) & 0xff;
ret = really_write(g_vpnkit_fd, header, sizeof(header));
if (ret == -1)
{
ERROR("failed to write packet header");
vpnkit_disconnect();
return;
}
ret = really_write(g_vpnkit_fd, buf, buflen);
if (ret == -1)
{
ERROR("failed to write packet payload");
vpnkit_disconnect();
return;
}
DEBUG("a packet sent (size %u)", buflen);
}
/****************************************************************************
* Name: vpnkit_ifup
*
****************************************************************************/
void vpnkit_ifup(in_addr_t ifaddr)
{
DEBUG("vpnkit_ifup called");
}
/****************************************************************************
* Name: vpnkit_ifdown
*
****************************************************************************/
void vpnkit_ifdown(void)
{
DEBUG("vpnkit_ifdown called");
}