/src/tinyusb/lib/lwip/src/core/netif.c
Line | Count | Source (jump to first uncovered line) |
1 | | /** |
2 | | * @file |
3 | | * lwIP network interface abstraction |
4 | | * |
5 | | * @defgroup netif Network interface (NETIF) |
6 | | * @ingroup callbackstyle_api |
7 | | * |
8 | | * @defgroup netif_ip4 IPv4 address handling |
9 | | * @ingroup netif |
10 | | * |
11 | | * @defgroup netif_ip6 IPv6 address handling |
12 | | * @ingroup netif |
13 | | * |
14 | | * @defgroup netif_cd Client data handling |
15 | | * Store data (void*) on a netif for application usage. |
16 | | * @see @ref LWIP_NUM_NETIF_CLIENT_DATA |
17 | | * @ingroup netif |
18 | | */ |
19 | | |
20 | | /* |
21 | | * Copyright (c) 2001-2004 Swedish Institute of Computer Science. |
22 | | * All rights reserved. |
23 | | * |
24 | | * Redistribution and use in source and binary forms, with or without modification, |
25 | | * are permitted provided that the following conditions are met: |
26 | | * |
27 | | * 1. Redistributions of source code must retain the above copyright notice, |
28 | | * this list of conditions and the following disclaimer. |
29 | | * 2. Redistributions in binary form must reproduce the above copyright notice, |
30 | | * this list of conditions and the following disclaimer in the documentation |
31 | | * and/or other materials provided with the distribution. |
32 | | * 3. The name of the author may not be used to endorse or promote products |
33 | | * derived from this software without specific prior written permission. |
34 | | * |
35 | | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED |
36 | | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
37 | | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT |
38 | | * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
39 | | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
40 | | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
41 | | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
42 | | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
43 | | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY |
44 | | * OF SUCH DAMAGE. |
45 | | * |
46 | | * This file is part of the lwIP TCP/IP stack. |
47 | | * |
48 | | * Author: Adam Dunkels <adam@sics.se> |
49 | | */ |
50 | | |
51 | | #include "lwip/opt.h" |
52 | | |
53 | | #include <string.h> /* memset */ |
54 | | #include <stdlib.h> /* atoi */ |
55 | | |
56 | | #include "lwip/def.h" |
57 | | #include "lwip/ip_addr.h" |
58 | | #include "lwip/ip6_addr.h" |
59 | | #include "lwip/netif.h" |
60 | | #include "lwip/priv/tcp_priv.h" |
61 | | #include "lwip/udp.h" |
62 | | #include "lwip/priv/raw_priv.h" |
63 | | #include "lwip/snmp.h" |
64 | | #include "lwip/igmp.h" |
65 | | #include "lwip/etharp.h" |
66 | | #include "lwip/stats.h" |
67 | | #include "lwip/sys.h" |
68 | | #include "lwip/ip.h" |
69 | | #if ENABLE_LOOPBACK |
70 | | #if LWIP_NETIF_LOOPBACK_MULTITHREADING |
71 | | #include "lwip/tcpip.h" |
72 | | #endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ |
73 | | #endif /* ENABLE_LOOPBACK */ |
74 | | |
75 | | #include "netif/ethernet.h" |
76 | | |
77 | | #if LWIP_AUTOIP |
78 | | #include "lwip/autoip.h" |
79 | | #endif /* LWIP_AUTOIP */ |
80 | | #if LWIP_DHCP |
81 | | #include "lwip/dhcp.h" |
82 | | #endif /* LWIP_DHCP */ |
83 | | #if LWIP_IPV6_DHCP6 |
84 | | #include "lwip/dhcp6.h" |
85 | | #endif /* LWIP_IPV6_DHCP6 */ |
86 | | #if LWIP_IPV6_MLD |
87 | | #include "lwip/mld6.h" |
88 | | #endif /* LWIP_IPV6_MLD */ |
89 | | #if LWIP_IPV6 |
90 | | #include "lwip/nd6.h" |
91 | | #endif |
92 | | |
93 | | #if LWIP_NETIF_STATUS_CALLBACK |
94 | | #define NETIF_STATUS_CALLBACK(n) do{ if (n->status_callback) { (n->status_callback)(n); }}while(0) |
95 | | #else |
96 | | #define NETIF_STATUS_CALLBACK(n) |
97 | | #endif /* LWIP_NETIF_STATUS_CALLBACK */ |
98 | | |
99 | | #if LWIP_NETIF_LINK_CALLBACK |
100 | | #define NETIF_LINK_CALLBACK(n) do{ if (n->link_callback) { (n->link_callback)(n); }}while(0) |
101 | | #else |
102 | | #define NETIF_LINK_CALLBACK(n) |
103 | | #endif /* LWIP_NETIF_LINK_CALLBACK */ |
104 | | |
105 | | #if LWIP_NETIF_EXT_STATUS_CALLBACK |
106 | | static netif_ext_callback_t *ext_callback; |
107 | | #endif |
108 | | |
109 | | #if !LWIP_SINGLE_NETIF |
110 | | struct netif *netif_list; |
111 | | #endif /* !LWIP_SINGLE_NETIF */ |
112 | | struct netif *netif_default; |
113 | | |
114 | 0 | #define netif_index_to_num(index) ((index) - 1) |
115 | | static u8_t netif_num; |
116 | | |
117 | | #if LWIP_NUM_NETIF_CLIENT_DATA > 0 |
118 | | static u8_t netif_client_id; |
119 | | #endif |
120 | | |
121 | 0 | #define NETIF_REPORT_TYPE_IPV4 0x01 |
122 | 0 | #define NETIF_REPORT_TYPE_IPV6 0x02 |
123 | | static void netif_issue_reports(struct netif *netif, u8_t report_type); |
124 | | |
125 | | #if LWIP_IPV6 |
126 | | static err_t netif_null_output_ip6(struct netif *netif, struct pbuf *p, const ip6_addr_t *ipaddr); |
127 | | #endif /* LWIP_IPV6 */ |
128 | | #if LWIP_IPV4 |
129 | | static err_t netif_null_output_ip4(struct netif *netif, struct pbuf *p, const ip4_addr_t *ipaddr); |
130 | | #endif /* LWIP_IPV4 */ |
131 | | |
132 | | #if LWIP_HAVE_LOOPIF |
133 | | #if LWIP_IPV4 |
134 | | static err_t netif_loop_output_ipv4(struct netif *netif, struct pbuf *p, const ip4_addr_t *addr); |
135 | | #endif |
136 | | #if LWIP_IPV6 |
137 | | static err_t netif_loop_output_ipv6(struct netif *netif, struct pbuf *p, const ip6_addr_t *addr); |
138 | | #endif |
139 | | |
140 | | |
141 | | static struct netif loop_netif; |
142 | | |
143 | | /** |
144 | | * Initialize a lwip network interface structure for a loopback interface |
145 | | * |
146 | | * @param netif the lwip network interface structure for this loopif |
147 | | * @return ERR_OK if the loopif is initialized |
148 | | * ERR_MEM if private data couldn't be allocated |
149 | | */ |
150 | | static err_t |
151 | | netif_loopif_init(struct netif *netif) |
152 | | { |
153 | | LWIP_ASSERT("netif_loopif_init: invalid netif", netif != NULL); |
154 | | |
155 | | /* initialize the snmp variables and counters inside the struct netif |
156 | | * ifSpeed: no assumption can be made! |
157 | | */ |
158 | | MIB2_INIT_NETIF(netif, snmp_ifType_softwareLoopback, 0); |
159 | | |
160 | | netif->name[0] = 'l'; |
161 | | netif->name[1] = 'o'; |
162 | | #if LWIP_IPV4 |
163 | | netif->output = netif_loop_output_ipv4; |
164 | | #endif |
165 | | #if LWIP_IPV6 |
166 | | netif->output_ip6 = netif_loop_output_ipv6; |
167 | | #endif |
168 | | #if LWIP_LOOPIF_MULTICAST |
169 | | netif_set_flags(netif, NETIF_FLAG_IGMP); |
170 | | #endif |
171 | | NETIF_SET_CHECKSUM_CTRL(netif, NETIF_CHECKSUM_DISABLE_ALL); |
172 | | return ERR_OK; |
173 | | } |
174 | | #endif /* LWIP_HAVE_LOOPIF */ |
175 | | |
176 | | void |
177 | | netif_init(void) |
178 | 0 | { |
179 | | #if LWIP_HAVE_LOOPIF |
180 | | #if LWIP_IPV4 |
181 | | #define LOOPIF_ADDRINIT &loop_ipaddr, &loop_netmask, &loop_gw, |
182 | | ip4_addr_t loop_ipaddr, loop_netmask, loop_gw; |
183 | | IP4_ADDR(&loop_gw, 127, 0, 0, 1); |
184 | | IP4_ADDR(&loop_ipaddr, 127, 0, 0, 1); |
185 | | IP4_ADDR(&loop_netmask, 255, 0, 0, 0); |
186 | | #else /* LWIP_IPV4 */ |
187 | | #define LOOPIF_ADDRINIT |
188 | | #endif /* LWIP_IPV4 */ |
189 | | |
190 | | #if NO_SYS |
191 | | netif_add(&loop_netif, LOOPIF_ADDRINIT NULL, netif_loopif_init, ip_input); |
192 | | #else /* NO_SYS */ |
193 | | netif_add(&loop_netif, LOOPIF_ADDRINIT NULL, netif_loopif_init, tcpip_input); |
194 | | #endif /* NO_SYS */ |
195 | | |
196 | | #if LWIP_IPV6 |
197 | | IP_ADDR6_HOST(loop_netif.ip6_addr, 0, 0, 0, 0x00000001UL); |
198 | | loop_netif.ip6_addr_state[0] = IP6_ADDR_VALID; |
199 | | #endif /* LWIP_IPV6 */ |
200 | | |
201 | | netif_set_link_up(&loop_netif); |
202 | | netif_set_up(&loop_netif); |
203 | | |
204 | | #endif /* LWIP_HAVE_LOOPIF */ |
205 | 0 | } |
206 | | |
207 | | /** |
208 | | * @ingroup lwip_nosys |
209 | | * Forwards a received packet for input processing with |
210 | | * ethernet_input() or ip_input() depending on netif flags. |
211 | | * Don't call directly, pass to netif_add() and call |
212 | | * netif->input(). |
213 | | * Only works if the netif driver correctly sets |
214 | | * NETIF_FLAG_ETHARP and/or NETIF_FLAG_ETHERNET flag! |
215 | | */ |
216 | | err_t |
217 | | netif_input(struct pbuf *p, struct netif *inp) |
218 | 0 | { |
219 | 0 | LWIP_ASSERT_CORE_LOCKED(); |
220 | |
|
221 | 0 | LWIP_ASSERT("netif_input: invalid pbuf", p != NULL); |
222 | 0 | LWIP_ASSERT("netif_input: invalid netif", inp != NULL); |
223 | |
|
224 | 0 | #if LWIP_ETHERNET |
225 | 0 | if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) { |
226 | 0 | return ethernet_input(p, inp); |
227 | 0 | } else |
228 | 0 | #endif /* LWIP_ETHERNET */ |
229 | 0 | return ip_input(p, inp); |
230 | 0 | } |
231 | | |
232 | | /** |
233 | | * @ingroup netif |
234 | | * Add a network interface to the list of lwIP netifs. |
235 | | * |
236 | | * Same as @ref netif_add but without IPv4 addresses |
237 | | */ |
238 | | struct netif * |
239 | | netif_add_noaddr(struct netif *netif, void *state, netif_init_fn init, netif_input_fn input) |
240 | 0 | { |
241 | 0 | return netif_add(netif, |
242 | 0 | #if LWIP_IPV4 |
243 | 0 | NULL, NULL, NULL, |
244 | 0 | #endif /* LWIP_IPV4*/ |
245 | 0 | state, init, input); |
246 | 0 | } |
247 | | |
248 | | /** |
249 | | * @ingroup netif |
250 | | * Add a network interface to the list of lwIP netifs. |
251 | | * |
252 | | * @param netif a pre-allocated netif structure |
253 | | * @param ipaddr IP address for the new netif |
254 | | * @param netmask network mask for the new netif |
255 | | * @param gw default gateway IP address for the new netif |
256 | | * @param state opaque data passed to the new netif |
257 | | * @param init callback function that initializes the interface |
258 | | * @param input callback function that is called to pass |
259 | | * ingress packets up in the protocol layer stack.\n |
260 | | * It is recommended to use a function that passes the input directly |
261 | | * to the stack (netif_input(), NO_SYS=1 mode) or via sending a |
262 | | * message to TCPIP thread (tcpip_input(), NO_SYS=0 mode).\n |
263 | | * These functions use netif flags NETIF_FLAG_ETHARP and NETIF_FLAG_ETHERNET |
264 | | * to decide whether to forward to ethernet_input() or ip_input(). |
265 | | * In other words, the functions only work when the netif |
266 | | * driver is implemented correctly!\n |
267 | | * Most members of struct netif should be be initialized by the |
268 | | * netif init function = netif driver (init parameter of this function).\n |
269 | | * IPv6: Don't forget to call netif_create_ip6_linklocal_address() after |
270 | | * setting the MAC address in struct netif.hwaddr |
271 | | * (IPv6 requires a link-local address). |
272 | | * |
273 | | * @return netif, or NULL if failed. |
274 | | */ |
275 | | struct netif * |
276 | | netif_add(struct netif *netif, |
277 | | #if LWIP_IPV4 |
278 | | const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw, |
279 | | #endif /* LWIP_IPV4 */ |
280 | | void *state, netif_init_fn init, netif_input_fn input) |
281 | 0 | { |
282 | | #if LWIP_IPV6 |
283 | | s8_t i; |
284 | | #endif |
285 | |
|
286 | 0 | LWIP_ASSERT_CORE_LOCKED(); |
287 | |
|
288 | 0 | #if LWIP_SINGLE_NETIF |
289 | 0 | if (netif_default != NULL) { |
290 | 0 | LWIP_ASSERT("single netif already set", 0); |
291 | 0 | return NULL; |
292 | 0 | } |
293 | 0 | #endif |
294 | | |
295 | 0 | LWIP_ERROR("netif_add: invalid netif", netif != NULL, return NULL); |
296 | 0 | LWIP_ERROR("netif_add: No init function given", init != NULL, return NULL); |
297 | | |
298 | 0 | #if LWIP_IPV4 |
299 | 0 | if (ipaddr == NULL) { |
300 | 0 | ipaddr = ip_2_ip4(IP4_ADDR_ANY); |
301 | 0 | } |
302 | 0 | if (netmask == NULL) { |
303 | 0 | netmask = ip_2_ip4(IP4_ADDR_ANY); |
304 | 0 | } |
305 | 0 | if (gw == NULL) { |
306 | 0 | gw = ip_2_ip4(IP4_ADDR_ANY); |
307 | 0 | } |
308 | | |
309 | | /* reset new interface configuration state */ |
310 | 0 | ip_addr_set_zero_ip4(&netif->ip_addr); |
311 | 0 | ip_addr_set_zero_ip4(&netif->netmask); |
312 | 0 | ip_addr_set_zero_ip4(&netif->gw); |
313 | 0 | netif->output = netif_null_output_ip4; |
314 | 0 | #endif /* LWIP_IPV4 */ |
315 | | #if LWIP_IPV6 |
316 | | for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { |
317 | | ip_addr_set_zero_ip6(&netif->ip6_addr[i]); |
318 | | netif->ip6_addr_state[i] = IP6_ADDR_INVALID; |
319 | | #if LWIP_IPV6_ADDRESS_LIFETIMES |
320 | | netif->ip6_addr_valid_life[i] = IP6_ADDR_LIFE_STATIC; |
321 | | netif->ip6_addr_pref_life[i] = IP6_ADDR_LIFE_STATIC; |
322 | | #endif /* LWIP_IPV6_ADDRESS_LIFETIMES */ |
323 | | } |
324 | | netif->output_ip6 = netif_null_output_ip6; |
325 | | #endif /* LWIP_IPV6 */ |
326 | 0 | NETIF_SET_CHECKSUM_CTRL(netif, NETIF_CHECKSUM_ENABLE_ALL); |
327 | 0 | netif->mtu = 0; |
328 | 0 | netif->flags = 0; |
329 | | #ifdef netif_get_client_data |
330 | | memset(netif->client_data, 0, sizeof(netif->client_data)); |
331 | | #endif /* LWIP_NUM_NETIF_CLIENT_DATA */ |
332 | | #if LWIP_IPV6 |
333 | | #if LWIP_IPV6_AUTOCONFIG |
334 | | /* IPv6 address autoconfiguration not enabled by default */ |
335 | | netif->ip6_autoconfig_enabled = 0; |
336 | | #endif /* LWIP_IPV6_AUTOCONFIG */ |
337 | | nd6_restart_netif(netif); |
338 | | #endif /* LWIP_IPV6 */ |
339 | | #if LWIP_NETIF_STATUS_CALLBACK |
340 | | netif->status_callback = NULL; |
341 | | #endif /* LWIP_NETIF_STATUS_CALLBACK */ |
342 | | #if LWIP_NETIF_LINK_CALLBACK |
343 | | netif->link_callback = NULL; |
344 | | #endif /* LWIP_NETIF_LINK_CALLBACK */ |
345 | | #if LWIP_IGMP |
346 | | netif->igmp_mac_filter = NULL; |
347 | | #endif /* LWIP_IGMP */ |
348 | | #if LWIP_IPV6 && LWIP_IPV6_MLD |
349 | | netif->mld_mac_filter = NULL; |
350 | | #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ |
351 | | #if ENABLE_LOOPBACK |
352 | | netif->loop_first = NULL; |
353 | | netif->loop_last = NULL; |
354 | | #endif /* ENABLE_LOOPBACK */ |
355 | | |
356 | | /* remember netif specific state information data */ |
357 | 0 | netif->state = state; |
358 | 0 | netif->num = netif_num; |
359 | 0 | netif->input = input; |
360 | |
|
361 | 0 | NETIF_RESET_HINTS(netif); |
362 | | #if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS |
363 | | netif->loop_cnt_current = 0; |
364 | | #endif /* ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS */ |
365 | |
|
366 | 0 | #if LWIP_IPV4 |
367 | 0 | netif_set_addr(netif, ipaddr, netmask, gw); |
368 | 0 | #endif /* LWIP_IPV4 */ |
369 | | |
370 | | /* call user specified initialization function for netif */ |
371 | 0 | if (init(netif) != ERR_OK) { |
372 | 0 | return NULL; |
373 | 0 | } |
374 | | #if LWIP_IPV6 && LWIP_ND6_ALLOW_RA_UPDATES |
375 | | /* Initialize the MTU for IPv6 to the one set by the netif driver. |
376 | | This can be updated later by RA. */ |
377 | | netif->mtu6 = netif->mtu; |
378 | | #endif /* LWIP_IPV6 && LWIP_ND6_ALLOW_RA_UPDATES */ |
379 | | |
380 | | #if !LWIP_SINGLE_NETIF |
381 | | /* Assign a unique netif number in the range [0..254], so that (num+1) can |
382 | | serve as an interface index that fits in a u8_t. |
383 | | We assume that the new netif has not yet been added to the list here. |
384 | | This algorithm is O(n^2), but that should be OK for lwIP. |
385 | | */ |
386 | | { |
387 | | struct netif *netif2; |
388 | | int num_netifs; |
389 | | do { |
390 | | if (netif->num == 255) { |
391 | | netif->num = 0; |
392 | | } |
393 | | num_netifs = 0; |
394 | | for (netif2 = netif_list; netif2 != NULL; netif2 = netif2->next) { |
395 | | LWIP_ASSERT("netif already added", netif2 != netif); |
396 | | num_netifs++; |
397 | | LWIP_ASSERT("too many netifs, max. supported number is 255", num_netifs <= 255); |
398 | | if (netif2->num == netif->num) { |
399 | | netif->num++; |
400 | | break; |
401 | | } |
402 | | } |
403 | | } while (netif2 != NULL); |
404 | | } |
405 | | if (netif->num == 254) { |
406 | | netif_num = 0; |
407 | | } else { |
408 | | netif_num = (u8_t)(netif->num + 1); |
409 | | } |
410 | | |
411 | | /* add this netif to the list */ |
412 | | netif->next = netif_list; |
413 | | netif_list = netif; |
414 | | #endif /* "LWIP_SINGLE_NETIF */ |
415 | 0 | mib2_netif_added(netif); |
416 | |
|
417 | | #if LWIP_IGMP |
418 | | /* start IGMP processing */ |
419 | | if (netif->flags & NETIF_FLAG_IGMP) { |
420 | | igmp_start(netif); |
421 | | } |
422 | | #endif /* LWIP_IGMP */ |
423 | |
|
424 | 0 | LWIP_DEBUGF(NETIF_DEBUG, ("netif: added interface %c%c IP", |
425 | 0 | netif->name[0], netif->name[1])); |
426 | 0 | #if LWIP_IPV4 |
427 | 0 | LWIP_DEBUGF(NETIF_DEBUG, (" addr ")); |
428 | 0 | ip4_addr_debug_print(NETIF_DEBUG, ipaddr); |
429 | 0 | LWIP_DEBUGF(NETIF_DEBUG, (" netmask ")); |
430 | 0 | ip4_addr_debug_print(NETIF_DEBUG, netmask); |
431 | 0 | LWIP_DEBUGF(NETIF_DEBUG, (" gw ")); |
432 | 0 | ip4_addr_debug_print(NETIF_DEBUG, gw); |
433 | 0 | #endif /* LWIP_IPV4 */ |
434 | 0 | LWIP_DEBUGF(NETIF_DEBUG, ("\n")); |
435 | |
|
436 | 0 | netif_invoke_ext_callback(netif, LWIP_NSC_NETIF_ADDED, NULL); |
437 | |
|
438 | 0 | return netif; |
439 | 0 | } |
440 | | |
441 | | static void |
442 | | netif_do_ip_addr_changed(const ip_addr_t *old_addr, const ip_addr_t *new_addr) |
443 | 0 | { |
444 | 0 | #if LWIP_TCP |
445 | 0 | tcp_netif_ip_addr_changed(old_addr, new_addr); |
446 | 0 | #endif /* LWIP_TCP */ |
447 | 0 | #if LWIP_UDP |
448 | 0 | udp_netif_ip_addr_changed(old_addr, new_addr); |
449 | 0 | #endif /* LWIP_UDP */ |
450 | | #if LWIP_RAW |
451 | | raw_netif_ip_addr_changed(old_addr, new_addr); |
452 | | #endif /* LWIP_RAW */ |
453 | 0 | } |
454 | | |
455 | | #if LWIP_IPV4 |
456 | | static int |
457 | | netif_do_set_ipaddr(struct netif *netif, const ip4_addr_t *ipaddr, ip_addr_t *old_addr) |
458 | 0 | { |
459 | 0 | LWIP_ASSERT("invalid pointer", ipaddr != NULL); |
460 | 0 | LWIP_ASSERT("invalid pointer", old_addr != NULL); |
461 | | |
462 | | /* address is actually being changed? */ |
463 | 0 | if (ip4_addr_cmp(ipaddr, netif_ip4_addr(netif)) == 0) { |
464 | 0 | ip_addr_t new_addr; |
465 | 0 | *ip_2_ip4(&new_addr) = *ipaddr; |
466 | 0 | IP_SET_TYPE_VAL(new_addr, IPADDR_TYPE_V4); |
467 | |
|
468 | 0 | ip_addr_copy(*old_addr, *netif_ip_addr4(netif)); |
469 | |
|
470 | 0 | LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: netif address being changed\n")); |
471 | 0 | netif_do_ip_addr_changed(old_addr, &new_addr); |
472 | |
|
473 | 0 | mib2_remove_ip4(netif); |
474 | 0 | mib2_remove_route_ip4(0, netif); |
475 | | /* set new IP address to netif */ |
476 | 0 | ip4_addr_set(ip_2_ip4(&netif->ip_addr), ipaddr); |
477 | 0 | IP_SET_TYPE_VAL(netif->ip_addr, IPADDR_TYPE_V4); |
478 | 0 | mib2_add_ip4(netif); |
479 | 0 | mib2_add_route_ip4(0, netif); |
480 | |
|
481 | 0 | netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV4); |
482 | |
|
483 | 0 | NETIF_STATUS_CALLBACK(netif); |
484 | 0 | return 1; /* address changed */ |
485 | 0 | } |
486 | 0 | return 0; /* address unchanged */ |
487 | 0 | } |
488 | | |
489 | | /** |
490 | | * @ingroup netif_ip4 |
491 | | * Change the IP address of a network interface |
492 | | * |
493 | | * @param netif the network interface to change |
494 | | * @param ipaddr the new IP address |
495 | | * |
496 | | * @note call netif_set_addr() if you also want to change netmask and |
497 | | * default gateway |
498 | | */ |
499 | | void |
500 | | netif_set_ipaddr(struct netif *netif, const ip4_addr_t *ipaddr) |
501 | 0 | { |
502 | 0 | ip_addr_t old_addr; |
503 | |
|
504 | 0 | LWIP_ERROR("netif_set_ipaddr: invalid netif", netif != NULL, return); |
505 | | |
506 | | /* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */ |
507 | 0 | if (ipaddr == NULL) { |
508 | 0 | ipaddr = IP4_ADDR_ANY4; |
509 | 0 | } |
510 | |
|
511 | 0 | LWIP_ASSERT_CORE_LOCKED(); |
512 | |
|
513 | 0 | if (netif_do_set_ipaddr(netif, ipaddr, &old_addr)) { |
514 | | #if LWIP_NETIF_EXT_STATUS_CALLBACK |
515 | | netif_ext_callback_args_t args; |
516 | | args.ipv4_changed.old_address = &old_addr; |
517 | | netif_invoke_ext_callback(netif, LWIP_NSC_IPV4_ADDRESS_CHANGED, &args); |
518 | | #endif |
519 | 0 | } |
520 | 0 | } |
521 | | |
522 | | static int |
523 | | netif_do_set_netmask(struct netif *netif, const ip4_addr_t *netmask, ip_addr_t *old_nm) |
524 | 0 | { |
525 | | /* address is actually being changed? */ |
526 | 0 | if (ip4_addr_cmp(netmask, netif_ip4_netmask(netif)) == 0) { |
527 | | #if LWIP_NETIF_EXT_STATUS_CALLBACK |
528 | | LWIP_ASSERT("invalid pointer", old_nm != NULL); |
529 | | ip_addr_copy(*old_nm, *netif_ip_netmask4(netif)); |
530 | | #else |
531 | 0 | LWIP_UNUSED_ARG(old_nm); |
532 | 0 | #endif |
533 | 0 | mib2_remove_route_ip4(0, netif); |
534 | | /* set new netmask to netif */ |
535 | 0 | ip4_addr_set(ip_2_ip4(&netif->netmask), netmask); |
536 | 0 | IP_SET_TYPE_VAL(netif->netmask, IPADDR_TYPE_V4); |
537 | 0 | mib2_add_route_ip4(0, netif); |
538 | 0 | LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: netmask of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", |
539 | 0 | netif->name[0], netif->name[1], |
540 | 0 | ip4_addr1_16(netif_ip4_netmask(netif)), |
541 | 0 | ip4_addr2_16(netif_ip4_netmask(netif)), |
542 | 0 | ip4_addr3_16(netif_ip4_netmask(netif)), |
543 | 0 | ip4_addr4_16(netif_ip4_netmask(netif)))); |
544 | 0 | return 1; /* netmask changed */ |
545 | 0 | } |
546 | 0 | return 0; /* netmask unchanged */ |
547 | 0 | } |
548 | | |
549 | | /** |
550 | | * @ingroup netif_ip4 |
551 | | * Change the netmask of a network interface |
552 | | * |
553 | | * @param netif the network interface to change |
554 | | * @param netmask the new netmask |
555 | | * |
556 | | * @note call netif_set_addr() if you also want to change ip address and |
557 | | * default gateway |
558 | | */ |
559 | | void |
560 | | netif_set_netmask(struct netif *netif, const ip4_addr_t *netmask) |
561 | 0 | { |
562 | | #if LWIP_NETIF_EXT_STATUS_CALLBACK |
563 | | ip_addr_t old_nm_val; |
564 | | ip_addr_t *old_nm = &old_nm_val; |
565 | | #else |
566 | 0 | ip_addr_t *old_nm = NULL; |
567 | 0 | #endif |
568 | 0 | LWIP_ASSERT_CORE_LOCKED(); |
569 | |
|
570 | 0 | LWIP_ERROR("netif_set_netmask: invalid netif", netif != NULL, return); |
571 | | |
572 | | /* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */ |
573 | 0 | if (netmask == NULL) { |
574 | 0 | netmask = IP4_ADDR_ANY4; |
575 | 0 | } |
576 | |
|
577 | 0 | if (netif_do_set_netmask(netif, netmask, old_nm)) { |
578 | | #if LWIP_NETIF_EXT_STATUS_CALLBACK |
579 | | netif_ext_callback_args_t args; |
580 | | args.ipv4_changed.old_netmask = old_nm; |
581 | | netif_invoke_ext_callback(netif, LWIP_NSC_IPV4_NETMASK_CHANGED, &args); |
582 | | #endif |
583 | 0 | } |
584 | 0 | } |
585 | | |
586 | | static int |
587 | | netif_do_set_gw(struct netif *netif, const ip4_addr_t *gw, ip_addr_t *old_gw) |
588 | 0 | { |
589 | | /* address is actually being changed? */ |
590 | 0 | if (ip4_addr_cmp(gw, netif_ip4_gw(netif)) == 0) { |
591 | | #if LWIP_NETIF_EXT_STATUS_CALLBACK |
592 | | LWIP_ASSERT("invalid pointer", old_gw != NULL); |
593 | | ip_addr_copy(*old_gw, *netif_ip_gw4(netif)); |
594 | | #else |
595 | 0 | LWIP_UNUSED_ARG(old_gw); |
596 | 0 | #endif |
597 | |
|
598 | 0 | ip4_addr_set(ip_2_ip4(&netif->gw), gw); |
599 | 0 | IP_SET_TYPE_VAL(netif->gw, IPADDR_TYPE_V4); |
600 | 0 | LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: GW address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", |
601 | 0 | netif->name[0], netif->name[1], |
602 | 0 | ip4_addr1_16(netif_ip4_gw(netif)), |
603 | 0 | ip4_addr2_16(netif_ip4_gw(netif)), |
604 | 0 | ip4_addr3_16(netif_ip4_gw(netif)), |
605 | 0 | ip4_addr4_16(netif_ip4_gw(netif)))); |
606 | 0 | return 1; /* gateway changed */ |
607 | 0 | } |
608 | 0 | return 0; /* gateway unchanged */ |
609 | 0 | } |
610 | | |
611 | | /** |
612 | | * @ingroup netif_ip4 |
613 | | * Change the default gateway for a network interface |
614 | | * |
615 | | * @param netif the network interface to change |
616 | | * @param gw the new default gateway |
617 | | * |
618 | | * @note call netif_set_addr() if you also want to change ip address and netmask |
619 | | */ |
620 | | void |
621 | | netif_set_gw(struct netif *netif, const ip4_addr_t *gw) |
622 | 0 | { |
623 | | #if LWIP_NETIF_EXT_STATUS_CALLBACK |
624 | | ip_addr_t old_gw_val; |
625 | | ip_addr_t *old_gw = &old_gw_val; |
626 | | #else |
627 | 0 | ip_addr_t *old_gw = NULL; |
628 | 0 | #endif |
629 | 0 | LWIP_ASSERT_CORE_LOCKED(); |
630 | |
|
631 | 0 | LWIP_ERROR("netif_set_gw: invalid netif", netif != NULL, return); |
632 | | |
633 | | /* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */ |
634 | 0 | if (gw == NULL) { |
635 | 0 | gw = IP4_ADDR_ANY4; |
636 | 0 | } |
637 | |
|
638 | 0 | if (netif_do_set_gw(netif, gw, old_gw)) { |
639 | | #if LWIP_NETIF_EXT_STATUS_CALLBACK |
640 | | netif_ext_callback_args_t args; |
641 | | args.ipv4_changed.old_gw = old_gw; |
642 | | netif_invoke_ext_callback(netif, LWIP_NSC_IPV4_GATEWAY_CHANGED, &args); |
643 | | #endif |
644 | 0 | } |
645 | 0 | } |
646 | | |
647 | | /** |
648 | | * @ingroup netif_ip4 |
649 | | * Change IP address configuration for a network interface (including netmask |
650 | | * and default gateway). |
651 | | * |
652 | | * @param netif the network interface to change |
653 | | * @param ipaddr the new IP address |
654 | | * @param netmask the new netmask |
655 | | * @param gw the new default gateway |
656 | | */ |
657 | | void |
658 | | netif_set_addr(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, |
659 | | const ip4_addr_t *gw) |
660 | 0 | { |
661 | | #if LWIP_NETIF_EXT_STATUS_CALLBACK |
662 | | netif_nsc_reason_t change_reason = LWIP_NSC_NONE; |
663 | | netif_ext_callback_args_t cb_args; |
664 | | ip_addr_t old_nm_val; |
665 | | ip_addr_t old_gw_val; |
666 | | ip_addr_t *old_nm = &old_nm_val; |
667 | | ip_addr_t *old_gw = &old_gw_val; |
668 | | #else |
669 | 0 | ip_addr_t *old_nm = NULL; |
670 | 0 | ip_addr_t *old_gw = NULL; |
671 | 0 | #endif |
672 | 0 | ip_addr_t old_addr; |
673 | 0 | int remove; |
674 | |
|
675 | 0 | LWIP_ASSERT_CORE_LOCKED(); |
676 | | |
677 | | /* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */ |
678 | 0 | if (ipaddr == NULL) { |
679 | 0 | ipaddr = IP4_ADDR_ANY4; |
680 | 0 | } |
681 | 0 | if (netmask == NULL) { |
682 | 0 | netmask = IP4_ADDR_ANY4; |
683 | 0 | } |
684 | 0 | if (gw == NULL) { |
685 | 0 | gw = IP4_ADDR_ANY4; |
686 | 0 | } |
687 | |
|
688 | 0 | remove = ip4_addr_isany(ipaddr); |
689 | 0 | if (remove) { |
690 | | /* when removing an address, we have to remove it *before* changing netmask/gw |
691 | | to ensure that tcp RST segment can be sent correctly */ |
692 | 0 | if (netif_do_set_ipaddr(netif, ipaddr, &old_addr)) { |
693 | | #if LWIP_NETIF_EXT_STATUS_CALLBACK |
694 | | change_reason |= LWIP_NSC_IPV4_ADDRESS_CHANGED; |
695 | | cb_args.ipv4_changed.old_address = &old_addr; |
696 | | #endif |
697 | 0 | } |
698 | 0 | } |
699 | 0 | if (netif_do_set_netmask(netif, netmask, old_nm)) { |
700 | | #if LWIP_NETIF_EXT_STATUS_CALLBACK |
701 | | change_reason |= LWIP_NSC_IPV4_NETMASK_CHANGED; |
702 | | cb_args.ipv4_changed.old_netmask = old_nm; |
703 | | #endif |
704 | 0 | } |
705 | 0 | if (netif_do_set_gw(netif, gw, old_gw)) { |
706 | | #if LWIP_NETIF_EXT_STATUS_CALLBACK |
707 | | change_reason |= LWIP_NSC_IPV4_GATEWAY_CHANGED; |
708 | | cb_args.ipv4_changed.old_gw = old_gw; |
709 | | #endif |
710 | 0 | } |
711 | 0 | if (!remove) { |
712 | | /* set ipaddr last to ensure netmask/gw have been set when status callback is called */ |
713 | 0 | if (netif_do_set_ipaddr(netif, ipaddr, &old_addr)) { |
714 | | #if LWIP_NETIF_EXT_STATUS_CALLBACK |
715 | | change_reason |= LWIP_NSC_IPV4_ADDRESS_CHANGED; |
716 | | cb_args.ipv4_changed.old_address = &old_addr; |
717 | | #endif |
718 | 0 | } |
719 | 0 | } |
720 | |
|
721 | | #if LWIP_NETIF_EXT_STATUS_CALLBACK |
722 | | if (change_reason != LWIP_NSC_NONE) { |
723 | | change_reason |= LWIP_NSC_IPV4_SETTINGS_CHANGED; |
724 | | netif_invoke_ext_callback(netif, change_reason, &cb_args); |
725 | | } |
726 | | #endif |
727 | 0 | } |
728 | | #endif /* LWIP_IPV4*/ |
729 | | |
730 | | /** |
731 | | * @ingroup netif |
732 | | * Remove a network interface from the list of lwIP netifs. |
733 | | * |
734 | | * @param netif the network interface to remove |
735 | | */ |
736 | | void |
737 | | netif_remove(struct netif *netif) |
738 | 0 | { |
739 | | #if LWIP_IPV6 |
740 | | int i; |
741 | | #endif |
742 | |
|
743 | 0 | LWIP_ASSERT_CORE_LOCKED(); |
744 | |
|
745 | 0 | if (netif == NULL) { |
746 | 0 | return; |
747 | 0 | } |
748 | | |
749 | 0 | netif_invoke_ext_callback(netif, LWIP_NSC_NETIF_REMOVED, NULL); |
750 | |
|
751 | 0 | #if LWIP_IPV4 |
752 | 0 | if (!ip4_addr_isany_val(*netif_ip4_addr(netif))) { |
753 | 0 | netif_do_ip_addr_changed(netif_ip_addr4(netif), NULL); |
754 | 0 | } |
755 | |
|
756 | | #if LWIP_IGMP |
757 | | /* stop IGMP processing */ |
758 | | if (netif->flags & NETIF_FLAG_IGMP) { |
759 | | igmp_stop(netif); |
760 | | } |
761 | | #endif /* LWIP_IGMP */ |
762 | 0 | #endif /* LWIP_IPV4*/ |
763 | |
|
764 | | #if LWIP_IPV6 |
765 | | for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { |
766 | | if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i))) { |
767 | | netif_do_ip_addr_changed(netif_ip_addr6(netif, i), NULL); |
768 | | } |
769 | | } |
770 | | #if LWIP_IPV6_MLD |
771 | | /* stop MLD processing */ |
772 | | mld6_stop(netif); |
773 | | #endif /* LWIP_IPV6_MLD */ |
774 | | #endif /* LWIP_IPV6 */ |
775 | 0 | if (netif_is_up(netif)) { |
776 | | /* set netif down before removing (call callback function) */ |
777 | 0 | netif_set_down(netif); |
778 | 0 | } |
779 | |
|
780 | 0 | mib2_remove_ip4(netif); |
781 | | |
782 | | /* this netif is default? */ |
783 | 0 | if (netif_default == netif) { |
784 | | /* reset default netif */ |
785 | 0 | netif_set_default(NULL); |
786 | 0 | } |
787 | | #if !LWIP_SINGLE_NETIF |
788 | | /* is it the first netif? */ |
789 | | if (netif_list == netif) { |
790 | | netif_list = netif->next; |
791 | | } else { |
792 | | /* look for netif further down the list */ |
793 | | struct netif *tmp_netif; |
794 | | NETIF_FOREACH(tmp_netif) { |
795 | | if (tmp_netif->next == netif) { |
796 | | tmp_netif->next = netif->next; |
797 | | break; |
798 | | } |
799 | | } |
800 | | if (tmp_netif == NULL) { |
801 | | return; /* netif is not on the list */ |
802 | | } |
803 | | } |
804 | | #endif /* !LWIP_SINGLE_NETIF */ |
805 | 0 | mib2_netif_removed(netif); |
806 | | #if LWIP_NETIF_REMOVE_CALLBACK |
807 | | if (netif->remove_callback) { |
808 | | netif->remove_callback(netif); |
809 | | } |
810 | | #endif /* LWIP_NETIF_REMOVE_CALLBACK */ |
811 | 0 | LWIP_DEBUGF( NETIF_DEBUG, ("netif_remove: removed netif\n") ); |
812 | 0 | } |
813 | | |
814 | | /** |
815 | | * @ingroup netif |
816 | | * Set a network interface as the default network interface |
817 | | * (used to output all packets for which no specific route is found) |
818 | | * |
819 | | * @param netif the default network interface |
820 | | */ |
821 | | void |
822 | | netif_set_default(struct netif *netif) |
823 | 0 | { |
824 | 0 | LWIP_ASSERT_CORE_LOCKED(); |
825 | |
|
826 | 0 | if (netif == NULL) { |
827 | | /* remove default route */ |
828 | 0 | mib2_remove_route_ip4(1, netif); |
829 | 0 | } else { |
830 | | /* install default route */ |
831 | 0 | mib2_add_route_ip4(1, netif); |
832 | 0 | } |
833 | 0 | netif_default = netif; |
834 | 0 | LWIP_DEBUGF(NETIF_DEBUG, ("netif: setting default interface %c%c\n", |
835 | 0 | netif ? netif->name[0] : '\'', netif ? netif->name[1] : '\'')); |
836 | 0 | } |
837 | | |
838 | | /** |
839 | | * @ingroup netif |
840 | | * Bring an interface up, available for processing |
841 | | * traffic. |
842 | | */ |
843 | | void |
844 | | netif_set_up(struct netif *netif) |
845 | 0 | { |
846 | 0 | LWIP_ASSERT_CORE_LOCKED(); |
847 | |
|
848 | 0 | LWIP_ERROR("netif_set_up: invalid netif", netif != NULL, return); |
849 | | |
850 | 0 | if (!(netif->flags & NETIF_FLAG_UP)) { |
851 | 0 | netif_set_flags(netif, NETIF_FLAG_UP); |
852 | |
|
853 | 0 | MIB2_COPY_SYSUPTIME_TO(&netif->ts); |
854 | |
|
855 | 0 | NETIF_STATUS_CALLBACK(netif); |
856 | |
|
857 | | #if LWIP_NETIF_EXT_STATUS_CALLBACK |
858 | | { |
859 | | netif_ext_callback_args_t args; |
860 | | args.status_changed.state = 1; |
861 | | netif_invoke_ext_callback(netif, LWIP_NSC_STATUS_CHANGED, &args); |
862 | | } |
863 | | #endif |
864 | |
|
865 | 0 | netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV4 | NETIF_REPORT_TYPE_IPV6); |
866 | | #if LWIP_IPV6 |
867 | | nd6_restart_netif(netif); |
868 | | #endif /* LWIP_IPV6 */ |
869 | 0 | } |
870 | 0 | } |
871 | | |
872 | | /** Send ARP/IGMP/MLD/RS events, e.g. on link-up/netif-up or addr-change |
873 | | */ |
874 | | static void |
875 | | netif_issue_reports(struct netif *netif, u8_t report_type) |
876 | 0 | { |
877 | 0 | LWIP_ASSERT("netif_issue_reports: invalid netif", netif != NULL); |
878 | | |
879 | | /* Only send reports when both link and admin states are up */ |
880 | 0 | if (!(netif->flags & NETIF_FLAG_LINK_UP) || |
881 | 0 | !(netif->flags & NETIF_FLAG_UP)) { |
882 | 0 | return; |
883 | 0 | } |
884 | | |
885 | 0 | #if LWIP_IPV4 |
886 | 0 | if ((report_type & NETIF_REPORT_TYPE_IPV4) && |
887 | 0 | !ip4_addr_isany_val(*netif_ip4_addr(netif))) { |
888 | 0 | #if LWIP_ARP |
889 | | /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */ |
890 | 0 | if (netif->flags & (NETIF_FLAG_ETHARP)) { |
891 | 0 | etharp_gratuitous(netif); |
892 | 0 | } |
893 | 0 | #endif /* LWIP_ARP */ |
894 | |
|
895 | | #if LWIP_IGMP |
896 | | /* resend IGMP memberships */ |
897 | | if (netif->flags & NETIF_FLAG_IGMP) { |
898 | | igmp_report_groups(netif); |
899 | | } |
900 | | #endif /* LWIP_IGMP */ |
901 | 0 | } |
902 | 0 | #endif /* LWIP_IPV4 */ |
903 | |
|
904 | | #if LWIP_IPV6 |
905 | | if (report_type & NETIF_REPORT_TYPE_IPV6) { |
906 | | #if LWIP_IPV6_MLD |
907 | | /* send mld memberships */ |
908 | | mld6_report_groups(netif); |
909 | | #endif /* LWIP_IPV6_MLD */ |
910 | | } |
911 | | #endif /* LWIP_IPV6 */ |
912 | 0 | } |
913 | | |
914 | | /** |
915 | | * @ingroup netif |
916 | | * Bring an interface down, disabling any traffic processing. |
917 | | */ |
918 | | void |
919 | | netif_set_down(struct netif *netif) |
920 | 0 | { |
921 | 0 | LWIP_ASSERT_CORE_LOCKED(); |
922 | |
|
923 | 0 | LWIP_ERROR("netif_set_down: invalid netif", netif != NULL, return); |
924 | | |
925 | 0 | if (netif->flags & NETIF_FLAG_UP) { |
926 | | #if LWIP_NETIF_EXT_STATUS_CALLBACK |
927 | | { |
928 | | netif_ext_callback_args_t args; |
929 | | args.status_changed.state = 0; |
930 | | netif_invoke_ext_callback(netif, LWIP_NSC_STATUS_CHANGED, &args); |
931 | | } |
932 | | #endif |
933 | |
|
934 | 0 | netif_clear_flags(netif, NETIF_FLAG_UP); |
935 | 0 | MIB2_COPY_SYSUPTIME_TO(&netif->ts); |
936 | |
|
937 | 0 | #if LWIP_IPV4 && LWIP_ARP |
938 | 0 | if (netif->flags & NETIF_FLAG_ETHARP) { |
939 | 0 | etharp_cleanup_netif(netif); |
940 | 0 | } |
941 | 0 | #endif /* LWIP_IPV4 && LWIP_ARP */ |
942 | |
|
943 | | #if LWIP_IPV6 |
944 | | nd6_cleanup_netif(netif); |
945 | | #endif /* LWIP_IPV6 */ |
946 | |
|
947 | 0 | NETIF_STATUS_CALLBACK(netif); |
948 | 0 | } |
949 | 0 | } |
950 | | |
951 | | #if LWIP_NETIF_STATUS_CALLBACK |
952 | | /** |
953 | | * @ingroup netif |
954 | | * Set callback to be called when interface is brought up/down or address is changed while up |
955 | | */ |
956 | | void |
957 | | netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback) |
958 | | { |
959 | | LWIP_ASSERT_CORE_LOCKED(); |
960 | | |
961 | | if (netif) { |
962 | | netif->status_callback = status_callback; |
963 | | } |
964 | | } |
965 | | #endif /* LWIP_NETIF_STATUS_CALLBACK */ |
966 | | |
967 | | #if LWIP_NETIF_REMOVE_CALLBACK |
968 | | /** |
969 | | * @ingroup netif |
970 | | * Set callback to be called when the interface has been removed |
971 | | */ |
972 | | void |
973 | | netif_set_remove_callback(struct netif *netif, netif_status_callback_fn remove_callback) |
974 | | { |
975 | | LWIP_ASSERT_CORE_LOCKED(); |
976 | | |
977 | | if (netif) { |
978 | | netif->remove_callback = remove_callback; |
979 | | } |
980 | | } |
981 | | #endif /* LWIP_NETIF_REMOVE_CALLBACK */ |
982 | | |
983 | | /** |
984 | | * @ingroup netif |
985 | | * Called by a driver when its link goes up |
986 | | */ |
987 | | void |
988 | | netif_set_link_up(struct netif *netif) |
989 | 0 | { |
990 | 0 | LWIP_ASSERT_CORE_LOCKED(); |
991 | |
|
992 | 0 | LWIP_ERROR("netif_set_link_up: invalid netif", netif != NULL, return); |
993 | | |
994 | 0 | if (!(netif->flags & NETIF_FLAG_LINK_UP)) { |
995 | 0 | netif_set_flags(netif, NETIF_FLAG_LINK_UP); |
996 | |
|
997 | | #if LWIP_DHCP |
998 | | dhcp_network_changed(netif); |
999 | | #endif /* LWIP_DHCP */ |
1000 | |
|
1001 | | #if LWIP_AUTOIP |
1002 | | autoip_network_changed(netif); |
1003 | | #endif /* LWIP_AUTOIP */ |
1004 | |
|
1005 | 0 | netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV4 | NETIF_REPORT_TYPE_IPV6); |
1006 | | #if LWIP_IPV6 |
1007 | | nd6_restart_netif(netif); |
1008 | | #endif /* LWIP_IPV6 */ |
1009 | |
|
1010 | 0 | NETIF_LINK_CALLBACK(netif); |
1011 | | #if LWIP_NETIF_EXT_STATUS_CALLBACK |
1012 | | { |
1013 | | netif_ext_callback_args_t args; |
1014 | | args.link_changed.state = 1; |
1015 | | netif_invoke_ext_callback(netif, LWIP_NSC_LINK_CHANGED, &args); |
1016 | | } |
1017 | | #endif |
1018 | 0 | } |
1019 | 0 | } |
1020 | | |
1021 | | /** |
1022 | | * @ingroup netif |
1023 | | * Called by a driver when its link goes down |
1024 | | */ |
1025 | | void |
1026 | | netif_set_link_down(struct netif *netif) |
1027 | 0 | { |
1028 | 0 | LWIP_ASSERT_CORE_LOCKED(); |
1029 | |
|
1030 | 0 | LWIP_ERROR("netif_set_link_down: invalid netif", netif != NULL, return); |
1031 | | |
1032 | 0 | if (netif->flags & NETIF_FLAG_LINK_UP) { |
1033 | 0 | netif_clear_flags(netif, NETIF_FLAG_LINK_UP); |
1034 | 0 | NETIF_LINK_CALLBACK(netif); |
1035 | | #if LWIP_NETIF_EXT_STATUS_CALLBACK |
1036 | | { |
1037 | | netif_ext_callback_args_t args; |
1038 | | args.link_changed.state = 0; |
1039 | | netif_invoke_ext_callback(netif, LWIP_NSC_LINK_CHANGED, &args); |
1040 | | } |
1041 | | #endif |
1042 | 0 | } |
1043 | 0 | } |
1044 | | |
1045 | | #if LWIP_NETIF_LINK_CALLBACK |
1046 | | /** |
1047 | | * @ingroup netif |
1048 | | * Set callback to be called when link is brought up/down |
1049 | | */ |
1050 | | void |
1051 | | netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback) |
1052 | | { |
1053 | | LWIP_ASSERT_CORE_LOCKED(); |
1054 | | |
1055 | | if (netif) { |
1056 | | netif->link_callback = link_callback; |
1057 | | } |
1058 | | } |
1059 | | #endif /* LWIP_NETIF_LINK_CALLBACK */ |
1060 | | |
1061 | | #if ENABLE_LOOPBACK |
1062 | | /** |
1063 | | * @ingroup netif |
1064 | | * Send an IP packet to be received on the same netif (loopif-like). |
1065 | | * The pbuf is simply copied and handed back to netif->input. |
1066 | | * In multithreaded mode, this is done directly since netif->input must put |
1067 | | * the packet on a queue. |
1068 | | * In callback mode, the packet is put on an internal queue and is fed to |
1069 | | * netif->input by netif_poll(). |
1070 | | * |
1071 | | * @param netif the lwip network interface structure |
1072 | | * @param p the (IP) packet to 'send' |
1073 | | * @return ERR_OK if the packet has been sent |
1074 | | * ERR_MEM if the pbuf used to copy the packet couldn't be allocated |
1075 | | */ |
1076 | | err_t |
1077 | | netif_loop_output(struct netif *netif, struct pbuf *p) |
1078 | | { |
1079 | | struct pbuf *r; |
1080 | | err_t err; |
1081 | | struct pbuf *last; |
1082 | | #if LWIP_LOOPBACK_MAX_PBUFS |
1083 | | u16_t clen = 0; |
1084 | | #endif /* LWIP_LOOPBACK_MAX_PBUFS */ |
1085 | | /* If we have a loopif, SNMP counters are adjusted for it, |
1086 | | * if not they are adjusted for 'netif'. */ |
1087 | | #if MIB2_STATS |
1088 | | #if LWIP_HAVE_LOOPIF |
1089 | | struct netif *stats_if = &loop_netif; |
1090 | | #else /* LWIP_HAVE_LOOPIF */ |
1091 | | struct netif *stats_if = netif; |
1092 | | #endif /* LWIP_HAVE_LOOPIF */ |
1093 | | #endif /* MIB2_STATS */ |
1094 | | #if LWIP_NETIF_LOOPBACK_MULTITHREADING |
1095 | | u8_t schedule_poll = 0; |
1096 | | #endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ |
1097 | | SYS_ARCH_DECL_PROTECT(lev); |
1098 | | |
1099 | | LWIP_ASSERT("netif_loop_output: invalid netif", netif != NULL); |
1100 | | LWIP_ASSERT("netif_loop_output: invalid pbuf", p != NULL); |
1101 | | |
1102 | | /* Allocate a new pbuf */ |
1103 | | r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM); |
1104 | | if (r == NULL) { |
1105 | | LINK_STATS_INC(link.memerr); |
1106 | | LINK_STATS_INC(link.drop); |
1107 | | MIB2_STATS_NETIF_INC(stats_if, ifoutdiscards); |
1108 | | return ERR_MEM; |
1109 | | } |
1110 | | #if LWIP_LOOPBACK_MAX_PBUFS |
1111 | | clen = pbuf_clen(r); |
1112 | | /* check for overflow or too many pbuf on queue */ |
1113 | | if (((netif->loop_cnt_current + clen) < netif->loop_cnt_current) || |
1114 | | ((netif->loop_cnt_current + clen) > LWIP_MIN(LWIP_LOOPBACK_MAX_PBUFS, 0xFFFF))) { |
1115 | | pbuf_free(r); |
1116 | | LINK_STATS_INC(link.memerr); |
1117 | | LINK_STATS_INC(link.drop); |
1118 | | MIB2_STATS_NETIF_INC(stats_if, ifoutdiscards); |
1119 | | return ERR_MEM; |
1120 | | } |
1121 | | netif->loop_cnt_current = (u16_t)(netif->loop_cnt_current + clen); |
1122 | | #endif /* LWIP_LOOPBACK_MAX_PBUFS */ |
1123 | | |
1124 | | /* Copy the whole pbuf queue p into the single pbuf r */ |
1125 | | if ((err = pbuf_copy(r, p)) != ERR_OK) { |
1126 | | pbuf_free(r); |
1127 | | LINK_STATS_INC(link.memerr); |
1128 | | LINK_STATS_INC(link.drop); |
1129 | | MIB2_STATS_NETIF_INC(stats_if, ifoutdiscards); |
1130 | | return err; |
1131 | | } |
1132 | | |
1133 | | /* Put the packet on a linked list which gets emptied through calling |
1134 | | netif_poll(). */ |
1135 | | |
1136 | | /* let last point to the last pbuf in chain r */ |
1137 | | for (last = r; last->next != NULL; last = last->next) { |
1138 | | /* nothing to do here, just get to the last pbuf */ |
1139 | | } |
1140 | | |
1141 | | SYS_ARCH_PROTECT(lev); |
1142 | | if (netif->loop_first != NULL) { |
1143 | | LWIP_ASSERT("if first != NULL, last must also be != NULL", netif->loop_last != NULL); |
1144 | | netif->loop_last->next = r; |
1145 | | netif->loop_last = last; |
1146 | | } else { |
1147 | | netif->loop_first = r; |
1148 | | netif->loop_last = last; |
1149 | | #if LWIP_NETIF_LOOPBACK_MULTITHREADING |
1150 | | /* No existing packets queued, schedule poll */ |
1151 | | schedule_poll = 1; |
1152 | | #endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ |
1153 | | } |
1154 | | SYS_ARCH_UNPROTECT(lev); |
1155 | | |
1156 | | LINK_STATS_INC(link.xmit); |
1157 | | MIB2_STATS_NETIF_ADD(stats_if, ifoutoctets, p->tot_len); |
1158 | | MIB2_STATS_NETIF_INC(stats_if, ifoutucastpkts); |
1159 | | |
1160 | | #if LWIP_NETIF_LOOPBACK_MULTITHREADING |
1161 | | /* For multithreading environment, schedule a call to netif_poll */ |
1162 | | if (schedule_poll) { |
1163 | | tcpip_try_callback((tcpip_callback_fn)netif_poll, netif); |
1164 | | } |
1165 | | #endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ |
1166 | | |
1167 | | return ERR_OK; |
1168 | | } |
1169 | | |
1170 | | #if LWIP_HAVE_LOOPIF |
1171 | | #if LWIP_IPV4 |
1172 | | static err_t |
1173 | | netif_loop_output_ipv4(struct netif *netif, struct pbuf *p, const ip4_addr_t *addr) |
1174 | | { |
1175 | | LWIP_UNUSED_ARG(addr); |
1176 | | return netif_loop_output(netif, p); |
1177 | | } |
1178 | | #endif /* LWIP_IPV4 */ |
1179 | | |
1180 | | #if LWIP_IPV6 |
1181 | | static err_t |
1182 | | netif_loop_output_ipv6(struct netif *netif, struct pbuf *p, const ip6_addr_t *addr) |
1183 | | { |
1184 | | LWIP_UNUSED_ARG(addr); |
1185 | | return netif_loop_output(netif, p); |
1186 | | } |
1187 | | #endif /* LWIP_IPV6 */ |
1188 | | #endif /* LWIP_HAVE_LOOPIF */ |
1189 | | |
1190 | | |
1191 | | /** |
1192 | | * Call netif_poll() in the main loop of your application. This is to prevent |
1193 | | * reentering non-reentrant functions like tcp_input(). Packets passed to |
1194 | | * netif_loop_output() are put on a list that is passed to netif->input() by |
1195 | | * netif_poll(). |
1196 | | */ |
1197 | | void |
1198 | | netif_poll(struct netif *netif) |
1199 | | { |
1200 | | /* If we have a loopif, SNMP counters are adjusted for it, |
1201 | | * if not they are adjusted for 'netif'. */ |
1202 | | #if MIB2_STATS |
1203 | | #if LWIP_HAVE_LOOPIF |
1204 | | struct netif *stats_if = &loop_netif; |
1205 | | #else /* LWIP_HAVE_LOOPIF */ |
1206 | | struct netif *stats_if = netif; |
1207 | | #endif /* LWIP_HAVE_LOOPIF */ |
1208 | | #endif /* MIB2_STATS */ |
1209 | | SYS_ARCH_DECL_PROTECT(lev); |
1210 | | |
1211 | | LWIP_ASSERT("netif_poll: invalid netif", netif != NULL); |
1212 | | |
1213 | | /* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */ |
1214 | | SYS_ARCH_PROTECT(lev); |
1215 | | while (netif->loop_first != NULL) { |
1216 | | struct pbuf *in, *in_end; |
1217 | | #if LWIP_LOOPBACK_MAX_PBUFS |
1218 | | u8_t clen = 1; |
1219 | | #endif /* LWIP_LOOPBACK_MAX_PBUFS */ |
1220 | | |
1221 | | in = in_end = netif->loop_first; |
1222 | | while (in_end->len != in_end->tot_len) { |
1223 | | LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL); |
1224 | | in_end = in_end->next; |
1225 | | #if LWIP_LOOPBACK_MAX_PBUFS |
1226 | | clen++; |
1227 | | #endif /* LWIP_LOOPBACK_MAX_PBUFS */ |
1228 | | } |
1229 | | #if LWIP_LOOPBACK_MAX_PBUFS |
1230 | | /* adjust the number of pbufs on queue */ |
1231 | | LWIP_ASSERT("netif->loop_cnt_current underflow", |
1232 | | ((netif->loop_cnt_current - clen) < netif->loop_cnt_current)); |
1233 | | netif->loop_cnt_current = (u16_t)(netif->loop_cnt_current - clen); |
1234 | | #endif /* LWIP_LOOPBACK_MAX_PBUFS */ |
1235 | | |
1236 | | /* 'in_end' now points to the last pbuf from 'in' */ |
1237 | | if (in_end == netif->loop_last) { |
1238 | | /* this was the last pbuf in the list */ |
1239 | | netif->loop_first = netif->loop_last = NULL; |
1240 | | } else { |
1241 | | /* pop the pbuf off the list */ |
1242 | | netif->loop_first = in_end->next; |
1243 | | LWIP_ASSERT("should not be null since first != last!", netif->loop_first != NULL); |
1244 | | } |
1245 | | /* De-queue the pbuf from its successors on the 'loop_' list. */ |
1246 | | in_end->next = NULL; |
1247 | | SYS_ARCH_UNPROTECT(lev); |
1248 | | |
1249 | | in->if_idx = netif_get_index(netif); |
1250 | | |
1251 | | LINK_STATS_INC(link.recv); |
1252 | | MIB2_STATS_NETIF_ADD(stats_if, ifinoctets, in->tot_len); |
1253 | | MIB2_STATS_NETIF_INC(stats_if, ifinucastpkts); |
1254 | | /* loopback packets are always IP packets! */ |
1255 | | if (ip_input(in, netif) != ERR_OK) { |
1256 | | pbuf_free(in); |
1257 | | } |
1258 | | SYS_ARCH_PROTECT(lev); |
1259 | | } |
1260 | | SYS_ARCH_UNPROTECT(lev); |
1261 | | } |
1262 | | |
1263 | | #if !LWIP_NETIF_LOOPBACK_MULTITHREADING |
1264 | | /** |
1265 | | * Calls netif_poll() for every netif on the netif_list. |
1266 | | */ |
1267 | | void |
1268 | | netif_poll_all(void) |
1269 | | { |
1270 | | struct netif *netif; |
1271 | | /* loop through netifs */ |
1272 | | NETIF_FOREACH(netif) { |
1273 | | netif_poll(netif); |
1274 | | } |
1275 | | } |
1276 | | #endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ |
1277 | | #endif /* ENABLE_LOOPBACK */ |
1278 | | |
1279 | | #if LWIP_NUM_NETIF_CLIENT_DATA > 0 |
1280 | | /** |
1281 | | * @ingroup netif_cd |
1282 | | * Allocate an index to store data in client_data member of struct netif. |
1283 | | * Returned value is an index in mentioned array. |
1284 | | * @see LWIP_NUM_NETIF_CLIENT_DATA |
1285 | | */ |
1286 | | u8_t |
1287 | | netif_alloc_client_data_id(void) |
1288 | | { |
1289 | | u8_t result = netif_client_id; |
1290 | | netif_client_id++; |
1291 | | |
1292 | | LWIP_ASSERT_CORE_LOCKED(); |
1293 | | |
1294 | | #if LWIP_NUM_NETIF_CLIENT_DATA > 256 |
1295 | | #error LWIP_NUM_NETIF_CLIENT_DATA must be <= 256 |
1296 | | #endif |
1297 | | LWIP_ASSERT("Increase LWIP_NUM_NETIF_CLIENT_DATA in lwipopts.h", result < LWIP_NUM_NETIF_CLIENT_DATA); |
1298 | | return (u8_t)(result + LWIP_NETIF_CLIENT_DATA_INDEX_MAX); |
1299 | | } |
1300 | | #endif |
1301 | | |
1302 | | #if LWIP_IPV6 |
1303 | | /** |
1304 | | * @ingroup netif_ip6 |
1305 | | * Change an IPv6 address of a network interface |
1306 | | * |
1307 | | * @param netif the network interface to change |
1308 | | * @param addr_idx index of the IPv6 address |
1309 | | * @param addr6 the new IPv6 address |
1310 | | * |
1311 | | * @note call netif_ip6_addr_set_state() to set the address valid/temptative |
1312 | | */ |
1313 | | void |
1314 | | netif_ip6_addr_set(struct netif *netif, s8_t addr_idx, const ip6_addr_t *addr6) |
1315 | | { |
1316 | | LWIP_ASSERT_CORE_LOCKED(); |
1317 | | |
1318 | | LWIP_ASSERT("netif_ip6_addr_set: invalid netif", netif != NULL); |
1319 | | LWIP_ASSERT("netif_ip6_addr_set: invalid addr6", addr6 != NULL); |
1320 | | |
1321 | | netif_ip6_addr_set_parts(netif, addr_idx, addr6->addr[0], addr6->addr[1], |
1322 | | addr6->addr[2], addr6->addr[3]); |
1323 | | } |
1324 | | |
1325 | | /* |
1326 | | * Change an IPv6 address of a network interface (internal version taking 4 * u32_t) |
1327 | | * |
1328 | | * @param netif the network interface to change |
1329 | | * @param addr_idx index of the IPv6 address |
1330 | | * @param i0 word0 of the new IPv6 address |
1331 | | * @param i1 word1 of the new IPv6 address |
1332 | | * @param i2 word2 of the new IPv6 address |
1333 | | * @param i3 word3 of the new IPv6 address |
1334 | | */ |
1335 | | void |
1336 | | netif_ip6_addr_set_parts(struct netif *netif, s8_t addr_idx, u32_t i0, u32_t i1, u32_t i2, u32_t i3) |
1337 | | { |
1338 | | ip_addr_t old_addr; |
1339 | | ip_addr_t new_ipaddr; |
1340 | | LWIP_ASSERT_CORE_LOCKED(); |
1341 | | LWIP_ASSERT("netif != NULL", netif != NULL); |
1342 | | LWIP_ASSERT("invalid index", addr_idx < LWIP_IPV6_NUM_ADDRESSES); |
1343 | | |
1344 | | ip6_addr_copy(*ip_2_ip6(&old_addr), *netif_ip6_addr(netif, addr_idx)); |
1345 | | IP_SET_TYPE_VAL(old_addr, IPADDR_TYPE_V6); |
1346 | | |
1347 | | /* address is actually being changed? */ |
1348 | | if ((ip_2_ip6(&old_addr)->addr[0] != i0) || (ip_2_ip6(&old_addr)->addr[1] != i1) || |
1349 | | (ip_2_ip6(&old_addr)->addr[2] != i2) || (ip_2_ip6(&old_addr)->addr[3] != i3)) { |
1350 | | LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_ip6_addr_set: netif address being changed\n")); |
1351 | | |
1352 | | IP_ADDR6(&new_ipaddr, i0, i1, i2, i3); |
1353 | | ip6_addr_assign_zone(ip_2_ip6(&new_ipaddr), IP6_UNICAST, netif); |
1354 | | |
1355 | | if (ip6_addr_isvalid(netif_ip6_addr_state(netif, addr_idx))) { |
1356 | | netif_do_ip_addr_changed(netif_ip_addr6(netif, addr_idx), &new_ipaddr); |
1357 | | } |
1358 | | /* @todo: remove/readd mib2 ip6 entries? */ |
1359 | | |
1360 | | ip_addr_copy(netif->ip6_addr[addr_idx], new_ipaddr); |
1361 | | |
1362 | | if (ip6_addr_isvalid(netif_ip6_addr_state(netif, addr_idx))) { |
1363 | | netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV6); |
1364 | | NETIF_STATUS_CALLBACK(netif); |
1365 | | } |
1366 | | |
1367 | | #if LWIP_NETIF_EXT_STATUS_CALLBACK |
1368 | | { |
1369 | | netif_ext_callback_args_t args; |
1370 | | args.ipv6_set.addr_index = addr_idx; |
1371 | | args.ipv6_set.old_address = &old_addr; |
1372 | | netif_invoke_ext_callback(netif, LWIP_NSC_IPV6_SET, &args); |
1373 | | } |
1374 | | #endif |
1375 | | } |
1376 | | |
1377 | | LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: IPv6 address %d of interface %c%c set to %s/0x%"X8_F"\n", |
1378 | | addr_idx, netif->name[0], netif->name[1], ip6addr_ntoa(netif_ip6_addr(netif, addr_idx)), |
1379 | | netif_ip6_addr_state(netif, addr_idx))); |
1380 | | } |
1381 | | |
1382 | | /** |
1383 | | * @ingroup netif_ip6 |
1384 | | * Change the state of an IPv6 address of a network interface |
1385 | | * (INVALID, TEMPTATIVE, PREFERRED, DEPRECATED, where TEMPTATIVE |
1386 | | * includes the number of checks done, see ip6_addr.h) |
1387 | | * |
1388 | | * @param netif the network interface to change |
1389 | | * @param addr_idx index of the IPv6 address |
1390 | | * @param state the new IPv6 address state |
1391 | | */ |
1392 | | void |
1393 | | netif_ip6_addr_set_state(struct netif *netif, s8_t addr_idx, u8_t state) |
1394 | | { |
1395 | | u8_t old_state; |
1396 | | LWIP_ASSERT_CORE_LOCKED(); |
1397 | | LWIP_ASSERT("netif != NULL", netif != NULL); |
1398 | | LWIP_ASSERT("invalid index", addr_idx < LWIP_IPV6_NUM_ADDRESSES); |
1399 | | |
1400 | | old_state = netif_ip6_addr_state(netif, addr_idx); |
1401 | | /* state is actually being changed? */ |
1402 | | if (old_state != state) { |
1403 | | u8_t old_valid = old_state & IP6_ADDR_VALID; |
1404 | | u8_t new_valid = state & IP6_ADDR_VALID; |
1405 | | LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_ip6_addr_set_state: netif address state being changed\n")); |
1406 | | |
1407 | | #if LWIP_IPV6_MLD |
1408 | | /* Reevaluate solicited-node multicast group membership. */ |
1409 | | if (netif->flags & NETIF_FLAG_MLD6) { |
1410 | | nd6_adjust_mld_membership(netif, addr_idx, state); |
1411 | | } |
1412 | | #endif /* LWIP_IPV6_MLD */ |
1413 | | |
1414 | | if (old_valid && !new_valid) { |
1415 | | /* address about to be removed by setting invalid */ |
1416 | | netif_do_ip_addr_changed(netif_ip_addr6(netif, addr_idx), NULL); |
1417 | | /* @todo: remove mib2 ip6 entries? */ |
1418 | | } |
1419 | | netif->ip6_addr_state[addr_idx] = state; |
1420 | | |
1421 | | if (!old_valid && new_valid) { |
1422 | | /* address added by setting valid */ |
1423 | | /* This is a good moment to check that the address is properly zoned. */ |
1424 | | IP6_ADDR_ZONECHECK_NETIF(netif_ip6_addr(netif, addr_idx), netif); |
1425 | | /* @todo: add mib2 ip6 entries? */ |
1426 | | netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV6); |
1427 | | } |
1428 | | if ((old_state & ~IP6_ADDR_TENTATIVE_COUNT_MASK) != |
1429 | | (state & ~IP6_ADDR_TENTATIVE_COUNT_MASK)) { |
1430 | | /* address state has changed -> call the callback function */ |
1431 | | NETIF_STATUS_CALLBACK(netif); |
1432 | | } |
1433 | | |
1434 | | #if LWIP_NETIF_EXT_STATUS_CALLBACK |
1435 | | { |
1436 | | netif_ext_callback_args_t args; |
1437 | | args.ipv6_addr_state_changed.addr_index = addr_idx; |
1438 | | args.ipv6_addr_state_changed.old_state = old_state; |
1439 | | args.ipv6_addr_state_changed.address = netif_ip_addr6(netif, addr_idx); |
1440 | | netif_invoke_ext_callback(netif, LWIP_NSC_IPV6_ADDR_STATE_CHANGED, &args); |
1441 | | } |
1442 | | #endif |
1443 | | } |
1444 | | LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: IPv6 address %d of interface %c%c set to %s/0x%"X8_F"\n", |
1445 | | addr_idx, netif->name[0], netif->name[1], ip6addr_ntoa(netif_ip6_addr(netif, addr_idx)), |
1446 | | netif_ip6_addr_state(netif, addr_idx))); |
1447 | | } |
1448 | | |
1449 | | /** |
1450 | | * Checks if a specific local address is present on the netif and returns its |
1451 | | * index. Depending on its state, it may or may not be assigned to the |
1452 | | * interface (as per RFC terminology). |
1453 | | * |
1454 | | * The given address may or may not be zoned (i.e., have a zone index other |
1455 | | * than IP6_NO_ZONE). If the address is zoned, it must have the correct zone |
1456 | | * for the given netif, or no match will be found. |
1457 | | * |
1458 | | * @param netif the netif to check |
1459 | | * @param ip6addr the IPv6 address to find |
1460 | | * @return >= 0: address found, this is its index |
1461 | | * -1: address not found on this netif |
1462 | | */ |
1463 | | s8_t |
1464 | | netif_get_ip6_addr_match(struct netif *netif, const ip6_addr_t *ip6addr) |
1465 | | { |
1466 | | s8_t i; |
1467 | | |
1468 | | LWIP_ASSERT_CORE_LOCKED(); |
1469 | | |
1470 | | LWIP_ASSERT("netif_get_ip6_addr_match: invalid netif", netif != NULL); |
1471 | | LWIP_ASSERT("netif_get_ip6_addr_match: invalid ip6addr", ip6addr != NULL); |
1472 | | |
1473 | | #if LWIP_IPV6_SCOPES |
1474 | | if (ip6_addr_has_zone(ip6addr) && !ip6_addr_test_zone(ip6addr, netif)) { |
1475 | | return -1; /* wrong zone, no match */ |
1476 | | } |
1477 | | #endif /* LWIP_IPV6_SCOPES */ |
1478 | | |
1479 | | for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { |
1480 | | if (!ip6_addr_isinvalid(netif_ip6_addr_state(netif, i)) && |
1481 | | ip6_addr_cmp_zoneless(netif_ip6_addr(netif, i), ip6addr)) { |
1482 | | return i; |
1483 | | } |
1484 | | } |
1485 | | return -1; |
1486 | | } |
1487 | | |
1488 | | /** |
1489 | | * @ingroup netif_ip6 |
1490 | | * Create a link-local IPv6 address on a netif (stored in slot 0) |
1491 | | * |
1492 | | * @param netif the netif to create the address on |
1493 | | * @param from_mac_48bit if != 0, assume hwadr is a 48-bit MAC address (std conversion) |
1494 | | * if == 0, use hwaddr directly as interface ID |
1495 | | */ |
1496 | | void |
1497 | | netif_create_ip6_linklocal_address(struct netif *netif, u8_t from_mac_48bit) |
1498 | | { |
1499 | | u8_t i, addr_index; |
1500 | | |
1501 | | LWIP_ASSERT_CORE_LOCKED(); |
1502 | | |
1503 | | LWIP_ASSERT("netif_create_ip6_linklocal_address: invalid netif", netif != NULL); |
1504 | | |
1505 | | /* Link-local prefix. */ |
1506 | | ip_2_ip6(&netif->ip6_addr[0])->addr[0] = PP_HTONL(0xfe800000ul); |
1507 | | ip_2_ip6(&netif->ip6_addr[0])->addr[1] = 0; |
1508 | | |
1509 | | /* Generate interface ID. */ |
1510 | | if (from_mac_48bit) { |
1511 | | /* Assume hwaddr is a 48-bit IEEE 802 MAC. Convert to EUI-64 address. Complement Group bit. */ |
1512 | | ip_2_ip6(&netif->ip6_addr[0])->addr[2] = lwip_htonl((((u32_t)(netif->hwaddr[0] ^ 0x02)) << 24) | |
1513 | | ((u32_t)(netif->hwaddr[1]) << 16) | |
1514 | | ((u32_t)(netif->hwaddr[2]) << 8) | |
1515 | | (0xff)); |
1516 | | ip_2_ip6(&netif->ip6_addr[0])->addr[3] = lwip_htonl((u32_t)(0xfeul << 24) | |
1517 | | ((u32_t)(netif->hwaddr[3]) << 16) | |
1518 | | ((u32_t)(netif->hwaddr[4]) << 8) | |
1519 | | (netif->hwaddr[5])); |
1520 | | } else { |
1521 | | /* Use hwaddr directly as interface ID. */ |
1522 | | ip_2_ip6(&netif->ip6_addr[0])->addr[2] = 0; |
1523 | | ip_2_ip6(&netif->ip6_addr[0])->addr[3] = 0; |
1524 | | |
1525 | | addr_index = 3; |
1526 | | for (i = 0; (i < 8) && (i < netif->hwaddr_len); i++) { |
1527 | | if (i == 4) { |
1528 | | addr_index--; |
1529 | | } |
1530 | | ip_2_ip6(&netif->ip6_addr[0])->addr[addr_index] |= lwip_htonl(((u32_t)(netif->hwaddr[netif->hwaddr_len - i - 1])) << (8 * (i & 0x03))); |
1531 | | } |
1532 | | } |
1533 | | |
1534 | | /* Set a link-local zone. Even though the zone is implied by the owning |
1535 | | * netif, setting the zone anyway has two important conceptual advantages: |
1536 | | * 1) it avoids the need for a ton of exceptions in internal code, allowing |
1537 | | * e.g. ip6_addr_cmp() to be used on local addresses; |
1538 | | * 2) the properly zoned address is visible externally, e.g. when any outside |
1539 | | * code enumerates available addresses or uses one to bind a socket. |
1540 | | * Any external code unaware of address scoping is likely to just ignore the |
1541 | | * zone field, so this should not create any compatibility problems. */ |
1542 | | ip6_addr_assign_zone(ip_2_ip6(&netif->ip6_addr[0]), IP6_UNICAST, netif); |
1543 | | |
1544 | | /* Set address state. */ |
1545 | | #if LWIP_IPV6_DUP_DETECT_ATTEMPTS |
1546 | | /* Will perform duplicate address detection (DAD). */ |
1547 | | netif_ip6_addr_set_state(netif, 0, IP6_ADDR_TENTATIVE); |
1548 | | #else |
1549 | | /* Consider address valid. */ |
1550 | | netif_ip6_addr_set_state(netif, 0, IP6_ADDR_PREFERRED); |
1551 | | #endif /* LWIP_IPV6_AUTOCONFIG */ |
1552 | | } |
1553 | | |
1554 | | /** |
1555 | | * @ingroup netif_ip6 |
1556 | | * This function allows for the easy addition of a new IPv6 address to an interface. |
1557 | | * It takes care of finding an empty slot and then sets the address tentative |
1558 | | * (to make sure that all the subsequent processing happens). |
1559 | | * |
1560 | | * @param netif netif to add the address on |
1561 | | * @param ip6addr address to add |
1562 | | * @param chosen_idx if != NULL, the chosen IPv6 address index will be stored here |
1563 | | */ |
1564 | | err_t |
1565 | | netif_add_ip6_address(struct netif *netif, const ip6_addr_t *ip6addr, s8_t *chosen_idx) |
1566 | | { |
1567 | | s8_t i; |
1568 | | |
1569 | | LWIP_ASSERT_CORE_LOCKED(); |
1570 | | |
1571 | | LWIP_ASSERT("netif_add_ip6_address: invalid netif", netif != NULL); |
1572 | | LWIP_ASSERT("netif_add_ip6_address: invalid ip6addr", ip6addr != NULL); |
1573 | | |
1574 | | i = netif_get_ip6_addr_match(netif, ip6addr); |
1575 | | if (i >= 0) { |
1576 | | /* Address already added */ |
1577 | | if (chosen_idx != NULL) { |
1578 | | *chosen_idx = i; |
1579 | | } |
1580 | | return ERR_OK; |
1581 | | } |
1582 | | |
1583 | | /* Find a free slot. The first one is reserved for link-local addresses. */ |
1584 | | for (i = ip6_addr_islinklocal(ip6addr) ? 0 : 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) { |
1585 | | if (ip6_addr_isinvalid(netif_ip6_addr_state(netif, i))) { |
1586 | | ip_addr_copy_from_ip6(netif->ip6_addr[i], *ip6addr); |
1587 | | ip6_addr_assign_zone(ip_2_ip6(&netif->ip6_addr[i]), IP6_UNICAST, netif); |
1588 | | netif_ip6_addr_set_state(netif, i, IP6_ADDR_TENTATIVE); |
1589 | | if (chosen_idx != NULL) { |
1590 | | *chosen_idx = i; |
1591 | | } |
1592 | | return ERR_OK; |
1593 | | } |
1594 | | } |
1595 | | |
1596 | | if (chosen_idx != NULL) { |
1597 | | *chosen_idx = -1; |
1598 | | } |
1599 | | return ERR_VAL; |
1600 | | } |
1601 | | |
1602 | | /** Dummy IPv6 output function for netifs not supporting IPv6 |
1603 | | */ |
1604 | | static err_t |
1605 | | netif_null_output_ip6(struct netif *netif, struct pbuf *p, const ip6_addr_t *ipaddr) |
1606 | | { |
1607 | | LWIP_UNUSED_ARG(netif); |
1608 | | LWIP_UNUSED_ARG(p); |
1609 | | LWIP_UNUSED_ARG(ipaddr); |
1610 | | |
1611 | | return ERR_IF; |
1612 | | } |
1613 | | #endif /* LWIP_IPV6 */ |
1614 | | |
1615 | | #if LWIP_IPV4 |
1616 | | /** Dummy IPv4 output function for netifs not supporting IPv4 |
1617 | | */ |
1618 | | static err_t |
1619 | | netif_null_output_ip4(struct netif *netif, struct pbuf *p, const ip4_addr_t *ipaddr) |
1620 | 0 | { |
1621 | 0 | LWIP_UNUSED_ARG(netif); |
1622 | 0 | LWIP_UNUSED_ARG(p); |
1623 | 0 | LWIP_UNUSED_ARG(ipaddr); |
1624 | |
|
1625 | 0 | return ERR_IF; |
1626 | 0 | } |
1627 | | #endif /* LWIP_IPV4 */ |
1628 | | |
1629 | | /** |
1630 | | * @ingroup netif |
1631 | | * Return the interface index for the netif with name |
1632 | | * or NETIF_NO_INDEX if not found/on error |
1633 | | * |
1634 | | * @param name the name of the netif |
1635 | | */ |
1636 | | u8_t |
1637 | | netif_name_to_index(const char *name) |
1638 | 0 | { |
1639 | 0 | struct netif *netif = netif_find(name); |
1640 | 0 | if (netif != NULL) { |
1641 | 0 | return netif_get_index(netif); |
1642 | 0 | } |
1643 | | /* No name found, return invalid index */ |
1644 | 0 | return NETIF_NO_INDEX; |
1645 | 0 | } |
1646 | | |
1647 | | /** |
1648 | | * @ingroup netif |
1649 | | * Return the interface name for the netif matching index |
1650 | | * or NULL if not found/on error |
1651 | | * |
1652 | | * @param idx the interface index of the netif |
1653 | | * @param name char buffer of at least NETIF_NAMESIZE bytes |
1654 | | */ |
1655 | | char * |
1656 | | netif_index_to_name(u8_t idx, char *name) |
1657 | 0 | { |
1658 | 0 | struct netif *netif = netif_get_by_index(idx); |
1659 | |
|
1660 | 0 | if (netif != NULL) { |
1661 | 0 | name[0] = netif->name[0]; |
1662 | 0 | name[1] = netif->name[1]; |
1663 | 0 | lwip_itoa(&name[2], NETIF_NAMESIZE - 2, netif_index_to_num(idx)); |
1664 | 0 | return name; |
1665 | 0 | } |
1666 | 0 | return NULL; |
1667 | 0 | } |
1668 | | |
1669 | | /** |
1670 | | * @ingroup netif |
1671 | | * Return the interface for the netif index |
1672 | | * |
1673 | | * @param idx index of netif to find |
1674 | | */ |
1675 | | struct netif * |
1676 | | netif_get_by_index(u8_t idx) |
1677 | 0 | { |
1678 | 0 | struct netif *netif; |
1679 | |
|
1680 | 0 | LWIP_ASSERT_CORE_LOCKED(); |
1681 | |
|
1682 | 0 | if (idx != NETIF_NO_INDEX) { |
1683 | 0 | NETIF_FOREACH(netif) { |
1684 | 0 | if (idx == netif_get_index(netif)) { |
1685 | 0 | return netif; /* found! */ |
1686 | 0 | } |
1687 | 0 | } |
1688 | 0 | } |
1689 | | |
1690 | 0 | return NULL; |
1691 | 0 | } |
1692 | | |
1693 | | /** |
1694 | | * @ingroup netif |
1695 | | * Find a network interface by searching for its name |
1696 | | * |
1697 | | * @param name the name of the netif (like netif->name) plus concatenated number |
1698 | | * in ascii representation (e.g. 'en0') |
1699 | | */ |
1700 | | struct netif * |
1701 | | netif_find(const char *name) |
1702 | 0 | { |
1703 | 0 | struct netif *netif; |
1704 | 0 | u8_t num; |
1705 | |
|
1706 | 0 | LWIP_ASSERT_CORE_LOCKED(); |
1707 | |
|
1708 | 0 | if (name == NULL) { |
1709 | 0 | return NULL; |
1710 | 0 | } |
1711 | | |
1712 | 0 | num = (u8_t)atoi(&name[2]); |
1713 | |
|
1714 | 0 | NETIF_FOREACH(netif) { |
1715 | 0 | if (num == netif->num && |
1716 | 0 | name[0] == netif->name[0] && |
1717 | 0 | name[1] == netif->name[1]) { |
1718 | 0 | LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: found %c%c\n", name[0], name[1])); |
1719 | 0 | return netif; |
1720 | 0 | } |
1721 | 0 | } |
1722 | 0 | LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: didn't find %c%c\n", name[0], name[1])); |
1723 | 0 | return NULL; |
1724 | 0 | } |
1725 | | |
1726 | | #if LWIP_NETIF_EXT_STATUS_CALLBACK |
1727 | | /** |
1728 | | * @ingroup netif |
1729 | | * Add extended netif events listener |
1730 | | * @param callback pointer to listener structure |
1731 | | * @param fn callback function |
1732 | | */ |
1733 | | void |
1734 | | netif_add_ext_callback(netif_ext_callback_t *callback, netif_ext_callback_fn fn) |
1735 | | { |
1736 | | LWIP_ASSERT_CORE_LOCKED(); |
1737 | | LWIP_ASSERT("callback must be != NULL", callback != NULL); |
1738 | | LWIP_ASSERT("fn must be != NULL", fn != NULL); |
1739 | | |
1740 | | callback->callback_fn = fn; |
1741 | | callback->next = ext_callback; |
1742 | | ext_callback = callback; |
1743 | | } |
1744 | | |
1745 | | /** |
1746 | | * @ingroup netif |
1747 | | * Remove extended netif events listener |
1748 | | * @param callback pointer to listener structure |
1749 | | */ |
1750 | | void |
1751 | | netif_remove_ext_callback(netif_ext_callback_t* callback) |
1752 | | { |
1753 | | netif_ext_callback_t *last, *iter; |
1754 | | |
1755 | | LWIP_ASSERT_CORE_LOCKED(); |
1756 | | LWIP_ASSERT("callback must be != NULL", callback != NULL); |
1757 | | |
1758 | | if (ext_callback == NULL) { |
1759 | | return; |
1760 | | } |
1761 | | |
1762 | | if (callback == ext_callback) { |
1763 | | ext_callback = ext_callback->next; |
1764 | | } else { |
1765 | | last = ext_callback; |
1766 | | for (iter = ext_callback->next; iter != NULL; last = iter, iter = iter->next) { |
1767 | | if (iter == callback) { |
1768 | | LWIP_ASSERT("last != NULL", last != NULL); |
1769 | | last->next = callback->next; |
1770 | | callback->next = NULL; |
1771 | | return; |
1772 | | } |
1773 | | } |
1774 | | } |
1775 | | } |
1776 | | |
1777 | | /** |
1778 | | * Invoke extended netif status event |
1779 | | * @param netif netif that is affected by change |
1780 | | * @param reason change reason |
1781 | | * @param args depends on reason, see reason description |
1782 | | */ |
1783 | | void |
1784 | | netif_invoke_ext_callback(struct netif *netif, netif_nsc_reason_t reason, const netif_ext_callback_args_t *args) |
1785 | | { |
1786 | | netif_ext_callback_t *callback = ext_callback; |
1787 | | |
1788 | | LWIP_ASSERT("netif must be != NULL", netif != NULL); |
1789 | | |
1790 | | while (callback != NULL) { |
1791 | | callback->callback_fn(netif, reason, args); |
1792 | | callback = callback->next; |
1793 | | } |
1794 | | } |
1795 | | #endif /* LWIP_NETIF_EXT_STATUS_CALLBACK */ |