5 Commits

Author SHA1 Message Date
Travis Geiselbrecht
f5afe9c4f1 WIP more irc 2022-04-10 13:58:22 -07:00
Travis Geiselbrecht
10853d3259 WIP more net stack 2022-04-04 00:49:58 -07:00
Travis Geiselbrecht
358b1815f3 WIP start of IRC app 2022-04-02 15:51:30 -07:00
Travis Geiselbrecht
9d5c8ee90e WIP adding network interface layer
First stab actually seems to work kinda.
virtio-net only
e1000 broken. other builds with nics almost certainly broken
2022-04-01 16:21:26 -07:00
Travis Geiselbrecht
d0a71b1b94 WIP minip add interface layer 2022-03-31 00:16:57 -07:00
23 changed files with 1238 additions and 453 deletions

338
app/irc/irc.cpp Normal file
View File

@@ -0,0 +1,338 @@
/*
* Copyright (c) 2021 Travis Geiselbrecht
*
* Use of this source code is governed by a MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT
*/
#include <string.h>
#include <stdio.h>
#include <lk/debug.h>
#include <lk/err.h>
#include <lk/trace.h>
#include <app.h>
#include <lib/minip.h>
#include <kernel/thread.h>
#include <kernel/mutex.h>
#include "lktl.h"
#define LOCAL_TRACE 1
//#define IRC_SERVER IPV4(176,58,122,119) // irc.libera.chat
#define IRC_SERVER IPV4(88,99,244,4) // irc.sortix.org
//#define IRC_SERVER IPV4(192,168,1,110) // localhost
#define IRC_PORT 6667
#define IRC_USER "geist"
#define IRC_NICK "geist-lk"
#define IRC_CHAN "#sortix"
//#define IRC_CHAN "#osdev"
class irc_client {
public:
irc_client();
~irc_client();
void init();
void shutdown();
status_t connect();
status_t handshake();
status_t read_loop();
status_t console_input_line(const char *line, bool &exit);
void set_server(uint32_t server) { server_ip_ = server; }
void set_server_port(uint16_t port) { server_port_ = port; }
private:
mutex_t lock_ = MUTEX_INITIAL_VALUE(lock_);
tcp_socket_t *sock_ = nullptr;
uint32_t server_ip_ = 0;
uint16_t server_port_ = 0;
enum {
INITIAL,
CONNECTED,
HANDSHOOK,
} state_ = INITIAL;
};
irc_client::irc_client() = default;
irc_client::~irc_client() = default;
void irc_client::init() {
}
void irc_client::shutdown() {
lktl::auto_lock al(&lock_);
if (sock_) {
if (state_ == HANDSHOOK) {
// send quit
tcp_write(sock_, "QUIT\r\n", strlen("QUIT\r\n"));
// XXX flush socket
thread_sleep(1000);
}
tcp_close(sock_);
sock_ = nullptr;
}
}
status_t irc_client::connect() {
lktl::auto_lock al(&lock_);
if (server_ip_ == 0 || server_port_ == 0) {
return ERR_NOT_CONFIGURED;
}
auto err = tcp_connect(&sock_, server_ip_, server_port_);
if (err < 0) {
printf("err %d connecting to server\n", err);
return ERR_CHANNEL_CLOSED; // TODO: better one
}
state_ = CONNECTED;
return NO_ERROR;
}
status_t irc_client::read_loop() {
char line[1024];
int pos = 0;
for (;;) {
char c;
ssize_t r = tcp_read(sock_, &c, sizeof(c));
if (r < 0) {
return r;
}
if (r == 0) {
TRACEF("tcp_read returns 0?\n");
return ERR_GENERIC;
}
// TODO: make sure we dont overwrite the line
// append the char to our accumulated line
if (c == '\r') {
// consume \r
continue;
}
// store the char
line[pos++] = c;
if (c != '\n') {
// we're done, loop around
continue;
}
// we've completed a line, process it
line[pos] = 0; // terminate the string
pos = 0; // next time around we start over
lktl::auto_lock al(&lock_);
if (strncmp(line, "PING", strlen("PING"))== 0) {
// handle a PONG
tcp_write(sock_, "PONG\r\n", strlen("PONG\r\n"));
printf("%s", line);
printf("PING/PONG\n");
} else {
printf("%s", line);
}
}
return NO_ERROR;
}
status_t irc_client::console_input_line(const char *line, bool &exit) {
//printf("CONSOLE LINE '%s'\n", line);
if (strlen(line) == 0) {
return NO_ERROR;
}
// see if it starts with /
if (line[0] == '/') {
if (line[1] == 0) {
// malformed command
return NO_ERROR;
}
// look for quit command
if (strncmp(&line[1], "quit", strlen("quit")) == 0) {
shutdown();
exit = true;
return NO_ERROR;
} else {
printf("bad command\n");
return NO_ERROR;
}
}
lktl::auto_lock al(&lock_);
// send it as a privmsg
char buf[256];
snprintf(buf, sizeof(buf), "PRIVMSG #sortix :%s\r\n", line);
status_t err = tcp_write(sock_, buf, strlen(buf));
return err;
}
status_t irc_client::handshake() {
lktl::auto_lock al(&lock_);
// send USER and NICK
char buf[128];
snprintf(buf, sizeof(buf), "USER %s host server :geist\r\n", IRC_USER);
status_t err = tcp_write(sock_, buf, strlen(buf));
if (err < 0) {
printf("error %d writing to server\n", err);
return err;
}
snprintf(buf, sizeof(buf), "NICK %s\r\n", IRC_NICK);
err = tcp_write(sock_, buf, strlen(buf));
if (err < 0) {
printf("error %d writing to server\n", err);
return err;
}
snprintf(buf, sizeof(buf), "JOIN %s\r\n", IRC_CHAN);
err = tcp_write(sock_, buf, strlen(buf));
if (err < 0) {
printf("error %d writing to server\n", err);
return err;
}
state_ = HANDSHOOK;
return NO_ERROR;
}
// console worker thread
static int console_thread_worker(void *arg) {
irc_client *irc = static_cast<irc_client *>(arg);
LTRACEF("top of console thread\n");
// read a line from the console, giving it to the irc client object at EOL
status_t err;
char line[256];
int pos = 0;
bool exit = false;
while (!exit) {
int c = getchar();
if (c <= 0) {
break;
}
if (pos == sizeof(line)) {
printf("line too long, discarding\n");
pos = 0;
}
//printf("char %c (%d)\n", c, c);
switch (c) {
case '\n':
case '\r':
if (pos > 0) {
putchar('\n');
// end of a line with characters in it, feed it to the irc client
line[pos++] = 0; // null terminate
err = irc->console_input_line(line, exit);
if (err < 0) {
exit = true;
}
pos = 0;
}
break;
case '\b': // backspace
case 127: // DEL
if (pos > 0) {
pos--;
fputs("\b \b", stdout); // wipe out a character
}
break;
default:
line[pos++] = (char)c;
putchar(c);
break;
}
}
LTRACEF("console thread exiting\n");
return 0;
};
static void irc_app_entry(const struct app_descriptor *app, void *args) {
LTRACE_ENTRY;
printf("welcome to IRC!\n");
// create a local state object
irc_client *irc = new irc_client();
if (!irc) {
return;
}
status_t err;
irc->init();
// clean up and delete the object on the way out
auto cleanup = [&irc]() {
printf("cleaning up IRC\n");
irc->shutdown();
delete irc;
};
auto ac = lktl::make_auto_call(cleanup);
// configure the parameters
irc->set_server(IRC_SERVER);
irc->set_server_port(IRC_PORT);
err = irc->connect();
if (err < 0) {
return;
}
err = irc->handshake();
if (err < 0) {
return;
}
// start two threads
thread_t *console_thread;
thread_t *server_thread;
console_thread = thread_create("irc console", console_thread_worker, irc, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
thread_resume(console_thread);
auto server_thread_worker = [](void *arg) -> int {
irc_client *_irc = static_cast<irc_client *>(arg);
printf("top of server thread\n");
_irc->read_loop();
return 0;
};
server_thread = thread_create("irc socket", server_thread_worker, irc, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
thread_resume(server_thread);
thread_join(server_thread, nullptr, INFINITE_TIME);
thread_join(console_thread, nullptr, INFINITE_TIME);
LTRACE_EXIT;
}
APP_START(irc)
.init = nullptr,
.entry = irc_app_entry,
.flags = APP_FLAG_NO_AUTOSTART,
.stack_size = 0,
APP_END

92
app/irc/lktl.h Normal file
View File

@@ -0,0 +1,92 @@
/*
* Copyright (c) 2021 Travis Geiselbrecht
*
* Use of this source code is governed by a MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT
*/
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <kernel/thread.h>
#include <kernel/mutex.h>
// Macro used to simplify the task of deleting all of the default copy
// constructors and assignment operators.
#define DISALLOW_COPY_ASSIGN_AND_MOVE(_class_name) \
_class_name(const _class_name&) = delete; \
_class_name(_class_name&&) = delete; \
_class_name& operator=(const _class_name&) = delete; \
_class_name& operator=(_class_name&&) = delete
// Macro used to simplify the task of deleting the non rvalue reference copy
// constructors and assignment operators. (IOW - forcing move semantics)
#define DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(_class_name) \
_class_name(const _class_name&) = delete; \
_class_name& operator=(const _class_name&) = delete
// Macro used to simplify the task of deleting the new and new[]
// operators. (IOW - disallow heap allocations)
#define DISALLOW_NEW \
static void* operator new(size_t) = delete; \
static void* operator new[](size_t) = delete
#pragma once
namespace lktl {
// call a routine when the object goes out of scope
template <typename T>
class auto_call {
public:
constexpr explicit auto_call(T call) : call_(call) {}
~auto_call() {
if (armed_) {
call_();
}
}
// move
auto_call(auto_call &&ac) : armed_(ac.armed_), call_(ac.call_) {
ac.cancel();
}
void cancel() {
armed_ = false;
}
private:
DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(auto_call);
bool armed_ = true;
T call_;
};
// create an auto caller with implicit template specialization.
//
// example:
// auto ac = make_auto_call([]() { printf("a lambda!\n"); });
template <typename T>
inline auto_call<T> make_auto_call(T c) {
return auto_call<T>(c);
}
// auto mutex scope guard
class auto_lock {
public:
explicit auto_lock(mutex_t *m) : m_(m) {
mutex_acquire(m_);
}
~auto_lock() {
mutex_release(m_);
}
private:
DISALLOW_COPY_ASSIGN_AND_MOVE(auto_lock);
mutex_t *m_ = nullptr;
};
} // namespace lktl

12
app/irc/rules.mk Normal file
View File

@@ -0,0 +1,12 @@
LOCAL_DIR := $(GET_LOCAL_DIR)
MODULE := $(LOCAL_DIR)
MODULE_SRCS += \
$(LOCAL_DIR)/irc.cpp \
MODULE_DEPS := \
lib/libcpp \
lib/minip
include make/module.mk

View File

@@ -241,7 +241,8 @@ int e1000::rx_worker_routine() {
}
// push it up the stack
minip_rx_driver_callback(p);
// XXX: broken
minip_rx_driver_callback(NULL, p);
// we own the pktbuf again
@@ -513,6 +514,7 @@ status_t e1000::init_device(pci_location_t loc, const e1000_id_features *id) {
extern "C"
status_t e1000_register_with_minip() {
#if 0
auto tx_routine = [](void *arg, pktbuf_t *p) {
auto *e = static_cast<e1000 *>(arg);
return e->tx(p);
@@ -522,6 +524,9 @@ status_t e1000_register_with_minip() {
minip_set_eth(tx_routine, the_e, the_e->mac_addr());
return NO_ERROR;
}
#endif
// XXX: move to netif
PANIC_UNIMPLEMENTED;
return ERR_NOT_FOUND;
}

View File

@@ -16,9 +16,3 @@ status_t virtio_net_start(void);
/* return the count of virtio interfaces found */
int virtio_net_found(void);
status_t virtio_net_get_mac_addr(uint8_t mac_addr[6]);
struct pktbuf;
extern status_t virtio_net_send_minip_pkt(void *arg, struct pktbuf *p);

View File

@@ -20,6 +20,7 @@
#include <kernel/spinlock.h>
#include <lib/pktbuf.h>
#include <lib/minip.h>
#include <lib/minip/netif.h>
#define LOCAL_TRACE 0
@@ -89,11 +90,16 @@ struct virtio_net_dev {
uint tx_pending_count;
struct list_node completed_rx_queue;
/* the minip ethernet structure */
netif_t netif;
};
static enum handler_return virtio_net_irq_driver_callback(struct virtio_device *dev, uint ring, const struct vring_used_elem *e);
static int virtio_net_rx_worker(void *arg);
static status_t virtio_net_queue_rx(struct virtio_net_dev *ndev, pktbuf_t *p);
static status_t virtio_net_get_mac_addr(uint8_t mac_addr[6]);
static status_t virtio_net_send_minip_pkt(void *arg, pktbuf_t *p);
// XXX remove need for this
static struct virtio_net_dev *the_ndev;
@@ -158,6 +164,9 @@ status_t virtio_net_init(struct virtio_device *dev, uint32_t host_features) {
virtio_alloc_ring(dev, RING_RX, RX_RING_SIZE); // rx
virtio_alloc_ring(dev, RING_TX, TX_RING_SIZE); // tx
/* construct the minip netif interface */
netif_create(&ndev->netif, "virtio");
the_ndev = ndev;
return NO_ERROR;
@@ -180,6 +189,12 @@ status_t virtio_net_start(void) {
}
}
/* register the nic with the net stack */
uint8_t mac[6];
virtio_net_get_mac_addr(mac);
netif_set_eth(&the_ndev->netif, virtio_net_send_minip_pkt, the_ndev, mac);
netif_register(&the_ndev->netif);
return NO_ERROR;
}
@@ -403,7 +418,7 @@ static int virtio_net_rx_worker(void *arg) {
struct virtio_net_hdr *hdr = pktbuf_consume(p, sizeof(struct virtio_net_hdr) - 2);
if (hdr) {
/* call up into the stack */
minip_rx_driver_callback(p);
minip_rx_driver_callback(&ndev->netif, p);
}
/* requeue the pktbuf in the rx queue */
@@ -417,7 +432,7 @@ int virtio_net_found(void) {
return the_ndev ? 1 : 0;
}
status_t virtio_net_get_mac_addr(uint8_t mac_addr[6]) {
static status_t virtio_net_get_mac_addr(uint8_t mac_addr[6]) {
if (!the_ndev)
return ERR_NOT_FOUND;
@@ -426,10 +441,11 @@ status_t virtio_net_get_mac_addr(uint8_t mac_addr[6]) {
return NO_ERROR;
}
status_t virtio_net_send_minip_pkt(void *arg, pktbuf_t *p) {
static status_t virtio_net_send_minip_pkt(void *arg, pktbuf_t *p) {
LTRACEF("p %p, dlen %u, flags 0x%x\n", p, p->dlen, p->flags);
DEBUG_ASSERT(p && p->dlen);
DEBUG_ASSERT(arg == the_ndev);
if ((p->flags & PKTBUF_FLAG_EOF) == 0) {
/* can't handle multi part packets yet */

View File

@@ -116,7 +116,7 @@ void arp_cache_dump(void) {
}
}
int arp_send_request(uint32_t addr) {
int arp_send_request(netif_t *netif, ipv4_addr_t addr) {
pktbuf_t *p;
struct eth_hdr *eth;
struct arp_pkt *arp;
@@ -127,19 +127,21 @@ int arp_send_request(uint32_t addr) {
eth = pktbuf_prepend(p, sizeof(struct eth_hdr));
arp = pktbuf_append(p, sizeof(struct arp_pkt));
minip_build_mac_hdr(eth, bcast_mac, ETH_TYPE_ARP);
minip_build_mac_hdr(netif, eth, bcast_mac, ETH_TYPE_ARP);
arp->htype = htons(0x0001);
arp->ptype = htons(0x0800);
arp->hlen = 6;
arp->plen = 4;
arp->oper = htons(ARP_OPER_REQUEST);
arp->spa = minip_get_ipaddr();
arp->spa = netif->ipv4_addr;
arp->tpa = addr;
minip_get_macaddr(arp->sha);
mac_addr_copy(arp->sha, netif->mac_address);
mac_addr_copy(arp->tha, bcast_mac);
minip_tx_handler(minip_tx_arg, p);
if (netif->tx_func) {
netif->tx_func(netif->tx_func_arg, p);
}
return 0;
}
@@ -158,7 +160,15 @@ const uint8_t *arp_get_dest_mac(uint32_t host) {
dst_mac = arp_cache_lookup(host);
if (dst_mac == NULL) {
arp_send_request(host);
// 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) {
@@ -168,7 +178,70 @@ const uint8_t *arp_get_dest_mac(uint32_t host) {
break;
}
}
ipv4_dec_route_ref(route);
}
return dst_mac;
}
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) {
return -1;
}
switch (ntohs(arp->oper)) {
case ARP_OPER_REQUEST: {
pktbuf_t *rp;
struct eth_hdr *reth;
struct arp_pkt *rarp;
if (memcmp(&arp->tpa, &netif->ipv4_addr, sizeof(netif->ipv4_addr)) == 0) {
if ((rp = pktbuf_alloc()) == NULL) {
break;
}
LTRACEF("arp request for us\n");
reth = pktbuf_prepend(rp, sizeof(struct eth_hdr));
rarp = pktbuf_append(rp, sizeof(struct arp_pkt));
// Eth header
minip_build_mac_hdr(netif, reth, eth->src_mac, ETH_TYPE_ARP);
// ARP packet
rarp->oper = htons(ARP_OPER_REPLY);
rarp->htype = htons(0x0001);
rarp->ptype = htons(0x0800);
rarp->hlen = 6;
rarp->plen = 4;
mac_addr_copy(rarp->sha, netif->mac_address);
rarp->spa = netif->ipv4_addr;
mac_addr_copy(rarp->tha, arp->sha);
rarp->tpa = arp->spa;
netif->tx_func(netif->tx_func_arg, rp);
}
}
break;
case ARP_OPER_REPLY: {
LTRACEF("arp reply for us\n");
uint32_t addr;
memcpy(&addr, &arp->spa, sizeof(addr)); // unaligned word
arp_cache_update(addr, arp->sha);
}
break;
}
return 0;
}

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

@@ -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
@@ -93,6 +93,7 @@ private:
Mutex lock_;
udp_socket_t *dhcp_udp_handle_ = nullptr;
thread_t *dhcp_thr_ = nullptr;
netif_t *netif_ = nullptr;
volatile bool configured_ = false;
uint32_t xid_ = rand();
@@ -118,7 +119,7 @@ status_t dhcp::send_discover() {
s.msg.hwalen = 6;
s.msg.xid = xid_;
s.msg.cookie = 0x63538263;
minip_get_macaddr(s.msg.chaddr);
mac_addr_copy(s.msg.chaddr, netif_->mac_address);
*opt++ = OPT_MSG_TYPE;
*opt++ = 1;
@@ -160,7 +161,7 @@ status_t dhcp::send_request(u32 server, u32 reqip) {
s.msg.hwalen = 6;
s.msg.xid = xid_;
s.msg.cookie = 0x63538263;
minip_get_macaddr(s.msg.chaddr);
mac_addr_copy(s.msg.chaddr, netif_->mac_address);
*opt++ = OPT_MSG_TYPE;
*opt++ = 1;
@@ -227,13 +228,11 @@ void dhcp::udp_callback(void *data, size_t sz, uint32_t srcip, uint16_t srcport)
if (sz < sizeof(dhcp_msg_t)) return;
uint8_t mac[6];
minip_get_macaddr(mac);
if (memcmp(msg->chaddr, mac, 6)) return;
if (memcmp(msg->chaddr, netif_->mac_address, sizeof(netif_->mac_address))) return;
#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
@@ -242,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]);
@@ -289,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) {
@@ -309,14 +308,16 @@ 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");
minip_set_ipaddr(msg->yiaddr);
uint8_t netwidth = 32;
if (netmask) {
minip_set_netmask(netmask);
netwidth = __builtin_ctz(~netmask);
//printf("netmask %#x netwidth %u\n", netmask, netwidth);
}
netif_set_ipv4_addr(netif_, msg->yiaddr, netwidth);
if (gateway) {
minip_set_gateway(gateway);
}
@@ -359,10 +360,13 @@ int dhcp::dhcp_thread(void *arg) {
return 0;
}
status_t dhcp::start() {
status_t dhcp::start(netif_t *netif) {
AutoLock guard(lock_);
int ret = udp_open(IPV4_BCAST, DHCP_CLIENT_PORT, DHCP_SERVER_PORT, &dhcp_udp_handle_);
netif_ = netif;
// 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;
@@ -378,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

@@ -24,18 +24,22 @@ __BEGIN_CDECLS
#define IPV4_BCAST (0xFFFFFFFF)
#define IPV4_NONE (0)
/* 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,
uint32_t srcaddr, uint16_t srcport, void *arg);
/* initialize and start minip with static configuration */
void minip_start_static(uint32_t ip, uint32_t netmask, uint32_t gateway);
//void minip_start_static(uint32_t ip, uint32_t netmask, uint32_t gateway);
/* initialize and start minip with DHCP configuration
* 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);
@@ -45,19 +49,11 @@ bool minip_is_configured(void);
status_t minip_wait_for_configured(lk_time_t timeout);
/* packet rx hook to hand to ethernet driver */
void minip_rx_driver_callback(pktbuf_t *p);
void minip_rx_driver_callback(netif_t *netif, pktbuf_t *p);
/* global configuration state */
void minip_get_macaddr(uint8_t *addr);
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_gateway(const ipv4_addr_t addr);
void minip_set_hostname(const char *name);
const char *minip_get_hostname(void);
void minip_set_configured(void); // set by dhcp or static init to signal minip is ready to be used
@@ -66,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);
@@ -87,10 +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

@@ -0,0 +1,72 @@
/*
* Copyright (c) 2022 Travis Geiselbrecht
*
* Use of this source code is governed by a MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT
*/
#pragma once
#include <lk/compiler.h>
#include <lib/minip.h>
__BEGIN_CDECLS
// Network interface layer for minip
// Per network interface structure, created by the network driver and registered
// with the net stack.
struct netif {
uint32_t magic;
struct list_node node;
uint32_t flags;
// mac address
uint8_t mac_address[6];
// ipv4 address
ipv4_addr_t ipv4_addr;
uint8_t ipv4_subnet_width;
// driver tx routine
tx_func_t tx_func;
void *tx_func_arg;
// name
char name[32];
};
typedef struct netif netif_t;
#define NETIF_MAGIC 'NETI'
#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.
netif_t *netif_create(netif_t *n, const char *name);
status_t netif_set_eth(netif_t *n, tx_func_t tx_handler, void *tx_arg, const uint8_t *macaddr);
status_t netif_set_ipv4_addr(netif_t *n, ipv4_addr_t addr, uint8_t subnet_width);
status_t netif_register(netif_t *n);
// construct netmask and broadcast addresses dynamically
static inline ipv4_addr_t netif_get_netmask_ipv4(netif_t *n) {
// subnet width 24 -> 0x00ffffff
// subnet width 16 -> 0x0000ffff, etc
return (1U << (n->ipv4_subnet_width)) - 1U;
}
static inline ipv4_addr_t netif_get_network_ipv4(netif_t *n) {
return n->ipv4_addr & netif_get_netmask_ipv4(n);
}
static inline ipv4_addr_t netif_get_broadcast_ipv4(netif_t *n) {
return netif_get_network_ipv4(n) | ~netif_get_netmask_ipv4(n);
}
__END_CDECLS

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(addr);
arp_get_dest_mac(addr);
} else {
arp_usage();
}
@@ -65,24 +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();
case 'i':
netif_dump();
break;
case 's': {
case 'r':
dump_ipv4_route_table();
break;
case 's':
printf("hostname: %s\n", minip_get_hostname());
printf("ip: %u.%u.%u.%u\n", IPV4_SPLIT(minip_get_ipaddr()));
printf("netmask: %u.%u.%u.%u\n", IPV4_SPLIT(minip_get_netmask()));
printf("broadcast: %u.%u.%u.%u\n", IPV4_SPLIT(minip_get_broadcast()));
printf("gateway: %u.%u.%u.%u\n", IPV4_SPLIT(minip_get_gateway()));
}
break;
printf("interfaces:\n");
netif_dump();
printf("ipv4 routing table:\n");
dump_ipv4_route_table();
break;
case 't': {
uint32_t count = 1;
uint32_t host = 0x0100000A; // 10.0.0.1
@@ -138,7 +141,7 @@ minip_usage:
udp_close(handle);
#undef BUFSIZE
}
break;
break;
default:
goto minip_usage;
}
@@ -147,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

@@ -15,9 +15,10 @@
#include <lk/list.h>
#include <stdint.h>
#include <string.h>
#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
@@ -86,12 +87,8 @@ enum {
ARP_OPER_REPLY = 0x0002,
};
extern tx_func_t minip_tx_handler;
extern void *minip_tx_arg;
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];
@@ -102,23 +99,57 @@ 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);
void arp_cache_dump(void);
int arp_send_request(uint32_t addr);
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(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);
void minip_build_mac_hdr(netif_t *netif, struct eth_hdr *pkt, const uint8_t *dst, uint16_t type);
status_t minip_ipv4_send(pktbuf_t *p, uint32_t dest_addr, uint8_t proto);
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(pktbuf_t *p, uint32_t src_ip, uint32_t dst_ip);
void udp_input(pktbuf_t *p, uint32_t src_ip);
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);
// 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 0
static uint32_t minip_ip = IPV4_NONE;
static uint32_t minip_netmask = IPV4_NONE;
static uint32_t minip_broadcast = IPV4_BCAST;
static uint32_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 ipv4_addr_t minip_gateway = IPV4_NONE;
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_mac_address(const uint8_t *mac);
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 (minip_ip == IPV4_NONE) return;
if (minip_netmask == IPV4_NONE) return;
if (minip_broadcast == IPV4_BCAST) return;
// minip_gateway doesn't have to be set
if (minip_mac[0] == 0xcc &&
minip_mac[1] == 0xcc &&
minip_mac[2] == 0xcc &&
minip_mac[3] == 0xcc &&
minip_mac[4] == 0xcc &&
minip_mac[5] == 0xcc) 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,45 +74,20 @@ const char *minip_get_hostname(void) {
return minip_hostname;
}
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 uint32_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 uint32_t netmask) {
minip_netmask = netmask;
compute_broadcast_address();
check_and_set_configured();
}
uint32_t minip_get_gateway(void) {
return minip_gateway;
}
void minip_set_gateway(const uint32_t addr) {
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();
}
@@ -141,36 +114,153 @@ void gen_random_mac_address(uint8_t *mac_addr) {
}
void minip_start_static(uint32_t ip, uint32_t mask, uint32_t gateway) {
minip_set_ipaddr(ip);
minip_set_netmask(mask);
PANIC_UNIMPLEMENTED;
minip_set_gateway(gateway);
}
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;
}
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));
}
void minip_build_mac_hdr(struct eth_hdr *pkt, const uint8_t *dst, uint16_t type) {
void minip_build_mac_hdr(netif_t *netif, struct eth_hdr *pkt, const uint8_t *dst, uint16_t type) {
mac_addr_copy(pkt->dst_mac, dst);
mac_addr_copy(pkt->src_mac, minip_mac);
mac_addr_copy(pkt->src_mac, netif->mac_address);
pkt->type = htons(type);
}
void minip_build_ipv4_hdr(struct ipv4_hdr *ipv4, uint32_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
@@ -179,113 +269,78 @@ void minip_build_ipv4_hdr(struct ipv4_hdr *ipv4, uint32_t dst, uint8_t proto, ui
ipv4->ttl = 64;
ipv4->proto = proto;
ipv4->dst_addr = dst;
ipv4->src_addr = minip_ip;
ipv4->src_addr = netif->ipv4_addr;
/* 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));
}
static int send_arp_request(uint32_t addr) {
pktbuf_t *p;
struct eth_hdr *eth;
struct arp_pkt *arp;
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);
if ((p = pktbuf_alloc()) == NULL) {
return -1;
}
eth = pktbuf_prepend(p, sizeof(struct eth_hdr));
arp = pktbuf_append(p, sizeof(struct arp_pkt));
minip_build_mac_hdr(eth, bcast_mac, ETH_TYPE_ARP);
arp->htype = htons(0x0001);
arp->ptype = htons(0x0800);
arp->hlen = 6;
arp->plen = 4;
arp->oper = htons(ARP_OPER_REQUEST);
arp->spa = minip_ip;
arp->tpa = addr;
mac_addr_copy(arp->sha, minip_mac);
mac_addr_copy(arp->tha, bcast_mac);
minip_tx_handler(minip_tx_arg, p);
return 0;
}
static void handle_arp_timeout_cb(void *arg) {
*(bool *)arg = true;
}
const uint8_t *get_dest_mac(uint32_t host) {
uint8_t *dst_mac = NULL;
bool arp_timeout = false;
net_timer_t arp_timeout_timer;
if (host == IPV4_BCAST) {
return bcast_mac;
}
dst_mac = arp_cache_lookup(host);
if (dst_mac == NULL) {
send_arp_request(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) {
dst_mac = arp_cache_lookup(host);
if (dst_mac) {
net_timer_cancel(&arp_timeout_timer);
break;
}
}
}
return dst_mac;
}
status_t minip_ipv4_send(pktbuf_t *p, uint32_t dest_addr, uint8_t proto) {
status_t ret = 0;
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));
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?
if (dest_addr == IPV4_BCAST || dest_addr == minip_broadcast) {
dst_mac = bcast_mac;
const uint8_t *dest_mac;
if (dest_addr == IPV4_BCAST || dest_addr == netif_get_broadcast_ipv4(netif)) {
dest_mac = bcast_mac;
goto ready;
}
// 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)) {
ipv4_addr_t target_addr = dest_addr;
ipv4_addr_t netmask = netif_get_netmask_ipv4(netif);
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(eth, dst_mac, ETH_TYPE_IPV4);
minip_build_ipv4_hdr(ip, dest_addr, proto, data_len);
minip_tx_handler(minip_tx_arg, p);
ret = minip_ipv4_send_raw(p, dest_addr, proto, dest_mac, netif);
err:
if (route) {
ipv4_dec_route_ref(route);
}
return ret;
}
@@ -293,7 +348,7 @@ err:
* According to spec the data portion doesn't matter, but ping itself validates that
* the payload is identical
*/
static void send_ping_reply(uint32_t ipaddr, struct icmp_pkt *req, size_t reqdatalen) {
static void send_ping_reply(netif_t *netif, uint32_t ipaddr, struct icmp_pkt *req, size_t reqdatalen) {
pktbuf_t *p;
size_t len;
struct eth_hdr *eth;
@@ -311,39 +366,35 @@ static void send_ping_reply(uint32_t ipaddr, struct icmp_pkt *req, size_t reqdat
len = sizeof(struct icmp_pkt) + reqdatalen;
minip_build_mac_hdr(eth, arp_cache_lookup(ipaddr), ETH_TYPE_IPV4);
minip_build_ipv4_hdr(ip, ipaddr, IP_PROTO_ICMP, len);
minip_build_mac_hdr(netif, eth, arp_cache_lookup(ipaddr), ETH_TYPE_IPV4);
minip_build_ipv4_hdr(netif, ip, ipaddr, IP_PROTO_ICMP, len);
icmp->type = ICMP_ECHO_REPLY;
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);
minip_tx_handler(minip_tx_arg, p);
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);
}
__NO_INLINE static void handle_ipv4_packet(pktbuf_t *p, const uint8_t *src_mac) {
__NO_INLINE static void handle_ipv4_packet(netif_t *netif, pktbuf_t *p, const uint8_t *src_mac) {
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) {
@@ -365,7 +416,7 @@ __NO_INLINE static void handle_ipv4_packet(pktbuf_t *p, const uint8_t *src_mac)
}
/* 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;
@@ -392,7 +443,7 @@ __NO_INLINE static void handle_ipv4_packet(pktbuf_t *p, const uint8_t *src_mac)
/* see if it's for us */
if (ip->dst_addr != IPV4_BCAST) {
if (minip_ip != IPV4_NONE && ip->dst_addr != minip_ip && ip->dst_addr != minip_broadcast) {
if (netif->ipv4_addr != IPV4_NONE && ip->dst_addr != netif->ipv4_addr && ip->dst_addr != netif_get_broadcast_ipv4(netif)) {
LTRACEF("REJECT: for another host\n");
return;
}
@@ -406,86 +457,34 @@ __NO_INLINE static void handle_ipv4_packet(pktbuf_t *p, const uint8_t *src_mac)
break;
}
if (icmp->type == ICMP_ECHO_REQUEST) {
send_ping_reply(ip->src_addr, icmp, p->dlen);
send_ping_reply(netif, ip->src_addr, icmp, p->dlen);
}
}
break;
case IP_PROTO_UDP:
udp_input(p, ip->src_addr);
udp_input(netif, p, ip->src_addr);
break;
case IP_PROTO_TCP:
tcp_input(p, ip->src_addr, ip->dst_addr);
tcp_input(netif, p, ip->src_addr, ip->dst_addr);
break;
}
}
__NO_INLINE static int handle_arp_pkt(pktbuf_t *p) {
struct eth_hdr *eth;
struct arp_pkt *arp;
eth = (void *) (p->data - sizeof(struct eth_hdr));
if ((arp = pktbuf_consume(p, sizeof(struct arp_pkt))) == NULL) {
return -1;
}
switch (ntohs(arp->oper)) {
case ARP_OPER_REQUEST: {
pktbuf_t *rp;
struct eth_hdr *reth;
struct arp_pkt *rarp;
if (memcmp(&arp->tpa, &minip_ip, sizeof(minip_ip)) == 0) {
if ((rp = pktbuf_alloc()) == NULL) {
break;
}
reth = pktbuf_prepend(rp, sizeof(struct eth_hdr));
rarp = pktbuf_append(rp, sizeof(struct arp_pkt));
// Eth header
minip_build_mac_hdr(reth, eth->src_mac, ETH_TYPE_ARP);
// ARP packet
rarp->oper = htons(ARP_OPER_REPLY);
rarp->htype = htons(0x0001);
rarp->ptype = htons(0x0800);
rarp->hlen = 6;
rarp->plen = 4;
mac_addr_copy(rarp->sha, minip_mac);
rarp->spa = minip_ip;
mac_addr_copy(rarp->tha, arp->sha);
rarp->tpa = arp->spa;
minip_tx_handler(minip_tx_arg, rp);
}
}
break;
case ARP_OPER_REPLY: {
uint32_t addr;
memcpy(&addr, &arp->spa, sizeof(addr)); // unaligned word
arp_cache_update(addr, arp->sha);
}
break;
}
return 0;
}
static void dump_eth_packet(const struct eth_hdr *eth) {
printf("ETH src ");
dump_mac_address(eth->src_mac);
print_mac_address(eth->src_mac);
printf(" dst ");
dump_mac_address(eth->dst_mac);
print_mac_address(eth->dst_mac);
printf(" type 0x%hx\n", htons(eth->type));
}
void minip_rx_driver_callback(pktbuf_t *p) {
struct eth_hdr *eth;
void minip_rx_driver_callback(netif_t *netif, pktbuf_t *p) {
DEBUG_ASSERT(netif);
DEBUG_ASSERT(p);
struct eth_hdr *eth;
if ((eth = (void *) pktbuf_consume(p, sizeof(struct eth_hdr))) == NULL) {
return;
}
@@ -494,30 +493,27 @@ void minip_rx_driver_callback(pktbuf_t *p) {
dump_eth_packet(eth);
}
if (memcmp(eth->dst_mac, minip_mac, 6) != 0 &&
memcmp(eth->dst_mac, broadcast_mac, 6) != 0) {
if (memcmp(eth->dst_mac, netif->mac_address, 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(p, eth->src_mac);
handle_ipv4_packet(netif, p, eth->src_mac);
break;
case ETH_TYPE_ARP:
LTRACEF("arp pkt\n");
handle_arp_pkt(p);
handle_arp_pkt(netif, p);
break;
default:
LTRACEF("unhandled pkt type %#hx\n", htons(eth->type));
break;
}
}
void dump_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;
@@ -538,26 +534,30 @@ 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
static void minip_init(uint level) {
arp_cache_init();
net_timer_init();
netif_init();
}
LK_INIT_HOOK(minip, minip_init, LK_INIT_LEVEL_THREADING);

148
lib/minip/netif.c Normal file
View File

@@ -0,0 +1,148 @@
/*
* Copyright (c) 2022 Travis Geiselbrecht
*
* Use of this source code is governed by a MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT
*/
#include <lib/minip/netif.h>
#include <lk/err.h>
#include <lk/list.h>
#include <lk/trace.h>
#include <lib/minip.h>
#include <assert.h>
#include <stdlib.h>
#include <kernel/mutex.h>
#include "minip-internal.h"
#define LOCAL_TRACE 1
static struct list_node netif_list = LIST_INITIAL_VALUE(netif_list);
static mutex_t lock = MUTEX_INITIAL_VALUE(lock);
static netif_t loopback;
static int loopback_tx_func(void *arg, pktbuf_t *p) {
LTRACEF("arg %p, pkt %p\n", arg, p);
return 0;
}
void netif_init(void) {
LTRACE;
// 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(127, 0, 0, 1), 8);
netif_register(&loopback);
}
netif_t *netif_create(netif_t *n, const char *name) {
LTRACEF("n %p\n", n);
if (!n) {
n = malloc(sizeof(netif_t));
}
if (!n) {
return NULL;
}
memset(n, 0, sizeof(*n));
n->magic = NETIF_MAGIC;
strlcpy(n->name, name, sizeof(n->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);
DEBUG_ASSERT(n->magic == NETIF_MAGIC);
mutex_acquire(&lock);
// check that it is at least configured
DEBUG_ASSERT(n->flags & NETIF_FLAG_ETH_CONFIGURED);
DEBUG_ASSERT((n->flags & NETIF_FLAG_REGISTERED) == 0);
list_add_head(&netif_list, &n->node);
n->flags |= NETIF_FLAG_REGISTERED;
mutex_release(&lock);
// let overridable external logic deal with this
netif_registration_callback(n);
return NO_ERROR;
}
status_t netif_set_eth(netif_t *n, tx_func_t tx_handler, void *tx_arg, const uint8_t *macaddr) {
DEBUG_ASSERT(n->magic == NETIF_MAGIC);
DEBUG_ASSERT(tx_handler);
mutex_acquire(&lock);
// must not have been already configured
DEBUG_ASSERT((n->flags & NETIF_FLAG_ETH_CONFIGURED) == 0);
// set the state and mark configured
mac_addr_copy(n->mac_address, macaddr);
n->tx_func = tx_handler;
n->tx_func_arg = tx_arg;
n->flags |= NETIF_FLAG_ETH_CONFIGURED;
mutex_release(&lock);
return NO_ERROR;
}
status_t netif_set_ipv4_addr(netif_t *n, ipv4_addr_t addr, uint8_t subnet_width) {
DEBUG_ASSERT(n->magic == NETIF_MAGIC);
mutex_acquire(&lock);
n->ipv4_addr = addr;
n->ipv4_subnet_width = subnet_width;
n->flags |= NETIF_FLAG_IPV4_CONFIGURED;
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;
}
void netif_dump(void) {
mutex_acquire(&lock);
netif_t *n;
list_for_every_entry(&netif_list, n, netif_t, node) {
printf("net interface @%p: name '%s' mac ", n, n->name);
print_mac_address(n->mac_address);
printf(" addr ");
print_ipv4_address(n->ipv4_addr);
printf("/%u", n->ipv4_subnet_width);
printf(" netmask ");
print_ipv4_address(netif_get_netmask_ipv4(n));
printf(" bcast ");
print_ipv4_address(netif_get_broadcast_ipv4(n));
printf("\n");
}
mutex_release(&lock);
}

View File

@@ -15,6 +15,7 @@ MODULE_SRCS += \
$(LOCAL_DIR)/lk_console.c \
$(LOCAL_DIR)/minip.c \
$(LOCAL_DIR)/net_timer.c \
$(LOCAL_DIR)/netif.c \
$(LOCAL_DIR)/pktbuf.c \
$(LOCAL_DIR)/tcp.c \
$(LOCAL_DIR)/udp.c

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 source_addr;
ipv4_addr 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 */
@@ -80,10 +72,11 @@ typedef struct tcp_socket {
volatile int ref;
tcp_state_t state;
ipv4_addr local_ip;
ipv4_addr remote_ip;
ipv4_addr_t local_ip;
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
@@ -138,11 +131,11 @@ static struct list_node tcp_socket_list = LIST_INITIAL_VALUE(tcp_socket_list);
static bool tcp_debug = false;
/* local routines */
static tcp_socket_t *lookup_socket(ipv4_addr remote_ip, ipv4_addr local_ip, uint16_t remote_port, uint16_t local_port);
static tcp_socket_t *lookup_socket(ipv4_addr_t remote_ip, ipv4_addr_t local_ip, uint16_t remote_port, uint16_t local_port);
static void add_socket_to_list(tcp_socket_t *s);
static void remove_socket_from_list(tcp_socket_t *s);
static tcp_socket_t *create_tcp_socket(bool alloc_buffers);
static status_t tcp_send(ipv4_addr dest_ip, uint16_t dest_port, ipv4_addr src_ip, uint16_t src_port, const void *buf,
static status_t tcp_send(ipv4_addr_t dest_ip, uint16_t dest_port, ipv4_addr_t src_ip, uint16_t src_port, const void *buf,
size_t len, tcp_flags_t flags, const void *options, size_t options_length, uint32_t ack, uint32_t sequence, uint16_t window_size);
static status_t tcp_socket_send(tcp_socket_t *s, const void *data, size_t len, tcp_flags_t flags, const void *options, size_t options_length, uint32_t sequence);
static void handle_data(tcp_socket_t *s, const void *data, size_t len, uint32_t sequence);
@@ -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),
@@ -216,7 +204,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) {
static tcp_socket_t *lookup_socket(ipv4_addr_t remote_ip, ipv4_addr_t local_ip, uint16_t remote_port, uint16_t 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);
@@ -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);
@@ -328,7 +320,7 @@ static void tcp_timer_cancel(tcp_socket_t *s, net_timer_t *timer) {
dec_socket_ref(s);
}
void tcp_input(pktbuf_t *p, uint32_t src_ip, uint32_t dst_ip) {
void tcp_input(netif_t *netif, pktbuf_t *p, uint32_t src_ip, uint32_t dst_ip) {
if (unlikely(tcp_debug))
TRACEF("p %p (len %u), src_ip 0x%x, dst_ip 0x%x\n", p, p->dlen, src_ip, dst_ip);
@@ -351,7 +343,7 @@ void tcp_input(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;
@@ -427,12 +419,19 @@ void tcp_input(pktbuf_t *p, uint32_t src_ip, uint32_t dst_ip) {
goto done;
/* set it up */
accept_socket->local_ip = minip_get_ipaddr();
accept_socket->local_ip = netif->ipv4_addr;
accept_socket->local_port = s->local_port;
accept_socket->remote_ip = src_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);
@@ -719,7 +718,7 @@ static void send_ack(tcp_socket_t *s) {
tcp_socket_send(s, NULL, 0, PKT_ACK, NULL, 0, s->tx_win_low);
}
static status_t tcp_send(ipv4_addr dest_ip, uint16_t dest_port, ipv4_addr src_ip, uint16_t src_port, const void *buf,
static status_t tcp_send(ipv4_addr_t dest_ip, uint16_t dest_port, ipv4_addr_t src_ip, uint16_t src_port, const void *buf,
size_t len, tcp_flags_t flags, const void *options, size_t options_length, uint32_t ack, uint32_t sequence, uint16_t window_size) {
DEBUG_ASSERT(len == 0 || buf);
DEBUG_ASSERT(options_length == 0 || options);
@@ -751,7 +750,7 @@ static status_t tcp_send(ipv4_addr dest_ip, uint16_t dest_port, ipv4_addr src_ip
/* 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,11 +993,18 @@ 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));
// 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 = minip_get_ipaddr();
s->local_ip = netif->ipv4_addr;
s->local_port = (rand() + 1024) & 0xffff; // TODO: allocate sanely
DEBUG_ASSERT(s->local_port <= 0xffff);
s->remote_ip = addr;
@@ -1028,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;
}
@@ -1277,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");
@@ -1360,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,14 @@ 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;
typedef struct udp_hdr {
@@ -43,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;
@@ -70,31 +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;
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;
@@ -106,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,29 +164,39 @@ status_t udp_send_iovec(const iovec_t *iov, uint iov_count, udp_socket_t *handle
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(eth, handle->mac, ETH_TYPE_IPV4);
minip_build_ipv4_hdr(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);
minip_tx_handler(minip_tx_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) {
@@ -170,7 +214,7 @@ status_t udp_send(void *buf, size_t len, udp_socket_t *handle) {
return udp_send_iovec(&iov, 1, handle);
}
void udp_input(pktbuf_t *p, uint32_t src_ip) {
void udp_input(netif_t *netif, pktbuf_t *p, uint32_t src_ip) {
udp_hdr_t *udp;
struct udp_listener *e;
uint16_t port;

View File

@@ -219,23 +219,9 @@ void platform_init(void) {
#if WITH_LIB_MINIP
if (virtio_net_found() > 0) {
uint8_t mac_addr[6];
virtio_net_get_mac_addr(mac_addr);
TRACEF("found virtio networking interface\n");
/* start minip */
minip_set_eth(virtio_net_send_minip_pkt, NULL, mac_addr);
__UNUSED uint32_t ip_addr = IPV4(192, 168, 0, 99);
__UNUSED uint32_t ip_mask = IPV4(255, 255, 255, 0);
__UNUSED uint32_t ip_gateway = IPV4_NONE;
virtio_net_start();
//minip_start_static(ip_addr, ip_mask, ip_gateway);
minip_start_dhcp();
}
#endif
}

View File

@@ -1,5 +1,6 @@
# main project for qemu-aarch64
MODULES += \
app/irc \
app/shell
include project/virtual/test.mk

View File

@@ -1,5 +1,6 @@
# main project for qemu-riscv64-supervisor
MODULES += \
app/irc \
app/shell
SUBARCH := 64
RISCV_MODE := supervisor

View File

@@ -76,9 +76,15 @@ if [ "$PROJECT" == "" ]; then
fi
ARGS=" -cpu $CPU -m $MEMSIZE -smp $SMP -machine $MACHINE -kernel build-${PROJECT}/lk.elf"
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,ifname=qemu0,script=no -device virtio-net-device,netdev=vmnic"
BLOCK_ARGS=" -drive if=none,file=blk.bin,id=blk,format=raw"
BLOCK_DEVICE_ARGS=" -device virtio-blk-device,drive=blk"
NET_DEVICE_ARGS=" -device virtio-net-device,netdev=vmnic"
NET_FWD_ARGS+=",hostfwd=tcp::10007-:7"
NET_FWD_ARGS+=",hostfwd=tcp::10009-:9"
NET_FWD_ARGS+=",hostfwd=tcp::10019-:19"
NET_FWD_ARGS+=",hostfwd=tcp::10025-:25"
NET_ARGS=" -netdev user,id=vmnic,hostname=qemu${NET_FWD_ARGS}"
NET_TAP_ARGS=" -netdev tap,id=vmnic,ifname=qemu0,script=no"
NO_NET_ARGS=" -net none"
DISPLAY_ARGS=" -device virtio-gpu-device -serial stdio"
NO_DISPLAY_ARGS=" -nographic"
@@ -88,15 +94,18 @@ echo DO_NET = $DO_NET
if [ $DO_BLOCK == 1 ]; then
ARGS+=$BLOCK_ARGS
ARGS+=$BLOCK_DEVICE_ARGS
fi
if [ $DO_NET == 1 ]; then
ARGS+=$NET_ARGS
ARGS+=$NET_DEVICE_ARGS
else
ARGS+=$NO_NET_ARGS
fi
if [ $DO_NET_TAP == 1 ]; then
ARGS+=$NET_TAP_ARGS
SUDO="sudo "
ARGS+=$NET_DEVICE_ARGS
#SUDO="sudo "
fi
if [ $DO_DISPLAY == 1 ]; then
ARGS+=$DISPLAY_ARGS

View File

@@ -56,5 +56,6 @@
#define ERR_BAD_HANDLE (-42)
#define ERR_ACCESS_DENIED (-43)
#define ERR_PARTIAL_WRITE (-44)
#define ERR_NO_ROUTE (-45)
#define ERR_USER_BASE (-16384)