| Jérôme Poichet | 402e106 | 2017-03-17 16:41:43 -0700 | [diff] [blame] | 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 | |
| 22 | static device_info_t devices[MAX_DEVICES]; |
| 23 | static uint32_t devices_count = 0; |
| 24 | |
| Erik Gilling | 6a84558 | 2017-04-05 11:31:20 -0700 | [diff] [blame] | 25 | static const char* appname; |
| 26 | |
| Jérôme Poichet | 402e106 | 2017-03-17 16:41:43 -0700 | [diff] [blame] | 27 | static bool has_device(const char* nodename) { |
| Roland McGrath | 29b10dc | 2019-08-06 23:34:54 +0000 | [diff] [blame] | 28 | for (uint32_t i = 0; i < devices_count; ++i) { |
| 29 | if (!strncmp(devices[i].nodename, nodename, sizeof(devices[i].nodename))) { |
| 30 | return true; |
| Jérôme Poichet | 402e106 | 2017-03-17 16:41:43 -0700 | [diff] [blame] | 31 | } |
| Roland McGrath | 29b10dc | 2019-08-06 23:34:54 +0000 | [diff] [blame] | 32 | } |
| 33 | return false; |
| Jérôme Poichet | 402e106 | 2017-03-17 16:41:43 -0700 | [diff] [blame] | 34 | } |
| 35 | |
| 36 | static device_info_t* get_device(const char* nodename) { |
| Roland McGrath | 29b10dc | 2019-08-06 23:34:54 +0000 | [diff] [blame] | 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]; |
| Jérôme Poichet | 402e106 | 2017-03-17 16:41:43 -0700 | [diff] [blame] | 40 | } |
| Roland McGrath | 29b10dc | 2019-08-06 23:34:54 +0000 | [diff] [blame] | 41 | } |
| 42 | return NULL; |
| Jérôme Poichet | 402e106 | 2017-03-17 16:41:43 -0700 | [diff] [blame] | 43 | } |
| 44 | |
| 45 | static device_info_t* add_device(device_info_t* device) { |
| Roland McGrath | 29b10dc | 2019-08-06 23:34:54 +0000 | [diff] [blame] | 46 | device_info_t* known_device = get_device(device->nodename); |
| 47 | if (!known_device) { |
| 48 | if (devices_count > MAX_DEVICES) { |
| 49 | return NULL; |
| Jérôme Poichet | 402e106 | 2017-03-17 16:41:43 -0700 | [diff] [blame] | 50 | } |
| Roland McGrath | 29b10dc | 2019-08-06 23:34:54 +0000 | [diff] [blame] | 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; |
| Jérôme Poichet | 402e106 | 2017-03-17 16:41:43 -0700 | [diff] [blame] | 61 | } |
| 62 | |
| 63 | static bool on_device(device_info_t* device, void* cookie) { |
| Roland McGrath | 29b10dc | 2019-08-06 23:34:54 +0000 | [diff] [blame] | 64 | if (!has_device(device->nodename)) { |
| 65 | if (device->state == UNKNOWN) { |
| 66 | device->state = OFFLINE; |
| Jérôme Poichet | 402e106 | 2017-03-17 16:41:43 -0700 | [diff] [blame] | 67 | } |
| Roland McGrath | 29b10dc | 2019-08-06 23:34:54 +0000 | [diff] [blame] | 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]", device->bootloader_version, |
| 91 | device->bootloader_port); |
| 92 | } |
| 93 | fprintf(stdout, "\n"); |
| 94 | if (add_device(device) == NULL) { |
| 95 | return false; |
| 96 | } |
| 97 | } |
| 98 | return true; |
| Jérôme Poichet | 402e106 | 2017-03-17 16:41:43 -0700 | [diff] [blame] | 99 | } |
| 100 | |
| Erik Gilling | 6a84558 | 2017-04-05 11:31:20 -0700 | [diff] [blame] | 101 | static void usage(void) { |
| Roland McGrath | 29b10dc | 2019-08-06 23:34:54 +0000 | [diff] [blame] | 102 | fprintf(stderr, "usage: %s [options]\n", appname); |
| 103 | netboot_usage(false); |
| Erik Gilling | 6a84558 | 2017-04-05 11:31:20 -0700 | [diff] [blame] | 104 | } |
| 105 | |
| Jérôme Poichet | 402e106 | 2017-03-17 16:41:43 -0700 | [diff] [blame] | 106 | int main(int argc, char** argv) { |
| Roland McGrath | 29b10dc | 2019-08-06 23:34:54 +0000 | [diff] [blame] | 107 | appname = argv[0]; |
| 108 | int index = netboot_handle_getopt(argc, argv); |
| 109 | if (index < 0) { |
| 110 | usage(); |
| 111 | return -1; |
| 112 | } |
| Erik Gilling | 6a84558 | 2017-04-05 11:31:20 -0700 | [diff] [blame] | 113 | |
| Joshua Seaton | 858c512 | 2023-04-02 01:32:44 +0000 | [diff] [blame] | 114 | if (netboot_discover(NETBOOT_PORT_SERVER, NULL, on_device, NULL)) { |
| Roland McGrath | 29b10dc | 2019-08-06 23:34:54 +0000 | [diff] [blame] | 115 | fprintf(stderr, "Failed to discover\n"); |
| 116 | return 1; |
| 117 | } |
| 118 | return 0; |
| Jérôme Poichet | 402e106 | 2017-03-17 16:41:43 -0700 | [diff] [blame] | 119 | } |