Merge tag 'dax-fix-5.2-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm...
[sfrench/cifs-2.6.git] / drivers / firmware / google / vpd_decode.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * vpd_decode.c
4  *
5  * Google VPD decoding routines.
6  *
7  * Copyright 2017 Google Inc.
8  */
9
10 #include <linux/export.h>
11
12 #include "vpd_decode.h"
13
14 static int vpd_decode_len(const s32 max_len, const u8 *in,
15                           s32 *length, s32 *decoded_len)
16 {
17         u8 more;
18         int i = 0;
19
20         if (!length || !decoded_len)
21                 return VPD_FAIL;
22
23         *length = 0;
24         do {
25                 if (i >= max_len)
26                         return VPD_FAIL;
27
28                 more = in[i] & 0x80;
29                 *length <<= 7;
30                 *length |= in[i] & 0x7f;
31                 ++i;
32         } while (more);
33
34         *decoded_len = i;
35
36         return VPD_OK;
37 }
38
39 int vpd_decode_string(const s32 max_len, const u8 *input_buf, s32 *consumed,
40                       vpd_decode_callback callback, void *callback_arg)
41 {
42         int type;
43         int res;
44         s32 key_len;
45         s32 value_len;
46         s32 decoded_len;
47         const u8 *key;
48         const u8 *value;
49
50         /* type */
51         if (*consumed >= max_len)
52                 return VPD_FAIL;
53
54         type = input_buf[*consumed];
55
56         switch (type) {
57         case VPD_TYPE_INFO:
58         case VPD_TYPE_STRING:
59                 (*consumed)++;
60
61                 /* key */
62                 res = vpd_decode_len(max_len - *consumed, &input_buf[*consumed],
63                                      &key_len, &decoded_len);
64                 if (res != VPD_OK || *consumed + decoded_len >= max_len)
65                         return VPD_FAIL;
66
67                 *consumed += decoded_len;
68                 key = &input_buf[*consumed];
69                 *consumed += key_len;
70
71                 /* value */
72                 res = vpd_decode_len(max_len - *consumed, &input_buf[*consumed],
73                                      &value_len, &decoded_len);
74                 if (res != VPD_OK || *consumed + decoded_len > max_len)
75                         return VPD_FAIL;
76
77                 *consumed += decoded_len;
78                 value = &input_buf[*consumed];
79                 *consumed += value_len;
80
81                 if (type == VPD_TYPE_STRING)
82                         return callback(key, key_len, value, value_len,
83                                         callback_arg);
84                 break;
85
86         default:
87                 return VPD_FAIL;
88         }
89
90         return VPD_OK;
91 }