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