Fix spelling mistakes in number of comments
[mech_eap.git] / src / utils / common.c
index 182c6a8..04a533a 100644 (file)
@@ -8,6 +8,7 @@
 
 #include "includes.h"
 
+#include "common/ieee802_11_defs.h"
 #include "common.h"
 
 
@@ -36,6 +37,25 @@ int hex2byte(const char *hex)
 }
 
 
+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")
@@ -44,25 +64,46 @@ int hex2byte(const char *hex)
  */
 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")
@@ -144,6 +185,30 @@ int hexstr2bin(const char *hex, u8 *buf, size_t len)
 }
 
 
+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
@@ -213,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)
 {
@@ -408,7 +498,7 @@ void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len)
                        *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",
@@ -520,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';
@@ -607,6 +697,29 @@ int is_hex(const u8 *data, size_t len)
 }
 
 
+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)
@@ -883,6 +996,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
+ *      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
@@ -892,23 +1047,156 @@ int random_mac_addr_keep_oui(u8 *addr)
  */
 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;
 }