* OS specific functions for UNIX/POSIX systems
* Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
+#include <time.h>
+#include <sys/wait.h>
+
+#ifdef ANDROID
+#include <sys/capability.h>
+#include <sys/prctl.h>
+#include <private/android_filesystem_config.h>
+#endif /* ANDROID */
+
+#ifdef __MACH__
+#include <CoreServices/CoreServices.h>
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#endif /* __MACH__ */
+
#include "os.h"
+#include "common.h"
#ifdef WPA_TRACE
-#include "common.h"
-#include "list.h"
#include "wpa_debug.h"
#include "trace.h"
+#include "list.h"
-static struct dl_list alloc_list;
+static struct dl_list alloc_list = DL_LIST_HEAD_INIT(alloc_list);
#define ALLOC_MAGIC 0xa84ef1b2
#define FREED_MAGIC 0x67fd487a
struct dl_list list;
size_t len;
WPA_TRACE_INFO
-};
+} __attribute__((aligned(16)));
#endif /* WPA_TRACE */
}
+int os_get_reltime(struct os_reltime *t)
+{
+#ifndef __MACH__
+#if defined(CLOCK_BOOTTIME)
+ static clockid_t clock_id = CLOCK_BOOTTIME;
+#elif defined(CLOCK_MONOTONIC)
+ static clockid_t clock_id = CLOCK_MONOTONIC;
+#else
+ static clockid_t clock_id = CLOCK_REALTIME;
+#endif
+ struct timespec ts;
+ int res;
+
+ while (1) {
+ res = clock_gettime(clock_id, &ts);
+ if (res == 0) {
+ t->sec = ts.tv_sec;
+ t->usec = ts.tv_nsec / 1000;
+ return 0;
+ }
+ switch (clock_id) {
+#ifdef CLOCK_BOOTTIME
+ case CLOCK_BOOTTIME:
+ clock_id = CLOCK_MONOTONIC;
+ break;
+#endif
+#ifdef CLOCK_MONOTONIC
+ case CLOCK_MONOTONIC:
+ clock_id = CLOCK_REALTIME;
+ break;
+#endif
+ case CLOCK_REALTIME:
+ return -1;
+ }
+ }
+#else /* __MACH__ */
+ uint64_t abstime, nano;
+ static mach_timebase_info_data_t info = { 0, 0 };
+
+ if (!info.denom) {
+ if (mach_timebase_info(&info) != KERN_SUCCESS)
+ return -1;
+ }
+
+ abstime = mach_absolute_time();
+ nano = (abstime * info.numer) / info.denom;
+
+ t->sec = nano / NSEC_PER_SEC;
+ t->usec = (nano - (((uint64_t) t->sec) * NSEC_PER_SEC)) / NSEC_PER_USEC;
+
+ return 0;
+#endif /* __MACH__ */
+}
+
+
int os_mktime(int year, int month, int day, int hour, int min, int sec,
os_time_t *t)
{
}
+int os_gmtime(os_time_t t, struct os_tm *tm)
+{
+ struct tm *tm2;
+ time_t t2 = t;
+
+ tm2 = gmtime(&t2);
+ if (tm2 == NULL)
+ return -1;
+ tm->sec = tm2->tm_sec;
+ tm->min = tm2->tm_min;
+ tm->hour = tm2->tm_hour;
+ tm->day = tm2->tm_mday;
+ tm->month = tm2->tm_mon + 1;
+ tm->year = tm2->tm_year + 1900;
+ return 0;
+}
+
+
#ifdef __APPLE__
#include <fcntl.h>
static int os_daemon(int nochdir, int noclose)
FILE *f;
size_t rc;
+ if (TEST_FAIL())
+ return -1;
+
f = fopen("/dev/urandom", "rb");
if (f == NULL) {
printf("Could not open /dev/urandom.\n");
size_t len = 128, cwd_len, rel_len, ret_len;
int last_errno;
+ if (!rel_path)
+ return NULL;
+
if (rel_path[0] == '/')
return os_strdup(rel_path);
int os_program_init(void)
{
-#ifdef WPA_TRACE
- dl_list_init(&alloc_list);
-#endif /* WPA_TRACE */
+#ifdef ANDROID
+ /*
+ * We ignore errors here since errors are normal if we
+ * are already running as non-root.
+ */
+#ifdef ANDROID_SETGROUPS_OVERRIDE
+ gid_t groups[] = { ANDROID_SETGROUPS_OVERRIDE };
+#else /* ANDROID_SETGROUPS_OVERRIDE */
+ gid_t groups[] = { AID_INET, AID_WIFI, AID_KEYSTORE };
+#endif /* ANDROID_SETGROUPS_OVERRIDE */
+ struct __user_cap_header_struct header;
+ struct __user_cap_data_struct cap;
+
+ setgroups(ARRAY_SIZE(groups), groups);
+
+ prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
+
+ setgid(AID_WIFI);
+ setuid(AID_WIFI);
+
+ header.version = _LINUX_CAPABILITY_VERSION;
+ header.pid = 0;
+ cap.effective = cap.permitted =
+ (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
+ cap.inheritable = 0;
+ capset(&header, &cap);
+#endif /* ANDROID */
+
return 0;
}
if (total)
wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes",
(unsigned long) total);
+ wpa_trace_deinit();
#endif /* WPA_TRACE */
}
{
FILE *f;
char *buf;
+ long pos;
f = fopen(name, "rb");
if (f == NULL)
return NULL;
- fseek(f, 0, SEEK_END);
- *len = ftell(f);
- fseek(f, 0, SEEK_SET);
+ if (fseek(f, 0, SEEK_END) < 0 || (pos = ftell(f)) < 0) {
+ fclose(f);
+ return NULL;
+ }
+ *len = pos;
+ if (fseek(f, 0, SEEK_SET) < 0) {
+ fclose(f);
+ return NULL;
+ }
buf = os_malloc(*len);
if (buf == NULL) {
}
+int os_file_exists(const char *fname)
+{
+ return access(fname, F_OK) == 0;
+}
+
+
+int os_fdatasync(FILE *stream)
+{
+ if (!fflush(stream)) {
+#ifdef __linux__
+ return fdatasync(fileno(stream));
+#else /* !__linux__ */
+#ifdef F_FULLFSYNC
+ /* OS X does not implement fdatasync(). */
+ return fcntl(fileno(stream), F_FULLFSYNC);
+#else /* F_FULLFSYNC */
+ return fsync(fileno(stream));
+#endif /* F_FULLFSYNC */
+#endif /* __linux__ */
+ }
+
+ return -1;
+}
+
+
#ifndef WPA_TRACE
void * os_zalloc(size_t size)
{
}
+int os_memcmp_const(const void *a, const void *b, size_t len)
+{
+ const u8 *aa = a;
+ const u8 *bb = b;
+ size_t i;
+ u8 res;
+
+ for (res = 0, i = 0; i < len; i++)
+ res |= aa[i] ^ bb[i];
+
+ return res;
+}
+
+
#ifdef WPA_TRACE
+#if defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS)
+char wpa_trace_fail_func[256] = { 0 };
+unsigned int wpa_trace_fail_after;
+
+static int testing_fail_alloc(void)
+{
+ const char *func[WPA_TRACE_LEN];
+ size_t i, res, len;
+ char *pos, *next;
+ int match;
+
+ if (!wpa_trace_fail_after)
+ return 0;
+
+ res = wpa_trace_calling_func(func, WPA_TRACE_LEN);
+ i = 0;
+ if (i < res && os_strcmp(func[i], __func__) == 0)
+ i++;
+ if (i < res && os_strcmp(func[i], "os_malloc") == 0)
+ i++;
+ if (i < res && os_strcmp(func[i], "os_zalloc") == 0)
+ i++;
+ if (i < res && os_strcmp(func[i], "os_calloc") == 0)
+ i++;
+ if (i < res && os_strcmp(func[i], "os_realloc") == 0)
+ i++;
+ if (i < res && os_strcmp(func[i], "os_realloc_array") == 0)
+ i++;
+ if (i < res && os_strcmp(func[i], "os_strdup") == 0)
+ i++;
+
+ pos = wpa_trace_fail_func;
+
+ match = 0;
+ while (i < res) {
+ int allow_skip = 1;
+ int maybe = 0;
+
+ if (*pos == '=') {
+ allow_skip = 0;
+ pos++;
+ } else if (*pos == '?') {
+ maybe = 1;
+ pos++;
+ }
+ next = os_strchr(pos, ';');
+ if (next)
+ len = next - pos;
+ else
+ len = os_strlen(pos);
+ if (os_memcmp(pos, func[i], len) != 0) {
+ if (maybe && next) {
+ pos = next + 1;
+ continue;
+ }
+ if (allow_skip) {
+ i++;
+ continue;
+ }
+ return 0;
+ }
+ if (!next) {
+ match = 1;
+ break;
+ }
+ pos = next + 1;
+ i++;
+ }
+ if (!match)
+ return 0;
+
+ wpa_trace_fail_after--;
+ if (wpa_trace_fail_after == 0) {
+ wpa_printf(MSG_INFO, "TESTING: fail allocation at %s",
+ wpa_trace_fail_func);
+ for (i = 0; i < res; i++)
+ wpa_printf(MSG_INFO, "backtrace[%d] = %s",
+ (int) i, func[i]);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+char wpa_trace_test_fail_func[256] = { 0 };
+unsigned int wpa_trace_test_fail_after;
+
+int testing_test_fail(void)
+{
+ const char *func[WPA_TRACE_LEN];
+ size_t i, res, len;
+ char *pos, *next;
+ int match;
+
+ if (!wpa_trace_test_fail_after)
+ return 0;
+
+ res = wpa_trace_calling_func(func, WPA_TRACE_LEN);
+ i = 0;
+ if (i < res && os_strcmp(func[i], __func__) == 0)
+ i++;
+
+ pos = wpa_trace_test_fail_func;
+
+ match = 0;
+ while (i < res) {
+ int allow_skip = 1;
+ int maybe = 0;
+
+ if (*pos == '=') {
+ allow_skip = 0;
+ pos++;
+ } else if (*pos == '?') {
+ maybe = 1;
+ pos++;
+ }
+ next = os_strchr(pos, ';');
+ if (next)
+ len = next - pos;
+ else
+ len = os_strlen(pos);
+ if (os_memcmp(pos, func[i], len) != 0) {
+ if (maybe && next) {
+ pos = next + 1;
+ continue;
+ }
+ if (allow_skip) {
+ i++;
+ continue;
+ }
+ return 0;
+ }
+ if (!next) {
+ match = 1;
+ break;
+ }
+ pos = next + 1;
+ i++;
+ }
+ if (!match)
+ return 0;
+
+ wpa_trace_test_fail_after--;
+ if (wpa_trace_test_fail_after == 0) {
+ wpa_printf(MSG_INFO, "TESTING: fail at %s",
+ wpa_trace_test_fail_func);
+ for (i = 0; i < res; i++)
+ wpa_printf(MSG_INFO, "backtrace[%d] = %s",
+ (int) i, func[i]);
+ return 1;
+ }
+
+ return 0;
+}
+
+#else
+
+static inline int testing_fail_alloc(void)
+{
+ return 0;
+}
+#endif
+
void * os_malloc(size_t size)
{
struct os_alloc_trace *a;
+
+ if (testing_fail_alloc())
+ return NULL;
+
a = malloc(sizeof(*a) + size);
if (a == NULL)
return NULL;
}
#endif /* WPA_TRACE */
+
+
+int os_exec(const char *program, const char *arg, int wait_completion)
+{
+ pid_t pid;
+ int pid_status;
+
+ pid = fork();
+ if (pid < 0) {
+ perror("fork");
+ return -1;
+ }
+
+ if (pid == 0) {
+ /* run the external command in the child process */
+ const int MAX_ARG = 30;
+ char *_program, *_arg, *pos;
+ char *argv[MAX_ARG + 1];
+ int i;
+
+ _program = os_strdup(program);
+ _arg = os_strdup(arg);
+
+ argv[0] = _program;
+
+ i = 1;
+ pos = _arg;
+ while (i < MAX_ARG && pos && *pos) {
+ while (*pos == ' ')
+ pos++;
+ if (*pos == '\0')
+ break;
+ argv[i++] = pos;
+ pos = os_strchr(pos, ' ');
+ if (pos)
+ *pos++ = '\0';
+ }
+ argv[i] = NULL;
+
+ execv(program, argv);
+ perror("execv");
+ os_free(_program);
+ os_free(_arg);
+ exit(0);
+ return -1;
+ }
+
+ if (wait_completion) {
+ /* wait for the child process to complete in the parent */
+ waitpid(pid, &pid_status, 0);
+ }
+
+ return 0;
+}