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 void send_resp(struct conn
*conn
, __u16 respcode
,
24 __u16 reasoncode
, char *reasontext
)
26 struct conn
*rconn
= conn
->reversedir
;
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
,
48 mutex_unlock(&(rconn
->target
.sock
.lock
));
49 } else if (rconn
->targettype
== TARGET_OUT
) {
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
) {
76 static int parse_connect_port(struct conn
*conn
)
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 "
86 send_resp(conn
, CDR_EXECFAILED
, CDR_EXECFAILED_CMD_TOO_SHORT
,
91 memcpy((char *) &addr
, conn
->target
.unconnected
.cmdparams
, 8);
93 rc
= connect_port(conn
, addr
);
96 char *msg
= "port is not open";
97 send_resp(conn
, CDR_EXECFAILED
,
98 CDR_EXECFAILED_TARGETADDR_DOESNTEXIST
, msg
);
100 char *msg
= "listener queue full";
101 send_resp(conn
, CDR_EXECFAILED
,
102 CDR_EXECFAILED_LISTENERQUEUE_FULL
, msg
);
103 } else if (unlikely(rc
!= 0)) {
110 static int parse_connect_nb(struct conn
*conn
)
116 char *msg
= "The length of the command is too short for all params";
119 BUG_ON(0 == conn
->target
.unconnected
.cmdparams
);
121 if (conn
->target
.unconnected
.paramlen
< 4)
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
)
137 addrtype
= conn
->target
.unconnected
.cmdparams
+ 4;
138 addr
= addrtype
+ addrtypelen
;
140 rc
= connect_neigh(conn
, addrtypelen
, addrtype
, addrlen
, addr
);
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)) {
161 send_resp(conn
, CDR_EXECFAILED
, CDR_EXECFAILED_CMD_TOO_SHORT
, msg
);
165 static void parse_cmd(struct conn
*conn
)
167 __u16 code
= conn
->target
.unconnected
.cmd
;
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
);
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
);
181 send_resp(conn
, CDR_EXECOK
, CDR_EXECOK_OK
, 0);
184 static void read_cmd(struct data
*data
, struct conn
*rconn
)
189 pull
= min(rconn
->target
.unconnected
.paramlen
+ 6 -
190 rconn
->target
.unconnected
.cmdread
, data_len(data
));
193 BUG_ON(0 == rconn
->target
.unconnected
.cmdparams
);
194 BUG_ON(6 > rconn
->target
.unconnected
.cmdread
);
199 buf
= data_pull(data
, pull
);
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
)
213 pull
= min(rconn
->target
.unconnected
.paramlen
+ 6 -
214 rconn
->target
.unconnected
.cmdread
, data_len(data
));
217 BUG_ON(6 > rconn
->target
.unconnected
.cmdread
);
222 buf
= data_pull(data
, pull
);
226 rconn
->target
.unconnected
.cmdread
+= pull
;
229 static void read_hdr(struct data
*data
, struct conn
*rconn
)
235 pull
= min(6 - rconn
->target
.unconnected
.cmdread
, data_len(data
));
242 buf
= data_pull(data
, pull
);
244 BUG_ON(rconn
->target
.unconnected
.cmdparams
== 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
];
252 rconn
->target
.unconnected
.paramlen
<<= 8;
253 rconn
->target
.unconnected
.paramlen
+=
256 rconn
->target
.unconnected
.cmdread
++;
260 void parse(struct data
*data
, struct conn
*rconn
)
264 BUG_ON(TARGET_UNCONNECTED
!= rconn
->targettype
);
266 if (0 == rconn
->target
.unconnected
.cmdparams
)
267 rconn
->target
.unconnected
.cmdparams
= kmalloc(MAX_CONN_CMD_LEN
,
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
)
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
);
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;
306 if (TARGET_UNCONNECTED
!= rconn
->targettype
)