databuf bugfixes
[cor_2_6_31.git] / net / cor / cpacket_parse.c
blobfaf1b5a4e8a30e33d1f56223f6e19a2df9a36457
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 *rconn, __u16 respcode,
48 __u16 reasoncode)
50 struct conn *sconn = rconn->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, 1024);
63 respcode = cpu_to_be16(respcode);
64 reasoncode = cpu_to_be16(reasoncode);
65 reasonlen_be = cpu_to_be16(reasonlen);
67 mutex_lock(&(sconn->rcv_lock));
68 BUG_ON(databuf_maypush(&(sconn->buf)) < (6 + reasonlen));
69 receive_buf(sconn, (char *) &respcode, 2);
70 receive_buf(sconn, (char *) &reasoncode, 2);
71 receive_buf(sconn, (char *) &reasonlen_be, 2);
72 receive_buf(sconn, reasontext, reasonlen);
73 mutex_unlock(&(sconn->rcv_lock));
76 static void send_resp_bin(struct conn *rconn, char *buf, __u32 len)
78 struct conn *sconn = rconn->reversedir;
80 __u32 code = cpu_to_be16(CDR_BINDATA);
81 __u32 len_be = cpu_to_be32(len);
83 mutex_lock(&(sconn->rcv_lock));
84 BUG_ON(databuf_maypush(&(sconn->buf)) < (6 + len));
85 receive_buf(sconn, (char *) &code, 2);
86 receive_buf(sconn, (char *) &len_be, 4);
87 receive_buf(sconn, buf, len);
88 mutex_unlock(&(sconn->rcv_lock));
91 static void parse_list_neigh(struct conn *rconn)
93 __u32 limit;
94 __u32 offset;
95 __u32 len;
97 char *buf;
99 if (rconn->target.unconnected.paramlen < 8) {
100 send_resp(rconn, CDR_EXECFAILED, CDR_EXECFAILED_CMD_TOO_SHORT);
101 return;
104 ((char *)&limit)[0] = rconn->target.unconnected.cmdparams[0];
105 ((char *)&limit)[1] = rconn->target.unconnected.cmdparams[1];
106 ((char *)&limit)[2] = rconn->target.unconnected.cmdparams[2];
107 ((char *)&limit)[3] = rconn->target.unconnected.cmdparams[3];
109 ((char *)&offset)[0] = rconn->target.unconnected.cmdparams[4];
110 ((char *)&offset)[1] = rconn->target.unconnected.cmdparams[5];
111 ((char *)&offset)[2] = rconn->target.unconnected.cmdparams[6];
112 ((char *)&offset)[3] = rconn->target.unconnected.cmdparams[7];
114 limit = be32_to_cpu(limit);
115 offset = be32_to_cpu(offset);
117 buf = kmalloc(2048, GFP_KERNEL);
119 if (unlikely(buf == 0)) {
120 send_resp(rconn, CDR_EXECFAILED,
121 CDR_EXECFAILED_TEMPORARILY_OUT_OF_RESSOURCES);
122 return;
125 send_resp(rconn, CDR_EXECOK, CDR_EXECOK_OK);
127 len = generate_neigh_list(buf, 2048, limit, offset);
128 send_resp_bin(rconn, buf, len);
131 static void parse_connect_port(struct conn *rconn)
133 __be64 addr;
134 int rc;
136 BUG_ON(0 == rconn->target.unconnected.cmdparams);
138 if (rconn->target.unconnected.paramlen < 8) {
139 send_resp(rconn, CDR_EXECFAILED, CDR_EXECFAILED_CMD_TOO_SHORT);
140 return;
143 memcpy((char *) &addr, rconn->target.unconnected.cmdparams, 8);
145 rc = connect_port(rconn, addr);
147 if (rc == 2) {
148 send_resp(rconn, CDR_EXECFAILED,
149 CDR_EXECFAILED_TARGETADDR_DOESNTEXIST);
150 } else if (rc != 3) {
151 send_resp(rconn, CDR_EXECFAILED,
152 CDR_EXECFAILED_LISTENERQUEUE_FULL);
153 } else if (rc == 0) {
154 send_resp(rconn, CDR_EXECOK, CDR_EXECOK_OK);
155 } else if (unlikely(rc != 0)) {
156 BUG();
160 static void parse_connect_nb(struct conn *rconn)
162 __u16 addrtypelen;
163 __u16 addrlen;
164 __u8 *addrtype;
165 __u8 *addr;
166 int rc;
168 BUG_ON(0 == rconn->target.unconnected.cmdparams);
170 if (rconn->target.unconnected.paramlen < 4) {
171 send_resp(rconn, CDR_EXECFAILED, CDR_EXECFAILED_CMD_TOO_SHORT);
172 return;
175 ((char *)&addrtypelen)[0] = rconn->target.unconnected.cmdparams[0];
176 ((char *)&addrtypelen)[1] = rconn->target.unconnected.cmdparams[1];
178 ((char *)&addrlen)[0] = rconn->target.unconnected.cmdparams[2];
179 ((char *)&addrlen)[1] = rconn->target.unconnected.cmdparams[3];
181 addrtypelen = be16_to_cpu(addrtypelen);
182 addrlen = be16_to_cpu(addrlen);
184 if ((4 + (__u32) addrtypelen + (__u32) addrlen) >
185 rconn->target.unconnected.paramlen) {
186 send_resp(rconn, CDR_EXECFAILED, CDR_EXECFAILED_CMD_TOO_SHORT);
187 return;
190 addrtype = rconn->target.unconnected.cmdparams + 4;
191 addr = addrtype + addrtypelen;
193 rc = connect_neigh(rconn, addrtypelen, addrtype, addrlen, addr);
195 if (rc == 2) {
196 send_resp(rconn, CDR_EXECFAILED,
197 CDR_EXECFAILED_TARGETADDRTYPE_UNKNOWN);
198 } else if (rc == 3) {
199 send_resp(rconn, CDR_EXECFAILED,
200 CDR_EXECFAILED_TARGETADDR_DOESNTEXIST);
201 } else if (rc == 4) {
202 send_resp(rconn, CDR_EXECFAILED,
203 CDR_EXECFAILED_TEMPORARILY_OUT_OF_RESSOURCES);
204 } else if (rc == 0) {
205 send_resp(rconn, CDR_EXECOK, CDR_EXECOK_OK);
206 } else if (unlikely(rc != 0)) {
207 BUG();
211 static void parse_cmd(struct conn *rconn)
213 __u16 code = rconn->target.unconnected.cmd;
215 if (code == CD_CONNECT_NB) {
216 parse_connect_nb(rconn);
217 } else if (code == CD_CONNECT_PORT) {
218 parse_connect_port(rconn);
219 } else if (code == CD_LIST_NEIGH) {
220 parse_list_neigh(rconn);
221 } else {
222 send_resp(rconn, CDR_EXECFAILED, CDR_EXECFAILED_UNKNOWN_COMMAND);
226 static void read_cmd(struct conn *rconn)
228 int pull;
230 pull = min(rconn->target.unconnected.paramlen + 6 -
231 rconn->target.unconnected.cmdread,
232 rconn->buf.read_remaining);
234 BUG_ON(0 > pull);
235 BUG_ON(0 == rconn->target.unconnected.cmdparams);
236 BUG_ON(6 > rconn->target.unconnected.cmdread);
238 if (pull == 0)
239 return;
241 databuf_pull(&(rconn->buf), rconn->target.unconnected.cmdparams +
242 rconn->target.unconnected.cmdread - 6, pull);
244 rconn->target.unconnected.cmdread += pull;
247 static void read_discard(struct conn *rconn)
249 BUG_ON(rconn->target.unconnected.cmdread < 6);
251 while (rconn->target.unconnected.paramlen + 6 <
252 rconn->target.unconnected.cmdread &&
253 rconn->buf.read_remaining > 0) {
254 char buf[1];
255 databuf_pull(&(rconn->buf), buf, 1);
257 rconn->target.unconnected.cmdread++;
261 static void read_hdr(struct conn *rconn)
263 BUG_ON(rconn->target.unconnected.cmdparams == 0);
265 while (rconn->target.unconnected.cmdread < 6 &&
266 rconn->buf.read_remaining > 0) {
268 char buf[1];
269 databuf_pull(&(rconn->buf), buf, 1);
271 if (2 > rconn->target.unconnected.cmdread) {
272 rconn->target.unconnected.cmd <<= 8;
273 rconn->target.unconnected.cmd += buf[0];
274 } else {
275 rconn->target.unconnected.paramlen <<= 8;
276 rconn->target.unconnected.paramlen +=
277 buf[0];
279 rconn->target.unconnected.cmdread++;
283 void parse(struct conn *rconn)
285 __u8 *cmd;
287 BUG_ON(TARGET_UNCONNECTED != rconn->targettype);
289 if (rconn->target.unconnected.cmdparams == 0)
290 rconn->target.unconnected.cmdparams = kmalloc(MAX_CONN_CMD_LEN,
291 GFP_KERNEL);
293 cmd = rconn->target.unconnected.cmdparams;
295 if (rconn->target.unconnected.cmdread == 0) {
296 rconn->target.unconnected.cmd = 0;
297 rconn->target.unconnected.paramlen = 0;
300 if (rconn->target.unconnected.cmdread < 6) {
301 read_hdr(rconn);
302 if (rconn->target.unconnected.cmdread < 6)
303 return;
305 if (rconn->target.unconnected.paramlen > MAX_CONN_CMD_LEN) {
306 send_resp(rconn, CDR_EXECFAILED,
307 CDR_EXECFAILED_CMD_TOO_LONG);
311 if (rconn->target.unconnected.paramlen > MAX_CONN_CMD_LEN) {
312 read_discard(rconn);
313 return;
316 if (rconn->target.unconnected.cmdread >= 6 &&
317 rconn->target.unconnected.paramlen >
318 rconn->target.unconnected.cmdread - 6) {
319 read_cmd(rconn);
322 if (rconn->target.unconnected.paramlen ==
323 rconn->target.unconnected.cmdread - 6) {
324 rconn->target.unconnected.cmdread = 0;
325 parse_cmd(rconn);
328 if (TARGET_UNCONNECTED != rconn->targettype)
329 kfree(cmd);