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
*rconn
, __u16 respcode
,
50 struct conn
*sconn
= rconn
->reversedir
;
57 if (unlikely(respcode
== CDR_EXECFAILED
))
58 reasontext
= get_error_reason_text(respcode
);
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_set_timeout(struct conn
*rconn
, int backwards
)
95 if (unlikely(rconn
->target
.unconnected
.paramlen
< 4)) {
96 send_resp(rconn
, CDR_EXECFAILED
, CDR_EXECFAILED_CMD_TOO_SHORT
);
100 ((char *)&timeout
)[0] = rconn
->target
.unconnected
.cmdparams
[0];
101 ((char *)&timeout
)[1] = rconn
->target
.unconnected
.cmdparams
[1];
102 ((char *)&timeout
)[2] = rconn
->target
.unconnected
.cmdparams
[2];
103 ((char *)&timeout
)[3] = rconn
->target
.unconnected
.cmdparams
[3];
105 timeout
= be32_to_cpu(timeout
);
108 if (rconn
->reversedir
->targettype
!= TARGET_OUT
) {
109 send_resp(rconn
, CDR_EXECFAILED
,
110 CDR_EXECFAILED_ILLEGAL_COMMAND
);
113 rconn
->reversedir
->target
.out
.stall_timeout_ms
= timeout
;
115 rconn
->target
.unconnected
.stall_timeout_ms
= timeout
;
118 send_resp(rconn
, CDR_EXECOK
, CDR_EXECOK_OK
);
121 static void parse_list_neigh(struct conn
*rconn
)
129 if (unlikely(rconn
->target
.unconnected
.paramlen
< 8)) {
130 send_resp(rconn
, CDR_EXECFAILED
, CDR_EXECFAILED_CMD_TOO_SHORT
);
134 ((char *)&limit
)[0] = rconn
->target
.unconnected
.cmdparams
[0];
135 ((char *)&limit
)[1] = rconn
->target
.unconnected
.cmdparams
[1];
136 ((char *)&limit
)[2] = rconn
->target
.unconnected
.cmdparams
[2];
137 ((char *)&limit
)[3] = rconn
->target
.unconnected
.cmdparams
[3];
139 ((char *)&offset
)[0] = rconn
->target
.unconnected
.cmdparams
[4];
140 ((char *)&offset
)[1] = rconn
->target
.unconnected
.cmdparams
[5];
141 ((char *)&offset
)[2] = rconn
->target
.unconnected
.cmdparams
[6];
142 ((char *)&offset
)[3] = rconn
->target
.unconnected
.cmdparams
[7];
144 limit
= be32_to_cpu(limit
);
145 offset
= be32_to_cpu(offset
);
147 buf
= kmalloc(2048, GFP_KERNEL
);
149 if (unlikely(buf
== 0)) {
150 send_resp(rconn
, CDR_EXECFAILED
,
151 CDR_EXECFAILED_TEMPORARILY_OUT_OF_RESSOURCES
);
155 send_resp(rconn
, CDR_EXECOK
, CDR_EXECOK_OK
);
157 len
= generate_neigh_list(buf
, 2048, limit
, offset
);
158 send_resp_bin(rconn
, buf
, len
);
161 static void parse_connect_port(struct conn
*rconn
)
166 BUG_ON(0 == rconn
->target
.unconnected
.cmdparams
);
168 if (unlikely(rconn
->target
.unconnected
.paramlen
< 8)) {
169 send_resp(rconn
, CDR_EXECFAILED
, CDR_EXECFAILED_CMD_TOO_SHORT
);
173 memcpy((char *) &addr
, rconn
->target
.unconnected
.cmdparams
, 8);
175 rc
= connect_port(rconn
, addr
);
178 send_resp(rconn
, CDR_EXECOK
, CDR_EXECOK_OK
);
179 } else if (rc
== 2) {
180 send_resp(rconn
, CDR_EXECFAILED
,
181 CDR_EXECFAILED_TARGETADDR_DOESNTEXIST
);
182 } else if (rc
== 3) {
183 send_resp(rconn
, CDR_EXECFAILED
,
184 CDR_EXECFAILED_LISTENERQUEUE_FULL
);
190 static void parse_connect_nb(struct conn
*rconn
)
198 BUG_ON(0 == rconn
->target
.unconnected
.cmdparams
);
200 if (unlikely(rconn
->target
.unconnected
.paramlen
< 4)) {
201 send_resp(rconn
, CDR_EXECFAILED
, CDR_EXECFAILED_CMD_TOO_SHORT
);
205 ((char *)&addrtypelen
)[0] = rconn
->target
.unconnected
.cmdparams
[0];
206 ((char *)&addrtypelen
)[1] = rconn
->target
.unconnected
.cmdparams
[1];
208 ((char *)&addrlen
)[0] = rconn
->target
.unconnected
.cmdparams
[2];
209 ((char *)&addrlen
)[1] = rconn
->target
.unconnected
.cmdparams
[3];
211 addrtypelen
= be16_to_cpu(addrtypelen
);
212 addrlen
= be16_to_cpu(addrlen
);
214 if (unlikely((4 + (__u32
) addrtypelen
+ (__u32
) addrlen
) >
215 rconn
->target
.unconnected
.paramlen
)) {
216 send_resp(rconn
, CDR_EXECFAILED
, CDR_EXECFAILED_CMD_TOO_SHORT
);
220 addrtype
= rconn
->target
.unconnected
.cmdparams
+ 4;
221 addr
= addrtype
+ addrtypelen
;
223 rc
= connect_neigh(rconn
, addrtypelen
, addrtype
, addrlen
, addr
);
226 send_resp(rconn
, CDR_EXECOK
, CDR_EXECOK_OK
);
227 } else if (rc
== 2) {
228 send_resp(rconn
, CDR_EXECFAILED
,
229 CDR_EXECFAILED_TARGETADDRTYPE_UNKNOWN
);
230 } else if (rc
== 3) {
231 send_resp(rconn
, CDR_EXECFAILED
,
232 CDR_EXECFAILED_TARGETADDR_DOESNTEXIST
);
233 } else if (rc
== 4) {
234 send_resp(rconn
, CDR_EXECFAILED
,
235 CDR_EXECFAILED_TEMPORARILY_OUT_OF_RESSOURCES
);
241 static void parse_cmd(struct conn
*rconn
)
243 __u16 code
= rconn
->target
.unconnected
.cmd
;
245 if (code
== CD_CONNECT_NB
) {
246 parse_connect_nb(rconn
);
247 } else if (code
== CD_CONNECT_PORT
) {
248 parse_connect_port(rconn
);
249 } else if (code
== CD_LIST_NEIGH
) {
250 parse_list_neigh(rconn
);
251 } else if (code
== CD_SET_FORWARD_TIMEOUT
) {
252 parse_set_timeout(rconn
, 0);
253 } else if (code
== CD_SET_BACKWARD_TIMEOUT
) {
254 parse_set_timeout(rconn
, 1);
256 send_resp(rconn
, CDR_EXECFAILED
,
257 CDR_EXECFAILED_UNKNOWN_COMMAND
);
261 static void read_cmd(struct conn
*rconn
)
265 pull
= min(rconn
->target
.unconnected
.paramlen
+ 6 -
266 rconn
->target
.unconnected
.cmdread
,
267 rconn
->buf
.read_remaining
);
270 BUG_ON(0 == rconn
->target
.unconnected
.cmdparams
);
271 BUG_ON(6 > rconn
->target
.unconnected
.cmdread
);
276 databuf_pull(&(rconn
->buf
), rconn
->target
.unconnected
.cmdparams
+
277 rconn
->target
.unconnected
.cmdread
- 6, pull
);
278 databuf_ackread(&(rconn
->buf
));
280 rconn
->target
.unconnected
.cmdread
+= pull
;
283 static void read_discard(struct conn
*rconn
)
285 BUG_ON(rconn
->target
.unconnected
.cmdread
< 6);
287 while (rconn
->target
.unconnected
.paramlen
+ 6 <
288 rconn
->target
.unconnected
.cmdread
&&
289 rconn
->buf
.read_remaining
> 0) {
291 databuf_pull(&(rconn
->buf
), buf
, 1);
292 databuf_ackread(&(rconn
->buf
));
294 rconn
->target
.unconnected
.cmdread
++;
298 static void read_hdr(struct conn
*rconn
)
300 BUG_ON(rconn
->target
.unconnected
.cmdparams
== 0);
302 while (rconn
->target
.unconnected
.cmdread
< 6 &&
303 rconn
->buf
.read_remaining
> 0) {
306 databuf_pull(&(rconn
->buf
), buf
, 1);
307 databuf_ackread(&(rconn
->buf
));
309 if (2 > rconn
->target
.unconnected
.cmdread
) {
310 rconn
->target
.unconnected
.cmd
<<= 8;
311 rconn
->target
.unconnected
.cmd
+= buf
[0];
313 rconn
->target
.unconnected
.paramlen
<<= 8;
314 rconn
->target
.unconnected
.paramlen
+= buf
[0];
316 rconn
->target
.unconnected
.cmdread
++;
320 void parse(struct conn
*rconn
)
324 BUG_ON(TARGET_UNCONNECTED
!= rconn
->targettype
);
326 if (rconn
->target
.unconnected
.cmdparams
== 0)
327 rconn
->target
.unconnected
.cmdparams
= kmalloc(MAX_CONN_CMD_LEN
,
330 cmd
= rconn
->target
.unconnected
.cmdparams
;
332 if (rconn
->target
.unconnected
.cmdread
== 0) {
333 rconn
->target
.unconnected
.cmd
= 0;
334 rconn
->target
.unconnected
.paramlen
= 0;
337 if (rconn
->target
.unconnected
.cmdread
< 6) {
339 if (rconn
->target
.unconnected
.cmdread
< 6)
342 if (rconn
->target
.unconnected
.paramlen
> MAX_CONN_CMD_LEN
) {
343 send_resp(rconn
, CDR_EXECFAILED
,
344 CDR_EXECFAILED_CMD_TOO_LONG
);
348 if (rconn
->target
.unconnected
.paramlen
> MAX_CONN_CMD_LEN
) {
353 if (rconn
->target
.unconnected
.cmdread
>= 6 &&
354 rconn
->target
.unconnected
.paramlen
>
355 rconn
->target
.unconnected
.cmdread
- 6) {
359 if (rconn
->target
.unconnected
.paramlen
==
360 rconn
->target
.unconnected
.cmdread
- 6) {
361 rconn
->target
.unconnected
.cmdread
= 0;
365 if (TARGET_UNCONNECTED
!= rconn
->targettype
)