1 /*
2 * TCP/IP or UDP/IP networking functions
3 * modified for LWIP support on ESP32
4 *
5 * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
6 * Additions Copyright (C) 2015 Angus Gratton
7 * SPDX-License-Identifier: Apache-2.0
8 *
9 * Licensed under the Apache License, Version 2.0 (the "License"); you may
10 * not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
17 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 *
21 * This file is part of mbed TLS (https://tls.mbed.org)
22 */
23
24 #if !defined(MBEDTLS_CONFIG_FILE)
25 #include "mbedtls/config.h"
26 #else
27 #include MBEDTLS_CONFIG_FILE
28 #endif
29
30 #ifdef CONFIG_ESP_NETIF_TCPIP_LWIP
31
32 #if !defined(MBEDTLS_NET_C)
33
34 #if defined(MBEDTLS_PLATFORM_C)
35 #include "mbedtls/platform.h"
36 #else
37 #include <stdlib.h>
38 #define mbedtls_calloc calloc
39 #define mbedtls_free free
40 #define mbedtls_time time
41 #define mbedtls_time_t time_t
42 #endif
43
44 #include "mbedtls/net_sockets.h"
45
46 #include <string.h>
47 #include <sys/types.h>
48 #include <sys/socket.h>
49 #include <unistd.h>
50 #include <netdb.h>
51 #include <stdlib.h>
52 #include <stdio.h>
53 #include <time.h>
54 #include <stdint.h>
55
56 /*
57 * Prepare for using the sockets interface
58 */
net_prepare(void)59 static int net_prepare( void )
60 {
61 return ( 0 );
62 }
63
64 /*
65 * Initialize a context
66 */
mbedtls_net_init(mbedtls_net_context * ctx)67 void mbedtls_net_init( mbedtls_net_context *ctx )
68 {
69 ctx->fd = -1;
70 }
71
72 /*
73 * Initiate a TCP connection with host:port and the given protocol
74 */
mbedtls_net_connect(mbedtls_net_context * ctx,const char * host,const char * port,int proto)75 int mbedtls_net_connect( mbedtls_net_context *ctx, const char *host, const char *port, int proto )
76 {
77 int ret;
78 struct addrinfo hints, *addr_list, *cur;
79
80 if ( ( ret = net_prepare() ) != 0 ) {
81 return ( ret );
82 }
83
84 /* Do name resolution with both IPv6 and IPv4 */
85 memset( &hints, 0, sizeof( hints ) );
86 hints.ai_family = AF_UNSPEC;
87 hints.ai_socktype = proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM;
88 hints.ai_protocol = proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP;
89
90 if ( getaddrinfo( host, port, &hints, &addr_list ) != 0 ) {
91 return ( MBEDTLS_ERR_NET_UNKNOWN_HOST );
92 }
93
94 /* Try the sockaddrs until a connection succeeds */
95 ret = MBEDTLS_ERR_NET_UNKNOWN_HOST;
96 for ( cur = addr_list; cur != NULL; cur = cur->ai_next ) {
97 int fd = socket( cur->ai_family, cur->ai_socktype, cur->ai_protocol );
98
99 if ( fd < 0 ) {
100 ret = MBEDTLS_ERR_NET_SOCKET_FAILED;
101 continue;
102 }
103
104 if ( connect( fd, cur->ai_addr, cur->ai_addrlen ) == 0 ) {
105 ctx->fd = fd; // connected!
106 ret = 0;
107 break;
108 }
109
110 close( fd );
111 ret = MBEDTLS_ERR_NET_CONNECT_FAILED;
112 }
113
114 freeaddrinfo( addr_list );
115
116 return ( ret );
117 }
118
119 /*
120 * Create a listening socket on bind_ip:port
121 */
mbedtls_net_bind(mbedtls_net_context * ctx,const char * bind_ip,const char * port,int proto)122 int mbedtls_net_bind( mbedtls_net_context *ctx, const char *bind_ip, const char *port, int proto )
123 {
124 int ret;
125 struct addrinfo hints, *addr_list, *cur;
126 struct sockaddr_in *serv_addr = NULL;
127 #if SO_REUSE
128 int n = 1;
129 #endif
130
131 if ( ( ret = net_prepare() ) != 0 ) {
132 return ( ret );
133 }
134
135 /* Bind to IPv6 and/or IPv4, but only in the desired protocol */
136 memset( &hints, 0, sizeof( hints ) );
137 hints.ai_family = AF_UNSPEC;
138 hints.ai_socktype = proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM;
139 hints.ai_protocol = proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP;
140
141 if ( getaddrinfo( bind_ip, port, &hints, &addr_list ) != 0 ) {
142 return ( MBEDTLS_ERR_NET_UNKNOWN_HOST );
143 }
144
145 /* Try the sockaddrs until a binding succeeds */
146 ret = MBEDTLS_ERR_NET_UNKNOWN_HOST;
147 for ( cur = addr_list; cur != NULL; cur = cur->ai_next ) {
148 int fd = socket( cur->ai_family, cur->ai_socktype, cur->ai_protocol );
149 if ( fd < 0 ) {
150 ret = MBEDTLS_ERR_NET_SOCKET_FAILED;
151 continue;
152 }
153
154 /*SO_REUSEADDR option dafault is disable in source code(lwip)*/
155 #if SO_REUSE
156 if ( setsockopt( fd, SOL_SOCKET, SO_REUSEADDR,
157 (const char *) &n, sizeof( n ) ) != 0 ) {
158 close( fd );
159 ret = MBEDTLS_ERR_NET_SOCKET_FAILED;
160 continue;
161 }
162 #endif
163 /*bind interface dafault don't process the addr is 0xffffffff for TCP Protocol*/
164 serv_addr = (struct sockaddr_in *)cur->ai_addr;
165 serv_addr->sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */
166 if ( bind( fd, (struct sockaddr *)serv_addr, cur->ai_addrlen ) != 0 ) {
167 close( fd );
168 ret = MBEDTLS_ERR_NET_BIND_FAILED;
169 continue;
170 }
171
172 /* Listen only makes sense for TCP */
173 if ( proto == MBEDTLS_NET_PROTO_TCP ) {
174 if ( listen( fd, MBEDTLS_NET_LISTEN_BACKLOG ) != 0 ) {
175 close( fd );
176 ret = MBEDTLS_ERR_NET_LISTEN_FAILED;
177 continue;
178 }
179 }
180
181 /* I we ever get there, it's a success */
182 ctx->fd = fd;
183 ret = 0;
184 break;
185 }
186
187 freeaddrinfo( addr_list );
188
189 return ( ret );
190
191 }
192
193 /*
194 * Check if the requested operation would be blocking on a non-blocking socket
195 * and thus 'failed' with a negative return value.
196 *
197 * Note: on a blocking socket this function always returns 0!
198 */
net_would_block(const mbedtls_net_context * ctx)199 static int net_would_block( const mbedtls_net_context *ctx )
200 {
201 int error = errno;
202
203 switch ( errno = error ) {
204 #if defined EAGAIN
205 case EAGAIN:
206 #endif
207 #if defined EWOULDBLOCK && EWOULDBLOCK != EAGAIN
208 case EWOULDBLOCK:
209 #endif
210 return ( 1 );
211 }
212 return ( 0 );
213 }
214
215 /*
216 * Accept a connection from a remote client
217 */
mbedtls_net_accept(mbedtls_net_context * bind_ctx,mbedtls_net_context * client_ctx,void * client_ip,size_t buf_size,size_t * ip_len)218 int mbedtls_net_accept( mbedtls_net_context *bind_ctx,
219 mbedtls_net_context *client_ctx,
220 void *client_ip, size_t buf_size, size_t *ip_len )
221 {
222 int ret;
223 int type;
224
225 struct sockaddr_in client_addr;
226
227 socklen_t n = (socklen_t) sizeof( client_addr );
228 socklen_t type_len = (socklen_t) sizeof( type );
229
230 /* Is this a TCP or UDP socket? */
231 if ( getsockopt( bind_ctx->fd, SOL_SOCKET, SO_TYPE,
232 (void *) &type, (socklen_t *) &type_len ) != 0 ||
233 ( type != SOCK_STREAM && type != SOCK_DGRAM ) ) {
234 return ( MBEDTLS_ERR_NET_ACCEPT_FAILED );
235 }
236
237 if ( type == SOCK_STREAM ) {
238 /* TCP: actual accept() */
239 ret = client_ctx->fd = (int) accept( bind_ctx->fd,
240 (struct sockaddr *) &client_addr, &n );
241 } else {
242 /* UDP: wait for a message, but keep it in the queue */
243 char buf[1] = { 0 };
244
245 ret = recvfrom( bind_ctx->fd, buf, sizeof( buf ), MSG_PEEK,
246 (struct sockaddr *) &client_addr, &n );
247
248 }
249
250 if ( ret < 0 ) {
251 if ( net_would_block( bind_ctx ) != 0 ) {
252 return ( MBEDTLS_ERR_SSL_WANT_READ );
253 }
254
255 return ( MBEDTLS_ERR_NET_ACCEPT_FAILED );
256 }
257
258 /* UDP: hijack the listening socket to communicate with the client,
259 * then bind a new socket to accept new connections */
260 if ( type != SOCK_STREAM ) {
261 struct sockaddr_in local_addr;
262 int one = 1;
263
264 if ( connect( bind_ctx->fd, (struct sockaddr *) &client_addr, n ) != 0 ) {
265 return ( MBEDTLS_ERR_NET_ACCEPT_FAILED );
266 }
267
268 client_ctx->fd = bind_ctx->fd;
269 bind_ctx->fd = -1; /* In case we exit early */
270
271 n = sizeof( struct sockaddr_in );
272 if ( getsockname( client_ctx->fd,
273 (struct sockaddr *) &local_addr, &n ) != 0 ||
274 ( bind_ctx->fd = (int) socket( AF_INET,
275 SOCK_DGRAM, IPPROTO_UDP ) ) < 0 ||
276 setsockopt( bind_ctx->fd, SOL_SOCKET, SO_REUSEADDR,
277 (const char *) &one, sizeof( one ) ) != 0 ) {
278 return ( MBEDTLS_ERR_NET_SOCKET_FAILED );
279 }
280
281 if ( bind( bind_ctx->fd, (struct sockaddr *) &local_addr, n ) != 0 ) {
282 return ( MBEDTLS_ERR_NET_BIND_FAILED );
283 }
284 }
285
286 if ( client_ip != NULL ) {
287 struct sockaddr_in *addr4 = (struct sockaddr_in *) &client_addr;
288 *ip_len = sizeof( addr4->sin_addr.s_addr );
289
290 if ( buf_size < *ip_len ) {
291 return ( MBEDTLS_ERR_NET_BUFFER_TOO_SMALL );
292 }
293
294 memcpy( client_ip, &addr4->sin_addr.s_addr, *ip_len );
295 }
296
297 return ( 0 );
298 }
299
300 /*
301 * Set the socket blocking or non-blocking
302 */
mbedtls_net_set_block(mbedtls_net_context * ctx)303 int mbedtls_net_set_block( mbedtls_net_context *ctx )
304 {
305 return ( fcntl( ctx->fd, F_SETFL, fcntl( ctx->fd, F_GETFL, 0 ) & ~O_NONBLOCK ) );
306 }
307
mbedtls_net_set_nonblock(mbedtls_net_context * ctx)308 int mbedtls_net_set_nonblock( mbedtls_net_context *ctx )
309 {
310 return ( fcntl( ctx->fd, F_SETFL, fcntl( ctx->fd, F_GETFL, 0 ) | O_NONBLOCK ) );
311 }
312
313 /*
314 * Portable usleep helper
315 */
mbedtls_net_usleep(unsigned long usec)316 void mbedtls_net_usleep( unsigned long usec )
317 {
318 struct timeval tv;
319 tv.tv_sec = usec / 1000000;
320 tv.tv_usec = usec % 1000000;
321 select( 0, NULL, NULL, NULL, &tv );
322 }
323
324 /*
325 * Read at most 'len' characters
326 */
mbedtls_net_recv(void * ctx,unsigned char * buf,size_t len)327 int mbedtls_net_recv( void *ctx, unsigned char *buf, size_t len )
328 {
329 int ret;
330 int fd = ((mbedtls_net_context *) ctx)->fd;
331
332 if ( fd < 0 ) {
333 return ( MBEDTLS_ERR_NET_INVALID_CONTEXT );
334 }
335
336 ret = (int) read( fd, buf, len );
337
338 if ( ret < 0 ) {
339 if ( net_would_block( ctx ) != 0 ) {
340 return ( MBEDTLS_ERR_SSL_WANT_READ );
341 }
342
343 if ( errno == EPIPE || errno == ECONNRESET ) {
344 return ( MBEDTLS_ERR_NET_CONN_RESET );
345 }
346
347 if ( errno == EINTR ) {
348 return ( MBEDTLS_ERR_SSL_WANT_READ );
349 }
350
351 return ( MBEDTLS_ERR_NET_RECV_FAILED );
352 }
353
354 return ( ret );
355 }
356
357 /*
358 * Read at most 'len' characters, blocking for at most 'timeout' ms
359 */
mbedtls_net_recv_timeout(void * ctx,unsigned char * buf,size_t len,uint32_t timeout)360 int mbedtls_net_recv_timeout( void *ctx, unsigned char *buf, size_t len,
361 uint32_t timeout )
362 {
363 int ret;
364 struct timeval tv;
365 fd_set read_fds;
366 int fd = ((mbedtls_net_context *) ctx)->fd;
367
368 if ( fd < 0 ) {
369 return ( MBEDTLS_ERR_NET_INVALID_CONTEXT );
370 }
371
372 FD_ZERO( &read_fds );
373 FD_SET( fd, &read_fds );
374
375 tv.tv_sec = timeout / 1000;
376 tv.tv_usec = ( timeout % 1000 ) * 1000;
377
378 ret = select( fd + 1, &read_fds, NULL, NULL, timeout == 0 ? NULL : &tv );
379
380 /* Zero fds ready means we timed out */
381 if ( ret == 0 ) {
382 return ( MBEDTLS_ERR_SSL_TIMEOUT );
383 }
384
385 if ( ret < 0 ) {
386 if ( errno == EINTR ) {
387 return ( MBEDTLS_ERR_SSL_WANT_READ );
388 }
389
390 return ( MBEDTLS_ERR_NET_RECV_FAILED );
391 }
392
393 /* This call will not block */
394 return ( mbedtls_net_recv( ctx, buf, len ) );
395 }
396
397 /*
398 * Write at most 'len' characters
399 */
mbedtls_net_send(void * ctx,const unsigned char * buf,size_t len)400 int mbedtls_net_send( void *ctx, const unsigned char *buf, size_t len )
401 {
402 int ret;
403 int fd = ((mbedtls_net_context *) ctx)->fd;
404
405 if ( fd < 0 ) {
406 return ( MBEDTLS_ERR_NET_INVALID_CONTEXT );
407 }
408
409 ret = (int) write( fd, buf, len );
410
411 if ( ret < 0 ) {
412 if ( net_would_block( ctx ) != 0 ) {
413 return ( MBEDTLS_ERR_SSL_WANT_WRITE );
414 }
415
416 if ( errno == EPIPE || errno == ECONNRESET ) {
417 return ( MBEDTLS_ERR_NET_CONN_RESET );
418 }
419
420 if ( errno == EINTR ) {
421 return ( MBEDTLS_ERR_SSL_WANT_WRITE );
422 }
423
424 return ( MBEDTLS_ERR_NET_SEND_FAILED );
425 }
426
427 return ( ret );
428 }
429
430 /*
431 * Gracefully close the connection
432 */
mbedtls_net_free(mbedtls_net_context * ctx)433 void mbedtls_net_free( mbedtls_net_context *ctx )
434 {
435 if ( ctx->fd == -1 ) {
436 return;
437 }
438
439 shutdown( ctx->fd, 2 );
440 close( ctx->fd );
441
442 ctx->fd = -1;
443 }
444
445 #endif /* MBEDTLS_NET_C */
446
447 #endif /* CONFIG_ESP_NETIF_TCPIP_LWIP */
448