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
vpdnext(vpdbuf_t * vpd)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
vpddone(vpdbuf_t * vpd)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 *
vpdref(vpdbuf_t * vpd)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 *
ocs_find_vpd(uint8_t * vpddata,uint32_t vpddata_length,const char * key)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