1 /*
2  *  TCP/IP or UDP/IP networking functions
3  *
4  *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
5  *  SPDX-License-Identifier: Apache-2.0
6  *
7  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
8  *  not use this file except in compliance with the License.
9  *  You may obtain a copy of the License at
10  *
11  *  http://www.apache.org/licenses/LICENSE-2.0
12  *
13  *  Unless required by applicable law or agreed to in writing, software
14  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  *  See the License for the specific language governing permissions and
17  *  limitations under the License.
18  *
19  */
20 
21 #if !defined(MBEDTLS_CONFIG_FILE)
22 #include "mbedtls/config.h"
23 #else
24 #include MBEDTLS_CONFIG_FILE
25 #endif
26 #if !defined(MBEDTLS_NET_C)
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <stdint.h>
30 #include <string.h>
31 
32 #include "mbedtls/net_sockets.h"
33 
34 #if defined(STM32_USE_SPI_WIFI)
35 
36 #include "stm32_wifi.h"
37 
38 #define WIFI_WRITE_TIMEOUT   200
39 #define WIFI_READ_TIMEOUT    200
40 #define WIFI_PAYLOAD_SIZE    ES_WIFI_PAYLOAD_SIZE
41 #define WIFI_READ_RETRY_TIME 5
42 
mbedtls_net_init(mbedtls_net_context * ctx)43 void mbedtls_net_init( mbedtls_net_context *ctx )
44 {
45     ctx->fd = -1;
46 }
47 
mbedtls_net_connect(mbedtls_net_context * ctx,const char * host,const char * port,int proto)48 int mbedtls_net_connect( mbedtls_net_context *ctx, const char *host, const char *port, int proto )
49 {
50     WIFI_Status_t ret;
51     WIFI_Protocol_t type;
52     uint8_t ip_addr[4];
53 
54     ret = WIFI_GetHostAddress( (char *)host, ip_addr );
55     if( ret != WIFI_STATUS_OK )
56         return( MBEDTLS_ERR_NET_UNKNOWN_HOST );
57 
58     type = ( proto == MBEDTLS_NET_PROTO_UDP ?
59            WIFI_UDP_PROTOCOL : WIFI_TCP_PROTOCOL );
60     ret = WIFI_OpenClientConnection( 0, type, "", ip_addr, atoi(port), 0 );
61     if( ret != WIFI_STATUS_OK )
62         return( MBEDTLS_ERR_NET_CONNECT_FAILED );
63 
64     ctx->fd = 0;
65 
66     return( ret );
67 }
68 
mbedtls_net_recv(void * ctx,unsigned char * buf,size_t len)69 int mbedtls_net_recv( void *ctx, unsigned char *buf, size_t len )
70 {
71     WIFI_Status_t ret;
72     uint16_t recv_size;
73     int fd = ((mbedtls_net_context *) ctx)->fd;
74 
75     if (fd < 0)
76         return( MBEDTLS_ERR_NET_INVALID_CONTEXT );
77 
78     if ( len > WIFI_PAYLOAD_SIZE )
79         len = WIFI_PAYLOAD_SIZE;
80 
81     int err_count = 0;
82     do
83     {
84         ret = WIFI_ReceiveData( (uint8_t)fd,
85                                buf, (uint16_t)len,
86                                &recv_size, WIFI_READ_TIMEOUT );
87         if( ret != WIFI_STATUS_OK )
88             return( MBEDTLS_ERR_NET_RECV_FAILED );
89 
90         if( recv_size == 0 )
91         {
92             if( err_count == WIFI_READ_RETRY_TIME )
93                 return( MBEDTLS_ERR_SSL_WANT_READ );
94             else
95                 err_count++;
96         }
97     } while( ( ret == WIFI_STATUS_OK ) && ( recv_size == 0 ) );
98 
99     return( recv_size );
100 }
101 
mbedtls_net_recv_timeout(void * ctx,unsigned char * buf,size_t len,uint32_t timeout)102 int mbedtls_net_recv_timeout( void *ctx, unsigned char *buf, size_t len,
103                                              uint32_t timeout )
104 {
105     WIFI_Status_t ret;
106     uint16_t recv_size;
107     int fd = ((mbedtls_net_context *) ctx)->fd;
108 
109     if( fd < 0 )
110         return( MBEDTLS_ERR_NET_INVALID_CONTEXT );
111 
112     if( len > WIFI_PAYLOAD_SIZE )
113         len = WIFI_PAYLOAD_SIZE;
114 
115     int err_count = 0;
116     do
117     {
118         ret = WIFI_ReceiveData( (uint8_t)fd,
119                                buf, (uint16_t)len,
120                                &recv_size, WIFI_READ_TIMEOUT );
121         if( ret != WIFI_STATUS_OK )
122             return( MBEDTLS_ERR_NET_RECV_FAILED );
123 
124         if( recv_size == 0 )
125         {
126             if( err_count == WIFI_READ_RETRY_TIME )
127                 return( MBEDTLS_ERR_SSL_WANT_READ );
128             else
129                 err_count++;
130         }
131     } while( ( ret == WIFI_STATUS_OK ) && ( recv_size == 0 ) );
132 
133     return( recv_size );
134 }
135 
mbedtls_net_send(void * ctx,const unsigned char * buf,size_t len)136 int mbedtls_net_send( void *ctx, const unsigned char *buf, size_t len )
137 {
138     WIFI_Status_t ret;
139     uint16_t send_size;
140     uint16_t once_len;
141     uint8_t *pdata = (uint8_t *)buf;
142     uint16_t send_total = 0;
143     int fd = ((mbedtls_net_context *) ctx)->fd;
144 
145     if( fd < 0 )
146         return( MBEDTLS_ERR_NET_INVALID_CONTEXT );
147 
148     do
149     {
150         if( len > WIFI_PAYLOAD_SIZE )
151         {
152             once_len = WIFI_PAYLOAD_SIZE;
153             len -= WIFI_PAYLOAD_SIZE;
154         }
155         else
156         {
157             once_len = len;
158             len = 0;
159         }
160 
161         ret = WIFI_SendData( (uint8_t)fd,
162                             pdata, once_len,
163                             &send_size, WIFI_WRITE_TIMEOUT );
164         if( ret != WIFI_STATUS_OK )
165             return( MBEDTLS_ERR_NET_SEND_FAILED );
166 
167         pdata += once_len;
168         send_total += send_size;
169     } while ( len > 0 );
170 
171     return( send_total );
172 }
173 
mbedtls_net_free(mbedtls_net_context * ctx)174 void mbedtls_net_free( mbedtls_net_context *ctx )
175 {
176     WIFI_Status_t ret;
177 
178     if (ctx->fd == -1)
179         return;
180 
181     ret = WIFI_CloseClientConnection( (uint32_t)ctx->fd );
182     if( ret != WIFI_STATUS_OK )
183         return;
184 
185     ctx->fd = -1;
186 }
187 
188 #else /* STM32_USE_SPI_WIFI */
189 
190 #include <fcntl.h>
191 #include <unistd.h>
192 
193 #include <netdb.h>
194 #include <sys/socket.h>
195 
mbedtls_net_init(mbedtls_net_context * ctx)196 void mbedtls_net_init( mbedtls_net_context *ctx )
197 {
198     ctx->fd = -1;
199 }
200 
mbedtls_net_connect(mbedtls_net_context * ctx,const char * host,const char * port,int proto)201 int mbedtls_net_connect( mbedtls_net_context *ctx, const char *host, const char *port, int proto )
202 {
203     int ret;
204     struct addrinfo hints, *addr_list, *cur;
205 
206     memset( &hints, 0, sizeof( hints ) );
207     hints.ai_family = AF_UNSPEC;
208     hints.ai_socktype = proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM;
209     hints.ai_protocol = proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP;
210 
211     if( getaddrinfo( host, port, &hints, &addr_list ) != 0 )
212         return( MBEDTLS_ERR_NET_UNKNOWN_HOST );
213 
214     ret = MBEDTLS_ERR_NET_UNKNOWN_HOST;
215 
216     for( cur = addr_list; cur != NULL; cur = cur->ai_next )
217     {
218         ctx->fd = (int) socket( cur->ai_family,
219                               cur->ai_socktype, cur->ai_protocol );
220         if( ctx->fd < 0 )
221         {
222             ret = MBEDTLS_ERR_NET_SOCKET_FAILED;
223             continue;
224         }
225 
226         do
227         {
228             ret = connect( ctx->fd, cur->ai_addr, cur->ai_addrlen );
229             if( ret == 0 )
230                 goto out;
231             else
232             {
233                 if (errno == EINTR)
234                     continue;
235 
236                 break;
237             }
238         } while( 1 );
239 
240         close( ctx->fd );
241         ret = MBEDTLS_ERR_NET_CONNECT_FAILED;
242     }
243 
244 out:
245     freeaddrinfo( addr_list );
246 
247     return( ret );
248 }
249 
net_would_block(const mbedtls_net_context * ctx)250 static int net_would_block( const mbedtls_net_context *ctx )
251 {
252     int err = errno;
253 
254     /*
255      * Never return 'WOULD BLOCK' on a non-blocking socket
256      */
257     if( ( fcntl( ctx->fd, F_GETFL, 0) & O_NONBLOCK ) != O_NONBLOCK )
258     {
259         errno = err;
260         return( 0 );
261     }
262 
263     switch( errno = err )
264     {
265 #if defined EAGAIN
266         case EAGAIN:
267 #endif
268 #if defined EWOULDBLOCK && EWOULDBLOCK != EAGAIN
269         case EWOULDBLOCK:
270 #endif
271             return( 1 );
272     }
273     return( 0 );
274 }
275 
mbedtls_net_set_block(mbedtls_net_context * ctx)276 int mbedtls_net_set_block( mbedtls_net_context *ctx )
277 {
278     int flags;
279 
280     flags = fcntl( ctx->fd, F_GETFL, 0 );
281     flags &= ~O_NONBLOCK;
282 
283     return fcntl( ctx->fd, F_SETFL, flags );
284 }
285 
mbedtls_net_set_nonblock(mbedtls_net_context * ctx)286 int mbedtls_net_set_nonblock( mbedtls_net_context *ctx )
287 {
288     int flags;
289 
290     flags = fcntl( ctx->fd, F_GETFL, 0 );
291     flags |= O_NONBLOCK;
292 
293     return fcntl( ctx->fd, F_SETFL, flags );
294 }
295 
mbedtls_net_recv(void * ctx,unsigned char * buf,size_t len)296 int mbedtls_net_recv( void *ctx, unsigned char *buf, size_t len )
297 {
298     int ret;
299     int fd = ((mbedtls_net_context *) ctx)->fd;
300 
301     if( fd < 0 )
302         return( MBEDTLS_ERR_NET_INVALID_CONTEXT );
303 
304     ret = (int) read( fd, buf, len );
305 
306     if( ret < 0 )
307     {
308         if( net_would_block( ctx ) != 0 )
309             return( MBEDTLS_ERR_SSL_WANT_READ );
310 
311         if( errno == EPIPE || errno == ECONNRESET )
312             return( MBEDTLS_ERR_NET_CONN_RESET );
313 
314         if( errno == EINTR )
315             return( MBEDTLS_ERR_SSL_WANT_READ );
316 
317         return( MBEDTLS_ERR_NET_RECV_FAILED );
318     }
319 
320     return( ret );
321 }
322 
mbedtls_net_recv_timeout(void * ctx,unsigned char * buf,size_t len,uint32_t timeout)323 int mbedtls_net_recv_timeout( void *ctx, unsigned char *buf, size_t len,
324                              uint32_t timeout )
325 {
326     int ret;
327     struct timeval tv;
328     fd_set read_fds;
329     int fd = ((mbedtls_net_context *) ctx)->fd;
330 
331     if( fd < 0 )
332         return( MBEDTLS_ERR_NET_INVALID_CONTEXT );
333 
334     FD_ZERO( &read_fds );
335     FD_SET( fd, &read_fds );
336 
337     tv.tv_sec  = timeout / 1000;
338     tv.tv_usec = ( timeout % 1000 ) * 1000;
339 
340     ret = select( fd + 1, &read_fds, NULL, NULL, timeout == 0 ? NULL : &tv );
341     if( ret == 0 )
342         return( MBEDTLS_ERR_SSL_TIMEOUT );
343 
344     if( ret < 0 )
345     {
346         if( errno == EINTR )
347             return( MBEDTLS_ERR_SSL_WANT_READ );
348 
349         return( MBEDTLS_ERR_NET_RECV_FAILED );
350     }
351 
352     return( mbedtls_net_recv( ctx, buf, len ) );
353 }
354 
mbedtls_net_send(void * ctx,const unsigned char * buf,size_t len)355 int mbedtls_net_send(void *ctx, const unsigned char *buf, size_t len)
356 {
357     int ret;
358     int fd = ((mbedtls_net_context *) ctx)->fd;
359 
360     if( fd < 0 )
361         return( MBEDTLS_ERR_NET_INVALID_CONTEXT );
362 
363     ret = (int) write( fd, buf, len );
364 
365     if( ret < 0 )
366     {
367         if( net_would_block( ctx ) != 0 )
368             return( MBEDTLS_ERR_SSL_WANT_WRITE );
369 
370         if( errno == EPIPE || errno == ECONNRESET )
371             return( MBEDTLS_ERR_NET_CONN_RESET );
372 
373         if( errno == EINTR )
374             return( MBEDTLS_ERR_SSL_WANT_WRITE );
375 
376         return( MBEDTLS_ERR_NET_SEND_FAILED );
377     }
378 
379     return ret;
380 }
381 
mbedtls_net_free(mbedtls_net_context * ctx)382 void mbedtls_net_free( mbedtls_net_context *ctx )
383 {
384     if( ctx->fd == -1 )
385         return;
386 
387     shutdown( ctx->fd, 2 );
388     close( ctx->fd );
389 
390     ctx->fd = -1;
391 }
392 
393 #endif /* STM32_USE_SPI_WIFI */
394 #endif /* MBEDTLS_NET_C */
395