# # This file and its contents are supplied under the terms of the # Common Development and Distribution License ("CDDL"), version 1.0. # You may only use this file in accordance with the terms of version # 1.0 of the CDDL. # # A full copy of the text of the CDDL should have accompanied this # source. A copy of the CDDL is also available via the Internet at # http://www.illumos.org/license/CDDL. # # # Copyright (c) 2017, Joyent, Inc. # Copyright 2024 Oxide Computer Company # PROG= dltraninfo dlsend dlrecv dlled DLTRANINFO_OBJS = dltraninfo.o $(HEXDUMP_OBJS) include ../Makefile.cmd include $(SRC)/common/hexdump/Makefile.com ROOTCMDDIR = $(ROOTLIB)/dl CFLAGS += $(CCVERBOSE) dltraninfo : LDLIBS += -ldladm -lsff -lnvpair dlled : LDLIBS += -ldladm dlsend : LDLIBS += -ldlpi -lsocket dlrecv : LDLIBS += -ldlpi ROOTLIBDLFILES = $(PROG:%=$(ROOTLIB)/dl/%) .KEEP_STATE: all: $(PROG) install: all $(ROOTCMD) clean: $(RM) $(DLTRANINFO_OBJS) dltraninfo: $(DLTRANINFO_OBJS) $(LINK.c) -o $@ $(DLTRANINFO_OBJS) $(LDLIBS) $(POST_PROCESS) include $(SRC)/common/hexdump/Makefile.targ include ../Makefile.targ /* * This file and its contents are supplied under the terms of the * Common Development and Distribution License ("CDDL"), version 1.0. * You may only use this file in accordance with the terms of version * 1.0 of the CDDL. * * A full copy of the text of the CDDL should have accompanied this * source. A copy of the CDDL is also available via the Internet at * http://www.illumos.org/license/CDDL. */ /* * Copyright (c) 2017, Joyent, Inc. */ /* * Private utility to get and set LED information on NICs. This should really * all be integrated into FM. Until we have figured out that plumbing, this * allows us to have a little something that we can use to drive work. */ #include #include #include #include #include #include #include #include #include #include #include #include #include static const char *dlled_progname; static dladm_handle_t dlled_hdl; static char dlled_dlerrmsg[DLADM_STRSIZE]; typedef struct dlled_led_map { const char *dlm_name; mac_led_mode_t dlm_bits; } dlled_led_map_t; static dlled_led_map_t dlled_map[] = { { "default", MAC_LED_DEFAULT }, { "off", MAC_LED_OFF }, { "on", MAC_LED_ON }, { "ident", MAC_LED_IDENT } }; #define DLLED_MAP_NENTRIES \ (sizeof (dlled_map) / sizeof (dlled_led_map_t)) static void dlled_usage(const char *fmt, ...) { if (fmt != NULL) { va_list ap; (void) fprintf(stderr, "%s: ", dlled_progname); va_start(ap, fmt); (void) vfprintf(stderr, fmt, ap); va_end(ap); } (void) fprintf(stderr, "Usage: %s [-s mode] [link]\n" "\n" "\t-s mode set LED to mode\n", dlled_progname); } static mac_led_mode_t dlled_parse_mode(const char *orig) { char *mode; char *part; mac_led_mode_t m = 0; mode = strdup(orig); if (mode == NULL) { fprintf(stderr, "failed to allocate memory to dup led " "mode: %s\n", strerror(errno)); exit(1); } part = strtok(mode, ","); while (part != NULL) { int i; for (i = 0; i < DLLED_MAP_NENTRIES; i++) { if (strcmp(dlled_map[i].dlm_name, part) == 0) { m |= dlled_map[i].dlm_bits; break; } } if (i == DLLED_MAP_NENTRIES) { fprintf(stderr, "unknown LED mode: %s\n", part); exit(1); } part = strtok(NULL, ","); } free(mode); if (m == 0) { fprintf(stderr, "failed to parse %s: no valid modes " "specified\n", orig); exit(1); } return (m); } static void dlled_mode2str(mac_led_mode_t mode, char *buf, size_t len) { int i; boolean_t first = B_TRUE; mac_led_mode_t orig = mode; for (i = 0; i < DLLED_MAP_NENTRIES; i++) { if ((mode & dlled_map[i].dlm_bits) != 0) { if (first) { first = B_FALSE; } else { (void) strlcat(buf, ",", len); } (void) strlcat(buf, dlled_map[i].dlm_name, len); mode &= ~dlled_map[i].dlm_bits; } } if (mode != 0) { (void) snprintf(buf, len, "unknown mode: 0x%x\n", orig); } } static int dlled_set(const char *link, mac_led_mode_t mode) { datalink_id_t linkid; dladm_status_t status; dld_ioc_led_t dil; if ((status = dladm_name2info(dlled_hdl, link, &linkid, NULL, NULL, NULL)) != DLADM_STATUS_OK) { (void) fprintf(stderr, "failed to get link " "id for link %s: %s\n", link, dladm_status2str(status, dlled_dlerrmsg)); return (1); } bzero(&dil, sizeof (dil)); dil.dil_linkid = linkid; dil.dil_active = mode; if (ioctl(dladm_dld_fd(dlled_hdl), DLDIOC_SETLED, &dil) != 0) { (void) fprintf(stderr, "failed to set LED on " "device %s: %s\n", link, strerror(errno)); return (1); } return (0); } static int dlled_get_led(dladm_handle_t hdl, datalink_id_t linkid, void *arg) { dladm_status_t status; char name[MAXLINKNAMELEN]; char supported[128], active[128]; dld_ioc_led_t dil; if ((status = dladm_datalink_id2info(hdl, linkid, NULL, NULL, NULL, name, sizeof (name))) != DLADM_STATUS_OK) { (void) fprintf(stderr, "failed to get datalink name for link " "%d: %s", linkid, dladm_status2str(status, dlled_dlerrmsg)); return (DLADM_WALK_CONTINUE); } bzero(&dil, sizeof (dil)); dil.dil_linkid = linkid; if (ioctl(dladm_dld_fd(hdl), DLDIOC_GETLED, &dil) != 0) { (void) fprintf(stderr, "failed to get LED information for " "device %s: %s\n", name, strerror(errno)); return (DLADM_WALK_CONTINUE); } active[0] = '\0'; supported[0] = '\0'; dlled_mode2str(dil.dil_active, active, sizeof (active)); dlled_mode2str(dil.dil_supported, supported, sizeof (supported)); printf("%-20s %-12s %s\n", name, active, supported); return (DLADM_WALK_CONTINUE); } int main(int argc, char *argv[]) { int c, ret; boolean_t opt_s = B_FALSE; mac_led_mode_t set_mode = 0; dladm_status_t status; dlled_progname = basename(argv[0]); while ((c = getopt(argc, argv, ":s:")) != -1) { switch (c) { case 's': opt_s = B_TRUE; set_mode = dlled_parse_mode(optarg); break; case ':': dlled_usage("option -%c requires an operand\n", optopt); return (2); case '?': default: dlled_usage("unknown option: -%c\n", optopt); return (2); } } argc -= optind; argv += optind; if (opt_s && argc > 1) { dlled_usage("-s only operates on a single datalink\n"); return (2); } if (opt_s && argc <= 0) { dlled_usage("-s requires a datalink\n"); return (2); } if ((status = dladm_open(&dlled_hdl)) != DLADM_STATUS_OK) { (void) fprintf(stderr, "failed to open /dev/dld: %s\n", dladm_status2str(status, dlled_dlerrmsg)); return (1); } if (opt_s) { return (dlled_set(argv[0], set_mode)); } (void) printf("%-20s %-12s %s\n", "LINK", "ACTIVE", "SUPPORTED"); ret = 0; if (argc == 0) { (void) dladm_walk_datalink_id(dlled_get_led, dlled_hdl, NULL, DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE); } else { int i, dlret; datalink_id_t linkid; for (i = 0; i < argc; i++) { if ((status = dladm_name2info(dlled_hdl, argv[i], &linkid, NULL, NULL, NULL)) != DLADM_STATUS_OK) { (void) fprintf(stderr, "failed to get link " "id for link %s: %s\n", argv[i], dladm_status2str(status, dlled_dlerrmsg)); return (1); } dlret = dlled_get_led(dlled_hdl, linkid, NULL); if (dlret != DLADM_WALK_CONTINUE) { ret = 1; break; } } } return (ret); } /* * This file and its contents are supplied under the terms of the * Common Development and Distribution License ("CDDL"), version 1.0. * You may only use this file in accordance with the terms of version * 1.0 of the CDDL. * * A full copy of the text of the CDDL should have accompanied this * source. A copy of the CDDL is also available via the Internet at * http://www.illumos.org/license/CDDL. */ /* * Copyright (c) 2018, Joyent, Inc. */ /* * Receive a raw Ethernet frame from dlsend. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dlsend.h" static uint_t dlrecv_sap = DLSEND_SAP; static const char *dlrecv_prog; static void dlrecv_usage(const char *fmt, ...) { if (fmt != NULL) { va_list ap; (void) fprintf(stderr, "%s: ", dlrecv_prog); va_start(ap, fmt); (void) vfprintf(stderr, fmt, ap); va_end(ap); } (void) fprintf(stderr, "Usage: %s [-s sap] device\n" "\t-s sap\tspecify SAP to send on\n", dlrecv_prog); } static boolean_t dlrecv_isvalid(dlsend_msg_t *msg) { uint_t i; boolean_t nul; nul = B_FALSE; for (i = 0; i < sizeof (msg->dm_host); i++) { if (!isprint(msg->dm_host[i]) && msg->dm_host[i] != '\0') { warnx("Encountered bad byte in dm_host[%d]", i); return (B_FALSE); } if (msg->dm_host[i] == '\0') nul = B_TRUE; } if (!nul) { warnx("Missing NUL in dm_host"); return (B_FALSE); } nul = B_FALSE; for (i = 0; i < sizeof (msg->dm_mesg); i++) { if (!isprint(msg->dm_mesg[i]) && msg->dm_mesg[i] != '\0') { warnx("Encountered bad byte in dm_mesg[%d]", i); return (B_FALSE); } if (msg->dm_mesg[i] == '\0') nul = B_TRUE; } if (!nul) { warnx("Missing NUL in dm_mesg"); return (B_FALSE); } if (strcmp(msg->dm_mesg, DLSEND_MSG) != 0) { warnx("Missing expected message (%s)", DLSEND_MSG); return (B_FALSE); } return (B_TRUE); } static void dlrecv_print(dlsend_msg_t *msg, dlpi_recvinfo_t *rinfo, boolean_t invalid) { uint_t i; (void) printf("Received %s from ", invalid ? "invalid message" : "Elbereth"); for (i = 0; i < rinfo->dri_destaddrlen; i++) { (void) printf("%02x", rinfo->dri_destaddr[i]); if (i + 1 != rinfo->dri_destaddrlen) (void) putchar(':'); } if (invalid) { return; } (void) printf(" seq=%" PRIu64 " host=%s\n", betoh64(msg->dm_count), msg->dm_host); } int main(int argc, char *argv[]) { int c, ret; char *eptr; unsigned long sap; uint_t bind_sap; dlpi_handle_t dh; dlrecv_prog = basename(argv[0]); while ((c = getopt(argc, argv, ":s:")) != -1) { switch (c) { case 's': errno = 0; sap = strtoul(optarg, &eptr, 10); if (errno != 0 || sap == 0 || sap >= UINT16_MAX || *eptr != '\0') { dlrecv_usage("Invalid value for sap (-s): %s\n", optarg); return (2); } dlrecv_sap = sap; break; case ':': dlrecv_usage("Option -%c requires an operand\n", optopt); return (2); case '?': dlrecv_usage("Unknown option: -%c\n", optopt); return (2); } } argc -= optind; argv += optind; if (argc != 1) { dlrecv_usage("missing required operands\n"); return (2); } if ((ret = dlpi_open(argv[0], &dh, 0)) != DLPI_SUCCESS) { warnx("failed to open %s: %s", argv[0], dlpi_strerror(ret)); exit(1); } if ((ret = dlpi_bind(dh, dlrecv_sap, &bind_sap)) != DLPI_SUCCESS) { warnx("failed to bind to sap 0x%x: %s", dlrecv_sap, dlpi_strerror(ret)); exit(1); } if (bind_sap != dlrecv_sap) { warnx("failed to bind to requested sap 0x%x, bound to " "0x%x", dlrecv_sap, bind_sap); exit(1); } for (;;) { dlpi_recvinfo_t rinfo; dlsend_msg_t msg; size_t msglen; boolean_t invalid = B_FALSE; msglen = sizeof (msg); ret = dlpi_recv(dh, NULL, NULL, &msg, &msglen, -1, &rinfo); if (ret != DLPI_SUCCESS) { warnx("failed to receive data: %s", dlpi_strerror(ret)); continue; } if (msglen != rinfo.dri_totmsglen) { warnx("message truncated: expected %zu bytes, " "got %zu", sizeof (dlsend_msg_t), rinfo.dri_totmsglen); invalid = B_TRUE; } if (msglen != sizeof (msg)) { warnx("message too short: expected %zu bytes, " "got %zu", sizeof (dlsend_msg_t), msglen); invalid = B_TRUE; } if (!invalid) { invalid = !dlrecv_isvalid(&msg); } dlrecv_print(&msg, &rinfo, invalid); } /* LINTED: E_STMT_NOT_REACHED */ return (0); } /* * This file and its contents are supplied under the terms of the * Common Development and Distribution License ("CDDL"), version 1.0. * You may only use this file in accordance with the terms of version * 1.0 of the CDDL. * * A full copy of the text of the CDDL should have accompanied this * source. A copy of the CDDL is also available via the Internet at * http://www.illumos.org/license/CDDL. */ /* * Copyright (c) 2018, Joyent, Inc. */ /* * Send a raw Ethernet frame once a second to a specified MAC address. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dlsend.h" static uint_t dlsend_sap = DLSEND_SAP; static const char *dlsend_msg = DLSEND_MSG; static const char *dlsend_prog; static void dlsend_usage(const char *fmt, ...) { if (fmt != NULL) { va_list ap; (void) fprintf(stderr, "%s: ", dlsend_prog); va_start(ap, fmt); (void) vfprintf(stderr, fmt, ap); va_end(ap); } (void) fprintf(stderr, "Usage: %s [-s sap] device target-mac\n" "\t-s sap\tspecify SAP to send on\n", dlsend_prog); } int main(int argc, char *argv[]) { int c, maclen, ret; unsigned long sap; char *eptr; uchar_t *mac; char host[MAXHOSTNAMELEN]; uint_t bind_sap; dlpi_handle_t dh; uint64_t count; dlsend_prog = basename(argv[0]); while ((c = getopt(argc, argv, ":s:")) != -1) { switch (c) { case 's': errno = 0; sap = strtoul(optarg, &eptr, 10); if (errno != 0 || sap == 0 || sap >= UINT16_MAX || *eptr != '\0') { dlsend_usage("Invalid value for sap (-s): %s\n", optarg); return (2); } dlsend_sap = sap; break; case ':': dlsend_usage("Option -%c requires an operand\n", optopt); return (2); case '?': dlsend_usage("Unknown option: -%c\n", optopt); return (2); } } argc -= optind; argv += optind; if (argc != 2) { dlsend_usage("missing required operands\n"); return (2); } if ((mac = _link_aton(argv[1], &maclen)) == NULL) { warnx("failed to convert target address %s\n", argv[1]); return (1); } if (gethostname(host, sizeof (host)) != 0) { warnx("failed to obtain the system hostname: %s\n", strerror(errno)); (void) strlcpy(host, "", sizeof (host)); } if ((ret = dlpi_open(argv[0], &dh, 0)) != DLPI_SUCCESS) { warnx("failed to open %s: %s\n", argv[0], dlpi_strerror(ret)); exit(1); } if ((ret = dlpi_bind(dh, dlsend_sap, &bind_sap)) != DLPI_SUCCESS) { warnx("failed to bind to sap 0x%x: %s\n", dlsend_sap, dlpi_strerror(ret)); exit(1); } if (bind_sap != dlsend_sap) { warnx("failed to bind to requested sap 0x%x, bound to " "0x%x\n", dlsend_sap, bind_sap); exit(1); } count = 0; for (;;) { dlsend_msg_t msg; count++; bzero(&msg, sizeof (msg)); msg.dm_count = htobe64(count); (void) strlcpy(msg.dm_host, host, sizeof (msg.dm_host)); (void) strlcpy(msg.dm_mesg, dlsend_msg, sizeof (msg.dm_mesg)); ret = dlpi_send(dh, mac, maclen, &msg, sizeof (msg), NULL); if (ret != DLPI_SUCCESS) { warnx("failed to send message: %s\n", dlpi_strerror(ret)); exit(1); } (void) sleep(1); } /* LINTED: E_STMT_NOT_REACHED */ return (0); } /* * This file and its contents are supplied under the terms of the * Common Development and Distribution License ("CDDL"), version 1.0. * You may only use this file in accordance with the terms of version * 1.0 of the CDDL. * * A full copy of the text of the CDDL should have accompanied this * source. A copy of the CDDL is also available via the Internet at * http://www.illumos.org/license/CDDL. */ /* * Copyright (c) 2017, Joyent, Inc. */ #ifndef _DLSEND_H #define _DLSEND_H /* * A common header file for things that dlsend and dlrecv need. */ #ifdef __cplusplus extern "C" { #endif /* * We need to pick an arbitrary Ethertype to squat on for the purposes of this * testing program. As such we use one with a recongizable string. If someone * comes along and uses this, then we should get off of it. */ #define DLSEND_SAP 0xdeed #define DLSEND_MSG "A Elbereth Gilthoniel" typedef struct dlsend_msg { uint64_t dm_count; char dm_host[MAXHOSTNAMELEN]; char dm_mesg[32]; } dlsend_msg_t; #ifdef __cplusplus } #endif #endif /* _DLSEND_H */ /* * This file and its contents are supplied under the terms of the * Common Development and Distribution License ("CDDL"), version 1.0. * You may only use this file in accordance with the terms of version * 1.0 of the CDDL. * * A full copy of the text of the CDDL should have accompanied this * source. A copy of the CDDL is also available via the Internet at * http://www.illumos.org/license/CDDL. */ /* * Copyright (c) 2017, Joyent, Inc. * Copyright 2024 Oxide Computer Company */ /* * Private utility to dump transceiver information for each physical datalink. * Something like this should eventually be a part of dladm or similar. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DLTRAN_KIND_LEN 64 static dladm_handle_t dltran_hdl; static char dltran_dlerrmsg[DLADM_STRSIZE]; static const char *dltran_progname; static boolean_t dltran_verbose; static boolean_t dltran_hex; static boolean_t dltran_write; static int dltran_outfd; static int dltran_errors; /* * This routine basically assumes that we'll have 16 byte aligned output to * print out the human readable output. */ static int dltran_dump_page_cb(void *arg, uint64_t addr, const char *buf, size_t len __unused) { uint_t page = (uint_t)(uintptr_t)arg; int ret; if (addr == UINT64_MAX) { /* Header row */ ret = printf("page %s\n", buf); } else { ret = printf("0x%02x %s\n", page, buf); } return (ret < 0 ? -1 : 0); } static void dltran_dump_page(uint8_t *buf, size_t nbytes, uint_t page) { static boolean_t first = B_TRUE; hexdump_flag_t flags = HDF_DEFAULT; if (first) first = B_FALSE; else flags &= ~HDF_HEADER; (void) hexdump(buf, nbytes, flags, dltran_dump_page_cb, (void *)(uintptr_t)page); } static int dltran_read_page(datalink_id_t link, uint_t tranid, uint_t page, uint8_t *bufp, size_t *buflen) { dld_ioc_tranio_t dti; bzero(bufp, *buflen); bzero(&dti, sizeof (dti)); dti.dti_linkid = link; dti.dti_tran_id = tranid; dti.dti_page = page; dti.dti_nbytes = *buflen; dti.dti_off = 0; dti.dti_buf = (uintptr_t)(void *)bufp; if (ioctl(dladm_dld_fd(dltran_hdl), DLDIOC_READTRAN, &dti) != 0) { (void) fprintf(stderr, "failed to read transceiver page " "0x%2x: %s\n", page, strerror(errno)); return (1); } *buflen = dti.dti_nbytes; return (0); } static boolean_t dltran_is_8472(uint8_t *buf) { switch (buf[0]) { case 0xc: case 0xd: case 0x11: /* * Catch cases that refer explicitly to QSFP and newer. */ return (B_FALSE); default: break; } /* * Check the byte that indicates compliance with SFF 8472. Use this to * know if we can read page 0xa2 or not. */ if (buf[94] == 0) return (B_FALSE); return (B_TRUE); } static void dltran_hex_dump(datalink_id_t linkid, uint_t tranid) { uint8_t buf[256]; size_t buflen = sizeof (buf); if (dltran_read_page(linkid, tranid, 0xa0, buf, &buflen) != 0) { dltran_errors++; return; } dltran_dump_page(buf, buflen, 0xa0); if (!dltran_is_8472(buf)) { return; } buflen = sizeof (buf); if (dltran_read_page(linkid, tranid, 0xa2, buf, &buflen) != 0) { dltran_errors++; return; } dltran_dump_page(buf, buflen, 0xa2); } static void dltran_write_page(datalink_id_t linkid, uint_t tranid) { uint8_t buf[256]; size_t buflen = sizeof (buf); off_t off; if (dltran_read_page(linkid, tranid, 0xa0, buf, &buflen) != 0) { dltran_errors++; return; } off = 0; while (buflen > 0) { ssize_t ret; ret = write(dltran_outfd, buf + off, buflen); if (ret == -1) { (void) fprintf(stderr, "failed to write data " "to output file: %s\n", strerror(errno)); dltran_errors++; return; } off += ret; buflen -= ret; } } static void dltran_verbose_dump(datalink_id_t linkid, uint_t tranid) { uint8_t buf[256]; size_t buflen = sizeof (buf); int ret; nvlist_t *nvl; if (dltran_read_page(linkid, tranid, 0xa0, buf, &buflen) != 0) { dltran_errors++; return; } ret = libsff_parse(buf, buflen, 0xa0, &nvl); if (ret == 0) { dump_nvlist(nvl, 8); nvlist_free(nvl); } else { fprintf(stderr, "failed to parse sfp data: %s\n", strerror(ret)); dltran_errors++; } } static int dltran_dump_transceivers(dladm_handle_t hdl, datalink_id_t linkid, void *arg) { dladm_status_t status; char name[MAXLINKNAMELEN]; dld_ioc_gettran_t gt; uint_t count, i, tranid = UINT_MAX; boolean_t tran_found = B_FALSE; uint_t *tranidp = arg; if (tranidp != NULL) tranid = *tranidp; if ((status = dladm_datalink_id2info(hdl, linkid, NULL, NULL, NULL, name, sizeof (name))) != DLADM_STATUS_OK) { (void) fprintf(stderr, "failed to get datalink name for link " "%d: %s", linkid, dladm_status2str(status, dltran_dlerrmsg)); dltran_errors++; return (DLADM_WALK_CONTINUE); } bzero(>, sizeof (gt)); gt.dgt_linkid = linkid; gt.dgt_tran_id = DLDIOC_GETTRAN_GETNTRAN; if (ioctl(dladm_dld_fd(hdl), DLDIOC_GETTRAN, >) != 0) { if (errno != ENOTSUP) { (void) fprintf(stderr, "failed to get transceiver " "count for device %s: %s\n", name, strerror(errno)); dltran_errors++; } return (DLADM_WALK_CONTINUE); } count = gt.dgt_tran_id; (void) printf("%s: discovered %d transceiver%s\n", name, count, count > 1 ? "s" : ""); for (i = 0; i < count; i++) { if (tranid != UINT_MAX && i != tranid) continue; if (tranid != UINT_MAX) tran_found = B_TRUE; bzero(>, sizeof (gt)); gt.dgt_linkid = linkid; gt.dgt_tran_id = i; if (ioctl(dladm_dld_fd(hdl), DLDIOC_GETTRAN, >) != 0) { (void) fprintf(stderr, "failed to get tran info for " "%s: %s\n", name, strerror(errno)); dltran_errors++; return (DLADM_WALK_CONTINUE); } if (dltran_hex && !gt.dgt_present) continue; if (!dltran_hex && !dltran_write) { (void) printf("\ttransceiver %d present: %s\n", i, gt.dgt_present ? "yes" : "no"); if (!gt.dgt_present) continue; (void) printf("\ttransceiver %d usable: %s\n", i, gt.dgt_usable ? "yes" : "no"); } if (dltran_verbose) { dltran_verbose_dump(linkid, i); } if (dltran_write) { if (!gt.dgt_present) { (void) fprintf(stderr, "warning: no " "transceiver present in port %d, not " "writing\n", i); dltran_errors++; continue; } dltran_write_page(linkid, i); } if (dltran_hex) { printf("transceiver %d data:\n", i); dltran_hex_dump(linkid, i); } } if (tranid != UINT_MAX && !tran_found) { dltran_errors++; (void) fprintf(stderr, "failed to find transceiver %d on " "link %s\n", tranid, name); } return (DLADM_WALK_CONTINUE); } static void dltran_usage(const char *fmt, ...) { if (fmt != NULL) { va_list ap; (void) fprintf(stderr, "%s: ", dltran_progname); va_start(ap, fmt); (void) vfprintf(stderr, fmt, ap); va_end(ap); } (void) fprintf(stderr, "Usage: %s [-x | -v | -w file] [tran]...\n" "\n" "\t-v display all transceiver information\n" "\t-w write transceiver data page 0xa0 to file\n" "\t-x dump raw hexadecimal for transceiver\n", dltran_progname); } int main(int argc, char *argv[]) { int c; dladm_status_t status; const char *outfile = NULL; uint_t count = 0; dltran_progname = basename(argv[0]); while ((c = getopt(argc, argv, ":xvw:")) != -1) { switch (c) { case 'v': dltran_verbose = B_TRUE; break; case 'x': dltran_hex = B_TRUE; break; case 'w': dltran_write = B_TRUE; outfile = optarg; break; case ':': dltran_usage("option -%c requires an " "operand\n", optopt); return (2); case '?': default: dltran_usage("unknown option: -%c\n", optopt); return (2); } } argc -= optind; argv += optind; if (dltran_verbose) count++; if (dltran_hex) count++; if (dltran_write) count++; if (count > 1) { (void) fprintf(stderr, "only one of -v, -w, and -x may be " "specified\n"); return (2); } if (dltran_write) { if ((dltran_outfd = open(outfile, O_RDWR | O_TRUNC | O_CREAT, 0644)) < 0) { (void) fprintf(stderr, "failed to open output file " "%s: %s\n", outfile, strerror(errno)); return (1); } } if ((status = dladm_open(&dltran_hdl)) != DLADM_STATUS_OK) { (void) fprintf(stderr, "failed to open /dev/dld: %s\n", dladm_status2str(status, dltran_dlerrmsg)); return (1); } if (argc == 0) { (void) dladm_walk_datalink_id(dltran_dump_transceivers, dltran_hdl, NULL, DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE); } else { int i; char *c; for (i = 0; i < argc; i++) { uint_t tran; uint_t *tranidp = NULL; datalink_id_t linkid; if ((c = strrchr(argv[i], '/')) != NULL) { unsigned long u; char *eptr; c++; errno = 0; u = strtoul(c, &eptr, 10); if (errno != 0 || *eptr != '\0' || u >= UINT_MAX) { (void) fprintf(stderr, "failed to " "parse link/transceiver: %s\n", argv[i]); return (1); } c--; *c = '\0'; tran = (uint_t)u; tranidp = &tran; } if ((status = dladm_name2info(dltran_hdl, argv[i], &linkid, NULL, NULL, NULL)) != DLADM_STATUS_OK) { (void) fprintf(stderr, "failed to get link " "id for link %s: %s\n", argv[i], dladm_status2str(status, dltran_dlerrmsg)); return (1); } (void) dltran_dump_transceivers(dltran_hdl, linkid, tranidp); } } return (dltran_errors != 0 ? 1 : 0); }