modem: Transparent IP proxy. Removes the need for a TAP/TUN device
This commit is contained in:
parent
dc5ce8fa8b
commit
2c343fddf2
|
@ -4,7 +4,6 @@
|
|||
#define PICO_SUPPORT_ETH
|
||||
#define PICO_SUPPORT_IPV4
|
||||
#define PICO_SUPPORT_IPV4FRAG
|
||||
#define PICO_SUPPORT_ICMP4
|
||||
#define PICO_SUPPORT_TCP
|
||||
#define PICO_SUPPORT_UDP
|
||||
#define PICO_SUPPORT_DNS_CLIENT
|
||||
|
|
|
@ -38,6 +38,7 @@ struct pico_device {
|
|||
#ifdef PICO_SUPPORT_IPV6
|
||||
struct pico_nd_hostvars hostvars;
|
||||
#endif
|
||||
int proxied;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -92,6 +92,9 @@ struct pico_frame {
|
|||
|
||||
uint8_t send_ttl; /* Special TTL/HOPS value, 0 = auto assign */
|
||||
uint8_t send_tos; /* Type of service */
|
||||
|
||||
struct pico_ip4 local_ip; /* address to masquerade */
|
||||
uint16_t local_port; /* port to masquerade */
|
||||
};
|
||||
|
||||
/** frame alloc/dealloc/copy **/
|
||||
|
|
|
@ -175,6 +175,8 @@ struct pico_msginfo {
|
|||
struct pico_device *dev;
|
||||
uint8_t ttl;
|
||||
uint8_t tos;
|
||||
union pico_address local_addr;
|
||||
uint16_t local_port;
|
||||
};
|
||||
|
||||
struct pico_socket *pico_socket_open(uint16_t net, uint16_t proto, void (*wakeup)(uint16_t ev, struct pico_socket *s));
|
||||
|
|
|
@ -1,231 +0,0 @@
|
|||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved.
|
||||
See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage.
|
||||
|
||||
Authors: Daniele Lacamera
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#include <signal.h>
|
||||
#include "pico_device.h"
|
||||
#include "pico_dev_tap.h"
|
||||
#include "pico_stack.h"
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
#include <linux/if_tun.h>
|
||||
#endif
|
||||
|
||||
#include <sys/poll.h>
|
||||
|
||||
struct pico_device_tap {
|
||||
struct pico_device dev;
|
||||
int fd;
|
||||
};
|
||||
|
||||
#define TUN_MTU 2048
|
||||
|
||||
/* We only support one global link state - we only have two USR signals, we */
|
||||
/* can't spread these out over an arbitrary amount of devices. When you unplug */
|
||||
/* one tap, you unplug all of them. */
|
||||
|
||||
static int tapdev_link_state = 0;
|
||||
|
||||
static void sig_handler(int signo)
|
||||
{
|
||||
if (signo == SIGUSR1) {
|
||||
tapdev_link_state = 0;
|
||||
}
|
||||
|
||||
if (signo == SIGUSR2) {
|
||||
tapdev_link_state = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int tap_link_state(__attribute__((unused)) struct pico_device *self)
|
||||
{
|
||||
return tapdev_link_state;
|
||||
}
|
||||
|
||||
|
||||
static int pico_tap_send(struct pico_device *dev, void *buf, int len)
|
||||
{
|
||||
struct pico_device_tap *tap = (struct pico_device_tap *) dev;
|
||||
return (int)write(tap->fd, buf, (uint32_t)len);
|
||||
}
|
||||
|
||||
static int pico_tap_poll(struct pico_device *dev, int loop_score)
|
||||
{
|
||||
struct pico_device_tap *tap = (struct pico_device_tap *) dev;
|
||||
struct pollfd pfd;
|
||||
unsigned char buf[TUN_MTU];
|
||||
int len;
|
||||
pfd.fd = tap->fd;
|
||||
pfd.events = POLLIN;
|
||||
do {
|
||||
if (poll(&pfd, 1, 0) <= 0) {
|
||||
return loop_score;
|
||||
}
|
||||
|
||||
len = (int)read(tap->fd, buf, TUN_MTU);
|
||||
if (len > 0) {
|
||||
loop_score--;
|
||||
pico_stack_recv(dev, buf, (uint32_t)len);
|
||||
}
|
||||
} while(loop_score > 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Public interface: create/destroy. */
|
||||
|
||||
void pico_tap_destroy(struct pico_device *dev)
|
||||
{
|
||||
struct pico_device_tap *tap = (struct pico_device_tap *) dev;
|
||||
if(tap->fd > 0) {
|
||||
close(tap->fd);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
static int tap_open(const char *name)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
int tap_fd;
|
||||
if((tap_fd = open("/dev/net/tun", O_RDWR)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
|
||||
strncpy(ifr.ifr_name, name, IFNAMSIZ);
|
||||
if(ioctl(tap_fd, TUNSETIFF, &ifr) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return tap_fd;
|
||||
}
|
||||
#else
|
||||
static int tap_open(const char *name)
|
||||
{
|
||||
int tap_fd;
|
||||
(void)name;
|
||||
tap_fd = open("/dev/tap0", O_RDWR);
|
||||
return tap_fd;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
static int tap_get_mac(const char *name, uint8_t *mac)
|
||||
{
|
||||
int sck;
|
||||
struct ifreq eth;
|
||||
int retval = -1;
|
||||
|
||||
sck = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if(sck < 0) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
memset(ð, 0, sizeof(struct ifreq));
|
||||
strcpy(eth.ifr_name, name);
|
||||
/* call the IOCTL */
|
||||
if (ioctl(sck, SIOCGIFHWADDR, ð) < 0) {
|
||||
perror("ioctl(SIOCGIFHWADDR)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy (mac, ð.ifr_hwaddr.sa_data, 6);
|
||||
close(sck);
|
||||
return 0;
|
||||
|
||||
}
|
||||
#else
|
||||
#include <net/if_dl.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if_types.h>
|
||||
static int tap_get_mac(const char *name, uint8_t *mac)
|
||||
{
|
||||
struct sockaddr_dl *sdl;
|
||||
struct ifaddrs *ifap, *root;
|
||||
if (getifaddrs(&ifap) != 0)
|
||||
return -1;
|
||||
|
||||
root = ifap;
|
||||
while(ifap) {
|
||||
if (strcmp(name, ifap->ifa_name) == 0) {
|
||||
sdl = (struct sockaddr_dl *) ifap->ifa_addr;
|
||||
}
|
||||
|
||||
if (sdl->sdl_type == IFT_ETHER) {
|
||||
memcpy(mac, LLADDR(sdl), 6);
|
||||
freeifaddrs(root);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ifap = ifap->ifa_next;
|
||||
}
|
||||
freeifaddrs(root);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct pico_device *pico_tap_create(const char *name)
|
||||
{
|
||||
struct pico_device_tap *tap = PICO_ZALLOC(sizeof(struct pico_device_tap));
|
||||
uint8_t mac[6] = {};
|
||||
struct sigaction sa;
|
||||
|
||||
if (!tap) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sa.sa_flags = 0;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_handler = sig_handler;
|
||||
|
||||
if ((sigaction(SIGUSR1, &sa, NULL) == 0) &&
|
||||
(sigaction(SIGUSR2, &sa, NULL) == 0)) {
|
||||
tap->dev.link_state = &tap_link_state;
|
||||
}
|
||||
|
||||
tap->dev.overhead = 0;
|
||||
tap->fd = tap_open(name);
|
||||
if (tap->fd < 0) {
|
||||
dbg("Tap creation failed.\n");
|
||||
pico_tap_destroy((struct pico_device *)tap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Host's mac address is generated * by the host kernel and is
|
||||
* retrieved via tap_get_mac().
|
||||
*/
|
||||
if (tap_get_mac(name, mac) < 0) {
|
||||
dbg("Tap mac query failed.\n");
|
||||
pico_tap_destroy((struct pico_device *)tap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* To act as a second endpoint in the same subnet, the picoTCP
|
||||
* app using the tap device must have a different mac address.
|
||||
* For simplicity, we just add 1 to the last byte of the linux
|
||||
* endpoint so the two addresses are consecutive.
|
||||
*/
|
||||
mac[5]++;
|
||||
|
||||
if( 0 != pico_device_init((struct pico_device *)tap, name, mac)) {
|
||||
dbg("Tap init failed.\n");
|
||||
pico_tap_destroy((struct pico_device *)tap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tap->dev.send = pico_tap_send;
|
||||
tap->dev.poll = pico_tap_poll;
|
||||
tap->dev.destroy = pico_tap_destroy;
|
||||
dbg("Device %s created.\n", tap->dev.name);
|
||||
return (struct pico_device *)tap;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,16 +0,0 @@
|
|||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved.
|
||||
See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage.
|
||||
|
||||
*********************************************************************/
|
||||
#ifndef _WIN32
|
||||
#ifndef INCLUDE_PICO_TAP
|
||||
#define INCLUDE_PICO_TAP
|
||||
#include "pico_config.h"
|
||||
#include "pico_device.h"
|
||||
|
||||
void pico_tap_destroy(struct pico_device *tap);
|
||||
struct pico_device *pico_tap_create(const char *name);
|
||||
|
||||
#endif
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -1,20 +0,0 @@
|
|||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2014-2017 Altran Intelligent Systems. Some rights reserved.
|
||||
See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage.
|
||||
|
||||
*********************************************************************/
|
||||
#ifdef _WIN32
|
||||
#ifndef INCLUDE_PICO_TAP
|
||||
#define INCLUDE_PICO_TAP
|
||||
#include "pico_config.h"
|
||||
#include "pico_device.h"
|
||||
|
||||
/* will look for the first TAP device available, and use it */
|
||||
struct pico_device *pico_tap_create(char *name, uint8_t *mac);
|
||||
/* TODO: not implemented yet */
|
||||
/* void pico_tap_destroy(struct pico_device *null); */
|
||||
const char *pico_tap_get_guid(struct pico_device *dev);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2014-2017 Altran Intelligent Systems. Some rights reserved.
|
||||
See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage.
|
||||
|
||||
Authors: Maxime Vincent
|
||||
Based on the OpenVPN tun.c driver, under GPL
|
||||
|
||||
NOTES: This is the Windows-only driver, a Linux-equivalent is available, too
|
||||
You need to have an OpenVPN TUN/TAP network adapter installed, first
|
||||
This driver is barely working:
|
||||
* Only TAP-mode is supported (TUN is not)
|
||||
* it will simply open the first TAP device it can find
|
||||
* there is memory being allocated that's never freed
|
||||
* there is no destroy function, yet
|
||||
* it has only been tested on a Windows 7 machine
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef __PICO_DEV_TAP_WINDOWS_PRIVATE_H
|
||||
#define __PICO_DEV_TAP_WINDOWS_PRIVATE_H
|
||||
|
||||
/* Extra defines (vnz) */
|
||||
#define TAP_WIN_COMPONENT_ID "tap0901"
|
||||
#define TAP_WIN_MIN_MAJOR 9
|
||||
#define TAP_WIN_MIN_MINOR 9
|
||||
#define PACKAGE_NAME "PicoTCP WinTAP"
|
||||
|
||||
/* Extra structs */
|
||||
struct tap_reg
|
||||
{
|
||||
const char *guid;
|
||||
struct tap_reg *next;
|
||||
};
|
||||
|
||||
struct panel_reg
|
||||
{
|
||||
const char *name;
|
||||
const char *guid;
|
||||
struct panel_reg *next;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* =============
|
||||
* TAP IOCTLs
|
||||
* =============
|
||||
*/
|
||||
|
||||
#define TAP_WIN_CONTROL_CODE(request, method) \
|
||||
CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)
|
||||
|
||||
/* Present in 8.1 */
|
||||
|
||||
#define TAP_WIN_IOCTL_GET_MAC TAP_WIN_CONTROL_CODE (1, METHOD_BUFFERED)
|
||||
#define TAP_WIN_IOCTL_GET_VERSION TAP_WIN_CONTROL_CODE (2, METHOD_BUFFERED)
|
||||
#define TAP_WIN_IOCTL_GET_MTU TAP_WIN_CONTROL_CODE (3, METHOD_BUFFERED)
|
||||
#define TAP_WIN_IOCTL_GET_INFO TAP_WIN_CONTROL_CODE (4, METHOD_BUFFERED)
|
||||
#define TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT TAP_WIN_CONTROL_CODE (5, METHOD_BUFFERED)
|
||||
#define TAP_WIN_IOCTL_SET_MEDIA_STATUS TAP_WIN_CONTROL_CODE (6, METHOD_BUFFERED)
|
||||
#define TAP_WIN_IOCTL_CONFIG_DHCP_MASQ TAP_WIN_CONTROL_CODE (7, METHOD_BUFFERED)
|
||||
#define TAP_WIN_IOCTL_GET_LOG_LINE TAP_WIN_CONTROL_CODE (8, METHOD_BUFFERED)
|
||||
#define TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT TAP_WIN_CONTROL_CODE (9, METHOD_BUFFERED)
|
||||
|
||||
/* Added in 8.2 */
|
||||
|
||||
/* obsoletes TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT */
|
||||
#define TAP_WIN_IOCTL_CONFIG_TUN TAP_WIN_CONTROL_CODE (10, METHOD_BUFFERED)
|
||||
|
||||
/*
|
||||
* =================
|
||||
* Registry keys
|
||||
* =================
|
||||
*/
|
||||
|
||||
#define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
|
||||
|
||||
#define NETWORK_CONNECTIONS_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
|
||||
|
||||
/*
|
||||
* ======================
|
||||
* Filesystem prefixes
|
||||
* ======================
|
||||
*/
|
||||
|
||||
#define USERMODEDEVICEDIR "\\\\.\\Global\\"
|
||||
#define SYSDEVICEDIR "\\Device\\"
|
||||
#define USERDEVICEDIR "\\DosDevices\\Global\\"
|
||||
#define TAP_WIN_SUFFIX ".tap"
|
||||
|
||||
#endif
|
|
@ -1,218 +0,0 @@
|
|||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved.
|
||||
See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage.
|
||||
|
||||
Authors: Daniele Lacamera
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#ifdef __APPLE__
|
||||
#include <sys/sys_domain.h>
|
||||
#include <net/if_utun.h> // UTUN_CONTROL_NAME
|
||||
#include <sys/kern_control.h> // struct socketaddr_ctl
|
||||
#else
|
||||
#include <linux/if_tun.h>
|
||||
#endif
|
||||
#include "pico_device.h"
|
||||
#include "pico_dev_tun.h"
|
||||
#include "pico_stack.h"
|
||||
|
||||
#include <sys/poll.h>
|
||||
|
||||
struct pico_device_tun {
|
||||
struct pico_device dev;
|
||||
int fd;
|
||||
};
|
||||
|
||||
#define TUN_MTU 2048
|
||||
|
||||
static int pico_tun_send(struct pico_device *dev, void *buf, int len)
|
||||
{
|
||||
struct pico_device_tun *tun = (struct pico_device_tun *) dev;
|
||||
#ifdef __APPLE__
|
||||
// Add the protocol (IP) before the packet (4 bytes)
|
||||
uint8_t *p = (uint8_t *)malloc(len + 4);
|
||||
*(uint32_t *)p = 2;
|
||||
memcpy(p + 4, buf, len);
|
||||
int rc = (int)write(tun->fd, p, len + 4);
|
||||
free(p);
|
||||
return rc;
|
||||
#endif
|
||||
return (int)write(tun->fd, buf, (uint32_t)len);
|
||||
}
|
||||
|
||||
static int pico_tun_poll(struct pico_device *dev, int loop_score)
|
||||
{
|
||||
struct pico_device_tun *tun = (struct pico_device_tun *) dev;
|
||||
struct pollfd pfd;
|
||||
unsigned char buf[TUN_MTU];
|
||||
int len;
|
||||
pfd.fd = tun->fd;
|
||||
pfd.events = POLLIN;
|
||||
do {
|
||||
if (poll(&pfd, 1, 0) <= 0)
|
||||
return loop_score;
|
||||
|
||||
len = (int)read(tun->fd, buf, TUN_MTU);
|
||||
if (len > 0) {
|
||||
loop_score--;
|
||||
#ifdef __APPLE__
|
||||
pico_stack_recv(dev, buf + 4, (uint32_t)len - 4);
|
||||
#else
|
||||
pico_stack_recv(dev, buf, (uint32_t)len);
|
||||
#endif
|
||||
}
|
||||
} while(loop_score > 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Public interface: create/destroy. */
|
||||
|
||||
void pico_tun_destroy(struct pico_device *dev)
|
||||
{
|
||||
struct pico_device_tun *tun = (struct pico_device_tun *) dev;
|
||||
if(tun->fd > 0)
|
||||
close(tun->fd);
|
||||
}
|
||||
|
||||
#ifdef IFF_TUN // Linux
|
||||
|
||||
static int tun_open(const char *name)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
int tun_fd;
|
||||
if((tun_fd = open("/dev/net/tun", O_RDWR)) < 0) {
|
||||
return(-1);
|
||||
}
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
|
||||
strncpy(ifr.ifr_name, name, IFNAMSIZ);
|
||||
if(ioctl(tun_fd, TUNSETIFF, &ifr) < 0) {
|
||||
return(-1);
|
||||
}
|
||||
|
||||
return tun_fd;
|
||||
}
|
||||
|
||||
#else // BSD, OS X, ...
|
||||
|
||||
#ifdef __APPLE__
|
||||
static int tun_open(const char *name)
|
||||
{
|
||||
struct ctl_info ctlInfo;
|
||||
strlcpy(ctlInfo.ctl_name, UTUN_CONTROL_NAME, sizeof(ctlInfo.ctl_name));
|
||||
int fd = -1;
|
||||
|
||||
for (int unit = 0; unit < 256 && fd == -1; unit++)
|
||||
{
|
||||
fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
|
||||
if (fd < 0) {
|
||||
perror("socket");
|
||||
continue;
|
||||
}
|
||||
|
||||
struct sockaddr_ctl sc;
|
||||
|
||||
if (ioctl(fd, CTLIOCGINFO, &ctlInfo) == -1) {
|
||||
close(fd);
|
||||
perror("ioctl");
|
||||
fd = -1;
|
||||
continue;
|
||||
}
|
||||
printf("ctl_info: {ctl_id: %ud, ctl_name: %s}\n",
|
||||
ctlInfo.ctl_id, ctlInfo.ctl_name);
|
||||
|
||||
sc.sc_id = ctlInfo.ctl_id;
|
||||
sc.sc_len = sizeof(sc);
|
||||
sc.sc_family = AF_SYSTEM;
|
||||
sc.ss_sysaddr = AF_SYS_CONTROL;
|
||||
sc.sc_unit = unit;
|
||||
|
||||
if (connect(fd, (struct sockaddr *)&sc, sizeof(sc)) < 0) {
|
||||
perror("connect");
|
||||
close(fd);
|
||||
fd = -1;
|
||||
continue;
|
||||
}
|
||||
printf("Opened tunnel utun%d\n", unit);
|
||||
|
||||
// set_nonblock (fd);
|
||||
fcntl (fd, F_SETFL, O_NONBLOCK);
|
||||
|
||||
// set_cloexec (fd);
|
||||
/*
|
||||
int s = socket(PF_ROUTE, SOCK_RAW, 0);
|
||||
af = AF_INET;
|
||||
aflen = sizeof(struct sockaddr_in);
|
||||
flags |= RTF_UP;
|
||||
flags |= RTF_HOST;
|
||||
if ((ret = rtmsg(*cmd, flags)) == 0)
|
||||
break;
|
||||
*/
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
#elif defined(SIOCIFCREATE)
|
||||
static int tun_open(const char *name)
|
||||
{
|
||||
int fd;
|
||||
int s;
|
||||
struct ifreq ifr;
|
||||
|
||||
fd = open(name, O_RDWR);
|
||||
if (fd == -1)
|
||||
{
|
||||
s = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (s < 0)
|
||||
return -1;
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strncpy(ifr.ifr_name, name + 5, sizeof(ifr.ifr_name) - 1);
|
||||
if (!ioctl(s, SIOCIFCREATE, &ifr))
|
||||
fd = open(name, O_RDWR);
|
||||
|
||||
close(s);
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
#else
|
||||
#define tun_open(tun_name) open(tun_name, O_RDWR)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
struct pico_device *pico_tun_create(const char *name)
|
||||
{
|
||||
struct pico_device_tun *tun = PICO_ZALLOC(sizeof(struct pico_device_tun));
|
||||
|
||||
if (!tun)
|
||||
return NULL;
|
||||
|
||||
if( 0 != pico_device_init((struct pico_device *)tun, name, NULL)) {
|
||||
printf("Tun init failed.\n");
|
||||
pico_tun_destroy((struct pico_device *)tun);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tun->dev.overhead = 0;
|
||||
tun->fd = tun_open(name);
|
||||
if (tun->fd < 0) {
|
||||
printf("Tun creation failed.\n");
|
||||
pico_tun_destroy((struct pico_device *)tun);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tun->dev.send = pico_tun_send;
|
||||
tun->dev.poll = pico_tun_poll;
|
||||
tun->dev.destroy = pico_tun_destroy;
|
||||
dbg("Device %s created.\n", tun->dev.name);
|
||||
return (struct pico_device *)tun;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,17 +0,0 @@
|
|||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved.
|
||||
See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage.
|
||||
|
||||
*********************************************************************/
|
||||
#ifndef _WIN32
|
||||
#ifndef INCLUDE_PICO_TUN
|
||||
#define INCLUDE_PICO_TUN
|
||||
#include "pico_config.h"
|
||||
#include "pico_device.h"
|
||||
|
||||
void pico_tun_destroy(struct pico_device *tun);
|
||||
struct pico_device *pico_tun_create(const char *name);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -1,190 +0,0 @@
|
|||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved.
|
||||
See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage.
|
||||
|
||||
.
|
||||
|
||||
Authors: Frederik Van Slycken
|
||||
*********************************************************************/
|
||||
|
||||
#include "pico_config.h"
|
||||
#include "pico_stack.h"
|
||||
#include "pico_dhcp_common.h"
|
||||
|
||||
#if defined (PICO_SUPPORT_DHCPC) || defined (PICO_SUPPORT_DHCPD)
|
||||
/* pico_dhcp_are_options_valid needs to be called first to prevent illegal memory access */
|
||||
/* The argument pointer is moved forward to the next option */
|
||||
struct pico_dhcp_opt *pico_dhcp_next_option(struct pico_dhcp_opt **ptr)
|
||||
{
|
||||
uint8_t **p = (uint8_t **)ptr;
|
||||
struct pico_dhcp_opt *opt = *ptr;
|
||||
|
||||
if (opt->code == PICO_DHCP_OPT_END)
|
||||
return NULL;
|
||||
|
||||
if (opt->code == PICO_DHCP_OPT_PAD) {
|
||||
*p += 1;
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
*p += (opt->len + 2); /* (len + 2) to account for code and len octet */
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
uint8_t pico_dhcp_are_options_valid(void *ptr, int32_t len)
|
||||
{
|
||||
uint8_t optlen = 0, *p = ptr;
|
||||
|
||||
while (len > 0) {
|
||||
switch (*p)
|
||||
{
|
||||
case PICO_DHCP_OPT_END:
|
||||
return 1;
|
||||
|
||||
case PICO_DHCP_OPT_PAD:
|
||||
p++;
|
||||
len--;
|
||||
break;
|
||||
|
||||
default:
|
||||
p++; /* move pointer from code octet to len octet */
|
||||
len--;
|
||||
if ((len <= 0) || (len - (*p + 1) < 0)) /* (*p + 1) to account for len octet */
|
||||
return 0;
|
||||
|
||||
optlen = *p;
|
||||
p += optlen + 1;
|
||||
len -= optlen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t pico_dhcp_opt_netmask(void *ptr, struct pico_ip4 *ip)
|
||||
{
|
||||
struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
|
||||
|
||||
/* option: netmask */
|
||||
opt->code = PICO_DHCP_OPT_NETMASK;
|
||||
opt->len = PICO_DHCP_OPTLEN_NETMASK - PICO_DHCP_OPTLEN_HDR;
|
||||
opt->ext.netmask.ip = *ip;
|
||||
return PICO_DHCP_OPTLEN_NETMASK;
|
||||
}
|
||||
|
||||
uint8_t pico_dhcp_opt_router(void *ptr, struct pico_ip4 *ip)
|
||||
{
|
||||
struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
|
||||
|
||||
/* option: router */
|
||||
opt->code = PICO_DHCP_OPT_ROUTER;
|
||||
opt->len = PICO_DHCP_OPTLEN_ROUTER - PICO_DHCP_OPTLEN_HDR;
|
||||
opt->ext.router.ip = *ip;
|
||||
return PICO_DHCP_OPTLEN_ROUTER;
|
||||
}
|
||||
|
||||
uint8_t pico_dhcp_opt_dns(void *ptr, struct pico_ip4 *ip)
|
||||
{
|
||||
struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
|
||||
|
||||
/* option: dns */
|
||||
opt->code = PICO_DHCP_OPT_DNS;
|
||||
opt->len = PICO_DHCP_OPTLEN_DNS - PICO_DHCP_OPTLEN_HDR;
|
||||
opt->ext.dns1.ip = *ip;
|
||||
return PICO_DHCP_OPTLEN_DNS;
|
||||
}
|
||||
|
||||
uint8_t pico_dhcp_opt_broadcast(void *ptr, struct pico_ip4 *ip)
|
||||
{
|
||||
struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
|
||||
|
||||
/* option: broadcast */
|
||||
opt->code = PICO_DHCP_OPT_BROADCAST;
|
||||
opt->len = PICO_DHCP_OPTLEN_BROADCAST - PICO_DHCP_OPTLEN_HDR;
|
||||
opt->ext.broadcast.ip = *ip;
|
||||
return PICO_DHCP_OPTLEN_BROADCAST;
|
||||
}
|
||||
|
||||
uint8_t pico_dhcp_opt_reqip(void *ptr, struct pico_ip4 *ip)
|
||||
{
|
||||
struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
|
||||
|
||||
/* option: request IP address */
|
||||
opt->code = PICO_DHCP_OPT_REQIP;
|
||||
opt->len = PICO_DHCP_OPTLEN_REQIP - PICO_DHCP_OPTLEN_HDR;
|
||||
opt->ext.req_ip.ip = *ip;
|
||||
return PICO_DHCP_OPTLEN_REQIP;
|
||||
}
|
||||
|
||||
uint8_t pico_dhcp_opt_leasetime(void *ptr, uint32_t time)
|
||||
{
|
||||
struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
|
||||
|
||||
/* option: lease time */
|
||||
opt->code = PICO_DHCP_OPT_LEASETIME;
|
||||
opt->len = PICO_DHCP_OPTLEN_LEASETIME - PICO_DHCP_OPTLEN_HDR;
|
||||
opt->ext.lease_time.time = time;
|
||||
return PICO_DHCP_OPTLEN_LEASETIME;
|
||||
}
|
||||
|
||||
uint8_t pico_dhcp_opt_msgtype(void *ptr, uint8_t type)
|
||||
{
|
||||
struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
|
||||
|
||||
/* option: message type */
|
||||
opt->code = PICO_DHCP_OPT_MSGTYPE;
|
||||
opt->len = PICO_DHCP_OPTLEN_MSGTYPE - PICO_DHCP_OPTLEN_HDR;
|
||||
opt->ext.msg_type.type = type;
|
||||
return PICO_DHCP_OPTLEN_MSGTYPE;
|
||||
}
|
||||
|
||||
uint8_t pico_dhcp_opt_serverid(void *ptr, struct pico_ip4 *ip)
|
||||
{
|
||||
struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
|
||||
|
||||
/* option: server identifier */
|
||||
opt->code = PICO_DHCP_OPT_SERVERID;
|
||||
opt->len = PICO_DHCP_OPTLEN_SERVERID - PICO_DHCP_OPTLEN_HDR;
|
||||
opt->ext.server_id.ip = *ip;
|
||||
return PICO_DHCP_OPTLEN_SERVERID;
|
||||
}
|
||||
|
||||
uint8_t pico_dhcp_opt_paramlist(void *ptr)
|
||||
{
|
||||
struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
|
||||
uint8_t *param_code = &(opt->ext.param_list.code[0]);
|
||||
|
||||
/* option: parameter list */
|
||||
opt->code = PICO_DHCP_OPT_PARAMLIST;
|
||||
opt->len = PICO_DHCP_OPTLEN_PARAMLIST - PICO_DHCP_OPTLEN_HDR;
|
||||
param_code[0] = PICO_DHCP_OPT_NETMASK;
|
||||
param_code[1] = PICO_DHCP_OPT_TIME;
|
||||
param_code[2] = PICO_DHCP_OPT_ROUTER;
|
||||
param_code[3] = PICO_DHCP_OPT_HOSTNAME;
|
||||
param_code[4] = PICO_DHCP_OPT_RENEWALTIME;
|
||||
param_code[5] = PICO_DHCP_OPT_REBINDINGTIME;
|
||||
param_code[6] = PICO_DHCP_OPT_DNS;
|
||||
return PICO_DHCP_OPTLEN_PARAMLIST;
|
||||
}
|
||||
|
||||
uint8_t pico_dhcp_opt_maxmsgsize(void *ptr, uint16_t size)
|
||||
{
|
||||
struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
|
||||
|
||||
/* option: maximum message size */
|
||||
opt->code = PICO_DHCP_OPT_MAXMSGSIZE;
|
||||
opt->len = PICO_DHCP_OPTLEN_MAXMSGSIZE - PICO_DHCP_OPTLEN_HDR;
|
||||
opt->ext.max_msg_size.size = short_be(size);
|
||||
return PICO_DHCP_OPTLEN_MAXMSGSIZE;
|
||||
}
|
||||
|
||||
uint8_t pico_dhcp_opt_end(void *ptr)
|
||||
{
|
||||
uint8_t *opt = (uint8_t *)ptr;
|
||||
|
||||
/* option: end of options */
|
||||
*opt = PICO_DHCP_OPT_END;
|
||||
return PICO_DHCP_OPTLEN_END;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,434 +0,0 @@
|
|||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved.
|
||||
See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage.
|
||||
|
||||
.
|
||||
|
||||
Authors: Daniele Lacamera
|
||||
*********************************************************************/
|
||||
|
||||
|
||||
#include "pico_icmp4.h"
|
||||
#include "pico_config.h"
|
||||
#include "pico_ipv4.h"
|
||||
#include "pico_eth.h"
|
||||
#include "pico_device.h"
|
||||
#include "pico_stack.h"
|
||||
#include "pico_tree.h"
|
||||
|
||||
/* Queues */
|
||||
static struct pico_queue icmp_in = {
|
||||
0
|
||||
};
|
||||
static struct pico_queue icmp_out = {
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
/* Functions */
|
||||
|
||||
static int pico_icmp4_checksum(struct pico_frame *f)
|
||||
{
|
||||
struct pico_icmp4_hdr *hdr = (struct pico_icmp4_hdr *) f->transport_hdr;
|
||||
if (!hdr) {
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
hdr->crc = 0;
|
||||
hdr->crc = short_be(pico_checksum(hdr, f->transport_len));
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef PICO_SUPPORT_PING
|
||||
static void ping_recv_reply(struct pico_frame *f);
|
||||
#endif
|
||||
|
||||
static int pico_icmp4_process_in(struct pico_protocol *self, struct pico_frame *f)
|
||||
{
|
||||
struct pico_icmp4_hdr *hdr = (struct pico_icmp4_hdr *) f->transport_hdr;
|
||||
static int firstpkt = 1;
|
||||
static uint16_t last_id = 0;
|
||||
static uint16_t last_seq = 0;
|
||||
IGNORE_PARAMETER(self);
|
||||
|
||||
if (hdr->type == PICO_ICMP_ECHO) {
|
||||
hdr->type = PICO_ICMP_ECHOREPLY;
|
||||
/* outgoing frames require a f->len without the ethernet header len */
|
||||
if (f->dev && f->dev->eth)
|
||||
f->len -= PICO_SIZE_ETHHDR;
|
||||
|
||||
if (!firstpkt && (hdr->hun.ih_idseq.idseq_id == last_id) && (last_seq == hdr->hun.ih_idseq.idseq_seq)) {
|
||||
/* The network duplicated the echo. Do not reply. */
|
||||
pico_frame_discard(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
firstpkt = 0;
|
||||
last_id = hdr->hun.ih_idseq.idseq_id;
|
||||
last_seq = hdr->hun.ih_idseq.idseq_seq;
|
||||
pico_icmp4_checksum(f);
|
||||
pico_ipv4_rebound(f);
|
||||
} else if (hdr->type == PICO_ICMP_UNREACH) {
|
||||
f->net_hdr = f->transport_hdr + PICO_ICMPHDR_UN_SIZE;
|
||||
pico_ipv4_unreachable(f, hdr->code);
|
||||
} else if (hdr->type == PICO_ICMP_ECHOREPLY) {
|
||||
#ifdef PICO_SUPPORT_PING
|
||||
ping_recv_reply(f);
|
||||
#endif
|
||||
pico_frame_discard(f);
|
||||
} else {
|
||||
pico_frame_discard(f);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pico_icmp4_process_out(struct pico_protocol *self, struct pico_frame *f)
|
||||
{
|
||||
IGNORE_PARAMETER(self);
|
||||
IGNORE_PARAMETER(f);
|
||||
dbg("Called %s\n", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Interface: protocol definition */
|
||||
struct pico_protocol pico_proto_icmp4 = {
|
||||
.name = "icmp4",
|
||||
.proto_number = PICO_PROTO_ICMP4,
|
||||
.layer = PICO_LAYER_TRANSPORT,
|
||||
.process_in = pico_icmp4_process_in,
|
||||
.process_out = pico_icmp4_process_out,
|
||||
.q_in = &icmp_in,
|
||||
.q_out = &icmp_out,
|
||||
};
|
||||
|
||||
static int pico_icmp4_notify(struct pico_frame *f, uint8_t type, uint8_t code)
|
||||
{
|
||||
struct pico_frame *reply;
|
||||
struct pico_icmp4_hdr *hdr;
|
||||
struct pico_ipv4_hdr *info;
|
||||
uint16_t f_tot_len;
|
||||
|
||||
if (f == NULL) {
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
f_tot_len = short_be(((struct pico_ipv4_hdr *)f->net_hdr)->len);
|
||||
|
||||
if (f_tot_len < (sizeof(struct pico_ipv4_hdr)))
|
||||
return -1;
|
||||
|
||||
/* Truncate tot len to be at most 8 bytes + iphdr */
|
||||
if (f_tot_len > (sizeof(struct pico_ipv4_hdr) + 8u)) {
|
||||
f_tot_len = (sizeof(struct pico_ipv4_hdr) + 8u);
|
||||
}
|
||||
|
||||
reply = pico_proto_ipv4.alloc(&pico_proto_ipv4, f->dev, (uint16_t) (f_tot_len + PICO_ICMPHDR_UN_SIZE));
|
||||
info = (struct pico_ipv4_hdr*)(f->net_hdr);
|
||||
hdr = (struct pico_icmp4_hdr *) reply->transport_hdr;
|
||||
hdr->type = type;
|
||||
hdr->code = code;
|
||||
hdr->hun.ih_pmtu.ipm_nmtu = short_be(1500);
|
||||
hdr->hun.ih_pmtu.ipm_void = 0;
|
||||
reply->transport_len = (uint16_t)(f_tot_len + PICO_ICMPHDR_UN_SIZE);
|
||||
reply->payload = reply->transport_hdr + PICO_ICMPHDR_UN_SIZE;
|
||||
memcpy(reply->payload, f->net_hdr, f_tot_len);
|
||||
pico_icmp4_checksum(reply);
|
||||
pico_ipv4_frame_push(reply, &info->src, PICO_PROTO_ICMP4);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pico_icmp4_port_unreachable(struct pico_frame *f)
|
||||
{
|
||||
/*Parameter check executed in pico_icmp4_notify*/
|
||||
return pico_icmp4_notify(f, PICO_ICMP_UNREACH, PICO_ICMP_UNREACH_PORT);
|
||||
}
|
||||
|
||||
int pico_icmp4_proto_unreachable(struct pico_frame *f)
|
||||
{
|
||||
/*Parameter check executed in pico_icmp4_notify*/
|
||||
return pico_icmp4_notify(f, PICO_ICMP_UNREACH, PICO_ICMP_UNREACH_PROTOCOL);
|
||||
}
|
||||
|
||||
int pico_icmp4_dest_unreachable(struct pico_frame *f)
|
||||
{
|
||||
/*Parameter check executed in pico_icmp4_notify*/
|
||||
return pico_icmp4_notify(f, PICO_ICMP_UNREACH, PICO_ICMP_UNREACH_HOST);
|
||||
}
|
||||
|
||||
int pico_icmp4_ttl_expired(struct pico_frame *f)
|
||||
{
|
||||
/*Parameter check executed in pico_icmp4_notify*/
|
||||
return pico_icmp4_notify(f, PICO_ICMP_TIME_EXCEEDED, PICO_ICMP_TIMXCEED_INTRANS);
|
||||
}
|
||||
|
||||
MOCKABLE int pico_icmp4_frag_expired(struct pico_frame *f)
|
||||
{
|
||||
/*Parameter check executed in pico_icmp4_notify*/
|
||||
return pico_icmp4_notify(f, PICO_ICMP_TIME_EXCEEDED, PICO_ICMP_TIMXCEED_REASS);
|
||||
}
|
||||
|
||||
int pico_icmp4_mtu_exceeded(struct pico_frame *f)
|
||||
{
|
||||
/*Parameter check executed in pico_icmp4_notify*/
|
||||
return pico_icmp4_notify(f, PICO_ICMP_UNREACH, PICO_ICMP_UNREACH_NEEDFRAG);
|
||||
}
|
||||
|
||||
int pico_icmp4_packet_filtered(struct pico_frame *f)
|
||||
{
|
||||
/*Parameter check executed in pico_icmp4_notify*/
|
||||
/*Packet Filtered: type 3, code 13 (Communication Administratively Prohibited)*/
|
||||
return pico_icmp4_notify(f, PICO_ICMP_UNREACH, PICO_ICMP_UNREACH_FILTER_PROHIB);
|
||||
}
|
||||
|
||||
int pico_icmp4_param_problem(struct pico_frame *f, uint8_t code)
|
||||
{
|
||||
return pico_icmp4_notify(f, PICO_ICMP_PARAMPROB, code);
|
||||
}
|
||||
|
||||
/***********************/
|
||||
/* Ping implementation */
|
||||
/***********************/
|
||||
/***********************/
|
||||
/***********************/
|
||||
/***********************/
|
||||
|
||||
|
||||
#ifdef PICO_SUPPORT_PING
|
||||
|
||||
|
||||
struct pico_icmp4_ping_cookie
|
||||
{
|
||||
struct pico_ip4 dst;
|
||||
uint16_t err;
|
||||
uint16_t id;
|
||||
uint16_t seq;
|
||||
uint16_t size;
|
||||
int count;
|
||||
pico_time timestamp;
|
||||
int interval;
|
||||
int timeout;
|
||||
void (*cb)(struct pico_icmp4_stats*);
|
||||
};
|
||||
|
||||
static int cookie_compare(void *ka, void *kb)
|
||||
{
|
||||
struct pico_icmp4_ping_cookie *a = ka, *b = kb;
|
||||
if (a->id < b->id)
|
||||
return -1;
|
||||
|
||||
if (a->id > b->id)
|
||||
return 1;
|
||||
|
||||
return (a->seq - b->seq);
|
||||
}
|
||||
|
||||
static PICO_TREE_DECLARE(Pings, cookie_compare);
|
||||
|
||||
static int8_t pico_icmp4_send_echo(struct pico_icmp4_ping_cookie *cookie)
|
||||
{
|
||||
struct pico_frame *echo = NULL;
|
||||
struct pico_icmp4_hdr *hdr;
|
||||
struct pico_device *dev = pico_ipv4_source_dev_find(&cookie->dst);
|
||||
if (!dev)
|
||||
return -1;
|
||||
|
||||
echo = pico_proto_ipv4.alloc(&pico_proto_ipv4, dev, (uint16_t)(PICO_ICMPHDR_UN_SIZE + cookie->size));
|
||||
if (!echo)
|
||||
return -1;
|
||||
|
||||
hdr = (struct pico_icmp4_hdr *) echo->transport_hdr;
|
||||
|
||||
hdr->type = PICO_ICMP_ECHO;
|
||||
hdr->code = 0;
|
||||
hdr->hun.ih_idseq.idseq_id = short_be(cookie->id);
|
||||
hdr->hun.ih_idseq.idseq_seq = short_be(cookie->seq);
|
||||
echo->transport_len = (uint16_t)(PICO_ICMPHDR_UN_SIZE + cookie->size);
|
||||
echo->payload = echo->transport_hdr + PICO_ICMPHDR_UN_SIZE;
|
||||
echo->payload_len = cookie->size;
|
||||
/* XXX: Fill payload */
|
||||
pico_icmp4_checksum(echo);
|
||||
pico_ipv4_frame_push(echo, &cookie->dst, PICO_PROTO_ICMP4);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void ping_timeout(pico_time now, void *arg)
|
||||
{
|
||||
struct pico_icmp4_ping_cookie *cookie = (struct pico_icmp4_ping_cookie *)arg;
|
||||
IGNORE_PARAMETER(now);
|
||||
|
||||
if(pico_tree_findKey(&Pings, cookie)) {
|
||||
if (cookie->err == PICO_PING_ERR_PENDING) {
|
||||
struct pico_icmp4_stats stats;
|
||||
stats.dst = cookie->dst;
|
||||
stats.seq = cookie->seq;
|
||||
stats.time = 0;
|
||||
stats.size = cookie->size;
|
||||
stats.err = PICO_PING_ERR_TIMEOUT;
|
||||
dbg(" ---- Ping timeout!!!\n");
|
||||
cookie->cb(&stats);
|
||||
}
|
||||
|
||||
pico_tree_delete(&Pings, cookie);
|
||||
PICO_FREE(cookie);
|
||||
}
|
||||
}
|
||||
|
||||
static void next_ping(pico_time now, void *arg);
|
||||
static int send_ping(struct pico_icmp4_ping_cookie *cookie)
|
||||
{
|
||||
uint32_t timeout_timer = 0;
|
||||
struct pico_icmp4_stats stats;
|
||||
pico_icmp4_send_echo(cookie);
|
||||
cookie->timestamp = pico_tick;
|
||||
timeout_timer = pico_timer_add((uint32_t)cookie->timeout, ping_timeout, cookie);
|
||||
if (!timeout_timer) {
|
||||
goto fail;
|
||||
}
|
||||
if (cookie->seq < (uint16_t)cookie->count) {
|
||||
if (!pico_timer_add((uint32_t)cookie->interval, next_ping, cookie)) {
|
||||
pico_timer_cancel(timeout_timer);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
dbg("ICMP4: Failed to start timer\n");
|
||||
cookie->err = PICO_PING_ERR_ABORTED;
|
||||
stats.err = cookie->err;
|
||||
cookie->cb(&stats);
|
||||
pico_tree_delete(&Pings, cookie);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void next_ping(pico_time now, void *arg)
|
||||
{
|
||||
struct pico_icmp4_ping_cookie *newcookie, *cookie = (struct pico_icmp4_ping_cookie *)arg;
|
||||
IGNORE_PARAMETER(now);
|
||||
|
||||
if(pico_tree_findKey(&Pings, cookie)) {
|
||||
if (cookie->err == PICO_PING_ERR_ABORTED)
|
||||
return;
|
||||
|
||||
if (cookie->seq < (uint16_t)cookie->count) {
|
||||
newcookie = PICO_ZALLOC(sizeof(struct pico_icmp4_ping_cookie));
|
||||
if (!newcookie)
|
||||
return;
|
||||
|
||||
memcpy(newcookie, cookie, sizeof(struct pico_icmp4_ping_cookie));
|
||||
newcookie->seq++;
|
||||
|
||||
if (pico_tree_insert(&Pings, newcookie)) {
|
||||
dbg("ICMP4: Failed to insert new cookie in tree \n");
|
||||
PICO_FREE(newcookie);
|
||||
return;
|
||||
}
|
||||
|
||||
if (send_ping(newcookie)) {
|
||||
dbg("ICMP4: Failed to send ping\n");
|
||||
PICO_FREE(newcookie);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void ping_recv_reply(struct pico_frame *f)
|
||||
{
|
||||
struct pico_icmp4_ping_cookie test, *cookie;
|
||||
struct pico_icmp4_hdr *hdr = (struct pico_icmp4_hdr *) f->transport_hdr;
|
||||
test.id = short_be(hdr->hun.ih_idseq.idseq_id );
|
||||
test.seq = short_be(hdr->hun.ih_idseq.idseq_seq);
|
||||
|
||||
cookie = pico_tree_findKey(&Pings, &test);
|
||||
if (cookie) {
|
||||
struct pico_icmp4_stats stats;
|
||||
if (cookie->err == PICO_PING_ERR_ABORTED)
|
||||
return;
|
||||
|
||||
cookie->err = PICO_PING_ERR_REPLIED;
|
||||
stats.dst = ((struct pico_ipv4_hdr *)f->net_hdr)->src;
|
||||
stats.seq = cookie->seq;
|
||||
stats.size = cookie->size;
|
||||
stats.time = pico_tick - cookie->timestamp;
|
||||
stats.err = cookie->err;
|
||||
stats.ttl = ((struct pico_ipv4_hdr *)f->net_hdr)->ttl;
|
||||
if(cookie->cb != NULL)
|
||||
cookie->cb(&stats);
|
||||
} else {
|
||||
dbg("Reply for seq=%d, not found.\n", test.seq);
|
||||
}
|
||||
}
|
||||
|
||||
int pico_icmp4_ping(char *dst, int count, int interval, int timeout, int size, void (*cb)(struct pico_icmp4_stats *))
|
||||
{
|
||||
static uint16_t next_id = 0x91c0;
|
||||
struct pico_icmp4_ping_cookie *cookie;
|
||||
|
||||
if((dst == NULL) || (interval == 0) || (timeout == 0) || (count == 0)) {
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
cookie = PICO_ZALLOC(sizeof(struct pico_icmp4_ping_cookie));
|
||||
if (!cookie) {
|
||||
pico_err = PICO_ERR_ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pico_string_to_ipv4(dst, (uint32_t *)&cookie->dst.addr) < 0) {
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
PICO_FREE(cookie);
|
||||
return -1;
|
||||
}
|
||||
|
||||
cookie->seq = 1;
|
||||
cookie->id = next_id++;
|
||||
cookie->err = PICO_PING_ERR_PENDING;
|
||||
cookie->size = (uint16_t)size;
|
||||
cookie->interval = interval;
|
||||
cookie->timeout = timeout;
|
||||
cookie->cb = cb;
|
||||
cookie->count = count;
|
||||
|
||||
if (pico_tree_insert(&Pings, cookie)) {
|
||||
dbg("ICMP4: Failed to insert cookie in tree \n");
|
||||
PICO_FREE(cookie);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (send_ping(cookie)) {
|
||||
PICO_FREE(cookie);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return cookie->id;
|
||||
|
||||
}
|
||||
|
||||
int pico_icmp4_ping_abort(int id)
|
||||
{
|
||||
struct pico_tree_node *node;
|
||||
int found = 0;
|
||||
pico_tree_foreach(node, &Pings)
|
||||
{
|
||||
struct pico_icmp4_ping_cookie *ck =
|
||||
(struct pico_icmp4_ping_cookie *) node->keyValue;
|
||||
if (ck->id == (uint16_t)id) {
|
||||
ck->err = PICO_PING_ERR_ABORTED;
|
||||
found++;
|
||||
}
|
||||
}
|
||||
if (found > 0)
|
||||
return 0; /* OK if at least one pending ping has been canceled */
|
||||
|
||||
pico_err = PICO_ERR_ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -349,6 +349,11 @@ static int pico_ipv4_process_local_unicast_in(struct pico_frame *f)
|
|||
else
|
||||
pico_transport_receive(f, hdr->proto);
|
||||
|
||||
return 1;
|
||||
} else if (f->dev->proxied) {
|
||||
// Proxied device: deliver all traffic locally
|
||||
pico_transport_receive(f, hdr->proto);
|
||||
|
||||
return 1;
|
||||
} else if (pico_tree_findKey(&Tree_dev_link, &test)) {
|
||||
#ifdef PICO_SUPPORT_UDP
|
||||
|
@ -1052,6 +1057,9 @@ int pico_ipv4_frame_push(struct pico_frame *f, struct pico_ip4 *dst, uint8_t pro
|
|||
}
|
||||
|
||||
hdr->dst.addr = dst->addr;
|
||||
if (f->local_ip.addr)
|
||||
hdr->src.addr = f->local_ip.addr; // Masqueraded
|
||||
else
|
||||
hdr->src.addr = link->address.addr;
|
||||
hdr->ttl = ttl;
|
||||
hdr->tos = f->send_tos;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,206 +0,0 @@
|
|||
/* ****************************************************************************
|
||||
* PicoTCP. Copyright (c) 2014 TASS Belgium NV. Some rights reserved.
|
||||
* See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage.
|
||||
* .
|
||||
* Author: Toon Stegen, Jelle De Vleeschouwer
|
||||
* ****************************************************************************/
|
||||
#ifndef INCLUDE_PICO_MDNS
|
||||
#define INCLUDE_PICO_MDNS
|
||||
|
||||
#include "pico_dns_common.h"
|
||||
#include "pico_tree.h"
|
||||
#include "pico_ipv4.h"
|
||||
|
||||
/* ********************************* CONFIG ***********************************/
|
||||
#define PICO_MDNS_PROBE_UNICAST 1 /* Probe queries as QU-questions */
|
||||
#define PICO_MDNS_CONTINUOUS_REFRESH 0 /* Continuously update cache */
|
||||
#define PICO_MDNS_ALLOW_CACHING 1 /* Enable caching on this host */
|
||||
#define PICO_MDNS_DEFAULT_TTL 120 /* Default TTL of mDNS records */
|
||||
#define PICO_MDNS_SERVICE_TTL 120 /* Default TTL of SRV/TXT/PTR/NSEC */
|
||||
#define PICO_MDNS_PROBE_COUNT 3
|
||||
/* Amount of probes to send:
|
||||
RFC6762: 8.1. Probing:
|
||||
250 ms after the first query, the host should send a second; then,
|
||||
250 ms after that, a third. If, by 250 ms after the third probe, no
|
||||
conflicting Multicast DNS responses have been received, the host may
|
||||
move to the next step, announcing.
|
||||
*/
|
||||
|
||||
#define PICO_MDNS_ANNOUNCEMENT_COUNT 3
|
||||
/* Amount of announcements to send: (we've opted for 1 extra for robustness)
|
||||
RFC6762: 8.3. Announcing:
|
||||
The Multicast DNS responder MUST send at least two unsolicited
|
||||
responses, one second apart. To provide increased robustness against
|
||||
packet loss, a responder MAY send up to eight unsolicited responses,
|
||||
provided that the interval between unsolicited responses increases by
|
||||
at least a factor of two with every response sent.
|
||||
*/
|
||||
/* ****************************************************************************/
|
||||
|
||||
#define PICO_MDNS_DEST_ADDR4 "224.0.0.251"
|
||||
|
||||
/* To make mDNS records unique or shared records */
|
||||
#define PICO_MDNS_RECORD_UNIQUE 0x00u
|
||||
#define PICO_MDNS_RECORD_SHARED 0x01u
|
||||
|
||||
/* To indicate if we reclaim or not */
|
||||
#define PICO_MDNS_RECLAIM 1
|
||||
#define PICO_MDNS_NO_RECLAIM 0
|
||||
|
||||
/* Flag to check for when records are returned, to determine the hostname */
|
||||
#define PICO_MDNS_RECORD_HOSTNAME 0x02u
|
||||
#define IS_HOSTNAME_RECORD(x) \
|
||||
(((x)->flags) & PICO_MDNS_RECORD_HOSTNAME) ? (1) : (0)
|
||||
|
||||
/* --- MDNS resource record --- */
|
||||
struct pico_mdns_record
|
||||
{
|
||||
struct pico_dns_record *record; /* DNS Resource Record */
|
||||
uint32_t current_ttl; /* Current TTL */
|
||||
uint8_t flags; /* Resource Record flags */
|
||||
uint8_t claim_id; /* Claim ID number */
|
||||
};
|
||||
|
||||
/* ****************************************************************************
|
||||
* Compares 2 mDNS records by type, name AND rdata for a truly unique result
|
||||
*
|
||||
* @param ra mDNS record A
|
||||
* @param rb mDNS record B
|
||||
* @return 0 when records are equal, returns difference when they're not.
|
||||
* ****************************************************************************/
|
||||
int
|
||||
pico_mdns_record_cmp( void *a, void *b );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Deletes a single mDNS resource record.
|
||||
*
|
||||
* @param record Void-pointer to mDNS Resource Record. Can be used with pico_-
|
||||
* tree-destroy.
|
||||
* @return Returns 0 on success, something else on failure.
|
||||
* ****************************************************************************/
|
||||
int
|
||||
pico_mdns_record_delete( void **record );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Creates a single standalone mDNS resource record with given name, type and
|
||||
* data to register on the network.
|
||||
*
|
||||
* @param url DNS rrecord name in URL format. Will be converted to DNS
|
||||
* name notation format.
|
||||
* @param _rdata Memory buffer with data to insert in the resource record. If
|
||||
* data of record should contain a DNS name, the name in the
|
||||
* databuffer needs to be in URL-format.
|
||||
* @param datalen The exact length in bytes of the _rdata-buffer. If data of
|
||||
* record should contain a DNS name, datalen needs to be
|
||||
* pico_dns_strlen(_rdata).
|
||||
* @param rtype DNS type of the resource record to be.
|
||||
* @param rclass DNS class of the resource record to be.
|
||||
* @param rttl DNS ttl of the resource record to be.
|
||||
* @param flags You can specify if the mDNS record should be a shared record
|
||||
* rather than a unique record.
|
||||
* @return Pointer to newly created mDNS resource record.
|
||||
* ****************************************************************************/
|
||||
struct pico_mdns_record *
|
||||
pico_mdns_record_create( const char *url,
|
||||
void *_rdata,
|
||||
uint16_t datalen,
|
||||
uint16_t rtype,
|
||||
uint32_t rttl,
|
||||
uint8_t flags );
|
||||
|
||||
|
||||
|
||||
/* ****************************************************************************
|
||||
* Definition of DNS record tree
|
||||
* ****************************************************************************/
|
||||
typedef struct pico_tree pico_mdns_rtree;
|
||||
#define PICO_MDNS_RTREE_DECLARE(name) \
|
||||
pico_mdns_rtree (name) = {&LEAF, pico_mdns_record_cmp}
|
||||
#define PICO_MDNS_RTREE_DESTROY(rtree) \
|
||||
pico_tree_destroy((rtree), pico_mdns_record_delete)
|
||||
#define PICO_MDNS_RTREE_ADD(tree, record) \
|
||||
pico_tree_insert((tree), (record))
|
||||
|
||||
/* ****************************************************************************
|
||||
* API-call to query a record with a certain URL and type. First checks the
|
||||
* Cache for this record. If no cache-entry is found, a query will be sent on
|
||||
* the wire for this record.
|
||||
*
|
||||
* @param url URL to query for.
|
||||
* @param type DNS type top query for.
|
||||
* @param callback Callback to call when records are found for the query.
|
||||
* @return 0 when query is correctly parsed, something else on failure.
|
||||
* ****************************************************************************/
|
||||
int
|
||||
pico_mdns_getrecord( const char *url, uint16_t type,
|
||||
void (*callback)(pico_mdns_rtree *,
|
||||
char *,
|
||||
void *),
|
||||
void *arg );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Claim all different mDNS records in a tree in a single API-call. All records
|
||||
* in tree are called in a single new claim-session.
|
||||
*
|
||||
* @param rtree mDNS record tree with records to claim
|
||||
* @param callback Callback to call when all record are properly claimed.
|
||||
* @return 0 When claiming didn't horribly fail.
|
||||
* ****************************************************************************/
|
||||
int
|
||||
pico_mdns_claim( pico_mdns_rtree record_tree,
|
||||
void (*callback)(pico_mdns_rtree *,
|
||||
char *,
|
||||
void *),
|
||||
void *arg );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Tries to claim a hostname for this machine. Claims automatically a
|
||||
* unique A record with the IPv4-address of this host.
|
||||
* The hostname won't be set directly when this functions returns,
|
||||
* but only if the claiming of the unique record succeeded.
|
||||
* Init-callback will be called when the hostname-record is successfully
|
||||
* registered.
|
||||
*
|
||||
* @param url URL to set the hostname to.
|
||||
* @param arg Argument to pass to the init-callback.
|
||||
* @return 0 when the host started registering the hostname-record successfully,
|
||||
* Returns something else when it didn't succeeded.
|
||||
* ****************************************************************************/
|
||||
int
|
||||
pico_mdns_tryclaim_hostname( const char *url, void *arg );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Get the current hostname for this machine.
|
||||
*
|
||||
* @return Returns the hostname for this machine when the module is initialised
|
||||
* Returns NULL when the module is not initialised.
|
||||
* ****************************************************************************/
|
||||
const char *
|
||||
pico_mdns_get_hostname( void );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Initialises the entire mDNS-module and sets the hostname for this machine.
|
||||
* Sets up the global mDNS socket properly and calls callback when succeeded.
|
||||
* Only when the module is properly initialised records can be registered on
|
||||
* the module.
|
||||
*
|
||||
* @param hostname URL to set the hostname to.
|
||||
* @param address IPv4-address of this host to bind to.
|
||||
* @param callback Callback to call when the hostname is registered and
|
||||
* also the global mDNS module callback. Gets called when
|
||||
* Passive conflicts occur, so changes in records can be
|
||||
* tracked in this callback.
|
||||
* @param arg Argument to pass to the init-callback.
|
||||
* @return 0 when the module is properly initialised and the host started regis-
|
||||
* tering the hostname. Returns something else went the host failed
|
||||
* initialising the module or registering the hostname.
|
||||
* ****************************************************************************/
|
||||
int
|
||||
pico_mdns_init( const char *hostname,
|
||||
struct pico_ip4 address,
|
||||
void (*callback)(pico_mdns_rtree *,
|
||||
char *,
|
||||
void *),
|
||||
void *arg );
|
||||
|
||||
#endif /* _INCLUDE_PICO_MDNS */
|
|
@ -980,6 +980,8 @@ static int tcp_send(struct pico_socket_tcp *ts, struct pico_frame *f)
|
|||
hdr->crc = 0;
|
||||
hdr->crc = short_be(pico_tcp_checksum(f));
|
||||
|
||||
f->local_ip.addr = ts->sock.local_addr.ip4.addr; // Masqueraded
|
||||
|
||||
return tcp_send_try_enqueue(ts, f);
|
||||
|
||||
}
|
||||
|
@ -1318,6 +1320,7 @@ static void tcp_send_empty(struct pico_socket_tcp *t, uint16_t flags, int is_kee
|
|||
hdr->crc = short_be(pico_tcp_checksum(f));
|
||||
|
||||
/* TCP: ENQUEUE to PROTO */
|
||||
f->local_ip.addr = t->sock.local_addr.ip4.addr; // Masqueraded
|
||||
pico_enqueue(&tcp_out, f);
|
||||
}
|
||||
|
||||
|
@ -1363,6 +1366,7 @@ static int tcp_do_send_rst(struct pico_socket *s, uint32_t seq)
|
|||
hdr->crc = short_be(pico_tcp_checksum(f));
|
||||
|
||||
/* TCP: ENQUEUE to PROTO */
|
||||
f->local_ip.addr = s->local_addr.ip4.addr; // Masqueraded
|
||||
pico_enqueue(&tcp_out, f);
|
||||
tcp_dbg("TCP SEND_RST >>>>>>>>>>>>>>> DONE\n");
|
||||
return 0;
|
||||
|
@ -1535,6 +1539,7 @@ static int tcp_nosync_rst(struct pico_socket *s, struct pico_frame *fr)
|
|||
hdr->crc = short_be(pico_tcp_checksum(f));
|
||||
|
||||
/* TCP: ENQUEUE to PROTO */
|
||||
f->local_ip.addr = s->local_addr.ip4.addr; // Masqueraded
|
||||
pico_enqueue(&tcp_out, f);
|
||||
|
||||
/***************************************************************************/
|
||||
|
@ -1585,6 +1590,7 @@ static void tcp_send_fin(struct pico_socket_tcp *t)
|
|||
hdr->crc = short_be(pico_tcp_checksum(f));
|
||||
/* tcp_dbg("SENDING FIN...\n"); */
|
||||
if (t->linger_timeout > 0) {
|
||||
f->local_ip.addr = t->sock.local_addr.ip4.addr; // Masqueraded
|
||||
pico_enqueue(&tcp_out, f);
|
||||
t->snd_nxt++;
|
||||
} else {
|
||||
|
@ -1853,6 +1859,7 @@ static int tcp_rto_xmit(struct pico_socket_tcp *t, struct pico_frame *f)
|
|||
return -1;
|
||||
}
|
||||
|
||||
cpy->local_ip.addr = t->sock.local_addr.ip4.addr; // Masqueraded
|
||||
if (pico_enqueue(&tcp_out, cpy) > 0) {
|
||||
t->snd_last_out = SEQN(cpy);
|
||||
add_retransmission_timer(t, (t->rto << (++t->backoff)) + TCP_TIME);
|
||||
|
@ -2010,6 +2017,7 @@ static int tcp_retrans(struct pico_socket_tcp *t, struct pico_frame *f)
|
|||
return -1;
|
||||
}
|
||||
|
||||
cpy->local_ip.addr = t->sock.local_addr.ip4.addr; // Masqueraded
|
||||
if (pico_enqueue(&tcp_out, cpy) > 0) {
|
||||
t->in_flight++;
|
||||
t->snd_last_out = SEQN(cpy);
|
||||
|
@ -2386,6 +2394,9 @@ static int tcp_syn(struct pico_socket *s, struct pico_frame *f)
|
|||
if (!new)
|
||||
return -1;
|
||||
|
||||
if (s->local_port == 0)
|
||||
new->sock.local_port = hdr->trans.dport; // Masqueraded
|
||||
|
||||
#ifdef PICO_TCP_SUPPORT_SOCKET_STATS
|
||||
if (!pico_timer_add(2000, sock_stats, s)) {
|
||||
tcp_dbg("TCP: Failed to start socket statistics timer\n");
|
||||
|
@ -3130,6 +3141,9 @@ int pico_tcp_push(struct pico_protocol *self, struct pico_frame *f)
|
|||
struct pico_socket_tcp *t = (struct pico_socket_tcp *) f->sock;
|
||||
IGNORE_PARAMETER(self);
|
||||
pico_err = PICO_ERR_NOERR;
|
||||
if (f->local_port)
|
||||
hdr->trans.sport = f->local_port; // Masqueraded
|
||||
else
|
||||
hdr->trans.sport = t->sock.local_port;
|
||||
hdr->trans.dport = t->sock.remote_port;
|
||||
hdr->seq = long_be(t->snd_last + 1);
|
||||
|
@ -3276,6 +3290,13 @@ int pico_tcp_get_bufsize_in(struct pico_socket *s, uint32_t *value)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int pico_tcp_get_bufspace_out(struct pico_socket *s, uint32_t *value)
|
||||
{
|
||||
struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
|
||||
*value = t->tcpq_out.max_size - t->tcpq_out.size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pico_tcp_get_bufsize_out(struct pico_socket *s, uint32_t *value)
|
||||
{
|
||||
struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
|
||||
|
|
|
@ -95,6 +95,7 @@ void pico_tcp_flags_update(struct pico_frame *f, struct pico_socket *s);
|
|||
int pico_tcp_set_bufsize_in(struct pico_socket *s, uint32_t value);
|
||||
int pico_tcp_set_bufsize_out(struct pico_socket *s, uint32_t value);
|
||||
int pico_tcp_get_bufsize_in(struct pico_socket *s, uint32_t *value);
|
||||
int pico_tcp_get_bufspace_out(struct pico_socket *s, uint32_t *value);
|
||||
int pico_tcp_get_bufsize_out(struct pico_socket *s, uint32_t *value);
|
||||
int pico_tcp_set_keepalive_probes(struct pico_socket *s, uint32_t value);
|
||||
int pico_tcp_set_keepalive_intvl(struct pico_socket *s, uint32_t value);
|
||||
|
|
|
@ -107,6 +107,9 @@ static int pico_udp_push(struct pico_protocol *self, struct pico_frame *f)
|
|||
|
||||
/* this (fragmented) frame should contain a transport header */
|
||||
if (f->transport_hdr != f->payload) {
|
||||
if (f->local_port)
|
||||
hdr->trans.sport = f->local_port; // Masqueraded
|
||||
else
|
||||
hdr->trans.sport = f->sock->local_port;
|
||||
if (remote_endpoint) {
|
||||
hdr->trans.dport = remote_endpoint->remote_port;
|
||||
|
@ -173,6 +176,8 @@ static void pico_udp_get_msginfo(struct pico_frame *f, struct pico_msginfo *msgi
|
|||
struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *)(f->net_hdr);
|
||||
msginfo->ttl = hdr->ttl;
|
||||
msginfo->tos = hdr->tos;
|
||||
msginfo->local_addr.ip4 = hdr->dst;
|
||||
msginfo->local_port = ((struct pico_udp_hdr *)f->transport_hdr)->trans.dport;
|
||||
#endif
|
||||
} else {
|
||||
#ifdef PICO_SUPPORT_IPV6
|
||||
|
|
|
@ -278,23 +278,20 @@ struct pico_frame *pico_frame_deepcopy(struct pico_frame *f)
|
|||
|
||||
static inline uint32_t pico_checksum_adder(uint32_t sum, void *data, uint32_t len)
|
||||
{
|
||||
uint16_t *buf = (uint16_t *)data;
|
||||
uint16_t *stop;
|
||||
|
||||
if (len & 0x01) {
|
||||
--len;
|
||||
uint8_t *p = (uint8_t *)data;
|
||||
uint8_t *stop = p + len;
|
||||
while (p < stop)
|
||||
{
|
||||
#ifdef PICO_BIGENDIAN
|
||||
sum += (((uint8_t *)data)[len]) << 8;
|
||||
sum += *p++ << 8;
|
||||
if (p < stop)
|
||||
sum += *p++;
|
||||
#else
|
||||
sum += ((uint8_t *)data)[len];
|
||||
sum += *p++;
|
||||
if (p < stop)
|
||||
sum += *p++ << 8;
|
||||
#endif
|
||||
}
|
||||
|
||||
stop = (uint16_t *)(((uint8_t *)data) + len);
|
||||
|
||||
while (buf < stop) {
|
||||
sum += *buf++;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
|
|
@ -582,7 +582,15 @@ static int pico_socket_deliver(struct pico_protocol *p, struct pico_frame *f, ui
|
|||
if (!tr)
|
||||
return -1;
|
||||
|
||||
// Try to find a socket using the local port number
|
||||
sp = pico_get_sockport(p->proto_number, localport);
|
||||
if (sp)
|
||||
{
|
||||
if (pico_socket_transport_deliver(p, sp, f) == 0)
|
||||
return 0;
|
||||
}
|
||||
// Try to find a wildcard socket
|
||||
sp = pico_get_sockport(p->proto_number, 0);
|
||||
if (!sp) {
|
||||
dbg("No such port %d\n", short_be(localport));
|
||||
return -1;
|
||||
|
@ -1118,6 +1126,8 @@ static int pico_socket_xmit_one(struct pico_socket *s, const void *buf, const in
|
|||
if (msginfo) {
|
||||
f->send_ttl = (uint8_t)msginfo->ttl;
|
||||
f->send_tos = (uint8_t)msginfo->tos;
|
||||
f->local_ip = msginfo->local_addr.ip4;
|
||||
f->local_port = msginfo->local_port;
|
||||
}
|
||||
|
||||
memcpy(f->payload, (const uint8_t *)buf, f->payload_len);
|
||||
|
@ -1377,7 +1387,10 @@ int MOCKABLE pico_socket_sendto_extended(struct pico_socket *s, const void *buf,
|
|||
if (pico_socket_sendto_initial_checks(s, buf, len, dst, remote_port) < 0)
|
||||
return -1;
|
||||
|
||||
|
||||
if (msginfo && msginfo->local_addr.ip4.addr)
|
||||
src = &msginfo->local_addr.ip4;
|
||||
else
|
||||
{
|
||||
src = pico_socket_sendto_get_src(s, dst);
|
||||
if (!src) {
|
||||
#ifdef PICO_SUPPORT_IPV6
|
||||
|
@ -1391,6 +1404,7 @@ int MOCKABLE pico_socket_sendto_extended(struct pico_socket *s, const void *buf,
|
|||
#endif
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
remote_endpoint = pico_socket_sendto_destination(s, dst, remote_port);
|
||||
if (pico_socket_sendto_set_localport(s) < 0) {
|
||||
|
@ -1589,13 +1603,14 @@ int MOCKABLE pico_socket_bind(struct pico_socket *s, void *local_addr, uint16_t
|
|||
}
|
||||
|
||||
/* When given port = 0, get a random high port to bind to. */
|
||||
if (*port == 0) {
|
||||
*port = pico_socket_high_port(PROTO(s));
|
||||
if (*port == 0) {
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
// Port 0 is used as a wildcard for "all ports"
|
||||
// if (*port == 0) {
|
||||
// *port = pico_socket_high_port(PROTO(s));
|
||||
// if (*port == 0) {
|
||||
// pico_err = PICO_ERR_EINVAL;
|
||||
// return -1;
|
||||
// }
|
||||
// }
|
||||
|
||||
if (pico_is_port_free(PROTO(s), *port, local_addr, s->net) == 0) {
|
||||
pico_err = PICO_ERR_EADDRINUSE;
|
||||
|
@ -1757,13 +1772,52 @@ struct pico_socket *pico_socket_accept(struct pico_socket *s, void *orig, uint16
|
|||
}
|
||||
|
||||
if (TCPSTATE(s) == PICO_SOCKET_STATE_TCP_LISTEN) {
|
||||
struct pico_sockport *sp = pico_get_sockport(PICO_PROTO_TCP, s->local_port);
|
||||
struct pico_socket *found;
|
||||
uint32_t socklen = sizeof(struct pico_ip4);
|
||||
/* If at this point no incoming connection socket is found,
|
||||
* the accept call is valid, but no connection is established yet.
|
||||
*/
|
||||
struct pico_socket *found;
|
||||
uint32_t socklen = sizeof(struct pico_ip4);
|
||||
struct pico_sockport *sp;
|
||||
|
||||
pico_err = PICO_ERR_EAGAIN;
|
||||
|
||||
if (s->local_port == 0)
|
||||
{
|
||||
// Wildcard socket: do a full scan of the TCP table to find a new child
|
||||
struct pico_tree_node *index, *indexp;
|
||||
|
||||
pico_tree_foreach(indexp, &TCPTable)
|
||||
{
|
||||
sp = indexp->keyValue;
|
||||
if (sp)
|
||||
{
|
||||
pico_tree_foreach(index, &sp->socks)
|
||||
{
|
||||
found = index->keyValue;
|
||||
if (found == NULL)
|
||||
continue;
|
||||
|
||||
if ((s == found->parent) && ((found->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_ESTABLISHED)) {
|
||||
found->parent = NULL;
|
||||
pico_err = PICO_ERR_NOERR;
|
||||
#ifdef PICO_SUPPORT_IPV6
|
||||
if (is_sock_ipv6(s))
|
||||
socklen = sizeof(struct pico_ip6);
|
||||
|
||||
#endif
|
||||
memcpy(orig, &found->remote_addr, socklen);
|
||||
*port = found->remote_port;
|
||||
s->number_of_pending_conn--;
|
||||
return found;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Normal search using the local port
|
||||
sp = pico_get_sockport(PICO_PROTO_TCP, s->local_port);
|
||||
if (sp) {
|
||||
struct pico_tree_node *index;
|
||||
/* RB_FOREACH(found, socket_tree, &sp->socks) { */
|
||||
|
@ -1785,6 +1839,7 @@ struct pico_socket *pico_socket_accept(struct pico_socket *s, void *orig, uint16
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
Created on: Sep 24, 2018
|
||||
|
||||
Copyright 2018 flyinghead
|
||||
|
||||
This file is part of reicast.
|
||||
|
||||
reicast is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
reicast is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with reicast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#ifndef _WIN32
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
#include <pico_stack.h>
|
||||
#include <pico_ipv4.h>
|
||||
#include <pico_dns_common.h>
|
||||
}
|
||||
|
||||
void get_host_by_name(const char *name, struct pico_ip4 dnsaddr);
|
||||
int get_dns_answer(struct pico_ip4 *address, struct pico_ip4 dnsaddr);
|
||||
char *read_name(char *reader, char *buffer, int *count);
|
||||
void set_non_blocking(int fd);
|
||||
|
||||
static int sock_fd = -1;
|
||||
static unsigned short qid = PICO_TIME_MS();
|
||||
static int qname_len;
|
||||
|
||||
void get_host_by_name(const char *host, struct pico_ip4 dnsaddr)
|
||||
{
|
||||
if (sock_fd < 0)
|
||||
{
|
||||
sock_fd = socket(AF_INET , SOCK_DGRAM , IPPROTO_UDP);
|
||||
set_non_blocking(sock_fd);
|
||||
}
|
||||
|
||||
struct sockaddr_in dest;
|
||||
dest.sin_family = AF_INET;
|
||||
dest.sin_port = htons(53);
|
||||
dest.sin_addr.s_addr = dnsaddr.addr;
|
||||
|
||||
// DNS Packet header
|
||||
char buf[1024];
|
||||
pico_dns_packet *dns = (pico_dns_packet *)&buf;
|
||||
|
||||
dns->id = qid++;
|
||||
dns->qr = PICO_DNS_QR_QUERY;
|
||||
dns->opcode = PICO_DNS_OPCODE_QUERY;
|
||||
dns->aa = PICO_DNS_AA_NO_AUTHORITY;
|
||||
dns->tc = PICO_DNS_TC_NO_TRUNCATION;
|
||||
dns->rd = PICO_DNS_RD_IS_DESIRED;
|
||||
dns->ra = PICO_DNS_RA_NO_SUPPORT;
|
||||
dns->z = 0;
|
||||
dns->rcode = PICO_DNS_RCODE_NO_ERROR;
|
||||
dns->qdcount = htons(1); // One question
|
||||
dns->ancount = 0;
|
||||
dns->nscount = 0;
|
||||
dns->arcount = 0;
|
||||
|
||||
char *qname = &buf[sizeof(pico_dns_packet)];
|
||||
|
||||
strcpy(qname + 1, host);
|
||||
pico_dns_name_to_dns_notation(qname, 128);
|
||||
qname_len = strlen(qname) + 1;
|
||||
|
||||
struct pico_dns_question_suffix *qinfo = (struct pico_dns_question_suffix *) &buf[sizeof(pico_dns_packet) + qname_len]; //fill it
|
||||
qinfo->qtype = htons(PICO_DNS_TYPE_A); // Address record
|
||||
qinfo->qclass = htons(PICO_DNS_CLASS_IN);
|
||||
|
||||
if (sendto(sock_fd, buf, sizeof(pico_dns_packet) + qname_len + sizeof(struct pico_dns_question_suffix), 0, (struct sockaddr *)&dest, sizeof(dest)) < 0)
|
||||
perror("DNS sendto failed");
|
||||
}
|
||||
|
||||
int get_dns_answer(struct pico_ip4 *address, struct pico_ip4 dnsaddr)
|
||||
{
|
||||
struct sockaddr_in peer;
|
||||
socklen_t peer_len = sizeof(peer);
|
||||
char buf[1024];
|
||||
|
||||
int r = recvfrom(sock_fd, buf, sizeof(buf), 0, (struct sockaddr*)&peer , &peer_len);
|
||||
if (r < 0)
|
||||
{
|
||||
if (errno != EAGAIN && errno != EWOULDBLOCK)
|
||||
perror("DNS recvfrom failed");
|
||||
return -1;
|
||||
}
|
||||
if (peer.sin_addr.s_addr != dnsaddr.addr)
|
||||
return -1;
|
||||
|
||||
pico_dns_packet *dns = (pico_dns_packet*) buf;
|
||||
|
||||
// move to the first answer
|
||||
char *reader = &buf[sizeof(pico_dns_packet) + qname_len + sizeof(struct pico_dns_question_suffix)];
|
||||
|
||||
int stop = 0;
|
||||
|
||||
for (int i = 0; i < ntohs(dns->ancount); i++)
|
||||
{
|
||||
// FIXME Check name?
|
||||
free(read_name(reader, buf, &stop));
|
||||
reader = reader + stop;
|
||||
|
||||
struct pico_dns_record_suffix *record = (struct pico_dns_record_suffix *)reader;
|
||||
reader = reader + sizeof(struct pico_dns_record_suffix);
|
||||
|
||||
if (ntohs(record->rtype) == PICO_DNS_TYPE_A) // Address record
|
||||
{
|
||||
memcpy(&address->addr, reader, 4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
reader = reader + ntohs(record->rdlength);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *read_name(char *reader, char *buffer, int *count)
|
||||
{
|
||||
char *name = (char *)malloc(128);
|
||||
if ((uint8_t)reader[0] & 0xC0)
|
||||
{
|
||||
int offset = (((uint8_t)reader[0] & ~0xC0) << 8) + (uint8_t)reader[1];
|
||||
reader = &buffer[offset];
|
||||
*count = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
*count = strlen(reader) + 1;
|
||||
}
|
||||
pico_dns_notation_to_name(reader, 128);
|
||||
strcpy(name, reader + 1);
|
||||
|
||||
return name;
|
||||
}
|
|
@ -142,7 +142,9 @@ static int modem_sched_func(int tag, int c, int j)
|
|||
{
|
||||
if (last_comm_stats != 0)
|
||||
{
|
||||
printf("Stats sent %d received %d TDBE %d RDBF %d\n", sent_bytes, recvd_bytes, modem_regs.reg1e.TDBE, modem_regs.reg1e.RDBF);
|
||||
printf("Stats sent %d (%.2f kB/s) received %d (%.2f kB/s) TDBE %d RDBF %d\n", sent_bytes, sent_bytes / 2000.0,
|
||||
recvd_bytes, recvd_bytes / 2000.0,
|
||||
modem_regs.reg1e.TDBE, modem_regs.reg1e.RDBF);
|
||||
sent_bytes = 0;
|
||||
recvd_bytes = 0;
|
||||
}
|
||||
|
@ -315,6 +317,7 @@ static int modem_sched_func(int tag, int c, int j)
|
|||
static void schedule_callback(int ms)
|
||||
{
|
||||
if (modem_sched == 0)
|
||||
// FIXME would break save state -> relies on all schedule to be registered at init
|
||||
modem_sched = sh4_sched_register(0, &modem_sched_func);
|
||||
sh4_sched_request(modem_sched, SH4_MAIN_CLOCK / 1000 * ms);
|
||||
}
|
||||
|
|
|
@ -1,51 +1,131 @@
|
|||
/*
|
||||
Created on: Sep 15, 2018
|
||||
|
||||
Copyright 2018 flyinghead
|
||||
|
||||
This file is part of reicast.
|
||||
|
||||
reicast is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
reicast is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with reicast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#include <queue>
|
||||
#include <map>
|
||||
|
||||
extern "C" {
|
||||
#include <pico_stack.h>
|
||||
#include <pico_dev_ppp.h>
|
||||
#ifdef _WIN32
|
||||
#include <pico_dev_tap_windows.h>
|
||||
#else
|
||||
#include <pico_dev_tap.h>
|
||||
#endif
|
||||
#include <pico_arp.h>
|
||||
#include <pico_dev_tun.h>
|
||||
#ifdef DHCP
|
||||
#include <pico_dhcp_client.h>
|
||||
#endif
|
||||
#include <pico_socket.h>
|
||||
#include <pico_socket_tcp.h>
|
||||
#include <pico_ipv4.h>
|
||||
#include <pico_tcp.h>
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <iphlpapi.h>
|
||||
#define NETWORK_TAP
|
||||
#else
|
||||
#define NETWORK_TUN
|
||||
#ifndef _WIN32
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include "types.h"
|
||||
#include "cfg/cfg.h"
|
||||
#include "picoppp.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#define closesocket close
|
||||
#endif
|
||||
|
||||
#define RESOLVER1_OPENDNS_COM "208.67.222.222"
|
||||
#define AFO_ORIG_IP 0x83f2fb3f // 63.251.242.131 in network order
|
||||
|
||||
static struct pico_device *ppp;
|
||||
struct pico_device* tap;
|
||||
struct pico_device* tun;
|
||||
u8 virtual_mac[] = { 0x76, 0x6D, 0x61, 0x63, 0x30, 0x31 };
|
||||
|
||||
static std::queue<u8> in_buffer;
|
||||
static std::queue<u8> out_buffer;
|
||||
|
||||
static cMutex in_buffer_lock;
|
||||
static cMutex out_buffer_lock;
|
||||
|
||||
struct pico_ip4 dcaddr;
|
||||
struct pico_ip4 dnsaddr;
|
||||
static struct pico_socket *pico_tcp_socket, *pico_udp_socket;
|
||||
|
||||
struct pico_ip4 public_ip;
|
||||
struct pico_ip4 afo_ip;
|
||||
|
||||
// src socket -> socket fd
|
||||
static map<struct pico_socket *, int> tcp_sockets;
|
||||
// src port -> socket fd
|
||||
static map<uint16_t, int> udp_sockets;
|
||||
|
||||
static const uint16_t games_udp_ports[] = {
|
||||
7980, // Alien Front Online
|
||||
9789, // ChuChu Rocket
|
||||
// NBA/NFL/NCAA 2K Series
|
||||
5502,
|
||||
5503,
|
||||
5656,
|
||||
3512, // The Next Tetris
|
||||
6001, // Ooga Booga
|
||||
// PBA Tour Bowling 2001, Starlancer
|
||||
// 2300-2400, ?
|
||||
6500,
|
||||
13139,
|
||||
// Planet Ring
|
||||
7648,
|
||||
1285,
|
||||
1028,
|
||||
// World Series Baseball 2K2
|
||||
37171,
|
||||
13713,
|
||||
};
|
||||
static const uint16_t games_tcp_ports[] = {
|
||||
// NBA/NFL/NCAA 2K Series
|
||||
5011,
|
||||
6666,
|
||||
3512, // The Next Tetris
|
||||
// PBA Tour Bowling 2001, Starlancer
|
||||
// 2300-2400, ?
|
||||
47624,
|
||||
17219, // Worms World Party
|
||||
};
|
||||
// listening port -> socket fd
|
||||
static map<uint16_t, int> tcp_listening_sockets;
|
||||
|
||||
static void read_native_sockets();
|
||||
void get_host_by_name(const char *name, struct pico_ip4 dnsaddr);
|
||||
int get_dns_answer(struct pico_ip4 *address, struct pico_ip4 dnsaddr);
|
||||
|
||||
static int modem_read(struct pico_device *dev, void *data, int len)
|
||||
{
|
||||
u8 *p = (u8 *)data;
|
||||
|
||||
int count = 0;
|
||||
out_buffer_lock.Lock();
|
||||
while (!out_buffer.empty() && count < len)
|
||||
{
|
||||
*p++ = out_buffer.front();
|
||||
out_buffer.pop();
|
||||
count++;
|
||||
}
|
||||
out_buffer_lock.Unlock();
|
||||
|
||||
return count;
|
||||
}
|
||||
|
@ -54,73 +134,469 @@ static int modem_write(struct pico_device *dev, const void *data, int len)
|
|||
{
|
||||
u8 *p = (u8 *)data;
|
||||
|
||||
in_buffer_lock.Lock();
|
||||
while (len > 0)
|
||||
{
|
||||
in_buffer.push(*p++);
|
||||
len--;
|
||||
}
|
||||
in_buffer_lock.Unlock();
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void write_pico(u8 b)
|
||||
{
|
||||
out_buffer_lock.Lock();
|
||||
out_buffer.push(b);
|
||||
out_buffer_lock.Unlock();
|
||||
}
|
||||
|
||||
int read_pico()
|
||||
{
|
||||
pico_stack_tick();
|
||||
|
||||
in_buffer_lock.Lock();
|
||||
if (in_buffer.empty())
|
||||
{
|
||||
in_buffer_lock.Unlock();
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 b = in_buffer.front();
|
||||
in_buffer.pop();
|
||||
in_buffer_lock.Unlock();
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
void set_non_blocking(int fd)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||
#else
|
||||
uint32_t optl = 1;
|
||||
ioctlsocket(fd, FIONBIO, &optl);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void tcp_callback(uint16_t ev, struct pico_socket *s)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
if (ev & PICO_SOCK_EV_RD)
|
||||
{
|
||||
auto it = tcp_sockets.find(s);
|
||||
if (it == tcp_sockets.end())
|
||||
{
|
||||
printf("Unknown socket: remote port %d\n", s->remote_port);
|
||||
}
|
||||
else
|
||||
{
|
||||
char buf[1510];
|
||||
|
||||
r = pico_socket_read(it->first, buf, sizeof(buf));
|
||||
if (r > 0) {
|
||||
if (write(it->second, buf, r) < r)
|
||||
perror("tcp_callback write");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ev & PICO_SOCK_EV_CONN)
|
||||
{
|
||||
uint32_t ka_val = 0;
|
||||
struct pico_ip4 orig;
|
||||
uint16_t port;
|
||||
char peer[30];
|
||||
int yes = 1;
|
||||
|
||||
struct pico_socket *sock_a = pico_socket_accept(s, &orig, &port);
|
||||
if (sock_a == NULL)
|
||||
{
|
||||
printf("pico_socket_accept: %s\n", strerror(pico_err));
|
||||
}
|
||||
else
|
||||
{
|
||||
pico_ipv4_to_string(peer, orig.addr);
|
||||
printf("Connection established with %s:%d.\n", peer, short_be(port));
|
||||
pico_socket_setoption(sock_a, PICO_TCP_NODELAY, &yes);
|
||||
/* Set keepalive options */
|
||||
// ka_val = 5;
|
||||
// pico_socket_setoption(sock_a, PICO_SOCKET_OPT_KEEPCNT, &ka_val);
|
||||
// ka_val = 30000;
|
||||
// pico_socket_setoption(sock_a, PICO_SOCKET_OPT_KEEPIDLE, &ka_val);
|
||||
// ka_val = 5000;
|
||||
// pico_socket_setoption(sock_a, PICO_SOCKET_OPT_KEEPINTVL, &ka_val);
|
||||
|
||||
int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (sockfd < 0)
|
||||
{
|
||||
perror("socket");
|
||||
}
|
||||
else
|
||||
{
|
||||
struct sockaddr_in serveraddr;
|
||||
memset(&serveraddr, 0, sizeof(serveraddr));
|
||||
serveraddr.sin_family = AF_INET;
|
||||
serveraddr.sin_addr.s_addr = sock_a->local_addr.ip4.addr;
|
||||
if (serveraddr.sin_addr.s_addr == AFO_ORIG_IP) // Alien Front Online
|
||||
serveraddr.sin_addr.s_addr = afo_ip.addr;
|
||||
|
||||
serveraddr.sin_port = sock_a->local_port;
|
||||
if (connect(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
|
||||
{
|
||||
pico_ipv4_to_string(peer, sock_a->local_addr.ip4.addr);
|
||||
printf("TCP connection to %s:%d failed: ", peer, sock_a->local_port);
|
||||
perror(NULL);
|
||||
closesocket(sockfd);
|
||||
}
|
||||
else
|
||||
{
|
||||
set_non_blocking(sockfd);
|
||||
|
||||
int optval = 1;
|
||||
socklen_t optlen = sizeof(optval);
|
||||
#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__NetBSD__)
|
||||
setsockopt(sockfd, SOL_TCP, TCP_NODELAY, (const void *)&optval, optlen);
|
||||
#else
|
||||
struct protoent *tcp_proto = getprotobyname("TCP");
|
||||
setsockopt(sockfd, tcp_proto->p_proto, TCP_NODELAY, &optval, optlen);
|
||||
#endif
|
||||
tcp_sockets[sock_a] = sockfd;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ev & PICO_SOCK_EV_FIN) {
|
||||
//printf("Socket closed. Exit normally. \n");
|
||||
auto it = tcp_sockets.find(s);
|
||||
if (it == tcp_sockets.end())
|
||||
{
|
||||
printf("PICO_SOCK_EV_FIN: Unknown socket: remote port %d\n", s->remote_port);
|
||||
}
|
||||
else
|
||||
{
|
||||
closesocket(it->second);
|
||||
pico_socket_close(s);
|
||||
tcp_sockets.erase(s);
|
||||
}
|
||||
}
|
||||
|
||||
if (ev & PICO_SOCK_EV_ERR) {
|
||||
printf("Socket error received: %s. Bailing out.\n", strerror(pico_err));
|
||||
auto it = tcp_sockets.find(s);
|
||||
if (it == tcp_sockets.end())
|
||||
{
|
||||
printf("PICO_SOCK_EV_ERR: Unknown socket: remote port %d\n", s->remote_port);
|
||||
}
|
||||
else
|
||||
{
|
||||
closesocket(it->second);
|
||||
pico_socket_close(s);
|
||||
tcp_sockets.erase(s);
|
||||
}
|
||||
}
|
||||
|
||||
// if (ev & PICO_SOCK_EV_CLOSE)
|
||||
// {
|
||||
// }
|
||||
|
||||
// if (ev & PICO_SOCK_EV_WR)
|
||||
// {
|
||||
// }
|
||||
}
|
||||
|
||||
static int find_udp_socket(uint16_t src_port)
|
||||
{
|
||||
auto it = udp_sockets.find(src_port);
|
||||
if (it != udp_sockets.end())
|
||||
return it->second;
|
||||
|
||||
int sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (sockfd < 0)
|
||||
{
|
||||
perror("socket");
|
||||
return -1;
|
||||
}
|
||||
#ifndef _WIN32
|
||||
fcntl(sockfd, F_SETFL, O_NONBLOCK);
|
||||
#else
|
||||
uint32_t optl = 1;
|
||||
ioctlsocket(sockfd, FIONBIO, &optl);
|
||||
#endif
|
||||
|
||||
// FIXME Need to clean up at some point?
|
||||
udp_sockets[src_port] = sockfd;
|
||||
|
||||
return sockfd;
|
||||
}
|
||||
|
||||
static void udp_callback(uint16_t ev, struct pico_socket *s)
|
||||
{
|
||||
if (ev & PICO_SOCK_EV_RD)
|
||||
{
|
||||
char buf[1510];
|
||||
struct pico_ip4 src_addr;
|
||||
uint16_t src_port;
|
||||
pico_msginfo msginfo;
|
||||
int r = 0;
|
||||
while (true)
|
||||
{
|
||||
r = pico_socket_recvfrom_extended(s, buf, sizeof(buf), &src_addr.addr, &src_port, &msginfo);
|
||||
|
||||
if (r <= 0)
|
||||
{
|
||||
if (r < 0)
|
||||
printf("%s: error UDP recv: %s\n", __FUNCTION__, strerror(pico_err));
|
||||
break;
|
||||
}
|
||||
|
||||
int sockfd = find_udp_socket(src_port);
|
||||
if (sockfd >= 0)
|
||||
{
|
||||
struct sockaddr_in dst_addr;
|
||||
socklen_t addr_len = sizeof(dst_addr);
|
||||
memset(&dst_addr, 0, sizeof(dst_addr));
|
||||
dst_addr.sin_family = AF_INET;
|
||||
dst_addr.sin_addr.s_addr = msginfo.local_addr.ip4.addr;
|
||||
dst_addr.sin_port = msginfo.local_port;
|
||||
if (sendto(sockfd, buf, r, 0, (const struct sockaddr *)&dst_addr, addr_len) < 0)
|
||||
perror("sendto udp socket");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ev & PICO_SOCK_EV_ERR) {
|
||||
printf("UDP Callback error received\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void read_native_sockets()
|
||||
{
|
||||
int r;
|
||||
struct sockaddr_in src_addr;
|
||||
socklen_t addr_len;
|
||||
|
||||
// Accept incoming TCP connections
|
||||
for (auto it = tcp_listening_sockets.begin(); it != tcp_listening_sockets.end(); it++)
|
||||
{
|
||||
addr_len = sizeof(src_addr);
|
||||
memset(&src_addr, 0, addr_len);
|
||||
int sockfd = accept(it->second, (struct sockaddr *)&src_addr, &addr_len);
|
||||
if (sockfd < 0)
|
||||
{
|
||||
if (errno != EAGAIN && errno != EWOULDBLOCK)
|
||||
perror("accept");
|
||||
continue;
|
||||
}
|
||||
printf("Incoming TCP connection from %08x to port %d\n", src_addr.sin_addr.s_addr, short_be(it->first));
|
||||
struct pico_socket *ps = pico_socket_tcp_open(PICO_PROTO_IPV4);
|
||||
if (ps == NULL)
|
||||
{
|
||||
printf("pico_socket_tcp_open failed: error %d\n", pico_err);
|
||||
closesocket(sockfd);
|
||||
continue;
|
||||
}
|
||||
ps->local_addr.ip4.addr = src_addr.sin_addr.s_addr;
|
||||
ps->local_port = src_addr.sin_port;
|
||||
if (pico_socket_connect(ps, &dcaddr.addr, it->first) != 0)
|
||||
{
|
||||
printf("pico_socket_connect failed: error %d\n", pico_err);
|
||||
closesocket(sockfd);
|
||||
pico_socket_del(ps);
|
||||
continue;
|
||||
}
|
||||
tcp_sockets[ps] = sockfd;
|
||||
}
|
||||
|
||||
char buf[1500]; // FIXME MTU ?
|
||||
struct pico_msginfo msginfo;
|
||||
|
||||
// If modem buffer is full, wait
|
||||
in_buffer_lock.Lock();
|
||||
size_t in_buffer_size = in_buffer.size();
|
||||
in_buffer_lock.Unlock();
|
||||
if (in_buffer_size >= 256)
|
||||
return;
|
||||
|
||||
// Read UDP sockets
|
||||
for (auto it = udp_sockets.begin(); it != udp_sockets.end(); it++)
|
||||
{
|
||||
addr_len = sizeof(src_addr);
|
||||
memset(&src_addr, 0, addr_len);
|
||||
r = recvfrom(it->second, buf, sizeof(buf), 0, (struct sockaddr *)&src_addr, &addr_len);
|
||||
if (r > 0)
|
||||
{
|
||||
msginfo.dev = ppp;
|
||||
msginfo.tos = 0;
|
||||
msginfo.ttl = 0;
|
||||
msginfo.local_addr.ip4.addr = src_addr.sin_addr.s_addr;
|
||||
msginfo.local_port = src_addr.sin_port;
|
||||
// printf("read_native_sockets UCP received %d bytes from %08x:%d\n", r, long_be(msginfo.local_addr.ip4.addr), short_be(msginfo.local_port));
|
||||
int r2 = pico_socket_sendto_extended(pico_udp_socket, buf, r, &dcaddr, it->first, &msginfo);
|
||||
if (r2 < r)
|
||||
printf("%s: error UDP sending to %d: %s\n", __FUNCTION__, short_be(it->first), strerror(pico_err));
|
||||
}
|
||||
else if (r < 0 && errno != EAGAIN)
|
||||
{
|
||||
perror("read udp socket");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Read TCP sockets
|
||||
for (auto it = tcp_sockets.begin(); it != tcp_sockets.end(); it++)
|
||||
{
|
||||
uint32_t space;
|
||||
pico_tcp_get_bufspace_out(it->first, &space);
|
||||
if (space < sizeof(buf))
|
||||
{
|
||||
// Wait for the out buffer to empty a bit
|
||||
continue;
|
||||
}
|
||||
r = read(it->second, buf, sizeof(buf));
|
||||
if (r > 0)
|
||||
{
|
||||
// printf("read_native_sockets TCP received %d bytes\n", r);
|
||||
int r2 = pico_socket_send(it->first, buf, r);
|
||||
if (r2 < 0)
|
||||
printf("%s: error TCP sending: %s\n", __FUNCTION__, strerror(pico_err));
|
||||
else if (r2 < r)
|
||||
// FIXME EAGAIN errors. Need to buffer data or wait for call back.
|
||||
printf("%s: truncated send: %d -> %d\n", __FUNCTION__, r, r2);
|
||||
}
|
||||
else if (r < 0 && errno != EAGAIN)
|
||||
{
|
||||
perror("read tcp socket");
|
||||
closesocket(it->second);
|
||||
pico_socket_close(it->first);
|
||||
tcp_sockets.erase(it);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void close_native_sockets()
|
||||
{
|
||||
for (auto it = udp_sockets.begin(); it != udp_sockets.end(); it++)
|
||||
closesocket(it->second);
|
||||
udp_sockets.clear();
|
||||
for (auto it = tcp_sockets.begin(); it != tcp_sockets.end(); it++)
|
||||
{
|
||||
pico_socket_close(it->first);
|
||||
closesocket(it->second);
|
||||
}
|
||||
tcp_sockets.clear();
|
||||
}
|
||||
|
||||
static int modem_set_speed(struct pico_device *dev, uint32_t speed)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef DHCP
|
||||
static uint32_t dhcpclient_xid;
|
||||
static struct pico_ip4 dchp_address = { 0 };
|
||||
|
||||
void callback_dhcpclient(void *arg, int code)
|
||||
#ifdef _WIN32
|
||||
static void usleep(unsigned int usec)
|
||||
{
|
||||
char s_address[16] = { }, s_gateway[16] = { };
|
||||
HANDLE timer;
|
||||
LARGE_INTEGER ft;
|
||||
|
||||
printf("DHCP client: callback happened with code %d!\n", code);
|
||||
if (code == PICO_DHCP_SUCCESS)
|
||||
{
|
||||
dchp_address = pico_dhcp_get_address(arg);
|
||||
//gateway = pico_dhcp_get_gateway(arg);
|
||||
pico_ipv4_to_string(s_address, dchp_address.addr);
|
||||
//pico_ipv4_to_string(s_gateway, gateway.addr);
|
||||
printf("DHCP client: got IP %s assigned with cli %p\n", s_address, arg);
|
||||
}
|
||||
ft.QuadPart = -(10 * (__int64)usec);
|
||||
|
||||
timer = CreateWaitableTimer(NULL, TRUE, NULL);
|
||||
SetWaitableTimer(timer, &ft, 0, NULL, NULL, 0);
|
||||
WaitForSingleObject(timer, INFINITE);
|
||||
CloseHandle(timer);
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool pico_stack_inited;
|
||||
|
||||
bool start_pico()
|
||||
static void check_dns_entries()
|
||||
{
|
||||
struct pico_ip4 ipaddr, dcaddr, dnsaddr, netmask, zero = {
|
||||
static uint32_t dns_query_start = 0;
|
||||
static uint32_t dns_query_attempts = 0;
|
||||
|
||||
|
||||
if (public_ip.addr == 0)
|
||||
{
|
||||
if (!dns_query_start)
|
||||
{
|
||||
dns_query_start = PICO_TIME_MS();
|
||||
struct pico_ip4 tmpdns;
|
||||
pico_string_to_ipv4(RESOLVER1_OPENDNS_COM, &tmpdns.addr);
|
||||
get_host_by_name("myip.opendns.com", tmpdns);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct pico_ip4 tmpdns;
|
||||
pico_string_to_ipv4(RESOLVER1_OPENDNS_COM, &tmpdns.addr);
|
||||
if (get_dns_answer(&public_ip, tmpdns) == 0)
|
||||
{
|
||||
dns_query_attempts = 0;
|
||||
dns_query_start = 0;
|
||||
char myip[16];
|
||||
pico_ipv4_to_string(myip, public_ip.addr);
|
||||
printf("My IP is %s\n", myip);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PICO_TIME_MS() - dns_query_start > 1000)
|
||||
{
|
||||
if (++dns_query_attempts >= 5)
|
||||
{
|
||||
public_ip.addr = 0xffffffff; // Bogus but not null
|
||||
dns_query_attempts = 0;
|
||||
}
|
||||
else
|
||||
// Retry
|
||||
dns_query_start = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (afo_ip.addr == 0)
|
||||
{
|
||||
if (!dns_query_start)
|
||||
{
|
||||
dns_query_start = PICO_TIME_MS();
|
||||
get_host_by_name("auriga.segasoft.com", dnsaddr); // Alien Front Online server
|
||||
}
|
||||
else
|
||||
{
|
||||
if (get_dns_answer(&afo_ip, dnsaddr) == 0)
|
||||
{
|
||||
dns_query_attempts = 0;
|
||||
dns_query_start = 0;
|
||||
char afoip[16];
|
||||
pico_ipv4_to_string(afoip, afo_ip.addr);
|
||||
printf("AFO server IP is %s\n", afoip);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PICO_TIME_MS() - dns_query_start > 1000)
|
||||
{
|
||||
if (++dns_query_attempts >= 5)
|
||||
{
|
||||
pico_string_to_ipv4("146.185.135.179", &afo_ip.addr); // Default address
|
||||
dns_query_attempts = 0;
|
||||
}
|
||||
else
|
||||
// Retry
|
||||
dns_query_start = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool pico_stack_inited;
|
||||
static bool pico_thread_running = false;
|
||||
|
||||
static void *pico_thread_func(void *)
|
||||
{
|
||||
struct pico_ip4 ipaddr, netmask, zero = {
|
||||
0
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
// No de-init on Windows yet
|
||||
if (pico_stack_inited)
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (!pico_stack_inited)
|
||||
{
|
||||
pico_stack_init();
|
||||
|
@ -130,173 +606,77 @@ bool start_pico()
|
|||
// PPP
|
||||
ppp = pico_ppp_create();
|
||||
if (!ppp)
|
||||
return false;
|
||||
string dc_ip = cfgLoadStr("network", "IP", "");
|
||||
if (dc_ip.length() == 0)
|
||||
{
|
||||
printf("No IP address set for Netplay. Set IP= in the [network] section\n");
|
||||
return false;
|
||||
}
|
||||
pico_string_to_ipv4(dc_ip.c_str(), &dcaddr.addr);
|
||||
return NULL;
|
||||
pico_string_to_ipv4("192.168.167.2", &dcaddr.addr);
|
||||
pico_ppp_set_peer_ip(ppp, dcaddr);
|
||||
pico_string_to_ipv4("192.168.167.1", &ipaddr.addr);
|
||||
pico_ppp_set_ip(ppp, ipaddr);
|
||||
|
||||
string dns_ip = cfgLoadStr("network", "DNS", "46.101.91.123");
|
||||
string dns_ip = cfgLoadStr("network", "DNS", "46.101.91.123"); // Dreamcast Live DNS
|
||||
pico_string_to_ipv4(dns_ip.c_str(), &dnsaddr.addr);
|
||||
pico_ppp_set_dns1(ppp, dnsaddr);
|
||||
|
||||
#ifdef NETWORK_TAP
|
||||
// TAP
|
||||
// tap config:
|
||||
// # ip tuntap add mode tap user joe
|
||||
// # ifconfig tap0 192.168.5.5
|
||||
// # ip link set tap0 up
|
||||
// # ip route add <IP>/32 dev tap0 # where <IP> is the value of network:IP in emu.cfg./. This also allows proxy arp
|
||||
// # echo '1' >/proc/sys/net/ipv4/conf/all/proxy_arp
|
||||
// (or ...conf/tap0/proxy_arp and ...conf/eth0/proxy_arp only)
|
||||
#ifdef _WIN32
|
||||
tap = pico_tap_create("tap0", virtual_mac);
|
||||
#else
|
||||
tap = pico_tap_create("tap0");
|
||||
#endif
|
||||
if (!tap)
|
||||
{
|
||||
stop_pico();
|
||||
return false;
|
||||
pico_udp_socket = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &udp_callback);
|
||||
if (pico_udp_socket == NULL) {
|
||||
printf("%s: error opening UDP socket: %s\n", __FUNCTION__, strerror(pico_err));
|
||||
}
|
||||
int yes = 1;
|
||||
struct pico_ip4 inaddr_any = {0};
|
||||
uint16_t listen_port = 0;
|
||||
int ret = pico_socket_bind(pico_udp_socket, &inaddr_any, &listen_port);
|
||||
if (ret < 0)
|
||||
printf("%s: error binding UDP socket to port %u: %s\n", __FUNCTION__, short_be(listen_port), strerror(pico_err));
|
||||
|
||||
pico_string_to_ipv4("192.168.166.2", &ipaddr.addr);
|
||||
pico_string_to_ipv4("255.255.255.0", &netmask.addr);
|
||||
pico_ipv4_link_add(tap, ipaddr, netmask);
|
||||
// Proxy ARP
|
||||
pico_arp_create_entry(tap->eth->mac.addr, ipaddr, ppp);
|
||||
|
||||
#ifdef _WIN32
|
||||
int err;
|
||||
|
||||
// Enable routing
|
||||
OVERLAPPED overlapped;
|
||||
memset(&overlapped, 0, sizeof(overlapped));
|
||||
overlapped.hEvent = overlapped.hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
|
||||
if (overlapped.hEvent == NULL)
|
||||
printf("CreateEvent failed with error %d\n", GetLastError());
|
||||
pico_tcp_socket = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_TCP, &tcp_callback);
|
||||
if (pico_tcp_socket == NULL) {
|
||||
printf("%s: error opening TCP socket: %s\n", __FUNCTION__, strerror(pico_err));
|
||||
}
|
||||
pico_socket_setoption(pico_tcp_socket, PICO_TCP_NODELAY, &yes);
|
||||
ret = pico_socket_bind(pico_tcp_socket, &inaddr_any, &listen_port);
|
||||
if (ret < 0) {
|
||||
printf("%s: error binding TCP socket to port %u: %s\n", __FUNCTION__, short_be(listen_port), strerror(pico_err));
|
||||
}
|
||||
else
|
||||
{
|
||||
HANDLE handle;
|
||||
err = EnableRouter(&handle, &overlapped);
|
||||
if (err != ERROR_IO_PENDING)
|
||||
printf("EnableRouter failed with error %d\n", err);
|
||||
else
|
||||
printf("Windows router enabled\n");
|
||||
CloseHandle(overlapped.hEvent);
|
||||
if (pico_socket_listen(pico_tcp_socket, 10) != 0)
|
||||
printf("%s: error listening on port %u\n", __FUNCTION__, short_be(listen_port));
|
||||
}
|
||||
ppp->proxied = 1;
|
||||
|
||||
// Get the LAN interface index
|
||||
DWORD idx = -1;
|
||||
err = GetBestInterface(dnsaddr.addr, &idx);
|
||||
if (err != NO_ERROR)
|
||||
printf("GetBestInterface failed error %d\n", err);
|
||||
|
||||
// Create a Proxy ARP entry for the DC on the local LAN
|
||||
if (idx != -1)
|
||||
struct sockaddr_in saddr;
|
||||
socklen_t saddr_len = sizeof(saddr);
|
||||
memset(&saddr, 0, sizeof(saddr));
|
||||
saddr.sin_family = AF_INET;
|
||||
saddr.sin_addr.s_addr = INADDR_ANY;
|
||||
for (int i = 0; i < sizeof(games_udp_ports) / sizeof(uint16_t); i++)
|
||||
{
|
||||
err = CreateProxyArpEntry(dcaddr.addr, 0xffffffff, idx);
|
||||
if (err == ERROR_OBJECT_ALREADY_EXISTS)
|
||||
printf("Proxy ARP entry already exists\n");
|
||||
else if (err != NO_ERROR)
|
||||
printf("CreateProxyArpEntry failed error %d\n", err);
|
||||
uint16_t port = short_be(games_udp_ports[i]);
|
||||
int sockfd = find_udp_socket(port);
|
||||
saddr.sin_port = port;
|
||||
|
||||
bind(sockfd, (struct sockaddr *)&saddr, saddr_len);
|
||||
}
|
||||
|
||||
// Get the TAP interface index
|
||||
unsigned long size = sizeof(IP_INTERFACE_INFO);
|
||||
IP_INTERFACE_INFO *infos = (IP_INTERFACE_INFO *)malloc(size);
|
||||
err = GetInterfaceInfo(infos, &size);
|
||||
if (err == ERROR_INSUFFICIENT_BUFFER)
|
||||
for (int i = 0; i < sizeof(games_tcp_ports) / sizeof(uint16_t); i++)
|
||||
{
|
||||
free(infos);
|
||||
infos = (IP_INTERFACE_INFO *)malloc(size);
|
||||
err = GetInterfaceInfo(infos, &size);
|
||||
if (err != NO_ERROR)
|
||||
uint16_t port = short_be(games_tcp_ports[i]);
|
||||
saddr.sin_port = port;
|
||||
int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (::bind(sockfd, (struct sockaddr *)&saddr, saddr_len) < 0)
|
||||
{
|
||||
printf("GetInterfaceInfo failed error %d\n", err);
|
||||
infos->NumAdapters = 0;
|
||||
perror("bind");
|
||||
close(sockfd);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
const char *tap_guid = pico_tap_get_guid(tap);
|
||||
wchar_t wtap_guid[40];
|
||||
MultiByteToWideChar(CP_UTF8, 0, tap_guid, strlen(tap_guid), &wtap_guid[0], 40);
|
||||
DWORD tap_idx = -1; // 11;
|
||||
for (int i = 0; i < infos->NumAdapters; i++)
|
||||
if (listen(sockfd, 5) < 0)
|
||||
{
|
||||
printf("Found interface %ls index %d\n", infos->Adapter[i].Name, infos->Adapter[i].Index);
|
||||
if (wcsstr(infos->Adapter[i].Name, wtap_guid) != NULL)
|
||||
{
|
||||
tap_idx = infos->Adapter[i].Index;
|
||||
break;
|
||||
perror("listen");
|
||||
close(sockfd);
|
||||
continue;
|
||||
}
|
||||
set_non_blocking(sockfd);
|
||||
tcp_listening_sockets[port] = sockfd;
|
||||
}
|
||||
free(infos);
|
||||
|
||||
// Set the TAP interface IP address
|
||||
pico_string_to_ipv4("192.168.166.1", &ipaddr.addr);
|
||||
pico_string_to_ipv4("255.255.255.0", &netmask.addr);
|
||||
unsigned long nte_context, nte_instance;
|
||||
err = AddIPAddress(ipaddr.addr, netmask.addr, tap_idx, &nte_context, &nte_instance);
|
||||
if (err == ERROR_OBJECT_ALREADY_EXISTS)
|
||||
printf("TAP IP address already set\n");
|
||||
else if (err != NO_ERROR)
|
||||
printf("AddIpAddress failed with error %d\n", err);
|
||||
else
|
||||
printf("TAP IP address set\n");
|
||||
|
||||
// Create a route to the DC through the TAP interface
|
||||
if (tap_idx != -1)
|
||||
{
|
||||
MIB_IPFORWARDROW fwd;
|
||||
memset(&fwd, 0, sizeof(fwd));
|
||||
fwd.dwForwardDest = dcaddr.addr;
|
||||
fwd.dwForwardMask = 0xffffffff;
|
||||
fwd.dwForwardIfIndex = tap_idx;
|
||||
fwd.dwForwardProto = MIB_IPPROTO_NETMGMT;
|
||||
fwd.dwForwardAge = INFINITE;
|
||||
fwd.dwForwardMetric1 = 500;
|
||||
err = CreateIpForwardEntry(&fwd);
|
||||
if (err == ERROR_OBJECT_ALREADY_EXISTS)
|
||||
printf("IP forward entry already exists\n");
|
||||
else if (err != NO_ERROR)
|
||||
printf("CreateIpForwardEntry failed with error %d\n", err);
|
||||
else
|
||||
printf("IP forward entry created\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef NETWORK_TUN
|
||||
// TUN
|
||||
// tun config:
|
||||
// # ip tuntap add mode tun user joe
|
||||
// # ip link set tun0 up
|
||||
// # ip route add <IP>/32 dev tun0 # where <IP> is the value of network:IP in emu.cfg./. This also allows proxy arp
|
||||
// # echo '1' >/proc/sys/net/ipv4/conf/all/proxy_arp
|
||||
// (or ...conf/tun0/proxy_arp and ...conf/eth0/proxy_arp only)
|
||||
tun = pico_tun_create("tun0");
|
||||
if (!tun)
|
||||
{
|
||||
stop_pico();
|
||||
return false;
|
||||
}
|
||||
|
||||
pico_string_to_ipv4("192.168.166.1", &ipaddr.addr);
|
||||
pico_string_to_ipv4("255.255.255.255", &netmask.addr);
|
||||
pico_ipv4_link_add(tun, ipaddr, netmask);
|
||||
#endif
|
||||
|
||||
// Default route
|
||||
pico_string_to_ipv4("192.168.166.1", &ipaddr.addr);
|
||||
pico_ipv4_route_add(zero, zero, ipaddr, 1, NULL);
|
||||
|
||||
pico_ppp_set_serial_read(ppp, modem_read);
|
||||
pico_ppp_set_serial_write(ppp, modem_write);
|
||||
|
@ -304,36 +684,43 @@ bool start_pico()
|
|||
|
||||
pico_ppp_connect(ppp);
|
||||
|
||||
#ifdef DHCP
|
||||
if (pico_dhcp_initiate_negotiation(tap, &callback_dhcpclient, &dhcpclient_xid) < 0)
|
||||
while (pico_thread_running)
|
||||
{
|
||||
printf("%s: error initiating negotiation: %s\n", __FUNCTION__, strerror(pico_err));
|
||||
return false;
|
||||
read_native_sockets();
|
||||
pico_stack_tick();
|
||||
check_dns_entries();
|
||||
usleep(1000);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (auto it = tcp_listening_sockets.begin(); it != tcp_listening_sockets.end(); it++)
|
||||
closesocket(it->second);
|
||||
close_native_sockets();
|
||||
pico_socket_close(pico_tcp_socket);
|
||||
pico_socket_close(pico_udp_socket);
|
||||
|
||||
if (ppp)
|
||||
{
|
||||
pico_ppp_destroy(ppp);
|
||||
ppp = NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static cThread pico_thread(pico_thread_func, NULL);
|
||||
|
||||
bool start_pico()
|
||||
{
|
||||
pico_thread_running = true;
|
||||
pico_thread.Start();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void stop_pico()
|
||||
{
|
||||
#ifndef _WIN32
|
||||
if (ppp)
|
||||
{
|
||||
pico_ppp_destroy(ppp);
|
||||
ppp = NULL;
|
||||
}
|
||||
if (tap)
|
||||
{
|
||||
pico_device_destroy(tap);
|
||||
tap = NULL;
|
||||
}
|
||||
if (tun)
|
||||
{
|
||||
pico_device_destroy(tun);
|
||||
tun = NULL;
|
||||
}
|
||||
#endif
|
||||
pico_thread_running = false;
|
||||
pico_thread.WaitToEnd();
|
||||
}
|
||||
|
||||
#else
|
||||
|
|
|
@ -1,3 +1,24 @@
|
|||
/*
|
||||
Created on: Sep 15, 2018
|
||||
|
||||
Copyright 2018 flyinghead
|
||||
|
||||
This file is part of reicast.
|
||||
|
||||
reicast is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
reicast is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with reicast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
bool start_pico();
|
||||
void stop_pico();
|
||||
void write_pico(u8 b);
|
||||
|
|
|
@ -1,257 +0,0 @@
|
|||
/*
|
||||
pppd.cpp
|
||||
|
||||
Created on: Sep 10, 2018
|
||||
|
||||
Copyright 2018 flyinghead
|
||||
|
||||
This file is part of reicast.
|
||||
|
||||
reicast is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
reicast is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with reicast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "types.h"
|
||||
|
||||
#if HOST_OS == OS_LINUX
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <bitset>
|
||||
#include <string>
|
||||
#include "oslib/oslib.h"
|
||||
#include "pppd.h"
|
||||
|
||||
static int pppd_pid;
|
||||
static int inpipe = -1;
|
||||
static int outpipe = -1;
|
||||
|
||||
static u8 in_buffer[128];
|
||||
static int in_bufsize;
|
||||
static int in_bufindex;
|
||||
static bool v42_negotiate = false;
|
||||
static u32 v42_odp_idx;
|
||||
static u32 v42_odp_count;
|
||||
const u8 v42_odp[] { 0x45, 0xfc, 0x17, 0xf9, 0x5f, 0xc4, 0x7f, 0x91, 0xff };
|
||||
double last_adp_sent;
|
||||
|
||||
void start_pppd()
|
||||
{
|
||||
int inpipefd[2];
|
||||
int outpipefd[2];
|
||||
|
||||
if (pipe(inpipefd) || pipe(outpipefd))
|
||||
{
|
||||
perror("pipe");
|
||||
return;
|
||||
}
|
||||
pppd_pid = fork();
|
||||
if (pppd_pid < 0)
|
||||
{
|
||||
perror("fork");
|
||||
close(inpipefd[0]);
|
||||
close(inpipefd[1]);
|
||||
close(outpipefd[0]);
|
||||
close(outpipefd[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pppd_pid == 0)
|
||||
{
|
||||
// Child
|
||||
close(inpipefd[0]);
|
||||
dup2(inpipefd[1], 1);
|
||||
close(outpipefd[1]);
|
||||
dup2(outpipefd[0], 0);
|
||||
execl("/usr/sbin/pppd", "pppd", "notty", NULL);
|
||||
perror("execl");
|
||||
exit(1);
|
||||
}
|
||||
// Parent
|
||||
inpipe = inpipefd[0];
|
||||
outpipe = outpipefd[1];
|
||||
fcntl(inpipe, F_SETFL, fcntl(inpipe, F_GETFL) | O_NONBLOCK);
|
||||
in_bufindex = 0;
|
||||
in_bufsize = 1;
|
||||
in_buffer[0] = 0;
|
||||
}
|
||||
|
||||
void stop_pppd()
|
||||
{
|
||||
if (pppd_pid > 0)
|
||||
{
|
||||
kill(SIGTERM, pppd_pid);
|
||||
// FIXME wait / waitpid
|
||||
pppd_pid = 0;
|
||||
}
|
||||
if (inpipe >= 0)
|
||||
{
|
||||
close(inpipe);
|
||||
inpipe = -1;
|
||||
}
|
||||
if (outpipe >= 0)
|
||||
{
|
||||
close(outpipe);
|
||||
outpipe = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static u8 reverse_bits(u8 x)
|
||||
{
|
||||
x = ((x * 0x0802 & 0x22110) | (x * 0x8020 & 0x88440)) * 0x10101 >> 16;
|
||||
|
||||
return x & 0xFF;
|
||||
}
|
||||
|
||||
static void send_v42_adp()
|
||||
{
|
||||
in_bufsize = 0;
|
||||
in_bufindex = 0;
|
||||
|
||||
// V.42 disabled E, 8-16 ones, NULL, 8-16 ones // FIXME leading one is a test
|
||||
const std::string adp_nov42("1" "0101000101" "11111111" "0000000001" "11111111");
|
||||
const std::string adp_v42("1" "0101000101" "11111111" "0110000101" "11111111");
|
||||
const std::string& adp = adp_nov42;
|
||||
const std::string ones("1111111111111111");
|
||||
|
||||
int adp_idx = 0;
|
||||
for (int i = 0; i < 10; )
|
||||
{
|
||||
int end = min(adp_idx + 8, (int)adp.length());
|
||||
std::string binary = adp.substr(adp_idx, end - adp_idx);
|
||||
adp_idx += 8;
|
||||
|
||||
if (adp_idx > end)
|
||||
{
|
||||
adp_idx -= adp.length();
|
||||
if (i == 9)
|
||||
binary += ones.substr(0, adp_idx);
|
||||
else
|
||||
binary += adp.substr(0, adp_idx);
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (adp_idx >= adp.length())
|
||||
{
|
||||
adp_idx = 0;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
std::bitset<8> bs(binary);
|
||||
in_buffer[in_bufsize++] = reverse_bits(bs.to_ulong());
|
||||
if (in_bufsize == sizeof(in_buffer))
|
||||
{
|
||||
printf("PPPD in buffer overflow\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
v42_negotiate = false;
|
||||
}
|
||||
|
||||
void write_pppd(u8 b)
|
||||
{
|
||||
if (v42_negotiate)
|
||||
{
|
||||
if (b == v42_odp[v42_odp_idx])
|
||||
{
|
||||
v42_odp_idx++;
|
||||
if (v42_odp_idx >= sizeof(v42_odp))
|
||||
{
|
||||
v42_odp_count++;
|
||||
if (v42_odp_count >= 2)
|
||||
{
|
||||
if (last_adp_sent == 0 || os_GetSeconds() - last_adp_sent > 0.75) // T400
|
||||
{
|
||||
printf("PPPD V42 2 ODP received. Sending ADP\n");
|
||||
last_adp_sent = os_GetSeconds();
|
||||
send_v42_adp();
|
||||
}
|
||||
v42_odp_count = 0;
|
||||
}
|
||||
v42_odp_idx = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
v42_odp_idx = 0;
|
||||
printf("PPPD ignored byte %02x\n", b);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int rc = write(outpipe, &b, 1);
|
||||
if (rc < 0)
|
||||
perror("write outpipe");
|
||||
else if (rc == 0)
|
||||
printf("pppd EOF on outpipe\n");
|
||||
}
|
||||
|
||||
int read_pppd()
|
||||
{
|
||||
if (in_bufindex == in_bufsize)
|
||||
{
|
||||
in_bufindex = 0;
|
||||
in_bufsize = 0;
|
||||
if (v42_negotiate)
|
||||
return -1;
|
||||
|
||||
int rc = read(inpipe, in_buffer, sizeof(in_buffer));
|
||||
if (rc < 0)
|
||||
{
|
||||
if (errno != EWOULDBLOCK)
|
||||
perror("read inpipe");
|
||||
return rc;
|
||||
}
|
||||
else if (rc == 0)
|
||||
{
|
||||
printf("pppd EOF on inpipe\n");
|
||||
return -1;
|
||||
}
|
||||
in_bufsize = rc;
|
||||
in_bufindex = 0;
|
||||
}
|
||||
return in_buffer[in_bufindex++];
|
||||
}
|
||||
|
||||
int avail_pppd()
|
||||
{
|
||||
return in_bufsize - in_bufindex;
|
||||
}
|
||||
|
||||
#else // not Linux
|
||||
|
||||
void start_pppd()
|
||||
{
|
||||
}
|
||||
|
||||
void stop_pppd()
|
||||
{
|
||||
}
|
||||
|
||||
void write_pppd(u8 b)
|
||||
{
|
||||
}
|
||||
|
||||
int read_pppd()
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int avail_pppd() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
/*
|
||||
pppd.h
|
||||
|
||||
Created on: Sep 10, 2018
|
||||
|
||||
Copyright 2018 flyinghead
|
||||
|
||||
This file is part of reicast.
|
||||
|
||||
reicast is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
reicast is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with reicast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CORE_HW_MODEM_PPPD_H_
|
||||
#define CORE_HW_MODEM_PPPD_H_
|
||||
#include "types.h"
|
||||
|
||||
void start_pppd();
|
||||
void stop_pppd();
|
||||
void write_pppd(u8 b);
|
||||
int read_pppd();
|
||||
int avail_pppd();
|
||||
|
||||
#endif /* CORE_HW_MODEM_PPPD_H_ */
|
Loading…
Reference in New Issue