1/**
2 * @file
3 * Network Interface Sequential API module
4 *
5 * @defgroup netifapi NETIF API
6 * @ingroup sequential_api
7 * Thread-safe functions to be called from non-TCPIP threads
8 *
9 * @defgroup netifapi_netif NETIF related
10 * @ingroup netifapi
11 * To be called from non-TCPIP threads
12 */
13
14/*
15 * Redistribution and use in source and binary forms, with or without modification,
16 * are permitted provided that the following conditions are met:
17 *
18 * 1. Redistributions of source code must retain the above copyright notice,
19 *    this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright notice,
21 *    this list of conditions and the following disclaimer in the documentation
22 *    and/or other materials provided with the distribution.
23 * 3. The name of the author may not be used to endorse or promote products
24 *    derived from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
27 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
28 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
29 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
31 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
34 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
35 * OF SUCH DAMAGE.
36 *
37 * This file is part of the lwIP TCP/IP stack.
38 *
39 */
40
41#include "lwip/opt.h"
42
43#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */
44
45#include "lwip/etharp.h"
46#include "lwip/netifapi.h"
47#include "lwip/memp.h"
48#include "lwip/priv/tcpip_priv.h"
49
50#include <string.h> /* strncpy */
51
52#define NETIFAPI_VAR_REF(name)      API_VAR_REF(name)
53#define NETIFAPI_VAR_DECLARE(name)  API_VAR_DECLARE(struct netifapi_msg, name)
54#define NETIFAPI_VAR_ALLOC(name)    API_VAR_ALLOC(struct netifapi_msg, MEMP_NETIFAPI_MSG, name, ERR_MEM)
55#define NETIFAPI_VAR_FREE(name)     API_VAR_FREE(MEMP_NETIFAPI_MSG, name)
56
57/**
58 * Call netif_add() inside the tcpip_thread context.
59 */
60static err_t
61netifapi_do_netif_add(struct tcpip_api_call_data *m)
62{
63  /* cast through void* to silence alignment warnings.
64   * We know it works because the structs have been instantiated as struct netifapi_msg */
65  struct netifapi_msg *msg = (struct netifapi_msg *)(void *)m;
66
67  if (!netif_add( msg->netif,
68#if LWIP_IPV4
69                  API_EXPR_REF(msg->msg.add.ipaddr),
70                  API_EXPR_REF(msg->msg.add.netmask),
71                  API_EXPR_REF(msg->msg.add.gw),
72#endif /* LWIP_IPV4 */
73                  msg->msg.add.state,
74                  msg->msg.add.init,
75                  msg->msg.add.input)) {
76    return ERR_IF;
77  } else {
78    return ERR_OK;
79  }
80}
81
82#if LWIP_IPV4
83/**
84 * Call netif_set_addr() inside the tcpip_thread context.
85 */
86static err_t
87netifapi_do_netif_set_addr(struct tcpip_api_call_data *m)
88{
89  /* cast through void* to silence alignment warnings.
90   * We know it works because the structs have been instantiated as struct netifapi_msg */
91  struct netifapi_msg *msg = (struct netifapi_msg *)(void *)m;
92
93  netif_set_addr( msg->netif,
94                  API_EXPR_REF(msg->msg.add.ipaddr),
95                  API_EXPR_REF(msg->msg.add.netmask),
96                  API_EXPR_REF(msg->msg.add.gw));
97  return ERR_OK;
98}
99#endif /* LWIP_IPV4 */
100
101/**
102* Call netif_name_to_index() inside the tcpip_thread context.
103*/
104static err_t
105netifapi_do_name_to_index(struct tcpip_api_call_data *m)
106{
107  /* cast through void* to silence alignment warnings.
108   * We know it works because the structs have been instantiated as struct netifapi_msg */
109  struct netifapi_msg *msg = (struct netifapi_msg *)(void *)m;
110
111  msg->msg.ifs.index = netif_name_to_index(msg->msg.ifs.name);
112  return ERR_OK;
113}
114
115/**
116* Call netif_index_to_name() inside the tcpip_thread context.
117*/
118static err_t
119netifapi_do_index_to_name(struct tcpip_api_call_data *m)
120{
121  /* cast through void* to silence alignment warnings.
122   * We know it works because the structs have been instantiated as struct netifapi_msg */
123  struct netifapi_msg *msg = (struct netifapi_msg *)(void *)m;
124
125  if (!netif_index_to_name(msg->msg.ifs.index, msg->msg.ifs.name)) {
126    /* return failure via empty name */
127    msg->msg.ifs.name[0] = '\0';
128  }
129  return ERR_OK;
130}
131
132/**
133 * Call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) inside the
134 * tcpip_thread context.
135 */
136static err_t
137netifapi_do_netif_common(struct tcpip_api_call_data *m)
138{
139  /* cast through void* to silence alignment warnings.
140   * We know it works because the structs have been instantiated as struct netifapi_msg */
141  struct netifapi_msg *msg = (struct netifapi_msg *)(void *)m;
142
143  if (msg->msg.common.errtfunc != NULL) {
144    return msg->msg.common.errtfunc(msg->netif);
145  } else {
146    msg->msg.common.voidfunc(msg->netif);
147    return ERR_OK;
148  }
149}
150
151#if LWIP_ARP && LWIP_IPV4
152/**
153 * @ingroup netifapi_arp
154 * Add or update an entry in the ARP cache.
155 * For an update, ipaddr is used to find the cache entry.
156 *
157 * @param ipaddr IPv4 address of cache entry
158 * @param ethaddr hardware address mapped to ipaddr
159 * @param type type of ARP cache entry
160 * @return ERR_OK: entry added/updated, else error from err_t
161 */
162err_t
163netifapi_arp_add(const ip4_addr_t *ipaddr, struct eth_addr *ethaddr, enum netifapi_arp_entry type)
164{
165  err_t err;
166
167  /* We only support permanent entries currently */
168  LWIP_UNUSED_ARG(type);
169
170#if ETHARP_SUPPORT_STATIC_ENTRIES && LWIP_TCPIP_CORE_LOCKING
171  LOCK_TCPIP_CORE();
172  err = etharp_add_static_entry(ipaddr, ethaddr);
173  UNLOCK_TCPIP_CORE();
174#else
175  /* @todo add new vars to struct netifapi_msg and create a 'do' func */
176  LWIP_UNUSED_ARG(ipaddr);
177  LWIP_UNUSED_ARG(ethaddr);
178  err = ERR_VAL;
179#endif /* ETHARP_SUPPORT_STATIC_ENTRIES && LWIP_TCPIP_CORE_LOCKING */
180
181  return err;
182}
183
184/**
185 * @ingroup netifapi_arp
186 * Remove an entry in the ARP cache identified by ipaddr
187 *
188 * @param ipaddr IPv4 address of cache entry
189 * @param type type of ARP cache entry
190 * @return ERR_OK: entry removed, else error from err_t
191 */
192err_t
193netifapi_arp_remove(const ip4_addr_t *ipaddr, enum netifapi_arp_entry type)
194{
195  err_t err;
196
197  /* We only support permanent entries currently */
198  LWIP_UNUSED_ARG(type);
199
200#if ETHARP_SUPPORT_STATIC_ENTRIES && LWIP_TCPIP_CORE_LOCKING
201  LOCK_TCPIP_CORE();
202  err = etharp_remove_static_entry(ipaddr);
203  UNLOCK_TCPIP_CORE();
204#else
205  /* @todo add new vars to struct netifapi_msg and create a 'do' func */
206  LWIP_UNUSED_ARG(ipaddr);
207  err = ERR_VAL;
208#endif /* ETHARP_SUPPORT_STATIC_ENTRIES && LWIP_TCPIP_CORE_LOCKING */
209
210  return err;
211}
212#endif /* LWIP_ARP && LWIP_IPV4 */
213
214/**
215 * @ingroup netifapi_netif
216 * Call netif_add() in a thread-safe way by running that function inside the
217 * tcpip_thread context.
218 *
219 * @note for params @see netif_add()
220 */
221err_t
222netifapi_netif_add(struct netif *netif,
223#if LWIP_IPV4
224                   const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw,
225#endif /* LWIP_IPV4 */
226                   void *state, netif_init_fn init, netif_input_fn input)
227{
228  err_t err;
229  NETIFAPI_VAR_DECLARE(msg);
230  NETIFAPI_VAR_ALLOC(msg);
231
232#if LWIP_IPV4
233  if (ipaddr == NULL) {
234    ipaddr = IP4_ADDR_ANY4;
235  }
236  if (netmask == NULL) {
237    netmask = IP4_ADDR_ANY4;
238  }
239  if (gw == NULL) {
240    gw = IP4_ADDR_ANY4;
241  }
242#endif /* LWIP_IPV4 */
243
244  NETIFAPI_VAR_REF(msg).netif = netif;
245#if LWIP_IPV4
246  NETIFAPI_VAR_REF(msg).msg.add.ipaddr  = NETIFAPI_VAR_REF(ipaddr);
247  NETIFAPI_VAR_REF(msg).msg.add.netmask = NETIFAPI_VAR_REF(netmask);
248  NETIFAPI_VAR_REF(msg).msg.add.gw      = NETIFAPI_VAR_REF(gw);
249#endif /* LWIP_IPV4 */
250  NETIFAPI_VAR_REF(msg).msg.add.state   = state;
251  NETIFAPI_VAR_REF(msg).msg.add.init    = init;
252  NETIFAPI_VAR_REF(msg).msg.add.input   = input;
253  err = tcpip_api_call(netifapi_do_netif_add, &API_VAR_REF(msg).call);
254  NETIFAPI_VAR_FREE(msg);
255  return err;
256}
257
258#if LWIP_IPV4
259/**
260 * @ingroup netifapi_netif
261 * Call netif_set_addr() in a thread-safe way by running that function inside the
262 * tcpip_thread context.
263 *
264 * @note for params @see netif_set_addr()
265 */
266err_t
267netifapi_netif_set_addr(struct netif *netif,
268                        const ip4_addr_t *ipaddr,
269                        const ip4_addr_t *netmask,
270                        const ip4_addr_t *gw)
271{
272  err_t err;
273  NETIFAPI_VAR_DECLARE(msg);
274  NETIFAPI_VAR_ALLOC(msg);
275
276  if (ipaddr == NULL) {
277    ipaddr = IP4_ADDR_ANY4;
278  }
279  if (netmask == NULL) {
280    netmask = IP4_ADDR_ANY4;
281  }
282  if (gw == NULL) {
283    gw = IP4_ADDR_ANY4;
284  }
285
286  NETIFAPI_VAR_REF(msg).netif = netif;
287  NETIFAPI_VAR_REF(msg).msg.add.ipaddr  = NETIFAPI_VAR_REF(ipaddr);
288  NETIFAPI_VAR_REF(msg).msg.add.netmask = NETIFAPI_VAR_REF(netmask);
289  NETIFAPI_VAR_REF(msg).msg.add.gw      = NETIFAPI_VAR_REF(gw);
290  err = tcpip_api_call(netifapi_do_netif_set_addr, &API_VAR_REF(msg).call);
291  NETIFAPI_VAR_FREE(msg);
292  return err;
293}
294#endif /* LWIP_IPV4 */
295
296/**
297 * call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) in a thread-safe
298 * way by running that function inside the tcpip_thread context.
299 *
300 * @note use only for functions where there is only "netif" parameter.
301 */
302err_t
303netifapi_netif_common(struct netif *netif, netifapi_void_fn voidfunc,
304                      netifapi_errt_fn errtfunc)
305{
306  err_t err;
307  NETIFAPI_VAR_DECLARE(msg);
308  NETIFAPI_VAR_ALLOC(msg);
309
310  NETIFAPI_VAR_REF(msg).netif = netif;
311  NETIFAPI_VAR_REF(msg).msg.common.voidfunc = voidfunc;
312  NETIFAPI_VAR_REF(msg).msg.common.errtfunc = errtfunc;
313  err = tcpip_api_call(netifapi_do_netif_common, &API_VAR_REF(msg).call);
314  NETIFAPI_VAR_FREE(msg);
315  return err;
316}
317
318/**
319* @ingroup netifapi_netif
320* Call netif_name_to_index() in a thread-safe way by running that function inside the
321* tcpip_thread context.
322*
323* @param name the interface name of the netif
324* @param idx output index of the found netif
325*/
326err_t
327netifapi_netif_name_to_index(const char *name, u8_t *idx)
328{
329  err_t err;
330  NETIFAPI_VAR_DECLARE(msg);
331  NETIFAPI_VAR_ALLOC(msg);
332
333  *idx = 0;
334
335#if LWIP_MPU_COMPATIBLE
336  strncpy(NETIFAPI_VAR_REF(msg).msg.ifs.name, name, NETIF_NAMESIZE - 1);
337  NETIFAPI_VAR_REF(msg).msg.ifs.name[NETIF_NAMESIZE - 1] = '\0';
338#else
339  NETIFAPI_VAR_REF(msg).msg.ifs.name = LWIP_CONST_CAST(char *, name);
340#endif /* LWIP_MPU_COMPATIBLE */
341  err = tcpip_api_call(netifapi_do_name_to_index, &API_VAR_REF(msg).call);
342  if (!err) {
343    *idx = NETIFAPI_VAR_REF(msg).msg.ifs.index;
344  }
345  NETIFAPI_VAR_FREE(msg);
346  return err;
347}
348
349/**
350* @ingroup netifapi_netif
351* Call netif_index_to_name() in a thread-safe way by running that function inside the
352* tcpip_thread context.
353*
354* @param idx the interface index of the netif
355* @param name output name of the found netif, empty '\0' string if netif not found.
356*             name should be of at least NETIF_NAMESIZE bytes
357*/
358err_t
359netifapi_netif_index_to_name(u8_t idx, char *name)
360{
361  err_t err;
362  NETIFAPI_VAR_DECLARE(msg);
363  NETIFAPI_VAR_ALLOC(msg);
364
365  NETIFAPI_VAR_REF(msg).msg.ifs.index = idx;
366#if !LWIP_MPU_COMPATIBLE
367  NETIFAPI_VAR_REF(msg).msg.ifs.name = name;
368#endif /* LWIP_MPU_COMPATIBLE */
369  err = tcpip_api_call(netifapi_do_index_to_name, &API_VAR_REF(msg).call);
370#if LWIP_MPU_COMPATIBLE
371  if (!err) {
372    strncpy(name, NETIFAPI_VAR_REF(msg).msg.ifs.name, NETIF_NAMESIZE - 1);
373    name[NETIF_NAMESIZE - 1] = '\0';
374  }
375#endif /* LWIP_MPU_COMPATIBLE */
376  NETIFAPI_VAR_FREE(msg);
377  return err;
378}
379
380#endif /* LWIP_NETIF_API */
381