Mistake on this page?
Report an issue in GitHub or email us
ip6_zone.h
Go to the documentation of this file.
1 /**
2  * @file
3  *
4  * IPv6 address scopes, zones, and scoping policy.
5  *
6  * This header provides the means to implement support for IPv6 address scopes,
7  * as per RFC 4007. An address scope can be either global or more constrained.
8  * In lwIP, we say that an address "has a scope" or "is scoped" when its scope
9  * is constrained, in which case the address is meaningful only in a specific
10  * "zone." For unicast addresses, only link-local addresses have a scope; in
11  * that case, the scope is the link. For multicast addresses, there are various
12  * scopes defined by RFC 4007 and others. For any constrained scope, a system
13  * must establish a (potentially one-to-many) mapping between zones and local
14  * interfaces. For example, a link-local address is valid on only one link (its
15  * zone). That link may be attached to one or more local interfaces. The
16  * decisions on which scopes are constrained and the mapping between zones and
17  * interfaces is together what we refer to as the "scoping policy" - more on
18  * this in a bit.
19  *
20  * In lwIP, each IPv6 address has an associated zone index. This zone index may
21  * be set to "no zone" (IP6_NO_ZONE, 0) or an actual zone. We say that an
22  * address "has a zone" or "is zoned" when its zone index is *not* set to "no
23  * zone." In lwIP, in principle, each address should be "properly zoned," which
24  * means that if the address has a zone if and only if has a scope. As such, it
25  * is a rule that an unscoped (e.g., global) address must never have a zone.
26  * Even though one could argue that there is always one zone even for global
27  * scopes, this rule exists for implementation simplicity. Violation of the
28  * rule will trigger assertions or otherwise result in undesired behavior.
29  *
30  * Backward compatibility prevents us from requiring that applications always
31  * provide properly zoned addresses. We do enforce the rule that the in the
32  * lwIP link layer (everything below netif->output_ip6() and in particular ND6)
33  * *all* addresses are properly zoned. Thus, on the output paths down the
34  * stack, various places deal with the case of addresses that lack a zone.
35  * Some of them are best-effort for efficiency (e.g. the PCB bind and connect
36  * API calls' attempts to add missing zones); ultimately the IPv6 output
37  * handler (@ref ip6_output_if_src) will set a zone if necessary.
38  *
39  * Aside from dealing with scoped addresses lacking a zone, a proper IPv6
40  * implementation must also ensure that a packet with a scoped source and/or
41  * destination address does not leave its zone. This is currently implemented
42  * in the input and forward functions. However, for output, these checks are
43  * deliberately omitted in order to keep the implementation lightweight. The
44  * routing algorithm in @ref ip6_route will take decisions such that it will
45  * not cause zone violations unless the application sets bad addresses, though.
46  *
47  * In terms of scoping policy, lwIP implements the default policy from RFC 4007
48  * using macros in this file. This policy considers link-local unicast
49  * addresses and (only) interface-local and link-local multicast addresses as
50  * having a scope. For all these addresses, the zone is equal to the interface.
51  * As shown below in this file, it is possible to implement a custom policy.
52  */
53 
54 /*
55  * Copyright (c) 2017 The MINIX 3 Project.
56  * All rights reserved.
57  *
58  * Redistribution and use in source and binary forms, with or without modification,
59  * are permitted provided that the following conditions are met:
60  *
61  * 1. Redistributions of source code must retain the above copyright notice,
62  * this list of conditions and the following disclaimer.
63  * 2. Redistributions in binary form must reproduce the above copyright notice,
64  * this list of conditions and the following disclaimer in the documentation
65  * and/or other materials provided with the distribution.
66  * 3. The name of the author may not be used to endorse or promote products
67  * derived from this software without specific prior written permission.
68  *
69  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
70  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
71  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
72  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
73  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
74  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
75  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
76  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
77  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
78  * OF SUCH DAMAGE.
79  *
80  * This file is part of the lwIP TCP/IP stack.
81  *
82  * Author: David van Moolenbroek <david@minix3.org>
83  *
84  */
85 #ifndef LWIP_HDR_IP6_ZONE_H
86 #define LWIP_HDR_IP6_ZONE_H
87 
88 #ifdef __cplusplus
89 extern "C" {
90 #endif
91 
92 /**
93  * @defgroup ip6_zones IPv6 Zones
94  * @ingroup ip6
95  * @{
96  */
97 
98 #if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
99 
100 /** Identifier for "no zone". */
101 #define IP6_NO_ZONE 0
102 
103 #if LWIP_IPV6_SCOPES
104 
105 /** Zone initializer for static IPv6 address initialization, including comma. */
106 #define IPADDR6_ZONE_INIT , IP6_NO_ZONE
107 
108 /** Return the zone index of the given IPv6 address; possibly "no zone". */
109 #define ip6_addr_zone(ip6addr) ((ip6addr)->zone)
110 
111 /** Does the given IPv6 address have a zone set? (0/1) */
112 #define ip6_addr_has_zone(ip6addr) (ip6_addr_zone(ip6addr) != IP6_NO_ZONE)
113 
114 /** Set the zone field of an IPv6 address to a particular value. */
115 #define ip6_addr_set_zone(ip6addr, zone_idx) ((ip6addr)->zone = (zone_idx))
116 
117 /** Clear the zone field of an IPv6 address, setting it to "no zone". */
118 #define ip6_addr_clear_zone(ip6addr) ((ip6addr)->zone = IP6_NO_ZONE)
119 
120 /** Copy the zone field from the second IPv6 address to the first one. */
121 #define ip6_addr_copy_zone(ip6addr1, ip6addr2) ((ip6addr1).zone = (ip6addr2).zone)
122 
123 /** Is the zone field of the given IPv6 address equal to the given zone index? (0/1) */
124 #define ip6_addr_equals_zone(ip6addr, zone_idx) ((ip6addr)->zone == (zone_idx))
125 
126 /** Are the zone fields of the given IPv6 addresses equal? (0/1)
127  * This macro must only be used on IPv6 addresses of the same scope. */
128 #define ip6_addr_cmp_zone(ip6addr1, ip6addr2) ((ip6addr1)->zone == (ip6addr2)->zone)
129 
130 /** Symbolic constants for the 'type' parameters in some of the macros.
131  * These exist for efficiency only, allowing the macros to avoid certain tests
132  * when the address is known not to be of a certain type. Dead code elimination
133  * will do the rest. IP6_MULTICAST is supported but currently not optimized.
134  * @see ip6_addr_has_scope, ip6_addr_assign_zone, ip6_addr_lacks_zone.
135  */
136 enum lwip_ipv6_scope_type
137 {
138  /** Unknown */
139  IP6_UNKNOWN = 0,
140  /** Unicast */
141  IP6_UNICAST = 1,
142  /** Multicast */
143  IP6_MULTICAST = 2
144 };
145 
146 /** IPV6_CUSTOM_SCOPES: together, the following three macro definitions,
147  * @ref ip6_addr_has_scope, @ref ip6_addr_assign_zone, and
148  * @ref ip6_addr_test_zone, completely define the lwIP scoping policy.
149  * The definitions below implement the default policy from RFC 4007 Sec. 6.
150  * Should an implementation desire to implement a different policy, it can
151  * define IPV6_CUSTOM_SCOPES to 1 and supply its own definitions for the three
152  * macros instead.
153  */
154 #ifndef IPV6_CUSTOM_SCOPES
155 #define IPV6_CUSTOM_SCOPES 0
156 #endif /* !IPV6_CUSTOM_SCOPES */
157 
158 #if !IPV6_CUSTOM_SCOPES
159 
160 /**
161  * Determine whether an IPv6 address has a constrained scope, and as such is
162  * meaningful only if accompanied by a zone index to identify the scope's zone.
163  * The given address type may be used to eliminate at compile time certain
164  * checks that will evaluate to false at run time anyway.
165  *
166  * This default implementation follows the default model of RFC 4007, where
167  * only interface-local and link-local scopes are defined.
168  *
169  * Even though the unicast loopback address does have an implied link-local
170  * scope, in this implementation it does not have an explicitly assigned zone
171  * index. As such it should not be tested for in this macro.
172  *
173  * @param ip6addr the IPv6 address (const); only its address part is examined.
174  * @param type address type; see @ref lwip_ipv6_scope_type.
175  * @return 1 if the address has a constrained scope, 0 if it does not.
176  */
177 #define ip6_addr_has_scope(ip6addr, type) \
178  (ip6_addr_islinklocal(ip6addr) || (((type) != IP6_UNICAST) && \
179  (ip6_addr_ismulticast_iflocal(ip6addr) || \
180  ip6_addr_ismulticast_linklocal(ip6addr))))
181 
182 /**
183  * Assign a zone index to an IPv6 address, based on a network interface. If the
184  * given address has a scope, the assigned zone index is that scope's zone of
185  * the given netif; otherwise, the assigned zone index is "no zone".
186  *
187  * This default implementation follows the default model of RFC 4007, where
188  * only interface-local and link-local scopes are defined, and the zone index
189  * of both of those scopes always equals the index of the network interface.
190  * As such, this default implementation need not distinguish between different
191  * constrained scopes when assigning the zone.
192  *
193  * @param ip6addr the IPv6 address; its address part is examined, and its zone
194  * index is assigned.
195  * @param type address type; see @ref lwip_ipv6_scope_type.
196  * @param netif the network interface (const).
197  */
198 #define ip6_addr_assign_zone(ip6addr, type, netif) \
199  (ip6_addr_set_zone((ip6addr), \
200  ip6_addr_has_scope((ip6addr), (type)) ? netif_get_index(netif) : 0))
201 
202 /**
203  * Test whether an IPv6 address is "zone-compatible" with a network interface.
204  * That is, test whether the network interface is part of the zone associated
205  * with the address. For efficiency, this macro is only ever called if the
206  * given address is either scoped or zoned, and thus, it need not test this.
207  * If an address is scoped but not zoned, or zoned and not scoped, it is
208  * considered not zone-compatible with any netif.
209  *
210  * This default implementation follows the default model of RFC 4007, where
211  * only interface-local and link-local scopes are defined, and the zone index
212  * of both of those scopes always equals the index of the network interface.
213  * As such, there is always only one matching netif for a specific zone index,
214  * but all call sites of this macro currently support multiple matching netifs
215  * as well (at no additional expense in the common case).
216  *
217  * @param ip6addr the IPv6 address (const).
218  * @param netif the network interface (const).
219  * @return 1 if the address is scope-compatible with the netif, 0 if not.
220  */
221 #define ip6_addr_test_zone(ip6addr, netif) \
222  (ip6_addr_equals_zone((ip6addr), netif_get_index(netif)))
223 
224 #endif /* !IPV6_CUSTOM_SCOPES */
225 
226 /** Does the given IPv6 address have a scope, and as such should also have a
227  * zone to be meaningful, but does not actually have a zone? (0/1) */
228 #define ip6_addr_lacks_zone(ip6addr, type) \
229  (!ip6_addr_has_zone(ip6addr) && ip6_addr_has_scope((ip6addr), (type)))
230 
231 /**
232  * Try to select a zone for a scoped address that does not yet have a zone.
233  * Called from PCB bind and connect routines, for two reasons: 1) to save on
234  * this (relatively expensive) selection for every individual packet route
235  * operation and 2) to allow the application to obtain the selected zone from
236  * the PCB as is customary for e.g. getsockname/getpeername BSD socket calls.
237  *
238  * Ideally, callers would always supply a properly zoned address, in which case
239  * this function would not be needed. It exists both for compatibility with the
240  * BSD socket API (which accepts zoneless destination addresses) and for
241  * backward compatibility with pre-scoping lwIP code.
242  *
243  * It may be impossible to select a zone, e.g. if there are no netifs. In that
244  * case, the address's zone field will be left as is.
245  *
246  * @param dest the IPv6 address for which to select and set a zone.
247  * @param src source IPv6 address (const); may be equal to dest.
248  */
249 #define ip6_addr_select_zone(dest, src) do { struct netif *selected_netif; \
250  selected_netif = ip6_route((src), (dest)); \
251  if (selected_netif != NULL) { \
252  ip6_addr_assign_zone((dest), IP6_UNKNOWN, selected_netif); \
253  } } while (0)
254 
255 /**
256  * @}
257  */
258 
259 #else /* LWIP_IPV6_SCOPES */
260 
261 #define IPADDR6_ZONE_INIT
262 #define ip6_addr_zone(ip6addr) (IP6_NO_ZONE)
263 #define ip6_addr_has_zone(ip6addr) (0)
264 #define ip6_addr_set_zone(ip6addr, zone_idx)
265 #define ip6_addr_clear_zone(ip6addr)
266 #define ip6_addr_copy_zone(ip6addr1, ip6addr2)
267 #define ip6_addr_equals_zone(ip6addr, zone_idx) (1)
268 #define ip6_addr_cmp_zone(ip6addr1, ip6addr2) (1)
269 #define IPV6_CUSTOM_SCOPES 0
270 #define ip6_addr_has_scope(ip6addr, type) (0)
271 #define ip6_addr_assign_zone(ip6addr, type, netif)
272 #define ip6_addr_test_zone(ip6addr, netif) (1)
273 #define ip6_addr_lacks_zone(ip6addr, type) (0)
274 #define ip6_addr_select_zone(ip6addr, src)
275 
276 #endif /* LWIP_IPV6_SCOPES */
277 
278 #if LWIP_IPV6_SCOPES && LWIP_IPV6_SCOPES_DEBUG
279 
280 /** Verify that the given IPv6 address is properly zoned. */
281 #define IP6_ADDR_ZONECHECK(ip6addr) LWIP_ASSERT("IPv6 zone check failed", \
282  ip6_addr_has_scope(ip6addr, IP6_UNKNOWN) == ip6_addr_has_zone(ip6addr))
283 
284 /** Verify that the given IPv6 address is properly zoned for the given netif. */
285 #define IP6_ADDR_ZONECHECK_NETIF(ip6addr, netif) LWIP_ASSERT("IPv6 netif zone check failed", \
286  ip6_addr_has_scope(ip6addr, IP6_UNKNOWN) ? \
287  (ip6_addr_has_zone(ip6addr) && \
288  (((netif) == NULL) || ip6_addr_test_zone((ip6addr), (netif)))) : \
289  !ip6_addr_has_zone(ip6addr))
290 
291 #else /* LWIP_IPV6_SCOPES && LWIP_IPV6_SCOPES_DEBUG */
292 
293 #define IP6_ADDR_ZONECHECK(ip6addr)
294 #define IP6_ADDR_ZONECHECK_NETIF(ip6addr, netif)
295 
296 #endif /* LWIP_IPV6_SCOPES && LWIP_IPV6_SCOPES_DEBUG */
297 
298 #endif /* LWIP_IPV6 */
299 
300 #ifdef __cplusplus
301 }
302 #endif
303 
304 #endif /* LWIP_HDR_IP6_ZONE_H */
Important Information for this Arm website

This site uses cookies to store information on your computer. By continuing to use our site, you consent to our cookies. If you are not happy with the use of these cookies, please review our Cookie Policy to learn how they can be disabled. By disabling cookies, some features of the site will not work.