1 /*
2 * lib/route/neigh.c Neighbours
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation version 2.1
7 * of the License.
8 *
9 * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
10 */
11
12 /**
13 * @ingroup rtnl
14 * @defgroup neigh Neighbours
15 * @brief
16 *
17 * The neighbour table establishes bindings between protocol addresses and
18 * link layer addresses for hosts sharing the same physical link. This
19 * module allows you to access and manipulate the content of these tables.
20 *
21 * @par Neighbour States
22 * @code
23 * NUD_INCOMPLETE
24 * NUD_REACHABLE
25 * NUD_STALE
26 * NUD_DELAY
27 * NUD_PROBE
28 * NUD_FAILED
29 * NUD_NOARP
30 * NUD_PERMANENT
31 * @endcode
32 *
33 * @par Neighbour Flags
34 * @code
35 * NTF_PROXY
36 * NTF_ROUTER
37 * @endcode
38 *
39 * @par Neighbour Identification
40 * A neighbour is uniquely identified by the attributes listed below, whenever
41 * you refer to an existing neighbour all of the attributes must be set.
42 * Neighbours from caches automatically have all required attributes set.
43 * - interface index (rtnl_neigh_set_ifindex())
44 * - destination address (rtnl_neigh_set_dst())
45 *
46 * @par Changeable Attributes
47 * \anchor neigh_changeable
48 * - state (rtnl_neigh_set_state())
49 * - link layer address (rtnl_neigh_set_lladdr())
50 *
51 * @par Required Caches for Dumping
52 * In order to dump neighbour attributes you must provide the following
53 * caches via nl_cache_provide()
54 * - link cache holding all links
55 *
56 * @par TODO
57 * - Document proxy settings
58 * - Document states and their influence
59 *
60 * @par 1) Retrieving information about configured neighbours
61 * @code
62 * // The first step is to retrieve a list of all available neighbour within
63 * // the kernel and put them into a cache.
64 * struct nl_cache *cache = rtnl_neigh_alloc_cache(sk);
65 *
66 * // Neighbours can then be looked up by the interface and destination
67 * // address:
68 * struct rtnl_neigh *neigh = rtnl_neigh_get(cache, ifindex, dst_addr);
69 *
70 * // After successful usage, the object must be given back to the cache
71 * rtnl_neigh_put(neigh);
72 * @endcode
73 *
74 * @par 2) Adding new neighbours
75 * @code
76 * // Allocate an empty neighbour handle to be filled out with the attributes
77 * // of the new neighbour.
78 * struct rtnl_neigh *neigh = rtnl_neigh_alloc();
79 *
80 * // Fill out the attributes of the new neighbour
81 * rtnl_neigh_set_ifindex(neigh, ifindex);
82 * rtnl_neigh_set_dst(neigh, dst_addr);
83 * rtnl_neigh_set_state(neigh, rtnl_neigh_str2state("permanent"));
84 *
85 * // Build the netlink message and send it to the kernel, the operation will
86 * // block until the operation has been completed. Alternatively the required
87 * // netlink message can be built using rtnl_neigh_build_add_request()
88 * // to be sent out using nl_send_auto_complete().
89 * rtnl_neigh_add(sk, neigh, NLM_F_CREATE);
90 *
91 * // Free the memory
92 * rtnl_neigh_put(neigh);
93 * @endcode
94 *
95 * @par 3) Deleting an existing neighbour
96 * @code
97 * // Allocate an empty neighbour object to be filled out with the attributes
98 * // matching the neighbour to be deleted. Alternatively a fully equipped
99 * // neighbour object out of a cache can be used instead.
100 * struct rtnl_neigh *neigh = rtnl_neigh_alloc();
101 *
102 * // Neighbours are uniquely identified by their interface index and
103 * // destination address, you may fill out other attributes but they
104 * // will have no influence.
105 * rtnl_neigh_set_ifindex(neigh, ifindex);
106 * rtnl_neigh_set_dst(neigh, dst_addr);
107 *
108 * // Build the netlink message and send it to the kernel, the operation will
109 * // block until the operation has been completed. Alternatively the required
110 * // netlink message can be built using rtnl_neigh_build_delete_request()
111 * // to be sent out using nl_send_auto_complete().
112 * rtnl_neigh_delete(sk, neigh, 0);
113 *
114 * // Free the memory
115 * rtnl_neigh_put(neigh);
116 * @endcode
117 *
118 * @par 4) Changing neighbour attributes
119 * @code
120 * // Allocate an empty neighbour object to be filled out with the attributes
121 * // matching the neighbour to be changed and the new parameters. Alternatively
122 * // a fully equipped modified neighbour object out of a cache can be used.
123 * struct rtnl_neigh *neigh = rtnl_neigh_alloc();
124 *
125 * // Identify the neighbour to be changed by its interface index and
126 * // destination address
127 * rtnl_neigh_set_ifindex(neigh, ifindex);
128 * rtnl_neigh_set_dst(neigh, dst_addr);
129 *
130 * // The link layer address may be modified, if so it is wise to change
131 * // its state to "permanent" in order to avoid having it overwritten.
132 * rtnl_neigh_set_lladdr(neigh, lladdr);
133 *
134 * // Secondly the state can be modified allowing normal neighbours to be
135 * // converted into permanent entries or to manually confirm a neighbour.
136 * rtnl_neigh_set_state(neigh, state);
137 *
138 * // Build the netlink message and send it to the kernel, the operation will
139 * // block until the operation has been completed. Alternatively the required
140 * // netlink message can be built using rtnl_neigh_build_change_request()
141 * // to be sent out using nl_send_auto_complete().
142 * rtnl_neigh_add(sk, neigh, NLM_F_REPLACE);
143 *
144 * // Free the memory
145 * rtnl_neigh_put(neigh);
146 * @endcode
147 * @{
148 */
149
150 #include <netlink-local.h>
151 #include <netlink/netlink.h>
152 #include <netlink/utils.h>
153 #include <netlink/route/rtnl.h>
154 #include <netlink/route/neighbour.h>
155 #include <netlink/route/link.h>
156
157 /** @cond SKIP */
158 #define NEIGH_ATTR_FLAGS 0x01
159 #define NEIGH_ATTR_STATE 0x02
160 #define NEIGH_ATTR_LLADDR 0x04
161 #define NEIGH_ATTR_DST 0x08
162 #define NEIGH_ATTR_CACHEINFO 0x10
163 #define NEIGH_ATTR_IFINDEX 0x20
164 #define NEIGH_ATTR_FAMILY 0x40
165 #define NEIGH_ATTR_TYPE 0x80
166 #define NEIGH_ATTR_PROBES 0x100
167
168 static struct nl_cache_ops rtnl_neigh_ops;
169 static struct nl_object_ops neigh_obj_ops;
170 /** @endcond */
171
neigh_free_data(struct nl_object * c)172 static void neigh_free_data(struct nl_object *c)
173 {
174 struct rtnl_neigh *neigh = nl_object_priv(c);
175
176 if (!neigh)
177 return;
178
179 nl_addr_put(neigh->n_lladdr);
180 nl_addr_put(neigh->n_dst);
181 }
182
neigh_clone(struct nl_object * _dst,struct nl_object * _src)183 static int neigh_clone(struct nl_object *_dst, struct nl_object *_src)
184 {
185 struct rtnl_neigh *dst = nl_object_priv(_dst);
186 struct rtnl_neigh *src = nl_object_priv(_src);
187
188 if (src->n_lladdr)
189 if (!(dst->n_lladdr = nl_addr_clone(src->n_lladdr)))
190 return -NLE_NOMEM;
191
192 if (src->n_dst)
193 if (!(dst->n_dst = nl_addr_clone(src->n_dst)))
194 return -NLE_NOMEM;
195
196 return 0;
197 }
198
neigh_compare(struct nl_object * _a,struct nl_object * _b,uint32_t attrs,int flags)199 static int neigh_compare(struct nl_object *_a, struct nl_object *_b,
200 uint32_t attrs, int flags)
201 {
202 struct rtnl_neigh *a = (struct rtnl_neigh *) _a;
203 struct rtnl_neigh *b = (struct rtnl_neigh *) _b;
204 int diff = 0;
205
206 #define NEIGH_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, NEIGH_ATTR_##ATTR, a, b, EXPR)
207
208 diff |= NEIGH_DIFF(IFINDEX, a->n_ifindex != b->n_ifindex);
209 diff |= NEIGH_DIFF(FAMILY, a->n_family != b->n_family);
210 diff |= NEIGH_DIFF(TYPE, a->n_type != b->n_type);
211 diff |= NEIGH_DIFF(LLADDR, nl_addr_cmp(a->n_lladdr, b->n_lladdr));
212 diff |= NEIGH_DIFF(DST, nl_addr_cmp(a->n_dst, b->n_dst));
213
214 if (flags & LOOSE_COMPARISON) {
215 diff |= NEIGH_DIFF(STATE,
216 (a->n_state ^ b->n_state) & b->n_state_mask);
217 diff |= NEIGH_DIFF(FLAGS,
218 (a->n_flags ^ b->n_flags) & b->n_flag_mask);
219 } else {
220 diff |= NEIGH_DIFF(STATE, a->n_state != b->n_state);
221 diff |= NEIGH_DIFF(FLAGS, a->n_flags != b->n_flags);
222 }
223
224 #undef NEIGH_DIFF
225
226 return diff;
227 }
228
229 static struct trans_tbl neigh_attrs[] = {
230 __ADD(NEIGH_ATTR_FLAGS, flags)
231 __ADD(NEIGH_ATTR_STATE, state)
232 __ADD(NEIGH_ATTR_LLADDR, lladdr)
233 __ADD(NEIGH_ATTR_DST, dst)
234 __ADD(NEIGH_ATTR_CACHEINFO, cacheinfo)
235 __ADD(NEIGH_ATTR_IFINDEX, ifindex)
236 __ADD(NEIGH_ATTR_FAMILY, family)
237 __ADD(NEIGH_ATTR_TYPE, type)
238 __ADD(NEIGH_ATTR_PROBES, probes)
239 };
240
neigh_attrs2str(int attrs,char * buf,size_t len)241 static char *neigh_attrs2str(int attrs, char *buf, size_t len)
242 {
243 return __flags2str(attrs, buf, len, neigh_attrs,
244 ARRAY_SIZE(neigh_attrs));
245 }
246
247 static struct nla_policy neigh_policy[NDA_MAX+1] = {
248 [NDA_CACHEINFO] = { .minlen = sizeof(struct nda_cacheinfo) },
249 [NDA_PROBES] = { .type = NLA_U32 },
250 };
251
neigh_msg_parser(struct nl_cache_ops * ops,struct sockaddr_nl * who,struct nlmsghdr * n,struct nl_parser_param * pp)252 static int neigh_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
253 struct nlmsghdr *n, struct nl_parser_param *pp)
254 {
255 struct rtnl_neigh *neigh;
256 struct nlattr *tb[NDA_MAX + 1];
257 struct ndmsg *nm;
258 int err;
259
260 neigh = rtnl_neigh_alloc();
261 if (!neigh) {
262 err = -NLE_NOMEM;
263 goto errout;
264 }
265
266 neigh->ce_msgtype = n->nlmsg_type;
267 nm = nlmsg_data(n);
268
269 err = nlmsg_parse(n, sizeof(*nm), tb, NDA_MAX, neigh_policy);
270 if (err < 0)
271 goto errout;
272
273 neigh->n_family = nm->ndm_family;
274 neigh->n_ifindex = nm->ndm_ifindex;
275 neigh->n_state = nm->ndm_state;
276 neigh->n_flags = nm->ndm_flags;
277 neigh->n_type = nm->ndm_type;
278
279 neigh->ce_mask |= (NEIGH_ATTR_FAMILY | NEIGH_ATTR_IFINDEX |
280 NEIGH_ATTR_STATE | NEIGH_ATTR_FLAGS |
281 NEIGH_ATTR_TYPE);
282
283 if (tb[NDA_LLADDR]) {
284 neigh->n_lladdr = nl_addr_alloc_attr(tb[NDA_LLADDR], AF_UNSPEC);
285 if (!neigh->n_lladdr) {
286 err = -NLE_NOMEM;
287 goto errout;
288 }
289 nl_addr_set_family(neigh->n_lladdr,
290 nl_addr_guess_family(neigh->n_lladdr));
291 neigh->ce_mask |= NEIGH_ATTR_LLADDR;
292 }
293
294 if (tb[NDA_DST]) {
295 neigh->n_dst = nl_addr_alloc_attr(tb[NDA_DST], neigh->n_family);
296 if (!neigh->n_dst) {
297 err = -NLE_NOMEM;
298 goto errout;
299 }
300 neigh->ce_mask |= NEIGH_ATTR_DST;
301 }
302
303 if (tb[NDA_CACHEINFO]) {
304 struct nda_cacheinfo *ci = nla_data(tb[NDA_CACHEINFO]);
305
306 neigh->n_cacheinfo.nci_confirmed = ci->ndm_confirmed;
307 neigh->n_cacheinfo.nci_used = ci->ndm_used;
308 neigh->n_cacheinfo.nci_updated = ci->ndm_updated;
309 neigh->n_cacheinfo.nci_refcnt = ci->ndm_refcnt;
310
311 neigh->ce_mask |= NEIGH_ATTR_CACHEINFO;
312 }
313
314 if (tb[NDA_PROBES]) {
315 neigh->n_probes = nla_get_u32(tb[NDA_PROBES]);
316 neigh->ce_mask |= NEIGH_ATTR_PROBES;
317 }
318
319 err = pp->pp_cb((struct nl_object *) neigh, pp);
320 errout:
321 rtnl_neigh_put(neigh);
322 return err;
323 }
324
neigh_request_update(struct nl_cache * c,struct nl_sock * h)325 static int neigh_request_update(struct nl_cache *c, struct nl_sock *h)
326 {
327 return nl_rtgen_request(h, RTM_GETNEIGH, AF_UNSPEC, NLM_F_DUMP);
328 }
329
330
neigh_dump_line(struct nl_object * a,struct nl_dump_params * p)331 static void neigh_dump_line(struct nl_object *a, struct nl_dump_params *p)
332 {
333 char dst[INET6_ADDRSTRLEN+5], lladdr[INET6_ADDRSTRLEN+5];
334 struct rtnl_neigh *n = (struct rtnl_neigh *) a;
335 struct nl_cache *link_cache;
336 char state[128], flags[64];
337
338 link_cache = nl_cache_mngt_require("route/link");
339
340 nl_dump_line(p, "%s ", nl_addr2str(n->n_dst, dst, sizeof(dst)));
341
342 if (link_cache)
343 nl_dump(p, "dev %s ",
344 rtnl_link_i2name(link_cache, n->n_ifindex,
345 state, sizeof(state)));
346 else
347 nl_dump(p, "dev %d ", n->n_ifindex);
348
349 if (n->ce_mask & NEIGH_ATTR_LLADDR)
350 nl_dump(p, "lladdr %s ",
351 nl_addr2str(n->n_lladdr, lladdr, sizeof(lladdr)));
352
353 rtnl_neigh_state2str(n->n_state, state, sizeof(state));
354 rtnl_neigh_flags2str(n->n_flags, flags, sizeof(flags));
355
356 if (state[0])
357 nl_dump(p, "<%s", state);
358 if (flags[0])
359 nl_dump(p, "%s%s", state[0] ? "," : "<", flags);
360 if (state[0] || flags[0])
361 nl_dump(p, ">");
362 nl_dump(p, "\n");
363 }
364
neigh_dump_details(struct nl_object * a,struct nl_dump_params * p)365 static void neigh_dump_details(struct nl_object *a, struct nl_dump_params *p)
366 {
367 char rtn_type[32];
368 struct rtnl_neigh *n = (struct rtnl_neigh *) a;
369 int hz = nl_get_hz();
370
371 neigh_dump_line(a, p);
372
373 nl_dump_line(p, " refcnt %u type %s confirmed %u used "
374 "%u updated %u\n",
375 n->n_cacheinfo.nci_refcnt,
376 nl_rtntype2str(n->n_type, rtn_type, sizeof(rtn_type)),
377 n->n_cacheinfo.nci_confirmed/hz,
378 n->n_cacheinfo.nci_used/hz, n->n_cacheinfo.nci_updated/hz);
379 }
380
neigh_dump_stats(struct nl_object * a,struct nl_dump_params * p)381 static void neigh_dump_stats(struct nl_object *a, struct nl_dump_params *p)
382 {
383 neigh_dump_details(a, p);
384 }
385
neigh_dump_env(struct nl_object * obj,struct nl_dump_params * p)386 static void neigh_dump_env(struct nl_object *obj, struct nl_dump_params *p)
387 {
388 struct rtnl_neigh *neigh = (struct rtnl_neigh *) obj;
389 char buf[128];
390
391 nl_dump_line(p, "NEIGH_FAMILY=%s\n",
392 nl_af2str(neigh->n_family, buf, sizeof(buf)));
393
394 if (neigh->ce_mask & NEIGH_ATTR_LLADDR)
395 nl_dump_line(p, "NEIGHT_LLADDR=%s\n",
396 nl_addr2str(neigh->n_lladdr, buf, sizeof(buf)));
397
398 if (neigh->ce_mask & NEIGH_ATTR_DST)
399 nl_dump_line(p, "NEIGH_DST=%s\n",
400 nl_addr2str(neigh->n_dst, buf, sizeof(buf)));
401
402 if (neigh->ce_mask & NEIGH_ATTR_IFINDEX) {
403 struct nl_cache *link_cache;
404
405 nl_dump_line(p, "NEIGH_IFINDEX=%u\n", neigh->n_ifindex);
406
407 link_cache = nl_cache_mngt_require("route/link");
408 if (link_cache)
409 nl_dump_line(p, "NEIGH_IFNAME=%s\n",
410 rtnl_link_i2name(link_cache,
411 neigh->n_ifindex,
412 buf, sizeof(buf)));
413 }
414
415 if (neigh->ce_mask & NEIGH_ATTR_PROBES)
416 nl_dump_line(p, "NEIGH_PROBES=%u\n", neigh->n_probes);
417
418 if (neigh->ce_mask & NEIGH_ATTR_TYPE)
419 nl_dump_line(p, "NEIGH_TYPE=%s\n",
420 nl_rtntype2str(neigh->n_type, buf, sizeof(buf)));
421
422 rtnl_neigh_flags2str(neigh->n_flags, buf, sizeof(buf));
423 if (buf[0])
424 nl_dump_line(p, "NEIGH_FLAGS=%s\n", buf);
425
426 rtnl_neigh_state2str(neigh->n_state, buf, sizeof(buf));
427 if (buf[0])
428 nl_dump_line(p, "NEIGH_STATE=%s\n", buf);
429 }
430
431 /**
432 * @name Neighbour Object Allocation/Freeage
433 * @{
434 */
435
rtnl_neigh_alloc(void)436 struct rtnl_neigh *rtnl_neigh_alloc(void)
437 {
438 return (struct rtnl_neigh *) nl_object_alloc(&neigh_obj_ops);
439 }
440
rtnl_neigh_put(struct rtnl_neigh * neigh)441 void rtnl_neigh_put(struct rtnl_neigh *neigh)
442 {
443 nl_object_put((struct nl_object *) neigh);
444 }
445
446 /** @} */
447
448 /**
449 * @name Neighbour Cache Managament
450 * @{
451 */
452
453 /**
454 * Build a neighbour cache including all neighbours currently configured in the kernel.
455 * @arg sk Netlink socket.
456 * @arg result Pointer to store resulting cache.
457 *
458 * Allocates a new neighbour cache, initializes it properly and updates it
459 * to include all neighbours currently configured in the kernel.
460 *
461 * @return 0 on success or a negative error code.
462 */
rtnl_neigh_alloc_cache(struct nl_sock * sock,struct nl_cache ** result)463 int rtnl_neigh_alloc_cache(struct nl_sock *sock, struct nl_cache **result)
464 {
465 return nl_cache_alloc_and_fill(&rtnl_neigh_ops, sock, result);
466 }
467
468 /**
469 * Look up a neighbour by interface index and destination address
470 * @arg cache neighbour cache
471 * @arg ifindex interface index the neighbour is on
472 * @arg dst destination address of the neighbour
473 * @return neighbour handle or NULL if no match was found.
474 */
rtnl_neigh_get(struct nl_cache * cache,int ifindex,struct nl_addr * dst)475 struct rtnl_neigh * rtnl_neigh_get(struct nl_cache *cache, int ifindex,
476 struct nl_addr *dst)
477 {
478 struct rtnl_neigh *neigh;
479
480 nl_list_for_each_entry(neigh, &cache->c_items, ce_list) {
481 if (neigh->n_ifindex == ifindex &&
482 !nl_addr_cmp(neigh->n_dst, dst)) {
483 nl_object_get((struct nl_object *) neigh);
484 return neigh;
485 }
486 }
487
488 return NULL;
489 }
490
491 /** @} */
492
493 /**
494 * @name Neighbour Addition
495 * @{
496 */
497
build_neigh_msg(struct rtnl_neigh * tmpl,int cmd,int flags,struct nl_msg ** result)498 static int build_neigh_msg(struct rtnl_neigh *tmpl, int cmd, int flags,
499 struct nl_msg **result)
500 {
501 struct nl_msg *msg;
502 struct ndmsg nhdr = {
503 .ndm_ifindex = tmpl->n_ifindex,
504 .ndm_state = NUD_PERMANENT,
505 };
506
507 if (!(tmpl->ce_mask & NEIGH_ATTR_DST))
508 return -NLE_MISSING_ATTR;
509
510 nhdr.ndm_family = nl_addr_get_family(tmpl->n_dst);
511
512 if (tmpl->ce_mask & NEIGH_ATTR_STATE)
513 nhdr.ndm_state = tmpl->n_state;
514
515 msg = nlmsg_alloc_simple(cmd, flags);
516 if (!msg)
517 return -NLE_NOMEM;
518
519 if (nlmsg_append(msg, &nhdr, sizeof(nhdr), NLMSG_ALIGNTO) < 0)
520 goto nla_put_failure;
521
522 NLA_PUT_ADDR(msg, NDA_DST, tmpl->n_dst);
523
524 if (tmpl->ce_mask & NEIGH_ATTR_LLADDR)
525 NLA_PUT_ADDR(msg, NDA_LLADDR, tmpl->n_lladdr);
526
527 *result = msg;
528 return 0;
529
530 nla_put_failure:
531 nlmsg_free(msg);
532 return -NLE_MSGSIZE;
533 }
534
535 /**
536 * Build netlink request message to add a new neighbour
537 * @arg tmpl template with data of new neighbour
538 * @arg flags additional netlink message flags
539 * @arg result Pointer to store resulting message.
540 *
541 * Builds a new netlink message requesting a addition of a new
542 * neighbour. The netlink message header isn't fully equipped with
543 * all relevant fields and must thus be sent out via nl_send_auto_complete()
544 * or supplemented as needed. \a tmpl must contain the attributes of the new
545 * neighbour set via \c rtnl_neigh_set_* functions.
546 *
547 * The following attributes must be set in the template:
548 * - Interface index (rtnl_neigh_set_ifindex())
549 * - State (rtnl_neigh_set_state())
550 * - Destination address (rtnl_neigh_set_dst())
551 * - Link layer address (rtnl_neigh_set_lladdr())
552 *
553 * @return 0 on success or a negative error code.
554 */
rtnl_neigh_build_add_request(struct rtnl_neigh * tmpl,int flags,struct nl_msg ** result)555 int rtnl_neigh_build_add_request(struct rtnl_neigh *tmpl, int flags,
556 struct nl_msg **result)
557 {
558 return build_neigh_msg(tmpl, RTM_NEWNEIGH, flags, result);
559 }
560
561 /**
562 * Add a new neighbour
563 * @arg sk Netlink socket.
564 * @arg tmpl template with requested changes
565 * @arg flags additional netlink message flags
566 *
567 * Builds a netlink message by calling rtnl_neigh_build_add_request(),
568 * sends the request to the kernel and waits for the next ACK to be
569 * received and thus blocks until the request has been fullfilled.
570 *
571 * The following attributes must be set in the template:
572 * - Interface index (rtnl_neigh_set_ifindex())
573 * - State (rtnl_neigh_set_state())
574 * - Destination address (rtnl_neigh_set_dst())
575 * - Link layer address (rtnl_neigh_set_lladdr())
576 *
577 * @return 0 on sucess or a negative error if an error occured.
578 */
rtnl_neigh_add(struct nl_sock * sk,struct rtnl_neigh * tmpl,int flags)579 int rtnl_neigh_add(struct nl_sock *sk, struct rtnl_neigh *tmpl, int flags)
580 {
581 int err;
582 struct nl_msg *msg;
583
584 if ((err = rtnl_neigh_build_add_request(tmpl, flags, &msg)) < 0)
585 return err;
586
587 err = nl_send_auto_complete(sk, msg);
588 nlmsg_free(msg);
589 if (err < 0)
590 return err;
591
592 return wait_for_ack(sk);
593 }
594
595 /** @} */
596
597 /**
598 * @name Neighbour Deletion
599 * @{
600 */
601
602 /**
603 * Build a netlink request message to delete a neighbour
604 * @arg neigh neighbour to delete
605 * @arg flags additional netlink message flags
606 * @arg result Pointer to store resulting message.
607 *
608 * Builds a new netlink message requesting a deletion of a neighbour.
609 * The netlink message header isn't fully equipped with all relevant
610 * fields and must thus be sent out via nl_send_auto_complete()
611 * or supplemented as needed. \a neigh must point to an existing
612 * neighbour.
613 *
614 * @return 0 on success or a negative error code.
615 */
rtnl_neigh_build_delete_request(struct rtnl_neigh * neigh,int flags,struct nl_msg ** result)616 int rtnl_neigh_build_delete_request(struct rtnl_neigh *neigh, int flags,
617 struct nl_msg **result)
618 {
619 return build_neigh_msg(neigh, RTM_DELNEIGH, flags, result);
620 }
621
622 /**
623 * Delete a neighbour
624 * @arg sk Netlink socket.
625 * @arg neigh neighbour to delete
626 * @arg flags additional netlink message flags
627 *
628 * Builds a netlink message by calling rtnl_neigh_build_delete_request(),
629 * sends the request to the kernel and waits for the next ACK to be
630 * received and thus blocks until the request has been fullfilled.
631 *
632 * @return 0 on sucess or a negative error if an error occured.
633 */
rtnl_neigh_delete(struct nl_sock * sk,struct rtnl_neigh * neigh,int flags)634 int rtnl_neigh_delete(struct nl_sock *sk, struct rtnl_neigh *neigh,
635 int flags)
636 {
637 struct nl_msg *msg;
638 int err;
639
640 if ((err = rtnl_neigh_build_delete_request(neigh, flags, &msg)) < 0)
641 return err;
642
643 err = nl_send_auto_complete(sk, msg);
644 nlmsg_free(msg);
645 if (err < 0)
646 return err;
647
648 return wait_for_ack(sk);
649 }
650
651 /** @} */
652
653 /**
654 * @name Neighbour States Translations
655 * @{
656 */
657
658 static struct trans_tbl neigh_states[] = {
659 __ADD(NUD_INCOMPLETE, incomplete)
660 __ADD(NUD_REACHABLE, reachable)
661 __ADD(NUD_STALE, stale)
662 __ADD(NUD_DELAY, delay)
663 __ADD(NUD_PROBE, probe)
664 __ADD(NUD_FAILED, failed)
665 __ADD(NUD_NOARP, norarp)
666 __ADD(NUD_PERMANENT, permanent)
667 };
668
rtnl_neigh_state2str(int state,char * buf,size_t len)669 char * rtnl_neigh_state2str(int state, char *buf, size_t len)
670 {
671 return __flags2str(state, buf, len, neigh_states,
672 ARRAY_SIZE(neigh_states));
673 }
674
rtnl_neigh_str2state(const char * name)675 int rtnl_neigh_str2state(const char *name)
676 {
677 return __str2type(name, neigh_states, ARRAY_SIZE(neigh_states));
678 }
679
680 /** @} */
681
682 /**
683 * @name Neighbour Flags Translations
684 * @{
685 */
686
687 static struct trans_tbl neigh_flags[] = {
688 __ADD(NTF_PROXY, proxy)
689 __ADD(NTF_ROUTER, router)
690 };
691
rtnl_neigh_flags2str(int flags,char * buf,size_t len)692 char * rtnl_neigh_flags2str(int flags, char *buf, size_t len)
693 {
694 return __flags2str(flags, buf, len, neigh_flags,
695 ARRAY_SIZE(neigh_flags));
696 }
697
rtnl_neigh_str2flag(const char * name)698 int rtnl_neigh_str2flag(const char *name)
699 {
700 return __str2type(name, neigh_flags, ARRAY_SIZE(neigh_flags));
701 }
702
703 /** @} */
704
705 /**
706 * @name Attributes
707 * @{
708 */
709
rtnl_neigh_set_state(struct rtnl_neigh * neigh,int state)710 void rtnl_neigh_set_state(struct rtnl_neigh *neigh, int state)
711 {
712 neigh->n_state_mask |= state;
713 neigh->n_state |= state;
714 neigh->ce_mask |= NEIGH_ATTR_STATE;
715 }
716
rtnl_neigh_get_state(struct rtnl_neigh * neigh)717 int rtnl_neigh_get_state(struct rtnl_neigh *neigh)
718 {
719 if (neigh->ce_mask & NEIGH_ATTR_STATE)
720 return neigh->n_state;
721 else
722 return -1;
723 }
724
rtnl_neigh_unset_state(struct rtnl_neigh * neigh,int state)725 void rtnl_neigh_unset_state(struct rtnl_neigh *neigh, int state)
726 {
727 neigh->n_state_mask |= state;
728 neigh->n_state &= ~state;
729 neigh->ce_mask |= NEIGH_ATTR_STATE;
730 }
731
rtnl_neigh_set_flags(struct rtnl_neigh * neigh,unsigned int flags)732 void rtnl_neigh_set_flags(struct rtnl_neigh *neigh, unsigned int flags)
733 {
734 neigh->n_flag_mask |= flags;
735 neigh->n_flags |= flags;
736 neigh->ce_mask |= NEIGH_ATTR_FLAGS;
737 }
738
rtnl_neigh_get_flags(struct rtnl_neigh * neigh)739 unsigned int rtnl_neigh_get_flags(struct rtnl_neigh *neigh)
740 {
741 return neigh->n_flags;
742 }
743
rtnl_neigh_unset_flags(struct rtnl_neigh * neigh,unsigned int flags)744 void rtnl_neigh_unset_flags(struct rtnl_neigh *neigh, unsigned int flags)
745 {
746 neigh->n_flag_mask |= flags;
747 neigh->n_flags &= ~flags;
748 neigh->ce_mask |= NEIGH_ATTR_FLAGS;
749 }
750
rtnl_neigh_set_ifindex(struct rtnl_neigh * neigh,int ifindex)751 void rtnl_neigh_set_ifindex(struct rtnl_neigh *neigh, int ifindex)
752 {
753 neigh->n_ifindex = ifindex;
754 neigh->ce_mask |= NEIGH_ATTR_IFINDEX;
755 }
756
rtnl_neigh_get_ifindex(struct rtnl_neigh * neigh)757 int rtnl_neigh_get_ifindex(struct rtnl_neigh *neigh)
758 {
759 return neigh->n_ifindex;
760 }
761
__assign_addr(struct rtnl_neigh * neigh,struct nl_addr ** pos,struct nl_addr * new,int flag,int nocheck)762 static inline int __assign_addr(struct rtnl_neigh *neigh, struct nl_addr **pos,
763 struct nl_addr *new, int flag, int nocheck)
764 {
765 if (!nocheck) {
766 if (neigh->ce_mask & NEIGH_ATTR_FAMILY) {
767 if (new->a_family != neigh->n_family)
768 return -NLE_AF_MISMATCH;
769 } else {
770 neigh->n_family = new->a_family;
771 neigh->ce_mask |= NEIGH_ATTR_FAMILY;
772 }
773 }
774
775 if (*pos)
776 nl_addr_put(*pos);
777
778 nl_addr_get(new);
779 *pos = new;
780
781 neigh->ce_mask |= flag;
782
783 return 0;
784 }
785
rtnl_neigh_set_lladdr(struct rtnl_neigh * neigh,struct nl_addr * addr)786 void rtnl_neigh_set_lladdr(struct rtnl_neigh *neigh, struct nl_addr *addr)
787 {
788 __assign_addr(neigh, &neigh->n_lladdr, addr, NEIGH_ATTR_LLADDR, 1);
789 }
790
rtnl_neigh_get_lladdr(struct rtnl_neigh * neigh)791 struct nl_addr *rtnl_neigh_get_lladdr(struct rtnl_neigh *neigh)
792 {
793 if (neigh->ce_mask & NEIGH_ATTR_LLADDR)
794 return neigh->n_lladdr;
795 else
796 return NULL;
797 }
798
rtnl_neigh_set_dst(struct rtnl_neigh * neigh,struct nl_addr * addr)799 int rtnl_neigh_set_dst(struct rtnl_neigh *neigh, struct nl_addr *addr)
800 {
801 return __assign_addr(neigh, &neigh->n_dst, addr,
802 NEIGH_ATTR_DST, 0);
803 }
804
rtnl_neigh_get_dst(struct rtnl_neigh * neigh)805 struct nl_addr *rtnl_neigh_get_dst(struct rtnl_neigh *neigh)
806 {
807 if (neigh->ce_mask & NEIGH_ATTR_DST)
808 return neigh->n_dst;
809 else
810 return NULL;
811 }
812
rtnl_neigh_set_family(struct rtnl_neigh * neigh,int family)813 void rtnl_neigh_set_family(struct rtnl_neigh *neigh, int family)
814 {
815 neigh->n_family = family;
816 neigh->ce_mask |= NEIGH_ATTR_FAMILY;
817 }
818
rtnl_neigh_get_family(struct rtnl_neigh * neigh)819 int rtnl_neigh_get_family(struct rtnl_neigh *neigh)
820 {
821 return neigh->n_family;
822 }
823
rtnl_neigh_set_type(struct rtnl_neigh * neigh,int type)824 void rtnl_neigh_set_type(struct rtnl_neigh *neigh, int type)
825 {
826 neigh->n_type = type;
827 neigh->ce_mask = NEIGH_ATTR_TYPE;
828 }
829
rtnl_neigh_get_type(struct rtnl_neigh * neigh)830 int rtnl_neigh_get_type(struct rtnl_neigh *neigh)
831 {
832 if (neigh->ce_mask & NEIGH_ATTR_TYPE)
833 return neigh->n_type;
834 else
835 return -1;
836 }
837
838 /** @} */
839
840 static struct nl_object_ops neigh_obj_ops = {
841 .oo_name = "route/neigh",
842 .oo_size = sizeof(struct rtnl_neigh),
843 .oo_free_data = neigh_free_data,
844 .oo_clone = neigh_clone,
845 .oo_dump = {
846 [NL_DUMP_LINE] = neigh_dump_line,
847 [NL_DUMP_DETAILS] = neigh_dump_details,
848 [NL_DUMP_STATS] = neigh_dump_stats,
849 [NL_DUMP_ENV] = neigh_dump_env,
850 },
851 .oo_compare = neigh_compare,
852 .oo_attrs2str = neigh_attrs2str,
853 .oo_id_attrs = (NEIGH_ATTR_IFINDEX | NEIGH_ATTR_DST | NEIGH_ATTR_FAMILY),
854 };
855
856 static struct nl_af_group neigh_groups[] = {
857 { AF_UNSPEC, RTNLGRP_NEIGH },
858 { END_OF_GROUP_LIST },
859 };
860
861 static struct nl_cache_ops rtnl_neigh_ops = {
862 .co_name = "route/neigh",
863 .co_hdrsize = sizeof(struct ndmsg),
864 .co_msgtypes = {
865 { RTM_NEWNEIGH, NL_ACT_NEW, "new" },
866 { RTM_DELNEIGH, NL_ACT_DEL, "del" },
867 { RTM_GETNEIGH, NL_ACT_GET, "get" },
868 END_OF_MSGTYPES_LIST,
869 },
870 .co_protocol = NETLINK_ROUTE,
871 .co_groups = neigh_groups,
872 .co_request_update = neigh_request_update,
873 .co_msg_parser = neigh_msg_parser,
874 .co_obj_ops = &neigh_obj_ops,
875 };
876
neigh_init(void)877 static void __init neigh_init(void)
878 {
879 nl_cache_mngt_register(&rtnl_neigh_ops);
880 }
881
neigh_exit(void)882 static void __exit neigh_exit(void)
883 {
884 nl_cache_mngt_unregister(&rtnl_neigh_ops);
885 }
886
887 /** @} */
888