diff options
author | David Herrmann <dh.herrmann@gmail.com> | 2013-11-06 17:06:54 +0100 |
---|---|---|
committer | David Herrmann <dh.herrmann@gmail.com> | 2013-11-06 17:06:54 +0100 |
commit | 9ce82277e6be7e4c215b074c6c7f2c71f7edc332 (patch) | |
tree | cecf5f7904075903cd3cc21a422fd0d37cbb89e1 | |
parent | 0339773076040aded86947d764654c0f962c70cc (diff) |
owfd: wpa: parse basic p2p/ap events
Add parsers for the most basic payloads that we need during the beginning.
Further payload parsers can be added once we have a use-case for them.
Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
-rw-r--r-- | src/wpa.h | 26 | ||||
-rw-r--r-- | src/wpa_parser.c | 261 | ||||
-rw-r--r-- | test/test_wpa.c | 53 |
3 files changed, 320 insertions, 20 deletions
@@ -104,6 +104,32 @@ struct owfd_wpa_event { unsigned int type; unsigned int priority; char *raw; + + union owfd_wpa_event_payload { + struct owfd_wpa_event_ap_sta_connected { + char mac[OWFD_WPA_EVENT_MAC_STRLEN]; + } ap_sta_connected; + struct owfd_wpa_event_ap_sta_disconnected { + char mac[OWFD_WPA_EVENT_MAC_STRLEN]; + } ap_sta_disconnected; + struct owfd_wpa_event_p2p_device_found { + char peer_mac[OWFD_WPA_EVENT_MAC_STRLEN]; + char *name; + } p2p_device_found; + struct owfd_wpa_event_p2p_prov_disc_show_pin { + char peer_mac[OWFD_WPA_EVENT_MAC_STRLEN]; + char *pin; + } p2p_prov_disc_show_pin; + struct owfd_wpa_event_p2p_prov_disc_enter_pin { + char peer_mac[OWFD_WPA_EVENT_MAC_STRLEN]; + } p2p_prov_disc_enter_pin; + struct owfd_wpa_event_p2p_prov_disc_pbc_req { + char peer_mac[OWFD_WPA_EVENT_MAC_STRLEN]; + } p2p_prov_disc_pbc_req; + struct owfd_wpa_event_p2p_prov_disc_pbc_resp { + char peer_mac[OWFD_WPA_EVENT_MAC_STRLEN]; + } p2p_prov_disc_pbc_resp; + } p; }; void owfd_wpa_event_init(struct owfd_wpa_event *ev); diff --git a/src/wpa_parser.c b/src/wpa_parser.c index 2acec9f..c65d55f 100644 --- a/src/wpa_parser.c +++ b/src/wpa_parser.c @@ -39,6 +39,17 @@ void owfd_wpa_event_reset(struct owfd_wpa_event *ev) { free(ev->raw); + switch (ev->type) { + case OWFD_WPA_EVENT_P2P_DEVICE_FOUND: + free(ev->p.p2p_device_found.name); + break; + case OWFD_WPA_EVENT_P2P_PROV_DISC_SHOW_PIN: + free(ev->p.p2p_prov_disc_show_pin.pin); + break; + default: + break; + } + memset(ev, 0, sizeof(*ev)); } @@ -97,11 +108,214 @@ static int event_comp(const void *key, const void *type) return 0; } +static char *tokenize(const char *src, size_t *num) +{ + char *buf, *dst; + char last_c; + size_t n; + bool quoted, escaped; + + buf = malloc(strlen(src) + 1); + if (!buf) + return NULL; + + dst = buf; + last_c = 0; + n = 0; + *dst = 0; + quoted = 0; + escaped = 0; + + for ( ; *src; ++src) { + if (quoted) { + if (escaped) { + escaped = 0; + last_c = *src; + *dst++ = last_c; + } else if (*src == '\'') { + quoted = 0; + } else if (*src == '\\') { + escaped = 1; + } else { + last_c = *src; + *dst++ = last_c; + } + } else { + if (*src == ' ' || + *src == '\n' || + *src == '\t' || + *src == '\r') { + if (last_c) { + *dst++ = 0; + ++n; + } + last_c = 0; + } else if (*src == '\'') { + quoted = 1; + escaped = 0; + last_c = *src; + } else { + last_c = *src; + *dst++ = last_c; + } + } + } + + if (last_c) { + *dst = 0; + ++n; + } + + *num = n; + return buf; +} + +static int parse_mac(char *buf, const char *src) +{ + int r, a1, a2, a3, a4, a5, a6; + + if (strlen(src) > 17) + return -EINVAL; + + r = sscanf(src, "%2d:%2d:%2d:%2d:%2d:%2d", + &a1, &a2, &a3, &a4, &a5, &a6); + if (r != 6) + return -EINVAL; + + strcpy(buf, src); + return 0; +} + +static int parse_ap_sta_connected(struct owfd_wpa_event *ev, + char *tokens, size_t num) +{ + int r; + + if (num < 1) + return -EINVAL; + + r = parse_mac(ev->p.ap_sta_connected.mac, tokens); + if (r < 0) + return r; + + return 0; +} + +static int parse_ap_sta_disconnected(struct owfd_wpa_event *ev, + char *tokens, size_t num) +{ + int r; + + if (num < 1) + return -EINVAL; + + r = parse_mac(ev->p.ap_sta_disconnected.mac, tokens); + if (r < 0) + return r; + + return 0; +} + +static int parse_p2p_device_found(struct owfd_wpa_event *ev, + char *tokens, size_t num) +{ + int r; + size_t i; + + if (num < 2) + return -EINVAL; + + r = parse_mac(ev->p.p2p_device_found.peer_mac, tokens); + if (r < 0) + return r; + + tokens += strlen(tokens) + 1; + for (i = 1; i < num; ++i, tokens += strlen(tokens) + 1) { + if (strncmp(tokens, "name=", 5)) + continue; + + ev->p.p2p_device_found.name = strdup(&tokens[5]); + if (!ev->p.p2p_device_found.name) + return -ENOMEM; + + break; + } + + return 0; +} + +static int parse_p2p_prov_disc_show_pin(struct owfd_wpa_event *ev, + char *tokens, size_t num) +{ + int r; + + if (num < 2) + return -EINVAL; + + r = parse_mac(ev->p.p2p_prov_disc_show_pin.peer_mac, tokens); + if (r < 0) + return r; + + tokens += strlen(tokens) + 1; + ev->p.p2p_prov_disc_show_pin.pin = strdup(tokens); + if (!ev->p.p2p_prov_disc_show_pin.pin) + return -ENOMEM; + + return 0; +} + +static int parse_p2p_prov_disc_enter_pin(struct owfd_wpa_event *ev, + char *tokens, size_t num) +{ + int r; + + if (num < 1) + return -EINVAL; + + r = parse_mac(ev->p.p2p_prov_disc_enter_pin.peer_mac, tokens); + if (r < 0) + return r; + + return 0; +} + +static int parse_p2p_prov_disc_pbc_req(struct owfd_wpa_event *ev, + char *tokens, size_t num) +{ + int r; + + if (num < 1) + return -EINVAL; + + r = parse_mac(ev->p.p2p_prov_disc_pbc_req.peer_mac, tokens); + if (r < 0) + return r; + + return 0; +} + +static int parse_p2p_prov_disc_pbc_resp(struct owfd_wpa_event *ev, + char *tokens, size_t num) +{ + int r; + + if (num < 1) + return -EINVAL; + + r = parse_mac(ev->p.p2p_prov_disc_pbc_resp.peer_mac, tokens); + if (r < 0) + return r; + + return 0; +} + int owfd_wpa_event_parse(struct owfd_wpa_event *ev, const char *event) { const char *t; - char *end; + char *end, *tokens = NULL; + size_t num; struct event_type *code; + int r; owfd_wpa_event_reset(ev); @@ -135,19 +349,56 @@ int owfd_wpa_event_parse(struct owfd_wpa_event *ev, const char *event) ++t; ev->raw = strdup(t); - if (!ev->raw) - goto oom; + if (!ev->raw) { + r = -ENOMEM; + goto error; + } + + tokens = tokenize(ev->raw, &num); + if (!tokens) { + r = -ENOMEM; + goto error; + } switch (ev->type) { + case OWFD_WPA_EVENT_AP_STA_CONNECTED: + r = parse_ap_sta_connected(ev, tokens, num); + break; + case OWFD_WPA_EVENT_AP_STA_DISCONNECTED: + r = parse_ap_sta_disconnected(ev, tokens, num); + break; + case OWFD_WPA_EVENT_P2P_DEVICE_FOUND: + r = parse_p2p_device_found(ev, tokens, num); + break; + case OWFD_WPA_EVENT_P2P_PROV_DISC_SHOW_PIN: + r = parse_p2p_prov_disc_show_pin(ev, tokens, num); + break; + case OWFD_WPA_EVENT_P2P_PROV_DISC_ENTER_PIN: + r = parse_p2p_prov_disc_enter_pin(ev, tokens, num); + break; + case OWFD_WPA_EVENT_P2P_PROV_DISC_PBC_REQ: + r = parse_p2p_prov_disc_pbc_req(ev, tokens, num); + break; + case OWFD_WPA_EVENT_P2P_PROV_DISC_PBC_RESP: + r = parse_p2p_prov_disc_pbc_resp(ev, tokens, num); + break; + default: + r = 0; + break; } + free(tokens); + + if (r < 0) + goto error; + return 0; unknown: ev->type = OWFD_WPA_EVENT_UNKNOWN; return 0; -oom: +error: owfd_wpa_event_reset(ev); - return -ENOMEM; + return r; } diff --git a/test/test_wpa.c b/test/test_wpa.c index b3f61c7..f2a9760 100644 --- a/test/test_wpa.c +++ b/test/test_wpa.c @@ -37,9 +37,9 @@ static void parse(struct owfd_wpa_event *ev, const char *event) static const char *event_list[] = { [OWFD_WPA_EVENT_UNKNOWN] = "", - [OWFD_WPA_EVENT_AP_STA_CONNECTED] = "AP-STA-CONNECTED", - [OWFD_WPA_EVENT_AP_STA_DISCONNECTED] = "AP-STA-DISCONNECTED", - [OWFD_WPA_EVENT_P2P_DEVICE_FOUND] = "P2P-DEVICE-FOUND", + [OWFD_WPA_EVENT_AP_STA_CONNECTED] = "AP-STA-CONNECTED 00:00:00:00:00:00", + [OWFD_WPA_EVENT_AP_STA_DISCONNECTED] = "AP-STA-DISCONNECTED 00:00:00:00:00:00", + [OWFD_WPA_EVENT_P2P_DEVICE_FOUND] = "P2P-DEVICE-FOUND 00:00:00:00:00:00 name=some-name", [OWFD_WPA_EVENT_P2P_GO_NEG_REQUEST] = "P2P-GO-NEG-REQUEST", [OWFD_WPA_EVENT_P2P_GO_NEG_SUCCESS] = "P2P-GO-NEG-SUCCESS", [OWFD_WPA_EVENT_P2P_GO_NEG_FAILURE] = "P2P-GO-NEG-FAILURE", @@ -47,10 +47,10 @@ static const char *event_list[] = { [OWFD_WPA_EVENT_P2P_GROUP_FORMATION_FAILURE] = "P2P-GROUP-FORMATION-FAILURE", [OWFD_WPA_EVENT_P2P_GROUP_STARTED] = "P2P-GROUP-STARTED", [OWFD_WPA_EVENT_P2P_GROUP_REMOVED] = "P2P-GROUP-REMOVED", - [OWFD_WPA_EVENT_P2P_PROV_DISC_SHOW_PIN] = "P2P-PROV-DISC-SHOW-PIN", - [OWFD_WPA_EVENT_P2P_PROV_DISC_ENTER_PIN] = "P2P-PROV-DISC-ENTER-PIN", - [OWFD_WPA_EVENT_P2P_PROV_DISC_PBC_REQ] = "P2P-PROV-DISC-PBC-REQ", - [OWFD_WPA_EVENT_P2P_PROV_DISC_PBC_RESP] = "P2P-PROV-DISC-PBC-RESP", + [OWFD_WPA_EVENT_P2P_PROV_DISC_SHOW_PIN] = "P2P-PROV-DISC-SHOW-PIN 00:00:00:00:00:00 pin", + [OWFD_WPA_EVENT_P2P_PROV_DISC_ENTER_PIN] = "P2P-PROV-DISC-ENTER-PIN 00:00:00:00:00:00", + [OWFD_WPA_EVENT_P2P_PROV_DISC_PBC_REQ] = "P2P-PROV-DISC-PBC-REQ 00:00:00:00:00:00", + [OWFD_WPA_EVENT_P2P_PROV_DISC_PBC_RESP] = "P2P-PROV-DISC-PBC-RESP 00:00:00:00:00:00", [OWFD_WPA_EVENT_P2P_SERV_DISC_REQ] = "P2P-SERV-DISC-REQ", [OWFD_WPA_EVENT_P2P_SERV_DISC_RESP] = "P2P-SERV-DISC-RESP", [OWFD_WPA_EVENT_P2P_INVITATION_RECEIVED] = "P2P-INVITATION-RECEIVED", @@ -75,11 +75,11 @@ START_TEST(test_wpa_parser) ck_assert_msg(ev.type == i, "event %d invalid", i); } - parse(&ev, "<5>AP-STA-CONNECTED"); + parse(&ev, "<5>AP-STA-CONNECTED 0:0:0:0:0:0"); ck_assert(ev.priority == OWFD_WPA_EVENT_P_MSGDUMP); ck_assert(ev.type == OWFD_WPA_EVENT_AP_STA_CONNECTED); - parse(&ev, "<4>AP-STA-CONNECTED"); + parse(&ev, "<4>AP-STA-CONNECTED 0:0:0:0:0:0"); ck_assert(ev.priority == OWFD_WPA_EVENT_P_ERROR); ck_assert(ev.type == OWFD_WPA_EVENT_AP_STA_CONNECTED); @@ -87,31 +87,54 @@ START_TEST(test_wpa_parser) ck_assert(ev.priority == OWFD_WPA_EVENT_P_ERROR); ck_assert(ev.type == OWFD_WPA_EVENT_UNKNOWN); - parse(&ev, "<4asdf>AP-STA-CONNECTED"); + parse(&ev, "<4asdf>AP-STA-CONNECTED 0:0:0:0:0:0"); ck_assert(ev.priority == OWFD_WPA_EVENT_P_MSGDUMP); ck_assert(ev.type == OWFD_WPA_EVENT_AP_STA_CONNECTED); - parse(&ev, "<4>AP-STA-CONNECTED something else"); + parse(&ev, "<4>AP-STA-CONNECTED 0:0:0:0:0:0"); ck_assert(ev.priority == OWFD_WPA_EVENT_P_ERROR); ck_assert(ev.type == OWFD_WPA_EVENT_AP_STA_CONNECTED); ck_assert(ev.raw != NULL); - ck_assert(!strcmp(ev.raw, "something else")); + ck_assert(!strcmp(ev.raw, "0:0:0:0:0:0")); parse(&ev, "<4>AP-STA something else"); ck_assert(ev.priority == OWFD_WPA_EVENT_P_ERROR); ck_assert(ev.type == OWFD_WPA_EVENT_UNKNOWN); ck_assert(!ev.raw); +} +END_TEST + +START_TEST(test_wpa_parser_payload) +{ + struct owfd_wpa_event ev; - parse(&ev, "<4>AP-STA-CONNECTED"); + parse(&ev, "<4>P2P-DEVICE-FOUND 0:0:0:0:0:0 name=some-name"); ck_assert(ev.priority == OWFD_WPA_EVENT_P_ERROR); - ck_assert(ev.type == OWFD_WPA_EVENT_AP_STA_CONNECTED); + ck_assert(ev.type == OWFD_WPA_EVENT_P2P_DEVICE_FOUND); + ck_assert(ev.raw != NULL); + ck_assert(!strcmp(ev.raw, "0:0:0:0:0:0 name=some-name")); + ck_assert(!strcmp(ev.p.p2p_device_found.peer_mac, "0:0:0:0:0:0")); + ck_assert(!strcmp(ev.p.p2p_device_found.name, "some-name")); + + parse(&ev, "<4>P2P-DEVICE-FOUND 0:0:0:0:0:0 name=some-'name\\\\\\''"); + ck_assert(ev.priority == OWFD_WPA_EVENT_P_ERROR); + ck_assert(ev.type == OWFD_WPA_EVENT_P2P_DEVICE_FOUND); + ck_assert(ev.raw != NULL); + ck_assert(!strcmp(ev.p.p2p_device_found.peer_mac, "0:0:0:0:0:0")); + ck_assert(!strcmp(ev.p.p2p_device_found.name, "some-name\\'")); + + parse(&ev, "<4>P2P-PROV-DISC-SHOW-PIN 0:0:0:0:0:0 1234567890"); + ck_assert(ev.priority == OWFD_WPA_EVENT_P_ERROR); + ck_assert(ev.type == OWFD_WPA_EVENT_P2P_PROV_DISC_SHOW_PIN); ck_assert(ev.raw != NULL); - ck_assert(!*ev.raw); + ck_assert(!strcmp(ev.p.p2p_prov_disc_show_pin.peer_mac, "0:0:0:0:0:0")); + ck_assert(!strcmp(ev.p.p2p_prov_disc_show_pin.pin, "1234567890")); } END_TEST TEST_DEFINE_CASE(parser) TEST(test_wpa_parser) + TEST(test_wpa_parser_payload) TEST_END_CASE TEST_DEFINE( |