| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | 
|---|
| 2 | #ifndef _NDISC_H | 
|---|
| 3 | #define _NDISC_H | 
|---|
| 4 |  | 
|---|
| 5 | #include <net/ipv6_stubs.h> | 
|---|
| 6 |  | 
|---|
| 7 | /* | 
|---|
| 8 | *	ICMP codes for neighbour discovery messages | 
|---|
| 9 | */ | 
|---|
| 10 |  | 
|---|
| 11 | #define NDISC_ROUTER_SOLICITATION	133 | 
|---|
| 12 | #define NDISC_ROUTER_ADVERTISEMENT	134 | 
|---|
| 13 | #define NDISC_NEIGHBOUR_SOLICITATION	135 | 
|---|
| 14 | #define NDISC_NEIGHBOUR_ADVERTISEMENT	136 | 
|---|
| 15 | #define NDISC_REDIRECT			137 | 
|---|
| 16 |  | 
|---|
| 17 | /* | 
|---|
| 18 | * Router type: cross-layer information from link-layer to | 
|---|
| 19 | * IPv6 layer reported by certain link types (e.g., RFC4214). | 
|---|
| 20 | */ | 
|---|
| 21 | #define NDISC_NODETYPE_UNSPEC		0	/* unspecified (default) */ | 
|---|
| 22 | #define NDISC_NODETYPE_HOST		1	/* host or unauthorized router */ | 
|---|
| 23 | #define NDISC_NODETYPE_NODEFAULT	2	/* non-default router */ | 
|---|
| 24 | #define NDISC_NODETYPE_DEFAULT		3	/* default router */ | 
|---|
| 25 |  | 
|---|
| 26 | /* | 
|---|
| 27 | *	ndisc options | 
|---|
| 28 | */ | 
|---|
| 29 |  | 
|---|
| 30 | enum { | 
|---|
| 31 | __ND_OPT_PREFIX_INFO_END = 0, | 
|---|
| 32 | ND_OPT_SOURCE_LL_ADDR = 1,	/* RFC2461 */ | 
|---|
| 33 | ND_OPT_TARGET_LL_ADDR = 2,	/* RFC2461 */ | 
|---|
| 34 | ND_OPT_PREFIX_INFO = 3,		/* RFC2461 */ | 
|---|
| 35 | ND_OPT_REDIRECT_HDR = 4,	/* RFC2461 */ | 
|---|
| 36 | ND_OPT_MTU = 5,			/* RFC2461 */ | 
|---|
| 37 | ND_OPT_NONCE = 14,              /* RFC7527 */ | 
|---|
| 38 | __ND_OPT_ARRAY_MAX, | 
|---|
| 39 | ND_OPT_ROUTE_INFO = 24,		/* RFC4191 */ | 
|---|
| 40 | ND_OPT_RDNSS = 25,		/* RFC5006 */ | 
|---|
| 41 | ND_OPT_DNSSL = 31,		/* RFC6106 */ | 
|---|
| 42 | ND_OPT_6CO = 34,		/* RFC6775 */ | 
|---|
| 43 | ND_OPT_CAPTIVE_PORTAL = 37,	/* RFC7710 */ | 
|---|
| 44 | ND_OPT_PREF64 = 38,		/* RFC8781 */ | 
|---|
| 45 | __ND_OPT_MAX | 
|---|
| 46 | }; | 
|---|
| 47 |  | 
|---|
| 48 | #define MAX_RTR_SOLICITATION_DELAY	HZ | 
|---|
| 49 |  | 
|---|
| 50 | #define ND_REACHABLE_TIME		(30*HZ) | 
|---|
| 51 | #define ND_RETRANS_TIMER		HZ | 
|---|
| 52 |  | 
|---|
| 53 | #include <linux/compiler.h> | 
|---|
| 54 | #include <linux/icmpv6.h> | 
|---|
| 55 | #include <linux/in6.h> | 
|---|
| 56 | #include <linux/types.h> | 
|---|
| 57 | #include <linux/if_arp.h> | 
|---|
| 58 | #include <linux/netdevice.h> | 
|---|
| 59 | #include <linux/hash.h> | 
|---|
| 60 |  | 
|---|
| 61 | #include <net/neighbour.h> | 
|---|
| 62 |  | 
|---|
| 63 | struct ctl_table; | 
|---|
| 64 | struct inet6_dev; | 
|---|
| 65 | struct net_device; | 
|---|
| 66 | struct net_proto_family; | 
|---|
| 67 | struct sk_buff; | 
|---|
| 68 | struct prefix_info; | 
|---|
| 69 |  | 
|---|
| 70 | extern struct neigh_table nd_tbl; | 
|---|
| 71 |  | 
|---|
| 72 | struct nd_msg { | 
|---|
| 73 | struct icmp6hdr	icmph; | 
|---|
| 74 | struct in6_addr	target; | 
|---|
| 75 | __u8		opt[]; | 
|---|
| 76 | }; | 
|---|
| 77 |  | 
|---|
| 78 | struct rs_msg { | 
|---|
| 79 | struct icmp6hdr	icmph; | 
|---|
| 80 | __u8		opt[]; | 
|---|
| 81 | }; | 
|---|
| 82 |  | 
|---|
| 83 | struct ra_msg { | 
|---|
| 84 | struct icmp6hdr		icmph; | 
|---|
| 85 | __be32			reachable_time; | 
|---|
| 86 | __be32			retrans_timer; | 
|---|
| 87 | }; | 
|---|
| 88 |  | 
|---|
| 89 | struct rd_msg { | 
|---|
| 90 | struct icmp6hdr icmph; | 
|---|
| 91 | struct in6_addr	target; | 
|---|
| 92 | struct in6_addr	dest; | 
|---|
| 93 | __u8		opt[]; | 
|---|
| 94 | }; | 
|---|
| 95 |  | 
|---|
| 96 | struct nd_opt_hdr { | 
|---|
| 97 | __u8		nd_opt_type; | 
|---|
| 98 | __u8		nd_opt_len; | 
|---|
| 99 | } __packed; | 
|---|
| 100 |  | 
|---|
| 101 | /* ND options */ | 
|---|
| 102 | struct ndisc_options { | 
|---|
| 103 | struct nd_opt_hdr *nd_opt_array[__ND_OPT_ARRAY_MAX]; | 
|---|
| 104 | #ifdef CONFIG_IPV6_ROUTE_INFO | 
|---|
| 105 | struct nd_opt_hdr *nd_opts_ri; | 
|---|
| 106 | struct nd_opt_hdr *nd_opts_ri_end; | 
|---|
| 107 | #endif | 
|---|
| 108 | struct nd_opt_hdr *nd_useropts; | 
|---|
| 109 | struct nd_opt_hdr *nd_useropts_end; | 
|---|
| 110 | #if IS_ENABLED(CONFIG_IEEE802154_6LOWPAN) | 
|---|
| 111 | struct nd_opt_hdr *nd_802154_opt_array[ND_OPT_TARGET_LL_ADDR + 1]; | 
|---|
| 112 | #endif | 
|---|
| 113 | }; | 
|---|
| 114 |  | 
|---|
| 115 | #define nd_opts_src_lladdr		nd_opt_array[ND_OPT_SOURCE_LL_ADDR] | 
|---|
| 116 | #define nd_opts_tgt_lladdr		nd_opt_array[ND_OPT_TARGET_LL_ADDR] | 
|---|
| 117 | #define nd_opts_pi			nd_opt_array[ND_OPT_PREFIX_INFO] | 
|---|
| 118 | #define nd_opts_pi_end			nd_opt_array[__ND_OPT_PREFIX_INFO_END] | 
|---|
| 119 | #define nd_opts_rh			nd_opt_array[ND_OPT_REDIRECT_HDR] | 
|---|
| 120 | #define nd_opts_mtu			nd_opt_array[ND_OPT_MTU] | 
|---|
| 121 | #define nd_opts_nonce			nd_opt_array[ND_OPT_NONCE] | 
|---|
| 122 | #define nd_802154_opts_src_lladdr	nd_802154_opt_array[ND_OPT_SOURCE_LL_ADDR] | 
|---|
| 123 | #define nd_802154_opts_tgt_lladdr	nd_802154_opt_array[ND_OPT_TARGET_LL_ADDR] | 
|---|
| 124 |  | 
|---|
| 125 | #define NDISC_OPT_SPACE(len) (((len)+2+7)&~7) | 
|---|
| 126 |  | 
|---|
| 127 | struct ndisc_options *ndisc_parse_options(const struct net_device *dev, | 
|---|
| 128 | u8 *opt, int opt_len, | 
|---|
| 129 | struct ndisc_options *ndopts); | 
|---|
| 130 |  | 
|---|
| 131 | void __ndisc_fill_addr_option(struct sk_buff *skb, int type, const void *data, | 
|---|
| 132 | int data_len, int pad); | 
|---|
| 133 |  | 
|---|
| 134 | #define NDISC_OPS_REDIRECT_DATA_SPACE	2 | 
|---|
| 135 |  | 
|---|
| 136 | /* | 
|---|
| 137 | * This structure defines the hooks for IPv6 neighbour discovery. | 
|---|
| 138 | * The following hooks can be defined; unless noted otherwise, they are | 
|---|
| 139 | * optional and can be filled with a null pointer. | 
|---|
| 140 | * | 
|---|
| 141 | * int (*parse_options)(const struct net_device *dev, | 
|---|
| 142 | *			struct nd_opt_hdr *nd_opt, | 
|---|
| 143 | *			struct ndisc_options *ndopts): | 
|---|
| 144 | *     This function is called while parsing ndisc ops and put each position | 
|---|
| 145 | *     as pointer into ndopts. If this function return unequal 0, then this | 
|---|
| 146 | *     function took care about the ndisc option, if 0 then the IPv6 ndisc | 
|---|
| 147 | *     option parser will take care about that option. | 
|---|
| 148 | * | 
|---|
| 149 | * void (*update)(const struct net_device *dev, struct neighbour *n, | 
|---|
| 150 | *		  u32 flags, u8 icmp6_type, | 
|---|
| 151 | *		  const struct ndisc_options *ndopts): | 
|---|
| 152 | *     This function is called when IPv6 ndisc updates the neighbour cache | 
|---|
| 153 | *     entry. Additional options which can be updated may be previously | 
|---|
| 154 | *     parsed by parse_opts callback and accessible over ndopts parameter. | 
|---|
| 155 | * | 
|---|
| 156 | * int (*opt_addr_space)(const struct net_device *dev, u8 icmp6_type, | 
|---|
| 157 | *			 struct neighbour *neigh, u8 *ha_buf, | 
|---|
| 158 | *			 u8 **ha): | 
|---|
| 159 | *     This function is called when the necessary option space will be | 
|---|
| 160 | *     calculated before allocating a skb. The parameters neigh, ha_buf | 
|---|
| 161 | *     abd ha are available on NDISC_REDIRECT messages only. | 
|---|
| 162 | * | 
|---|
| 163 | * void (*fill_addr_option)(const struct net_device *dev, | 
|---|
| 164 | *			    struct sk_buff *skb, u8 icmp6_type, | 
|---|
| 165 | *			    const u8 *ha): | 
|---|
| 166 | *     This function is called when the skb will finally fill the option | 
|---|
| 167 | *     fields inside skb. NOTE: this callback should fill the option | 
|---|
| 168 | *     fields to the skb which are previously indicated by opt_space | 
|---|
| 169 | *     parameter. That means the decision to add such option should | 
|---|
| 170 | *     not lost between these two callbacks, e.g. protected by interface | 
|---|
| 171 | *     up state. | 
|---|
| 172 | * | 
|---|
| 173 | * void (*prefix_rcv_add_addr)(struct net *net, struct net_device *dev, | 
|---|
| 174 | *			       const struct prefix_info *pinfo, | 
|---|
| 175 | *			       struct inet6_dev *in6_dev, | 
|---|
| 176 | *			       struct in6_addr *addr, | 
|---|
| 177 | *			       int addr_type, u32 addr_flags, | 
|---|
| 178 | *			       bool sllao, bool tokenized, | 
|---|
| 179 | *			       __u32 valid_lft, u32 prefered_lft, | 
|---|
| 180 | *			       bool dev_addr_generated): | 
|---|
| 181 | *     This function is called when a RA messages is received with valid | 
|---|
| 182 | *     PIO option fields and an IPv6 address will be added to the interface | 
|---|
| 183 | *     for autoconfiguration. The parameter dev_addr_generated reports about | 
|---|
| 184 | *     if the address was based on dev->dev_addr or not. This can be used | 
|---|
| 185 | *     to add a second address if link-layer operates with two link layer | 
|---|
| 186 | *     addresses. E.g. 802.15.4 6LoWPAN. | 
|---|
| 187 | */ | 
|---|
| 188 | struct ndisc_ops { | 
|---|
| 189 | int	(*parse_options)(const struct net_device *dev, | 
|---|
| 190 | struct nd_opt_hdr *nd_opt, | 
|---|
| 191 | struct ndisc_options *ndopts); | 
|---|
| 192 | void	(*update)(const struct net_device *dev, struct neighbour *n, | 
|---|
| 193 | u32 flags, u8 icmp6_type, | 
|---|
| 194 | const struct ndisc_options *ndopts); | 
|---|
| 195 | int	(*opt_addr_space)(const struct net_device *dev, u8 icmp6_type, | 
|---|
| 196 | struct neighbour *neigh, u8 *ha_buf, | 
|---|
| 197 | u8 **ha); | 
|---|
| 198 | void	(*fill_addr_option)(const struct net_device *dev, | 
|---|
| 199 | struct sk_buff *skb, u8 icmp6_type, | 
|---|
| 200 | const u8 *ha); | 
|---|
| 201 | void	(*prefix_rcv_add_addr)(struct net *net, struct net_device *dev, | 
|---|
| 202 | const struct prefix_info *pinfo, | 
|---|
| 203 | struct inet6_dev *in6_dev, | 
|---|
| 204 | struct in6_addr *addr, | 
|---|
| 205 | int addr_type, u32 addr_flags, | 
|---|
| 206 | bool sllao, bool tokenized, | 
|---|
| 207 | __u32 valid_lft, u32 prefered_lft, | 
|---|
| 208 | bool dev_addr_generated); | 
|---|
| 209 | }; | 
|---|
| 210 |  | 
|---|
| 211 | #if IS_ENABLED(CONFIG_IPV6) | 
|---|
| 212 | static inline int ndisc_ops_parse_options(const struct net_device *dev, | 
|---|
| 213 | struct nd_opt_hdr *nd_opt, | 
|---|
| 214 | struct ndisc_options *ndopts) | 
|---|
| 215 | { | 
|---|
| 216 | if (dev->ndisc_ops && dev->ndisc_ops->parse_options) | 
|---|
| 217 | return dev->ndisc_ops->parse_options(dev, nd_opt, ndopts); | 
|---|
| 218 | else | 
|---|
| 219 | return 0; | 
|---|
| 220 | } | 
|---|
| 221 |  | 
|---|
| 222 | static inline void ndisc_ops_update(const struct net_device *dev, | 
|---|
| 223 | struct neighbour *n, u32 flags, | 
|---|
| 224 | u8 icmp6_type, | 
|---|
| 225 | const struct ndisc_options *ndopts) | 
|---|
| 226 | { | 
|---|
| 227 | if (dev->ndisc_ops && dev->ndisc_ops->update) | 
|---|
| 228 | dev->ndisc_ops->update(dev, n, flags, icmp6_type, ndopts); | 
|---|
| 229 | } | 
|---|
| 230 |  | 
|---|
| 231 | static inline int ndisc_ops_opt_addr_space(const struct net_device *dev, | 
|---|
| 232 | u8 icmp6_type) | 
|---|
| 233 | { | 
|---|
| 234 | if (dev->ndisc_ops && dev->ndisc_ops->opt_addr_space && | 
|---|
| 235 | icmp6_type != NDISC_REDIRECT) | 
|---|
| 236 | return dev->ndisc_ops->opt_addr_space(dev, icmp6_type, NULL, | 
|---|
| 237 | NULL, NULL); | 
|---|
| 238 | else | 
|---|
| 239 | return 0; | 
|---|
| 240 | } | 
|---|
| 241 |  | 
|---|
| 242 | static inline int ndisc_ops_redirect_opt_addr_space(const struct net_device *dev, | 
|---|
| 243 | struct neighbour *neigh, | 
|---|
| 244 | u8 *ha_buf, u8 **ha) | 
|---|
| 245 | { | 
|---|
| 246 | if (dev->ndisc_ops && dev->ndisc_ops->opt_addr_space) | 
|---|
| 247 | return dev->ndisc_ops->opt_addr_space(dev, NDISC_REDIRECT, | 
|---|
| 248 | neigh, ha_buf, ha); | 
|---|
| 249 | else | 
|---|
| 250 | return 0; | 
|---|
| 251 | } | 
|---|
| 252 |  | 
|---|
| 253 | static inline void ndisc_ops_fill_addr_option(const struct net_device *dev, | 
|---|
| 254 | struct sk_buff *skb, | 
|---|
| 255 | u8 icmp6_type) | 
|---|
| 256 | { | 
|---|
| 257 | if (dev->ndisc_ops && dev->ndisc_ops->fill_addr_option && | 
|---|
| 258 | icmp6_type != NDISC_REDIRECT) | 
|---|
| 259 | dev->ndisc_ops->fill_addr_option(dev, skb, icmp6_type, NULL); | 
|---|
| 260 | } | 
|---|
| 261 |  | 
|---|
| 262 | static inline void ndisc_ops_fill_redirect_addr_option(const struct net_device *dev, | 
|---|
| 263 | struct sk_buff *skb, | 
|---|
| 264 | const u8 *ha) | 
|---|
| 265 | { | 
|---|
| 266 | if (dev->ndisc_ops && dev->ndisc_ops->fill_addr_option) | 
|---|
| 267 | dev->ndisc_ops->fill_addr_option(dev, skb, NDISC_REDIRECT, ha); | 
|---|
| 268 | } | 
|---|
| 269 |  | 
|---|
| 270 | static inline void ndisc_ops_prefix_rcv_add_addr(struct net *net, | 
|---|
| 271 | struct net_device *dev, | 
|---|
| 272 | const struct prefix_info *pinfo, | 
|---|
| 273 | struct inet6_dev *in6_dev, | 
|---|
| 274 | struct in6_addr *addr, | 
|---|
| 275 | int addr_type, u32 addr_flags, | 
|---|
| 276 | bool sllao, bool tokenized, | 
|---|
| 277 | __u32 valid_lft, | 
|---|
| 278 | u32 prefered_lft, | 
|---|
| 279 | bool dev_addr_generated) | 
|---|
| 280 | { | 
|---|
| 281 | if (dev->ndisc_ops && dev->ndisc_ops->prefix_rcv_add_addr) | 
|---|
| 282 | dev->ndisc_ops->prefix_rcv_add_addr(net, dev, pinfo, in6_dev, | 
|---|
| 283 | addr, addr_type, | 
|---|
| 284 | addr_flags, sllao, | 
|---|
| 285 | tokenized, valid_lft, | 
|---|
| 286 | prefered_lft, | 
|---|
| 287 | dev_addr_generated); | 
|---|
| 288 | } | 
|---|
| 289 | #endif | 
|---|
| 290 |  | 
|---|
| 291 | /* | 
|---|
| 292 | * Return the padding between the option length and the start of the | 
|---|
| 293 | * link addr.  Currently only IP-over-InfiniBand needs this, although | 
|---|
| 294 | * if RFC 3831 IPv6-over-Fibre Channel is ever implemented it may | 
|---|
| 295 | * also need a pad of 2. | 
|---|
| 296 | */ | 
|---|
| 297 | static inline int ndisc_addr_option_pad(unsigned short type) | 
|---|
| 298 | { | 
|---|
| 299 | switch (type) { | 
|---|
| 300 | case ARPHRD_INFINIBAND: return 2; | 
|---|
| 301 | default:                return 0; | 
|---|
| 302 | } | 
|---|
| 303 | } | 
|---|
| 304 |  | 
|---|
| 305 | static inline int __ndisc_opt_addr_space(unsigned char addr_len, int pad) | 
|---|
| 306 | { | 
|---|
| 307 | return NDISC_OPT_SPACE(addr_len + pad); | 
|---|
| 308 | } | 
|---|
| 309 |  | 
|---|
| 310 | #if IS_ENABLED(CONFIG_IPV6) | 
|---|
| 311 | static inline int ndisc_opt_addr_space(struct net_device *dev, u8 icmp6_type) | 
|---|
| 312 | { | 
|---|
| 313 | return __ndisc_opt_addr_space(addr_len: dev->addr_len, | 
|---|
| 314 | pad: ndisc_addr_option_pad(type: dev->type)) + | 
|---|
| 315 | ndisc_ops_opt_addr_space(dev, icmp6_type); | 
|---|
| 316 | } | 
|---|
| 317 |  | 
|---|
| 318 | static inline int ndisc_redirect_opt_addr_space(struct net_device *dev, | 
|---|
| 319 | struct neighbour *neigh, | 
|---|
| 320 | u8 *ops_data_buf, | 
|---|
| 321 | u8 **ops_data) | 
|---|
| 322 | { | 
|---|
| 323 | return __ndisc_opt_addr_space(addr_len: dev->addr_len, | 
|---|
| 324 | pad: ndisc_addr_option_pad(type: dev->type)) + | 
|---|
| 325 | ndisc_ops_redirect_opt_addr_space(dev, neigh, ha_buf: ops_data_buf, | 
|---|
| 326 | ha: ops_data); | 
|---|
| 327 | } | 
|---|
| 328 | #endif | 
|---|
| 329 |  | 
|---|
| 330 | static inline u8 *__ndisc_opt_addr_data(struct nd_opt_hdr *p, | 
|---|
| 331 | unsigned char addr_len, int prepad) | 
|---|
| 332 | { | 
|---|
| 333 | u8 *lladdr = (u8 *)(p + 1); | 
|---|
| 334 | int lladdrlen = p->nd_opt_len << 3; | 
|---|
| 335 | if (lladdrlen != __ndisc_opt_addr_space(addr_len, pad: prepad)) | 
|---|
| 336 | return NULL; | 
|---|
| 337 | return lladdr + prepad; | 
|---|
| 338 | } | 
|---|
| 339 |  | 
|---|
| 340 | static inline u8 *ndisc_opt_addr_data(struct nd_opt_hdr *p, | 
|---|
| 341 | struct net_device *dev) | 
|---|
| 342 | { | 
|---|
| 343 | return __ndisc_opt_addr_data(p, addr_len: dev->addr_len, | 
|---|
| 344 | prepad: ndisc_addr_option_pad(type: dev->type)); | 
|---|
| 345 | } | 
|---|
| 346 |  | 
|---|
| 347 | static inline u32 ndisc_hashfn(const void *pkey, const struct net_device *dev, __u32 *hash_rnd) | 
|---|
| 348 | { | 
|---|
| 349 | const u32 *p32 = pkey; | 
|---|
| 350 |  | 
|---|
| 351 | return (((p32[0] ^ hash32_ptr(ptr: dev)) * hash_rnd[0]) + | 
|---|
| 352 | (p32[1] * hash_rnd[1]) + | 
|---|
| 353 | (p32[2] * hash_rnd[2]) + | 
|---|
| 354 | (p32[3] * hash_rnd[3])); | 
|---|
| 355 | } | 
|---|
| 356 |  | 
|---|
| 357 | static inline struct neighbour *__ipv6_neigh_lookup_noref(struct net_device *dev, const void *pkey) | 
|---|
| 358 | { | 
|---|
| 359 | return ___neigh_lookup_noref(tbl: &nd_tbl, key_eq: neigh_key_eq128, hash: ndisc_hashfn, pkey, dev); | 
|---|
| 360 | } | 
|---|
| 361 |  | 
|---|
| 362 | static inline | 
|---|
| 363 | struct neighbour *__ipv6_neigh_lookup_noref_stub(struct net_device *dev, | 
|---|
| 364 | const void *pkey) | 
|---|
| 365 | { | 
|---|
| 366 | return ___neigh_lookup_noref(tbl: ipv6_stub->nd_tbl, key_eq: neigh_key_eq128, | 
|---|
| 367 | hash: ndisc_hashfn, pkey, dev); | 
|---|
| 368 | } | 
|---|
| 369 |  | 
|---|
| 370 | static inline struct neighbour *__ipv6_neigh_lookup(struct net_device *dev, const void *pkey) | 
|---|
| 371 | { | 
|---|
| 372 | struct neighbour *n; | 
|---|
| 373 |  | 
|---|
| 374 | rcu_read_lock(); | 
|---|
| 375 | n = __ipv6_neigh_lookup_noref(dev, pkey); | 
|---|
| 376 | if (n && !refcount_inc_not_zero(r: &n->refcnt)) | 
|---|
| 377 | n = NULL; | 
|---|
| 378 | rcu_read_unlock(); | 
|---|
| 379 |  | 
|---|
| 380 | return n; | 
|---|
| 381 | } | 
|---|
| 382 |  | 
|---|
| 383 | static inline void __ipv6_confirm_neigh(struct net_device *dev, | 
|---|
| 384 | const void *pkey) | 
|---|
| 385 | { | 
|---|
| 386 | struct neighbour *n; | 
|---|
| 387 |  | 
|---|
| 388 | rcu_read_lock(); | 
|---|
| 389 | n = __ipv6_neigh_lookup_noref(dev, pkey); | 
|---|
| 390 | neigh_confirm(n); | 
|---|
| 391 | rcu_read_unlock(); | 
|---|
| 392 | } | 
|---|
| 393 |  | 
|---|
| 394 | static inline void __ipv6_confirm_neigh_stub(struct net_device *dev, | 
|---|
| 395 | const void *pkey) | 
|---|
| 396 | { | 
|---|
| 397 | struct neighbour *n; | 
|---|
| 398 |  | 
|---|
| 399 | rcu_read_lock(); | 
|---|
| 400 | n = __ipv6_neigh_lookup_noref_stub(dev, pkey); | 
|---|
| 401 | neigh_confirm(n); | 
|---|
| 402 | rcu_read_unlock(); | 
|---|
| 403 | } | 
|---|
| 404 |  | 
|---|
| 405 | /* uses ipv6_stub and is meant for use outside of IPv6 core */ | 
|---|
| 406 | static inline struct neighbour *ip_neigh_gw6(struct net_device *dev, | 
|---|
| 407 | const void *addr) | 
|---|
| 408 | { | 
|---|
| 409 | struct neighbour *neigh; | 
|---|
| 410 |  | 
|---|
| 411 | neigh = __ipv6_neigh_lookup_noref_stub(dev, pkey: addr); | 
|---|
| 412 | if (unlikely(!neigh)) | 
|---|
| 413 | neigh = __neigh_create(tbl: ipv6_stub->nd_tbl, pkey: addr, dev, want_ref: false); | 
|---|
| 414 |  | 
|---|
| 415 | return neigh; | 
|---|
| 416 | } | 
|---|
| 417 |  | 
|---|
| 418 | int ndisc_init(void); | 
|---|
| 419 | int ndisc_late_init(void); | 
|---|
| 420 |  | 
|---|
| 421 | void ndisc_late_cleanup(void); | 
|---|
| 422 | void ndisc_cleanup(void); | 
|---|
| 423 |  | 
|---|
| 424 | enum skb_drop_reason ndisc_rcv(struct sk_buff *skb); | 
|---|
| 425 |  | 
|---|
| 426 | struct sk_buff *ndisc_ns_create(struct net_device *dev, const struct in6_addr *solicit, | 
|---|
| 427 | const struct in6_addr *saddr, u64 nonce); | 
|---|
| 428 | void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit, | 
|---|
| 429 | const struct in6_addr *daddr, const struct in6_addr *saddr, | 
|---|
| 430 | u64 nonce); | 
|---|
| 431 |  | 
|---|
| 432 | void ndisc_send_skb(struct sk_buff *skb, const struct in6_addr *daddr, | 
|---|
| 433 | const struct in6_addr *saddr); | 
|---|
| 434 |  | 
|---|
| 435 | void ndisc_send_rs(struct net_device *dev, | 
|---|
| 436 | const struct in6_addr *saddr, const struct in6_addr *daddr); | 
|---|
| 437 | void ndisc_send_na(struct net_device *dev, const struct in6_addr *daddr, | 
|---|
| 438 | const struct in6_addr *solicited_addr, | 
|---|
| 439 | bool router, bool solicited, bool override, bool inc_opt); | 
|---|
| 440 |  | 
|---|
| 441 | void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target); | 
|---|
| 442 |  | 
|---|
| 443 | int ndisc_mc_map(const struct in6_addr *addr, char *buf, struct net_device *dev, | 
|---|
| 444 | int dir); | 
|---|
| 445 |  | 
|---|
| 446 | void ndisc_update(const struct net_device *dev, struct neighbour *neigh, | 
|---|
| 447 | const u8 *lladdr, u8 new, u32 flags, u8 icmp6_type, | 
|---|
| 448 | struct ndisc_options *ndopts); | 
|---|
| 449 |  | 
|---|
| 450 | /* | 
|---|
| 451 | *	IGMP | 
|---|
| 452 | */ | 
|---|
| 453 | int igmp6_init(void); | 
|---|
| 454 | int igmp6_late_init(void); | 
|---|
| 455 |  | 
|---|
| 456 | void igmp6_cleanup(void); | 
|---|
| 457 | void igmp6_late_cleanup(void); | 
|---|
| 458 |  | 
|---|
| 459 | void igmp6_event_query(struct sk_buff *skb); | 
|---|
| 460 |  | 
|---|
| 461 | void igmp6_event_report(struct sk_buff *skb); | 
|---|
| 462 |  | 
|---|
| 463 |  | 
|---|
| 464 | #ifdef CONFIG_SYSCTL | 
|---|
| 465 | int ndisc_ifinfo_sysctl_change(const struct ctl_table *ctl, int write, | 
|---|
| 466 | void *buffer, size_t *lenp, loff_t *ppos); | 
|---|
| 467 | #endif | 
|---|
| 468 |  | 
|---|
| 469 | void inet6_ifinfo_notify(int event, struct inet6_dev *idev); | 
|---|
| 470 |  | 
|---|
| 471 | #endif | 
|---|
| 472 |  | 
|---|