Ben Hutchings | a4bcc79 | 2013-11-22 20:10:24 +0000 | [diff] [blame] | 1 | /* Test program for SIOC{G,S}HWTSTAMP |
| 2 | * Copyright 2013 Solarflare Communications |
| 3 | * Author: Ben Hutchings |
| 4 | */ |
| 5 | |
| 6 | #include <errno.h> |
| 7 | #include <stdio.h> |
| 8 | #include <stdlib.h> |
| 9 | #include <string.h> |
| 10 | |
| 11 | #include <sys/socket.h> |
| 12 | #include <sys/ioctl.h> |
| 13 | |
| 14 | #include <linux/if.h> |
| 15 | #include <linux/net_tstamp.h> |
| 16 | #include <linux/sockios.h> |
| 17 | |
| 18 | static int |
| 19 | lookup_value(const char **names, int size, const char *name) |
| 20 | { |
| 21 | int value; |
| 22 | |
| 23 | for (value = 0; value < size; value++) |
| 24 | if (names[value] && strcasecmp(names[value], name) == 0) |
| 25 | return value; |
| 26 | |
| 27 | return -1; |
| 28 | } |
| 29 | |
| 30 | static const char * |
| 31 | lookup_name(const char **names, int size, int value) |
| 32 | { |
| 33 | return (value >= 0 && value < size) ? names[value] : NULL; |
| 34 | } |
| 35 | |
| 36 | static void list_names(FILE *f, const char **names, int size) |
| 37 | { |
| 38 | int value; |
| 39 | |
| 40 | for (value = 0; value < size; value++) |
| 41 | if (names[value]) |
| 42 | fprintf(f, " %s\n", names[value]); |
| 43 | } |
| 44 | |
| 45 | static const char *tx_types[] = { |
| 46 | #define TX_TYPE(name) [HWTSTAMP_TX_ ## name] = #name |
| 47 | TX_TYPE(OFF), |
| 48 | TX_TYPE(ON), |
| 49 | TX_TYPE(ONESTEP_SYNC) |
| 50 | #undef TX_TYPE |
| 51 | }; |
| 52 | #define N_TX_TYPES ((int)(sizeof(tx_types) / sizeof(tx_types[0]))) |
| 53 | |
| 54 | static const char *rx_filters[] = { |
| 55 | #define RX_FILTER(name) [HWTSTAMP_FILTER_ ## name] = #name |
| 56 | RX_FILTER(NONE), |
| 57 | RX_FILTER(ALL), |
| 58 | RX_FILTER(SOME), |
| 59 | RX_FILTER(PTP_V1_L4_EVENT), |
| 60 | RX_FILTER(PTP_V1_L4_SYNC), |
| 61 | RX_FILTER(PTP_V1_L4_DELAY_REQ), |
| 62 | RX_FILTER(PTP_V2_L4_EVENT), |
| 63 | RX_FILTER(PTP_V2_L4_SYNC), |
| 64 | RX_FILTER(PTP_V2_L4_DELAY_REQ), |
| 65 | RX_FILTER(PTP_V2_L2_EVENT), |
| 66 | RX_FILTER(PTP_V2_L2_SYNC), |
| 67 | RX_FILTER(PTP_V2_L2_DELAY_REQ), |
| 68 | RX_FILTER(PTP_V2_EVENT), |
| 69 | RX_FILTER(PTP_V2_SYNC), |
| 70 | RX_FILTER(PTP_V2_DELAY_REQ), |
| 71 | #undef RX_FILTER |
| 72 | }; |
| 73 | #define N_RX_FILTERS ((int)(sizeof(rx_filters) / sizeof(rx_filters[0]))) |
| 74 | |
| 75 | static void usage(void) |
| 76 | { |
| 77 | fputs("Usage: hwtstamp_config if_name [tx_type rx_filter]\n" |
| 78 | "tx_type is any of (case-insensitive):\n", |
| 79 | stderr); |
| 80 | list_names(stderr, tx_types, N_TX_TYPES); |
| 81 | fputs("rx_filter is any of (case-insensitive):\n", stderr); |
| 82 | list_names(stderr, rx_filters, N_RX_FILTERS); |
| 83 | } |
| 84 | |
| 85 | int main(int argc, char **argv) |
| 86 | { |
| 87 | struct ifreq ifr; |
| 88 | struct hwtstamp_config config; |
| 89 | const char *name; |
| 90 | int sock; |
| 91 | |
| 92 | if ((argc != 2 && argc != 4) || (strlen(argv[1]) >= IFNAMSIZ)) { |
| 93 | usage(); |
| 94 | return 2; |
| 95 | } |
| 96 | |
| 97 | if (argc == 4) { |
| 98 | config.flags = 0; |
| 99 | config.tx_type = lookup_value(tx_types, N_TX_TYPES, argv[2]); |
| 100 | config.rx_filter = lookup_value(rx_filters, N_RX_FILTERS, argv[3]); |
| 101 | if (config.tx_type < 0 || config.rx_filter < 0) { |
| 102 | usage(); |
| 103 | return 2; |
| 104 | } |
| 105 | } |
| 106 | |
| 107 | sock = socket(AF_INET, SOCK_DGRAM, 0); |
| 108 | if (sock < 0) { |
| 109 | perror("socket"); |
| 110 | return 1; |
| 111 | } |
| 112 | |
| 113 | strcpy(ifr.ifr_name, argv[1]); |
| 114 | ifr.ifr_data = (caddr_t)&config; |
| 115 | |
| 116 | if (ioctl(sock, (argc == 2) ? SIOCGHWTSTAMP : SIOCSHWTSTAMP, &ifr)) { |
| 117 | perror("ioctl"); |
| 118 | return 1; |
| 119 | } |
| 120 | |
| 121 | printf("flags = %#x\n", config.flags); |
| 122 | name = lookup_name(tx_types, N_TX_TYPES, config.tx_type); |
| 123 | if (name) |
| 124 | printf("tx_type = %s\n", name); |
| 125 | else |
| 126 | printf("tx_type = %d\n", config.tx_type); |
| 127 | name = lookup_name(rx_filters, N_RX_FILTERS, config.rx_filter); |
| 128 | if (name) |
| 129 | printf("rx_filter = %s\n", name); |
| 130 | else |
| 131 | printf("rx_filter = %d\n", config.rx_filter); |
| 132 | |
| 133 | return 0; |
| 134 | } |