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(cor_get_conn_reversedir(trgt_unconn_ll
),
97 (char *) &respcode
, 1, reset_needed
);
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(cor_get_conn_reversedir(trgt_unconn_ll
),
110 msg
, 3, reset_needed
);
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(cor_get_conn_reversedir(trgt_unconn_ll
),
125 hdr
, len_len
+ 1, reset_needed
);
126 cor_receive_cpacketresp(cor_get_conn_reversedir(trgt_unconn_ll
),
127 buf
, len
, reset_needed
);
130 static __u32
cor_list_l4_protocols(char *buf
, __u32 buflen
)
132 if (unlikely(buflen
< 2)) {
137 cor_put_u16(buf
, L4PROTO_STREAM
);
141 static int cor_proc_bindata(struct cor_conn
*trgt_unconn_ll
, __u16 cmd
,
147 buf
= kmalloc(CD_RESP_BIN_MAXSIZE
, GFP_ATOMIC
);
148 if (unlikely(buf
== 0)) {
149 cor_send_resp_failed(trgt_unconn_ll
,
150 CDR_EXECFAILED_TEMPORARILY_OUT_OF_RESSOURCES
,
155 cor_send_resp_ok(trgt_unconn_ll
, reset_needed
);
157 if (cmd
== CD_LIST_NEIGH
) {
158 len
= cor_generate_neigh_list(buf
, CD_RESP_BIN_MAXSIZE
);
159 } else if (cmd
== CD_LIST_SERVICES
) {
160 len
= cor_list_services(buf
, CD_RESP_BIN_MAXSIZE
);
161 } else if (cmd
== CD_LIST_L4PROTOCOLS
) {
162 len
= cor_list_l4_protocols(buf
, CD_RESP_BIN_MAXSIZE
);
166 cor_send_resp_bin(trgt_unconn_ll
, buf
, len
, reset_needed
);
171 static int cor_proc_connect_port(struct cor_conn
*trgt_unconn_ll
,
178 if (unlikely(trgt_unconn_ll
->target
.unconnected
.paramlen
< 6)) {
179 /* command too short */
180 cor_send_resp_failed(trgt_unconn_ll
,
181 CDR_EXECFAILED_INVALID_COMMAND
, reset_needed
);
185 proto
= cor_parse_u16(trgt_unconn_ll
->target
.unconnected
.cmdparams
);
186 port
= cor_parse_be32(trgt_unconn_ll
->target
.unconnected
.cmdparams
+ 2);
188 if (proto
!= L4PROTO_STREAM
) {
189 cor_send_resp_failed(trgt_unconn_ll
,
190 CDR_EXECFAILED_UNKNOWN_L4PROTOCOL
,
195 rc
= cor_connect_port(trgt_unconn_ll
, port
);
198 cor_send_resp_ok(trgt_unconn_ll
, reset_needed
);
200 } else if (rc
== 2) {
201 cor_send_resp_failed(trgt_unconn_ll
,
202 CDR_EXECFAILED_PORTCLOSED
, reset_needed
);
203 } else if (rc
== 3) {
204 cor_send_resp_failed(trgt_unconn_ll
,
205 CDR_EXECFAILED_TEMPORARILY_OUT_OF_RESSOURCES
,
213 static int cor_proc_connect_nb(struct cor_conn
*trgt_unconn_ll
,
216 char *addr
= trgt_unconn_ll
->target
.unconnected
.cmdparams
;
217 __u32 addrlen
= trgt_unconn_ll
->target
.unconnected
.paramlen
;
221 if (unlikely(addrlen
> 65535)) {
222 cor_send_resp_failed(trgt_unconn_ll
,
223 CDR_EXECFAILED_NB_DOESNTEXIST
, reset_needed
);
227 rc
= cor_connect_neigh(trgt_unconn_ll
, addr
, (__u16
) addrlen
);
230 cor_send_resp_ok(trgt_unconn_ll
, reset_needed
);
232 } else if (rc
== 3) {
233 cor_send_resp_failed(trgt_unconn_ll
,
234 CDR_EXECFAILED_NB_DOESNTEXIST
, reset_needed
);
235 } else if (rc
== 4) {
236 cor_send_resp_failed(trgt_unconn_ll
,
237 CDR_EXECFAILED_TEMPORARILY_OUT_OF_RESSOURCES
,
245 static void cor_proc_cmd(struct cor_conn
*trgt_unconn_ll
, int *reset_needed
)
247 __u16 cmd
= trgt_unconn_ll
->target
.unconnected
.cmd
;
248 char *params
= trgt_unconn_ll
->target
.unconnected
.cmdparams
;
249 int discard_on_error
= (cmd
& CD_CONTINUE_ON_ERROR_FLAG
) == 0;
252 cmd
= cmd
& (~CD_CONTINUE_ON_ERROR_FLAG
);
254 BUG_ON(trgt_unconn_ll
->target
.unconnected
.cmdparams
== 0);
256 if (cmd
== CD_CONNECT_NB
) {
257 rc
= cor_proc_connect_nb(trgt_unconn_ll
, reset_needed
);
258 } else if (cmd
== CD_CONNECT_PORT
) {
259 rc
= cor_proc_connect_port(trgt_unconn_ll
, reset_needed
);
260 } else if (cmd
== CD_LIST_NEIGH
|| cmd
== CD_LIST_SERVICES
||
261 cmd
== CD_LIST_L4PROTOCOLS
) {
262 rc
= cor_proc_bindata(trgt_unconn_ll
, cmd
, reset_needed
);
264 cor_send_resp_failed(trgt_unconn_ll
,
265 CDR_EXECFAILED_INVALID_COMMAND
, reset_needed
);
271 if (trgt_unconn_ll
->targettype
== TARGET_UNCONNECTED
) {
272 trgt_unconn_ll
->target
.unconnected
.cmdparams
= 0;
273 trgt_unconn_ll
->target
.unconnected
.cmdread
= 0;
274 trgt_unconn_ll
->target
.unconnected
.paramlen_read
= 0;
275 trgt_unconn_ll
->target
.unconnected
.cmd
= 0;
276 trgt_unconn_ll
->target
.unconnected
.paramlen
= 0;
278 if (rc
!= 0 && discard_on_error
) {
279 trgt_unconn_ll
->targettype
= TARGET_DISCARD
;
284 static void cor_read_cmd(struct cor_conn
*trgt_unconn_ll
)
288 pull
= min(trgt_unconn_ll
->target
.unconnected
.paramlen
-
289 trgt_unconn_ll
->target
.unconnected
.cmdread
,
290 trgt_unconn_ll
->data_buf
.read_remaining
);
293 BUG_ON(trgt_unconn_ll
->target
.unconnected
.cmdparams
== 0);
298 cor_databuf_pull(trgt_unconn_ll
,
299 trgt_unconn_ll
->target
.unconnected
.cmdparams
+
300 trgt_unconn_ll
->target
.unconnected
.cmdread
, pull
);
301 cor_databuf_ackread(trgt_unconn_ll
);
303 trgt_unconn_ll
->target
.unconnected
.cmdread
+= pull
;
306 static void cor_read_discard(struct cor_conn
*trgt_unconn_ll
)
308 BUG_ON(trgt_unconn_ll
->target
.unconnected
.paramlen_read
== 0);
310 while (trgt_unconn_ll
->target
.unconnected
.paramlen
<
311 trgt_unconn_ll
->target
.unconnected
.cmdread
&&
312 trgt_unconn_ll
->data_buf
.read_remaining
> 0) {
314 cor_databuf_pull(trgt_unconn_ll
, buf
, 1);
315 cor_databuf_ackread(trgt_unconn_ll
);
317 trgt_unconn_ll
->target
.unconnected
.cmdread
++;
321 #define RC_READ_HDR_FINISHED 0
322 #define RC_READ_HDR_INCOMPLETE 1
323 static int cor_read_hdr(struct cor_conn
*trgt_unconn_ll
)
325 BUG_ON(trgt_unconn_ll
->target
.unconnected
.cmdparams
!= 0);
329 if (trgt_unconn_ll
->target
.unconnected
.paramlen_read
!= 0)
330 return RC_READ_HDR_FINISHED
;
331 else if (trgt_unconn_ll
->data_buf
.read_remaining
== 0)
332 return RC_READ_HDR_INCOMPLETE
;
334 BUG_ON(trgt_unconn_ll
->target
.unconnected
.cmdread
>= 6);
336 if (trgt_unconn_ll
->target
.unconnected
.cmdread
< 2) {
338 cor_databuf_pull(trgt_unconn_ll
, buf
, 1);
339 trgt_unconn_ll
->target
.unconnected
.cmd
<<= 8;
340 trgt_unconn_ll
->target
.unconnected
.cmd
+= buf
[0];
341 trgt_unconn_ll
->target
.unconnected
.cmdread
+= 1;
345 cor_databuf_pull(trgt_unconn_ll
,
346 trgt_unconn_ll
->target
.unconnected
.paramlen_buf
+
347 trgt_unconn_ll
->target
.unconnected
.cmdread
- 2,
349 cor_databuf_ackread(trgt_unconn_ll
);
350 trgt_unconn_ll
->target
.unconnected
.cmdread
+= 1;
353 trgt_unconn_ll
->target
.unconnected
.paramlen_buf
,
354 trgt_unconn_ll
->target
.unconnected
.cmdread
- 2,
355 &(trgt_unconn_ll
->target
.unconnected
.paramlen
));
358 trgt_unconn_ll
->target
.unconnected
.paramlen_read
= 1;
359 trgt_unconn_ll
->target
.unconnected
.cmdread
= 0;
360 return RC_READ_HDR_FINISHED
;
365 #define RC_PC_FINISHED 0
366 #define RC_PC_OUT_OF_BUFSPACE 1
367 #define RC_PC_INCOMPLETEREAD 2
368 static int _cor_proc_cpacket(struct cor_conn
*trgt_unconn_ll
, int *reset_needed
)
372 if (cor_conn_src_unconn_write_allowed(cor_get_conn_reversedir(
373 trgt_unconn_ll
)) == 0)
374 return RC_PC_OUT_OF_BUFSPACE
;
376 if (trgt_unconn_ll
->target
.unconnected
.paramlen_read
!= 0)
379 rc
= cor_read_hdr(trgt_unconn_ll
);
380 if (rc
== RC_READ_HDR_INCOMPLETE
) {
381 return RC_PC_INCOMPLETEREAD
;
382 } else if (rc
== RC_READ_HDR_FINISHED
) {
383 trgt_unconn_ll
->target
.unconnected
.paramlen_read
= 1;
385 if (trgt_unconn_ll
->target
.unconnected
.paramlen
>
387 /* command too long */
388 cor_send_resp_failed(trgt_unconn_ll
,
389 CDR_EXECFAILED_INVALID_COMMAND
,
397 if (trgt_unconn_ll
->target
.unconnected
.paramlen
>
399 cor_read_discard(trgt_unconn_ll
);
400 return RC_PC_INCOMPLETEREAD
;
403 if (trgt_unconn_ll
->target
.unconnected
.cmdparams
== 0) {
404 trgt_unconn_ll
->target
.unconnected
.cmdparams
= kmalloc(
405 trgt_unconn_ll
->target
.unconnected
.paramlen
,
407 if (trgt_unconn_ll
->target
.unconnected
.cmdparams
== 0) {
409 return RC_PC_INCOMPLETEREAD
;
413 cor_read_cmd(trgt_unconn_ll
);
415 BUG_ON(trgt_unconn_ll
->target
.unconnected
.cmdread
>
416 trgt_unconn_ll
->target
.unconnected
.paramlen
);
418 if (trgt_unconn_ll
->target
.unconnected
.cmdread
<
419 trgt_unconn_ll
->target
.unconnected
.paramlen
)
420 return RC_PC_INCOMPLETEREAD
;
422 cor_proc_cmd(trgt_unconn_ll
, reset_needed
);
424 return RC_PC_FINISHED
;
427 void cor_proc_cpacket(struct cor_conn
*trgt_unconn_l
)
429 struct cor_conn
*src_in
= cor_get_conn_reversedir(trgt_unconn_l
);
430 int reset_needed
= 0;
432 if (unlikely(trgt_unconn_l
->isreset
!= 0))
435 BUG_ON(trgt_unconn_l
->targettype
!= TARGET_UNCONNECTED
);
437 BUG_ON(trgt_unconn_l
->is_client
== 0);
438 spin_lock_bh(&(src_in
->rcv_lock
));
441 int rc
= _cor_proc_cpacket(trgt_unconn_l
, &reset_needed
);
443 BUG_ON(rc
!= RC_PC_FINISHED
&&
444 rc
!= RC_PC_OUT_OF_BUFSPACE
&&
445 rc
!= RC_PC_INCOMPLETEREAD
);
447 if (trgt_unconn_l
->targettype
== TARGET_UNCONNECTED
) {
448 if (trgt_unconn_l
->flush
!= 0 &&
449 trgt_unconn_l
->data_buf
.read_remaining
== 0)
454 cor_flush_buf(cor_get_conn_reversedir(trgt_unconn_l
));
456 if (rc
== RC_PC_OUT_OF_BUFSPACE
||
457 rc
== RC_PC_INCOMPLETEREAD
)
460 BUG_ON(rc
!= RC_PC_FINISHED
);
462 if (trgt_unconn_l
->targettype
== TARGET_SOCK
||
463 trgt_unconn_l
->is_highlatency
== 0 ||
464 LOWLATENCY_SEND_UNFLUSHED_DATA
!= 0 || (
465 trgt_unconn_l
->flush
!= 0 &&
466 trgt_unconn_l
->data_buf
.read_remaining
== 0))
471 cor_flush_buf(src_in
);
472 cor_flush_buf(trgt_unconn_l
);
476 if (reset_needed
!= 0)
477 cor_reset_conn_locked(cor_get_conn_bidir(
481 spin_unlock_bh(&(src_in
->rcv_lock
));
484 MODULE_LICENSE("GPL");