1 /* parser.c
2 *
3 * Copyright (C) 2010 - 2013 UNISYS CORPORATION
4 * All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or (at
9 * your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
14 * NON INFRINGEMENT. See the GNU General Public License for more
15 * details.
16 */
17
18 #include "parser.h"
19 #include "memregion.h"
20 #include "controlvmchannel.h"
21 #include <linux/ctype.h>
22 #include <linux/mm.h>
23 #include <linux/uuid.h>
24
25 #define MYDRVNAME "visorchipset_parser"
26 #define CURRENT_FILE_PC VISOR_CHIPSET_PC_parser_c
27
28 /* We will refuse to allocate more than this many bytes to copy data from
29 * incoming payloads. This serves as a throttling mechanism.
30 */
31 #define MAX_CONTROLVM_PAYLOAD_BYTES (1024*128)
32 static ulong controlvm_payload_bytes_buffered;
33
34 struct parser_context {
35 ulong allocbytes;
36 ulong param_bytes;
37 u8 *curr;
38 ulong bytes_remaining;
39 BOOL byte_stream;
40 char data[0];
41 };
42
43 static struct parser_context *
parser_init_guts(u64 addr,u32 bytes,BOOL local,BOOL standard_payload_header,BOOL * retry)44 parser_init_guts(u64 addr, u32 bytes, BOOL local,
45 BOOL standard_payload_header, BOOL *retry)
46 {
47 int allocbytes = sizeof(struct parser_context) + bytes;
48 struct parser_context *rc = NULL;
49 struct parser_context *ctx = NULL;
50 struct memregion *rgn = NULL;
51 struct spar_controlvm_parameters_header *phdr = NULL;
52
53 if (retry)
54 *retry = FALSE;
55 if (!standard_payload_header)
56 /* alloc and 0 extra byte to ensure payload is
57 * '\0'-terminated
58 */
59 allocbytes++;
60 if ((controlvm_payload_bytes_buffered + bytes)
61 > MAX_CONTROLVM_PAYLOAD_BYTES) {
62 if (retry)
63 *retry = TRUE;
64 rc = NULL;
65 goto cleanup;
66 }
67 ctx = kzalloc(allocbytes, GFP_KERNEL|__GFP_NORETRY);
68 if (!ctx) {
69 if (retry)
70 *retry = TRUE;
71 rc = NULL;
72 goto cleanup;
73 }
74
75 ctx->allocbytes = allocbytes;
76 ctx->param_bytes = bytes;
77 ctx->curr = NULL;
78 ctx->bytes_remaining = 0;
79 ctx->byte_stream = FALSE;
80 if (local) {
81 void *p;
82
83 if (addr > virt_to_phys(high_memory - 1)) {
84 rc = NULL;
85 goto cleanup;
86 }
87 p = __va((ulong) (addr));
88 memcpy(ctx->data, p, bytes);
89 } else {
90 rgn = visor_memregion_create(addr, bytes);
91 if (!rgn) {
92 rc = NULL;
93 goto cleanup;
94 }
95 if (visor_memregion_read(rgn, 0, ctx->data, bytes) < 0) {
96 rc = NULL;
97 goto cleanup;
98 }
99 }
100 if (!standard_payload_header) {
101 ctx->byte_stream = TRUE;
102 rc = ctx;
103 goto cleanup;
104 }
105 phdr = (struct spar_controlvm_parameters_header *)(ctx->data);
106 if (phdr->total_length != bytes) {
107 rc = NULL;
108 goto cleanup;
109 }
110 if (phdr->total_length < phdr->header_length) {
111 rc = NULL;
112 goto cleanup;
113 }
114 if (phdr->header_length <
115 sizeof(struct spar_controlvm_parameters_header)) {
116 rc = NULL;
117 goto cleanup;
118 }
119
120 rc = ctx;
121 cleanup:
122 if (rgn) {
123 visor_memregion_destroy(rgn);
124 rgn = NULL;
125 }
126 if (rc) {
127 controlvm_payload_bytes_buffered += ctx->param_bytes;
128 } else {
129 if (ctx) {
130 parser_done(ctx);
131 ctx = NULL;
132 }
133 }
134 return rc;
135 }
136
137 struct parser_context *
parser_init(u64 addr,u32 bytes,BOOL local,BOOL * retry)138 parser_init(u64 addr, u32 bytes, BOOL local, BOOL *retry)
139 {
140 return parser_init_guts(addr, bytes, local, TRUE, retry);
141 }
142
143 /* Call this instead of parser_init() if the payload area consists of just
144 * a sequence of bytes, rather than a struct spar_controlvm_parameters_header
145 * structures. Afterwards, you can call parser_simpleString_get() or
146 * parser_byteStream_get() to obtain the data.
147 */
148 struct parser_context *
parser_init_byte_stream(u64 addr,u32 bytes,BOOL local,BOOL * retry)149 parser_init_byte_stream(u64 addr, u32 bytes, BOOL local, BOOL *retry)
150 {
151 return parser_init_guts(addr, bytes, local, FALSE, retry);
152 }
153
154 /* Obtain '\0'-terminated copy of string in payload area.
155 */
156 char *
parser_simpleString_get(struct parser_context * ctx)157 parser_simpleString_get(struct parser_context *ctx)
158 {
159 if (!ctx->byte_stream)
160 return NULL;
161 return ctx->data; /* note this IS '\0'-terminated, because of
162 * the num of bytes we alloc+clear in
163 * parser_init_byteStream() */
164 }
165
166 /* Obtain a copy of the buffer in the payload area.
167 */
parser_byte_stream_get(struct parser_context * ctx,ulong * nbytes)168 void *parser_byte_stream_get(struct parser_context *ctx, ulong *nbytes)
169 {
170 if (!ctx->byte_stream)
171 return NULL;
172 if (nbytes)
173 *nbytes = ctx->param_bytes;
174 return (void *)ctx->data;
175 }
176
177 uuid_le
parser_id_get(struct parser_context * ctx)178 parser_id_get(struct parser_context *ctx)
179 {
180 struct spar_controlvm_parameters_header *phdr = NULL;
181
182 if (ctx == NULL)
183 return NULL_UUID_LE;
184 phdr = (struct spar_controlvm_parameters_header *)(ctx->data);
185 return phdr->id;
186 }
187
188 void
parser_param_start(struct parser_context * ctx,PARSER_WHICH_STRING which_string)189 parser_param_start(struct parser_context *ctx, PARSER_WHICH_STRING which_string)
190 {
191 struct spar_controlvm_parameters_header *phdr = NULL;
192
193 if (ctx == NULL)
194 goto Away;
195 phdr = (struct spar_controlvm_parameters_header *)(ctx->data);
196 switch (which_string) {
197 case PARSERSTRING_INITIATOR:
198 ctx->curr = ctx->data + phdr->initiator_offset;
199 ctx->bytes_remaining = phdr->initiator_length;
200 break;
201 case PARSERSTRING_TARGET:
202 ctx->curr = ctx->data + phdr->target_offset;
203 ctx->bytes_remaining = phdr->target_length;
204 break;
205 case PARSERSTRING_CONNECTION:
206 ctx->curr = ctx->data + phdr->connection_offset;
207 ctx->bytes_remaining = phdr->connection_length;
208 break;
209 case PARSERSTRING_NAME:
210 ctx->curr = ctx->data + phdr->name_offset;
211 ctx->bytes_remaining = phdr->name_length;
212 break;
213 default:
214 break;
215 }
216
217 Away:
218 return;
219 }
220
221 void
parser_done(struct parser_context * ctx)222 parser_done(struct parser_context *ctx)
223 {
224 if (!ctx)
225 return;
226 controlvm_payload_bytes_buffered -= ctx->param_bytes;
227 kfree(ctx);
228 }
229
230 /** Return length of string not counting trailing spaces. */
231 static int
string_length_no_trail(char * s,int len)232 string_length_no_trail(char *s, int len)
233 {
234 int i = len - 1;
235
236 while (i >= 0) {
237 if (!isspace(s[i]))
238 return i + 1;
239 i--;
240 }
241 return 0;
242 }
243
244 /** Grab the next name and value out of the parameter buffer.
245 * The entire parameter buffer looks like this:
246 * <name>=<value>\0
247 * <name>=<value>\0
248 * ...
249 * \0
250 * If successful, the next <name> value is returned within the supplied
251 * <nam> buffer (the value is always upper-cased), and the corresponding
252 * <value> is returned within a kmalloc()ed buffer, whose pointer is
253 * provided as the return value of this function.
254 * (The total number of bytes allocated is strlen(<value>)+1.)
255 *
256 * NULL is returned to indicate failure, which can occur for several reasons:
257 * - all <name>=<value> pairs have already been processed
258 * - bad parameter
259 * - parameter buffer ends prematurely (couldn't find an '=' or '\0' within
260 * the confines of the parameter buffer)
261 * - the <nam> buffer is not large enough to hold the <name> of the next
262 * parameter
263 */
264 void *
parser_param_get(struct parser_context * ctx,char * nam,int namesize)265 parser_param_get(struct parser_context *ctx, char *nam, int namesize)
266 {
267 u8 *pscan, *pnam = nam;
268 ulong nscan;
269 int value_length = -1, orig_value_length = -1;
270 void *value = NULL;
271 int i;
272 int closing_quote = 0;
273
274 if (!ctx)
275 return NULL;
276 pscan = ctx->curr;
277 nscan = ctx->bytes_remaining;
278 if (nscan == 0)
279 return NULL;
280 if (*pscan == '\0')
281 /* This is the normal return point after you have processed
282 * all of the <name>=<value> pairs in a syntactically-valid
283 * parameter buffer.
284 */
285 return NULL;
286
287 /* skip whitespace */
288 while (isspace(*pscan)) {
289 pscan++;
290 nscan--;
291 if (nscan == 0)
292 return NULL;
293 }
294
295 while (*pscan != ':') {
296 if (namesize <= 0)
297 return NULL;
298 *pnam = toupper(*pscan);
299 pnam++;
300 namesize--;
301 pscan++;
302 nscan--;
303 if (nscan == 0)
304 return NULL;
305 }
306 if (namesize <= 0)
307 return NULL;
308 *pnam = '\0';
309 nam[string_length_no_trail(nam, strlen(nam))] = '\0';
310
311 /* point to char immediately after ":" in "<name>:<value>" */
312 pscan++;
313 nscan--;
314 /* skip whitespace */
315 while (isspace(*pscan)) {
316 pscan++;
317 nscan--;
318 if (nscan == 0)
319 return NULL;
320 }
321 if (nscan == 0)
322 return NULL;
323 if (*pscan == '\'' || *pscan == '"') {
324 closing_quote = *pscan;
325 pscan++;
326 nscan--;
327 if (nscan == 0)
328 return NULL;
329 }
330
331 /* look for a separator character, terminator character, or
332 * end of data
333 */
334 for (i = 0, value_length = -1; i < nscan; i++) {
335 if (closing_quote) {
336 if (pscan[i] == '\0')
337 return NULL;
338 if (pscan[i] == closing_quote) {
339 value_length = i;
340 break;
341 }
342 } else
343 if (pscan[i] == ',' || pscan[i] == ';'
344 || pscan[i] == '\0') {
345 value_length = i;
346 break;
347 }
348 }
349 if (value_length < 0) {
350 if (closing_quote)
351 return NULL;
352 value_length = nscan;
353 }
354 orig_value_length = value_length;
355 if (closing_quote == 0)
356 value_length = string_length_no_trail(pscan, orig_value_length);
357 value = kmalloc(value_length + 1, GFP_KERNEL|__GFP_NORETRY);
358 if (value == NULL)
359 return NULL;
360 memcpy(value, pscan, value_length);
361 ((u8 *) (value))[value_length] = '\0';
362
363 pscan += orig_value_length;
364 nscan -= orig_value_length;
365
366 /* skip past separator or closing quote */
367 if (nscan > 0) {
368 if (*pscan != '\0') {
369 pscan++;
370 nscan--;
371 }
372 }
373
374 if (closing_quote && (nscan > 0)) {
375 /* we still need to skip around the real separator if present */
376 /* first, skip whitespace */
377 while (isspace(*pscan)) {
378 pscan++;
379 nscan--;
380 if (nscan == 0)
381 break;
382 }
383 if (nscan > 0) {
384 if (*pscan == ',' || *pscan == ';') {
385 pscan++;
386 nscan--;
387 } else if (*pscan != '\0') {
388 kfree(value);
389 value = NULL;
390 return NULL;
391 }
392 }
393 }
394 ctx->curr = pscan;
395 ctx->bytes_remaining = nscan;
396 return value;
397 }
398
399 void *
parser_string_get(struct parser_context * ctx)400 parser_string_get(struct parser_context *ctx)
401 {
402 u8 *pscan;
403 ulong nscan;
404 int value_length = -1;
405 void *value = NULL;
406 int i;
407
408 if (!ctx)
409 return NULL;
410 pscan = ctx->curr;
411 nscan = ctx->bytes_remaining;
412 if (nscan == 0)
413 return NULL;
414 if (!pscan)
415 return NULL;
416 for (i = 0, value_length = -1; i < nscan; i++)
417 if (pscan[i] == '\0') {
418 value_length = i;
419 break;
420 }
421 if (value_length < 0) /* '\0' was not included in the length */
422 value_length = nscan;
423 value = kmalloc(value_length + 1, GFP_KERNEL|__GFP_NORETRY);
424 if (value == NULL)
425 return NULL;
426 if (value_length > 0)
427 memcpy(value, pscan, value_length);
428 ((u8 *) (value))[value_length] = '\0';
429 return value;
430 }
431