Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f5afe9c4f1 | ||
|
|
10853d3259 | ||
|
|
358b1815f3 | ||
|
|
9d5c8ee90e | ||
|
|
d0a71b1b94 |
338
app/irc/irc.cpp
Normal file
338
app/irc/irc.cpp
Normal 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
92
app/irc/lktl.h
Normal 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
12
app/irc/rules.mk
Normal 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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
72
lib/minip/include/lib/minip/netif.h
Normal file
72
lib/minip/include/lib/minip/netif.h
Normal 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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 *);
|
||||
|
||||
@@ -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
148
lib/minip/netif.c
Normal 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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# main project for qemu-aarch64
|
||||
MODULES += \
|
||||
app/irc \
|
||||
app/shell
|
||||
|
||||
include project/virtual/test.mk
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# main project for qemu-riscv64-supervisor
|
||||
MODULES += \
|
||||
app/irc \
|
||||
app/shell
|
||||
SUBARCH := 64
|
||||
RISCV_MODE := supervisor
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user