#include "includes.h"
+#include "common/ieee802_11_defs.h"
#include "common.h"
}
+static const char * hwaddr_parse(const char *txt, u8 *addr)
+{
+ size_t i;
+
+ for (i = 0; i < ETH_ALEN; i++) {
+ int a;
+
+ a = hex2byte(txt);
+ if (a < 0)
+ return NULL;
+ txt += 2;
+ addr[i] = a;
+ if (i < ETH_ALEN - 1 && *txt++ != ':')
+ return NULL;
+ }
+ return txt;
+}
+
+
/**
* hwaddr_aton - Convert ASCII string to MAC address (colon-delimited format)
* @txt: MAC address as a string (e.g., "00:11:22:33:44:55")
*/
int hwaddr_aton(const char *txt, u8 *addr)
{
- int i;
+ return hwaddr_parse(txt, addr) ? 0 : -1;
+}
- for (i = 0; i < 6; i++) {
- int a, b;
- a = hex2num(*txt++);
- if (a < 0)
- return -1;
- b = hex2num(*txt++);
- if (b < 0)
- return -1;
- *addr++ = (a << 4) | b;
- if (i < 5 && *txt++ != ':')
+/**
+ * hwaddr_masked_aton - Convert ASCII string with optional mask to MAC address (colon-delimited format)
+ * @txt: MAC address with optional mask as a string (e.g., "00:11:22:33:44:55/ff:ff:ff:ff:00:00")
+ * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
+ * @mask: Buffer for the MAC address mask (ETH_ALEN = 6 bytes)
+ * @maskable: Flag to indicate whether a mask is allowed
+ * Returns: 0 on success, -1 on failure (e.g., string not a MAC address)
+ */
+int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable)
+{
+ const char *r;
+
+ /* parse address part */
+ r = hwaddr_parse(txt, addr);
+ if (!r)
+ return -1;
+
+ /* check for optional mask */
+ if (*r == '\0' || isspace((unsigned char) *r)) {
+ /* no mask specified, assume default */
+ os_memset(mask, 0xff, ETH_ALEN);
+ } else if (maskable && *r == '/') {
+ /* mask specified and allowed */
+ r = hwaddr_parse(r + 1, mask);
+ /* parser error? */
+ if (!r)
return -1;
+ } else {
+ /* mask specified but not allowed or trailing garbage */
+ return -1;
}
return 0;
}
+
/**
* hwaddr_compact_aton - Convert ASCII string to MAC address (no colon delimitors format)
* @txt: MAC address as a string (e.g., "001122334455")
}
+int hwaddr_mask_txt(char *buf, size_t len, const u8 *addr, const u8 *mask)
+{
+ size_t i;
+ int print_mask = 0;
+ int res;
+
+ for (i = 0; i < ETH_ALEN; i++) {
+ if (mask[i] != 0xff) {
+ print_mask = 1;
+ break;
+ }
+ }
+
+ if (print_mask)
+ res = os_snprintf(buf, len, MACSTR "/" MACSTR,
+ MAC2STR(addr), MAC2STR(mask));
+ else
+ res = os_snprintf(buf, len, MACSTR, MAC2STR(addr));
+ if (os_snprintf_error(len, res))
+ return -1;
+ return res;
+}
+
+
/**
* inc_byte_array - Increment arbitrary length byte array by one
* @counter: Pointer to byte array
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)
{
*txt++ = 't';
break;
default:
- if (data[i] >= 32 && data[i] <= 127) {
+ if (data[i] >= 32 && data[i] <= 126) {
*txt++ = data[i];
} else {
txt += os_snprintf(txt, end - txt, "\\x%02x",
*/
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';
}
+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;
+}
+
+
+int has_newline(const char *str)
+{
+ while (*str) {
+ if (*str == '\n' || *str == '\r')
+ return 1;
+ str++;
+ }
+ return 0;
+}
+
+
size_t merge_byte_arrays(u8 *res, size_t res_len,
const u8 *src1, size_t src1_len,
const u8 *src2, size_t src2_len)
/**
+ * 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
+ * further 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
*/
char * str_token(char *str, const char *delim, char **context)
{
- char *end, *pos = str;
+ char *token = (char *) cstr_token(str, delim, (const char **) context);
- if (*context)
- pos = *context;
+ if (token && **context)
+ *(*context)++ = '\0';
- while (*pos && os_strchr(delim, *pos))
- pos++;
- if (!*pos)
- return NULL;
+ return token;
+}
+
+
+size_t utf8_unescape(const char *inp, size_t in_size,
+ char *outp, size_t out_size)
+{
+ size_t res_size = 0;
+
+ if (!inp || !outp)
+ return 0;
+
+ if (!in_size)
+ in_size = os_strlen(inp);
+
+ /* Advance past leading single quote */
+ if (*inp == '\'' && in_size) {
+ inp++;
+ in_size--;
+ }
+
+ while (in_size--) {
+ if (res_size >= out_size)
+ return 0;
+
+ switch (*inp) {
+ case '\'':
+ /* Terminate on bare single quote */
+ *outp = '\0';
+ return res_size;
+
+ case '\\':
+ if (!in_size--)
+ return 0;
+ inp++;
+ /* fall through */
+
+ default:
+ *outp++ = *inp++;
+ res_size++;
+ }
+ }
+
+ /* NUL terminate if space allows */
+ if (res_size < out_size)
+ *outp = '\0';
+
+ return res_size;
+}
- end = pos + 1;
- while (*end && !os_strchr(delim, *end))
- end++;
- if (*end)
- *end++ = '\0';
+size_t utf8_escape(const char *inp, size_t in_size,
+ char *outp, size_t out_size)
+{
+ size_t res_size = 0;
+
+ if (!inp || !outp)
+ return 0;
- *context = end;
- return pos;
+ /* inp may or may not be NUL terminated, but must be if 0 size
+ * is specified */
+ if (!in_size)
+ in_size = os_strlen(inp);
+
+ while (in_size--) {
+ if (res_size++ >= out_size)
+ return 0;
+
+ switch (*inp) {
+ case '\\':
+ case '\'':
+ if (res_size++ >= out_size)
+ return 0;
+ *outp++ = '\\';
+ /* fall through */
+
+ default:
+ *outp++ = *inp++;
+ break;
+ }
+ }
+
+ /* NUL terminate if space allows */
+ if (res_size < out_size)
+ *outp = '\0';
+
+ return res_size;
+}
+
+
+int is_ctrl_char(char c)
+{
+ return c > 0 && c < 32;
+}
+
+
+/**
+ * ssid_parse - Parse a string that contains SSID in hex or text format
+ * @buf: Input NULL terminated string that contains the SSID
+ * @ssid: Output SSID
+ * Returns: 0 on success, -1 otherwise
+ *
+ * The SSID has to be enclosed in double quotes for the text format or space
+ * or NULL terminated string of hex digits for the hex format. buf can include
+ * additional arguments after the SSID.
+ */
+int ssid_parse(const char *buf, struct wpa_ssid_value *ssid)
+{
+ char *tmp, *res, *end;
+ size_t len;
+
+ ssid->ssid_len = 0;
+
+ tmp = os_strdup(buf);
+ if (!tmp)
+ return -1;
+
+ if (*tmp != '"') {
+ end = os_strchr(tmp, ' ');
+ if (end)
+ *end = '\0';
+ } else {
+ end = os_strchr(tmp + 1, '"');
+ if (!end) {
+ os_free(tmp);
+ return -1;
+ }
+
+ end[1] = '\0';
+ }
+
+ res = wpa_config_parse_string(tmp, &len);
+ if (res && len <= SSID_MAX_LEN) {
+ ssid->ssid_len = len;
+ os_memcpy(ssid->ssid, res, len);
+ }
+
+ os_free(tmp);
+ os_free(res);
+
+ return ssid->ssid_len ? 0 : -1;
+}
+
+
+int str_starts(const char *str, const char *start)
+{
+ return os_strncmp(str, start, os_strlen(start)) == 0;
}