2 * Connection oriented routing
3 * Copyright (C) 2007-2021 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 int cor_encode_len(char *buf
, int buflen
, __u32 len
)
31 } else if (len
< 16512) {
32 __u16 len_be
= cpu_to_be16(len
- 128);
33 char *len_p
= (char *) &len_be
;
35 buf
[0] = len_p
[0] + 128;
38 } else if (len
< 1073758336) {
39 __u32 len_be
= cpu_to_be32(len
- 16512);
40 char *len_p
= (char *) &len_be
;
42 buf
[0] = len_p
[0] + 192;
52 int cor_decode_len(char *buf
, int buflen
, __u32
*len
)
54 __u8 b0
= (__u8
) buf
[0];
58 if (buflen
>= 1 && b0
< 128) {
61 } else if (buflen
>= 2 && b0
>= 128 && b0
< 192) {
62 ((char *) len
)[0] = buf
[0] - 128;
63 ((char *) len
)[1] = buf
[1];
65 *len
= be16_to_cpu(*len
) + 128;
67 } else if (buflen
>= 4 && b0
>= 192) {
68 ((char *) len
)[0] = buf
[0] - 192;
69 ((char *) len
)[1] = buf
[1];
70 ((char *) len
)[2] = buf
[2];
71 ((char *) len
)[3] = buf
[3];
73 *len
= be32_to_cpu(*len
) + 16512;
80 static void cor_receive_cpacketresp(struct cor_conn
*src_unconn_ll
, char *buf
,
81 __u32 len
, int *reset_needed
)
84 if (unlikely((*reset_needed
) != 0))
86 rc
= cor_receive_buf(src_unconn_ll
, buf
, len
, 0, 0);
87 if (unlikely(rc
< len
))
92 static void cor_send_resp_ok(struct cor_conn
*trgt_unconn_ll
, int *reset_needed
)
94 __u8 respcode
= CDR_EXECOK
;
96 cor_receive_cpacketresp(trgt_unconn_ll
->reversedir
, (char *) &respcode
,
100 static void cor_send_resp_failed(struct cor_conn
*trgt_unconn_ll
,
101 __u16 reasoncode
, int *reset_needed
)
105 msg
[0] = CDR_EXECFAILED
;
107 cor_put_u16(&(msg
[1]), reasoncode
);
109 cor_receive_cpacketresp(trgt_unconn_ll
->reversedir
, msg
, 3,
113 static void cor_send_resp_bin(struct cor_conn
*trgt_unconn_ll
, char *buf
,
114 __u32 len
, int *reset_needed
)
119 hdr
[0] = CDR_BINDATA
;
120 len_len
= cor_encode_len(hdr
+ 1, 4, len
);
122 BUG_ON(len_len
<= 0);
124 cor_receive_cpacketresp(trgt_unconn_ll
->reversedir
, hdr
, len_len
+ 1,
126 cor_receive_cpacketresp(trgt_unconn_ll
->reversedir
, buf
, len
,
130 static int cor_proc_bindata(struct cor_conn
*trgt_unconn_ll
, __u16 cmd
,
136 buf
= kmalloc(CD_RESP_BIN_MAXSIZE
, GFP_ATOMIC
);
137 if (unlikely(buf
== 0)) {
138 cor_send_resp_failed(trgt_unconn_ll
,
139 CDR_EXECFAILED_TEMPORARILY_OUT_OF_RESSOURCES
,
144 cor_send_resp_ok(trgt_unconn_ll
, reset_needed
);
146 if (cmd
== CD_LIST_NEIGH
) {
147 len
= cor_generate_neigh_list(buf
, CD_RESP_BIN_MAXSIZE
);
148 } else if (cmd
== CD_LIST_SERVICES
) {
149 len
= cor_list_services(buf
, CD_RESP_BIN_MAXSIZE
);
153 cor_send_resp_bin(trgt_unconn_ll
, buf
, len
, reset_needed
);
157 static int cor_proc_connect_port(struct cor_conn
*trgt_unconn_ll
,
163 if (unlikely(trgt_unconn_ll
->target
.unconnected
.paramlen
< 4)) {
164 /* command too short */
165 cor_send_resp_failed(trgt_unconn_ll
,
166 CDR_EXECFAILED_INVALID_COMMAND
, reset_needed
);
170 memcpy((char *) &port
, trgt_unconn_ll
->target
.unconnected
.cmdparams
, 4);
172 rc
= cor_connect_port(trgt_unconn_ll
, port
);
175 cor_send_resp_ok(trgt_unconn_ll
, reset_needed
);
177 } else if (rc
== 2) {
178 cor_send_resp_failed(trgt_unconn_ll
,
179 CDR_EXECFAILED_PORTCLOSED
, reset_needed
);
180 } else if (rc
== 3) {
181 cor_send_resp_failed(trgt_unconn_ll
,
182 CDR_EXECFAILED_TEMPORARILY_OUT_OF_RESSOURCES
,
190 static int cor_proc_connect_nb(struct cor_conn
*trgt_unconn_ll
,
193 char *addr
= trgt_unconn_ll
->target
.unconnected
.cmdparams
;
194 __u32 addrlen
= trgt_unconn_ll
->target
.unconnected
.paramlen
;
198 if (unlikely(addrlen
> 65535)) {
199 cor_send_resp_failed(trgt_unconn_ll
,
200 CDR_EXECFAILED_NB_DOESNTEXIST
, reset_needed
);
204 rc
= cor_connect_neigh(trgt_unconn_ll
, addr
, (__u16
) addrlen
);
207 cor_send_resp_ok(trgt_unconn_ll
, reset_needed
);
209 } else if (rc
== 3) {
210 cor_send_resp_failed(trgt_unconn_ll
,
211 CDR_EXECFAILED_NB_DOESNTEXIST
, reset_needed
);
212 } else if (rc
== 4) {
213 cor_send_resp_failed(trgt_unconn_ll
,
214 CDR_EXECFAILED_TEMPORARILY_OUT_OF_RESSOURCES
,
222 static void cor_proc_cmd(struct cor_conn
*trgt_unconn_ll
, int *reset_needed
)
224 __u16 cmd
= trgt_unconn_ll
->target
.unconnected
.cmd
;
225 char *params
= trgt_unconn_ll
->target
.unconnected
.cmdparams
;
226 int discard_on_error
= (cmd
& CD_CONTINUE_ON_ERROR_FLAG
) == 0;
229 cmd
= cmd
& (~CD_CONTINUE_ON_ERROR_FLAG
);
231 BUG_ON(trgt_unconn_ll
->target
.unconnected
.cmdparams
== 0);
233 if (cmd
== CD_CONNECT_NB
) {
234 rc
= cor_proc_connect_nb(trgt_unconn_ll
, reset_needed
);
235 } else if (cmd
== CD_CONNECT_PORT
) {
236 rc
= cor_proc_connect_port(trgt_unconn_ll
, reset_needed
);
237 } else if (cmd
== CD_LIST_NEIGH
|| cmd
== CD_LIST_SERVICES
) {
238 rc
= cor_proc_bindata(trgt_unconn_ll
, cmd
, reset_needed
);
240 cor_send_resp_failed(trgt_unconn_ll
,
241 CDR_EXECFAILED_INVALID_COMMAND
, reset_needed
);
247 if (trgt_unconn_ll
->targettype
== TARGET_UNCONNECTED
) {
248 trgt_unconn_ll
->target
.unconnected
.cmdparams
= 0;
249 trgt_unconn_ll
->target
.unconnected
.cmdread
= 0;
250 trgt_unconn_ll
->target
.unconnected
.paramlen_read
= 0;
251 trgt_unconn_ll
->target
.unconnected
.cmd
= 0;
252 trgt_unconn_ll
->target
.unconnected
.paramlen
= 0;
254 if (rc
!= 0 && discard_on_error
) {
255 trgt_unconn_ll
->targettype
= TARGET_DISCARD
;
260 static void cor_read_cmd(struct cor_conn
*trgt_unconn_ll
)
264 pull
= min(trgt_unconn_ll
->target
.unconnected
.paramlen
-
265 trgt_unconn_ll
->target
.unconnected
.cmdread
,
266 trgt_unconn_ll
->data_buf
.read_remaining
);
269 BUG_ON(trgt_unconn_ll
->target
.unconnected
.cmdparams
== 0);
274 cor_databuf_pull(trgt_unconn_ll
,
275 trgt_unconn_ll
->target
.unconnected
.cmdparams
+
276 trgt_unconn_ll
->target
.unconnected
.cmdread
, pull
);
277 cor_databuf_ackread(trgt_unconn_ll
);
279 trgt_unconn_ll
->target
.unconnected
.cmdread
+= pull
;
282 static void cor_read_discard(struct cor_conn
*trgt_unconn_ll
)
284 BUG_ON(trgt_unconn_ll
->target
.unconnected
.paramlen_read
== 0);
286 while (trgt_unconn_ll
->target
.unconnected
.paramlen
<
287 trgt_unconn_ll
->target
.unconnected
.cmdread
&&
288 trgt_unconn_ll
->data_buf
.read_remaining
> 0) {
290 cor_databuf_pull(trgt_unconn_ll
, buf
, 1);
291 cor_databuf_ackread(trgt_unconn_ll
);
293 trgt_unconn_ll
->target
.unconnected
.cmdread
++;
297 #define RC_READ_HDR_FINISHED 0
298 #define RC_READ_HDR_INCOMPLETE 1
299 static int cor_read_hdr(struct cor_conn
*trgt_unconn_ll
)
301 BUG_ON(trgt_unconn_ll
->target
.unconnected
.cmdparams
!= 0);
305 if (trgt_unconn_ll
->target
.unconnected
.paramlen_read
!= 0)
306 return RC_READ_HDR_FINISHED
;
307 else if (trgt_unconn_ll
->data_buf
.read_remaining
== 0)
308 return RC_READ_HDR_INCOMPLETE
;
310 BUG_ON(trgt_unconn_ll
->target
.unconnected
.cmdread
>= 6);
312 if (trgt_unconn_ll
->target
.unconnected
.cmdread
< 2) {
314 cor_databuf_pull(trgt_unconn_ll
, buf
, 1);
315 trgt_unconn_ll
->target
.unconnected
.cmd
<<= 8;
316 trgt_unconn_ll
->target
.unconnected
.cmd
+= buf
[0];
317 trgt_unconn_ll
->target
.unconnected
.cmdread
+= 1;
321 cor_databuf_pull(trgt_unconn_ll
,
322 trgt_unconn_ll
->target
.unconnected
.paramlen_buf
+
323 trgt_unconn_ll
->target
.unconnected
.cmdread
- 2,
325 cor_databuf_ackread(trgt_unconn_ll
);
326 trgt_unconn_ll
->target
.unconnected
.cmdread
+= 1;
329 trgt_unconn_ll
->target
.unconnected
.paramlen_buf
,
330 trgt_unconn_ll
->target
.unconnected
.cmdread
- 2,
331 &(trgt_unconn_ll
->target
.unconnected
.paramlen
));
334 trgt_unconn_ll
->target
.unconnected
.paramlen_read
= 1;
335 trgt_unconn_ll
->target
.unconnected
.cmdread
= 0;
336 return RC_READ_HDR_FINISHED
;
341 #define RC_PC_FINISHED 0
342 #define RC_PC_OUT_OF_BUFSPACE 1
343 #define RC_PC_INCOMPLETEREAD 2
344 static int _cor_proc_cpacket(struct cor_conn
*trgt_unconn_ll
, int *reset_needed
)
348 if (cor_cpacket_write_allowed(trgt_unconn_ll
->reversedir
) == 0)
349 return RC_PC_OUT_OF_BUFSPACE
;
351 if (trgt_unconn_ll
->target
.unconnected
.paramlen_read
!= 0)
354 rc
= cor_read_hdr(trgt_unconn_ll
);
355 if (rc
== RC_READ_HDR_INCOMPLETE
) {
356 return RC_PC_INCOMPLETEREAD
;
357 } else if (rc
== RC_READ_HDR_FINISHED
) {
358 trgt_unconn_ll
->target
.unconnected
.paramlen_read
= 1;
360 if (trgt_unconn_ll
->target
.unconnected
.paramlen
>
362 /* command too long */
363 cor_send_resp_failed(trgt_unconn_ll
,
364 CDR_EXECFAILED_INVALID_COMMAND
,
372 if (trgt_unconn_ll
->target
.unconnected
.paramlen
>
374 cor_read_discard(trgt_unconn_ll
);
375 return RC_PC_INCOMPLETEREAD
;
378 if (trgt_unconn_ll
->target
.unconnected
.cmdparams
== 0) {
379 trgt_unconn_ll
->target
.unconnected
.cmdparams
= kmalloc(
380 trgt_unconn_ll
->target
.unconnected
.paramlen
,
382 if (trgt_unconn_ll
->target
.unconnected
.cmdparams
== 0) {
384 return RC_PC_INCOMPLETEREAD
;
388 cor_read_cmd(trgt_unconn_ll
);
390 BUG_ON(trgt_unconn_ll
->target
.unconnected
.cmdread
>
391 trgt_unconn_ll
->target
.unconnected
.paramlen
);
393 if (trgt_unconn_ll
->target
.unconnected
.cmdread
<
394 trgt_unconn_ll
->target
.unconnected
.paramlen
)
395 return RC_PC_INCOMPLETEREAD
;
397 cor_proc_cmd(trgt_unconn_ll
, reset_needed
);
399 return RC_PC_FINISHED
;
402 void cor_proc_cpacket(struct cor_conn
*trgt_unconn_l
)
404 int reset_needed
= 0;
406 if (unlikely(trgt_unconn_l
->isreset
!= 0))
409 BUG_ON(trgt_unconn_l
->targettype
!= TARGET_UNCONNECTED
);
411 BUG_ON(trgt_unconn_l
->is_client
== 0);
412 spin_lock_bh(&(trgt_unconn_l
->reversedir
->rcv_lock
));
415 int rc
= _cor_proc_cpacket(trgt_unconn_l
, &reset_needed
);
417 BUG_ON(rc
!= RC_PC_FINISHED
&&
418 rc
!= RC_PC_OUT_OF_BUFSPACE
&&
419 rc
!= RC_PC_INCOMPLETEREAD
);
421 if (trgt_unconn_l
->targettype
== TARGET_UNCONNECTED
) {
422 if (trgt_unconn_l
->flush
!= 0 &&
423 trgt_unconn_l
->data_buf
.read_remaining
== 0)
424 trgt_unconn_l
->reversedir
->flush
= 1;
426 trgt_unconn_l
->reversedir
->flush
= 0;
428 cor_flush_buf(trgt_unconn_l
->reversedir
);
430 if (rc
== RC_PC_OUT_OF_BUFSPACE
||
431 rc
== RC_PC_INCOMPLETEREAD
)
434 BUG_ON(rc
!= RC_PC_FINISHED
);
436 if (trgt_unconn_l
->targettype
== TARGET_SOCK
||
437 trgt_unconn_l
->is_highlatency
== 0 || (
438 trgt_unconn_l
->flush
!= 0 &&
439 trgt_unconn_l
->data_buf
.read_remaining
== 0))
440 trgt_unconn_l
->reversedir
->flush
= 1;
442 trgt_unconn_l
->reversedir
->flush
= 0;
444 cor_flush_buf(trgt_unconn_l
->reversedir
);
445 cor_flush_buf(trgt_unconn_l
);
449 if (reset_needed
!= 0)
450 cor_reset_conn_locked(trgt_unconn_l
);
453 spin_unlock_bh(&(trgt_unconn_l
->reversedir
->rcv_lock
));
456 MODULE_LICENSE("GPL");