1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright (c) 2018, Joyent, Inc. 14 */ 15 16 /* 17 * Receive a raw Ethernet frame from dlsend. 18 */ 19 20 #include <stdio.h> 21 #include <errno.h> 22 #include <strings.h> 23 #include <unistd.h> 24 #include <stdarg.h> 25 #include <libgen.h> 26 #include <limits.h> 27 #include <stdlib.h> 28 #include <unistd.h> 29 #include <netdb.h> 30 #include <libdlpi.h> 31 #include <stddef.h> 32 #include <stdint.h> 33 #include <endian.h> 34 #include <ctype.h> 35 #include <err.h> 36 37 #include "dlsend.h" 38 39 40 static uint_t dlrecv_sap = DLSEND_SAP; 41 static const char *dlrecv_prog; 42 43 static void 44 dlrecv_usage(const char *fmt, ...) 45 { 46 if (fmt != NULL) { 47 va_list ap; 48 49 (void) fprintf(stderr, "%s: ", dlrecv_prog); 50 va_start(ap, fmt); 51 (void) vfprintf(stderr, fmt, ap); 52 va_end(ap); 53 } 54 55 (void) fprintf(stderr, "Usage: %s [-s sap] device\n" 56 "\t-s sap\tspecify SAP to send on\n", 57 dlrecv_prog); 58 } 59 60 static boolean_t 61 dlrecv_isvalid(dlsend_msg_t *msg) 62 { 63 uint_t i; 64 boolean_t nul; 65 66 nul = B_FALSE; 67 for (i = 0; i < sizeof (msg->dm_host); i++) { 68 if (!isprint(msg->dm_host[i]) && 69 msg->dm_host[i] != '\0') { 70 warnx("Encountered bad byte in dm_host[%d]", 71 i); 72 return (B_FALSE); 73 } 74 75 if (msg->dm_host[i] == '\0') 76 nul = B_TRUE; 77 } 78 79 if (!nul) { 80 warnx("Missing NUL in dm_host"); 81 return (B_FALSE); 82 } 83 84 nul = B_FALSE; 85 for (i = 0; i < sizeof (msg->dm_mesg); i++) { 86 if (!isprint(msg->dm_mesg[i]) && 87 msg->dm_mesg[i] != '\0') { 88 warnx("Encountered bad byte in dm_mesg[%d]", 89 i); 90 return (B_FALSE); 91 } 92 93 if (msg->dm_mesg[i] == '\0') 94 nul = B_TRUE; 95 } 96 97 if (!nul) { 98 warnx("Missing NUL in dm_mesg"); 99 return (B_FALSE); 100 } 101 102 if (strcmp(msg->dm_mesg, DLSEND_MSG) != 0) { 103 warnx("Missing expected message (%s)", DLSEND_MSG); 104 return (B_FALSE); 105 } 106 107 return (B_TRUE); 108 } 109 110 static void 111 dlrecv_print(dlsend_msg_t *msg, dlpi_recvinfo_t *rinfo, boolean_t invalid) 112 { 113 uint_t i; 114 115 (void) printf("Received %s from ", invalid ? 116 "invalid message" : "Elbereth"); 117 118 for (i = 0; i < rinfo->dri_destaddrlen; i++) { 119 (void) printf("%02x", rinfo->dri_destaddr[i]); 120 if (i + 1 != rinfo->dri_destaddrlen) 121 (void) putchar(':'); 122 } 123 124 if (invalid) { 125 return; 126 } 127 128 (void) printf(" seq=%" PRIu64 " host=%s\n", betoh64(msg->dm_count), 129 msg->dm_host); 130 } 131 132 int 133 main(int argc, char *argv[]) 134 { 135 int c, ret; 136 char *eptr; 137 unsigned long sap; 138 uint_t bind_sap; 139 dlpi_handle_t dh; 140 141 dlrecv_prog = basename(argv[0]); 142 143 while ((c = getopt(argc, argv, ":s:")) != -1) { 144 switch (c) { 145 case 's': 146 errno = 0; 147 sap = strtoul(optarg, &eptr, 10); 148 if (errno != 0 || sap == 0 || sap >= UINT16_MAX || 149 *eptr != '\0') { 150 dlrecv_usage("Invalid value for sap (-s): %s\n", 151 optarg); 152 return (2); 153 } 154 dlrecv_sap = sap; 155 break; 156 case ':': 157 dlrecv_usage("Option -%c requires an operand\n", 158 optopt); 159 return (2); 160 case '?': 161 dlrecv_usage("Unknown option: -%c\n", optopt); 162 return (2); 163 } 164 } 165 166 argc -= optind; 167 argv += optind; 168 169 if (argc != 1) { 170 dlrecv_usage("missing required operands\n"); 171 return (2); 172 } 173 174 if ((ret = dlpi_open(argv[0], &dh, 0)) != DLPI_SUCCESS) { 175 warnx("failed to open %s: %s", argv[0], 176 dlpi_strerror(ret)); 177 exit(1); 178 } 179 180 if ((ret = dlpi_bind(dh, dlrecv_sap, &bind_sap)) != DLPI_SUCCESS) { 181 warnx("failed to bind to sap 0x%x: %s", dlrecv_sap, 182 dlpi_strerror(ret)); 183 exit(1); 184 } 185 186 if (bind_sap != dlrecv_sap) { 187 warnx("failed to bind to requested sap 0x%x, bound to " 188 "0x%x", dlrecv_sap, bind_sap); 189 exit(1); 190 } 191 192 for (;;) { 193 dlpi_recvinfo_t rinfo; 194 dlsend_msg_t msg; 195 size_t msglen; 196 boolean_t invalid = B_FALSE; 197 198 msglen = sizeof (msg); 199 ret = dlpi_recv(dh, NULL, NULL, &msg, &msglen, -1, &rinfo); 200 if (ret != DLPI_SUCCESS) { 201 warnx("failed to receive data: %s", dlpi_strerror(ret)); 202 continue; 203 } 204 205 if (msglen != rinfo.dri_totmsglen) { 206 warnx("message truncated: expected %zu bytes, " 207 "got %zu", sizeof (dlsend_msg_t), 208 rinfo.dri_totmsglen); 209 invalid = B_TRUE; 210 } 211 212 if (msglen != sizeof (msg)) { 213 warnx("message too short: expected %zu bytes, " 214 "got %zu", sizeof (dlsend_msg_t), msglen); 215 invalid = B_TRUE; 216 } 217 218 if (!invalid) { 219 invalid = !dlrecv_isvalid(&msg); 220 } 221 222 dlrecv_print(&msg, &rinfo, invalid); 223 } 224 225 /* LINTED: E_STMT_NOT_REACHED */ 226 return (0); 227 } 228