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