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
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";
47 static void send_resp(struct conn
*conn
, __u16 respcode
,
50 struct conn
*rconn
= conn
->reversedir
;
57 if (respcode
== CDR_EXECFAILED
)
58 get_error_reason_text(respcode
);
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
,
77 mutex_unlock(&(rconn
->target
.sock
.lock
));
78 } else if (rconn
->targettype
== TARGET_OUT
) {
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
) {
107 static void parse_list_neigh(struct conn
*rconn
)
115 if (rconn
->target
.unconnected
.paramlen
< 8) {
116 send_resp(rconn
, CDR_EXECFAILED
, CDR_EXECFAILED_CMD_TOO_SHORT
);
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
);
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
)
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
);
159 memcpy((char *) &addr
, rconn
->target
.unconnected
.cmdparams
, 8);
161 rc
= connect_port(rconn
, addr
);
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)) {
176 static void parse_connect_nb(struct conn
*rconn
)
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
);
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
);
206 addrtype
= rconn
->target
.unconnected
.cmdparams
+ 4;
207 addr
= addrtype
+ addrtypelen
;
209 rc
= connect_neigh(rconn
, addrtypelen
, addrtype
, addrlen
, addr
);
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)) {
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
);
238 send_resp(rconn
, CDR_EXECFAILED
, CDR_EXECFAILED_UNKNOWN_COMMAND
);
242 static void read_cmd(struct data
*data
, struct conn
*rconn
)
247 pull
= min(rconn
->target
.unconnected
.paramlen
+ 6 -
248 rconn
->target
.unconnected
.cmdread
, data_len(data
));
251 BUG_ON(0 == rconn
->target
.unconnected
.cmdparams
);
252 BUG_ON(6 > rconn
->target
.unconnected
.cmdread
);
257 buf
= data_pull(data
, pull
);
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
)
271 pull
= min(rconn
->target
.unconnected
.paramlen
+ 6 -
272 rconn
->target
.unconnected
.cmdread
, data_len(data
));
275 BUG_ON(6 > rconn
->target
.unconnected
.cmdread
);
280 buf
= data_pull(data
, pull
);
284 rconn
->target
.unconnected
.cmdread
+= pull
;
287 static void read_hdr(struct data
*data
, struct conn
*rconn
)
293 pull
= min(6 - rconn
->target
.unconnected
.cmdread
, data_len(data
));
300 buf
= data_pull(data
, pull
);
302 BUG_ON(rconn
->target
.unconnected
.cmdparams
== 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
];
310 rconn
->target
.unconnected
.paramlen
<<= 8;
311 rconn
->target
.unconnected
.paramlen
+=
314 rconn
->target
.unconnected
.cmdread
++;
318 void parse(struct data
*data
, struct conn
*rconn
)
322 BUG_ON(TARGET_UNCONNECTED
!= rconn
->targettype
);
324 if (rconn
->target
.unconnected
.cmdparams
== 0)
325 rconn
->target
.unconnected
.cmdparams
= kmalloc(MAX_CONN_CMD_LEN
,
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)
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
);
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;
363 if (TARGET_UNCONNECTED
!= rconn
->targettype
)