162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci// Copyright 2010 Cisco Systems, Inc.  All rights reserved.
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/kernel.h>
562306a36Sopenharmony_ci#include <linux/errno.h>
662306a36Sopenharmony_ci#include <linux/types.h>
762306a36Sopenharmony_ci#include <linux/slab.h>
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include "vnic_vic.h"
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_cistruct vic_provinfo *vic_provinfo_alloc(gfp_t flags, const u8 *oui,
1262306a36Sopenharmony_ci	const u8 type)
1362306a36Sopenharmony_ci{
1462306a36Sopenharmony_ci	struct vic_provinfo *vp;
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci	if (!oui)
1762306a36Sopenharmony_ci		return NULL;
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci	vp = kzalloc(VIC_PROVINFO_MAX_DATA, flags);
2062306a36Sopenharmony_ci	if (!vp)
2162306a36Sopenharmony_ci		return NULL;
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci	memcpy(vp->oui, oui, sizeof(vp->oui));
2462306a36Sopenharmony_ci	vp->type = type;
2562306a36Sopenharmony_ci	vp->length = htonl(sizeof(vp->num_tlvs));
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	return vp;
2862306a36Sopenharmony_ci}
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_civoid vic_provinfo_free(struct vic_provinfo *vp)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	kfree(vp);
3362306a36Sopenharmony_ci}
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ciint vic_provinfo_add_tlv(struct vic_provinfo *vp, u16 type, u16 length,
3662306a36Sopenharmony_ci	const void *value)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	struct vic_provinfo_tlv *tlv;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	if (!vp || !value)
4162306a36Sopenharmony_ci		return -EINVAL;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	if (ntohl(vp->length) + offsetof(struct vic_provinfo_tlv, value) +
4462306a36Sopenharmony_ci		length > VIC_PROVINFO_MAX_TLV_DATA)
4562306a36Sopenharmony_ci		return -ENOMEM;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	tlv = (struct vic_provinfo_tlv *)((u8 *)vp->tlv +
4862306a36Sopenharmony_ci		ntohl(vp->length) - sizeof(vp->num_tlvs));
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	tlv->type = htons(type);
5162306a36Sopenharmony_ci	tlv->length = htons(length);
5262306a36Sopenharmony_ci	memcpy(tlv->value, value, length);
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	vp->num_tlvs = htonl(ntohl(vp->num_tlvs) + 1);
5562306a36Sopenharmony_ci	vp->length = htonl(ntohl(vp->length) +
5662306a36Sopenharmony_ci		offsetof(struct vic_provinfo_tlv, value) + length);
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	return 0;
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cisize_t vic_provinfo_size(struct vic_provinfo *vp)
6262306a36Sopenharmony_ci{
6362306a36Sopenharmony_ci	return vp ?  ntohl(vp->length) + sizeof(*vp) - sizeof(vp->num_tlvs) : 0;
6462306a36Sopenharmony_ci}
65