// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Copyright (C) 2024 PHYTEC Messtechnik GmbH
 * Author: Daniel Schultz <d.schultz@phytec.de>
 */

#include <malloc.h>
#include <u-boot/crc.h>
#include <net.h>
#include <vsprintf.h>

#include "phytec_som_detection_blocks.h"

#if IS_ENABLED(CONFIG_PHYTEC_SOM_DETECTION_BLOCKS)

struct phytec_api3_element *
	phytec_blocks_init_mac(struct phytec_api3_block_header *header,
			       uint8_t *payload)
{
	struct phytec_api3_element *element;
	struct phytec_api3_block_mac *mac;
	unsigned int crc;
	unsigned int len = sizeof(struct phytec_api3_block_mac);

	if (!header)
		return NULL;
	if (!payload)
		return NULL;

	element = (struct phytec_api3_element *)
			calloc(8, PHYTEC_API3_ELEMENT_HEADER_SIZE + len);
	if (!element) {
		pr_err("%s: Unable to allocate memory\n", __func__);
		return NULL;
	}
	element->block_type = header->block_type;
	memcpy(&element->block.mac, payload, len);
	mac = &element->block.mac;

	debug("%s: interface: %i\n", __func__, mac->interface);
	debug("%s: MAC %pM\n", __func__, mac->address);

	crc = crc8(0, (const unsigned char *)mac, len);
	debug("%s: crc: %x\n", __func__, crc);
	if (crc) {
		pr_err("%s: CRC mismatch. API3 block payload is unusable\n",
		       __func__);
		return NULL;
	}

	return element;
}

int __maybe_unused
	phytec_blocks_add_mac_to_env(struct phytec_api3_element *element)
{
	char enetenv[9] = "ethaddr";
	char buf[ARP_HLEN_ASCII + 1];
	struct phytec_api3_block_mac *block = &element->block.mac;
	int ret;

	if (!is_valid_ethaddr(block->address)) {
		pr_err("%s: Invalid MAC address in block.\n", __func__);
		return -1;
	}

	if (block->interface > 0) {
		ret = sprintf(enetenv, "eth%iaddr", block->interface);
		if (ret != 8) {
			pr_err("%s: Unable to create env string\n", __func__);
			return -1;
		}
	}

	ret = sprintf(buf, "%pM", block->address);
	if (ret != ARP_HLEN_ASCII) {
		pr_err("%s: Unable to convert MAC address\n", __func__);
		return -1;
	}
	ret = env_set(enetenv, buf);
	if (ret) {
		pr_err("%s: Failed to set MAC address to env.\n", __func__);
		return -1;
	}

	debug("%s: Added %s to %s\n", __func__, buf, enetenv);
	return 0;
}

#else

inline struct phytec_api3_element *
	phytec_api3_init_mac_block(struct phytec_api3_block_header *header,
				   uint8_t *payload)
{
	return NULL;
}

inline int __maybe_unused
	phytec_blocks_add_mac_to_env(struct phytec_api3_element *element)
{
	return -1;
}

#endif
