aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--utils/cec-compliance/Makefile.am2
-rw-r--r--utils/cec-compliance/cec-compliance.1.in4
-rw-r--r--utils/cec-compliance/cec-compliance.cpp15
-rw-r--r--utils/cec-compliance/cec-compliance.h8
-rw-r--r--utils/cec-compliance/cec-test-fuzzing.cpp116
5 files changed, 142 insertions, 3 deletions
diff --git a/utils/cec-compliance/Makefile.am b/utils/cec-compliance/Makefile.am
index 0c18a9ab..958b2f9d 100644
--- a/utils/cec-compliance/Makefile.am
+++ b/utils/cec-compliance/Makefile.am
@@ -1,7 +1,7 @@
bin_PROGRAMS = cec-compliance
man_MANS = cec-compliance.1
-cec_compliance_SOURCES = cec-compliance.cpp cec-compliance.h cec-test.cpp cec-test-adapter.cpp cec-test-audio.cpp cec-test-power.cpp cec-info.cpp
+cec_compliance_SOURCES = cec-compliance.cpp cec-compliance.h cec-test.cpp cec-test-adapter.cpp cec-test-audio.cpp cec-test-power.cpp cec-test-fuzzing.cpp cec-info.cpp
cec_compliance_CPPFLAGS = -I$(top_srcdir)/utils/common
cec_compliance_LDFLAGS = -lrt
diff --git a/utils/cec-compliance/cec-compliance.1.in b/utils/cec-compliance/cec-compliance.1.in
index fa96fb01..0f4ebf44 100644
--- a/utils/cec-compliance/cec-compliance.1.in
+++ b/utils/cec-compliance/cec-compliance.1.in
@@ -129,6 +129,10 @@ Set the standby/resume timeout to the given number of seconds. Default is 60s.
\fB\-A\fR, \fB\-\-test\-adapter\fR
Test the CEC adapter API
.TP
+\fB\-F\fR, \fB\-\-test\-fuzzing\fR
+Test the remote CEC adapter by randomly creating CEC messages.
+This runs forever until an error occurs.
+.TP
\fB\-\-test\-core\fR
Test the core functionality
.TP
diff --git a/utils/cec-compliance/cec-compliance.cpp b/utils/cec-compliance/cec-compliance.cpp
index 756d8dbf..faaaa432 100644
--- a/utils/cec-compliance/cec-compliance.cpp
+++ b/utils/cec-compliance/cec-compliance.cpp
@@ -40,6 +40,7 @@ enum Option {
OptSetDevice = 'd',
OptSetDriver = 'D',
OptExitOnFail = 'E',
+ OptTestFuzzing = 'F',
OptHelp = 'h',
OptInteractive = 'i',
OptNoWarnings = 'n',
@@ -129,6 +130,7 @@ static struct option long_options[] = {
{"reply-threshold", required_argument, 0, OptReplyThreshold},
{"test-adapter", no_argument, 0, OptTestAdapter},
+ {"test-fuzzing", no_argument, 0, OptTestFuzzing},
{"test-core", no_argument, 0, OptTestCore},
{"test-audio-rate-control", no_argument, 0, OptTestAudioRateControl},
{"test-audio-return-channel-control", no_argument, 0, OptTestARCControl},
@@ -186,6 +188,7 @@ static void usage(void)
" -t, --timeout <secs> Set the standby/resume timeout to <secs>. Default is 60s.\n"
"\n"
" -A, --test-adapter Test the CEC adapter API\n"
+ " -F, --test-fuzzing Test by fuzzing CEC messages\n"
" --test-core Test the core functionality\n"
"\n"
"By changing --test to --skip-test in the following options you can skip tests\n"
@@ -586,6 +589,15 @@ const char *cdc_errcode2s(__u8 cdc_errcode)
}
}
+const char *opcode2s(__u8 opcode)
+{
+ for (unsigned i = 0; i < ARRAY_SIZE(msgtable); i++) {
+ if (msgtable[i].opcode == opcode)
+ return msgtable[i].name;
+ }
+ return NULL;
+}
+
std::string opcode2s(const struct cec_msg *msg)
{
std::stringstream oss;
@@ -1399,6 +1411,9 @@ int main(int argc, char **argv)
topology_probe_device(&node, i, node.log_addr[0]);
printf("\n");
+ if (options[OptTestFuzzing] && remote_la >= 0)
+ exit(testFuzzing(node, laddrs.log_addr[0], remote_la));
+
unsigned remote_la_mask = node.remote_la_mask;
if (remote_la >= 0)
diff --git a/utils/cec-compliance/cec-compliance.h b/utils/cec-compliance/cec-compliance.h
index 023c34d4..9468f535 100644
--- a/utils/cec-compliance/cec-compliance.h
+++ b/utils/cec-compliance/cec-compliance.h
@@ -297,6 +297,7 @@ int cec_named_ioctl(struct node *node, const char *name,
#define doioctl(n, r, p) cec_named_ioctl(n, #r, r, p)
+const char *opcode2s(__u8 opcode);
std::string opcode2s(const struct cec_msg *msg);
static inline bool is_tv(unsigned la, unsigned prim_type)
@@ -400,6 +401,9 @@ int testLostMsgs(struct node *node);
void testAdapter(struct node &node, struct cec_log_addrs &laddrs,
const char *device);
+// CEC fuzzing test
+int testFuzzing(struct node &node, unsigned me, unsigned la);
+
// CEC core tests
int testCore(struct node *node);
int core_unknown(struct node *node, unsigned me, unsigned la, bool interactive);
@@ -419,7 +423,7 @@ int testProcessing(struct node *node, unsigned me);
void testRemote(struct node *node, unsigned me, unsigned la, unsigned test_tags,
bool interactive);
-// cec-audio.cpp
+// cec-test-audio.cpp
extern struct remote_subtest sac_subtests[];
extern const unsigned sac_subtests_size;
extern struct remote_subtest dal_subtests[];
@@ -429,7 +433,7 @@ extern const unsigned arc_subtests_size;
extern struct remote_subtest audio_rate_ctl_subtests[];
extern const unsigned audio_rate_ctl_subtests_size;
-// cec-power.cpp
+// cec-test-power.cpp
bool util_interactive_ensure_power_state(struct node *node, unsigned me, unsigned la, bool interactive,
__u8 target_pwr);
extern struct remote_subtest standby_subtests[];
diff --git a/utils/cec-compliance/cec-test-fuzzing.cpp b/utils/cec-compliance/cec-test-fuzzing.cpp
new file mode 100644
index 00000000..fe3c8f21
--- /dev/null
+++ b/utils/cec-compliance/cec-test-fuzzing.cpp
@@ -0,0 +1,116 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <config.h>
+#include <sstream>
+
+#include "cec-compliance.h"
+
+int testFuzzing(struct node &node, unsigned me, unsigned la)
+{
+ printf("test fuzzing CEC local LA %d (%s) to remote LA %d (%s):\n\n",
+ me, la2s(me), la, la2s(la));
+
+ if (node.remote[la].in_standby) {
+ announce("The remote device is in standby. It should be powered on when fuzzing. Aborting.");
+ return 0;
+ }
+ if (!node.remote[la].has_power_status) {
+ announce("The device didn't support Give Device Power Status.");
+ announce("Assuming that the device is powered on.");
+ }
+
+ unsigned int cnt = 0;
+
+ for (;;) {
+ cec_msg msg;
+ __u8 cmd;
+ unsigned offset = 2;
+
+ cec_msg_init(&msg, me, la);
+ msg.msg[1] = cmd = random() & 0xff;
+ if (msg.msg[1] == CEC_MSG_STANDBY)
+ continue;
+ msg.len = (random() & 0xf) + 2;
+ if (msg.msg[1] == CEC_MSG_VENDOR_COMMAND_WITH_ID &&
+ node.remote[la].vendor_id != CEC_VENDOR_ID_NONE) {
+ msg.len += 3;
+ offset += 3;
+ msg.msg[2] = (node.remote[la].vendor_id & 0xff0000) >> 16;
+ msg.msg[3] = (node.remote[la].vendor_id & 0xff00) >> 8;
+ msg.msg[4] = node.remote[la].vendor_id & 0xff;
+ }
+ if (msg.len > CEC_MAX_MSG_SIZE)
+ continue;
+
+ const char *name = opcode2s(msg.msg[1]);
+
+ printf("Send message %u:", cnt);
+ for (unsigned int i = 0; i < offset; i++)
+ printf(" %02x", msg.msg[i]);
+ for (unsigned int i = offset; i < msg.len; i++) {
+ msg.msg[i] = random() & 0xff;
+ printf(" %02x", msg.msg[i]);
+ }
+ if (name)
+ printf(" (%s)", name);
+ printf(": ");
+ msg.reply = CEC_MSG_FEATURE_ABORT;
+ fail_on_test(!transmit_timeout(&node, &msg, 1200));
+ printf("%s", timed_out(&msg) ? "Timed out" : "Feature Abort");
+
+ if (cec_msg_status_is_abort(&msg)) {
+ __u8 abort_msg, reason;
+
+ cec_ops_feature_abort(&msg, &abort_msg, &reason);
+ fail_on_test(abort_msg != cmd);
+ switch (reason) {
+ case CEC_OP_ABORT_UNRECOGNIZED_OP:
+ printf(" (Unrecognized Op)");
+ break;
+ case CEC_OP_ABORT_UNDETERMINED:
+ printf(" (Undetermined)");
+ break;
+ case CEC_OP_ABORT_INVALID_OP:
+ printf(" (Invalid Op)");
+ break;
+ case CEC_OP_ABORT_NO_SOURCE:
+ printf(" (No Source)");
+ break;
+ case CEC_OP_ABORT_REFUSED:
+ printf(" (Refused)");
+ break;
+ case CEC_OP_ABORT_INCORRECT_MODE:
+ printf(" (Incorrect Mode)");
+ break;
+ default:
+ printf(" (0x%02x)\n", reason);
+ fail("Invalid reason\n");
+ break;
+ }
+ }
+ printf("\n");
+ if (++cnt % 10)
+ continue;
+ if (la == CEC_LOG_ADDR_BROADCAST)
+ continue;
+ cec_msg_init(&msg, me, la);
+ cec_msg_get_cec_version(&msg, true);
+ printf("Query CEC Version: ");
+ fail_on_test(!transmit_timeout(&node, &msg) || timed_out_or_abort(&msg));
+ printf("OK\n");
+ }
+}

Privacy Policy