blob: 6d9aa81b00f34890040ac9d8575095e93cd8e454 [file] [log] [blame]
Yida Wang0bf43bd2017-03-22 18:16:31 -04001/*
2 * Copyright (c) 2015, 2017, The Linux Foundation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/seemp_param_id.h>
15#include "seemp_logk.h"
16#include "seemp_event_encoder.h"
17
18static char *scan_id(char *s);
19static void encode_seemp_section(char *section_start, char *section_eq,
20 char *section_end, bool param, bool numeric,
21 int id, __s32 numeric_value);
22
23static void check_param_range(char *section_eq, bool param,
24 bool *numeric, int val_len, __s32 *numeric_value)
25{
26 long long_value = 0;
27
28 if (param && *numeric) {
29 /*check if 2 bytes & in[-99999,999999]*/
30 *numeric = (val_len >= 2) && (val_len <= 6);
31 if (*numeric) {
32 if (kstrtol(section_eq + 1, 10, &long_value)
33 != 0) {
34 *numeric = false;
35 } else {
36 *numeric_value = (__s32)long_value;
37 /* We are checking whether the value
38 * lies within 16bits
39 */
40 *numeric = (long_value >= -32768) &&
41 (long_value <= 32767);
42 }
43 }
44 }
45}
46
47void encode_seemp_params(struct seemp_logk_blk *blk)
48{
49 struct seemp_logk_blk tmp;
50 char *s = 0;
51 char *msg_section_start = 0;
52 char *msg_section_eq = 0;
53 char *msg_s = 0;
54
55 memcpy(tmp.payload.msg, blk->payload.msg, BLK_MAX_MSG_SZ);
56 s = tmp.payload.msg + 1;
57 tmp.payload.msg[BLK_MAX_MSG_SZ - 1] = 0; /* zero-terminate */
58
59 while (true) {
60 char *section_start = s;
61 char *section_eq = scan_id(s);
62 bool param = (section_eq - section_start >= 2) &&
63 (*section_eq == '=') && (section_eq[1] != ' ');
64 bool numeric = false;
65 int id = -1;
66 __s32 numeric_value = 0;
67 int id_len;
68 int val_len;
69 char ch;
70
71 if (param) {
72 id = param_id_index(section_start, section_eq);
73
74 if (id < 0)
75 param = false;
76 }
77
78 if (!param) {
79 s = section_eq;
80 while ((*s != 0) && (*s != ','))
81 s++;
82 } else {
83 s = section_eq + 1; /* equal sign */
84 numeric = (*s == '-') || ((*s >= '0') && (*s <= '9'));
85
86 if (numeric)
87 s++; /* first char of number */
88
89 while ((*s != 0) && (*s != ',')) {
90 if (*s == '=')
91 param = false;
92 else if (!((*s >= '0') && (*s <= '9')))
93 numeric = false;
94
95 s++;
96 }
97
98 if (param) {
99 id_len = section_eq - section_start;
100 val_len = s - (section_eq + 1);
101 param = (id_len >= 2) && (id_len <= 31)
102 && (val_len <= 31);
103 ch = *s;
104 *s = 0;
105
106 check_param_range(section_eq, param,
107 &numeric, val_len, &numeric_value);
108 *s = ch;
109 }
110 }
111
112 msg_section_start = blk->payload.msg + (section_start -
113 tmp.payload.msg);
114 msg_section_eq = blk->payload.msg + (section_eq -
115 tmp.payload.msg);
116 msg_s = blk->payload.msg + (s - tmp.payload.msg);
117 encode_seemp_section(msg_section_start, msg_section_eq,
118 msg_s, param, numeric, id, numeric_value);
119
120 if (*s == 0)
121 break;
122
123 s++;
124 }
125
126 blk->len = s - blk->payload.msg;
127}
128
129static char *scan_id(char *s)
130{
131 while ((*s == '_') ||
132 ((*s >= 'A') && (*s <= 'Z')) ||
133 ((*s >= 'a') && (*s <= 'z'))) {
134 s++;
135 }
136
137 return s;
138}
139
140static void encode_seemp_section(char *section_start, char *section_eq,
141 char *section_end, bool param, bool numeric,
142 int id, __s32 numeric_value) {
143 param = param && (section_eq + 1 < section_end);
144
145 if (!param) {
146 /* Encode skip section */
147 int skip_len = section_end - section_start;
148 char skip_len_hi = skip_len & 0xE0;
149 char skip_len_lo = skip_len & 0x1F;
150
151 if (skip_len < 32) {
152 section_start[-1] = 0xC0 | skip_len_lo;
153 /* [1:1:0:0 0000] */
154 } else {
155 section_start[-1] = 0xE0 | skip_len_lo;
156 /* [1:1:1:0 0000] */
157
158 if (skip_len_hi & 0x20)
159 section_start[0] |= 0x80;
160
161 if (skip_len_hi & 0x40)
162 section_start[1] |= 0x80;
163
164 if (skip_len_hi & 0x80)
165 section_start[2] |= 0x80;
166 }
167 } else {
168 /* Encode ID=VALUE section */
169 char id_len = section_eq - section_start;
170 char value_len = section_end - (section_eq + 1);
171
172 section_start[-1] = 0x00 | id_len;
173 *(__s16 *)section_start = id;
174 section_eq[0] = (!numeric ? 0x80 : 0x00) | value_len;
175
176 if (numeric)
177 *(__s16 *)(section_eq + 1) = numeric_value;
178 }
179}