00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150 #include <netlink-local.h>
00151 #include <netlink/netlink.h>
00152 #include <netlink/utils.h>
00153 #include <netlink/route/rtnl.h>
00154 #include <netlink/route/neighbour.h>
00155 #include <netlink/route/link.h>
00156
00157
00158 #define NEIGH_ATTR_FLAGS 0x01
00159 #define NEIGH_ATTR_STATE 0x02
00160 #define NEIGH_ATTR_LLADDR 0x04
00161 #define NEIGH_ATTR_DST 0x08
00162 #define NEIGH_ATTR_CACHEINFO 0x10
00163 #define NEIGH_ATTR_IFINDEX 0x20
00164 #define NEIGH_ATTR_FAMILY 0x40
00165 #define NEIGH_ATTR_TYPE 0x80
00166 #define NEIGH_ATTR_PROBES 0x100
00167
00168 static struct nl_cache_ops rtnl_neigh_ops;
00169 static struct nl_object_ops neigh_obj_ops;
00170
00171
00172 static void neigh_free_data(struct nl_object *c)
00173 {
00174 struct rtnl_neigh *neigh = nl_object_priv(c);
00175
00176 if (!neigh)
00177 return;
00178
00179 nl_addr_put(neigh->n_lladdr);
00180 nl_addr_put(neigh->n_dst);
00181 }
00182
00183 static int neigh_clone(struct nl_object *_dst, struct nl_object *_src)
00184 {
00185 struct rtnl_neigh *dst = nl_object_priv(_dst);
00186 struct rtnl_neigh *src = nl_object_priv(_src);
00187
00188 if (src->n_lladdr)
00189 if (!(dst->n_lladdr = nl_addr_clone(src->n_lladdr)))
00190 goto errout;
00191
00192 if (src->n_dst)
00193 if (!(dst->n_dst = nl_addr_clone(src->n_dst)))
00194 goto errout;
00195
00196 return 0;
00197 errout:
00198 return nl_get_errno();
00199 }
00200
00201 static int neigh_compare(struct nl_object *_a, struct nl_object *_b,
00202 uint32_t attrs, int flags)
00203 {
00204 struct rtnl_neigh *a = (struct rtnl_neigh *) _a;
00205 struct rtnl_neigh *b = (struct rtnl_neigh *) _b;
00206 int diff = 0;
00207
00208 #define NEIGH_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, NEIGH_ATTR_##ATTR, a, b, EXPR)
00209
00210 diff |= NEIGH_DIFF(IFINDEX, a->n_ifindex != b->n_ifindex);
00211 diff |= NEIGH_DIFF(FAMILY, a->n_family != b->n_family);
00212 diff |= NEIGH_DIFF(TYPE, a->n_type != b->n_type);
00213 diff |= NEIGH_DIFF(LLADDR, nl_addr_cmp(a->n_lladdr, b->n_lladdr));
00214 diff |= NEIGH_DIFF(DST, nl_addr_cmp(a->n_dst, b->n_dst));
00215
00216 if (flags & LOOSE_FLAG_COMPARISON) {
00217 diff |= NEIGH_DIFF(STATE,
00218 (a->n_state ^ b->n_state) & b->n_state_mask);
00219 diff |= NEIGH_DIFF(FLAGS,
00220 (a->n_flags ^ b->n_flags) & b->n_flag_mask);
00221 } else {
00222 diff |= NEIGH_DIFF(STATE, a->n_state != b->n_state);
00223 diff |= NEIGH_DIFF(FLAGS, a->n_flags != b->n_flags);
00224 }
00225
00226 #undef NEIGH_DIFF
00227
00228 return diff;
00229 }
00230
00231 static struct trans_tbl neigh_attrs[] = {
00232 __ADD(NEIGH_ATTR_FLAGS, flags)
00233 __ADD(NEIGH_ATTR_STATE, state)
00234 __ADD(NEIGH_ATTR_LLADDR, lladdr)
00235 __ADD(NEIGH_ATTR_DST, dst)
00236 __ADD(NEIGH_ATTR_CACHEINFO, cacheinfo)
00237 __ADD(NEIGH_ATTR_IFINDEX, ifindex)
00238 __ADD(NEIGH_ATTR_FAMILY, family)
00239 __ADD(NEIGH_ATTR_TYPE, type)
00240 __ADD(NEIGH_ATTR_PROBES, probes)
00241 };
00242
00243 static char *neigh_attrs2str(int attrs, char *buf, size_t len)
00244 {
00245 return __flags2str(attrs, buf, len, neigh_attrs,
00246 ARRAY_SIZE(neigh_attrs));
00247 }
00248
00249 static struct nla_policy neigh_policy[NDA_MAX+1] = {
00250 [NDA_CACHEINFO] = { .minlen = sizeof(struct nda_cacheinfo) },
00251 [NDA_PROBES] = { .type = NLA_U32 },
00252 };
00253
00254 static int neigh_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
00255 struct nlmsghdr *n, struct nl_parser_param *pp)
00256 {
00257 struct rtnl_neigh *neigh;
00258 struct nlattr *tb[NDA_MAX + 1];
00259 struct ndmsg *nm;
00260 int err;
00261
00262 neigh = rtnl_neigh_alloc();
00263 if (!neigh) {
00264 err = nl_errno(ENOMEM);
00265 goto errout;
00266 }
00267
00268 neigh->ce_msgtype = n->nlmsg_type;
00269 nm = nlmsg_data(n);
00270
00271 err = nlmsg_parse(n, sizeof(*nm), tb, NDA_MAX, neigh_policy);
00272 if (err < 0)
00273 goto errout;
00274
00275 neigh->n_family = nm->ndm_family;
00276 neigh->n_ifindex = nm->ndm_ifindex;
00277 neigh->n_state = nm->ndm_state;
00278 neigh->n_flags = nm->ndm_flags;
00279 neigh->n_type = nm->ndm_type;
00280
00281 neigh->ce_mask |= (NEIGH_ATTR_FAMILY | NEIGH_ATTR_IFINDEX |
00282 NEIGH_ATTR_STATE | NEIGH_ATTR_FLAGS |
00283 NEIGH_ATTR_TYPE);
00284
00285 if (tb[NDA_LLADDR]) {
00286 neigh->n_lladdr = nla_get_addr(tb[NDA_LLADDR], AF_UNSPEC);
00287 if (!neigh->n_lladdr)
00288 goto errout;
00289 nl_addr_set_family(neigh->n_lladdr,
00290 nl_addr_guess_family(neigh->n_lladdr));
00291 neigh->ce_mask |= NEIGH_ATTR_LLADDR;
00292 }
00293
00294 if (tb[NDA_DST]) {
00295 neigh->n_dst = nla_get_addr(tb[NDA_DST], neigh->n_family);
00296 if (!neigh->n_dst)
00297 goto errout;
00298 neigh->ce_mask |= NEIGH_ATTR_DST;
00299 }
00300
00301 if (tb[NDA_CACHEINFO]) {
00302 struct nda_cacheinfo *ci = nla_data(tb[NDA_CACHEINFO]);
00303
00304 neigh->n_cacheinfo.nci_confirmed = ci->ndm_confirmed;
00305 neigh->n_cacheinfo.nci_used = ci->ndm_used;
00306 neigh->n_cacheinfo.nci_updated = ci->ndm_updated;
00307 neigh->n_cacheinfo.nci_refcnt = ci->ndm_refcnt;
00308
00309 neigh->ce_mask |= NEIGH_ATTR_CACHEINFO;
00310 }
00311
00312 if (tb[NDA_PROBES]) {
00313 neigh->n_probes = nla_get_u32(tb[NDA_PROBES]);
00314 neigh->ce_mask |= NEIGH_ATTR_PROBES;
00315 }
00316
00317 err = pp->pp_cb((struct nl_object *) neigh, pp);
00318 if (err < 0)
00319 goto errout;
00320
00321 err = P_ACCEPT;
00322
00323 errout:
00324 rtnl_neigh_put(neigh);
00325 return err;
00326 }
00327
00328 static int neigh_request_update(struct nl_cache *c, struct nl_handle *h)
00329 {
00330 return nl_rtgen_request(h, RTM_GETNEIGH, AF_UNSPEC, NLM_F_DUMP);
00331 }
00332
00333
00334 static int neigh_dump_brief(struct nl_object *a, struct nl_dump_params *p)
00335 {
00336 char dst[INET6_ADDRSTRLEN+5], lladdr[INET6_ADDRSTRLEN+5];
00337 struct rtnl_neigh *n = (struct rtnl_neigh *) a;
00338 struct nl_cache *link_cache;
00339 char state[128], flags[64];
00340
00341 link_cache = nl_cache_mngt_require("route/link");
00342
00343 dp_dump(p, "%s ", nl_addr2str(n->n_dst, dst, sizeof(dst)));
00344
00345 if (link_cache)
00346 dp_dump(p, "dev %s ",
00347 rtnl_link_i2name(link_cache, n->n_ifindex,
00348 state, sizeof(state)));
00349 else
00350 dp_dump(p, "dev %d ", n->n_ifindex);
00351
00352 if (n->ce_mask & NEIGH_ATTR_LLADDR)
00353 dp_dump(p, "lladdr %s ",
00354 nl_addr2str(n->n_lladdr, lladdr, sizeof(lladdr)));
00355
00356 rtnl_neigh_state2str(n->n_state, state, sizeof(state));
00357 rtnl_neigh_flags2str(n->n_flags, flags, sizeof(flags));
00358
00359 if (state[0])
00360 dp_dump(p, "<%s", state);
00361 if (flags[0])
00362 dp_dump(p, "%s%s", state[0] ? "," : "<", flags);
00363 if (state[0] || flags[0])
00364 dp_dump(p, ">");
00365 dp_dump(p, "\n");
00366
00367 return 1;
00368 }
00369
00370 static int neigh_dump_full(struct nl_object *a, struct nl_dump_params *p)
00371 {
00372 char rtn_type[32];
00373 struct rtnl_neigh *n = (struct rtnl_neigh *) a;
00374 int hz = nl_get_hz();
00375
00376 int line = neigh_dump_brief(a, p);
00377
00378 dp_dump_line(p, line++, " refcnt %u type %s confirmed %u used "
00379 "%u updated %u\n",
00380 n->n_cacheinfo.nci_refcnt,
00381 nl_rtntype2str(n->n_type, rtn_type, sizeof(rtn_type)),
00382 n->n_cacheinfo.nci_confirmed/hz,
00383 n->n_cacheinfo.nci_used/hz, n->n_cacheinfo.nci_updated/hz);
00384
00385 return line;
00386 }
00387
00388 static int neigh_dump_stats(struct nl_object *a, struct nl_dump_params *p)
00389 {
00390 return neigh_dump_full(a, p);
00391 }
00392
00393 static int neigh_dump_xml(struct nl_object *obj, struct nl_dump_params *p)
00394 {
00395 struct rtnl_neigh *neigh = (struct rtnl_neigh *) obj;
00396 char buf[128];
00397 int line = 0;
00398
00399 dp_dump_line(p, line++, "<neighbour>\n");
00400 dp_dump_line(p, line++, " <family>%s</family>\n",
00401 nl_af2str(neigh->n_family, buf, sizeof(buf)));
00402
00403 if (neigh->ce_mask & NEIGH_ATTR_LLADDR)
00404 dp_dump_line(p, line++, " <lladdr>%s</lladdr>\n",
00405 nl_addr2str(neigh->n_lladdr, buf, sizeof(buf)));
00406
00407 if (neigh->ce_mask & NEIGH_ATTR_DST)
00408 dp_dump_line(p, line++, " <dst>%s</dst>\n",
00409 nl_addr2str(neigh->n_dst, buf, sizeof(buf)));
00410
00411 if (neigh->ce_mask & NEIGH_ATTR_IFINDEX) {
00412 struct nl_cache *link_cache;
00413
00414 link_cache = nl_cache_mngt_require("route/link");
00415
00416 if (link_cache)
00417 dp_dump_line(p, line++, " <device>%s</device>\n",
00418 rtnl_link_i2name(link_cache,
00419 neigh->n_ifindex,
00420 buf, sizeof(buf)));
00421 else
00422 dp_dump_line(p, line++, " <device>%u</device>\n",
00423 neigh->n_ifindex);
00424 }
00425
00426 if (neigh->ce_mask & NEIGH_ATTR_PROBES)
00427 dp_dump_line(p, line++, " <probes>%u</probes>\n",
00428 neigh->n_probes);
00429
00430 if (neigh->ce_mask & NEIGH_ATTR_TYPE)
00431 dp_dump_line(p, line++, " <type>%s</type>\n",
00432 nl_rtntype2str(neigh->n_type, buf, sizeof(buf)));
00433
00434 rtnl_neigh_flags2str(neigh->n_flags, buf, sizeof(buf));
00435 if (buf[0])
00436 dp_dump_line(p, line++, " <flags>%s</flags>\n", buf);
00437
00438 rtnl_neigh_state2str(neigh->n_state, buf, sizeof(buf));
00439 if (buf[0])
00440 dp_dump_line(p, line++, " <state>%s</state>\n", buf);
00441
00442 dp_dump_line(p, line++, "</neighbour>\n");
00443
00444 #if 0
00445 struct rtnl_ncacheinfo n_cacheinfo;
00446 #endif
00447
00448 return line;
00449 }
00450
00451 static int neigh_dump_env(struct nl_object *obj, struct nl_dump_params *p)
00452 {
00453 struct rtnl_neigh *neigh = (struct rtnl_neigh *) obj;
00454 char buf[128];
00455 int line = 0;
00456
00457 dp_dump_line(p, line++, "NEIGH_FAMILY=%s\n",
00458 nl_af2str(neigh->n_family, buf, sizeof(buf)));
00459
00460 if (neigh->ce_mask & NEIGH_ATTR_LLADDR)
00461 dp_dump_line(p, line++, "NEIGHT_LLADDR=%s\n",
00462 nl_addr2str(neigh->n_lladdr, buf, sizeof(buf)));
00463
00464 if (neigh->ce_mask & NEIGH_ATTR_DST)
00465 dp_dump_line(p, line++, "NEIGH_DST=%s\n",
00466 nl_addr2str(neigh->n_dst, buf, sizeof(buf)));
00467
00468 if (neigh->ce_mask & NEIGH_ATTR_IFINDEX) {
00469 struct nl_cache *link_cache;
00470
00471 dp_dump_line(p, line++, "NEIGH_IFINDEX=%u\n",
00472 neigh->n_ifindex);
00473
00474 link_cache = nl_cache_mngt_require("route/link");
00475 if (link_cache)
00476 dp_dump_line(p, line++, "NEIGH_IFNAME=%s\n",
00477 rtnl_link_i2name(link_cache,
00478 neigh->n_ifindex,
00479 buf, sizeof(buf)));
00480 }
00481
00482 if (neigh->ce_mask & NEIGH_ATTR_PROBES)
00483 dp_dump_line(p, line++, "NEIGH_PROBES=%u\n",
00484 neigh->n_probes);
00485
00486 if (neigh->ce_mask & NEIGH_ATTR_TYPE)
00487 dp_dump_line(p, line++, "NEIGH_TYPE=%s\n",
00488 nl_rtntype2str(neigh->n_type, buf, sizeof(buf)));
00489
00490 rtnl_neigh_flags2str(neigh->n_flags, buf, sizeof(buf));
00491 if (buf[0])
00492 dp_dump_line(p, line++, "NEIGH_FLAGS=%s\n", buf);
00493
00494 rtnl_neigh_state2str(neigh->n_state, buf, sizeof(buf));
00495 if (buf[0])
00496 dp_dump_line(p, line++, "NEIGH_STATE=%s\n", buf);
00497
00498 return line;
00499 }
00500
00501
00502
00503
00504
00505
00506 struct rtnl_neigh *rtnl_neigh_alloc(void)
00507 {
00508 return (struct rtnl_neigh *) nl_object_alloc(&neigh_obj_ops);
00509 }
00510
00511 void rtnl_neigh_put(struct rtnl_neigh *neigh)
00512 {
00513 nl_object_put((struct nl_object *) neigh);
00514 }
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534 struct nl_cache *rtnl_neigh_alloc_cache(struct nl_handle *handle)
00535 {
00536 struct nl_cache *cache;
00537
00538 cache = nl_cache_alloc(&rtnl_neigh_ops);
00539 if (cache == NULL)
00540 return NULL;
00541
00542 if (handle && nl_cache_refill(handle, cache) < 0) {
00543 nl_cache_free(cache);
00544 return NULL;
00545 }
00546
00547 NL_DBG(2, "Returning new cache %p\n", cache);
00548
00549 return cache;
00550 }
00551
00552
00553
00554
00555
00556
00557
00558
00559 struct rtnl_neigh * rtnl_neigh_get(struct nl_cache *cache, int ifindex,
00560 struct nl_addr *dst)
00561 {
00562 struct rtnl_neigh *neigh;
00563
00564 nl_list_for_each_entry(neigh, &cache->c_items, ce_list) {
00565 if (neigh->n_ifindex == ifindex &&
00566 !nl_addr_cmp(neigh->n_dst, dst)) {
00567 nl_object_get((struct nl_object *) neigh);
00568 return neigh;
00569 }
00570 }
00571
00572 return NULL;
00573 }
00574
00575
00576
00577
00578
00579
00580
00581
00582 static struct nl_msg * build_neigh_msg(struct rtnl_neigh *tmpl, int cmd,
00583 int flags)
00584 {
00585 struct nl_msg *msg;
00586 struct ndmsg nhdr = {
00587 .ndm_ifindex = tmpl->n_ifindex,
00588 .ndm_family = nl_addr_get_family(tmpl->n_dst),
00589 .ndm_state = NUD_PERMANENT,
00590 };
00591
00592 if (tmpl->ce_mask & NEIGH_ATTR_STATE)
00593 nhdr.ndm_state = tmpl->n_state;
00594
00595 msg = nlmsg_alloc_simple(cmd, flags);
00596 if (!msg)
00597 return NULL;
00598
00599 if (nlmsg_append(msg, &nhdr, sizeof(nhdr), NLMSG_ALIGNTO) < 0)
00600 goto nla_put_failure;
00601
00602 NLA_PUT_ADDR(msg, NDA_DST, tmpl->n_dst);
00603
00604 if (tmpl->ce_mask & NEIGH_ATTR_LLADDR)
00605 NLA_PUT_ADDR(msg, NDA_LLADDR, tmpl->n_lladdr);
00606
00607 return msg;
00608
00609 nla_put_failure:
00610 nlmsg_free(msg);
00611 return NULL;
00612 }
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633 struct nl_msg * rtnl_neigh_build_add_request(struct rtnl_neigh *tmpl, int flags)
00634 {
00635 return build_neigh_msg(tmpl, RTM_NEWNEIGH, NLM_F_CREATE | flags);
00636 }
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656 int rtnl_neigh_add(struct nl_handle *handle, struct rtnl_neigh *tmpl, int flags)
00657 {
00658 int err;
00659 struct nl_msg *msg;
00660
00661 msg = rtnl_neigh_build_add_request(tmpl, flags);
00662 if (!msg)
00663 return nl_errno(ENOMEM);
00664
00665 err = nl_send_auto_complete(handle, msg);
00666 if (err < 0)
00667 return err;
00668
00669 nlmsg_free(msg);
00670 return nl_wait_for_ack(handle);
00671 }
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693 struct nl_msg *rtnl_neigh_build_delete_request(struct rtnl_neigh *neigh,
00694 int flags)
00695 {
00696 return build_neigh_msg(neigh, RTM_DELNEIGH, flags);
00697 }
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711 int rtnl_neigh_delete(struct nl_handle *handle, struct rtnl_neigh *neigh,
00712 int flags)
00713 {
00714 int err;
00715 struct nl_msg *msg;
00716
00717 msg = rtnl_neigh_build_delete_request(neigh, flags);
00718 if (!msg)
00719 return nl_errno(ENOMEM);
00720
00721 err = nl_send_auto_complete(handle, msg);
00722 if (err < 0)
00723 return err;
00724
00725 nlmsg_free(msg);
00726 return nl_wait_for_ack(handle);
00727 }
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750 struct nl_msg *rtnl_neigh_build_change_request(struct rtnl_neigh *neigh,
00751 int flags)
00752 {
00753 return build_neigh_msg(neigh, RTM_NEWNEIGH, NLM_F_REPLACE | flags);
00754 }
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770 int rtnl_neigh_change(struct nl_handle *handle, struct rtnl_neigh *neigh,
00771 int flags)
00772 {
00773 int err;
00774 struct nl_msg *msg;
00775
00776 msg = rtnl_neigh_build_change_request(neigh, flags);
00777 if (!msg)
00778 return nl_errno(ENOMEM);
00779
00780 err = nl_send_auto_complete(handle, msg);
00781 if (err < 0)
00782 return err;
00783
00784 nlmsg_free(msg);
00785 return nl_wait_for_ack(handle);
00786 }
00787
00788
00789
00790
00791
00792
00793
00794
00795 static struct trans_tbl neigh_states[] = {
00796 __ADD(NUD_INCOMPLETE, incomplete)
00797 __ADD(NUD_REACHABLE, reachable)
00798 __ADD(NUD_STALE, stale)
00799 __ADD(NUD_DELAY, delay)
00800 __ADD(NUD_PROBE, probe)
00801 __ADD(NUD_FAILED, failed)
00802 __ADD(NUD_NOARP, norarp)
00803 __ADD(NUD_PERMANENT, permanent)
00804 };
00805
00806 char * rtnl_neigh_state2str(int state, char *buf, size_t len)
00807 {
00808 return __flags2str(state, buf, len, neigh_states,
00809 ARRAY_SIZE(neigh_states));
00810 }
00811
00812 int rtnl_neigh_str2state(const char *name)
00813 {
00814 return __str2type(name, neigh_states, ARRAY_SIZE(neigh_states));
00815 }
00816
00817
00818
00819
00820
00821
00822
00823
00824 static struct trans_tbl neigh_flags[] = {
00825 __ADD(NTF_PROXY, proxy)
00826 __ADD(NTF_ROUTER, router)
00827 };
00828
00829 char * rtnl_neigh_flags2str(int flags, char *buf, size_t len)
00830 {
00831 return __flags2str(flags, buf, len, neigh_flags,
00832 ARRAY_SIZE(neigh_flags));
00833 }
00834
00835 int rtnl_neigh_str2flag(const char *name)
00836 {
00837 return __str2type(name, neigh_flags, ARRAY_SIZE(neigh_flags));
00838 }
00839
00840
00841
00842
00843
00844
00845
00846
00847 void rtnl_neigh_set_state(struct rtnl_neigh *neigh, int state)
00848 {
00849 neigh->n_state_mask |= state;
00850 neigh->n_state |= state;
00851 neigh->ce_mask |= NEIGH_ATTR_STATE;
00852 }
00853
00854 int rtnl_neigh_get_state(struct rtnl_neigh *neigh)
00855 {
00856 if (neigh->ce_mask & NEIGH_ATTR_STATE)
00857 return neigh->n_state;
00858 else
00859 return -1;
00860 }
00861
00862 void rtnl_neigh_unset_state(struct rtnl_neigh *neigh, int state)
00863 {
00864 neigh->n_state_mask |= state;
00865 neigh->n_state &= ~state;
00866 neigh->ce_mask |= NEIGH_ATTR_STATE;
00867 }
00868
00869 void rtnl_neigh_set_flags(struct rtnl_neigh *neigh, unsigned int flags)
00870 {
00871 neigh->n_flag_mask |= flags;
00872 neigh->n_flags |= flags;
00873 neigh->ce_mask |= NEIGH_ATTR_FLAGS;
00874 }
00875
00876 unsigned int rtnl_neigh_get_flags(struct rtnl_neigh *neigh)
00877 {
00878 return neigh->n_flags;
00879 }
00880
00881 void rtnl_neigh_unset_flags(struct rtnl_neigh *neigh, unsigned int flags)
00882 {
00883 neigh->n_flag_mask |= flags;
00884 neigh->n_flags &= ~flags;
00885 neigh->ce_mask |= NEIGH_ATTR_FLAGS;
00886 }
00887
00888 void rtnl_neigh_set_ifindex(struct rtnl_neigh *neigh, int ifindex)
00889 {
00890 neigh->n_ifindex = ifindex;
00891 neigh->ce_mask |= NEIGH_ATTR_IFINDEX;
00892 }
00893
00894 int rtnl_neigh_get_ifindex(struct rtnl_neigh *neigh)
00895 {
00896 if (neigh->ce_mask & NEIGH_ATTR_IFINDEX)
00897 return neigh->n_ifindex;
00898 else
00899 return RTNL_LINK_NOT_FOUND;
00900 }
00901
00902 static inline int __assign_addr(struct rtnl_neigh *neigh, struct nl_addr **pos,
00903 struct nl_addr *new, int flag, int nocheck)
00904 {
00905 if (!nocheck) {
00906 if (neigh->ce_mask & NEIGH_ATTR_FAMILY) {
00907 if (new->a_family != neigh->n_family)
00908 return nl_error(EINVAL,
00909 "Address family mismatch");
00910 } else {
00911 neigh->n_family = new->a_family;
00912 neigh->ce_mask |= NEIGH_ATTR_FAMILY;
00913 }
00914 }
00915
00916 if (*pos)
00917 nl_addr_put(*pos);
00918
00919 nl_addr_get(new);
00920 *pos = new;
00921
00922 neigh->ce_mask |= flag;
00923
00924 return 0;
00925 }
00926
00927 void rtnl_neigh_set_lladdr(struct rtnl_neigh *neigh, struct nl_addr *addr)
00928 {
00929 __assign_addr(neigh, &neigh->n_lladdr, addr, NEIGH_ATTR_LLADDR, 1);
00930 }
00931
00932 struct nl_addr *rtnl_neigh_get_lladdr(struct rtnl_neigh *neigh)
00933 {
00934 if (neigh->ce_mask & NEIGH_ATTR_LLADDR)
00935 return neigh->n_lladdr;
00936 else
00937 return NULL;
00938 }
00939
00940 int rtnl_neigh_set_dst(struct rtnl_neigh *neigh, struct nl_addr *addr)
00941 {
00942 return __assign_addr(neigh, &neigh->n_dst, addr,
00943 NEIGH_ATTR_DST, 0);
00944 }
00945
00946 struct nl_addr *rtnl_neigh_get_dst(struct rtnl_neigh *neigh)
00947 {
00948 if (neigh->ce_mask & NEIGH_ATTR_DST)
00949 return neigh->n_dst;
00950 else
00951 return NULL;
00952 }
00953
00954 void rtnl_neigh_set_family(struct rtnl_neigh *neigh, int family)
00955 {
00956 neigh->n_family = family;
00957 neigh->ce_mask |= NEIGH_ATTR_FAMILY;
00958 }
00959
00960 void rtnl_neigh_set_type(struct rtnl_neigh *neigh, int type)
00961 {
00962 neigh->n_type = type;
00963 neigh->ce_mask = NEIGH_ATTR_TYPE;
00964 }
00965
00966 int rtnl_neigh_get_type(struct rtnl_neigh *neigh)
00967 {
00968 if (neigh->ce_mask & NEIGH_ATTR_TYPE)
00969 return neigh->n_type;
00970 else
00971 return -1;
00972 }
00973
00974
00975
00976 static struct nl_object_ops neigh_obj_ops = {
00977 .oo_name = "route/neigh",
00978 .oo_size = sizeof(struct rtnl_neigh),
00979 .oo_free_data = neigh_free_data,
00980 .oo_clone = neigh_clone,
00981 .oo_dump[NL_DUMP_BRIEF] = neigh_dump_brief,
00982 .oo_dump[NL_DUMP_FULL] = neigh_dump_full,
00983 .oo_dump[NL_DUMP_STATS] = neigh_dump_stats,
00984 .oo_dump[NL_DUMP_XML] = neigh_dump_xml,
00985 .oo_dump[NL_DUMP_ENV] = neigh_dump_env,
00986 .oo_compare = neigh_compare,
00987 .oo_attrs2str = neigh_attrs2str,
00988 .oo_id_attrs = (NEIGH_ATTR_DST | NEIGH_ATTR_FAMILY),
00989 };
00990
00991 static struct nl_af_group neigh_groups[] = {
00992 { AF_UNSPEC, RTNLGRP_NEIGH },
00993 { END_OF_GROUP_LIST },
00994 };
00995
00996 static struct nl_cache_ops rtnl_neigh_ops = {
00997 .co_name = "route/neigh",
00998 .co_hdrsize = sizeof(struct ndmsg),
00999 .co_msgtypes = {
01000 { RTM_NEWNEIGH, NL_ACT_NEW, "new" },
01001 { RTM_DELNEIGH, NL_ACT_DEL, "del" },
01002 { RTM_GETNEIGH, NL_ACT_GET, "get" },
01003 END_OF_MSGTYPES_LIST,
01004 },
01005 .co_protocol = NETLINK_ROUTE,
01006 .co_groups = neigh_groups,
01007 .co_request_update = neigh_request_update,
01008 .co_msg_parser = neigh_msg_parser,
01009 .co_obj_ops = &neigh_obj_ops,
01010 };
01011
01012 static void __init neigh_init(void)
01013 {
01014 nl_cache_mngt_register(&rtnl_neigh_ops);
01015 }
01016
01017 static void __exit neigh_exit(void)
01018 {
01019 nl_cache_mngt_unregister(&rtnl_neigh_ops);
01020 }
01021
01022