parse_connect_nb endian bug (thank you Sohail Qayum Malik)
[cor_2_6_31.git] / net / cor / cpacket_parse.c
blob33207156edf1a0e2057f5696706083d81da39689
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 int reasonlen = 0;
28 if (reasontext)
29 reasonlen = strnlen(reasontext, 65535);
31 #warning todo
34 static int parse_connect_port(struct conn *conn)
36 __be64 addr;
37 int rc;
39 BUG_ON(0 == conn->target.unconnected.cmdparams);
41 if (8 < conn->target.unconnected.paramlen) {
42 char *msg = "The length of the command is too short for all "
43 "params";
44 send_resp(conn, CDR_EXECFAILED, CDR_EXECFAILED_CMD_TOO_SHORT,
45 msg);
46 return 1;
49 memcpy((char *) &addr, conn->target.unconnected.cmdparams, 8);
51 rc = connect_port(conn, addr);
53 if (rc == 2) {
54 char *msg = "port is not open";
55 send_resp(conn, CDR_EXECFAILED,
56 CDR_EXECFAILED_TARGETADDR_DOESNTEXIST, msg);
57 } else if (rc != 3) {
58 char *msg = "listener queue full";
59 send_resp(conn, CDR_EXECFAILED,
60 CDR_EXECFAILED_LISTENERQUEUE_FULL, msg);
61 } else if (unlikely(rc != 0)) {
62 BUG();
65 return rc;
68 static int parse_connect_nb(struct conn *conn)
70 __u16 addrtypelen;
71 __u16 addrlen;
72 __u8 *addrtype;
73 __u8 *addr;
74 char *msg = "The length of the command is too short for all params";
75 int rc;
77 BUG_ON(0 == conn->target.unconnected.cmdparams);
79 if (4 < conn->target.unconnected.paramlen)
80 goto tooshort;
82 ((char *)&addrtypelen)[0] = conn->target.unconnected.cmdparams[0];
83 ((char *)&addrtypelen)[1] = conn->target.unconnected.cmdparams[1];
85 ((char *)&addrlen)[0] = conn->target.unconnected.cmdparams[2];
86 ((char *)&addrlen)[1] = conn->target.unconnected.cmdparams[3];
88 addrtypelen = be16_to_cpu(addrtypelen);
89 addrlen = be16_to_cpu(addrlen);
91 if ((4 + (__u32) addrtypelen + (__u32) addrlen) >
92 conn->target.unconnected.paramlen)
93 goto tooshort;
95 addrtype = conn->target.unconnected.cmdparams + 4;
96 addr = addrtype + addrtypelen;
98 rc = connect_neigh(conn, addrtypelen, addrtype, addrlen, addr);
100 if (rc == 2) {
101 char *msg1 = "targettype unknown";
102 send_resp(conn, CDR_EXECFAILED,
103 CDR_EXECFAILED_TARGETADDRTYPE_UNKNOWN, msg1);
104 } else if (rc == 3) {
105 char *msg1 = "targetaddr does not exist";
106 send_resp(conn, CDR_EXECFAILED,
107 CDR_EXECFAILED_TARGETADDR_DOESNTEXIST, msg1);
108 } else if (rc == 4) {
109 char *msg1 = "temporarily out of ressources";
110 send_resp(conn, CDR_EXECFAILED,
111 CDR_TEMPORARILY_OUT_OF_RESSOURCES, msg1);
112 } else if (unlikely(rc != 0)) {
113 BUG();
116 return rc;
118 tooshort:
119 send_resp(conn, CDR_EXECFAILED, CDR_EXECFAILED_CMD_TOO_SHORT, msg);
120 return 1;
123 static void parse_cmd(struct conn *conn)
125 __u16 code = conn->target.unconnected.cmd;
126 int rc;
128 if (code == CD_CONNECT_NB) {
129 rc = parse_connect_nb(conn);
130 } else if (code == CD_CONNECT_PORT) {
131 rc = parse_connect_port(conn);
132 } else {
133 char *msg = "The length of the command is too short for all params";
134 send_resp(conn, CDR_EXECFAILED, CDR_EXECFAILED_CMD_TOO_SHORT, msg);
135 rc = 1;
138 if (0 == rc)
139 send_resp(conn, CDR_EXECOK, CDR_EXECOK_OK, 0);
142 static void read_cmd(struct data *data, struct conn *rconn)
144 char *buf;
145 int pull;
147 pull = min(rconn->target.unconnected.paramlen + 6 -
148 rconn->target.unconnected.cmdread, data_len(data));
150 BUG_ON(0 > pull);
151 BUG_ON(0 == rconn->target.unconnected.cmdparams);
152 BUG_ON(6 > rconn->target.unconnected.cmdread);
154 if (pull == 0)
155 return;
157 buf = data_pull(data, pull);
159 BUG_ON(0 == buf);
161 memcpy(rconn->target.unconnected.cmdparams +
162 rconn->target.unconnected.cmdread - 6, buf, pull);
163 rconn->target.unconnected.cmdread += pull;
166 static void read_discard(struct data *data, struct conn *rconn)
168 char *buf;
169 int pull;
171 pull = min(rconn->target.unconnected.paramlen + 6 -
172 rconn->target.unconnected.cmdread, data_len(data));
174 BUG_ON(0 > pull);
175 BUG_ON(6 > rconn->target.unconnected.cmdread);
177 if (pull == 0)
178 return;
180 buf = data_pull(data, pull);
182 BUG_ON(data == 0);
184 rconn->target.unconnected.cmdread += pull;
187 static void read_hdr(struct data *data, struct conn *rconn)
189 char *buf;
190 int readoffset;
191 int pull;
193 pull = min(6 - rconn->target.unconnected.cmdread, data_len(data));
195 if (pull == 0)
196 return;
198 BUG_ON(pull < 0);
200 buf = data_pull(data, pull);
202 BUG_ON(rconn->target.unconnected.cmdparams == 0);
203 BUG_ON(buf == 0);
205 for (readoffset=0;readoffset<pull;readoffset++) {
206 if (2 > rconn->target.unconnected.cmdread) {
207 rconn->target.unconnected.cmd <<= 8;
208 rconn->target.unconnected.cmd += buf[readoffset];
209 } else {
210 rconn->target.unconnected.paramlen <<= 8;
211 rconn->target.unconnected.paramlen +=
212 buf[readoffset];
214 rconn->target.unconnected.cmdread++;
218 void parse(struct data *data, struct conn *rconn)
220 __u8 *cmd;
222 BUG_ON(TARGET_UNCONNECTED != rconn->targettype);
224 if (0 == rconn->target.unconnected.cmdparams)
225 rconn->target.unconnected.cmdparams = kmalloc(MAX_CONN_CMD_LEN,
226 GFP_KERNEL);
228 cmd = rconn->target.unconnected.cmdparams;
230 if (0 == rconn->target.unconnected.cmdread) {
231 rconn->target.unconnected.cmd = 0;
232 rconn->target.unconnected.paramlen = 0;
235 if (6 > rconn->target.unconnected.cmdread) {
236 read_hdr(data, rconn);
237 if (6 > rconn->target.unconnected.cmdread)
238 return;
240 if (rconn->target.unconnected.paramlen > MAX_CONN_CMD_LEN) {
241 char *msg = "command param is too long";
242 send_resp(rconn, CDR_EXECFAILED,
243 CDR_EXECFAILED_CMD_TOO_LONG, msg);
247 if (rconn->target.unconnected.paramlen > MAX_CONN_CMD_LEN) {
248 read_discard(data, rconn);
249 return;
252 if (6 <= rconn->target.unconnected.cmdread &&
253 rconn->target.unconnected.paramlen >
254 rconn->target.unconnected.cmdread - 6) {
255 read_cmd(data, rconn);
258 if (rconn->target.unconnected.paramlen ==
259 rconn->target.unconnected.cmdread - 6) {
260 rconn->target.unconnected.cmdread = 0;
261 parse_cmd(rconn);
264 if (TARGET_UNCONNECTED != rconn->targettype)
265 kfree(cmd);