blob: ebc80022665b3815f45cedadd94d6117613bc73a [file] [log] [blame]
// 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 "netsvc.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <threads.h>
#include <unistd.h>
#include <inet6/inet6.h>
#include <inet6/netifc.h>
#include <lib/fdio/io.h>
#include <lib/fdio/spawn.h>
#include <zircon/boot/netboot.h>
#include <zircon/process.h>
#include <zircon/processargs.h>
#include <zircon/syscalls.h>
#include <zircon/syscalls/log.h>
#include <zircon/time.h>
#include "device_id.h"
#include "debuglog.h"
#include "netboot.h"
#include "tftp.h"
#define FILTER_IPV6 1
static bool g_netbootloader = false;
static const char* g_nodename = "zircon";
bool netbootloader() { return g_netbootloader; }
const char* nodename() { return g_nodename; }
void udp6_recv(void* data, size_t len, const ip6_addr_t* daddr, uint16_t dport,
const ip6_addr_t* saddr, uint16_t sport) {
bool mcast = (memcmp(daddr, &ip6_ll_all_nodes, sizeof(ip6_addr_t)) == 0);
switch (dport) {
case NB_SERVER_PORT:
netboot_recv(data, len, mcast, daddr, dport, saddr, sport);
break;
case DEBUGLOG_ACK_PORT:
debuglog_recv(data, len, mcast);
break;
case NB_TFTP_INCOMING_PORT:
case NB_TFTP_OUTGOING_PORT:
tftp_recv(data, len, daddr, dport, saddr, sport);
break;
}
}
void netifc_recv(void* data, size_t len) {
eth_recv(data, len);
}
bool netifc_send_pending() {
if (!tftp_has_pending()) {
return false;
}
tftp_send_next();
return tftp_has_pending();
}
void update_timeouts() {
zx_time_t now = zx_clock_get_monotonic();
zx_time_t next_timeout = (debuglog_next_timeout() < tftp_next_timeout())
? debuglog_next_timeout()
: tftp_next_timeout();
if (next_timeout != ZX_TIME_INFINITE) {
uint32_t ms = static_cast<uint32_t>(
(next_timeout < now) ? 0 : (zx_time_sub_time(next_timeout, now)) / ZX_MSEC(1));
netifc_set_timer(ms);
}
}
static const char* zedboot_banner = " _ _ _ \n"
" | | | | | \n"
" _______ __| | |__ ___ ___ | |_ \n"
" |_ / _ \\/ _` | '_ \\ / _ \\ / _ \\| __|\n"
" / / __/ (_| | |_) | (_) | (_) | |_ \n"
" /___\\___|\\__,_|_.__/ \\___/ \\___/ \\__|\n"
" \n"
"\n";
int main(int argc, char** argv) {
unsigned char mac[6];
uint16_t mtu;
char device_id[DEVICE_ID_MAX];
bool print_nodename_and_exit = false;
if (debuglog_init() < 0) {
return -1;
}
const char* interface = NULL;
bool nodename_provided = false;
bool should_advertise = false;
while (argc > 1) {
if (!strncmp(argv[1], "--netboot", 9)) {
g_netbootloader = true;
} else if (!strncmp(argv[1], "--advertise", 11)) {
should_advertise = true;
} else if (!strncmp(argv[1], "--interface", 11)) {
if (argc < 3) {
printf("netsvc: fatal error: missing argument to --interface\n");
return -1;
}
interface = argv[2];
// Advance args one position. The second arg will be advanced below.
argv++;
argc--;
} else if (!strncmp(argv[1], "--nodename", 10)) {
print_nodename_and_exit = true;
} else {
g_nodename = argv[1];
nodename_provided = true;
}
argv++;
argc--;
}
if (interface != NULL) {
printf("netsvc: looking for interface %s\n", interface);
}
for (;;) {
if (netifc_open(interface, /*quiet=*/print_nodename_and_exit) != 0) {
printf("netsvc: fatal error initializing network\n");
return -1;
}
// Use mac address to generate unique nodename unless one was provided.
if (!nodename_provided) {
netifc_get_info(mac, &mtu);
device_id_get(mac, device_id);
g_nodename = device_id;
if (print_nodename_and_exit) {
printf("%s\n", g_nodename);
return 0;
}
}
if (g_netbootloader) {
printf("%szedboot: version: %s\n\n", zedboot_banner, BOOTLOADER_VERSION);
}
printf("netsvc: nodename='%s'\n", g_nodename);
if (!should_advertise) {
printf("netsvc: will not advertise\n");
}
printf("netsvc: start\n");
for (;;) {
if (g_netbootloader && should_advertise) {
netboot_advertise(g_nodename);
}
update_timeouts();
if (netifc_poll()) {
printf("netsvc: netifc_poll() failed - terminating\n");
break;
}
zx_time_t now = zx_clock_get_monotonic();
if (now > debuglog_next_timeout()) {
debuglog_timeout_expired();
}
if (now > tftp_next_timeout()) {
tftp_timeout_expired();
}
}
netifc_close();
}
return 0;
}