1// Copyright 2017 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#define _POSIX_C_SOURCE 200809L 6 7#define _GNU_SOURCE 8#define _DARWIN_C_SOURCE 9 10#include <errno.h> 11#include <fcntl.h> 12#include <netinet/in.h> 13#include <stdio.h> 14#include <stdlib.h> 15#include <string.h> 16#include <sys/time.h> 17 18#include "netprotocol.h" 19 20#define MAX_DEVICES 255 21 22static device_info_t devices[MAX_DEVICES]; 23static uint32_t devices_count = 0; 24 25static const char* appname; 26 27static bool has_device(const char* nodename) { 28 for (uint32_t i = 0; i < devices_count; ++i) { 29 if (!strncmp(devices[i].nodename, nodename, sizeof(devices[i].nodename))) { 30 return true; 31 } 32 } 33 return false; 34} 35 36static device_info_t* get_device(const char* nodename) { 37 for (uint32_t i = 0; i < devices_count; ++i) { 38 if (!strncmp(devices[i].nodename, nodename, sizeof(devices[i].nodename))) { 39 return &devices[i]; 40 } 41 } 42 return NULL; 43} 44 45static device_info_t* add_device(device_info_t* device) { 46 device_info_t* known_device = get_device(device->nodename); 47 if (!known_device) { 48 if (devices_count > MAX_DEVICES) { 49 return NULL; 50 } 51 known_device = &devices[devices_count]; 52 devices_count++; 53 strncpy(known_device->nodename, device->nodename, sizeof(known_device->nodename)); 54 } 55 strncpy(known_device->inet6_addr_s, device->inet6_addr_s, INET6_ADDRSTRLEN); 56 memcpy(&known_device->inet6_addr, &device->inet6_addr, sizeof(known_device->inet6_addr)); 57 known_device->state = device->state; 58 known_device->bootloader_port = device->bootloader_port; 59 known_device->bootloader_version = device->bootloader_version; 60 return known_device; 61} 62 63static bool on_device(device_info_t* device, void* cookie) { 64 if (!has_device(device->nodename)) { 65 if (device->state == UNKNOWN) { 66 device->state = OFFLINE; 67 } 68 const char* state = "unknown"; 69 switch (device->state) { 70 case UNKNOWN: 71 state = "unknown"; 72 break; 73 case OFFLINE: 74 state = "offline"; 75 break; 76 case DEVICE: 77 state = "device"; 78 break; 79 case BOOTLOADER: 80 state = "bootloader"; 81 break; 82 } 83 84 // TODO(jimbe): Print the type of the device based on the vendor id of the mac address. 85 fprintf(stdout, "%10s %s", state, device->nodename); 86 if (device->inet6_addr.sin6_scope_id != 0) { 87 fprintf(stdout, " (%s/%d)", device->inet6_addr_s, device->inet6_addr.sin6_scope_id); 88 } 89 if (device->state == BOOTLOADER) { 90 fprintf(stdout, " [Bootloader version 0x%08X listening on %d]", 91 device->bootloader_version, device->bootloader_port); 92 } 93 fprintf(stdout, "\n"); 94 if (add_device(device) == NULL) { 95 return false; 96 } 97 } 98 return true; 99} 100 101static void usage(void) { 102 fprintf(stderr, "usage: %s [options]\n", appname); 103 netboot_usage(false); 104} 105 106int main(int argc, char** argv) { 107 appname = argv[0]; 108 int index = netboot_handle_getopt(argc, argv); 109 if (index < 0) { 110 usage(); 111 return -1; 112 } 113 114 if (netboot_discover(NB_SERVER_PORT, NULL, on_device, NULL)) { 115 fprintf(stderr, "Failed to discover\n"); 116 return 1; 117 } 118 return 0; 119} 120