neighbor discovecy receive skb leak
[cor_2_6_31.git] / net / cor / cpacket_parse.c
blobde1f854b1345b5829e0ac1fa89de8648f8dd941b
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 void send_resp(struct conn *conn, __u16 respcode,
24 __u16 reasoncode, char *reasontext)
26 struct conn *rconn = conn->reversedir;
28 int reasonlen = 0;
29 __u16 reasonlen_be;
31 if (reasontext)
32 reasonlen = strnlen(reasontext, 65535);
34 respcode = cpu_to_be16(respcode);
35 reasoncode = cpu_to_be16(reasoncode);
36 reasonlen_be = cpu_to_be16(reasonlen);
38 if (rconn->targettype == TARGET_SOCK) {
39 mutex_lock(&(rconn->target.sock.lock));
40 ringbuffer_put(&(rconn->target.sock.rbuf),
41 (char *) &respcode, 2, 0);
42 ringbuffer_put(&(rconn->target.sock.rbuf),
43 (char *) &reasoncode, 2, 0);
44 ringbuffer_put(&(rconn->target.sock.rbuf),
45 (char *) &reasonlen_be, 2, 0);
46 ringbuffer_put(&(rconn->target.sock.rbuf), reasontext,
47 reasonlen, 0);
48 mutex_unlock(&(rconn->target.sock.lock));
49 } else if (rconn->targettype == TARGET_OUT) {
50 #warning todo
51 } else {
52 BUG();
56 static void send_resp_bin(struct conn *conn, char *data, __u32 len)
58 struct conn *rconn = conn->reversedir;
60 __u32 code = cpu_to_be16(CDR_BINDATA);
61 __u32 len_be = cpu_to_be32(len);
63 if (rconn->targettype == TARGET_SOCK) {
64 mutex_lock(&(rconn->target.sock.lock));
65 ringbuffer_put(&(rconn->target.sock.rbuf),
66 (char *) &len_be, 4, 0);
67 ringbuffer_put(&(rconn->target.sock.rbuf), data, len, 0);
68 mutex_unlock(&(rconn->target.sock.lock));
69 } else if (rconn->targettype == TARGET_OUT) {
70 #warning todo
71 } else {
72 BUG();
76 static int parse_connect_port(struct conn *conn)
78 __be64 addr;
79 int rc;
81 BUG_ON(0 == conn->target.unconnected.cmdparams);
83 if (conn->target.unconnected.paramlen < 8) {
84 char *msg = "The length of the command is too short for all "
85 "params";
86 send_resp(conn, CDR_EXECFAILED, CDR_EXECFAILED_CMD_TOO_SHORT,
87 msg);
88 return 1;
91 memcpy((char *) &addr, conn->target.unconnected.cmdparams, 8);
93 rc = connect_port(conn, addr);
95 if (rc == 2) {
96 char *msg = "port is not open";
97 send_resp(conn, CDR_EXECFAILED,
98 CDR_EXECFAILED_TARGETADDR_DOESNTEXIST, msg);
99 } else if (rc != 3) {
100 char *msg = "listener queue full";
101 send_resp(conn, CDR_EXECFAILED,
102 CDR_EXECFAILED_LISTENERQUEUE_FULL, msg);
103 } else if (unlikely(rc != 0)) {
104 BUG();
107 return rc;
110 static int parse_connect_nb(struct conn *conn)
112 __u16 addrtypelen;
113 __u16 addrlen;
114 __u8 *addrtype;
115 __u8 *addr;
116 char *msg = "The length of the command is too short for all params";
117 int rc;
119 BUG_ON(0 == conn->target.unconnected.cmdparams);
121 if (conn->target.unconnected.paramlen < 4)
122 goto tooshort;
124 ((char *)&addrtypelen)[0] = conn->target.unconnected.cmdparams[0];
125 ((char *)&addrtypelen)[1] = conn->target.unconnected.cmdparams[1];
127 ((char *)&addrlen)[0] = conn->target.unconnected.cmdparams[2];
128 ((char *)&addrlen)[1] = conn->target.unconnected.cmdparams[3];
130 addrtypelen = be16_to_cpu(addrtypelen);
131 addrlen = be16_to_cpu(addrlen);
133 if ((4 + (__u32) addrtypelen + (__u32) addrlen) >
134 conn->target.unconnected.paramlen)
135 goto tooshort;
137 addrtype = conn->target.unconnected.cmdparams + 4;
138 addr = addrtype + addrtypelen;
140 rc = connect_neigh(conn, addrtypelen, addrtype, addrlen, addr);
142 if (rc == 2) {
143 char *msg1 = "targettype unknown";
144 send_resp(conn, CDR_EXECFAILED,
145 CDR_EXECFAILED_TARGETADDRTYPE_UNKNOWN, msg1);
146 } else if (rc == 3) {
147 char *msg1 = "targetaddr does not exist";
148 send_resp(conn, CDR_EXECFAILED,
149 CDR_EXECFAILED_TARGETADDR_DOESNTEXIST, msg1);
150 } else if (rc == 4) {
151 char *msg1 = "temporarily out of ressources";
152 send_resp(conn, CDR_EXECFAILED,
153 CDR_TEMPORARILY_OUT_OF_RESSOURCES, msg1);
154 } else if (unlikely(rc != 0)) {
155 BUG();
158 return rc;
160 tooshort:
161 send_resp(conn, CDR_EXECFAILED, CDR_EXECFAILED_CMD_TOO_SHORT, msg);
162 return 1;
165 static void parse_cmd(struct conn *conn)
167 __u16 code = conn->target.unconnected.cmd;
168 int rc;
170 if (code == CD_CONNECT_NB) {
171 rc = parse_connect_nb(conn);
172 } else if (code == CD_CONNECT_PORT) {
173 rc = parse_connect_port(conn);
174 } else {
175 char *msg = "The length of the command is too short for all params";
176 send_resp(conn, CDR_EXECFAILED, CDR_EXECFAILED_CMD_TOO_SHORT, msg);
177 rc = 1;
180 if (0 == rc)
181 send_resp(conn, CDR_EXECOK, CDR_EXECOK_OK, 0);
184 static void read_cmd(struct data *data, struct conn *rconn)
186 char *buf;
187 int pull;
189 pull = min(rconn->target.unconnected.paramlen + 6 -
190 rconn->target.unconnected.cmdread, data_len(data));
192 BUG_ON(0 > pull);
193 BUG_ON(0 == rconn->target.unconnected.cmdparams);
194 BUG_ON(6 > rconn->target.unconnected.cmdread);
196 if (pull == 0)
197 return;
199 buf = data_pull(data, pull);
201 BUG_ON(0 == buf);
203 memcpy(rconn->target.unconnected.cmdparams +
204 rconn->target.unconnected.cmdread - 6, buf, pull);
205 rconn->target.unconnected.cmdread += pull;
208 static void read_discard(struct data *data, struct conn *rconn)
210 char *buf;
211 int pull;
213 pull = min(rconn->target.unconnected.paramlen + 6 -
214 rconn->target.unconnected.cmdread, data_len(data));
216 BUG_ON(0 > pull);
217 BUG_ON(6 > rconn->target.unconnected.cmdread);
219 if (pull == 0)
220 return;
222 buf = data_pull(data, pull);
224 BUG_ON(data == 0);
226 rconn->target.unconnected.cmdread += pull;
229 static void read_hdr(struct data *data, struct conn *rconn)
231 char *buf;
232 int readoffset;
233 int pull;
235 pull = min(6 - rconn->target.unconnected.cmdread, data_len(data));
237 if (pull == 0)
238 return;
240 BUG_ON(pull < 0);
242 buf = data_pull(data, pull);
244 BUG_ON(rconn->target.unconnected.cmdparams == 0);
245 BUG_ON(buf == 0);
247 for (readoffset=0;readoffset<pull;readoffset++) {
248 if (2 > rconn->target.unconnected.cmdread) {
249 rconn->target.unconnected.cmd <<= 8;
250 rconn->target.unconnected.cmd += buf[readoffset];
251 } else {
252 rconn->target.unconnected.paramlen <<= 8;
253 rconn->target.unconnected.paramlen +=
254 buf[readoffset];
256 rconn->target.unconnected.cmdread++;
260 void parse(struct data *data, struct conn *rconn)
262 __u8 *cmd;
264 BUG_ON(TARGET_UNCONNECTED != rconn->targettype);
266 if (0 == rconn->target.unconnected.cmdparams)
267 rconn->target.unconnected.cmdparams = kmalloc(MAX_CONN_CMD_LEN,
268 GFP_KERNEL);
270 cmd = rconn->target.unconnected.cmdparams;
272 if (0 == rconn->target.unconnected.cmdread) {
273 rconn->target.unconnected.cmd = 0;
274 rconn->target.unconnected.paramlen = 0;
277 if (6 > rconn->target.unconnected.cmdread) {
278 read_hdr(data, rconn);
279 if (6 > rconn->target.unconnected.cmdread)
280 return;
282 if (rconn->target.unconnected.paramlen > MAX_CONN_CMD_LEN) {
283 char *msg = "command param is too long";
284 send_resp(rconn, CDR_EXECFAILED,
285 CDR_EXECFAILED_CMD_TOO_LONG, msg);
289 if (rconn->target.unconnected.paramlen > MAX_CONN_CMD_LEN) {
290 read_discard(data, rconn);
291 return;
294 if (6 <= rconn->target.unconnected.cmdread &&
295 rconn->target.unconnected.paramlen >
296 rconn->target.unconnected.cmdread - 6) {
297 read_cmd(data, rconn);
300 if (rconn->target.unconnected.paramlen ==
301 rconn->target.unconnected.cmdread - 6) {
302 rconn->target.unconnected.cmdread = 0;
303 parse_cmd(rconn);
306 if (TARGET_UNCONNECTED != rconn->targettype)
307 kfree(cmd);