summaryrefslogtreecommitdiffstats
path: root/common/state/state.h
blob: 3a0662fd2594307202ed2e4d739aa0576494b12b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
#include <linux/types.h>
#include <linux/list.h>
#include <driver.h>

struct state;
struct mtd_info_user;

enum state_flags {
	STATE_FLAG_NO_AUTHENTIFICATION = (1 << 0),
};

enum state_variable_type {
	STATE_VARIABLE_TYPE_UINT8,
	STATE_VARIABLE_TYPE_UINT32,
	STATE_VARIABLE_TYPE_ENUM32,
	STATE_VARIABLE_TYPE_MAC,
	STATE_VARIABLE_TYPE_STRING
};

/**
 * state_backend_storage_bucket - This class describes a single backend storage
 * object copy
 *
 * @init Optional, initiates the given bucket
 * @write Required, writes the given data to the storage in any form. Returns 0
 * on success
 * @read Required, reads the last successfully written data from the backend
 * storage. Returns 0 on success and allocates a matching memory area to buf.
 * len_hint can be a hint of the storage format how large the data to be read
 * is. After the operation len_hint contains the size of the allocated buffer.
 * @free Required, Frees all internally used memory
 * @bucket_list A list element struct to attach this bucket to a list
 */
struct state_backend_storage_bucket {
	int (*write) (struct state_backend_storage_bucket * bucket,
		      const void * buf, ssize_t len);
	int (*read) (struct state_backend_storage_bucket * bucket,
		     void ** buf, ssize_t * len_hint);
	void (*free) (struct state_backend_storage_bucket * bucket);

	int num;
	off_t offset;

	struct list_head bucket_list;

	void *buf;
	ssize_t len;
	bool needs_refresh;
	bool wrong_magic;
};

/**
 * state_backend_format - This class describes a data format.
 *
 * @verify Required, Verifies the validity of the given data. The buffer that is
 * passed into this function may be larger than the actual data in the buffer.
 * The magic is supplied by the state to verify that this is an expected state
 * entity. The function should return 0 on success or a negative errno otherwise.
 * @pack Required, Packs data from the given state into a newly created buffer.
 * The buffer and its length are stored in the given argument pointers. Returns
 * 0 on success, -errno otherwise.
 * @unpack Required, Unpacks the data from the given buffer into the state. Do
 * not free the buffer.
 * @free Optional, Frees all allocated memory and structures.
 * @name Name of this backend.
 */
struct state_backend_format {
	int (*verify) (struct state_backend_format * format, uint32_t magic,
		       const void * buf, ssize_t *lenp, enum state_flags flags);
	int (*pack) (struct state_backend_format * format, struct state * state,
		     void ** buf, ssize_t * len);
	int (*unpack) (struct state_backend_format * format,
		       struct state * state, const void * buf, ssize_t len);
	void (*free) (struct state_backend_format * format);
	const char *name;
};

/**
 * state_backend_storage - Storage backend of the state.
 *
 * @buckets List of storage buckets that are available
 * @stridesize The distance between copies
 * @offset Offset in the backend device where the data starts
 * @max_size The maximum size of the data we can use
 */
struct state_backend_storage {
	struct list_head buckets;

	/* For outputs */
	struct device_d *dev;

	const char *name;

	uint32_t stridesize;
	off_t offset;
	size_t max_size;
	char *path;

	bool readonly;
};

struct state {
	struct list_head list; /* Entry to enqueue on list of states */

	struct device_d dev;
	char *of_path;
	const char *name;
	uint32_t magic;
	bool keep_prev_content;

	struct list_head variables; /* Sorted list of variables */

	unsigned int dirty;
	unsigned int init_from_defaults;
	unsigned int save_on_shutdown;

	struct state_backend_format *format;
	struct state_backend_storage storage;
	char *backend_path;
	char *backend_reproducible_name;
};

enum state_convert {
	STATE_CONVERT_FROM_NODE,
	STATE_CONVERT_FROM_NODE_CREATE,
	STATE_CONVERT_TO_NODE,
	STATE_CONVERT_FIXUP,
};

struct state_variable;

/* A variable type (uint32, enum32) */
struct variable_type {
	const char *type_name;
	enum state_variable_type type;
	struct list_head list;
	int (*export) (struct state_variable *, struct device_node *,
		       enum state_convert);
	int (*import) (struct state_variable *, struct device_node *);
	struct state_variable *(*create) (struct state *,
					  const char *,
					  struct device_node *,
					  const struct variable_type *);
};

/* instance of a single variable */
struct state_variable {
	struct state *state;
	struct list_head list;
	const struct variable_type *type;
	const char *name;
	unsigned int start;
	unsigned int size;
	void *raw;
};

/*
 *  uint32
 */
struct state_uint32 {
	struct state_variable var;
	struct param_d *param;
	uint32_t value;
	uint32_t value_default;
};

/*
 *  enum32
 */
struct state_enum32 {
	struct state_variable var;
	struct param_d *param;
	uint32_t value;
	uint32_t value_default;
	const char **names;
	int num_names;
};

/*
 *  MAC address
 */
struct state_mac {
	struct state_variable var;
	struct param_d *param;
	uint8_t value[6];
	uint8_t value_default[6];
};

/*
 *  string
 */
struct state_string {
	struct state_variable var;
	struct param_d *param;
	char *value;
	const char *value_default;
	char raw[];
};

int state_from_node(struct state *state, struct device_node *node, bool create);
struct device_node *state_to_node(struct state *state,
				  struct device_node *parent,
				  enum state_convert conv);
int backend_format_raw_create(struct state_backend_format **format,
			      struct device_node *node, const char *secret_name,
			      struct device_d *dev);
int backend_format_dtb_create(struct state_backend_format **format,
			      struct device_d *dev);
int state_storage_init(struct state *state, const char *path,
		       off_t offset, size_t max_size, uint32_t stridesize,
		       const char *storagetype);
void state_storage_set_readonly(struct state_backend_storage *storage);
void state_add_var(struct state *state, struct state_variable *var);
struct variable_type *state_find_type_by_name(const char *name);
int state_backend_bucket_circular_create(struct device_d *dev, const char *path,
					 struct state_backend_storage_bucket **bucket,
					 unsigned int eraseblock,
					 ssize_t writesize,
					 struct mtd_info_user *mtd_uinfo);
int state_backend_bucket_cached_create(struct device_d *dev,
				       struct state_backend_storage_bucket *raw,
				       struct state_backend_storage_bucket **out);
struct state_variable *state_find_var(struct state *state, const char *name);
struct digest *state_backend_format_raw_get_digest(struct state_backend_format
						   *format);
void state_backend_set_readonly(struct state *state);
void state_storage_free(struct state_backend_storage *storage);
int state_backend_bucket_direct_create(struct device_d *dev, const char *path,
				       struct state_backend_storage_bucket **bucket,
				       off_t offset, ssize_t max_size);
int state_storage_write(struct state_backend_storage *storage,
			const void * buf, ssize_t len);
int state_storage_read(struct state_backend_storage *storage,
		       struct state_backend_format *format,
		       uint32_t magic, void **buf, ssize_t *len,
		       enum state_flags flags);

static inline struct state_uint32 *to_state_uint32(struct state_variable *s)
{
	return container_of(s, struct state_uint32, var);
}

static inline struct state_enum32 *to_state_enum32(struct state_variable *s)
{
	return container_of(s, struct state_enum32, var);
}

static inline struct state_mac *to_state_mac(struct state_variable *s)
{
	return container_of(s, struct state_mac, var);
}

static inline struct state_string *to_state_string(struct state_variable *s)
{
	return container_of(s, struct state_string, var);
}

static inline int state_string_copy_to_raw(struct state_string *string,
				    const char *src)
{
	size_t len;

	len = strlen(src);
	if (len > string->var.size)
		return -EILSEQ;

	/* copy string and clear remaining contents of buffer */
	memcpy(string->raw, src, len);
	memset(string->raw + len, 0x0, string->var.size - len);

	return 0;
}