Merge 3.18-rc3 into staging-next
[cascardo/linux.git] / drivers / staging / unisys / visorchipset / parser.c
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_Tag {
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 PARSER_CONTEXT *
44 parser_init_guts(u64 addr, u32 bytes, BOOL isLocal,
45                  BOOL hasStandardPayloadHeader, BOOL *tryAgain)
46 {
47         int allocbytes = sizeof(PARSER_CONTEXT) + bytes;
48         PARSER_CONTEXT *rc = NULL;
49         PARSER_CONTEXT *ctx = NULL;
50         MEMREGION *rgn = NULL;
51         struct spar_controlvm_parameters_header *phdr = NULL;
52
53         if (tryAgain)
54                 *tryAgain = FALSE;
55         if (!hasStandardPayloadHeader)
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                 ERRDRV("%s (%s:%d) - prevented allocation of %d bytes to prevent exceeding throttling max (%d)",
63                        __func__, __FILE__, __LINE__, allocbytes,
64                        MAX_CONTROLVM_PAYLOAD_BYTES);
65                 if (tryAgain)
66                         *tryAgain = TRUE;
67                 rc = NULL;
68                 goto Away;
69         }
70         ctx = kzalloc(allocbytes, GFP_KERNEL|__GFP_NORETRY);
71         if (ctx == NULL) {
72                 ERRDRV("%s (%s:%d) - failed to allocate %d bytes",
73                        __func__, __FILE__, __LINE__, allocbytes);
74                 if (tryAgain)
75                         *tryAgain = TRUE;
76                 rc = NULL;
77                 goto Away;
78         }
79
80         ctx->allocbytes = allocbytes;
81         ctx->param_bytes = bytes;
82         ctx->curr = NULL;
83         ctx->bytes_remaining = 0;
84         ctx->byte_stream = FALSE;
85         if (isLocal) {
86                 void *p;
87
88                 if (addr > virt_to_phys(high_memory - 1)) {
89                         ERRDRV("%s - bad local address (0x%-16.16Lx for %lu)",
90                                __func__,
91                                (unsigned long long) addr, (ulong) bytes);
92                         rc = NULL;
93                         goto Away;
94                 }
95                 p = __va((ulong) (addr));
96                 memcpy(ctx->data, p, bytes);
97         } else {
98                 rgn = visor_memregion_create(addr, bytes);
99                 if (!rgn) {
100                         rc = NULL;
101                         goto Away;
102                 }
103                 if (visor_memregion_read(rgn, 0, ctx->data, bytes) < 0) {
104                         rc = NULL;
105                         goto Away;
106                 }
107         }
108         if (!hasStandardPayloadHeader) {
109                 ctx->byte_stream = TRUE;
110                 rc = ctx;
111                 goto Away;
112         }
113         phdr = (struct spar_controlvm_parameters_header *)(ctx->data);
114         if (phdr->total_length != bytes) {
115                 ERRDRV("%s - bad total length %lu (should be %lu)",
116                        __func__,
117                        (ulong) (phdr->total_length), (ulong) (bytes));
118                 rc = NULL;
119                 goto Away;
120         }
121         if (phdr->total_length < phdr->header_length) {
122                 ERRDRV("%s - total length < header length (%lu < %lu)",
123                        __func__,
124                        (ulong) (phdr->total_length),
125                        (ulong) (phdr->header_length));
126                 rc = NULL;
127                 goto Away;
128         }
129         if (phdr->header_length <
130             sizeof(struct spar_controlvm_parameters_header)) {
131                 ERRDRV("%s - header is too small (%lu < %lu)",
132                        __func__,
133                        (ulong) (phdr->header_length),
134                        (ulong)(sizeof(
135                                 struct spar_controlvm_parameters_header)));
136                 rc = NULL;
137                 goto Away;
138         }
139
140         rc = ctx;
141 Away:
142         if (rgn) {
143                 visor_memregion_destroy(rgn);
144                 rgn = NULL;
145         }
146         if (rc)
147                 Controlvm_Payload_Bytes_Buffered += ctx->param_bytes;
148         else {
149                 if (ctx) {
150                         parser_done(ctx);
151                         ctx = NULL;
152                 }
153         }
154         return rc;
155 }
156
157 PARSER_CONTEXT *
158 parser_init(u64 addr, u32 bytes, BOOL isLocal, BOOL *tryAgain)
159 {
160         return parser_init_guts(addr, bytes, isLocal, TRUE, tryAgain);
161 }
162
163 /* Call this instead of parser_init() if the payload area consists of just
164  * a sequence of bytes, rather than a struct spar_controlvm_parameters_header
165  * structures.  Afterwards, you can call parser_simpleString_get() or
166  * parser_byteStream_get() to obtain the data.
167  */
168 PARSER_CONTEXT *
169 parser_init_byteStream(u64 addr, u32 bytes, BOOL isLocal, BOOL *tryAgain)
170 {
171         return parser_init_guts(addr, bytes, isLocal, FALSE, tryAgain);
172 }
173
174 /* Obtain '\0'-terminated copy of string in payload area.
175  */
176 char *
177 parser_simpleString_get(PARSER_CONTEXT *ctx)
178 {
179         if (!ctx->byte_stream)
180                 return NULL;
181         return ctx->data;       /* note this IS '\0'-terminated, because of
182                                  * the num of bytes we alloc+clear in
183                                  * parser_init_byteStream() */
184 }
185
186 /* Obtain a copy of the buffer in the payload area.
187  */
188 void *
189 parser_byteStream_get(PARSER_CONTEXT *ctx, ulong *nbytes)
190 {
191         if (!ctx->byte_stream)
192                 return NULL;
193         if (nbytes)
194                 *nbytes = ctx->param_bytes;
195         return (void *) ctx->data;
196 }
197
198 uuid_le
199 parser_id_get(PARSER_CONTEXT *ctx)
200 {
201         struct spar_controlvm_parameters_header *phdr = NULL;
202
203         if (ctx == NULL) {
204                 ERRDRV("%s (%s:%d) - no context",
205                        __func__, __FILE__, __LINE__);
206                 return NULL_UUID_LE;
207         }
208         phdr = (struct spar_controlvm_parameters_header *)(ctx->data);
209         return phdr->id;
210 }
211
212 void
213 parser_param_start(PARSER_CONTEXT *ctx, PARSER_WHICH_STRING which_string)
214 {
215         struct spar_controlvm_parameters_header *phdr = NULL;
216
217         if (ctx == NULL) {
218                 ERRDRV("%s (%s:%d) - no context",
219                        __func__, __FILE__, __LINE__);
220                 goto Away;
221         }
222         phdr = (struct spar_controlvm_parameters_header *)(ctx->data);
223         switch (which_string) {
224         case PARSERSTRING_INITIATOR:
225                 ctx->curr = ctx->data + phdr->initiator_offset;
226                 ctx->bytes_remaining = phdr->initiator_length;
227                 break;
228         case PARSERSTRING_TARGET:
229                 ctx->curr = ctx->data + phdr->target_offset;
230                 ctx->bytes_remaining = phdr->target_length;
231                 break;
232         case PARSERSTRING_CONNECTION:
233                 ctx->curr = ctx->data + phdr->connection_offset;
234                 ctx->bytes_remaining = phdr->connection_length;
235                 break;
236         case PARSERSTRING_NAME:
237                 ctx->curr = ctx->data + phdr->name_offset;
238                 ctx->bytes_remaining = phdr->name_length;
239                 break;
240         default:
241                 ERRDRV("%s - bad which_string %d", __func__, which_string);
242                 break;
243         }
244
245 Away:
246         return;
247 }
248
249 void
250 parser_done(PARSER_CONTEXT *ctx)
251 {
252         if (!ctx)
253                 return;
254         Controlvm_Payload_Bytes_Buffered -= ctx->param_bytes;
255         kfree(ctx);
256 }
257
258 /** Return length of string not counting trailing spaces. */
259 static int
260 string_length_no_trail(char *s, int len)
261 {
262         int i = len - 1;
263
264         while (i >= 0) {
265                 if (!isspace(s[i]))
266                         return i + 1;
267                 i--;
268         }
269         return 0;
270 }
271
272 /** Grab the next name and value out of the parameter buffer.
273  *  The entire parameter buffer looks like this:
274  *      <name>=<value>\0
275  *      <name>=<value>\0
276  *      ...
277  *      \0
278  *  If successful, the next <name> value is returned within the supplied
279  *  <nam> buffer (the value is always upper-cased), and the corresponding
280  *  <value> is returned within a kmalloc()ed buffer, whose pointer is
281  *  provided as the return value of this function.
282  *  (The total number of bytes allocated is strlen(<value>)+1.)
283  *
284  *  NULL is returned to indicate failure, which can occur for several reasons:
285  *  - all <name>=<value> pairs have already been processed
286  *  - bad parameter
287  *  - parameter buffer ends prematurely (couldn't find an '=' or '\0' within
288  *    the confines of the parameter buffer)
289  *  - the <nam> buffer is not large enough to hold the <name> of the next
290  *    parameter
291  */
292 void *
293 parser_param_get(PARSER_CONTEXT *ctx, char *nam, int namesize)
294 {
295         u8 *pscan, *pnam = nam;
296         ulong nscan;
297         int value_length = -1, orig_value_length = -1;
298         void *value = NULL;
299         int i;
300         int closing_quote = 0;
301
302         if (!ctx)
303                 return NULL;
304         pscan = ctx->curr;
305         nscan = ctx->bytes_remaining;
306         if (nscan == 0)
307                 return NULL;
308         if (*pscan == '\0')
309                 /*  This is the normal return point after you have processed
310                  *  all of the <name>=<value> pairs in a syntactically-valid
311                  *  parameter buffer.
312                  */
313                 return NULL;
314
315         /* skip whitespace */
316         while (isspace(*pscan)) {
317                 pscan++;
318                 nscan--;
319                 if (nscan == 0)
320                         return NULL;
321         }
322
323         while (*pscan != ':') {
324                 if (namesize <= 0) {
325                         ERRDRV("%s - name too big", __func__);
326                         return NULL;
327                 }
328                 *pnam = toupper(*pscan);
329                 pnam++;
330                 namesize--;
331                 pscan++;
332                 nscan--;
333                 if (nscan == 0) {
334                         ERRDRV("%s - unexpected end of input parsing name",
335                                __func__);
336                         return NULL;
337                 }
338         }
339         if (namesize <= 0) {
340                 ERRDRV("%s - name too big", __func__);
341                 return NULL;
342         }
343         *pnam = '\0';
344         nam[string_length_no_trail(nam, strlen(nam))] = '\0';
345
346         /* point to char immediately after ":" in "<name>:<value>" */
347         pscan++;
348         nscan--;
349         /* skip whitespace */
350         while (isspace(*pscan)) {
351                 pscan++;
352                 nscan--;
353                 if (nscan == 0) {
354                         ERRDRV("%s - unexpected end of input looking for value",
355                                __func__);
356                         return NULL;
357                 }
358         }
359         if (nscan == 0) {
360                 ERRDRV("%s - unexpected end of input looking for value",
361                        __func__);
362                 return NULL;
363         }
364         if (*pscan == '\'' || *pscan == '"') {
365                 closing_quote = *pscan;
366                 pscan++;
367                 nscan--;
368                 if (nscan == 0) {
369                         ERRDRV("%s - unexpected end of input after %c",
370                                __func__, closing_quote);
371                         return NULL;
372                 }
373         }
374
375         /* look for a separator character, terminator character, or
376          * end of data
377          */
378         for (i = 0, value_length = -1; i < nscan; i++) {
379                 if (closing_quote) {
380                         if (pscan[i] == '\0') {
381                                 ERRDRV("%s - unexpected end of input parsing quoted value", __func__);
382                                 return NULL;
383                         }
384                         if (pscan[i] == closing_quote) {
385                                 value_length = i;
386                                 break;
387                         }
388                 } else
389                     if (pscan[i] == ',' || pscan[i] == ';'
390                         || pscan[i] == '\0') {
391                         value_length = i;
392                         break;
393                 }
394         }
395         if (value_length < 0) {
396                 if (closing_quote) {
397                         ERRDRV("%s - unexpected end of input parsing quoted value", __func__);
398                         return NULL;
399                 }
400                 value_length = nscan;
401         }
402         orig_value_length = value_length;
403         if (closing_quote == 0)
404                 value_length = string_length_no_trail(pscan, orig_value_length);
405         value = kmalloc(value_length + 1, GFP_KERNEL|__GFP_NORETRY);
406         if (value == NULL)
407                 return NULL;
408         memcpy(value, pscan, value_length);
409         ((u8 *) (value))[value_length] = '\0';
410
411         pscan += orig_value_length;
412         nscan -= orig_value_length;
413
414         /* skip past separator or closing quote */
415         if (nscan > 0) {
416                 if (*pscan != '\0') {
417                         pscan++;
418                         nscan--;
419                 }
420         }
421
422         if (closing_quote && (nscan > 0)) {
423                 /* we still need to skip around the real separator if present */
424                 /* first, skip whitespace */
425                 while (isspace(*pscan)) {
426                         pscan++;
427                         nscan--;
428                         if (nscan == 0)
429                                 break;
430                 }
431                 if (nscan > 0) {
432                         if (*pscan == ',' || *pscan == ';') {
433                                 pscan++;
434                                 nscan--;
435                         } else if (*pscan != '\0') {
436                                 ERRDRV("%s - missing separator after quoted string", __func__);
437                                 kfree(value);
438                                 value = NULL;
439                                 return NULL;
440                         }
441                 }
442         }
443         ctx->curr = pscan;
444         ctx->bytes_remaining = nscan;
445         return value;
446 }
447
448 void *
449 parser_string_get(PARSER_CONTEXT *ctx)
450 {
451         u8 *pscan;
452         ulong nscan;
453         int value_length = -1;
454         void *value = NULL;
455         int i;
456
457         if (!ctx)
458                 return NULL;
459         pscan = ctx->curr;
460         nscan = ctx->bytes_remaining;
461         if (nscan == 0)
462                 return NULL;
463         if (!pscan)
464                 return NULL;
465         for (i = 0, value_length = -1; i < nscan; i++)
466                 if (pscan[i] == '\0') {
467                         value_length = i;
468                         break;
469                 }
470         if (value_length < 0)   /* '\0' was not included in the length */
471                 value_length = nscan;
472         value = kmalloc(value_length + 1, GFP_KERNEL|__GFP_NORETRY);
473         if (value == NULL)
474                 return NULL;
475         if (value_length > 0)
476                 memcpy(value, pscan, value_length);
477         ((u8 *) (value))[value_length] = '\0';
478         return value;
479 }