[PATCH 1/2] dpp: unref DPP frame if sending fails
by James Prestwood
---
src/dpp.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/dpp.c b/src/dpp.c
index 54947193..f62bcebb 100644
--- a/src/dpp.c
+++ b/src/dpp.c
@@ -219,8 +219,10 @@ static void dpp_send_frame(uint64_t wdev_id, struct iovec *iov, size_t iov_len,
l_debug("Sending frame on frequency %u", freq);
- if (!l_genl_family_send(nl80211, msg, dpp_send_frame_cb, NULL, NULL))
+ if (!l_genl_family_send(nl80211, msg, dpp_send_frame_cb, NULL, NULL)) {
l_error("Could not send CMD_FRAME");
+ l_genl_msg_unref(msg);
+ }
}
static size_t dpp_build_header(const uint8_t *src, const uint8_t *dest,
--
2.31.1
5 months, 2 weeks
[PATCH 1/2] dpp: parse configuration request values
by James Prestwood
With better JSON support the configuration request object
can now be fully parsed. As stated in the previous comment
there really isn't much use from the configurator side apart
from verifying mandatory values are included.
This patch also modifies the configuration result to handle
sending non 'OK' status codes in case of JSON parsing errors.
---
src/dpp.c | 76 ++++++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 58 insertions(+), 18 deletions(-)
diff --git a/src/dpp.c b/src/dpp.c
index 5f25f1c2..dedbd3b2 100644
--- a/src/dpp.c
+++ b/src/dpp.c
@@ -579,14 +579,13 @@ static void dpp_handle_config_response_frame(const struct mmpdu_header *frame,
send_config_result(dpp, dpp->auth_addr);
}
-static void dpp_send_config_response(struct dpp_sm *dpp)
+static void dpp_send_config_response(struct dpp_sm *dpp, uint8_t status)
{
- _auto_(l_free) char *json;
+ _auto_(l_free) char *json = NULL;
struct iovec iov[3];
uint8_t hdr[41];
uint8_t attrs[512];
size_t json_len;
- uint8_t zero = 0;
uint8_t *ptr = hdr + 24;
l_put_le16(0x00d0, hdr);
@@ -611,9 +610,6 @@ static void dpp_send_config_response(struct dpp_sm *dpp)
*ptr++ = 0x1a;
*ptr++ = 1;
- json = dpp_configuration_to_json(dpp->config);
- json_len = strlen(json);
-
iov[0].iov_base = hdr;
iov[0].iov_len = ptr - hdr;
@@ -621,12 +617,31 @@ static void dpp_send_config_response(struct dpp_sm *dpp)
ptr += 2; /* length */
- ptr += dpp_append_attr(ptr, DPP_ATTR_STATUS, &zero, 1);
+ ptr += dpp_append_attr(ptr, DPP_ATTR_STATUS, &status, 1);
- ptr += dpp_append_wrapped_data(attrs + 2, ptr - attrs - 2, NULL, 0, ptr,
- sizeof(attrs), dpp->ke, dpp->key_len, 2,
- DPP_ATTR_ENROLLEE_NONCE, dpp->nonce_len, dpp->e_nonce,
- DPP_ATTR_CONFIGURATION_OBJECT, json_len, json);
+ /*
+ * There are several failure status codes that can be used (defined in
+ * 6.4.3.1), each with their own set of attributes that should be
+ * included. For now IWD's basic DPP implementation will assume
+ * STATUS_CONFIGURE_FAILURE which only includes the E-Nonce.
+ */
+ if (status == DPP_STATUS_OK) {
+ json = dpp_configuration_to_json(dpp->config);
+ json_len = strlen(json);
+
+ ptr += dpp_append_wrapped_data(attrs + 2, ptr - attrs - 2,
+ NULL, 0, ptr, sizeof(attrs),
+ dpp->ke, dpp->key_len, 2,
+ DPP_ATTR_ENROLLEE_NONCE,
+ dpp->nonce_len, dpp->e_nonce,
+ DPP_ATTR_CONFIGURATION_OBJECT,
+ json_len, json);
+ } else
+ ptr += dpp_append_wrapped_data(attrs + 2, ptr - attrs - 2,
+ NULL, 0, ptr, sizeof(attrs),
+ dpp->ke, dpp->key_len, 2,
+ DPP_ATTR_ENROLLEE_NONCE,
+ dpp->nonce_len, dpp->e_nonce);
l_put_le16(ptr - attrs - 2, attrs);
@@ -655,6 +670,9 @@ static void dpp_handle_config_request_frame(const struct mmpdu_header *frame,
_auto_(l_free) uint8_t *unwrapped = NULL;
uint8_t hdr_check[] = { IE_TYPE_ADVERTISEMENT_PROTOCOL, 0x08, 0x7f,
IE_TYPE_VENDOR_SPECIFIC, 5 };
+ struct json_iter jsiter;
+ _auto_(l_free) char *tech = NULL;
+ _auto_(l_free) char *role = NULL;
if (dpp->state != DPP_STATE_AUTHENTICATING) {
l_debug("Configuration request in wrong state");
@@ -747,25 +765,47 @@ static void dpp_handle_config_request_frame(const struct mmpdu_header *frame,
return;
}
- /*
- * TODO: Full JSON type support (arrays/numbers) is not yet implemented.
- * Just verify the JSON is valid for now. There really isn't much need
- * to parse this anyhow since IWD only supports configuring stations.
- * If this request is for anything else it will fail regardless.
- */
c = json_contents_new(json, json_len);
if (!c) {
json_contents_free(c);
return;
}
+ json_iter_init(&jsiter, c);
+
+ /*
+ * Check mandatory values (Table 7). There isn't much that can be done
+ * with these, but the spec requires they be included.
+ */
+ if (!json_iter_parse(&jsiter,
+ JSON_MANDATORY("name", JSON_STRING, NULL),
+ JSON_MANDATORY("wi-fi_tech", JSON_STRING, &tech),
+ JSON_MANDATORY("netRole", JSON_STRING, &role),
+ JSON_UNDEFINED))
+ goto configure_failure;
+
+ if (strcmp(tech, "infra"))
+ goto configure_failure;
+
+ if (strcmp(role, "sta"))
+ goto configure_failure;
+
json_contents_free(c);
memcpy(dpp->e_nonce, e_nonce, dpp->nonce_len);
dpp->state = DPP_STATE_CONFIGURING;
- dpp_send_config_response(dpp);
+ dpp_send_config_response(dpp, DPP_STATUS_OK);
+
+ return;
+
+configure_failure:
+ dpp_send_config_response(dpp, DPP_STATUS_CONFIGURE_FAILURE);
+ /*
+ * The other peer is still authenticated, and can potentially send
+ * additional requests so keep this session alive.
+ */
}
static void dpp_handle_config_result_frame(struct dpp_sm *dpp,
--
2.31.1
5 months, 2 weeks
[PATCH v2 1/5] json: add json_iter_get_string
by James Prestwood
---
src/json.c | 14 ++++++++++++++
src/json.h | 1 +
2 files changed, 15 insertions(+)
diff --git a/src/json.c b/src/json.c
index b48dba4a..b89fbaa6 100644
--- a/src/json.c
+++ b/src/json.c
@@ -398,6 +398,20 @@ bool json_iter_get_container(struct json_iter *iter,
return true;
}
+bool json_iter_get_string(struct json_iter *iter, char **s)
+{
+ struct json_contents *c = iter->contents;
+ jsmntok_t *t = c->tokens + iter->current;
+
+ if (t->type != JSMN_STRING)
+ return false;
+
+ if (s)
+ *s = TOK_TO_STR(c->json, t);
+
+ return true;
+}
+
enum json_type json_iter_get_type(struct json_iter *iter)
{
struct json_contents *c = iter->contents;
diff --git a/src/json.h b/src/json.h
index 518d778c..1db3428d 100644
--- a/src/json.h
+++ b/src/json.h
@@ -95,6 +95,7 @@ bool json_iter_get_boolean(struct json_iter *iter, bool *b);
bool json_iter_get_null(struct json_iter *iter);
bool json_iter_get_container(struct json_iter *iter,
struct json_iter *container);
+bool json_iter_get_string(struct json_iter *iter, char **s);
enum json_type json_iter_get_type(struct json_iter *iter);
bool json_iter_next(struct json_iter *iter);
--
2.31.1
5 months, 2 weeks
[PATCH 1/5] json: add json_iter_get_string
by James Prestwood
---
src/json.c | 14 ++++++++++++++
src/json.h | 1 +
2 files changed, 15 insertions(+)
diff --git a/src/json.c b/src/json.c
index b48dba4a..b89fbaa6 100644
--- a/src/json.c
+++ b/src/json.c
@@ -398,6 +398,20 @@ bool json_iter_get_container(struct json_iter *iter,
return true;
}
+bool json_iter_get_string(struct json_iter *iter, char **s)
+{
+ struct json_contents *c = iter->contents;
+ jsmntok_t *t = c->tokens + iter->current;
+
+ if (t->type != JSMN_STRING)
+ return false;
+
+ if (s)
+ *s = TOK_TO_STR(c->json, t);
+
+ return true;
+}
+
enum json_type json_iter_get_type(struct json_iter *iter)
{
struct json_contents *c = iter->contents;
diff --git a/src/json.h b/src/json.h
index 518d778c..1db3428d 100644
--- a/src/json.h
+++ b/src/json.h
@@ -95,6 +95,7 @@ bool json_iter_get_boolean(struct json_iter *iter, bool *b);
bool json_iter_get_null(struct json_iter *iter);
bool json_iter_get_container(struct json_iter *iter,
struct json_iter *container);
+bool json_iter_get_string(struct json_iter *iter, char **s);
enum json_type json_iter_get_type(struct json_iter *iter);
bool json_iter_next(struct json_iter *iter);
--
2.31.1
5 months, 2 weeks
[PATCH v2 1/9] json: fix find_object_tokens
by James Prestwood
First, this was renamed to 'count_tokens_in_container' to be
more general purpose (i.e. include future array counting).
The way the tokens are counted also changed to be more intuitive.
While the previous way was correct, it was somewhat convoluted in
how it worked (finding the next parent of the objects parent).
Instead we can use the container token itself as the parent and
begin counting tokens. When we find a token with a parent index
less than the target we have reached the end of this container.
This also works for nested containers, including arrays since we
no longer rely on a key (which an array element would not have).
For example::
{
"first":{"foo":"bar"},
"second":{"foo2":"bar2"}
}
index 0 <overall object>
index 1 "first" with parent 0
index 2 {"foo":"bar"} with parent 1
Counting tokens inside "first"'s object we have:
index 3 "foo" with parent 2
index 4 "bar" with parent 3
If we continue counting we reach:
index 5 "second" with parent 0
This terminates the counting loop since the parent index is
less than '2' (the index of {"foo":"bar"} object).
---
src/json.c | 20 ++++++++------------
1 file changed, 8 insertions(+), 12 deletions(-)
diff --git a/src/json.c b/src/json.c
index 39570e7e..a917fb89 100644
--- a/src/json.c
+++ b/src/json.c
@@ -69,20 +69,16 @@ static jsmntok_t *next_key_in_parent(struct json_iter *iter, jsmntok_t *current)
return NULL;
}
-/*
- * 'object' is expected to be a value, so object - 1 is its key. Find
- * the next key who's parent matches the parent of object - 1. The
- * token preceeding this next key will mark the end of 'object'.
- */
-static int find_object_tokens(struct json_iter *iter, jsmntok_t *object)
+static int count_tokens_in_container(struct json_iter *iter, jsmntok_t *container)
{
- jsmntok_t *next = next_key_in_parent(iter, object - 1);
+ int idx = container - iter->contents->tokens;
+ jsmntok_t *contents;
- /* End of token list */
- if (!next)
- next = ITER_END(iter);
+ for (contents = ++container; contents < ITER_END(iter); contents++)
+ if (contents->parent < idx)
+ break;
- return next - object - 1;
+ return contents - container;
}
static void iter_recurse(struct json_iter *iter, jsmntok_t *object,
@@ -92,7 +88,7 @@ static void iter_recurse(struct json_iter *iter, jsmntok_t *object,
child->contents = c;
child->start = object - c->tokens;
- child->count = find_object_tokens(iter, object);
+ child->count = count_tokens_in_container(iter, object);
}
struct json_contents *json_contents_new(const char *json, size_t json_len)
--
2.31.1
5 months, 2 weeks
[PATCH] dpp: use %zu for printing size_t
by James Prestwood
---
src/dpp.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/dpp.c b/src/dpp.c
index 9eb1d642..dedbd3b2 100644
--- a/src/dpp.c
+++ b/src/dpp.c
@@ -1272,7 +1272,7 @@ static void authenticate_request(struct dpp_sm *dpp, const uint8_t *from,
}
if (i_nonce_len != dpp->nonce_len) {
- l_debug("I-Nonce has unexpected length %lu", i_nonce_len);
+ l_debug("I-Nonce has unexpected length %zu", i_nonce_len);
goto auth_request_failed;
}
--
2.31.1
5 months, 3 weeks
[PATCH 1/8] json: add support for primitive types
by James Prestwood
This adds support for boolean, (unsigned) integers, and
null types. JSON_PRIMITIVE should be used as the type when
parsing and the value should be struct json_iter.
Once parsed the actual value can be obtained using one of
the primitive getters. If the type does not match they will
return false.
If using JSON_OPTIONAL with JSON_PRIMITIVE the resulting
iterator can be checked with json_iter_is_valid. If false
the key/value was not found or the type was not matching.
---
src/json.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++---
src/json.h | 13 ++++-
2 files changed, 143 insertions(+), 8 deletions(-)
diff --git a/src/json.c b/src/json.c
index 39570e7e..a83ba464 100644
--- a/src/json.c
+++ b/src/json.c
@@ -85,14 +85,26 @@ static int find_object_tokens(struct json_iter *iter, jsmntok_t *object)
return next - object - 1;
}
-static void iter_recurse(struct json_iter *iter, jsmntok_t *object,
+static void iter_recurse(struct json_iter *iter, jsmntok_t *token,
struct json_iter *child)
{
struct json_contents *c = iter->contents;
child->contents = c;
- child->start = object - c->tokens;
- child->count = find_object_tokens(iter, object);
+ child->start = token - c->tokens;
+
+ /*
+ * For objects iterating all tokens with the object as the parent
+ * parent should give the total number of tokens for this object.
+ *
+ * For strings/primitives the value is always going to one token which
+ * will not be iteratable. Because of this the count is set to zero to
+ * disallow any iteration on this child iterator.
+ */
+ if (token->type == JSMN_OBJECT)
+ child->count = find_object_tokens(iter, token);
+ else
+ child->count = 0;
}
struct json_contents *json_contents_new(const char *json, size_t json_len)
@@ -153,7 +165,7 @@ static void assign_arg(void *data, void *user_data)
struct json_arg *arg = data;
struct json_contents *c = iter->contents;
char **sval;
- struct json_iter *oval;
+ struct json_iter *iter_val;
switch (arg->type) {
case JSON_STRING:
@@ -163,12 +175,13 @@ static void assign_arg(void *data, void *user_data)
break;
case JSON_OBJECT:
- oval = arg->value;
+ case JSON_PRIMITIVE:
+ iter_val = arg->value;
if (!arg->v)
- oval->start = -1;
+ iter_val->start = -1;
else
- iter_recurse(iter, arg->v, oval);
+ iter_recurse(iter, arg->v, iter_val);
break;
default:
@@ -209,6 +222,7 @@ bool json_iter_parse(struct json_iter *iter, enum json_type type, ...)
goto done;
case JSON_STRING:
case JSON_OBJECT:
+ case JSON_PRIMITIVE:
break;
default:
goto error;
@@ -268,3 +282,113 @@ error:
l_queue_destroy(args, l_free);
return false;
}
+
+static bool iter_get_primitive_data(struct json_iter *iter, void **ptr,
+ size_t *len)
+{
+ struct json_contents *c = iter->contents;
+ jsmntok_t *t = c->tokens + iter->start;
+
+ if (t->type != JSMN_PRIMITIVE)
+ return false;
+
+ *ptr = TOK_PTR(c->json, t);
+ *len = TOK_LEN(t);
+
+ return true;
+}
+
+bool json_iter_get_int(struct json_iter *iter, int *i)
+{
+ void *ptr;
+ size_t len;
+ long int r;
+ int t;
+ char *endp;
+
+ if (json_iter_get_null(iter) || json_iter_get_boolean(iter, NULL))
+ return false;
+
+ if (!iter_get_primitive_data(iter, &ptr, &len))
+ return false;
+
+ errno = 0;
+
+ t = r = strtol(ptr, &endp, 0);
+ if (endp == ptr)
+ return false;
+
+ if (errno == ERANGE || r != t)
+ return false;
+
+ if (i)
+ *i = r;
+
+ return true;
+}
+
+bool json_iter_get_uint(struct json_iter *iter, unsigned int *i)
+{
+ void *ptr;
+ size_t len;
+ unsigned long int r;
+ unsigned int t;
+ char *endp;
+
+ if (json_iter_get_null(iter) || json_iter_get_boolean(iter, NULL))
+ return false;
+
+ if (!iter_get_primitive_data(iter, &ptr, &len))
+ return false;
+
+ errno = 0;
+
+ t = r = strtoul(ptr, &endp, 0);
+ if (endp == ptr)
+ return false;
+
+ if (errno == ERANGE || r != t)
+ return false;
+
+ if (i)
+ *i = r;
+
+ return true;
+}
+
+bool json_iter_get_boolean(struct json_iter *iter, bool *b)
+{
+ void *ptr;
+ size_t len;
+
+ if (!iter_get_primitive_data(iter, &ptr, &len))
+ return false;
+
+ if (len == 4 && !memcmp(ptr, "true", 4)) {
+ if (b)
+ *b = true;
+
+ return true;
+ } else if (len == 5 && !memcmp(ptr, "false", 5)) {
+ if (b)
+ *b = false;
+
+ return true;
+ }
+
+ return false;
+}
+
+bool json_iter_get_null(struct json_iter *iter)
+{
+ void *ptr;
+ size_t len;
+
+ if (!iter_get_primitive_data(iter, &ptr, &len))
+ return false;
+
+ if (len == 4 && !memcmp(ptr, "null", 4))
+ return true;
+
+ return false;
+}
diff --git a/src/json.h b/src/json.h
index 915b675b..9f00a9d5 100644
--- a/src/json.h
+++ b/src/json.h
@@ -73,11 +73,22 @@ void json_iter_init(struct json_iter *iter, struct json_contents *c);
*
* String values should be of type char ** and must be freed
* Object values should be of type struct json_iter *
+ * Primitive types (numbers, booleans, null) should be of type
+ * struct json_iter *. This is to allow the caller to distinguish
+ * between the actual value type after parsing using a getter for
+ * the expected type (get_uint/get_int/get_boolean etc.). In
+ * addition this lets the caller use JSON_OPTIONAL and check post
+ * json_iter_parse if the iterator is valid (json_iter_is_valid).
*
* No other types are supported at this time, and json_iter_parse will fail if
* other types are encountered.
*
* JSON_OPTIONAL string values will point to NULL if not found
- * JSON_OPTIONAL objects can be checked with json_object_not_found.
+ * JSON_OPTIONAL objects/primitives can be checked with json_object_is_valid.
*/
bool json_iter_parse(struct json_iter *iter, enum json_type type, ...);
+
+bool json_iter_get_int(struct json_iter *iter, int *i);
+bool json_iter_get_uint(struct json_iter *iter, unsigned int *i);
+bool json_iter_get_boolean(struct json_iter *iter, bool *b);
+bool json_iter_get_null(struct json_iter *iter);
--
2.31.1
5 months, 3 weeks
[PATCH] auto-t: iwd.py: use spaces instead of tabs
by James Prestwood
---
autotests/util/iwd.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/autotests/util/iwd.py b/autotests/util/iwd.py
index 4e69c7e8..54b4819e 100755
--- a/autotests/util/iwd.py
+++ b/autotests/util/iwd.py
@@ -710,7 +710,7 @@ class Network(IWDDBusAbstract):
Connect to the network. Request the device implied by the object
path to connect to specified network.
- Possible exception: AbortedEx
+ Possible exception: AbortedEx
BusyEx
FailedEx
NoAgentEx
--
2.31.1
5 months, 3 weeks
[PATCH 1/6] auto-t: wpas.py: don't require strict match on wait_for_event
by James Prestwood
wait_for_event was checking the event string presence in the rx_data
array which meant the event string had to match perfectly to any
received events. This poses problems with events that include additional
information which the caller may not be able to know or does not care
about. For example:
DPP-RX src=02:00:00:00:02:00 freq=2437 type=11
Waiting for this event previously would require the caller know src, freq,
and type. If the caller only wants to wait for DPP-RX, it can now do that.
---
autotests/util/wpas.py | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/autotests/util/wpas.py b/autotests/util/wpas.py
index 8fb725f8..5680ec2a 100644
--- a/autotests/util/wpas.py
+++ b/autotests/util/wpas.py
@@ -70,9 +70,10 @@ class Wpas:
while True:
context.iteration(may_block=True)
- if event in self._rx_data:
- GLib.source_remove(timeout)
- return self._rx_data
+ for e in self._rx_data:
+ if event in e:
+ GLib.source_remove(timeout)
+ return self._rx_data
if self._wait_timed_out:
raise TimeoutError('waiting for wpas event timed out')
--
2.31.1
5 months, 3 weeks
[PATCH 1/3] auto-t: iwd.py: remove StationDebug out of Device init
by James Prestwood
Since a Device class can represent multiple modes (AP, AdHoc, station)
move StationDebug out of the init and only create this class when it
is used (presumably only when the device is in station mode).
The StationDebug class is now created in a property method consistent
with 'station_if'. If Device is not in station mode it is automatically
switched if the test tries any StationDebug methods.
If the Device mode is changed from 'station' the StationDebug class
instance is destroyed.
---
autotests/util/iwd.py | 24 +++++++++++++++++-------
1 file changed, 17 insertions(+), 7 deletions(-)
diff --git a/autotests/util/iwd.py b/autotests/util/iwd.py
index e95bd96d..7f511187 100755
--- a/autotests/util/iwd.py
+++ b/autotests/util/iwd.py
@@ -280,17 +280,13 @@ class Device(IWDDBusAbstract):
'''
_iface_name = IWD_DEVICE_INTERFACE
- def __init__(self, object_path = None, properties = None,
- service=IWD_SERVICE, namespace=ctx):
+ def __init__(self, *args, **kwargs):
self._wps_manager_if = None
self._station_if = None
self._station_props = None
+ self._station_debug_obj = None
- IWDDBusAbstract.__init__(self, object_path, properties, service,
- namespace)
-
- self._station_debug = StationDebug(object_path=object_path,
- namespace=namespace)
+ IWDDBusAbstract.__init__(self, *args, **kwargs)
@property
def _wps_manager(self):
@@ -309,6 +305,17 @@ class Device(IWDDBusAbstract):
IWD_STATION_INTERFACE)
return self._station_if
+ @property
+ def _station_debug(self):
+ if self._properties['Mode'] != 'station':
+ self._prop_proxy.Set(IWD_DEVICE_INTERFACE, 'Mode', 'station')
+
+ if self._station_debug_obj is None:
+ self._station_debug_obj = StationDebug(object_path=self._object_path,
+ namespace=self._namespace)
+
+ return self._station_debug_obj
+
def _station_properties(self):
if self._station_props is not None:
return self._station_props
@@ -335,6 +342,9 @@ class Device(IWDDBusAbstract):
for name, value in changed.items():
self._station_props[name] = value
+ if name == 'Mode' and value != 'station':
+ self._station_debug_obj = None
+
@property
def device_path(self):
'''
--
2.31.1
5 months, 3 weeks