2 * Connection oriented routing
3 * Copyright (C) 2007-2011 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 struct work_struct cpacket_resume_work
;
24 static int cpacket_resume_running
;
25 DEFINE_SPINLOCK(cpacket_bufferlimits_lock
);
26 static __u64 cpacket_bufferusage
;
27 static int cpacket_kmallocfailed
;
28 LIST_HEAD(cpacket_bufferwaiting
);
30 static int reserve_cpacket_buffer(struct conn
*trtg_unconn_l
, int fromresume
)
35 __u32 paramlen
= trtg_unconn_l
->target
.unconnected
.paramlen
;
38 if (trtg_unconn_l
->target
.unconnected
.cmd
== CD_LIST_NEIGH
)
39 resplen
= LISTNEIGH_RESP_MAXSIZE
+ 128;
41 if (trtg_unconn_l
->target
.unconnected
.in_buffer_wait_list
&&
45 if (trtg_unconn_l
->data_buf
.cpacket_buffer
+ paramlen
+ resplen
>
46 BUFFERLIMIT_CONNDATA_PERCONN
)
49 spin_lock_irqsave(&cpacket_bufferlimits_lock
, iflags
);
51 if (list_empty(&cpacket_bufferwaiting
) == 0 || paramlen
+ resplen
+
52 cpacket_bufferusage
> BUFFERLIMIT_CONNDATA_GLOBAL
) {
53 /* out of bufferspace */
54 if (trtg_unconn_l
->target
.unconnected
.in_buffer_wait_list
== 0){
55 trtg_unconn_l
->target
.unconnected
.in_buffer_wait_list
=1;
56 list_add_tail(&(trtg_unconn_l
->target
.unconnected
.buffer_wait_list
),
57 &cpacket_bufferwaiting
);
58 kref_get(&(trtg_unconn_l
->ref
));
60 if (cpacket_resume_running
== 0) {
61 schedule_work(&cpacket_resume_work
);
62 cpacket_resume_running
= 1;
65 spin_unlock_irqrestore(&cpacket_bufferlimits_lock
,
70 cpacket_bufferusage
+= paramlen
+ resplen
;
72 if (trtg_unconn_l
->target
.unconnected
.in_buffer_wait_list
) {
73 trtg_unconn_l
->target
.unconnected
.in_buffer_wait_list
= 0;
74 list_del(&(trtg_unconn_l
->target
.unconnected
.buffer_wait_list
));
78 spin_unlock_irqrestore(&cpacket_bufferlimits_lock
, iflags
);
80 trtg_unconn_l
->target
.unconnected
.cmdparams
= kmalloc(paramlen
,
82 if (unlikely(trtg_unconn_l
->target
.unconnected
.cmdparams
== 0)) {
83 spin_lock_irqsave(&cpacket_bufferlimits_lock
, iflags
);
84 cpacket_kmallocfailed
= 1;
85 trtg_unconn_l
->target
.unconnected
.in_buffer_wait_list
= 1;
86 list_add(&(trtg_unconn_l
->target
.unconnected
.buffer_wait_list
),
87 &cpacket_bufferwaiting
);
88 if (cpacket_resume_running
== 0) {
89 schedule_work(&cpacket_resume_work
);
90 cpacket_resume_running
= 1;
93 kref_get(&(trtg_unconn_l
->ref
));
94 cpacket_bufferusage
-= paramlen
+ resplen
;
95 spin_unlock_irqrestore(&cpacket_bufferlimits_lock
, iflags
);
99 mutex_lock(&(trtg_unconn_l
->reversedir
->rcv_lock
));
100 trtg_unconn_l
->reversedir
->data_buf
.cpacket_buffer
+= resplen
;
101 mutex_unlock(&(trtg_unconn_l
->reversedir
->rcv_lock
));
104 kref_put(&(trtg_unconn_l
->ref
), free_conn
);
109 static void cpacket_buffer_resume(struct work_struct
*work
)
111 unsigned long iflags
;
114 spin_lock_irqsave(&cpacket_bufferlimits_lock
, iflags
);
116 cpacket_kmallocfailed
= 0;
118 for (i
=0;i
<100;i
++) {
119 struct conn
*trtg_unconn
;
121 if (list_empty(&cpacket_bufferwaiting
))
124 if (cpacket_kmallocfailed
)
127 trtg_unconn
= container_of(cpacket_bufferwaiting
.next
,
129 target
.unconnected
.buffer_wait_list
);
131 kref_get(&(trtg_unconn
->ref
));
133 spin_unlock_irqrestore(&cpacket_bufferlimits_lock
, iflags
);
135 mutex_lock(&(trtg_unconn
->rcv_lock
));
137 if (unlikely(trtg_unconn
->targettype
!= TARGET_UNCONNECTED
))
140 spin_lock_irqsave(&cpacket_bufferlimits_lock
, iflags
);
142 BUG_ON(trtg_unconn
->target
.unconnected
.in_buffer_wait_list
==
145 if (unlikely(atomic_read(&(trtg_unconn
->isreset
)) != 0)) {
146 trtg_unconn
->target
.unconnected
.in_buffer_wait_list
= 0;
147 list_del(&(trtg_unconn
->target
.unconnected
.buffer_wait_list
));
152 spin_unlock_irqrestore(&cpacket_bufferlimits_lock
, iflags
);
153 mutex_unlock(&(trtg_unconn
->rcv_lock
));
155 parse(trtg_unconn
, 1);
158 kref_put(&(trtg_unconn
->ref
), free_conn
);
159 spin_lock_irqsave(&cpacket_bufferlimits_lock
, iflags
);
162 schedule_work(&cpacket_resume_work
);
166 cpacket_resume_running
= 0;
169 spin_unlock_irqrestore(&cpacket_bufferlimits_lock
, iflags
);
172 void free_cpacket_buffer(__s32 amount
)
174 unsigned long iflags
;
175 spin_lock_irqsave(&cpacket_bufferlimits_lock
, iflags
);
176 BUG_ON(amount
> 0 && amount
> cpacket_bufferusage
);
177 cpacket_bufferusage
-= amount
;
179 if (amount
> 0 && list_empty(&cpacket_bufferwaiting
) == 0 &&
180 cpacket_resume_running
== 0) {
181 schedule_work(&cpacket_resume_work
);
182 cpacket_resume_running
= 1;
184 spin_unlock_irqrestore(&cpacket_bufferlimits_lock
, iflags
);
187 void connreset_cpacket_buffer(struct conn
*trtg_unconn_l
)
189 if (trtg_unconn_l
->target
.unconnected
.in_buffer_wait_list
) {
190 unsigned long iflags
;
191 spin_lock_irqsave(&cpacket_bufferlimits_lock
, iflags
);
192 trtg_unconn_l
->target
.unconnected
.in_buffer_wait_list
= 0;
193 list_del(&(trtg_unconn_l
->target
.unconnected
.buffer_wait_list
));
194 spin_unlock_irqrestore(&cpacket_bufferlimits_lock
, iflags
);
197 if (trtg_unconn_l
->target
.unconnected
.cmdparams
!= 0) {
198 BUG_ON(trtg_unconn_l
->target
.unconnected
.paramlen
<= 0);
199 kfree(trtg_unconn_l
->target
.unconnected
.cmdparams
);
200 trtg_unconn_l
->target
.unconnected
.cmdparams
= 0;
201 free_cpacket_buffer(trtg_unconn_l
->target
.unconnected
.paramlen
);
205 int encode_len(char *buf
, int buflen
, __u32 len
)
216 buf
[0] = (__u8
) ((len
- 128) /256 + 128);
217 buf
[1] = (__u8
) ((len
- 128) & 255);
221 if (len
< 1073741951) {
222 __u32 len_be
= cpu_to_be32(len
- 16511);
223 char *len_p
= (char *) &len_be
;
225 buf
[0] = len_p
[0] + 192;
235 int decode_len(char *buf
, int buflen
, __u32
*len
)
240 if ((__u8
) buf
[0] <= 127) {
241 *len
= (__u8
) buf
[0];
248 if ((__u8
) buf
[0] <= 191) {
249 *len
= 128 + ((__u32
) ((__u8
) buf
[0]) - 128) * 256 +
257 ((char *) len
)[0] = buf
[0] - 192;
258 ((char *) len
)[1] = buf
[1];
259 ((char *) len
)[2] = buf
[2];
260 ((char *) len
)[3] = buf
[3];
262 *len
= be32_to_cpu(*len
) + 16511;
266 static void send_resp_ok(struct conn
*trtg_unconn_l
)
268 __u8 respcode
= CDR_EXECOK
;
270 mutex_lock(&(trtg_unconn_l
->reversedir
->rcv_lock
));
271 receive_cpacketresp(trtg_unconn_l
->reversedir
, (char *) &respcode
, 1);
272 mutex_unlock(&(trtg_unconn_l
->reversedir
->rcv_lock
));
275 static char *get_error_reason_text(__u16 reasoncode
)
277 if (reasoncode
== CDR_EXECFAILED_UNKNOWN_COMMAND
)
278 return "Unknown command";
279 else if (reasoncode
== CDR_EXECFAILED_PERMISSION_DENIED
)
280 return "Permission denied";
281 else if (reasoncode
== CDR_EXECFAILED_TEMPORARILY_OUT_OF_RESSOURCES
)
282 return "Temporarily out of ressources";
283 else if (reasoncode
== CDR_EXECFAILED_CMD_TOO_SHORT
)
284 return "The length of the command is too short for all params";
285 else if (reasoncode
== CDR_EXECFAILED_CMD_TOO_LONG
)
286 return "command param is too long";
287 else if (reasoncode
== CDR_EXECFAILED_TARGETADDRTYPE_UNKNOWN
)
288 return "targettype unknown";
289 else if (reasoncode
== CDR_EXECFAILED_TARGETADDR_DOESNTEXIST
)
290 return "targetaddr does not exist";
291 else if (reasoncode
== CDR_EXECFAILED_TARGETADDR_PORTCLOSED
)
292 return "Port is on open";
293 else if (reasoncode
== CDR_EXECFAILED_LISTENERQUEUE_FULL
)
294 return "Listener queue full";
299 static void send_resp_failed(struct conn
*trtg_unconn_l
, __u16 reasoncode
)
307 hdr
[0] = CDR_EXECFAILED
;
309 reasoncode
= cpu_to_be16(reasoncode
);
310 hdr
[1] = ((char *) &reasoncode
)[0];
311 hdr
[2] = ((char *) &reasoncode
)[1];
313 reasontext
= get_error_reason_text(reasoncode
);
315 reasonlen
= strnlen(reasontext
, 1024);
316 reasonlen_len
= encode_len(hdr
+ 3, 4, reasonlen
);
317 BUG_ON(reasonlen_len
<= 0);
319 mutex_lock(&(trtg_unconn_l
->reversedir
->rcv_lock
));
320 receive_cpacketresp(trtg_unconn_l
->reversedir
, hdr
, 3 + reasonlen_len
);
321 receive_cpacketresp(trtg_unconn_l
->reversedir
, reasontext
, reasonlen
);
322 mutex_unlock(&(trtg_unconn_l
->reversedir
->rcv_lock
));
325 static void send_resp_bin(struct conn
*trtg_unconn_l
, char *buf
, __u32 len
)
330 hdr
[0] = CDR_BINDATA
;
331 len_len
= encode_len(hdr
+ 1, 4, len
);
333 BUG_ON(len_len
<= 0);
335 mutex_lock(&(trtg_unconn_l
->reversedir
->rcv_lock
));
336 receive_cpacketresp(trtg_unconn_l
->reversedir
, hdr
, len_len
+ 1);
337 receive_cpacketresp(trtg_unconn_l
->reversedir
, buf
, len
);
338 mutex_unlock(&(trtg_unconn_l
->reversedir
->rcv_lock
));
341 static void parse_set_tos(struct conn
*trtg_unconn_l
)
343 if (unlikely(trtg_unconn_l
->target
.unconnected
.paramlen
< 2)) {
344 send_resp_failed(trtg_unconn_l
, CDR_EXECFAILED_CMD_TOO_SHORT
);
349 (trtg_unconn_l
->target
.unconnected
.cmdparams
[0]) & 3;
350 trtg_unconn_l
->reversedir
->tos
=
351 (trtg_unconn_l
->target
.unconnected
.cmdparams
[1]) & 3;
354 static void parse_list_neigh(struct conn
*trtg_unconn_l
)
365 BUG_ON(read
> trtg_unconn_l
->target
.unconnected
.paramlen
);
366 rc
= decode_len(trtg_unconn_l
->target
.unconnected
.cmdparams
+ read
,
367 trtg_unconn_l
->target
.unconnected
.paramlen
- read
,
370 if (unlikely(rc
<= 0)) {
371 send_resp_failed(trtg_unconn_l
, CDR_EXECFAILED_CMD_TOO_SHORT
);
377 BUG_ON(read
> trtg_unconn_l
->target
.unconnected
.paramlen
);
378 rc
= decode_len(trtg_unconn_l
->target
.unconnected
.cmdparams
+ read
,
379 trtg_unconn_l
->target
.unconnected
.paramlen
- read
,
382 if (unlikely(rc
<= 0)) {
383 send_resp_failed(trtg_unconn_l
, CDR_EXECFAILED_CMD_TOO_SHORT
);
389 buf
= kmalloc(LISTNEIGH_RESP_MAXSIZE
, GFP_KERNEL
);
391 if (unlikely(buf
== 0)) {
392 send_resp_failed(trtg_unconn_l
,
393 CDR_EXECFAILED_TEMPORARILY_OUT_OF_RESSOURCES
);
397 send_resp_ok(trtg_unconn_l
);
399 len
= generate_neigh_list(buf
, 2048, limit
, offset
);
400 send_resp_bin(trtg_unconn_l
, buf
, len
);
403 static void parse_connect_port(struct conn
*trtg_unconn_l
)
408 if (unlikely(trtg_unconn_l
->target
.unconnected
.paramlen
< 8)) {
409 send_resp_failed(trtg_unconn_l
, CDR_EXECFAILED_CMD_TOO_SHORT
);
413 memcpy((char *) &addr
, trtg_unconn_l
->target
.unconnected
.cmdparams
, 8);
415 rc
= connect_port(trtg_unconn_l
, addr
);
418 send_resp_ok(trtg_unconn_l
);
419 } else if (rc
== 2) {
420 send_resp_failed(trtg_unconn_l
,
421 CDR_EXECFAILED_TARGETADDR_DOESNTEXIST
);
422 } else if (rc
== 3) {
423 send_resp_failed(trtg_unconn_l
,
424 CDR_EXECFAILED_LISTENERQUEUE_FULL
);
430 static void parse_connect_nb(struct conn
*trtg_unconn_l
)
440 BUG_ON(read
> trtg_unconn_l
->target
.unconnected
.paramlen
);
441 rc
= decode_len(trtg_unconn_l
->target
.unconnected
.cmdparams
+ read
,
442 trtg_unconn_l
->target
.unconnected
.paramlen
- read
,
445 if (unlikely(rc
<= 0)) {
446 send_resp_failed(trtg_unconn_l
, CDR_EXECFAILED_CMD_TOO_SHORT
);
452 BUG_ON(read
> trtg_unconn_l
->target
.unconnected
.paramlen
);
453 rc
= decode_len(trtg_unconn_l
->target
.unconnected
.cmdparams
+ read
,
454 trtg_unconn_l
->target
.unconnected
.paramlen
- read
,
457 if (unlikely(rc
<= 0)) {
458 send_resp_failed(trtg_unconn_l
, CDR_EXECFAILED_CMD_TOO_SHORT
);
464 if (unlikely(addrtypelen
> 65535 || addrtypelen
> 65535)) {
465 send_resp_failed(trtg_unconn_l
,
466 CDR_EXECFAILED_TARGETADDR_DOESNTEXIST
);
470 if (unlikely((read
+ addrtypelen
+ addrlen
) >
471 trtg_unconn_l
->target
.unconnected
.paramlen
)) {
472 send_resp_failed(trtg_unconn_l
, CDR_EXECFAILED_CMD_TOO_SHORT
);
476 addrtype
= trtg_unconn_l
->target
.unconnected
.cmdparams
+ read
;
477 addr
= addrtype
+ addrtypelen
;
479 rc
= connect_neigh(trtg_unconn_l
, (__u16
) addrtypelen
, addrtype
,
480 (__u16
) addrlen
, addr
);
483 send_resp_ok(trtg_unconn_l
);
484 } else if (rc
== 2) {
485 send_resp_failed(trtg_unconn_l
,
486 CDR_EXECFAILED_TARGETADDRTYPE_UNKNOWN
);
487 } else if (rc
== 3) {
488 send_resp_failed(trtg_unconn_l
,
489 CDR_EXECFAILED_TARGETADDR_DOESNTEXIST
);
490 } else if (rc
== 4) {
491 send_resp_failed(trtg_unconn_l
,
492 CDR_EXECFAILED_TEMPORARILY_OUT_OF_RESSOURCES
);
498 static void parse_cmd(struct conn
*trtg_unconn_l
)
500 __u16 code
= trtg_unconn_l
->target
.unconnected
.cmd
;
502 BUG_ON(trtg_unconn_l
->target
.unconnected
.cmdparams
== 0);
504 if (code
== CD_CONNECT_NB
) {
505 parse_connect_nb(trtg_unconn_l
);
506 } else if (code
== CD_CONNECT_PORT
) {
507 parse_connect_port(trtg_unconn_l
);
508 } else if (code
== CD_LIST_NEIGH
) {
509 parse_list_neigh(trtg_unconn_l
);
510 } else if (code
== CD_SET_TOS
) {
511 parse_set_tos(trtg_unconn_l
);
513 send_resp_failed(trtg_unconn_l
, CDR_EXECFAILED_UNKNOWN_COMMAND
);
517 static void read_cmd(struct conn
*trtg_unconn_l
)
521 pull
= min(trtg_unconn_l
->target
.unconnected
.paramlen
-
522 trtg_unconn_l
->target
.unconnected
.cmdread
,
523 trtg_unconn_l
->data_buf
.read_remaining
);
526 BUG_ON(trtg_unconn_l
->target
.unconnected
.cmdparams
== 0);
531 databuf_pull(trtg_unconn_l
,
532 trtg_unconn_l
->target
.unconnected
.cmdparams
+
533 trtg_unconn_l
->target
.unconnected
.cmdread
, pull
);
534 databuf_ackread(trtg_unconn_l
);
536 trtg_unconn_l
->target
.unconnected
.cmdread
+= pull
;
539 static void read_discard(struct conn
*trtg_unconn_l
)
541 BUG_ON(trtg_unconn_l
->target
.unconnected
.paramlen_read
== 0);
543 while (trtg_unconn_l
->target
.unconnected
.paramlen
<
544 trtg_unconn_l
->target
.unconnected
.cmdread
&&
545 trtg_unconn_l
->data_buf
.read_remaining
> 0) {
547 databuf_pull(trtg_unconn_l
, buf
, 1);
548 databuf_ackread(trtg_unconn_l
);
550 trtg_unconn_l
->target
.unconnected
.cmdread
++;
554 static void read_hdr(struct conn
*trtg_unconn_l
)
556 BUG_ON(trtg_unconn_l
->target
.unconnected
.cmdparams
!= 0);
558 while (trtg_unconn_l
->target
.unconnected
.paramlen_read
== 0 &&
559 trtg_unconn_l
->data_buf
.read_remaining
> 0) {
562 BUG_ON(trtg_unconn_l
->target
.unconnected
.cmdread
>= 6);
564 if (trtg_unconn_l
->target
.unconnected
.cmdread
< 2) {
566 databuf_pull(trtg_unconn_l
, buf
, 1);
567 trtg_unconn_l
->target
.unconnected
.cmd
<<= 8;
568 trtg_unconn_l
->target
.unconnected
.cmd
+= buf
[0];
569 trtg_unconn_l
->target
.unconnected
.cmdread
+= 1;
573 databuf_pull(trtg_unconn_l
,
574 trtg_unconn_l
->target
.unconnected
.paramlen_buf
+
575 trtg_unconn_l
->target
.unconnected
.cmdread
- 2,
577 trtg_unconn_l
->target
.unconnected
.cmdread
+= 1;
579 rc
= decode_len(trtg_unconn_l
->target
.unconnected
.paramlen_buf
,
580 trtg_unconn_l
->target
.unconnected
.cmdread
- 2,
581 &(trtg_unconn_l
->target
.unconnected
.paramlen
));
584 trtg_unconn_l
->target
.unconnected
.paramlen_read
= 1;
585 trtg_unconn_l
->target
.unconnected
.cmdread
= 0;
591 void parse(struct conn
*trtg_unconn
, int fromresume
)
594 mutex_lock(&(trtg_unconn
->rcv_lock
));
596 if (unlikely(atomic_read(&(trtg_unconn
->isreset
)) != 0))
599 if (unlikely(trtg_unconn
->targettype
!= TARGET_UNCONNECTED
))
602 BUG_ON(trtg_unconn
->data_buf
.cpacket_buffer
!= 0);
604 if (trtg_unconn
->target
.unconnected
.paramlen_read
== 0) {
605 read_hdr(trtg_unconn
);
606 if (trtg_unconn
->target
.unconnected
.paramlen_read
== 0)
609 if (trtg_unconn
->target
.unconnected
.paramlen
>
611 send_resp_failed(trtg_unconn
,
612 CDR_EXECFAILED_CMD_TOO_LONG
);
616 if (trtg_unconn
->target
.unconnected
.paramlen
> MAX_CONN_CMD_LEN
) {
617 read_discard(trtg_unconn
);
621 if (trtg_unconn
->target
.unconnected
.cmdparams
== 0) {
622 if (reserve_cpacket_buffer(trtg_unconn
, fromresume
))
626 if (trtg_unconn
->target
.unconnected
.paramlen
>
627 trtg_unconn
->target
.unconnected
.cmdread
) {
628 read_cmd(trtg_unconn
);
631 if (trtg_unconn
->target
.unconnected
.paramlen
==
632 trtg_unconn
->target
.unconnected
.cmdread
) {
633 char *cmd
= trtg_unconn
->target
.unconnected
.cmdparams
;
634 __s32 cpacket_buffer
;
635 __u32 paramlen
= trtg_unconn
->target
.unconnected
.paramlen
;
638 BUG_ON(trtg_unconn
->is_client
== 0);
639 mutex_lock(&(trtg_unconn
->reversedir
->rcv_lock
));
640 cpacket_buffer
= trtg_unconn
->reversedir
->data_buf
.cpacket_buffer
;
641 mutex_unlock(&(trtg_unconn
->reversedir
->rcv_lock
));
642 parse_cmd(trtg_unconn
);
644 mutex_lock(&(trtg_unconn
->reversedir
->rcv_lock
));
645 trtg_unconn
->reversedir
->data_buf
.cpacket_buffer
=
646 trtg_unconn
->reversedir
->data_buf
.totalsize
+
647 trtg_unconn
->reversedir
->data_buf
.overhead
;
648 cpacket_buffer
-= trtg_unconn
->reversedir
->data_buf
.cpacket_buffer
;
649 mutex_unlock(&(trtg_unconn
->reversedir
->rcv_lock
));
650 free_cpacket_buffer(paramlen
+ cpacket_buffer
);
652 if (trtg_unconn
->targettype
!= TARGET_UNCONNECTED
) {
655 trtg_unconn
->target
.unconnected
.cmdparams
= 0;
656 trtg_unconn
->target
.unconnected
.cmdread
= 0;
657 trtg_unconn
->target
.unconnected
.paramlen_read
= 0;
658 trtg_unconn
->target
.unconnected
.cmd
= 0;
659 trtg_unconn
->target
.unconnected
.paramlen
= 0;
662 mutex_unlock(&(trtg_unconn
->rcv_lock
));
664 flush_buf(trtg_unconn
);
665 flush_buf(trtg_unconn
->reversedir
);
672 mutex_unlock(&(trtg_unconn
->rcv_lock
));
675 int __init
cor_cpacket_init(void)
677 INIT_WORK(&cpacket_resume_work
, cpacket_buffer_resume
);
678 cpacket_resume_running
= 0;
679 cpacket_bufferusage
= 0;
680 cpacket_kmallocfailed
= 0;
684 MODULE_LICENSE("GPL");