| 1 | |
| 2 | |
| 3 | * IPv6 library code, needed by static components when full IPv6 support is
|
| 4 | * not configured or static.
|
| 5 |
|
| 6 |
|
| 7 | #include <linux/export.h>
|
| 8 | #include <net/ipv6.h>
|
| 9 | #include <net/addrconf.h>
|
| 10 | #include <net/ip.h>
|
| 11 |
|
| 12 | |
| 13 | * sockets to relookup their nodes - this is fairly expensive, be
|
| 14 | * careful
|
| 15 |
|
| 16 | void (*__fib6_flush_trees)(struct net *);
|
| 17 | EXPORT_SYMBOL(__fib6_flush_trees);
|
| 18 |
|
| 19 | #define IPV6_ADDR_SCOPE_TYPE(scope) ((scope) << 16)
|
| 20 |
|
| 21 | static inline unsigned int ipv6_addr_scope2type(unsigned int scope)
|
| 22 | {
|
| 23 | switch (scope) {
|
| 24 | case IPV6_ADDR_SCOPE_NODELOCAL:
|
| 25 | return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_NODELOCAL) |
|
| 26 | IPV6_ADDR_LOOPBACK);
|
| 27 | case IPV6_ADDR_SCOPE_LINKLOCAL:
|
| 28 | return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL) |
|
| 29 | IPV6_ADDR_LINKLOCAL);
|
| 30 | case IPV6_ADDR_SCOPE_SITELOCAL:
|
| 31 | return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL) |
|
| 32 | IPV6_ADDR_SITELOCAL);
|
| 33 | }
|
| 34 | return IPV6_ADDR_SCOPE_TYPE(scope);
|
| 35 | }
|
| 36 |
|
| 37 | int __ipv6_addr_type(const struct in6_addr *addr)
|
| 38 | {
|
| 39 | __be32 st;
|
| 40 |
|
| 41 | st = addr->s6_addr32[0];
|
| 42 |
|
| 43 | |
| 44 | 000 and 111 as unicasts.
|
| 45 |
|
| 46 | if ((st & htonl(0xE0000000)) != htonl(0x00000000) &&
|
| 47 | (st & htonl(0xE0000000)) != htonl(0xE0000000))
|
| 48 | return (IPV6_ADDR_UNICAST |
|
| 49 | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));
|
| 50 |
|
| 51 | if ((st & htonl(0xFF000000)) == htonl(0xFF000000)) {
|
| 52 |
|
| 53 |
|
| 54 | return (IPV6_ADDR_MULTICAST |
|
| 55 | ipv6_addr_scope2type(IPV6_ADDR_MC_SCOPE(addr)));
|
| 56 | }
|
| 57 |
|
| 58 | if ((st & htonl(0xFFC00000)) == htonl(0xFE800000))
|
| 59 | return (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST |
|
| 60 | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL));
|
| 61 | if ((st & htonl(0xFFC00000)) == htonl(0xFEC00000))
|
| 62 | return (IPV6_ADDR_SITELOCAL | IPV6_ADDR_UNICAST |
|
| 63 | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL));
|
| 64 | if ((st & htonl(0xFE000000)) == htonl(0xFC000000))
|
| 65 | return (IPV6_ADDR_UNICAST |
|
| 66 | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));
|
| 67 |
|
| 68 | if ((addr->s6_addr32[0] | addr->s6_addr32[1]) == 0) {
|
| 69 | if (addr->s6_addr32[2] == 0) {
|
| 70 | if (addr->s6_addr32[3] == 0)
|
| 71 | return IPV6_ADDR_ANY;
|
| 72 |
|
| 73 | if (addr->s6_addr32[3] == htonl(0x00000001))
|
| 74 | return (IPV6_ADDR_LOOPBACK | IPV6_ADDR_UNICAST |
|
| 75 | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL));
|
| 76 |
|
| 77 | return (IPV6_ADDR_COMPATv4 | IPV6_ADDR_UNICAST |
|
| 78 | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));
|
| 79 | }
|
| 80 |
|
| 81 | if (addr->s6_addr32[2] == htonl(0x0000ffff))
|
| 82 | return (IPV6_ADDR_MAPPED |
|
| 83 | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));
|
| 84 | }
|
| 85 |
|
| 86 | return (IPV6_ADDR_UNICAST |
|
| 87 | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));
|
| 88 | }
|
| 89 | EXPORT_SYMBOL(__ipv6_addr_type);
|
| 90 |
|
| 91 | static ATOMIC_NOTIFIER_HEAD(inet6addr_chain);
|
| 92 | static BLOCKING_NOTIFIER_HEAD(inet6addr_validator_chain);
|
| 93 |
|
| 94 | int register_inet6addr_notifier(struct notifier_block *nb)
|
| 95 | {
|
| 96 | return atomic_notifier_chain_register(&inet6addr_chain, nb);
|
| 97 | }
|
| 98 | EXPORT_SYMBOL(register_inet6addr_notifier);
|
| 99 |
|
| 100 | int unregister_inet6addr_notifier(struct notifier_block *nb)
|
| 101 | {
|
| 102 | return atomic_notifier_chain_unregister(&inet6addr_chain, nb);
|
| 103 | }
|
| 104 | EXPORT_SYMBOL(unregister_inet6addr_notifier);
|
| 105 |
|
| 106 | int inet6addr_notifier_call_chain(unsigned long val, void *v)
|
| 107 | {
|
| 108 | return atomic_notifier_call_chain(&inet6addr_chain, val, v);
|
| 109 | }
|
| 110 |
|
| 111 | int register_inet6addr_validator_notifier(struct notifier_block *nb)
|
| 112 | {
|
| 113 | return blocking_notifier_chain_register(&inet6addr_validator_chain, nb);
|
| 114 | }
|
| 115 | EXPORT_SYMBOL(register_inet6addr_validator_notifier);
|
| 116 |
|
| 117 | int unregister_inet6addr_validator_notifier(struct notifier_block *nb)
|
| 118 | {
|
| 119 | return blocking_notifier_chain_unregister(&inet6addr_validator_chain,
|
| 120 | nb);
|
| 121 | }
|
| 122 | EXPORT_SYMBOL(unregister_inet6addr_validator_notifier);
|
| 123 |
|
| 124 | int inet6addr_validator_notifier_call_chain(unsigned long val, void *v)
|
| 125 | {
|
| 126 | return blocking_notifier_call_chain(&inet6addr_validator_chain, val, v);
|
| 127 | }
|
| 128 |
|
| 129 |
|
| 130 | const struct in6_addr in6addr_loopback __aligned(BITS_PER_LONG/8)
|
| 131 | = IN6ADDR_LOOPBACK_INIT;
|
| 132 | EXPORT_SYMBOL(in6addr_loopback);
|
| 133 | const struct in6_addr in6addr_any __aligned(BITS_PER_LONG/8)
|
| 134 | = IN6ADDR_ANY_INIT;
|
| 135 | EXPORT_SYMBOL(in6addr_any);
|
| 136 | const struct in6_addr in6addr_linklocal_allnodes __aligned(BITS_PER_LONG/8)
|
| 137 | = IN6ADDR_LINKLOCAL_ALLNODES_INIT;
|
| 138 | EXPORT_SYMBOL(in6addr_linklocal_allnodes);
|
| 139 | const struct in6_addr in6addr_linklocal_allrouters __aligned(BITS_PER_LONG/8)
|
| 140 | = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT;
|
| 141 | const struct in6_addr in6addr_interfacelocal_allnodes __aligned(BITS_PER_LONG/8)
|
| 142 | = IN6ADDR_INTERFACELOCAL_ALLNODES_INIT;
|
| 143 | const struct in6_addr in6addr_interfacelocal_allrouters __aligned(BITS_PER_LONG/8)
|
| 144 | = IN6ADDR_INTERFACELOCAL_ALLROUTERS_INIT;
|
| 145 | const struct in6_addr in6addr_sitelocal_allrouters __aligned(BITS_PER_LONG/8)
|
| 146 | = IN6ADDR_SITELOCAL_ALLROUTERS_INIT;
|
| 147 |
|
| 148 | static void snmp6_free_dev(struct inet6_dev *idev)
|
| 149 | {
|
| 150 | kfree(idev->stats.icmpv6msgdev);
|
| 151 | kfree(idev->stats.icmpv6dev);
|
| 152 | free_percpu(idev->stats.ipv6);
|
| 153 | }
|
| 154 |
|
| 155 | static void in6_dev_finish_destroy_rcu(struct rcu_head *head)
|
| 156 | {
|
| 157 | struct inet6_dev *idev = container_of(head, struct inet6_dev, rcu);
|
| 158 |
|
| 159 | snmp6_free_dev(idev);
|
| 160 | kfree(idev);
|
| 161 | }
|
| 162 |
|
| 163 |
|
| 164 |
|
| 165 | void in6_dev_finish_destroy(struct inet6_dev *idev)
|
| 166 | {
|
| 167 | struct net_device *dev = idev->dev;
|
| 168 |
|
| 169 | WARN_ON(!list_empty(&idev->addr_list));
|
| 170 | WARN_ON(rcu_access_pointer(idev->mc_list));
|
| 171 | WARN_ON(timer_pending(&idev->rs_timer));
|
| 172 |
|
| 173 | #ifdef NET_REFCNT_DEBUG
|
| 174 | pr_debug("%s: %s\n", __func__, dev ? dev->name : "NIL");
|
| 175 | #endif
|
| 176 | netdev_put(dev, &idev->dev_tracker);
|
| 177 | if (!idev->dead) {
|
| 178 | pr_warn("Freeing alive inet6 device %p\n", idev);
|
| 179 | return;
|
| 180 | }
|
| 181 | call_rcu(&idev->rcu, in6_dev_finish_destroy_rcu);
|
| 182 | }
|
| 183 | EXPORT_SYMBOL(in6_dev_finish_destroy);
|