/* * wpa_supplicant/hostapd / common helper functions, etc. * Copyright (c) 2002-2019, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #include "includes.h" #include #include #include "common/ieee802_11_defs.h" #include "common.h" static int hex2num(char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return c - 'a' + 10; if (c >= 'A' && c <= 'F') return c - 'A' + 10; return -1; } int hex2byte(const char *hex) { int a, b; a = hex2num(*hex++); if (a < 0) return -1; b = hex2num(*hex++); if (b < 0) return -1; return (a << 4) | b; } /** * hwaddr_aton2 - Convert ASCII string to MAC address (in any known format) * @txt: MAC address as a string (e.g., 00:11:22:33:44:55 or 0011.2233.4455) * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes) * Returns: Characters used (> 0) on success, -1 on failure */ int hwaddr_aton2(const char *txt, u8 *addr) { int i; const char *pos = txt; for (i = 0; i < 6; i++) { int a, b; while (*pos == ':' || *pos == '.' || *pos == '-') pos++; a = hex2num(*pos++); if (a < 0) return -1; b = hex2num(*pos++); if (b < 0) return -1; *addr++ = (a << 4) | b; } return pos - txt; } /** * hexstr2bin - Convert ASCII hex string into binary data * @hex: ASCII hex string (e.g., "01ab") * @buf: Buffer for the binary data * @len: Length of the text to convert in bytes (of buf); hex will be double * this size * Returns: 0 on success, -1 on failure (invalid hex string) */ int hexstr2bin(const char *hex, u8 *buf, size_t len) { size_t i; int a; const char *ipos = hex; u8 *opos = buf; for (i = 0; i < len; i++) { a = hex2byte(ipos); if (a < 0) return -1; *opos++ = a; ipos += 2; } return 0; } /** * inc_byte_array - Increment arbitrary length byte array by one * @counter: Pointer to byte array * @len: Length of the counter in bytes * * This function increments the last byte of the counter by one and continues * rolling over to more significant bytes if the byte was incremented from * 0xff to 0x00. */ void inc_byte_array(u8 *counter, size_t len) { int pos = len - 1; while (pos >= 0) { counter[pos]++; if (counter[pos] != 0) break; pos--; } } void wpa_get_ntp_timestamp(u8 *buf) { struct os_time now; u32 sec, usec; be32 tmp; /* 64-bit NTP timestamp (time from 1900-01-01 00:00:00) */ os_get_time(&now); sec = now.sec + 2208988800U; /* Epoch to 1900 */ /* Estimate 2^32/10^6 = 4295 - 1/32 - 1/512 */ usec = now.usec; usec = 4295 * usec - (usec >> 5) - (usec >> 9); tmp = host_to_be32(sec); os_memcpy(buf, (u8 *) &tmp, 4); tmp = host_to_be32(usec); os_memcpy(buf + 4, (u8 *) &tmp, 4); } void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len) { char *end = txt + maxlen; size_t i; for (i = 0; i < len; i++) { if (txt + 4 >= end) break; switch (data[i]) { case '\"': *txt++ = '\\'; *txt++ = '\"'; break; case '\\': *txt++ = '\\'; *txt++ = '\\'; break; case '\033': *txt++ = '\\'; *txt++ = 'e'; break; case '\n': *txt++ = '\\'; *txt++ = 'n'; break; case '\r': *txt++ = '\\'; *txt++ = 'r'; break; case '\t': *txt++ = '\\'; *txt++ = 't'; break; default: if (data[i] >= 32 && data[i] <= 126) { *txt++ = data[i]; } else { txt += os_snprintf(txt, end - txt, "\\x%02x", data[i]); } break; } } *txt = '\0'; } size_t printf_decode(u8 *buf, size_t maxlen, const char *str) { const char *pos = str; size_t len = 0; int val; while (*pos) { if (len + 1 >= maxlen) break; switch (*pos) { case '\\': pos++; switch (*pos) { case '\\': buf[len++] = '\\'; pos++; break; case '"': buf[len++] = '"'; pos++; break; case 'n': buf[len++] = '\n'; pos++; break; case 'r': buf[len++] = '\r'; pos++; break; case 't': buf[len++] = '\t'; pos++; break; case 'e': buf[len++] = '\033'; pos++; break; case 'x': pos++; val = hex2byte(pos); if (val < 0) { val = hex2num(*pos); if (val < 0) break; buf[len++] = val; pos++; } else { buf[len++] = val; pos += 2; } break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': val = *pos++ - '0'; if (*pos >= '0' && *pos <= '7') val = val * 8 + (*pos++ - '0'); if (*pos >= '0' && *pos <= '7') val = val * 8 + (*pos++ - '0'); buf[len++] = val; break; default: break; } break; default: buf[len++] = *pos++; break; } } if (maxlen > len) buf[len] = '\0'; return len; } /** * wpa_ssid_txt - Convert SSID to a printable string * @ssid: SSID (32-octet string) * @ssid_len: Length of ssid in octets * Returns: Pointer to a printable string * * This function can be used to convert SSIDs into printable form. In most * cases, SSIDs do not use unprintable characters, but IEEE 802.11 standard * does not limit the used character set, so anything could be used in an SSID. * * This function uses a static buffer, so only one call can be used at the * time, i.e., this is not re-entrant and the returned buffer must be used * before calling this again. */ const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len) { static char ssid_txt[SSID_MAX_LEN * 4 + 1]; if (ssid == NULL) { ssid_txt[0] = '\0'; return ssid_txt; } printf_encode(ssid_txt, sizeof(ssid_txt), ssid, ssid_len); return ssid_txt; } void * __hide_aliasing_typecast(void *foo) { return foo; } char * wpa_config_parse_string(const char *value, size_t *len) { if (*value == '"') { const char *pos; char *str; value++; pos = os_strrchr(value, '"'); if (pos == NULL || pos[1] != '\0') return NULL; *len = pos - value; str = dup_binstr(value, *len); if (str == NULL) return NULL; return str; } else if (*value == 'P' && value[1] == '"') { const char *pos; char *tstr, *str; size_t tlen; value += 2; pos = os_strrchr(value, '"'); if (pos == NULL || pos[1] != '\0') return NULL; tlen = pos - value; tstr = dup_binstr(value, tlen); if (tstr == NULL) return NULL; str = os_malloc(tlen + 1); if (str == NULL) { os_free(tstr); return NULL; } *len = printf_decode((u8 *) str, tlen + 1, tstr); os_free(tstr); return str; } else { u8 *str; size_t tlen, hlen = os_strlen(value); #ifndef ESP_SUPPLICANT if (hlen & 1) return NULL; #else if (hlen == 5 || hlen == 13) { *len = hlen; str = (u8 *)os_malloc(*len + 1); if (str == NULL) { return NULL; } memcpy(str, value, *len); str[*len] = '\0'; return (char *) str; } #endif tlen = hlen / 2; str = os_malloc(tlen + 1); if (str == NULL) return NULL; if (hexstr2bin(value, str, tlen)) { os_free(str); return NULL; } str[tlen] = '\0'; *len = tlen; return (char *) str; } } int wpa_is_hex(const u8 *data, size_t len) { size_t i; for (i = 0; i < len; i++) { if (data[i] < 32 || data[i] >= 127) return 1; } return 0; } int has_ctrl_char(const u8 *data, size_t len) { size_t i; for (i = 0; i < len; i++) { if (data[i] < 32 || data[i] == 127) return 1; } return 0; } size_t wpa_merge_byte_arrays(u8 *res, size_t res_len, const u8 *src1, size_t src1_len, const u8 *src2, size_t src2_len) { size_t len = 0; os_memset(res, 0, res_len); if (src1) { if (src1_len >= res_len) { os_memcpy(res, src1, res_len); return res_len; } os_memcpy(res, src1, src1_len); len += src1_len; } if (src2) { if (len + src2_len >= res_len) { os_memcpy(res + len, src2, res_len - len); return res_len; } os_memcpy(res + len, src2, src2_len); len += src2_len; } return len; } char * dup_binstr(const void *src, size_t len) { char *res; if (src == NULL) return NULL; res = os_malloc(len + 1); if (res == NULL) return NULL; os_memcpy(res, src, len); res[len] = '\0'; return res; } size_t int_array_len(const int *a) { size_t i; for (i = 0; a && a[i]; i++) ; return i; } void str_clear_free(char *str) { if (str) { size_t len = os_strlen(str); forced_memzero(str, len); os_free(str); } } void bin_clear_free(void *bin, size_t len) { if (bin) { forced_memzero(bin, len); os_free(bin); } } 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; } int os_mktime(int year, int month, int day, int hour, int min, int sec, os_time_t *t) { struct tm tm; if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 || hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 || sec > 60) return -1; os_memset(&tm, 0, sizeof(tm)); tm.tm_year = year - 1900; tm.tm_mon = month - 1; tm.tm_mday = day; tm.tm_hour = hour; tm.tm_min = min; tm.tm_sec = sec; *t = (os_time_t) mktime(&tm); return 0; } void * os_memdup(const void *src, size_t len) { void *r = os_malloc(len); if (r && src) os_memcpy(r, src, len); return r; } int os_reltime_expired(struct os_time *now, struct os_time *ts, os_time_t timeout_secs) { struct os_time age; os_time_sub(now, ts, &age); return (age.sec > timeout_secs) || (age.sec == timeout_secs && age.usec > 0); } u8 rssi_to_rcpi(int rssi) { if (!rssi) return 255; /* not available */ if (rssi < -110) return 0; if (rssi > 0) return 220; return (rssi + 110) * 2; } char * get_param(const char *cmd, const char *param) { const char *pos, *end; char *val; size_t len; pos = os_strstr(cmd, param); if (!pos) return NULL; pos += os_strlen(param); end = os_strchr(pos, ' '); if (end) len = end - pos; else len = os_strlen(pos); val = os_malloc(len + 1); if (!val) return NULL; os_memcpy(val, pos, len); val[len] = '\0'; return val; }