forked from ARMmbed/mbed-os
-
Notifications
You must be signed in to change notification settings - Fork 0
/
LWIPStack.h
601 lines (537 loc) · 24.4 KB
/
LWIPStack.h
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
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef LWIPSTACK_H_
#define LWIPSTACK_H_
#include "lwip/tcpip.h"
#include "lwip/tcp.h"
#include "lwip/ip.h"
#include "lwip/api.h"
#include "netif/etharp.h"
#include "lwip/ethip6.h"
#include "netsocket/nsapi_types.h"
#include "netsocket/EMAC.h"
#include "netsocket/L3IP.h"
#include "netsocket/OnboardNetworkStack.h"
#include "LWIPMemoryManager.h"
class LWIP : public OnboardNetworkStack, private mbed::NonCopyable<LWIP> {
public:
using NetworkStack::get_ip_address;
static LWIP &get_instance();
class Interface : public OnboardNetworkStack::Interface {
public:
/** Connect the interface to the network
*
* Sets up a connection on specified network interface, using DHCP or provided network details. If the @a dhcp is set to
* true all the remaining parameters are ignored.
*
* @param dhcp true if the network details should be acquired using DHCP
* @param ip IP address to be used for the interface as "W:X:Y:Z" or NULL
* @param netmask Net mask to be used for the interface as "W:X:Y:Z" or NULL
* @param gw Gateway address to be used for the interface as "W:X:Y:Z" or NULL
* @param stack Allow manual selection of IPv4 and/or IPv6.
* @param blocking Specify whether bringup blocks for connection completion.
* @return NSAPI_ERROR_OK on success, or error code
*/
virtual nsapi_error_t bringup(bool dhcp, const char *ip,
const char *netmask, const char *gw,
nsapi_ip_stack_t stack = DEFAULT_STACK,
bool blocking = true
);
/** Disconnect interface from the network
*
* After this call the network interface is inactive, to use it again user needs to call @a mbed_ipstack_bringup again.
*
* @return NSAPI_ERROR_OK on success, or error code
*/
virtual nsapi_error_t bringdown();
/** Register callback for status reporting
*
* The specified status callback function will be called on status changes
* on the network. The parameters on the callback are the event type and
* event-type dependent reason parameter.
*
* @param status_cb The callback for status changes
*/
virtual void attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb);
/** Get the connection status
*
* @return The connection status according to ConnectionStatusType
*/
virtual nsapi_connection_status_t get_connection_status() const;
/** Return netif interface name
*
* @return netif name eg "en0"
*/
virtual char *get_interface_name(char *buf);
/** Return MAC address of the network interface
*
* @return MAC address as "V:W:X:Y:Z"
*/
virtual char *get_mac_address(char *buf, nsapi_size_t buflen);
/** Copies IP address of the network interface to user supplied buffer
*
* @param buf buffer to which IP address will be copied as "W:X:Y:Z"
* @param buflen size of supplied buffer
* @return Pointer to a buffer, or NULL if the buffer is too small
*/
virtual char *get_ip_address(char *buf, nsapi_size_t buflen);
/** Copies IP address of the name based network interface to user supplied buffer
*
* @param buf buffer to which IP address will be copied as "W:X:Y:Z"
* @param buflen size of supplied buffer
* @param interface_name naame of the interface
* @return Pointer to a buffer, or NULL if the buffer is too small
*/
virtual char *get_ip_address_if(char *buf, nsapi_size_t buflen, const char *interface_name);
/** Copies netmask of the network interface to user supplied buffer
*
* @param buf buffer to which netmask will be copied as "W:X:Y:Z"
* @param buflen size of supplied buffer
* @return Pointer to a buffer, or NULL if the buffer is too small
*/
virtual char *get_netmask(char *buf, nsapi_size_t buflen);
/** Copies gateway address of the network interface to user supplied buffer
*
* @param buf buffer to which gateway address will be copied as "W:X:Y:Z"
* @param buflen size of supplied buffer
* @return Pointer to a buffer, or NULL if the buffer is too small
*/
virtual char *get_gateway(char *buf, nsapi_size_t buflen);
private:
friend class LWIP;
Interface();
nsapi_error_t set_dhcp();
static void netif_link_irq(struct netif *netif);
static void netif_status_irq(struct netif *netif);
static Interface *our_if_from_netif(struct netif *netif);
#if LWIP_ETHERNET
static err_t emac_low_level_output(struct netif *netif, struct pbuf *p);
void emac_input(net_stack_mem_buf_t *buf);
void emac_state_change(bool up);
#if LWIP_IGMP
static err_t emac_igmp_mac_filter(struct netif *netif, const ip4_addr_t *group, enum netif_mac_filter_action action);
#endif
#if LWIP_IPV6_MLD
static err_t emac_mld_mac_filter(struct netif *netif, const ip6_addr_t *group, enum netif_mac_filter_action action);
#endif
static err_t emac_if_init(struct netif *netif);
#endif
#if LWIP_L3IP
#if LWIP_IPV4
static err_t l3ip4_output(struct netif *netif, struct pbuf *p, const ip4_addr_t *ipaddr);
#endif
#if LWIP_IPV6
static err_t l3ip6_output(struct netif *netif, struct pbuf *p, const ip6_addr_t *ipaddr);
#endif
void l3ip_input(net_stack_mem_buf_t *buf);
void l3ip_state_change(bool up);
#if LWIP_IGMP
static err_t l3ip_multicast_ipv4_filter(struct netif *netif, const ip4_addr_t *group, enum netif_mac_filter_action action);
#endif
#if LWIP_IPV6_MLD
static err_t l3ip_multicast_ipv6_filter(struct netif *netif, const ip6_addr_t *group, enum netif_mac_filter_action action);
#endif
static err_t l3ip_if_init(struct netif *netif);
#endif
union {
#if LWIP_ETHERNET
EMAC *emac; /**< HW specific emac implementation */
#endif
#if LWIP_L3IP
L3IP *l3ip; /**< L3IP implementation */
#endif
void *hw; /**< alternative implementation pointer - used for PPP */
};
mbed_rtos_storage_semaphore_t linked_sem;
osSemaphoreId_t linked;
mbed_rtos_storage_semaphore_t unlinked_sem;
osSemaphoreId_t unlinked;
mbed_rtos_storage_semaphore_t has_any_addr_sem;
osSemaphoreId_t has_any_addr;
#define HAS_ANY_ADDR 1
#if PREF_ADDR_TIMEOUT
mbed_rtos_storage_semaphore_t has_pref_addr_sem;
osSemaphoreId_t has_pref_addr;
#define HAS_PREF_ADDR 2
#endif
#if BOTH_ADDR_TIMEOUT
mbed_rtos_storage_semaphore_t has_both_addr_sem;
osSemaphoreId_t has_both_addr;
#define HAS_BOTH_ADDR 4
#endif
char _interface_name[NSAPI_INTERFACE_NAME_MAX_SIZE];
char has_addr_state;
nsapi_connection_status_t connected;
bool dhcp_started;
bool dhcp_has_to_be_set;
bool blocking;
bool ppp;
mbed::Callback<void(nsapi_event_t, intptr_t)> client_callback;
struct netif netif;
static Interface *list;
Interface *next;
LWIPMemoryManager *memory_manager;
};
/** Register a network interface with the IP stack
*
* Connects EMAC layer with the IP stack and initializes all the required infrastructure.
* This function should be called only once for each available interface.
*
* @param emac EMAC HAL implementation for this network interface
* @param default_if true if the interface should be treated as the default one
* @param[out] interface_out pointer to stack interface object controlling the EMAC
* @return NSAPI_ERROR_OK on success, or error code
*/
virtual nsapi_error_t add_ethernet_interface(EMAC &emac, bool default_if, OnboardNetworkStack::Interface **interface_out);
/** Register a network interface with the IP stack
*
* Connects L3IP layer with the IP stack and initializes all the required infrastructure.
* This function should be called only once for each available interface.
*
* @param l3ip L3IP HAL implementation for this network interface
* @param default_if true if the interface should be treated as the default one
* @param[out] interface_out pointer to stack interface object controlling the L3IP
* @return NSAPI_ERROR_OK on success, or error code
*/
virtual nsapi_error_t add_l3ip_interface(L3IP &l3ip, bool default_if, OnboardNetworkStack::Interface **interface_out);
/** Register a PPP interface with the IP stack
*
* Connects PPP layer with the IP stack and initializes all the required infrastructure.
* This function should be called only once for each available interface.
*
* This is an internal function that links ppp_lwip.cpp to mbed_ipstack_lwip.cpp,
* once a driver starts it via the nsapi_ppp.h API.
*
* Ultimately the nsapi_ppp.h API will be deprecated, and there will be a
* mbed_ipstack_add_ppp_interface() replacing nsapi_ppp_connect().
*
* @param pcb PPP implementation specific user data; will be passed to PPP callbacks
* @param default_if true if the interface should be treated as the default one
* @param stack Allow manual selection of IPv4 and/or IPv6
* @param[out] interface_out set to interface handle that must be passed to subsequent mbed_stack calls
* @return NSAPI_ERROR_OK on success, or error code
*/
nsapi_error_t _add_ppp_interface(void *pcb, bool default_if, nsapi_ip_stack_t stack, LWIP::Interface **interface_out);
/** Remove a network interface from IP stack
*
* Removes layer 3 IP objects,network interface from stack list, and shutdown device driver .
* @param[out] interface_out pointer to stack interface object controlling the L3IP
* @return NSAPI_ERROR_OK on success, or error code
*/
virtual nsapi_error_t remove_l3ip_interface(OnboardNetworkStack::Interface **interface_out);
/** Get a domain name server from a list of servers to query
*
* Returns a DNS server address for a index. If returns error no more
* DNS servers to read.
*
* @param index Index of the DNS server, starts from zero
* @param address Destination for the host address
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t get_dns_server(int index, SocketAddress *address, const char *interface_name);
/** Add a domain name server to list of servers to query
*
* @param address Destination for the host address
* @param interface_name Network interface name
* @return NSAPI_ERROR_OK on success, negative error code on failure
*/
virtual nsapi_error_t add_dns_server(const SocketAddress &address, const char *interface_name);
/** Get the local IP address
*
* @return Null-terminated representation of the local IP address
* or null if not yet connected
*/
virtual const char *get_ip_address();
/** Set the network interface as default one
*/
virtual void set_default_interface(OnboardNetworkStack::Interface *interface);
protected:
LWIP();
virtual ~LWIP() {}
/** Opens a socket
*
* Creates a network socket and stores it in the specified handle.
* The handle must be passed to following calls on the socket.
*
* A stack may have a finite number of sockets, in this case
* NSAPI_ERROR_NO_SOCKET is returned if no socket is available.
*
* @param handle Destination for the handle to a newly created socket
* @param proto Protocol of socket to open, NSAPI_TCP or NSAPI_UDP
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t socket_open(nsapi_socket_t *handle, nsapi_protocol_t proto);
/** Close the socket
*
* Closes any open connection and deallocates any memory associated
* with the socket.
*
* @param handle Socket handle
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t socket_close(nsapi_socket_t handle);
/** Bind a specific address to a socket
*
* Binding a socket specifies the address and port on which to recieve
* data. If the IP address is zeroed, only the port is bound.
*
* @param handle Socket handle
* @param address Local address to bind
* @return 0 on success, negative error code on failure.
*/
virtual nsapi_error_t socket_bind(nsapi_socket_t handle, const SocketAddress &address);
/** Listen for connections on a TCP socket
*
* Marks the socket as a passive socket that can be used to accept
* incoming connections.
*
* @param handle Socket handle
* @param backlog Number of pending connections that can be queued
* simultaneously
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t socket_listen(nsapi_socket_t handle, int backlog);
/** Connects TCP socket to a remote host
*
* Initiates a connection to a remote server specified by the
* indicated address.
*
* @param handle Socket handle
* @param address The SocketAddress of the remote host
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t socket_connect(nsapi_socket_t handle, const SocketAddress &address);
/** Accepts a connection on a TCP socket
*
* The server socket must be bound and set to listen for connections.
* On a new connection, creates a network socket and stores it in the
* specified handle. The handle must be passed to following calls on
* the socket.
*
* A stack may have a finite number of sockets, in this case
* NSAPI_ERROR_NO_SOCKET is returned if no socket is available.
*
* This call is non-blocking. If accept would block,
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
*
* @param server Socket handle to server to accept from
* @param handle Destination for a handle to the newly created socket
* @param address Destination for the remote address or NULL
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t socket_accept(nsapi_socket_t server,
nsapi_socket_t *handle, SocketAddress *address = 0);
/** Send data over a TCP socket
*
* The socket must be connected to a remote host. Returns the number of
* bytes sent from the buffer.
*
* This call is non-blocking. If send would block,
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
*
* @param handle Socket handle
* @param data Buffer of data to send to the host
* @param size Size of the buffer in bytes
* @return Number of sent bytes on success, negative error
* code on failure
*/
virtual nsapi_size_or_error_t socket_send(nsapi_socket_t handle,
const void *data, nsapi_size_t size);
/** Receive data over a TCP socket
*
* The socket must be connected to a remote host. Returns the number of
* bytes received into the buffer.
*
* This call is non-blocking. If recv would block,
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
*
* @param handle Socket handle
* @param data Destination buffer for data received from the host
* @param size Size of the buffer in bytes
* @return Number of received bytes on success, negative error
* code on failure
*/
virtual nsapi_size_or_error_t socket_recv(nsapi_socket_t handle,
void *data, nsapi_size_t size);
/** Send a packet over a UDP socket
*
* Sends data to the specified address. Returns the number of bytes
* sent from the buffer.
*
* This call is non-blocking. If sendto would block,
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
*
* @param handle Socket handle
* @param address The SocketAddress of the remote host
* @param data Buffer of data to send to the host
* @param size Size of the buffer in bytes
* @return Number of sent bytes on success, negative error
* code on failure
*/
virtual nsapi_size_or_error_t socket_sendto(nsapi_socket_t handle, const SocketAddress &address,
const void *data, nsapi_size_t size);
/** Receive a packet over a UDP socket
*
* Receives data and stores the source address in address if address
* is not NULL. Returns the number of bytes received into the buffer.
*
* This call is non-blocking. If recvfrom would block,
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
*
* @param handle Socket handle
* @param address Destination for the source address or NULL
* @param buffer Destination buffer for data received from the host
* @param size Size of the buffer in bytes
* @return Number of received bytes on success, negative error
* code on failure
*/
virtual nsapi_size_or_error_t socket_recvfrom(nsapi_socket_t handle, SocketAddress *address,
void *buffer, nsapi_size_t size);
/** Register a callback on state change of the socket
*
* The specified callback will be called on state changes such as when
* the socket can recv/send/accept successfully and on when an error
* occurs. The callback may also be called spuriously without reason.
*
* The callback may be called in an interrupt context and should not
* perform expensive operations such as recv/send calls.
*
* @param handle Socket handle
* @param callback Function to call on state change
* @param data Argument to pass to callback
*/
virtual void socket_attach(nsapi_socket_t handle, void (*callback)(void *), void *data);
/* Set stack-specific socket options
*
* The setsockopt allow an application to pass stack-specific hints
* to the underlying stack. For unsupported options,
* NSAPI_ERROR_UNSUPPORTED is returned and the socket is unmodified.
*
* @param handle Socket handle
* @param level Stack-specific protocol level
* @param optname Stack-specific option identifier
* @param optval Option value
* @param optlen Length of the option value
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t setsockopt(nsapi_socket_t handle, int level,
int optname, const void *optval, unsigned optlen);
/* Get stack-specific socket options
*
* The getstackopt allow an application to retrieve stack-specific hints
* from the underlying stack. For unsupported options,
* NSAPI_ERROR_UNSUPPORTED is returned and optval is unmodified.
*
* @param handle Socket handle
* @param level Stack-specific protocol level
* @param optname Stack-specific option identifier
* @param optval Destination for option value
* @param optlen Length of the option value
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t getsockopt(nsapi_socket_t handle, int level,
int optname, void *optval, unsigned *optlen);
private:
/** Call in callback
*
* Callback is used to call the call in method of the network stack.
*/
typedef mbed::Callback<nsapi_error_t (int delay_ms, mbed::Callback<void()> user_cb)> call_in_callback_cb_t;
/** Get a call in callback
*
* Get a call in callback from the network stack context.
*
* Callback should not take more than 10ms to execute, otherwise it might
* prevent underlying thread processing. A portable user of the callback
* should not make calls to network operations due to stack size limitations.
* The callback should not perform expensive operations such as socket recv/send
* calls or blocking operations.
*
* @return Call in callback
*/
virtual call_in_callback_cb_t get_call_in_callback();
/** Call a callback after a delay
*
* Call a callback from the network stack context after a delay. If function
* returns error callback will not be called.
*
* @param delay Delay in milliseconds
* @param func Callback to be called
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t call_in(int delay, mbed::Callback<void()> func);
struct mbed_lwip_socket {
bool in_use;
struct netconn *conn;
struct pbuf *buf;
u16_t offset;
void (*cb)(void *);
void *data;
// Track multicast addresses subscribed to by this socket
nsapi_ip_mreq_t *multicast_memberships;
uint32_t multicast_memberships_count;
uint32_t multicast_memberships_registry;
};
struct lwip_callback {
unsigned int delay;
mbed::Callback<void()> callback;
};
static nsapi_error_t err_remap(err_t err);
static bool is_local_addr(const ip_addr_t *ip_addr);
static const ip_addr_t *get_ip_addr(bool any_addr, const struct netif *netif);
static const ip_addr_t *get_ipv4_addr(const struct netif *netif);
static const ip_addr_t *get_ipv6_addr(const struct netif *netif);
static void add_dns_addr(struct netif *lwip_netif, const char *interface_name);
/* Static arena of sockets */
struct mbed_lwip_socket arena[MEMP_NUM_NETCONN];
void arena_init(void);
struct mbed_lwip_socket *arena_alloc();
void arena_dealloc(struct mbed_lwip_socket *s);
static uint32_t next_registered_multicast_member(const struct mbed_lwip_socket *s, uint32_t index)
{
while (!(s->multicast_memberships_registry & (0x0001 << index))) {
index++;
}
return index;
}
static uint32_t next_free_multicast_member(const struct mbed_lwip_socket *s, uint32_t index)
{
while ((s->multicast_memberships_registry & (0x0001 << index))) {
index++;
}
return index;
}
static void set_multicast_member_registry_bit(struct mbed_lwip_socket *s, uint32_t index)
{
s->multicast_memberships_registry |= (0x0001 << index);
}
static void clear_multicast_member_registry_bit(struct mbed_lwip_socket *s, uint32_t index)
{
s->multicast_memberships_registry &= ~(0x0001 << index);
}
static int32_t find_multicast_member(const struct mbed_lwip_socket *s, const nsapi_ip_mreq_t *imr);
static void socket_callback(struct netconn *nc, enum netconn_evt eh, u16_t len);
static void tcpip_init_irq(void *handle);
static void tcpip_thread_callback(void *ptr);
char ip_address[40];
Interface *default_interface;
LWIPMemoryManager memory_manager;
osThreadId tcpip_thread_id;
rtos::Mutex adaptation;
rtos::EventFlags _event_flag;
static const int TCP_CLOSED_FLAG = 0x4u;
};
#endif /* LWIPSTACK_H_ */