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
)
29 reasonlen
= strnlen(reasontext
, 65535);
34 static int parse_connect_port(struct conn
*conn
)
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 "
44 send_resp(conn
, CDR_EXECFAILED
, CDR_EXECFAILED_CMD_TOO_SHORT
,
49 memcpy((char *) &addr
, conn
->target
.unconnected
.cmdparams
, 8);
51 rc
= connect_port(conn
, addr
);
54 char *msg
= "port is not open";
55 send_resp(conn
, CDR_EXECFAILED
,
56 CDR_EXECFAILED_TARGETADDR_DOESNTEXIST
, msg
);
58 char *msg
= "listener queue full";
59 send_resp(conn
, CDR_EXECFAILED
,
60 CDR_EXECFAILED_LISTENERQUEUE_FULL
, msg
);
61 } else if (unlikely(rc
!= 0)) {
68 static int parse_connect_nb(struct conn
*conn
)
74 char *msg
= "The length of the command is too short for all params";
77 BUG_ON(0 == conn
->target
.unconnected
.cmdparams
);
79 if (4 < conn
->target
.unconnected
.paramlen
)
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
)
95 addrtype
= conn
->target
.unconnected
.cmdparams
+ 4;
96 addr
= addrtype
+ addrtypelen
;
98 rc
= connect_neigh(conn
, addrtypelen
, addrtype
, addrlen
, addr
);
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)) {
119 send_resp(conn
, CDR_EXECFAILED
, CDR_EXECFAILED_CMD_TOO_SHORT
, msg
);
123 static void parse_cmd(struct conn
*conn
)
125 __u16 code
= conn
->target
.unconnected
.cmd
;
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
);
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
);
139 send_resp(conn
, CDR_EXECOK
, CDR_EXECOK_OK
, 0);
142 static void read_cmd(struct data
*data
, struct conn
*rconn
)
147 pull
= min(rconn
->target
.unconnected
.paramlen
+ 6 -
148 rconn
->target
.unconnected
.cmdread
, data_len(data
));
151 BUG_ON(0 == rconn
->target
.unconnected
.cmdparams
);
152 BUG_ON(6 > rconn
->target
.unconnected
.cmdread
);
157 buf
= data_pull(data
, pull
);
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
)
171 pull
= min(rconn
->target
.unconnected
.paramlen
+ 6 -
172 rconn
->target
.unconnected
.cmdread
, data_len(data
));
175 BUG_ON(6 > rconn
->target
.unconnected
.cmdread
);
180 buf
= data_pull(data
, pull
);
184 rconn
->target
.unconnected
.cmdread
+= pull
;
187 static void read_hdr(struct data
*data
, struct conn
*rconn
)
193 pull
= min(6 - rconn
->target
.unconnected
.cmdread
, data_len(data
));
200 buf
= data_pull(data
, pull
);
202 BUG_ON(rconn
->target
.unconnected
.cmdparams
== 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
];
210 rconn
->target
.unconnected
.paramlen
<<= 8;
211 rconn
->target
.unconnected
.paramlen
+=
214 rconn
->target
.unconnected
.cmdread
++;
218 void parse(struct data
*data
, struct conn
*rconn
)
222 BUG_ON(TARGET_UNCONNECTED
!= rconn
->targettype
);
224 if (0 == rconn
->target
.unconnected
.cmdparams
)
225 rconn
->target
.unconnected
.cmdparams
= kmalloc(MAX_CONN_CMD_LEN
,
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
)
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
);
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;
264 if (TARGET_UNCONNECTED
!= rconn
->targettype
)