1 /*- 2 * Copyright (c) 2017 Broadcom. All rights reserved. 3 * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * 3. Neither the name of the copyright holder nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /** 33 * @file 34 * OCS VPD parser 35 */ 36 37 #if !defined(__OCS_VPD_H__) 38 #define __OCS_VPD_H__ 39 40 /** 41 * @brief VPD buffer structure 42 */ 43 44 typedef struct { 45 uint8_t *buffer; 46 uint32_t length; 47 uint32_t offset; 48 uint8_t checksum; 49 } vpdbuf_t; 50 51 /** 52 * @brief return next VPD byte 53 * 54 * Returns next VPD byte and updates accumulated checksum 55 * 56 * @param vpd pointer to vpd buffer 57 * 58 * @return returns next byte for success, or a negative error code value for failure. 59 * 60 */ 61 62 static inline int 63 vpdnext(vpdbuf_t *vpd) 64 { 65 int rc = -1; 66 if (vpd->offset < vpd->length) { 67 rc = vpd->buffer[vpd->offset++]; 68 vpd->checksum += rc; 69 } 70 return rc; 71 } 72 73 /** 74 * @brief return true if no more vpd buffer data 75 * 76 * return true if the vpd buffer data has been completely consumed 77 * 78 * @param vpd pointer to vpd buffer 79 * 80 * @return returns true if no more data 81 * 82 */ 83 static inline int 84 vpddone(vpdbuf_t *vpd) 85 { 86 return vpd->offset >= vpd->length; 87 } 88 /** 89 * @brief return pointer to current VPD data location 90 * 91 * Returns a pointer to the current location in the VPD data 92 * 93 * @param vpd pointer to vpd buffer 94 * 95 * @return pointer to current VPD data location 96 */ 97 98 static inline uint8_t * 99 vpdref(vpdbuf_t *vpd) 100 { 101 return &vpd->buffer[vpd->offset]; 102 } 103 104 #define VPD_LARGE_RESOURCE_TYPE_ID_STRING_TAG 0x82 105 #define VPD_LARGE_RESOURCE_TYPE_R_TAG 0x90 106 #define VPD_LARGE_RESOURCE_TYPE_W_TAG 0x91 107 #define VPD_SMALL_RESOURCE_TYPE_END_TAG 0x78 108 109 /** 110 * @brief find a VPD entry 111 * 112 * Finds a VPD entry given the two character code 113 * 114 * @param vpddata pointer to raw vpd data buffer 115 * @param vpddata_length length of vpddata buffer in bytes 116 * @param key key to look up 117 118 * @return returns a pointer to the key location or NULL if not found or checksum error 119 */ 120 121 static inline uint8_t * 122 ocs_find_vpd(uint8_t *vpddata, uint32_t vpddata_length, const char *key) 123 { 124 vpdbuf_t vpdbuf; 125 uint8_t *pret = NULL; 126 uint8_t c0 = key[0]; 127 uint8_t c1 = key[1]; 128 129 vpdbuf.buffer = (uint8_t*) vpddata; 130 vpdbuf.length = vpddata_length; 131 vpdbuf.offset = 0; 132 vpdbuf.checksum = 0; 133 134 while (!vpddone(&vpdbuf)) { 135 int type = vpdnext(&vpdbuf); 136 int len_lo; 137 int len_hi; 138 int len; 139 int i; 140 141 if (type == VPD_SMALL_RESOURCE_TYPE_END_TAG) { 142 break; 143 } 144 145 len_lo = vpdnext(&vpdbuf); 146 len_hi = vpdnext(&vpdbuf); 147 len = len_lo + (len_hi << 8); 148 149 if ((type == VPD_LARGE_RESOURCE_TYPE_R_TAG) || (type == VPD_LARGE_RESOURCE_TYPE_W_TAG)) { 150 while (len > 0) { 151 int rc0; 152 int rc1; 153 int sublen; 154 uint8_t *pstart; 155 156 rc0 = vpdnext(&vpdbuf); 157 rc1 = vpdnext(&vpdbuf); 158 159 /* Mark this location */ 160 pstart = vpdref(&vpdbuf); 161 162 sublen = vpdnext(&vpdbuf); 163 164 /* Adjust remaining len */ 165 len -= (sublen + 3); 166 167 /* check for match with request */ 168 if ((c0 == rc0) && (c1 == rc1)) { 169 pret = pstart; 170 for (i = 0; i < sublen; i++) { 171 vpdnext(&vpdbuf); 172 } 173 /* check for "RV" end */ 174 } else if ('R' == rc0 && 'V' == rc1) { 175 /* Read the checksum */ 176 for (i = 0; i < sublen; i++) { 177 vpdnext(&vpdbuf); 178 } 179 180 /* The accumulated checksum should be zero here */ 181 if (vpdbuf.checksum != 0) { 182 ocs_log_test(NULL, "checksum error\n"); 183 return NULL; 184 } 185 } 186 else 187 for (i = 0; i < sublen; i++) { 188 vpdnext(&vpdbuf); 189 } 190 } 191 } 192 193 for (i = 0; i < len; i++) { 194 vpdnext(&vpdbuf); 195 } 196 } 197 198 return pret; 199 } 200 #endif 201