Compare commits
No commits in common. "master" and "socket-callbacks" have entirely different histories.
master
...
socket-cal
35 changed files with 294 additions and 6409 deletions
|
@ -1,33 +0,0 @@
|
|||
Name: Linux interop tests
|
||||
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ 'master', 'main', 'release/**' ]
|
||||
pull_request:
|
||||
branches: [ '*' ]
|
||||
|
||||
jobs:
|
||||
unit_test:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Update repo
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo modprobe tun
|
||||
|
||||
- name: Build linux tests
|
||||
run: |
|
||||
mkdir -p build/port
|
||||
make
|
||||
|
||||
# - name: Run interop tests
|
||||
# run: |
|
||||
# sudo build/test
|
||||
#
|
||||
#
|
|
@ -1,33 +0,0 @@
|
|||
Name: Unit Tests
|
||||
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ 'master', 'main', 'release/**' ]
|
||||
pull_request:
|
||||
branches: [ '*' ]
|
||||
|
||||
jobs:
|
||||
unit_test:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Update repo
|
||||
run: |
|
||||
sudo apt-get update
|
||||
|
||||
- name: Install check
|
||||
run: |
|
||||
sudo apt-get -y install check
|
||||
|
||||
- name: Build unit tests
|
||||
run: |
|
||||
make unit
|
||||
|
||||
- name: Run unit tests
|
||||
run: |
|
||||
build/test/unit
|
8
.gitignore
vendored
8
.gitignore
vendored
|
@ -1,14 +1,6 @@
|
|||
*.o
|
||||
*.a
|
||||
*.pcap
|
||||
*.so
|
||||
*.dis
|
||||
*.uf2
|
||||
*.bin
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
CMakeScripts
|
||||
CMakeTmp
|
||||
build/*
|
||||
test/unit/unit
|
||||
tags
|
||||
|
|
125
Makefile
125
Makefile
|
@ -1,131 +1,42 @@
|
|||
CC?=gcc
|
||||
CFLAGS:=-Wall -Werror -Wextra -I.
|
||||
CFLAGS+=-g -ggdb
|
||||
LDFLAGS+=-pthread
|
||||
OBJ=build/femtotcp.o build/test-linux.o build/port/linux.o
|
||||
|
||||
OBJ=build/femtotcp.o \
|
||||
build/port/posix/linux_tap.o
|
||||
all: build/test
|
||||
|
||||
EXE=build/tcpecho build/tcp_netcat_poll build/tcp_netcat_select \
|
||||
build/test-evloop build/test-dns
|
||||
LIB=libfemtotcp.so
|
||||
|
||||
PREFIX=/usr/local
|
||||
|
||||
|
||||
all: $(EXE) $(LIB)
|
||||
|
||||
#Static library
|
||||
static: CFLAGS+=-static
|
||||
static: libtcpip.a
|
||||
|
||||
|
||||
|
||||
libtcpip.a: $(OBJ)
|
||||
@ar rcs $@ $^
|
||||
|
||||
libfemtotcp.so:CFLAGS+=-fPIC
|
||||
libfemtotcp.so: build/pie/port/posix/bsd_socket.o build/pie/femtotcp.o \
|
||||
build/pie/port/posix/linux_tap.o
|
||||
@mkdir -p `dirname $@` || true
|
||||
@echo "[LD] $@"
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ -Wl,--start-group $(^) -Wl,--end-group
|
||||
|
||||
|
||||
clean:
|
||||
@rm -rf build
|
||||
|
||||
asan: $(EXE) $(LIB)
|
||||
asan:CFLAGS+=-fsanitize=address
|
||||
asan:LDFLAGS+=-static-libasan
|
||||
|
||||
@rm -f build/*.o build/port/*.o
|
||||
@make -C test/unit clean
|
||||
|
||||
# Test
|
||||
|
||||
unit:LDFLAGS+=-lcheck -lm -lpthread -lrt -ldl -lsubunit
|
||||
build/test-evloop: $(OBJ) build/test/test_linux_eventloop.o
|
||||
@echo "[LD] $@"
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -o $@ -Wl,--start-group $(^) -Wl,--end-group
|
||||
|
||||
build/test-dns: $(OBJ) build/test/test_linux_dhcp_dns.o
|
||||
@echo "[LD] $@"
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -o $@ -Wl,--start-group $(^) -Wl,--end-group
|
||||
|
||||
build/tcpecho: $(OBJ) build/port/posix/bsd_socket.o build/test/tcp_echo.o
|
||||
@echo "[LD] $@"
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -o $@ -Wl,--start-group $(^) -Wl,--end-group
|
||||
|
||||
build/tcp_netcat_poll: $(OBJ) build/port/posix/bsd_socket.o build/test/tcp_netcat_poll.o
|
||||
@echo "[LD] $@"
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -o $@ -Wl,--start-group $(^) -Wl,--end-group
|
||||
|
||||
build/tcp_netcat_select: $(OBJ) build/port/posix/bsd_socket.o build/test/tcp_netcat_select.o
|
||||
@echo "[LD] $@"
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -o $@ -Wl,--start-group $(^) -Wl,--end-group
|
||||
asan: build/test
|
||||
asan:CFLAGS+=-fsanitize=address
|
||||
asan:LDFLAGS+=-static-libasan
|
||||
build/test:CFLAGS+=-g -ggdb -DTEST_MAIN -DETHERNET
|
||||
build/test:LDFLAGS+=-pthread
|
||||
|
||||
|
||||
build/test-wolfssl:CFLAGS+=-Wno-cpp -DWOLFSSL_DEBUG -DWOLFSSL_FEMTOTCP
|
||||
build/test-httpd:CFLAGS+=-Wno-cpp -DWOLFSSL_DEBUG -DWOLFSSL_FEMTOTCP -Isrc/http
|
||||
build/test: $(OBJ)
|
||||
@echo "Linking $@"
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJ)
|
||||
|
||||
|
||||
build/test-wolfssl: $(OBJ) build/test/test_native_wolfssl.o build/port/wolfssl_io.o build/certs/server_key.o build/certs/ca_cert.o build/certs/server_cert.o
|
||||
@echo "[LD] $@"
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -o $@ -Wl,--start-group $(^) -lwolfssl -Wl,--end-group
|
||||
|
||||
build/test-httpd: $(OBJ) build/test/test_httpd.o build/port/wolfssl_io.o build/certs/server_key.o build/certs/server_cert.o build/http/httpd.o
|
||||
@echo "[LD] $@"
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -o $@ -Wl,--start-group $(^) -lwolfssl -Wl,--end-group
|
||||
build/test-linux.o: test/test-linux.c
|
||||
@echo "Compiling $<"
|
||||
@$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
build/%.o: src/%.c
|
||||
@mkdir -p `dirname $@` || true
|
||||
@echo "[CC] $<"
|
||||
@echo "Compiling $<"
|
||||
@$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
build/pie/%.o: src/%.c
|
||||
@mkdir -p `dirname $@` || true
|
||||
@echo "[CC] $<"
|
||||
@$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
build/certs/%.o: build/certs/%.c
|
||||
@mkdir -p `dirname $@` || true
|
||||
@echo "[CC] $<"
|
||||
@$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
build/http/%.o: build/http/%.c
|
||||
@mkdir -p `dirname $@` || true
|
||||
@echo "[CC] $<"
|
||||
@$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
build/certs/ca_cert.c:
|
||||
@echo "[MKCERTS] `dirname $@`"
|
||||
@tools/certs/mkcerts.sh
|
||||
|
||||
build/certs/server_key.c:
|
||||
@echo "[MKCERTS] `dirname $@`"
|
||||
@tools/certs/mkcerts.sh
|
||||
|
||||
build/certs/server_cert.c:
|
||||
@echo "[MKCERTS] `dirname $@`"
|
||||
@tools/certs/mkcerts.sh
|
||||
|
||||
build/certs/server_key.o: build/certs/server_key.c
|
||||
@mkdir -p `dirname $@` || true
|
||||
@echo "[CC] $<"
|
||||
@$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
unit: build/test/unit
|
||||
|
||||
build/test/unit:
|
||||
@mkdir -p build/test/
|
||||
@echo "[CC] unit.c"
|
||||
@$(CC) $(CFLAGS) -c src/test/unit/unit.c -o build/test/unit.o
|
||||
@echo "[LD] $@"
|
||||
@$(CC) -o build/test/unit build/test/unit.o $(LDFLAGS)
|
||||
|
||||
# Install dynamic library to re-link linux applications
|
||||
#
|
||||
install:
|
||||
install libfemtotcp.so $(PREFIX)/lib
|
||||
ldconfig
|
||||
unit:
|
||||
@make -C test/unit
|
||||
|
||||
.PHONY: clean all static
|
||||
|
|
|
@ -19,14 +19,11 @@ A single network interface can be associated with the device.
|
|||
- IPv4 (RFC 791)
|
||||
- ICMP (RFC 792): only ping replies
|
||||
- DHCP (RFC 2131): client only
|
||||
- DNS (RFC 1035): client only
|
||||
- UDP (RFC 768): unicast only
|
||||
- TCP (RFC 793)
|
||||
- TCP options supported: Timestamps, Maximum Segment Size
|
||||
- BSD-like, non blocking socket API, with custom callbacks
|
||||
- No dynamic memory allocation
|
||||
- Fixed number of concurrent sockets
|
||||
- Pre-allocated buffers for packet processing in static memory
|
||||
|
||||
|
||||
## Copyright and License
|
||||
|
|
18
config.h
18
config.h
|
@ -1,18 +0,0 @@
|
|||
#ifndef FEMTO_CONFIG_H
|
||||
#define FEMTO_CONFIG_H
|
||||
|
||||
#define ETHERNET
|
||||
#define LINK_MTU 1536
|
||||
|
||||
#define MAX_TCPSOCKETS 20
|
||||
#define MAX_UDPSOCKETS 2
|
||||
#define RXBUF_SIZE LINK_MTU * 4
|
||||
#define TXBUF_SIZE LINK_MTU * 16
|
||||
|
||||
#define MAX_NEIGHBORS 16
|
||||
|
||||
/* Linux test configuration */
|
||||
#define FEMTOTCP_IP "10.10.10.2"
|
||||
#define LINUX_IP "10.10.10.1"
|
||||
|
||||
#endif
|
95
femtotcp.h
95
femtotcp.h
|
@ -1,5 +1,5 @@
|
|||
#ifndef FEMTOTCP_H
|
||||
#define FEMTOTCP_H
|
||||
#ifndef QUECTONET_H
|
||||
#define QUECTONET_H
|
||||
#include <stdint.h>
|
||||
|
||||
/* Types */
|
||||
|
@ -12,7 +12,6 @@ typedef uint32_t ip4;
|
|||
#define ee32(x) __builtin_bswap32(x)
|
||||
#define DEBUG
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <stdio.h>
|
||||
#define LOG(fmt, ...) printf(fmt, ##__VA_ARGS__)
|
||||
|
@ -26,9 +25,9 @@ struct ll {
|
|||
uint8_t mac[6];
|
||||
char ifname[16];
|
||||
/* poll function */
|
||||
int (*poll)(struct ll *ll, void *buf, uint32_t len);
|
||||
int (*poll)(struct ll *ll, void *buf, int len);
|
||||
/* send function */
|
||||
int (*send)(struct ll *ll, void *buf, uint32_t len);
|
||||
int (*send)(struct ll *ll, void *buf, int len);
|
||||
};
|
||||
|
||||
/* Struct to contain an IP device configuration */
|
||||
|
@ -40,18 +39,9 @@ struct ipconf {
|
|||
};
|
||||
|
||||
/* Socket interface */
|
||||
#define MARK_TCP_SOCKET 0x100 /* Mark a socket as TCP */
|
||||
#define MARK_UDP_SOCKET 0x200 /* Mark a socket as UDP */
|
||||
#if (MARK_TCP_SOCKET >= MARK_UDP_SOCKET)
|
||||
#error "MARK_TCP_SOCKET must be less than MARK_UDP_SOCKET"
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef FEMTO_POSIX
|
||||
#ifndef NATIVE_POSIX_SOCKET
|
||||
#define IPSTACK_SOCK_STREAM 1
|
||||
#define IPSTACK_SOCK_DGRAM 2
|
||||
|
||||
|
||||
struct ipstack_sockaddr_in {
|
||||
uint16_t sin_family;
|
||||
uint16_t sin_port;
|
||||
|
@ -62,13 +52,6 @@ typedef uint32_t socklen_t;
|
|||
#ifndef AF_INET
|
||||
#define AF_INET 2
|
||||
#endif
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#define ipstack_sockaddr_in sockaddr_in
|
||||
#define ipstack_sockaddr sockaddr
|
||||
#endif
|
||||
|
||||
int ft_socket(struct ipstack *s, int domain, int type, int protocol);
|
||||
|
@ -77,11 +60,7 @@ int ft_listen(struct ipstack *s, int sockfd, int backlog);
|
|||
int ft_accept(struct ipstack *s, int sockfd, struct ipstack_sockaddr *addr, socklen_t *addrlen);
|
||||
int ft_connect(struct ipstack *s, int sockfd, const struct ipstack_sockaddr *addr, socklen_t addrlen);
|
||||
int ft_sendto(struct ipstack *s, int sockfd, const void *buf, size_t len, int flags, const struct ipstack_sockaddr *dest_addr, socklen_t addrlen);
|
||||
int ft_send(struct ipstack *s, int sockfd, const void *buf, size_t len, int flags);
|
||||
int ft_write(struct ipstack *s, int sockfd, const void *buf, size_t len);
|
||||
int ft_recvfrom(struct ipstack *s, int sockfd, void *buf, size_t len, int flags, struct ipstack_sockaddr *src_addr, socklen_t *addrlen);
|
||||
int ft_recv(struct ipstack *s, int sockfd, void *buf, size_t len, int flags);
|
||||
int ft_read(struct ipstack *s, int sockfd, void *buf, size_t len);
|
||||
int ft_close(struct ipstack *s, int sockfd);
|
||||
int ft_getpeername(struct ipstack *s, int sockfd, struct ipstack_sockaddr *addr, socklen_t *addrlen);
|
||||
int ft_getsockname(struct ipstack *s, int sockfd, struct ipstack_sockaddr *addr, socklen_t *addrlen);
|
||||
|
@ -89,80 +68,24 @@ int ft_getsockname(struct ipstack *s, int sockfd, struct ipstack_sockaddr *addr,
|
|||
int dhcp_client_init(struct ipstack *s);
|
||||
int dhcp_bound(struct ipstack *s);
|
||||
|
||||
/* DNS client */
|
||||
|
||||
int nslookup(struct ipstack *s, const char *name, uint16_t *id, void (*lookup_cb)(uint32_t ip));
|
||||
|
||||
/* IP stack interface */
|
||||
void ipstack_init(struct ipstack *s);
|
||||
void ipstack_init_static(struct ipstack **s);
|
||||
int ipstack_poll(struct ipstack *s, uint64_t now);
|
||||
void ipstack_recv(struct ipstack *s, void *buf, uint32_t len);
|
||||
void ipstack_ipconfig_set(struct ipstack *s, ip4 ip, ip4 mask, ip4 gw);
|
||||
void ipstack_ipconfig_get(struct ipstack *s, ip4 *ip, ip4 *mask, ip4 *gw);
|
||||
|
||||
struct ll *ipstack_getdev(struct ipstack *s);
|
||||
ip4 atoip4(const char *ip);
|
||||
|
||||
/* Callback flags */
|
||||
#define CB_EVENT_READABLE 0x01 /* Accepted connection or data available */
|
||||
#define CB_EVENT_TIMEOUT 0x02 /* Timeout */
|
||||
#define CB_EVENT_WRITABLE 0x04 /* Connected or space available to send */
|
||||
#define CB_EVENT_CLOSED 0x10 /* Connection closed by peer */
|
||||
#define CB_EVENT_WRITABLE 0x02 /* Connected or space available to send */
|
||||
#define CB_EVENT_CLOSED 0x04 /* Connection closed by peer */
|
||||
#define CB_EVENT_TIMEOUT 0x08 /* Timeout */
|
||||
void ipstack_register_callback(struct ipstack *s, int sock_fd, void (*cb)(int sock_fd, uint16_t events, void *arg), void *arg);
|
||||
|
||||
/* External requirements */
|
||||
uint32_t ipstack_getrandom(void);
|
||||
|
||||
/* Inline utility functions */
|
||||
static inline uint32_t atou(const char *s)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
while (*s >= '0' && *s <= '9') {
|
||||
ret = ret * 10 + (*s - '0');
|
||||
s++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline ip4 atoip4(const char *ip)
|
||||
{
|
||||
ip4 ret = 0;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
for (i = 0; i < 4; i++) {
|
||||
ret |= (atou(ip + j) << (24 - i * 8));
|
||||
while (ip[j] != '.' && ip[j] != '\0') j++;
|
||||
if (ip[j] == '\0') break;
|
||||
j++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void iptoa(ip4 ip, char *buf)
|
||||
{
|
||||
int i, j = 0;
|
||||
buf[0] = 0;
|
||||
for (i = 0; i < 4; i++) {
|
||||
uint8_t x = (ip >> (24 - i * 8)) & 0xFF;
|
||||
if (x > 99) buf[j++] = x / 100 + '0';
|
||||
if (x > 9) buf[j++] = (x / 10) % 10 + '0';
|
||||
buf[j++] = x % 10 + '0';
|
||||
if (i < 3) buf[j++] = '.';
|
||||
}
|
||||
buf[j] = 0;
|
||||
}
|
||||
|
||||
#ifdef WOLFSSL_FEMTOTCP
|
||||
#ifdef WOLFSSL_USER_SETTINGS
|
||||
#include "user_settings.h"
|
||||
#else
|
||||
#include <wolfssl/options.h>
|
||||
#endif
|
||||
#include <wolfssl/wolfcrypt/settings.h>
|
||||
#include <wolfssl/ssl.h>
|
||||
/* Defined in wolfssl_io.c */
|
||||
int wolfSSL_SetIO_FT(WOLFSSL* ssl, int fd);
|
||||
int wolfSSL_SetIO_FT_CTX(WOLFSSL_CTX *ctx, struct ipstack *s);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
511
src/femtotcp.c
511
src/femtotcp.c
|
@ -8,19 +8,25 @@
|
|||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "femtotcp.h"
|
||||
#include "config.h"
|
||||
|
||||
/* Fixed size binary heap: each element is a timer. */
|
||||
#define MAX_TIMERS MAX_TCPSOCKETS * 3
|
||||
/* Config (TODO: move to some config.h later) */
|
||||
|
||||
#define LINK_MTU 1536
|
||||
|
||||
#define MAX_TCPSOCKETS 2
|
||||
#define MAX_UDPSOCKETS 2
|
||||
#define RXBUF_SIZE LINK_MTU * 8
|
||||
#define TXBUF_SIZE LINK_MTU * 2
|
||||
|
||||
#define MAX_NEIGHBORS 16
|
||||
|
||||
/* Constants */
|
||||
#define ICMP_ECHO_REPLY 0
|
||||
#define ICMP_ECHO_REQUEST 8
|
||||
#define ICMP_TTL_EXCEEDED 11
|
||||
#define MARK_TCP_SOCKET 0x1000 /* Mark a socket as TCP */
|
||||
#define MARK_UDP_SOCKET 0x4000 /* Mark a socket as UDP */
|
||||
|
||||
#define FT_IPPROTO_ICMP 0x01
|
||||
#define FT_IPPROTO_TCP 0x06
|
||||
#define FT_IPPROTO_UDP 0x11
|
||||
#define IPPROTO_ICMP 0x01
|
||||
#define IPPROTO_TCP 0x06
|
||||
#define IPPROTO_UDP 0x11
|
||||
#define IPADDR_ANY 0x00000000
|
||||
|
||||
#define TCP_OPTION_MSS 0x02
|
||||
|
@ -48,8 +54,8 @@
|
|||
|
||||
#define NO_TIMER 0
|
||||
|
||||
#define FT_IP_MTU 1500
|
||||
#define TCP_MSS (FT_IP_MTU - (IP_HEADER_LEN + TCP_HEADER_LEN))
|
||||
#define IP_MTU 1500
|
||||
#define TCP_MSS (IP_MTU - (IP_HEADER_LEN + TCP_HEADER_LEN))
|
||||
|
||||
/* Macros */
|
||||
#define IS_IP_BCAST(ip) (ip == 0xFFFFFFFF)
|
||||
|
@ -66,7 +72,7 @@
|
|||
|
||||
|
||||
/* Random number generator, provided by the user */
|
||||
//extern uint32_t ipstack_getrandom(void);
|
||||
uint32_t ipstack_getrandom(void);
|
||||
|
||||
struct PACKED pkt_desc {
|
||||
uint32_t pos, len;
|
||||
|
@ -513,6 +519,8 @@ struct ipstack_timer {
|
|||
void (*cb)(void *arg);
|
||||
};
|
||||
|
||||
/* Fixed size binary heap: each element is a timer. */
|
||||
#define MAX_TIMERS MAX_TCPSOCKETS * 3
|
||||
/* Timer binary heap */
|
||||
struct timers_binheap {
|
||||
struct ipstack_timer timers[MAX_TIMERS];
|
||||
|
@ -530,10 +538,6 @@ struct ipstack
|
|||
uint32_t dhcp_timeout_count; /* DHCP timeout counter */
|
||||
ip4 dhcp_server_ip; /* DHCP server IP */
|
||||
ip4 dhcp_ip; /* IP address assigned by DHCP */
|
||||
ip4 dns_server;
|
||||
uint16_t dns_id;
|
||||
int dns_udp_sd;
|
||||
void (*dns_lookup_cb)(ip4 ip);
|
||||
struct timers_binheap timers;
|
||||
struct tsocket tcpsockets[MAX_TCPSOCKETS];
|
||||
struct tsocket udpsockets[MAX_UDPSOCKETS];
|
||||
|
@ -563,7 +567,7 @@ void ipstack_register_callback(struct ipstack *s, int sock_fd, void (*cb)(int so
|
|||
t->callback = cb;
|
||||
t->callback_arg = arg;
|
||||
} else if (sock_fd & MARK_UDP_SOCKET) {
|
||||
if ((sock_fd &(~MARK_UDP_SOCKET)) >= MAX_UDPSOCKETS)
|
||||
if (sock_fd >= MAX_UDPSOCKETS)
|
||||
return;
|
||||
t = &s->udpsockets[sock_fd & ~MARK_UDP_SOCKET];
|
||||
t->callback = cb;
|
||||
|
@ -649,11 +653,11 @@ static struct tsocket *udp_new_socket(struct ipstack *s)
|
|||
for (int i = 0; i < MAX_UDPSOCKETS; i++) {
|
||||
t = &s->udpsockets[i];
|
||||
if (t->proto == 0) {
|
||||
t->proto = FT_IPPROTO_UDP;
|
||||
t->proto = IPPROTO_UDP;
|
||||
t->S = s;
|
||||
fifo_init(&t->sock.udp.rxbuf, t->rxmem, RXBUF_SIZE);
|
||||
fifo_init(&t->sock.udp.txbuf, t->txmem, TXBUF_SIZE);
|
||||
t->events |= CB_EVENT_WRITABLE;
|
||||
t->events = CB_EVENT_WRITABLE;
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
@ -673,19 +677,19 @@ static void udp_try_recv(struct ipstack *s, struct ipstack_udp_datagram *udp, ui
|
|||
return;
|
||||
/* Insert into socket buffer */
|
||||
fifo_push(&t->sock.udp.rxbuf, udp, frame_len);
|
||||
t->events |= CB_EVENT_READABLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* TCP */
|
||||
|
||||
static struct tsocket *tcp_new_socket(struct ipstack *s)
|
||||
{
|
||||
struct tsocket *t;
|
||||
for (int i = 0; i < MAX_TCPSOCKETS; i++) {
|
||||
t = &s->tcpsockets[i];
|
||||
if (t->proto == 0) {
|
||||
t->proto = FT_IPPROTO_TCP;
|
||||
t->proto = IPPROTO_TCP;
|
||||
t->S = s;
|
||||
t->sock.tcp.state = TCP_CLOSED;
|
||||
t->sock.tcp.rto = 1000;
|
||||
|
@ -826,20 +830,6 @@ static uint16_t transport_checksum(union transport_pseudo_header *ph, void *_dat
|
|||
return ~sum;
|
||||
}
|
||||
|
||||
static uint16_t icmp_checksum(struct ipstack_icmp_packet *icmp)
|
||||
{
|
||||
uint32_t sum = 0;
|
||||
uint32_t i = 0;
|
||||
uint16_t *ptr = (uint16_t *)(&icmp->type);
|
||||
for (i = 0; i < ICMP_HEADER_LEN / 2; i++) {
|
||||
sum += ee16(ptr[i]);
|
||||
}
|
||||
while (sum >> 16) {
|
||||
sum = (sum & 0xffff) + (sum >> 16);
|
||||
}
|
||||
return ~sum;
|
||||
}
|
||||
|
||||
static void iphdr_set_checksum(struct ipstack_ip_packet *ip)
|
||||
{
|
||||
uint32_t sum = 0;
|
||||
|
@ -893,11 +883,11 @@ static int ip_output_add_header(struct tsocket *t, struct ipstack_ip_packet *ip,
|
|||
ph.ph.zero = 0;
|
||||
ph.ph.proto = proto;
|
||||
ph.ph.len = ee16(len - IP_HEADER_LEN);
|
||||
if (proto == FT_IPPROTO_TCP) {
|
||||
if (proto == IPPROTO_TCP) {
|
||||
struct ipstack_tcp_seg *tcp = (struct ipstack_tcp_seg *)ip;
|
||||
tcp->csum = 0;
|
||||
tcp->csum = ee16(transport_checksum(&ph, &tcp->src_port));
|
||||
} else if (proto == FT_IPPROTO_UDP) {
|
||||
} else if (proto == IPPROTO_UDP) {
|
||||
struct ipstack_udp_datagram *udp = (struct ipstack_udp_datagram *)ip;
|
||||
udp->csum = 0;
|
||||
udp->csum = ee16(transport_checksum(&ph, &udp->src_port));
|
||||
|
@ -909,25 +899,25 @@ static int ip_output_add_header(struct tsocket *t, struct ipstack_ip_packet *ip,
|
|||
}
|
||||
|
||||
/* Process timestamp option, calculate RTT */
|
||||
static int tcp_process_ts(struct tsocket *t, const struct ipstack_tcp_seg *tcp)
|
||||
static int tcp_process_ts(struct tsocket *t, struct ipstack_tcp_seg *tcp)
|
||||
{
|
||||
const struct tcp_opt_ts *ts;
|
||||
const uint8_t *opt = tcp->data;
|
||||
struct tcp_opt_ts *ts;
|
||||
uint8_t *opt = tcp->data;
|
||||
while (opt < (tcp->data + (tcp->hlen >> 2))) {
|
||||
if (*opt == TCP_OPTION_NOP)
|
||||
opt++;
|
||||
else if (*opt == TCP_OPTION_EOO)
|
||||
break;
|
||||
else {
|
||||
ts = (const struct tcp_opt_ts *)opt;
|
||||
ts = (struct tcp_opt_ts *)opt;
|
||||
if (ts->opt == TCP_OPTION_TS) {
|
||||
t->sock.tcp.last_ts = ts->val;
|
||||
if (ts->ecr != 0)
|
||||
return -1;
|
||||
if (t->sock.tcp.rtt == 0)
|
||||
t->sock.tcp.rtt = (uint32_t)(t->S->last_tick - ee32(ts->ecr));
|
||||
t->sock.tcp.rtt = t->S->last_tick - ee32(ts->ecr);
|
||||
else {
|
||||
t->sock.tcp.rtt = (uint32_t)(7 * (t->sock.tcp.rtt << 3)) +
|
||||
t->sock.tcp.rtt = (7 * (t->sock.tcp.rtt << 3)) +
|
||||
((t->S->last_tick - ee32(ts->ecr)) << 3);
|
||||
}
|
||||
return 0;
|
||||
|
@ -942,7 +932,7 @@ static int tcp_process_ts(struct tsocket *t, const struct ipstack_tcp_seg *tcp)
|
|||
#define SEQ_DIFF(a,b) ((a - b) > 0x7FFFFFFF) ? (b - a) : (a - b)
|
||||
|
||||
/* Receive an ack */
|
||||
static void tcp_ack(struct tsocket *t, const struct ipstack_tcp_seg *tcp)
|
||||
static void tcp_ack(struct tsocket *t, struct ipstack_tcp_seg *tcp)
|
||||
{
|
||||
uint32_t ack = ee32(tcp->ack);
|
||||
struct pkt_desc *desc;
|
||||
|
@ -972,7 +962,7 @@ static void tcp_ack(struct tsocket *t, const struct ipstack_tcp_seg *tcp)
|
|||
}
|
||||
}
|
||||
if (ack_count > 0) {
|
||||
struct pkt_desc *fresh_desc = NULL;
|
||||
struct pkt_desc *fresh_desc;
|
||||
struct ipstack_tcp_seg *tcp;
|
||||
/* This ACK ackwnowledged some data. */
|
||||
desc = fifo_peek(&t->sock.tcp.txbuf);
|
||||
|
@ -980,31 +970,30 @@ static void tcp_ack(struct tsocket *t, const struct ipstack_tcp_seg *tcp)
|
|||
fresh_desc = fifo_pop(&t->sock.tcp.txbuf);
|
||||
desc = fifo_peek(&t->sock.tcp.txbuf);
|
||||
}
|
||||
if (fresh_desc) {
|
||||
tcp = (struct ipstack_tcp_seg *)(t->txmem + fresh_desc->pos + sizeof(*fresh_desc));
|
||||
/* Update rtt */
|
||||
if (tcp_process_ts(t, tcp) < 0) {
|
||||
/* No timestamp option, use coarse RTT estimation */
|
||||
int rtt = t->S->last_tick - fresh_desc->time_sent;
|
||||
if (t->sock.tcp.rtt == 0) {
|
||||
t->sock.tcp.rtt = rtt;
|
||||
} else {
|
||||
t->sock.tcp.rtt = (7 * (t->sock.tcp.rtt << 3)) + (rtt << 3);
|
||||
}
|
||||
}
|
||||
/* Update cwnd */
|
||||
if (t->sock.tcp.cwnd < t->sock.tcp.ssthresh) {
|
||||
t->sock.tcp.cwnd += TCP_MSS;
|
||||
|
||||
tcp = (struct ipstack_tcp_seg *)(t->txmem + fresh_desc->pos + sizeof(*fresh_desc));
|
||||
/* Update rtt */
|
||||
if (tcp_process_ts(t, tcp) < 0) {
|
||||
/* No timestamp option, use coarse RTT estimation */
|
||||
int rtt = t->S->last_tick - fresh_desc->time_sent;
|
||||
if (t->sock.tcp.rtt == 0) {
|
||||
t->sock.tcp.rtt = rtt;
|
||||
} else {
|
||||
t->sock.tcp.cwnd_count++;
|
||||
if (t->sock.tcp.cwnd_count == t->sock.tcp.cwnd) {
|
||||
t->sock.tcp.cwnd_count = 0;
|
||||
t->sock.tcp.cwnd += TCP_MSS;
|
||||
}
|
||||
t->sock.tcp.rtt = (7 * (t->sock.tcp.rtt << 3)) + (rtt << 3);
|
||||
}
|
||||
if (fifo_space(&t->sock.tcp.txbuf) > 0)
|
||||
t->events |= CB_EVENT_WRITABLE;
|
||||
}
|
||||
/* Update cwnd */
|
||||
if (t->sock.tcp.cwnd < t->sock.tcp.ssthresh) {
|
||||
t->sock.tcp.cwnd += TCP_MSS;
|
||||
} else {
|
||||
t->sock.tcp.cwnd_count++;
|
||||
if (t->sock.tcp.cwnd_count == t->sock.tcp.cwnd) {
|
||||
t->sock.tcp.cwnd_count = 0;
|
||||
t->sock.tcp.cwnd += TCP_MSS;
|
||||
}
|
||||
}
|
||||
if (fifo_space(&t->sock.tcp.txbuf) > 0)
|
||||
t->events |= CB_EVENT_WRITABLE;
|
||||
} else {
|
||||
struct pkt_desc *desc;
|
||||
/* Duplicate ack */
|
||||
|
@ -1024,6 +1013,7 @@ static void tcp_ack(struct tsocket *t, const struct ipstack_tcp_seg *tcp)
|
|||
continue;
|
||||
}
|
||||
if (ee32(seg->seq) == ack) {
|
||||
LOG("Retransmit %u size %d due to dupack %u\n", ee32(seg->seq), seg_len, ack);
|
||||
desc->flags &= ~PKT_FLAG_SENT; /* Resend */
|
||||
break;
|
||||
}
|
||||
|
@ -1044,37 +1034,16 @@ static void tcp_input(struct ipstack *S, struct ipstack_tcp_seg *tcp, uint32_t f
|
|||
/* TCP segment sanity checks */
|
||||
iplen = ee16(tcp->ip.len);
|
||||
if (iplen > frame_len - sizeof(struct ipstack_eth_frame)) {
|
||||
LOG("Wrong packet size %d, frame is %d\n", iplen, frame_len);
|
||||
return; /* discard */
|
||||
}
|
||||
|
||||
if (t->sock.tcp.state > TCP_LISTEN) {
|
||||
if (t->dst_port != ee16(tcp->src_port) || t->remote_ip != ee32(tcp->ip.src)) {
|
||||
/* Not the right socket */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/* Check IP ttl */
|
||||
if (tcp->ip.ttl == 0) {
|
||||
/* Send ICMP TTL exceeded */
|
||||
struct ipstack_icmp_packet icmp;
|
||||
memset(&icmp, 0, sizeof(icmp));
|
||||
icmp.type = ICMP_TTL_EXCEEDED;
|
||||
icmp.csum = ee16(icmp_checksum(&icmp));
|
||||
icmp.ip.src = tcp->ip.dst;
|
||||
icmp.ip.dst = tcp->ip.src;
|
||||
icmp.ip.proto = FT_IPPROTO_ICMP;
|
||||
icmp.ip.id = ee16(S->ipcounter++);
|
||||
icmp.ip.csum = 0;
|
||||
iphdr_set_checksum(&icmp.ip);
|
||||
eth_output_add_header(S, icmp.ip.eth.src, &icmp.ip.eth, ETH_TYPE_IP);
|
||||
S->ll_dev.send(&S->ll_dev, &icmp, sizeof(struct ipstack_icmp_packet));
|
||||
return;
|
||||
}
|
||||
tcplen = iplen - (IP_HEADER_LEN + (tcp->hlen >> 2));
|
||||
/* Check if RST, close socket only if in SYN_SENT */
|
||||
if ((tcp->flags & 0x04) && (t->sock.tcp.state == TCP_SYN_SENT)) {
|
||||
close_socket(t);
|
||||
}
|
||||
|
||||
/* Check if FIN */
|
||||
if (tcp->flags & 0x01) {
|
||||
|
@ -1082,15 +1051,16 @@ static void tcp_input(struct ipstack *S, struct ipstack_tcp_seg *tcp, uint32_t f
|
|||
t->sock.tcp.state = TCP_CLOSE_WAIT;
|
||||
t->sock.tcp.ack = ee32(tcp->seq) + 1;
|
||||
tcp_send_ack(t);
|
||||
t->events |= CB_EVENT_CLOSED | CB_EVENT_READABLE;
|
||||
t->events |= CB_EVENT_CLOSED;
|
||||
}
|
||||
else if (t->sock.tcp.state == TCP_FIN_WAIT_1) {
|
||||
t->sock.tcp.state = TCP_CLOSING;
|
||||
t->sock.tcp.ack = ee32(tcp->seq) + 1;
|
||||
tcp_send_ack(t);
|
||||
t->events |= CB_EVENT_CLOSED | CB_EVENT_READABLE;
|
||||
t->events |= CB_EVENT_CLOSED;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if SYN */
|
||||
if (tcp->flags & 0x02) {
|
||||
if (t->sock.tcp.state == TCP_LISTEN) {
|
||||
|
@ -1139,7 +1109,7 @@ static void tcp_input(struct ipstack *S, struct ipstack_tcp_seg *tcp, uint32_t f
|
|||
t->sock.tcp.state = TCP_CLOSING;
|
||||
}
|
||||
t->sock.tcp.ack = ee32(tcp->seq) + 1;
|
||||
t->events |= CB_EVENT_CLOSED | CB_EVENT_READABLE;
|
||||
t->events |= CB_EVENT_CLOSED;
|
||||
tcp_send_ack(t);
|
||||
}
|
||||
if (tcp->flags & 0x10) {
|
||||
|
@ -1163,12 +1133,15 @@ static void tcp_rto_cb(void *arg)
|
|||
struct ipstack_timer tmr = { };
|
||||
struct ipstack_timer *ptmr = NULL;
|
||||
int pending = 0;
|
||||
if ((ts->proto != FT_IPPROTO_TCP) || (ts->sock.tcp.state != TCP_ESTABLISHED))
|
||||
if ((ts->proto != IPPROTO_TCP) || (ts->sock.tcp.state != TCP_ESTABLISHED))
|
||||
return;
|
||||
desc = fifo_peek(&ts->sock.tcp.txbuf);
|
||||
while (desc) {
|
||||
if (desc->flags & PKT_FLAG_SENT) {
|
||||
desc->flags &= ~PKT_FLAG_SENT;
|
||||
LOG("Scheduling retransmit %u\n", ee32(((struct ipstack_tcp_seg *)(ts->txmem + desc->pos + sizeof(*desc)))->seq));
|
||||
LOG("Fifo len: %d\n", fifo_len(&ts->sock.tcp.txbuf));
|
||||
LOG("Fifo space: %d\n", fifo_space(&ts->sock.tcp.txbuf));
|
||||
pending++;
|
||||
}
|
||||
desc = fifo_next(&ts->sock.tcp.txbuf, desc);
|
||||
|
@ -1179,6 +1152,7 @@ static void tcp_rto_cb(void *arg)
|
|||
ts->sock.tcp.tmr_rto = NO_TIMER;
|
||||
}
|
||||
if (pending) {
|
||||
LOG("RTO backoff: %d\n", ts->sock.tcp.rto_backoff);
|
||||
ts->sock.tcp.rto_backoff++;
|
||||
ts->sock.tcp.cwnd = TCP_MSS;
|
||||
ts->sock.tcp.ssthresh = ts->sock.tcp.cwnd / 2;
|
||||
|
@ -1222,18 +1196,11 @@ int ft_socket(struct ipstack *s, int domain, int type, int protocol)
|
|||
int ft_connect(struct ipstack *s, int sockfd, const struct ipstack_sockaddr *addr, socklen_t addrlen)
|
||||
{
|
||||
struct tsocket *ts;
|
||||
const struct ipstack_sockaddr_in *sin = (const struct ipstack_sockaddr_in *)addr;
|
||||
struct ipstack_sockaddr_in *sin = (struct ipstack_sockaddr_in *)addr;
|
||||
struct ipstack_tcp_seg tcp;
|
||||
if (!addr)
|
||||
return -2;
|
||||
if (sockfd & MARK_UDP_SOCKET) {
|
||||
ts = &s->udpsockets[sockfd & ~MARK_UDP_SOCKET];
|
||||
ts->dst_port = ee16(sin->sin_port);
|
||||
ts->remote_ip = ee32(sin->sin_addr.s_addr);
|
||||
return 0;
|
||||
}
|
||||
if ((sockfd & MARK_TCP_SOCKET) == 0)
|
||||
return -1;
|
||||
ts = &s->tcpsockets[sockfd & ~MARK_TCP_SOCKET];
|
||||
ts = &s->tcpsockets[sockfd];
|
||||
if (ts->sock.tcp.state == TCP_ESTABLISHED)
|
||||
return 0;
|
||||
if (ts->sock.tcp.state == TCP_SYN_SENT)
|
||||
|
@ -1249,7 +1216,16 @@ int ft_connect(struct ipstack *s, int sockfd, const struct ipstack_sockaddr *add
|
|||
if (ts->src_port < 1024)
|
||||
ts->src_port += 1024;
|
||||
ts->dst_port = ee16(sin->sin_port);
|
||||
tcp_send_syn(ts, 0x02);
|
||||
tcp.src_port = ts->src_port;
|
||||
tcp.dst_port = sin->sin_port;
|
||||
tcp.seq = ts->sock.tcp.seq;
|
||||
tcp.ack = 0;
|
||||
tcp.hlen = (TCP_HEADER_LEN + TCP_OPTIONS_LEN) << 2;
|
||||
tcp.flags = 0x02; /* SYN */
|
||||
tcp.win = ee16((uint16_t)queue_space(&ts->sock.tcp.rxbuf));
|
||||
tcp.csum = 0;
|
||||
tcp.urg = 0;
|
||||
fifo_push(&ts->sock.tcp.txbuf, &tcp, sizeof(struct ipstack_tcp_seg) + TCP_OPTIONS_LEN);
|
||||
return -11;
|
||||
}
|
||||
return -2;
|
||||
|
@ -1354,7 +1330,7 @@ int ft_sendto(struct ipstack *s, int sockfd, const void *buf, size_t len, int fl
|
|||
else
|
||||
return sent;
|
||||
} else if (sockfd & MARK_UDP_SOCKET) {
|
||||
const struct ipstack_sockaddr_in *sin = (const struct ipstack_sockaddr_in *)dest_addr;
|
||||
struct ipstack_sockaddr_in *sin = (struct ipstack_sockaddr_in *)dest_addr;
|
||||
ts = &s->udpsockets[sockfd & ~MARK_UDP_SOCKET];
|
||||
if ((ts->dst_port == 0) && (dest_addr == NULL))
|
||||
return -1;
|
||||
|
@ -1367,7 +1343,7 @@ int ft_sendto(struct ipstack *s, int sockfd, const void *buf, size_t len, int fl
|
|||
}
|
||||
if ((ts->dst_port==0) || (ts->remote_ip==0))
|
||||
return -1;
|
||||
if (len > FT_IP_MTU - IP_HEADER_LEN - UDP_HEADER_LEN)
|
||||
if (len > IP_MTU - IP_HEADER_LEN - UDP_HEADER_LEN)
|
||||
return -1; /* Fragmentation not supported */
|
||||
if (fifo_space(&ts->sock.udp.txbuf) < len)
|
||||
return -11;
|
||||
|
@ -1376,9 +1352,6 @@ int ft_sendto(struct ipstack *s, int sockfd, const void *buf, size_t len, int fl
|
|||
if (ts->src_port < 1024)
|
||||
ts->src_port += 1024;
|
||||
}
|
||||
if(ts->local_ip == 0)
|
||||
ts->local_ip = s->ipconf.ip;
|
||||
|
||||
udp->src_port = ee16(ts->src_port);
|
||||
udp->dst_port = ee16(ts->dst_port);
|
||||
udp->len = ee16(len + UDP_HEADER_LEN);
|
||||
|
@ -1389,16 +1362,6 @@ int ft_sendto(struct ipstack *s, int sockfd, const void *buf, size_t len, int fl
|
|||
} else return -1;
|
||||
}
|
||||
|
||||
int ft_send(struct ipstack *s, int sockfd, const void *buf, size_t len, int flags)
|
||||
{
|
||||
return ft_sendto(s, sockfd, buf, len, flags, NULL, 0);
|
||||
}
|
||||
|
||||
int ft_write(struct ipstack *s, int sockfd, const void *buf, size_t len)
|
||||
{
|
||||
return ft_sendto(s, sockfd, buf, len, 0, NULL, 0);
|
||||
}
|
||||
|
||||
int ft_recvfrom(struct ipstack *s, int sockfd, void *buf, size_t len, int flags,
|
||||
struct ipstack_sockaddr *src_addr, socklen_t *addrlen)
|
||||
{
|
||||
|
@ -1417,10 +1380,7 @@ int ft_recvfrom(struct ipstack *s, int sockfd, void *buf, size_t len, int flags,
|
|||
return 0;
|
||||
return queue_pop(&ts->sock.tcp.rxbuf, buf, len);
|
||||
} else if (ts->sock.tcp.state == TCP_ESTABLISHED) {
|
||||
int ret = queue_pop(&ts->sock.tcp.rxbuf, buf, len);
|
||||
if ((ret > 0) && (queue_len(&ts->sock.tcp.rxbuf) > 0))
|
||||
ts->events |= CB_EVENT_READABLE;
|
||||
return ret;
|
||||
return queue_pop(&ts->sock.tcp.rxbuf, buf, len);
|
||||
} else { /* Not established */
|
||||
return -1;
|
||||
}
|
||||
|
@ -1429,7 +1389,7 @@ int ft_recvfrom(struct ipstack *s, int sockfd, void *buf, size_t len, int flags,
|
|||
ts = &s->udpsockets[sockfd & ~MARK_UDP_SOCKET];
|
||||
if (sin && *addrlen < sizeof(struct ipstack_sockaddr_in))
|
||||
return -1;
|
||||
if (addrlen) *addrlen = sizeof(struct ipstack_sockaddr_in);
|
||||
*addrlen = sizeof(struct ipstack_sockaddr_in);
|
||||
if (fifo_len(&ts->sock.udp.rxbuf) == 0)
|
||||
return -11;
|
||||
desc = fifo_peek(&ts->sock.udp.rxbuf);
|
||||
|
@ -1448,22 +1408,13 @@ int ft_recvfrom(struct ipstack *s, int sockfd, void *buf, size_t len, int flags,
|
|||
} else return -1;
|
||||
}
|
||||
|
||||
int ft_recv(struct ipstack *s, int sockfd, void *buf, size_t len, int flags)
|
||||
{
|
||||
return ft_recvfrom(s, sockfd, buf, len, flags, NULL, 0);
|
||||
}
|
||||
|
||||
int ft_read(struct ipstack *s, int sockfd, void *buf, size_t len)
|
||||
{
|
||||
return ft_recvfrom(s, sockfd, buf, len, 0, NULL, 0);
|
||||
}
|
||||
|
||||
int ft_close(struct ipstack *s, int sockfd)
|
||||
{
|
||||
if (sockfd & MARK_TCP_SOCKET) {
|
||||
struct tsocket *ts = &s->tcpsockets[sockfd & ~MARK_TCP_SOCKET];
|
||||
if (ts->sock.tcp.state == TCP_ESTABLISHED) {
|
||||
ts->sock.tcp.state = TCP_FIN_WAIT_1;
|
||||
LOG("close(): Sending FIN\n");
|
||||
tcp_send_finack(ts);
|
||||
return -11;
|
||||
} else if (ts->sock.tcp.state == TCP_CLOSE_WAIT) {
|
||||
|
@ -1507,7 +1458,7 @@ int ft_getsockname(struct ipstack *s, int sockfd, struct ipstack_sockaddr *addr,
|
|||
int ft_bind(struct ipstack *s, int sockfd, const struct ipstack_sockaddr *addr, socklen_t addrlen)
|
||||
{
|
||||
struct tsocket *ts;
|
||||
const struct ipstack_sockaddr_in *sin = (const struct ipstack_sockaddr_in *)addr;
|
||||
struct ipstack_sockaddr_in *sin = (struct ipstack_sockaddr_in *)addr;
|
||||
if (!sin || addrlen < sizeof(struct ipstack_sockaddr_in))
|
||||
return -1;
|
||||
|
||||
|
@ -1557,8 +1508,11 @@ int ft_getpeername(struct ipstack *s, int sockfd, struct ipstack_sockaddr *addr,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* ICMP */
|
||||
#define ICMP_ECHO_REPLY 0
|
||||
#define ICMP_ECHO_REQUEST 8
|
||||
|
||||
/* Reply to ICecho requests */
|
||||
/* Reply to ICMP echo requests */
|
||||
static void icmp_input(struct ipstack *s, struct ipstack_ip_packet *ip, uint32_t len)
|
||||
{
|
||||
struct ipstack_icmp_packet *icmp = (struct ipstack_icmp_packet *)ip;
|
||||
|
@ -1652,27 +1606,30 @@ static int dhcp_parse_offer(struct ipstack *s, struct dhcp_msg *msg)
|
|||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int dhcp_parse_ack(struct ipstack *s, struct dhcp_msg *msg)
|
||||
{
|
||||
struct dhcp_option *opt = (struct dhcp_option *)(msg->options);
|
||||
while (opt->code != 0xFF) {
|
||||
if (opt->code == DHCP_OPTION_MSG_TYPE) {
|
||||
if (opt->data[0] == DHCP_ACK) {
|
||||
uint32_t data;
|
||||
opt = (struct dhcp_option *)((uint8_t *)opt + 3);
|
||||
data = opt->data[0] | (opt->data[1] << 8) | (opt->data[2] << 16) | (opt->data[3] << 24);
|
||||
while (opt->code != 0xFF) {
|
||||
if (opt->code == DHCP_OPTION_SERVER_ID)
|
||||
if (opt->code == DHCP_OPTION_SERVER_ID) {
|
||||
uint32_t data = opt->data[0] | (opt->data[1] << 8) | (opt->data[2] << 16) | (opt->data[3] << 24);
|
||||
s->dhcp_server_ip = ee32(data);
|
||||
if (opt->code == DHCP_OPTION_OFFER_IP)
|
||||
}
|
||||
if (opt->code == DHCP_OPTION_OFFER_IP) {
|
||||
uint32_t data = opt->data[0] | (opt->data[1] << 8) | (opt->data[2] << 16) | (opt->data[3] << 24);
|
||||
s->ipconf.ip = ee32(data);
|
||||
if (opt->code == DHCP_OPTION_SUBNET_MASK)
|
||||
}
|
||||
if (opt->code == DHCP_OPTION_SUBNET_MASK) {
|
||||
uint32_t data = opt->data[0] | (opt->data[1] << 8) | (opt->data[2] << 16) | (opt->data[3] << 24);
|
||||
s->ipconf.mask = ee32(data);
|
||||
if (opt->code == DHCP_OPTION_ROUTER)
|
||||
}
|
||||
if (opt->code == DHCP_OPTION_ROUTER) {
|
||||
uint32_t data = opt->data[0] | (opt->data[1] << 8) | (opt->data[2] << 16) | (opt->data[3] << 24);
|
||||
s->ipconf.gw = ee32(data);
|
||||
if ((opt->code == DHCP_OPTION_DNS) && (s->dns_server == 0))
|
||||
s->dns_server = ee32(data);
|
||||
}
|
||||
opt = (struct dhcp_option *)((uint8_t *)opt + 2 + opt->len);
|
||||
}
|
||||
if ((s->ipconf.ip != 0) && (s->ipconf.mask != 0)) {
|
||||
|
@ -1698,14 +1655,8 @@ static int dhcp_poll(struct ipstack *s)
|
|||
return -1;
|
||||
if ((s->dhcp_state == DHCP_DISCOVER_SENT) && (dhcp_parse_offer(s, &msg) == 0))
|
||||
dhcp_send_request(s);
|
||||
else if ((s->dhcp_state == DHCP_REQUEST_SENT) && (dhcp_parse_ack(s, &msg) == 0)) {
|
||||
else if ((s->dhcp_state == DHCP_REQUEST_SENT) && (dhcp_parse_ack(s, &msg) == 0))
|
||||
LOG("DHCP configuration received.\n");
|
||||
LOG("IP Address: %u.%u.%u.%u\n", (s->ipconf.ip >> 24) & 0xFF, (s->ipconf.ip >> 16) & 0xFF, (s->ipconf.ip >> 8) & 0xFF, (s->ipconf.ip >> 0) & 0xFF);
|
||||
LOG("Subnet Mask: %u.%u.%u.%u\n", (s->ipconf.mask >> 24) & 0xFF, (s->ipconf.mask >> 16) & 0xFF, (s->ipconf.mask >> 8) & 0xFF, (s->ipconf.mask >> 0) & 0xFF);
|
||||
LOG("Gateway: %u.%u.%u.%u\n", (s->ipconf.gw >> 24) & 0xFF, (s->ipconf.gw >> 16) & 0xFF, (s->ipconf.gw >> 8) & 0xFF, (s->ipconf.gw >> 0) & 0xFF);
|
||||
if (s->dns_server)
|
||||
LOG("DNS Server: %u.%u.%u.%u\n", (s->dns_server >> 24) & 0xFF, (s->dns_server >> 16) & 0xFF, (s->dns_server >> 8) & 0xFF, (s->dns_server >> 0) & 0xFF);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1770,16 +1721,6 @@ static int dhcp_send_request(struct ipstack *s)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void dhcp_callback(int sockfd, uint16_t ev, void *arg)
|
||||
{
|
||||
struct ipstack *s = (struct ipstack *)arg;
|
||||
(void)sockfd;
|
||||
(void)ev;
|
||||
if (!s)
|
||||
return;
|
||||
dhcp_poll(s);
|
||||
}
|
||||
|
||||
static int dhcp_send_discover(struct ipstack *s)
|
||||
{
|
||||
struct dhcp_msg disc;
|
||||
|
@ -1842,7 +1783,7 @@ int dhcp_client_init(struct ipstack *s)
|
|||
ft_close(s, s->dhcp_udp_sd);
|
||||
}
|
||||
|
||||
s->dhcp_udp_sd = ft_socket(s, AF_INET, IPSTACK_SOCK_DGRAM, FT_IPPROTO_UDP);
|
||||
s->dhcp_udp_sd = ft_socket(s, AF_INET, IPSTACK_SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (s->dhcp_udp_sd < 0) {
|
||||
s->dhcp_state = DHCP_OFF;
|
||||
return -1;
|
||||
|
@ -1854,7 +1795,6 @@ int dhcp_client_init(struct ipstack *s)
|
|||
s->dhcp_state = DHCP_OFF;
|
||||
return -1;
|
||||
}
|
||||
ipstack_register_callback(s, s->dhcp_udp_sd, dhcp_callback, s);
|
||||
return dhcp_send_discover(s);
|
||||
}
|
||||
|
||||
|
@ -1957,167 +1897,6 @@ void ipstack_init_static(struct ipstack **s)
|
|||
*s = &ipstack_static;
|
||||
}
|
||||
|
||||
static inline void ip_recv(struct ipstack *s, struct ipstack_ip_packet *ip,
|
||||
uint32_t len)
|
||||
{
|
||||
if (ip->ver_ihl == 0x45 && ip->proto == 0x06) {
|
||||
struct ipstack_tcp_seg *tcp = (struct ipstack_tcp_seg *)ip;
|
||||
tcp_input(s, tcp, len);
|
||||
}
|
||||
else if (ip->ver_ihl == 0x45 && ip->proto == 0x11) {
|
||||
struct ipstack_udp_datagram *udp = (struct ipstack_udp_datagram *)ip;
|
||||
udp_try_recv(s, udp, len);
|
||||
} else if (ip->ver_ihl == 0x45 && ip->proto == 0x01) {
|
||||
icmp_input(s, ip, len);
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to receive a packet from the network interface.
|
||||
*
|
||||
* This function is called either after polling the device driver
|
||||
* in the loop, or in the device driver dsr callback.
|
||||
*/
|
||||
void ipstack_recv(struct ipstack *s, void *buf, uint32_t len)
|
||||
{
|
||||
#ifdef ETHERNET
|
||||
struct ipstack_eth_frame *eth = (struct ipstack_eth_frame *)buf;
|
||||
if (eth->type == ee16(0x0800)) {
|
||||
struct ipstack_ip_packet *ip = (struct ipstack_ip_packet *)eth;
|
||||
if ((memcmp(eth->dst, s->ll_dev.mac, 6) != 0) && (memcmp(eth->dst, "\xff\xff\xff\xff\xff\xff", 6) != 0)) {
|
||||
return; /* Not for us */
|
||||
}
|
||||
ip_recv(s, ip, len);
|
||||
} else if (eth->type == ee16(0x0806)) {
|
||||
arp_recv(s, buf, len);
|
||||
}
|
||||
#else
|
||||
/* No ethernet, assume IP */
|
||||
struct ipstack_ip_packet *ip = (struct ipstack_ip_packet *)buf;
|
||||
ip_recv(s, ip, len);
|
||||
#endif
|
||||
/* No default action required: the buffer is in stack and will be discarded on return */
|
||||
}
|
||||
|
||||
/* DNS Client */
|
||||
#define DNS_PORT 53
|
||||
#define DNS_QUERY 0x00
|
||||
#define DNS_RESPONSE 0x80
|
||||
#define DNS_A 0x01 /* A record only */
|
||||
#define DNS_RD 0x0100 /* Recursion desired */
|
||||
|
||||
struct PACKED dns_header {
|
||||
uint16_t id;
|
||||
uint16_t flags;
|
||||
uint16_t qdcount;
|
||||
uint16_t ancount;
|
||||
uint16_t nscount;
|
||||
uint16_t arcount;
|
||||
};
|
||||
|
||||
struct PACKED dns_question {
|
||||
uint16_t qtype;
|
||||
uint16_t qclass;
|
||||
};
|
||||
#define MAX_DNS_RESPONSE 512
|
||||
|
||||
void dns_callback(int dns_sd, uint16_t ev, void *arg)
|
||||
{
|
||||
struct ipstack *s = (struct ipstack *)arg;
|
||||
char buf[MAX_DNS_RESPONSE];
|
||||
struct dns_header *hdr = (struct dns_header *)buf;
|
||||
struct dns_question *q;
|
||||
int dns_len;
|
||||
if (!s)
|
||||
return;
|
||||
if (ev & CB_EVENT_READABLE) {
|
||||
dns_len = ft_recvfrom(s, dns_sd, buf, MAX_DNS_RESPONSE, 0, NULL, 0);
|
||||
if (dns_len < 0) {
|
||||
ft_close(s, dns_sd);
|
||||
s->dns_udp_sd = -1;
|
||||
s->dns_id = 0;
|
||||
return;
|
||||
}
|
||||
/* Parse DNS response */
|
||||
if ((ee16(hdr->flags) & 0x8100) == 0x8100) {
|
||||
/* Skip the question */
|
||||
char *q_name = buf + sizeof(struct dns_header);
|
||||
uint32_t ip;
|
||||
while (*q_name) q_name++;
|
||||
if (q_name - buf > dns_len) {
|
||||
s->dns_id = 0;
|
||||
return;
|
||||
}
|
||||
q_name++; /* Skip the null terminator */
|
||||
q = (struct dns_question *)q_name;
|
||||
if (ee16(q->qtype) == DNS_A) {
|
||||
uint8_t *ip_ptr = (uint8_t *)(buf + dns_len - 4);
|
||||
ip = ip_ptr[3] | (ip_ptr[2] << 8) | (ip_ptr[1] << 16) | (ip_ptr[0] << 24);
|
||||
if(s->dns_lookup_cb)
|
||||
s->dns_lookup_cb(ee32(ip));
|
||||
LOG("DNS response: %u.%u.%u.%u\n", (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, ip & 0xFF);
|
||||
s->dns_id = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int nslookup(struct ipstack *s, const char *dname, uint16_t *id, void (*lookup_cb)(uint32_t ip))
|
||||
{
|
||||
uint8_t buf[512];
|
||||
struct dns_header *hdr;
|
||||
struct dns_question *q;
|
||||
char *q_name, *tok_start, *tok_end;
|
||||
struct ipstack_sockaddr_in dns_srv;
|
||||
uint32_t tok_len = 0;
|
||||
if (!dname || !id || !lookup_cb) return -22; /* Invalid arguments */
|
||||
if (strlen(dname) > 256) return -22; /* Invalid arguments */
|
||||
if (s->dns_server == 0) return -101; /* Network unreachable: No DNS server configured */
|
||||
if (s->dns_id != 0) return -16; /* DNS query already in progress */
|
||||
if (s->dns_udp_sd <= 0) {
|
||||
s->dns_udp_sd = ft_socket(s, AF_INET, IPSTACK_SOCK_DGRAM, FT_IPPROTO_UDP);
|
||||
if (s->dns_udp_sd < 0)
|
||||
return -1;
|
||||
ipstack_register_callback(s, s->dns_udp_sd, dns_callback, s);
|
||||
}
|
||||
s->dns_lookup_cb = lookup_cb;
|
||||
s->dns_id = ipstack_getrandom();
|
||||
*id = s->dns_id;
|
||||
memset(buf, 0, 512);
|
||||
hdr = (struct dns_header *)buf;
|
||||
hdr->id = ee16(s->dns_id);
|
||||
hdr->flags = ee16(DNS_QUERY);
|
||||
hdr->qdcount = ee16(1);
|
||||
hdr->flags = ee16(DNS_RD);
|
||||
/* Prepare the DNS query name */
|
||||
q_name = (char *)(buf + sizeof(struct dns_header));
|
||||
tok_start = (char *)dname;
|
||||
while(*tok_start) {
|
||||
tok_end = tok_start;
|
||||
while ((*tok_end != '.') && (*tok_end != 0)) {
|
||||
tok_end++;
|
||||
}
|
||||
*q_name = tok_end - tok_start;
|
||||
q_name++;
|
||||
memcpy(q_name, tok_start, tok_end - tok_start);
|
||||
q_name += tok_end - tok_start;
|
||||
tok_len += (tok_end - tok_start) + 1;
|
||||
if (*tok_end == 0)
|
||||
break;
|
||||
tok_start = tok_end + 1;
|
||||
}
|
||||
*q_name = 0;
|
||||
tok_len++;
|
||||
q = (struct dns_question *)(buf + sizeof(struct dns_header) + tok_len);
|
||||
q->qtype = ee16(DNS_A);
|
||||
q->qclass = ee16(1);
|
||||
memset(&dns_srv, 0, sizeof(struct ipstack_sockaddr_in));
|
||||
dns_srv.sin_family = AF_INET;
|
||||
dns_srv.sin_port = ee16(DNS_PORT);
|
||||
dns_srv.sin_addr.s_addr = ee32(s->dns_server);
|
||||
ft_sendto(s, s->dns_udp_sd, buf, sizeof(struct dns_header) + tok_len + sizeof(struct dns_question), 0, (struct ipstack_sockaddr *)&dns_srv, sizeof(struct ipstack_sockaddr_in));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ipstack_poll: poll the network stack for incoming packets
|
||||
* This function should be called in a loop to process incoming packets.
|
||||
* It will call the poll function of the device driver and process the
|
||||
|
@ -2139,15 +1918,49 @@ int ipstack_poll(struct ipstack *s, uint64_t now)
|
|||
s->last_tick = now;
|
||||
|
||||
/* Step 1: Poll the device */
|
||||
if (s->ll_dev.poll) {
|
||||
do {
|
||||
len = s->ll_dev.poll(&s->ll_dev, buf, LINK_MTU);
|
||||
if (len > 0) {
|
||||
/* Process packet */
|
||||
ipstack_recv(s, buf, len);
|
||||
do {
|
||||
len = s->ll_dev.poll(&s->ll_dev, buf, LINK_MTU);
|
||||
if (len > 0) {
|
||||
/* Process packet */
|
||||
#ifdef ETHERNET
|
||||
struct ipstack_eth_frame *eth = (struct ipstack_eth_frame *)buf;
|
||||
if (eth->type == ee16(0x0800)) {
|
||||
if ((memcmp(eth->dst, s->ll_dev.mac, 6) != 0) && (memcmp(eth->dst, "\xff\xff\xff\xff\xff\xff", 6) != 0)) {
|
||||
/* Not for us */
|
||||
continue;
|
||||
}
|
||||
struct ipstack_ip_packet *ip = (struct ipstack_ip_packet *)eth;
|
||||
if (ip->ver_ihl == 0x45 && ip->proto == 0x06) {
|
||||
struct ipstack_tcp_seg *tcp = (struct ipstack_tcp_seg *)ip;
|
||||
tcp_input(s, tcp, len);
|
||||
}
|
||||
else if (ip->ver_ihl == 0x45 && ip->proto == 0x11) {
|
||||
struct ipstack_udp_datagram *udp = (struct ipstack_udp_datagram *)ip;
|
||||
udp_try_recv(s, udp, len);
|
||||
} else if (ip->ver_ihl == 0x45 && ip->proto == 0x01) {
|
||||
icmp_input(s, ip, len);
|
||||
}
|
||||
} else if (eth->type == ee16(0x0806)) {
|
||||
arp_recv(s, buf, len);
|
||||
}
|
||||
} while (len > 0);
|
||||
}
|
||||
#else
|
||||
/* No ethernet, assume IP */
|
||||
struct ipstack_ip_packet *ip = (struct ipstack_ip_packet *)buf;
|
||||
if (ip->ver_ihl == 0x45 && ip->proto == 0x06) {
|
||||
struct ipstack_tcp_seg *tcp = (struct ipstack_tcp_seg *)ip;
|
||||
tcp_input(s, tcp, len);
|
||||
}
|
||||
else if (ip->ver_ihl == 0x45 && ip->proto == 0x11) {
|
||||
struct ipstack_udp_datagram *udp = (struct ipstack_udp_datagram *)ip;
|
||||
udp_try_recv(s, udp, len);
|
||||
} else if (ip->ver_ihl == 0x45 && ip->proto == 0x01) {
|
||||
icmp_input(s, ip, len);
|
||||
}
|
||||
#endif
|
||||
/* No default action required: the buffer is in stack and will be discarded on return */
|
||||
}
|
||||
} while (len > 0);
|
||||
|
||||
/* Step 2: Handle timers */
|
||||
while(is_timer_expired(&s->timers, now)) {
|
||||
tmr = timers_binheap_pop(&s->timers);
|
||||
|
@ -2160,6 +1973,7 @@ int ipstack_poll(struct ipstack *s, uint64_t now)
|
|||
ts->callback(i | MARK_TCP_SOCKET, ts->events, ts->callback_arg);
|
||||
ts->events = 0;
|
||||
}
|
||||
|
||||
}
|
||||
for (i = 0; i < MAX_UDPSOCKETS; i++) {
|
||||
struct tsocket *ts = &s->udpsockets[i];
|
||||
|
@ -2168,6 +1982,10 @@ int ipstack_poll(struct ipstack *s, uint64_t now)
|
|||
ts->events = 0;
|
||||
}
|
||||
}
|
||||
/* Poll DHCP */
|
||||
if (s->dhcp_state == DHCP_DISCOVER_SENT || s->dhcp_state == DHCP_REQUEST_SENT) {
|
||||
dhcp_poll(s);
|
||||
}
|
||||
|
||||
/* Step 4: attempt to write any pending data */
|
||||
for (i = 0; i < MAX_TCPSOCKETS; i++) {
|
||||
|
@ -2208,7 +2026,7 @@ int ipstack_poll(struct ipstack *s, uint64_t now)
|
|||
ts->sock.tcp.last_ack = ts->sock.tcp.ack;
|
||||
tcp->ack = ee32(ts->sock.tcp.ack);
|
||||
tcp->win = ee16(queue_space(&ts->sock.tcp.rxbuf));
|
||||
ip_output_add_header(ts, (struct ipstack_ip_packet *)tcp, FT_IPPROTO_TCP, len);
|
||||
ip_output_add_header(ts, (struct ipstack_ip_packet *)tcp, IPPROTO_TCP, len);
|
||||
s->ll_dev.send(&s->ll_dev, tcp, desc->len);
|
||||
desc->flags |= PKT_FLAG_SENT;
|
||||
desc->time_sent = now;
|
||||
|
@ -2248,7 +2066,7 @@ int ipstack_poll(struct ipstack *s, uint64_t now)
|
|||
if (IS_IP_BCAST(nexthop)) memset(t->nexthop_mac, 0xFF, 6);
|
||||
#endif
|
||||
len = desc->len - ETH_HEADER_LEN;
|
||||
ip_output_add_header(t, (struct ipstack_ip_packet *)udp, FT_IPPROTO_UDP, len);
|
||||
ip_output_add_header(t, (struct ipstack_ip_packet *)udp, IPPROTO_UDP, len);
|
||||
s->ll_dev.send(&s->ll_dev, udp, desc->len);
|
||||
fifo_pop(&t->sock.udp.txbuf);
|
||||
desc = fifo_peek(&t->sock.udp.txbuf);
|
||||
|
@ -2271,3 +2089,26 @@ void ipstack_ipconfig_get(struct ipstack *s, ip4 *ip, ip4 *mask, ip4 *gw)
|
|||
*gw = s->ipconf.gw;
|
||||
}
|
||||
|
||||
static uint32_t atou(const char *s)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
while (*s >= '0' && *s <= '9') {
|
||||
ret = ret * 10 + (*s - '0');
|
||||
s++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ip4 atoip4(const char *ip)
|
||||
{
|
||||
ip4 ret = 0;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
for (i = 0; i < 4; i++) {
|
||||
ret |= (atou(ip + j) << (24 - i * 8));
|
||||
while (ip[j] != '.' && ip[j] != '\0') j++;
|
||||
if (ip[j] == '\0') break;
|
||||
j++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
412
src/http/httpd.c
412
src/http/httpd.c
|
@ -1,412 +0,0 @@
|
|||
/* HTTP 1.1 server
|
||||
* (c) Danielinux 2024 <root@danielinux.net>
|
||||
* This code is licensed under the GPLv3 license.
|
||||
*/
|
||||
#include "femtotcp.h"
|
||||
#include "httpd.h"
|
||||
|
||||
static const char *http_status_text(int status_code) {
|
||||
switch (status_code) {
|
||||
case HTTP_STATUS_OK:
|
||||
return "OK";
|
||||
case HTTP_STATUS_BAD_REQUEST:
|
||||
return "Bad Request";
|
||||
case HTTP_STATUS_NOT_FOUND:
|
||||
return "Not Found";
|
||||
case HTTP_STATUS_TEAPOT:
|
||||
return "I'm a teapot";
|
||||
case HTTP_STATUS_TOO_MANY_REQUESTS:
|
||||
return "Too Many Requests";
|
||||
case HTTP_STATUS_INTERNAL_SERVER_ERROR:
|
||||
return "Internal Server Error";
|
||||
case HTTP_STATUS_SERVICE_UNAVAILABLE:
|
||||
return "Service Unavailable";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
/*
|
||||
static struct http_client *http_client_find(struct httpd *httpd, int sd) {
|
||||
for (int i = 0; i < HTTPD_MAX_CLIENTS; i++) {
|
||||
if (httpd->clients[i].client_sd == sd) {
|
||||
return &httpd->clients[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
*/
|
||||
|
||||
int httpd_register_handler(struct httpd *httpd, const char *path, int (*handler)(struct httpd *httpd, struct http_client *hc, struct http_request *req)) {
|
||||
for (int i = 0; i < HTTPD_MAX_URLS; i++) {
|
||||
if (httpd->urls[i].handler == NULL) {
|
||||
strncpy(httpd->urls[i].path, path, HTTP_PATH_LEN);
|
||||
httpd->urls[i].handler = handler;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int httpd_register_static_page(struct httpd *httpd, const char *path, const char *content) {
|
||||
for (int i = 0; i < HTTPD_MAX_URLS; i++) {
|
||||
if (httpd->urls[i].handler == NULL) {
|
||||
strncpy(httpd->urls[i].path, path, HTTP_PATH_LEN);
|
||||
httpd->urls[i].handler = NULL;
|
||||
httpd->urls[i].static_content = content;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static struct http_url *http_find_url(struct httpd *httpd, const char *path) {
|
||||
for (int i = 0; i < HTTPD_MAX_URLS; i++) {
|
||||
if (strcmp(httpd->urls[i].path, path) == 0) {
|
||||
return &httpd->urls[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void http_send_response_headers(struct http_client *hc, int status_code, const char *status_text, const char *content_type, size_t content_length)
|
||||
{
|
||||
char txt_response[HTTP_TX_BUF_LEN];
|
||||
memset(txt_response, 0, sizeof(txt_response));
|
||||
if (!hc) return;
|
||||
/* If content_lenght is 0, assume chunked encoding */
|
||||
if (content_length == 0) {
|
||||
snprintf(txt_response, sizeof(txt_response), "HTTP/1.1 %d %s\r\n"
|
||||
"Content-Type: %s\r\n"
|
||||
"Transfer-Encoding: chunked\r\n"
|
||||
"\r\n",
|
||||
status_code, status_text, content_type);
|
||||
} else {
|
||||
snprintf(txt_response, sizeof(txt_response), "HTTP/1.1 %d %s\r\n"
|
||||
"Content-Type: %s\r\n"
|
||||
"Content-Length: %lu\r\n"
|
||||
"\r\n",
|
||||
status_code, status_text, content_type, content_length);
|
||||
}
|
||||
if (hc->ssl) {
|
||||
wolfSSL_write(hc->ssl, txt_response, strlen(txt_response));
|
||||
} else {
|
||||
ft_send(hc->httpd->ipstack, hc->client_sd, txt_response, strlen(txt_response), 0);
|
||||
}
|
||||
}
|
||||
|
||||
void http_send_response_body(struct http_client *hc, const void *body, size_t len) {
|
||||
if (!hc) return;
|
||||
if (hc->ssl) {
|
||||
wolfSSL_write(hc->ssl, body, len);
|
||||
} else {
|
||||
ft_send(hc->httpd->ipstack, hc->client_sd, body, len, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void http_send_response_chunk(struct http_client *hc, const void *chunk, size_t len) {
|
||||
char txt_chunk[8];
|
||||
memset(txt_chunk, 0, sizeof(txt_chunk));
|
||||
if (!hc) return;
|
||||
snprintf(txt_chunk, sizeof(txt_chunk), "%lx\r\n", len);
|
||||
if (hc->ssl) {
|
||||
wolfSSL_write(hc->ssl, txt_chunk, strlen(txt_chunk));
|
||||
wolfSSL_write(hc->ssl, chunk, len);
|
||||
wolfSSL_write(hc->ssl, "\r\n", 2);
|
||||
} else {
|
||||
struct ipstack *s = hc->httpd->ipstack;
|
||||
ft_send(s, hc->client_sd, txt_chunk, strlen(txt_chunk), 0);
|
||||
ft_send(s, hc->client_sd, chunk, len, 0);
|
||||
ft_send(s, hc->client_sd, "\r\n", 2, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void http_send_response_chunk_end(struct http_client *hc) {
|
||||
if (!hc) return;
|
||||
if (hc->ssl) {
|
||||
wolfSSL_write(hc->ssl, "0\r\n\r\n", 5);
|
||||
} else {
|
||||
ft_send(hc->httpd->ipstack, hc->client_sd, "0\r\n\r\n", 5, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void http_send_200_OK(struct http_client *hc) {
|
||||
http_send_response_headers(hc, HTTP_STATUS_OK,
|
||||
http_status_text(HTTP_STATUS_OK), "text/plain", 0);
|
||||
}
|
||||
|
||||
void http_send_500_server_error(struct http_client *hc) {
|
||||
http_send_response_headers(hc, HTTP_STATUS_INTERNAL_SERVER_ERROR,
|
||||
http_status_text(HTTP_STATUS_INTERNAL_SERVER_ERROR), "text/plain", 0);
|
||||
}
|
||||
|
||||
void http_send_503_service_unavailable(struct http_client *hc) {
|
||||
http_send_response_headers(hc, HTTP_STATUS_SERVICE_UNAVAILABLE,
|
||||
http_status_text(HTTP_STATUS_SERVICE_UNAVAILABLE), "text/plain", 0);
|
||||
}
|
||||
|
||||
void http_send_418_teapot(struct http_client *hc) {
|
||||
http_send_response_headers(hc, HTTP_STATUS_TEAPOT,
|
||||
http_status_text(HTTP_STATUS_TEAPOT), "text/plain", 0);
|
||||
}
|
||||
|
||||
int http_url_decode(char *buf, size_t len) {
|
||||
char *p = buf;
|
||||
char *q;
|
||||
while (p < buf + len) {
|
||||
q = strchr(p, '%');
|
||||
if (!q) {
|
||||
break;
|
||||
}
|
||||
if (q + 2 >= buf + len) {
|
||||
break;
|
||||
}
|
||||
*q = (char) strtol(q + 1, NULL, 16);
|
||||
memmove(q + 1, q + 3, len - (q + 3 - buf));
|
||||
len -= 2;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
int http_url_encode(char *buf, size_t len, size_t max_len) {
|
||||
char *p = buf;
|
||||
char *q;
|
||||
while (p < buf + len) {
|
||||
q = strchr(p, ' ');
|
||||
if (!q) {
|
||||
break;
|
||||
}
|
||||
if (len + 2 >= max_len) {
|
||||
return -1; /* Not enough space */
|
||||
}
|
||||
memmove(q + 3, q + 1, len - (q + 1 - buf));
|
||||
*q = '%';
|
||||
*(q + 1) = '2';
|
||||
*(q + 2) = '0';
|
||||
len += 2;
|
||||
}
|
||||
q[len] = '\0';
|
||||
return len;
|
||||
}
|
||||
|
||||
static int parse_http_request(struct http_client *hc, uint8_t *buf, size_t len) {
|
||||
char *p = (char *) buf;
|
||||
char *end = p + len;
|
||||
char *q;
|
||||
size_t n;
|
||||
int ret;
|
||||
struct http_request req;
|
||||
struct http_url *url = NULL;
|
||||
memset(&req, 0, sizeof(struct http_request));
|
||||
http_url_decode(p, len); /* Decode can be done in place */
|
||||
if (len < 4) goto bad_request;
|
||||
/* Parse the request line */
|
||||
q = strchr(p, ' ');
|
||||
if (!q) goto bad_request;
|
||||
n = q - p;
|
||||
if (n >= sizeof(req.method)) goto bad_request;
|
||||
memcpy(req.method, p, n);
|
||||
req.method[n] = '\0';
|
||||
p = q + 1;
|
||||
q = strchr(p, ' ');
|
||||
if (!q) goto bad_request;
|
||||
n = q - p;
|
||||
if (n >= sizeof(req.path)) goto bad_request;
|
||||
memcpy(req.path, p, n);
|
||||
req.path[n] = '\0';
|
||||
p = q + 1;
|
||||
q = strchr(p, '\r');
|
||||
if (!q) goto bad_request;
|
||||
n = q - p;
|
||||
if (n >= sizeof(req.query)) goto bad_request;
|
||||
memcpy(req.query, p, n);
|
||||
req.query[n] = '\0';
|
||||
p = q + 2;
|
||||
|
||||
/* Parse the headers */
|
||||
while (p < end) {
|
||||
q = strstr(p, "\r\n");
|
||||
if (!q) goto bad_request;
|
||||
n = q - p;
|
||||
if (n == 0) {
|
||||
break;
|
||||
}
|
||||
if (n >= sizeof(req.headers)) goto bad_request;
|
||||
memcpy(req.headers, p, n);
|
||||
req.headers[n] = '\0';
|
||||
p = q + 2;
|
||||
}
|
||||
/* Parse the body */
|
||||
if (p < end) {
|
||||
n = end - p;
|
||||
if (n >= sizeof(req.body)) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(req.body, p, n);
|
||||
req.body[n] = '\0';
|
||||
req.body_len = n;
|
||||
}
|
||||
|
||||
if ((strcmp(req.method, "GET") != 0) && (strcmp(req.method, "POST") != 0))
|
||||
goto bad_request;
|
||||
url = http_find_url(hc->httpd, req.path);
|
||||
if (!url) goto not_found;
|
||||
|
||||
if ((url->handler == NULL) && (url->static_content == NULL))
|
||||
goto service_unavailable;
|
||||
if (url->handler == NULL) {
|
||||
http_send_response_headers(hc, HTTP_STATUS_OK, http_status_text(HTTP_STATUS_OK), "text/html", strlen(url->static_content));
|
||||
http_send_response_body(hc, url->static_content, strlen(url->static_content));
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = url->handler(hc->httpd, hc, &req);
|
||||
}
|
||||
return ret;
|
||||
bad_request:
|
||||
http_send_response_headers(hc, HTTP_STATUS_BAD_REQUEST, http_status_text(HTTP_STATUS_BAD_REQUEST), "text/plain", 0);
|
||||
return -1;
|
||||
not_found:
|
||||
http_send_response_headers(hc, HTTP_STATUS_NOT_FOUND, http_status_text(HTTP_STATUS_NOT_FOUND), "text/plain", 0);
|
||||
return -1;
|
||||
service_unavailable:
|
||||
http_send_response_headers(hc, HTTP_STATUS_SERVICE_UNAVAILABLE, http_status_text(HTTP_STATUS_SERVICE_UNAVAILABLE), "text/plain", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void http_recv_cb(int sd, uint16_t event, void *arg) {
|
||||
struct http_client *hc = (struct http_client *) arg;
|
||||
int parse_r;
|
||||
uint8_t buf[HTTP_RECV_BUF_LEN];
|
||||
int ret;
|
||||
if (!hc) return;
|
||||
(void) event;
|
||||
if (hc->ssl) {
|
||||
ret = wolfSSL_read(hc->ssl, buf, sizeof(buf));
|
||||
if (ret < 0) {
|
||||
if (wolfSSL_get_error(hc->ssl, ret) == WOLFSSL_ERROR_WANT_READ) {
|
||||
return;
|
||||
} else {
|
||||
goto fail_close;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret = ft_recv(hc->httpd->ipstack, sd, buf, sizeof(buf), 0);
|
||||
if (ret == -11)
|
||||
return;
|
||||
}
|
||||
if (ret <= 0)
|
||||
goto fail_close;
|
||||
parse_r = parse_http_request(hc, buf, ret);
|
||||
if (parse_r < 0)
|
||||
goto fail_close;
|
||||
|
||||
return;
|
||||
|
||||
fail_close:
|
||||
if (hc->ssl) {
|
||||
wolfSSL_free(hc->ssl);
|
||||
hc->ssl = NULL;
|
||||
}
|
||||
ft_close(hc->httpd->ipstack, sd);
|
||||
hc->client_sd = 0;
|
||||
}
|
||||
|
||||
static void http_accept_cb(int sd, uint16_t event, void *arg) {
|
||||
struct httpd *httpd = (struct httpd *) arg;
|
||||
struct ipstack_sockaddr_in addr;
|
||||
socklen_t addr_len = sizeof(struct ipstack_sockaddr_in);
|
||||
int client_sd = ft_accept(httpd->ipstack, sd, (struct ipstack_sockaddr *) &addr, &addr_len);
|
||||
if (client_sd < 0) {
|
||||
return;
|
||||
}
|
||||
(void) event;
|
||||
for (int i = 0; i < HTTPD_MAX_CLIENTS; i++) {
|
||||
if (httpd->clients[i].client_sd == 0) {
|
||||
httpd->clients[i].client_sd = client_sd;
|
||||
httpd->clients[i].httpd = httpd;
|
||||
memcpy(&httpd->clients[i].addr, &addr, sizeof(addr));
|
||||
if (httpd->ssl_ctx) {
|
||||
httpd->clients[i].ssl = wolfSSL_new(httpd->ssl_ctx);
|
||||
if (httpd->clients[i].ssl) {
|
||||
wolfSSL_SetIO_FT(httpd->clients[i].ssl, client_sd);
|
||||
} else {
|
||||
/* Failed to create SSL object */
|
||||
ft_close(httpd->ipstack, client_sd);
|
||||
httpd->clients[i].client_sd = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
ipstack_register_callback(httpd->ipstack, client_sd, http_recv_cb, &httpd->clients[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Extra utility to extract requests arguments */
|
||||
int httpd_get_request_arg(struct http_request *req, const char *name, char *value, size_t value_len) {
|
||||
char *p;
|
||||
char *q;
|
||||
char *sep;
|
||||
|
||||
if (strcmp(req->method, "GET") == 0)
|
||||
p = req->query;
|
||||
else if (strcmp(req->method, "POST") == 0)
|
||||
p = req->body;
|
||||
else
|
||||
return -1; // Unsupported method
|
||||
|
||||
while (*p) {
|
||||
q = strchr(p, '&');
|
||||
if (!q) {
|
||||
q = p + strlen(p); // End of key-value pair
|
||||
}
|
||||
sep = strchr(p, '=');
|
||||
if (sep && sep < q) { // Ensure '=' is within bounds
|
||||
size_t key_len = sep - p;
|
||||
if (key_len == strlen(name) && strncmp(p, name, key_len) == 0) {
|
||||
size_t value_len_actual = q - (sep + 1);
|
||||
if (value_len_actual >= value_len) {
|
||||
return -1; // Insufficient buffer size
|
||||
}
|
||||
memcpy(value, sep + 1, value_len_actual);
|
||||
value[value_len_actual] = '\0';
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
p = q + 1; // Move to next key-value pair
|
||||
}
|
||||
return -1; // Key not found
|
||||
}
|
||||
|
||||
int httpd_init(struct httpd *httpd, struct ipstack *s, uint16_t port, void *ssl_ctx) {
|
||||
struct ipstack_sockaddr_in addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
if (!httpd) {
|
||||
return -1;
|
||||
}
|
||||
memset(httpd, 0, sizeof(struct httpd));
|
||||
httpd->ipstack = s;
|
||||
httpd->port = port;
|
||||
httpd->listen_sd = ft_socket(s, AF_INET, SOCK_STREAM, 0);
|
||||
if (httpd->listen_sd < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (ft_bind(s, httpd->listen_sd, (struct ipstack_sockaddr *) &addr, sizeof(addr)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (ft_listen(s, httpd->listen_sd, 5) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (ssl_ctx) {
|
||||
httpd->ssl_ctx = (WOLFSSL_CTX *) ssl_ctx;
|
||||
wolfSSL_SetIO_FT_CTX(httpd->ssl_ctx, httpd->ipstack);
|
||||
}
|
||||
ipstack_register_callback(s, httpd->listen_sd, http_accept_cb, httpd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
#ifndef FEMTO_HTTPD_H
|
||||
#define FEMTO_HTTPD_H
|
||||
#ifdef WOLFSSL_USER_SETTINGS
|
||||
#include <user_settings.h>
|
||||
#else
|
||||
#include <wolfssl/options.h>
|
||||
#endif
|
||||
#include <wolfssl/wolfcrypt/settings.h>
|
||||
#include <wolfssl/ssl.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define HTTP_METHOD_LEN 8
|
||||
#define HTTP_PATH_LEN 128
|
||||
#define HTTP_QUERY_LEN 256
|
||||
#define HTTP_HEADERS_LEN 512
|
||||
#define HTTP_BODY_LEN 1024
|
||||
|
||||
|
||||
/* Config */
|
||||
#define HTTP_RECV_BUF_LEN 1460
|
||||
#define HTTP_TX_BUF_LEN 1460
|
||||
|
||||
#define HTTPD_MAX_URLS 16
|
||||
#define HTTPD_MAX_CLIENTS 4
|
||||
|
||||
/* Constants for HTTP status codes */
|
||||
#define HTTP_STATUS_OK 200
|
||||
#define HTTP_STATUS_BAD_REQUEST 400
|
||||
#define HTTP_STATUS_NOT_FOUND 404
|
||||
#define HTTP_STATUS_TEAPOT 418
|
||||
#define HTTP_STATUS_TOO_MANY_REQUESTS 429
|
||||
#define HTTP_STATUS_INTERNAL_SERVER_ERROR 500
|
||||
#define HTTP_STATUS_SERVICE_UNAVAILABLE 503
|
||||
|
||||
struct httpd;
|
||||
|
||||
struct http_request {
|
||||
char method[HTTP_METHOD_LEN]; // "GET", "POST", etc.
|
||||
char path[HTTP_PATH_LEN]; // URL path
|
||||
char query[HTTP_QUERY_LEN]; // URL query string (for GET requests)
|
||||
char headers[HTTP_HEADERS_LEN]; // HTTP headers
|
||||
char body[HTTP_BODY_LEN]; // HTTP body (for POST requests)
|
||||
size_t body_len;
|
||||
};
|
||||
|
||||
struct http_client {
|
||||
struct httpd *httpd;
|
||||
int client_sd;
|
||||
struct ipstack_sockaddr_in addr;
|
||||
WOLFSSL *ssl; /* NULL if not using SSL */
|
||||
};
|
||||
|
||||
struct http_url {
|
||||
char path[HTTP_PATH_LEN];
|
||||
int (*handler)(struct httpd *httpd, struct http_client *hc, struct http_request *req);
|
||||
const char *static_content;
|
||||
};
|
||||
|
||||
struct httpd {
|
||||
struct http_url urls[HTTPD_MAX_URLS];
|
||||
struct http_client clients[HTTPD_MAX_CLIENTS];
|
||||
struct ipstack *ipstack;
|
||||
int listen_sd;
|
||||
uint16_t port;
|
||||
WOLFSSL_CTX *ssl_ctx;
|
||||
};
|
||||
|
||||
int httpd_init(struct httpd *httpd, struct ipstack *s, uint16_t port, void *ssl_ctx);
|
||||
int httpd_register_handler(struct httpd *httpd, const char *path, int (*handler)(struct httpd *httpd, struct http_client *hc, struct http_request *req));
|
||||
int httpd_register_static_page(struct httpd *httpd, const char *path, const char *content);
|
||||
int httpd_get_request_arg(struct http_request *req, const char *name, char *value, size_t value_len);
|
||||
void http_send_response_headers(struct http_client *hc, int status_code, const char *status_text, const char *content_type, size_t content_length);
|
||||
void http_send_response_body(struct http_client *hc, const void *body, size_t len);
|
||||
void http_send_response_chunk(struct http_client *hc, const void *chunk, size_t len);
|
||||
void http_send_response_chunk_end(struct http_client *hc);
|
||||
void http_send_200_OK(struct http_client *hc);
|
||||
void http_send_500_server_error(struct http_client *hc);
|
||||
void http_send_503_service_unavailable(struct http_client *hc);
|
||||
void http_send_418_teapot(struct http_client *hc);
|
||||
|
||||
int http_url_decode(char *buf, size_t len);
|
||||
int http_url_encode(char *buf, size_t len, size_t max_len);
|
||||
|
||||
|
||||
#endif
|
|
@ -25,7 +25,7 @@ void print_buffer(uint8_t *buf, int len)
|
|||
printf("\n");
|
||||
}
|
||||
|
||||
static int tap_poll(struct ll *ll, void *buf, uint32_t len)
|
||||
static int tap_poll(struct ll *ll, void *buf, int len)
|
||||
{
|
||||
struct pollfd pfd;
|
||||
(void)ll;
|
||||
|
@ -43,7 +43,7 @@ static int tap_poll(struct ll *ll, void *buf, uint32_t len)
|
|||
return read(tap_fd, buf, len);
|
||||
}
|
||||
|
||||
static int tap_send(struct ll *ll, void *buf, uint32_t len)
|
||||
static int tap_send(struct ll *ll, void *buf, int len)
|
||||
{
|
||||
(void)ll;
|
||||
//print_buffer(buf, len);
|
|
@ -1,574 +0,0 @@
|
|||
/* POSIX socket calls wrapper for femtoTCP */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdarg.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <dlfcn.h>
|
||||
#include <sys/time.h>
|
||||
#include <poll.h>
|
||||
#include <string.h>
|
||||
#define FEMTO_POSIX
|
||||
#include "config.h"
|
||||
#include "femtotcp.h"
|
||||
|
||||
static __thread int in_the_stack = 1;
|
||||
static struct ipstack *IPSTACK = NULL;
|
||||
pthread_mutex_t ipstack_mutex;
|
||||
|
||||
/* host_ functions are the original functions from the libc */
|
||||
static int (*host_socket ) (int domain, int type, int protocol) = NULL;
|
||||
static int (*host_bind ) (int sockfd, const struct sockaddr *addr, socklen_t addrlen);
|
||||
static int (*host_connect ) (int sockfd, const struct sockaddr *addr, socklen_t addrlen);
|
||||
static int (*host_accept ) (int sockfd, struct sockaddr *addr, socklen_t *addrlen);
|
||||
static int (*host_listen ) (int sockfd, int backlog);
|
||||
static ssize_t (*host_recvfrom) (int sockfd, void *buf, size_t len, int flags, struct sockaddr *addr, socklen_t *addrlen);
|
||||
static ssize_t (*host_recv ) (int sockfd, void *buf, size_t len, int flags);
|
||||
static ssize_t (*host_read ) (int sockfd, void *buf, size_t len);
|
||||
static ssize_t (*host_sendto ) (int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t addrlen);
|
||||
static ssize_t (*host_send ) (int sockfd, const void *buf, size_t len, int flags);
|
||||
static ssize_t (*host_write ) (int sockfd, const void *buf, size_t len);
|
||||
static int (*host_close ) (int sockfd);
|
||||
static int (*host_setsockopt) (int sockfd, int level, int optname, const void *optval, socklen_t optlen);
|
||||
static int (*host_getsockopt) (int sockfd, int level, int optname, void *optval, socklen_t *optlen);
|
||||
static int (*host_getsockname) (int sockfd, struct sockaddr *addr, socklen_t *addrlen);
|
||||
static int (*host_getpeername) (int sockfd, struct sockaddr *addr, socklen_t *addrlen);
|
||||
|
||||
static int (*host_poll) (struct pollfd *fds, nfds_t nfds, int timeout);
|
||||
static int (*host_select) (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
|
||||
static int (*host_fcntl) (int fd, int cmd, ...);
|
||||
|
||||
#define swap_socketcall(call, name) \
|
||||
{ \
|
||||
const char *msg; \
|
||||
if (host_##call == NULL) { \
|
||||
*(void **)(&host_##call) = dlsym(RTLD_NEXT, name); \
|
||||
if ((msg = dlerror()) != NULL) \
|
||||
fprintf (stderr, "%s: dlsym(%s): %s\n", "femtoTCP", name, msg); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
#define conditional_steal_call(call, fd, ...) \
|
||||
if(in_the_stack) { \
|
||||
return host_##call(fd, ## __VA_ARGS__); \
|
||||
} else { \
|
||||
pthread_mutex_lock(&ipstack_mutex); \
|
||||
if ((fd & (MARK_TCP_SOCKET | MARK_UDP_SOCKET)) != 0) { \
|
||||
int __femto_retval = ft_##call(IPSTACK, fd, ## __VA_ARGS__); \
|
||||
if (__femto_retval < 0) { \
|
||||
errno = __femto_retval; \
|
||||
pthread_mutex_unlock(&ipstack_mutex); \
|
||||
return -1; \
|
||||
} \
|
||||
pthread_mutex_unlock(&ipstack_mutex); \
|
||||
return __femto_retval; \
|
||||
}else { \
|
||||
pthread_mutex_unlock(&ipstack_mutex); \
|
||||
return host_##call(fd, ## __VA_ARGS__); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define conditional_steal_blocking_call(call, fd, ...) \
|
||||
if(in_the_stack) { \
|
||||
return host_##call(fd, ## __VA_ARGS__); \
|
||||
} else { \
|
||||
pthread_mutex_lock(&ipstack_mutex); \
|
||||
if ((fd & (MARK_TCP_SOCKET | MARK_UDP_SOCKET)) != 0) { \
|
||||
int __femto_retval; \
|
||||
do { \
|
||||
__femto_retval = ft_##call(IPSTACK, fd, ## __VA_ARGS__); \
|
||||
if (__femto_retval == -11) { \
|
||||
usleep(1000); \
|
||||
} \
|
||||
} while (__femto_retval == -11); \
|
||||
if (__femto_retval < 0) { \
|
||||
errno = __femto_retval; \
|
||||
pthread_mutex_unlock(&ipstack_mutex); \
|
||||
return -1; \
|
||||
} \
|
||||
pthread_mutex_unlock(&ipstack_mutex); \
|
||||
return __femto_retval; \
|
||||
}else { \
|
||||
pthread_mutex_unlock(&ipstack_mutex); \
|
||||
return host_##call(fd, ## __VA_ARGS__); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
int ft_setsockopt(struct ipstack *ipstack, int fd, int level, int optname, const void *optval, socklen_t optlen) {
|
||||
printf("Intercepted setsockopt\n");
|
||||
(void)ipstack;
|
||||
(void)fd;
|
||||
(void)level;
|
||||
(void)optname;
|
||||
(void)optval;
|
||||
(void)optlen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ft_getsockopt(struct ipstack *ipstack, int fd, int level, int optname, void *optval, socklen_t *optlen) {
|
||||
printf("Intercepted getsockopt\n");
|
||||
(void)ipstack;
|
||||
(void)fd;
|
||||
(void)level;
|
||||
(void)optname;
|
||||
(void)optval;
|
||||
(void)optlen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ft_fcntl(struct ipstack *ipstack, int fd, int cmd, int arg) {
|
||||
printf("Intercepted fcntl\n");
|
||||
(void)ipstack;
|
||||
(void)fd;
|
||||
(void)cmd;
|
||||
(void)arg;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fcntl(int fd, int cmd, ...) {
|
||||
va_list ap;
|
||||
int arg;
|
||||
va_start(ap, cmd);
|
||||
arg = va_arg(ap, int);
|
||||
va_end(ap);
|
||||
int ret;
|
||||
if (in_the_stack) {
|
||||
return host_fcntl(fd, cmd, arg);
|
||||
} else {
|
||||
pthread_mutex_lock(&ipstack_mutex);
|
||||
ret = ft_fcntl(IPSTACK, fd, cmd, arg);
|
||||
pthread_mutex_unlock(&ipstack_mutex);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct bsd_poll_helper {
|
||||
int fd; /* Original fd */
|
||||
int events; /* Original events */
|
||||
int pipefds[2]; /* Pipe for triggering events */
|
||||
};
|
||||
|
||||
/* Static arrays for poll helpers */
|
||||
static struct bsd_poll_helper tcp_pollers[MAX_TCPSOCKETS] = {{0}};
|
||||
static struct bsd_poll_helper udp_pollers[MAX_UDPSOCKETS] = {{0}};
|
||||
|
||||
void poller_callback(int fd, uint16_t event, void *arg)
|
||||
{
|
||||
struct bsd_poll_helper *poller;
|
||||
char c;
|
||||
(void)arg;
|
||||
if ((fd & MARK_TCP_SOCKET) != 0)
|
||||
poller = &tcp_pollers[fd & ~MARK_TCP_SOCKET];
|
||||
else if ((fd & MARK_UDP_SOCKET) != 0)
|
||||
poller = &udp_pollers[fd & ~MARK_UDP_SOCKET];
|
||||
else
|
||||
return;
|
||||
if (poller->fd != fd)
|
||||
return;
|
||||
if (event & CB_EVENT_READABLE)
|
||||
c = 'r';
|
||||
else if (event & CB_EVENT_WRITABLE)
|
||||
c = 'w';
|
||||
else if (event & CB_EVENT_CLOSED)
|
||||
c = 'h';
|
||||
else
|
||||
return;
|
||||
write(poller->pipefds[1], &c, 1);
|
||||
}
|
||||
|
||||
int ft_poll(struct ipstack *ipstack, struct pollfd *fds, nfds_t nfds, int timeout) {
|
||||
nfds_t i;
|
||||
int fd;
|
||||
int ret;
|
||||
int miss = 0;
|
||||
if (in_the_stack) {
|
||||
return host_poll(fds, nfds, timeout);
|
||||
}
|
||||
memset(tcp_pollers, 0, sizeof(tcp_pollers));
|
||||
memset(udp_pollers, 0, sizeof(udp_pollers));
|
||||
for (i = 0; i < nfds; i++) {
|
||||
struct bsd_poll_helper *poller = NULL;
|
||||
fd = fds[i].fd;
|
||||
|
||||
if ((fd & MARK_TCP_SOCKET) != 0)
|
||||
poller = &tcp_pollers[fd & ~MARK_TCP_SOCKET];
|
||||
else if ((fd & MARK_UDP_SOCKET) != 0)
|
||||
poller = &udp_pollers[fd & ~MARK_UDP_SOCKET];
|
||||
else
|
||||
continue;
|
||||
if (pipe(poller->pipefds) < 0) {
|
||||
perror("pipe");
|
||||
return -1;
|
||||
}
|
||||
poller->fd = fd;
|
||||
poller->events = fds[i].events;
|
||||
/* Replace the original fd with the read end of the pipe */
|
||||
fds[i].fd = poller->pipefds[0];
|
||||
fds[i].events = POLLIN;
|
||||
fds[i].revents = 0;
|
||||
/* Assign the callback */
|
||||
ipstack_register_callback(ipstack, fd, poller_callback, ipstack);
|
||||
}
|
||||
/* Call the original poll */
|
||||
repeat:
|
||||
miss = 0;
|
||||
pthread_mutex_unlock(&ipstack_mutex);
|
||||
ret = host_poll(fds, nfds, timeout);
|
||||
pthread_mutex_lock(&ipstack_mutex);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
for (i = 0; i < nfds; i++) {
|
||||
struct bsd_poll_helper *poller = NULL;
|
||||
int j;
|
||||
int fd = fds[i].fd;
|
||||
char c = 0;
|
||||
for (j = 0; j < MAX_TCPSOCKETS; j++) {
|
||||
if (tcp_pollers[j].fd == 0)
|
||||
continue;
|
||||
if (tcp_pollers[j].pipefds[0] == fd) {
|
||||
poller = &tcp_pollers[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!poller) {
|
||||
for (j = 0; j < MAX_UDPSOCKETS; j++) {
|
||||
if (udp_pollers[j].fd == 0)
|
||||
continue;
|
||||
if (udp_pollers[j].pipefds[0] == fd) {
|
||||
poller = &udp_pollers[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (poller) {
|
||||
if ((fds[i].revents & POLLIN) != 0) {
|
||||
fds[i].revents = 0;
|
||||
host_read(poller->pipefds[0], &c, 1);
|
||||
switch(c) {
|
||||
case 'r':
|
||||
fds[i].revents |= POLLIN;
|
||||
break;
|
||||
case 'w':
|
||||
fds[i].revents |= POLLOUT;
|
||||
break;
|
||||
case 'e':
|
||||
fds[i].revents |= POLLERR;
|
||||
break;
|
||||
case 'h':
|
||||
fds[i].revents |= POLLHUP;
|
||||
break;
|
||||
}
|
||||
if ((fds[i].revents != 0) && (fds[i].revents & (poller->events | POLLHUP | POLLERR)) == 0) {
|
||||
miss++;
|
||||
ret--;
|
||||
continue;
|
||||
}
|
||||
fds[i].revents &= (POLLHUP | POLLERR | poller->events);
|
||||
} else {
|
||||
fds[i].revents = 0;
|
||||
}
|
||||
fds[i].fd = poller->fd;
|
||||
fds[i].events = poller->events;
|
||||
host_close(poller->pipefds[0]);
|
||||
host_close(poller->pipefds[1]);
|
||||
poller->fd = 0;
|
||||
ipstack_register_callback(ipstack, poller->fd, NULL, NULL);
|
||||
}
|
||||
}
|
||||
if ((miss != 0) && (ret == 0))
|
||||
goto repeat;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ft_select(struct ipstack *ipstack, int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) {
|
||||
int i;
|
||||
int maxfd;
|
||||
int ret;
|
||||
fd_set readfds_local;
|
||||
/* Assume MARK_TCP_SOCKET < MARK_UDP_SOCKET */
|
||||
if (nfds < MARK_TCP_SOCKET + 1) {
|
||||
return host_select(nfds, readfds, writefds, exceptfds, timeout);
|
||||
}
|
||||
memset(tcp_pollers, 0, sizeof(tcp_pollers));
|
||||
memset(udp_pollers, 0, sizeof(udp_pollers));
|
||||
for (i = 0; (i < MARK_TCP_SOCKET) && (i < nfds); i++) {
|
||||
if ((readfds && FD_ISSET(i, readfds)) ||
|
||||
(writefds && FD_ISSET(i, writefds)) ||
|
||||
(exceptfds && FD_ISSET(i, exceptfds))) {
|
||||
maxfd = i;
|
||||
}
|
||||
}
|
||||
/* At this point, we do need a fd_set to read from pipes */
|
||||
if (!readfds) {
|
||||
FD_ZERO(&readfds_local);
|
||||
readfds = &readfds_local;
|
||||
}
|
||||
for (i = MARK_TCP_SOCKET; i < nfds && i < (MARK_TCP_SOCKET | MAX_TCPSOCKETS); i++) {
|
||||
int tcp_pos = i & (~MARK_TCP_SOCKET);
|
||||
if ((readfds && (FD_ISSET(i, readfds))) || (writefds && (FD_ISSET(i, writefds))) || (exceptfds && (FD_ISSET(i, exceptfds)))) {
|
||||
if (pipe(tcp_pollers[tcp_pos].pipefds) < 0)
|
||||
return -1;
|
||||
tcp_pollers[tcp_pos].fd = i;
|
||||
tcp_pollers[tcp_pos].events = 0;
|
||||
ipstack_register_callback(ipstack, i, poller_callback, ipstack);
|
||||
if (readfds && (FD_ISSET(i, readfds))) {
|
||||
tcp_pollers[tcp_pos].events |= POLLIN;
|
||||
FD_CLR(i, readfds);
|
||||
FD_SET(tcp_pollers[tcp_pos].pipefds[0], readfds);
|
||||
}
|
||||
if (writefds && (FD_ISSET(i, writefds))) {
|
||||
tcp_pollers[tcp_pos].events |= POLLOUT;
|
||||
FD_CLR(i, writefds);
|
||||
FD_SET(tcp_pollers[tcp_pos].pipefds[0], writefds);
|
||||
}
|
||||
if (exceptfds && (FD_ISSET(i, exceptfds))) {
|
||||
tcp_pollers[tcp_pos].events |= POLLERR | POLLHUP;
|
||||
FD_CLR(i, exceptfds);
|
||||
FD_SET(tcp_pollers[tcp_pos].pipefds[0], exceptfds);
|
||||
}
|
||||
if (maxfd < tcp_pollers[tcp_pos].pipefds[0]) {
|
||||
maxfd = tcp_pollers[tcp_pos].pipefds[0];
|
||||
}
|
||||
} else {
|
||||
}
|
||||
}
|
||||
for (i = MARK_UDP_SOCKET; i < nfds && i < (MARK_UDP_SOCKET | MAX_UDPSOCKETS); i++) {
|
||||
int udp_pos = i & (~MARK_UDP_SOCKET);
|
||||
if (FD_ISSET(i, readfds) || FD_ISSET(i, writefds) || FD_ISSET(i, exceptfds)) {
|
||||
pipe(udp_pollers[udp_pos].pipefds);
|
||||
udp_pollers[udp_pos].fd = i;
|
||||
udp_pollers[udp_pos].events = 0;
|
||||
ipstack_register_callback(ipstack, i, poller_callback, ipstack);
|
||||
if (readfds && FD_ISSET(i, readfds)) {
|
||||
udp_pollers[udp_pos].events |= POLLIN;
|
||||
FD_CLR(i, readfds);
|
||||
FD_SET(udp_pollers[udp_pos].pipefds[0], readfds);
|
||||
}
|
||||
if (writefds && FD_ISSET(i, writefds)) {
|
||||
udp_pollers[udp_pos].events |= POLLOUT;
|
||||
FD_CLR(i, writefds);
|
||||
FD_SET(udp_pollers[udp_pos].pipefds[0], writefds);
|
||||
}
|
||||
if (exceptfds && FD_ISSET(i, exceptfds)) {
|
||||
udp_pollers[udp_pos].events |= POLLERR | POLLHUP;
|
||||
FD_CLR(i, exceptfds);
|
||||
FD_SET(udp_pollers[udp_pos].pipefds[0], exceptfds);
|
||||
}
|
||||
if (maxfd < udp_pollers[udp_pos].pipefds[0]) {
|
||||
maxfd = udp_pollers[udp_pos].pipefds[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Call the original select */
|
||||
pthread_mutex_unlock(&ipstack_mutex);
|
||||
ret = host_select(maxfd + 1, readfds, writefds, exceptfds, timeout);
|
||||
pthread_mutex_lock(&ipstack_mutex);
|
||||
if (ret <= 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_TCPSOCKETS; i++) {
|
||||
if (tcp_pollers[i].fd == 0) {
|
||||
continue;
|
||||
}
|
||||
if (FD_ISSET(tcp_pollers[i].pipefds[0], readfds)) {
|
||||
char c;
|
||||
host_read(tcp_pollers[i].pipefds[0], &c, 1);
|
||||
if (readfds && (c == 'r')) {
|
||||
FD_SET(tcp_pollers[i].fd, readfds);
|
||||
} else if (writefds && (c == 'w')) {
|
||||
FD_SET(tcp_pollers[i].fd, writefds);
|
||||
} else if (exceptfds && (c == 'e')) {
|
||||
FD_SET(tcp_pollers[i].fd, exceptfds);
|
||||
}
|
||||
}
|
||||
ipstack_register_callback(ipstack, tcp_pollers[i].fd, NULL, NULL);
|
||||
host_close(tcp_pollers[i].pipefds[0]);
|
||||
host_close(tcp_pollers[i].pipefds[1]);
|
||||
tcp_pollers[i].fd = 0;
|
||||
}
|
||||
for (i = 0; i < MAX_UDPSOCKETS; i++) {
|
||||
if (udp_pollers[i].fd == 0) {
|
||||
continue;
|
||||
}
|
||||
if (FD_ISSET(udp_pollers[i].pipefds[0], readfds)) {
|
||||
char c;
|
||||
read(udp_pollers[i].pipefds[0], &c, 1);
|
||||
if (readfds && (c == 'r')) {
|
||||
FD_SET(udp_pollers[i].fd, readfds);
|
||||
} else if (writefds && (c == 'w')) {
|
||||
FD_SET(udp_pollers[i].fd, writefds);
|
||||
} else if (exceptfds && (c == 'e')) {
|
||||
FD_SET(udp_pollers[i].fd, exceptfds);
|
||||
}
|
||||
}
|
||||
host_close(udp_pollers[i].pipefds[0]);
|
||||
host_close(udp_pollers[i].pipefds[1]);
|
||||
ipstack_register_callback(ipstack, tcp_pollers[i].fd, NULL, NULL);
|
||||
udp_pollers[i].fd = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) {
|
||||
int ret;
|
||||
if (in_the_stack) {
|
||||
return host_select(nfds, readfds, writefds, exceptfds, timeout);
|
||||
} else {
|
||||
pthread_mutex_lock(&ipstack_mutex);
|
||||
ret = ft_select(IPSTACK, nfds, readfds, writefds, exceptfds, timeout);
|
||||
pthread_mutex_unlock(&ipstack_mutex);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
int socket(int domain, int type, int protocol) {
|
||||
if (in_the_stack) {
|
||||
return host_socket(domain, type, protocol);
|
||||
} else {
|
||||
return ft_socket(IPSTACK, domain, type, protocol);
|
||||
}
|
||||
}
|
||||
|
||||
int listen(int sockfd, int backlog) {
|
||||
conditional_steal_call(listen, sockfd, backlog);
|
||||
}
|
||||
|
||||
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
|
||||
conditional_steal_call(bind, sockfd, addr, addrlen);
|
||||
}
|
||||
|
||||
int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen) {
|
||||
conditional_steal_call(getsockopt, sockfd, level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
|
||||
conditional_steal_call(getpeername, sockfd, addr, addrlen);
|
||||
}
|
||||
|
||||
int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
|
||||
conditional_steal_call(getsockname, sockfd, addr, addrlen);
|
||||
}
|
||||
|
||||
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen) {
|
||||
conditional_steal_call(setsockopt, sockfd, level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
int close(int sockfd) {
|
||||
conditional_steal_call(close, sockfd);
|
||||
}
|
||||
|
||||
/* Blocking calls */
|
||||
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
|
||||
conditional_steal_blocking_call(accept, sockfd, addr, addrlen);
|
||||
}
|
||||
|
||||
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
|
||||
conditional_steal_blocking_call(connect, sockfd, addr, addrlen);
|
||||
}
|
||||
|
||||
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *addr, socklen_t *addrlen) {
|
||||
conditional_steal_blocking_call(recvfrom, sockfd, buf, len, flags, addr, addrlen);
|
||||
}
|
||||
|
||||
ssize_t recv(int sockfd, void *buf, size_t len, int flags) {
|
||||
conditional_steal_blocking_call(recv, sockfd, buf, len, flags);
|
||||
}
|
||||
|
||||
ssize_t read(int sockfd, void *buf, size_t len) {
|
||||
conditional_steal_blocking_call(read, sockfd, buf, len);
|
||||
}
|
||||
|
||||
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t addrlen) {
|
||||
conditional_steal_blocking_call(sendto, sockfd, buf, len, flags, addr, addrlen);
|
||||
}
|
||||
|
||||
ssize_t send(int sockfd, const void *buf, size_t len, int flags) {
|
||||
conditional_steal_blocking_call(send, sockfd, buf, len, flags);
|
||||
}
|
||||
|
||||
ssize_t write(int sockfd, const void *buf, size_t len) {
|
||||
conditional_steal_blocking_call(write, sockfd, buf, len);
|
||||
}
|
||||
|
||||
int poll(struct pollfd *fds, nfds_t nfds, int timeout) {
|
||||
int ret;
|
||||
if (in_the_stack) {
|
||||
return host_poll(fds, nfds, timeout);
|
||||
} else {
|
||||
pthread_mutex_lock(&ipstack_mutex);
|
||||
ret = ft_poll(IPSTACK, fds, nfds, timeout);
|
||||
pthread_mutex_unlock(&ipstack_mutex);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Catch-all function to initialize a new tap device as the network interface.
|
||||
* This is defined in port/linux.c
|
||||
* */
|
||||
extern int tap_init(struct ll *dev, const char *name, uint32_t host_ip);
|
||||
|
||||
void *ft_posix_ip_loop(void *arg) {
|
||||
struct ipstack *ipstack = (struct ipstack *)arg;
|
||||
uint32_t ms_next;
|
||||
struct timeval tv;
|
||||
while (1) {
|
||||
pthread_mutex_lock(&ipstack_mutex);
|
||||
gettimeofday(&tv, NULL);
|
||||
ms_next = ipstack_poll(ipstack, tv.tv_sec * 1000 + tv.tv_usec / 1000);
|
||||
pthread_mutex_unlock(&ipstack_mutex);
|
||||
usleep(ms_next * 1000);
|
||||
in_the_stack = 1;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void __attribute__((constructor)) init_femto_posix() {
|
||||
struct in_addr linux_ip;
|
||||
struct ll *tapdev;
|
||||
pthread_t ipstack_thread;
|
||||
if (IPSTACK)
|
||||
return;
|
||||
inet_aton(LINUX_IP, &linux_ip);
|
||||
swap_socketcall(socket, "socket");
|
||||
swap_socketcall(bind, "bind");
|
||||
swap_socketcall(listen, "listen");
|
||||
swap_socketcall(accept, "accept");
|
||||
swap_socketcall(connect, "connect");
|
||||
swap_socketcall(sendto, "sendto");
|
||||
swap_socketcall(recvfrom, "recvfrom");
|
||||
swap_socketcall(recv, "recv");
|
||||
swap_socketcall(send, "send");
|
||||
swap_socketcall(close, "close");
|
||||
swap_socketcall(write, "write");
|
||||
swap_socketcall(read, "read");
|
||||
swap_socketcall(getsockname, "getsockname");
|
||||
swap_socketcall(getpeername, "getpeername");
|
||||
swap_socketcall(setsockopt, "getaddrinfo");
|
||||
swap_socketcall(getsockopt, "freeaddrinfo");
|
||||
swap_socketcall(poll, "poll");
|
||||
swap_socketcall(select, "select");
|
||||
swap_socketcall(fcntl, "fcntl");
|
||||
|
||||
pthread_mutex_init(&ipstack_mutex, NULL);
|
||||
ipstack_init_static(&IPSTACK);
|
||||
tapdev = ipstack_getdev(IPSTACK);
|
||||
if (tap_init(tapdev, "femt0", linux_ip.s_addr) < 0) {
|
||||
perror("tap init");
|
||||
}
|
||||
ipstack_ipconfig_set(IPSTACK, atoip4(FEMTOTCP_IP), atoip4("255.255.255.0"),
|
||||
atoip4(LINUX_IP));
|
||||
printf("IP: manually configured - %s\n", FEMTOTCP_IP);
|
||||
sleep(1);
|
||||
pthread_create(&ipstack_thread, NULL, ft_posix_ip_loop, IPSTACK);
|
||||
in_the_stack = 0;
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
cmake_minimum_required(VERSION 3.17)
|
||||
|
||||
#include(${CMAKE_CURRENT_LIST_DIR}/../../../hw/bsp/family_support.cmake)
|
||||
include(${PICO_SDK_PATH}/lib/tinyusb/hw/bsp/family_support.cmake)
|
||||
|
||||
# gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
|
||||
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
|
||||
project(${PROJECT} C CXX ASM)
|
||||
|
||||
# Checks this example is valid for the family and initializes the project
|
||||
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
add_executable(${PROJECT})
|
||||
|
||||
# Example source
|
||||
target_sources(${PROJECT} PUBLIC
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/main.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/rand.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/motd.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb_descriptors.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../femtotcp.c
|
||||
)
|
||||
|
||||
# Example include
|
||||
target_include_directories(${PROJECT} PUBLIC
|
||||
${CMAKE_CURRENT_LIST_DIR}/src
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../..
|
||||
)
|
||||
|
||||
# lib/networking sources
|
||||
target_sources(${PROJECT} PUBLIC
|
||||
)
|
||||
|
||||
|
||||
# due to warnings from other net source, we need to prevent error from some of the warnings options
|
||||
if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
|
||||
target_compile_options(${PROJECT} PUBLIC
|
||||
-Wno-error=null-dereference
|
||||
-Wno-error=conversion
|
||||
-Wno-error=sign-conversion
|
||||
-Wno-error=sign-compare
|
||||
-Wno-error=cast-align
|
||||
)
|
||||
elseif (CMAKE_C_COMPILER_ID STREQUAL "IAR")
|
||||
|
||||
endif ()
|
||||
target_link_libraries(${PROJECT} PUBLIC hardware_adc)
|
||||
|
||||
# Configure compilation flags and libraries for the example without RTOS.
|
||||
# See the corresponding function in hw/bsp/FAMILY/family.cmake for details.
|
||||
family_configure_device_example(${PROJECT} noos)
|
File diff suppressed because it is too large
Load diff
|
@ -1,29 +0,0 @@
|
|||
## FemtoTCP demo on raspberry pi pico
|
||||
|
||||
### Instructions
|
||||
|
||||
- clone pico-sdk
|
||||
|
||||
`git clone https://github.com/raspberrypi/pico-sdk.git`
|
||||
|
||||
- run CMake from this directory, specitying the FAMILY and PICO_COMPILER variables. Also specify the path where you cloned the pico-sdk in the previous step.
|
||||
|
||||
cmake . -DPICO_SDK_PATH=/path/to/src/pico-sdk -DFAMILY=rp2040 -DPICO_COMPILER=arm-none-eabi-gcc
|
||||
|
||||
- run make
|
||||
|
||||
`make`
|
||||
|
||||
- copy the uf2 file to the pico
|
||||
|
||||
`cp raspberrypi-pico-usb-server.uf2 /media/$USER/RPI-RP2`
|
||||
|
||||
- Assign a static IP to the usb0 interface on the host machine
|
||||
|
||||
`sudo ip addr add usb0 192.168.7.1/24`
|
||||
|
||||
- Ping the pico board!
|
||||
|
||||
`ping 192.168.7.2`
|
||||
|
||||
|
|
@ -1 +0,0 @@
|
|||
FLASH(rx) : ORIGIN = 0x10000000, LENGTH = (2 * 1024 * 1024)
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(__ICCARM__)
|
||||
#pragma pack(1)
|
||||
#endif
|
|
@ -1,75 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
#ifndef __CC_H__
|
||||
#define __CC_H__
|
||||
|
||||
//#include "cpu.h"
|
||||
|
||||
typedef int sys_prot_t;
|
||||
|
||||
|
||||
|
||||
/* define compiler specific symbols */
|
||||
#if defined (__ICCARM__)
|
||||
|
||||
#define PACK_STRUCT_BEGIN
|
||||
#define PACK_STRUCT_STRUCT
|
||||
#define PACK_STRUCT_END
|
||||
#define PACK_STRUCT_FIELD(x) x
|
||||
#define PACK_STRUCT_USE_INCLUDES
|
||||
|
||||
#elif defined (__CC_ARM)
|
||||
|
||||
#define PACK_STRUCT_BEGIN __packed
|
||||
#define PACK_STRUCT_STRUCT
|
||||
#define PACK_STRUCT_END
|
||||
#define PACK_STRUCT_FIELD(x) x
|
||||
|
||||
#elif defined (__GNUC__)
|
||||
|
||||
#define PACK_STRUCT_BEGIN
|
||||
#define PACK_STRUCT_STRUCT __attribute__ ((__packed__))
|
||||
#define PACK_STRUCT_END
|
||||
#define PACK_STRUCT_FIELD(x) x
|
||||
|
||||
#elif defined (__TASKING__)
|
||||
|
||||
#define PACK_STRUCT_BEGIN
|
||||
#define PACK_STRUCT_STRUCT
|
||||
#define PACK_STRUCT_END
|
||||
#define PACK_STRUCT_FIELD(x) x
|
||||
|
||||
#endif
|
||||
|
||||
#define LWIP_PLATFORM_ASSERT(x) do { if(!(x)) while(1); } while(0)
|
||||
|
||||
#endif /* __CC_H__ */
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(__ICCARM__)
|
||||
#pragma pack()
|
||||
#endif
|
|
@ -1,267 +0,0 @@
|
|||
/* FemtoTCP: Raspberry-pi pico port + example
|
||||
*
|
||||
* This file is part of femtoTCP
|
||||
* (c) 2024 Daniele Lacamera <root@danielinux.net>
|
||||
*
|
||||
* FemtoTCP 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.
|
||||
*
|
||||
* FemtoTCP 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*
|
||||
* *****
|
||||
*
|
||||
* Based on LwIP drivers for TinyUSB,
|
||||
* Copyright (c) 2020 Peter Lawrence (MIT Licensed),
|
||||
* which was also influenced by lrndis https://github.com/fetisov/lrndis
|
||||
|
||||
This appears as either a RNDIS or CDC-ECM USB virtual network adapter; the OS picks its preference
|
||||
|
||||
RNDIS should be valid on Linux and Windows hosts, and CDC-ECM should be valid on Linux and macOS hosts
|
||||
|
||||
The MCU appears to the host as IP address 192.168.7.1.
|
||||
|
||||
Some smartphones *may* work with this implementation as well, but likely have limited (broken) drivers,
|
||||
and likely their manufacturer has not tested such functionality. Some code workarounds could be tried:
|
||||
|
||||
The smartphone may only have an ECM driver, but refuse to automatically pick ECM (unlike the OSes above);
|
||||
try modifying usb_descriptors.c so that CONFIG_ID_ECM is default.
|
||||
|
||||
The smartphone may be artificially picky about which Ethernet MAC address to recognize; if this happens,
|
||||
try changing the first byte of tud_network_mac_address[] below from 0x02 to 0x00 (clearing bit 1).
|
||||
*/
|
||||
|
||||
#include "bsp/board_api.h"
|
||||
#include "tusb.h"
|
||||
#include "config.h"
|
||||
#include "femtotcp.h"
|
||||
|
||||
extern char MOTD[];
|
||||
|
||||
/* Our globals */
|
||||
static struct ipstack *IPStack = NULL;
|
||||
|
||||
/* Two static buffers for RX frames from USB host */
|
||||
uint8_t tusb_net_rxbuf[LINK_MTU][2];
|
||||
uint8_t tusb_net_rxbuf_used[2] = {0, 0};
|
||||
|
||||
/* Two static buffers for TX frames to USB host */
|
||||
uint8_t tusb_net_txbuf[LINK_MTU][2];
|
||||
uint16_t tusb_net_txbuf_sz[2] = {0, 0};
|
||||
|
||||
/* Fixed mac-address for the raspberry side of the link.
|
||||
* it is suggested that the first byte is 0x02 to indicate a link-local address
|
||||
*/
|
||||
uint8_t tud_network_mac_address[6] = {0x02, 0x02, 0x84, 0x6A, 0x96, 0x00};
|
||||
|
||||
/* ipstack_getrandom is a frontend to the ADC-based random number generator.
|
||||
* See rand.c for more details.
|
||||
*/
|
||||
extern int custom_random_seed(unsigned char *seed, unsigned int size);
|
||||
uint32_t ipstack_getrandom(void)
|
||||
{
|
||||
uint32_t seed;
|
||||
custom_random_seed((unsigned char *)&seed, 4);
|
||||
return seed;
|
||||
}
|
||||
|
||||
/* ll_usb_send is the function that sends a frame to the USB host.
|
||||
* It is called by the femtoTCP stack when a frame is ready to be sent.
|
||||
* It will return the number of bytes sent, or 0 if the USB host is not ready.
|
||||
*/
|
||||
static int ll_usb_send(struct ll *dev, void *frame, uint32_t sz) {
|
||||
uint16_t sz16 = (uint16_t)sz;
|
||||
uint32_t i;
|
||||
(void) dev;
|
||||
board_led_on();
|
||||
for (;;) {
|
||||
if (!tud_ready()) {
|
||||
return 0;
|
||||
}
|
||||
if (tud_network_can_xmit(sz16)) {
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (tusb_net_txbuf_sz[i] == 0) {
|
||||
memcpy(tusb_net_txbuf[i], frame, sz16);
|
||||
tusb_net_txbuf_sz[i] = sz16;
|
||||
tud_network_xmit(tusb_net_txbuf[i], tusb_net_txbuf_sz[i]);
|
||||
board_led_on();
|
||||
return (int)sz16;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/* transfer execution to TinyUSB in the hopes that it will finish transmitting the prior packet */
|
||||
tud_task();
|
||||
}
|
||||
}
|
||||
|
||||
/* This is the callback that TinyUSB calls when it is ready to send a frame.
|
||||
* This is where the write operation is finalized.
|
||||
*/
|
||||
uint16_t tud_network_xmit_cb(uint8_t *dst, void *ref, uint16_t arg) {
|
||||
uint16_t ret = arg;
|
||||
(void) ref;
|
||||
(void) arg;
|
||||
memcpy(dst, ref, arg);
|
||||
if (ref == tusb_net_rxbuf[0])
|
||||
tusb_net_txbuf_sz[0] = 0;
|
||||
else if (ref == tusb_net_txbuf[1])
|
||||
tusb_net_txbuf_sz[1] = 0;
|
||||
board_led_off();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* This is the callback that TinyUSB calls when it is ready to receive a frame.
|
||||
* This is where the read operation is initiated, the frame is copied to the
|
||||
* static buffer, and the buffer is marked as used.
|
||||
*/
|
||||
|
||||
static void tusb_net_push_rx(const uint8_t *src, uint16_t size) {
|
||||
uint8_t *dst = NULL;
|
||||
int i;
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (!tusb_net_rxbuf_used[i]) {
|
||||
dst = tusb_net_rxbuf[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (dst) {
|
||||
memcpy(dst, src, size);
|
||||
tusb_net_rxbuf_used[i] = 1;
|
||||
board_led_on();
|
||||
}
|
||||
}
|
||||
|
||||
bool tud_network_recv_cb(const uint8_t *src, uint16_t size) {
|
||||
tusb_net_push_rx(src, size);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* This is the poll function of the femtoTCP device driver.
|
||||
* It is called by the femtoTCP stack when it is ready to receive a frame.
|
||||
* It will return the number of bytes received, or 0 if no frame is available.
|
||||
*
|
||||
* Frames copied in tusb_net_push_rx are processed here and sent to the stack.
|
||||
*/
|
||||
int ll_usb_poll(struct ll *dev, void *frame, uint32_t sz) {
|
||||
int i;
|
||||
(void) dev;
|
||||
if (sz < 64)
|
||||
return 0;
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (tusb_net_rxbuf_used[i]) {
|
||||
memcpy(frame, tusb_net_rxbuf[i], sz);
|
||||
tusb_net_rxbuf_used[i] = 0;
|
||||
board_led_off();
|
||||
return (int)sz;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tud_network_init_cb(void)
|
||||
{
|
||||
}
|
||||
|
||||
/* Telnet server (telnetd) initialization */
|
||||
static int tel_s = -1;
|
||||
static int tel_c = -1;
|
||||
|
||||
static void telnet_cb(int fd, uint16_t event, void *arg)
|
||||
{
|
||||
struct ipstack_sockaddr_in addr;
|
||||
uint32_t socklen = sizeof(addr);
|
||||
(void)arg;
|
||||
if ((fd == tel_s) && (event & CB_EVENT_READABLE) && (tel_c == -1)) {
|
||||
char ipaddr[16];
|
||||
char welcome_msg[32];
|
||||
tel_c = ft_accept(IPStack, tel_s, (struct ipstack_sockaddr*)&addr, &socklen);
|
||||
if (tel_c > 0) {
|
||||
iptoa(ee32(addr.sin_addr.s_addr), ipaddr);
|
||||
snprintf(welcome_msg, sizeof(welcome_msg), "Welcome %s!\n", ipaddr);
|
||||
ft_write(IPStack, tel_c, MOTD, strlen(MOTD));
|
||||
ft_write(IPStack, tel_c, welcome_msg, strlen(welcome_msg));
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
else if ((fd == tel_c) && (event & CB_EVENT_READABLE )) {
|
||||
int ret;
|
||||
ret = ft_recv((struct ipstack *)arg, tel_c, buf, sizeof(buf), 0);
|
||||
if (ret != -11) {
|
||||
if (ret < 0) {
|
||||
printf("Recv error: %d\n", ret);
|
||||
ft_close((struct ipstack *)arg, tel_c);
|
||||
} else if (ret == 0) {
|
||||
printf("Client side closed the connection.\n");
|
||||
ft_close((struct ipstack *)arg, tel_c);
|
||||
printf("Server: Exiting.\n");
|
||||
exit_ok = 1;
|
||||
} else if (ret > 0) {
|
||||
printf("recv: %d, echoing back\n", ret);
|
||||
tot_recv += ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void telnetd_init(void)
|
||||
{
|
||||
struct ipstack_sockaddr_in addr;
|
||||
if (tel_s < 0)
|
||||
tel_s = ft_socket(IPStack, AF_INET, IPSTACK_SOCK_STREAM, 0);
|
||||
ipstack_register_callback(IPStack, tel_s, telnet_cb, NULL);
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = ee16(23);
|
||||
addr.sin_addr.s_addr = 0;
|
||||
|
||||
ft_bind(IPStack, tel_s, (struct ipstack_sockaddr *)&addr, sizeof(addr));
|
||||
ft_listen(IPStack, tel_s, 1);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct ll *tusb_netdev;
|
||||
/* initialize TinyUSB */
|
||||
board_init();
|
||||
|
||||
// init device stack on configured roothub port
|
||||
tud_init(BOARD_TUD_RHPORT);
|
||||
|
||||
if (board_init_after_tusb) {
|
||||
board_init_after_tusb();
|
||||
}
|
||||
|
||||
board_led_on();
|
||||
|
||||
ipstack_init_static(&IPStack);
|
||||
tusb_netdev = ipstack_getdev(IPStack);
|
||||
memcpy(tusb_netdev->mac, tud_network_mac_address, 6);
|
||||
strcpy(tusb_netdev->ifname, "tusb");
|
||||
tusb_netdev->poll = ll_usb_poll;
|
||||
tusb_netdev->send = ll_usb_send;
|
||||
|
||||
/* set the IP address, netmask, and gateway */
|
||||
/* 192.168.7.2/24, gateway 192.168.7.1 */
|
||||
ipstack_ipconfig_set(IPStack, atoip4("192.168.7.2"),
|
||||
atoip4("255.255.255.0"), atoip4("192.168.7.1"));
|
||||
|
||||
telnetd_init();
|
||||
|
||||
board_led_off();
|
||||
while (1) {
|
||||
tud_task();
|
||||
ipstack_poll(IPStack, board_millis());
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
const char MOTD[] =
|
||||
" \n"
|
||||
" /\\_/\\ \n"
|
||||
" ( o.o )\n"
|
||||
" > ^ < ⭐️ ⭐️ ⭐️ \n"
|
||||
" \n"
|
||||
" 🟪🟪🟪🟪 ⭐️ ⭐️ 🟪 🟪🟪🟪🟪🟪 🟪🟪🟪 🟪🟪🟪 \n"
|
||||
"⭐️🟪 🟪🟪 🟪🟪🟪🟪🟪🟪 🟪🟪🟪🟪 🟪🟪 🟪 🟪 🟪 🟪 \n"
|
||||
" 🟪🟪🟪 🟪🟪🟪🟪 🟪 🟪 🟪 🟪 🟪 🟪 🟪 ⭐️ 🟪 🟪🟪🟪 \n"
|
||||
" 🟪 🟪 🟪 🟪 🟪 🟪 🟪 🟪 🟪 🟪 🟪 ⭐️ \n"
|
||||
" 🟪 🟪🟪🟪 🟪 🟪 🟪 🟪🟪 🟪🟪 🟪 🟪🟪🟪 🟪 \n"
|
||||
" ⭐️ by Danielinux \n"
|
||||
"Best viewed in (80 x 30)\n";
|
|
@ -1,74 +0,0 @@
|
|||
/*
|
||||
* (c) 2023 Daniele Lacamera <root@danielinux.net>
|
||||
*
|
||||
*
|
||||
* FemtoTCP 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.
|
||||
*
|
||||
* FemtoTCP 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*
|
||||
*/
|
||||
#include "pico/stdlib.h"
|
||||
#include "hardware/gpio.h"
|
||||
#include "hardware/adc.h"
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#define IN3_PIN 29
|
||||
#define IN0_PIN 28
|
||||
#define IN1_PIN 27
|
||||
#define IN2_PIN 26
|
||||
|
||||
const uint32_t IN[4] = {IN0_PIN, IN1_PIN, IN2_PIN, IN3_PIN};
|
||||
static int adc_initialized = 0;
|
||||
|
||||
const int in_a[8] = { 0, 1, 2, 3, 1, 3, 0, 2 };
|
||||
|
||||
int custom_random_seed(unsigned char *output, unsigned int sz) {
|
||||
uint32_t i;
|
||||
uint32_t result = 0;
|
||||
uint32_t rd = 0, wsz;
|
||||
|
||||
if (!adc_initialized) {
|
||||
adc_init();
|
||||
for (i = 0; i < 4; i++) {
|
||||
adc_gpio_init(IN[i]);
|
||||
}
|
||||
adc_initialized = 1;
|
||||
sleep_ms(10);
|
||||
}
|
||||
|
||||
/* Perform eight 3-bit samples with sources 0-1-2-4 */
|
||||
for (i = 0; rd < sz; i = (i + 1) % 8) {
|
||||
adc_select_input(in_a[i]);
|
||||
|
||||
/* Read the least significant 3 bits from the ADC */
|
||||
result = (result << 3) | (adc_read() & 0x00000007);
|
||||
|
||||
/* Introduce a delay to capture environmental noise */
|
||||
sleep_ms(1);
|
||||
|
||||
/* If we've completed eight samples, copy the result to the output */
|
||||
if (i == 7) {
|
||||
wsz = 3;
|
||||
if (wsz > (sz - rd)) {
|
||||
wsz = sz - rd;
|
||||
}
|
||||
|
||||
memcpy(output + rd, &result, wsz);
|
||||
rd += wsz;
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,137 +0,0 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _TUSB_CONFIG_H_
|
||||
#define _TUSB_CONFIG_H_
|
||||
|
||||
#include "config.h"
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Board Specific Configuration
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// RHPort number used for device can be defined by board.mk, default to port 0
|
||||
#ifndef BOARD_TUD_RHPORT
|
||||
#define BOARD_TUD_RHPORT 0
|
||||
#endif
|
||||
|
||||
// RHPort max operational speed can defined by board.mk
|
||||
#ifndef BOARD_TUD_MAX_SPEED
|
||||
#define BOARD_TUD_MAX_SPEED OPT_MODE_DEFAULT_SPEED
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Common Configuration
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
// defined by compiler flags for flexibility
|
||||
#ifndef CFG_TUSB_MCU
|
||||
#error CFG_TUSB_MCU must be defined
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_OS
|
||||
#define CFG_TUSB_OS OPT_OS_NONE
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_DEBUG
|
||||
#define CFG_TUSB_DEBUG 0
|
||||
#endif
|
||||
|
||||
// Enable Device stack
|
||||
#define CFG_TUD_ENABLED 1
|
||||
|
||||
// Default is max speed that hardware controller could support with on-chip PHY
|
||||
#define CFG_TUD_MAX_SPEED BOARD_TUD_MAX_SPEED
|
||||
|
||||
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
|
||||
* Tinyusb use follows macros to declare transferring memory so that they can be put
|
||||
* into those specific section.
|
||||
* e.g
|
||||
* - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
|
||||
* - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
|
||||
*/
|
||||
#ifndef CFG_TUSB_MEM_SECTION
|
||||
#define CFG_TUSB_MEM_SECTION
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_MEM_ALIGN
|
||||
#define CFG_TUSB_MEM_ALIGN __attribute__((aligned(4)))
|
||||
#endif
|
||||
|
||||
// Use different configurations to test all net devices (also due to resource limitations)
|
||||
#if TU_CHECK_MCU(OPT_MCU_LPC15XX, OPT_MCU_LPC40XX, OPT_MCU_LPC51UXX, OPT_MCU_LPC54)
|
||||
#define USE_ECM 1
|
||||
#elif TU_CHECK_MCU(OPT_MCU_SAMD21, OPT_MCU_SAML21, OPT_MCU_SAML22)
|
||||
#define USE_ECM 1
|
||||
#elif TU_CHECK_MCU(OPT_MCU_STM32F0, OPT_MCU_STM32F1)
|
||||
#define USE_ECM 1
|
||||
#else
|
||||
#define USE_ECM 0
|
||||
#define INCLUDE_IPERF
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// NCM CLASS CONFIGURATION, SEE "ncm.h" FOR PERFORMANCE TUNING
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
// Must be >> MTU
|
||||
// Can be set to 2048 without impact
|
||||
#define CFG_TUD_NCM_IN_NTB_MAX_SIZE (2 * LINK_MTU)
|
||||
|
||||
// Must be >> MTU
|
||||
// Can be set to smaller values if wNtbOutMaxDatagrams==1
|
||||
#define CFG_TUD_NCM_OUT_NTB_MAX_SIZE (2 * LINK_MTU)
|
||||
|
||||
// Number of NCM transfer blocks for reception side
|
||||
#ifndef CFG_TUD_NCM_OUT_NTB_N
|
||||
#define CFG_TUD_NCM_OUT_NTB_N 1
|
||||
#endif
|
||||
|
||||
// Number of NCM transfer blocks for transmission side
|
||||
#ifndef CFG_TUD_NCM_IN_NTB_N
|
||||
#define CFG_TUD_NCM_IN_NTB_N 1
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// DEVICE CONFIGURATION
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
#ifndef CFG_TUD_ENDPOINT0_SIZE
|
||||
#define CFG_TUD_ENDPOINT0_SIZE 64
|
||||
#endif
|
||||
|
||||
//------------- CLASS -------------//
|
||||
|
||||
// Network class has 2 drivers: ECM/RNDIS and NCM.
|
||||
// Only one of the drivers can be enabled
|
||||
#define CFG_TUD_ECM_RNDIS USE_ECM
|
||||
#define CFG_TUD_NCM (1 - CFG_TUD_ECM_RNDIS)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_CONFIG_H_ */
|
|
@ -1,250 +0,0 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "bsp/board_api.h"
|
||||
#include "tusb.h"
|
||||
|
||||
/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
|
||||
* Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
|
||||
*
|
||||
* Auto ProductID layout's Bitmap:
|
||||
* [MSB] NET | VENDOR | MIDI | HID | MSC | CDC [LSB]
|
||||
*/
|
||||
#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) )
|
||||
#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
|
||||
_PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) | _PID_MAP(ECM_RNDIS, 5) | _PID_MAP(NCM, 5) )
|
||||
|
||||
// String Descriptor Index
|
||||
enum
|
||||
{
|
||||
STRID_LANGID = 0,
|
||||
STRID_MANUFACTURER,
|
||||
STRID_PRODUCT,
|
||||
STRID_SERIAL,
|
||||
STRID_INTERFACE,
|
||||
STRID_MAC
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ITF_NUM_CDC = 0,
|
||||
ITF_NUM_CDC_DATA,
|
||||
ITF_NUM_TOTAL
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
#if CFG_TUD_ECM_RNDIS
|
||||
CONFIG_ID_RNDIS = 0,
|
||||
CONFIG_ID_ECM = 1,
|
||||
#else
|
||||
CONFIG_ID_NCM = 0,
|
||||
#endif
|
||||
CONFIG_ID_COUNT
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Device Descriptors
|
||||
//--------------------------------------------------------------------+
|
||||
tusb_desc_device_t const desc_device =
|
||||
{
|
||||
.bLength = sizeof(tusb_desc_device_t),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||
.bcdUSB = 0x0200,
|
||||
|
||||
// Use Interface Association Descriptor (IAD) device class
|
||||
.bDeviceClass = TUSB_CLASS_MISC,
|
||||
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
|
||||
.idVendor = 0xCafe,
|
||||
.idProduct = USB_PID,
|
||||
.bcdDevice = 0x0101,
|
||||
|
||||
.iManufacturer = STRID_MANUFACTURER,
|
||||
.iProduct = STRID_PRODUCT,
|
||||
.iSerialNumber = STRID_SERIAL,
|
||||
|
||||
.bNumConfigurations = CONFIG_ID_COUNT // multiple configurations
|
||||
};
|
||||
|
||||
// Invoked when received GET DEVICE DESCRIPTOR
|
||||
// Application return pointer to descriptor
|
||||
uint8_t const * tud_descriptor_device_cb(void)
|
||||
{
|
||||
return (uint8_t const *) &desc_device;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Configuration Descriptor
|
||||
//--------------------------------------------------------------------+
|
||||
#define MAIN_CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_RNDIS_DESC_LEN)
|
||||
#define ALT_CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_ECM_DESC_LEN)
|
||||
#define NCM_CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_NCM_DESC_LEN)
|
||||
|
||||
#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX
|
||||
// LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
|
||||
// 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ...
|
||||
#define EPNUM_NET_NOTIF 0x81
|
||||
#define EPNUM_NET_OUT 0x02
|
||||
#define EPNUM_NET_IN 0x82
|
||||
|
||||
#elif CFG_TUSB_MCU == OPT_MCU_SAMG || CFG_TUSB_MCU == OPT_MCU_SAMX7X
|
||||
// SAMG & SAME70 don't support a same endpoint number with different direction IN and OUT
|
||||
// e.g EP1 OUT & EP1 IN cannot exist together
|
||||
#define EPNUM_NET_NOTIF 0x81
|
||||
#define EPNUM_NET_OUT 0x02
|
||||
#define EPNUM_NET_IN 0x83
|
||||
|
||||
#else
|
||||
#define EPNUM_NET_NOTIF 0x81
|
||||
#define EPNUM_NET_OUT 0x02
|
||||
#define EPNUM_NET_IN 0x82
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_ECM_RNDIS
|
||||
|
||||
static uint8_t const rndis_configuration[] =
|
||||
{
|
||||
// Config number (index+1), interface count, string index, total length, attribute, power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(CONFIG_ID_RNDIS+1, ITF_NUM_TOTAL, 0, MAIN_CONFIG_TOTAL_LEN, 0, 100),
|
||||
|
||||
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
|
||||
TUD_RNDIS_DESCRIPTOR(ITF_NUM_CDC, STRID_INTERFACE, EPNUM_NET_NOTIF, 8, EPNUM_NET_OUT, EPNUM_NET_IN, CFG_TUD_NET_ENDPOINT_SIZE),
|
||||
};
|
||||
|
||||
static uint8_t const ecm_configuration[] =
|
||||
{
|
||||
// Config number (index+1), interface count, string index, total length, attribute, power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(CONFIG_ID_ECM+1, ITF_NUM_TOTAL, 0, ALT_CONFIG_TOTAL_LEN, 0, 100),
|
||||
|
||||
// Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), and size, max segment size.
|
||||
TUD_CDC_ECM_DESCRIPTOR(ITF_NUM_CDC, STRID_INTERFACE, STRID_MAC, EPNUM_NET_NOTIF, 64, EPNUM_NET_OUT, EPNUM_NET_IN, CFG_TUD_NET_ENDPOINT_SIZE, CFG_TUD_NET_MTU),
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
static uint8_t const ncm_configuration[] =
|
||||
{
|
||||
// Config number (index+1), interface count, string index, total length, attribute, power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(CONFIG_ID_NCM+1, ITF_NUM_TOTAL, 0, NCM_CONFIG_TOTAL_LEN, 0, 100),
|
||||
|
||||
// Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), and size, max segment size.
|
||||
TUD_CDC_NCM_DESCRIPTOR(ITF_NUM_CDC, STRID_INTERFACE, STRID_MAC, EPNUM_NET_NOTIF, 64, EPNUM_NET_OUT, EPNUM_NET_IN, CFG_TUD_NET_ENDPOINT_SIZE, CFG_TUD_NET_MTU),
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
// Configuration array: RNDIS and CDC-ECM
|
||||
// - Windows only works with RNDIS
|
||||
// - MacOS only works with CDC-ECM
|
||||
// - Linux will work on both
|
||||
static uint8_t const * const configuration_arr[2] =
|
||||
{
|
||||
#if CFG_TUD_ECM_RNDIS
|
||||
[CONFIG_ID_RNDIS] = rndis_configuration,
|
||||
[CONFIG_ID_ECM ] = ecm_configuration
|
||||
#else
|
||||
[CONFIG_ID_NCM ] = ncm_configuration
|
||||
#endif
|
||||
};
|
||||
|
||||
// Invoked when received GET CONFIGURATION DESCRIPTOR
|
||||
// Application return pointer to descriptor
|
||||
// Descriptor contents must exist long enough for transfer to complete
|
||||
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
|
||||
{
|
||||
return (index < CONFIG_ID_COUNT) ? configuration_arr[index] : NULL;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// String Descriptors
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// array of pointer to string descriptors
|
||||
static char const* string_desc_arr [] =
|
||||
{
|
||||
[STRID_LANGID] = (const char[]) { 0x09, 0x04 }, // supported language is English (0x0409)
|
||||
[STRID_MANUFACTURER] = "TinyUSB", // Manufacturer
|
||||
[STRID_PRODUCT] = "TinyUSB Device", // Product
|
||||
[STRID_SERIAL] = NULL, // Serials will use unique ID if possible
|
||||
[STRID_INTERFACE] = "TinyUSB Network Interface" // Interface Description
|
||||
|
||||
// STRID_MAC index is handled separately
|
||||
};
|
||||
|
||||
static uint16_t _desc_str[32 + 1];
|
||||
|
||||
// Invoked when received GET STRING DESCRIPTOR request
|
||||
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
|
||||
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
|
||||
(void) langid;
|
||||
unsigned int chr_count = 0;
|
||||
|
||||
switch ( index ) {
|
||||
case STRID_LANGID:
|
||||
memcpy(&_desc_str[1], string_desc_arr[0], 2);
|
||||
chr_count = 1;
|
||||
break;
|
||||
|
||||
case STRID_SERIAL:
|
||||
chr_count = board_usb_get_serial(_desc_str + 1, 32);
|
||||
break;
|
||||
|
||||
case STRID_MAC:
|
||||
// Convert MAC address into UTF-16
|
||||
for (unsigned i=0; i<sizeof(tud_network_mac_address); i++) {
|
||||
_desc_str[1+chr_count++] = "0123456789ABCDEF"[(tud_network_mac_address[i] >> 4) & 0xf];
|
||||
_desc_str[1+chr_count++] = "0123456789ABCDEF"[(tud_network_mac_address[i] >> 0) & 0xf];
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
|
||||
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
|
||||
|
||||
if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL;
|
||||
|
||||
const char *str = string_desc_arr[index];
|
||||
|
||||
// Cap at max char
|
||||
chr_count = strlen(str);
|
||||
size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type
|
||||
if ( chr_count > max_count ) chr_count = max_count;
|
||||
|
||||
// Convert ASCII string into UTF-16
|
||||
for ( size_t i = 0; i < chr_count; i++ ) {
|
||||
_desc_str[1 + i] = str[i];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// first byte is length (including header), second byte is string type
|
||||
_desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8 ) | (2*chr_count + 2));
|
||||
|
||||
return _desc_str;
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
#include "femtotcp.h"
|
||||
#include <wolfssl/wolfcrypt/settings.h>
|
||||
#include <wolfssl/ssl.h>
|
||||
|
||||
static struct ipstack *ref_ipstack = NULL;
|
||||
|
||||
static int ipstack_io_recv(WOLFSSL* ssl, char* buf, int sz, void* ctx)
|
||||
{
|
||||
int ret = 0;
|
||||
int fd = (intptr_t)ctx;
|
||||
(void)ssl;
|
||||
if (!ref_ipstack)
|
||||
return -1;
|
||||
ret = ft_recv(ref_ipstack, fd, buf, sz, 0);
|
||||
if (ret == -11)
|
||||
return WOLFSSL_CBIO_ERR_WANT_READ;
|
||||
else if (ret <= 0)
|
||||
return WOLFSSL_CBIO_ERR_CONN_CLOSE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ipstack_io_send(WOLFSSL* ssl, char* buf, int sz, void* ctx)
|
||||
{
|
||||
int ret = 0;
|
||||
int fd = (intptr_t)ctx;
|
||||
(void)ssl;
|
||||
if (!ref_ipstack)
|
||||
return -1;
|
||||
ret = ft_send(ref_ipstack, fd, buf, sz, 0);
|
||||
if (ret == -11)
|
||||
return WOLFSSL_CBIO_ERR_WANT_WRITE;
|
||||
else if (ret <= 0)
|
||||
return WOLFSSL_CBIO_ERR_CONN_CLOSE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wolfSSL_SetIO_FT_CTX(WOLFSSL_CTX* ctx, struct ipstack *s)
|
||||
{
|
||||
wolfSSL_SetIORecv(ctx, ipstack_io_recv);
|
||||
wolfSSL_SetIOSend(ctx, ipstack_io_send);
|
||||
ref_ipstack = s;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wolfSSL_SetIO_FT(WOLFSSL* ssl, int fd)
|
||||
{
|
||||
wolfSSL_SetIOReadCtx(ssl, (void*)(intptr_t)fd);
|
||||
wolfSSL_SetIOWriteCtx(ssl, (void*)(intptr_t)fd);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#define PORT 8
|
||||
#define BUFFER_SIZE 1024
|
||||
|
||||
int main() {
|
||||
int server_fd, client_fd;
|
||||
struct sockaddr_in address;
|
||||
int addrlen = sizeof(address);
|
||||
char buffer[BUFFER_SIZE];
|
||||
|
||||
// Create a socket
|
||||
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
|
||||
perror("Socket failed");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
printf("Socket created: %d\n", server_fd);
|
||||
|
||||
// Bind to the specified port
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_addr.s_addr = INADDR_ANY;
|
||||
address.sin_port = htons(PORT);
|
||||
|
||||
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
|
||||
perror("Bind failed");
|
||||
close(server_fd);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
printf("Bind successful\n");
|
||||
|
||||
// Start listening for incoming connections
|
||||
if (listen(server_fd, 3) < 0) {
|
||||
perror("Listen failed");
|
||||
close(server_fd);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
printf("Echo server listening on port %d\n", PORT);
|
||||
|
||||
while (1) {
|
||||
// Accept a client connection
|
||||
if ((client_fd = accept(server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0) {
|
||||
perror("Accept failed");
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("Client connected, fd: %d\n", client_fd);
|
||||
|
||||
ssize_t bytes_read;
|
||||
while ((bytes_read = read(client_fd, buffer, BUFFER_SIZE)) > 0) {
|
||||
write(client_fd, buffer, bytes_read); // Echo data back to the client
|
||||
}
|
||||
|
||||
printf("Client disconnected\n");
|
||||
close(client_fd);
|
||||
}
|
||||
|
||||
close(server_fd);
|
||||
return 0;
|
||||
}
|
|
@ -1,101 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <poll.h>
|
||||
|
||||
#define PORT 12345
|
||||
|
||||
int main() {
|
||||
int server_fd, new_socket = -1, nfds;
|
||||
struct sockaddr_in server_addr;
|
||||
struct pollfd fds[2];
|
||||
|
||||
// Create a TCP socket
|
||||
server_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (server_fd == -1) {
|
||||
perror("Socket creation failed");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
server_addr.sin_family = AF_INET;
|
||||
server_addr.sin_addr.s_addr = INADDR_ANY;
|
||||
server_addr.sin_port = htons(PORT);
|
||||
|
||||
// Bind the socket to the address
|
||||
if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
|
||||
perror("Bind failed");
|
||||
close(server_fd);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Listen for incoming connections
|
||||
if (listen(server_fd, 3) == -1) {
|
||||
perror("Listen failed");
|
||||
close(server_fd);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Set up poll to monitor stdin and the socket
|
||||
fds[0].fd = STDIN_FILENO; // Monitor stdin
|
||||
fds[1].fd = server_fd; // Monitor the server socket
|
||||
|
||||
while (1) {
|
||||
fds[0].events = POLLIN;
|
||||
fds[1].events = POLLIN;
|
||||
// Poll for events
|
||||
nfds = poll(fds, 2, -1); // -1 means wait indefinitely
|
||||
if (nfds == -1) {
|
||||
perror("Poll error");
|
||||
close(server_fd);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (fds[0].revents & POLLIN) {
|
||||
// Data available on stdin
|
||||
char buffer[1024];
|
||||
ssize_t bytes_read = read(STDIN_FILENO, buffer, sizeof(buffer));
|
||||
if (bytes_read > 0) {
|
||||
// Write stdin data to the socket
|
||||
if (new_socket != -1) {
|
||||
send(new_socket, buffer, bytes_read, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fds[1].revents & POLLIN) {
|
||||
// New connection on the socket
|
||||
if (new_socket == -1) {
|
||||
printf("Calling accept()\n");
|
||||
new_socket = accept(server_fd, NULL, NULL);
|
||||
if (new_socket == -1) {
|
||||
perror("Accept failed");
|
||||
continue;
|
||||
}
|
||||
fds[1].fd = new_socket;
|
||||
printf("New connection established\n");
|
||||
continue;
|
||||
} else {
|
||||
// Data available on the socket
|
||||
char buffer[1024];
|
||||
ssize_t bytes_received = recv(new_socket, buffer, sizeof(buffer), 0);
|
||||
if (bytes_received > 0) {
|
||||
// Write socket data to stdout
|
||||
write(STDOUT_FILENO, buffer, bytes_received);
|
||||
} else if (bytes_received == 0) {
|
||||
// Connection closed by the client
|
||||
close(new_socket);
|
||||
new_socket = -1;
|
||||
fds[1].fd = server_fd;
|
||||
printf("Connection closed\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
close(server_fd);
|
||||
return 0;
|
||||
}
|
|
@ -1,102 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/select.h>
|
||||
|
||||
#define PORT 12346
|
||||
|
||||
int main() {
|
||||
int server_fd, new_socket = -1;
|
||||
struct sockaddr_in server_addr;
|
||||
fd_set readfds;
|
||||
int max_fd;
|
||||
|
||||
// Create a TCP socket
|
||||
server_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (server_fd == -1) {
|
||||
perror("Socket creation failed");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
printf("server socket: %d\n", server_fd);
|
||||
|
||||
server_addr.sin_family = AF_INET;
|
||||
server_addr.sin_addr.s_addr = INADDR_ANY;
|
||||
server_addr.sin_port = htons(PORT);
|
||||
|
||||
// Bind the socket to the address
|
||||
if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
|
||||
perror("Bind failed");
|
||||
close(server_fd);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Listen for incoming connections
|
||||
if (listen(server_fd, 3) == -1) {
|
||||
perror("Listen failed");
|
||||
close(server_fd);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Initialize file descriptor sets
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(STDIN_FILENO, &readfds); // Monitor stdin
|
||||
FD_SET(server_fd, &readfds); // Monitor the server socket
|
||||
max_fd = server_fd;
|
||||
|
||||
while (1) {
|
||||
fd_set tempfds = readfds;
|
||||
int activity = select(max_fd + 1, &tempfds, NULL, NULL, NULL);
|
||||
if (activity == -1) {
|
||||
perror("Select error");
|
||||
close(server_fd);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (FD_ISSET(STDIN_FILENO, &tempfds)) {
|
||||
// Data available on stdin
|
||||
char buffer[1024];
|
||||
ssize_t bytes_read = read(STDIN_FILENO, buffer, sizeof(buffer));
|
||||
if (bytes_read > 0 && new_socket != -1) {
|
||||
// Write stdin data to the socket
|
||||
send(new_socket, buffer, bytes_read, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if ((new_socket == -1) && FD_ISSET(server_fd, &tempfds)) {
|
||||
printf("Server socket activity\n");
|
||||
// New connection on the socket
|
||||
if (new_socket == -1) {
|
||||
new_socket = accept(server_fd, NULL, NULL);
|
||||
if (new_socket == -1) {
|
||||
perror("Accept failed");
|
||||
continue;
|
||||
}
|
||||
printf("New connection established\n");
|
||||
FD_SET(new_socket, &readfds); // Monitor the new socket
|
||||
max_fd = (new_socket > max_fd) ? new_socket : max_fd;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ((new_socket != -1) && FD_ISSET(new_socket, &tempfds)) {
|
||||
// Data available on the socket
|
||||
char buffer[1024];
|
||||
ssize_t bytes_received = recv(new_socket, buffer, sizeof(buffer), 0);
|
||||
if (bytes_received > 0) {
|
||||
write(STDOUT_FILENO, buffer, bytes_received);
|
||||
} else if (bytes_received == 0) {
|
||||
// Connection closed by the client
|
||||
close(new_socket);
|
||||
FD_CLR(new_socket, &readfds); // Stop monitoring the socket
|
||||
new_socket = -1;
|
||||
printf("Connection closed\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
close(server_fd);
|
||||
return 0;
|
||||
}
|
|
@ -1,162 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "config.h"
|
||||
#include "femtotcp.h"
|
||||
#include "httpd.h"
|
||||
|
||||
#define TEST_SIZE (8 * 1024)
|
||||
|
||||
#define BUFFER_SIZE TEST_SIZE
|
||||
|
||||
static int exit_ok = 0, exit_count = 0;
|
||||
static int tot_sent = 0;
|
||||
static int femtotcp_closing = 0;
|
||||
static int closed = 0;
|
||||
|
||||
|
||||
|
||||
|
||||
/* FemtoTCP side: main loop of the stack under test. */
|
||||
static int test_loop(struct ipstack *s, int active_close)
|
||||
{
|
||||
exit_ok = 0;
|
||||
exit_count = 0;
|
||||
tot_sent = 0;
|
||||
femtotcp_closing = active_close;
|
||||
closed = 0;
|
||||
|
||||
while(1) {
|
||||
uint32_t ms_next;
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
ms_next = ipstack_poll(s, tv.tv_sec * 1000 + tv.tv_usec / 1000);
|
||||
usleep(ms_next * 1000);
|
||||
if (exit_ok > 0) {
|
||||
if (exit_count++ < 10)
|
||||
continue;
|
||||
else break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Catch-all function to initialize a new tap device as the network interface.
|
||||
* This is defined in port/linux.c
|
||||
* */
|
||||
extern int tap_init(struct ll *dev, const char *name, uint32_t host_ip);
|
||||
|
||||
/* Test cases */
|
||||
|
||||
extern const unsigned char server_der[];
|
||||
extern const unsigned long server_der_len;
|
||||
extern const unsigned char server_key_der[];
|
||||
extern const unsigned long server_key_der_len;
|
||||
|
||||
|
||||
static void test_httpd(struct ipstack *s)
|
||||
{
|
||||
int ret;
|
||||
struct httpd httpd;
|
||||
WOLFSSL_CTX *server_ctx;
|
||||
const char homepage[] = "<html><body><h1>Hello, world!</h1></body></html>";
|
||||
|
||||
printf("HTTP server test\n");
|
||||
|
||||
printf("Creating TLS server context\n");
|
||||
server_ctx = wolfSSL_CTX_new(wolfTLSv1_2_server_method());
|
||||
if (!server_ctx) {
|
||||
printf("Failed to create server context\n");
|
||||
return;
|
||||
}
|
||||
printf("Importing server certificate\n");
|
||||
ret = wolfSSL_CTX_use_certificate_buffer(server_ctx, server_der,
|
||||
server_der_len, SSL_FILETYPE_ASN1);
|
||||
if (ret != SSL_SUCCESS) {
|
||||
printf("Failed to import server certificate\n");
|
||||
return;
|
||||
}
|
||||
printf("Importing server private key\n");
|
||||
ret = wolfSSL_CTX_use_PrivateKey_buffer(server_ctx, server_key_der,
|
||||
server_key_der_len, SSL_FILETYPE_ASN1);
|
||||
if (ret != SSL_SUCCESS) {
|
||||
printf("Failed to import server private key\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Initializing HTTPD server */
|
||||
printf("Initializing HTTPD server\n");
|
||||
ret = httpd_init(&httpd, s, 443, server_ctx);
|
||||
if (ret < 0) {
|
||||
printf("Failed to initialize HTTPD server\n");
|
||||
return;
|
||||
}
|
||||
httpd_register_static_page(&httpd, "/", homepage);
|
||||
test_loop(s, 0);
|
||||
}
|
||||
|
||||
/* Main test function. */
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct ipstack *s;
|
||||
struct ll *tapdev;
|
||||
struct timeval tv;
|
||||
struct in_addr linux_ip;
|
||||
uint32_t srv_ip;
|
||||
ip4 ip = 0, nm = 0, gw = 0;
|
||||
|
||||
wolfSSL_Init();
|
||||
wolfSSL_Debugging_OFF();
|
||||
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
(void)ip;
|
||||
(void)nm;
|
||||
(void)gw;
|
||||
(void)tv;
|
||||
ipstack_init_static(&s);
|
||||
tapdev = ipstack_getdev(s);
|
||||
if (!tapdev)
|
||||
return 1;
|
||||
inet_aton(LINUX_IP, &linux_ip);
|
||||
if (tap_init(tapdev, "femt0", linux_ip.s_addr) < 0) {
|
||||
perror("tap init");
|
||||
return 2;
|
||||
}
|
||||
system("tcpdump -i femt0 -w test.pcap &");
|
||||
|
||||
#ifdef DHCP
|
||||
gettimeofday(&tv, NULL);
|
||||
ipstack_poll(s, tv.tv_sec * 1000 + tv.tv_usec / 1000);
|
||||
dhcp_client_init(s);
|
||||
do {
|
||||
gettimeofday(&tv, NULL);
|
||||
ipstack_poll(s, tv.tv_sec * 1000 + tv.tv_usec / 1000);
|
||||
usleep(1000);
|
||||
ipstack_ipconfig_get(s, &ip, &nm, &gw);
|
||||
} while (!dhcp_bound(s));
|
||||
printf("DHCP: obtained IP address.\n");
|
||||
ipstack_ipconfig_get(s, &ip, &nm, &gw);
|
||||
srv_ip = htonl(ip);
|
||||
#else
|
||||
ipstack_ipconfig_set(s, atoip4(FEMTOTCP_IP), atoip4("255.255.255.0"),
|
||||
atoip4(LINUX_IP));
|
||||
printf("IP: manually configured\n");
|
||||
inet_pton(AF_INET, FEMTOTCP_IP, &srv_ip);
|
||||
#endif
|
||||
|
||||
/* Server side test */
|
||||
test_httpd(s);
|
||||
sleep(2);
|
||||
sync();
|
||||
system("killall tcpdump");
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,274 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "config.h"
|
||||
#include "femtotcp.h"
|
||||
|
||||
#define DHCP
|
||||
#define TEST_SIZE (8 * 1024)
|
||||
|
||||
#define BUFFER_SIZE TEST_SIZE
|
||||
|
||||
static int conn_fd = -1;
|
||||
static int exit_ok = 0, exit_count = 0;
|
||||
static uint8_t buf[TEST_SIZE];
|
||||
static int tot_sent = 0;
|
||||
static int femtotcp_closing = 0;
|
||||
static int closed = 0;
|
||||
static int client_connected = 0;
|
||||
static const uint8_t test_pattern[16] = "Test pattern - -";
|
||||
|
||||
|
||||
/* Client-side callback. */
|
||||
static void client_cb(int fd, uint16_t event, void *arg)
|
||||
{
|
||||
struct ipstack *s = (struct ipstack *)arg;
|
||||
uint32_t i;
|
||||
int ret;
|
||||
static unsigned int total_r = 0, total_w = 0;
|
||||
if (fd == conn_fd) {
|
||||
if ((event & CB_EVENT_WRITABLE) && (client_connected == 0)) {
|
||||
printf("Client: connected\n");
|
||||
client_connected = 1;
|
||||
}
|
||||
}
|
||||
if (total_w == 0) {
|
||||
for (i = 0; i < sizeof(buf); i += sizeof(test_pattern)) {
|
||||
memcpy(buf + i, test_pattern, sizeof(test_pattern));
|
||||
}
|
||||
}
|
||||
if (client_connected && (event & CB_EVENT_WRITABLE) && (total_w < sizeof(buf))) {
|
||||
ret = ft_sendto(s, fd, buf + total_w, sizeof(buf) - total_w, 0, NULL, 0);
|
||||
if (ret <= 0) {
|
||||
printf("Test client write: %d\n", ret);
|
||||
return;
|
||||
}
|
||||
total_w += ret;
|
||||
}
|
||||
|
||||
while ((total_r < total_w) && (event & CB_EVENT_READABLE)) {
|
||||
ret = ft_recvfrom(s, fd, buf + total_r, sizeof(buf) - total_r, 0, NULL, NULL);
|
||||
if (ret < 0){
|
||||
if (ret != -11) {
|
||||
printf("Client read: %d\n", ret);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (ret == 0) {
|
||||
printf("Client read: server has closed the connection.\n");
|
||||
return;
|
||||
}
|
||||
total_r += ret;
|
||||
printf("Client RX total: %u\n", total_r);
|
||||
}
|
||||
if (total_r == sizeof(buf)) {
|
||||
exit_ok = 1;
|
||||
for (i = 0; i < sizeof(buf); i += sizeof(test_pattern)) {
|
||||
if (memcmp(buf + i, test_pattern, sizeof(test_pattern))) {
|
||||
printf("test client: pattern mismatch\n");
|
||||
printf("at position %d\n", i);
|
||||
buf[i + 16] = 0;
|
||||
printf("%s\n", &buf[i]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (femtotcp_closing) {
|
||||
ft_close(s, fd);
|
||||
conn_fd = -1;
|
||||
}
|
||||
printf("Test client: success\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* FemtoTCP side: main loop of the stack under test. */
|
||||
static int test_loop(struct ipstack *s, int active_close)
|
||||
{
|
||||
exit_ok = 0;
|
||||
exit_count = 0;
|
||||
tot_sent = 0;
|
||||
femtotcp_closing = active_close;
|
||||
closed = 0;
|
||||
|
||||
while(1) {
|
||||
uint32_t ms_next;
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
ms_next = ipstack_poll(s, tv.tv_sec * 1000 + tv.tv_usec / 1000);
|
||||
usleep(ms_next * 1000);
|
||||
if (exit_ok > 0) {
|
||||
if (exit_count++ < 10)
|
||||
continue;
|
||||
else break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Test code (Linux side).
|
||||
* Thread with echo server to test the client.
|
||||
*/
|
||||
static void *pt_echoserver(void *arg)
|
||||
{
|
||||
int fd, ret;
|
||||
unsigned total_r = 0;
|
||||
uint8_t buf[BUFFER_SIZE];
|
||||
struct sockaddr_in local_sock = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_port = ntohs(8), /* Echo */
|
||||
.sin_addr.s_addr = 0
|
||||
};
|
||||
femtotcp_closing = (uintptr_t)arg;
|
||||
fd = socket(AF_INET, IPSTACK_SOCK_STREAM, 0);
|
||||
if (fd < 0) {
|
||||
printf("test server socket: %d\n", fd);
|
||||
return (void *)-1;
|
||||
}
|
||||
local_sock.sin_addr.s_addr = inet_addr(LINUX_IP);
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int));
|
||||
ret = bind(fd, (struct sockaddr *)&local_sock, sizeof(local_sock));
|
||||
if (ret < 0) {
|
||||
printf("test server bind: %d (%s)\n", ret, strerror(errno));
|
||||
return (void *)-1;
|
||||
}
|
||||
ret = listen(fd, 1);
|
||||
if (ret < 0) {
|
||||
printf("test server listen: %d\n", ret);
|
||||
return (void *)-1;
|
||||
}
|
||||
printf("Waiting for client\n");
|
||||
ret = accept(fd, NULL, NULL);
|
||||
if (ret < 0) {
|
||||
printf("test server accept: %d\n", ret);
|
||||
return (void *)-1;
|
||||
}
|
||||
printf("test server: client %d connected\n", ret);
|
||||
fd = ret;
|
||||
while (1) {
|
||||
ret = read(fd, buf + total_r, sizeof(buf) - total_r);
|
||||
if (ret < 0) {
|
||||
printf("failed test server read: %d (%s) \n", ret, strerror(errno));
|
||||
return (void *)-1;
|
||||
}
|
||||
if (ret == 0) {
|
||||
printf("test server read: client has closed the connection.\n");
|
||||
if (femtotcp_closing)
|
||||
return (void *)0;
|
||||
else
|
||||
return (void *)-1;
|
||||
}
|
||||
total_r += ret;
|
||||
write(fd, buf + total_r - ret, ret);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Catch-all function to initialize a new tap device as the network interface.
|
||||
* This is defined in port/linux.c
|
||||
* */
|
||||
extern int tap_init(struct ll *dev, const char *name, uint32_t host_ip);
|
||||
|
||||
void test_femtotcp_echoclient(struct ipstack *s)
|
||||
{
|
||||
int ret, test_ret = 0;
|
||||
pthread_t pt;
|
||||
struct ipstack_sockaddr_in remote_sock;
|
||||
/* Client side test: client is closing the connection */
|
||||
remote_sock.sin_family = AF_INET;
|
||||
remote_sock.sin_port = ee16(8);
|
||||
remote_sock.sin_addr.s_addr = inet_addr(LINUX_IP);
|
||||
printf("TCP client tests\n");
|
||||
conn_fd = ft_socket(s, AF_INET, IPSTACK_SOCK_STREAM, 0);
|
||||
printf("client socket: %04x\n", conn_fd);
|
||||
ipstack_register_callback(s, conn_fd, client_cb, s);
|
||||
printf("Connecting to %s:8\n", LINUX_IP);
|
||||
ft_connect(s, conn_fd, (struct ipstack_sockaddr *)&remote_sock, sizeof(remote_sock));
|
||||
pthread_create(&pt, NULL, pt_echoserver, (void*)1);
|
||||
printf("Starting test: echo client active close\n");
|
||||
ret = test_loop(s, 1);
|
||||
printf("Test echo client active close: %d\n", ret);
|
||||
pthread_join(pt, (void **)&test_ret);
|
||||
printf("Test linux server: %d\n", test_ret);
|
||||
|
||||
if (conn_fd >= 0) {
|
||||
ft_close(s, conn_fd);
|
||||
conn_fd = -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int example_com_resolved = 0;
|
||||
|
||||
|
||||
void ns_cb(uint32_t ip)
|
||||
{
|
||||
printf("Obtained ip address for example.com: %s\n", inet_ntoa(*(struct in_addr *)&ip));
|
||||
example_com_resolved = 1;
|
||||
}
|
||||
|
||||
|
||||
/* Main test function. */
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct ipstack *s;
|
||||
struct ll *tapdev;
|
||||
struct timeval tv;
|
||||
struct in_addr linux_ip;
|
||||
uint32_t srv_ip;
|
||||
uint16_t dns_id = 0;
|
||||
ip4 ip = 0, nm = 0, gw = 0;
|
||||
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
(void)ip;
|
||||
(void)nm;
|
||||
(void)gw;
|
||||
(void)tv;
|
||||
ipstack_init_static(&s);
|
||||
tapdev = ipstack_getdev(s);
|
||||
if (!tapdev)
|
||||
return 1;
|
||||
inet_aton(LINUX_IP, &linux_ip);
|
||||
if (tap_init(tapdev, "femt0", linux_ip.s_addr) < 0) {
|
||||
perror("tap init");
|
||||
return 2;
|
||||
}
|
||||
system("tcpdump -i femt0 -w test.pcap &");
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
ipstack_poll(s, tv.tv_sec * 1000 + tv.tv_usec / 1000);
|
||||
dhcp_client_init(s);
|
||||
do {
|
||||
gettimeofday(&tv, NULL);
|
||||
ipstack_poll(s, tv.tv_sec * 1000 + tv.tv_usec / 1000);
|
||||
usleep(1000);
|
||||
ipstack_ipconfig_get(s, &ip, &nm, &gw);
|
||||
} while (!dhcp_bound(s));
|
||||
printf("DHCP: obtained IP address.\n");
|
||||
ipstack_ipconfig_get(s, &ip, &nm, &gw);
|
||||
srv_ip = htonl(ip);
|
||||
(void)srv_ip;
|
||||
|
||||
nslookup(s, "example.com", &dns_id, ns_cb);
|
||||
|
||||
while(!example_com_resolved) {
|
||||
gettimeofday(&tv, NULL);
|
||||
ipstack_poll(s, tv.tv_sec * 1000 + tv.tv_usec / 1000);
|
||||
usleep(1000);
|
||||
}
|
||||
|
||||
/* Client side test */
|
||||
test_femtotcp_echoclient(s);
|
||||
|
||||
sleep(2);
|
||||
sync();
|
||||
system("killall tcpdump");
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,455 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "config.h"
|
||||
#include "femtotcp.h"
|
||||
|
||||
#define TEST_SIZE (8 * 1024)
|
||||
|
||||
#define BUFFER_SIZE TEST_SIZE
|
||||
|
||||
static int listen_fd = -1, client_fd = -1;
|
||||
static int exit_ok = 0, exit_count = 0;
|
||||
static uint8_t buf[TEST_SIZE];
|
||||
static int tot_sent = 0;
|
||||
static int tot_recv = 0;
|
||||
static int femtotcp_closing = 0;
|
||||
static int closed = 0;
|
||||
static int conn_fd = -1;
|
||||
static int client_connected = 0;
|
||||
static const uint8_t test_pattern[16] = "Test pattern - -";
|
||||
|
||||
|
||||
|
||||
/* FemtoTCP: server side callback. */
|
||||
static void server_cb(int fd, uint16_t event, void *arg)
|
||||
{
|
||||
int ret = 0;
|
||||
if ((fd == listen_fd) && (event & CB_EVENT_READABLE) && (client_fd == -1)) {
|
||||
client_fd = ft_accept((struct ipstack *)arg, listen_fd, NULL, NULL);
|
||||
if (client_fd > 0) {
|
||||
printf("accept: %04x\n", client_fd);
|
||||
}
|
||||
} else if ((fd == client_fd) && (event & CB_EVENT_READABLE )) {
|
||||
ret = ft_recvfrom((struct ipstack *)arg, client_fd, buf, sizeof(buf), 0, NULL, NULL);
|
||||
if (ret != -11) {
|
||||
if (ret < 0) {
|
||||
printf("Recv error: %d\n", ret);
|
||||
ft_close((struct ipstack *)arg, client_fd);
|
||||
} else if (ret == 0) {
|
||||
printf("Client side closed the connection.\n");
|
||||
ft_close((struct ipstack *)arg, client_fd);
|
||||
printf("Server: Exiting.\n");
|
||||
exit_ok = 1;
|
||||
} else if (ret > 0) {
|
||||
printf("recv: %d, echoing back\n", ret);
|
||||
tot_recv += ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((event & CB_EVENT_WRITABLE) || ((ret > 0) && !closed)) {
|
||||
int snd_ret;
|
||||
if ((tot_sent >= 4096) && femtotcp_closing) {
|
||||
ft_close((struct ipstack *)arg, client_fd);
|
||||
printf("Server: I closed the connection.\n");
|
||||
closed = 1;
|
||||
exit_ok = 1;
|
||||
}
|
||||
if ((!closed) && (tot_sent < tot_recv)) {
|
||||
snd_ret = ft_sendto((struct ipstack *)arg, client_fd, buf + tot_sent, tot_recv - tot_sent, 0, NULL, 0);
|
||||
if (snd_ret != -11) {
|
||||
if (snd_ret < 0) {
|
||||
printf("Send error: %d\n", snd_ret);
|
||||
ft_close((struct ipstack *)arg, client_fd);
|
||||
} else {
|
||||
tot_sent += snd_ret;
|
||||
printf("sent %d bytes\n", snd_ret);
|
||||
if (tot_recv == tot_sent) {
|
||||
tot_sent = 0;
|
||||
tot_recv = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (event & CB_EVENT_CLOSED) {
|
||||
printf("Closing %d, client fd: %d\n", fd, client_fd);
|
||||
}
|
||||
if ((fd == client_fd) && (event & CB_EVENT_CLOSED)) {
|
||||
printf("Client side closed the connection (EVENT_CLOSED)\n");
|
||||
ft_close((struct ipstack *)arg, client_fd);
|
||||
client_fd = -1;
|
||||
printf("Server: Exiting.\n");
|
||||
exit_ok = 1;
|
||||
}
|
||||
(void)arg;
|
||||
}
|
||||
|
||||
/* Client-side callback. */
|
||||
static void client_cb(int fd, uint16_t event, void *arg)
|
||||
{
|
||||
struct ipstack *s = (struct ipstack *)arg;
|
||||
uint32_t i;
|
||||
int ret;
|
||||
static unsigned int total_r = 0, total_w = 0;
|
||||
if (fd == conn_fd) {
|
||||
if ((event & CB_EVENT_WRITABLE) && (client_connected == 0)) {
|
||||
printf("Client: connected\n");
|
||||
client_connected = 1;
|
||||
}
|
||||
}
|
||||
if (total_w == 0) {
|
||||
for (i = 0; i < sizeof(buf); i += sizeof(test_pattern)) {
|
||||
memcpy(buf + i, test_pattern, sizeof(test_pattern));
|
||||
}
|
||||
}
|
||||
if (client_connected && (event & CB_EVENT_WRITABLE) && (total_w < sizeof(buf))) {
|
||||
ret = ft_sendto(s, fd, buf + total_w, sizeof(buf) - total_w, 0, NULL, 0);
|
||||
if (ret <= 0) {
|
||||
printf("Test client write: %d\n", ret);
|
||||
return;
|
||||
}
|
||||
total_w += ret;
|
||||
}
|
||||
|
||||
while ((total_r < total_w) && (event & CB_EVENT_READABLE)) {
|
||||
ret = ft_recvfrom(s, fd, buf + total_r, sizeof(buf) - total_r, 0, NULL, NULL);
|
||||
if (ret < 0){
|
||||
if (ret != -11) {
|
||||
printf("Client read: %d\n", ret);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (ret == 0) {
|
||||
printf("Client read: server has closed the connection.\n");
|
||||
return;
|
||||
}
|
||||
total_r += ret;
|
||||
printf("Client RX total: %u\n", total_r);
|
||||
}
|
||||
if (total_r == sizeof(buf)) {
|
||||
exit_ok = 1;
|
||||
for (i = 0; i < sizeof(buf); i += sizeof(test_pattern)) {
|
||||
if (memcmp(buf + i, test_pattern, sizeof(test_pattern))) {
|
||||
printf("test client: pattern mismatch\n");
|
||||
printf("at position %d\n", i);
|
||||
buf[i + 16] = 0;
|
||||
printf("%s\n", &buf[i]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (femtotcp_closing) {
|
||||
ft_close(s, fd);
|
||||
conn_fd = -1;
|
||||
}
|
||||
printf("Test client: success\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* FemtoTCP side: main loop of the stack under test. */
|
||||
static int test_loop(struct ipstack *s, int active_close)
|
||||
{
|
||||
exit_ok = 0;
|
||||
exit_count = 0;
|
||||
tot_sent = 0;
|
||||
femtotcp_closing = active_close;
|
||||
closed = 0;
|
||||
|
||||
while(1) {
|
||||
uint32_t ms_next;
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
ms_next = ipstack_poll(s, tv.tv_sec * 1000 + tv.tv_usec / 1000);
|
||||
usleep(ms_next * 1000);
|
||||
if (exit_ok > 0) {
|
||||
if (exit_count++ < 10)
|
||||
continue;
|
||||
else break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Test code (Linux side).
|
||||
* Thread with client to test the echoserver.
|
||||
*/
|
||||
void *pt_echoclient(void *arg)
|
||||
{
|
||||
int fd, ret;
|
||||
unsigned total_r = 0;
|
||||
unsigned i;
|
||||
uint8_t buf[BUFFER_SIZE];
|
||||
uint32_t *srv_addr = (uint32_t *)arg;
|
||||
struct sockaddr_in remote_sock = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_port = ntohs(8), /* Echo */
|
||||
};
|
||||
remote_sock.sin_addr.s_addr = *srv_addr;
|
||||
fd = socket(AF_INET, IPSTACK_SOCK_STREAM, 0);
|
||||
if (fd < 0) {
|
||||
printf("test client socket: %d\n", fd);
|
||||
return (void *)-1;
|
||||
}
|
||||
sleep(1);
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int));
|
||||
printf("Connecting to echo server\n");
|
||||
ret = connect(fd, (struct sockaddr *)&remote_sock, sizeof(remote_sock));
|
||||
if (ret < 0) {
|
||||
printf("test client connect: %d\n", ret);
|
||||
perror("connect");
|
||||
return (void *)-1;
|
||||
}
|
||||
for (i = 0; i < sizeof(buf); i += sizeof(test_pattern)) {
|
||||
memcpy(buf + i, test_pattern, sizeof(test_pattern));
|
||||
}
|
||||
ret = write(fd, buf, sizeof(buf));
|
||||
if (ret < 0) {
|
||||
printf("test client write: %d\n", ret);
|
||||
return (void *)-1;
|
||||
}
|
||||
while (total_r < sizeof(buf)) {
|
||||
ret = read(fd, buf + total_r, sizeof(buf) - total_r);
|
||||
if (ret < 0) {
|
||||
printf("failed test client read: %d\n", ret);
|
||||
return (void *)-1;
|
||||
}
|
||||
if (ret == 0) {
|
||||
printf("test client read: server has closed the connection.\n");
|
||||
if (femtotcp_closing)
|
||||
return (void *)0;
|
||||
else
|
||||
return (void *)-1;
|
||||
}
|
||||
total_r += ret;
|
||||
}
|
||||
for (i = 0; i < sizeof(buf); i += sizeof(test_pattern)) {
|
||||
if (memcmp(buf + i, test_pattern, sizeof(test_pattern))) {
|
||||
printf("test client: pattern mismatch\n");
|
||||
printf("at position %d\n", i);
|
||||
buf[i + 16] = 0;
|
||||
printf("%s\n", &buf[i]);
|
||||
return (void *)-1;
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
printf("Test client: success\n");
|
||||
return (void *)0;
|
||||
}
|
||||
|
||||
/* Test code (Linux side).
|
||||
* Thread with echo server to test the client.
|
||||
*/
|
||||
static void *pt_echoserver(void *arg)
|
||||
{
|
||||
int fd, ret;
|
||||
unsigned total_r = 0;
|
||||
uint8_t buf[BUFFER_SIZE];
|
||||
struct sockaddr_in local_sock = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_port = ntohs(8), /* Echo */
|
||||
.sin_addr.s_addr = 0
|
||||
};
|
||||
femtotcp_closing = (uintptr_t)arg;
|
||||
fd = socket(AF_INET, IPSTACK_SOCK_STREAM, 0);
|
||||
if (fd < 0) {
|
||||
printf("test server socket: %d\n", fd);
|
||||
return (void *)-1;
|
||||
}
|
||||
local_sock.sin_addr.s_addr = inet_addr(LINUX_IP);
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int));
|
||||
ret = bind(fd, (struct sockaddr *)&local_sock, sizeof(local_sock));
|
||||
if (ret < 0) {
|
||||
printf("test server bind: %d (%s)\n", ret, strerror(errno));
|
||||
return (void *)-1;
|
||||
}
|
||||
ret = listen(fd, 1);
|
||||
if (ret < 0) {
|
||||
printf("test server listen: %d\n", ret);
|
||||
return (void *)-1;
|
||||
}
|
||||
printf("Waiting for client\n");
|
||||
ret = accept(fd, NULL, NULL);
|
||||
if (ret < 0) {
|
||||
printf("test server accept: %d\n", ret);
|
||||
return (void *)-1;
|
||||
}
|
||||
printf("test server: client %d connected\n", ret);
|
||||
fd = ret;
|
||||
while (1) {
|
||||
ret = read(fd, buf + total_r, sizeof(buf) - total_r);
|
||||
if (ret < 0) {
|
||||
printf("failed test server read: %d (%s) \n", ret, strerror(errno));
|
||||
return (void *)-1;
|
||||
}
|
||||
if (ret == 0) {
|
||||
printf("test server read: client has closed the connection.\n");
|
||||
if (femtotcp_closing)
|
||||
return (void *)0;
|
||||
else
|
||||
return (void *)-1;
|
||||
}
|
||||
total_r += ret;
|
||||
write(fd, buf + total_r - ret, ret);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Catch-all function to initialize a new tap device as the network interface.
|
||||
* This is defined in port/linux.c
|
||||
* */
|
||||
extern int tap_init(struct ll *dev, const char *name, uint32_t host_ip);
|
||||
|
||||
/* Test cases */
|
||||
|
||||
void test_femtotcp_echoserver(struct ipstack *s, uint32_t srv_ip)
|
||||
{
|
||||
int ret, test_ret = 0;
|
||||
pthread_t pt;
|
||||
struct ipstack_sockaddr_in local_sock = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_port = ee16(8), /* Echo */
|
||||
.sin_addr.s_addr = 0
|
||||
};
|
||||
printf("TCP server tests\n");
|
||||
|
||||
listen_fd = ft_socket(s, AF_INET, IPSTACK_SOCK_STREAM, 0);
|
||||
printf("socket: %04x\n", listen_fd);
|
||||
ipstack_register_callback(s, listen_fd, server_cb, s);
|
||||
|
||||
pthread_create(&pt, NULL, pt_echoclient, &srv_ip);
|
||||
printf("Starting test: echo server close-wait\n");
|
||||
ret = ft_bind(s, listen_fd, (struct ipstack_sockaddr *)&local_sock, sizeof(local_sock));
|
||||
printf("bind: %d\n", ret);
|
||||
ret = ft_listen(s, listen_fd, 1);
|
||||
printf("listen: %d\n", ret);
|
||||
ret = test_loop(s, 0);
|
||||
pthread_join(pt, (void **)&test_ret);
|
||||
printf("Test echo server close-wait: %d\n", ret);
|
||||
printf("Test linux client: %d\n", test_ret);
|
||||
sleep(1);
|
||||
|
||||
pthread_create(&pt, NULL, pt_echoclient, &srv_ip);
|
||||
printf("Starting test: echo server active close\n");
|
||||
ret = test_loop(s, 1);
|
||||
printf("Test echo server close-wait: %d\n", ret);
|
||||
pthread_join(pt, (void **)&test_ret);
|
||||
printf("Test linux client: %d\n", test_ret);
|
||||
sleep(1);
|
||||
|
||||
ft_close(s, listen_fd);
|
||||
}
|
||||
|
||||
void test_femtotcp_echoclient(struct ipstack *s)
|
||||
{
|
||||
int ret, test_ret = 0;
|
||||
pthread_t pt;
|
||||
struct ipstack_sockaddr_in remote_sock;
|
||||
/* Client side test: client is closing the connection */
|
||||
remote_sock.sin_family = AF_INET;
|
||||
remote_sock.sin_port = ee16(8);
|
||||
remote_sock.sin_addr.s_addr = inet_addr(LINUX_IP);
|
||||
printf("TCP client tests\n");
|
||||
conn_fd = ft_socket(s, AF_INET, IPSTACK_SOCK_STREAM, 0);
|
||||
printf("client socket: %04x\n", conn_fd);
|
||||
ipstack_register_callback(s, conn_fd, client_cb, s);
|
||||
printf("Connecting to %s:8\n", LINUX_IP);
|
||||
ft_connect(s, conn_fd, (struct ipstack_sockaddr *)&remote_sock, sizeof(remote_sock));
|
||||
pthread_create(&pt, NULL, pt_echoserver, (void*)1);
|
||||
printf("Starting test: echo client active close\n");
|
||||
ret = test_loop(s, 1);
|
||||
printf("Test echo client active close: %d\n", ret);
|
||||
pthread_join(pt, (void **)&test_ret);
|
||||
printf("Test linux server: %d\n", test_ret);
|
||||
|
||||
if (conn_fd >= 0) {
|
||||
ft_close(s, conn_fd);
|
||||
conn_fd = -1;
|
||||
}
|
||||
|
||||
/* Client side test: server is closing the connection */
|
||||
/* Excluded for now as linux cannot bind twice on port 8 */
|
||||
#if 0
|
||||
conn_fd = ft_socket(s, AF_INET, IPSTACK_SOCK_STREAM, 0);
|
||||
if (conn_fd < 0) {
|
||||
printf("cannot create socket: %d\n", conn_fd);
|
||||
}
|
||||
printf("client socket: %04x\n", conn_fd);
|
||||
ipstack_register_callback(s, conn_fd, client_cb, s);
|
||||
printf("Connecting to %s:8\n", LINUX_IP);
|
||||
ft_connect(s, conn_fd, (struct ipstack_sockaddr *)&remote_sock, sizeof(remote_sock));
|
||||
pthread_create(&pt, NULL, pt_echoserver, (void*)0);
|
||||
printf("Starting test: echo client passive close\n");
|
||||
ret = test_loop(s, 0);
|
||||
printf("Test echo client, server closing: %d\n", ret);
|
||||
pthread_join(pt, (void **)&test_ret);
|
||||
printf("Test linux server: %d\n", test_ret);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* Main test function. */
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct ipstack *s;
|
||||
struct ll *tapdev;
|
||||
struct timeval tv;
|
||||
struct in_addr linux_ip;
|
||||
uint32_t srv_ip;
|
||||
ip4 ip = 0, nm = 0, gw = 0;
|
||||
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
(void)ip;
|
||||
(void)nm;
|
||||
(void)gw;
|
||||
(void)tv;
|
||||
ipstack_init_static(&s);
|
||||
tapdev = ipstack_getdev(s);
|
||||
if (!tapdev)
|
||||
return 1;
|
||||
inet_aton(LINUX_IP, &linux_ip);
|
||||
if (tap_init(tapdev, "femt0", linux_ip.s_addr) < 0) {
|
||||
perror("tap init");
|
||||
return 2;
|
||||
}
|
||||
system("tcpdump -i femt0 -w test.pcap &");
|
||||
|
||||
#ifdef DHCP
|
||||
gettimeofday(&tv, NULL);
|
||||
ipstack_poll(s, tv.tv_sec * 1000 + tv.tv_usec / 1000);
|
||||
dhcp_client_init(s);
|
||||
do {
|
||||
gettimeofday(&tv, NULL);
|
||||
ipstack_poll(s, tv.tv_sec * 1000 + tv.tv_usec / 1000);
|
||||
usleep(1000);
|
||||
ipstack_ipconfig_get(s, &ip, &nm, &gw);
|
||||
} while (!dhcp_bound(s));
|
||||
printf("DHCP: obtained IP address.\n");
|
||||
ipstack_ipconfig_get(s, &ip, &nm, &gw);
|
||||
srv_ip = htonl(ip);
|
||||
#else
|
||||
ipstack_ipconfig_set(s, atoip4(FEMTOTCP_IP), atoip4("255.255.255.0"),
|
||||
atoip4(LINUX_IP));
|
||||
printf("IP: manually configured\n");
|
||||
inet_pton(AF_INET, FEMTOTCP_IP, &srv_ip);
|
||||
#endif
|
||||
|
||||
/* Server side test */
|
||||
test_femtotcp_echoserver(s, srv_ip);
|
||||
|
||||
/* Client side test */
|
||||
test_femtotcp_echoclient(s);
|
||||
|
||||
system("killall tcpdump");
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -3,16 +3,14 @@
|
|||
#include <arpa/inet.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include "femtotcp.h"
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "config.h"
|
||||
#include "femtotcp.h"
|
||||
#include <wolfssl/options.h>
|
||||
#include <wolfssl/wolfcrypt/settings.h>
|
||||
#include <wolfssl/ssl.h>
|
||||
|
||||
//#define DHCP
|
||||
#define FEMTOTCP_IP "10.10.10.2"
|
||||
#define LINUX_IP "10.10.10.1"
|
||||
#define TEST_SIZE (8 * 1024)
|
||||
|
||||
#define BUFFER_SIZE TEST_SIZE
|
||||
|
@ -22,72 +20,49 @@ static int exit_ok = 0, exit_count = 0;
|
|||
static uint8_t buf[TEST_SIZE];
|
||||
static int tot_sent = 0;
|
||||
static int tot_recv = 0;
|
||||
static int femtotcp_closing = 0;
|
||||
static int server_closing = 0;
|
||||
static int closed = 0;
|
||||
static const uint8_t test_pattern[16] = "Test pattern - -";
|
||||
|
||||
static WOLFSSL_CTX *server_ctx = NULL; /* Used by femtoTCP */
|
||||
static WOLFSSL_CTX *client_ctx = NULL; /* Used by Linux */
|
||||
static WOLFSSL *client_ssl = NULL;
|
||||
static WOLFSSL *server_ssl = NULL;
|
||||
|
||||
|
||||
/* Defined in wolfssl_io.c */
|
||||
int wolfSSL_SetIO_FT(WOLFSSL* ssl, int fd);
|
||||
int wolfSSL_SetIO_FT_CTX(WOLFSSL_CTX *ctx, struct ipstack *s);
|
||||
|
||||
/* FemtoTCP: server side callback. */
|
||||
static void server_cb(int fd, uint16_t event, void *arg)
|
||||
static void socket_cb(int fd, uint16_t event, void *arg)
|
||||
{
|
||||
int ret = 0;
|
||||
printf("Called socket_cb, events: %04x fd %d\n", event, fd & (~0x1000));
|
||||
|
||||
if ((fd == listen_fd) && (event & CB_EVENT_READABLE) && (client_fd == -1)) {
|
||||
client_fd = ft_accept((struct ipstack *)arg, listen_fd, NULL, NULL);
|
||||
if (client_fd > 0) {
|
||||
printf("accept: Client FD is 0x%04x\n", client_fd);
|
||||
/* Create the wolfSSL object */
|
||||
server_ssl = wolfSSL_new(server_ctx);
|
||||
if (!server_ssl) {
|
||||
printf("Failed to create server SSL object\n");
|
||||
return;
|
||||
}
|
||||
wolfSSL_SetIO_FT(server_ssl, client_fd);
|
||||
/* Accepting the TLS session is not necessary here, as the
|
||||
* first read will trigger the handshake.
|
||||
*/
|
||||
printf("Server: TCP connection established\n");
|
||||
printf("accept: %04x\n", client_fd);
|
||||
}
|
||||
} else if ((fd == client_fd) && (event & CB_EVENT_READABLE )) {
|
||||
ret = wolfSSL_read(server_ssl, buf, sizeof(buf));
|
||||
if (ret < 0) {
|
||||
ret = wolfSSL_get_error(server_ssl, 0);
|
||||
if (ret != WOLFSSL_ERROR_WANT_READ) {
|
||||
ret = ft_recvfrom((struct ipstack *)arg, client_fd, buf, sizeof(buf), 0, NULL, NULL);
|
||||
if (ret != -11) {
|
||||
if (ret < 0) {
|
||||
printf("Recv error: %d\n", ret);
|
||||
ft_close((struct ipstack *)arg, client_fd);
|
||||
} else if (ret == 0) {
|
||||
printf("Client side closed the connection.\n");
|
||||
ft_close((struct ipstack *)arg, client_fd);
|
||||
printf("Server: Exiting.\n");
|
||||
exit_ok = 1;
|
||||
} else if (ret > 0) {
|
||||
printf("recv: %d, echoing back\n", ret);
|
||||
tot_recv += ret;
|
||||
}
|
||||
} else if (ret == 0) {
|
||||
printf("Client side closed the connection.\n");
|
||||
ft_close((struct ipstack *)arg, client_fd);
|
||||
printf("Server: Exiting.\n");
|
||||
exit_ok = 1;
|
||||
} else if (ret > 0) {
|
||||
printf("recv: %d, echoing back\n", ret);
|
||||
tot_recv += ret;
|
||||
}
|
||||
}
|
||||
if ((event & CB_EVENT_WRITABLE) || ((ret > 0) && !closed)) {
|
||||
int snd_ret;
|
||||
if ((tot_sent >= 4096) && femtotcp_closing) {
|
||||
if ((tot_sent >= 4096) && server_closing) {
|
||||
ft_close((struct ipstack *)arg, client_fd);
|
||||
printf("Server: I closed the connection.\n");
|
||||
closed = 1;
|
||||
exit_ok = 1;
|
||||
}
|
||||
if ((!closed) && (tot_sent < tot_recv)) {
|
||||
snd_ret = wolfSSL_write(server_ssl, buf + tot_sent, tot_recv - tot_sent);
|
||||
if (snd_ret != WANT_WRITE) {
|
||||
snd_ret = ft_sendto((struct ipstack *)arg, client_fd, buf + tot_sent, tot_recv - tot_sent, 0, NULL, 0);
|
||||
if (snd_ret != -11) {
|
||||
if (snd_ret < 0) {
|
||||
printf("Send error: %d\n", snd_ret);
|
||||
wolfSSL_free(server_ssl);
|
||||
ft_close((struct ipstack *)arg, client_fd);
|
||||
} else {
|
||||
tot_sent += snd_ret;
|
||||
|
@ -102,27 +77,24 @@ static void server_cb(int fd, uint16_t event, void *arg)
|
|||
}
|
||||
if (event & CB_EVENT_CLOSED) {
|
||||
printf("Closing %d, client fd: %d\n", fd, client_fd);
|
||||
wolfSSL_free(server_ssl);
|
||||
server_ssl = NULL;
|
||||
}
|
||||
if ((fd == client_fd) && (event & CB_EVENT_CLOSED)) {
|
||||
printf("Client side closed the connection (EVENT_CLOSED)\n");
|
||||
wolfSSL_free(server_ssl);
|
||||
ft_close((struct ipstack *)arg, client_fd);
|
||||
client_fd = -1;
|
||||
printf("Server: Exiting.\n");
|
||||
exit_ok = 1;
|
||||
}
|
||||
(void)arg;
|
||||
}
|
||||
|
||||
|
||||
/* FemtoTCP side: main loop of the stack under test. */
|
||||
static int test_loop(struct ipstack *s, int active_close)
|
||||
static int test_echoserver(struct ipstack *s, int active_close)
|
||||
{
|
||||
exit_ok = 0;
|
||||
exit_count = 0;
|
||||
tot_sent = 0;
|
||||
femtotcp_closing = active_close;
|
||||
server_closing = active_close;
|
||||
closed = 0;
|
||||
|
||||
while(1) {
|
||||
|
@ -140,47 +112,25 @@ static int test_loop(struct ipstack *s, int active_close)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Test code (Linux side).
|
||||
* Thread with client to test the echoserver.
|
||||
*/
|
||||
extern const unsigned char ca_der[];
|
||||
extern const unsigned long ca_der_len;
|
||||
|
||||
void *pt_echoclient(void *arg)
|
||||
{
|
||||
int fd, ret;
|
||||
unsigned total_r = 0;
|
||||
unsigned i;
|
||||
uint8_t buf[BUFFER_SIZE];
|
||||
uint8_t test_pattern[16] = "Test pattern - -";
|
||||
uint32_t *srv_addr = (uint32_t *)arg;
|
||||
struct sockaddr_in remote_sock = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_port = ntohs(8), /* Echo */
|
||||
};
|
||||
|
||||
client_ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method());
|
||||
if (!client_ctx) {
|
||||
printf("Failed to create client context\n");
|
||||
return (void *)-1;
|
||||
}
|
||||
|
||||
client_ssl = wolfSSL_new(client_ctx);
|
||||
if (!client_ssl) {
|
||||
printf("Failed to create client SSL object\n");
|
||||
return (void *)-1;
|
||||
}
|
||||
|
||||
wolfSSL_CTX_load_verify_buffer(client_ctx, ca_der, ca_der_len, SSL_FILETYPE_ASN1);
|
||||
|
||||
remote_sock.sin_addr.s_addr = *srv_addr;
|
||||
fd = socket(AF_INET, IPSTACK_SOCK_STREAM, 0);
|
||||
if (fd < 0) {
|
||||
printf("test client socket: %d\n", fd);
|
||||
return (void *)-1;
|
||||
}
|
||||
wolfSSL_set_fd(client_ssl, fd);
|
||||
sleep(1);
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int));
|
||||
printf("Connecting to echo server\n");
|
||||
ret = connect(fd, (struct sockaddr *)&remote_sock, sizeof(remote_sock));
|
||||
if (ret < 0) {
|
||||
|
@ -188,29 +138,23 @@ void *pt_echoclient(void *arg)
|
|||
perror("connect");
|
||||
return (void *)-1;
|
||||
}
|
||||
printf("Linux client: TCP connection established\n");
|
||||
ret = wolfSSL_connect(client_ssl);
|
||||
if (ret != SSL_SUCCESS) {
|
||||
printf("Linux client: Failed to connect to TLS server, err: %d\n", ret);
|
||||
return (void *)-1;
|
||||
}
|
||||
for (i = 0; i < sizeof(buf); i += sizeof(test_pattern)) {
|
||||
memcpy(buf + i, test_pattern, sizeof(test_pattern));
|
||||
}
|
||||
ret = wolfSSL_write(client_ssl, buf, sizeof(buf));
|
||||
ret = write(fd, buf, sizeof(buf));
|
||||
if (ret < 0) {
|
||||
printf("test client write: %d\n", ret);
|
||||
return (void *)-1;
|
||||
}
|
||||
while (total_r < sizeof(buf)) {
|
||||
ret = wolfSSL_read(client_ssl, buf + total_r, sizeof(buf) - total_r);
|
||||
ret = read(fd, buf + total_r, sizeof(buf) - total_r);
|
||||
if (ret < 0) {
|
||||
printf("failed test client read: %d\n", ret);
|
||||
return (void *)-1;
|
||||
}
|
||||
if (ret == 0) {
|
||||
printf("test client read: server has closed the connection.\n");
|
||||
if (femtotcp_closing)
|
||||
if (server_closing)
|
||||
return (void *)0;
|
||||
else
|
||||
return (void *)-1;
|
||||
|
@ -226,108 +170,37 @@ void *pt_echoclient(void *arg)
|
|||
return (void *)-1;
|
||||
}
|
||||
}
|
||||
client_ssl = NULL;
|
||||
close(fd);
|
||||
printf("Test client: success\n");
|
||||
wolfSSL_free(client_ssl);
|
||||
return (void *)0;
|
||||
}
|
||||
|
||||
|
||||
/* Catch-all function to initialize a new tap device as the network interface.
|
||||
* This is defined in port/linux.c
|
||||
* */
|
||||
extern int tap_init(struct ll *dev, const char *name, uint32_t host_ip);
|
||||
|
||||
/* Test cases */
|
||||
|
||||
extern const unsigned char server_der[];
|
||||
extern const unsigned long server_der_len;
|
||||
extern const unsigned char server_key_der[];
|
||||
extern const unsigned long server_key_der_len;
|
||||
|
||||
|
||||
void test_femtotcp_echoserver(struct ipstack *s, uint32_t srv_ip)
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret, test_ret = 0;
|
||||
struct ipstack *s;
|
||||
struct ll *tapdev;
|
||||
pthread_t pt;
|
||||
struct timeval tv;
|
||||
struct in_addr linux_ip;
|
||||
ip4 ip = 0, nm = 0, gw = 0;
|
||||
uint32_t srv_ip;
|
||||
struct ipstack_sockaddr_in local_sock = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_port = ee16(8), /* Echo */
|
||||
.sin_addr.s_addr = 0
|
||||
};
|
||||
printf("TCP server tests\n");
|
||||
|
||||
printf("Creating TLS server context\n");
|
||||
server_ctx = wolfSSL_CTX_new(wolfTLSv1_3_server_method());
|
||||
if (!server_ctx) {
|
||||
printf("Failed to create server context\n");
|
||||
return;
|
||||
}
|
||||
printf("Associating server context with femtoTCP\n");
|
||||
wolfSSL_SetIO_FT_CTX(server_ctx, s);
|
||||
|
||||
printf("Importing server certificate\n");
|
||||
ret = wolfSSL_CTX_use_certificate_buffer(server_ctx, server_der,
|
||||
server_der_len, SSL_FILETYPE_ASN1);
|
||||
if (ret != SSL_SUCCESS) {
|
||||
printf("Failed to import server certificate\n");
|
||||
return;
|
||||
}
|
||||
printf("Importing server private key\n");
|
||||
ret = wolfSSL_CTX_use_PrivateKey_buffer(server_ctx, server_key_der,
|
||||
server_key_der_len, SSL_FILETYPE_ASN1);
|
||||
if (ret != SSL_SUCCESS) {
|
||||
printf("Failed to import server private key\n");
|
||||
return;
|
||||
}
|
||||
|
||||
listen_fd = ft_socket(s, AF_INET, IPSTACK_SOCK_STREAM, 0);
|
||||
printf("socket: %04x\n", listen_fd);
|
||||
ipstack_register_callback(s, listen_fd, server_cb, s);
|
||||
|
||||
pthread_create(&pt, NULL, pt_echoclient, &srv_ip);
|
||||
printf("Starting test: echo server close-wait\n");
|
||||
ret = ft_bind(s, listen_fd, (struct ipstack_sockaddr *)&local_sock, sizeof(local_sock));
|
||||
printf("bind: %d\n", ret);
|
||||
ret = ft_listen(s, listen_fd, 1);
|
||||
printf("listen: %d\n", ret);
|
||||
ret = test_loop(s, 0);
|
||||
pthread_join(pt, (void **)&test_ret);
|
||||
printf("Test echo server close-wait: %d\n", ret);
|
||||
printf("Test linux client: %d\n", test_ret);
|
||||
sleep(1);
|
||||
|
||||
pthread_create(&pt, NULL, pt_echoclient, &srv_ip);
|
||||
printf("Starting test: echo server active close\n");
|
||||
ret = test_loop(s, 1);
|
||||
printf("Test echo server close-wait: %d\n", ret);
|
||||
pthread_join(pt, (void **)&test_ret);
|
||||
printf("Test linux client: %d\n", test_ret);
|
||||
sleep(1);
|
||||
|
||||
ft_close(s, listen_fd);
|
||||
}
|
||||
|
||||
/* Main test function. */
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct ipstack *s;
|
||||
struct ll *tapdev;
|
||||
struct timeval tv;
|
||||
struct in_addr linux_ip;
|
||||
uint32_t srv_ip;
|
||||
ip4 ip = 0, nm = 0, gw = 0;
|
||||
|
||||
wolfSSL_Init();
|
||||
wolfSSL_Debugging_OFF();
|
||||
|
||||
int ret, test_ret = 0;
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
(void)ip;
|
||||
(void)nm;
|
||||
(void)gw;
|
||||
(void)tv;
|
||||
(void)pt;
|
||||
(void)srv_ip;
|
||||
ipstack_init_static(&s);
|
||||
tapdev = ipstack_getdev(s);
|
||||
if (!tapdev)
|
||||
|
@ -337,6 +210,7 @@ int main(int argc, char **argv)
|
|||
perror("tap init");
|
||||
return 2;
|
||||
}
|
||||
|
||||
system("tcpdump -i femt0 -w test.pcap &");
|
||||
|
||||
#ifdef DHCP
|
||||
|
@ -359,10 +233,32 @@ int main(int argc, char **argv)
|
|||
inet_pton(AF_INET, FEMTOTCP_IP, &srv_ip);
|
||||
#endif
|
||||
|
||||
/* Server side test */
|
||||
test_femtotcp_echoserver(s, srv_ip);
|
||||
sleep(2);
|
||||
sync();
|
||||
listen_fd = ft_socket(s, AF_INET, IPSTACK_SOCK_STREAM, 0);
|
||||
printf("socket: %04x\n", listen_fd);
|
||||
ipstack_register_callback(s, listen_fd, socket_cb, s);
|
||||
|
||||
pthread_create(&pt, NULL, pt_echoclient, &srv_ip);
|
||||
printf("Starting test: echo server close-wait\n");
|
||||
ret = ft_bind(s, listen_fd, (struct ipstack_sockaddr *)&local_sock, sizeof(local_sock));
|
||||
printf("bind: %d\n", ret);
|
||||
ret = ft_listen(s, listen_fd, 1);
|
||||
printf("listen: %d\n", ret);
|
||||
ret = test_echoserver(s, 0);
|
||||
pthread_join(pt, (void **)&test_ret);
|
||||
printf("Test echo server close-wait: %d\n", ret);
|
||||
printf("Test linux client: %d\n", test_ret);
|
||||
sleep(1);
|
||||
|
||||
pthread_create(&pt, NULL, pt_echoclient, &srv_ip);
|
||||
printf("Starting test: echo server active close\n");
|
||||
ret = test_echoserver(s, 1);
|
||||
printf("Test echo server close-wait: %d\n", ret);
|
||||
pthread_join(pt, (void **)&test_ret);
|
||||
printf("Test linux client: %d\n", test_ret);
|
||||
sleep(1);
|
||||
|
||||
|
||||
|
||||
system("killall tcpdump");
|
||||
return 0;
|
||||
}
|
15
test/unit/Makefile
Normal file
15
test/unit/Makefile
Normal file
|
@ -0,0 +1,15 @@
|
|||
LDFLAGS=-lcheck -lm -lpthread -lrt -ldl -lsubunit
|
||||
CFLAGS=-g -Wall -Wextra -Werror -I../../ -DETHERNET
|
||||
CC=gcc
|
||||
|
||||
all: unit
|
||||
|
||||
unit: unit.o
|
||||
$(CC) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $<
|
||||
|
||||
clean:
|
||||
rm -f *.o unit
|
|
@ -1,5 +1,5 @@
|
|||
#include "check.h"
|
||||
#include "../../femtotcp.c"
|
||||
#include "../../src/femtotcp.c"
|
||||
#include <stdlib.h> /* for random() */
|
||||
|
||||
/* MOCKS */
|
||||
|
@ -18,7 +18,7 @@ static const uint8_t ifmac[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55};
|
|||
static uint8_t last_frame_sent[LINK_MTU];
|
||||
static uint32_t last_frame_sent_size = 0;
|
||||
|
||||
static int mock_send(struct ll *dev, void *frame, uint32_t len)
|
||||
static int mock_send(struct ll *dev, void *frame, int len)
|
||||
{
|
||||
(void)dev;
|
||||
memcpy(last_frame_sent, frame, len);
|
||||
|
@ -26,7 +26,7 @@ static int mock_send(struct ll *dev, void *frame, uint32_t len)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int mock_poll(struct ll *dev, void *frame, uint32_t len)
|
||||
static int mock_poll(struct ll *dev, void *frame, int len)
|
||||
{
|
||||
(void)dev;
|
||||
(void)frame;
|
||||
|
@ -592,7 +592,7 @@ START_TEST(test_transport_checksum) {
|
|||
// Set up pseudo-header values for test
|
||||
ph.ph.src = 0xc0a80101; // 192.168.1.1
|
||||
ph.ph.dst = 0xc0a80102; // 192.168.1.2
|
||||
ph.ph.proto = FT_IPPROTO_TCP;
|
||||
ph.ph.proto = IPPROTO_TCP;
|
||||
ph.ph.len = ee16(20); // TCP header length (without options)
|
||||
|
||||
// Test with a simple TCP header with src/dst ports and no data
|
||||
|
@ -620,7 +620,7 @@ START_TEST(test_iphdr_set_checksum) {
|
|||
ip.id = ee16(1);
|
||||
ip.flags_fo = 0;
|
||||
ip.ttl = 64;
|
||||
ip.proto = FT_IPPROTO_TCP;
|
||||
ip.proto = IPPROTO_TCP;
|
||||
ip.src = ee32(0xc0a80101); // 192.168.1.1
|
||||
ip.dst = ee32(0xc0a80102); // 192.168.1.2
|
||||
|
||||
|
@ -662,13 +662,13 @@ START_TEST(test_ip_output_add_header) {
|
|||
t.S = &S;
|
||||
|
||||
// Run the function for a TCP packet
|
||||
int result = ip_output_add_header(&t, &ip, FT_IPPROTO_TCP, 40);
|
||||
int result = ip_output_add_header(&t, &ip, IPPROTO_TCP, 40);
|
||||
ck_assert_int_eq(result, 0);
|
||||
|
||||
// Validate IP header fields
|
||||
ck_assert_uint_eq(ip.ver_ihl, 0x45);
|
||||
ck_assert_uint_eq(ip.ttl, 64);
|
||||
ck_assert_uint_eq(ip.proto, FT_IPPROTO_TCP);
|
||||
ck_assert_uint_eq(ip.proto, IPPROTO_TCP);
|
||||
ck_assert_uint_eq(ip.src, ee32(t.local_ip));
|
||||
ck_assert_uint_eq(ip.dst, ee32(t.remote_ip));
|
||||
ck_assert_msg(ip.csum != 0, "IP header checksum should not be zero");
|
|
@ -1,61 +0,0 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
OUT_DIR=build/certs
|
||||
|
||||
: "${COUNTRY:=US}"
|
||||
: "${STATE:=State}"
|
||||
: "${CITY:=City}"
|
||||
: "${ORG:=ExampleOrg}"
|
||||
: "${ORG_UNIT:=IT}"
|
||||
: "${CA_COMMON_NAME:=Example CA}"
|
||||
: "${SERVER_COMMON_NAME:=example.com}"
|
||||
: "${DAYS_CA:=3650}" # CA certificate validity in days (10 years)
|
||||
: "${DAYS_SERVER:=825}" # Server certificate validity in days (2 years)
|
||||
: "${ECC_CURVE:=secp384r1}" # ECC curve to use
|
||||
|
||||
# Create the output directory if it doesn't exist
|
||||
mkdir -p "$OUT_DIR"
|
||||
|
||||
# 1. Generate CA private key
|
||||
openssl ecparam -name "$ECC_CURVE" -genkey -noout -out "$OUT_DIR/ca.key"
|
||||
|
||||
# 2. Generate the CA self-signed certificate (PEM format)
|
||||
openssl req -x509 -new -key "$OUT_DIR/ca.key" -sha256 -days "$DAYS_CA" -out "$OUT_DIR/ca.crt" \
|
||||
-subj "/C=$COUNTRY/ST=$STATE/L=$CITY/O=$ORG/OU=$ORG_UNIT/CN=$CA_COMMON_NAME"
|
||||
|
||||
# 3. Convert CA certificate to DER format
|
||||
openssl x509 -in "$OUT_DIR/ca.crt" -outform DER -out "$OUT_DIR/ca.der"
|
||||
|
||||
xxd -i "$OUT_DIR/ca.der" |sed -e "s/unsigned/const unsigned/g" | sed -e "s/build_certs_//g" > "$OUT_DIR/ca_cert.c"
|
||||
|
||||
|
||||
echo "==== Generating server private key ===="
|
||||
|
||||
# 4. Generate server private key
|
||||
openssl ecparam -name "$ECC_CURVE" -genkey -noout -out "$OUT_DIR/server.key"
|
||||
|
||||
# 5. Convert server private key to DER format
|
||||
openssl pkcs8 -topk8 -nocrypt -in "$OUT_DIR/server.key" -outform DER -out "$OUT_DIR/server.key.der"
|
||||
|
||||
xxd -i "$OUT_DIR/server.key.der" |sed -e "s/unsigned/const unsigned/g" | sed -e "s/build_certs_//g" > "$OUT_DIR/server_key.c"
|
||||
|
||||
|
||||
echo "==== Generating server Certificate Signing Request (CSR) ===="
|
||||
|
||||
# 6. Generate server Certificate Signing Request (CSR)
|
||||
openssl req -new -key "$OUT_DIR/server.key" -out "$OUT_DIR/server.csr" \
|
||||
-subj "/C=$COUNTRY/ST=$STATE/L=$CITY/O=$ORG/OU=$ORG_UNIT/CN=$SERVER_COMMON_NAME"
|
||||
|
||||
echo "==== Signing server certificate with the CA ===="
|
||||
|
||||
# 7. Sign the server CSR with the CA to create a server certificate (PEM format)
|
||||
openssl x509 -req -in "$OUT_DIR/server.csr" -CA "$OUT_DIR/ca.crt" -CAkey "$OUT_DIR/ca.key" \
|
||||
-CAcreateserial -out "$OUT_DIR/server.crt" -days "$DAYS_SERVER" -sha256
|
||||
|
||||
# 8. Convert server certificate to DER format
|
||||
openssl x509 -in "$OUT_DIR/server.crt" -outform DER -out "$OUT_DIR/server.der"
|
||||
|
||||
xxd -i "$OUT_DIR/server.der" |sed -e "s/unsigned/const unsigned/g" | sed -e "s/build_certs_//g" > "$OUT_DIR/server_cert.c"
|
||||
|
||||
echo "==== Done ===="
|
||||
|
Loading…
Reference in a new issue