aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/tools/testing/selftests/networking/timestamping/hwtstamp_config.c
blob: e1fdee84102119175390a727f80039802d6d9b16 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// SPDX-License-Identifier: GPL-2.0
/* Test program for SIOC{G,S}HWTSTAMP
 * Copyright 2013 Solarflare Communications
 * Author: Ben Hutchings
 */

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sys/socket.h>
#include <sys/ioctl.h>

#include <linux/if.h>
#include <linux/net_tstamp.h>
#include <linux/sockios.h>

static int
lookup_value(const char **names, int size, const char *name)
{
	int value;

	for (value = 0; value < size; value++)
		if (names[value] && strcasecmp(names[value], name) == 0)
			return value;

	return -1;
}

static const char *
lookup_name(const char **names, int size, int value)
{
	return (value >= 0 && value < size) ? names[value] : NULL;
}

static void list_names(FILE *f, const char **names, int size)
{
	int value;

	for (value = 0; value < size; value++)
		if (names[value])
			fprintf(f, "    %s\n", names[value]);
}

static const char *tx_types[] = {
#define TX_TYPE(name) [HWTSTAMP_TX_ ## name] = #name
	TX_TYPE(OFF),
	TX_TYPE(ON),
	TX_TYPE(ONESTEP_SYNC)
#undef TX_TYPE
};
#define N_TX_TYPES ((int)(sizeof(tx_types) / sizeof(tx_types[0])))

static const char *rx_filters[] = {
#define RX_FILTER(name) [HWTSTAMP_FILTER_ ## name] = #name
	RX_FILTER(NONE),
	RX_FILTER(ALL),
	RX_FILTER(SOME),
	RX_FILTER(PTP_V1_L4_EVENT),
	RX_FILTER(PTP_V1_L4_SYNC),
	RX_FILTER(PTP_V1_L4_DELAY_REQ),
	RX_FILTER(PTP_V2_L4_EVENT),
	RX_FILTER(PTP_V2_L4_SYNC),
	RX_FILTER(PTP_V2_L4_DELAY_REQ),
	RX_FILTER(PTP_V2_L2_EVENT),
	RX_FILTER(PTP_V2_L2_SYNC),
	RX_FILTER(PTP_V2_L2_DELAY_REQ),
	RX_FILTER(PTP_V2_EVENT),
	RX_FILTER(PTP_V2_SYNC),
	RX_FILTER(PTP_V2_DELAY_REQ),
#undef RX_FILTER
};
#define N_RX_FILTERS ((int)(sizeof(rx_filters) / sizeof(rx_filters[0])))

static void usage(void)
{
	fputs("Usage: hwtstamp_config if_name [tx_type rx_filter]\n"
	      "tx_type is any of (case-insensitive):\n",
	      stderr);
	list_names(stderr, tx_types, N_TX_TYPES);
	fputs("rx_filter is any of (case-insensitive):\n", stderr);
	list_names(stderr, rx_filters, N_RX_FILTERS);
}

int main(int argc, char **argv)
{
	struct ifreq ifr;
	struct hwtstamp_config config;
	const char *name;
	int sock;

	if ((argc != 2 && argc != 4) || (strlen(argv[1]) >= IFNAMSIZ)) {
		usage();
		return 2;
	}

	if (argc == 4) {
		config.flags = 0;
		config.tx_type = lookup_value(tx_types, N_TX_TYPES, argv[2]);
		config.rx_filter = lookup_value(rx_filters, N_RX_FILTERS, argv[3]);
		if (config.tx_type < 0 || config.rx_filter < 0) {
			usage();
			return 2;
		}
	}

	sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock < 0) {
		perror("socket");
		return 1;
	}

	strcpy(ifr.ifr_name, argv[1]);
	ifr.ifr_data = (caddr_t)&config;

	if (ioctl(sock, (argc == 2) ? SIOCGHWTSTAMP : SIOCSHWTSTAMP, &ifr)) {
		perror("ioctl");
		return 1;
	}

	printf("flags = %#x\n", config.flags);
	name = lookup_name(tx_types, N_TX_TYPES, config.tx_type);
	if (name)
		printf("tx_type = %s\n", name);
	else
		printf("tx_type = %d\n", config.tx_type);
	name = lookup_name(rx_filters, N_RX_FILTERS, config.rx_filter);
	if (name)
		printf("rx_filter = %s\n", name);
	else
		printf("rx_filter = %d\n", config.rx_filter);

	return 0;
}