WIP more net stack

This commit is contained in:
Travis Geiselbrecht
2022-04-02 15:40:55 -07:00
parent 358b1815f3
commit 10853d3259
12 changed files with 418 additions and 299 deletions

View File

@@ -16,7 +16,7 @@
#include <kernel/mutex.h>
#include <lk/trace.h>
#define LOCAL_TRACE 1
#define LOCAL_TRACE 0
typedef struct {
struct list_node node;
uint32_t addr;
@@ -160,9 +160,15 @@ const uint8_t *arp_get_dest_mac(uint32_t host) {
dst_mac = arp_cache_lookup(host);
if (dst_mac == NULL) {
// TODO: lookup netif based on route
netif_t *netif = netif_main;
// look up route to set local address
ipv4_route_t *route = ipv4_search_route(host);
if (!route) {
return NULL;
}
netif_t *netif = route->interface;
arp_send_request(netif, host);
memset(&arp_timeout_timer, 0, sizeof(arp_timeout_timer));
net_timer_set(&arp_timeout_timer, handle_arp_timeout_cb, &arp_timeout, 100);
while (!arp_timeout) {
@@ -172,6 +178,7 @@ const uint8_t *arp_get_dest_mac(uint32_t host) {
break;
}
}
ipv4_dec_route_ref(route);
}
return dst_mac;
@@ -181,6 +188,8 @@ int handle_arp_pkt(netif_t *netif, pktbuf_t *p) {
struct eth_hdr *eth;
struct arp_pkt *arp;
LTRACEF("ARP packet, len %u\n", p->dlen);
eth = (void *) (p->data - sizeof(struct eth_hdr));
if ((arp = pktbuf_consume(p, sizeof(struct arp_pkt))) == NULL) {

View File

@@ -8,7 +8,6 @@
#include "minip-internal.h"
/* XXX alternate implementation, merge */
uint16_t ones_sum16(uint32_t sum, const void *_buf, int len) {
const uint16_t *buf = _buf;
@@ -29,52 +28,3 @@ uint16_t ones_sum16(uint32_t sum, const void *_buf, int len) {
return sum;
}
uint16_t rfc1701_chksum(const uint8_t *buf, size_t len) {
uint32_t total = 0;
uint16_t chksum = 0;
const uint16_t *p = (const uint16_t *) buf;
// Length is in bytes
for (size_t i = 0; i < len / 2; i++ ) {
total += p[i];
}
chksum = (total & 0xFFFF) + (total >> 16);
chksum = ~chksum;
return chksum;
}
#if MINIP_USE_UDP_CHECKSUM
uint16_t rfc768_chksum(struct ipv4_hdr *ipv4, struct udp_hdr *udp) {
uint32_t total = 0;
uint16_t chksum = 0;
size_t len = ntohs(udp->len);
uint16_t *p;
p = (uint16_t *)ipv4->src_addr;
total += htons(p[0]);
total += htons(p[1]);
p = (uint16_t *)ipv4->dst_addr;
total += htons(p[0]);
total += htons(p[1]);
p = (const uint16_t *)udp->data;
for (size_t i = 0; i < len / 2; i++ ) {
total += p[i];
}
total += IP_PROTO_UDP;
total += udp->len;
total += udp->src_port;
total += udp->dst_port;
total += ipv4->len;
chksum = (total & 0xFFFF) + (total >> 16);
chksum = ~chksum;
return chksum;
}
#endif

View File

@@ -22,7 +22,7 @@
#include <string.h>
#include <sys/types.h>
#define TRACE_DHCP 1
#define TRACE_DHCP 0
namespace {
@@ -77,7 +77,7 @@ public:
dhcp() = default;
~dhcp() = default;
status_t start();
status_t start(netif_t *netif);
private:
// must call the following two with the lock held
@@ -232,7 +232,7 @@ void dhcp::udp_callback(void *data, size_t sz, uint32_t srcip, uint16_t srcport)
#if TRACE_DHCP
printf("received DHCP op %d, len %zu, from p %d, ip=", msg->opcode, sz, srcport);
printip(srcip);
print_ipv4_address(srcip);
printf("\n");
#endif
@@ -241,10 +241,10 @@ void dhcp::udp_callback(void *data, size_t sz, uint32_t srcip, uint16_t srcport)
return;
}
#if TRACE_DHCP
printip_named("\tciaddr", msg->ciaddr);
printip_named(" yiaddr", msg->yiaddr);
printip_named(" siaddr", msg->siaddr);
printip_named(" giaddr", msg->giaddr);
print_ipv4_address_named("\tciaddr", msg->ciaddr);
print_ipv4_address_named(" yiaddr", msg->yiaddr);
print_ipv4_address_named(" siaddr", msg->siaddr);
print_ipv4_address_named(" giaddr", msg->giaddr);
printf(" chaddr %02x:%02x:%02x:%02x:%02x:%02x\n",
msg->chaddr[0], msg->chaddr[1], msg->chaddr[2],
msg->chaddr[3], msg->chaddr[4], msg->chaddr[5]);
@@ -288,16 +288,16 @@ void dhcp::udp_callback(void *data, size_t sz, uint32_t srcip, uint16_t srcport)
done:
#if TRACE_DHCP
printf("\n\t");
if (server) printip_named("server", server);
if (netmask) printip_named(" netmask", netmask);
if (gateway) printip_named(" gateway", gateway);
if (dns) printip_named(" dns", dns);
if (server) print_ipv4_address_named("server", server);
if (netmask) print_ipv4_address_named(" netmask", netmask);
if (gateway) print_ipv4_address_named(" gateway", gateway);
if (dns) print_ipv4_address_named(" dns", dns);
printf("\n");
#endif
if (state_ == DISCOVER_SENT) {
if (op == OP_DHCPOFFER) {
#if TRACE_DHCP
printip_named("dhcp: offer:", msg->yiaddr);
print_ipv4_address_named("dhcp: offer:", msg->yiaddr);
printf("\n");
#endif
if (server) {
@@ -308,7 +308,7 @@ done:
} else if (state_ == REQUEST_SENT) {
if (op == OP_DHCPACK) {
#if TRACE_DHCP
printip_named("dhcp: ack:", msg->yiaddr);
print_ipv4_address_named("dhcp: ack:", msg->yiaddr);
printf("\n");
#endif
printf("DHCP configured\n");
@@ -360,14 +360,13 @@ int dhcp::dhcp_thread(void *arg) {
return 0;
}
status_t dhcp::start() {
status_t dhcp::start(netif_t *netif) {
AutoLock guard(lock_);
// for now just try to set up for the main netif
netif_ = netif_main;
netif_ = netif;
// TODO: bind udp socket to this interface
int ret = udp_open(IPV4_BCAST, DHCP_CLIENT_PORT, DHCP_SERVER_PORT, &dhcp_udp_handle_);
// open a udp socket bound to the interface we're dhcping
int ret = udp_open_raw(IPV4_BCAST, DHCP_CLIENT_PORT, DHCP_SERVER_PORT, netif_, &dhcp_udp_handle_);
if (ret != NO_ERROR) {
printf("DHCP: error opening udp socket\n");
return ret;
@@ -383,7 +382,9 @@ status_t dhcp::start() {
} // anonymous namespace
void minip_start_dhcp() {
static dhcp d;
d.start();
void minip_start_dhcp(netif_t *netif) {
DEBUG_ASSERT(netif);
auto *d = new dhcp();
d->start(netif);
}

View File

@@ -26,6 +26,7 @@ __BEGIN_CDECLS
/* types */
typedef uint32_t ipv4_addr_t;
typedef struct netif netif_t;
typedef int (*tx_func_t)(void *arg, pktbuf_t *p);
typedef void (*udp_callback_t)(void *data, size_t len,
@@ -38,7 +39,7 @@ typedef void (*udp_callback_t)(void *data, size_t len,
* note: may take a while to have an ip address assigned, check
* for configuration with minip_is_configured()
*/
void minip_start_dhcp(void);
void minip_start_dhcp(netif_t *);
/* ethernet driver install hook */
void minip_set_eth(tx_func_t tx_handler, void *tx_arg, const uint8_t *macaddr);
@@ -48,7 +49,6 @@ bool minip_is_configured(void);
status_t minip_wait_for_configured(lk_time_t timeout);
/* packet rx hook to hand to ethernet driver */
typedef struct netif netif_t;
void minip_rx_driver_callback(netif_t *netif, pktbuf_t *p);
/* global configuration state */
@@ -62,7 +62,8 @@ void minip_set_configured(void); // set by dhcp or static init to signal minip i
typedef struct udp_socket udp_socket_t;
int udp_listen(uint16_t port, udp_callback_t cb, void *arg);
status_t udp_open(uint32_t host, uint16_t sport, uint16_t dport, udp_socket_t **handle);
status_t udp_open(ipv4_addr_t host, uint16_t sport, uint16_t dport, udp_socket_t **handle);
status_t udp_open_raw(ipv4_addr_t host, uint16_t sport, uint16_t dport, netif_t *netif, udp_socket_t **handle);
status_t udp_send(void *buf, size_t len, udp_socket_t *handle);
status_t udp_send_iovec(const iovec_t *iov, uint iov_count, udp_socket_t *handle);
status_t udp_close(udp_socket_t *handle);
@@ -83,11 +84,9 @@ static inline status_t tcp_accept(tcp_socket_t *listen_socket, tcp_socket_t **ac
/* utilities */
void gen_random_mac_address(uint8_t *mac_addr);
uint32_t minip_parse_ipaddr(const char *addr, size_t len);
uint32_t minip_parse_ipaddr(const char *addr, size_t len);
void printip(uint32_t x);
void printip_named(const char *s, u32 x);
ipv4_addr_t minip_parse_ipaddr(const char *addr, size_t len);
void print_mac_address(const uint8_t *mac);
void print_ipv4_address(ipv4_addr_t x);
void print_ipv4_address_named(const char *s, ipv4_addr_t x);
__END_CDECLS

View File

@@ -39,9 +39,10 @@ struct netif {
typedef struct netif netif_t;
#define NETIF_MAGIC 'NETI'
#define NETIF_FLAG_ETH_CONFIGURED (1U << 0) // mac address and tx func set
#define NETIF_FLAG_REGISTERED (1U << 1) // added to the main list
#define NETIF_FLAG_IPV4_CONFIGURED (1U << 2) // ipv4 address is set
#define NETIF_FLAG_LOOPBACK (1U << 0) // loopback interface is a bit special
#define NETIF_FLAG_ETH_CONFIGURED (1U << 1) // mac address and tx func set
#define NETIF_FLAG_REGISTERED (1U << 2) // added to the main list
#define NETIF_FLAG_IPV4_CONFIGURED (1U << 3) // ipv4 address is set
// Initialize a netif struct.
// Allocates a new one if passed in pointer is null.

View File

@@ -53,7 +53,7 @@ static int cmd_arp(int argc, const console_cmd_args *argv) {
const char *addr_s = argv[2].str;
uint32_t addr = str_ip_to_int(addr_s, strlen(addr_s));
arp_send_request(netif_main, addr);
arp_get_dest_mac(addr);
} else {
arp_usage();
}
@@ -65,26 +65,27 @@ static int cmd_minip(int argc, const console_cmd_args *argv) {
if (argc == 1) {
minip_usage:
printf("minip commands\n");
printf("mi [a]rp dump arp table\n");
printf("mi [i]interfaces dump interface list\n");
printf("mi [r]outes dump routing table\n");
printf("mi [s]tatus print ip status\n");
printf("mi [t]est [dest] [port] [cnt] send <cnt> test packets to the dest:port\n");
} else {
switch (argv[1].str[0]) {
case 'a':
arp_cache_dump();
break;
case 'i':
netif_dump();
break;
case 's': {
case 'r':
dump_ipv4_route_table();
break;
case 's':
printf("hostname: %s\n", minip_get_hostname());
printf("gateway: %u.%u.%u.%u\n", IPV4_SPLIT(minip_get_gateway()));
printf("interfaces:\n");
netif_dump();
}
break;
printf("ipv4 routing table:\n");
dump_ipv4_route_table();
break;
case 't': {
uint32_t count = 1;
uint32_t host = 0x0100000A; // 10.0.0.1
@@ -140,7 +141,7 @@ minip_usage:
udp_close(handle);
#undef BUFSIZE
}
break;
break;
default:
goto minip_usage;
}
@@ -149,7 +150,10 @@ minip_usage:
return 0;
}
extern int cmd_tcp(int argc, const console_cmd_args *argv);
STATIC_COMMAND_START
STATIC_COMMAND("arp", "arp commands", &cmd_arp)
STATIC_COMMAND("mi", "minip commands", &cmd_minip)
STATIC_COMMAND("tcp", "tcp commands", &cmd_tcp)
STATIC_COMMAND_END(minip);

View File

@@ -18,7 +18,7 @@
#include <lib/minip/netif.h>
/* Lib configuration */
#define MINIP_USE_UDP_CHECKSUM 0
#define MINIP_USE_UDP_CHECKSUM 1
#define MINIP_MTU_SIZE 1536
#define MINIP_USE_ARP 1
@@ -103,28 +103,54 @@ int arp_send_request(netif_t *, ipv4_addr_t addr);
const uint8_t *arp_get_dest_mac(uint32_t host);
int handle_arp_pkt(netif_t *netif, pktbuf_t *p);
uint16_t rfc1701_chksum(const uint8_t *buf, size_t len);
uint16_t rfc768_chksum(struct ipv4_hdr *ipv4, udp_hdr_t *udp);
// checksums
uint16_t ones_sum16(uint32_t sum, const void *_buf, int len);
typedef struct ipv4_pseudo_header {
ipv4_addr_t source_addr;
ipv4_addr_t dest_addr;
uint8_t zero;
uint8_t protocol;
uint16_t tcp_length;
} __PACKED ipv4_pseudo_header_t;
static inline uint16_t cksum_pheader(const ipv4_pseudo_header_t *pheader, const void *buf, size_t len) {
uint16_t checksum = ones_sum16(0, pheader, sizeof(*pheader));
return ~ones_sum16(checksum, buf, len);
}
// ipv4 routing
typedef struct ipv4_route {
uint32_t flags;
int ref;
ipv4_addr_t dest;
ipv4_addr_t mask;
netif_t *interface;
} ipv4_route_t;
#define IPV4_ROUTE_UP (1<<0)
#define IPV4_ROUTE_DEFAULT (1<<1)
ipv4_route_t *ipv4_search_route(ipv4_addr_t dest);
void ipv4_dec_route_ref(ipv4_route_t *r);
status_t ipv4_add_route(ipv4_addr_t dest, ipv4_addr_t mask, netif_t *n);
status_t ipv4_add_default_route(ipv4_addr_t dest, netif_t *n);
void dump_ipv4_route_table(void);
// Helper methods for building headers
void minip_build_mac_hdr(netif_t *netif, struct eth_hdr *pkt, const uint8_t *dst, uint16_t type);
void minip_build_ipv4_hdr(netif_t *netif, struct ipv4_hdr *ipv4, ipv4_addr_t dst, uint8_t proto, uint16_t len);
status_t minip_ipv4_send(pktbuf_t *p, ipv4_addr_t dest_addr, uint8_t proto);
status_t minip_ipv4_send_raw(pktbuf_t *p, ipv4_addr_t dest_addr, uint8_t proto, const uint8_t *dest_mac, netif_t *netif);
void tcp_input(netif_t *netif, pktbuf_t *p, uint32_t src_ip, uint32_t dst_ip);
void udp_input(netif_t *netif, pktbuf_t *p, uint32_t src_ip);
const uint8_t *get_dest_mac(uint32_t host);
// interface list
void netif_init(void);
void netif_dump(void);
extern netif_t *netif_loopback;
extern netif_t *netif_main;
// timers
typedef void (*net_timer_callback_t)(void *);

View File

@@ -20,47 +20,45 @@
#include <string.h>
#include <lk/trace.h>
#include <malloc.h>
#include <arch/atomic.h>
#include <lk/list.h>
#include <lk/init.h>
#include <kernel/event.h>
#include <kernel/mutex.h>
#include <kernel/thread.h>
// TODO
// 1. Tear endian code out into something that flips words before/after tx/rx calls
#define LOCAL_TRACE 1
//static ipv4_addr_t minip_ip = IPV4_NONE;
//static ipv4_addr_t minip_netmask = IPV4_NONE;
//static ipv4_addr_t minip_broadcast = IPV4_BCAST;
#define LOCAL_TRACE 0
static ipv4_addr_t minip_gateway = IPV4_NONE;
static const uint8_t broadcast_mac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
//static uint8_t minip_mac[6] = {0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC};
static char minip_hostname[32] = "";
static volatile bool minip_configured = false;
static event_t minip_configured_event = EVENT_INITIAL_VALUE(minip_configured_event, false, 0);
/* This function is called by minip to send packets */
//tx_func_t minip_tx_handler;
//void *minip_tx_arg;
static void dump_ipv4_addr(uint32_t addr);
/* routing table */
static mutex_t route_lock = MUTEX_INITIAL_VALUE(route_lock);
static ipv4_route_t route_table[16];
/* if all the important configuration bits are set, signal that we're configured */
static void check_and_set_configured(void) {
if (netif_main == NULL) return;
if (netif_main->ipv4_addr == IPV4_NONE) return;
if (netif_get_netmask_ipv4(netif_main) == IPV4_NONE) return;
if (netif_get_broadcast_ipv4(netif_main) == IPV4_BCAST) return;
// minip_gateway doesn't have to be set
if (netif_main->mac_address[0] == 0 &&
netif_main->mac_address[1] == 0 &&
netif_main->mac_address[2] == 0 &&
netif_main->mac_address[3] == 0 &&
netif_main->mac_address[4] == 0 &&
netif_main->mac_address[5] == 0) return;
// search for an ip route other than loopback to signal configured
mutex_acquire(&route_lock);
bool found = false;
for (size_t i = 0; i < countof(route_table); i++) {
if (route_table[i].flags & IPV4_ROUTE_UP) {
if ((route_table[i].interface->flags & NETIF_FLAG_LOOPBACK) == 0) {
found = true;
break;
}
}
}
mutex_release(&route_lock);
if (!found) return;
// we're configured
printf("MINIP: setting configured state\n");
@@ -76,47 +74,20 @@ const char *minip_get_hostname(void) {
return minip_hostname;
}
#if 0
static void compute_broadcast_address(void) {
minip_broadcast = (minip_ip & minip_netmask) | (IPV4_BCAST & ~minip_netmask);
}
void minip_get_macaddr(uint8_t *addr) {
mac_addr_copy(addr, minip_mac);
}
uint32_t minip_get_ipaddr(void) {
return minip_ip;
}
void minip_set_ipaddr(const ipv4_addr_t addr) {
minip_ip = addr;
compute_broadcast_address();
check_and_set_configured();
}
uint32_t minip_get_broadcast(void) {
return minip_broadcast;
}
uint32_t minip_get_netmask(void) {
return minip_netmask;
}
void minip_set_netmask(const ipv4_addr_t netmask) {
minip_netmask = netmask;
compute_broadcast_address();
check_and_set_configured();
}
#endif
uint32_t minip_get_gateway(void) {
return minip_gateway;
}
void minip_set_gateway(const ipv4_addr_t addr) {
minip_gateway = addr;
// TODO: check that it is reacheable on local network
// look up the route to this and set a default route
ipv4_route_t *route = ipv4_search_route(addr);
if (route) {
ipv4_add_default_route(addr, route->interface);
ipv4_dec_route_ref(route);
}
check_and_set_configured();
}
@@ -147,22 +118,138 @@ void minip_start_static(uint32_t ip, uint32_t mask, uint32_t gateway) {
minip_set_gateway(gateway);
}
#if 0
void minip_set_eth(tx_func_t tx_handler, void *tx_arg, const uint8_t *macaddr) {
LTRACEF("handler %p, arg %p, macaddr %p\n", tx_handler, tx_arg, macaddr);
// search for an ipv4 route given the destination
// bumps the ref of the route upon return
ipv4_route_t *ipv4_search_route(ipv4_addr_t dest) {
ipv4_route_t *r = NULL;
ipv4_route_t *def_route = NULL;
DEBUG_ASSERT(minip_tx_handler == NULL);
DEBUG_ASSERT(minip_tx_arg == NULL);
// TODO: assert mac address is not already set
mutex_acquire(&route_lock);
// set up the low level driver handler
minip_tx_handler = tx_handler;
minip_tx_arg = tx_arg;
for (size_t i = 0; i < countof(route_table); i++) {
ipv4_route_t *rtemp = &route_table[i];
if (rtemp->flags & IPV4_ROUTE_UP) {
if (rtemp->flags & IPV4_ROUTE_DEFAULT) {
def_route = rtemp;
} else {
// does this route satisfy our destination
if ((dest & rtemp->mask) == rtemp->dest) {
r = rtemp;
break;
}
}
}
}
mac_addr_copy(minip_mac, macaddr);
if (!r && def_route) {
r = def_route;
}
if (r) {
// inc ref on the route and pass it back
r->ref++;
}
mutex_release(&route_lock);
return r;
}
#endif
void ipv4_dec_route_ref(ipv4_route_t *r) {
DEBUG_ASSERT(r);
mutex_acquire(&route_lock);
DEBUG_ASSERT(r->ref >= 1);
r->ref--;
mutex_release(&route_lock);
}
status_t ipv4_add_route(ipv4_addr_t dest, ipv4_addr_t mask, netif_t *n) {
LTRACE_ENTRY;
DEBUG_ASSERT(n);
mutex_acquire(&route_lock);
// find an unused slot
status_t err;
for (size_t i = 0; i < countof(route_table); i++) {
ipv4_route_t *r = &route_table[i];
if (r->ref == 0 && r->flags == 0) {
// unused route, use this slot
r->dest = dest;
r->mask = mask;
r->interface = n;
r->ref = 0;
r->flags |= IPV4_ROUTE_UP;
err = NO_ERROR;
goto done;
}
}
err = ERR_NO_MEMORY;
done:
mutex_release(&route_lock);
return err;
}
status_t ipv4_add_default_route(ipv4_addr_t dest, netif_t *n) {
LTRACE_ENTRY;
DEBUG_ASSERT(n);
mutex_acquire(&route_lock);
// find an unused slot
status_t err;
for (size_t i = 0; i < countof(route_table); i++) {
ipv4_route_t *r = &route_table[i];
if (r->ref == 0 && r->flags == 0) {
// unused route, use this slot
r->dest = dest;
r->mask = 0;
r->interface = n;
r->ref = 0;
r->flags |= IPV4_ROUTE_UP;
r->flags |= IPV4_ROUTE_DEFAULT;
err = NO_ERROR;
goto done;
}
}
err = ERR_NO_MEMORY;
done:
mutex_release(&route_lock);
return err;
}
void dump_ipv4_route_table(void) {
mutex_acquire(&route_lock);
for (size_t i = 0; i < countof(route_table); i++) {
ipv4_route_t *r = &route_table[i];
if (r->ref > 0 || r->flags != 0) {
printf("route dest ");
print_ipv4_address(r->dest);
printf(" mask ");
print_ipv4_address(r->mask);
printf(" flags %c%c ref %d interface %s\n",
r->flags & IPV4_ROUTE_UP ? 'U' : ' ',
r->flags & IPV4_ROUTE_DEFAULT ? 'D' : ' ',
r->ref,
r->interface->name);
}
}
mutex_release(&route_lock);
}
// ipv4 send/receive logic
static uint16_t ipv4_payload_len(struct ipv4_hdr *pkt) {
return (pkt->len - ((pkt->ver_ihl >> 4) * 5));
}
@@ -173,7 +260,7 @@ void minip_build_mac_hdr(netif_t *netif, struct eth_hdr *pkt, const uint8_t *dst
pkt->type = htons(type);
}
void minip_build_ipv4_hdr(netif_t *netif, struct ipv4_hdr *ipv4, ipv4_addr_t dst, uint8_t proto, uint16_t len) {
static void minip_build_ipv4_hdr(netif_t *netif, struct ipv4_hdr *ipv4, ipv4_addr_t dst, uint8_t proto, uint16_t len) {
ipv4->ver_ihl = 0x45;
ipv4->dscp_ecn = 0;
ipv4->len = htons(20 + len); // 5 * 4 from ihl, plus payload length
@@ -186,27 +273,44 @@ void minip_build_ipv4_hdr(netif_t *netif, struct ipv4_hdr *ipv4, ipv4_addr_t dst
/* This may be unnecessary if the controller supports checksum offloading */
ipv4->chksum = 0;
ipv4->chksum = rfc1701_chksum((uint8_t *) ipv4, sizeof(struct ipv4_hdr));
ipv4->chksum = ~ones_sum16(0, (uint8_t *) ipv4, sizeof(struct ipv4_hdr));
}
status_t minip_ipv4_send(pktbuf_t *p, ipv4_addr_t dest_addr, uint8_t proto) {
status_t ret = 0;
status_t minip_ipv4_send_raw(pktbuf_t *p, ipv4_addr_t dest_addr, uint8_t proto, const uint8_t *dest_mac, netif_t *netif) {
DEBUG_ASSERT(p);
DEBUG_ASSERT(netif);
size_t data_len = p->dlen;
const uint8_t *dst_mac;
struct ipv4_hdr *ip = pktbuf_prepend(p, sizeof(struct ipv4_hdr));
struct eth_hdr *eth = pktbuf_prepend(p, sizeof(struct eth_hdr));
// TODO: consult routing table here
netif_t *netif = netif_main;
if (!netif) {
if (LOCAL_TRACE) {
printf("sending ipv4\n");
}
minip_build_mac_hdr(netif, eth, dest_mac, ETH_TYPE_IPV4);
minip_build_ipv4_hdr(netif, ip, dest_addr, proto, data_len);
return netif->tx_func(netif->tx_func_arg, p);
}
status_t minip_ipv4_send(pktbuf_t *p, ipv4_addr_t dest_addr, uint8_t proto) {
status_t ret = 0;
// TODO: cache route at socket creation
ipv4_route_t *route = ipv4_search_route(dest_addr);
if (!route) {
ret = -EHOSTUNREACH;
goto err;
}
DEBUG_ASSERT(route->interface);
netif_t *netif = route->interface;
// are we sending a broadcast packet?
const uint8_t *dest_mac;
if (dest_addr == IPV4_BCAST || dest_addr == netif_get_broadcast_ipv4(netif)) {
dst_mac = bcast_mac;
dest_mac = bcast_mac;
goto ready;
}
@@ -216,30 +320,27 @@ status_t minip_ipv4_send(pktbuf_t *p, ipv4_addr_t dest_addr, uint8_t proto) {
if ((dest_addr & netmask) != (netif->ipv4_addr & netmask)) {
// need to use the gateway
if (minip_gateway == IPV4_NONE) {
return ERR_NOT_FOUND; // TODO: better error code
ret = ERR_NOT_FOUND; // TODO: better error code
goto err;
}
target_addr = minip_gateway;
}
dst_mac = arp_get_dest_mac(target_addr);
if (!dst_mac) {
dest_mac = arp_get_dest_mac(target_addr);
if (!dest_mac) {
pktbuf_free(p, true);
ret = -EHOSTUNREACH;
goto err;
}
ready:
if (LOCAL_TRACE) {
printf("sending ipv4\n");
}
minip_build_mac_hdr(netif, eth, dst_mac, ETH_TYPE_IPV4);
minip_build_ipv4_hdr(netif, ip, dest_addr, proto, data_len);
netif->tx_func(netif->tx_func_arg, p);
ret = minip_ipv4_send_raw(p, dest_addr, proto, dest_mac, netif);
err:
if (route) {
ipv4_dec_route_ref(route);
}
return ret;
}
@@ -272,22 +373,16 @@ static void send_ping_reply(netif_t *netif, uint32_t ipaddr, struct icmp_pkt *re
icmp->code = 0;
memcpy(icmp->hdr_data, req->hdr_data, sizeof(icmp->hdr_data));
icmp->chksum = 0;
icmp->chksum = rfc1701_chksum((uint8_t *) icmp, len);
icmp->chksum = ~ones_sum16(0, (uint8_t *) icmp, len);
netif->tx_func(netif->tx_func_arg, p);
}
static void dump_ipv4_addr(uint32_t addr) {
const uint8_t *a = (void *)&addr;
printf("%hhu.%hhu.%hhu.%hhu", a[0], a[1], a[2], a[3]);
}
static void dump_ipv4_packet(const struct ipv4_hdr *ip) {
__NO_INLINE static void dump_ipv4_packet(const struct ipv4_hdr *ip) {
printf("IP ");
dump_ipv4_addr(ip->src_addr);
print_ipv4_address(ip->src_addr);
printf(" -> ");
dump_ipv4_addr(ip->dst_addr);
print_ipv4_address(ip->dst_addr);
printf(" hlen 0x%x, prot 0x%x, cksum 0x%x, len 0x%x, ident 0x%x, frag offset 0x%x\n",
(ip->ver_ihl & 0xf) * 4, ip->proto, ntohs(ip->chksum), ntohs(ip->len), ntohs(ip->id), ntohs(ip->flags_frags) & 0x1fff);
}
@@ -296,8 +391,10 @@ __NO_INLINE static void handle_ipv4_packet(netif_t *netif, pktbuf_t *p, const ui
struct ipv4_hdr *ip;
ip = (struct ipv4_hdr *)p->data;
if (p->dlen < sizeof(struct ipv4_hdr))
if (p->dlen < sizeof(struct ipv4_hdr)) {
LTRACEF("REJECT: packet too short to hold header\n");
return;
}
/* print packets for us */
if (LOCAL_TRACE) {
@@ -319,7 +416,7 @@ __NO_INLINE static void handle_ipv4_packet(netif_t *netif, pktbuf_t *p, const ui
}
/* compute checksum */
if (rfc1701_chksum((void *)ip, header_len) != 0) {
if (ones_sum16(0, (void *)ip, header_len) == 0) {
/* bad checksum */
LTRACEF("REJECT: bad checksum\n");
return;
@@ -397,29 +494,26 @@ void minip_rx_driver_callback(netif_t *netif, pktbuf_t *p) {
}
if (memcmp(eth->dst_mac, netif->mac_address, 6) != 0 &&
memcmp(eth->dst_mac, broadcast_mac, 6) != 0) {
memcmp(eth->dst_mac, bcast_mac, 6) != 0) {
/* not for us */
return;
}
switch (htons(eth->type)) {
case ETH_TYPE_IPV4:
LTRACEF("ipv4 pkt\n");
handle_ipv4_packet(netif, p, eth->src_mac);
break;
case ETH_TYPE_ARP:
LTRACEF("arp pkt\n");
handle_arp_pkt(netif, p);
break;
default:
LTRACEF("unhandled pkt type %#hx\n", htons(eth->type));
break;
}
}
void print_mac_address(const uint8_t *mac) {
printf("%02x:%02x:%02x:%02x:%02x:%02x",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}
// utility routines
uint32_t minip_parse_ipaddr(const char *ipaddr_str, size_t len) {
uint8_t ip[4] = { 0, 0, 0, 0 };
uint8_t pos = 0, i = 0;
@@ -440,19 +534,23 @@ uint32_t minip_parse_ipaddr(const char *ipaddr_str, size_t len) {
return IPV4_PACK(ip);
}
// printf the ip address passed in
void printip(uint32_t x) {
void print_mac_address(const uint8_t *mac) {
printf("%02x:%02x:%02x:%02x:%02x:%02x",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}
void print_ipv4_address(ipv4_addr_t x) {
union {
u32 u;
u8 b[4];
uint32_t u;
uint8_t b[4];
} ip;
ip.u = x;
printf("%d.%d.%d.%d", ip.b[0], ip.b[1], ip.b[2], ip.b[3]);
}
void printip_named(const char *s, uint32_t x) {
void print_ipv4_address_named(const char *s, ipv4_addr_t x) {
printf("%s ", s);
printip(x);
print_ipv4_address(x);
}
// run static initialization
@@ -462,5 +560,4 @@ static void minip_init(uint level) {
netif_init();
}
LK_INIT_HOOK(minip, minip_init, LK_INIT_LEVEL_THREADING);

View File

@@ -25,12 +25,6 @@ static struct list_node netif_list = LIST_INITIAL_VALUE(netif_list);
static mutex_t lock = MUTEX_INITIAL_VALUE(lock);
static netif_t loopback;
// Used by the ip layer to directly get a handle to the loopback and first
// registered interface (main).
// TODO: remove once proper routing is in place
netif_t *netif_loopback = NULL;
netif_t *netif_main = NULL;
static int loopback_tx_func(void *arg, pktbuf_t *p) {
LTRACEF("arg %p, pkt %p\n", arg, p);
return 0;
@@ -41,12 +35,10 @@ void netif_init(void) {
// loopback device
netif_create(&loopback, "loopback");
loopback.flags |= NETIF_FLAG_LOOPBACK;
netif_set_eth(&loopback, loopback_tx_func, NULL, bcast_mac);
netif_set_ipv4_addr(&loopback, IPV4(128, 0, 0, 1), 8);
netif_set_ipv4_addr(&loopback, IPV4(127, 0, 0, 1), 8);
netif_register(&loopback);
// publish for the main stack to find
netif_loopback = &loopback;
}
netif_t *netif_create(netif_t *n, const char *name) {
@@ -56,7 +48,7 @@ netif_t *netif_create(netif_t *n, const char *name) {
n = malloc(sizeof(netif_t));
}
if (!n) {
return n;
return NULL;
}
memset(n, 0, sizeof(*n));
@@ -67,6 +59,15 @@ netif_t *netif_create(netif_t *n, const char *name) {
return n;
}
// generic logic to decide what to do when a netif comes up
// TODO: make this overridable
void netif_registration_callback(netif_t *n) {
// if the interface isn't already configured, kick off a dhcp thread
if ((n->flags & NETIF_FLAG_IPV4_CONFIGURED) == 0) {
minip_start_dhcp(n);
}
}
status_t netif_register(netif_t *n) {
LTRACEF("n %p\n", n);
@@ -81,14 +82,11 @@ status_t netif_register(netif_t *n) {
list_add_head(&netif_list, &n->node);
n->flags |= NETIF_FLAG_REGISTERED;
// TODO: replace with mechanism to set up ip routing (probably in DHCP)
if (netif_main == NULL && n != &loopback) {
// register this as the 'main' interface
netif_main = n;
}
mutex_release(&lock);
// let overridable external logic deal with this
netif_registration_callback(n);
return NO_ERROR;
}
@@ -123,6 +121,9 @@ status_t netif_set_ipv4_addr(netif_t *n, ipv4_addr_t addr, uint8_t subnet_width)
mutex_release(&lock);
// set an ipv4 route for this
ipv4_add_route(netif_get_network_ipv4(n), netif_get_netmask_ipv4(n), n);
return NO_ERROR;
}
@@ -134,12 +135,12 @@ void netif_dump(void) {
printf("net interface @%p: name '%s' mac ", n, n->name);
print_mac_address(n->mac_address);
printf(" addr ");
printip(n->ipv4_addr);
print_ipv4_address(n->ipv4_addr);
printf("/%u", n->ipv4_subnet_width);
printf(" netmask ");
printip(netif_get_netmask_ipv4(n));
print_ipv4_address(netif_get_netmask_ipv4(n));
printf(" bcast ");
printip(netif_get_broadcast_ipv4(n));
print_ipv4_address(netif_get_broadcast_ipv4(n));
printf("\n");
}

View File

@@ -36,14 +36,6 @@ typedef struct tcp_header {
uint16_t urg_pointer;
} __PACKED tcp_header_t;
typedef struct tcp_pseudo_header {
ipv4_addr_t source_addr;
ipv4_addr_t dest_addr;
uint8_t zero;
uint8_t protocol;
uint16_t tcp_length;
} __PACKED tcp_pseudo_header_t;
typedef struct tcp_mss_option {
uint8_t kind; /* 0x2 */
uint8_t len; /* 0x4 */
@@ -84,6 +76,7 @@ typedef struct tcp_socket {
ipv4_addr_t remote_ip;
uint16_t local_port;
uint16_t remote_port;
ipv4_route_t *route;
uint32_t mss;
@@ -121,7 +114,7 @@ typedef struct tcp_socket {
#define DEFAULT_RX_WINDOW_SIZE (8192)
#define DEFAULT_TX_BUFFER_SIZE (8192)
#define RETRANSMIT_TIMEOUT (50)
#define RETRANSMIT_TIMEOUT (250)
#define DELAYED_ACK_TIMEOUT (50)
#define TIME_WAIT_TIMEOUT (60000) // 1 minute
@@ -156,11 +149,6 @@ static void tcp_wakeup_waiters(tcp_socket_t *s);
static void inc_socket_ref(tcp_socket_t *s);
static bool dec_socket_ref(tcp_socket_t *s);
static uint16_t cksum_pheader(const tcp_pseudo_header_t *pheader, const void *buf, size_t len) {
uint16_t checksum = ones_sum16(0, pheader, sizeof(*pheader));
return ~ones_sum16(checksum, buf, len);
}
__NO_INLINE static void dump_tcp_header(const tcp_header_t *header) {
printf("TCP: src_port %u, dest_port %u, seq %u, ack %u, win %u, flags %c%c%c%c%c%c\n",
ntohs(header->source_port), ntohs(header->dest_port), ntohl(header->seq_num), ntohl(header->ack_num),
@@ -299,6 +287,10 @@ static bool dec_socket_ref(tcp_socket_t *s) {
if (oldval == 1) {
LTRACEF("destroying socket\n");
if (s->route) {
ipv4_dec_route_ref(s->route);
s->route = NULL;
}
event_destroy(&s->tx_event);
event_destroy(&s->rx_event);
event_destroy(&s->connect_event);
@@ -351,7 +343,7 @@ void tcp_input(netif_t *netif, pktbuf_t *p, uint32_t src_ip, uint32_t dst_ip) {
/* checksum */
if (FORCE_TCP_CHECKSUM || (p->flags & PKTBUF_FLAG_CKSUM_TCP_GOOD) == 0) {
tcp_pseudo_header_t pheader;
ipv4_pseudo_header_t pheader;
// set up the pseudo header for checksum purposes
pheader.source_addr = src_ip;
@@ -433,6 +425,13 @@ void tcp_input(netif_t *netif, pktbuf_t *p, uint32_t src_ip, uint32_t dst_ip) {
accept_socket->remote_port = header->source_port;
accept_socket->state = STATE_SYN_RCVD;
/* look up and cache the route for the accepted socket */
ipv4_route_t *route = ipv4_search_route(src_ip);
if (!route) {
goto done;
}
accept_socket->route = route;
mutex_acquire(&accept_socket->lock);
add_socket_to_list(accept_socket);
@@ -751,7 +750,7 @@ static status_t tcp_send(ipv4_addr_t dest_ip, uint16_t dest_port, ipv4_addr_t sr
/* compute the checksum */
/* XXX get the tx ckecksum capability from the nic */
if (FORCE_TCP_CHECKSUM || true) {
tcp_pseudo_header_t pheader;
ipv4_pseudo_header_t pheader;
pheader.source_addr = src_ip;
pheader.dest_addr = dest_ip;
pheader.zero = 0;
@@ -994,14 +993,15 @@ status_t tcp_connect(tcp_socket_t **handle, uint32_t addr, uint16_t port) {
// 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));
// TODO: look up route to set local address
netif_t *netif = netif_main;
if (!netif) {
// look up route to set local address
ipv4_route_t *route = ipv4_search_route(addr);
if (!route) {
return ERR_NO_ROUTE;
}
netif_t *netif = route->interface;
s->route = route;
// set up the socket for outgoing connections
s->local_ip = netif->ipv4_addr;
@@ -1034,6 +1034,7 @@ status_t tcp_connect(tcp_socket_t **handle, uint32_t addr, uint16_t port) {
// block to wait for a successful connection
if (event_wait(&s->connect_event) == ERR_TIMED_OUT) {
ipv4_dec_route_ref(s->route);
return ERR_TIMED_OUT;
}
@@ -1283,7 +1284,7 @@ out:
}
/* debug stuff */
static int cmd_tcp(int argc, const console_cmd_args *argv) {
int cmd_tcp(int argc, const console_cmd_args *argv) {
if (argc < 2) {
notenoughargs:
printf("ERROR not enough arguments\n");
@@ -1366,7 +1367,3 @@ usage:
return NO_ERROR;
}
STATIC_COMMAND_START
STATIC_COMMAND("tcp", "tcp commands", &cmd_tcp)
STATIC_COMMAND_END(tcp);

View File

@@ -30,10 +30,13 @@ struct udp_listener {
};
typedef struct udp_socket {
uint32_t host;
ipv4_addr_t local_ip;
ipv4_addr_t remote_ip;
uint16_t sport;
uint16_t dport;
const uint8_t *mac;
ipv4_route_t *route;
// only set if bound to a particular network interface
netif_t *netif;
} udp_socket_t;
@@ -44,7 +47,6 @@ typedef struct udp_hdr {
uint16_t chksum;
} __PACKED udp_hdr_t;
int udp_listen(uint16_t port, udp_callback_t cb, void *arg) {
struct udp_listener *entry, *temp;
@@ -71,33 +73,61 @@ int udp_listen(uint16_t port, udp_callback_t cb, void *arg) {
return 0;
}
status_t udp_open(uint32_t host, uint16_t sport, uint16_t dport, udp_socket_t **handle) {
status_t udp_open(ipv4_addr_t host, uint16_t sport, uint16_t dport, udp_socket_t **handle) {
LTRACEF("host %u.%u.%u.%u sport %u dport %u handle %p\n",
IPV4_SPLIT(host), sport, dport, handle);
udp_socket_t *socket;
const uint8_t *dst_mac;
if (handle == NULL) {
return -EINVAL;
}
socket = (udp_socket_t *) malloc(sizeof(udp_socket_t));
socket = (udp_socket_t *) calloc(1, sizeof(udp_socket_t));
if (!socket) {
return -ENOMEM;
}
dst_mac = arp_get_dest_mac(host);
if (dst_mac == NULL) {
free(socket);
return -EHOSTUNREACH;
// look up route to set local address
ipv4_route_t *route = ipv4_search_route(host);
if (!route) {
return ERR_NO_ROUTE;
}
socket->host = host;
netif_t *netif = route->interface;
socket->local_ip = netif->ipv4_addr;
socket->remote_ip = host;
socket->sport = sport;
socket->dport = dport;
socket->mac = dst_mac;
// TODO: replace with route lookup
socket->netif = netif_main;
socket->route = route;
*handle = socket;
return NO_ERROR;
}
status_t udp_open_raw(ipv4_addr_t host, uint16_t sport, uint16_t dport, netif_t *netif, udp_socket_t **handle) {
LTRACEF("host %u.%u.%u.%u sport %u dport %u netif '%s' handle %p\n",
IPV4_SPLIT(host), sport, dport, netif->name, handle);
udp_socket_t *socket;
if (handle == NULL) {
return -EINVAL;
}
if (netif == NULL) {
return -EINVAL;
}
socket = (udp_socket_t *) calloc(1, sizeof(udp_socket_t));
if (!socket) {
return -ENOMEM;
}
socket->local_ip = netif->ipv4_addr;
socket->remote_ip = host;
socket->sport = sport;
socket->dport = dport;
socket->netif = netif;
*handle = socket;
@@ -109,16 +139,17 @@ status_t udp_close(udp_socket_t *handle) {
return -EINVAL;
}
if (handle->route) {
ipv4_dec_route_ref(handle->route);
}
free(handle);
return NO_ERROR;
}
status_t udp_send_iovec(const iovec_t *iov, uint iov_count, udp_socket_t *handle) {
pktbuf_t *p;
struct eth_hdr *eth;
struct ipv4_hdr *ip;
udp_hdr_t *udp;
status_t ret = NO_ERROR;
void *buf;
ssize_t len;
@@ -130,37 +161,42 @@ status_t udp_send_iovec(const iovec_t *iov, uint iov_count, udp_socket_t *handle
return -ENOMEM;
}
if (handle->netif == NULL) {
LTRACEF("aborting send due to lack of netif\n");
return -EHOSTUNREACH;
}
len = iovec_size(iov, iov_count);
buf = pktbuf_append(p, len);
udp = pktbuf_prepend(p, sizeof(udp_hdr_t));
ip = pktbuf_prepend(p, sizeof(struct ipv4_hdr));
eth = pktbuf_prepend(p, sizeof(struct eth_hdr));
iovec_to_membuf(buf, len, iov, iov_count, 0);
udp = pktbuf_prepend(p, sizeof(udp_hdr_t));
udp->src_port = htons(handle->sport);
udp->dst_port = htons(handle->dport);
udp->len = htons(sizeof(udp_hdr_t) + len);
udp->chksum = 0;
minip_build_mac_hdr(handle->netif, eth, handle->mac, ETH_TYPE_IPV4);
minip_build_ipv4_hdr(handle->netif, ip, handle->host, IP_PROTO_UDP, len + sizeof(udp_hdr_t));
#if MINIP_USE_UDP_CHECKSUM
{
ipv4_pseudo_header_t pheader;
pheader.source_addr = handle->local_ip;
pheader.dest_addr = handle->remote_ip;
pheader.zero = 0;
pheader.protocol = IP_PROTO_UDP;
pheader.tcp_length = htons(p->dlen);
#if (MINIP_USE_UDP_CHECKSUM != 0)
udp->chksum = rfc768_chksum(ip, udp);
udp->chksum = cksum_pheader(&pheader, p->data, p->dlen);
}
#endif
LTRACEF("packet paylod len %ld\n", len);
LTRACEF("sending udp packet, len %u\n", p->dlen);
handle->netif->tx_func(handle->netif->tx_func_arg, p);
status_t err;
if (handle->netif) {
// XXX: does this always use the broadcast mac?
err = minip_ipv4_send_raw(p, handle->remote_ip, IP_PROTO_UDP, bcast_mac, handle->netif);
} else {
err = minip_ipv4_send(p, handle->remote_ip, IP_PROTO_UDP);
}
return ret;
return err;
}
status_t udp_send(void *buf, size_t len, udp_socket_t *handle) {

View File

@@ -222,8 +222,6 @@ void platform_init(void) {
TRACEF("found virtio networking interface\n");
virtio_net_start();
minip_start_dhcp();
}
#endif
}