convert rcv_conn_list to snd_conn_list
[cor.git] / net / cor / conn_trgt_unconn.c
blob4ecc95e57a9e5b082fcc5bfe40d0c1f46ce145c7
1 /**
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
18 * 02110-1301, USA.
21 #include "cor.h"
23 int cor_encode_len(char *buf, int buflen, __u32 len)
25 BUG_ON(buf == 0);
26 BUG_ON(buflen < 4);
28 if (len < 128) {
29 buf[0] = (__u8) len;
30 return 1;
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;
36 buf[1] = len_p[1];
37 return 2;
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;
43 buf[1] = len_p[1];
44 buf[2] = len_p[2];
45 buf[3] = len_p[3];
46 return 4;
47 } else {
48 return -1;
52 int cor_decode_len(char *buf, int buflen, __u32 *len)
54 __u8 b0 = (__u8) buf[0];
56 *len = 0;
58 if (buflen >= 1 && b0 < 128) {
59 *len = (__u8) buf[0];
60 return 1;
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;
66 return 2;
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;
74 return 4;
75 } else {
76 return 0;
80 static void cor_receive_cpacketresp(struct cor_conn *src_unconn_ll, char *buf,
81 __u32 len, int *reset_needed)
83 __u32 rc;
84 if (unlikely((*reset_needed) != 0))
85 return;
86 rc = cor_receive_buf(src_unconn_ll, buf, len, 0, 0);
87 if (unlikely(rc < len))
88 (*reset_needed) = 1;
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)
103 char msg[3];
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)
116 char hdr[5];
117 int len_len;
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)) {
133 BUG();
134 return 0;
137 cor_put_u16(buf, L4PROTO_STREAM);
138 return 2;
141 static int cor_proc_bindata(struct cor_conn *trgt_unconn_ll, __u16 cmd,
142 int *reset_needed)
144 __u32 len = 0;
145 char *buf;
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,
151 reset_needed);
152 return 1;
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);
163 } else {
164 BUG();
166 cor_send_resp_bin(trgt_unconn_ll, buf, len, reset_needed);
167 kfree(buf);
168 return 0;
171 static int cor_proc_connect_port(struct cor_conn *trgt_unconn_ll,
172 int *reset_needed)
174 __u16 proto;
175 __be32 port;
176 int rc;
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);
182 return 1;
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,
191 reset_needed);
192 return 1;
195 rc = cor_connect_port(trgt_unconn_ll, port);
197 if (rc == 0) {
198 cor_send_resp_ok(trgt_unconn_ll, reset_needed);
199 return 0;
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,
206 reset_needed);
207 } else {
208 BUG();
210 return 1;
213 static int cor_proc_connect_nb(struct cor_conn *trgt_unconn_ll,
214 int *reset_needed)
216 char *addr = trgt_unconn_ll->target.unconnected.cmdparams;
217 __u32 addrlen = trgt_unconn_ll->target.unconnected.paramlen;
219 int rc;
221 if (unlikely(addrlen > 65535)) {
222 cor_send_resp_failed(trgt_unconn_ll,
223 CDR_EXECFAILED_NB_DOESNTEXIST, reset_needed);
224 return 1;
227 rc = cor_connect_neigh(trgt_unconn_ll, addr, (__u16) addrlen);
229 if (rc == 0) {
230 cor_send_resp_ok(trgt_unconn_ll, reset_needed);
231 return 0;
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,
238 reset_needed);
239 } else {
240 BUG();
242 return 1;
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;
250 int rc;
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);
263 } else {
264 cor_send_resp_failed(trgt_unconn_ll,
265 CDR_EXECFAILED_INVALID_COMMAND, reset_needed);
266 rc = 1;
269 kfree(params);
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)
286 int pull;
288 pull = min(trgt_unconn_ll->target.unconnected.paramlen -
289 trgt_unconn_ll->target.unconnected.cmdread,
290 trgt_unconn_ll->data_buf.read_remaining);
292 BUG_ON(pull < 0);
293 BUG_ON(trgt_unconn_ll->target.unconnected.cmdparams == 0);
295 if (pull == 0)
296 return;
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) {
313 char buf[1];
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);
327 while (1) {
328 int rc;
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) {
337 char buf[1];
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;
342 continue;
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;
352 rc = cor_decode_len(
353 trgt_unconn_ll->target.unconnected.paramlen_buf,
354 trgt_unconn_ll->target.unconnected.cmdread - 2,
355 &(trgt_unconn_ll->target.unconnected.paramlen));
357 if (rc > 0) {
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)
370 int rc;
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)
377 goto hdrdone;
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 >
386 MAX_CONN_CMD_LEN) {
387 /* command too long */
388 cor_send_resp_failed(trgt_unconn_ll,
389 CDR_EXECFAILED_INVALID_COMMAND,
390 reset_needed);
392 } else {
393 BUG();
396 hdrdone:
397 if (trgt_unconn_ll->target.unconnected.paramlen >
398 MAX_CONN_CMD_LEN) {
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,
406 GFP_ATOMIC);
407 if (trgt_unconn_ll->target.unconnected.cmdparams == 0) {
408 *reset_needed = 1;
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))
433 return;
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));
440 while (1) {
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)
450 src_in->flush = 1;
451 else
452 src_in->flush = 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)
458 break;
459 } else {
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))
467 src_in->flush = 1;
468 else
469 src_in->flush = 0;
471 cor_flush_buf(src_in);
472 cor_flush_buf(trgt_unconn_l);
473 break;
476 if (reset_needed != 0)
477 cor_reset_conn_locked(cor_get_conn_bidir(
478 trgt_unconn_l));
481 spin_unlock_bh(&(src_in->rcv_lock));
484 MODULE_LICENSE("GPL");