diff options
Diffstat (limited to 'src/utils')
| -rw-r--r-- | src/utils/browser-wpadebug.c | 6 | ||||
| -rw-r--r-- | src/utils/common.c | 97 | ||||
| -rw-r--r-- | src/utils/common.h | 41 | ||||
| -rw-r--r-- | src/utils/eloop.c | 45 | ||||
| -rw-r--r-- | src/utils/http_curl.c | 14 | ||||
| -rw-r--r-- | src/utils/includes.h | 7 | ||||
| -rw-r--r-- | src/utils/os.h | 15 | ||||
| -rw-r--r-- | src/utils/os_internal.c | 6 | ||||
| -rw-r--r-- | src/utils/os_none.c | 6 | ||||
| -rw-r--r-- | src/utils/os_unix.c | 120 | ||||
| -rw-r--r-- | src/utils/os_win32.c | 18 | ||||
| -rw-r--r-- | src/utils/radiotap.c | 4 | ||||
| -rw-r--r-- | src/utils/utils_module_tests.c | 440 | ||||
| -rw-r--r-- | src/utils/wpa_debug.c | 90 | ||||
| -rw-r--r-- | src/utils/wpa_debug.h | 27 | ||||
| -rw-r--r-- | src/utils/wpabuf.c | 2 |
16 files changed, 854 insertions, 84 deletions
diff --git a/src/utils/browser-wpadebug.c b/src/utils/browser-wpadebug.c index 5fc40fac610e..59ba4d1e02d8 100644 --- a/src/utils/browser-wpadebug.c +++ b/src/utils/browser-wpadebug.c @@ -96,7 +96,7 @@ int hs20_web_browser(const char *url) if (pid == 0) { /* run the external command in the child process */ - char *argv[12]; + char *argv[14]; argv[0] = "browser-wpadebug"; argv[1] = "start"; @@ -109,7 +109,9 @@ int hs20_web_browser(const char *url) argv[8] = "-e"; argv[9] = "w1.fi.wpadebug.URL"; argv[10] = (void *) url; - argv[11] = NULL; + argv[11] = "--user"; + argv[12] = "-3"; /* USER_CURRENT_OR_SELF */ + argv[13] = NULL; execv("/system/bin/am", argv); wpa_printf(MSG_ERROR, "execv: %s", strerror(errno)); diff --git a/src/utils/common.c b/src/utils/common.c index 5fd795f3f303..660e9fc985d6 100644 --- a/src/utils/common.c +++ b/src/utils/common.c @@ -8,6 +8,7 @@ #include "includes.h" +#include "common/ieee802_11_defs.h" #include "common.h" @@ -277,6 +278,31 @@ int wpa_scnprintf(char *buf, size_t size, const char *fmt, ...) return ret; } + +int wpa_snprintf_hex_sep(char *buf, size_t buf_size, const u8 *data, size_t len, + char sep) +{ + size_t i; + char *pos = buf, *end = buf + buf_size; + int ret; + + if (buf_size == 0) + return 0; + + for (i = 0; i < len; i++) { + ret = os_snprintf(pos, end - pos, "%02x%c", + data[i], sep); + if (os_snprintf_error(end - pos, ret)) { + end[-1] = '\0'; + return pos - buf; + } + pos += ret; + } + pos[-1] = '\0'; + return pos - buf; +} + + static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len, int uppercase) { @@ -584,7 +610,7 @@ size_t printf_decode(u8 *buf, size_t maxlen, const char *str) */ const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len) { - static char ssid_txt[32 * 4 + 1]; + static char ssid_txt[SSID_MAX_LEN * 4 + 1]; if (ssid == NULL) { ssid_txt[0] = '\0'; @@ -947,6 +973,48 @@ int random_mac_addr_keep_oui(u8 *addr) /** + * cstr_token - Get next token from const char string + * @str: a constant string to tokenize + * @delim: a string of delimiters + * @last: a pointer to a character following the returned token + * It has to be set to NULL for the first call and passed for any + * futher call. + * Returns: a pointer to token position in str or NULL + * + * This function is similar to str_token, but it can be used with both + * char and const char strings. Differences: + * - The str buffer remains unmodified + * - The returned token is not a NULL terminated string, but a token + * position in str buffer. If a return value is not NULL a size + * of the returned token could be calculated as (last - token). + */ +const char * cstr_token(const char *str, const char *delim, const char **last) +{ + const char *end, *token = str; + + if (!str || !delim || !last) + return NULL; + + if (*last) + token = *last; + + while (*token && os_strchr(delim, *token)) + token++; + + if (!*token) + return NULL; + + end = token + 1; + + while (*end && !os_strchr(delim, *end)) + end++; + + *last = end; + return token; +} + + +/** * str_token - Get next token from a string * @buf: String to tokenize. Note that the string might be modified. * @delim: String of delimiters @@ -956,25 +1024,12 @@ int random_mac_addr_keep_oui(u8 *addr) */ char * str_token(char *str, const char *delim, char **context) { - char *end, *pos = str; - - if (*context) - pos = *context; - - while (*pos && os_strchr(delim, *pos)) - pos++; - if (!*pos) - return NULL; - - end = pos + 1; - while (*end && !os_strchr(delim, *end)) - end++; + char *token = (char *) cstr_token(str, delim, (const char **) context); - if (*end) - *end++ = '\0'; + if (token && **context) + *(*context)++ = '\0'; - *context = end; - return pos; + return token; } @@ -1062,3 +1117,9 @@ size_t utf8_escape(const char *inp, size_t in_size, return res_size; } + + +int is_ctrl_char(char c) +{ + return c > 0 && c < 32; +} diff --git a/src/utils/common.h b/src/utils/common.h index 576e8e7e2d4e..0b9cc3d88209 100644 --- a/src/utils/common.h +++ b/src/utils/common.h @@ -53,16 +53,6 @@ static inline unsigned int bswap_32(unsigned int v) } #endif /* __APPLE__ */ -#ifdef CONFIG_TI_COMPILER -#define __BIG_ENDIAN 4321 -#define __LITTLE_ENDIAN 1234 -#ifdef __big_endian__ -#define __BYTE_ORDER __BIG_ENDIAN -#else -#define __BYTE_ORDER __LITTLE_ENDIAN -#endif -#endif /* CONFIG_TI_COMPILER */ - #ifdef CONFIG_NATIVE_WINDOWS #include <winsock.h> @@ -110,22 +100,6 @@ typedef INT8 s8; #define WPA_TYPES_DEFINED #endif /* __vxworks */ -#ifdef CONFIG_TI_COMPILER -#ifdef _LLONG_AVAILABLE -typedef unsigned long long u64; -#else -/* - * TODO: 64-bit variable not available. Using long as a workaround to test the - * build, but this will likely not work for all operations. - */ -typedef unsigned long u64; -#endif -typedef unsigned int u32; -typedef unsigned short u16; -typedef unsigned char u8; -#define WPA_TYPES_DEFINED -#endif /* CONFIG_TI_COMPILER */ - #ifndef WPA_TYPES_DEFINED #ifdef CONFIG_USE_INTTYPES_H #include <inttypes.h> @@ -262,7 +236,7 @@ static inline void WPA_PUT_BE24(u8 *a, u32 val) static inline u32 WPA_GET_BE32(const u8 *a) { - return (a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3]; + return ((u32) a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3]; } static inline void WPA_PUT_BE32(u8 *a, u32 val) @@ -275,7 +249,7 @@ static inline void WPA_PUT_BE32(u8 *a, u32 val) static inline u32 WPA_GET_LE32(const u8 *a) { - return (a[3] << 24) | (a[2] << 16) | (a[1] << 8) | a[0]; + return ((u32) a[3] << 24) | (a[2] << 16) | (a[1] << 8) | a[0]; } static inline void WPA_PUT_LE32(u8 *a, u32 val) @@ -433,7 +407,7 @@ void perror(const char *s); #endif #ifndef BIT -#define BIT(x) (1 << (x)) +#define BIT(x) (1U << (x)) #endif /* @@ -480,6 +454,8 @@ int hexstr2bin(const char *hex, u8 *buf, size_t len); void inc_byte_array(u8 *counter, size_t len); void wpa_get_ntp_timestamp(u8 *buf); int wpa_scnprintf(char *buf, size_t size, const char *fmt, ...); +int wpa_snprintf_hex_sep(char *buf, size_t buf_size, const u8 *data, size_t len, + char sep); int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len); int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data, size_t len); @@ -516,6 +492,11 @@ static inline int is_broadcast_ether_addr(const u8 *a) return (a[0] & a[1] & a[2] & a[3] & a[4] & a[5]) == 0xff; } +static inline int is_multicast_ether_addr(const u8 *a) +{ + return a[0] & 0x01; +} + #define broadcast_ether_addr (const u8 *) "\xff\xff\xff\xff\xff\xff" #include "wpa_debug.h" @@ -547,11 +528,13 @@ void bin_clear_free(void *bin, size_t len); int random_mac_addr(u8 *addr); int random_mac_addr_keep_oui(u8 *addr); +const char * cstr_token(const char *str, const char *delim, const char **last); char * str_token(char *str, const char *delim, char **context); size_t utf8_escape(const char *inp, size_t in_size, char *outp, size_t out_size); size_t utf8_unescape(const char *inp, size_t in_size, char *outp, size_t out_size); +int is_ctrl_char(char c); /* diff --git a/src/utils/eloop.c b/src/utils/eloop.c index 4a565ebdbd0a..8647229b8eb5 100644 --- a/src/utils/eloop.c +++ b/src/utils/eloop.c @@ -61,11 +61,8 @@ struct eloop_signal { struct eloop_sock_table { int count; struct eloop_sock *table; -#ifdef CONFIG_ELOOP_EPOLL eloop_event_type type; -#else /* CONFIG_ELOOP_EPOLL */ int changed; -#endif /* CONFIG_ELOOP_EPOLL */ }; struct eloop_data { @@ -256,9 +253,7 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table, table->table = tmp; eloop.max_sock = new_max_sock; eloop.count++; -#ifndef CONFIG_ELOOP_EPOLL table->changed = 1; -#endif /* CONFIG_ELOOP_EPOLL */ eloop_trace_sock_add_ref(table); #ifdef CONFIG_ELOOP_EPOLL @@ -314,9 +309,7 @@ static void eloop_sock_table_remove_sock(struct eloop_sock_table *table, } table->count--; eloop.count--; -#ifndef CONFIG_ELOOP_EPOLL table->changed = 1; -#endif /* CONFIG_ELOOP_EPOLL */ eloop_trace_sock_add_ref(table); #ifdef CONFIG_ELOOP_EPOLL if (epoll_ctl(eloop.epollfd, EPOLL_CTL_DEL, sock, NULL) < 0) { @@ -523,6 +516,10 @@ static void eloop_sock_table_dispatch(struct epoll_event *events, int nfds) continue; table->handler(table->sock, table->eloop_data, table->user_data); + if (eloop.readers.changed || + eloop.writers.changed || + eloop.exceptions.changed) + break; } } #endif /* CONFIG_ELOOP_EPOLL */ @@ -923,6 +920,20 @@ void eloop_run(void) (!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 || eloop.writers.count > 0 || eloop.exceptions.count > 0)) { struct eloop_timeout *timeout; + + if (eloop.pending_terminate) { + /* + * This may happen in some corner cases where a signal + * is received during a blocking operation. We need to + * process the pending signals and exit if requested to + * avoid hitting the SIGALRM limit if the blocking + * operation took more than two seconds. + */ + eloop_process_pending_signals(); + if (eloop.terminate) + break; + } + timeout = dl_list_first(&eloop.timeout, struct eloop_timeout, list); if (timeout) { @@ -977,6 +988,11 @@ void eloop_run(void) , strerror(errno)); goto out; } + + eloop.readers.changed = 0; + eloop.writers.changed = 0; + eloop.exceptions.changed = 0; + eloop_process_pending_signals(); /* check if some registered timeouts have occurred */ @@ -998,6 +1014,19 @@ void eloop_run(void) if (res <= 0) continue; + if (eloop.readers.changed || + eloop.writers.changed || + eloop.exceptions.changed) { + /* + * Sockets may have been closed and reopened with the + * same FD in the signal or timeout handlers, so we + * must skip the previous results and check again + * whether any of the currently registered sockets have + * events. + */ + continue; + } + #ifdef CONFIG_ELOOP_POLL eloop_sock_table_dispatch(&eloop.readers, &eloop.writers, &eloop.exceptions, eloop.pollfds_map, @@ -1073,7 +1102,7 @@ void eloop_destroy(void) int eloop_terminated(void) { - return eloop.terminate; + return eloop.terminate || eloop.pending_terminate; } diff --git a/src/utils/http_curl.c b/src/utils/http_curl.c index b38cf796ca2a..653eb541ab47 100644 --- a/src/utils/http_curl.c +++ b/src/utils/http_curl.c @@ -855,8 +855,10 @@ static int validate_server_cert(struct http_ctx *ctx, X509 *cert) struct http_cert hcert; int ret; - if (ctx->cert_cb == NULL) + if (ctx->cert_cb == NULL) { + wpa_printf(MSG_DEBUG, "%s: no cert_cb configured", __func__); return 0; + } if (0) { BIO *out; @@ -950,7 +952,8 @@ static int curl_cb_ssl_verify(int preverify_ok, X509_STORE_CTX *x509_ctx) ssl_ctx = ssl->ctx; ctx = SSL_CTX_get_app_data(ssl_ctx); - wpa_printf(MSG_DEBUG, "curl_cb_ssl_verify"); + wpa_printf(MSG_DEBUG, "curl_cb_ssl_verify, preverify_ok: %d", + preverify_ok); err = X509_STORE_CTX_get_error(x509_ctx); err_str = X509_verify_cert_error_string(err); @@ -1249,9 +1252,14 @@ static CURL * setup_curl_post(struct http_ctx *ctx, const char *address, const char *client_key) { CURL *curl; +#ifdef EAP_TLS_OPENSSL + const char *extra = " tls=openssl"; +#else /* EAP_TLS_OPENSSL */ + const char *extra = ""; +#endif /* EAP_TLS_OPENSSL */ wpa_printf(MSG_DEBUG, "Start HTTP client: address=%s ca_fname=%s " - "username=%s", address, ca_fname, username); + "username=%s%s", address, ca_fname, username, extra); curl = curl_easy_init(); if (curl == NULL) diff --git a/src/utils/includes.h b/src/utils/includes.h index 6c6ec87d0eaf..75513fc8c1ef 100644 --- a/src/utils/includes.h +++ b/src/utils/includes.h @@ -17,26 +17,22 @@ #include "build_config.h" #include <stdlib.h> +#include <stddef.h> #include <stdio.h> #include <stdarg.h> #include <string.h> #ifndef _WIN32_WCE -#ifndef CONFIG_TI_COMPILER #include <signal.h> #include <sys/types.h> -#endif /* CONFIG_TI_COMPILER */ #include <errno.h> #endif /* _WIN32_WCE */ #include <ctype.h> -#ifndef CONFIG_TI_COMPILER #ifndef _MSC_VER #include <unistd.h> #endif /* _MSC_VER */ -#endif /* CONFIG_TI_COMPILER */ #ifndef CONFIG_NATIVE_WINDOWS -#ifndef CONFIG_TI_COMPILER #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> @@ -44,7 +40,6 @@ #include <sys/uio.h> #include <sys/time.h> #endif /* __vxworks */ -#endif /* CONFIG_TI_COMPILER */ #endif /* CONFIG_NATIVE_WINDOWS */ #endif /* INCLUDES_H */ diff --git a/src/utils/os.h b/src/utils/os.h index 77250d6371c9..9e496fb65978 100644 --- a/src/utils/os.h +++ b/src/utils/os.h @@ -247,6 +247,13 @@ char * os_readfile(const char *name, size_t *len); int os_file_exists(const char *fname); /** + * os_fdatasync - Sync a file's (for a given stream) state with storage device + * @stream: the stream to be flushed + * Returns: 0 if the operation succeeded or -1 on failure + */ +int os_fdatasync(FILE *stream); + +/** * os_zalloc - Allocate and zero memory * @size: Number of bytes to allocate * Returns: Pointer to allocated and zeroed memory or %NULL on failure @@ -646,4 +653,12 @@ int os_exec(const char *program, const char *arg, int wait_completion); #define strcpy OS_DO_NOT_USE_strcpy #endif /* OS_REJECT_C_LIB_FUNCTIONS */ + +#if defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS) +#define TEST_FAIL() testing_test_fail() +int testing_test_fail(void); +#else +#define TEST_FAIL() 0 +#endif + #endif /* OS_H */ diff --git a/src/utils/os_internal.c b/src/utils/os_internal.c index 77733ad916cd..ed6eb3c6b677 100644 --- a/src/utils/os_internal.c +++ b/src/utils/os_internal.c @@ -243,6 +243,12 @@ char * os_readfile(const char *name, size_t *len) } +int os_fdatasync(FILE *stream) +{ + return 0; +} + + void * os_zalloc(size_t size) { void *n = os_malloc(size); diff --git a/src/utils/os_none.c b/src/utils/os_none.c index 83fe025167b6..0c3214d32ce5 100644 --- a/src/utils/os_none.c +++ b/src/utils/os_none.c @@ -102,6 +102,12 @@ char * os_readfile(const char *name, size_t *len) } +int os_fdatasync(FILE *stream) +{ + return 0; +} + + void * os_zalloc(size_t size) { return NULL; diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c index e0c1125d5305..ffa2e788b3db 100644 --- a/src/utils/os_unix.c +++ b/src/utils/os_unix.c @@ -17,6 +17,12 @@ #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" @@ -36,7 +42,7 @@ struct os_alloc_trace { struct dl_list list; size_t len; WPA_TRACE_INFO -}; +} __attribute__((aligned(16))); #endif /* WPA_TRACE */ @@ -63,6 +69,7 @@ int os_get_time(struct os_time *t) 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) @@ -95,6 +102,23 @@ int os_get_reltime(struct os_reltime *t) 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__ */ } @@ -226,6 +250,9 @@ int os_get_random(unsigned char *buf, size_t len) 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"); @@ -415,6 +442,25 @@ int os_file_exists(const char *fname) } +int os_fdatasync(FILE *stream) +{ + if (!fflush(stream)) { +#ifndef __MACH__ + return fdatasync(fileno(stream)); +#else /* __MACH__ */ +#ifdef F_FULLFSYNC + /* OS X does not implement fdatasync(). */ + return fcntl(fileno(stream), F_FULLFSYNC); +#else /* F_FULLFSYNC */ +#error Neither fdatasync nor F_FULLSYNC are defined +#endif /* F_FULLFSYNC */ +#endif /* __MACH__ */ + } + + return -1; +} + + #ifndef WPA_TRACE void * os_zalloc(size_t size) { @@ -548,6 +594,78 @@ static int testing_fail_alloc(void) 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) diff --git a/src/utils/os_win32.c b/src/utils/os_win32.c index 296ea13f153b..dea27b9f2ad8 100644 --- a/src/utils/os_win32.c +++ b/src/utils/os_win32.c @@ -216,6 +216,24 @@ char * os_readfile(const char *name, size_t *len) } +int os_fdatasync(FILE *stream) +{ + HANDLE h; + + if (stream == NULL) + return -1; + + h = (HANDLE) _get_osfhandle(_fileno(stream)); + if (h == INVALID_HANDLE_VALUE) + return -1; + + if (!FlushFileBuffers(h)) + return -1; + + return 0; +} + + void * os_zalloc(size_t size) { return calloc(1, size); diff --git a/src/utils/radiotap.c b/src/utils/radiotap.c index f8f815a86be9..c9a502335592 100644 --- a/src/utils/radiotap.c +++ b/src/utils/radiotap.c @@ -123,13 +123,13 @@ int ieee80211_radiotap_iterator_init( /* find payload start allowing for extended bitmap(s) */ - if (iterator->_bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT)) { + if (iterator->_bitmap_shifter & BIT(IEEE80211_RADIOTAP_EXT)) { if ((unsigned long)iterator->_arg - (unsigned long)iterator->_rtheader + sizeof(uint32_t) > (unsigned long)iterator->_max_length) return -EINVAL; while (get_unaligned_le32(iterator->_arg) & - (1 << IEEE80211_RADIOTAP_EXT)) { + BIT(IEEE80211_RADIOTAP_EXT)) { iterator->_arg += sizeof(uint32_t); /* diff --git a/src/utils/utils_module_tests.c b/src/utils/utils_module_tests.c index 4b97dadd786c..41511b9999a6 100644 --- a/src/utils/utils_module_tests.c +++ b/src/utils/utils_module_tests.c @@ -9,10 +9,13 @@ #include "utils/includes.h" #include "utils/common.h" +#include "common/ieee802_11_defs.h" #include "utils/bitfield.h" #include "utils/ext_password.h" #include "utils/trace.h" #include "utils/base64.h" +#include "utils/ip_addr.h" +#include "utils/eloop.h" struct printf_test_data { @@ -43,6 +46,7 @@ static int printf_encode_decode_tests(void) char buf[100]; u8 bin[100]; int errors = 0; + int array[10]; wpa_printf(MSG_INFO, "printf encode/decode tests"); @@ -91,9 +95,24 @@ static int printf_encode_decode_tests(void) if (printf_decode(bin, 3, "\\xa") != 1 || bin[0] != 10) errors++; + if (printf_decode(bin, 3, "\\xq") != 1 || bin[0] != 'q') + errors++; + if (printf_decode(bin, 3, "\\a") != 1 || bin[0] != 'a') errors++; + array[0] = 10; + array[1] = 10; + array[2] = 5; + array[3] = 10; + array[4] = 5; + array[5] = 0; + if (int_array_len(array) != 5) + errors++; + int_array_sort_unique(array); + if (int_array_len(array) != 2) + errors++; + if (errors) { wpa_printf(MSG_ERROR, "%d printf test(s) failed", errors); return -1; @@ -335,11 +354,14 @@ static int base64_tests(void) static int common_tests(void) { - char buf[3]; + char buf[3], longbuf[100]; u8 addr[ETH_ALEN] = { 1, 2, 3, 4, 5, 6 }; u8 bin[3]; int errors = 0; struct wpa_freq_range_list ranges; + size_t len; + const char *txt; + u8 ssid[255]; wpa_printf(MSG_INFO, "common tests"); @@ -395,6 +417,21 @@ static int common_tests(void) if (utf8_escape("a", 0, buf, sizeof(buf)) != 1 || buf[0] != 'a') errors++; + os_memset(ssid, 0, sizeof(ssid)); + txt = wpa_ssid_txt(ssid, sizeof(ssid)); + len = os_strlen(txt); + /* Verify that SSID_MAX_LEN * 4 buffer limit is enforced. */ + if (len != SSID_MAX_LEN * 4) { + wpa_printf(MSG_ERROR, + "Unexpected wpa_ssid_txt() result with too long SSID"); + errors++; + } + + if (wpa_snprintf_hex_sep(longbuf, 0, addr, ETH_ALEN, '-') != 0 || + wpa_snprintf_hex_sep(longbuf, 5, addr, ETH_ALEN, '-') != 3 || + os_strcmp(longbuf, "01-0") != 0) + errors++; + if (errors) { wpa_printf(MSG_ERROR, "%d common test(s) failed", errors); return -1; @@ -404,6 +441,403 @@ static int common_tests(void) } +static int os_tests(void) +{ + int errors = 0; + void *ptr; + os_time_t t; + + wpa_printf(MSG_INFO, "os tests"); + + ptr = os_calloc((size_t) -1, (size_t) -1); + if (ptr) { + errors++; + os_free(ptr); + } + ptr = os_calloc((size_t) 2, (size_t) -1); + if (ptr) { + errors++; + os_free(ptr); + } + ptr = os_calloc((size_t) -1, (size_t) 2); + if (ptr) { + errors++; + os_free(ptr); + } + + ptr = os_realloc_array(NULL, (size_t) -1, (size_t) -1); + if (ptr) { + errors++; + os_free(ptr); + } + + os_sleep(1, 1); + + if (os_mktime(1969, 1, 1, 1, 1, 1, &t) == 0 || + os_mktime(1971, 0, 1, 1, 1, 1, &t) == 0 || + os_mktime(1971, 13, 1, 1, 1, 1, &t) == 0 || + os_mktime(1971, 1, 0, 1, 1, 1, &t) == 0 || + os_mktime(1971, 1, 32, 1, 1, 1, &t) == 0 || + os_mktime(1971, 1, 1, -1, 1, 1, &t) == 0 || + os_mktime(1971, 1, 1, 24, 1, 1, &t) == 0 || + os_mktime(1971, 1, 1, 1, -1, 1, &t) == 0 || + os_mktime(1971, 1, 1, 1, 60, 1, &t) == 0 || + os_mktime(1971, 1, 1, 1, 1, -1, &t) == 0 || + os_mktime(1971, 1, 1, 1, 1, 61, &t) == 0 || + os_mktime(1971, 1, 1, 1, 1, 1, &t) != 0 || + os_mktime(2020, 1, 2, 3, 4, 5, &t) != 0 || + os_mktime(2015, 12, 31, 23, 59, 59, &t) != 0) + errors++; + + if (os_setenv("hwsim_test_env", "test value", 0) != 0 || + os_setenv("hwsim_test_env", "test value 2", 1) != 0 || + os_unsetenv("hwsim_test_env") != 0) + errors++; + + if (os_file_exists("/this-file-does-not-exists-hwsim") != 0) + errors++; + + if (errors) { + wpa_printf(MSG_ERROR, "%d os test(s) failed", errors); + return -1; + } + + return 0; +} + + +static int wpabuf_tests(void) +{ + int errors = 0; + void *ptr; + struct wpabuf *buf; + + wpa_printf(MSG_INFO, "wpabuf tests"); + + ptr = os_malloc(100); + if (ptr) { + buf = wpabuf_alloc_ext_data(ptr, 100); + if (buf) { + if (wpabuf_resize(&buf, 100) < 0) + errors++; + else + wpabuf_put(buf, 100); + wpabuf_free(buf); + } else { + errors++; + os_free(ptr); + } + } else { + errors++; + } + + buf = wpabuf_alloc(100); + if (buf) { + struct wpabuf *buf2; + + wpabuf_put(buf, 100); + if (wpabuf_resize(&buf, 100) < 0) + errors++; + else + wpabuf_put(buf, 100); + buf2 = wpabuf_concat(buf, NULL); + if (buf2 != buf) + errors++; + wpabuf_free(buf2); + } else { + errors++; + } + + buf = NULL; + buf = wpabuf_zeropad(buf, 10); + if (buf != NULL) + errors++; + + if (errors) { + wpa_printf(MSG_ERROR, "%d wpabuf test(s) failed", errors); + return -1; + } + + return 0; +} + + +static int ip_addr_tests(void) +{ + int errors = 0; + struct hostapd_ip_addr addr; + char buf[100]; + + wpa_printf(MSG_INFO, "ip_addr tests"); + + if (hostapd_parse_ip_addr("1.2.3.4", &addr) != 0 || + addr.af != AF_INET || + hostapd_ip_txt(NULL, buf, sizeof(buf)) != NULL || + hostapd_ip_txt(&addr, buf, 1) != buf || buf[0] != '\0' || + hostapd_ip_txt(&addr, buf, 0) != NULL || + hostapd_ip_txt(&addr, buf, sizeof(buf)) != buf) + errors++; + + if (hostapd_parse_ip_addr("::", &addr) != 0 || + addr.af != AF_INET6 || + hostapd_ip_txt(&addr, buf, 1) != buf || buf[0] != '\0' || + hostapd_ip_txt(&addr, buf, sizeof(buf)) != buf) + errors++; + + if (errors) { + wpa_printf(MSG_ERROR, "%d ip_addr test(s) failed", errors); + return -1; + } + + return 0; +} + + +struct test_eloop { + unsigned int magic; + int close_in_timeout; + int pipefd1[2]; + int pipefd2[2]; +}; + + +static void eloop_tests_start(int close_in_timeout); + + +static void eloop_test_read_2(int sock, void *eloop_ctx, void *sock_ctx) +{ + struct test_eloop *t = eloop_ctx; + ssize_t res; + char buf[10]; + + wpa_printf(MSG_INFO, "%s: sock=%d", __func__, sock); + + if (t->magic != 0x12345678) { + wpa_printf(MSG_INFO, "%s: unexpected magic 0x%x", + __func__, t->magic); + } + + if (t->pipefd2[0] != sock) { + wpa_printf(MSG_INFO, "%s: unexpected sock %d != %d", + __func__, sock, t->pipefd2[0]); + } + + res = read(sock, buf, sizeof(buf)); + wpa_printf(MSG_INFO, "%s: sock=%d --> res=%d", + __func__, sock, (int) res); +} + + +static void eloop_test_read_2_wrong(int sock, void *eloop_ctx, void *sock_ctx) +{ + struct test_eloop *t = eloop_ctx; + + wpa_printf(MSG_INFO, "%s: sock=%d", __func__, sock); + + if (t->magic != 0x12345678) { + wpa_printf(MSG_INFO, "%s: unexpected magic 0x%x", + __func__, t->magic); + } + + if (t->pipefd2[0] != sock) { + wpa_printf(MSG_INFO, "%s: unexpected sock %d != %d", + __func__, sock, t->pipefd2[0]); + } + + /* + * This is expected to block due to the original socket with data having + * been closed and no new data having been written to the new socket + * with the same fd. To avoid blocking the process during test, skip the + * read here. + */ + wpa_printf(MSG_ERROR, "%s: FAIL - should not have called this function", + __func__); +} + + +static void reopen_pipefd2(struct test_eloop *t) +{ + if (t->pipefd2[0] < 0) { + wpa_printf(MSG_INFO, "pipefd2 had been closed"); + } else { + int res; + + wpa_printf(MSG_INFO, "close pipefd2"); + eloop_unregister_read_sock(t->pipefd2[0]); + close(t->pipefd2[0]); + t->pipefd2[0] = -1; + close(t->pipefd2[1]); + t->pipefd2[1] = -1; + + res = pipe(t->pipefd2); + if (res < 0) { + wpa_printf(MSG_INFO, "pipe: %s", strerror(errno)); + t->pipefd2[0] = -1; + t->pipefd2[1] = -1; + return; + } + + wpa_printf(MSG_INFO, + "re-register pipefd2 with new sockets %d,%d", + t->pipefd2[0], t->pipefd2[1]); + eloop_register_read_sock(t->pipefd2[0], eloop_test_read_2_wrong, + t, NULL); + } +} + + +static void eloop_test_read_1(int sock, void *eloop_ctx, void *sock_ctx) +{ + struct test_eloop *t = eloop_ctx; + ssize_t res; + char buf[10]; + + wpa_printf(MSG_INFO, "%s: sock=%d", __func__, sock); + + if (t->magic != 0x12345678) { + wpa_printf(MSG_INFO, "%s: unexpected magic 0x%x", + __func__, t->magic); + } + + if (t->pipefd1[0] != sock) { + wpa_printf(MSG_INFO, "%s: unexpected sock %d != %d", + __func__, sock, t->pipefd1[0]); + } + + res = read(sock, buf, sizeof(buf)); + wpa_printf(MSG_INFO, "%s: sock=%d --> res=%d", + __func__, sock, (int) res); + + if (!t->close_in_timeout) + reopen_pipefd2(t); +} + + +static void eloop_test_cb(void *eloop_data, void *user_ctx) +{ + struct test_eloop *t = eloop_data; + + wpa_printf(MSG_INFO, "%s", __func__); + + if (t->magic != 0x12345678) { + wpa_printf(MSG_INFO, "%s: unexpected magic 0x%x", + __func__, t->magic); + } + + if (t->close_in_timeout) + reopen_pipefd2(t); +} + + +static void eloop_test_timeout(void *eloop_data, void *user_ctx) +{ + struct test_eloop *t = eloop_data; + int next_run = 0; + + wpa_printf(MSG_INFO, "%s", __func__); + + if (t->magic != 0x12345678) { + wpa_printf(MSG_INFO, "%s: unexpected magic 0x%x", + __func__, t->magic); + } + + if (t->pipefd1[0] >= 0) { + wpa_printf(MSG_INFO, "pipefd1 had not been closed"); + eloop_unregister_read_sock(t->pipefd1[0]); + close(t->pipefd1[0]); + t->pipefd1[0] = -1; + close(t->pipefd1[1]); + t->pipefd1[1] = -1; + } + + if (t->pipefd2[0] >= 0) { + wpa_printf(MSG_INFO, "pipefd2 had not been closed"); + eloop_unregister_read_sock(t->pipefd2[0]); + close(t->pipefd2[0]); + t->pipefd2[0] = -1; + close(t->pipefd2[1]); + t->pipefd2[1] = -1; + } + + next_run = t->close_in_timeout; + t->magic = 0; + wpa_printf(MSG_INFO, "%s - free(%p)", __func__, t); + os_free(t); + + if (next_run) + eloop_tests_start(0); +} + + +static void eloop_tests_start(int close_in_timeout) +{ + struct test_eloop *t; + int res; + + t = os_zalloc(sizeof(*t)); + if (!t) + return; + t->magic = 0x12345678; + t->close_in_timeout = close_in_timeout; + + wpa_printf(MSG_INFO, "starting eloop tests (%p) (close_in_timeout=%d)", + t, close_in_timeout); + + res = pipe(t->pipefd1); + if (res < 0) { + wpa_printf(MSG_INFO, "pipe: %s", strerror(errno)); + os_free(t); + return; + } + + res = pipe(t->pipefd2); + if (res < 0) { + wpa_printf(MSG_INFO, "pipe: %s", strerror(errno)); + close(t->pipefd1[0]); + close(t->pipefd1[1]); + os_free(t); + return; + } + + wpa_printf(MSG_INFO, "pipe fds: %d,%d %d,%d", + t->pipefd1[0], t->pipefd1[1], + t->pipefd2[0], t->pipefd2[1]); + + eloop_register_read_sock(t->pipefd1[0], eloop_test_read_1, t, NULL); + eloop_register_read_sock(t->pipefd2[0], eloop_test_read_2, t, NULL); + eloop_register_timeout(0, 0, eloop_test_cb, t, NULL); + eloop_register_timeout(0, 200000, eloop_test_timeout, t, NULL); + + if (write(t->pipefd1[1], "HELLO", 5) < 0) + wpa_printf(MSG_INFO, "write: %s", strerror(errno)); + if (write(t->pipefd2[1], "TEST", 4) < 0) + wpa_printf(MSG_INFO, "write: %s", strerror(errno)); + os_sleep(0, 50000); + wpa_printf(MSG_INFO, "waiting for eloop callbacks"); +} + + +static void eloop_tests_run(void *eloop_data, void *user_ctx) +{ + eloop_tests_start(1); +} + + +static int eloop_tests(void) +{ + wpa_printf(MSG_INFO, "schedule eloop tests to be run"); + + /* + * Cannot return error from these without a significant design change, + * so for now, run the tests from a scheduled timeout and require + * separate verification of the results from the debug log. + */ + eloop_register_timeout(0, 0, eloop_tests_run, NULL, NULL); + + return 0; +} + + int utils_module_tests(void) { int ret = 0; @@ -416,6 +850,10 @@ int utils_module_tests(void) bitfield_tests() < 0 || base64_tests() < 0 || common_tests() < 0 || + os_tests() < 0 || + wpabuf_tests() < 0 || + ip_addr_tests() < 0 || + eloop_tests() < 0 || int_array_tests() < 0) ret = -1; diff --git a/src/utils/wpa_debug.c b/src/utils/wpa_debug.c index 0d1190518536..61c0d5ce68c7 100644 --- a/src/utils/wpa_debug.c +++ b/src/utils/wpa_debug.c @@ -307,7 +307,7 @@ static void _wpa_hexdump(int level, const char *title, const u8 *buf, "%s - hexdump(len=%lu):%s%s", title, (long unsigned int) len, display, len > slen ? " ..." : ""); - os_free(strbuf); + bin_clear_free(strbuf, 1 + 3 * slen); return; } #else /* CONFIG_ANDROID_LOG */ @@ -339,7 +339,7 @@ static void _wpa_hexdump(int level, const char *title, const u8 *buf, syslog(syslog_priority(level), "%s - hexdump(len=%lu):%s", title, (unsigned long) len, display); - os_free(strbuf); + bin_clear_free(strbuf, 1 + 3 * len); return; } #endif /* CONFIG_DEBUG_SYSLOG */ @@ -635,8 +635,8 @@ void wpa_msg(void *ctx, int level, const char *fmt, ...) va_end(ap); wpa_printf(level, "%s%s", prefix, buf); if (wpa_msg_cb) - wpa_msg_cb(ctx, level, 0, buf, len); - os_free(buf); + wpa_msg_cb(ctx, level, WPA_MSG_PER_INTERFACE, buf, len); + bin_clear_free(buf, buflen); } @@ -663,8 +663,8 @@ void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...) va_start(ap, fmt); len = vsnprintf(buf, buflen, fmt, ap); va_end(ap); - wpa_msg_cb(ctx, level, 0, buf, len); - os_free(buf); + wpa_msg_cb(ctx, level, WPA_MSG_PER_INTERFACE, buf, len); + bin_clear_free(buf, buflen); } @@ -690,8 +690,8 @@ void wpa_msg_global(void *ctx, int level, const char *fmt, ...) va_end(ap); wpa_printf(level, "%s", buf); if (wpa_msg_cb) - wpa_msg_cb(ctx, level, 1, buf, len); - os_free(buf); + wpa_msg_cb(ctx, level, WPA_MSG_GLOBAL, buf, len); + bin_clear_free(buf, buflen); } @@ -718,8 +718,8 @@ void wpa_msg_global_ctrl(void *ctx, int level, const char *fmt, ...) va_start(ap, fmt); len = vsnprintf(buf, buflen, fmt, ap); va_end(ap); - wpa_msg_cb(ctx, level, 1, buf, len); - os_free(buf); + wpa_msg_cb(ctx, level, WPA_MSG_GLOBAL, buf, len); + bin_clear_free(buf, buflen); } @@ -745,7 +745,34 @@ void wpa_msg_no_global(void *ctx, int level, const char *fmt, ...) va_end(ap); wpa_printf(level, "%s", buf); if (wpa_msg_cb) - wpa_msg_cb(ctx, level, 2, buf, len); + wpa_msg_cb(ctx, level, WPA_MSG_NO_GLOBAL, buf, len); + bin_clear_free(buf, buflen); +} + + +void wpa_msg_global_only(void *ctx, int level, const char *fmt, ...) +{ + va_list ap; + char *buf; + int buflen; + int len; + + va_start(ap, fmt); + buflen = vsnprintf(NULL, 0, fmt, ap) + 1; + va_end(ap); + + buf = os_malloc(buflen); + if (buf == NULL) { + wpa_printf(MSG_ERROR, "%s: Failed to allocate message buffer", + __func__); + return; + } + va_start(ap, fmt); + len = vsnprintf(buf, buflen, fmt, ap); + va_end(ap); + wpa_printf(level, "%s", buf); + if (wpa_msg_cb) + wpa_msg_cb(ctx, level, WPA_MSG_ONLY_GLOBAL, buf, len); os_free(buf); } @@ -789,6 +816,45 @@ void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level, MAC2STR(addr), buf); else wpa_printf(MSG_DEBUG, "hostapd_logger: %s", buf); - os_free(buf); + bin_clear_free(buf, buflen); } #endif /* CONFIG_NO_HOSTAPD_LOGGER */ + + +const char * debug_level_str(int level) +{ + switch (level) { + case MSG_EXCESSIVE: + return "EXCESSIVE"; + case MSG_MSGDUMP: + return "MSGDUMP"; + case MSG_DEBUG: + return "DEBUG"; + case MSG_INFO: + return "INFO"; + case MSG_WARNING: + return "WARNING"; + case MSG_ERROR: + return "ERROR"; + default: + return "?"; + } +} + + +int str_to_debug_level(const char *s) +{ + if (os_strcasecmp(s, "EXCESSIVE") == 0) + return MSG_EXCESSIVE; + if (os_strcasecmp(s, "MSGDUMP") == 0) + return MSG_MSGDUMP; + if (os_strcasecmp(s, "DEBUG") == 0) + return MSG_DEBUG; + if (os_strcasecmp(s, "INFO") == 0) + return MSG_INFO; + if (os_strcasecmp(s, "WARNING") == 0) + return MSG_WARNING; + if (os_strcasecmp(s, "ERROR") == 0) + return MSG_ERROR; + return -1; +} diff --git a/src/utils/wpa_debug.h b/src/utils/wpa_debug.h index 400bea9e599f..17d8f963802e 100644 --- a/src/utils/wpa_debug.h +++ b/src/utils/wpa_debug.h @@ -164,6 +164,7 @@ void wpa_hexdump_ascii_key(int level, const char *title, const void *buf, #define wpa_msg_global(args...) do { } while (0) #define wpa_msg_global_ctrl(args...) do { } while (0) #define wpa_msg_no_global(args...) do { } while (0) +#define wpa_msg_global_only(args...) do { } while (0) #define wpa_msg_register_cb(f) do { } while (0) #define wpa_msg_register_ifname_cb(f) do { } while (0) #else /* CONFIG_NO_WPA_MSG */ @@ -243,7 +244,28 @@ PRINTF_FORMAT(3, 4); void wpa_msg_no_global(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4); -typedef void (*wpa_msg_cb_func)(void *ctx, int level, int global, +/** + * wpa_msg_global_only - Conditional printf for ctrl_iface monitors + * @ctx: Pointer to context data; this is the ctx variable registered + * with struct wpa_driver_ops::init() + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. + * This function is like wpa_msg_global(), but it sends the output only as a + * global event. + */ +void wpa_msg_global_only(void *ctx, int level, const char *fmt, ...) +PRINTF_FORMAT(3, 4); + +enum wpa_msg_type { + WPA_MSG_PER_INTERFACE, + WPA_MSG_GLOBAL, + WPA_MSG_NO_GLOBAL, + WPA_MSG_ONLY_GLOBAL, +}; + +typedef void (*wpa_msg_cb_func)(void *ctx, int level, enum wpa_msg_type type, const char *txt, size_t len); /** @@ -342,4 +364,7 @@ static inline void wpa_debug_close_linux_tracing(void) #define WPA_ASSERT(a) do { } while (0) #endif +const char * debug_level_str(int level); +int str_to_debug_level(const char *s); + #endif /* WPA_DEBUG_H */ diff --git a/src/utils/wpabuf.c b/src/utils/wpabuf.c index 7aafa0a5169b..11e7323619de 100644 --- a/src/utils/wpabuf.c +++ b/src/utils/wpabuf.c @@ -17,7 +17,7 @@ struct wpabuf_trace { unsigned int magic; -}; +} __attribute__((aligned(8))); static struct wpabuf_trace * wpabuf_get_trace(const struct wpabuf *buf) { |
