blob: 07e3b9cb9377357a107cc36f16b27513b1f3f6c5 [file] [log] [blame]
James Kuszmaul871d0712021-01-17 11:30:43 -08001
2#include <re_types.h>
3#include <re_fmt.h>
4#include <re_mem.h>
5#include <re_mbuf.h>
6#include <re_tcp.h>
7#include <re_net.h>
8#include <re_shim.h>
9
10
11#define DEBUG_MODULE "shim"
12#define DEBUG_LEVEL 5
13#include <re_dbg.h>
14
15
16struct shim {
17 struct tcp_conn *tc;
18 struct tcp_helper *th;
19 struct mbuf *mb;
20 shim_frame_h *frameh;
21 void *arg;
22
23 uint64_t n_tx;
24 uint64_t n_rx;
25};
26
27
28/* responsible for adding the SHIM header
29 - assumes that the sent MBUF contains a complete packet
30 */
31static bool shim_send_handler(int *err, struct mbuf *mb, void *arg)
32{
33 struct shim *shim = arg;
34 size_t len;
35 (void)shim;
36
37 if (mb->pos < SHIM_HDR_SIZE) {
38 DEBUG_WARNING("send: not enough space for SHIM header\n");
39 *err = ENOMEM;
40 return true;
41 }
42
43 len = mbuf_get_left(mb);
44
45 mb->pos -= SHIM_HDR_SIZE;
46 *err = mbuf_write_u16(mb, htons(len));
47 mb->pos -= SHIM_HDR_SIZE;
48
49 ++shim->n_tx;
50
51 return false;
52}
53
54
55static bool shim_recv_handler(int *errp, struct mbuf *mbx, bool *estab,
56 void *arg)
57{
58 struct shim *shim = arg;
59 int err = 0;
60 (void)estab;
61
62 /* handle re-assembly */
63 if (!shim->mb) {
64 shim->mb = mbuf_alloc(1024);
65 if (!shim->mb) {
66 *errp = ENOMEM;
67 return true;
68 }
69 }
70
71 if (shim->mb) {
72 size_t pos;
73
74 pos = shim->mb->pos;
75
76 shim->mb->pos = shim->mb->end;
77
78 err = mbuf_write_mem(shim->mb, mbuf_buf(mbx),
79 mbuf_get_left(mbx));
80 if (err)
81 goto out;
82
83 shim->mb->pos = pos;
84 }
85
86 /* extract all SHIM-frames in the TCP-stream */
87 for (;;) {
88
89 size_t start, len, pos, end;
90 bool hdld;
91
92 start = shim->mb->pos;
93
94 if (mbuf_get_left(shim->mb) < (SHIM_HDR_SIZE))
95 break;
96
97 len = ntohs(mbuf_read_u16(shim->mb));
98
99 if (mbuf_get_left(shim->mb) < len)
100 goto rewind;
101
102 pos = shim->mb->pos;
103 end = shim->mb->end;
104
105 shim->mb->end = pos + len;
106
107 ++shim->n_rx;
108
109 hdld = shim->frameh(shim->mb, shim->arg);
110 if (!hdld) {
111 /* XXX: handle multiple frames per segment */
112
113 shim->mb->pos = pos;
114 shim->mb->end = pos + len;
115
116 mbx->pos = mbx->end = 2;
117 err = mbuf_write_mem(mbx, mbuf_buf(shim->mb), len);
118 if (err)
119 goto out;
120 mbx->pos = 2;
121
122 shim->mb->pos = pos + len;
123 shim->mb->end = end;
124
125 return false; /* continue recv-handlers */
126 }
127
128 shim->mb->pos = pos + len;
129 shim->mb->end = end;
130
131 if (shim->mb->pos >= shim->mb->end) {
132 shim->mb = mem_deref(shim->mb);
133 break;
134 }
135
136 continue;
137
138 rewind:
139 shim->mb->pos = start;
140 break;
141 }
142
143 out:
144 if (err)
145 *errp = err;
146
147 return true; /* always handled */
148}
149
150
151static void destructor(void *arg)
152{
153 struct shim *shim = arg;
154
155 mem_deref(shim->th);
156 mem_deref(shim->tc);
157 mem_deref(shim->mb);
158}
159
160
161int shim_insert(struct shim **shimp, struct tcp_conn *tc, int layer,
162 shim_frame_h *frameh, void *arg)
163{
164 struct shim *shim;
165 int err;
166
167 if (!shimp || !tc || !frameh)
168 return EINVAL;
169
170 shim = mem_zalloc(sizeof(*shim), destructor);
171 if (!shim)
172 return ENOMEM;
173
174 shim->tc = mem_ref(tc);
175 err = tcp_register_helper(&shim->th, tc, layer, NULL,
176 shim_send_handler,
177 shim_recv_handler, shim);
178 if (err)
179 goto out;
180
181 shim->frameh = frameh;
182 shim->arg = arg;
183
184 out:
185 if (err)
186 mem_deref(shim);
187 else
188 *shimp = shim;
189
190 return err;
191}
192
193
194int shim_debug(struct re_printf *pf, const struct shim *shim)
195{
196 if (!shim)
197 return 0;
198
199 return re_hprintf(pf, "tx=%llu, rx=%llu", shim->n_tx, shim->n_rx);
200}