split dev_queue
[cor.git] / net / cor / conn_trgt_unconn.c
blob7e1c205b2b57730f7ef8629ed3e202c06e0eaaa6
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.
16 #include "cor.h"
18 int cor_encode_len(char *buf, int buflen, __u32 len)
20 BUG_ON(buf == 0);
21 BUG_ON(buflen < 4);
23 if (len < 128) {
24 buf[0] = (__u8) len;
25 return 1;
26 } else if (len < 16512) {
27 __u16 len_be = cpu_to_be16(len - 128);
28 char *len_p = (char *) &len_be;
30 buf[0] = len_p[0] + 128;
31 buf[1] = len_p[1];
32 return 2;
33 } else if (len < 1073758336) {
34 __u32 len_be = cpu_to_be32(len - 16512);
35 char *len_p = (char *) &len_be;
37 buf[0] = len_p[0] + 192;
38 buf[1] = len_p[1];
39 buf[2] = len_p[2];
40 buf[3] = len_p[3];
41 return 4;
42 } else {
43 return -1;
47 int cor_decode_len(char *buf, int buflen, __u32 *len)
49 __u8 b0 = (__u8) buf[0];
51 *len = 0;
53 if (buflen >= 1 && b0 < 128) {
54 *len = (__u8) buf[0];
55 return 1;
56 } else if (buflen >= 2 && b0 >= 128 && b0 < 192) {
57 ((char *) len)[0] = buf[0] - 128;
58 ((char *) len)[1] = buf[1];
60 *len = be16_to_cpu(*len) + 128;
61 return 2;
62 } else if (buflen >= 4 && b0 >= 192) {
63 ((char *) len)[0] = buf[0] - 192;
64 ((char *) len)[1] = buf[1];
65 ((char *) len)[2] = buf[2];
66 ((char *) len)[3] = buf[3];
68 *len = be32_to_cpu(*len) + 16512;
69 return 4;
70 } else {
71 return 0;
75 static void cor_receive_cpacketresp(struct cor_conn *src_unconn_ll, char *buf,
76 __u32 len, int *reset_needed)
78 __u32 rc;
80 if (unlikely((*reset_needed) != 0))
81 return;
82 rc = cor_receive_buf(src_unconn_ll, buf, len, 0, 0);
83 if (unlikely(rc < len))
84 (*reset_needed) = 1;
88 static void cor_send_resp_ok(struct cor_conn *trgt_unconn_ll, int *reset_needed)
90 __u8 respcode = CDR_EXECOK;
92 cor_receive_cpacketresp(cor_get_conn_reversedir(trgt_unconn_ll),
93 (char *) &respcode, 1, reset_needed);
96 static void cor_send_resp_failed(struct cor_conn *trgt_unconn_ll,
97 __u16 reasoncode, int *reset_needed)
99 char msg[3];
101 msg[0] = CDR_EXECFAILED;
103 cor_put_u16(&msg[1], reasoncode);
105 cor_receive_cpacketresp(cor_get_conn_reversedir(trgt_unconn_ll),
106 msg, 3, reset_needed);
109 static void cor_send_resp_bin(struct cor_conn *trgt_unconn_ll, char *buf,
110 __u32 len, int *reset_needed)
112 char hdr[5];
113 int len_len;
115 if (len == 0) {
116 hdr[0] = CDR_EXECOK_BINDATA_NORESP;
117 len_len = 0;
118 } else {
119 hdr[0] = CDR_EXECOK_BINDATA;
120 len_len = cor_encode_len(hdr + 1, 4, len);
121 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_RESOURCES,
151 reset_needed);
152 return 1;
155 if (cmd == CD_LIST_NEIGH) {
156 len = cor_generate_neigh_list(buf, CD_RESP_BIN_MAXSIZE);
157 } else if (cmd == CD_LIST_SERVICES) {
158 len = cor_list_services(buf, CD_RESP_BIN_MAXSIZE);
159 } else if (cmd == CD_LIST_L4PROTOCOLS) {
160 len = cor_list_l4_protocols(buf, CD_RESP_BIN_MAXSIZE);
161 } else {
162 BUG();
164 cor_send_resp_bin(trgt_unconn_ll, buf, len, reset_needed);
165 kfree(buf);
166 return 0;
169 static int cor_proc_connect_port(struct cor_conn *trgt_unconn_ll,
170 int *reset_needed)
172 __u16 proto;
173 __be32 port;
174 int rc;
176 if (unlikely(trgt_unconn_ll->trgt.unconnected.paramlen < 6)) {
177 /* command too short */
178 cor_send_resp_failed(trgt_unconn_ll,
179 CDR_EXECFAILED_INVALID_COMMAND, reset_needed);
180 return 1;
183 proto = cor_parse_u16(trgt_unconn_ll->trgt.unconnected.cmdparams);
184 port = cor_parse_be32(trgt_unconn_ll->trgt.unconnected.cmdparams + 2);
186 if (proto != L4PROTO_STREAM) {
187 cor_send_resp_failed(trgt_unconn_ll,
188 CDR_EXECFAILED_UNKNOWN_L4PROTOCOL,
189 reset_needed);
190 return 1;
193 rc = cor_connect_port(trgt_unconn_ll, port);
195 if (rc == CONNECT_PORT_OK) {
196 cor_send_resp_ok(trgt_unconn_ll, reset_needed);
197 return 0;
198 } else if (rc == CONNECT_PORT_PORTCLOSED) {
199 cor_send_resp_failed(trgt_unconn_ll,
200 CDR_EXECFAILED_PORTCLOSED, reset_needed);
201 } else if (rc == CONNECT_PORT_TEMPORARILY_OUT_OF_RESOURCES) {
202 cor_send_resp_failed(trgt_unconn_ll,
203 CDR_EXECFAILED_TEMPORARILY_OUT_OF_RESOURCES,
204 reset_needed);
205 } else {
206 BUG();
208 return 1;
211 static int cor_proc_connect_nb(struct cor_conn *trgt_unconn_ll,
212 int *reset_needed)
214 __be64 addr;
216 int rc;
218 if (unlikely(trgt_unconn_ll->trgt.unconnected.paramlen != 8)) {
219 cor_send_resp_failed(trgt_unconn_ll,
220 CDR_EXECFAILED_COMMAND_PARSE_ERROR,
221 reset_needed);
222 return 1;
225 addr = cor_parse_be64(trgt_unconn_ll->trgt.unconnected.cmdparams);
227 rc = cor_connect_neigh(trgt_unconn_ll, addr);
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_RESOURCES,
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->trgt.unconnected.cmd;
248 char *params = trgt_unconn_ll->trgt.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);
253 cmd = cmd & (~CD_NOPARAM_FLAG);
255 BUG_ON(trgt_unconn_ll->trgt.unconnected.cmdparams == 0);
257 if (cmd == CD_CONNECT_NB) {
258 rc = cor_proc_connect_nb(trgt_unconn_ll, reset_needed);
259 } else if (cmd == CD_CONNECT_PORT) {
260 rc = cor_proc_connect_port(trgt_unconn_ll, reset_needed);
261 } else if (cmd == CD_LIST_NEIGH || cmd == CD_LIST_SERVICES ||
262 cmd == CD_LIST_L4PROTOCOLS) {
263 rc = cor_proc_bindata(trgt_unconn_ll, cmd, reset_needed);
264 } else {
265 cor_send_resp_failed(trgt_unconn_ll,
266 CDR_EXECFAILED_INVALID_COMMAND, reset_needed);
267 rc = 1;
270 kfree(params);
272 if (trgt_unconn_ll->targettype == TARGET_UNCONNECTED) {
273 trgt_unconn_ll->trgt.unconnected.cmdparams = 0;
274 trgt_unconn_ll->trgt.unconnected.cmdread = 0;
275 trgt_unconn_ll->trgt.unconnected.paramlen_read = 0;
276 trgt_unconn_ll->trgt.unconnected.cmd = 0;
277 trgt_unconn_ll->trgt.unconnected.paramlen = 0;
279 if (rc != 0 && discard_on_error) {
280 trgt_unconn_ll->targettype = TARGET_DISCARD;
285 static void cor_read_cmd(struct cor_conn *trgt_unconn_ll)
287 int pull;
289 pull = min(trgt_unconn_ll->trgt.unconnected.paramlen -
290 trgt_unconn_ll->trgt.unconnected.cmdread,
291 trgt_unconn_ll->data_buf.read_remaining);
293 BUG_ON(pull < 0);
294 BUG_ON(trgt_unconn_ll->trgt.unconnected.cmdparams == 0);
296 if (pull == 0)
297 return;
299 cor_databuf_pull(trgt_unconn_ll,
300 trgt_unconn_ll->trgt.unconnected.cmdparams +
301 trgt_unconn_ll->trgt.unconnected.cmdread, pull);
302 cor_databuf_ackread(trgt_unconn_ll);
304 trgt_unconn_ll->trgt.unconnected.cmdread += pull;
307 static void cor_read_discard(struct cor_conn *trgt_unconn_ll)
309 BUG_ON(trgt_unconn_ll->trgt.unconnected.paramlen_read == 0);
311 while (trgt_unconn_ll->trgt.unconnected.paramlen <
312 trgt_unconn_ll->trgt.unconnected.cmdread &&
313 trgt_unconn_ll->data_buf.read_remaining > 0) {
314 char buf[1];
316 cor_databuf_pull(trgt_unconn_ll, buf, 1);
317 cor_databuf_ackread(trgt_unconn_ll);
319 trgt_unconn_ll->trgt.unconnected.cmdread++;
323 #define RC_READ_HDR_FINISHED 0
324 #define RC_READ_HDR_INCOMPLETE 1
325 static int cor_read_hdr(struct cor_conn *trgt_unconn_ll)
327 BUG_ON(trgt_unconn_ll->trgt.unconnected.cmdparams != 0);
329 if (trgt_unconn_ll->trgt.unconnected.paramlen_read != 0)
330 return RC_READ_HDR_FINISHED;
333 while (trgt_unconn_ll->trgt.unconnected.cmdread < 2) {
334 char buf[1];
336 if (trgt_unconn_ll->data_buf.read_remaining == 0)
337 return RC_READ_HDR_INCOMPLETE;
339 cor_databuf_pull(trgt_unconn_ll, buf, 1);
340 trgt_unconn_ll->trgt.unconnected.cmd <<= 8;
341 trgt_unconn_ll->trgt.unconnected.cmd += buf[0];
342 trgt_unconn_ll->trgt.unconnected.cmdread += 1;
345 if ((trgt_unconn_ll->trgt.unconnected.cmd & CD_NOPARAM_FLAG) != 0) {
346 trgt_unconn_ll->trgt.unconnected.paramlen = 0;
347 trgt_unconn_ll->trgt.unconnected.paramlen_read = 1;
348 trgt_unconn_ll->trgt.unconnected.cmdread = 0;
349 return RC_READ_HDR_FINISHED;
352 while (1) {
353 int rc;
355 if (trgt_unconn_ll->data_buf.read_remaining == 0)
356 return RC_READ_HDR_INCOMPLETE;
358 cor_databuf_pull(trgt_unconn_ll,
359 trgt_unconn_ll->trgt.unconnected.paramlen_buf +
360 trgt_unconn_ll->trgt.unconnected.cmdread - 2,
362 cor_databuf_ackread(trgt_unconn_ll);
363 trgt_unconn_ll->trgt.unconnected.cmdread += 1;
365 BUG_ON(trgt_unconn_ll->trgt.unconnected.cmdread >= 6);
367 rc = cor_decode_len(
368 trgt_unconn_ll->trgt.unconnected.paramlen_buf,
369 trgt_unconn_ll->trgt.unconnected.cmdread - 2,
370 &trgt_unconn_ll->trgt.unconnected.paramlen);
372 if (rc > 0) {
373 trgt_unconn_ll->trgt.unconnected.paramlen_read = 1;
374 trgt_unconn_ll->trgt.unconnected.cmdread = 0;
375 return RC_READ_HDR_FINISHED;
380 #define RC_PC_FINISHED 0
381 #define RC_PC_OUT_OF_BUFSPACE 1
382 #define RC_PC_INCOMPLETEREAD 2
383 static int _cor_proc_cpacket(struct cor_conn *trgt_unconn_ll, int *reset_needed)
385 int rc;
387 if (cor_conn_src_unconn_write_allowed(cor_get_conn_reversedir(
388 trgt_unconn_ll)) == 0)
389 return RC_PC_OUT_OF_BUFSPACE;
391 if (trgt_unconn_ll->trgt.unconnected.paramlen_read != 0)
392 goto hdrdone;
394 rc = cor_read_hdr(trgt_unconn_ll);
395 if (rc == RC_READ_HDR_INCOMPLETE) {
396 return RC_PC_INCOMPLETEREAD;
397 } else if (rc == RC_READ_HDR_FINISHED) {
398 trgt_unconn_ll->trgt.unconnected.paramlen_read = 1;
400 if (trgt_unconn_ll->trgt.unconnected.paramlen >
401 MAX_CONN_CMD_LEN) {
402 /* command too long */
403 cor_send_resp_failed(trgt_unconn_ll,
404 CDR_EXECFAILED_INVALID_COMMAND,
405 reset_needed);
407 } else {
408 BUG();
411 hdrdone:
412 if (trgt_unconn_ll->trgt.unconnected.paramlen > MAX_CONN_CMD_LEN) {
413 cor_read_discard(trgt_unconn_ll);
414 return RC_PC_INCOMPLETEREAD;
417 if (trgt_unconn_ll->trgt.unconnected.cmdparams == 0) {
418 trgt_unconn_ll->trgt.unconnected.cmdparams = kmalloc(
419 trgt_unconn_ll->trgt.unconnected.paramlen,
420 GFP_ATOMIC);
421 if (trgt_unconn_ll->trgt.unconnected.cmdparams == 0) {
422 *reset_needed = 1;
423 return RC_PC_INCOMPLETEREAD;
427 cor_read_cmd(trgt_unconn_ll);
429 BUG_ON(trgt_unconn_ll->trgt.unconnected.cmdread >
430 trgt_unconn_ll->trgt.unconnected.paramlen);
432 if (trgt_unconn_ll->trgt.unconnected.cmdread <
433 trgt_unconn_ll->trgt.unconnected.paramlen)
434 return RC_PC_INCOMPLETEREAD;
436 cor_proc_cmd(trgt_unconn_ll, reset_needed);
438 return RC_PC_FINISHED;
441 void cor_proc_cpacket(struct cor_conn *trgt_unconn_l)
443 struct cor_conn *src_in = cor_get_conn_reversedir(trgt_unconn_l);
444 int reset_needed = 0;
446 if (unlikely(trgt_unconn_l->isreset != 0))
447 return;
449 BUG_ON(trgt_unconn_l->targettype != TARGET_UNCONNECTED);
451 BUG_ON(trgt_unconn_l->is_client == 0);
452 spin_lock_bh(&src_in->rcv_lock);
454 while (1) {
455 int rc = _cor_proc_cpacket(trgt_unconn_l, &reset_needed);
457 BUG_ON(rc != RC_PC_FINISHED &&
458 rc != RC_PC_OUT_OF_BUFSPACE &&
459 rc != RC_PC_INCOMPLETEREAD);
461 if (trgt_unconn_l->targettype == TARGET_UNCONNECTED) {
462 if (trgt_unconn_l->flush != 0 &&
463 trgt_unconn_l->data_buf.read_remaining == 0)
464 src_in->flush = 1;
465 else
466 src_in->flush = 0;
468 cor_flush_buf(cor_get_conn_reversedir(trgt_unconn_l));
470 if (rc == RC_PC_OUT_OF_BUFSPACE ||
471 rc == RC_PC_INCOMPLETEREAD)
472 break;
473 } else {
474 BUG_ON(rc != RC_PC_FINISHED);
476 if (trgt_unconn_l->targettype == TARGET_SOCK || (
477 trgt_unconn_l->flush != 0 &&
478 trgt_unconn_l->data_buf.read_remaining == 0))
479 src_in->flush = 1;
480 else
481 src_in->flush = 0;
483 cor_flush_buf(src_in);
484 cor_flush_buf(trgt_unconn_l);
485 break;
488 if (reset_needed != 0)
489 cor_reset_conn_locked(cor_get_conn_bidir(
490 trgt_unconn_l));
493 spin_unlock_bh(&src_in->rcv_lock);
496 MODULE_LICENSE("GPL");