diff --git a/kernel/exceptions/timer.c b/kernel/exceptions/timer.c index 2f3f0384..5cb4edb7 100644 --- a/kernel/exceptions/timer.c +++ b/kernel/exceptions/timer.c @@ -2,14 +2,24 @@ static uint64_t _msecs; +static int64_t g_wall_offset_us = 0; +static int g_sync = 0; + +static int32_t g_tz_offset_min = 0; + +static inline uint64_t rd_cntfrq_el0(void) { + uint64_t v; + asm volatile ("mrs %0, cntfrq_el0" : "=r"(v)); + return v; +} + void timer_reset() { - uint64_t freq; - asm volatile ("mrs %0, cntfrq_el0" : "=r"(freq)); - uint64_t interval = (freq * _msecs)/1000; + uint64_t freq = rd_cntfrq_el0(); + uint64_t interval = (freq * _msecs) / 1000; asm volatile ("msr cntp_tval_el0, %0" :: "r"(interval)); } -void timer_enable() { +static inline void timer_enable() { uint64_t val = 1; asm volatile ("msr cntp_ctl_el0, %0" :: "r"(val)); asm volatile ("msr cntkctl_el1, %0" :: "r"(val)); @@ -27,9 +37,8 @@ void timer_init(uint64_t msecs) { } void virtual_timer_reset(uint64_t smsecs) { - uint64_t freq; - asm volatile ("mrs %0, cntfrq_el0" : "=r"(freq)); - uint64_t interval = (freq * smsecs)/1000; + uint64_t freq = rd_cntfrq_el0(); + uint64_t interval = (freq * smsecs) / 1000; asm volatile ("msr cntv_tval_el0, %0" :: "r"(interval)); } @@ -40,9 +49,8 @@ void virtual_timer_enable() { uint64_t virtual_timer_remaining_msec() { uint64_t ticks; - uint64_t freq; + uint64_t freq = rd_cntfrq_el0(); asm volatile ("mrs %0, cntv_tval_el0" : "=r"(ticks)); - asm volatile ("mrs %0, cntfrq_el0" : "=r"(freq)); return (ticks * 1000) / freq; } @@ -53,8 +61,171 @@ uint64_t timer_now() { } uint64_t timer_now_msec() { - uint64_t ticks, freq; - asm volatile ("mrs %0, cntvct_el0" : "=r"(ticks)); - asm volatile ("mrs %0, cntfrq_el0" : "=r"(freq)); + uint64_t ticks = timer_now(); + uint64_t freq = rd_cntfrq_el0(); return (ticks * 1000) / freq; -} \ No newline at end of file +} + +uint64_t timer_now_usec(void) { + uint64_t ticks = timer_now(); + uint64_t freq = rd_cntfrq_el0(); + + uint64_t q = ticks / freq; + uint64_t r = ticks % freq; + + uint64_t us = q * 1000000ULL; + us += (r * 1000000ULL) / freq; + return us; +} + +void timer_apply_sntp_sample_us(uint64_t server_unix_us) { + int64_t mono_us = (int64_t)timer_now_usec(); + int64_t off = (int64_t)server_unix_us - mono_us; + + g_wall_offset_us = off; + g_sync = 1; +} + +int timer_is_synchronised(void) { + return g_sync; +} + +uint64_t timer_unix_time_ms(void) { + if (!g_sync) return 0; + uint64_t now_us = timer_now_usec(); + int64_t off = g_wall_offset_us; + + int64_t unix_us = (int64_t)now_us + off; + if (unix_us < 0) return 0; + return (uint64_t)unix_us / 1000ULL; +} + +void timer_set_timezone_minutes(int32_t minutes){ + g_tz_offset_min = minutes; +} + +int32_t timer_get_timezone_minutes(void){ + return g_tz_offset_min; +} + +uint64_t timer_local_time_ms(void){ + uint64_t utc_ms = timer_unix_time_ms(); + if (utc_ms == 0) return 0; + int64_t adj = (int64_t)utc_ms + (int64_t)g_tz_offset_min * 60LL * 1000LL; + if (adj < 0) return 0; + return (uint64_t)adj; +} + +int timer_set_manual_unix_time_ms(uint64_t unix_ms){ + if (g_sync) return -1; + uint64_t now_us = timer_now_usec(); + int64_t off = (int64_t)(unix_ms * 1000ULL) - (int64_t)now_us; + g_wall_offset_us = off; + return 0; +} + +static int64_t days_from_civil(int64_t y, unsigned m, unsigned d){ + y -= (m <= 2); + const int64_t era = (y >= 0 ? y : y - 399) / 400; + const unsigned yoe = (unsigned)(y - era * 400); + const unsigned doy = (153*(m + (m > 2 ? -3 : 9)) + 2)/5 + d - 1; + const unsigned doe = yoe * 365 + yoe/4 - yoe/100 + yoe/400 + doy; + return era * 146097 + (int64_t)doe - 719468; +} + +static void civil_from_days(int64_t z, int64_t* y, unsigned* m, unsigned* d){ + z += 719468; + const int64_t era = (z >= 0 ? z : z - 146096) / 146097; + const unsigned doe = (unsigned)(z - era * 146097); + const unsigned yoe = (doe - doe/1460 + doe/36524 - doe/146096) / 365; + int64_t y_full = (int64_t)yoe + era * 400; + const unsigned doy = doe - (365*yoe + yoe/4 - yoe/100 + yoe/400); + const unsigned mp = (5*doy + 2)/153; + const unsigned dd = doy - (153*mp + 2)/5 + 1; + const unsigned mm = mp + (mp < 10 ? 3 : -9); + y_full += (mm <= 2); + *y = y_full; *m = mm; *d = dd; +} + +static void fmt2u(uint64_t v, char out[3]){ //maybe move this in a helper file + out[0] = (char)('0' + (v/10u)%10u); + out[1] = (char)('0' + (v%10u)); + out[2] = '\0'; +} + +void timer_unix_ms_to_datetime(uint64_t unix_ms, int use_local, DateTime* out){ + if (!out) return; + int64_t ms = (int64_t)unix_ms; + if (use_local) ms += (int64_t)g_tz_offset_min * 60LL * 1000LL; + if (ms < 0) ms = 0; + + uint64_t sec = (uint64_t)ms / 1000ULL; + uint64_t sod = sec % 86400ULL; + uint64_t days= sec / 86400ULL; + + int64_t Y; + unsigned M,D; + civil_from_days((int64_t)days, &Y, &M, &D); + + out->year = (uint16_t)Y; + out->month = (uint8_t)M; + out->day = (uint8_t)D; + out->hour = (uint8_t)(sod / 3600ULL); + out->minute = (uint8_t)((sod % 3600ULL) / 60ULL); + out->second = (uint8_t)(sod % 60ULL); +} + +uint64_t timer_datetime_to_unix_ms(const DateTime* dt, int is_local){ + if (!dt) return 0; + uint16_t Y = dt->year; + if (Y < 1970) Y = 1970; + unsigned M = (dt->month >= 1 && dt->month <= 12) ? dt->month : 1; + unsigned D = (dt->day >= 1 && dt->day <= 31) ? dt->day : 1; + unsigned h = (dt->hour <= 23) ? dt->hour : 0; + unsigned m = (dt->minute <= 59) ? dt->minute : 0; + unsigned s = (dt->second <= 59) ? dt->second : 0; + + int64_t days = days_from_civil((int64_t)Y, M, D); + uint64_t sec = (uint64_t)(days >= 0 ? days : 0) * 86400ULL + (uint64_t)h*3600ULL + (uint64_t)m*60ULL + (uint64_t)s; + + int64_t ms = (int64_t)sec * 1000LL; + if (is_local) ms -= (int64_t)g_tz_offset_min * 60LL * 1000LL; + if (ms < 0) ms = 0; + return (uint64_t)ms; +} + +int timer_now_datetime(DateTime* out, int use_local){ + if (!out) return 0; + uint64_t ms = use_local ? timer_local_time_ms() : timer_unix_time_ms(); + if (ms == 0) return 0; + timer_unix_ms_to_datetime(ms, 0, out); + return 1; +} + +void timer_datetime_to_string(const DateTime* dt, char* buf, uint32_t buflen){ + if (!dt || !buf || buflen < 20) return; + uint16_t Y = dt->year; + buf[0] = (char)('0' + (Y/1000)%10); + buf[1] = (char)('0' + (Y/100)%10); + buf[2] = (char)('0' + (Y/10)%10); + buf[3] = (char)('0' + (Y%10)); + buf[4] = '-'; + + char mm[3], dd[3], HH[3], MM[3], SS[3]; + fmt2u(dt->month, mm); + fmt2u(dt->day, dd); + fmt2u(dt->hour, HH); + fmt2u(dt->minute, MM); + fmt2u(dt->second, SS); + + buf[5] = mm[0]; buf[6] = mm[1]; + buf[7] = '-'; + buf[8] = dd[0]; buf[9] = dd[1]; + buf[10] = ' '; + buf[11] = HH[0]; buf[12] = HH[1]; + buf[13] = ':'; + buf[14] = MM[0]; buf[15] = MM[1]; + buf[16] = ':'; + buf[17] = SS[0]; buf[18] = SS[1]; + buf[19] = '\0'; +} diff --git a/kernel/exceptions/timer.h b/kernel/exceptions/timer.h index eb3a1414..f73cc1b7 100644 --- a/kernel/exceptions/timer.h +++ b/kernel/exceptions/timer.h @@ -2,6 +2,10 @@ #include "types.h" +#ifdef __cplusplus +extern "C" { +#endif + void timer_init(uint64_t msecs); void timer_reset(); @@ -11,5 +15,34 @@ uint64_t virtual_timer_remaining_msec(); uint64_t timer_now(); uint64_t timer_now_msec(); +uint64_t timer_now_usec(void); + +void timer_apply_sntp_sample_us(uint64_t server_unix_us); +int timer_is_synchronised(void); +uint64_t timer_unix_time_ms(void); + +void timer_set_timezone_minutes(int32_t minutes); +int32_t timer_get_timezone_minutes(void); + +uint64_t timer_local_time_ms(void); +int timer_set_manual_unix_time_ms(uint64_t unix_ms); + +typedef struct { + uint16_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint8_t second; +} DateTime; + +void timer_unix_ms_to_datetime(uint64_t unix_ms, int use_local, DateTime* out); +uint64_t timer_datetime_to_unix_ms(const DateTime* dt, int is_local); +int timer_now_datetime(DateTime* out, int use_local); +void timer_datetime_to_string(const DateTime* dt, char* buf, uint32_t buflen); + +void permanent_disable_timer(); -void permanent_disable_timer(); \ No newline at end of file +#ifdef __cplusplus +} +#endif diff --git a/kernel/networking/network.cpp b/kernel/networking/network.cpp index ed8dcf95..0a56442f 100644 --- a/kernel/networking/network.cpp +++ b/kernel/networking/network.cpp @@ -35,7 +35,7 @@ int net_rx_frame(sizedptr *out_frame) { } const net_l2l3_endpoint* network_get_local_endpoint() { - static net_l2l3_endpoint dummy = {0}; + static net_l2l3_endpoint dummy = {}; return dispatch ? &dispatch->get_local_ep() : &dummy; } diff --git a/kernel/networking/network_dispatch.cpp b/kernel/networking/network_dispatch.cpp index c49b0c04..2a6a6de3 100644 --- a/kernel/networking/network_dispatch.cpp +++ b/kernel/networking/network_dispatch.cpp @@ -81,9 +81,10 @@ bool NetworkDispatch::enqueue_frame(const sizedptr &frame) int NetworkDispatch::net_task() { + network_net_set_pid(get_current_proc_pid()); for (;;) { bool did_work = false; - sizedptr pkt; + sizedptr pkt{0,0}; if (!rx_queue.is_empty() && rx_queue.dequeue(pkt)) { did_work = true; @@ -126,21 +127,6 @@ bool NetworkDispatch::dequeue_packet_for(uint16_t pid, sizedptr *out) return true; } -static sizedptr make_user_copy(const sizedptr &src) -{ - sizedptr out{0, 0}; - uintptr_t mem = malloc(src.size); - if (!mem) return out; - - memcpy(reinterpret_cast(mem), - reinterpret_cast(src.ptr), - src.size); - - out.ptr = mem; - out.size = src.size; - return out; -} - sizedptr NetworkDispatch::make_copy(const sizedptr &in) { sizedptr out{0, 0}; diff --git a/kernel/networking/port_manager.c b/kernel/networking/port_manager.c index 51ededb7..4fbd746d 100644 --- a/kernel/networking/port_manager.c +++ b/kernel/networking/port_manager.c @@ -2,18 +2,20 @@ #include "types.h" #include "networking/port_manager.h" #include "net/internet_layer/ipv4.h" +#include "math/rng.h" static port_entry_t g_port_table[PROTO_COUNT][MAX_PORTS];//tab proto/port -static inline bool port_valid(uint16_t p) { +static inline bool port_valid(uint32_t p) { return p > 0 && p < MAX_PORTS; } + static inline bool proto_valid(protocol_t proto) { - return (uint32_t)proto< PROTO_COUNT; + return (uint32_t)proto < PROTO_COUNT; } -void port_manager_init() { - for (int pr = 0; pr < PROTO_COUNT; ++pr) { +void port_manager_init(void) { + for (uint32_t pr = 0; pr < PROTO_COUNT; ++pr) { for (uint32_t p = 0; p < MAX_PORTS; ++p) { g_port_table[pr][p].used = false; g_port_table[pr][p].pid = PORT_FREE_OWNER; @@ -27,7 +29,18 @@ int port_alloc_ephemeral(protocol_t proto, port_recv_handler_t handler) { if (!proto_valid(proto)) return -1; - for (uint16_t p = PORT_MIN_EPHEMERAL; p <= PORT_MAX_EPHEMERAL; ++p) { + + rng_t rng; + rng_init_random(&rng); + uint32_t seed = rng_next32(&rng); + + uint32_t minp = (uint32_t)PORT_MIN_EPHEMERAL; + uint32_t maxp = (uint32_t)PORT_MAX_EPHEMERAL; + uint32_t range = maxp - minp + 1u; + uint32_t first = minp + (seed % range); + + for (uint32_t i = 0; i < range; ++i) { + uint32_t p = minp + ((first - minp + i) % range); port_entry_t *e = &g_port_table[proto][p]; if (!e->used) { e->used = true; @@ -67,8 +80,8 @@ bool port_unbind(protocol_t proto, } void port_unbind_all(uint16_t pid) { - for (int pr = 0; pr < PROTO_COUNT; ++pr) { - for (uint16_t p = 1; p < MAX_PORTS; ++p) { + for (uint32_t pr = 0; pr < PROTO_COUNT; ++pr) { + for (uint32_t p = 1; p < MAX_PORTS; ++p) { port_entry_t *e = &g_port_table[pr][p]; if (e->used && e->pid == pid) { e->used = false; diff --git a/kernel/networking/processes/net_proc.c b/kernel/networking/processes/net_proc.c index 61a92f29..a3db7903 100644 --- a/kernel/networking/processes/net_proc.c +++ b/kernel/networking/processes/net_proc.c @@ -4,22 +4,27 @@ #include "console/kio.h" #include "std/memfunctions.h" #include "std/string.h" + +#include "net/network_types.h" +#include "networking/network.h" + +#include "net/link_layer/arp.h" + #include "net/internet_layer/ipv4.h" + #include "net/transport_layer/csocket_udp.h" + #include "net/application_layer/csocket_http_client.h" #include "net/application_layer/csocket_http_server.h" #include "net/application_layer/dhcp_daemon.h" -#include "net/network_types.h" -#include "net/link_layer/arp.h" -#include "networking/network.h" -#include "net/net.h" +#include "net/application_layer/dns_daemon.h" +#include "net/application_layer/dns.h" +#include "net/application_layer/sntp_daemon.h" +#include "exceptions/timer.h" extern uintptr_t malloc(uint64_t size); -extern void free(void *ptr, uint64_t size); -extern void sleep(uint64_t ms); - -#define KP(fmt, ...) \ - do { kprintf(fmt, ##__VA_ARGS__); } while (0) +extern void free(void *ptr, uint64_t size); +extern void sleep(uint64_t ms); static uint32_t pick_probe_ip() { const net_cfg_t *cfg = ipv4_get_cfg(); @@ -33,11 +38,7 @@ static uint32_t pick_probe_ip() { return ipv4_first_host(cfg->ip, cfg->mask); } -static int udp_probe_server(uint32_t probe_ip, - uint16_t probe_port, - net_l2l3_endpoint *out_l2, - net_l4_endpoint *out_l4) -{ +static int udp_probe_server(uint32_t probe_ip, uint16_t probe_port, net_l2l3_endpoint *out_l2, net_l4_endpoint *out_l4) { const net_l2l3_endpoint *local = network_get_local_endpoint(); if (!local) return 0; @@ -54,18 +55,14 @@ static int udp_probe_server(uint32_t probe_ip, char recv_buf[64]; uint32_t waited = 0; - const uint32_t TIMEOUT_MS = 1000; + const uint32_t TIMEOUT_MS = 2000; const uint32_t INTERVAL_MS = 50; - int64_t recvd = 0; + int64_t recvd = 0; uint32_t resp_ip = 0; uint16_t resp_port = 0; while (waited < TIMEOUT_MS) { - recvd = socket_recvfrom_udp(sock, - recv_buf, - sizeof(recv_buf), - &resp_ip, - &resp_port); + recvd = socket_recvfrom_udp(sock, recv_buf, sizeof(recv_buf), &resp_ip, &resp_port); if (recvd > 0) break; sleep(INTERVAL_MS); @@ -89,9 +86,7 @@ static int udp_probe_server(uint32_t probe_ip, return resp_ip; } - -void free_request(HTTPRequestMsg *req) -{ +static void free_request(HTTPRequestMsg *req) { if (req->path.mem_length) free(req->path.data, req->path.mem_length); @@ -110,8 +105,7 @@ void free_request(HTTPRequestMsg *req) free((void*)req->body.ptr, req->body.size); } -void http_server_hello_entry() -{ +static void run_http_server() { uint16_t pid = get_current_proc_pid(); http_server_handle_t srv = http_server_create(pid); if (!srv) { @@ -132,7 +126,7 @@ void http_server_hello_entry() return; } - KP("[HTTP] listening at %i.%i.%i.%i on port 80", FORMAT_IP(ipv4_get_cfg()->ip)); + kprintf("[HTTP] listening on port 80"); static const char HTML_ROOT[] = "

Hello, world!

\n" @@ -141,11 +135,11 @@ void http_server_hello_entry() static const char HTML_404[] = "

404 Regrettably, no such page exists in this realm

\n" "

Im rather inclined to deduce that your page simply does not exist. Given the state of affairs, I dare say it's not altogether surprising, innit?

"; - //comically british 404 error page - const string STR_OK = string_from_const("OK"); - const string STR_HTML = string_from_const("text/html"); - const string STR_CLOSE = string_from_const("close"); - const string STR_NOTFOUND = string_from_const("Not Found"); + + const string STR_OK = string_from_const("OK"); + const string STR_HTML = string_from_const("text/html"); + const string STR_CLOSE = string_from_const("close"); + const string STR_NOTFOUND= string_from_const("Not Found"); while (1) { http_connection_handle_t conn = http_server_accept(srv); @@ -156,11 +150,9 @@ void http_server_hello_entry() if (req.path.length) { char tmp[128] = {0}; - uint32_t n = req.path.length < sizeof(tmp) - 1 - ? req.path.length - : sizeof(tmp) - 1; + uint32_t n = req.path.length < sizeof(tmp) - 1 ? req.path.length : sizeof(tmp) - 1; memcpy(tmp, req.path.data, n); - KP("[HTTP] GET %s", tmp); + kprintf("[HTTP] GET %s", tmp); } HTTPResponseMsg res = {0}; @@ -171,16 +163,15 @@ void http_server_hello_entry() res.headers_common.length = sizeof(HTML_ROOT) - 1; res.headers_common.type = STR_HTML; res.headers_common.connection = STR_CLOSE; - res.body.ptr = (uintptr_t)HTML_ROOT; + res.body.ptr = (uintptr_t)HTML_ROOT; res.body.size = sizeof(HTML_ROOT) - 1; - } - else { + } else { res.status_code = HTTP_NOT_FOUND; res.reason = STR_NOTFOUND; res.headers_common.length = sizeof(HTML_404) - 1; res.headers_common.type = STR_HTML; res.headers_common.connection = STR_CLOSE; - res.body.ptr = (uintptr_t)HTML_404; + res.body.ptr = (uintptr_t)HTML_404; res.body.size = sizeof(HTML_404) - 1; } @@ -190,16 +181,11 @@ void http_server_hello_entry() } } +static void test_http(uint32_t ip) { + char ip_str[16]; + ipv4_to_string(ip, ip_str); - -static void test_http(uint32_t ip) -{ - KP("[HTTP] GET %i.%i.%i.%i:80\n", - (ip >> 24) & 0xFF, - (ip >> 16) & 0xFF, - (ip >> 8) & 0xFF, - (ip ) & 0xFF); - + kprintf("[HTTP] GET %s:80\n", ip_str); uint16_t pid = get_current_proc_pid(); http_client_handle_t cli = http_client_create(pid); if (!cli) @@ -224,18 +210,18 @@ static void test_http(uint32_t ip) if (body_str) { memcpy(body_str, (void*)resp.body.ptr, resp.body.size); body_str[resp.body.size] = '\0'; - KP("[HTTP] %i %i bytes of body%s\n", - (uint64_t)resp.status_code, - (uint64_t)resp.body.size, - body_str); + kprintf("[HTTP] %i %i bytes of body", resp.status_code, resp.body.size); + kprintf("%s\n", body_str); free(body_str, resp.body.size + 1); } } http_client_close(cli); http_client_destroy(cli); + if (resp.reason.data && resp.reason.mem_length) free(resp.reason.data, resp.reason.mem_length); + for (uint32_t i = 0; i < resp.extra_header_count; i++) { HTTPHeader *h = &resp.extra_headers[i]; if (h->key.mem_length) @@ -243,47 +229,89 @@ static void test_http(uint32_t ip) if (h->value.mem_length) free(h->value.data, h->value.mem_length); } + if (resp.extra_headers) - free(resp.extra_headers, - resp.extra_header_count * sizeof(HTTPHeader)); + free(resp.extra_headers, resp.extra_header_count * sizeof(HTTPHeader)); } -void test_network() -{ +static void print_info() { + if (!sntp_is_running()) { + create_kernel_process("sntpd", sntp_daemon_entry, 0, 0); + while (!timer_is_synchronised()); + + const net_cfg_t *cfg = ipv4_get_cfg(); + if (cfg && cfg->mode != NET_MODE_DISABLED && cfg->ip != 0) { + char ip_str[16], mask_str[16], gw_str[16]; + ipv4_to_string(cfg->ip, ip_str); + ipv4_to_string(cfg->mask, mask_str); + ipv4_to_string(cfg->gw, gw_str); + + kprintf("[NET] IP: %s MASK: %s GW: %s", ip_str, mask_str, gw_str); + } + kprintf("[NET] PIDs -- NET: %i ARP: %i DHCP: %i DNS: %i SNTP: %i", + network_net_get_pid(), + arp_get_pid(), + dhcp_get_pid(), + dns_get_pid(), + sntp_get_pid()); + + timer_set_timezone_minutes(120); + kprintf("[TIME]timezone offset %i minutes", (int32_t)timer_get_timezone_minutes()); + + DateTime now_dt_utc, now_dt_loc; + if (timer_now_datetime(&now_dt_utc, 0)) { + char s[20]; + timer_datetime_to_string(&now_dt_utc, s, sizeof s); + kprintf("[TIME] UTC: %s", s); + } + if (timer_now_datetime(&now_dt_loc, 1)) { + char s[20]; + timer_datetime_to_string(&now_dt_loc, s, sizeof s); + kprintf("[TIME] LOCAL: %s (TZ %i min)", s, (int32_t)timer_get_timezone_minutes()); + } + } +} + +static void test_net() { const net_cfg_t *cfg = ipv4_get_cfg(); net_l2l3_endpoint l2 = {0}; net_l4_endpoint srv = {0}; if (cfg && cfg->mode != NET_MODE_DISABLED && cfg->ip != 0) { + print_info(); + uint32_t bcast = ipv4_broadcast(cfg->ip, cfg->mask); - KP("[NET] probing broadcast %i.%i.%i.%i", - (bcast>>24)&0xFF,(bcast>>16)&0xFF, - (bcast>>8)&0xFF,(bcast&0xFF)); + char bcast_str[16]; + ipv4_to_string(bcast, bcast_str); + + kprintf("[NET] probing broadcast %s", bcast_str); - if (udp_probe_server(bcast, 8080, &l2, &srv)) { + if (udp_probe_server(bcast, 8080, &l2, &srv)) test_http(srv.ip); - } - http_server_hello_entry(); + + sleep(2000); + run_http_server(); return; } uint32_t fallback = pick_probe_ip(); if (!fallback) fallback = (192<<24)|(168<<16)|(1<<8)|255; - if (udp_probe_server(fallback, 8080, &l2, &srv)) { + + if (udp_probe_server(fallback, 8080, &l2, &srv)) test_http(srv.ip); - } else { - KP("[NET] could not find update server\n"); - } + else + kprintf("[NET] could not find update server\n"); } -int net_test_entry(){ - test_network(); +static int net_test_entry(int argc, char* argv[]) { + (void)argc; (void)argv; + test_net(); return 0; } -int ip_waiter_entry() -{ +static int ip_waiter_entry(int argc, char* argv[]) { + (void)argc; (void)argv; for (;;) { const net_cfg_t *cfg = ipv4_get_cfg(); if (cfg && cfg->mode != NET_MODE_DISABLED && cfg->ip != 0) { @@ -295,23 +323,20 @@ int ip_waiter_entry() return 0; } -process_t* launch_net_process() -{ - const net_cfg_t *cfg = ipv4_get_cfg(); - process_t* net = create_kernel_process("net_net", network_net_task_entry, 0, 0); - network_net_set_pid(net ? net->id : 0xFFFF); +process_t* launch_net_process() { + const net_cfg_t *cfg = ipv4_get_cfg(); - process_t* arp = create_kernel_process("arp_daemon", arp_daemon_entry, 0, 0); - arp_set_pid(arp ? arp->id : 0xFFFF); + create_kernel_process("net_net", network_net_task_entry, 0, 0); + create_kernel_process("arp_daemon", arp_daemon_entry, 0, 0); + create_kernel_process("dhcp_daemon", dhcp_daemon_entry, 0, 0); + create_kernel_process("dns_daemon", dns_deamon_entry, 0, 0); if (cfg && cfg->mode != NET_MODE_DISABLED && cfg->ip != 0) { create_kernel_process("net_test", net_test_entry, 0, 0); return NULL; } - process_t* dhcp = create_kernel_process("dhcp_daemon", dhcp_daemon_entry, 0, 0); - dhcp_set_pid(dhcp ? dhcp->id : 0xFFFF); create_kernel_process("ip_waiter", ip_waiter_entry, 0, 0); - return dhcp; -} + return NULL; +} \ No newline at end of file diff --git a/shared/net/application_layer/csocket_http_client.cpp b/shared/net/application_layer/csocket_http_client.cpp index baac959b..a33c03b2 100644 --- a/shared/net/application_layer/csocket_http_client.cpp +++ b/shared/net/application_layer/csocket_http_client.cpp @@ -1,4 +1,3 @@ -#pragma once #include "csocket_http_client.h" #include "socket_http_client.hpp" #include "net/transport_layer/socket_tcp.hpp" @@ -12,17 +11,15 @@ extern "C" { extern "C" { http_client_handle_t http_client_create(uint16_t pid) { - uintptr_t mem = malloc(sizeof(HTTPClient)); - if (!mem) return NULL; - HTTPClient *cli = reinterpret_cast( (void*)mem ); - return reinterpret_cast(new HTTPClient(pid)); + HTTPClient* cli = new HTTPClient(pid); + if (!cli) return nullptr; + return reinterpret_cast(cli); } void http_client_destroy(http_client_handle_t h) { if (!h) return; - HTTPClient *cli = reinterpret_cast(h); - cli->~HTTPClient(); - free(cli, sizeof(HTTPClient)); + HTTPClient* cli = reinterpret_cast(h); + delete cli; } int32_t http_client_connect(http_client_handle_t h, diff --git a/shared/net/application_layer/csocket_http_server.cpp b/shared/net/application_layer/csocket_http_server.cpp index 7398cf43..607ca4b0 100644 --- a/shared/net/application_layer/csocket_http_server.cpp +++ b/shared/net/application_layer/csocket_http_server.cpp @@ -10,17 +10,15 @@ extern "C" { extern "C" { http_server_handle_t http_server_create(uint16_t pid) { - void* raw = (void*)malloc(sizeof(HTTPServer)); - if (!raw) return nullptr; - HTTPServer* srv = reinterpret_cast(raw); - return reinterpret_cast(new HTTPServer(pid)); + HTTPServer* srv = new HTTPServer(pid); + if (!srv) return nullptr; + return reinterpret_cast(srv); } void http_server_destroy(http_server_handle_t h) { if (!h) return; HTTPServer* srv = reinterpret_cast(h); - srv->~HTTPServer(); - free(srv, sizeof(HTTPServer)); + delete srv; } int32_t http_server_bind(http_server_handle_t h, uint16_t port) { diff --git a/shared/net/application_layer/dhcp.c b/shared/net/application_layer/dhcp.c index 431292df..6768ff5e 100644 --- a/shared/net/application_layer/dhcp.c +++ b/shared/net/application_layer/dhcp.c @@ -5,8 +5,6 @@ #include "types.h" #include "net/transport_layer/csocket_udp.h" -static socket_handle_t g_dhcp_socket = NULL; - extern uintptr_t malloc(uint64_t size); extern void free(void *ptr, uint64_t size); extern void sleep(uint64_t ms); @@ -71,6 +69,9 @@ uint16_t dhcp_parse_option(const dhcp_packet *p, uint16_t wanted) { } uint8_t dhcp_option_len(const dhcp_packet *p, uint16_t idx) { - if (idx == 0 || idx + 1 >= sizeof(p->options)) return 0; - return p->options[idx+1]; + size_t opt_size = sizeof(p->options); + + if (idx == 0 || (size_t)idx + 1 >= opt_size) return 0; + return p->options[idx + 1]; } + diff --git a/shared/net/application_layer/dhcp_daemon.c b/shared/net/application_layer/dhcp_daemon.c index ff093f52..28c95612 100644 --- a/shared/net/application_layer/dhcp_daemon.c +++ b/shared/net/application_layer/dhcp_daemon.c @@ -14,8 +14,6 @@ #include "net/transport_layer/csocket_udp.h" -#include "../net.h" - extern void sleep(uint64_t ms); extern uintptr_t malloc(uint64_t size); extern void free(void *ptr, uint64_t size); @@ -42,8 +40,6 @@ typedef enum { DHCP_S_REBINDING } dhcp_state_t; -#define KP(fmt, ...) \ - do { kprintf(fmt, ##__VA_ARGS__); } while(0) static dhcp_state_t g_state = DHCP_S_INIT; static net_l2l3_endpoint g_local_ep = {0}; static volatile bool g_force_renew = false; @@ -53,17 +49,13 @@ static uint16_t g_pid_dhcpd = 0xFFFF; static socket_handle_t g_sock = 0; -uint16_t get_dhcp_pid() { return g_pid_dhcpd; } +uint16_t dhcp_get_pid() { return g_pid_dhcpd; } bool dhcp_is_running() { return g_pid_dhcpd != 0xFFFF; } void dhcp_set_pid(uint16_t p){ g_pid_dhcpd = p; } void dhcp_force_renew() { g_force_renew = true; } -static inline uint32_t rd_be32(const uint8_t* p){ - uint32_t v; memcpy(&v, p, 4); return __builtin_bswap32(v); -} - static void log_state_change(dhcp_state_t old, dhcp_state_t now){ - KP("[DHCP] state %i -> %i", old, now); + kprintf("[DHCP] state %i -> %i", old, now); } static void dhcp_apply_offer(dhcp_packet *p, dhcp_request *req, uint32_t xid); @@ -79,7 +71,7 @@ static void dhcp_tx_packet(const dhcp_request *req, } static void dhcp_send_discover(uint32_t xid){ - KP("[DHCP] discover xid=%i", xid); + kprintf("[DHCP] discover xid=%i", xid); dhcp_request req = {0}; memcpy(req.mac, g_local_ep.mac, 6); dhcp_tx_packet(&req, DHCPDISCOVER, xid, 0xFFFFFFFFu); @@ -90,7 +82,7 @@ static void dhcp_send_request(const dhcp_request *req, bool broadcast) { uint32_t dst = broadcast ? 0xFFFFFFFFu : __builtin_bswap32(req->server_ip); - //KP("[DHCP] request xid=%i dst=%x\n", (uint64_t)xid, (uint64_t)dst); + //kprintf("[DHCP] request xid=%i dst=%x\n", (uint64_t)xid, (uint64_t)dst); dhcp_tx_packet(req, DHCPREQUEST, xid, dst); } @@ -101,7 +93,7 @@ static void dhcp_send_renew(uint32_t xid) { req.offered_ip = __builtin_bswap32(cfg->ip); req.server_ip = cfg->rt ? cfg->rt->server_ip : 0; uint32_t dst = req.server_ip ? __builtin_bswap32(req.server_ip) : 0xFFFFFFFFu; - KP("[DHCP] renew xid=%i dst=%x", xid, dst); + kprintf("[DHCP] renew xid=%i dst=%x", xid, dst); dhcp_tx_packet(&req, DHCPREQUEST, xid, dst); } @@ -111,7 +103,7 @@ static void dhcp_send_rebind(uint32_t xid) { memcpy(req.mac, g_local_ep.mac, 6); req.offered_ip = __builtin_bswap32(cfg->ip); req.server_ip = 0; - KP("[DHCP] rebind xid=%i", xid); + kprintf("[DHCP] rebind xid=%i", xid); dhcp_tx_packet(&req, DHCPREQUEST, xid, 0xFFFFFFFFu); } @@ -140,7 +132,7 @@ static bool dhcp_wait_for_type(uint8_t wanted, waited += 50; } } - KP("[DHCP] wait timeout type=%i", wanted); + kprintf("[DHCP] wait timeout type=%i", wanted); return false; } @@ -247,12 +239,13 @@ static void dhcp_fsm_once() if (old != g_state) log_state_change(old, g_state); } -int dhcp_daemon_entry(){ - KP("[DHCP] daemon start pid=%i", get_current_proc_pid()); +int dhcp_daemon_entry(int argc, char* argv[]){ + (void)argc; (void)argv; g_pid_dhcpd = (uint16_t)get_current_proc_pid(); + dhcp_set_pid(g_pid_dhcpd); g_sock = udp_socket_create(SOCK_ROLE_SERVER, g_pid_dhcpd); if(socket_bind_udp(g_sock, 68) != 0){ - KP("[DHCP] bind failed\n"); + kprint("[DHCP] bind failed\n"); return 1; } @@ -336,16 +329,12 @@ static void dhcp_apply_offer(dhcp_packet *p, dhcp_request *req, uint32_t xid) { uint32_t t1_net; memcpy(&t1_net, &p->options[idx+2], 4); cfg_local.rt->t1 = __builtin_bswap32(t1_net); - } else { - cfg_local.rt->t1 = cfg_local.rt->lease / 2; } idx = dhcp_parse_option(p, 59); if (idx != UINT16_MAX && p->options[idx+1] >= 4) { uint32_t t2_net; memcpy(&t2_net, &p->options[idx+2], 4); cfg_local.rt->t2 = __builtin_bswap32(t2_net); - } else { - cfg_local.rt->t2 = cfg_local.rt->t1 * 2; } idx = dhcp_parse_option(p, 54); @@ -355,14 +344,17 @@ static void dhcp_apply_offer(dhcp_packet *p, dhcp_request *req, uint32_t xid) { cfg_local.rt->server_ip = __builtin_bswap32(srv_net); req->server_ip = srv_net; } + + if (cfg_local.rt->dns[0] == 0 && cfg_local.gw != 0) { + cfg_local.rt->dns[0] = cfg_local.gw; + } + uint32_t bcast = ipv4_broadcast(cfg_local.ip, cfg_local.mask); static const uint8_t bmac[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; arp_table_put(bcast, bmac, 0, true); ipv4_set_cfg(&cfg_local); - kprintf("Local IP: %i.%i.%i.%i",FORMAT_IP(cfg_local.ip)); - g_t1_left_ms = cfg_local.rt->t1 * 1000; g_t2_left_ms = cfg_local.rt->t2 * 1000; } diff --git a/shared/net/application_layer/dhcp_daemon.h b/shared/net/application_layer/dhcp_daemon.h index 0b530d84..9b1f281a 100644 --- a/shared/net/application_layer/dhcp_daemon.h +++ b/shared/net/application_layer/dhcp_daemon.h @@ -5,8 +5,10 @@ extern "C" { #endif -int dhcp_daemon_entry(); -uint16_t get_dhcp_pid(); + +int dhcp_daemon_entry(int argc, char* argv[]); +uint16_t dhcp_get_pid(); + bool dhcp_is_running(); void dhcp_set_pid(uint16_t pid); diff --git a/shared/net/application_layer/dns.c b/shared/net/application_layer/dns.c new file mode 100644 index 00000000..4d2301c6 --- /dev/null +++ b/shared/net/application_layer/dns.c @@ -0,0 +1,119 @@ +#include "dns.h" +#include "std/memfunctions.h" +#include "math/rng.h" +#include "process/scheduler.h" +#include "net/internet_layer/ipv4.h" +#include "dns_daemon.h" +#include "types.h" + +extern void sleep(uint64_t ms); + +static uint32_t encode_dns_qname(uint8_t* dst, const char* name){ + uint32_t index = 0; + uint32_t label_len = 0; + uint32_t label_pos = 0; + dst[index++] = 0; + while (*name) { + if (*name == '.') { dst[label_pos] = (uint8_t)label_len; label_len = 0; label_pos = index; dst[index++] = 0; name++; continue; } + dst[index++] = (uint8_t)(*name); label_len++; name++; + } + dst[label_pos] = (uint8_t)label_len; + dst[index++] = 0; + return index; +} + +static uint32_t skip_dns_name(const uint8_t* message, uint32_t message_len, uint32_t offset){ + if (offset >= message_len) return message_len + 1; + uint32_t cursor = offset; + while (cursor < message_len) { + uint8_t len = message[cursor++]; + if (len == 0) break; + if ((len & 0xC0) == 0xC0) { if (cursor >= message_len) return message_len + 1; cursor++; break; } + cursor += len; + if (cursor > message_len) return message_len + 1; + } + return cursor; +} + +static dns_result_t parse_dns_a_record(uint8_t* buffer, uint32_t buffer_len, uint16_t message_id, uint32_t* out_ip){ + if (buffer_len < 12) return DNS_ERR_FORMAT; + if (rd_be16(buffer+0) != message_id) return DNS_ERR_FORMAT; + uint16_t flags = rd_be16(buffer+2); + uint16_t question_count = rd_be16(buffer+4); + uint16_t answer_count = rd_be16(buffer+6); + if ((flags & 0x000F) == 3) return DNS_ERR_NXDOMAIN; + uint32_t offset = 12; + for (uint16_t i = 0; i < question_count; ++i){ + offset = skip_dns_name(buffer, buffer_len, offset); + if (offset + 4 > buffer_len) return DNS_ERR_FORMAT; + offset += 4; + } + for (uint16_t i = 0; i < answer_count; ++i){ + offset = skip_dns_name(buffer, buffer_len, offset); + if (offset + 10 > buffer_len) return DNS_ERR_FORMAT; + uint16_t type = rd_be16(buffer+offset+0); + uint16_t klass = rd_be16(buffer+offset+2); + uint16_t rdlength = rd_be16(buffer+offset+8); + offset += 10; + if (offset + rdlength > buffer_len) return DNS_ERR_FORMAT; + if (type == 1 && klass == 1 && rdlength == 4){ + uint32_t ip_host = rd_be32(buffer+offset); + *out_ip = ip_host; + return DNS_OK; + } + offset += rdlength; + } + return DNS_ERR_NO_ANSWER; +} + +static dns_result_t perform_dns_query_once(socket_handle_t sock, uint32_t dns_ip_host, const char* name, uint32_t timeout_ms, uint32_t* out_ip){ + uint8_t request_buffer[512]; memset(request_buffer,0,sizeof(request_buffer)); + rng_t rng; rng_init_random(&rng); + uint16_t message_id = (uint16_t)(rng_next32(&rng) & 0xFFFF); + wr_be16(request_buffer+0, message_id); + wr_be16(request_buffer+2, 0x0100); + wr_be16(request_buffer+4, 1); + uint32_t offset = 12; + offset += encode_dns_qname(request_buffer+offset, name); + wr_be16(request_buffer+offset+0, 1); + wr_be16(request_buffer+offset+2, 1); + offset += 4; + int64_t sent = socket_sendto_udp(sock, dns_ip_host, 53, request_buffer, offset); + if (sent < 0) return DNS_ERR_SEND; + uint32_t waited_ms = 0; + while (waited_ms < timeout_ms){ + uint8_t response_buffer[512]; + uint32_t source_ip; uint16_t source_port; + int64_t received = socket_recvfrom_udp(sock, response_buffer, sizeof(response_buffer), &source_ip, &source_port); + if (received > 0 && source_port == 53 && source_ip == dns_ip_host){ + uint32_t ip_host; + dns_result_t pr = parse_dns_a_record(response_buffer, (uint32_t)received, message_id, &ip_host); + if (pr == DNS_OK){ *out_ip = ip_host; return DNS_OK; } + if (pr == DNS_ERR_NXDOMAIN) return pr; + } else { + sleep(50); + waited_ms += 50; + } + } + return DNS_ERR_TIMEOUT; +} + +dns_result_t dns_resolve_a(const char* hostname, uint32_t* out_ip, dns_server_sel_t which, uint32_t timeout_ms){ + const net_cfg_t* cfg = ipv4_get_cfg(); + if (!cfg || !cfg->rt) return DNS_ERR_NO_DNS; + uint32_t dns_primary = cfg->rt->dns[0]; + uint32_t dns_secondary = cfg->rt->dns[1]; + if (which == DNS_USE_PRIMARY && dns_primary == 0) return DNS_ERR_NO_DNS; + if (which == DNS_USE_SECONDARY && dns_secondary == 0) return DNS_ERR_NO_DNS; + if (which == DNS_USE_BOTH && dns_primary == 0 && dns_secondary == 0) return DNS_ERR_NO_DNS; + socket_handle_t sock = dns_socket_handle(); + if (sock == 0) return DNS_ERR_SOCKET; + dns_result_t res = DNS_ERR_NO_DNS; + if (which == DNS_USE_PRIMARY) res = perform_dns_query_once(sock, dns_primary, hostname, timeout_ms, out_ip); + else if (which == DNS_USE_SECONDARY) res = perform_dns_query_once(sock, dns_secondary, hostname, timeout_ms, out_ip); + else { + res = perform_dns_query_once(sock, dns_primary ? dns_primary : dns_secondary, hostname, timeout_ms, out_ip); + if (res != DNS_OK && dns_secondary && dns_secondary != dns_primary) res = perform_dns_query_once(sock, dns_secondary, hostname, timeout_ms, out_ip); + } + return res; +} diff --git a/shared/net/application_layer/dns.h b/shared/net/application_layer/dns.h new file mode 100644 index 00000000..8d429627 --- /dev/null +++ b/shared/net/application_layer/dns.h @@ -0,0 +1,26 @@ +#pragma once +#include "net/transport_layer/csocket_udp.h" +#ifdef __cplusplus +extern "C" { +#endif +typedef enum { + DNS_OK = 0, + DNS_ERR_NO_DNS = -1, + DNS_ERR_SOCKET = -2, + DNS_ERR_SEND = -3, + DNS_ERR_TIMEOUT = -4, + DNS_ERR_FORMAT = -5, + DNS_ERR_NXDOMAIN = -6, + DNS_ERR_NO_ANSWER = -7 +} dns_result_t; + +typedef enum { + DNS_USE_PRIMARY = 0, + DNS_USE_SECONDARY = 1, + DNS_USE_BOTH = 2 +} dns_server_sel_t; + +dns_result_t dns_resolve_a(const char* hostname, uint32_t* out_ip, dns_server_sel_t which, uint32_t timeout_ms); +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/shared/net/application_layer/dns_daemon.c b/shared/net/application_layer/dns_daemon.c new file mode 100644 index 00000000..2ab1ec55 --- /dev/null +++ b/shared/net/application_layer/dns_daemon.c @@ -0,0 +1,21 @@ +#include "dns_daemon.h" +#include "process/scheduler.h" +#include "std/memfunctions.h" + +extern void sleep(uint64_t ms); + +static uint16_t g_pid_dnsd = 0xFFFF; +static socket_handle_t g_sock = 0; + +uint16_t dns_get_pid(void){ return g_pid_dnsd; } +bool dns_is_running(void){ return g_pid_dnsd != 0xFFFF; } +void dns_set_pid(uint16_t p){ g_pid_dnsd = p; } +socket_handle_t dns_socket_handle(void){ return g_sock; } + +int dns_deamon_entry(int argc, char* argv[]){ + (void)argc; (void)argv; + dns_set_pid(get_current_proc_pid()); + g_sock = udp_socket_create(0, g_pid_dnsd); + for(;;){ sleep(250); } + return 1; +} diff --git a/shared/net/application_layer/dns_daemon.h b/shared/net/application_layer/dns_daemon.h new file mode 100644 index 00000000..add7fa4e --- /dev/null +++ b/shared/net/application_layer/dns_daemon.h @@ -0,0 +1,14 @@ +#pragma once +#include "net/transport_layer/csocket_udp.h" + +#ifdef __cplusplus +extern "C" { +#endif + bool dns_is_running(void); + void dns_set_pid(uint16_t p); + socket_handle_t dns_socket_handle(void); + uint16_t dns_get_pid(void); + int dns_deamon_entry(int argc, char* argv[]); +#ifdef __cplusplus +} +#endif diff --git a/shared/net/application_layer/sntp.c b/shared/net/application_layer/sntp.c new file mode 100644 index 00000000..54c9f5b7 --- /dev/null +++ b/shared/net/application_layer/sntp.c @@ -0,0 +1,147 @@ +#include "sntp.h" +#include "exceptions/timer.h" +#include "std/memfunctions.h" +#include "net/internet_layer/ipv4.h" +#include "net/transport_layer/csocket_udp.h" +#include "process/scheduler.h" +#include "console/kio.h" +#include "types.h" + +#define NTP_PORT 123 +#define NTP_UNIX_EPOCH_DELTA 2208988800UL + +extern void sleep(uint64_t ms); + +typedef struct __attribute__((packed)) { + uint8_t li_vn_mode; + uint8_t stratum; + uint8_t poll; + int8_t precision; + uint32_t rootDelay; + uint32_t rootDispersion; + uint32_t refId; + uint64_t refTs; + uint64_t origTs; + uint64_t recvTs; + uint64_t txTs; +} ntp_packet_t; + +static uint64_t unix_us_to_ntp64_be(uint64_t unix_us){ + uint64_t sec = unix_us / 1000000ULL; + uint64_t frac = ((unix_us % 1000000ULL) << 32) / 1000000ULL; + sec += NTP_UNIX_EPOCH_DELTA; + uint64_t ntp = (sec << 32) | (frac & 0xffffffffULL); + return be64(ntp); +} + +static uint64_t ntp64_be_to_unix_us(uint64_t ntp_be){ + uint64_t ntp = be64(ntp_be); + uint64_t sec = ntp >> 32; + uint64_t frac = ntp & 0xffffffffULL; + if (sec < NTP_UNIX_EPOCH_DELTA) return 0; + sec -= NTP_UNIX_EPOCH_DELTA; + return sec * 1000000ULL + ((frac * 1000000ULL) >> 32); +} + +static sntp_result_t sntp_send_query(socket_handle_t sock, uint32_t server_ip_host, uint64_t* t1_us_out){ + ntp_packet_t p; + memset(&p, 0, sizeof(p)); + p.li_vn_mode = (0u<<6) | (4u<<3) | 3u; + + uint64_t t1_us = timer_now_usec(); + p.txTs = unix_us_to_ntp64_be(t1_us); + + int64_t sent = socket_sendto_udp(sock, server_ip_host, NTP_PORT, &p, sizeof(p)); + if (sent < 0) return SNTP_ERR_SEND; + *t1_us_out = t1_us; + return SNTP_OK; +} + +sntp_result_t sntp_poll_once(uint32_t timeout_ms){ + const net_cfg_t* cfg = ipv4_get_cfg(); + if (!cfg || !cfg->rt) return SNTP_ERR_NO_CFG; + + uint32_t s0 = cfg->rt->ntp[0]; + uint32_t s1 = cfg->rt->ntp[1]; + if (s0 == 0 && s1 == 0) return SNTP_ERR_NO_SERVER; + + socket_handle_t sock = udp_socket_create(0, (uint32_t)get_current_proc_pid()); + if (sock == 0) return SNTP_ERR_SOCKET; + + uint64_t t1_0 = 0, t1_1 = 0; + + if (s0) { + if (sntp_send_query(sock, s0, &t1_0) != SNTP_OK) t1_0 = 0; + } + if (s1 && s1 != s0) { + if (sntp_send_query(sock, s1, &t1_1) != SNTP_OK) t1_1 = 0; + } + + uint32_t waited = 0; + uint64_t best_server_unix_us = 0; + uint64_t best_rtt_us = (uint64_t)-1; + + while (waited < timeout_ms){ + uint8_t buf[96]; + uint32_t rip; uint16_t rport; + int64_t n = socket_recvfrom_udp(sock, buf, sizeof(buf), &rip, &rport); + + if (n >= (int64_t)sizeof(ntp_packet_t) && rport == NTP_PORT && (rip == s0 || rip == s1)){ + ntp_packet_t* r = (ntp_packet_t*)buf; + uint64_t t4_us = timer_now_usec(); + + uint64_t T1 = ntp64_be_to_unix_us(r->origTs); + uint64_t T2 = ntp64_be_to_unix_us(r->recvTs); + uint64_t T3 = ntp64_be_to_unix_us(r->txTs); + + if (T1 != 0 && T3 != 0) { + uint64_t t1_us = (rip == s0) ? t1_0 : t1_1; + uint64_t d = (T1 > t1_us) ? (T1 - t1_us) : (t1_us - T1); + if (t1_us != 0 && d <= 1000000ULL) { + int64_t rtt = (int64_t)(t4_us - t1_us) - (int64_t)(T3 - T2); + if (rtt < 0) rtt = 0; + int64_t off = ((int64_t)(T2 - t1_us) + (int64_t)(T3 - t4_us)) / 2; + + uint64_t server_unix_us = (uint64_t)((int64_t)t4_us + off); + + const uint64_t year2000 = 946684800ULL * 1000000ULL; + bool ok_range = false; + + if (timer_is_synchronised()) { + uint64_t now_wall_ms = timer_unix_time_ms(); + uint64_t now_wall_us = now_wall_ms ? (now_wall_ms * 1000ULL) : 0; + const uint64_t plus1d = 86400ULL * 1000000ULL; + ok_range = (server_unix_us >= year2000) &&(now_wall_us == 0||server_unix_us <= now_wall_us + plus1d); + } else { + ok_range = (server_unix_us >= year2000); + } + + if (ok_range) { + + + if ((uint64_t)rtt < best_rtt_us){ + best_rtt_us = (uint64_t)rtt; + best_server_unix_us = server_unix_us; + } + } + } + } + } else { + sleep(50); + waited += 50; + } + + if (best_server_unix_us != 0 && waited >= (timeout_ms / 2)) break; + } + + socket_destroy_udp(sock); + + if (best_server_unix_us == 0) return SNTP_ERR_TIMEOUT; + + //uint64_t sec = best_server_unix_us / 1000000ULL; + //uint64_t frac = ((best_server_unix_us % 1000000ULL) << 32) / 1000000ULL; + //uint64_t ntp64 = ((sec + NTP_UNIX_EPOCH_DELTA) << 32) | frac; + + timer_apply_sntp_sample_us(best_server_unix_us); + return SNTP_OK; +} diff --git a/shared/net/application_layer/sntp.h b/shared/net/application_layer/sntp.h new file mode 100644 index 00000000..16701a38 --- /dev/null +++ b/shared/net/application_layer/sntp.h @@ -0,0 +1,22 @@ +#pragma once +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + SNTP_OK = 0, + SNTP_ERR_NO_CFG, + SNTP_ERR_NO_SERVER, + SNTP_ERR_SOCKET, + SNTP_ERR_SEND, + SNTP_ERR_TIMEOUT, + SNTP_ERR_FORMAT +} sntp_result_t; + +sntp_result_t sntp_poll_once(uint32_t timeout_ms); + +#ifdef __cplusplus +} +#endif diff --git a/shared/net/application_layer/sntp_daemon.c b/shared/net/application_layer/sntp_daemon.c new file mode 100644 index 00000000..eacb061d --- /dev/null +++ b/shared/net/application_layer/sntp_daemon.c @@ -0,0 +1,50 @@ +#include "sntp_daemon.h" +#include "sntp.h" +#include "exceptions/timer.h" +#include "process/scheduler.h" +#include "net/internet_layer/ipv4.h" +#include "process/scheduler.h" + +extern void sleep(uint64_t ms); + +static uint16_t g_pid_sntp = 0xFFFF; +static socket_handle_t g_sock = 0; + +uint16_t sntp_get_pid(void){ return g_pid_sntp; } +bool sntp_is_running(void){ return g_pid_sntp != 0xFFFF; } +void sntp_set_pid(uint16_t p){ g_pid_sntp = p; } +socket_handle_t sntp_socket_handle(void){ return g_sock; } + +#define SNTP_POLL_INTERVAL_MS (10u * 60u * 1000u) +#define SNTP_QUERY_TIMEOUT_MS 1200u +#define SNTP_BOOTSTRAP_MAX_RETRY 5u + +int sntp_daemon_entry(int argc, char* argv[]){ + (void)argc; (void)argv; + g_pid_sntp = (uint16_t)get_current_proc_pid(); + g_sock = udp_socket_create(0, g_pid_sntp); + sntp_set_pid(get_current_proc_pid()); + uint32_t attempts = 0; + while (attempts < SNTP_BOOTSTRAP_MAX_RETRY){ + const net_cfg_t* cfg = ipv4_get_cfg(); + if (!cfg || cfg->mode == NET_MODE_DISABLED || cfg->ip == 0){ + sleep(500); + continue; + } + + sntp_result_t r = sntp_poll_once(SNTP_QUERY_TIMEOUT_MS); + if (r == SNTP_OK){ + break; + } + attempts++; + uint32_t backoff_ms = (1u << (attempts <= 4 ? attempts : 4)) * 250u; + uint32_t jitter = backoff_ms / 10u; + sleep(backoff_ms + (jitter / 2u)); + } + + for(;;){ + sntp_poll_once(SNTP_QUERY_TIMEOUT_MS); + sleep(SNTP_POLL_INTERVAL_MS); + } + return 1; +} diff --git a/shared/net/application_layer/sntp_daemon.h b/shared/net/application_layer/sntp_daemon.h new file mode 100644 index 00000000..cdc7beb8 --- /dev/null +++ b/shared/net/application_layer/sntp_daemon.h @@ -0,0 +1,17 @@ +#pragma once +#include "types.h" +#include "net/transport_layer/csocket_udp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +uint16_t sntp_get_pid(void); +bool sntp_is_running(void); +void sntp_set_pid(uint16_t p); +socket_handle_t sntp_socket_handle(void); +int sntp_daemon_entry(int argc, char* argv[]); + +#ifdef __cplusplus +} +#endif diff --git a/shared/net/application_layer/socket_http_client.hpp b/shared/net/application_layer/socket_http_client.hpp index 728ee4c0..d8524512 100644 --- a/shared/net/application_layer/socket_http_client.hpp +++ b/shared/net/application_layer/socket_http_client.hpp @@ -4,8 +4,6 @@ #include "http.h" #include "std/string.h" #include "std/memfunctions.h" -#define KP(fmt, ...) \ - do { kprintf(fmt, ##__VA_ARGS__); } while (0) class HTTPClient { private: diff --git a/shared/net/application_layer/socket_http_server.hpp b/shared/net/application_layer/socket_http_server.hpp index 80d495e7..ae7808b4 100644 --- a/shared/net/application_layer/socket_http_server.hpp +++ b/shared/net/application_layer/socket_http_server.hpp @@ -1,14 +1,9 @@ -#pragma once - #include "console/kio.h" #include "net/transport_layer/socket_tcp.hpp" #include "http.h" #include "std/string.h" #include "std/memfunctions.h" -#define KP(fmt, ...) \ - do { kprintf(fmt, ##__VA_ARGS__); } while (0) - class HTTPServer { private: TCPSocket sock; diff --git a/shared/net/internet_layer/icmp.c b/shared/net/internet_layer/icmp.c index 11aa79d9..804eacd9 100644 --- a/shared/net/internet_layer/icmp.c +++ b/shared/net/internet_layer/icmp.c @@ -53,10 +53,8 @@ void create_icmp_packet(uintptr_t p, pkt->id = __builtin_bswap16(d->id); pkt->seq = __builtin_bswap16(d->seq); - if (d->payload) - memcpy(pkt->payload, d->payload, 56); - else - memset(pkt->payload, 0, 56); + memset(pkt->payload, 0, sizeof(pkt->payload)); + memcpy(pkt->payload, d->payload, sizeof(pkt->payload)); pkt->checksum = 0; } diff --git a/shared/net/internet_layer/ipv4.c b/shared/net/internet_layer/ipv4.c index 6ee6545d..92637d36 100644 --- a/shared/net/internet_layer/ipv4.c +++ b/shared/net/internet_layer/ipv4.c @@ -59,12 +59,33 @@ const net_cfg_t* ipv4_get_cfg() { return &g_net_cfg; } -string ipv4_to_string(uint32_t ip) { - return string_format("%i.%i.%i.%i", - (ip>>24)&0xFF, - (ip>>16)&0xFF, - (ip>>8)&0xFF, - ip&0xFF); +static char* u8_to_str(uint8_t val, char* out) { + if (val >= 100) { + *out++ = '0' + (val / 100); + val %= 100; + *out++ = '0' + (val / 10); + *out++ = '0' + (val % 10); + } else if (val >= 10) { + *out++ = '0' + (val / 10); + *out++ = '0' + (val % 10); + } else { + *out++ = '0' + val; + } + return out; +} + +void ipv4_to_string(uint32_t ip, char* buf) { + uint8_t a = (ip >> 24) & 0xFF; + uint8_t b = (ip >> 16) & 0xFF; + uint8_t c = (ip >> 8) & 0xFF; + uint8_t d = ip & 0xFF; + + char* p = buf; + p = u8_to_str(a, p); *p++ = '.'; + p = u8_to_str(b, p); *p++ = '.'; + p = u8_to_str(c, p); *p++ = '.'; + p = u8_to_str(d, p); + *p = '\0'; } static uint16_t ipv4_checksum(const void *buf, size_t len) { @@ -106,7 +127,7 @@ void ip_input(uintptr_t ip_ptr, arp_table_put(sip, src_mac, 60000, false); uint32_t dip = __builtin_bswap32(hdr->dst_ip); - const net_cfg_t *cfg = ipv4_get_cfg(); //TODO manage special ip + //TODO manage special ip uintptr_t payload_ptr = ip_ptr + header_bytes; uint32_t payload_len = __builtin_bswap16(hdr->total_length) - header_bytes; @@ -121,7 +142,7 @@ void ip_input(uintptr_t ip_ptr, udp_input(payload_ptr, payload_len, sip, dip); break; default: - //everything elese + //everything else break; } } diff --git a/shared/net/internet_layer/ipv4.h b/shared/net/internet_layer/ipv4.h index 40fefe2d..b005ef9f 100644 --- a/shared/net/internet_layer/ipv4.h +++ b/shared/net/internet_layer/ipv4.h @@ -47,7 +47,7 @@ void ipv4_cfg_init(); void ipv4_set_cfg(const net_cfg_t *src); const net_cfg_t* ipv4_get_cfg(); -string ipv4_to_string(uint32_t ip); +void ipv4_to_string(uint32_t ip, char* buf); void ipv4_send_segment(uint32_t src_ip, uint32_t dst_ip, diff --git a/shared/net/link_layer/arp.c b/shared/net/link_layer/arp.c index 0e950e4f..8db4c6c4 100644 --- a/shared/net/link_layer/arp.c +++ b/shared/net/link_layer/arp.c @@ -20,14 +20,11 @@ extern void free(void *ptr, uint64_t size); static uint16_t g_arp_pid = 0xFFFF; static arp_entry_t g_arp_table[ARP_TABLE_MAX]; static bool init = false; -#define KP(fmt, ...) \ - do { kprintf(fmt, ##__VA_ARGS__); } while (0) void arp_set_pid(uint16_t pid) { g_arp_pid = pid; } uint16_t arp_get_pid() { return g_arp_pid; } void arp_table_init() { - KP("[ARP] init"); memset(g_arp_table, 0, sizeof(g_arp_table)); init = true; arp_table_init_static_defaults(); @@ -61,13 +58,6 @@ void arp_table_put(uint32_t ip, const uint8_t mac[6], uint32_t ttl_ms, bool is_s memcpy(g_arp_table[idx].mac, mac, 6); g_arp_table[idx].ttl_ms = is_static ? 0 : ttl_ms; g_arp_table[idx].static_entry = is_static ? 1 : 0; - - /*KP("[ARP] put %i.%i.%i.%i -> %x:%x:%x:%x:%x:%x static=%i ttl=%i\n", - (uint64_t)((ip>>24)&0xFF), (uint64_t)((ip>>16)&0xFF), - (uint64_t)((ip>>8)&0xFF), (uint64_t)(ip&0xFF), - (uint64_t)mac[0], (uint64_t)mac[1], (uint64_t)mac[2], - (uint64_t)mac[3], (uint64_t)mac[4], (uint64_t)mac[5], - (uint64_t)g_arp_table[idx].static_entry, (uint64_t)ttl_ms);*/ } bool arp_table_get(uint32_t ip, uint8_t mac_out[6]) { @@ -153,7 +143,10 @@ bool arp_can_reply() { return (cfg && cfg->ip != 0 && cfg->mode != NET_MODE_DISABLED); } -int arp_daemon_entry() { + +int arp_daemon_entry(int argc, char* argv[]){ + (void)argc; (void)argv; + arp_set_pid(get_current_proc_pid()); while (1){ const net_cfg_t *cfg = ipv4_get_cfg(); if(cfg && cfg->ip != 0 && cfg->mode != NET_MODE_DISABLED) break; diff --git a/shared/net/link_layer/arp.h b/shared/net/link_layer/arp.h index 0066a149..0543b2fe 100644 --- a/shared/net/link_layer/arp.h +++ b/shared/net/link_layer/arp.h @@ -43,7 +43,7 @@ void arp_table_init_static_defaults(); void arp_send_request(uint32_t target_ip); -int arp_daemon_entry(); +int arp_daemon_entry(int argc, char* argv[]); bool arp_can_reply(); void arp_set_pid(uint16_t pid); uint16_t arp_get_pid(); diff --git a/shared/net/transport_layer/csocket_tcp.cpp b/shared/net/transport_layer/csocket_tcp.cpp index af408fb6..ceb86119 100644 --- a/shared/net/transport_layer/csocket_tcp.cpp +++ b/shared/net/transport_layer/csocket_tcp.cpp @@ -1,4 +1,3 @@ -#pragma once #include "net/transport_layer/socket_tcp.hpp" #include "net/transport_layer/socket.hpp" #include "csocket_tcp.h" diff --git a/shared/net/transport_layer/csocket_udp.cpp b/shared/net/transport_layer/csocket_udp.cpp index ea2ae548..4dae93c3 100644 --- a/shared/net/transport_layer/csocket_udp.cpp +++ b/shared/net/transport_layer/csocket_udp.cpp @@ -1,4 +1,3 @@ -#pragma once #include "net/transport_layer/socket_udp.hpp" #include "net/transport_layer/socket.hpp" #include "csocket_udp.h" diff --git a/shared/net/transport_layer/socket_tcp.hpp b/shared/net/transport_layer/socket_tcp.hpp index 59363d5c..4fbc9800 100644 --- a/shared/net/transport_layer/socket_tcp.hpp +++ b/shared/net/transport_layer/socket_tcp.hpp @@ -9,9 +9,6 @@ #include "types.h" #include "data_struct/ring_buffer.hpp" -#define KP(fmt, ...) \ - do { kprintf(fmt, ##__VA_ARGS__); } while (0) - extern "C" { void sleep(uint64_t ms); uintptr_t malloc(uint64_t size); @@ -154,7 +151,7 @@ class TCPSocket : public Socket { flow->payload = { (uintptr_t)buf, (uint32_t)len }; flow->flags = (1<(len) : static_cast(res); } int64_t recv(void* buf, uint64_t len) { diff --git a/shared/net/transport_layer/tcp.c b/shared/net/transport_layer/tcp.c index 5bd86a31..ff63ad33 100644 --- a/shared/net/transport_layer/tcp.c +++ b/shared/net/transport_layer/tcp.c @@ -88,7 +88,7 @@ uint16_t tcp_compute_checksum(const void *segment, return htons((uint16_t)(~sum & 0xFFFF)); } -static int find_flow(uint16_t local_port, uint32_t remote_ip, uint16_t remote_port) { +int find_flow(uint16_t local_port, uint32_t remote_ip, uint16_t remote_port) { for (int i = 0; i < MAX_TCP_FLOWS; ++i) { tcp_flow_t *f = &tcp_flows[i]; if (f->state != TCP_STATE_CLOSED) { @@ -424,13 +424,17 @@ void tcp_input(uintptr_t ptr, uint32_t len, uint32_t src_ip, uint32_t dst_ip) { uint16_t window = ntohs(hdr->window); int idx = find_flow(dst_port, src_ip, src_port); tcp_flow_t *flow = (idx >= 0 ? &tcp_flows[idx] : NULL); + if (flow) { + flow->ctx.window = window; + } if (!flow) { int listen_idx = find_flow(dst_port, 0, 0); - if ((flags & (1<= 0) { - //TODO: use a syscall for the rng + if ((flags & (1u<= 0) { + // TODO syscall for rng rng_t rng; rng_init_random(&rng); + tcp_flow_t *lf = &tcp_flows[listen_idx]; int new_idx = allocate_flow_entry(); if (new_idx < 0) return; @@ -441,16 +445,16 @@ void tcp_input(uintptr_t ptr, uint32_t len, uint32_t src_ip, uint32_t dst_ip) { flow->remote.port = src_port; flow->state = TCP_SYN_RECEIVED; flow->retries = TCP_SYN_RETRIES; - + + flow->ctx.window = lf->ctx.window ? lf->ctx.window : 0xFFFF; + flow->ctx.flags = 0; + flow->ctx.options = lf->ctx.options; + flow->ctx.payload.ptr = 0; + flow->ctx.payload.size = 0; + uint32_t iss = rng_next32(&rng); flow->ctx.sequence = iss; flow->ctx.ack = seq + 1; - flow->ctx.window = 0xFFFF; - flow->ctx.flags = 0; - flow->ctx.options.ptr = 0; - flow->ctx.options.size = 0; - flow->ctx.payload.ptr = 0; - flow->ctx.payload.size = 0; flow->ctx.expected_ack = iss + 1; flow->ctx.ack_received = 0; @@ -459,16 +463,15 @@ void tcp_input(uintptr_t ptr, uint32_t len, uint32_t src_ip, uint32_t dst_ip) { synack_hdr.dst_port = htons(src_port); synack_hdr.sequence = htonl(iss); synack_hdr.ack = htonl(seq + 1); - synack_hdr.flags = (1<ctx.window; + synack_hdr.flags = (uint8_t)((1u<ctx.window); synack_hdr.urgent_ptr = 0; uint32_t src_ip_local = ipv4_get_cfg()->ip; send_tcp_segment(src_ip_local, src_ip, &synack_hdr, NULL, 0); - return; } else { - if (!(flags & (1<data_offset_reserved >> 4) * 4; - uint32_t data_len = len - hdr_len; + case TCP_ESTABLISHED: { + uint8_t hdr_len = (uint8_t)((hdr->data_offset_reserved >> 4) * 4); + if (len < hdr_len) return; - if ((flags & ACK_F) - && !(flags & (SYN_F|FIN_F|RST_F)) - && data_len == 0 - && seq + 1 == flow->ctx.ack) - { - tcp_hdr_t ack_hdr = { - .src_port = htons(flow->local_port), - .dst_port = htons(flow->remote.port), - .sequence = htonl(flow->ctx.sequence), - .ack = htonl(flow->ctx.ack), - .flags = (1 << ACK_F), - .window = flow->ctx.window, - .urgent_ptr = 0 + uint32_t data_len = len - hdr_len; + const bool is_ack_only = + ( (flags & (1u << ACK_F)) != 0 ) && + ( (flags & ((1u << SYN_F) | (1u << FIN_F) | (1u << RST_F))) == 0 ) && + ( data_len == 0 ) && + ( seq + 1u == flow->ctx.ack ); + + if (is_ack_only) { + tcp_hdr_t ack_hdr = (tcp_hdr_t){ + .src_port = htons(flow->local_port), + .dst_port = htons(flow->remote.port), + .sequence = htonl(flow->ctx.sequence), + .ack = htonl(flow->ctx.ack), + .flags = (uint8_t)(1u << ACK_F), + .window = htons(flow->ctx.window), + .urgent_ptr = 0 }; send_tcp_segment( ipv4_get_cfg()->ip, @@ -544,6 +550,9 @@ void tcp_input(uintptr_t ptr, uint32_t len, uint32_t src_ip, uint32_t dst_ip) { ); return; } + + __attribute__((fallthrough)); + } case TCP_FIN_WAIT_1: case TCP_FIN_WAIT_2: case TCP_CLOSE_WAIT: diff --git a/shared/net/transport_layer/tcp.h b/shared/net/transport_layer/tcp.h index 4a6f20c2..70f546a1 100644 --- a/shared/net/transport_layer/tcp.h +++ b/shared/net/transport_layer/tcp.h @@ -81,7 +81,7 @@ typedef struct { #define TCP_DATA_RETRIES 5 #define TCP_RETRY_TIMEOUT_MS 1000 -static int find_flow(uint16_t local_port, uint32_t remote_ip, uint16_t remote_port); +int find_flow(uint16_t local_port, uint32_t remote_ip, uint16_t remote_port); tcp_data* tcp_get_ctx(uint16_t local_port, uint32_t remote_ip, diff --git a/shared/net/transport_layer/udp.c b/shared/net/transport_layer/udp.c index 7a478b6e..bed8334e 100644 --- a/shared/net/transport_layer/udp.c +++ b/shared/net/transport_layer/udp.c @@ -9,8 +9,6 @@ extern void sleep(uint64_t ms); extern uintptr_t malloc(uint64_t size); extern void free(void *ptr, uint64_t size); -static inline uint16_t bswap16(uint16_t v) { return __builtin_bswap16(v); } - bool udp_bind(uint16_t port, uint16_t pid, port_recv_handler_t handler) diff --git a/shared/types.h b/shared/types.h index a787599d..e87cd995 100644 --- a/shared/types.h +++ b/shared/types.h @@ -8,7 +8,39 @@ extern "C" { #endif +#define bswap16(v) __builtin_bswap16((uint16_t)(v)) +#define bswap32(v) __builtin_bswap32((uint32_t)(v)) +#define bswap64(v) __builtin_bswap64((uint64_t)(v)) +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + #define be16(v) bswap16(v) + #define be32(v) bswap32(v) + #define be64(v) bswap64(v) +#else + #define be16(v) ((uint16_t)(v)) + #define be32(v) ((uint32_t)(v)) + #define be64(v) ((uint64_t)(v)) +#endif + +#define rd_be16(p) ( ((uint16_t)((const uint8_t*)(p))[0] << 8) | \ + ((uint16_t)((const uint8_t*)(p))[1]) ) + +#define rd_be32(p) ( ((uint32_t)((const uint8_t*)(p))[0] << 24) | \ + ((uint32_t)((const uint8_t*)(p))[1] << 16) | \ + ((uint32_t)((const uint8_t*)(p))[2] << 8) | \ + ((uint32_t)((const uint8_t*)(p))[3]) ) + +#define wr_be16(p, v) do { \ + (p)[0] = (uint8_t)((v) >> 8); \ + (p)[1] = (uint8_t)(v); \ +} while(0) + +#define wr_be32(p, v) do { \ + (p)[0] = (uint8_t)((v) >> 24); \ + (p)[1] = (uint8_t)((v) >> 16); \ + (p)[2] = (uint8_t)((v) >> 8); \ + (p)[3] = (uint8_t)(v); \ +} while(0) typedef unsigned int uint32_t; typedef long unsigned int size_t;