Knight KE / Mbed OS Game_Master
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers LWIPStack.h Source File

LWIPStack.h

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2017 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #ifndef LWIPSTACK_H_
00018 #define LWIPSTACK_H_
00019 
00020 #include "lwip/tcpip.h"
00021 #include "lwip/tcp.h"
00022 #include "lwip/ip.h"
00023 #include "lwip/api.h"
00024 #include "netif/etharp.h"
00025 #include "lwip/ethip6.h"
00026 #include "netsocket/nsapi_types.h"
00027 #include "netsocket/EMAC.h"
00028 #include "netsocket/OnboardNetworkStack.h"
00029 #include "LWIPMemoryManager.h"
00030 
00031 
00032 class LWIP : public OnboardNetworkStack, private mbed::NonCopyable<LWIP> {
00033 public:
00034 
00035     static LWIP &get_instance();
00036 
00037     class Interface : public OnboardNetworkStack::Interface {
00038     public:
00039         /** Connect the interface to the network
00040          *
00041          * Sets up a connection on specified network interface, using DHCP or provided network details. If the @a dhcp is set to
00042          * true all the remaining parameters are ignored.
00043          *
00044          * @param    dhcp       true if the network details should be acquired using DHCP
00045          * @param    ip         IP address to be used for the interface as "W:X:Y:Z" or NULL
00046          * @param    netmask    Net mask to be used for the interface as "W:X:Y:Z" or NULL
00047          * @param    gw         Gateway address to be used for the interface as "W:X:Y:Z" or NULL
00048          * @param    stack      Allow manual selection of IPv4 and/or IPv6.
00049          * @param    blocking   Specify whether bringup blocks for connection completion.
00050          * @return              NSAPI_ERROR_OK on success, or error code
00051          */
00052         virtual nsapi_error_t bringup(bool dhcp, const char *ip,
00053                                       const char *netmask, const char *gw,
00054                                       nsapi_ip_stack_t stack = DEFAULT_STACK,
00055                                       bool blocking = true
00056                                       );
00057 
00058         /** Disconnect interface from the network
00059          *
00060          * After this call the network interface is inactive, to use it again user needs to call @a mbed_ipstack_bringup again.
00061          *
00062          * @return    NSAPI_ERROR_OK on success, or error code
00063          */
00064         virtual nsapi_error_t bringdown();
00065 
00066         /** Register callback for status reporting
00067          *
00068          *  The specified status callback function will be called on status changes
00069          *  on the network. The parameters on the callback are the event type and
00070          *  event-type dependent reason parameter.
00071          *
00072          *  @param status_cb The callback for status changes
00073          */
00074         virtual void attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb);
00075 
00076         /** Get the connection status
00077          *
00078          *  @return         The connection status according to ConnectionStatusType
00079          */
00080         virtual nsapi_connection_status_t get_connection_status() const;
00081 
00082         /** Return MAC address of the network interface
00083          *
00084          * @return              MAC address as "V:W:X:Y:Z"
00085          */
00086         virtual char *get_mac_address(char *buf, nsapi_size_t buflen);
00087 
00088         /** Copies IP address of the network interface to user supplied buffer
00089          *
00090          * @param    emac       EMAC HAL implementation for this network interface
00091          * @param    buf        buffer to which IP address will be copied as "W:X:Y:Z"
00092          * @param    buflen     size of supplied buffer
00093          * @return              Pointer to a buffer, or NULL if the buffer is too small
00094          */
00095         virtual char *get_ip_address(char *buf, nsapi_size_t buflen);
00096 
00097         /** Copies netmask of the network interface to user supplied buffer
00098          *
00099          * @param    buf        buffer to which netmask will be copied as "W:X:Y:Z"
00100          * @param    buflen     size of supplied buffer
00101          * @return              Pointer to a buffer, or NULL if the buffer is too small
00102          */
00103         virtual char *get_netmask(char *buf, nsapi_size_t buflen);
00104 
00105         /** Copies gateway address of the network interface to user supplied buffer
00106          *
00107          * @param    buf        buffer to which gateway address will be copied as "W:X:Y:Z"
00108          * @param    buflen     size of supplied buffer
00109          * @return              Pointer to a buffer, or NULL if the buffer is too small
00110          */
00111         virtual char *get_gateway(char *buf, nsapi_size_t buflen);
00112 
00113     private:
00114         friend LWIP;
00115 
00116         Interface();
00117 
00118         nsapi_error_t set_dhcp();
00119         static void netif_link_irq(struct netif *netif);
00120         static void netif_status_irq(struct netif *netif);
00121         static Interface *our_if_from_netif(struct netif *netif);
00122 
00123     #if LWIP_ETHERNET
00124         static err_t emac_low_level_output(struct netif *netif, struct pbuf *p);
00125         void emac_input(emac_mem_buf_t *buf);
00126         void emac_state_change(bool up);
00127     #if LWIP_IGMP
00128         static err_t emac_igmp_mac_filter(struct netif *netif, const ip4_addr_t *group, enum netif_mac_filter_action action);
00129     #endif
00130     #if LWIP_IPV6_MLD
00131         static err_t emac_mld_mac_filter(struct netif *netif, const ip6_addr_t *group, enum netif_mac_filter_action action);
00132     #endif
00133 
00134         static err_t emac_if_init(struct netif *netif);
00135     #endif
00136 
00137         union {
00138     #if LWIP_ETHERNET
00139             EMAC *emac; /**< HW specific emac implementation */
00140     #endif
00141             void *hw; /**< alternative implementation pointer - used for PPP */
00142         };
00143 
00144         os_semaphore_t linked_sem;
00145         osSemaphoreId_t linked;
00146         os_semaphore_t unlinked_sem;
00147         osSemaphoreId_t unlinked;
00148         os_semaphore_t has_any_addr_sem;
00149         osSemaphoreId_t has_any_addr;
00150     #define HAS_ANY_ADDR 1
00151     #if PREF_ADDR_TIMEOUT
00152         os_semaphore_t has_pref_addr_sem;
00153         osSemaphoreId_t has_pref_addr;
00154     #define HAS_PREF_ADDR 2
00155     #endif
00156     #if BOTH_ADDR_TIMEOUT
00157         os_semaphore_t has_both_addr_sem;
00158         osSemaphoreId_t has_both_addr;
00159     #define HAS_BOTH_ADDR 4
00160     #endif
00161         char has_addr_state;
00162         nsapi_connection_status_t connected;
00163         bool dhcp_started;
00164         bool dhcp_has_to_be_set;
00165         bool blocking;
00166         bool ppp;
00167         mbed::Callback<void(nsapi_event_t, intptr_t)> client_callback;
00168         struct netif netif;
00169         static Interface *list;
00170         Interface *next;
00171         LWIPMemoryManager *memory_manager;
00172     };
00173 
00174     /** Register a network interface with the IP stack
00175      *
00176      * Connects EMAC layer with the IP stack and initializes all the required infrastructure.
00177      * This function should be called only once for each available interface.
00178      *
00179      * @param      emac             EMAC HAL implementation for this network interface
00180      * @param      default_if       true if the interface should be treated as the default one
00181      * @param[out] interface_out    pointer to stack interface object controlling the EMAC
00182      * @return                      NSAPI_ERROR_OK on success, or error code
00183      */
00184     virtual nsapi_error_t add_ethernet_interface(EMAC &emac, bool default_if, OnboardNetworkStack::Interface **interface_out);
00185 
00186     /** Register a PPP interface with the IP stack
00187      *
00188      * Connects PPP layer with the IP stack and initializes all the required infrastructure.
00189      * This function should be called only once for each available interface.
00190      *
00191      * This is an internal function that links ppp_lwip.cpp to mbed_ipstack_lwip.cpp,
00192      * once a driver starts it via the nsapi_ppp.h API.
00193      *
00194      * Ultimately the nsapi_ppp.h API will be deprecated, and there will be a
00195      * mbed_ipstack_add_ppp_interface() replacing nsapi_ppp_connect().
00196      *
00197      * @param      pcb              PPP implementation specific user data; will be passed to PPP callbacks
00198      * @param      default_if       true if the interface should be treated as the default one
00199      * @param      stack            Allow manual selection of IPv4 and/or IPv6
00200      * @param[out] interface_out    set to interface handle that must be passed to subsequent mbed_stack calls
00201      * @return                      NSAPI_ERROR_OK on success, or error code
00202      */
00203     nsapi_error_t _add_ppp_interface(void *pcb, bool default_if, nsapi_ip_stack_t stack, LWIP::Interface **interface_out);
00204 
00205     /** Get a domain name server from a list of servers to query
00206      *
00207      *  Returns a DNS server address for a index. If returns error no more
00208      *  DNS servers to read.
00209      *
00210      *  @param index    Index of the DNS server, starts from zero
00211      *  @param address  Destination for the host address
00212      *  @return         0 on success, negative error code on failure
00213      */
00214     virtual nsapi_error_t get_dns_server(int index, SocketAddress *address);
00215 
00216     /** Get the local IP address
00217      *
00218      *  @return         Null-terminated representation of the local IP address
00219      *                  or null if not yet connected
00220      */
00221     virtual const char *get_ip_address();
00222 
00223 protected:
00224     LWIP();
00225     virtual ~LWIP() {}
00226 
00227     /** Opens a socket
00228      *
00229      *  Creates a network socket and stores it in the specified handle.
00230      *  The handle must be passed to following calls on the socket.
00231      *
00232      *  A stack may have a finite number of sockets, in this case
00233      *  NSAPI_ERROR_NO_SOCKET is returned if no socket is available.
00234      *
00235      *  @param handle   Destination for the handle to a newly created socket
00236      *  @param proto    Protocol of socket to open, NSAPI_TCP or NSAPI_UDP
00237      *  @return         0 on success, negative error code on failure
00238      */
00239     virtual nsapi_error_t socket_open(nsapi_socket_t *handle, nsapi_protocol_t proto);
00240 
00241     /** Close the socket
00242      *
00243      *  Closes any open connection and deallocates any memory associated
00244      *  with the socket.
00245      *
00246      *  @param handle   Socket handle
00247      *  @return         0 on success, negative error code on failure
00248      */
00249     virtual nsapi_error_t socket_close(nsapi_socket_t handle);
00250 
00251     /** Bind a specific address to a socket
00252      *
00253      *  Binding a socket specifies the address and port on which to recieve
00254      *  data. If the IP address is zeroed, only the port is bound.
00255      *
00256      *  @param handle   Socket handle
00257      *  @param address  Local address to bind
00258      *  @return         0 on success, negative error code on failure.
00259      */
00260     virtual nsapi_error_t socket_bind(nsapi_socket_t handle, const SocketAddress &address);
00261 
00262     /** Listen for connections on a TCP socket
00263      *
00264      *  Marks the socket as a passive socket that can be used to accept
00265      *  incoming connections.
00266      *
00267      *  @param handle   Socket handle
00268      *  @param backlog  Number of pending connections that can be queued
00269      *                  simultaneously
00270      *  @return         0 on success, negative error code on failure
00271      */
00272     virtual nsapi_error_t socket_listen(nsapi_socket_t handle, int backlog);
00273 
00274     /** Connects TCP socket to a remote host
00275      *
00276      *  Initiates a connection to a remote server specified by the
00277      *  indicated address.
00278      *
00279      *  @param handle   Socket handle
00280      *  @param address  The SocketAddress of the remote host
00281      *  @return         0 on success, negative error code on failure
00282      */
00283     virtual nsapi_error_t socket_connect(nsapi_socket_t handle, const SocketAddress &address);
00284 
00285     /** Accepts a connection on a TCP socket
00286      *
00287      *  The server socket must be bound and set to listen for connections.
00288      *  On a new connection, creates a network socket and stores it in the
00289      *  specified handle. The handle must be passed to following calls on
00290      *  the socket.
00291      *
00292      *  A stack may have a finite number of sockets, in this case
00293      *  NSAPI_ERROR_NO_SOCKET is returned if no socket is available.
00294      *
00295      *  This call is non-blocking. If accept would block,
00296      *  NSAPI_ERROR_WOULD_BLOCK is returned immediately.
00297      *
00298      *  @param server   Socket handle to server to accept from
00299      *  @param handle   Destination for a handle to the newly created socket
00300      *  @param address  Destination for the remote address or NULL
00301      *  @return         0 on success, negative error code on failure
00302      */
00303     virtual nsapi_error_t socket_accept(nsapi_socket_t server,
00304                                         nsapi_socket_t *handle, SocketAddress *address=0);
00305 
00306     /** Send data over a TCP socket
00307      *
00308      *  The socket must be connected to a remote host. Returns the number of
00309      *  bytes sent from the buffer.
00310      *
00311      *  This call is non-blocking. If send would block,
00312      *  NSAPI_ERROR_WOULD_BLOCK is returned immediately.
00313      *
00314      *  @param handle   Socket handle
00315      *  @param data     Buffer of data to send to the host
00316      *  @param size     Size of the buffer in bytes
00317      *  @return         Number of sent bytes on success, negative error
00318      *                  code on failure
00319      */
00320     virtual nsapi_size_or_error_t socket_send(nsapi_socket_t handle,
00321                                               const void *data, nsapi_size_t size);
00322 
00323     /** Receive data over a TCP socket
00324      *
00325      *  The socket must be connected to a remote host. Returns the number of
00326      *  bytes received into the buffer.
00327      *
00328      *  This call is non-blocking. If recv would block,
00329      *  NSAPI_ERROR_WOULD_BLOCK is returned immediately.
00330      *
00331      *  @param handle   Socket handle
00332      *  @param data     Destination buffer for data received from the host
00333      *  @param size     Size of the buffer in bytes
00334      *  @return         Number of received bytes on success, negative error
00335      *                  code on failure
00336      */
00337     virtual nsapi_size_or_error_t socket_recv(nsapi_socket_t handle,
00338                                               void *data, nsapi_size_t size);
00339 
00340     /** Send a packet over a UDP socket
00341      *
00342      *  Sends data to the specified address. Returns the number of bytes
00343      *  sent from the buffer.
00344      *
00345      *  This call is non-blocking. If sendto would block,
00346      *  NSAPI_ERROR_WOULD_BLOCK is returned immediately.
00347      *
00348      *  @param handle   Socket handle
00349      *  @param address  The SocketAddress of the remote host
00350      *  @param data     Buffer of data to send to the host
00351      *  @param size     Size of the buffer in bytes
00352      *  @return         Number of sent bytes on success, negative error
00353      *                  code on failure
00354      */
00355     virtual nsapi_size_or_error_t socket_sendto(nsapi_socket_t handle, const SocketAddress &address,
00356                                                 const void *data, nsapi_size_t size);
00357 
00358     /** Receive a packet over a UDP socket
00359      *
00360      *  Receives data and stores the source address in address if address
00361      *  is not NULL. Returns the number of bytes received into the buffer.
00362      *
00363      *  This call is non-blocking. If recvfrom would block,
00364      *  NSAPI_ERROR_WOULD_BLOCK is returned immediately.
00365      *
00366      *  @param handle   Socket handle
00367      *  @param address  Destination for the source address or NULL
00368      *  @param buffer   Destination buffer for data received from the host
00369      *  @param size     Size of the buffer in bytes
00370      *  @return         Number of received bytes on success, negative error
00371      *                  code on failure
00372      */
00373     virtual nsapi_size_or_error_t socket_recvfrom(nsapi_socket_t handle, SocketAddress *address,
00374                                                   void *buffer, nsapi_size_t size);
00375 
00376     /** Register a callback on state change of the socket
00377      *
00378      *  The specified callback will be called on state changes such as when
00379      *  the socket can recv/send/accept successfully and on when an error
00380      *  occurs. The callback may also be called spuriously without reason.
00381      *
00382      *  The callback may be called in an interrupt context and should not
00383      *  perform expensive operations such as recv/send calls.
00384      *
00385      *  @param handle   Socket handle
00386      *  @param callback Function to call on state change
00387      *  @param data     Argument to pass to callback
00388      */
00389     virtual void socket_attach(nsapi_socket_t handle, void (*callback)(void *), void *data);
00390 
00391     /*  Set stack-specific socket options
00392      *
00393      *  The setsockopt allow an application to pass stack-specific hints
00394      *  to the underlying stack. For unsupported options,
00395      *  NSAPI_ERROR_UNSUPPORTED is returned and the socket is unmodified.
00396      *
00397      *  @param handle   Socket handle
00398      *  @param level    Stack-specific protocol level
00399      *  @param optname  Stack-specific option identifier
00400      *  @param optval   Option value
00401      *  @param optlen   Length of the option value
00402      *  @return         0 on success, negative error code on failure
00403      */
00404     virtual nsapi_error_t setsockopt(nsapi_socket_t handle, int level,
00405                                      int optname, const void *optval, unsigned optlen);
00406 
00407     /*  Get stack-specific socket options
00408      *
00409      *  The getstackopt allow an application to retrieve stack-specific hints
00410      *  from the underlying stack. For unsupported options,
00411      *  NSAPI_ERROR_UNSUPPORTED is returned and optval is unmodified.
00412      *
00413      *  @param handle   Socket handle
00414      *  @param level    Stack-specific protocol level
00415      *  @param optname  Stack-specific option identifier
00416      *  @param optval   Destination for option value
00417      *  @param optlen   Length of the option value
00418      *  @return         0 on success, negative error code on failure
00419      */
00420     virtual nsapi_error_t getsockopt(nsapi_socket_t handle, int level,
00421                                      int optname, void *optval, unsigned *optlen);
00422 private:
00423 
00424     /** Call in callback
00425       *
00426       *  Callback is used to call the call in method of the network stack.
00427       */
00428     typedef mbed::Callback<nsapi_error_t (int delay_ms, mbed::Callback<void()> user_cb)> call_in_callback_cb_t;
00429 
00430     /** Get a call in callback
00431      *
00432      *  Get a call in callback from the network stack context.
00433      *
00434      *  Callback should not take more than 10ms to execute, otherwise it might
00435      *  prevent underlying thread processing. A portable user of the callback
00436      *  should not make calls to network operations due to stack size limitations.
00437      *  The callback should not perform expensive operations such as socket recv/send
00438      *  calls or blocking operations.
00439      *
00440      *  @return         Call in callback
00441      */
00442     virtual call_in_callback_cb_t get_call_in_callback();
00443 
00444     /** Call a callback after a delay
00445      *
00446      *  Call a callback from the network stack context after a delay. If function
00447      *  returns error callback will not be called.
00448      *
00449      *  @param delay    Delay in milliseconds
00450      *  @param func     Callback to be called
00451      *  @return         0 on success, negative error code on failure
00452      */
00453     nsapi_error_t call_in(int delay, mbed::Callback<void()> func);
00454 
00455     struct mbed_lwip_socket {
00456         bool in_use;
00457 
00458         struct netconn *conn;
00459         struct netbuf *buf;
00460         u16_t offset;
00461 
00462         void (*cb)(void *);
00463         void *data;
00464 
00465         // Track multicast addresses subscribed to by this socket
00466         nsapi_ip_mreq_t *multicast_memberships;
00467         uint32_t         multicast_memberships_count;
00468         uint32_t         multicast_memberships_registry;
00469     };
00470 
00471     struct lwip_callback {
00472         unsigned int delay;
00473         mbed::Callback<void()> callback;
00474     };
00475 
00476     static nsapi_error_t err_remap(err_t err);
00477     static bool is_local_addr(const ip_addr_t *ip_addr);
00478     static const ip_addr_t *get_ip_addr(bool any_addr, const struct netif *netif);
00479     static const ip_addr_t *get_ipv4_addr(const struct netif *netif);
00480     static const ip_addr_t *get_ipv6_addr(const struct netif *netif);
00481 
00482     static void add_dns_addr(struct netif *lwip_netif);
00483 
00484     /* Static arena of sockets */
00485     struct mbed_lwip_socket arena[MEMP_NUM_NETCONN];
00486     void arena_init(void);
00487     struct mbed_lwip_socket *arena_alloc();
00488     void arena_dealloc(struct mbed_lwip_socket *s);
00489 
00490     static uint32_t next_registered_multicast_member(const struct mbed_lwip_socket *s, uint32_t index) {
00491         while (!(s->multicast_memberships_registry & (0x0001 << index))) { index++; }
00492         return index;
00493     }
00494 
00495     static uint32_t next_free_multicast_member(const struct mbed_lwip_socket *s, uint32_t index) {
00496         while ((s->multicast_memberships_registry & (0x0001 << index))) { index++; }
00497         return index;
00498     }
00499 
00500     static void set_multicast_member_registry_bit(struct mbed_lwip_socket *s, uint32_t index) {
00501         s->multicast_memberships_registry |= (0x0001 << index);
00502     }
00503 
00504     static void clear_multicast_member_registry_bit(struct mbed_lwip_socket *s, uint32_t index) {
00505         s->multicast_memberships_registry &= ~(0x0001 << index);
00506     }
00507     static int32_t find_multicast_member(const struct mbed_lwip_socket *s, const nsapi_ip_mreq_t *imr);
00508 
00509     static void socket_callback(struct netconn *nc, enum netconn_evt eh, u16_t len);
00510 
00511     static void tcpip_init_irq(void *handle);
00512     static void tcpip_thread_callback(void *ptr);
00513 
00514     char ip_address[40];
00515     rtos::Semaphore tcpip_inited;
00516     Interface *default_interface;
00517     LWIPMemoryManager memory_manager;
00518     osThreadId tcpip_thread_id;
00519     rtos::Mutex adaptation;
00520 };
00521 
00522 #endif /* LWIPSTACK_H_ */