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