/** * @file hwstamp_ctl.c * @brief Utility program to set time stamping policy at the driver level. * @note Copyright (C) 2012 Richard Cochran * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include #include #include #include #include #include "version.h" #include "missing.h" static void usage(char *progname) { fprintf(stderr, "\n" "usage: %s [options]\n\n" " -h prints this message and exits\n" " -i [device] interface device to use, for example 'eth0'\n" " -r [%d..%d] select receive time stamping:\n" "\t\t%2d time stamp no incoming packet at all\n" "\t\t%2d time stamp any incoming packet\n" "\t\t%2d (reserved value)\n" "\t\t%2d PTP v1, UDP, any kind of event packet\n" "\t\t%2d PTP v1, UDP, Sync packet\n" "\t\t%2d PTP v1, UDP, Delay_req packet\n" "\t\t%2d PTP v2, UDP, any kind of event packet\n" "\t\t%2d PTP v2, UDP, Sync packet\n" "\t\t%2d PTP v2, UDP, Delay_req packet\n" "\t\t%2d 802.AS1, Ethernet, any kind of event packet\n" "\t\t%2d 802.AS1, Ethernet, Sync packet\n" "\t\t%2d 802.AS1, Ethernet, Delay_req packet\n" "\t\t%2d PTP v2/802.AS1, any layer, any kind of event packet\n" "\t\t%2d PTP v2/802.AS1, any layer, Sync packet\n" "\t\t%2d PTP v2/802.AS1, any layer, Delay_req packet\n" " -t [%d|%d] disable or enable transmit time stamping\n" " -v prints the software version and exits\n" "\n", progname, HWTSTAMP_FILTER_NONE, HWTSTAMP_FILTER_PTP_V2_DELAY_REQ, HWTSTAMP_FILTER_NONE, HWTSTAMP_FILTER_ALL, HWTSTAMP_FILTER_SOME, HWTSTAMP_FILTER_PTP_V1_L4_EVENT, HWTSTAMP_FILTER_PTP_V1_L4_SYNC, HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ, HWTSTAMP_FILTER_PTP_V2_L4_EVENT, HWTSTAMP_FILTER_PTP_V2_L4_SYNC, HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ, HWTSTAMP_FILTER_PTP_V2_L2_EVENT, HWTSTAMP_FILTER_PTP_V2_L2_SYNC, HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ, HWTSTAMP_FILTER_PTP_V2_EVENT, HWTSTAMP_FILTER_PTP_V2_SYNC, HWTSTAMP_FILTER_PTP_V2_DELAY_REQ, HWTSTAMP_TX_OFF, HWTSTAMP_TX_ON); } int main(int argc, char *argv[]) { struct ifreq ifreq; struct hwtstamp_config cfg; char *device = NULL, *progname; int c, err, fd, rxopt = HWTSTAMP_FILTER_NONE, txopt = HWTSTAMP_TX_OFF; int setrx = 0, settx = 0; /* Process the command line arguments. */ progname = strrchr(argv[0], '/'); progname = progname ? 1+progname : argv[0]; while (EOF != (c = getopt(argc, argv, "hi:r:t:v"))) { switch (c) { case 'i': device = optarg; break; case 'r': setrx = 1; rxopt = atoi(optarg); break; case 't': settx = 1; txopt = atoi(optarg); break; case 'v': version_show(stdout); return 0; case 'h': usage(progname); return 0; case '?': default: usage(progname); return -1; } } if (!device) { usage(progname); return -1; } if (rxopt < HWTSTAMP_FILTER_NONE || rxopt > HWTSTAMP_FILTER_PTP_V2_DELAY_REQ || txopt < HWTSTAMP_TX_OFF || txopt > HWTSTAMP_TX_ON) { usage(progname); return -1; } memset(&ifreq, 0, sizeof(ifreq)); memset(&cfg, 0, sizeof(cfg)); strncpy(ifreq.ifr_name, device, sizeof(ifreq.ifr_name) - 1); ifreq.ifr_data = (void *) &cfg; fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); if (fd < 0) { perror("socket"); return -1; } /* First, attempt to get the current settings. */ err = ioctl(fd, SIOCGHWTSTAMP, &ifreq); if (err < 0) { err = errno; if (err == ENOTTY) fprintf(stderr, "Kernel does not have support " "for non-destructive SIOCGHWTSTAMP.\n"); else if (err == EOPNOTSUPP) fprintf(stderr, "Device driver does not have support " "for non-destructive SIOCGHWTSTAMP.\n"); else perror("SIOCGHWTSTAMP failed"); } else { printf("current settings:\n" "tx_type %d\n" "rx_filter %d\n", cfg.tx_type, cfg.rx_filter); } /* Now, attempt to set values. Only change the values actually * requested by user, rather than blindly resetting th zero if * unrequested. */ if (settx || setrx) { if (settx) cfg.tx_type = txopt; if (setrx) cfg.rx_filter = rxopt; err = ioctl(fd, SIOCSHWTSTAMP, &ifreq); if (err < 0) { err = errno; perror("SIOCSHWTSTAMP failed"); if (err == ERANGE) fprintf(stderr, "The requested time stamping mode is " "not supported by the hardware.\n"); } else { printf("new settings:\n" "tx_type %d\n" "rx_filter %d\n", cfg.tx_type, cfg.rx_filter); } } return err; }