18c2ecf20Sopenharmony_ci/* valid adjtimex test
28c2ecf20Sopenharmony_ci *              by: John Stultz <john.stultz@linaro.org>
38c2ecf20Sopenharmony_ci *              (C) Copyright Linaro 2015
48c2ecf20Sopenharmony_ci *              Licensed under the GPLv2
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci *  This test validates adjtimex interface with valid
78c2ecf20Sopenharmony_ci *  and invalid test data.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci *  Usage: valid-adjtimex
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci *  To build:
128c2ecf20Sopenharmony_ci *	$ gcc valid-adjtimex.c -o valid-adjtimex -lrt
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci *   This program is free software: you can redistribute it and/or modify
158c2ecf20Sopenharmony_ci *   it under the terms of the GNU General Public License as published by
168c2ecf20Sopenharmony_ci *   the Free Software Foundation, either version 2 of the License, or
178c2ecf20Sopenharmony_ci *   (at your option) any later version.
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci *   This program is distributed in the hope that it will be useful,
208c2ecf20Sopenharmony_ci *   but WITHOUT ANY WARRANTY; without even the implied warranty of
218c2ecf20Sopenharmony_ci *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
228c2ecf20Sopenharmony_ci *   GNU General Public License for more details.
238c2ecf20Sopenharmony_ci */
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#include <stdio.h>
288c2ecf20Sopenharmony_ci#include <stdlib.h>
298c2ecf20Sopenharmony_ci#include <time.h>
308c2ecf20Sopenharmony_ci#include <sys/time.h>
318c2ecf20Sopenharmony_ci#include <sys/timex.h>
328c2ecf20Sopenharmony_ci#include <string.h>
338c2ecf20Sopenharmony_ci#include <signal.h>
348c2ecf20Sopenharmony_ci#include <unistd.h>
358c2ecf20Sopenharmony_ci#include "../kselftest.h"
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#define NSEC_PER_SEC 1000000000LL
388c2ecf20Sopenharmony_ci#define USEC_PER_SEC 1000000LL
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#define ADJ_SETOFFSET 0x0100
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci#include <sys/syscall.h>
438c2ecf20Sopenharmony_ciint clock_adjtime(clockid_t id, struct timex *tx)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	return syscall(__NR_clock_adjtime, id, tx);
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci/* clear NTP time_status & time_state */
508c2ecf20Sopenharmony_ciint clear_time_state(void)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	struct timex tx;
538c2ecf20Sopenharmony_ci	int ret;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	tx.modes = ADJ_STATUS;
568c2ecf20Sopenharmony_ci	tx.status = 0;
578c2ecf20Sopenharmony_ci	ret = adjtimex(&tx);
588c2ecf20Sopenharmony_ci	return ret;
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci#define NUM_FREQ_VALID 32
628c2ecf20Sopenharmony_ci#define NUM_FREQ_OUTOFRANGE 4
638c2ecf20Sopenharmony_ci#define NUM_FREQ_INVALID 2
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cilong valid_freq[NUM_FREQ_VALID] = {
668c2ecf20Sopenharmony_ci	-499<<16,
678c2ecf20Sopenharmony_ci	-450<<16,
688c2ecf20Sopenharmony_ci	-400<<16,
698c2ecf20Sopenharmony_ci	-350<<16,
708c2ecf20Sopenharmony_ci	-300<<16,
718c2ecf20Sopenharmony_ci	-250<<16,
728c2ecf20Sopenharmony_ci	-200<<16,
738c2ecf20Sopenharmony_ci	-150<<16,
748c2ecf20Sopenharmony_ci	-100<<16,
758c2ecf20Sopenharmony_ci	-75<<16,
768c2ecf20Sopenharmony_ci	-50<<16,
778c2ecf20Sopenharmony_ci	-25<<16,
788c2ecf20Sopenharmony_ci	-10<<16,
798c2ecf20Sopenharmony_ci	-5<<16,
808c2ecf20Sopenharmony_ci	-1<<16,
818c2ecf20Sopenharmony_ci	-1000,
828c2ecf20Sopenharmony_ci	1<<16,
838c2ecf20Sopenharmony_ci	5<<16,
848c2ecf20Sopenharmony_ci	10<<16,
858c2ecf20Sopenharmony_ci	25<<16,
868c2ecf20Sopenharmony_ci	50<<16,
878c2ecf20Sopenharmony_ci	75<<16,
888c2ecf20Sopenharmony_ci	100<<16,
898c2ecf20Sopenharmony_ci	150<<16,
908c2ecf20Sopenharmony_ci	200<<16,
918c2ecf20Sopenharmony_ci	250<<16,
928c2ecf20Sopenharmony_ci	300<<16,
938c2ecf20Sopenharmony_ci	350<<16,
948c2ecf20Sopenharmony_ci	400<<16,
958c2ecf20Sopenharmony_ci	450<<16,
968c2ecf20Sopenharmony_ci	499<<16,
978c2ecf20Sopenharmony_ci};
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cilong outofrange_freq[NUM_FREQ_OUTOFRANGE] = {
1008c2ecf20Sopenharmony_ci	-1000<<16,
1018c2ecf20Sopenharmony_ci	-550<<16,
1028c2ecf20Sopenharmony_ci	550<<16,
1038c2ecf20Sopenharmony_ci	1000<<16,
1048c2ecf20Sopenharmony_ci};
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci#define LONG_MAX (~0UL>>1)
1078c2ecf20Sopenharmony_ci#define LONG_MIN (-LONG_MAX - 1)
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cilong invalid_freq[NUM_FREQ_INVALID] = {
1108c2ecf20Sopenharmony_ci	LONG_MAX,
1118c2ecf20Sopenharmony_ci	LONG_MIN,
1128c2ecf20Sopenharmony_ci};
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ciint validate_freq(void)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	struct timex tx;
1178c2ecf20Sopenharmony_ci	int ret, pass = 0;
1188c2ecf20Sopenharmony_ci	int i;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	clear_time_state();
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	memset(&tx, 0, sizeof(struct timex));
1238c2ecf20Sopenharmony_ci	/* Set the leap second insert flag */
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	printf("Testing ADJ_FREQ... ");
1268c2ecf20Sopenharmony_ci	fflush(stdout);
1278c2ecf20Sopenharmony_ci	for (i = 0; i < NUM_FREQ_VALID; i++) {
1288c2ecf20Sopenharmony_ci		tx.modes = ADJ_FREQUENCY;
1298c2ecf20Sopenharmony_ci		tx.freq = valid_freq[i];
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci		ret = adjtimex(&tx);
1328c2ecf20Sopenharmony_ci		if (ret < 0) {
1338c2ecf20Sopenharmony_ci			printf("[FAIL]\n");
1348c2ecf20Sopenharmony_ci			printf("Error: adjtimex(ADJ_FREQ, %ld - %ld ppm\n",
1358c2ecf20Sopenharmony_ci				valid_freq[i], valid_freq[i]>>16);
1368c2ecf20Sopenharmony_ci			pass = -1;
1378c2ecf20Sopenharmony_ci			goto out;
1388c2ecf20Sopenharmony_ci		}
1398c2ecf20Sopenharmony_ci		tx.modes = 0;
1408c2ecf20Sopenharmony_ci		ret = adjtimex(&tx);
1418c2ecf20Sopenharmony_ci		if (tx.freq != valid_freq[i]) {
1428c2ecf20Sopenharmony_ci			printf("Warning: freq value %ld not what we set it (%ld)!\n",
1438c2ecf20Sopenharmony_ci					tx.freq, valid_freq[i]);
1448c2ecf20Sopenharmony_ci		}
1458c2ecf20Sopenharmony_ci	}
1468c2ecf20Sopenharmony_ci	for (i = 0; i < NUM_FREQ_OUTOFRANGE; i++) {
1478c2ecf20Sopenharmony_ci		tx.modes = ADJ_FREQUENCY;
1488c2ecf20Sopenharmony_ci		tx.freq = outofrange_freq[i];
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci		ret = adjtimex(&tx);
1518c2ecf20Sopenharmony_ci		if (ret < 0) {
1528c2ecf20Sopenharmony_ci			printf("[FAIL]\n");
1538c2ecf20Sopenharmony_ci			printf("Error: adjtimex(ADJ_FREQ, %ld - %ld ppm\n",
1548c2ecf20Sopenharmony_ci				outofrange_freq[i], outofrange_freq[i]>>16);
1558c2ecf20Sopenharmony_ci			pass = -1;
1568c2ecf20Sopenharmony_ci			goto out;
1578c2ecf20Sopenharmony_ci		}
1588c2ecf20Sopenharmony_ci		tx.modes = 0;
1598c2ecf20Sopenharmony_ci		ret = adjtimex(&tx);
1608c2ecf20Sopenharmony_ci		if (tx.freq == outofrange_freq[i]) {
1618c2ecf20Sopenharmony_ci			printf("[FAIL]\n");
1628c2ecf20Sopenharmony_ci			printf("ERROR: out of range value %ld actually set!\n",
1638c2ecf20Sopenharmony_ci					tx.freq);
1648c2ecf20Sopenharmony_ci			pass = -1;
1658c2ecf20Sopenharmony_ci			goto out;
1668c2ecf20Sopenharmony_ci		}
1678c2ecf20Sopenharmony_ci	}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	if (sizeof(long) == 8) { /* this case only applies to 64bit systems */
1718c2ecf20Sopenharmony_ci		for (i = 0; i < NUM_FREQ_INVALID; i++) {
1728c2ecf20Sopenharmony_ci			tx.modes = ADJ_FREQUENCY;
1738c2ecf20Sopenharmony_ci			tx.freq = invalid_freq[i];
1748c2ecf20Sopenharmony_ci			ret = adjtimex(&tx);
1758c2ecf20Sopenharmony_ci			if (ret >= 0) {
1768c2ecf20Sopenharmony_ci				printf("[FAIL]\n");
1778c2ecf20Sopenharmony_ci				printf("Error: No failure on invalid ADJ_FREQUENCY %ld\n",
1788c2ecf20Sopenharmony_ci					invalid_freq[i]);
1798c2ecf20Sopenharmony_ci				pass = -1;
1808c2ecf20Sopenharmony_ci				goto out;
1818c2ecf20Sopenharmony_ci			}
1828c2ecf20Sopenharmony_ci		}
1838c2ecf20Sopenharmony_ci	}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	printf("[OK]\n");
1868c2ecf20Sopenharmony_ciout:
1878c2ecf20Sopenharmony_ci	/* reset freq to zero */
1888c2ecf20Sopenharmony_ci	tx.modes = ADJ_FREQUENCY;
1898c2ecf20Sopenharmony_ci	tx.freq = 0;
1908c2ecf20Sopenharmony_ci	ret = adjtimex(&tx);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	return pass;
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ciint set_offset(long long offset, int use_nano)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	struct timex tmx = {};
1998c2ecf20Sopenharmony_ci	int ret;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	tmx.modes = ADJ_SETOFFSET;
2028c2ecf20Sopenharmony_ci	if (use_nano) {
2038c2ecf20Sopenharmony_ci		tmx.modes |= ADJ_NANO;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci		tmx.time.tv_sec = offset / NSEC_PER_SEC;
2068c2ecf20Sopenharmony_ci		tmx.time.tv_usec = offset % NSEC_PER_SEC;
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci		if (offset < 0 && tmx.time.tv_usec) {
2098c2ecf20Sopenharmony_ci			tmx.time.tv_sec -= 1;
2108c2ecf20Sopenharmony_ci			tmx.time.tv_usec += NSEC_PER_SEC;
2118c2ecf20Sopenharmony_ci		}
2128c2ecf20Sopenharmony_ci	} else {
2138c2ecf20Sopenharmony_ci		tmx.time.tv_sec = offset / USEC_PER_SEC;
2148c2ecf20Sopenharmony_ci		tmx.time.tv_usec = offset % USEC_PER_SEC;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci		if (offset < 0 && tmx.time.tv_usec) {
2178c2ecf20Sopenharmony_ci			tmx.time.tv_sec -= 1;
2188c2ecf20Sopenharmony_ci			tmx.time.tv_usec += USEC_PER_SEC;
2198c2ecf20Sopenharmony_ci		}
2208c2ecf20Sopenharmony_ci	}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	ret = clock_adjtime(CLOCK_REALTIME, &tmx);
2238c2ecf20Sopenharmony_ci	if (ret < 0) {
2248c2ecf20Sopenharmony_ci		printf("(sec: %ld  usec: %ld) ", tmx.time.tv_sec, tmx.time.tv_usec);
2258c2ecf20Sopenharmony_ci		printf("[FAIL]\n");
2268c2ecf20Sopenharmony_ci		return -1;
2278c2ecf20Sopenharmony_ci	}
2288c2ecf20Sopenharmony_ci	return 0;
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ciint set_bad_offset(long sec, long usec, int use_nano)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	struct timex tmx = {};
2348c2ecf20Sopenharmony_ci	int ret;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	tmx.modes = ADJ_SETOFFSET;
2378c2ecf20Sopenharmony_ci	if (use_nano)
2388c2ecf20Sopenharmony_ci		tmx.modes |= ADJ_NANO;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	tmx.time.tv_sec = sec;
2418c2ecf20Sopenharmony_ci	tmx.time.tv_usec = usec;
2428c2ecf20Sopenharmony_ci	ret = clock_adjtime(CLOCK_REALTIME, &tmx);
2438c2ecf20Sopenharmony_ci	if (ret >= 0) {
2448c2ecf20Sopenharmony_ci		printf("Invalid (sec: %ld  usec: %ld) did not fail! ", tmx.time.tv_sec, tmx.time.tv_usec);
2458c2ecf20Sopenharmony_ci		printf("[FAIL]\n");
2468c2ecf20Sopenharmony_ci		return -1;
2478c2ecf20Sopenharmony_ci	}
2488c2ecf20Sopenharmony_ci	return 0;
2498c2ecf20Sopenharmony_ci}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ciint validate_set_offset(void)
2528c2ecf20Sopenharmony_ci{
2538c2ecf20Sopenharmony_ci	printf("Testing ADJ_SETOFFSET... ");
2548c2ecf20Sopenharmony_ci	fflush(stdout);
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	/* Test valid values */
2578c2ecf20Sopenharmony_ci	if (set_offset(NSEC_PER_SEC - 1, 1))
2588c2ecf20Sopenharmony_ci		return -1;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	if (set_offset(-NSEC_PER_SEC + 1, 1))
2618c2ecf20Sopenharmony_ci		return -1;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	if (set_offset(-NSEC_PER_SEC - 1, 1))
2648c2ecf20Sopenharmony_ci		return -1;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	if (set_offset(5 * NSEC_PER_SEC, 1))
2678c2ecf20Sopenharmony_ci		return -1;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	if (set_offset(-5 * NSEC_PER_SEC, 1))
2708c2ecf20Sopenharmony_ci		return -1;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	if (set_offset(5 * NSEC_PER_SEC + NSEC_PER_SEC / 2, 1))
2738c2ecf20Sopenharmony_ci		return -1;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	if (set_offset(-5 * NSEC_PER_SEC - NSEC_PER_SEC / 2, 1))
2768c2ecf20Sopenharmony_ci		return -1;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	if (set_offset(USEC_PER_SEC - 1, 0))
2798c2ecf20Sopenharmony_ci		return -1;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	if (set_offset(-USEC_PER_SEC + 1, 0))
2828c2ecf20Sopenharmony_ci		return -1;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	if (set_offset(-USEC_PER_SEC - 1, 0))
2858c2ecf20Sopenharmony_ci		return -1;
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	if (set_offset(5 * USEC_PER_SEC, 0))
2888c2ecf20Sopenharmony_ci		return -1;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	if (set_offset(-5 * USEC_PER_SEC, 0))
2918c2ecf20Sopenharmony_ci		return -1;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	if (set_offset(5 * USEC_PER_SEC + USEC_PER_SEC / 2, 0))
2948c2ecf20Sopenharmony_ci		return -1;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	if (set_offset(-5 * USEC_PER_SEC - USEC_PER_SEC / 2, 0))
2978c2ecf20Sopenharmony_ci		return -1;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	/* Test invalid values */
3008c2ecf20Sopenharmony_ci	if (set_bad_offset(0, -1, 1))
3018c2ecf20Sopenharmony_ci		return -1;
3028c2ecf20Sopenharmony_ci	if (set_bad_offset(0, -1, 0))
3038c2ecf20Sopenharmony_ci		return -1;
3048c2ecf20Sopenharmony_ci	if (set_bad_offset(0, 2 * NSEC_PER_SEC, 1))
3058c2ecf20Sopenharmony_ci		return -1;
3068c2ecf20Sopenharmony_ci	if (set_bad_offset(0, 2 * USEC_PER_SEC, 0))
3078c2ecf20Sopenharmony_ci		return -1;
3088c2ecf20Sopenharmony_ci	if (set_bad_offset(0, NSEC_PER_SEC, 1))
3098c2ecf20Sopenharmony_ci		return -1;
3108c2ecf20Sopenharmony_ci	if (set_bad_offset(0, USEC_PER_SEC, 0))
3118c2ecf20Sopenharmony_ci		return -1;
3128c2ecf20Sopenharmony_ci	if (set_bad_offset(0, -NSEC_PER_SEC, 1))
3138c2ecf20Sopenharmony_ci		return -1;
3148c2ecf20Sopenharmony_ci	if (set_bad_offset(0, -USEC_PER_SEC, 0))
3158c2ecf20Sopenharmony_ci		return -1;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	printf("[OK]\n");
3188c2ecf20Sopenharmony_ci	return 0;
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ciint main(int argc, char **argv)
3228c2ecf20Sopenharmony_ci{
3238c2ecf20Sopenharmony_ci	if (validate_freq())
3248c2ecf20Sopenharmony_ci		return ksft_exit_fail();
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	if (validate_set_offset())
3278c2ecf20Sopenharmony_ci		return ksft_exit_fail();
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	return ksft_exit_pass();
3308c2ecf20Sopenharmony_ci}
331