144d362409d5469aed47d19e7908d19bd194493aThomas Graf/*
244d362409d5469aed47d19e7908d19bd194493aThomas Graf * lib/route/neigh.c	Neighbours
344d362409d5469aed47d19e7908d19bd194493aThomas Graf *
444d362409d5469aed47d19e7908d19bd194493aThomas Graf *	This library is free software; you can redistribute it and/or
544d362409d5469aed47d19e7908d19bd194493aThomas Graf *	modify it under the terms of the GNU Lesser General Public
644d362409d5469aed47d19e7908d19bd194493aThomas Graf *	License as published by the Free Software Foundation version 2.1
744d362409d5469aed47d19e7908d19bd194493aThomas Graf *	of the License.
844d362409d5469aed47d19e7908d19bd194493aThomas Graf *
98a3efffa5b3fde252675239914118664d36a2c24Thomas Graf * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
1044d362409d5469aed47d19e7908d19bd194493aThomas Graf */
1144d362409d5469aed47d19e7908d19bd194493aThomas Graf
1244d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
1344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @ingroup rtnl
1444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @defgroup neigh Neighbours
1544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @brief
1644d362409d5469aed47d19e7908d19bd194493aThomas Graf *
1744d362409d5469aed47d19e7908d19bd194493aThomas Graf * The neighbour table establishes bindings between protocol addresses and
1844d362409d5469aed47d19e7908d19bd194493aThomas Graf * link layer addresses for hosts sharing the same physical link. This
1944d362409d5469aed47d19e7908d19bd194493aThomas Graf * module allows you to access and manipulate the content of these tables.
2044d362409d5469aed47d19e7908d19bd194493aThomas Graf *
2144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @par Neighbour States
2244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @code
2344d362409d5469aed47d19e7908d19bd194493aThomas Graf * NUD_INCOMPLETE
2444d362409d5469aed47d19e7908d19bd194493aThomas Graf * NUD_REACHABLE
2544d362409d5469aed47d19e7908d19bd194493aThomas Graf * NUD_STALE
2644d362409d5469aed47d19e7908d19bd194493aThomas Graf * NUD_DELAY
2744d362409d5469aed47d19e7908d19bd194493aThomas Graf * NUD_PROBE
2844d362409d5469aed47d19e7908d19bd194493aThomas Graf * NUD_FAILED
2944d362409d5469aed47d19e7908d19bd194493aThomas Graf * NUD_NOARP
3044d362409d5469aed47d19e7908d19bd194493aThomas Graf * NUD_PERMANENT
3144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @endcode
3244d362409d5469aed47d19e7908d19bd194493aThomas Graf *
3344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @par Neighbour Flags
3444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @code
3544d362409d5469aed47d19e7908d19bd194493aThomas Graf * NTF_PROXY
3644d362409d5469aed47d19e7908d19bd194493aThomas Graf * NTF_ROUTER
3744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @endcode
3844d362409d5469aed47d19e7908d19bd194493aThomas Graf *
3944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @par Neighbour Identification
4044d362409d5469aed47d19e7908d19bd194493aThomas Graf * A neighbour is uniquely identified by the attributes listed below, whenever
4144d362409d5469aed47d19e7908d19bd194493aThomas Graf * you refer to an existing neighbour all of the attributes must be set.
4244d362409d5469aed47d19e7908d19bd194493aThomas Graf * Neighbours from caches automatically have all required attributes set.
4344d362409d5469aed47d19e7908d19bd194493aThomas Graf *   - interface index (rtnl_neigh_set_ifindex())
4444d362409d5469aed47d19e7908d19bd194493aThomas Graf *   - destination address (rtnl_neigh_set_dst())
4544d362409d5469aed47d19e7908d19bd194493aThomas Graf *
4644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @par Changeable Attributes
4744d362409d5469aed47d19e7908d19bd194493aThomas Graf * \anchor neigh_changeable
4844d362409d5469aed47d19e7908d19bd194493aThomas Graf *  - state (rtnl_neigh_set_state())
4944d362409d5469aed47d19e7908d19bd194493aThomas Graf *  - link layer address (rtnl_neigh_set_lladdr())
5044d362409d5469aed47d19e7908d19bd194493aThomas Graf *
5144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @par Required Caches for Dumping
5244d362409d5469aed47d19e7908d19bd194493aThomas Graf * In order to dump neighbour attributes you must provide the following
5344d362409d5469aed47d19e7908d19bd194493aThomas Graf * caches via nl_cache_provide()
5444d362409d5469aed47d19e7908d19bd194493aThomas Graf *  - link cache holding all links
5544d362409d5469aed47d19e7908d19bd194493aThomas Graf *
5644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @par TODO
5744d362409d5469aed47d19e7908d19bd194493aThomas Graf *   - Document proxy settings
5844d362409d5469aed47d19e7908d19bd194493aThomas Graf *   - Document states and their influence
5944d362409d5469aed47d19e7908d19bd194493aThomas Graf *
6044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @par 1) Retrieving information about configured neighbours
6144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @code
6244d362409d5469aed47d19e7908d19bd194493aThomas Graf * // The first step is to retrieve a list of all available neighbour within
6344d362409d5469aed47d19e7908d19bd194493aThomas Graf * // the kernel and put them into a cache.
641155370f520cb64657e25153255cf7dc1424317fThomas Graf * struct nl_cache *cache = rtnl_neigh_alloc_cache(sk);
6544d362409d5469aed47d19e7908d19bd194493aThomas Graf *
6644d362409d5469aed47d19e7908d19bd194493aThomas Graf * // Neighbours can then be looked up by the interface and destination
6744d362409d5469aed47d19e7908d19bd194493aThomas Graf * // address:
6844d362409d5469aed47d19e7908d19bd194493aThomas Graf * struct rtnl_neigh *neigh = rtnl_neigh_get(cache, ifindex, dst_addr);
6944d362409d5469aed47d19e7908d19bd194493aThomas Graf *
7044d362409d5469aed47d19e7908d19bd194493aThomas Graf * // After successful usage, the object must be given back to the cache
7144d362409d5469aed47d19e7908d19bd194493aThomas Graf * rtnl_neigh_put(neigh);
7244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @endcode
7344d362409d5469aed47d19e7908d19bd194493aThomas Graf *
7444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @par 2) Adding new neighbours
7544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @code
7644d362409d5469aed47d19e7908d19bd194493aThomas Graf * // Allocate an empty neighbour handle to be filled out with the attributes
7744d362409d5469aed47d19e7908d19bd194493aThomas Graf * // of the new neighbour.
7844d362409d5469aed47d19e7908d19bd194493aThomas Graf * struct rtnl_neigh *neigh = rtnl_neigh_alloc();
7944d362409d5469aed47d19e7908d19bd194493aThomas Graf *
8044d362409d5469aed47d19e7908d19bd194493aThomas Graf * // Fill out the attributes of the new neighbour
8144d362409d5469aed47d19e7908d19bd194493aThomas Graf * rtnl_neigh_set_ifindex(neigh, ifindex);
8244d362409d5469aed47d19e7908d19bd194493aThomas Graf * rtnl_neigh_set_dst(neigh, dst_addr);
8344d362409d5469aed47d19e7908d19bd194493aThomas Graf * rtnl_neigh_set_state(neigh, rtnl_neigh_str2state("permanent"));
8444d362409d5469aed47d19e7908d19bd194493aThomas Graf *
8544d362409d5469aed47d19e7908d19bd194493aThomas Graf * // Build the netlink message and send it to the kernel, the operation will
8644d362409d5469aed47d19e7908d19bd194493aThomas Graf * // block until the operation has been completed. Alternatively the required
8744d362409d5469aed47d19e7908d19bd194493aThomas Graf * // netlink message can be built using rtnl_neigh_build_add_request()
8844d362409d5469aed47d19e7908d19bd194493aThomas Graf * // to be sent out using nl_send_auto_complete().
89531029c130db95a82c9f2121e59698e86cd84e79Thomas Graf * rtnl_neigh_add(sk, neigh, NLM_F_CREATE);
9044d362409d5469aed47d19e7908d19bd194493aThomas Graf *
9144d362409d5469aed47d19e7908d19bd194493aThomas Graf * // Free the memory
9244d362409d5469aed47d19e7908d19bd194493aThomas Graf * rtnl_neigh_put(neigh);
9344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @endcode
9444d362409d5469aed47d19e7908d19bd194493aThomas Graf *
9544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @par 3) Deleting an existing neighbour
9644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @code
9744d362409d5469aed47d19e7908d19bd194493aThomas Graf * // Allocate an empty neighbour object to be filled out with the attributes
9844d362409d5469aed47d19e7908d19bd194493aThomas Graf * // matching the neighbour to be deleted. Alternatively a fully equipped
9944d362409d5469aed47d19e7908d19bd194493aThomas Graf * // neighbour object out of a cache can be used instead.
10044d362409d5469aed47d19e7908d19bd194493aThomas Graf * struct rtnl_neigh *neigh = rtnl_neigh_alloc();
10144d362409d5469aed47d19e7908d19bd194493aThomas Graf *
10244d362409d5469aed47d19e7908d19bd194493aThomas Graf * // Neighbours are uniquely identified by their interface index and
10344d362409d5469aed47d19e7908d19bd194493aThomas Graf * // destination address, you may fill out other attributes but they
10444d362409d5469aed47d19e7908d19bd194493aThomas Graf * // will have no influence.
10544d362409d5469aed47d19e7908d19bd194493aThomas Graf * rtnl_neigh_set_ifindex(neigh, ifindex);
10644d362409d5469aed47d19e7908d19bd194493aThomas Graf * rtnl_neigh_set_dst(neigh, dst_addr);
10744d362409d5469aed47d19e7908d19bd194493aThomas Graf *
10844d362409d5469aed47d19e7908d19bd194493aThomas Graf * // Build the netlink message and send it to the kernel, the operation will
10944d362409d5469aed47d19e7908d19bd194493aThomas Graf * // block until the operation has been completed. Alternatively the required
11044d362409d5469aed47d19e7908d19bd194493aThomas Graf * // netlink message can be built using rtnl_neigh_build_delete_request()
11144d362409d5469aed47d19e7908d19bd194493aThomas Graf * // to be sent out using nl_send_auto_complete().
1121155370f520cb64657e25153255cf7dc1424317fThomas Graf * rtnl_neigh_delete(sk, neigh, 0);
11344d362409d5469aed47d19e7908d19bd194493aThomas Graf *
11444d362409d5469aed47d19e7908d19bd194493aThomas Graf * // Free the memory
11544d362409d5469aed47d19e7908d19bd194493aThomas Graf * rtnl_neigh_put(neigh);
11644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @endcode
11744d362409d5469aed47d19e7908d19bd194493aThomas Graf *
11844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @par 4) Changing neighbour attributes
11944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @code
12044d362409d5469aed47d19e7908d19bd194493aThomas Graf * // Allocate an empty neighbour object to be filled out with the attributes
12144d362409d5469aed47d19e7908d19bd194493aThomas Graf * // matching the neighbour to be changed and the new parameters. Alternatively
12244d362409d5469aed47d19e7908d19bd194493aThomas Graf * // a fully equipped modified neighbour object out of a cache can be used.
12344d362409d5469aed47d19e7908d19bd194493aThomas Graf * struct rtnl_neigh *neigh = rtnl_neigh_alloc();
12444d362409d5469aed47d19e7908d19bd194493aThomas Graf *
12544d362409d5469aed47d19e7908d19bd194493aThomas Graf * // Identify the neighbour to be changed by its interface index and
12644d362409d5469aed47d19e7908d19bd194493aThomas Graf * // destination address
12744d362409d5469aed47d19e7908d19bd194493aThomas Graf * rtnl_neigh_set_ifindex(neigh, ifindex);
12844d362409d5469aed47d19e7908d19bd194493aThomas Graf * rtnl_neigh_set_dst(neigh, dst_addr);
12944d362409d5469aed47d19e7908d19bd194493aThomas Graf *
13044d362409d5469aed47d19e7908d19bd194493aThomas Graf * // The link layer address may be modified, if so it is wise to change
13144d362409d5469aed47d19e7908d19bd194493aThomas Graf * // its state to "permanent" in order to avoid having it overwritten.
13244d362409d5469aed47d19e7908d19bd194493aThomas Graf * rtnl_neigh_set_lladdr(neigh, lladdr);
13344d362409d5469aed47d19e7908d19bd194493aThomas Graf *
13444d362409d5469aed47d19e7908d19bd194493aThomas Graf * // Secondly the state can be modified allowing normal neighbours to be
13544d362409d5469aed47d19e7908d19bd194493aThomas Graf * // converted into permanent entries or to manually confirm a neighbour.
13644d362409d5469aed47d19e7908d19bd194493aThomas Graf * rtnl_neigh_set_state(neigh, state);
13744d362409d5469aed47d19e7908d19bd194493aThomas Graf *
13844d362409d5469aed47d19e7908d19bd194493aThomas Graf * // Build the netlink message and send it to the kernel, the operation will
13944d362409d5469aed47d19e7908d19bd194493aThomas Graf * // block until the operation has been completed. Alternatively the required
14044d362409d5469aed47d19e7908d19bd194493aThomas Graf * // netlink message can be built using rtnl_neigh_build_change_request()
14144d362409d5469aed47d19e7908d19bd194493aThomas Graf * // to be sent out using nl_send_auto_complete().
142531029c130db95a82c9f2121e59698e86cd84e79Thomas Graf * rtnl_neigh_add(sk, neigh, NLM_F_REPLACE);
14344d362409d5469aed47d19e7908d19bd194493aThomas Graf *
14444d362409d5469aed47d19e7908d19bd194493aThomas Graf * // Free the memory
14544d362409d5469aed47d19e7908d19bd194493aThomas Graf * rtnl_neigh_put(neigh);
14644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @endcode
14744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
14844d362409d5469aed47d19e7908d19bd194493aThomas Graf */
14944d362409d5469aed47d19e7908d19bd194493aThomas Graf
15044d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink-local.h>
15144d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/netlink.h>
15244d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/utils.h>
15344d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/route/rtnl.h>
15444d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/route/neighbour.h>
15544d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/route/link.h>
15644d362409d5469aed47d19e7908d19bd194493aThomas Graf
15744d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @cond SKIP */
15844d362409d5469aed47d19e7908d19bd194493aThomas Graf#define NEIGH_ATTR_FLAGS        0x01
15944d362409d5469aed47d19e7908d19bd194493aThomas Graf#define NEIGH_ATTR_STATE        0x02
16044d362409d5469aed47d19e7908d19bd194493aThomas Graf#define NEIGH_ATTR_LLADDR       0x04
16144d362409d5469aed47d19e7908d19bd194493aThomas Graf#define NEIGH_ATTR_DST          0x08
16244d362409d5469aed47d19e7908d19bd194493aThomas Graf#define NEIGH_ATTR_CACHEINFO    0x10
16344d362409d5469aed47d19e7908d19bd194493aThomas Graf#define NEIGH_ATTR_IFINDEX      0x20
16444d362409d5469aed47d19e7908d19bd194493aThomas Graf#define NEIGH_ATTR_FAMILY       0x40
16544d362409d5469aed47d19e7908d19bd194493aThomas Graf#define NEIGH_ATTR_TYPE         0x80
16644d362409d5469aed47d19e7908d19bd194493aThomas Graf#define NEIGH_ATTR_PROBES       0x100
16744d362409d5469aed47d19e7908d19bd194493aThomas Graf
16844d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct nl_cache_ops rtnl_neigh_ops;
16944d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct nl_object_ops neigh_obj_ops;
17044d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @endcond */
17144d362409d5469aed47d19e7908d19bd194493aThomas Graf
17244d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic void neigh_free_data(struct nl_object *c)
17344d362409d5469aed47d19e7908d19bd194493aThomas Graf{
17444d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_neigh *neigh = nl_object_priv(c);
17544d362409d5469aed47d19e7908d19bd194493aThomas Graf
17644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!neigh)
17744d362409d5469aed47d19e7908d19bd194493aThomas Graf		return;
17844d362409d5469aed47d19e7908d19bd194493aThomas Graf
17944d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_addr_put(neigh->n_lladdr);
18044d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_addr_put(neigh->n_dst);
18144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
18244d362409d5469aed47d19e7908d19bd194493aThomas Graf
18344d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int neigh_clone(struct nl_object *_dst, struct nl_object *_src)
18444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
18544d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_neigh *dst = nl_object_priv(_dst);
18644d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_neigh *src = nl_object_priv(_src);
18744d362409d5469aed47d19e7908d19bd194493aThomas Graf
18844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (src->n_lladdr)
18944d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!(dst->n_lladdr = nl_addr_clone(src->n_lladdr)))
1908a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			return -NLE_NOMEM;
19144d362409d5469aed47d19e7908d19bd194493aThomas Graf
19244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (src->n_dst)
19344d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!(dst->n_dst = nl_addr_clone(src->n_dst)))
1948a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			return -NLE_NOMEM;
19544d362409d5469aed47d19e7908d19bd194493aThomas Graf
19644d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
19744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
19844d362409d5469aed47d19e7908d19bd194493aThomas Graf
19944d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int neigh_compare(struct nl_object *_a, struct nl_object *_b,
20044d362409d5469aed47d19e7908d19bd194493aThomas Graf			uint32_t attrs, int flags)
20144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
20244d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_neigh *a = (struct rtnl_neigh *) _a;
20344d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_neigh *b = (struct rtnl_neigh *) _b;
20444d362409d5469aed47d19e7908d19bd194493aThomas Graf	int diff = 0;
20544d362409d5469aed47d19e7908d19bd194493aThomas Graf
20644d362409d5469aed47d19e7908d19bd194493aThomas Graf#define NEIGH_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, NEIGH_ATTR_##ATTR, a, b, EXPR)
20744d362409d5469aed47d19e7908d19bd194493aThomas Graf
20844d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= NEIGH_DIFF(IFINDEX,	a->n_ifindex != b->n_ifindex);
20944d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= NEIGH_DIFF(FAMILY,	a->n_family != b->n_family);
21044d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= NEIGH_DIFF(TYPE,	a->n_type != b->n_type);
21144d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= NEIGH_DIFF(LLADDR,	nl_addr_cmp(a->n_lladdr, b->n_lladdr));
21244d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= NEIGH_DIFF(DST,		nl_addr_cmp(a->n_dst, b->n_dst));
21344d362409d5469aed47d19e7908d19bd194493aThomas Graf
214535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (flags & LOOSE_COMPARISON) {
21544d362409d5469aed47d19e7908d19bd194493aThomas Graf		diff |= NEIGH_DIFF(STATE,
21644d362409d5469aed47d19e7908d19bd194493aThomas Graf				  (a->n_state ^ b->n_state) & b->n_state_mask);
21744d362409d5469aed47d19e7908d19bd194493aThomas Graf		diff |= NEIGH_DIFF(FLAGS,
21844d362409d5469aed47d19e7908d19bd194493aThomas Graf				  (a->n_flags ^ b->n_flags) & b->n_flag_mask);
21944d362409d5469aed47d19e7908d19bd194493aThomas Graf	} else {
22044d362409d5469aed47d19e7908d19bd194493aThomas Graf		diff |= NEIGH_DIFF(STATE, a->n_state != b->n_state);
22144d362409d5469aed47d19e7908d19bd194493aThomas Graf		diff |= NEIGH_DIFF(FLAGS, a->n_flags != b->n_flags);
22244d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
22344d362409d5469aed47d19e7908d19bd194493aThomas Graf
22444d362409d5469aed47d19e7908d19bd194493aThomas Graf#undef NEIGH_DIFF
22544d362409d5469aed47d19e7908d19bd194493aThomas Graf
22644d362409d5469aed47d19e7908d19bd194493aThomas Graf	return diff;
22744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
22844d362409d5469aed47d19e7908d19bd194493aThomas Graf
22944d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct trans_tbl neigh_attrs[] = {
23044d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(NEIGH_ATTR_FLAGS, flags)
23144d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(NEIGH_ATTR_STATE, state)
23244d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(NEIGH_ATTR_LLADDR, lladdr)
23344d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(NEIGH_ATTR_DST, dst)
23444d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(NEIGH_ATTR_CACHEINFO, cacheinfo)
23544d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(NEIGH_ATTR_IFINDEX, ifindex)
23644d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(NEIGH_ATTR_FAMILY, family)
23744d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(NEIGH_ATTR_TYPE, type)
23844d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(NEIGH_ATTR_PROBES, probes)
23944d362409d5469aed47d19e7908d19bd194493aThomas Graf};
24044d362409d5469aed47d19e7908d19bd194493aThomas Graf
24144d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic char *neigh_attrs2str(int attrs, char *buf, size_t len)
24244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
24344d362409d5469aed47d19e7908d19bd194493aThomas Graf	return __flags2str(attrs, buf, len, neigh_attrs,
24444d362409d5469aed47d19e7908d19bd194493aThomas Graf			   ARRAY_SIZE(neigh_attrs));
24544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
24644d362409d5469aed47d19e7908d19bd194493aThomas Graf
24744d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct nla_policy neigh_policy[NDA_MAX+1] = {
24844d362409d5469aed47d19e7908d19bd194493aThomas Graf	[NDA_CACHEINFO]	= { .minlen = sizeof(struct nda_cacheinfo) },
24944d362409d5469aed47d19e7908d19bd194493aThomas Graf	[NDA_PROBES]	= { .type = NLA_U32 },
25044d362409d5469aed47d19e7908d19bd194493aThomas Graf};
25144d362409d5469aed47d19e7908d19bd194493aThomas Graf
25244d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int neigh_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
2533040a1d6254465bed9e44e4d1bf279c2c50cd16aThomas Graf			    struct nlmsghdr *n, struct nl_parser_param *pp)
25444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
25544d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_neigh *neigh;
25644d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nlattr *tb[NDA_MAX + 1];
25744d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct ndmsg *nm;
25844d362409d5469aed47d19e7908d19bd194493aThomas Graf	int err;
25944d362409d5469aed47d19e7908d19bd194493aThomas Graf
26044d362409d5469aed47d19e7908d19bd194493aThomas Graf	neigh = rtnl_neigh_alloc();
26144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!neigh) {
2628a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		err = -NLE_NOMEM;
26344d362409d5469aed47d19e7908d19bd194493aThomas Graf		goto errout;
26444d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
26544d362409d5469aed47d19e7908d19bd194493aThomas Graf
26644d362409d5469aed47d19e7908d19bd194493aThomas Graf	neigh->ce_msgtype = n->nlmsg_type;
26744d362409d5469aed47d19e7908d19bd194493aThomas Graf	nm = nlmsg_data(n);
26844d362409d5469aed47d19e7908d19bd194493aThomas Graf
26944d362409d5469aed47d19e7908d19bd194493aThomas Graf	err = nlmsg_parse(n, sizeof(*nm), tb, NDA_MAX, neigh_policy);
27044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (err < 0)
27144d362409d5469aed47d19e7908d19bd194493aThomas Graf		goto errout;
27244d362409d5469aed47d19e7908d19bd194493aThomas Graf
27344d362409d5469aed47d19e7908d19bd194493aThomas Graf	neigh->n_family  = nm->ndm_family;
27444d362409d5469aed47d19e7908d19bd194493aThomas Graf	neigh->n_ifindex = nm->ndm_ifindex;
27544d362409d5469aed47d19e7908d19bd194493aThomas Graf	neigh->n_state   = nm->ndm_state;
27644d362409d5469aed47d19e7908d19bd194493aThomas Graf	neigh->n_flags   = nm->ndm_flags;
27744d362409d5469aed47d19e7908d19bd194493aThomas Graf	neigh->n_type    = nm->ndm_type;
27844d362409d5469aed47d19e7908d19bd194493aThomas Graf
27944d362409d5469aed47d19e7908d19bd194493aThomas Graf	neigh->ce_mask |= (NEIGH_ATTR_FAMILY | NEIGH_ATTR_IFINDEX |
28044d362409d5469aed47d19e7908d19bd194493aThomas Graf			   NEIGH_ATTR_STATE | NEIGH_ATTR_FLAGS |
28144d362409d5469aed47d19e7908d19bd194493aThomas Graf			   NEIGH_ATTR_TYPE);
28244d362409d5469aed47d19e7908d19bd194493aThomas Graf
28344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[NDA_LLADDR]) {
284eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		neigh->n_lladdr = nl_addr_alloc_attr(tb[NDA_LLADDR], AF_UNSPEC);
285eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		if (!neigh->n_lladdr) {
286eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf			err = -NLE_NOMEM;
28744d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout;
288eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		}
28944d362409d5469aed47d19e7908d19bd194493aThomas Graf		nl_addr_set_family(neigh->n_lladdr,
29044d362409d5469aed47d19e7908d19bd194493aThomas Graf				   nl_addr_guess_family(neigh->n_lladdr));
29144d362409d5469aed47d19e7908d19bd194493aThomas Graf		neigh->ce_mask |= NEIGH_ATTR_LLADDR;
29244d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
29344d362409d5469aed47d19e7908d19bd194493aThomas Graf
29444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[NDA_DST]) {
295eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		neigh->n_dst = nl_addr_alloc_attr(tb[NDA_DST], neigh->n_family);
296eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		if (!neigh->n_dst) {
297eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf			err = -NLE_NOMEM;
29844d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout;
299eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		}
30044d362409d5469aed47d19e7908d19bd194493aThomas Graf		neigh->ce_mask |= NEIGH_ATTR_DST;
30144d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
30244d362409d5469aed47d19e7908d19bd194493aThomas Graf
30344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[NDA_CACHEINFO]) {
30444d362409d5469aed47d19e7908d19bd194493aThomas Graf		struct nda_cacheinfo *ci = nla_data(tb[NDA_CACHEINFO]);
30544d362409d5469aed47d19e7908d19bd194493aThomas Graf
30644d362409d5469aed47d19e7908d19bd194493aThomas Graf		neigh->n_cacheinfo.nci_confirmed = ci->ndm_confirmed;
30744d362409d5469aed47d19e7908d19bd194493aThomas Graf		neigh->n_cacheinfo.nci_used = ci->ndm_used;
30844d362409d5469aed47d19e7908d19bd194493aThomas Graf		neigh->n_cacheinfo.nci_updated = ci->ndm_updated;
30944d362409d5469aed47d19e7908d19bd194493aThomas Graf		neigh->n_cacheinfo.nci_refcnt = ci->ndm_refcnt;
31044d362409d5469aed47d19e7908d19bd194493aThomas Graf
31144d362409d5469aed47d19e7908d19bd194493aThomas Graf		neigh->ce_mask |= NEIGH_ATTR_CACHEINFO;
31244d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
31344d362409d5469aed47d19e7908d19bd194493aThomas Graf
31444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[NDA_PROBES]) {
31544d362409d5469aed47d19e7908d19bd194493aThomas Graf		neigh->n_probes = nla_get_u32(tb[NDA_PROBES]);
31644d362409d5469aed47d19e7908d19bd194493aThomas Graf		neigh->ce_mask |= NEIGH_ATTR_PROBES;
31744d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
31844d362409d5469aed47d19e7908d19bd194493aThomas Graf
31944d362409d5469aed47d19e7908d19bd194493aThomas Graf	err = pp->pp_cb((struct nl_object *) neigh, pp);
32044d362409d5469aed47d19e7908d19bd194493aThomas Graferrout:
32144d362409d5469aed47d19e7908d19bd194493aThomas Graf	rtnl_neigh_put(neigh);
32244d362409d5469aed47d19e7908d19bd194493aThomas Graf	return err;
32344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
32444d362409d5469aed47d19e7908d19bd194493aThomas Graf
3251155370f520cb64657e25153255cf7dc1424317fThomas Grafstatic int neigh_request_update(struct nl_cache *c, struct nl_sock *h)
32644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
32744d362409d5469aed47d19e7908d19bd194493aThomas Graf	return nl_rtgen_request(h, RTM_GETNEIGH, AF_UNSPEC, NLM_F_DUMP);
32844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
32944d362409d5469aed47d19e7908d19bd194493aThomas Graf
33044d362409d5469aed47d19e7908d19bd194493aThomas Graf
331d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Grafstatic void neigh_dump_line(struct nl_object *a, struct nl_dump_params *p)
33244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
33344d362409d5469aed47d19e7908d19bd194493aThomas Graf	char dst[INET6_ADDRSTRLEN+5], lladdr[INET6_ADDRSTRLEN+5];
33444d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_neigh *n = (struct rtnl_neigh *) a;
33544d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_cache *link_cache;
33644d362409d5469aed47d19e7908d19bd194493aThomas Graf	char state[128], flags[64];
33744d362409d5469aed47d19e7908d19bd194493aThomas Graf
33844d362409d5469aed47d19e7908d19bd194493aThomas Graf	link_cache = nl_cache_mngt_require("route/link");
33944d362409d5469aed47d19e7908d19bd194493aThomas Graf
340d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump_line(p, "%s ", nl_addr2str(n->n_dst, dst, sizeof(dst)));
34144d362409d5469aed47d19e7908d19bd194493aThomas Graf
34244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link_cache)
343d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump(p, "dev %s ",
34444d362409d5469aed47d19e7908d19bd194493aThomas Graf			rtnl_link_i2name(link_cache, n->n_ifindex,
34544d362409d5469aed47d19e7908d19bd194493aThomas Graf					 state, sizeof(state)));
34644d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
347d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump(p, "dev %d ", n->n_ifindex);
34844d362409d5469aed47d19e7908d19bd194493aThomas Graf
34944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (n->ce_mask & NEIGH_ATTR_LLADDR)
350d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump(p, "lladdr %s ",
35144d362409d5469aed47d19e7908d19bd194493aThomas Graf			nl_addr2str(n->n_lladdr, lladdr, sizeof(lladdr)));
35244d362409d5469aed47d19e7908d19bd194493aThomas Graf
35344d362409d5469aed47d19e7908d19bd194493aThomas Graf	rtnl_neigh_state2str(n->n_state, state, sizeof(state));
35444d362409d5469aed47d19e7908d19bd194493aThomas Graf	rtnl_neigh_flags2str(n->n_flags, flags, sizeof(flags));
35544d362409d5469aed47d19e7908d19bd194493aThomas Graf
35644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (state[0])
357d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump(p, "<%s", state);
35844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (flags[0])
359d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump(p, "%s%s", state[0] ? "," : "<", flags);
36044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (state[0] || flags[0])
361d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump(p, ">");
362d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump(p, "\n");
36344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
36444d362409d5469aed47d19e7908d19bd194493aThomas Graf
365d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Grafstatic void neigh_dump_details(struct nl_object *a, struct nl_dump_params *p)
36644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
36744d362409d5469aed47d19e7908d19bd194493aThomas Graf	char rtn_type[32];
36844d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_neigh *n = (struct rtnl_neigh *) a;
36944d362409d5469aed47d19e7908d19bd194493aThomas Graf	int hz = nl_get_hz();
37044d362409d5469aed47d19e7908d19bd194493aThomas Graf
371d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	neigh_dump_line(a, p);
37244d362409d5469aed47d19e7908d19bd194493aThomas Graf
373d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump_line(p, "    refcnt %u type %s confirmed %u used "
37444d362409d5469aed47d19e7908d19bd194493aThomas Graf				"%u updated %u\n",
37544d362409d5469aed47d19e7908d19bd194493aThomas Graf		n->n_cacheinfo.nci_refcnt,
37644d362409d5469aed47d19e7908d19bd194493aThomas Graf		nl_rtntype2str(n->n_type, rtn_type, sizeof(rtn_type)),
37744d362409d5469aed47d19e7908d19bd194493aThomas Graf		n->n_cacheinfo.nci_confirmed/hz,
37844d362409d5469aed47d19e7908d19bd194493aThomas Graf		n->n_cacheinfo.nci_used/hz, n->n_cacheinfo.nci_updated/hz);
37944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
38044d362409d5469aed47d19e7908d19bd194493aThomas Graf
381d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Grafstatic void neigh_dump_stats(struct nl_object *a, struct nl_dump_params *p)
38244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
383d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	neigh_dump_details(a, p);
38444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
38544d362409d5469aed47d19e7908d19bd194493aThomas Graf
386d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Grafstatic void neigh_dump_env(struct nl_object *obj, struct nl_dump_params *p)
38744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
38844d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_neigh *neigh = (struct rtnl_neigh *) obj;
38944d362409d5469aed47d19e7908d19bd194493aThomas Graf	char buf[128];
39044d362409d5469aed47d19e7908d19bd194493aThomas Graf
391d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump_line(p, "NEIGH_FAMILY=%s\n",
39244d362409d5469aed47d19e7908d19bd194493aThomas Graf		     nl_af2str(neigh->n_family, buf, sizeof(buf)));
39344d362409d5469aed47d19e7908d19bd194493aThomas Graf
39444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (neigh->ce_mask & NEIGH_ATTR_LLADDR)
395d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump_line(p, "NEIGHT_LLADDR=%s\n",
39644d362409d5469aed47d19e7908d19bd194493aThomas Graf			     nl_addr2str(neigh->n_lladdr, buf, sizeof(buf)));
39744d362409d5469aed47d19e7908d19bd194493aThomas Graf
39844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (neigh->ce_mask & NEIGH_ATTR_DST)
399d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump_line(p, "NEIGH_DST=%s\n",
40044d362409d5469aed47d19e7908d19bd194493aThomas Graf			     nl_addr2str(neigh->n_dst, buf, sizeof(buf)));
40144d362409d5469aed47d19e7908d19bd194493aThomas Graf
40244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (neigh->ce_mask & NEIGH_ATTR_IFINDEX) {
40344d362409d5469aed47d19e7908d19bd194493aThomas Graf		struct nl_cache *link_cache;
40444d362409d5469aed47d19e7908d19bd194493aThomas Graf
405d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump_line(p, "NEIGH_IFINDEX=%u\n", neigh->n_ifindex);
40644d362409d5469aed47d19e7908d19bd194493aThomas Graf
40744d362409d5469aed47d19e7908d19bd194493aThomas Graf		link_cache = nl_cache_mngt_require("route/link");
40844d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (link_cache)
409d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf			nl_dump_line(p, "NEIGH_IFNAME=%s\n",
41044d362409d5469aed47d19e7908d19bd194493aThomas Graf				     rtnl_link_i2name(link_cache,
41144d362409d5469aed47d19e7908d19bd194493aThomas Graf						      neigh->n_ifindex,
41244d362409d5469aed47d19e7908d19bd194493aThomas Graf						      buf, sizeof(buf)));
41344d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
41444d362409d5469aed47d19e7908d19bd194493aThomas Graf
41544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (neigh->ce_mask & NEIGH_ATTR_PROBES)
416d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump_line(p, "NEIGH_PROBES=%u\n", neigh->n_probes);
41744d362409d5469aed47d19e7908d19bd194493aThomas Graf
41844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (neigh->ce_mask & NEIGH_ATTR_TYPE)
419d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump_line(p, "NEIGH_TYPE=%s\n",
42044d362409d5469aed47d19e7908d19bd194493aThomas Graf			     nl_rtntype2str(neigh->n_type, buf, sizeof(buf)));
42144d362409d5469aed47d19e7908d19bd194493aThomas Graf
42244d362409d5469aed47d19e7908d19bd194493aThomas Graf	rtnl_neigh_flags2str(neigh->n_flags, buf, sizeof(buf));
42344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (buf[0])
424d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump_line(p, "NEIGH_FLAGS=%s\n", buf);
42544d362409d5469aed47d19e7908d19bd194493aThomas Graf
42644d362409d5469aed47d19e7908d19bd194493aThomas Graf	rtnl_neigh_state2str(neigh->n_state, buf, sizeof(buf));
42744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (buf[0])
428d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump_line(p, "NEIGH_STATE=%s\n", buf);
42944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
43044d362409d5469aed47d19e7908d19bd194493aThomas Graf
43144d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
43244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Neighbour Object Allocation/Freeage
43344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
43444d362409d5469aed47d19e7908d19bd194493aThomas Graf */
43544d362409d5469aed47d19e7908d19bd194493aThomas Graf
43644d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct rtnl_neigh *rtnl_neigh_alloc(void)
43744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
43844d362409d5469aed47d19e7908d19bd194493aThomas Graf	return (struct rtnl_neigh *) nl_object_alloc(&neigh_obj_ops);
43944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
44044d362409d5469aed47d19e7908d19bd194493aThomas Graf
44144d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_neigh_put(struct rtnl_neigh *neigh)
44244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
44344d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_object_put((struct nl_object *) neigh);
44444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
44544d362409d5469aed47d19e7908d19bd194493aThomas Graf
44644d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
44744d362409d5469aed47d19e7908d19bd194493aThomas Graf
44844d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
44944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Neighbour Cache Managament
45044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
45144d362409d5469aed47d19e7908d19bd194493aThomas Graf */
45244d362409d5469aed47d19e7908d19bd194493aThomas Graf
45344d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
45444d362409d5469aed47d19e7908d19bd194493aThomas Graf * Build a neighbour cache including all neighbours currently configured in the kernel.
4551155370f520cb64657e25153255cf7dc1424317fThomas Graf * @arg sk		Netlink socket.
4568a3efffa5b3fde252675239914118664d36a2c24Thomas Graf * @arg result		Pointer to store resulting cache.
45744d362409d5469aed47d19e7908d19bd194493aThomas Graf *
45844d362409d5469aed47d19e7908d19bd194493aThomas Graf * Allocates a new neighbour cache, initializes it properly and updates it
45944d362409d5469aed47d19e7908d19bd194493aThomas Graf * to include all neighbours currently configured in the kernel.
46044d362409d5469aed47d19e7908d19bd194493aThomas Graf *
4618a3efffa5b3fde252675239914118664d36a2c24Thomas Graf * @return 0 on success or a negative error code.
46244d362409d5469aed47d19e7908d19bd194493aThomas Graf */
4631155370f520cb64657e25153255cf7dc1424317fThomas Grafint rtnl_neigh_alloc_cache(struct nl_sock *sock, struct nl_cache **result)
46444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
4658a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	return nl_cache_alloc_and_fill(&rtnl_neigh_ops, sock, result);
46644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
46744d362409d5469aed47d19e7908d19bd194493aThomas Graf
46844d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
46944d362409d5469aed47d19e7908d19bd194493aThomas Graf * Look up a neighbour by interface index and destination address
47044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg cache		neighbour cache
47144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg ifindex		interface index the neighbour is on
47244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg dst		destination address of the neighbour
47344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return neighbour handle or NULL if no match was found.
47444d362409d5469aed47d19e7908d19bd194493aThomas Graf */
47544d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct rtnl_neigh * rtnl_neigh_get(struct nl_cache *cache, int ifindex,
47644d362409d5469aed47d19e7908d19bd194493aThomas Graf				   struct nl_addr *dst)
47744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
47844d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_neigh *neigh;
47944d362409d5469aed47d19e7908d19bd194493aThomas Graf
48044d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_list_for_each_entry(neigh, &cache->c_items, ce_list) {
48144d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (neigh->n_ifindex == ifindex &&
48244d362409d5469aed47d19e7908d19bd194493aThomas Graf		    !nl_addr_cmp(neigh->n_dst, dst)) {
48344d362409d5469aed47d19e7908d19bd194493aThomas Graf			nl_object_get((struct nl_object *) neigh);
48444d362409d5469aed47d19e7908d19bd194493aThomas Graf			return neigh;
48544d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
48644d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
48744d362409d5469aed47d19e7908d19bd194493aThomas Graf
48844d362409d5469aed47d19e7908d19bd194493aThomas Graf	return NULL;
48944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
49044d362409d5469aed47d19e7908d19bd194493aThomas Graf
49144d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
49244d362409d5469aed47d19e7908d19bd194493aThomas Graf
49344d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
49444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Neighbour Addition
49544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
49644d362409d5469aed47d19e7908d19bd194493aThomas Graf */
49744d362409d5469aed47d19e7908d19bd194493aThomas Graf
4988a3efffa5b3fde252675239914118664d36a2c24Thomas Grafstatic int build_neigh_msg(struct rtnl_neigh *tmpl, int cmd, int flags,
4998a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			   struct nl_msg **result)
50044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
50144d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_msg *msg;
50244d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct ndmsg nhdr = {
50344d362409d5469aed47d19e7908d19bd194493aThomas Graf		.ndm_ifindex = tmpl->n_ifindex,
50444d362409d5469aed47d19e7908d19bd194493aThomas Graf		.ndm_state = NUD_PERMANENT,
50544d362409d5469aed47d19e7908d19bd194493aThomas Graf	};
50644d362409d5469aed47d19e7908d19bd194493aThomas Graf
507531029c130db95a82c9f2121e59698e86cd84e79Thomas Graf	if (!(tmpl->ce_mask & NEIGH_ATTR_DST))
508531029c130db95a82c9f2121e59698e86cd84e79Thomas Graf		return -NLE_MISSING_ATTR;
509531029c130db95a82c9f2121e59698e86cd84e79Thomas Graf
510531029c130db95a82c9f2121e59698e86cd84e79Thomas Graf	nhdr.ndm_family = nl_addr_get_family(tmpl->n_dst);
511531029c130db95a82c9f2121e59698e86cd84e79Thomas Graf
51244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tmpl->ce_mask & NEIGH_ATTR_STATE)
51344d362409d5469aed47d19e7908d19bd194493aThomas Graf		nhdr.ndm_state = tmpl->n_state;
51444d362409d5469aed47d19e7908d19bd194493aThomas Graf
51544d362409d5469aed47d19e7908d19bd194493aThomas Graf	msg = nlmsg_alloc_simple(cmd, flags);
51644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!msg)
5178a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_NOMEM;
51844d362409d5469aed47d19e7908d19bd194493aThomas Graf
51944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (nlmsg_append(msg, &nhdr, sizeof(nhdr), NLMSG_ALIGNTO) < 0)
52044d362409d5469aed47d19e7908d19bd194493aThomas Graf		goto nla_put_failure;
52144d362409d5469aed47d19e7908d19bd194493aThomas Graf
52244d362409d5469aed47d19e7908d19bd194493aThomas Graf	NLA_PUT_ADDR(msg, NDA_DST, tmpl->n_dst);
52344d362409d5469aed47d19e7908d19bd194493aThomas Graf
52444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tmpl->ce_mask & NEIGH_ATTR_LLADDR)
52544d362409d5469aed47d19e7908d19bd194493aThomas Graf		NLA_PUT_ADDR(msg, NDA_LLADDR, tmpl->n_lladdr);
52644d362409d5469aed47d19e7908d19bd194493aThomas Graf
5278a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	*result = msg;
5288a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	return 0;
52944d362409d5469aed47d19e7908d19bd194493aThomas Graf
53044d362409d5469aed47d19e7908d19bd194493aThomas Grafnla_put_failure:
53144d362409d5469aed47d19e7908d19bd194493aThomas Graf	nlmsg_free(msg);
5328a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	return -NLE_MSGSIZE;
53344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
53444d362409d5469aed47d19e7908d19bd194493aThomas Graf
53544d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
53644d362409d5469aed47d19e7908d19bd194493aThomas Graf * Build netlink request message to add a new neighbour
53744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg tmpl		template with data of new neighbour
53844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg flags		additional netlink message flags
5398a3efffa5b3fde252675239914118664d36a2c24Thomas Graf * @arg result		Pointer to store resulting message.
54044d362409d5469aed47d19e7908d19bd194493aThomas Graf *
54144d362409d5469aed47d19e7908d19bd194493aThomas Graf * Builds a new netlink message requesting a addition of a new
54244d362409d5469aed47d19e7908d19bd194493aThomas Graf * neighbour. The netlink message header isn't fully equipped with
54344d362409d5469aed47d19e7908d19bd194493aThomas Graf * all relevant fields and must thus be sent out via nl_send_auto_complete()
54444d362409d5469aed47d19e7908d19bd194493aThomas Graf * or supplemented as needed. \a tmpl must contain the attributes of the new
54544d362409d5469aed47d19e7908d19bd194493aThomas Graf * neighbour set via \c rtnl_neigh_set_* functions.
54644d362409d5469aed47d19e7908d19bd194493aThomas Graf *
54744d362409d5469aed47d19e7908d19bd194493aThomas Graf * The following attributes must be set in the template:
54844d362409d5469aed47d19e7908d19bd194493aThomas Graf *  - Interface index (rtnl_neigh_set_ifindex())
54944d362409d5469aed47d19e7908d19bd194493aThomas Graf *  - State (rtnl_neigh_set_state())
55044d362409d5469aed47d19e7908d19bd194493aThomas Graf *  - Destination address (rtnl_neigh_set_dst())
55144d362409d5469aed47d19e7908d19bd194493aThomas Graf *  - Link layer address (rtnl_neigh_set_lladdr())
55244d362409d5469aed47d19e7908d19bd194493aThomas Graf *
5538a3efffa5b3fde252675239914118664d36a2c24Thomas Graf * @return 0 on success or a negative error code.
55444d362409d5469aed47d19e7908d19bd194493aThomas Graf */
5558a3efffa5b3fde252675239914118664d36a2c24Thomas Grafint rtnl_neigh_build_add_request(struct rtnl_neigh *tmpl, int flags,
5568a3efffa5b3fde252675239914118664d36a2c24Thomas Graf				 struct nl_msg **result)
55744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
558531029c130db95a82c9f2121e59698e86cd84e79Thomas Graf	return build_neigh_msg(tmpl, RTM_NEWNEIGH, flags, result);
55944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
56044d362409d5469aed47d19e7908d19bd194493aThomas Graf
56144d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
56244d362409d5469aed47d19e7908d19bd194493aThomas Graf * Add a new neighbour
5631155370f520cb64657e25153255cf7dc1424317fThomas Graf * @arg sk		Netlink socket.
56444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg tmpl		template with requested changes
56544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg flags		additional netlink message flags
56644d362409d5469aed47d19e7908d19bd194493aThomas Graf *
56744d362409d5469aed47d19e7908d19bd194493aThomas Graf * Builds a netlink message by calling rtnl_neigh_build_add_request(),
56844d362409d5469aed47d19e7908d19bd194493aThomas Graf * sends the request to the kernel and waits for the next ACK to be
56944d362409d5469aed47d19e7908d19bd194493aThomas Graf * received and thus blocks until the request has been fullfilled.
57044d362409d5469aed47d19e7908d19bd194493aThomas Graf *
57144d362409d5469aed47d19e7908d19bd194493aThomas Graf * The following attributes must be set in the template:
57244d362409d5469aed47d19e7908d19bd194493aThomas Graf *  - Interface index (rtnl_neigh_set_ifindex())
57344d362409d5469aed47d19e7908d19bd194493aThomas Graf *  - State (rtnl_neigh_set_state())
57444d362409d5469aed47d19e7908d19bd194493aThomas Graf *  - Destination address (rtnl_neigh_set_dst())
57544d362409d5469aed47d19e7908d19bd194493aThomas Graf *  - Link layer address (rtnl_neigh_set_lladdr())
57644d362409d5469aed47d19e7908d19bd194493aThomas Graf *
57744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return 0 on sucess or a negative error if an error occured.
57844d362409d5469aed47d19e7908d19bd194493aThomas Graf */
5791155370f520cb64657e25153255cf7dc1424317fThomas Grafint rtnl_neigh_add(struct nl_sock *sk, struct rtnl_neigh *tmpl, int flags)
58044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
58144d362409d5469aed47d19e7908d19bd194493aThomas Graf	int err;
58244d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_msg *msg;
58344d362409d5469aed47d19e7908d19bd194493aThomas Graf
5848a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	if ((err = rtnl_neigh_build_add_request(tmpl, flags, &msg)) < 0)
5858a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return err;
58644d362409d5469aed47d19e7908d19bd194493aThomas Graf
587ef50a38fbd8682a5c9efd559e7db68664977f080Thomas Graf	err = nl_send_auto_complete(sk, msg);
588ef50a38fbd8682a5c9efd559e7db68664977f080Thomas Graf	nlmsg_free(msg);
589ef50a38fbd8682a5c9efd559e7db68664977f080Thomas Graf	if (err < 0)
59044d362409d5469aed47d19e7908d19bd194493aThomas Graf		return err;
59144d362409d5469aed47d19e7908d19bd194493aThomas Graf
592cfcfca070355b246028df60da79813f09ed65755Thomas Graf	return wait_for_ack(sk);
59344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
59444d362409d5469aed47d19e7908d19bd194493aThomas Graf
59544d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
59644d362409d5469aed47d19e7908d19bd194493aThomas Graf
59744d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
59844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Neighbour Deletion
59944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
60044d362409d5469aed47d19e7908d19bd194493aThomas Graf */
60144d362409d5469aed47d19e7908d19bd194493aThomas Graf
60244d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
60344d362409d5469aed47d19e7908d19bd194493aThomas Graf * Build a netlink request message to delete a neighbour
60444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg neigh		neighbour to delete
60544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg flags		additional netlink message flags
6068a3efffa5b3fde252675239914118664d36a2c24Thomas Graf * @arg result		Pointer to store resulting message.
60744d362409d5469aed47d19e7908d19bd194493aThomas Graf *
60844d362409d5469aed47d19e7908d19bd194493aThomas Graf * Builds a new netlink message requesting a deletion of a neighbour.
60944d362409d5469aed47d19e7908d19bd194493aThomas Graf * The netlink message header isn't fully equipped with all relevant
61044d362409d5469aed47d19e7908d19bd194493aThomas Graf * fields and must thus be sent out via nl_send_auto_complete()
61144d362409d5469aed47d19e7908d19bd194493aThomas Graf * or supplemented as needed. \a neigh must point to an existing
61244d362409d5469aed47d19e7908d19bd194493aThomas Graf * neighbour.
61344d362409d5469aed47d19e7908d19bd194493aThomas Graf *
6148a3efffa5b3fde252675239914118664d36a2c24Thomas Graf * @return 0 on success or a negative error code.
61544d362409d5469aed47d19e7908d19bd194493aThomas Graf */
6168a3efffa5b3fde252675239914118664d36a2c24Thomas Grafint rtnl_neigh_build_delete_request(struct rtnl_neigh *neigh, int flags,
6178a3efffa5b3fde252675239914118664d36a2c24Thomas Graf				    struct nl_msg **result)
61844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
6198a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	return build_neigh_msg(neigh, RTM_DELNEIGH, flags, result);
62044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
62144d362409d5469aed47d19e7908d19bd194493aThomas Graf
62244d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
62344d362409d5469aed47d19e7908d19bd194493aThomas Graf * Delete a neighbour
6241155370f520cb64657e25153255cf7dc1424317fThomas Graf * @arg sk		Netlink socket.
62544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg neigh		neighbour to delete
62644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg flags		additional netlink message flags
62744d362409d5469aed47d19e7908d19bd194493aThomas Graf *
62844d362409d5469aed47d19e7908d19bd194493aThomas Graf * Builds a netlink message by calling rtnl_neigh_build_delete_request(),
62944d362409d5469aed47d19e7908d19bd194493aThomas Graf * sends the request to the kernel and waits for the next ACK to be
63044d362409d5469aed47d19e7908d19bd194493aThomas Graf * received and thus blocks until the request has been fullfilled.
63144d362409d5469aed47d19e7908d19bd194493aThomas Graf *
63244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return 0 on sucess or a negative error if an error occured.
63344d362409d5469aed47d19e7908d19bd194493aThomas Graf */
6341155370f520cb64657e25153255cf7dc1424317fThomas Grafint rtnl_neigh_delete(struct nl_sock *sk, struct rtnl_neigh *neigh,
63544d362409d5469aed47d19e7908d19bd194493aThomas Graf		      int flags)
63644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
63744d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_msg *msg;
6388a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	int err;
63944d362409d5469aed47d19e7908d19bd194493aThomas Graf
6408a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	if ((err = rtnl_neigh_build_delete_request(neigh, flags, &msg)) < 0)
6418a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return err;
64244d362409d5469aed47d19e7908d19bd194493aThomas Graf
643ef50a38fbd8682a5c9efd559e7db68664977f080Thomas Graf	err = nl_send_auto_complete(sk, msg);
644ef50a38fbd8682a5c9efd559e7db68664977f080Thomas Graf	nlmsg_free(msg);
645ef50a38fbd8682a5c9efd559e7db68664977f080Thomas Graf	if (err < 0)
64644d362409d5469aed47d19e7908d19bd194493aThomas Graf		return err;
64744d362409d5469aed47d19e7908d19bd194493aThomas Graf
648cfcfca070355b246028df60da79813f09ed65755Thomas Graf	return wait_for_ack(sk);
64944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
65044d362409d5469aed47d19e7908d19bd194493aThomas Graf
65144d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
65244d362409d5469aed47d19e7908d19bd194493aThomas Graf
65344d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
65444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Neighbour States Translations
65544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
65644d362409d5469aed47d19e7908d19bd194493aThomas Graf */
65744d362409d5469aed47d19e7908d19bd194493aThomas Graf
65844d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct trans_tbl neigh_states[] = {
65944d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(NUD_INCOMPLETE, incomplete)
66044d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(NUD_REACHABLE, reachable)
66144d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(NUD_STALE, stale)
66244d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(NUD_DELAY, delay)
66344d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(NUD_PROBE, probe)
66444d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(NUD_FAILED, failed)
66544d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(NUD_NOARP, norarp)
66644d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(NUD_PERMANENT, permanent)
66744d362409d5469aed47d19e7908d19bd194493aThomas Graf};
66844d362409d5469aed47d19e7908d19bd194493aThomas Graf
66944d362409d5469aed47d19e7908d19bd194493aThomas Grafchar * rtnl_neigh_state2str(int state, char *buf, size_t len)
67044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
67144d362409d5469aed47d19e7908d19bd194493aThomas Graf	return __flags2str(state, buf, len, neigh_states,
67244d362409d5469aed47d19e7908d19bd194493aThomas Graf	    ARRAY_SIZE(neigh_states));
67344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
67444d362409d5469aed47d19e7908d19bd194493aThomas Graf
67544d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_neigh_str2state(const char *name)
67644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
67744d362409d5469aed47d19e7908d19bd194493aThomas Graf	return __str2type(name, neigh_states, ARRAY_SIZE(neigh_states));
67844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
67944d362409d5469aed47d19e7908d19bd194493aThomas Graf
68044d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
68144d362409d5469aed47d19e7908d19bd194493aThomas Graf
68244d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
68344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Neighbour Flags Translations
68444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
68544d362409d5469aed47d19e7908d19bd194493aThomas Graf */
68644d362409d5469aed47d19e7908d19bd194493aThomas Graf
68744d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct trans_tbl neigh_flags[] = {
68844d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(NTF_PROXY, proxy)
68944d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(NTF_ROUTER, router)
69044d362409d5469aed47d19e7908d19bd194493aThomas Graf};
69144d362409d5469aed47d19e7908d19bd194493aThomas Graf
69244d362409d5469aed47d19e7908d19bd194493aThomas Grafchar * rtnl_neigh_flags2str(int flags, char *buf, size_t len)
69344d362409d5469aed47d19e7908d19bd194493aThomas Graf{
69444d362409d5469aed47d19e7908d19bd194493aThomas Graf	return __flags2str(flags, buf, len, neigh_flags,
69544d362409d5469aed47d19e7908d19bd194493aThomas Graf	    ARRAY_SIZE(neigh_flags));
69644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
69744d362409d5469aed47d19e7908d19bd194493aThomas Graf
69844d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_neigh_str2flag(const char *name)
69944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
70044d362409d5469aed47d19e7908d19bd194493aThomas Graf	return __str2type(name, neigh_flags, ARRAY_SIZE(neigh_flags));
70144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
70244d362409d5469aed47d19e7908d19bd194493aThomas Graf
70344d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
70444d362409d5469aed47d19e7908d19bd194493aThomas Graf
70544d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
70644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Attributes
70744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
70844d362409d5469aed47d19e7908d19bd194493aThomas Graf */
70944d362409d5469aed47d19e7908d19bd194493aThomas Graf
71044d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_neigh_set_state(struct rtnl_neigh *neigh, int state)
71144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
71244d362409d5469aed47d19e7908d19bd194493aThomas Graf	neigh->n_state_mask |= state;
71344d362409d5469aed47d19e7908d19bd194493aThomas Graf	neigh->n_state |= state;
71444d362409d5469aed47d19e7908d19bd194493aThomas Graf	neigh->ce_mask |= NEIGH_ATTR_STATE;
71544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
71644d362409d5469aed47d19e7908d19bd194493aThomas Graf
71744d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_neigh_get_state(struct rtnl_neigh *neigh)
71844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
71944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (neigh->ce_mask & NEIGH_ATTR_STATE)
72044d362409d5469aed47d19e7908d19bd194493aThomas Graf		return neigh->n_state;
72144d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
72244d362409d5469aed47d19e7908d19bd194493aThomas Graf		return -1;
72344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
72444d362409d5469aed47d19e7908d19bd194493aThomas Graf
72544d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_neigh_unset_state(struct rtnl_neigh *neigh, int state)
72644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
72744d362409d5469aed47d19e7908d19bd194493aThomas Graf	neigh->n_state_mask |= state;
72844d362409d5469aed47d19e7908d19bd194493aThomas Graf	neigh->n_state &= ~state;
72944d362409d5469aed47d19e7908d19bd194493aThomas Graf	neigh->ce_mask |= NEIGH_ATTR_STATE;
73044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
73144d362409d5469aed47d19e7908d19bd194493aThomas Graf
73244d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_neigh_set_flags(struct rtnl_neigh *neigh, unsigned int flags)
73344d362409d5469aed47d19e7908d19bd194493aThomas Graf{
73444d362409d5469aed47d19e7908d19bd194493aThomas Graf	neigh->n_flag_mask |= flags;
73544d362409d5469aed47d19e7908d19bd194493aThomas Graf	neigh->n_flags |= flags;
73644d362409d5469aed47d19e7908d19bd194493aThomas Graf	neigh->ce_mask |= NEIGH_ATTR_FLAGS;
73744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
73844d362409d5469aed47d19e7908d19bd194493aThomas Graf
73944d362409d5469aed47d19e7908d19bd194493aThomas Grafunsigned int rtnl_neigh_get_flags(struct rtnl_neigh *neigh)
74044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
74144d362409d5469aed47d19e7908d19bd194493aThomas Graf	return neigh->n_flags;
74244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
74344d362409d5469aed47d19e7908d19bd194493aThomas Graf
74444d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_neigh_unset_flags(struct rtnl_neigh *neigh, unsigned int flags)
74544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
74644d362409d5469aed47d19e7908d19bd194493aThomas Graf	neigh->n_flag_mask |= flags;
74744d362409d5469aed47d19e7908d19bd194493aThomas Graf	neigh->n_flags &= ~flags;
74844d362409d5469aed47d19e7908d19bd194493aThomas Graf	neigh->ce_mask |= NEIGH_ATTR_FLAGS;
74944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
75044d362409d5469aed47d19e7908d19bd194493aThomas Graf
75144d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_neigh_set_ifindex(struct rtnl_neigh *neigh, int ifindex)
75244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
75344d362409d5469aed47d19e7908d19bd194493aThomas Graf	neigh->n_ifindex = ifindex;
75444d362409d5469aed47d19e7908d19bd194493aThomas Graf	neigh->ce_mask |= NEIGH_ATTR_IFINDEX;
75544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
75644d362409d5469aed47d19e7908d19bd194493aThomas Graf
75744d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_neigh_get_ifindex(struct rtnl_neigh *neigh)
75844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
759b4fbe1d34d6f54045b5c6236d86aacd4340ec83dThomas Graf	return neigh->n_ifindex;
76044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
76144d362409d5469aed47d19e7908d19bd194493aThomas Graf
76244d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline int __assign_addr(struct rtnl_neigh *neigh, struct nl_addr **pos,
76344d362409d5469aed47d19e7908d19bd194493aThomas Graf			        struct nl_addr *new, int flag, int nocheck)
76444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
76544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!nocheck) {
76644d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (neigh->ce_mask & NEIGH_ATTR_FAMILY) {
76744d362409d5469aed47d19e7908d19bd194493aThomas Graf			if (new->a_family != neigh->n_family)
7688a3efffa5b3fde252675239914118664d36a2c24Thomas Graf				return -NLE_AF_MISMATCH;
76944d362409d5469aed47d19e7908d19bd194493aThomas Graf		} else {
77044d362409d5469aed47d19e7908d19bd194493aThomas Graf			neigh->n_family = new->a_family;
77144d362409d5469aed47d19e7908d19bd194493aThomas Graf			neigh->ce_mask |= NEIGH_ATTR_FAMILY;
77244d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
77344d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
77444d362409d5469aed47d19e7908d19bd194493aThomas Graf
77544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (*pos)
77644d362409d5469aed47d19e7908d19bd194493aThomas Graf		nl_addr_put(*pos);
77744d362409d5469aed47d19e7908d19bd194493aThomas Graf
77844d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_addr_get(new);
77944d362409d5469aed47d19e7908d19bd194493aThomas Graf	*pos = new;
78044d362409d5469aed47d19e7908d19bd194493aThomas Graf
78144d362409d5469aed47d19e7908d19bd194493aThomas Graf	neigh->ce_mask |= flag;
78244d362409d5469aed47d19e7908d19bd194493aThomas Graf
78344d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
78444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
78544d362409d5469aed47d19e7908d19bd194493aThomas Graf
78644d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_neigh_set_lladdr(struct rtnl_neigh *neigh, struct nl_addr *addr)
78744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
78844d362409d5469aed47d19e7908d19bd194493aThomas Graf	__assign_addr(neigh, &neigh->n_lladdr, addr, NEIGH_ATTR_LLADDR, 1);
78944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
79044d362409d5469aed47d19e7908d19bd194493aThomas Graf
79144d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct nl_addr *rtnl_neigh_get_lladdr(struct rtnl_neigh *neigh)
79244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
79344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (neigh->ce_mask & NEIGH_ATTR_LLADDR)
79444d362409d5469aed47d19e7908d19bd194493aThomas Graf		return neigh->n_lladdr;
79544d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
79644d362409d5469aed47d19e7908d19bd194493aThomas Graf		return NULL;
79744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
79844d362409d5469aed47d19e7908d19bd194493aThomas Graf
79944d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_neigh_set_dst(struct rtnl_neigh *neigh, struct nl_addr *addr)
80044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
80144d362409d5469aed47d19e7908d19bd194493aThomas Graf	return __assign_addr(neigh, &neigh->n_dst, addr,
80244d362409d5469aed47d19e7908d19bd194493aThomas Graf			     NEIGH_ATTR_DST, 0);
80344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
80444d362409d5469aed47d19e7908d19bd194493aThomas Graf
80544d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct nl_addr *rtnl_neigh_get_dst(struct rtnl_neigh *neigh)
80644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
80744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (neigh->ce_mask & NEIGH_ATTR_DST)
80844d362409d5469aed47d19e7908d19bd194493aThomas Graf		return neigh->n_dst;
80944d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
81044d362409d5469aed47d19e7908d19bd194493aThomas Graf		return NULL;
81144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
81244d362409d5469aed47d19e7908d19bd194493aThomas Graf
81344d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_neigh_set_family(struct rtnl_neigh *neigh, int family)
81444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
81544d362409d5469aed47d19e7908d19bd194493aThomas Graf	neigh->n_family = family;
81644d362409d5469aed47d19e7908d19bd194493aThomas Graf	neigh->ce_mask |= NEIGH_ATTR_FAMILY;
81744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
81844d362409d5469aed47d19e7908d19bd194493aThomas Graf
8195d82806b48959e4726ae3913ae0b3ce279c4c04aThomas Grafint rtnl_neigh_get_family(struct rtnl_neigh *neigh)
8205d82806b48959e4726ae3913ae0b3ce279c4c04aThomas Graf{
8215d82806b48959e4726ae3913ae0b3ce279c4c04aThomas Graf	return neigh->n_family;
8225d82806b48959e4726ae3913ae0b3ce279c4c04aThomas Graf}
8235d82806b48959e4726ae3913ae0b3ce279c4c04aThomas Graf
82444d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_neigh_set_type(struct rtnl_neigh *neigh, int type)
82544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
82644d362409d5469aed47d19e7908d19bd194493aThomas Graf	neigh->n_type = type;
82744d362409d5469aed47d19e7908d19bd194493aThomas Graf	neigh->ce_mask = NEIGH_ATTR_TYPE;
82844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
82944d362409d5469aed47d19e7908d19bd194493aThomas Graf
83044d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_neigh_get_type(struct rtnl_neigh *neigh)
83144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
83244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (neigh->ce_mask & NEIGH_ATTR_TYPE)
83344d362409d5469aed47d19e7908d19bd194493aThomas Graf		return neigh->n_type;
83444d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
83544d362409d5469aed47d19e7908d19bd194493aThomas Graf		return -1;
83644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
83744d362409d5469aed47d19e7908d19bd194493aThomas Graf
83844d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
83944d362409d5469aed47d19e7908d19bd194493aThomas Graf
84044d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct nl_object_ops neigh_obj_ops = {
84144d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_name		= "route/neigh",
84244d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_size		= sizeof(struct rtnl_neigh),
84344d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_free_data		= neigh_free_data,
84444d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_clone		= neigh_clone,
845d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	.oo_dump = {
846d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	    [NL_DUMP_LINE]	= neigh_dump_line,
847d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	    [NL_DUMP_DETAILS]	= neigh_dump_details,
848d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	    [NL_DUMP_STATS]	= neigh_dump_stats,
849d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	    [NL_DUMP_ENV]	= neigh_dump_env,
850d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	},
85144d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_compare		= neigh_compare,
85244d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_attrs2str		= neigh_attrs2str,
85382907257184f647353a9a993caaa1ebadaee2842Patrick McHardy	.oo_id_attrs		= (NEIGH_ATTR_IFINDEX | NEIGH_ATTR_DST | NEIGH_ATTR_FAMILY),
85444d362409d5469aed47d19e7908d19bd194493aThomas Graf};
85544d362409d5469aed47d19e7908d19bd194493aThomas Graf
85644d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct nl_af_group neigh_groups[] = {
85744d362409d5469aed47d19e7908d19bd194493aThomas Graf	{ AF_UNSPEC, RTNLGRP_NEIGH },
85844d362409d5469aed47d19e7908d19bd194493aThomas Graf	{ END_OF_GROUP_LIST },
85944d362409d5469aed47d19e7908d19bd194493aThomas Graf};
86044d362409d5469aed47d19e7908d19bd194493aThomas Graf
86144d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct nl_cache_ops rtnl_neigh_ops = {
86244d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_name		= "route/neigh",
86344d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_hdrsize		= sizeof(struct ndmsg),
86444d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_msgtypes		= {
86544d362409d5469aed47d19e7908d19bd194493aThomas Graf					{ RTM_NEWNEIGH, NL_ACT_NEW, "new" },
86644d362409d5469aed47d19e7908d19bd194493aThomas Graf					{ RTM_DELNEIGH, NL_ACT_DEL, "del" },
86744d362409d5469aed47d19e7908d19bd194493aThomas Graf					{ RTM_GETNEIGH, NL_ACT_GET, "get" },
86844d362409d5469aed47d19e7908d19bd194493aThomas Graf					END_OF_MSGTYPES_LIST,
86944d362409d5469aed47d19e7908d19bd194493aThomas Graf				  },
87044d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_protocol		= NETLINK_ROUTE,
87144d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_groups		= neigh_groups,
87244d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_request_update	= neigh_request_update,
87344d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_msg_parser		= neigh_msg_parser,
87444d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_obj_ops		= &neigh_obj_ops,
87544d362409d5469aed47d19e7908d19bd194493aThomas Graf};
87644d362409d5469aed47d19e7908d19bd194493aThomas Graf
87744d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic void __init neigh_init(void)
87844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
87944d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_cache_mngt_register(&rtnl_neigh_ops);
88044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
88144d362409d5469aed47d19e7908d19bd194493aThomas Graf
88244d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic void __exit neigh_exit(void)
88344d362409d5469aed47d19e7908d19bd194493aThomas Graf{
88444d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_cache_mngt_unregister(&rtnl_neigh_ops);
88544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
88644d362409d5469aed47d19e7908d19bd194493aThomas Graf
88744d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
888