memory corruption bugfixes
[cor_2_6_31.git] / net / cor / cpacket_parse.c
blobe4211b09984028b9f6d4671e2f0bf9bd69baa864
1 /*
2 * Connection oriented routing
3 * Copyright (C) 2007-2008 Michael Blizek
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA.
21 #include "cor.h"
23 static char *get_error_reason_text(__u16 reasoncode)
25 if (reasoncode == CDR_EXECFAILED_UNKNOWN_COMMAND)
26 return "Unknown command";
27 else if (reasoncode == CDR_EXECFAILED_PERMISSION_DENIED)
28 return "Permission denied";
29 else if (reasoncode == CDR_EXECFAILED_TEMPORARILY_OUT_OF_RESSOURCES)
30 return "Temporarily out of ressources";
31 else if (reasoncode == CDR_EXECFAILED_CMD_TOO_SHORT)
32 return "The length of the command is too short for all params";
33 else if (reasoncode == CDR_EXECFAILED_CMD_TOO_LONG)
34 return "command param is too long";
35 else if (reasoncode == CDR_EXECFAILED_TARGETADDRTYPE_UNKNOWN)
36 return "targettype unknown";
37 else if (reasoncode == CDR_EXECFAILED_TARGETADDR_DOESNTEXIST)
38 return "targetaddr does not exist";
39 else if (reasoncode == CDR_EXECFAILED_TARGETADDR_PORTCLOSED)
40 return "Port is on open";
41 else if (reasoncode == CDR_EXECFAILED_LISTENERQUEUE_FULL)
42 return "Listener queue full";
43 else
44 return 0;
47 static void send_resp(struct conn *conn, __u16 respcode,
48 __u16 reasoncode)
50 struct conn *rconn = conn->reversedir;
52 int reasonlen = 0;
53 __u16 reasonlen_be;
55 char *reasontext = 0;
57 if (respcode == CDR_EXECFAILED)
58 get_error_reason_text(respcode);
60 if (reasontext)
61 reasonlen = strnlen(reasontext, 65535);
63 respcode = cpu_to_be16(respcode);
64 reasoncode = cpu_to_be16(reasoncode);
65 reasonlen_be = cpu_to_be16(reasonlen);
67 if (rconn->targettype == TARGET_SOCK) {
68 mutex_lock(&(rconn->target.sock.lock));
69 ringbuffer_put(&(rconn->target.sock.rbuf),
70 (char *) &respcode, 2, 0);
71 ringbuffer_put(&(rconn->target.sock.rbuf),
72 (char *) &reasoncode, 2, 0);
73 ringbuffer_put(&(rconn->target.sock.rbuf),
74 (char *) &reasonlen_be, 2, 0);
75 ringbuffer_put(&(rconn->target.sock.rbuf), reasontext,
76 reasonlen, 0);
77 mutex_unlock(&(rconn->target.sock.lock));
78 } else if (rconn->targettype == TARGET_OUT) {
79 #warning todo
80 } else {
81 BUG();
85 static void send_resp_bin(struct conn *rconn, char *buf, __u32 len)
87 struct conn *sconn = rconn->reversedir;
89 __u32 code = cpu_to_be16(CDR_BINDATA);
90 __u32 len_be = cpu_to_be32(len);
92 if (sconn->targettype == TARGET_SOCK) {
93 mutex_lock(&(sconn->target.sock.lock));
94 ringbuffer_put(&(sconn->target.sock.rbuf),
95 (char *) &code, 2, 0);
96 ringbuffer_put(&(sconn->target.sock.rbuf),
97 (char *) &len_be, 4, 0);
98 ringbuffer_put(&(sconn->target.sock.rbuf), buf, len, 0);
99 mutex_unlock(&(sconn->target.sock.lock));
100 } else if (sconn->targettype == TARGET_OUT) {
101 #warning todo
102 } else {
103 BUG();
107 static void parse_list_neigh(struct conn *rconn)
109 __u32 limit;
110 __u32 offset;
111 __u32 len;
113 char *buf;
115 if (rconn->target.unconnected.paramlen < 8) {
116 send_resp(rconn, CDR_EXECFAILED, CDR_EXECFAILED_CMD_TOO_SHORT);
117 return;
120 ((char *)&limit)[0] = rconn->target.unconnected.cmdparams[0];
121 ((char *)&limit)[1] = rconn->target.unconnected.cmdparams[1];
122 ((char *)&limit)[2] = rconn->target.unconnected.cmdparams[2];
123 ((char *)&limit)[3] = rconn->target.unconnected.cmdparams[3];
125 ((char *)&offset)[0] = rconn->target.unconnected.cmdparams[4];
126 ((char *)&offset)[1] = rconn->target.unconnected.cmdparams[5];
127 ((char *)&offset)[2] = rconn->target.unconnected.cmdparams[6];
128 ((char *)&offset)[3] = rconn->target.unconnected.cmdparams[7];
130 limit = be32_to_cpu(limit);
131 offset = be32_to_cpu(offset);
133 buf = kmalloc(2048, GFP_KERNEL);
135 if (unlikely(buf == 0)) {
136 send_resp(rconn, CDR_EXECFAILED,
137 CDR_EXECFAILED_TEMPORARILY_OUT_OF_RESSOURCES);
138 return;
141 send_resp(rconn, CDR_EXECOK, CDR_EXECOK_OK);
143 len = generate_neigh_list(buf, 2048, limit, offset);
144 send_resp_bin(rconn, buf, len);
147 static void parse_connect_port(struct conn *rconn)
149 __be64 addr;
150 int rc;
152 BUG_ON(0 == rconn->target.unconnected.cmdparams);
154 if (rconn->target.unconnected.paramlen < 8) {
155 send_resp(rconn, CDR_EXECFAILED, CDR_EXECFAILED_CMD_TOO_SHORT);
156 return;
159 memcpy((char *) &addr, rconn->target.unconnected.cmdparams, 8);
161 rc = connect_port(rconn, addr);
163 if (rc == 2) {
164 send_resp(rconn, CDR_EXECFAILED,
165 CDR_EXECFAILED_TARGETADDR_DOESNTEXIST);
166 } else if (rc != 3) {
167 send_resp(rconn, CDR_EXECFAILED,
168 CDR_EXECFAILED_LISTENERQUEUE_FULL);
169 } else if (rc == 0) {
170 send_resp(rconn, CDR_EXECOK, CDR_EXECOK_OK);
171 } else if (unlikely(rc != 0)) {
172 BUG();
176 static void parse_connect_nb(struct conn *rconn)
178 __u16 addrtypelen;
179 __u16 addrlen;
180 __u8 *addrtype;
181 __u8 *addr;
182 int rc;
184 BUG_ON(0 == rconn->target.unconnected.cmdparams);
186 if (rconn->target.unconnected.paramlen < 4) {
187 send_resp(rconn, CDR_EXECFAILED, CDR_EXECFAILED_CMD_TOO_SHORT);
188 return;
191 ((char *)&addrtypelen)[0] = rconn->target.unconnected.cmdparams[0];
192 ((char *)&addrtypelen)[1] = rconn->target.unconnected.cmdparams[1];
194 ((char *)&addrlen)[0] = rconn->target.unconnected.cmdparams[2];
195 ((char *)&addrlen)[1] = rconn->target.unconnected.cmdparams[3];
197 addrtypelen = be16_to_cpu(addrtypelen);
198 addrlen = be16_to_cpu(addrlen);
200 if ((4 + (__u32) addrtypelen + (__u32) addrlen) >
201 rconn->target.unconnected.paramlen) {
202 send_resp(rconn, CDR_EXECFAILED, CDR_EXECFAILED_CMD_TOO_SHORT);
203 return;
206 addrtype = rconn->target.unconnected.cmdparams + 4;
207 addr = addrtype + addrtypelen;
209 rc = connect_neigh(rconn, addrtypelen, addrtype, addrlen, addr);
211 if (rc == 2) {
212 send_resp(rconn, CDR_EXECFAILED,
213 CDR_EXECFAILED_TARGETADDRTYPE_UNKNOWN);
214 } else if (rc == 3) {
215 send_resp(rconn, CDR_EXECFAILED,
216 CDR_EXECFAILED_TARGETADDR_DOESNTEXIST);
217 } else if (rc == 4) {
218 send_resp(rconn, CDR_EXECFAILED,
219 CDR_EXECFAILED_TEMPORARILY_OUT_OF_RESSOURCES);
220 } else if (rc == 0) {
221 send_resp(rconn, CDR_EXECOK, CDR_EXECOK_OK);
222 } else if (unlikely(rc != 0)) {
223 BUG();
227 static void parse_cmd(struct conn *rconn)
229 __u16 code = rconn->target.unconnected.cmd;
231 if (code == CD_CONNECT_NB) {
232 parse_connect_nb(rconn);
233 } else if (code == CD_CONNECT_PORT) {
234 parse_connect_port(rconn);
235 } else if (code == CD_LIST_NEIGH) {
236 parse_list_neigh(rconn);
237 } else {
238 send_resp(rconn, CDR_EXECFAILED, CDR_EXECFAILED_UNKNOWN_COMMAND);
242 static void read_cmd(struct data *data, struct conn *rconn)
244 char *buf;
245 int pull;
247 pull = min(rconn->target.unconnected.paramlen + 6 -
248 rconn->target.unconnected.cmdread, data_len(data));
250 BUG_ON(0 > pull);
251 BUG_ON(0 == rconn->target.unconnected.cmdparams);
252 BUG_ON(6 > rconn->target.unconnected.cmdread);
254 if (pull == 0)
255 return;
257 buf = data_pull(data, pull);
259 BUG_ON(0 == buf);
261 memcpy(rconn->target.unconnected.cmdparams +
262 rconn->target.unconnected.cmdread - 6, buf, pull);
263 rconn->target.unconnected.cmdread += pull;
266 static void read_discard(struct data *data, struct conn *rconn)
268 char *buf;
269 int pull;
271 pull = min(rconn->target.unconnected.paramlen + 6 -
272 rconn->target.unconnected.cmdread, data_len(data));
274 BUG_ON(0 > pull);
275 BUG_ON(6 > rconn->target.unconnected.cmdread);
277 if (pull == 0)
278 return;
280 buf = data_pull(data, pull);
282 BUG_ON(data == 0);
284 rconn->target.unconnected.cmdread += pull;
287 static void read_hdr(struct data *data, struct conn *rconn)
289 char *buf;
290 int readoffset;
291 int pull;
293 pull = min(6 - rconn->target.unconnected.cmdread, data_len(data));
295 if (pull == 0)
296 return;
298 BUG_ON(pull < 0);
300 buf = data_pull(data, pull);
302 BUG_ON(rconn->target.unconnected.cmdparams == 0);
303 BUG_ON(buf == 0);
305 for (readoffset=0;readoffset<pull;readoffset++) {
306 if (2 > rconn->target.unconnected.cmdread) {
307 rconn->target.unconnected.cmd <<= 8;
308 rconn->target.unconnected.cmd += buf[readoffset];
309 } else {
310 rconn->target.unconnected.paramlen <<= 8;
311 rconn->target.unconnected.paramlen +=
312 buf[readoffset];
314 rconn->target.unconnected.cmdread++;
318 void parse(struct data *data, struct conn *rconn)
320 __u8 *cmd;
322 BUG_ON(TARGET_UNCONNECTED != rconn->targettype);
324 if (rconn->target.unconnected.cmdparams == 0)
325 rconn->target.unconnected.cmdparams = kmalloc(MAX_CONN_CMD_LEN,
326 GFP_KERNEL);
328 cmd = rconn->target.unconnected.cmdparams;
330 if (rconn->target.unconnected.cmdread == 0) {
331 rconn->target.unconnected.cmd = 0;
332 rconn->target.unconnected.paramlen = 0;
335 if (rconn->target.unconnected.cmdread < 6) {
336 read_hdr(data, rconn);
337 if (rconn->target.unconnected.cmdread < 6)
338 return;
340 if (rconn->target.unconnected.paramlen > MAX_CONN_CMD_LEN) {
341 send_resp(rconn, CDR_EXECFAILED,
342 CDR_EXECFAILED_CMD_TOO_LONG);
346 if (rconn->target.unconnected.paramlen > MAX_CONN_CMD_LEN) {
347 read_discard(data, rconn);
348 return;
351 if (rconn->target.unconnected.cmdread >= 6 &&
352 rconn->target.unconnected.paramlen >
353 rconn->target.unconnected.cmdread - 6) {
354 read_cmd(data, rconn);
357 if (rconn->target.unconnected.paramlen ==
358 rconn->target.unconnected.cmdread - 6) {
359 rconn->target.unconnected.cmdread = 0;
360 parse_cmd(rconn);
363 if (TARGET_UNCONNECTED != rconn->targettype)
364 kfree(cmd);