aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/addrconf.c
diff options
context:
space:
mode:
authorYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2005-11-08 12:38:12 -0500
committerDavid S. Miller <davem@davemloft.net>2005-11-08 12:38:12 -0500
commitb1cacb6820e0afc4aeeea67bcb5296a316862cad (patch)
treee7a563d832dfb028b31492ec76054ca30c2c8878 /net/ipv6/addrconf.c
parent971f359ddcb2e7a0d577479c7561bda407febe1b (diff)
[IPV6]: Make ipv6_addr_type() more generic so that we can use it for source address selection.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r--net/ipv6/addrconf.c90
1 files changed, 47 insertions, 43 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 2c5f57299d63..ff895da6395b 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -35,6 +35,9 @@
35 * YOSHIFUJI Hideaki @USAGI : ARCnet support 35 * YOSHIFUJI Hideaki @USAGI : ARCnet support
36 * YOSHIFUJI Hideaki @USAGI : convert /proc/net/if_inet6 to 36 * YOSHIFUJI Hideaki @USAGI : convert /proc/net/if_inet6 to
37 * seq_file. 37 * seq_file.
38 * YOSHIFUJI Hideaki @USAGI : improved source address
39 * selection; consider scope,
40 * status etc.
38 */ 41 */
39 42
40#include <linux/config.h> 43#include <linux/config.h>
@@ -193,46 +196,51 @@ const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
193#endif 196#endif
194const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; 197const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
195 198
196int ipv6_addr_type(const struct in6_addr *addr) 199#define IPV6_ADDR_SCOPE_TYPE(scope) ((scope) << 16)
200
201static inline unsigned ipv6_addr_scope2type(unsigned scope)
202{
203 switch(scope) {
204 case IPV6_ADDR_SCOPE_NODELOCAL:
205 return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_NODELOCAL) |
206 IPV6_ADDR_LOOPBACK);
207 case IPV6_ADDR_SCOPE_LINKLOCAL:
208 return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL) |
209 IPV6_ADDR_LINKLOCAL);
210 case IPV6_ADDR_SCOPE_SITELOCAL:
211 return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL) |
212 IPV6_ADDR_SITELOCAL);
213 }
214 return IPV6_ADDR_SCOPE_TYPE(scope);
215}
216
217int __ipv6_addr_type(const struct in6_addr *addr)
197{ 218{
198 int type;
199 u32 st; 219 u32 st;
200 220
201 st = addr->s6_addr32[0]; 221 st = addr->s6_addr32[0];
202 222
203 if ((st & htonl(0xFF000000)) == htonl(0xFF000000)) {
204 type = IPV6_ADDR_MULTICAST;
205
206 switch((st & htonl(0x00FF0000))) {
207 case __constant_htonl(0x00010000):
208 type |= IPV6_ADDR_LOOPBACK;
209 break;
210
211 case __constant_htonl(0x00020000):
212 type |= IPV6_ADDR_LINKLOCAL;
213 break;
214
215 case __constant_htonl(0x00050000):
216 type |= IPV6_ADDR_SITELOCAL;
217 break;
218 };
219 return type;
220 }
221
222 type = IPV6_ADDR_UNICAST;
223
224 /* Consider all addresses with the first three bits different of 223 /* Consider all addresses with the first three bits different of
225 000 and 111 as finished. 224 000 and 111 as unicasts.
226 */ 225 */
227 if ((st & htonl(0xE0000000)) != htonl(0x00000000) && 226 if ((st & htonl(0xE0000000)) != htonl(0x00000000) &&
228 (st & htonl(0xE0000000)) != htonl(0xE0000000)) 227 (st & htonl(0xE0000000)) != htonl(0xE0000000))
229 return type; 228 return (IPV6_ADDR_UNICAST |
230 229 IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));
231 if ((st & htonl(0xFFC00000)) == htonl(0xFE800000))
232 return (IPV6_ADDR_LINKLOCAL | type);
233 230
231 if ((st & htonl(0xFF000000)) == htonl(0xFF000000)) {
232 /* multicast */
233 /* addr-select 3.1 */
234 return (IPV6_ADDR_MULTICAST |
235 ipv6_addr_scope2type(IPV6_ADDR_MC_SCOPE(addr)));
236 }
237
238 if ((st & htonl(0xFFC00000)) == htonl(0xFE800000))
239 return (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST |
240 IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL)); /* addr-select 3.1 */
234 if ((st & htonl(0xFFC00000)) == htonl(0xFEC00000)) 241 if ((st & htonl(0xFFC00000)) == htonl(0xFEC00000))
235 return (IPV6_ADDR_SITELOCAL | type); 242 return (IPV6_ADDR_SITELOCAL | IPV6_ADDR_UNICAST |
243 IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL)); /* addr-select 3.1 */
236 244
237 if ((addr->s6_addr32[0] | addr->s6_addr32[1]) == 0) { 245 if ((addr->s6_addr32[0] | addr->s6_addr32[1]) == 0) {
238 if (addr->s6_addr32[2] == 0) { 246 if (addr->s6_addr32[2] == 0) {
@@ -240,24 +248,20 @@ int ipv6_addr_type(const struct in6_addr *addr)
240 return IPV6_ADDR_ANY; 248 return IPV6_ADDR_ANY;
241 249
242 if (addr->s6_addr32[3] == htonl(0x00000001)) 250 if (addr->s6_addr32[3] == htonl(0x00000001))
243 return (IPV6_ADDR_LOOPBACK | type); 251 return (IPV6_ADDR_LOOPBACK | IPV6_ADDR_UNICAST |
252 IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL)); /* addr-select 3.4 */
244 253
245 return (IPV6_ADDR_COMPATv4 | type); 254 return (IPV6_ADDR_COMPATv4 | IPV6_ADDR_UNICAST |
255 IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.3 */
246 } 256 }
247 257
248 if (addr->s6_addr32[2] == htonl(0x0000ffff)) 258 if (addr->s6_addr32[2] == htonl(0x0000ffff))
249 return IPV6_ADDR_MAPPED; 259 return (IPV6_ADDR_MAPPED |
250 } 260 IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.3 */
251 261 }
252 st &= htonl(0xFF000000); 262
253 if (st == 0) 263 return (IPV6_ADDR_RESERVED |
254 return IPV6_ADDR_RESERVED; 264 IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.4 */
255 st &= htonl(0xFE000000);
256 if (st == htonl(0x02000000))
257 return IPV6_ADDR_RESERVED; /* for NSAP */
258 if (st == htonl(0x04000000))
259 return IPV6_ADDR_RESERVED; /* for IPX */
260 return type;
261} 265}
262 266
263static void addrconf_del_timer(struct inet6_ifaddr *ifp) 267static void addrconf_del_timer(struct inet6_ifaddr *ifp)