1 // SPDX-License-Identifier: GPL-2.0-only 2 // Copyright 2010 Cisco Systems, Inc. All rights reserved. 3 4 #include <linux/kernel.h> 5 #include <linux/errno.h> 6 #include <linux/types.h> 7 #include <linux/slab.h> 8 9 #include "vnic_vic.h" 10 11 struct vic_provinfo *vic_provinfo_alloc(gfp_t flags, const u8 *oui, 12 const u8 type) 13 { 14 struct vic_provinfo *vp; 15 16 if (!oui) 17 return NULL; 18 19 vp = kzalloc(VIC_PROVINFO_MAX_DATA, flags); 20 if (!vp) 21 return NULL; 22 23 memcpy(vp->oui, oui, sizeof(vp->oui)); 24 vp->type = type; 25 vp->length = htonl(sizeof(vp->num_tlvs)); 26 27 return vp; 28 } 29 30 void vic_provinfo_free(struct vic_provinfo *vp) 31 { 32 kfree(vp); 33 } 34 35 int vic_provinfo_add_tlv(struct vic_provinfo *vp, u16 type, u16 length, 36 const void *value) 37 { 38 struct vic_provinfo_tlv *tlv; 39 40 if (!vp || !value) 41 return -EINVAL; 42 43 if (ntohl(vp->length) + offsetof(struct vic_provinfo_tlv, value) + 44 length > VIC_PROVINFO_MAX_TLV_DATA) 45 return -ENOMEM; 46 47 tlv = (struct vic_provinfo_tlv *)((u8 *)vp->tlv + 48 ntohl(vp->length) - sizeof(vp->num_tlvs)); 49 50 tlv->type = htons(type); 51 tlv->length = htons(length); 52 unsafe_memcpy(tlv->value, value, length, 53 /* Flexible array of flexible arrays */); 54 55 vp->num_tlvs = htonl(ntohl(vp->num_tlvs) + 1); 56 vp->length = htonl(ntohl(vp->length) + 57 offsetof(struct vic_provinfo_tlv, value) + length); 58 59 return 0; 60 } 61 62 size_t vic_provinfo_size(struct vic_provinfo *vp) 63 { 64 return vp ? ntohl(vp->length) + sizeof(*vp) - sizeof(vp->num_tlvs) : 0; 65 } 66