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