blob: 227c2278b7ec82f4c18f95f41727ad9aa1274531 [file] [log] [blame]
// Copyright 2017 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.
#define _POSIX_C_SOURCE 200809L
#define _GNU_SOURCE
#define _DARWIN_C_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include "netprotocol.h"
#define MAX_DEVICES 255
static device_info_t devices[MAX_DEVICES];
static uint32_t devices_count = 0;
static const char* appname;
static bool has_device(const char* nodename) {
for (uint32_t i = 0; i < devices_count; ++i) {
if (!strncmp(devices[i].nodename, nodename, sizeof(devices[i].nodename))) {
return true;
}
}
return false;
}
static device_info_t* get_device(const char* nodename) {
for (uint32_t i = 0; i < devices_count; ++i) {
if (!strncmp(devices[i].nodename, nodename, sizeof(devices[i].nodename))) {
return &devices[i];
}
}
return NULL;
}
static device_info_t* add_device(device_info_t* device) {
device_info_t* known_device = get_device(device->nodename);
if (!known_device) {
if (devices_count > MAX_DEVICES) {
return NULL;
}
known_device = &devices[devices_count];
devices_count++;
strncpy(known_device->nodename, device->nodename, sizeof(known_device->nodename));
}
strncpy(known_device->inet6_addr_s, device->inet6_addr_s, INET6_ADDRSTRLEN);
memcpy(&known_device->inet6_addr, &device->inet6_addr, sizeof(known_device->inet6_addr));
known_device->state = device->state;
known_device->bootloader_port = device->bootloader_port;
known_device->bootloader_version = device->bootloader_version;
return known_device;
}
static bool on_device(device_info_t* device, void* cookie) {
if (!has_device(device->nodename)) {
if (device->state == UNKNOWN) {
device->state = OFFLINE;
}
const char* state = "unknown";
switch (device->state) {
case UNKNOWN:
state = "unknown";
break;
case OFFLINE:
state = "offline";
break;
case DEVICE:
state = "device";
break;
case BOOTLOADER:
state = "bootloader";
break;
}
// TODO(jimbe): Print the type of the device based on the vendor id of the mac address.
fprintf(stdout, "%10s %s", state, device->nodename);
if (device->inet6_addr.sin6_scope_id != 0) {
fprintf(stdout, " (%s/%d)", device->inet6_addr_s, device->inet6_addr.sin6_scope_id);
}
if (device->state == BOOTLOADER) {
fprintf(stdout, " [Bootloader version 0x%08X listening on %d]", device->bootloader_version,
device->bootloader_port);
}
fprintf(stdout, "\n");
if (add_device(device) == NULL) {
return false;
}
}
return true;
}
static void usage(void) {
fprintf(stderr, "usage: %s [options]\n", appname);
netboot_usage(false);
}
int main(int argc, char** argv) {
appname = argv[0];
int index = netboot_handle_getopt(argc, argv);
if (index < 0) {
usage();
return -1;
}
if (netboot_discover(NETBOOT_PORT_SERVER, NULL, on_device, NULL)) {
fprintf(stderr, "Failed to discover\n");
return 1;
}
return 0;
}