-
Notifications
You must be signed in to change notification settings - Fork 2
/
lwipr_compat.c
370 lines (315 loc) · 9.42 KB
/
lwipr_compat.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
/*
* Compatibility for AxTLS with LWIP raw tcp mode (http://lwip.wikia.com/wiki/Raw/TCP)
*
* Created on: Jan 15, 2016
* Author: Slavey Karadzhov
*/
#include "lwipr_compat.h"
AxlTcpDataArray axlFdArray;
#include <stdlib.h>
/* High Level "public" functions */
/**
* Function that should be called once we are ready to use the axTLS - LWIP raw compatibility
* @param int capacity - the desired capacity
* @return int - the actual capacity
* - 0 - not enough memory
* > 0 && capacity != actual capacity - the axl_init was already called and this is the current capacity
*/
int axl_init(int capacity) {
if(axlFdArray.capacity > 0 && axlFdArray.data != NULL) {
// we are already initialized.
return axlFdArray.capacity;
}
return ax_fd_init(&axlFdArray, capacity);
}
/**
* Appends a tcp to the internal array. Returns client file descriptor
*/
int axl_append(struct tcp_pcb *tcp) {
return ax_fd_append(&axlFdArray, tcp);
}
/**
* Frees the internal mapping from this tcp. Returns the number of occurrences of the tcp
*/
int axl_free(struct tcp_pcb *tcp) {
int i;
int occurances = 0;
if(tcp == NULL) {
return 0;
}
AxlTcpDataArray *vector = &axlFdArray;
AXL_DEBUG_PRINT("axl_free: Freeing %d tcp item", vector->size);
for (i = 0; i < vector->size; i++) {
if (vector->data[i].tcp == tcp) {
if(vector->data[i].tcp_pbuf != NULL) {
// Don't free tcp_pbuf here. It should be freed manually outside of this code.
vector->data[i].tcp_pbuf = NULL;
}
vector->data[i].tcp = NULL;
vector->data[i].pbuf_offset = 0;
occurances++;
}
}
return occurances;
}
/**
* Frees completely the FD mapping.
*/
void axl_destroy()
{
if(axlFdArray.data != NULL) {
free(axlFdArray.data);
}
axlFdArray.size = 0;
axlFdArray.capacity = 0;
}
/**
* Reads data from the SSL over TCP stream. Returns decrypted data.
* @param SSL *sslObj
* @param uint8_t **in_data - pointer to the decrypted incoming data, or NULL if nothing was read
* @param void *arg - possible arguments passed to the tcp raw layer during initialization
* @param tcp_pcb *tcp - pointer to the raw tcp object
* @param pbuf *pin - pointer to the buffer with the encrypted TCP packet data
* - the freeing of the pbuf should be done separately
* - the confirmation for the received bytes should be done separately
* @param pbuf **pout - pointer to the buffer with the decrypted TCP packet data
* - the freeing of the pbuf should be done separately
*
* @return int
* 0 - when everything is fine but there are no symbols to process yet
* < 0 - when there is an error
* > 0 - the length of the clear text characters that were read
*/
int axl_ssl_read(SSL *ssl, struct tcp_pcb *tcp, struct pbuf *pin, struct pbuf **pout) {
int read_bytes = 0;
int total_bytes = 0;
int clientfd = -1;
uint8_t *read_buffer = NULL;
uint8_t *total_read_buffer = NULL;
AxlTcpData* data = NULL;
if (ssl == NULL) {
AXL_DEBUG_PRINT("axl_ssl_read: SSL is null\n");
return ERR_AXL_INVALID_SSL;
}
if(pin == NULL) {
AXL_DEBUG_PRINT("axl_ssl_read: PBUF is null\n");
return ERR_AXL_INVALID_PBUF;
}
if(pin->tot_len == 0) {
// nothing to read
return 0;
}
clientfd = ax_fd_getfd(&axlFdArray, tcp);
if(clientfd == -1) {
AXL_DEBUG_PRINT("axl_ssl_read: ClientFD not found\n");
return ERR_AXL_INVALID_CLIENTFD;
}
data = ax_fd_get(&axlFdArray, clientfd);
if(data == NULL) {
AXL_DEBUG_PRINT("axl_ssl_read: ClientFD data not found\n");
return ERR_AXL_INVALID_CLIENTFD_DATA;
}
data->tcp_pbuf = pin;
data->pbuf_offset = 0;
do {
WATCHDOG_RESET();
read_bytes = ssl_read(ssl, &read_buffer);
AXL_DEBUG_PRINT("axl_ssl_read: Read bytes: %d\n", read_bytes);
if(read_bytes < SSL_OK) {
/* An error has occurred. Give it back for further processing */
if(total_bytes == 0) {
// Nothing is read so far -> give back the error
total_bytes = read_bytes;
}
else {
// We already have read some data -> deliver it back
// and silence the error for now..
AXL_DEBUG_PRINT("axl_ssl_read: Silently ignoring SSL error %d\n", read_bytes);
}
break;
}
else if (read_bytes > 0 ){
if(total_read_buffer == NULL) {
total_read_buffer = (uint8_t *)malloc(read_bytes);
}
else {
AXL_DEBUG_PRINT("axl_ssl_read: Got more than one SSL packet inside one TCP packet\n");
uint8_t* new_buffer = (uint8_t *)realloc(total_read_buffer, total_bytes + read_bytes);
if(new_buffer == NULL) {
free(total_read_buffer);
total_read_buffer = NULL;
} else {
total_read_buffer = new_buffer;
}
}
if(total_read_buffer == NULL) {
AXL_DEBUG_PRINT("axl_ssl_read: Unable to allocate additional %d bytes", read_bytes);
total_bytes = -1;
break;
// while(1) {}
}
memcpy(total_read_buffer + total_bytes, read_buffer, read_bytes);
}
total_bytes+= read_bytes;
} while (pin->tot_len - data->pbuf_offset > 0);
if(total_bytes > 0) {
// put the decrypted data in a brand new pbuf
*pout = pbuf_alloc(PBUF_TRANSPORT, total_bytes, PBUF_RAM);
if(*pout != NULL) {
memcpy((*pout)->payload, total_read_buffer, total_bytes);
}
else {
AXL_DEBUG_PRINT("Unable to allocate pbuf memory. Required %d. Check MEM_SIZE in your lwipopts.h file and increase if needed.", total_bytes);
total_bytes = -1;
}
free(total_read_buffer);
}
return total_bytes;
}
/*
* Lower Level LWIP RAW functions
*/
/*
* The LWIP tcp raw version of the SOCKET_WRITE(A, B, C)
*/
int ax_port_write(int clientfd, uint8_t *buf, uint16_t bytes_needed) {
AxlTcpData *data = NULL;
int tcp_len = 0;
err_t err = ERR_OK;
data = ax_fd_get(&axlFdArray, clientfd);
if(data == NULL) {
AXL_DEBUG_PRINT("ax_port_write: Invalid ClientFD.\n");
return ERR_AXL_INVALID_CLIENTFD;
}
if (data == NULL || data->tcp == NULL || buf == NULL || bytes_needed == 0) {
AXL_DEBUG_PRINT("ax_port_write: Return Zero.\n");
return 0;
}
if (tcp_sndbuf(data->tcp) < bytes_needed) {
tcp_len = tcp_sndbuf(data->tcp);
if(tcp_len == 0) {
err = tcp_output(data->tcp);
AXL_DEBUG_PRINT("ax_port_write: The send buffer is full! We have problem.\n");
return 0;
}
} else {
tcp_len = bytes_needed;
}
if (tcp_len > 2 * data->tcp->mss) {
tcp_len = 2 * data->tcp->mss;
}
do {
err = tcp_write(data->tcp, buf, tcp_len, TCP_WRITE_FLAG_COPY);
if(err < SSL_OK) {
AXL_DEBUG_PRINT("ax_port_write: Got error: %d\n", err);
}
if (err == ERR_MEM) {
AXL_DEBUG_PRINT("ax_port_write: Not enough memory to write data with length: %d (%d)\n", tcp_len, bytes_needed);
tcp_len /= 2;
}
} while (err == ERR_MEM && tcp_len > 1);
AXL_DEBUG_PRINT("ax_port_write: send_raw_packet length %d(%d)\n", tcp_len, bytes_needed);
if (err == ERR_OK) {
err = tcp_output(data->tcp);
if(err != ERR_OK) {
AXL_DEBUG_PRINT("ax_port_write: tcp_output got err: %d\n", err);
}
}
return tcp_len;
}
/*
* The LWIP tcp raw version of the SOCKET_READ(A, B, C)
*/
int ax_port_read(int clientfd, uint8_t *buf, int bytes_needed) {
AxlTcpData *data = NULL;
uint8_t *read_buf = NULL;
uint8_t *pread_buf = NULL;
u16_t recv_len = 0;
data = ax_fd_get(&axlFdArray, clientfd);
if (data == NULL) {
return ERR_AXL_INVALID_CLIENTFD_DATA;
}
if(data->tcp_pbuf == NULL || data->tcp_pbuf->tot_len == 0) {
AXL_DEBUG_PRINT("ax_port_read: Nothing to read?! May be the connection needs resetting?\n");
return 0;
}
read_buf =(uint8_t*)calloc(data->tcp_pbuf->len + 1, sizeof(uint8_t));
pread_buf = read_buf;
if (pread_buf != NULL){
recv_len = pbuf_copy_partial(data->tcp_pbuf, read_buf, bytes_needed, data->pbuf_offset);
data->pbuf_offset += recv_len;
}
if (recv_len != 0) {
memcpy(buf, read_buf, recv_len);
}
if(bytes_needed < recv_len) {
AXL_DEBUG_PRINT("ax_port_read: Bytes needed: %d, Bytes read: %d\n", bytes_needed, recv_len);
}
free(pread_buf);
pread_buf = NULL;
return recv_len;
}
int ax_get_file(const char *filename, uint8_t **buf) {
*buf = 0;
return 0;
}
/*
* Utility functions
*
* @param AxlTcpDataArray the tcp data vector
* @param int capacity - the desired capacity.
* @return int - the actual capacity
*/
int ax_fd_init(AxlTcpDataArray *vector, int capacity) {
vector->size = 0;
vector->capacity = capacity;
vector->data = (AxlTcpData*) malloc(sizeof(AxlTcpData) * vector->capacity);
if(vector->data == NULL) {
return 0;
}
return capacity;
}
int ax_fd_append(AxlTcpDataArray *vector, struct tcp_pcb *tcp) {
int index;
ax_fd_double_capacity_if_full(vector);
index = vector->size++;
vector->data[index].tcp = tcp;
vector->data[index].tcp_pbuf = NULL;
vector->data[index].pbuf_offset = 0;
return index;
}
AxlTcpData* ax_fd_get(AxlTcpDataArray *vector, int index) {
if (index >= vector->size || index < 0) {
AXL_DEBUG_PRINT("ax_fd_get: Index %d out of bounds for vector of size %d\n", index, vector->size);
return NULL;
}
return &(vector->data[index]);
}
int ax_fd_getfd(AxlTcpDataArray *vector, struct tcp_pcb *tcp) {
int i;
for (i = 0; i < vector->size; i++) {
if (vector->data[i].tcp == tcp) {
return i;
}
}
return -1;
}
void ax_fd_set(AxlTcpDataArray *vector, int index, struct tcp_pcb *tcp) {
AxlTcpData value;
while (index >= vector->size) {
ax_fd_append(vector, 0);
}
value.tcp = tcp;
value.tcp_pbuf = NULL;
value.pbuf_offset = 0;
vector->data[index] = value;
}
void ax_fd_double_capacity_if_full(AxlTcpDataArray *vector) {
if (vector->size >= vector->capacity) {
vector->capacity *= 2;
vector->data = (AxlTcpData*)realloc(vector->data, sizeof(AxlTcpData) * vector->capacity);
}
}
void ax_fd_free(AxlTcpDataArray *vector) {
free(vector->data);
}