Compare commits
6 commits
fbb1eaf711
...
574abdca7b
Author | SHA1 | Date | |
---|---|---|---|
574abdca7b | |||
f11153b3c6 | |||
15b4d7d6ea | |||
fe8a25b446 | |||
1829548cd5 | |||
653ff61ca3 |
8 changed files with 800 additions and 428 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -2,5 +2,5 @@
|
|||
*.a
|
||||
*.pcap
|
||||
build/*
|
||||
test/unit/unit-core
|
||||
test/unit/unit
|
||||
tags
|
||||
|
|
4
Makefile
4
Makefile
|
@ -1,6 +1,6 @@
|
|||
CC?=gcc
|
||||
CFLAGS:=-Wall -Werror -Wextra -I.
|
||||
OBJ=build/femtotcp.o build/test-linux.o
|
||||
OBJ=build/femtotcp.o build/test-linux.o build/port/linux.o
|
||||
|
||||
all: build/test
|
||||
|
||||
|
@ -13,7 +13,7 @@ libtcpip.a: $(OBJ)
|
|||
@ar rcs $@ $^
|
||||
|
||||
clean:
|
||||
@rm -f build/*
|
||||
@rm -f build/*.o build/port/*.o
|
||||
@make -C test/unit clean
|
||||
|
||||
# Test
|
||||
|
|
107
core.md
Normal file
107
core.md
Normal file
|
@ -0,0 +1,107 @@
|
|||
# FemtoTCP
|
||||
|
||||
## Stack architecture
|
||||
|
||||
- No dynamic allocation (pre-allocated sockets and buffers)
|
||||
- Four-steps main loop function
|
||||
- Callback-based socket interface (allows implementing blocking BSD calls)
|
||||
|
||||
|
||||
|
||||
## Data structures
|
||||
|
||||
* Two types of circular buffers (fixed size):
|
||||
|
||||
- "fifo" : contains entire frames, including a descriptor.
|
||||
- "queue" : contains pure data, indexed by byte. Used for TCP receive buffer
|
||||
only.
|
||||
|
||||
* One binary heap for timers
|
||||
|
||||
|
||||
|
||||
### FemtoTCP fifo
|
||||
|
||||
```
|
||||
+---------------------------------------------------------------------------------------------------------------------------+
|
||||
| +-----+---+----+-----+------------------+-----+---+----+-----+------------------+ |
|
||||
| | De | E | IP | TCP | Payload | De | E | IP | TCP | Payload | |
|
||||
| | sc | T | | | | sc | T | | | | |
|
||||
|* FREE SPACE * | ri | H | | | | ri | H | | | | * FREE SPACE* |
|
||||
| | pt | | | | | pt | | | | | |
|
||||
| | or | | | | | or | | | | | |
|
||||
| +-----+---+----+-----+------------------+-----+---+----+-----+------------------+ |
|
||||
+---------------------------------------------------------------------------------------------------------------------------+
|
||||
^ ^
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
|Tail Head|
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
### FemtoTCP queue
|
||||
|
||||
```
|
||||
+--------------+--------------------------------------------+---------------------------------------------------------------+
|
||||
| |*------------------------------------------*| |
|
||||
| || || |
|
||||
| || || |
|
||||
|* FREE SPACE *|| DATA PAYLOAD || * FREE SPACE * |
|
||||
| || || |
|
||||
| || || |
|
||||
| |*------------------------------------------*| |
|
||||
+--------------+--------------------------------------------+---------------------------------------------------------------+
|
||||
^ ^
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
|Tail Head|
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Sockets
|
||||
|
||||
### TCP socket
|
||||
|
||||
```
|
||||
+-------------+
|
||||
|Main loop TX |
|
||||
+-------------+
|
||||
^
|
||||
+----------------------------------+ |
|
||||
| | +------+
|
||||
| TCP Socket | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| +-----------------------+
|
||||
| +---------------+ | |
|
||||
>DATA OUT==>>|socket send() |-->| TX buffer (fifo) |
|
||||
| +---------------+ | |
|
||||
| +-----------------------+
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| +-----------------------+
|
||||
| +-------------+ | |
|
||||
<DATA IN<<====|socket recv()|<---| RX buffer (queue) |
|
||||
| +-------------+ | |
|
||||
| +-----------------------+
|
||||
+----------------------------------+ ^
|
||||
|
|
||||
|
|
||||
|
|
||||
+--------------+
|
||||
| tcp_recv() |
|
||||
+--------------+
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
27
femtotcp.h
27
femtotcp.h
|
@ -54,16 +54,16 @@ typedef uint32_t socklen_t;
|
|||
#endif
|
||||
#endif
|
||||
|
||||
int posix_socket(struct ipstack *s, int domain, int type, int protocol);
|
||||
int posix_bind(struct ipstack *s, int sockfd, const struct ipstack_sockaddr *addr, socklen_t addrlen);
|
||||
int posix_listen(struct ipstack *s, int sockfd, int backlog);
|
||||
int posix_accept(struct ipstack *s, int sockfd, struct ipstack_sockaddr *addr, socklen_t *addrlen);
|
||||
int posix_connect(struct ipstack *s, int sockfd, const struct ipstack_sockaddr *addr, socklen_t addrlen);
|
||||
int posix_sendto(struct ipstack *s, int sockfd, const void *buf, size_t len, int flags, const struct ipstack_sockaddr *dest_addr, socklen_t addrlen);
|
||||
int posix_recvfrom(struct ipstack *s, int sockfd, void *buf, size_t len, int flags, struct ipstack_sockaddr *src_addr, socklen_t *addrlen);
|
||||
int posix_close(struct ipstack *s, int sockfd);
|
||||
int posix_getpeername(struct ipstack *s, int sockfd, struct ipstack_sockaddr *addr, socklen_t *addrlen);
|
||||
int posix_getsockname(struct ipstack *s, int sockfd, struct ipstack_sockaddr *addr, socklen_t *addrlen);
|
||||
int ft_socket(struct ipstack *s, int domain, int type, int protocol);
|
||||
int ft_bind(struct ipstack *s, int sockfd, const struct ipstack_sockaddr *addr, socklen_t addrlen);
|
||||
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_recvfrom(struct ipstack *s, int sockfd, void *buf, size_t len, int flags, struct ipstack_sockaddr *src_addr, socklen_t *addrlen);
|
||||
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);
|
||||
|
||||
int dhcp_client_init(struct ipstack *s);
|
||||
int dhcp_bound(struct ipstack *s);
|
||||
|
@ -78,6 +78,13 @@ 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_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);
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
112
src/femtotcp.c
112
src/femtotcp.c
|
@ -4,7 +4,7 @@
|
|||
* Copyright: 2024 Danielinux
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "femtotcp.h"
|
||||
|
@ -21,7 +21,7 @@
|
|||
#define MAX_NEIGHBORS 16
|
||||
|
||||
/* Constants */
|
||||
#define MARK_TCP_SOCKET 0x8000 /* Mark a socket as TCP */
|
||||
#define MARK_TCP_SOCKET 0x1000 /* Mark a socket as TCP */
|
||||
#define MARK_UDP_SOCKET 0x4000 /* Mark a socket as UDP */
|
||||
|
||||
#define IPPROTO_ICMP 0x01
|
||||
|
@ -70,11 +70,6 @@
|
|||
#define PKT_FLAG_ACKED 0x02
|
||||
#define PKT_FLAG_FIN 0x04
|
||||
|
||||
/* Callback flags */
|
||||
#define CB_EVENT_READABLE 0x01 /* Accepted connection or data available */
|
||||
#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 */
|
||||
|
||||
/* Random number generator, provided by the user */
|
||||
uint32_t ipstack_getrandom(void);
|
||||
|
@ -92,7 +87,7 @@ struct fifo {
|
|||
/* TCP TX is a circular buffer and contains an array of full packets */
|
||||
/* TCP RX only contains application data */
|
||||
|
||||
/* FIFO functions
|
||||
/* FIFO functions
|
||||
* head: next empty slot
|
||||
* tail: oldest populated slot
|
||||
*
|
||||
|
@ -148,7 +143,7 @@ static struct pkt_desc *fifo_peek(struct fifo *f)
|
|||
f->tail = 0;
|
||||
f->h_wrap = 0;
|
||||
}
|
||||
if (f->tail == f->head)
|
||||
if (f->tail == f->head)
|
||||
return NULL;
|
||||
while (f->tail % 4)
|
||||
f->tail++;
|
||||
|
@ -532,7 +527,7 @@ struct timers_binheap {
|
|||
uint32_t size;
|
||||
};
|
||||
|
||||
struct ipstack
|
||||
struct ipstack
|
||||
{
|
||||
struct ll ll_dev;
|
||||
struct ipconf ipconf;
|
||||
|
@ -566,7 +561,7 @@ void ipstack_register_callback(struct ipstack *s, int sock_fd, void (*cb)(int so
|
|||
if (sock_fd < 0)
|
||||
return;
|
||||
if (sock_fd & MARK_TCP_SOCKET) {
|
||||
if (sock_fd >= MAX_TCPSOCKETS)
|
||||
if ((sock_fd & (~MARK_TCP_SOCKET)) >= MAX_TCPSOCKETS)
|
||||
return;
|
||||
t = &s->tcpsockets[sock_fd & ~MARK_TCP_SOCKET];
|
||||
t->callback = cb;
|
||||
|
@ -584,23 +579,26 @@ void ipstack_register_callback(struct ipstack *s, int sock_fd, void (*cb)(int so
|
|||
static struct ipstack_timer timers_binheap_pop(struct timers_binheap *heap)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
struct ipstack_timer tmr = heap->timers[0];
|
||||
heap->size--;
|
||||
heap->timers[0] = heap->timers[heap->size];
|
||||
while (2*i+1 < heap->size) {
|
||||
struct ipstack_timer tmp;
|
||||
uint32_t j = 2*i+1;
|
||||
if (j+1 < heap->size && heap->timers[j+1].expires < heap->timers[j].expires) {
|
||||
j++;
|
||||
struct ipstack_timer tmr = {0};
|
||||
do {
|
||||
tmr = heap->timers[0];
|
||||
heap->size--;
|
||||
heap->timers[0] = heap->timers[heap->size];
|
||||
while (2*i+1 < heap->size) {
|
||||
struct ipstack_timer tmp;
|
||||
uint32_t j = 2*i+1;
|
||||
if (j+1 < heap->size && heap->timers[j+1].expires < heap->timers[j].expires) {
|
||||
j++;
|
||||
}
|
||||
if (heap->timers[i].expires <= heap->timers[j].expires) {
|
||||
break;
|
||||
}
|
||||
tmp = heap->timers[i];
|
||||
heap->timers[i] = heap->timers[j];
|
||||
heap->timers[j] = tmp;
|
||||
i = j;
|
||||
}
|
||||
if (heap->timers[i].expires <= heap->timers[j].expires) {
|
||||
break;
|
||||
}
|
||||
tmp = heap->timers[i];
|
||||
heap->timers[i] = heap->timers[j];
|
||||
heap->timers[j] = tmp;
|
||||
i = j;
|
||||
}
|
||||
} while ((tmr.expires == 0) && (heap->size > 0));
|
||||
return tmr;
|
||||
}
|
||||
|
||||
|
@ -670,7 +668,7 @@ static void udp_try_recv(struct ipstack *s, struct ipstack_udp_datagram *udp, ui
|
|||
{
|
||||
for (int i = 0; i < MAX_UDPSOCKETS; i++) {
|
||||
struct tsocket *t = &s->udpsockets[i];
|
||||
if (t->src_port == ee16(udp->dst_port) && t->dst_port == ee16(udp->src_port) &&
|
||||
if (t->src_port == ee16(udp->dst_port) && t->dst_port == ee16(udp->src_port) &&
|
||||
(((t->local_ip == 0) && DHCP_IS_RUNNING(s)) ||
|
||||
(t->local_ip == ee32(udp->ip.dst) && t->remote_ip != s->ipconf.ip)) ) {
|
||||
|
||||
|
@ -801,6 +799,7 @@ static void tcp_recv(struct tsocket *t, struct ipstack_tcp_seg *seg)
|
|||
t->sock.tcp.ack = seq + seg_len;
|
||||
timer_binheap_cancel(&t->S->timers, t->sock.tcp.tmr_rto);
|
||||
t->sock.tcp.tmr_rto = NO_TIMER;
|
||||
t->events |= CB_EVENT_READABLE;
|
||||
}
|
||||
tcp_send_ack(t);
|
||||
}
|
||||
|
@ -993,6 +992,8 @@ static void tcp_ack(struct tsocket *t, struct ipstack_tcp_seg *tcp)
|
|||
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 */
|
||||
|
@ -1019,7 +1020,7 @@ static void tcp_ack(struct tsocket *t, struct ipstack_tcp_seg *tcp)
|
|||
desc = fifo_next(&t->sock.tcp.txbuf, desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Preselect socket, parse options, manage handshakes, pass to application */
|
||||
static void tcp_input(struct ipstack *S, struct ipstack_tcp_seg *tcp, uint32_t frame_len)
|
||||
|
@ -1050,13 +1051,15 @@ 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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if SYN */
|
||||
if (tcp->flags & 0x02) {
|
||||
|
@ -1101,12 +1104,12 @@ static void tcp_input(struct ipstack *S, struct ipstack_tcp_seg *tcp, uint32_t f
|
|||
/* FIN */
|
||||
if (t->sock.tcp.state == TCP_ESTABLISHED) {
|
||||
t->sock.tcp.state = TCP_CLOSE_WAIT;
|
||||
t->events |= CB_EVENT_CLOSED;
|
||||
t->events &= ~CB_EVENT_READABLE;
|
||||
} else if (t->sock.tcp.state == TCP_FIN_WAIT_1) {
|
||||
t->sock.tcp.state = TCP_CLOSING;
|
||||
}
|
||||
t->sock.tcp.ack = ee32(tcp->seq) + 1;
|
||||
t->events |= CB_EVENT_CLOSED;
|
||||
tcp_send_ack(t);
|
||||
}
|
||||
if (tcp->flags & 0x10) {
|
||||
|
@ -1170,7 +1173,7 @@ static void close_socket(struct tsocket *ts)
|
|||
}
|
||||
|
||||
|
||||
int posix_socket(struct ipstack *s, int domain, int type, int protocol)
|
||||
int ft_socket(struct ipstack *s, int domain, int type, int protocol)
|
||||
{
|
||||
struct tsocket *ts;
|
||||
if (domain != AF_INET)
|
||||
|
@ -1190,7 +1193,7 @@ int posix_socket(struct ipstack *s, int domain, int type, int protocol)
|
|||
return -1;
|
||||
}
|
||||
|
||||
int posix_connect(struct ipstack *s, int sockfd, const struct ipstack_sockaddr *addr, socklen_t addrlen)
|
||||
int ft_connect(struct ipstack *s, int sockfd, const struct ipstack_sockaddr *addr, socklen_t addrlen)
|
||||
{
|
||||
struct tsocket *ts;
|
||||
struct ipstack_sockaddr_in *sin = (struct ipstack_sockaddr_in *)addr;
|
||||
|
@ -1228,7 +1231,7 @@ int posix_connect(struct ipstack *s, int sockfd, const struct ipstack_sockaddr *
|
|||
return -2;
|
||||
}
|
||||
|
||||
int posix_accept(struct ipstack *s, int sockfd, struct ipstack_sockaddr *addr, socklen_t *addrlen)
|
||||
int ft_accept(struct ipstack *s, int sockfd, struct ipstack_sockaddr *addr, socklen_t *addrlen)
|
||||
{
|
||||
struct tsocket *ts;
|
||||
struct ipstack_sockaddr_in *sin = (struct ipstack_sockaddr_in *)addr;
|
||||
|
@ -1251,6 +1254,9 @@ int posix_accept(struct ipstack *s, int sockfd, struct ipstack_sockaddr *addr, s
|
|||
if (!newts)
|
||||
return -1;
|
||||
ts->events &= ~CB_EVENT_READABLE;
|
||||
newts->events |= CB_EVENT_WRITABLE;
|
||||
newts->callback = ts->callback;
|
||||
newts->callback_arg = ts->callback_arg;
|
||||
newts->local_ip = ts->local_ip;
|
||||
newts->remote_ip = ts->remote_ip;
|
||||
newts->src_port = ts->src_port;
|
||||
|
@ -1273,10 +1279,10 @@ int posix_accept(struct ipstack *s, int sockfd, struct ipstack_sockaddr *addr, s
|
|||
return -1;;
|
||||
}
|
||||
|
||||
int posix_sendto(struct ipstack *s, int sockfd, const void *buf, size_t len, int flags,
|
||||
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)
|
||||
{
|
||||
uint8_t frame[LINK_MTU];
|
||||
uint8_t frame[LINK_MTU];
|
||||
struct tsocket *ts;
|
||||
struct ipstack_tcp_seg *tcp = (struct ipstack_tcp_seg *)frame;
|
||||
struct ipstack_udp_datagram *udp = (struct ipstack_udp_datagram *)frame;
|
||||
|
@ -1356,7 +1362,7 @@ int posix_sendto(struct ipstack *s, int sockfd, const void *buf, size_t len, int
|
|||
} else return -1;
|
||||
}
|
||||
|
||||
int posix_recvfrom(struct ipstack *s, int sockfd, void *buf, size_t len, int flags,
|
||||
int ft_recvfrom(struct ipstack *s, int sockfd, void *buf, size_t len, int flags,
|
||||
struct ipstack_sockaddr *src_addr, socklen_t *addrlen)
|
||||
{
|
||||
uint32_t seg_len;
|
||||
|
@ -1402,12 +1408,13 @@ int posix_recvfrom(struct ipstack *s, int sockfd, void *buf, size_t len, int fla
|
|||
} else return -1;
|
||||
}
|
||||
|
||||
int posix_close(struct ipstack *s, int sockfd)
|
||||
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) {
|
||||
|
@ -1436,7 +1443,7 @@ int posix_close(struct ipstack *s, int sockfd)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int posix_getsockname(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)
|
||||
{
|
||||
struct tsocket *ts = &s->tcpsockets[sockfd];
|
||||
struct ipstack_sockaddr_in *sin = (struct ipstack_sockaddr_in *)addr;
|
||||
|
@ -1448,7 +1455,7 @@ int posix_getsockname(struct ipstack *s, int sockfd, struct ipstack_sockaddr *ad
|
|||
return 0;
|
||||
}
|
||||
|
||||
int posix_bind(struct ipstack *s, int sockfd, const struct ipstack_sockaddr *addr, socklen_t addrlen)
|
||||
int ft_bind(struct ipstack *s, int sockfd, const struct ipstack_sockaddr *addr, socklen_t addrlen)
|
||||
{
|
||||
struct tsocket *ts;
|
||||
struct ipstack_sockaddr_in *sin = (struct ipstack_sockaddr_in *)addr;
|
||||
|
@ -1476,7 +1483,7 @@ int posix_bind(struct ipstack *s, int sockfd, const struct ipstack_sockaddr *add
|
|||
|
||||
}
|
||||
|
||||
int posix_listen(struct ipstack *s, int sockfd, int backlog)
|
||||
int ft_listen(struct ipstack *s, int sockfd, int backlog)
|
||||
{
|
||||
struct tsocket *ts;
|
||||
(void)backlog;
|
||||
|
@ -1489,7 +1496,7 @@ int posix_listen(struct ipstack *s, int sockfd, int backlog)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int posix_getpeername(struct ipstack *s, int sockfd, struct ipstack_sockaddr *addr, socklen_t *addrlen)
|
||||
int ft_getpeername(struct ipstack *s, int sockfd, struct ipstack_sockaddr *addr, socklen_t *addrlen)
|
||||
{
|
||||
struct tsocket *ts = &s->tcpsockets[sockfd];
|
||||
struct ipstack_sockaddr_in *sin = (struct ipstack_sockaddr_in *)addr;
|
||||
|
@ -1643,7 +1650,7 @@ static int dhcp_poll(struct ipstack *s)
|
|||
struct dhcp_msg msg;
|
||||
int len;
|
||||
memset(&msg, 0xBB, sizeof(msg));
|
||||
len = posix_recvfrom(s, s->dhcp_udp_sd, &msg, sizeof(struct dhcp_msg), 0, (struct ipstack_sockaddr *)&sin, &sl);
|
||||
len = ft_recvfrom(s, s->dhcp_udp_sd, &msg, sizeof(struct dhcp_msg), 0, (struct ipstack_sockaddr *)&sin, &sl);
|
||||
if (len < 0)
|
||||
return -1;
|
||||
if ((s->dhcp_state == DHCP_DISCOVER_SENT) && (dhcp_parse_offer(s, &msg) == 0))
|
||||
|
@ -1705,7 +1712,7 @@ static int dhcp_send_request(struct ipstack *s)
|
|||
sin.sin_port = ee16(DHCP_SERVER_PORT);
|
||||
sin.sin_addr.s_addr = ee32(0xFFFFFFFF); /* Broadcast */
|
||||
sin.sin_family = AF_INET;
|
||||
posix_sendto(s, s->dhcp_udp_sd, &req, DHCP_HEADER_LEN + opt_sz, 0,
|
||||
ft_sendto(s, s->dhcp_udp_sd, &req, DHCP_HEADER_LEN + opt_sz, 0,
|
||||
(struct ipstack_sockaddr *)&sin, sizeof(struct ipstack_sockaddr_in));
|
||||
tmr.expires = s->last_tick + DHCP_REQUEST_TIMEOUT + (ipstack_getrandom() % 200);
|
||||
tmr.arg = s;
|
||||
|
@ -1749,7 +1756,7 @@ static int dhcp_send_discover(struct ipstack *s)
|
|||
sin.sin_port = ee16(DHCP_SERVER_PORT);
|
||||
sin.sin_addr.s_addr = ee32(0xFFFFFFFF); /* Broadcast */
|
||||
sin.sin_family = AF_INET;
|
||||
posix_sendto(s, s->dhcp_udp_sd, &disc, DHCP_HEADER_LEN + opt_sz, 0,
|
||||
ft_sendto(s, s->dhcp_udp_sd, &disc, DHCP_HEADER_LEN + opt_sz, 0,
|
||||
(struct ipstack_sockaddr *)&sin, sizeof(struct ipstack_sockaddr_in));
|
||||
tmr.expires = s->last_tick + DHCP_DISCOVER_TIMEOUT + (ipstack_getrandom() % 200);
|
||||
tmr.arg = s;
|
||||
|
@ -1773,10 +1780,10 @@ int dhcp_client_init(struct ipstack *s)
|
|||
s->dhcp_xid = ipstack_getrandom();
|
||||
|
||||
if (s->dhcp_udp_sd > 0) {
|
||||
posix_close(s, s->dhcp_udp_sd);
|
||||
ft_close(s, s->dhcp_udp_sd);
|
||||
}
|
||||
|
||||
s->dhcp_udp_sd = posix_socket(s, AF_INET, IPSTACK_SOCK_DGRAM, 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;
|
||||
|
@ -1784,7 +1791,7 @@ int dhcp_client_init(struct ipstack *s)
|
|||
memset(&sin, 0, sizeof(struct ipstack_sockaddr_in));
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = ee16(DHCP_CLIENT_PORT);
|
||||
if (posix_bind(s, s->dhcp_udp_sd, (struct ipstack_sockaddr *)&sin, sizeof(struct ipstack_sockaddr_in)) < 0) {
|
||||
if (ft_bind(s, s->dhcp_udp_sd, (struct ipstack_sockaddr *)&sin, sizeof(struct ipstack_sockaddr_in)) < 0) {
|
||||
s->dhcp_state = DHCP_OFF;
|
||||
return -1;
|
||||
}
|
||||
|
@ -1893,7 +1900,7 @@ void ipstack_init_static(struct ipstack **s)
|
|||
/* 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
|
||||
* received packets.
|
||||
* received packets.
|
||||
*
|
||||
* This function also handles timers for all supported protocols.
|
||||
*
|
||||
|
@ -1966,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];
|
||||
|
@ -2006,7 +2014,7 @@ int ipstack_poll(struct ipstack *s, uint64_t now)
|
|||
struct ipstack_timer tmr = {};
|
||||
len = desc->len - ETH_HEADER_LEN;
|
||||
tcp = (struct ipstack_tcp_seg *)(ts->txmem + desc->pos + sizeof(*desc));
|
||||
if ((ts->sock.tcp.ack == ts->sock.tcp.last_ack) &&
|
||||
if ((ts->sock.tcp.ack == ts->sock.tcp.last_ack) &&
|
||||
(len == IP_HEADER_LEN + (uint32_t)(tcp->hlen >> 2)) &&
|
||||
(tcp->flags == 0x10)) {
|
||||
desc->flags |= PKT_FLAG_SENT;
|
||||
|
@ -2054,7 +2062,7 @@ int ipstack_poll(struct ipstack *s, uint64_t now)
|
|||
/* Send ARP request */
|
||||
arp_request(s, nexthop);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (IS_IP_BCAST(nexthop)) memset(t->nexthop_mac, 0xFF, 6);
|
||||
#endif
|
||||
len = desc->len - ETH_HEADER_LEN;
|
||||
|
|
140
src/port/linux.c
Normal file
140
src/port/linux.c
Normal file
|
@ -0,0 +1,140 @@
|
|||
#include <net/if.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
/* tap device */
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/if_tun.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/poll.h>
|
||||
#include <string.h>
|
||||
#include "femtotcp.h"
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
static int tap_fd;
|
||||
|
||||
void print_buffer(uint8_t *buf, int len)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < len; i++) {
|
||||
if (i % 16 == 0)
|
||||
printf("\n");
|
||||
printf("%02x ", buf[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static int tap_poll(struct ll *ll, void *buf, int len)
|
||||
{
|
||||
struct pollfd pfd;
|
||||
(void)ll;
|
||||
int ret;
|
||||
pfd.fd = tap_fd;
|
||||
pfd.events = POLLIN;
|
||||
ret = poll(&pfd, 1, 2);
|
||||
if (ret < 0) {
|
||||
perror("poll");
|
||||
return -1;
|
||||
}
|
||||
if (ret == 0) {
|
||||
return 0;
|
||||
}
|
||||
return read(tap_fd, buf, len);
|
||||
}
|
||||
|
||||
static int tap_send(struct ll *ll, void *buf, int len)
|
||||
{
|
||||
(void)ll;
|
||||
//print_buffer(buf, len);
|
||||
return write(tap_fd, buf, len);
|
||||
}
|
||||
|
||||
int tap_init(struct ll *ll, const char *ifname, uint32_t host_ip)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
struct sockaddr_in *addr;
|
||||
int sock_fd;
|
||||
|
||||
if ((tap_fd = open("/dev/net/tun", O_RDWR)) < 0) {
|
||||
perror("accessing /dev/net/tun");
|
||||
return -1;
|
||||
}
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
|
||||
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
|
||||
if (ioctl(tap_fd, TUNSETIFF, (void *)&ifr) < 0) {
|
||||
perror("ioctl TUNSETIFF");
|
||||
close(tap_fd);
|
||||
return -1;
|
||||
}
|
||||
/* Get mac address */
|
||||
if (ioctl(tap_fd, SIOCGIFHWADDR, &ifr) < 0) {
|
||||
perror("ioctl SIOCGIFHWADDR");
|
||||
close(tap_fd);
|
||||
return -1;
|
||||
}
|
||||
strncpy(ll->ifname, ifname, sizeof(ll->ifname) - 1);
|
||||
memcpy(ll->mac, ifr.ifr_hwaddr.sa_data, 6);
|
||||
ll->mac[5] ^= 1;
|
||||
ll->poll = tap_poll;
|
||||
ll->send = tap_send;
|
||||
|
||||
|
||||
/* Set up network side */
|
||||
sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sock_fd < 0) {
|
||||
perror("socket");
|
||||
close(tap_fd);
|
||||
return -1;
|
||||
}
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
|
||||
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
|
||||
if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr) < 0) {
|
||||
perror("ioctl SIOCGIFFLAGS");
|
||||
close(sock_fd);
|
||||
return -1;
|
||||
}
|
||||
ifr.ifr_flags |= IFF_UP;
|
||||
if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) < 0) {
|
||||
perror("ioctl SIOCSIFFLAGS");
|
||||
close(sock_fd);
|
||||
return -1;
|
||||
}
|
||||
addr = (struct sockaddr_in *)&ifr.ifr_addr;
|
||||
addr->sin_family = AF_INET;
|
||||
addr->sin_addr.s_addr = host_ip;
|
||||
if (ioctl(sock_fd, SIOCSIFADDR, &ifr) < 0) {
|
||||
perror("ioctl SIOCSIFADDR");
|
||||
close(sock_fd);
|
||||
return -1;
|
||||
}
|
||||
inet_pton(AF_INET, "255.255.255.0", &addr->sin_addr);
|
||||
if (ioctl(sock_fd, SIOCSIFNETMASK, &ifr) < 0) {
|
||||
perror("ioctl SIOCSIFNETMASK");
|
||||
close(sock_fd);
|
||||
return -1;
|
||||
}
|
||||
if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr) < 0) {
|
||||
perror("ioctl SIOCGIFFLAGS");
|
||||
close(sock_fd);
|
||||
return -1;
|
||||
}
|
||||
ifr.ifr_flags = IFF_UP | IFF_RUNNING;
|
||||
if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) < 0) {
|
||||
perror("ioctl SIOCSIFFLAGS");
|
||||
close(sock_fd);
|
||||
return -1;
|
||||
}
|
||||
printf("Successfully initialized tap device %s\n", ifname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <sys/random.h>
|
||||
uint32_t ipstack_getrandom(void)
|
||||
{
|
||||
uint32_t ret;
|
||||
getrandom(&ret, sizeof(ret), 0);
|
||||
return ret;
|
||||
}
|
|
@ -1,171 +1,104 @@
|
|||
#include <net/if.h>
|
||||
#include <stdio.h>
|
||||
/* tap device */
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/if_tun.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/poll.h>
|
||||
#include <string.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include "femtotcp.h"
|
||||
static int tap_fd;
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
//#define DHCP
|
||||
#define FEMTOTCP_IP "10.10.10.2"
|
||||
#define LINUX_IP "10.10.10.1"
|
||||
#define TEST_SIZE (8 * 1024)
|
||||
|
||||
void print_buffer(uint8_t *buf, int len)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < len; i++) {
|
||||
if (i % 16 == 0)
|
||||
printf("\n");
|
||||
printf("%02x ", buf[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int tap_poll(struct ll *ll, void *buf, int len)
|
||||
{
|
||||
struct pollfd pfd;
|
||||
(void)ll;
|
||||
int ret;
|
||||
pfd.fd = tap_fd;
|
||||
pfd.events = POLLIN;
|
||||
ret = poll(&pfd, 1, 2);
|
||||
if (ret < 0) {
|
||||
perror("poll");
|
||||
return -1;
|
||||
}
|
||||
if (ret == 0) {
|
||||
return 0;
|
||||
}
|
||||
return read(tap_fd, buf, len);
|
||||
}
|
||||
|
||||
int tap_send(struct ll *ll, void *buf, int len)
|
||||
{
|
||||
(void)ll;
|
||||
//print_buffer(buf, len);
|
||||
return write(tap_fd, buf, len);
|
||||
}
|
||||
|
||||
int tap_init(struct ll *ll, const char *ifname)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
struct sockaddr_in *addr;
|
||||
int sock_fd;
|
||||
|
||||
if ((tap_fd = open("/dev/net/tun", O_RDWR)) < 0) {
|
||||
perror("accessing /dev/net/tun");
|
||||
return -1;
|
||||
}
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
|
||||
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
|
||||
if (ioctl(tap_fd, TUNSETIFF, (void *)&ifr) < 0) {
|
||||
perror("ioctl TUNSETIFF");
|
||||
close(tap_fd);
|
||||
return -1;
|
||||
}
|
||||
/* Get mac address */
|
||||
if (ioctl(tap_fd, SIOCGIFHWADDR, &ifr) < 0) {
|
||||
perror("ioctl SIOCGIFHWADDR");
|
||||
close(tap_fd);
|
||||
return -1;
|
||||
}
|
||||
strncpy(ll->ifname, ifname, sizeof(ll->ifname) - 1);
|
||||
memcpy(ll->mac, ifr.ifr_hwaddr.sa_data, 6);
|
||||
ll->mac[5] ^= 1;
|
||||
ll->poll = tap_poll;
|
||||
ll->send = tap_send;
|
||||
|
||||
|
||||
/* Set up network side */
|
||||
sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sock_fd < 0) {
|
||||
perror("socket");
|
||||
close(tap_fd);
|
||||
return -1;
|
||||
}
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
|
||||
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
|
||||
if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr) < 0) {
|
||||
perror("ioctl SIOCGIFFLAGS");
|
||||
close(sock_fd);
|
||||
return -1;
|
||||
}
|
||||
ifr.ifr_flags |= IFF_UP;
|
||||
if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) < 0) {
|
||||
perror("ioctl SIOCSIFFLAGS");
|
||||
close(sock_fd);
|
||||
return -1;
|
||||
}
|
||||
addr = (struct sockaddr_in *)&ifr.ifr_addr;
|
||||
addr->sin_family = AF_INET;
|
||||
inet_pton(AF_INET, LINUX_IP, &addr->sin_addr);
|
||||
if (ioctl(sock_fd, SIOCSIFADDR, &ifr) < 0) {
|
||||
perror("ioctl SIOCSIFADDR");
|
||||
close(sock_fd);
|
||||
return -1;
|
||||
}
|
||||
inet_pton(AF_INET, "255.255.255.0", &addr->sin_addr);
|
||||
if (ioctl(sock_fd, SIOCSIFNETMASK, &ifr) < 0) {
|
||||
perror("ioctl SIOCSIFNETMASK");
|
||||
close(sock_fd);
|
||||
return -1;
|
||||
}
|
||||
if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr) < 0) {
|
||||
perror("ioctl SIOCGIFFLAGS");
|
||||
close(sock_fd);
|
||||
return -1;
|
||||
}
|
||||
ifr.ifr_flags = IFF_UP | IFF_RUNNING;
|
||||
if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) < 0) {
|
||||
perror("ioctl SIOCSIFFLAGS");
|
||||
close(sock_fd);
|
||||
return -1;
|
||||
}
|
||||
printf("Successfully initialized tap device %s\n", ifname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <sys/random.h>
|
||||
uint32_t ipstack_getrandom(void)
|
||||
{
|
||||
uint32_t ret;
|
||||
getrandom(&ret, sizeof(ret), 0);
|
||||
return ret;
|
||||
}
|
||||
#define BUFFER_SIZE TEST_SIZE
|
||||
static int test_echoserver_closewait(struct ipstack *s)
|
||||
|
||||
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 server_closing = 0;
|
||||
static int closed = 0;
|
||||
|
||||
static void socket_cb(int fd, uint16_t event, void *arg)
|
||||
{
|
||||
int fd, ret;
|
||||
int client_fd = -1;
|
||||
int tot_sent = 0;
|
||||
int exit_ok = 0, exit_count = 0;
|
||||
struct ipstack_sockaddr_in local_sock = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_port = ee16(8), /* Echo */
|
||||
.sin_addr.s_addr = 0
|
||||
};
|
||||
fd = posix_socket(s, AF_INET, IPSTACK_SOCK_STREAM, 0);
|
||||
printf("socket: %04x\n", fd);
|
||||
ret = posix_bind(s, fd, (struct ipstack_sockaddr *)&local_sock, sizeof(local_sock));
|
||||
printf("bind: %d\n", ret);
|
||||
ret = posix_listen(s, fd, 1);
|
||||
printf("listen: %d\n", ret);
|
||||
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: %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) && 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 = 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;
|
||||
}
|
||||
|
||||
|
||||
static int test_echoserver(struct ipstack *s, int active_close)
|
||||
{
|
||||
exit_ok = 0;
|
||||
exit_count = 0;
|
||||
tot_sent = 0;
|
||||
server_closing = active_close;
|
||||
closed = 0;
|
||||
|
||||
while(1) {
|
||||
uint32_t ms_next;
|
||||
uint8_t buf[BUFFER_SIZE];
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
ms_next = ipstack_poll(s, tv.tv_sec * 1000 + tv.tv_usec / 1000);
|
||||
|
@ -175,55 +108,11 @@ static int test_echoserver_closewait(struct ipstack *s)
|
|||
continue;
|
||||
else break;
|
||||
}
|
||||
if (client_fd < 0) {
|
||||
client_fd = posix_accept(s, fd, NULL, NULL);
|
||||
if (client_fd > 0) {
|
||||
printf("accept: %04x\n", client_fd);
|
||||
}
|
||||
} else {
|
||||
if (ret <= 0) {
|
||||
ret = posix_recvfrom(s, client_fd, buf, sizeof(buf), 0, NULL, NULL);
|
||||
if (ret == -11)
|
||||
continue; /* Call again */
|
||||
if (ret < 0) {
|
||||
printf("Recv error: %d\n", ret);
|
||||
posix_close(s, client_fd);
|
||||
return -1;
|
||||
} else if (ret == 0) {
|
||||
printf("Client side closed the connection.\n");
|
||||
posix_close(s, client_fd);
|
||||
client_fd = -1;
|
||||
printf("Server: Exiting.\n");
|
||||
exit_ok = 1;
|
||||
continue;
|
||||
} else if (ret > 0) {
|
||||
printf("recv: %d, echoing back\n", ret);
|
||||
}
|
||||
}
|
||||
if (ret > 0) {
|
||||
int snd_ret;
|
||||
snd_ret = posix_sendto(s, client_fd, buf + tot_sent, ret - tot_sent, 0, NULL, 0);
|
||||
if (snd_ret == -11)
|
||||
continue; /* Call again */
|
||||
if (snd_ret < 0) {
|
||||
printf("Send error: %d\n", snd_ret);
|
||||
posix_close(s, client_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
tot_sent += snd_ret;
|
||||
printf("sent %d bytes\n", snd_ret);
|
||||
if (ret == tot_sent) {
|
||||
tot_sent = 0;
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *pt_echoclient_closing(void *arg)
|
||||
void *pt_echoclient(void *arg)
|
||||
{
|
||||
int fd, ret;
|
||||
unsigned total_r = 0;
|
||||
|
@ -265,7 +154,10 @@ static void *pt_echoclient_closing(void *arg)
|
|||
}
|
||||
if (ret == 0) {
|
||||
printf("test client read: server has closed the connection.\n");
|
||||
return (void *)-1;
|
||||
if (server_closing)
|
||||
return (void *)0;
|
||||
else
|
||||
return (void *)-1;
|
||||
}
|
||||
total_r += ret;
|
||||
}
|
||||
|
@ -283,35 +175,43 @@ static void *pt_echoclient_closing(void *arg)
|
|||
return (void *)0;
|
||||
}
|
||||
|
||||
extern int tap_init(struct ll *dev, const char *name, uint32_t host_ip);
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
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
|
||||
};
|
||||
|
||||
int ret, test_ret;
|
||||
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)
|
||||
return 1;
|
||||
|
||||
|
||||
if (tap_init(tapdev, "femt0") < 0) {
|
||||
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 &");
|
||||
sleep(1);
|
||||
|
||||
#ifdef DHCP
|
||||
gettimeofday(&tv, NULL);
|
||||
|
@ -333,14 +233,32 @@ int main(int argc, char **argv)
|
|||
inet_pton(AF_INET, FEMTOTCP_IP, &srv_ip);
|
||||
#endif
|
||||
|
||||
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_closing, &srv_ip);
|
||||
pthread_create(&pt, NULL, pt_echoclient, &srv_ip);
|
||||
printf("Starting test: echo server close-wait\n");
|
||||
ret = test_echoserver_closewait(s);
|
||||
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;
|
||||
}
|
||||
|
|
510
test/unit/unit.c
510
test/unit/unit.c
|
@ -45,162 +45,10 @@ void mock_link_init(struct ipstack *s)
|
|||
ll->send = mock_send;
|
||||
}
|
||||
|
||||
START_TEST(test_arp_request_basic)
|
||||
{
|
||||
struct ipstack s;
|
||||
struct arp_packet *arp;
|
||||
ipstack_init(&s);
|
||||
uint32_t target_ip = 0xC0A80002; /* 192.168.0.2 */
|
||||
mock_link_init(&s);
|
||||
s.last_tick = 1000;
|
||||
arp_request(&s, target_ip);
|
||||
ck_assert_int_eq(last_frame_sent_size, sizeof(struct arp_packet));
|
||||
arp = (struct arp_packet *)last_frame_sent;
|
||||
ck_assert_mem_eq(arp->eth.dst, "\xff\xff\xff\xff\xff\xff", 6);
|
||||
ck_assert_mem_eq(arp->eth.src, s.ll_dev.mac, 6);
|
||||
ck_assert_int_eq(arp->eth.type, ee16(0x0806));
|
||||
ck_assert_int_eq(arp->htype, ee16(1));
|
||||
ck_assert_int_eq(arp->ptype, ee16(0x0800));
|
||||
ck_assert_int_eq(arp->hlen, 6);
|
||||
ck_assert_int_eq(arp->plen, 4);
|
||||
ck_assert_int_eq(arp->opcode, ee16(ARP_REQUEST));
|
||||
ck_assert_mem_eq(arp->sma, s.ll_dev.mac, 6);
|
||||
ck_assert_int_eq(arp->sip, ee32(s.ipconf.ip));
|
||||
ck_assert_mem_eq(arp->tma, "\x00\x00\x00\x00\x00\x00", 6);
|
||||
ck_assert_int_eq(arp->tip, ee32(target_ip));
|
||||
static struct timers_binheap heap;
|
||||
static void reset_heap(void) {
|
||||
heap.size = 0;
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_arp_request_throttle)
|
||||
{
|
||||
struct ipstack s;
|
||||
ipstack_init(&s);
|
||||
uint32_t target_ip = 0xC0A80002; /*192.168.0.2*/
|
||||
mock_link_init(&s);
|
||||
s.last_tick = 1000;
|
||||
s.arp.last_arp = 880;
|
||||
last_frame_sent_size = 0;
|
||||
arp_request(&s, target_ip);
|
||||
ck_assert_int_eq(last_frame_sent_size, 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_arp_request_target_ip) {
|
||||
uint32_t target_ip = 0xC0A80002;
|
||||
struct ipstack s;
|
||||
ipstack_init(&s);
|
||||
mock_link_init(&s);
|
||||
s.last_tick = 1000;
|
||||
arp_request(&s, target_ip);
|
||||
ck_assert_int_eq(((struct arp_packet *)(last_frame_sent))->tip, ee32(target_ip));
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_arp_request_handling) {
|
||||
struct arp_packet arp_req;
|
||||
struct arp_packet *arp_reply;
|
||||
memset(&arp_req, 0, sizeof(arp_req));
|
||||
uint32_t req_ip = 0xC0A80002; // 192.168.0.2
|
||||
uint32_t device_ip = 0xC0A80001; // 192.168.0.1
|
||||
uint8_t req_mac[6] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF};
|
||||
//uint8_t mac[6] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55};
|
||||
struct ipstack s;
|
||||
ipstack_init(&s);
|
||||
mock_link_init(&s);
|
||||
s.ipconf.ip = device_ip;
|
||||
|
||||
/* Prepare ARP request */
|
||||
arp_req.opcode = ee16(ARP_REQUEST);
|
||||
arp_req.sip = ee32(req_ip);
|
||||
memcpy(arp_req.sma, req_mac, 6);
|
||||
arp_req.tip = ee32(device_ip);
|
||||
|
||||
/* Call arp_recv with the ARP request */
|
||||
arp_recv(&s, &arp_req, sizeof(arp_req));
|
||||
ipstack_poll(&s, 1000);
|
||||
ipstack_poll(&s, 1001);
|
||||
ipstack_poll(&s, 1002);
|
||||
|
||||
/* Check if ARP table updated with requester's MAC and IP */
|
||||
/* TODO */
|
||||
//ck_assert_int_eq(arp_lookup(&s, req_ip, mac), 0);
|
||||
//ck_assert_mem_eq(mac, req_mac, 6);
|
||||
|
||||
/* Check if an ARP reply was generated */
|
||||
arp_reply = (struct arp_packet *)last_frame_sent;
|
||||
ck_assert_int_eq(last_frame_sent_size, sizeof(struct arp_packet));
|
||||
ck_assert_int_eq(arp_reply->opcode, ee16(ARP_REPLY));
|
||||
ck_assert_mem_eq(arp_reply->sma, s.ll_dev.mac, 6); // source MAC
|
||||
ck_assert_int_eq(arp_reply->sip, ee32(device_ip)); // source IP
|
||||
ck_assert_mem_eq(arp_reply->tma, req_mac, 6); // target MAC
|
||||
ck_assert_int_eq(arp_reply->tip, ee32(req_ip)); // target IP
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_arp_reply_handling) {
|
||||
struct arp_packet arp_reply;
|
||||
memset(&arp_reply, 0, sizeof(arp_reply));
|
||||
uint32_t reply_ip = 0xC0A80003; // 192.168.0.3
|
||||
uint8_t reply_mac[6] = {0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x01};
|
||||
struct ipstack s;
|
||||
ipstack_init(&s);
|
||||
mock_link_init(&s);
|
||||
|
||||
/* Prepare ARP reply */
|
||||
arp_reply.opcode = ee16(ARP_REPLY);
|
||||
arp_reply.sip = ee32(reply_ip);
|
||||
memcpy(arp_reply.sma, reply_mac, 6);
|
||||
|
||||
/* Call arp_recv with the ARP reply */
|
||||
arp_recv(&s, &arp_reply, sizeof(arp_reply));
|
||||
|
||||
/* Check if ARP table updated with reply IP and MAC */
|
||||
ck_assert_int_eq(s.arp.neighbors[0].ip, reply_ip);
|
||||
ck_assert_mem_eq(s.arp.neighbors[0].mac, reply_mac, 6);
|
||||
|
||||
/* Update same IP with a different MAC address */
|
||||
uint8_t new_mac[6] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
|
||||
memcpy(arp_reply.sma, new_mac, 6);
|
||||
arp_recv(&s, &arp_reply, sizeof(arp_reply));
|
||||
|
||||
/* Check if ARP table updates with new MAC */
|
||||
ck_assert_mem_eq(s.arp.neighbors[0].mac, new_mac, 6);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_arp_lookup_success) {
|
||||
uint8_t found_mac[6];
|
||||
uint32_t ip = 0xC0A80002;
|
||||
const uint8_t mock_mac[6] = {0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x01};
|
||||
struct ipstack s;
|
||||
ipstack_init(&s);
|
||||
mock_link_init(&s);
|
||||
|
||||
/* Add a known IP-MAC pair */
|
||||
s.arp.neighbors[0].ip = ip;
|
||||
memcpy(s.arp.neighbors[0].mac, mock_mac, 6);
|
||||
|
||||
/* Test arp_lookup */
|
||||
int result = arp_lookup(&s, ip, found_mac);
|
||||
ck_assert_int_eq(result, 0);
|
||||
ck_assert_mem_eq(found_mac, mock_mac, 6);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_arp_lookup_failure) {
|
||||
uint8_t found_mac[6];
|
||||
uint32_t ip = 0xC0A80004;
|
||||
struct ipstack s;
|
||||
ipstack_init(&s);
|
||||
mock_link_init(&s);
|
||||
|
||||
/* Ensure arp_lookup fails for unknown IP */
|
||||
int result = arp_lookup(&s, ip, found_mac);
|
||||
ck_assert_int_eq(result, -1);
|
||||
uint8_t zero_mac[6] = {0, 0, 0, 0, 0, 0};
|
||||
ck_assert_mem_eq(found_mac, zero_mac, 6);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST(test_fifo_init)
|
||||
|
@ -505,19 +353,348 @@ START_TEST(test_queue_pop_wraparound) {
|
|||
END_TEST
|
||||
|
||||
|
||||
/* Utils */
|
||||
START_TEST(test_insert_timer) {
|
||||
reset_heap();
|
||||
|
||||
struct ipstack_timer tmr1 = { .expires = 100 };
|
||||
struct ipstack_timer tmr2 = { .expires = 50 };
|
||||
struct ipstack_timer tmr3 = { .expires = 200 };
|
||||
|
||||
int id1 = timers_binheap_insert(&heap, tmr1);
|
||||
int id2 = timers_binheap_insert(&heap, tmr2);
|
||||
int id3 = timers_binheap_insert(&heap, tmr3);
|
||||
|
||||
ck_assert_int_eq(heap.size, 3);
|
||||
ck_assert_int_lt(heap.timers[0].expires, heap.timers[1].expires);
|
||||
ck_assert_int_lt(heap.timers[0].expires, heap.timers[2].expires);
|
||||
ck_assert_int_ne(id1, id2);
|
||||
ck_assert_int_ne(id2, id3);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_pop_timer) {
|
||||
reset_heap();
|
||||
|
||||
struct ipstack_timer tmr1 = { .expires = 300 };
|
||||
struct ipstack_timer tmr2 = { .expires = 100 };
|
||||
struct ipstack_timer tmr3 = { .expires = 200 };
|
||||
|
||||
timers_binheap_insert(&heap, tmr1);
|
||||
timers_binheap_insert(&heap, tmr2);
|
||||
timers_binheap_insert(&heap, tmr3);
|
||||
|
||||
struct ipstack_timer popped = timers_binheap_pop(&heap);
|
||||
ck_assert_int_eq(popped.expires, 100);
|
||||
ck_assert_int_eq(heap.size, 2);
|
||||
ck_assert_int_lt(heap.timers[0].expires, heap.timers[1].expires);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_is_timer_expired) {
|
||||
reset_heap();
|
||||
|
||||
struct ipstack_timer tmr = { .expires = 150 };
|
||||
timers_binheap_insert(&heap, tmr);
|
||||
|
||||
ck_assert_int_eq(is_timer_expired(&heap, 100), 0);
|
||||
ck_assert_int_eq(is_timer_expired(&heap, 150), 1);
|
||||
ck_assert_int_eq(is_timer_expired(&heap, 200), 1);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_cancel_timer) {
|
||||
reset_heap();
|
||||
|
||||
struct ipstack_timer tmr1 = { .expires = 100 };
|
||||
struct ipstack_timer tmr2 = { .expires = 200 };
|
||||
|
||||
int id1 = timers_binheap_insert(&heap, tmr1);
|
||||
int id2 = timers_binheap_insert(&heap, tmr2);
|
||||
(void)id2;
|
||||
|
||||
timer_binheap_cancel(&heap, id1);
|
||||
ck_assert_int_eq(heap.timers[0].expires, 0); // tmr1 canceled
|
||||
|
||||
struct ipstack_timer popped = timers_binheap_pop(&heap);
|
||||
ck_assert_int_eq(popped.expires, 200); // Only tmr2 should remain
|
||||
ck_assert_int_eq(heap.size, 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
/* Arp suite */
|
||||
START_TEST(test_arp_request_basic)
|
||||
{
|
||||
struct ipstack s;
|
||||
struct arp_packet *arp;
|
||||
ipstack_init(&s);
|
||||
uint32_t target_ip = 0xC0A80002; /* 192.168.0.2 */
|
||||
mock_link_init(&s);
|
||||
s.last_tick = 1000;
|
||||
arp_request(&s, target_ip);
|
||||
ck_assert_int_eq(last_frame_sent_size, sizeof(struct arp_packet));
|
||||
arp = (struct arp_packet *)last_frame_sent;
|
||||
ck_assert_mem_eq(arp->eth.dst, "\xff\xff\xff\xff\xff\xff", 6);
|
||||
ck_assert_mem_eq(arp->eth.src, s.ll_dev.mac, 6);
|
||||
ck_assert_int_eq(arp->eth.type, ee16(0x0806));
|
||||
ck_assert_int_eq(arp->htype, ee16(1));
|
||||
ck_assert_int_eq(arp->ptype, ee16(0x0800));
|
||||
ck_assert_int_eq(arp->hlen, 6);
|
||||
ck_assert_int_eq(arp->plen, 4);
|
||||
ck_assert_int_eq(arp->opcode, ee16(ARP_REQUEST));
|
||||
ck_assert_mem_eq(arp->sma, s.ll_dev.mac, 6);
|
||||
ck_assert_int_eq(arp->sip, ee32(s.ipconf.ip));
|
||||
ck_assert_mem_eq(arp->tma, "\x00\x00\x00\x00\x00\x00", 6);
|
||||
ck_assert_int_eq(arp->tip, ee32(target_ip));
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_arp_request_throttle)
|
||||
{
|
||||
struct ipstack s;
|
||||
ipstack_init(&s);
|
||||
uint32_t target_ip = 0xC0A80002; /*192.168.0.2*/
|
||||
mock_link_init(&s);
|
||||
s.last_tick = 1000;
|
||||
s.arp.last_arp = 880;
|
||||
last_frame_sent_size = 0;
|
||||
arp_request(&s, target_ip);
|
||||
ck_assert_int_eq(last_frame_sent_size, 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_arp_request_target_ip) {
|
||||
uint32_t target_ip = 0xC0A80002;
|
||||
struct ipstack s;
|
||||
ipstack_init(&s);
|
||||
mock_link_init(&s);
|
||||
s.last_tick = 1000;
|
||||
arp_request(&s, target_ip);
|
||||
ck_assert_int_eq(((struct arp_packet *)(last_frame_sent))->tip, ee32(target_ip));
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_arp_request_handling) {
|
||||
struct arp_packet arp_req;
|
||||
struct arp_packet *arp_reply;
|
||||
memset(&arp_req, 0, sizeof(arp_req));
|
||||
uint32_t req_ip = 0xC0A80002; // 192.168.0.2
|
||||
uint32_t device_ip = 0xC0A80001; // 192.168.0.1
|
||||
uint8_t req_mac[6] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF};
|
||||
//uint8_t mac[6] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55};
|
||||
struct ipstack s;
|
||||
ipstack_init(&s);
|
||||
mock_link_init(&s);
|
||||
s.ipconf.ip = device_ip;
|
||||
|
||||
/* Prepare ARP request */
|
||||
arp_req.opcode = ee16(ARP_REQUEST);
|
||||
arp_req.sip = ee32(req_ip);
|
||||
memcpy(arp_req.sma, req_mac, 6);
|
||||
arp_req.tip = ee32(device_ip);
|
||||
|
||||
/* Call arp_recv with the ARP request */
|
||||
arp_recv(&s, &arp_req, sizeof(arp_req));
|
||||
ipstack_poll(&s, 1000);
|
||||
ipstack_poll(&s, 1001);
|
||||
ipstack_poll(&s, 1002);
|
||||
|
||||
/* Check if ARP table updated with requester's MAC and IP */
|
||||
/* TODO */
|
||||
//ck_assert_int_eq(arp_lookup(&s, req_ip, mac), 0);
|
||||
//ck_assert_mem_eq(mac, req_mac, 6);
|
||||
|
||||
/* Check if an ARP reply was generated */
|
||||
arp_reply = (struct arp_packet *)last_frame_sent;
|
||||
ck_assert_int_eq(last_frame_sent_size, sizeof(struct arp_packet));
|
||||
ck_assert_int_eq(arp_reply->opcode, ee16(ARP_REPLY));
|
||||
ck_assert_mem_eq(arp_reply->sma, s.ll_dev.mac, 6); // source MAC
|
||||
ck_assert_int_eq(arp_reply->sip, ee32(device_ip)); // source IP
|
||||
ck_assert_mem_eq(arp_reply->tma, req_mac, 6); // target MAC
|
||||
ck_assert_int_eq(arp_reply->tip, ee32(req_ip)); // target IP
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_arp_reply_handling) {
|
||||
struct arp_packet arp_reply;
|
||||
memset(&arp_reply, 0, sizeof(arp_reply));
|
||||
uint32_t reply_ip = 0xC0A80003; // 192.168.0.3
|
||||
uint8_t reply_mac[6] = {0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x01};
|
||||
struct ipstack s;
|
||||
ipstack_init(&s);
|
||||
mock_link_init(&s);
|
||||
|
||||
/* Prepare ARP reply */
|
||||
arp_reply.opcode = ee16(ARP_REPLY);
|
||||
arp_reply.sip = ee32(reply_ip);
|
||||
memcpy(arp_reply.sma, reply_mac, 6);
|
||||
|
||||
/* Call arp_recv with the ARP reply */
|
||||
arp_recv(&s, &arp_reply, sizeof(arp_reply));
|
||||
|
||||
/* Check if ARP table updated with reply IP and MAC */
|
||||
ck_assert_int_eq(s.arp.neighbors[0].ip, reply_ip);
|
||||
ck_assert_mem_eq(s.arp.neighbors[0].mac, reply_mac, 6);
|
||||
|
||||
/* Update same IP with a different MAC address */
|
||||
uint8_t new_mac[6] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
|
||||
memcpy(arp_reply.sma, new_mac, 6);
|
||||
arp_recv(&s, &arp_reply, sizeof(arp_reply));
|
||||
|
||||
/* Check if ARP table updates with new MAC */
|
||||
ck_assert_mem_eq(s.arp.neighbors[0].mac, new_mac, 6);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_arp_lookup_success) {
|
||||
uint8_t found_mac[6];
|
||||
uint32_t ip = 0xC0A80002;
|
||||
const uint8_t mock_mac[6] = {0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x01};
|
||||
struct ipstack s;
|
||||
ipstack_init(&s);
|
||||
mock_link_init(&s);
|
||||
|
||||
/* Add a known IP-MAC pair */
|
||||
s.arp.neighbors[0].ip = ip;
|
||||
memcpy(s.arp.neighbors[0].mac, mock_mac, 6);
|
||||
|
||||
/* Test arp_lookup */
|
||||
int result = arp_lookup(&s, ip, found_mac);
|
||||
ck_assert_int_eq(result, 0);
|
||||
ck_assert_mem_eq(found_mac, mock_mac, 6);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_arp_lookup_failure) {
|
||||
uint8_t found_mac[6];
|
||||
uint32_t ip = 0xC0A80004;
|
||||
struct ipstack s;
|
||||
ipstack_init(&s);
|
||||
mock_link_init(&s);
|
||||
|
||||
/* Ensure arp_lookup fails for unknown IP */
|
||||
int result = arp_lookup(&s, ip, found_mac);
|
||||
ck_assert_int_eq(result, -1);
|
||||
uint8_t zero_mac[6] = {0, 0, 0, 0, 0, 0};
|
||||
ck_assert_mem_eq(found_mac, zero_mac, 6);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
// Test for `transport_checksum` calculation
|
||||
START_TEST(test_transport_checksum) {
|
||||
union transport_pseudo_header ph;
|
||||
struct ipstack_tcp_seg tcp_data;
|
||||
memset(&ph, 0, sizeof(ph));
|
||||
memset(&tcp_data, 0, sizeof(tcp_data));
|
||||
|
||||
// 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 = 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
|
||||
tcp_data.src_port = ee16(12345);
|
||||
tcp_data.dst_port = ee16(80);
|
||||
tcp_data.seq = ee32(1);
|
||||
tcp_data.ack = ee32(0);
|
||||
tcp_data.hlen = 5; // offset=5 (20 bytes)
|
||||
tcp_data.flags = 0x02; // SYN
|
||||
tcp_data.win = ee16(65535);
|
||||
|
||||
uint16_t checksum = transport_checksum(&ph, &tcp_data.src_port);
|
||||
ck_assert_msg(checksum != 0, "Transport checksum should not be zero");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
// Test for `iphdr_set_checksum` calculation
|
||||
START_TEST(test_iphdr_set_checksum) {
|
||||
struct ipstack_ip_packet ip;
|
||||
memset(&ip, 0, sizeof(ip));
|
||||
|
||||
ip.ver_ihl = 0x45;
|
||||
ip.tos = 0;
|
||||
ip.len = ee16(20);
|
||||
ip.id = ee16(1);
|
||||
ip.flags_fo = 0;
|
||||
ip.ttl = 64;
|
||||
ip.proto = IPPROTO_TCP;
|
||||
ip.src = ee32(0xc0a80101); // 192.168.1.1
|
||||
ip.dst = ee32(0xc0a80102); // 192.168.1.2
|
||||
|
||||
iphdr_set_checksum(&ip);
|
||||
ck_assert_msg(ip.csum != 0, "IP header checksum should not be zero");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
// Test for `eth_output_add_header` to add Ethernet headers
|
||||
START_TEST(test_eth_output_add_header) {
|
||||
struct ipstack_eth_frame eth_frame;
|
||||
struct ipstack S;
|
||||
memset(&S, 0, sizeof(S));
|
||||
memset(ð_frame, 0, sizeof(eth_frame));
|
||||
|
||||
uint8_t test_mac[6] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
|
||||
memcpy(S.ll_dev.mac, test_mac, 6);
|
||||
|
||||
eth_output_add_header(&S, NULL, ð_frame, ETH_TYPE_IP);
|
||||
|
||||
ck_assert_mem_eq(eth_frame.dst, "\xff\xff\xff\xff\xff\xff", 6); // Broadcast
|
||||
ck_assert_mem_eq(eth_frame.src, test_mac, 6);
|
||||
ck_assert_uint_eq(eth_frame.type, ee16(ETH_TYPE_IP));
|
||||
}
|
||||
END_TEST
|
||||
|
||||
// Test for `ip_output_add_header` to set up IP headers and calculate checksums
|
||||
START_TEST(test_ip_output_add_header) {
|
||||
struct tsocket t;
|
||||
struct ipstack_ip_packet ip;
|
||||
struct ipstack S;
|
||||
memset(&t, 0, sizeof(t));
|
||||
memset(&ip, 0, sizeof(ip));
|
||||
memset(&S, 0, sizeof(S));
|
||||
|
||||
// Setup socket and IP stack parameters
|
||||
t.local_ip = 0xc0a80101; // 192.168.1.1
|
||||
t.remote_ip = 0xc0a80102; // 192.168.1.2
|
||||
t.S = &S;
|
||||
|
||||
// Run the function for a TCP packet
|
||||
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, 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");
|
||||
|
||||
// Check the pseudo-header checksum calculation for TCP segment
|
||||
struct ipstack_tcp_seg *tcp = (struct ipstack_tcp_seg *)&ip;
|
||||
ck_assert_msg(tcp->csum != 0, "TCP checksum should not be zero");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
|
||||
Suite *femto_suite(void)
|
||||
{
|
||||
Suite *s;
|
||||
TCase *tc_core, *tc_proto;
|
||||
TCase *tc_core, *tc_proto, *tc_utils;
|
||||
|
||||
s = suite_create("FemtoTCP");
|
||||
tc_core = tcase_create("Core");
|
||||
tc_utils = tcase_create("Utils");
|
||||
tc_proto = tcase_create("Protocols");
|
||||
|
||||
|
||||
tcase_add_test(tc_core, test_fifo_init);
|
||||
suite_add_tcase(s, tc_core);
|
||||
suite_add_tcase(s, tc_utils);
|
||||
suite_add_tcase(s, tc_proto);
|
||||
|
||||
tcase_add_test(tc_core, test_fifo_push_and_pop);
|
||||
|
@ -560,6 +737,15 @@ Suite *femto_suite(void)
|
|||
tcase_add_test(tc_core, test_queue_pop_wraparound);
|
||||
suite_add_tcase(s, tc_core);
|
||||
|
||||
tcase_add_test(tc_utils, test_insert_timer);
|
||||
suite_add_tcase(s, tc_utils);
|
||||
tcase_add_test(tc_utils, test_pop_timer);
|
||||
suite_add_tcase(s, tc_utils);
|
||||
tcase_add_test(tc_utils, test_is_timer_expired);
|
||||
suite_add_tcase(s, tc_utils);
|
||||
tcase_add_test(tc_utils, test_cancel_timer);
|
||||
suite_add_tcase(s, tc_utils);
|
||||
|
||||
tcase_add_test(tc_proto, test_arp_request_basic);
|
||||
suite_add_tcase(s, tc_proto);
|
||||
tcase_add_test(tc_proto, test_arp_request_throttle);
|
||||
|
@ -574,9 +760,15 @@ Suite *femto_suite(void)
|
|||
suite_add_tcase(s, tc_proto);
|
||||
tcase_add_test(tc_proto, test_arp_lookup_failure);
|
||||
suite_add_tcase(s, tc_proto);
|
||||
|
||||
|
||||
|
||||
|
||||
tcase_add_test(tc_utils, test_transport_checksum);
|
||||
suite_add_tcase(s, tc_proto);
|
||||
tcase_add_test(tc_utils, test_iphdr_set_checksum);
|
||||
suite_add_tcase(s, tc_proto);
|
||||
tcase_add_test(tc_utils, test_eth_output_add_header);
|
||||
suite_add_tcase(s, tc_proto);
|
||||
tcase_add_test(tc_utils, test_ip_output_add_header);
|
||||
suite_add_tcase(s, tc_proto);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue