[lib][minip] start of TCP connect state machine
A few miscellaneous tweaks outside of that.
This commit is contained in:
committed by
Travis Geiselbrecht
parent
dc09bac586
commit
9caf62273c
@@ -16,26 +16,19 @@
|
||||
#include <kernel/mutex.h>
|
||||
#include <lk/trace.h>
|
||||
|
||||
typedef union {
|
||||
uint32_t u;
|
||||
uint8_t b[4];
|
||||
} ipv4_t;
|
||||
|
||||
#define LOCAL_TRACE 0
|
||||
static struct list_node arp_list;
|
||||
typedef struct {
|
||||
struct list_node node;
|
||||
uint32_t addr;
|
||||
uint8_t mac[6];
|
||||
} arp_entry_t;
|
||||
|
||||
static struct list_node arp_list = LIST_INITIAL_VALUE(arp_list);
|
||||
static mutex_t arp_mutex = MUTEX_INITIAL_VALUE(arp_mutex);
|
||||
|
||||
void arp_cache_init(void) {
|
||||
list_initialize(&arp_list);
|
||||
}
|
||||
void arp_cache_init(void) {}
|
||||
|
||||
static inline void mru_update(struct list_node *entry) {
|
||||
static void mru_update(struct list_node *entry) {
|
||||
if (arp_list.next == entry)
|
||||
return;
|
||||
|
||||
@@ -77,7 +70,7 @@ void arp_cache_update(uint32_t addr, const uint8_t mac[6]) {
|
||||
}
|
||||
|
||||
arp->addr = addr;
|
||||
memcpy(arp->mac, mac, sizeof(arp->mac));
|
||||
mac_addr_copy(arp->mac, mac);
|
||||
list_add_head(&arp_list, &arp->node);
|
||||
}
|
||||
|
||||
|
||||
@@ -253,6 +253,9 @@ void dhcp::udp_callback(void *data, size_t sz, uint32_t srcip, uint16_t srcport)
|
||||
#endif
|
||||
sz -= sizeof(dhcp_msg_t);
|
||||
opt = msg->options;
|
||||
#if TRACE_DHCP
|
||||
printf("\toptions: ");
|
||||
#endif
|
||||
while (sz >= 2) {
|
||||
sz -= 2;
|
||||
if (opt[1] > sz) {
|
||||
|
||||
@@ -8,15 +8,14 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <lk/compiler.h>
|
||||
#include <endian.h>
|
||||
#include <iovec.h>
|
||||
#include <lib/pktbuf.h>
|
||||
#include <lk/compiler.h>
|
||||
#include <lk/list.h>
|
||||
#include <stdint.h>
|
||||
#include <iovec.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <lib/pktbuf.h>
|
||||
|
||||
__BEGIN_CDECLS
|
||||
|
||||
#define IPV4(a,b,c,d) (((a)&0xFF)|(((b)&0xFF)<<8)|(((c)&0xFF)<<16)|(((d)&0xFF)<<24))
|
||||
@@ -45,6 +44,11 @@ void minip_set_macaddr(const uint8_t *addr);
|
||||
|
||||
uint32_t minip_get_ipaddr(void);
|
||||
void minip_set_ipaddr(const uint32_t addr);
|
||||
uint32_t minip_get_netmask(void);
|
||||
void minip_set_netmask(const uint32_t mask);
|
||||
uint32_t minip_get_broadcast(void); // computed from ipaddr & netmask
|
||||
uint32_t minip_get_gateway(void);
|
||||
void minip_set_gateway(const uint32_t addr);
|
||||
|
||||
void minip_set_hostname(const char *name);
|
||||
const char *minip_get_hostname(void);
|
||||
@@ -69,6 +73,7 @@ status_t udp_close(udp_socket_t *handle);
|
||||
/* tcp */
|
||||
typedef struct tcp_socket tcp_socket_t;
|
||||
|
||||
status_t tcp_connect(tcp_socket_t **handle, uint32_t addr, uint16_t port);
|
||||
status_t tcp_open_listen(tcp_socket_t **handle, uint16_t port);
|
||||
status_t tcp_accept_timeout(tcp_socket_t *listen_socket, tcp_socket_t **accept_socket, lk_time_t timeout);
|
||||
status_t tcp_close(tcp_socket_t *socket);
|
||||
|
||||
@@ -89,7 +89,13 @@ enum {
|
||||
extern tx_func_t minip_tx_handler;
|
||||
typedef struct udp_hdr udp_hdr_t;
|
||||
static const uint8_t bcast_mac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
typedef uint32_t ipv4_addr;
|
||||
typedef union {
|
||||
uint32_t u;
|
||||
uint8_t b[4];
|
||||
} ipv4_t;
|
||||
|
||||
// ARP cache
|
||||
void arp_cache_init(void);
|
||||
void arp_cache_update(uint32_t addr, const uint8_t mac[6]);
|
||||
uint8_t *arp_cache_lookup(uint32_t addr);
|
||||
@@ -101,7 +107,7 @@ uint16_t rfc1701_chksum(const uint8_t *buf, size_t len);
|
||||
uint16_t rfc768_chksum(struct ipv4_hdr *ipv4, udp_hdr_t *udp);
|
||||
uint16_t ones_sum16(uint32_t sum, const void *_buf, int len);
|
||||
|
||||
/* Helper methods for building headers */
|
||||
// Helper methods for building headers
|
||||
void minip_build_mac_hdr(struct eth_hdr *pkt, const uint8_t *dst, uint16_t type);
|
||||
void minip_build_ipv4_hdr(struct ipv4_hdr *ipv4, uint32_t dst, uint8_t proto, uint16_t len);
|
||||
|
||||
|
||||
@@ -22,8 +22,6 @@
|
||||
#include <lk/list.h>
|
||||
#include <kernel/thread.h>
|
||||
|
||||
static struct list_node arp_list = LIST_INITIAL_VALUE(arp_list);
|
||||
|
||||
// TODO
|
||||
// 1. Tear endian code out into something that flips words before/after tx/rx calls
|
||||
|
||||
@@ -109,10 +107,9 @@ void minip_init(tx_func_t tx_handler, void *tx_arg,
|
||||
minip_tx_handler = tx_handler;
|
||||
minip_tx_arg = tx_arg;
|
||||
|
||||
minip_ip = ip;
|
||||
minip_netmask = mask;
|
||||
minip_gateway = gateway;
|
||||
compute_broadcast_address();
|
||||
minip_set_ipaddr(ip);
|
||||
minip_set_netmask(mask);
|
||||
minip_set_gateway(gateway);
|
||||
|
||||
arp_cache_init();
|
||||
net_timer_init();
|
||||
@@ -209,13 +206,24 @@ status_t minip_ipv4_send(pktbuf_t *p, uint32_t dest_addr, uint8_t proto) {
|
||||
struct ipv4_hdr *ip = pktbuf_prepend(p, sizeof(struct ipv4_hdr));
|
||||
struct eth_hdr *eth = pktbuf_prepend(p, sizeof(struct eth_hdr));
|
||||
|
||||
|
||||
// are we sending a broadcast packet?
|
||||
if (dest_addr == IPV4_BCAST || dest_addr == minip_broadcast) {
|
||||
dst_mac = bcast_mac;
|
||||
goto ready;
|
||||
}
|
||||
|
||||
dst_mac = get_dest_mac(dest_addr);
|
||||
// is this a local subnet packet or do we need to send to the router?
|
||||
uint32_t target_addr = dest_addr;
|
||||
if ((dest_addr & minip_netmask) != (minip_ip & minip_netmask)) {
|
||||
// need to use the gateway
|
||||
if (minip_gateway == IPV4_NONE) {
|
||||
return ERR_NOT_FOUND; // TODO: better error code
|
||||
}
|
||||
|
||||
target_addr = minip_gateway;
|
||||
}
|
||||
|
||||
dst_mac = arp_get_dest_mac(target_addr);
|
||||
if (!dst_mac) {
|
||||
pktbuf_free(p, true);
|
||||
ret = -EHOSTUNREACH;
|
||||
|
||||
116
lib/minip/tcp.c
116
lib/minip/tcp.c
@@ -25,8 +25,6 @@
|
||||
|
||||
#define LOCAL_TRACE 0
|
||||
|
||||
typedef uint32_t ipv4_addr;
|
||||
|
||||
typedef struct tcp_header {
|
||||
uint16_t source_port;
|
||||
uint16_t dest_port;
|
||||
@@ -114,6 +112,9 @@ typedef struct tcp_socket {
|
||||
struct tcp_socket *accepted;
|
||||
|
||||
net_timer_t time_wait_timer;
|
||||
|
||||
/* connect waiting */
|
||||
event_t connect_event;
|
||||
} tcp_socket_t;
|
||||
|
||||
#define DEFAULT_MSS (1460)
|
||||
@@ -216,7 +217,7 @@ static void dump_socket(tcp_socket_t *s) {
|
||||
}
|
||||
|
||||
static tcp_socket_t *lookup_socket(ipv4_addr remote_ip, ipv4_addr local_ip, uint16_t remote_port, uint16_t local_port) {
|
||||
LTRACEF("remote ip 0x%x local ip 0x%x remote port %u local port %u\n", remote_ip, local_ip, remote_port, local_port);
|
||||
LTRACEF_LEVEL(2, "remote ip 0x%x local ip 0x%x remote port %u local port %u\n", remote_ip, local_ip, remote_port, local_port);
|
||||
|
||||
mutex_acquire(&tcp_socket_list_lock);
|
||||
|
||||
@@ -286,7 +287,7 @@ static void inc_socket_ref(tcp_socket_t *s) {
|
||||
DEBUG_ASSERT(s);
|
||||
|
||||
__UNUSED int oldval = atomic_add(&s->ref, 1);
|
||||
LTRACEF("caller %p, thread %p, socket %p, ref now %d\n", __GET_CALLER(), get_current_thread(), s, oldval + 1);
|
||||
LTRACEF_LEVEL(2, "caller %p, thread %p, socket %p, ref now %d\n", __GET_CALLER(), get_current_thread(), s, oldval + 1);
|
||||
DEBUG_ASSERT(oldval > 0);
|
||||
}
|
||||
|
||||
@@ -294,12 +295,13 @@ static bool dec_socket_ref(tcp_socket_t *s) {
|
||||
DEBUG_ASSERT(s);
|
||||
|
||||
int oldval = atomic_add(&s->ref, -1);
|
||||
LTRACEF("caller %p, thread %p, socket %p, ref now %d\n", __GET_CALLER(), get_current_thread(), s, oldval - 1);
|
||||
LTRACEF_LEVEL(2, "caller %p, thread %p, socket %p, ref now %d\n", __GET_CALLER(), get_current_thread(), s, oldval - 1);
|
||||
|
||||
if (oldval == 1) {
|
||||
LTRACEF("destroying socket\n");
|
||||
event_destroy(&s->tx_event);
|
||||
event_destroy(&s->rx_event);
|
||||
event_destroy(&s->connect_event);
|
||||
|
||||
free(s->rx_buffer_raw);
|
||||
free(s->tx_buffer);
|
||||
@@ -482,6 +484,44 @@ void tcp_input(pktbuf_t *p, uint32_t src_ip, uint32_t dst_ip) {
|
||||
|
||||
break;
|
||||
|
||||
/* active connection state */
|
||||
case STATE_SYN_SENT:
|
||||
if ((packet_flags & PKT_SYN) == 0) {
|
||||
// we got data on the packet without a syn, reset
|
||||
goto send_reset;
|
||||
}
|
||||
|
||||
if ((packet_flags & PKT_ACK) == 0) {
|
||||
// simultaneous SYN/ACK
|
||||
// TODO: handle
|
||||
goto send_reset;
|
||||
}
|
||||
|
||||
LTRACEF("ack num %d tx win_low %d\n", header->ack_num, s->tx_win_low);
|
||||
|
||||
if (header->ack_num != s->tx_win_low + 1) {
|
||||
// they didn't ack our syn
|
||||
goto send_reset;
|
||||
}
|
||||
|
||||
// remember their sequence
|
||||
s->rx_win_low = header->seq_num + 1;
|
||||
s->rx_win_high = s->rx_win_low + s->rx_win_size - 1;
|
||||
|
||||
s->tx_win_low++;
|
||||
s->tx_win_high = s->tx_win_low + header->win_size;
|
||||
s->tx_highest_seq = s->tx_win_low;
|
||||
|
||||
s->state = STATE_ESTABLISHED;
|
||||
|
||||
send_ack(s);
|
||||
|
||||
event_signal(&s->connect_event, true);
|
||||
|
||||
break;
|
||||
|
||||
/* established state */
|
||||
|
||||
case STATE_ESTABLISHED:
|
||||
if (packet_flags & PKT_ACK) {
|
||||
/* they're acking us */
|
||||
@@ -565,9 +605,6 @@ fin_wait_2:
|
||||
case STATE_TIME_WAIT:
|
||||
/* /dev/null of packets */
|
||||
break;
|
||||
|
||||
case STATE_SYN_SENT:
|
||||
PANIC_UNIMPLEMENTED;
|
||||
}
|
||||
|
||||
done:
|
||||
@@ -887,6 +924,7 @@ static void tcp_wakeup_waiters(tcp_socket_t *s) {
|
||||
// wake up any waiters
|
||||
event_signal(&s->rx_event, true);
|
||||
event_signal(&s->tx_event, true);
|
||||
event_signal(&s->connect_event, true);
|
||||
}
|
||||
|
||||
static void tcp_remote_close(tcp_socket_t *s) {
|
||||
@@ -938,11 +976,72 @@ static tcp_socket_t *create_tcp_socket(bool alloc_buffers) {
|
||||
}
|
||||
|
||||
sem_init(&s->accept_sem, 0);
|
||||
event_init(&s->connect_event, false, 0);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/* user api */
|
||||
status_t tcp_connect(tcp_socket_t **handle, uint32_t addr, uint16_t port) {
|
||||
tcp_socket_t *s;
|
||||
|
||||
if (!handle)
|
||||
return ERR_INVALID_ARGS;
|
||||
|
||||
s = create_tcp_socket(true);
|
||||
if (!s)
|
||||
return ERR_NO_MEMORY;
|
||||
|
||||
// XXX add some entropy to try to better randomize things
|
||||
lk_bigtime_t t = current_time_hires();
|
||||
printf("%lld\n", t);
|
||||
rand_add_entropy(&t, sizeof(t));
|
||||
|
||||
// set up the socket for outgoing connections
|
||||
s->local_ip = minip_get_ipaddr();
|
||||
s->local_port = (rand() + 1024) & 0xffff; // TODO: allocate sanely
|
||||
DEBUG_ASSERT(s->local_port <= 0xffff);
|
||||
s->remote_ip = addr;
|
||||
s->remote_port = port;
|
||||
|
||||
if (LOCAL_TRACE) {
|
||||
dump_socket(s);
|
||||
}
|
||||
|
||||
// send a SYN packet
|
||||
mutex_acquire(&s->lock);
|
||||
|
||||
s->state = STATE_SYN_SENT;
|
||||
add_socket_to_list(s);
|
||||
|
||||
/* set up a mss option for sending back */
|
||||
tcp_mss_option_t mss_option;
|
||||
mss_option.kind = 0x2;
|
||||
mss_option.len = 0x4;
|
||||
mss_option.mss = ntohs(s->mss);
|
||||
|
||||
tcp_send(s->remote_ip, s->remote_port, s->local_ip, s->local_port, NULL, 0, PKT_SYN, &mss_option, 0x4, 0, s->tx_win_low, s->rx_win_size);
|
||||
|
||||
// TODO: handle retransmit
|
||||
|
||||
mutex_release(&s->lock);
|
||||
|
||||
// block to wait for a successful connection
|
||||
if (event_wait(&s->connect_event) == ERR_TIMED_OUT) {
|
||||
return ERR_TIMED_OUT;
|
||||
}
|
||||
|
||||
status_t err = NO_ERROR;
|
||||
mutex_acquire(&s->lock);
|
||||
if (s->state != STATE_ESTABLISHED) {
|
||||
err = ERR_CHANNEL_CLOSED;
|
||||
}
|
||||
mutex_release(&s->lock);
|
||||
|
||||
*handle = s;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
status_t tcp_open_listen(tcp_socket_t **handle, uint16_t port) {
|
||||
tcp_socket_t *s;
|
||||
@@ -1150,6 +1249,7 @@ status_t tcp_close(tcp_socket_t *socket) {
|
||||
|
||||
// XXX set up fin retransmit timer here
|
||||
break;
|
||||
case STATE_SYN_SENT:
|
||||
case STATE_FIN_WAIT_1:
|
||||
case STATE_FIN_WAIT_2:
|
||||
case STATE_CLOSING:
|
||||
|
||||
@@ -104,7 +104,7 @@ fi
|
||||
|
||||
BLOCK_ARGS=" -drive if=none,file=blk.bin,id=blk,format=raw -device virtio-blk-device,drive=blk"
|
||||
NET_ARGS=" -netdev user,id=vmnic,hostname=qemu -device virtio-net-device,netdev=vmnic"
|
||||
NET_TAP_ARGS=" -netdev tap,id=vmnic -device virtio-net-device,netdev=vmnic"
|
||||
NET_TAP_ARGS=" -netdev tap,id=vmnic,ifname=qemu0,script=no -device virtio-net-device,netdev=vmnic"
|
||||
NO_DISPLAY_ARGS=" -nographic"
|
||||
DISPLAY_ARGS=" -device virtio-gpu-device -serial stdio"
|
||||
|
||||
@@ -130,7 +130,7 @@ if (( $DO_NET )); then
|
||||
fi
|
||||
if (( $DO_NET_TAP )); then
|
||||
ARGS+=$NET_TAP_ARGS
|
||||
SUDO="sudo "
|
||||
#SUDO="sudo "
|
||||
fi
|
||||
if (( $DO_DISPLAY )); then
|
||||
ARGS+=$DISPLAY_ARGS
|
||||
|
||||
Reference in New Issue
Block a user