// 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 #include #include #include #include #include #include #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(NB_SERVER_PORT, NULL, on_device, NULL)) { fprintf(stderr, "Failed to discover\n"); return 1; } return 0; }