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
24 static __u8
cor_flush_sock_managed_hdr(struct cor_conn
*trgt_sock_lx
,
27 __u32 hdr_rcvd
= trgt_sock_lx
->target
.sock
.rcvd
;
28 if (hdr_rcvd
< CONN_MNGD_HEADERLEN
) {
29 __u32 len
= CONN_MNGD_HEADERLEN
- hdr_rcvd
;
33 pulled
= cor_databuf_trypull(trgt_sock_lx
,
34 trgt_sock_lx
->target
.sock
.rcv_hdr
+ hdr_rcvd
,
37 if (pulled
> 0 && trgt_sock_lx
->sourcetype
== SOURCE_SOCK
)
38 cor_update_src_sock_sndspeed(trgt_sock_lx
, pulled
);
40 trgt_sock_lx
->target
.sock
.rcvd
+= pulled
;
45 return RCV_BUF_STATE_INCOMPLETE
;
47 BUG_ON(CONN_MNGD_HEADERLEN
!= 2);
49 hdr
= cor_parse_u16(&(trgt_sock_lx
->target
.sock
.rcv_hdr
[0]));
51 trgt_sock_lx
->target
.sock
.rcv_hdr_flags
= hdr
;
52 trgt_sock_lx
->target
.sock
.rcv_data_len
= 0;
54 if (likely((hdr
& CONN_MNGD_HASDATA
) != 0)) {
55 trgt_sock_lx
->target
.sock
.rcv_data_len
=
56 (hdr
& CONN_MNGD_DATALEN
) + 1;
58 if (unlikely((hdr
& CONN_MNGD_KEEPALIVE_REQ
) != 0))
59 trgt_sock_lx
->target
.sock
.rcv_data_len
+= 4;
61 if (unlikely((hdr
& CONN_MNGD_KEEPALIVE_RESP
) != 0))
62 trgt_sock_lx
->target
.sock
.rcv_data_len
+= 4;
66 return RCV_BUF_STATE_OK
;
69 static __u8
cor_flush_sock_managed_data(struct cor_conn
*trgt_sock_lx
,
72 __u32 data_rcvd
= trgt_sock_lx
->target
.sock
.rcvd
- CONN_MNGD_HEADERLEN
;
73 if (data_rcvd
< trgt_sock_lx
->target
.sock
.rcv_data_len
) {
74 __u32 len
= trgt_sock_lx
->target
.sock
.rcv_data_len
- data_rcvd
;
77 BUG_ON(trgt_sock_lx
->target
.sock
.rcv_buf
== 0);
79 pulled
= cor_databuf_trypull(trgt_sock_lx
,
80 trgt_sock_lx
->target
.sock
.rcv_buf
+ data_rcvd
,
83 if (pulled
> 0 && trgt_sock_lx
->sourcetype
== SOURCE_SOCK
)
84 cor_update_src_sock_sndspeed(trgt_sock_lx
, pulled
);
86 trgt_sock_lx
->target
.sock
.rcvd
+= pulled
;
91 return RCV_BUF_STATE_INCOMPLETE
;
94 return RCV_BUF_STATE_OK
;
97 static __u8
cor_flush_sock_managed_chksum(struct cor_conn
*trgt_sock_lx
,
100 __u32 checksum_rcvd
= trgt_sock_lx
->target
.sock
.rcvd
-
101 CONN_MNGD_HEADERLEN
-
102 trgt_sock_lx
->target
.sock
.rcv_data_len
;
103 if (checksum_rcvd
< CONN_MNGD_CHECKSUMLEN
) {
104 __u32 len
= CONN_MNGD_CHECKSUMLEN
- checksum_rcvd
;
106 char checksum_calc
[CONN_MNGD_CHECKSUMLEN
];
108 pulled
= cor_databuf_trypull(trgt_sock_lx
,
109 trgt_sock_lx
->target
.sock
.rcv_chksum
+
112 if (pulled
> 0 && trgt_sock_lx
->sourcetype
== SOURCE_SOCK
)
113 cor_update_src_sock_sndspeed(trgt_sock_lx
, pulled
);
115 trgt_sock_lx
->target
.sock
.rcvd
+= pulled
;
120 return RCV_BUF_STATE_INCOMPLETE
;
122 cor_mngdsocket_chksum(trgt_sock_lx
->target
.sock
.rcv_hdr
,
124 trgt_sock_lx
->target
.sock
.rcv_buf
,
125 trgt_sock_lx
->target
.sock
.rcv_data_len
,
126 checksum_calc
, CONN_MNGD_CHECKSUMLEN
);
128 if (unlikely(memcmp(trgt_sock_lx
->target
.sock
.rcv_chksum
,
129 checksum_calc
, CONN_MNGD_CHECKSUMLEN
) != 0)) {
131 __u16 hdr
= cor_parse_u16(
132 trgt_sock_lx
->target
.sock
.rcv_hdr
);
133 __u32 chk_calc
= cor_parse_u32(checksum_calc
);
134 __u32 chk
= cor_parse_u32(
135 trgt_sock_lx
->target
.sock
.rcv_chksum
);
136 printk(KERN_WARNING
"cor: user socket chksum mismatch hdr %u rcvlen %u chksum_calc %x chksum_rcvd %x\n",
138 trgt_sock_lx
->target
.sock
.rcv_data_len
,
141 return RCV_BUF_STATE_RESET
;
145 return RCV_BUF_STATE_OK
;
149 void cor_flush_sock_managed(struct cor_conn
*trgt_sock_lx
, int from_recvmsg
,
150 __u8
*do_wake_sender
)
152 struct cor_sock
*cs
= trgt_sock_lx
->target
.sock
.cs
;
157 if (trgt_sock_lx
->target
.sock
.rcv_buf_state
!= RCV_BUF_STATE_INCOMPLETE
)
160 rc
= cor_flush_sock_managed_hdr(trgt_sock_lx
, do_wake_sender
);
161 if (rc
!= RCV_BUF_STATE_OK
)
164 rc
= cor_flush_sock_managed_data(trgt_sock_lx
, do_wake_sender
);
165 if (rc
!= RCV_BUF_STATE_OK
)
168 rc
= cor_flush_sock_managed_chksum(trgt_sock_lx
, do_wake_sender
);
170 BUG_ON(trgt_sock_lx
->target
.sock
.rcvd
>
171 CONN_MNGD_HEADERLEN
+
172 trgt_sock_lx
->target
.sock
.rcv_data_len
+
173 CONN_MNGD_CHECKSUMLEN
);
175 cor_databuf_ackread(trgt_sock_lx
);
176 cor_bufsize_read_to_sock(trgt_sock_lx
);
178 trgt_sock_lx
->target
.sock
.rcv_buf_state
= rc
;
181 if (rc
== RCV_BUF_STATE_INCOMPLETE
) {
182 atomic_set(&(cs
->ready_to_read
), 0);
185 /* This does not work because on the next call
186 * rcv_buf_state == RCV_BUF_STATE_OK and we do not get this far
188 /*if (trgt_sock_lx->is_highlatency != 0 &&
189 trgt_sock_lx->flush == 0 &&
190 trgt_sock_lx->data_buf.read_remaining < 4096 &&
191 trgt_sock_lx->sourcetype == SOURCE_SOCK &&
192 cor_sock_sndbufavailable(trgt_sock_lx) != 0)
195 if (trgt_sock_lx->is_highlatency != 0 &&
196 trgt_sock_lx->flush == 0 &&
197 trgt_sock_lx->data_buf.read_remaining < 4096 &&
198 trgt_sock_lx->sourcetype == SOURCE_IN &&
199 cor_srcin_buflimit_reached(trgt_sock_lx) == 0)
202 if (likely(rc
== RCV_BUF_STATE_OK
&&
203 (trgt_sock_lx
->target
.sock
.rcv_hdr_flags
&
204 CONN_MNGD_HASDATA
) != 0 &&
205 trgt_sock_lx
->target
.sock
.rcv_data_len
> 0)) {
206 cor_sk_data_ready(cs
);
208 cor_mngdsocket_readfromconn_fromatomic(cs
);
213 void cor_flush_sock(struct cor_conn
*trgt_sock_lx
)
215 struct cor_sock
*cs
= trgt_sock_lx
->target
.sock
.cs
;
217 if (unlikely(cs
== 0))
220 if (unlikely(trgt_sock_lx
->data_buf
.read_remaining
== 0))
223 if (trgt_sock_lx
->target
.sock
.waiting_for_userspace
== 0) {
224 trgt_sock_lx
->target
.sock
.waiting_for_userspace
= 1;
225 trgt_sock_lx
->target
.sock
.waiting_for_userspace_since
= jiffies
;
228 if (trgt_sock_lx
->target
.sock
.socktype
== SOCKTYPE_RAW
) {
229 cor_sk_data_ready(cs
);
230 } else if (trgt_sock_lx
->target
.sock
.socktype
== SOCKTYPE_MANAGED
) {
231 __u8 do_wake_sender
= 0;
232 cor_flush_sock_managed(trgt_sock_lx
, 0, &do_wake_sender
);
238 MODULE_LICENSE("GPL");