Skip to content
Snippets Groups Projects
dpp.c 7.79 KiB
/*
 * Copyright (C) 2023 IOPSYS Software Solutions AB. All rights reserved.
 */
#if (EASYMESH_VERSION > 2)
#ifdef USE_LIBDPP

#include "dpp.h"

#include <libubox/list.h>
#include <easy/easy.h>
#include <wifidefs.h>
#include <dpp_api.h>
#include <dpputils.h>
#include <string.h>

#include "cmdu.h"
#include "cntlr.h"
#include "cntlr_cmdu.h"
#include "cntlr_map.h"
#include "easy/utils.h"
#include "utils/debug.h"


const char *dpp_frame_type2str(uint8_t type)
{
	if (type == DPP_PA_AUTHENTICATION_REQ)
		return "Authentication Request";
	else if (type == DPP_PA_AUTHENTICATION_RESP)
		return "Authentication Response";
	else if (type == DPP_PA_AUTHENTICATION_CONF)
		return "Authentication Confirm";
	else if (type == DPP_PA_PEER_DISCOVERY_REQ)
		return "Peer Discovery Request";
	else if (type == DPP_PA_PEER_DISCOVERY_RESP)
		return "Peer Discovery Response";
	else if (type == DPP_PA_PKEX_V1_EXCHANGE_REQ)
		return "PKEX Version 1 Exchange Request";
	else if (type == DPP_PA_PKEX_EXCHANGE_RESP)
		return "PKEX Exchange Response";
	else if (type == DPP_PA_PKEX_COMMIT_REVEAL_REQ)
		return "PKEX Commit-Reveal Request";
	else if (type == DPP_PA_PKEX_COMMIT_REVEAL_RESP)
		return "PKEX Commit-Reveal Response";
	else if (type == DPP_PA_CONFIGURATION_RESULT)
		return "Configuration Result";
	else if (type == DPP_PA_CONNECTION_STATUS_RESULT)
		return "Connection Status Result";
	else if (type == DPP_PA_PRESENCE_ANNOUNCEMENT)
		return "Presence Announcement";
	else if (type == DPP_PA_RECONFIG_ANNOUNCEMENT)
		return "Reconfiguration Announcement";
	else if (type == DPP_PA_RECONFIG_AUTH_REQ)
		return "Reconfiguration Authentication Request";
	else if (type == DPP_PA_RECONFIG_AUTH_RESP)
		return "Reconfiguration Authentication Response";
	else if (type == DPP_PA_RECONFIG_AUTH_CONF)
		return "Reconfiguration Authentication Confirm";
	else if (type == DPP_PA_PKEX_EXCHANGE_REQ)
		return "PKEX Exchange Request";
	else if (type == 0x13)
		return "Push Button Presence Announcement";
	else if (type == 0x14)
		return "Push Button Presence Announcement Response";
	else if (type == 0x15)
		return "Private Peer Introduction Query";
	else if (type == 0x16)
		return "Private Peer Introduction Notify";
	else if (type == 0x17)
		return "Private Peer Introduction Update";
	return "Unknown";
}

#if 0
/* will generate an enrollee if it does not exist */
int dpp_append_uri_file(struct controller *c, char *uri)
{
	struct json_object *uri_json, *arr, *val, *new;
	int rv, len, i;

	uri_json = json_object_from_file(DPP_URI_FILE);
	if (!uri_json) {
		dbg("|%s:%d| failed to read json:%s error:%s. "\
		     "Try to generate new\n", __func__, __LINE__, DPP_URI_FILE,
		     json_util_get_last_err());

		uri_json = json_object_new_object();
		if (!uri_json)
			goto out;

		arr = json_object_new_array();
		if (!arr)
			goto out_uri;

		json_object_object_add(uri_json, "uris", arr);
	}

	rv = json_object_object_get_ex(uri_json, "uris", &arr);
	if (!rv || !arr)
		goto out_uri;

	if (!json_object_is_type(arr, json_type_array)) {
		warn("|%s:%d| file:%s is not expected format\n", __func__,
		     __LINE__, DPP_URI_FILE);
		goto out_uri;
	}

	len = json_object_array_length(uri_json);
	for (i = 0; i < len; i++) {
		struct json_object *t;
		const char *p;

		t = json_object_array_get_idx(arr, i);
		if (!t) {
			warn("|%s:%d| couldn't get entry:%d from uri array",
			     __func__, __LINE__, i);
			continue;
		}

		p = json_get_string(t, "uri");
		if (strncmp(p, uri, 128))
			continue;

		/* hash already exists in file */
		/* TODO: possibly type has changed? */
		goto out;
	}

	new = json_object_new_object();
	if (!new)
		goto out_uri;

	val = json_object_new_string(uri);
	if (!val) {
		json_object_put(new);
		goto out_uri;
	}

	json_object_object_add(new, "uri", val);

	val = json_object_new_string("qr");
	if (!val) {
		json_object_put(new);
		goto out_uri;
	}

	json_object_object_add(new, "type", val);
	json_object_array_add(arr, new);
	json_object_to_file(DPP_URI_FILE, uri_json);
out_uri:
	json_object_put(uri_json);
out:
	return 0;
}

int dpp_cntlr_read_uris(struct controller *c)
{
	struct blob_buf uris = { 0 };
	struct blob_attr *uri;
	int rem;
	int rc = -1;
	static const struct blobmsg_policy attr[] = {
		[0] = { .name = "uris", .type = BLOBMSG_TYPE_ARRAY },
	};
	struct blob_attr *tb[ARRAY_SIZE(attr)];

	blob_buf_init(&uris, 0);

	if (!blobmsg_add_json_from_file(&uris, DPP_URI_FILE)) {
		warn("Failed to parse %s\n", DPP_URI_FILE);
		goto out;
	}

	blobmsg_parse(attr, ARRAY_SIZE(attr), tb, blob_data(uris.head), blob_len(uris.head));
	if (!tb[0])
		goto out;

	blobmsg_for_each_attr(uri, tb[0], rem) {
		static const struct blobmsg_policy uri_attr[4] = {
			[0] = { .name = "uri", .type = BLOBMSG_TYPE_STRING },
			[1] = { .name = "type", .type = BLOBMSG_TYPE_STRING },
		};
		struct blob_attr *tb1[ARRAY_SIZE(uri_attr)];
		struct dpp_enrollee *e;
		char *uri_str;

		blobmsg_parse(uri_attr, ARRAY_SIZE(uri_attr), tb1, blobmsg_data(uri), blob_len(uri));
		if (!tb1[0] || !tb1[1])
			continue;

		uri_str = blobmsg_data(tb1[0]);
		if (!uri_str)
			continue;

		e = dpp_process_new_uri(c, uri_str);
		if (!e)
			continue;

		if (strcmp("qr", blobmsg_data(tb1[1])))
			e->type = DPP_BOOTSTRAP_QR_CODE_WIFI;
		else
			e->type = DPP_BOOTSTRAP_QR_CODE_WIFI;
	}

out:
	blob_buf_free(&uris);
	return rc;
}
#endif

int dpp_frame_handler(void *dpp, uint8_t *smac, enum dpp_event ev,
		      uint8_t *frame, size_t framelen)
{
	struct controller *c;
	int ret = 0;

	err("%s: ----->\n", __func__);

	if (!smac) {
		warn("%s: Error: smac = NULL\n", __func__);
		ret = -1;
		goto out;
	}

	err("%s: DPP_EVENT: event = %d smac = " MACFMT", frame = %p, len = %zu\n",
		__func__, ev, MAC2STR(smac), frame, framelen);

	switch (ev) {
	case DPP_EVENT_TX_FRAME: {
		struct cmdu_buff *resp;
		int frametype = 0;
		struct node *proxy = NULL;

		frametype = dpp_get_frame_type(frame + 1, framelen - 1);
		if (frametype == 255) {
			warn("Invalid frametype\n");
			ret = -1;
			goto out;
		}

		err("DPP frametype %s\n", dpp_frame_type2str(frametype));

		c = dpp_get_ctx_private_data(dpp);
		if (!c) {
			ret = -1;
			goto out;
		}
		dump(frame, framelen, "DPP Frame Response");

		/* if peer has private data, it is the proxy node
		 * thus we can infer its a proxied encap DPP message
		 */
		proxy = dpp_get_peer_private_data(dpp, smac);
		if (proxy) {
			err("|%s:%d|\n", __func__, __LINE__);
			resp = cntlr_gen_proxied_encap_dpp(c, smac, frametype,
							   frame, framelen,
							   NULL, 0);
			if (!resp) {
				warn("|%s:%d| DPP: ----> Error generating proxy encap\n",
				__func__, __LINE__);
				ret = -1;
				goto out;
			}
		} else {
			err("|%s:%d|\n", __func__, __LINE__);
			resp = cntlr_gen_direct_encap_dpp(c, smac, frame,
							  framelen);
			if (!resp) {
				warn("|%s:%d| DPP: ----> Error generating direct encap\n",
				__func__, __LINE__);
				ret = -1;
				goto out;
			}
		}

		switch (frametype) {
		case DPP_PA_AUTHENTICATION_REQ: {
			if (proxy) {
				struct node *n = NULL;
				list_for_each_entry(n, &c->nodelist, list) {
					memcpy(resp->origin, n->almacaddr, 6);
					err("|%s:%d| send frame to "MACFMT"\n", __func__, __LINE__, MAC2STR(n->almacaddr));
					send_cmdu(c, resp);
				}
				cmdu_free(resp);
				break;
			}
			/* FALLTHROUGH */
		}
		case DPP_PA_AUTHENTICATION_CONF:
		case DPP_PUB_AF_GAS_INITIAL_RESP:
		case DPP_PA_PEER_DISCOVERY_RESP:
			if (proxy)
				memcpy(resp->origin, proxy->almacaddr, 6);
			else
				memcpy(resp->origin, smac, 6);
			send_cmdu(c, resp);
			cmdu_free(resp);
			break;
		default:
			warn("|%s:%d| DPP: ----> Unknown frame\n", __func__, __LINE__);
			break;
		}
		break;
	}
	case DPP_EVENT_BAD_AUTH:
		err("DPP: BAD AUTH!\n");
		/* FALLTHROUGH */
	case DPP_EVENT_TIMEOUT: {
		struct dpp_peer *peer = dpp_lookup_peer(dpp, smac);

		err("DPP: EVENT TIMEOUT!\n");

		if (peer) {
			list_del(&peer->list);
			dpp_free_peer(dpp, peer);
		}
		break;
	}
	default:
		break;
	}

out:
	return ret;
}
#endif
#endif