X-Git-Url: http://git.onelab.eu/?p=libnl.git;a=blobdiff_plain;f=lib%2Froute%2Fneigh.c;fp=lib%2Froute%2Fneigh.c;h=0000000000000000000000000000000000000000;hp=e8e0e40cfc88144a68a2cd8ff3f13559314fb50c;hb=332c8b7561dcac7ac95cc0d07328b1cb22d780a6;hpb=eabdd897b75ecc1fac5e255229a899126085e57a diff --git a/lib/route/neigh.c b/lib/route/neigh.c deleted file mode 100644 index e8e0e40..0000000 --- a/lib/route/neigh.c +++ /dev/null @@ -1,1115 +0,0 @@ -/* - * lib/route/neigh.c Neighbours - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * Copyright (c) 2003-2006 Thomas Graf - */ - -/** - * @ingroup rtnl - * @defgroup neigh Neighbours - * @brief - * - * The neighbour table establishes bindings between protocol addresses and - * link layer addresses for hosts sharing the same physical link. This - * module allows you to access and manipulate the content of these tables. - * - * @par Neighbour States - * @code - * NUD_INCOMPLETE - * NUD_REACHABLE - * NUD_STALE - * NUD_DELAY - * NUD_PROBE - * NUD_FAILED - * NUD_NOARP - * NUD_PERMANENT - * @endcode - * - * @par Neighbour Flags - * @code - * NTF_PROXY - * NTF_ROUTER - * @endcode - * - * @par Neighbour Identification - * A neighbour is uniquely identified by the attributes listed below, whenever - * you refer to an existing neighbour all of the attributes must be set. - * Neighbours from caches automatically have all required attributes set. - * - interface index (rtnl_neigh_set_ifindex()) - * - destination address (rtnl_neigh_set_dst()) - * - * @par Changeable Attributes - * \anchor neigh_changeable - * - state (rtnl_neigh_set_state()) - * - link layer address (rtnl_neigh_set_lladdr()) - * - * @par Required Caches for Dumping - * In order to dump neighbour attributes you must provide the following - * caches via nl_cache_provide() - * - link cache holding all links - * - * @par TODO - * - Document proxy settings - * - Document states and their influence - * - * @par 1) Retrieving information about configured neighbours - * @code - * // The first step is to retrieve a list of all available neighbour within - * // the kernel and put them into a cache. - * struct nl_cache *cache = rtnl_neigh_alloc_cache(handle); - * - * // Neighbours can then be looked up by the interface and destination - * // address: - * struct rtnl_neigh *neigh = rtnl_neigh_get(cache, ifindex, dst_addr); - * - * // After successful usage, the object must be given back to the cache - * rtnl_neigh_put(neigh); - * @endcode - * - * @par 2) Adding new neighbours - * @code - * // Allocate an empty neighbour handle to be filled out with the attributes - * // of the new neighbour. - * struct rtnl_neigh *neigh = rtnl_neigh_alloc(); - * - * // Fill out the attributes of the new neighbour - * rtnl_neigh_set_ifindex(neigh, ifindex); - * rtnl_neigh_set_dst(neigh, dst_addr); - * rtnl_neigh_set_state(neigh, rtnl_neigh_str2state("permanent")); - * - * // Build the netlink message and send it to the kernel, the operation will - * // block until the operation has been completed. Alternatively the required - * // netlink message can be built using rtnl_neigh_build_add_request() - * // to be sent out using nl_send_auto_complete(). - * rtnl_neigh_add(nl_handle, neigh, NLM_F_REPLACE); - * - * // Free the memory - * rtnl_neigh_put(neigh); - * @endcode - * - * @par 3) Deleting an existing neighbour - * @code - * // Allocate an empty neighbour object to be filled out with the attributes - * // matching the neighbour to be deleted. Alternatively a fully equipped - * // neighbour object out of a cache can be used instead. - * struct rtnl_neigh *neigh = rtnl_neigh_alloc(); - * - * // Neighbours are uniquely identified by their interface index and - * // destination address, you may fill out other attributes but they - * // will have no influence. - * rtnl_neigh_set_ifindex(neigh, ifindex); - * rtnl_neigh_set_dst(neigh, dst_addr); - * - * // Build the netlink message and send it to the kernel, the operation will - * // block until the operation has been completed. Alternatively the required - * // netlink message can be built using rtnl_neigh_build_delete_request() - * // to be sent out using nl_send_auto_complete(). - * rtnl_neigh_delete(handle, neigh, 0); - * - * // Free the memory - * rtnl_neigh_put(neigh); - * @endcode - * - * @par 4) Changing neighbour attributes - * @code - * // Allocate an empty neighbour object to be filled out with the attributes - * // matching the neighbour to be changed and the new parameters. Alternatively - * // a fully equipped modified neighbour object out of a cache can be used. - * struct rtnl_neigh *neigh = rtnl_neigh_alloc(); - * - * // Identify the neighbour to be changed by its interface index and - * // destination address - * rtnl_neigh_set_ifindex(neigh, ifindex); - * rtnl_neigh_set_dst(neigh, dst_addr); - * - * // The link layer address may be modified, if so it is wise to change - * // its state to "permanent" in order to avoid having it overwritten. - * rtnl_neigh_set_lladdr(neigh, lladdr); - * - * // Secondly the state can be modified allowing normal neighbours to be - * // converted into permanent entries or to manually confirm a neighbour. - * rtnl_neigh_set_state(neigh, state); - * - * // Build the netlink message and send it to the kernel, the operation will - * // block until the operation has been completed. Alternatively the required - * // netlink message can be built using rtnl_neigh_build_change_request() - * // to be sent out using nl_send_auto_complete(). - * rtnl_neigh_change(handle, neigh, 0); - * - * // Free the memory - * rtnl_neigh_put(neigh); - * @endcode - * @{ - */ - -#include -#include -#include -#include -#include -#include - -/** @cond SKIP */ -#define NEIGH_ATTR_FLAGS 0x01 -#define NEIGH_ATTR_STATE 0x02 -#define NEIGH_ATTR_LLADDR 0x04 -#define NEIGH_ATTR_DST 0x08 -#define NEIGH_ATTR_CACHEINFO 0x10 -#define NEIGH_ATTR_IFINDEX 0x20 -#define NEIGH_ATTR_FAMILY 0x40 -#define NEIGH_ATTR_TYPE 0x80 -#define NEIGH_ATTR_PROBES 0x100 - -static struct nl_cache_ops rtnl_neigh_ops; -/** @endcond */ - -static void neigh_free_data(struct nl_object *c) -{ - struct rtnl_neigh *neigh = nl_object_priv(c); - - if (!neigh) - return; - - nl_addr_put(neigh->n_lladdr); - nl_addr_put(neigh->n_dst); -} - -static int neigh_filter(struct nl_object *obj, struct nl_object *filter) -{ - struct rtnl_neigh *o = (struct rtnl_neigh *) obj; - struct rtnl_neigh *f = (struct rtnl_neigh *) filter; - -#define REQ(F) (f->n_mask & NEIGH_ATTR_##F) -#define AVAIL(F) (o->n_mask & NEIGH_ATTR_##F) -#define _O(F, EXPR) (REQ(F) && (!AVAIL(F) || (EXPR))) -#define _C(F, N) (REQ(F) && (!AVAIL(F) || (o->N != f->N))) - if (_C(IFINDEX, n_ifindex) || - _C(FAMILY, n_family) || - _C(TYPE, n_type) || - _O(LLADDR, nl_addr_cmp(o->n_lladdr, f->n_lladdr)) || - _O(DST, nl_addr_cmp(o->n_dst, f->n_dst)) || - _O(STATE, f->n_state ^ (o->n_state & f->n_state_mask)) || - _O(FLAGS, f->n_flags ^ (o->n_flags & f->n_flag_mask))) - return 0; -#undef REQ -#undef AVAIL -#undef _O -#undef _C - - return 1; -} - -static struct nla_policy neigh_policy[NDA_MAX+1] = { - [NDA_CACHEINFO] = { .minlen = sizeof(struct nda_cacheinfo) }, - [NDA_PROBES] = { .type = NLA_U32 }, -}; - -static int neigh_msg_parser(struct sockaddr_nl *who, struct nlmsghdr *n, - void *arg) -{ - struct rtnl_neigh *neigh; - struct nlattr *tb[NDA_MAX + 1]; - struct nl_parser_param *pp = arg; - struct ndmsg *nm; - int err; - - neigh = rtnl_neigh_alloc(); - if (!neigh) { - err = nl_errno(ENOMEM); - goto errout; - } - - neigh->ce_msgtype = n->nlmsg_type; - nm = nlmsg_data(n); - - err = nlmsg_parse(n, sizeof(*nm), tb, NDA_MAX, neigh_policy); - if (err < 0) - goto errout; - - neigh->n_family = nm->ndm_family; - neigh->n_ifindex = nm->ndm_ifindex; - neigh->n_state = nm->ndm_state; - neigh->n_flags = nm->ndm_flags; - neigh->n_type = nm->ndm_type; - - neigh->n_mask |= (NEIGH_ATTR_FAMILY | NEIGH_ATTR_IFINDEX | - NEIGH_ATTR_STATE | NEIGH_ATTR_FLAGS | - NEIGH_ATTR_TYPE); - - if (tb[NDA_LLADDR]) { - neigh->n_lladdr = nla_get_addr(tb[NDA_LLADDR], AF_UNSPEC); - if (!neigh->n_lladdr) - goto errout; - nl_addr_set_family(neigh->n_lladdr, - nl_addr_guess_family(neigh->n_lladdr)); - neigh->n_mask |= NEIGH_ATTR_LLADDR; - } - - if (tb[NDA_DST]) { - neigh->n_dst = nla_get_addr(tb[NDA_DST], neigh->n_family); - if (!neigh->n_dst) - goto errout; - neigh->n_mask |= NEIGH_ATTR_DST; - } - - if (tb[NDA_CACHEINFO]) { - struct nda_cacheinfo *ci = nla_data(tb[NDA_CACHEINFO]); - - neigh->n_cacheinfo.nci_confirmed = ci->ndm_confirmed; - neigh->n_cacheinfo.nci_used = ci->ndm_used; - neigh->n_cacheinfo.nci_updated = ci->ndm_updated; - neigh->n_cacheinfo.nci_refcnt = ci->ndm_refcnt; - - neigh->n_mask |= NEIGH_ATTR_CACHEINFO; - } - - if (tb[NDA_PROBES]) { - neigh->n_probes = nla_get_u32(tb[NDA_PROBES]); - neigh->n_mask |= NEIGH_ATTR_PROBES; - } - - err = pp->pp_cb((struct nl_object *) neigh, pp); - if (err < 0) - goto errout; - - return P_ACCEPT; - -errout: - rtnl_neigh_put(neigh); - return err; -} - -static int neigh_request_update(struct nl_cache *c, struct nl_handle *h) -{ - return nl_rtgen_request(h, RTM_GETNEIGH, AF_UNSPEC, NLM_F_DUMP); -} - - -static int neigh_dump_brief(struct nl_object *a, struct nl_dump_params *p) -{ - char dst[INET6_ADDRSTRLEN+5], lladdr[INET6_ADDRSTRLEN+5]; - struct rtnl_neigh *n = (struct rtnl_neigh *) a; - struct nl_cache *link_cache; - char state[128], flags[64]; - - link_cache = nl_cache_mngt_require("route/link"); - - dp_dump(p, "%s ", nl_addr2str(n->n_dst, dst, sizeof(dst))); - - if (link_cache) - dp_dump(p, "dev %s ", - rtnl_link_i2name(link_cache, n->n_ifindex, - state, sizeof(state))); - else - dp_dump(p, "dev %d ", n->n_ifindex); - - if (n->n_mask & NEIGH_ATTR_LLADDR) - dp_dump(p, "lladdr %s ", - nl_addr2str(n->n_lladdr, lladdr, sizeof(lladdr))); - - rtnl_neigh_state2str(n->n_state, state, sizeof(state)); - rtnl_neigh_flags2str(n->n_flags, flags, sizeof(flags)); - - if (state[0]) - dp_dump(p, "<%s", state); - if (flags[0]) - dp_dump(p, "%s%s", state[0] ? "," : "<", flags); - if (state[0] || flags[0]) - dp_dump(p, ">"); - dp_dump(p, "\n"); - - return 1; -} - -static int neigh_dump_full(struct nl_object *a, struct nl_dump_params *p) -{ - char rtn_type[32]; - struct rtnl_neigh *n = (struct rtnl_neigh *) a; - int hz = nl_get_hz(); - - int line = neigh_dump_brief(a, p); - - dp_dump_line(p, line++, " refcnt %u type %s confirmed %u used " - "%u updated %u\n", - n->n_cacheinfo.nci_refcnt, - nl_rtntype2str(n->n_type, rtn_type, sizeof(rtn_type)), - n->n_cacheinfo.nci_confirmed/hz, - n->n_cacheinfo.nci_used/hz, n->n_cacheinfo.nci_updated/hz); - - return line; -} - -static int neigh_dump_stats(struct nl_object *a, struct nl_dump_params *p) -{ - return neigh_dump_full(a, p); -} - -static int neigh_dump_xml(struct nl_object *obj, struct nl_dump_params *p) -{ - struct rtnl_neigh *neigh = (struct rtnl_neigh *) obj; - char buf[128]; - int line = 0; - - dp_dump_line(p, line++, "\n"); - dp_dump_line(p, line++, " %s\n", - nl_af2str(neigh->n_family, buf, sizeof(buf))); - - if (neigh->n_mask & NEIGH_ATTR_LLADDR) - dp_dump_line(p, line++, " %s\n", - nl_addr2str(neigh->n_lladdr, buf, sizeof(buf))); - - if (neigh->n_mask & NEIGH_ATTR_DST) - dp_dump_line(p, line++, " %s\n", - nl_addr2str(neigh->n_dst, buf, sizeof(buf))); - - if (neigh->n_mask & NEIGH_ATTR_IFINDEX) { - struct nl_cache *link_cache; - - link_cache = nl_cache_mngt_require("route/link"); - - if (link_cache) - dp_dump_line(p, line++, " %s\n", - rtnl_link_i2name(link_cache, - neigh->n_ifindex, - buf, sizeof(buf))); - else - dp_dump_line(p, line++, " %u\n", - neigh->n_ifindex); - } - - if (neigh->n_mask & NEIGH_ATTR_PROBES) - dp_dump_line(p, line++, " %u\n", - neigh->n_probes); - - if (neigh->n_mask & NEIGH_ATTR_TYPE) - dp_dump_line(p, line++, " %s\n", - nl_rtntype2str(neigh->n_type, buf, sizeof(buf))); - - rtnl_neigh_flags2str(neigh->n_flags, buf, sizeof(buf)); - if (buf[0]) - dp_dump_line(p, line++, " %s\n", buf); - - rtnl_neigh_state2str(neigh->n_state, buf, sizeof(buf)); - if (buf[0]) - dp_dump_line(p, line++, " %s\n", buf); - - dp_dump_line(p, line++, "\n"); - -#if 0 - struct rtnl_ncacheinfo n_cacheinfo; -#endif - - return line; -} - -static int neigh_dump_env(struct nl_object *obj, struct nl_dump_params *p) -{ - struct rtnl_neigh *neigh = (struct rtnl_neigh *) obj; - char buf[128]; - int line = 0; - - dp_dump_line(p, line++, "NEIGH_FAMILY=%s\n", - nl_af2str(neigh->n_family, buf, sizeof(buf))); - - if (neigh->n_mask & NEIGH_ATTR_LLADDR) - dp_dump_line(p, line++, "NEIGHT_LLADDR=%s\n", - nl_addr2str(neigh->n_lladdr, buf, sizeof(buf))); - - if (neigh->n_mask & NEIGH_ATTR_DST) - dp_dump_line(p, line++, "NEIGH_DST=%s\n", - nl_addr2str(neigh->n_dst, buf, sizeof(buf))); - - if (neigh->n_mask & NEIGH_ATTR_IFINDEX) { - struct nl_cache *link_cache; - - dp_dump_line(p, line++, "NEIGH_IFINDEX=%u\n", - neigh->n_ifindex); - - link_cache = nl_cache_mngt_require("route/link"); - if (link_cache) - dp_dump_line(p, line++, "NEIGH_IFNAME=%s\n", - rtnl_link_i2name(link_cache, - neigh->n_ifindex, - buf, sizeof(buf))); - } - - if (neigh->n_mask & NEIGH_ATTR_PROBES) - dp_dump_line(p, line++, "NEIGH_PROBES=%u\n", - neigh->n_probes); - - if (neigh->n_mask & NEIGH_ATTR_TYPE) - dp_dump_line(p, line++, "NEIGH_TYPE=%s\n", - nl_rtntype2str(neigh->n_type, buf, sizeof(buf))); - - rtnl_neigh_flags2str(neigh->n_flags, buf, sizeof(buf)); - if (buf[0]) - dp_dump_line(p, line++, "NEIGH_FLAGS=%s\n", buf); - - rtnl_neigh_state2str(neigh->n_state, buf, sizeof(buf)); - if (buf[0]) - dp_dump_line(p, line++, "NEIGH_STATE=%s\n", buf); - - return line; -} - -/** - * @name Neighbour Object Allocation/Freeage - * @{ - */ - -/** - * Allocate a new neighbour object - * @return New neighbour object - */ -struct rtnl_neigh *rtnl_neigh_alloc(void) -{ - return (struct rtnl_neigh *) nl_object_alloc_from_ops(&rtnl_neigh_ops); -} - -/** - * Give back reference on neighbour object. - * @arg neigh Neighbour object to be given back. - * - * Decrements the reference counter and frees the object if the - * last reference has been released. - */ -void rtnl_neigh_put(struct rtnl_neigh *neigh) -{ - nl_object_put((struct nl_object *) neigh); -} -/** - * Free neighbour object. - * @arg neigh Neighbour object to be freed. - * - * @note Always use rtnl_neigh_put() unless you're absolutely sure - * that no other user may have a reference on this object. - */ -void rtnl_neigh_free(struct rtnl_neigh *neigh) -{ - nl_object_free((struct nl_object *) neigh); -} - -/** @} */ - -/** - * @name Neighbour Cache Managament - * @{ - */ - -/** - * Build a neighbour cache including all neighbours currently configured in the kernel. - * @arg handle netlink handle - * - * Allocates a new neighbour cache, initializes it properly and updates it - * to include all neighbours currently configured in the kernel. - * - * @note The caller is responsible for destroying and freeing the - * cache after using it. - * @return The new cache or NULL if an error occured. - */ -struct nl_cache *rtnl_neigh_alloc_cache(struct nl_handle *handle) -{ - struct nl_cache *cache = nl_cache_alloc_from_ops(&rtnl_neigh_ops); - - if (cache == NULL) - return NULL; - - if (nl_cache_update(handle, cache) < 0) { - nl_cache_free(cache); - return NULL; - } - - NL_DBG(2, "Returning new cache %p\n", cache); - - return cache; -} - -/** - * Look up a neighbour by interface index and destination address - * @arg cache neighbour cache - * @arg ifindex interface index the neighbour is on - * @arg dst destination address of the neighbour - * @return neighbour handle or NULL if no match was found. - */ -struct rtnl_neigh * rtnl_neigh_get(struct nl_cache *cache, int ifindex, - struct nl_addr *dst) -{ - struct rtnl_neigh *neigh; - - nl_list_for_each_entry(neigh, &cache->c_items, ce_list) { - if (neigh->n_ifindex == ifindex && - !nl_addr_cmp(neigh->n_dst, dst)) { - nl_object_get((struct nl_object *) neigh); - return neigh; - } - } - - return NULL; -} - -/** @} */ - -/** - * @name Neighbour Addition - * @{ - */ - -static struct nl_msg * build_neigh_msg(struct rtnl_neigh *tmpl, int cmd, - int flags) -{ - struct nl_msg *msg; - struct ndmsg nhdr = { - .ndm_ifindex = tmpl->n_ifindex, - .ndm_family = nl_addr_get_family(tmpl->n_dst), - .ndm_state = NUD_PERMANENT, - }; - - if (tmpl->n_mask & NEIGH_ATTR_STATE) - nhdr.ndm_state = tmpl->n_state; - - msg = nlmsg_build_simple(cmd, flags); - if (!msg) - return NULL; - - if (nlmsg_append(msg, &nhdr, sizeof(nhdr), 1) < 0) - goto nla_put_failure; - - NLA_PUT_ADDR(msg, NDA_DST, tmpl->n_dst); - - if (tmpl->n_mask & NEIGH_ATTR_LLADDR) - NLA_PUT_ADDR(msg, NDA_LLADDR, tmpl->n_lladdr); - - return msg; - -nla_put_failure: - nlmsg_free(msg); - return NULL; -} - -/** - * Build netlink request message to add a new neighbour - * @arg tmpl template with data of new neighbour - * @arg flags additional netlink message flags - * - * Builds a new netlink message requesting a addition of a new - * neighbour. The netlink message header isn't fully equipped with - * all relevant fields and must thus be sent out via nl_send_auto_complete() - * or supplemented as needed. \a tmpl must contain the attributes of the new - * neighbour set via \c rtnl_neigh_set_* functions. - * - * The following attributes must be set in the template: - * - Interface index (rtnl_neigh_set_ifindex()) - * - State (rtnl_neigh_set_state()) - * - Destination address (rtnl_neigh_set_dst()) - * - Link layer address (rtnl_neigh_set_lladdr()) - * - * @return The netlink message - */ -struct nl_msg * rtnl_neigh_build_add_request(struct rtnl_neigh *tmpl, int flags) -{ - return build_neigh_msg(tmpl, RTM_NEWNEIGH, NLM_F_CREATE | flags); -} - -/** - * Add a new neighbour - * @arg handle netlink handle - * @arg tmpl template with requested changes - * @arg flags additional netlink message flags - * - * Builds a netlink message by calling rtnl_neigh_build_add_request(), - * sends the request to the kernel and waits for the next ACK to be - * received and thus blocks until the request has been fullfilled. - * - * The following attributes must be set in the template: - * - Interface index (rtnl_neigh_set_ifindex()) - * - State (rtnl_neigh_set_state()) - * - Destination address (rtnl_neigh_set_dst()) - * - Link layer address (rtnl_neigh_set_lladdr()) - * - * @return 0 on sucess or a negative error if an error occured. - */ -int rtnl_neigh_add(struct nl_handle *handle, struct rtnl_neigh *tmpl, int flags) -{ - int err; - struct nl_msg *msg; - - msg = rtnl_neigh_build_add_request(tmpl, flags); - if (!msg) - return nl_errno(ENOMEM); - - err = nl_send_auto_complete(handle, msg); - if (err < 0) - return err; - - nlmsg_free(msg); - return nl_wait_for_ack(handle); -} - -/** @} */ - -/** - * @name Neighbour Deletion - * @{ - */ - -/** - * Build a netlink request message to delete a neighbour - * @arg neigh neighbour to delete - * @arg flags additional netlink message flags - * - * Builds a new netlink message requesting a deletion of a neighbour. - * The netlink message header isn't fully equipped with all relevant - * fields and must thus be sent out via nl_send_auto_complete() - * or supplemented as needed. \a neigh must point to an existing - * neighbour. - * - * @return The netlink message - */ -struct nl_msg *rtnl_neigh_build_delete_request(struct rtnl_neigh *neigh, - int flags) -{ - return build_neigh_msg(neigh, RTM_DELNEIGH, flags); -} - -/** - * Delete a neighbour - * @arg handle netlink handle - * @arg neigh neighbour to delete - * @arg flags additional netlink message flags - * - * Builds a netlink message by calling rtnl_neigh_build_delete_request(), - * sends the request to the kernel and waits for the next ACK to be - * received and thus blocks until the request has been fullfilled. - * - * @return 0 on sucess or a negative error if an error occured. - */ -int rtnl_neigh_delete(struct nl_handle *handle, struct rtnl_neigh *neigh, - int flags) -{ - int err; - struct nl_msg *msg; - - msg = rtnl_neigh_build_delete_request(neigh, flags); - if (!msg) - return nl_errno(ENOMEM); - - err = nl_send_auto_complete(handle, msg); - if (err < 0) - return err; - - nlmsg_free(msg); - return nl_wait_for_ack(handle); -} - -/** @} */ - -/** - * @name Neighbour Modification - * @{ - */ - -/** - * Build a netlink request message to change neighbour attributes - * @arg neigh the neighbour to change - * @arg flags additional netlink message flags - * - * Builds a new netlink message requesting a change of a neigh - * attributes. The netlink message header isn't fully equipped with - * all relevant fields and must thus be sent out via nl_send_auto_complete() - * or supplemented as needed. - * - * @return The netlink message - * @note Not all attributes can be changed, see - * \ref neigh_changeable "Changeable Attributes" for a list. - */ -struct nl_msg *rtnl_neigh_build_change_request(struct rtnl_neigh *neigh, - int flags) -{ - return build_neigh_msg(neigh, RTM_NEWNEIGH, NLM_F_REPLACE | flags); -} - -/** - * Change neighbour attributes - * @arg handle netlink handle - * @arg neigh neighbour to be changed - * @arg flags additional netlink message flags - * - * Builds a netlink message by calling rtnl_neigh_build_change_request(), - * sends the request to the kernel and waits for the next ACK to be - * received and thus blocks until the request has been fullfilled. - * - * @return 0 on sucess or a negative error if an error occured. - * @note Not all attributes can be changed, see - * \ref neigh_changeable "Changeable Attributes" for a list. - */ -int rtnl_neigh_change(struct nl_handle *handle, struct rtnl_neigh *neigh, - int flags) -{ - int err; - struct nl_msg *msg; - - msg = rtnl_neigh_build_change_request(neigh, flags); - if (!msg) - return nl_errno(ENOMEM); - - err = nl_send_auto_complete(handle, msg); - if (err < 0) - return err; - - nlmsg_free(msg); - return nl_wait_for_ack(handle); -} - -/** @} */ - -/** - * @name Neighbour States Translations - * @{ - */ - -static struct trans_tbl neigh_states[] = { - __ADD(NUD_INCOMPLETE, incomplete) - __ADD(NUD_REACHABLE, reachable) - __ADD(NUD_STALE, stale) - __ADD(NUD_DELAY, delay) - __ADD(NUD_PROBE, probe) - __ADD(NUD_FAILED, failed) - __ADD(NUD_NOARP, norarp) - __ADD(NUD_PERMANENT, permanent) -}; - -/** - * Convert neighbour states to a character string (Reentrant). - * @arg state neighbour state - * @arg buf destination buffer - * @arg len buffer length - * - * Converts a neighbour state to a character string separated by - * commands and stores it in the specified destination buffer. - * - * @return The destination buffer - */ -char * rtnl_neigh_state2str(int state, char *buf, size_t len) -{ - return __flags2str(state, buf, len, neigh_states, - ARRAY_SIZE(neigh_states)); -} - -/** - * Convert a character string to a neighbour state - * @arg name Name of cscope - * - * Converts the provided character string specifying a neighbour - * state the corresponding numeric value. - * - * @return Neighbour state or a negative value if none was found. - */ -int rtnl_neigh_str2state(const char *name) -{ - return __str2type(name, neigh_states, ARRAY_SIZE(neigh_states)); -} - -/** @} */ - -/** - * @name Neighbour Flags Translations - * @{ - */ - -static struct trans_tbl neigh_flags[] = { - __ADD(NTF_PROXY, proxy) - __ADD(NTF_ROUTER, router) -}; - -/** - * Convert neighbour flags to a character string (Reentrant). - * @arg flags neighbour flags - * @arg buf destination buffer - * @arg len buffer length - * - * Converts neighbour flags to a character string separated by - * commands and stores it in the specified destination buffer. - * - * @return The destination buffer or a empty string if no flags are set. - */ -char * rtnl_neigh_flags2str(int flags, char *buf, size_t len) -{ - return __flags2str(flags, buf, len, neigh_flags, - ARRAY_SIZE(neigh_flags)); -} - -/** - * Convert a character string to a neighbour flag - * @arg name name of the flag - * - * Converts the provided character string specifying a neighbour - * flag the corresponding numeric value. - * - * @return Neighbour flag or a negative value if none was found. - */ -int rtnl_neigh_str2flag(const char *name) -{ - return __str2type(name, neigh_flags, ARRAY_SIZE(neigh_flags)); -} - -/** @} */ - -/** - * @name Attribute Modification - * @{ - */ - -/** - * Set a neighbour state - * @arg neigh neighbour to change - * @arg state state to set - */ -void rtnl_neigh_set_state(struct rtnl_neigh *neigh, int state) -{ - neigh->n_state_mask |= state; - neigh->n_state |= state; - neigh->n_mask |= NEIGH_ATTR_STATE; -} - -/** - * Get neighbour states - * @arg neigh neighbour handle - * @return Neighbour state or -1 if not set - */ -int rtnl_neigh_get_state(struct rtnl_neigh *neigh) -{ - if (neigh->n_mask & NEIGH_ATTR_STATE) - return neigh->n_state; - else - return -1; -} - -/** - * Unset a neigbour state - * @arg neigh neighbour to change - * @arg state state to unset - */ -void rtnl_neigh_unset_state(struct rtnl_neigh *neigh, int state) -{ - neigh->n_state_mask |= state; - neigh->n_state &= ~state; - neigh->n_mask |= NEIGH_ATTR_STATE; -} - -/** - * Set neighbour flags - * @arg neigh neighbour to change - * @arg flags flag to set - */ -void rtnl_neigh_set_flags(struct rtnl_neigh *neigh, unsigned int flags) -{ - neigh->n_flag_mask |= flags; - neigh->n_flags |= flags; - neigh->n_mask |= NEIGH_ATTR_FLAGS; -} - -/** - * Get neighbour flags - * @arg neigh neighbour handle - * @return Neighbour flags - */ -unsigned int rtnl_neigh_get_flags(struct rtnl_neigh *neigh) -{ - return neigh->n_flags; -} - -/** - * Unset neighbour flags - * @arg neigh neighbour to change - * @arg flags flag to unset - */ -void rtnl_neigh_unset_flags(struct rtnl_neigh *neigh, unsigned int flags) -{ - neigh->n_flag_mask |= flags; - neigh->n_flags &= ~flags; - neigh->n_mask |= NEIGH_ATTR_FLAGS; -} - -/** - * Set the interface index of device this neighbour is on - * @arg neigh neighbour to change - * @arg ifindex new interface index - */ -void rtnl_neigh_set_ifindex(struct rtnl_neigh *neigh, int ifindex) -{ - neigh->n_ifindex = ifindex; - neigh->n_mask |= NEIGH_ATTR_IFINDEX; -} - -/** - * Get the interface index of the device this neighbour is on - * @arg neigh neighbour handle - * @return Interface index or RTNL_LINK_NOT_FOUND if not set - */ -int rtnl_neigh_get_ifindex(struct rtnl_neigh *neigh) -{ - if (neigh->n_mask & NEIGH_ATTR_IFINDEX) - return neigh->n_ifindex; - else - return RTNL_LINK_NOT_FOUND; -} - -static inline int __assign_addr(struct rtnl_neigh *neigh, struct nl_addr **pos, - struct nl_addr *new, int flag, int nocheck) -{ - if (!nocheck) { - if (neigh->n_mask & NEIGH_ATTR_FAMILY) { - if (new->a_family != neigh->n_family) - return nl_error(EINVAL, - "Address family mismatch"); - } else { - neigh->n_family = new->a_family; - neigh->n_mask |= NEIGH_ATTR_FAMILY; - } - } - - if (*pos) - nl_addr_put(*pos); - - nl_addr_get(new); - *pos = new; - - neigh->n_mask |= flag; - - return 0; -} - -/** - * Set link layer address of a neighbour - * @arg neigh neighbour to change - * @arg addr new link layer address - * - * Assigns the new link layer address to the specified neighbour handle. - * - * @note The prefix length of the address will be ignored. - */ -void rtnl_neigh_set_lladdr(struct rtnl_neigh *neigh, struct nl_addr *addr) -{ - __assign_addr(neigh, &neigh->n_lladdr, addr, NEIGH_ATTR_LLADDR, 1); -} - -/** - * Get link layer address of a neighbour - * @arg neigh neighbour handle - * @return Link layer address or NULL if not set - */ -struct nl_addr *rtnl_neigh_get_lladdr(struct rtnl_neigh *neigh) -{ - if (neigh->n_mask & NEIGH_ATTR_LLADDR) - return neigh->n_lladdr; - else - return NULL; -} - -/** - * Set destination address of a neighbour - * @arg neigh neighbour to change - * @arg addr new destination address - * - * Assigns the new destination address to the specified neighbour handle. - * The address is validated against the address family if set already via - * rtnl_neigh_set_family(). The assignment fails if the address families - * mismatch. In case the address family has not been specified yet, the - * address family of this new address is elected to be the requirement. - * - * @return 0 on success or a negative error code. - */ -int rtnl_neigh_set_dst(struct rtnl_neigh *neigh, struct nl_addr *addr) -{ - return __assign_addr(neigh, &neigh->n_dst, addr, - NEIGH_ATTR_DST, 0); -} - -/** - * Get the destination address of a neighbour - * @arg neigh neighbour handle - * @return Destination address or NULL if not set - */ -struct nl_addr *rtnl_neigh_get_dst(struct rtnl_neigh *neigh) -{ - if (neigh->n_mask & NEIGH_ATTR_DST) - return neigh->n_dst; - else - return NULL; -} - -/** - * Set destination address family - * @arg neigh neighbour to change - * @arg family new destination address family - */ -void rtnl_neigh_set_family(struct rtnl_neigh *neigh, int family) -{ - neigh->n_family = family; - neigh->n_mask |= NEIGH_ATTR_FAMILY; -} - -/** - * Set RTN type of a neighbour - * @arg neigh neighbour to change - * @arg type new rtn type - */ -void rtnl_neigh_set_type(struct rtnl_neigh *neigh, int type) -{ - neigh->n_type = type; - neigh->n_mask = NEIGH_ATTR_TYPE; -} - -/** - * Get RTN type of a neighbour - * @arg neigh neighbour handle - * @return Type or -1 if not set - */ -int rtnl_neigh_get_type(struct rtnl_neigh *neigh) -{ - if (neigh->n_mask & NEIGH_ATTR_TYPE) - return neigh->n_type; - else - return -1; -} - -/** @} */ - -static struct nl_cache_ops rtnl_neigh_ops = { - .co_name = "route/neigh", - .co_size = sizeof(struct rtnl_neigh), - .co_hdrsize = sizeof(struct ndmsg), - .co_msgtypes = { - { RTM_NEWNEIGH, "new" }, - { RTM_DELNEIGH, "delete" }, - { RTM_GETNEIGH, "get" }, - { -1, NULL }, - }, - .co_protocol = NETLINK_ROUTE, - .co_request_update = neigh_request_update, - .co_msg_parser = neigh_msg_parser, - .co_free_data = neigh_free_data, - .co_dump[NL_DUMP_BRIEF] = neigh_dump_brief, - .co_dump[NL_DUMP_FULL] = neigh_dump_full, - .co_dump[NL_DUMP_STATS] = neigh_dump_stats, - .co_dump[NL_DUMP_XML] = neigh_dump_xml, - .co_dump[NL_DUMP_ENV] = neigh_dump_env, - .co_filter = neigh_filter, -}; - -static void __init neigh_init(void) -{ - nl_cache_mngt_register(&rtnl_neigh_ops); -} - -static void __exit neigh_exit(void) -{ - nl_cache_mngt_unregister(&rtnl_neigh_ops); -} - -/** @} */