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 #define _GNU_SOURCE 1
00030
00031 #include <sys/types.h>
00032 #include <unistd.h>
00033 #include <nic.h>
00034 #include <net/if.h>
00035 #include <net/if_arp.h>
00036 #include <arpa/inet.h>
00037 #include <sys/stat.h>
00038 #include <sys/syslog.h>
00039 #include <malloc.h>
00040 #include <stdio.h>
00041 #include <stdlib.h>
00042 #include <stdarg.h>
00043 #include <search.h>
00044 #include <time.h>
00045 #include <errno.h>
00046
00047 #include <libdhcp.h>
00048
00049
00050
00051 #include <netlink/netlink.h>
00052 #include <netlink/netlink-kernel.h>
00053 #include <netlink/rtnetlink-kernel.h>
00054 #include <netlink/msg.h>
00055 #include <netlink/attr.h>
00056 #include <netlink/utils.h>
00057 #include <netlink/addr.h>
00058 #include <netlink/route/rtnl.h>
00059 #include <netlink/route/link.h>
00060 #include <netlink/route/addr.h>
00061 #include <netlink/route/route.h>
00062 extern int nl_get_errno(void);
00063
00064 #define eprintf(level, fmt, arg...) ({if (nh && nh->eh) (nh->eh)(nh, (level), (fmt), ##arg ); })
00065
00066
00067
00068
00069 struct nlh_s
00070 {
00071 struct nl_handle *nl;
00072
00073 void *nic_name_tree;
00074 void *nic_index_tree;
00075 void *nic_foreach_arg;
00076
00077 void *nic_addr_tree;
00078 void *nic_addr_foreach_arg;
00079
00080 void *nic_route_tree;
00081 void *nic_route_foreach_arg;
00082
00083 int ll;
00084 NIC_Error_Handler_t eh;
00085 NIC_VA_Error_Handler_t va_eh;
00086 void *va_eh_arg;
00087 };
00088
00089 NLH_t nic_open(NIC_Error_Handler_t eh)
00090 {
00091 NLH_t nh;
00092
00093 if (!(nh = calloc(1, sizeof(struct nlh_s))))
00094 goto nic_open_fail;
00095
00096 if (eh) {
00097 nh->ll = NIC_ERR;
00098 nh->eh = eh;
00099 }
00100 if (!(nh->nl = nl_handle_alloc())) {
00101 eprintf(NIC_FATAL, "cannot allocate NIC library handle: %m" );
00102 goto nic_open_fail;
00103 }
00104
00105 if (nl_connect(nh->nl, NETLINK_ROUTE) < 0 ) {
00106 eprintf(NIC_FATAL, "cannot connect netlink socket: %m" );
00107 goto nic_open_fail;
00108 }
00109
00110 return nh;
00111
00112 nic_open_fail:
00113 if (nh) {
00114 if (nh->nl) {
00115 nl_handle_destroy(nh->nl);
00116 nh->nl = NULL;
00117 }
00118 free(nh);
00119 }
00120 return NULL;
00121 }
00122
00123 static void tdestroy_nil(void *n) {}
00124
00125 void nic_close(struct nlh_s **nhp)
00126 {
00127 struct nlh_s *nh;
00128
00129 if (!nhp || !*nhp)
00130 return;
00131 nh = *nhp;
00132
00133 if (nh->nl) {
00134 nl_close(nh->nl);
00135 nl_handle_destroy(nh->nl);
00136 nh->nl = NULL;
00137 }
00138
00139 if (nh->nic_name_tree) {
00140 tdestroy(nh->nic_name_tree, free);
00141 if (nh->nic_index_tree)
00142 tdestroy(nh->nic_index_tree, tdestroy_nil);
00143 nh->nic_name_tree = 0;
00144 nh->nic_index_tree = 0;
00145 } else if (nh->nic_index_tree) {
00146 tdestroy(nh->nic_index_tree, free);
00147 if (nh->nic_name_tree)
00148 tdestroy(nh->nic_name_tree, tdestroy_nil);
00149 nh->nic_name_tree = 0;
00150 nh->nic_index_tree = 0;
00151 }
00152
00153 if (nh->nic_addr_tree) {
00154 tdestroy(nh->nic_addr_tree, nic_addr_free);
00155 nh->nic_addr_tree = 0;
00156 }
00157
00158 if (nh->nic_route_tree)
00159 {
00160 tdestroy(nh->nic_route_tree, nic_route_free);
00161 nh->nic_route_tree = 0;
00162 }
00163
00164 free(nh);
00165 *nhp = NULL;
00166 }
00167
00168
00169
00170
00171 void nic_sys_logger( NLH_t nh, NIC_Error_Level_t el, char *fmt, ... )
00172 {
00173 if ( (nh == 0L) || ( el > nh->ll ) )
00174 return;
00175 va_list va;
00176
00177 va_start(va, fmt);
00178
00179 if( nh->va_eh )
00180 nh->va_eh ( nh->va_eh_arg, el, fmt, va );
00181 else
00182 vsyslog( el, fmt, va );
00183
00184 va_end(va);
00185
00186 if ( el == LOG_FATAL )
00187 nic_close(&nh);
00188 }
00189
00190 void nic_stderr_logger( NLH_t nh, NIC_Error_Level_t el, char *fmt, ... )
00191 {
00192 if ( (nh == 0L) || ( el > nh->ll ) )
00193 return;
00194
00195 va_list va;
00196
00197 va_start(va, fmt);
00198 if( nh->va_eh )
00199 nh->va_eh ( nh->va_eh_arg, el, fmt, va );
00200 else
00201 {
00202 vfprintf(stderr, fmt, va);
00203 fprintf(stderr,"\n");
00204 fflush(stderr);
00205 }
00206 va_end(va);
00207 }
00208
00209 NIC_Res_t nic_set_loglevel( NLH_t nh, NIC_Error_Level_t ll )
00210 {
00211 if ( nh == 0 )
00212 return NIC_FAIL;
00213
00214 nh -> ll = ll;
00215
00216 return NIC_OK;
00217 }
00218
00219 extern
00220 void nic_set_logger(NLH_t nh, NIC_Error_Handler_t eh)
00221 {
00222 nh -> eh = eh;
00223 }
00224
00225 extern
00226 void nic_set_va_logger(NLH_t nh, NIC_VA_Error_Handler_t va_eh, void *va_eh_arg)
00227 {
00228 nh -> va_eh = va_eh;
00229 nh -> eh = nic_stderr_logger;
00230 }
00231
00232 #ifndef IFQDISCSIZ
00233 #define IFQDISCSIZ 32
00234 #endif
00235
00236 struct nic_s
00237 {
00238 NLH_t nh;
00239
00240 struct nic_link
00241 {
00242 struct nlmsghdr hdr;
00243 struct ifinfomsg ifi;
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257 ip_addr_t addr;
00258
00259 ip_addr_t broadcast;
00260
00261 char name[IFNAMSIZ];
00262 char qdisc[IFQDISCSIZ];
00263 uint32_t mtu;
00264 uint32_t link;
00265 uint32_t txqlen;
00266 uint32_t weight;
00267 uint32_t master;
00268 uint32_t cost;
00269 uint32_t priority;
00270 uint32_t protinfo;
00271 struct rtnl_link_stats stats;
00272 struct rtnl_link_ifmap ifmap;
00273
00274 enum nic_mask_e
00275 {
00276 NIC_LINK_ADDRESS = 1,
00277 NIC_LINK_BROADCAST = 2,
00278 NIC_LINK_NAME = 4,
00279 NIC_LINK_MTU = 8,
00280 NIC_LINK_LINK = 16,
00281 NIC_LINK_QDISC = 32,
00282 NIC_LINK_STATS = 64,
00283 NIC_LINK_COST = 128,
00284 NIC_LINK_PRIORITY = 256,
00285 NIC_LINK_MASTER = 512,
00286 NIC_LINK_WIRELESS =1024,
00287 NIC_LINK_PROTINFO =2048,
00288 NIC_LINK_TXQLEN =4096,
00289 NIC_LINK_IFMAP =8192,
00290 NIC_LINK_WEIGHT =16384,
00291 NIC_LINK_OPERSTATE =32768,
00292 NIC_LINK_LINKMODE =65536
00293 } have, change;
00294 } l;
00295 };
00296
00297 static struct nla_policy nic_link_policy[IFLA_MAX+1] = {
00298 [IFLA_IFNAME] = { .type = NLA_STRING,
00299 .maxlen = IFNAMSIZ },
00300 [IFLA_MTU] = { .type = NLA_U32 },
00301 [IFLA_TXQLEN] = { .type = NLA_U32 },
00302 [IFLA_LINK] = { .type = NLA_U32 },
00303 [IFLA_WEIGHT] = { .type = NLA_U32 },
00304 [IFLA_COST] = { .type = NLA_U32 },
00305 [IFLA_PRIORITY] = { .type = NLA_U32 },
00306 [IFLA_PROTINFO] = { .type = NLA_U32 },
00307 [IFLA_MASTER] = { .type = NLA_U32 },
00308 [IFLA_QDISC] = { .type = NLA_STRING,
00309 .maxlen = IFQDISCSIZ },
00310 [IFLA_STATS] = { .minlen = sizeof(struct rtnl_link_stats) },
00311 [IFLA_MAP] = { .minlen = sizeof(struct rtnl_link_ifmap) },
00312 };
00313
00314 static int nic_name_comparator( const void *p1, const void *p2 )
00315 {
00316 const struct nic_s *n1 = p1, *n2 = p2;
00317 return strcmp(n1->l.name, n2->l.name);
00318 }
00319
00320 static int nic_index_comparator( const void *p1, const void *p2 )
00321 {
00322 const struct nic_s *n1 = p1, *n2 = p2;
00323 return ( (n1->l.ifi.ifi_index == n2->l.ifi.ifi_index)
00324 ? 0
00325 : (n1->l.ifi.ifi_index > n2->l.ifi.ifi_index)
00326 ? 1
00327 : -1
00328 );
00329 }
00330
00331 static int nic_get_links(NLH_t nh, char *if_name, int if_index)
00332 {
00333 struct nlmsghdr hdr, *rhdrs = NULL, *rhdr = NULL;
00334 struct sockaddr_nl addr = { AF_NETLINK, 0, 0, 0 };
00335 struct nl_msg *msg = NULL;
00336 int nlinks = 0;
00337 int rlen;
00338
00339 errno = 0;
00340 memset(&hdr, '\0', sizeof (hdr));
00341
00342 hdr.nlmsg_type = RTM_GETLINK;
00343
00344 if ((if_name && *if_name) || if_index != -1)
00345 hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH | NLM_F_ATOMIC;
00346 else
00347 hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
00348
00349 if (!(msg = nlmsg_build(&hdr))) {
00350 eprintf(NIC_FATAL, "nic_get_links: %m");
00351 return -1;
00352 }
00353
00354 if (if_name && *if_name) {
00355 eprintf(NIC_DEBUG, "looking for name %s\n", if_name);
00356 NLA_PUT_STRING(msg, IFLA_IFNAME, if_name);
00357 }
00358
00359 if( if_index != -1 ) {
00360 struct ifinfomsg info;
00361 memset(&info, '\0', sizeof (info));
00362
00363 eprintf(NIC_DEBUG, "looking for index %d\n", if_index);
00364 info.ifi_index = if_index;
00365
00366 if (nlmsg_append(msg, &info, sizeof (info), 1) < 0) {
00367 eprintf(NIC_FATAL, "nic_get_links: %m\n");
00368 return -1;
00369 }
00370 }
00371
00372 if (nl_send_auto_complete(nh->nl, nlmsg_hdr(msg)) < 0) {
00373 eprintf(NIC_FATAL, "nic_get_links: %m\n");
00374 return -1;
00375 }
00376
00377 rlen = 1;
00378 while (rlen > 0) {
00379 rhdrs = NULL;
00380 if ((rlen = nl_recv(nh->nl, &addr, (void *)&rhdrs)) <= 0)
00381 break;
00382
00383 if (rlen < sizeof (*rhdr) + sizeof (struct ifinfomsg)) {
00384 nlmsg_free(msg);
00385 return nlinks;
00386 }
00387
00388 rhdr = rhdrs;
00389 while (nlmsg_ok(rhdr, rlen)) {
00390 struct nl_attr *tb[__IFLA_MAX];
00391 struct nic_s *nic = NULL, **nnic = NULL, **inic = NULL;
00392 int rc;
00393
00394 memset(tb, '\0', sizeof (tb));
00395 if (rhdr->nlmsg_type == NLMSG_DONE)
00396 break;
00397 if (rhdr->nlmsg_type != RTM_NEWLINK) {
00398 rhdr = nlmsg_next(rhdr, &rlen);
00399 continue;
00400 }
00401
00402 if (!(nic = calloc(1, sizeof (*nic)))) {
00403 eprintf(NIC_ERR, "nic_get_links: %m");
00404 free(rhdrs);
00405 rhdr = NULL;
00406 nlmsg_free(msg);
00407 return nlinks;
00408 }
00409 nic->nh = nh;
00410
00411 if ((rc = nlmsg_parse(rhdr, sizeof (struct ifinfomsg), (void *)tb, IFLA_MAX, nic_link_policy)) < 0) {
00412 eprintf(NIC_ERR, "nic_get_links: nl_parse_failed: %s", nl_geterror());
00413 free(nic);
00414 free(rhdrs);
00415 rhdr = NULL;
00416 nlmsg_free(msg);
00417 return nlinks;
00418 }
00419
00420 nic->l.ifi = *(struct ifinfomsg *)nlmsg_data(rhdr);
00421 if (nic->l.ifi.ifi_index != -1)
00422 eprintf(NIC_DEBUG, "found index %d\n", nic->l.ifi.ifi_index);
00423
00424 if (tb[IFLA_IFNAME]) {
00425 int len = nla_len((void *)tb[IFLA_IFNAME]);
00426 char *nambuf;
00427
00428 nambuf = alloca(len + 1);
00429 memcpy(nambuf, nla_data((void *)tb[IFLA_IFNAME]), len);
00430 nambuf[len] = '\0';
00431 eprintf(NIC_DEBUG, "got name: %s", nambuf);
00432
00433 strncpy(nic->l.name, nla_data((void *)tb[IFLA_IFNAME]), len);
00434 nic->l.name[len] = '\0';
00435 nic->l.have |= NIC_LINK_NAME;
00436 eprintf(NIC_DEBUG, " %s\n", nic->l.name);
00437 } else {
00438 eprintf(NIC_DEBUG, "didn't get name\n");
00439 }
00440
00441 if (tb[IFLA_TXQLEN]) {
00442 nic->l.txqlen = nla_get_u32((void*)tb[IFLA_TXQLEN]);
00443 nic->l.have |= NIC_LINK_TXQLEN;
00444 }
00445
00446 if (tb[IFLA_MTU]) {
00447 nic->l.mtu = nla_get_u32((void*)tb[IFLA_MTU]);
00448 nic->l.have |= NIC_LINK_MTU;
00449 }
00450
00451
00452 if (tb[IFLA_ADDRESS]) {
00453 nic->l.addr = ip_addr_binary(
00454 nla_data((void*)tb[IFLA_ADDRESS]),
00455 nla_len((void*)tb[IFLA_ADDRESS]));
00456 nic->l.have |= NIC_LINK_ADDRESS;
00457 }
00458
00459 if (tb[IFLA_BROADCAST]) {
00460 nic->l.broadcast = ip_addr_binary(
00461 nla_data((void*)tb[IFLA_BROADCAST]),
00462 nla_len((void*)tb[IFLA_BROADCAST]));
00463 nic->l.have |= NIC_LINK_BROADCAST;
00464 }
00465
00466 if (tb[IFLA_LINK]) {
00467 nic->l.link = nla_get_u32((void*)tb[IFLA_LINK]);
00468 nic->l.have |= NIC_LINK_LINK;
00469 }
00470
00471 if (tb[IFLA_WEIGHT]) {
00472 nic->l.weight = nla_get_u32((void*)tb[IFLA_WEIGHT]);
00473 nic->l.have |= NIC_LINK_WEIGHT;
00474 }
00475
00476 if (tb[IFLA_MASTER]) {
00477 nic->l.master = nla_get_u32((void*)tb[IFLA_MASTER]);
00478 nic->l.have |= NIC_LINK_MASTER;
00479 }
00480
00481 if (tb[IFLA_COST]) {
00482 nic->l.cost = nla_get_u32((void*)tb[IFLA_COST]);
00483 nic->l.have |= NIC_LINK_COST;
00484 }
00485
00486 if (tb[IFLA_PRIORITY]) {
00487 nic->l.priority = nla_get_u32((void*)tb[IFLA_PRIORITY]);
00488 nic->l.have |= NIC_LINK_PRIORITY;
00489 }
00490
00491 if (tb[IFLA_PROTINFO]) {
00492 nic->l.priority = nla_get_u32((void*)tb[IFLA_PROTINFO]);
00493 nic->l.have |= NIC_LINK_PROTINFO;
00494 }
00495
00496 if (tb[IFLA_QDISC]) {
00497 memcpy(&(nic->l.qdisc[0]), nla_data((void*)tb[IFLA_QDISC]), nla_len((void*)tb[IFLA_QDISC]));
00498 nic->l.have |= NIC_LINK_QDISC;
00499 nic->l.have |= NIC_LINK_QDISC;
00500 }
00501
00502 if (tb[IFLA_STATS]) {
00503 memcpy( &(nic->l.stats), nla_data((void*)tb[IFLA_STATS]), sizeof(struct rtnl_link_stats));
00504 nic->l.have |= NIC_LINK_STATS;
00505 }
00506
00507 if (tb[IFLA_MAP]) {
00508 memcpy( &(nic->l.ifmap), nla_data((void*)tb[IFLA_MAP]), sizeof(struct rtnl_link_ifmap));
00509 nic->l.have |= NIC_LINK_IFMAP;
00510 }
00511
00512 nnic = tfind(nic, &nh->nic_name_tree, nic_name_comparator);
00513 if (!nnic) {
00514 if (!(nnic = tsearch(nic, &(nh->nic_name_tree), nic_name_comparator))) {
00515 free(nic);
00516 free(rhdrs);
00517 rhdr = NULL;
00518 goto return_nlinks;
00519 }
00520 if (!(inic = tsearch(nic, &(nh->nic_index_tree), nic_index_comparator))) {
00521 free(nic);
00522 free(rhdrs);
00523 rhdr = NULL;
00524 goto return_nlinks;
00525 }
00526 }
00527 if (nic != *nnic) {
00528 free(nic);
00529 nic = *nnic;
00530 }
00531 nlinks++;
00532
00533 if ((if_index != -1 && nic->l.ifi.ifi_index == if_index) ||
00534 (if_name && !strcmp(nic->l.name, if_name))) {
00535 free(rhdrs);
00536 rhdr = NULL;
00537 goto return_nlinks;
00538 }
00539 rhdr = nlmsg_next(rhdr, &rlen);
00540 }
00541 }
00542 if (rlen < 0)
00543 eprintf(NIC_ERR, "rlen: %d\n", rlen);
00544
00545 nla_put_failure:
00546 nlmsg_free(msg);
00547 return -1;
00548
00549 return_nlinks:
00550 nlmsg_free(msg);
00551 return nlinks;
00552
00553 }
00554
00555 NIC_t nic_by_name(NLH_t nh, char *if_name)
00556 {
00557 struct nic_s snic, *nic=0, **pnic=0;
00558
00559 if (!nh->nic_name_tree)
00560 nic_get_links(nh, "", -1);
00561
00562 if( (if_name == 0L) || ( *if_name == '\0' ) )
00563 {
00564 eprintf(NIC_FATAL, "nic_by_name: invalid nil argument" );
00565 return( 0L );
00566 }
00567
00568 strncpy(&(snic.l.name[0]),if_name, IFNAMSIZ);
00569
00570 if ( (pnic = tfind(&snic, &(nh->nic_name_tree), nic_name_comparator)) != 0L )
00571 return *pnic;
00572
00573 if( ( nic_get_links(nh, if_name, -1) <= 0 )
00574 ||((pnic = tfind(&snic, &(nh->nic_name_tree), nic_name_comparator)) == 0L)
00575 )
00576 {
00577 eprintf(NIC_ERR, "nic_by_name: no interface named %s found", if_name );
00578 return(0L);
00579 }else
00580 nic = *pnic;
00581
00582 return nic;
00583 }
00584
00585 NIC_t nic_by_index(NLH_t nh, int16_t if_index)
00586 {
00587 struct nic_s snic, *nic=0, **pnic=0;
00588
00589
00590 if (!nh->nic_name_tree)
00591 nic_get_links(nh, "", -1);
00592
00593 if( if_index == -1 )
00594 {
00595 eprintf(NIC_FATAL, "nic_by_index: invalid -1 argument" );
00596 return( 0L );
00597 }
00598
00599 snic.l.ifi.ifi_index = if_index;
00600
00601 if ( (pnic = tfind(&snic, &(nh->nic_index_tree), nic_index_comparator)) != 0L )
00602 return *pnic;
00603
00604
00605 if( ( nic_get_links(nh, "", if_index ) <= 0 )
00606 ||((pnic = tfind(&snic, &(nh->nic_index_tree), nic_index_comparator)) == 0L)
00607 )
00608 {
00609 eprintf(NIC_ERR, "nic_by_index: no interface with index %d found", if_index );
00610 return(0L);
00611 }else
00612 nic = *pnic;
00613
00614 return nic;
00615 }
00616
00617 struct nic_cbarg
00618 {
00619 NIC_handler_t cb;
00620 void *arg;
00621 };
00622
00623 static void nic_twalker( const void *p, const VISIT which, const int depth )
00624 {
00625 struct nic_s *nic, *const*npp=p;
00626 struct nic_cbarg *cb;
00627
00628 if( (npp == 0L) || ((nic = *npp) == 0L)
00629 ||(nic->nh == 0) || (nic->nh->nic_foreach_arg == 0 )
00630 ||( (which != postorder) && (which != leaf) )
00631 ) return;
00632
00633 cb = nic->nh->nic_foreach_arg;
00634
00635 cb->cb( nic->nh, nic, cb->arg );
00636 }
00637
00638 void nic_foreach(NLH_t nh, NIC_handler_t handler, void *arg)
00639 {
00640 struct nic_cbarg cb = { handler, arg };
00641 struct nic_s snic;
00642
00643 if ( nh->nic_foreach_arg )
00644 return;
00645
00646 nh->nic_foreach_arg = &cb;
00647 memset(&snic, '\0', sizeof(struct nic_s));
00648 snic.l.ifi.ifi_index = -1;
00649 snic.nh = nh;
00650
00651
00652 nic_get_links(nh, "", -1 ) ;
00653
00654 if( nh->nic_name_tree )
00655 twalk( nh->nic_name_tree, nic_twalker);
00656
00657 nh->nic_foreach_arg = 0L;
00658 }
00659
00660 char* nic_get_name( NIC_t nic )
00661 {
00662 if( nic == 0 ) return 0;
00663
00664 return &(nic->l.name[0]);
00665 }
00666
00667 int16_t nic_get_index( NIC_t nic )
00668 {
00669 if ( nic == 0 ) return -1;
00670
00671 return nic->l.ifi.ifi_index ;
00672 }
00673
00674 ip_addr_t nic_get_link_addr(NIC_t nic)
00675 {
00676 ip_addr_t ip;
00677 memset(&ip, '\0', sizeof(ip));
00678 if( nic == 0L )
00679 return ip;
00680 return nic->l.addr;
00681 }
00682
00683 ip_addr_t nic_get_link_broadcast(NIC_t nic)
00684 {
00685 ip_addr_t ip;
00686 memset(&ip, '\0', sizeof(ip));
00687 if( nic == 0L )
00688 return ip;
00689 return nic->l.broadcast;
00690 }
00691
00692 uint32_t nic_get_flags( NIC_t nic )
00693 {
00694 if(nic == 0L)
00695 return 0;
00696 return nic->l.ifi.ifi_flags;
00697 }
00698
00699 NIC_Res_t nic_update( NIC_t nic )
00700 {
00701 NLH_t nh;
00702 if( nic == 0L )
00703 return NIC_FAIL;
00704
00705 nh = nic->nh;
00706
00707 memset(&nic->l.hdr, '\0', sizeof(struct nlmsghdr));
00708
00709 nic->l.hdr.nlmsg_type = RTM_SETLINK;
00710 nic->l.hdr.nlmsg_flags = NLM_F_REPLACE | NLM_F_REQUEST | NLM_F_ACK | NLM_F_MATCH | NLM_F_ATOMIC;
00711
00712 struct nl_msg *msg = nlmsg_build(&(nic->l.hdr));
00713
00714 if ( msg == 0L ) {
00715 eprintf(NIC_ERR, "nic_link_update (%s): nlmsg_build failed - %d %s" ,
00716 nic->l.name, nl_get_errno(), nl_geterror());
00717 return NIC_FAIL;
00718 }
00719
00720 nlmsg_append( msg, &(nic->l.ifi), sizeof( struct ifinfomsg ), 1);
00721
00722 if( nic->l.have & NIC_LINK_NAME )
00723 NLA_PUT_STRING(msg, IFLA_IFNAME, &(nic->l.name[0]));
00724
00725 if( nic->l.change & NIC_LINK_QDISC )
00726 NLA_PUT_STRING(msg, IFLA_QDISC, &(nic->l.qdisc[0]));
00727
00728 if( nic->l.have & NIC_LINK_LINK )
00729 NLA_PUT_U32(msg, IFLA_LINK, nic->l.link );
00730
00731 if( nic->l.change & NIC_LINK_MTU )
00732 NLA_PUT_U32(msg, IFLA_MTU, nic->l.mtu);
00733
00734 if( nic->l.change & NIC_LINK_TXQLEN )
00735 NLA_PUT_U32(msg, IFLA_TXQLEN, nic->l.txqlen);
00736
00737 if( nic->l.change & NIC_LINK_WEIGHT )
00738 NLA_PUT_U32(msg, IFLA_WEIGHT, nic->l.weight);
00739
00740 if( nic->l.change & NIC_LINK_COST )
00741 NLA_PUT_U32(msg, IFLA_COST, nic->l.cost);
00742
00743 if( nic->l.change & NIC_LINK_PRIORITY )
00744 NLA_PUT_U32(msg, IFLA_PRIORITY, nic->l.priority);
00745
00746 if( nic->l.change & NIC_LINK_PROTINFO )
00747 NLA_PUT_U32(msg, IFLA_PROTINFO, nic->l.protinfo);
00748
00749 if( nl_send_auto_complete(nic->nh->nl, nlmsg_hdr(msg)) < 0 )
00750 {
00751 eprintf(NIC_ERR,"nic_update_link: send failed - %d %s",
00752 nl_get_errno(), nl_geterror());
00753 return NIC_FAIL;
00754 }
00755
00756 nlmsg_free(msg);
00757
00758 if( nl_wait_for_ack(nic->nh->nl) < 0 )
00759 {
00760 eprintf(NIC_ERR,"nic_update_link failed - %d: %s",
00761 nl_get_errno(), nl_geterror());
00762 return NIC_FAIL;
00763 }
00764
00765 return NIC_OK;
00766
00767 nla_put_failure:
00768
00769 eprintf(NIC_ERR, "nic_update_link append attr failed - out of memory?");
00770
00771 nlmsg_free(msg);
00772
00773 return NIC_FAIL;
00774 }
00775
00776 void nic_set_flags( NIC_t nic, uint32_t flags )
00777 {
00778 if(nic == 0L) return;
00779
00780 nic->l.ifi.ifi_flags = flags;
00781 }
00782
00783 uint32_t nic_get_mtu( NIC_t nic )
00784 {
00785 if((nic == 0L) || ((nic->l.have & NIC_LINK_MTU)==0))
00786 return 0;
00787 return nic->l.mtu;
00788 }
00789
00790 void nic_set_mtu( NIC_t nic, uint32_t mtu )
00791 {
00792 if( nic == 0 ) return ;
00793 nic->l.mtu = mtu;
00794 nic->l.change |= NIC_LINK_MTU;
00795 }
00796
00797 char *nic_get_qdisc( NIC_t nic )
00798 {
00799 if((nic == 0) || ((nic->l.have & NIC_LINK_QDISC)==0))
00800 return 0;
00801 return &(nic->l.qdisc[0]);
00802 }
00803
00804 extern
00805 void nic_set_qdisc( NIC_t nic, char *qdisc )
00806 {
00807 if(nic == 0) return ;
00808 strncpy(&(nic->l.qdisc[0]), qdisc, IFQDISCSIZ);
00809 nic->l.change |= NIC_LINK_QDISC;
00810 }
00811
00812 uint32_t nic_get_txqlen( NIC_t nic )
00813 {
00814 if((nic == 0L) || ((nic->l.have & NIC_LINK_TXQLEN)==0))
00815 return 0;
00816 return nic->l.txqlen;
00817 }
00818
00819 void nic_set_txqlen( NIC_t nic, uint32_t txq )
00820 {
00821 if(nic == 0L) return;
00822 nic->l.txqlen = txq;
00823 nic->l.change |= NIC_LINK_TXQLEN;
00824 }
00825
00826 uint32_t nic_get_link( NIC_t nic )
00827 {
00828 if((nic == 0L) || ((nic->l.have & NIC_LINK_LINK)==0))
00829 return 0;
00830 return nic->l.link;
00831 }
00832
00833 void nic_set_link( NIC_t nic, uint32_t link )
00834 {
00835 if( nic == 0L) return;
00836 nic->l.link = link;
00837 nic->l.change |= NIC_LINK_LINK;
00838 }
00839
00840 uint32_t nic_get_weight( NIC_t nic )
00841 {
00842 if((nic == 0L) || ((nic->l.have & NIC_LINK_WEIGHT)==0))
00843 return 0;
00844 return nic->l.weight;
00845 }
00846
00847 void nic_set_weight( NIC_t nic, uint32_t weight )
00848 {
00849 if( nic == 0L) return;
00850 nic->l.weight = weight;
00851 nic->l.change |= NIC_LINK_WEIGHT;
00852 }
00853
00854 uint32_t nic_get_master( NIC_t nic )
00855 {
00856 if((nic == 0L) || ((nic->l.have & NIC_LINK_MASTER)==0))
00857 return 0;
00858 return nic->l.master;
00859 }
00860
00861 void nic_set_master( NIC_t nic, uint32_t master )
00862 {
00863 if( nic == 0L) return;
00864 nic->l.master = master;
00865 nic->l.change |= NIC_LINK_MASTER;
00866 }
00867
00868 uint32_t nic_get_cost( NIC_t nic )
00869 {
00870 if((nic == 0L) || ((nic->l.have & NIC_LINK_COST)==0))
00871 return 0;
00872 return nic->l.cost;
00873 }
00874
00875 void nic_set_cost( NIC_t nic, uint32_t cost )
00876 {
00877 if( nic == 0L) return;
00878 nic->l.cost = cost;
00879 nic->l.change |= NIC_LINK_COST;
00880 }
00881
00882 uint32_t nic_get_priority( NIC_t nic )
00883 {
00884 if((nic == 0L) || ((nic->l.have & NIC_LINK_PRIORITY)==0))
00885 return 0;
00886 return nic->l.priority;
00887 }
00888
00889 void nic_set_priority( NIC_t nic, uint32_t priority )
00890 {
00891 if( nic == 0L) return;
00892 nic->l.priority = priority;
00893 nic->l.change |= NIC_LINK_PRIORITY;
00894 }
00895
00896 uint32_t nic_get_protinfo( NIC_t nic )
00897 {
00898 if((nic == 0L) || ((nic->l.have & NIC_LINK_PROTINFO)==0))
00899 return 0;
00900 return nic->l.protinfo;
00901 }
00902
00903 void nic_set_protinfo( NIC_t nic, uint32_t protinfo )
00904 {
00905 if( nic == 0L) return;
00906 nic->l.protinfo = protinfo;
00907 nic->l.change |= NIC_LINK_PROTINFO;
00908 }
00909
00910 struct rtnl_link_stats nic_get_stats(NIC_t nic)
00911 {
00912 struct rtnl_link_stats st;
00913 memset(&st, '\0', sizeof(struct rtnl_link_stats));
00914 if((nic == 0L) || ((nic->l.have & NIC_LINK_STATS)==0))
00915 return st;
00916 return nic->l.stats;
00917 }
00918
00919 struct rtnl_link_ifmap nic_get_ifmap(NIC_t nic)
00920 {
00921 struct rtnl_link_ifmap ifm;
00922 memset(&ifm, '\0', sizeof(struct rtnl_link_ifmap));
00923 if((nic == 0L) || ((nic->l.have & NIC_LINK_IFMAP)==0))
00924 return ifm;
00925 return nic->l.ifmap;
00926 }
00927
00928 struct nic_ip_address_s
00929 {
00930 NLH_t nh;
00931
00932
00933 struct nic_addr_s
00934 {
00935 struct nlmsghdr hdr;
00936 struct ifaddrmsg ifa;
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947 uint32_t index;
00948 uint32_t flags;
00949 ip_addr_t addr;
00950 ip_addr_t broadcast;
00951 ip_addr_t anycast;
00952 ip_addr_t multicast;
00953 ip_addr_t local;
00954 struct ifa_cacheinfo cacheinfo;
00955 char label [ IFNAMSIZ ];
00956
00957 enum ifa_e
00958 {
00959 NIC_ADDR_ADDRESS = 1,
00960 NIC_ADDR_LOCAL = 2,
00961 NIC_ADDR_LABEL = 4,
00962 NIC_ADDR_BROADCAST = 8,
00963 NIC_ADDR_ANYCAST = 16,
00964 NIC_ADDR_CACHEINFO = 32,
00965 NIC_ADDR_MULTICAST = 64
00966 } have, change;
00967
00968 } nla;
00969 };
00970
00971 static struct nla_policy nic_addr_policy[IFA_MAX+1] = {
00972 [IFA_LABEL] = { .type = NLA_STRING,
00973 .maxlen = IFNAMSIZ },
00974 [IFA_CACHEINFO] = { .minlen = sizeof(struct ifa_cacheinfo) },
00975 };
00976
00977 static int nic_addr_comparator( const void *p1, const void *p2 )
00978 {
00979 const struct nic_ip_address_s *ipa1=p1, *ipa2=p2;
00980
00981 if( ipa1->nla.ifa.ifa_index > ipa2->nla.ifa.ifa_index )
00982 return 1;
00983 else
00984 if( ipa1->nla.ifa.ifa_index < ipa2->nla.ifa.ifa_index )
00985 return -1;
00986
00987 uint8_t
00988 pfx1 = ipa1->nla.ifa.ifa_prefixlen,
00989 pfx2 = ipa2->nla.ifa.ifa_prefixlen;
00990
00991 const ip_addr_t *ip1=0, *ip2=0;
00992
00993 if( ipa1->nla.have & NIC_ADDR_ADDRESS )
00994 ip1 = &(ipa1->nla.addr);
00995 else
00996 if( ipa1->nla.have & NIC_ADDR_LOCAL )
00997 {
00998 ip1 = &(ipa1->nla.local);
00999 pfx1 = IP_ADDR_SIZE(ip1) * 8;
01000 }
01001
01002 if( ipa2->nla.have & NIC_ADDR_ADDRESS )
01003 ip2 = &(ipa2->nla.addr);
01004 else
01005 if( ipa2->nla.have & NIC_ADDR_LOCAL )
01006 {
01007 ip2 = &(ipa2->nla.local);
01008 pfx2= IP_ADDR_SIZE(ip2) * 8;
01009 }
01010
01011 if( ip1 == 0 )
01012 return -1;
01013
01014 if( ip2 == 0 )
01015 return 1;
01016
01017 uint8_t
01018 alen1 = IP_ADDR_SIZE(ip1),
01019 alen2 = IP_ADDR_SIZE(ip2);
01020
01021 if( alen1 > alen2 )
01022 return 1;
01023 else
01024 if( alen1 < alen2 )
01025 return -1;
01026
01027 if( pfx1 > pfx2 )
01028 return 1;
01029 else
01030 if( pfx1 < pfx2 )
01031 return -1;
01032
01033 const uint8_t
01034 *ap1 = IP_ADDR(ip1),
01035 *ap2 = IP_ADDR(ip2);
01036
01037 for(; alen1 && pfx1; alen1--, pfx1-=8, ap1++, ap2++ )
01038 {
01039 const uint8_t
01040 v1=*ap1,
01041 v2=*ap2;
01042
01043 if( pfx1 < 8 )
01044 {
01045 const uint8_t
01046 vb1 = v1 & ((1 << pfx1)-1),
01047 vb2 = v2 & ((1 << pfx1)-1);
01048 return
01049 ( vb1 > vb2 )
01050 ? 1
01051 : ( vb1 < vb2 )
01052 ? -1
01053 : 0;
01054 }else
01055 {
01056 if( v1 > v2 )
01057 return 1;
01058 if( v1 < v2 )
01059 return -1;
01060 }
01061 }
01062 return 0;
01063 }
01064
01065 static int nic_get_addresses(NLH_t nh, IPaddr_t ipa)
01066 {
01067 char abuf[32];
01068 struct nic_ip_address_s ipaf, *addr;
01069
01070 if(nh == 0)
01071 return 0;
01072
01073 int n_addrs = 0;
01074 struct nic_addr_s *nla;
01075
01076 if( ipa )
01077 {
01078 ipaf = *ipa;
01079 addr = ipa;
01080 nla = &(ipa->nla);
01081 memset(&(nla->hdr),'\0',sizeof(struct nlmsghdr));
01082 nla->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ATOMIC | NLM_F_MATCH;
01083 }else
01084 {
01085 memset(&ipaf, '\0', sizeof(struct nic_ip_address_s));
01086 ipaf.nh = nh;
01087 addr = &ipaf;
01088 nla = &(ipaf.nla);
01089 addr=&ipaf;
01090 nla->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
01091 }
01092
01093 nla->hdr.nlmsg_type = RTM_GETADDR;
01094
01095 struct nl_msg *msg = nlmsg_build(&(nla->hdr));
01096
01097 if( msg == 0L )
01098 {
01099 eprintf(NIC_ERR, "nic_get_addresses: out of memory" );
01100 return n_addrs;
01101 }
01102
01103 if( nlmsg_append(msg, &(nla->ifa), sizeof(struct ifaddrmsg), 1) < 0 )
01104 {
01105 eprintf(NIC_ERR,"nic_get_addresses: nlmsg_append failed: %d %s\n",
01106 nl_get_errno(), nl_geterror());
01107 goto nla_put_failure;
01108 }
01109
01110 if( addr->nla.addr.sa_family )
01111 NLA_PUT(msg, IFLA_ADDRESS,
01112 IP_ADDR_SIZE(&(addr->nla.addr)),
01113 IP_ADDR(&(addr->nla.addr))
01114 );
01115
01116 if ( nl_send_auto_complete( nh->nl, nlmsg_hdr(msg) ) < 0 )
01117 {
01118 eprintf(NIC_ERR,"nic_get_addresses: send failed: %d %s\n",
01119 nl_get_errno(), nl_geterror());
01120 goto nla_put_failure;
01121 }
01122
01123 struct nic_addr_s *buf = 0;
01124
01125 if( buf == 0L )
01126 {
01127 eprintf(NIC_ERR,"nic_get_addresses: out of memory.");
01128 goto nla_put_failure;
01129 }
01130
01131 struct nlmsghdr *hdr = (struct nlmsghdr *)buf;
01132 struct sockaddr_nl kernel;
01133 int rlen = 0;
01134 int remaining = 0;
01135
01136 do
01137 {
01138 if ( (rlen = nl_recv( nh->nl, &kernel, (void*)&buf)) > 0 )
01139 {
01140 if( rlen < (sizeof(struct nlmsghdr) + sizeof(struct ifaddrmsg)) )
01141 goto nla_return;
01142
01143 hdr = (struct nlmsghdr*)buf;
01144 remaining = rlen;
01145
01146 if( hdr->nlmsg_type != RTM_NEWADDR )
01147 goto nla_return;
01148
01149 do
01150 {
01151 memset(nla, '\0', sizeof(struct nic_addr_s));
01152
01153 memcpy(nla, hdr, sizeof(struct nlmsghdr));
01154
01155 struct nl_attr *tb[__IFA_MAX];
01156
01157 int i;
01158 for (i=0; i < __IFA_MAX; i++) tb[i]=0;
01159 int err =
01160 nlmsg_parse((struct nlmsghdr*)hdr, sizeof(struct ifaddrmsg),
01161 (void*)tb, IFA_MAX, nic_addr_policy);
01162 if( err < 0 )
01163 {
01164 eprintf(NIC_ERR,"nic_get_addresses: nl_parse failed: %d %s",
01165 err, nl_geterror());
01166 goto nla_return;
01167 }
01168
01169 nla->ifa = *((struct ifaddrmsg*)nlmsg_data((struct nlmsghdr*)hdr));
01170
01171 if( tb[ IFA_ADDRESS ] )
01172 {
01173 nla->addr =
01174 ip_addr_binary
01175 ( nla_data((void*)tb[IFA_ADDRESS]),
01176 nla_len((void*)tb[IFA_ADDRESS])
01177 );
01178
01179 eprintf(NIC_DEBUG,"nic %d address: %s/%hd",
01180 nla->ifa.ifa_index,
01181 ip_text_addr(&nla->addr, abuf, 32),
01182 nla->ifa.ifa_prefixlen);
01183 nla->have |= NIC_ADDR_ADDRESS;
01184 }
01185
01186 if( tb[ IFA_LOCAL ] )
01187 {
01188 nla->local =
01189 ip_addr_binary
01190 ( nla_data((void*)tb[IFA_ADDRESS]),
01191 nla_len((void*)tb[IFA_ADDRESS])
01192 );
01193 eprintf(NIC_DEBUG,"nic %d local (PtP) address: %s",
01194 nla->ifa.ifa_index,
01195 ip_text_addr(&nla->local, abuf, 32));
01196 nla->have |= NIC_ADDR_LOCAL;
01197 }
01198
01199 if( tb[ IFA_BROADCAST ] )
01200 {
01201 nla->broadcast =
01202 ip_addr_binary
01203 ( nla_data((void*)tb[IFA_BROADCAST]),
01204 nla_len((void*)tb[IFA_BROADCAST])
01205 );
01206 eprintf(NIC_DEBUG,"nic %d broadcast address: %s",
01207 nla->ifa.ifa_index,
01208 ip_text_addr(&nla->broadcast, abuf, 32));
01209 nla->have |= NIC_ADDR_BROADCAST;
01210 }
01211
01212 if( tb[ IFA_ANYCAST ] )
01213 {
01214 nla->anycast =
01215 ip_addr_binary
01216 ( nla_data((void*)tb[IFA_ANYCAST]),
01217 nla_len((void*)tb[IFA_ANYCAST])
01218 );
01219 eprintf(NIC_DEBUG,"nic %d anycast address: %s",
01220 nla->ifa.ifa_index,
01221 ip_text_addr(&nla->anycast, abuf, 32));
01222 nla->have |= NIC_ADDR_ANYCAST;
01223 }
01224
01225 if( tb[ IFA_MULTICAST ] )
01226 {
01227 nla->multicast =
01228 ip_addr_binary
01229 ( nla_data((void*)tb[IFA_MULTICAST]),
01230 nla_len((void*)tb[IFA_MULTICAST])
01231 );
01232 eprintf(NIC_DEBUG,"nic %d multicast address: %s",
01233 nla->ifa.ifa_index,
01234 ip_text_addr(&nla->multicast, abuf, 32));
01235 nla->have |= NIC_ADDR_MULTICAST;
01236 }
01237
01238 if( tb[IFA_CACHEINFO] )
01239 {
01240 memcpy
01241 ( &(nla->cacheinfo),
01242 nla_data((void*)tb[IFA_CACHEINFO]),
01243 sizeof(struct ifa_cacheinfo)
01244 );
01245 eprintf(NIC_DEBUG,"nic %d have cacheinfo",
01246 nla->ifa.ifa_index);
01247 nla->have |= NIC_ADDR_CACHEINFO;
01248 }
01249
01250 if( tb[IFA_LABEL] )
01251 {
01252 strncpy
01253 ( &(nla->label[0]),
01254 nla_data((void*)tb[IFA_LABEL]),
01255 nla_len((void*)tb[IFA_LABEL])
01256 );
01257 eprintf(NIC_DEBUG,"nic %d addr label: %s",
01258 nla->ifa.ifa_index, nla->label);
01259 nla->have |= NIC_ADDR_LABEL;
01260 }
01261
01262 n_addrs++;
01263
01264 struct nic_ip_address_s **paddr, *taddr=0L, *naddr = 0L;
01265
01266 if( ipa == 0 )
01267 {
01268 naddr = calloc(1, sizeof(struct nic_ip_address_s));
01269 if( naddr == 0L )
01270 {
01271 eprintf(NIC_ERR, "nic_get_addresses: out of memory.");
01272 goto nla_return;
01273 }
01274 *naddr = *addr;
01275 taddr = addr;
01276 addr = naddr;
01277 naddr = taddr;
01278 taddr = 0;
01279 }
01280
01281 if( (nh->nic_addr_tree == 0L)
01282 ||((paddr = tfind(addr, &(nh->nic_addr_tree), nic_addr_comparator)) == 0L)
01283 ) tsearch(addr, &(nh->nic_addr_tree), nic_addr_comparator);
01284
01285 if( paddr != 0L )
01286 {
01287 taddr = *paddr;
01288 *taddr = *addr;
01289 if( naddr )
01290 free(naddr);
01291 }
01292
01293 if( ipa == 0L )
01294 addr = &ipaf;
01295
01296 if( ipa && ( nic_addr_comparator( ipa , addr ) == 0 ) )
01297 goto nla_return;
01298
01299 hdr = nlmsg_next( hdr, &remaining );
01300
01301 } while ( remaining > 0 );
01302
01303 }else
01304 {
01305 eprintf(NIC_ERR,"nic_addresses: netlink recv failed: %s %d\n",
01306 nl_get_errno(), nl_geterror());
01307 goto nla_return;
01308 }
01309 } while ( (hdr->nlmsg_type == RTM_NEWADDR) && (remaining > 0) );
01310
01311 nla_return:
01312 if( buf )
01313 free(buf);
01314 nlmsg_free(msg);
01315 return n_addrs;
01316
01317 nla_put_failure:
01318 nlmsg_free(msg);
01319 return n_addrs;
01320 }
01321
01322 struct nic_addr_cbarg
01323 {
01324 IPaddr_Handler_t cb;
01325 void *arg;
01326 };
01327
01328 static void nic_addr_twalker( const void *p, const VISIT which, const int depth )
01329 {
01330 struct nic_ip_address_s *addr, *const*app=p;
01331 struct nic_addr_cbarg *cb;
01332
01333 if( (app == 0L) || ((addr = *app) == 0L)
01334 ||(addr->nh == 0) || (addr->nh->nic_addr_foreach_arg == 0 )
01335 ||( (which != postorder) && (which != leaf) )
01336 ) return;
01337
01338 cb = addr->nh->nic_addr_foreach_arg;
01339
01340 cb->cb( addr->nh, addr, cb->arg );
01341 }
01342
01343 void nic_addr_foreach(NLH_t nh, IPaddr_Handler_t handler, void *arg)
01344 {
01345 struct nic_addr_cbarg cb = { handler, arg };
01346
01347 if ( nh->nic_addr_foreach_arg )
01348 return;
01349
01350 nh->nic_addr_foreach_arg = &cb;
01351
01352 nic_get_addresses(nh, 0L);
01353
01354 if( nh->nic_addr_tree )
01355 twalk( nh->nic_addr_tree, nic_addr_twalker);
01356
01357 nh->nic_addr_foreach_arg = 0L;
01358 }
01359
01360 IPaddr_t nic_addr_ip( NLH_t nh, ip_addr_t *ip)
01361 {
01362 if( ( nh == 0L ) || ( ip == 0L )
01363 ||( (ip->sa_family != AF_INET)
01364 &&(ip->sa_family != AF_INET6)
01365 )
01366 ) return 0;
01367
01368 IPaddr_t ipa = calloc(1, sizeof(struct nic_ip_address_s));
01369
01370 if( ipa == 0L )
01371 {
01372 eprintf(NIC_ERR, "nic_addr_ip: out of memory");
01373 }
01374 ipa->nh = nh;
01375 ipa->nla.addr = *ip;
01376 ipa->nla.have |= NIC_ADDR_ADDRESS;
01377 return ipa;
01378 }
01379
01380 IPaddr_t nic_addr( NLH_t nh, ip_addr_t ip)
01381 {
01382 if( ( nh == 0L )
01383 ||( (ip.sa_family != AF_INET)
01384 &&(ip.sa_family != AF_INET6)
01385 )
01386 ) return 0;
01387
01388 IPaddr_t ipa = calloc(1, sizeof(struct nic_ip_address_s));
01389
01390 if( ipa == 0L )
01391 {
01392 eprintf(NIC_ERR, "nic_addr: out of memory");
01393 }
01394 ipa->nh = nh;
01395 ipa->nla.addr = ip;
01396 ipa->nla.ifa.ifa_family = ip.sa_family;
01397 ipa->nla.have |= NIC_ADDR_ADDRESS;
01398 return ipa;
01399 }
01400
01401 IPaddr_t nic_addr_local( NLH_t nh, ip_addr_t ip)
01402 {
01403 if( ( nh == 0L )
01404 ||((ip.sa_family != AF_INET)
01405 &&(ip.sa_family != AF_INET6)
01406 )
01407 ) return 0;
01408
01409 IPaddr_t ipa = calloc(1, sizeof(struct nic_ip_address_s));
01410
01411 if( ipa == 0L )
01412 {
01413 eprintf(NIC_ERR, "nic_addr_local: out of memory");
01414 }
01415 ipa->nh = nh;
01416 ipa->nla.local = ip;
01417 ipa->nla.have |= NIC_ADDR_LOCAL;
01418 return ipa;
01419 }
01420
01421 ip_addr_t nic_ip_addr( IPaddr_t ipa )
01422 {
01423 ip_addr_t ip;
01424 memset(&ip, '\0', sizeof(ip_addr_t));
01425 if( (ipa == 0L) || ((ipa->nla.have & NIC_ADDR_ADDRESS) == 0))
01426 return ip;
01427 return ipa->nla.addr;
01428 }
01429
01430 ip_addr_t nic_addr_get_local( IPaddr_t ipa )
01431 {
01432 ip_addr_t ip;
01433 memset(&ip, '\0', sizeof(ip_addr_t));
01434 if( (ipa == 0L) || ((ipa->nla.have & NIC_ADDR_LOCAL) == 0))
01435 return ip;
01436 return ipa->nla.local;
01437 }
01438
01439 void nic_addr_set_local( IPaddr_t ipa, ip_addr_t ip )
01440 {
01441 if((ipa == 0L)
01442 ||((ip.sa_family != AF_INET)
01443 &&(ip.sa_family != AF_INET6)
01444 )
01445 ) return;
01446
01447 ipa->nla.local = ip;
01448 ipa->nla.have |= NIC_ADDR_LOCAL;
01449 }
01450
01451 uint8_t nic_addr_get_family( IPaddr_t ipa )
01452 {
01453 if(ipa == 0L) return 0;
01454 return ipa->nla.ifa.ifa_family;
01455 }
01456
01457 uint8_t nic_addr_get_prefix( IPaddr_t ipa)
01458 {
01459 if(ipa == 0L) return 0;
01460 return ipa->nla.ifa.ifa_prefixlen;
01461 }
01462
01463 void nic_addr_set_prefix( IPaddr_t ipa, uint8_t prefix)
01464 {
01465 if( (ipa == 0L)
01466 ||((ipa->nla.ifa.ifa_family == AF_INET) && (prefix > 32))
01467 ||((ipa->nla.ifa.ifa_family == AF_INET6) && (prefix > 128))
01468 )
01469 return;
01470
01471 ipa->nla.ifa.ifa_prefixlen = prefix;
01472 }
01473
01474 ip_addr_t nic_addr_get_broadcast( IPaddr_t ipa )
01475 {
01476 ip_addr_t ip;
01477 memset(&ip, '\0', sizeof(ip_addr_t));
01478 if( (ipa == 0L) || ((ipa->nla.have & NIC_ADDR_BROADCAST) == 0))
01479 return ip;
01480 return ipa->nla.broadcast;
01481 }
01482
01483 void nic_addr_set_broadcast( IPaddr_t ipa, ip_addr_t ip )
01484 {
01485 if( (ipa == 0L)
01486 ||((ip.sa_family != AF_INET)
01487 &&(ip.sa_family != AF_INET6)
01488 )
01489 ) return;
01490
01491 ipa->nla.broadcast = ip;
01492 ipa->nla.have |= NIC_ADDR_BROADCAST;
01493 }
01494
01495 ip_addr_t nic_addr_get_anycast( IPaddr_t ipa )
01496 {
01497 ip_addr_t ip;
01498 memset(&ip, '\0', sizeof(ip_addr_t));
01499 if( (ipa == 0L) || ((ipa->nla.have & NIC_ADDR_ANYCAST) == 0))
01500 return ip;
01501 return ipa->nla.anycast;
01502 }
01503
01504 void nic_addr_set_anycast( IPaddr_t ipa, ip_addr_t ip )
01505 {
01506 if( (ipa == 0L)
01507 ||((ip.sa_family != AF_INET)
01508 &&(ip.sa_family != AF_INET6)
01509 )
01510 ) return;
01511
01512 ipa->nla.anycast = ip;
01513 ipa->nla.have |= NIC_ADDR_ANYCAST;
01514 }
01515
01516 ip_addr_t nic_addr_get_multicast( IPaddr_t ipa )
01517 {
01518 ip_addr_t ip;
01519 memset(&ip, '\0', sizeof(ip_addr_t));
01520 if( (ipa == 0L) || ((ipa->nla.have & NIC_ADDR_MULTICAST) == 0))
01521 return ip;
01522 return ipa->nla.multicast;
01523 }
01524
01525 void nic_addr_set_multicast( IPaddr_t ipa, ip_addr_t ip )
01526 {
01527 if( (ipa == 0L)
01528 ||( (ip.sa_family != AF_INET)
01529 &&(ip.sa_family != AF_INET6)
01530 )
01531 ) return;
01532
01533 ipa->nla.multicast = ip;
01534 ipa->nla.have |= NIC_ADDR_MULTICAST;
01535 }
01536
01537 int8_t nic_addr_get_scope(IPaddr_t ipa)
01538 {
01539 if(ipa == 0L) return 0;
01540
01541 return ipa->nla.ifa.ifa_scope;
01542 }
01543
01544 void nic_addr_set_scope(IPaddr_t ipa, int8_t scope )
01545 {
01546 if(ipa == 0L) return;
01547
01548 ipa->nla.ifa.ifa_scope = scope;
01549 }
01550
01551 uint8_t nic_addr_get_flags(IPaddr_t ipa)
01552 {
01553 if(ipa == 0L) return 0;
01554
01555 return ipa->nla.ifa.ifa_flags;
01556 }
01557
01558 void nic_addr_set_flags(IPaddr_t ipa, uint8_t flags )
01559 {
01560 if(ipa == 0L) return;
01561
01562 ipa->nla.ifa.ifa_flags = flags;
01563 }
01564
01565 const char *nic_addr_get_label(IPaddr_t ipa)
01566 {
01567 if( (ipa == 0L) || ((ipa->nla.have & NIC_ADDR_LABEL) == 0))
01568 return "";
01569 return &(ipa->nla.label[0]);
01570 }
01571
01572 void nic_addr_set_label(IPaddr_t ipa, const char *label)
01573 {
01574 if((ipa == 0L) || (label == 0L)) return;
01575 strncpy(&(ipa->nla.label[0]), label, IFNAMSIZ);
01576 ipa->nla.have |= NIC_ADDR_LABEL;
01577 }
01578
01579 struct ifa_cacheinfo nic_addr_get_cacheinfo( IPaddr_t ipa )
01580 {
01581 struct ifa_cacheinfo ifa_ca;
01582 memset(&ifa_ca, '\0', sizeof(struct ifa_cacheinfo));
01583 if( (ipa == 0L) || ((ipa->nla.have & NIC_ADDR_CACHEINFO) == 0))
01584 return ifa_ca;
01585 return ipa->nla.cacheinfo;
01586 }
01587
01588 void nic_addr_set_cacheinfo( IPaddr_t ipa, struct ifa_cacheinfo *ca)
01589 {
01590 if((ipa == 0L) || (ca == 0L)) return;
01591 ipa->nla.cacheinfo = *ca;
01592 ipa->nla.have |= NIC_ADDR_CACHEINFO;
01593 }
01594
01595 IPaddr_list_t *nic_address_list_new( IPaddr_t ip1, ... )
01596 {
01597 va_list va;
01598 NLH_t nh = ip1->nh;
01599 va_start(va, ip1);
01600
01601 IPaddr_list_t *head = calloc(1,sizeof(IPaddr_list_t));
01602 IPaddr_list_node_t *n;
01603 struct nic_ip_address_s *ip;
01604
01605 if( head == 0 )
01606 {
01607 va_end(va);
01608 eprintf(NIC_ERR, "out of memory" );
01609 return 0;
01610 }
01611 ip=ip1;
01612 STAILQ_INIT(head);
01613 do
01614 {
01615 n = calloc(1,sizeof(IPaddr_list_node_t));
01616 if ( n == 0L )
01617 {
01618 va_end(va);
01619 free(head);
01620 eprintf(NIC_ERR, "out of memory" );
01621 return 0L;
01622 }
01623 n->addr = ip;
01624 STAILQ_INSERT_TAIL( head, n, link );
01625 }while( (ip = va_arg(va, struct nic_ip_address_s*)) != 0) ;
01626 va_end(va);
01627 return(head);
01628 }
01629
01630 void nic_address_list_free( IPaddr_list_t *head )
01631 {
01632 IPaddr_list_node_t *n, *a;
01633
01634 if ( !STAILQ_EMPTY(head) )
01635 {
01636 n = STAILQ_FIRST( head );
01637 do
01638 {
01639 a = STAILQ_NEXT(n, link);
01640 free(n->addr);
01641 free(n);
01642 n = a;
01643 } while (n);
01644 }
01645 }
01646
01647 typedef
01648 enum nic_ar_e
01649 {
01650 NIC_ADD_ADDRESS,
01651 NIC_DELETE_ADDRESS
01652 } NIC_Address_Request;
01653
01654 static
01655 int nic_addr_send( IPaddr_t ipa, NIC_Address_Request req )
01656 {
01657 char abuf[64];
01658 int err=0;
01659 NLH_t nh;
01660
01661 if(ipa == 0L)
01662 return -1;
01663 nh = ipa->nh;
01664
01665 memset(&(ipa->nla.hdr), '\0', sizeof(struct nlmsghdr));
01666
01667 ipa->nla.hdr.nlmsg_type =
01668 (req == NIC_DELETE_ADDRESS)
01669 ? RTM_DELADDR
01670 : RTM_NEWADDR;
01671
01672 ipa->nla.hdr.nlmsg_flags =
01673 ( (req == NIC_ADD_ADDRESS)
01674 ? (NLM_F_REPLACE | NLM_F_MATCH)
01675 : 0
01676 ) | NLM_F_REQUEST | NLM_F_ACK | NLM_F_ROOT;
01677
01678 ipa->nla.hdr.nlmsg_len = sizeof(struct nlmsghdr);
01679
01680 if( ipa->nla.ifa.ifa_flags == 0 )
01681 ipa->nla.ifa.ifa_flags = IFA_F_PERMANENT;
01682
01683 struct nl_msg *msg = nlmsg_build(&(ipa->nla.hdr));
01684
01685 if ( msg == 0L ) {
01686 eprintf(NIC_ERR, "nic_addr_send: nlmsg_build failed - %d %s" ,
01687 nl_get_errno(), nl_geterror());
01688 return NIC_FAIL;
01689 }
01690
01691 nlmsg_append( msg, &(ipa->nla.ifa), sizeof( struct ifaddrmsg ), 1);
01692
01693 if( ipa->nla.have & NIC_ADDR_ADDRESS )
01694 {
01695 NLA_PUT(msg, IFA_ADDRESS, IP_ADDR_SIZE(&(ipa->nla.addr)), IP_ADDR( &(ipa->nla.addr) ));
01696 if( (ipa->nla.ifa.ifa_family == AF_INET) && ((ipa->nla.have & NIC_ADDR_LOCAL)==0) )
01697 {
01698 ipa->nla.have |= NIC_ADDR_LOCAL;
01699 ipa->nla.local = ipa->nla.addr;
01700 }
01701 eprintf(NIC_DEBUG,"nic_addr_send: add IFA_ADDRESS: %d %s/%d\n",
01702 ipa->nla.ifa.ifa_index, ip_text_addr(&(ipa->nla.addr),abuf,64),
01703 ipa->nla.ifa.ifa_prefixlen);
01704 }
01705
01706 if( ipa->nla.have & NIC_ADDR_LOCAL )
01707 {
01708 NLA_PUT(msg, IFA_LOCAL, IP_ADDR_SIZE(&(ipa->nla.local)), IP_ADDR( &(ipa->nla.local) ));
01709 eprintf(NIC_DEBUG,"nic_addr_send: add IFA_LOCAL: %d %s\n",
01710 ipa->nla.ifa.ifa_index,
01711 ip_text_addr(&(ipa->nla.local),abuf,64));
01712 }
01713
01714 if( ipa->nla.have & NIC_ADDR_LABEL )
01715 NLA_PUT_STRING(msg, IFA_LABEL, &(ipa->nla.label[0]));
01716
01717 if( ipa->nla.have & NIC_ADDR_BROADCAST )
01718 {
01719 NLA_PUT(msg, IFA_BROADCAST, IP_ADDR_SIZE(&(ipa->nla.broadcast)), IP_ADDR( &(ipa->nla.broadcast) ));
01720 eprintf(NIC_DEBUG,"nic_addr_send: add address: %d broadcast: %s\n",
01721 ipa->nla.ifa.ifa_index,
01722 ip_text_addr(&(ipa->nla.broadcast), abuf, 64));
01723 }
01724
01725 if( ipa->nla.have & NIC_ADDR_ANYCAST )
01726 NLA_PUT(msg, IFA_ANYCAST, IP_ADDR_SIZE(&(ipa->nla.broadcast)), IP_ADDR( &(ipa->nla.broadcast) ));
01727
01728 if( ipa->nla.have & NIC_ADDR_MULTICAST )
01729 NLA_PUT(msg, IFA_MULTICAST, IP_ADDR_SIZE(&(ipa->nla.broadcast)), IP_ADDR( &(ipa->nla.multicast) ));
01730
01731 if( ipa->nla.have & NIC_ADDR_CACHEINFO )
01732 NLA_PUT(msg, IFA_CACHEINFO, sizeof(struct ifa_cacheinfo), &(ipa->nla.cacheinfo));
01733
01734 if( (err = nl_send_auto_complete(ipa->nh->nl, nlmsg_hdr(msg))) < 0 )
01735 {
01736 eprintf(NIC_ERR,"nic_addr_send: send failed - %d %d %s",
01737 err, nl_get_errno(), nl_geterror());
01738 return NIC_FAIL;
01739 }
01740
01741 nlmsg_free(msg);
01742
01743 int n_tries = 0;
01744 try_again:
01745
01746 if( (n_tries < 10) && ((err= nl_wait_for_ack(ipa->nh->nl)) < 0) )
01747 {
01748 if( err == - EBUSY )
01749 {
01750 struct timespec ts = { 0, 500000000 };
01751 ++n_tries;
01752
01753 nanosleep(&ts,0);
01754 goto try_again;
01755 }
01756
01757 if( err == -EEXIST )
01758 {
01759
01760 return NIC_OK;
01761 }
01762 eprintf(NIC_ERR,"nic_addr_send failed - %d: %s", nl_get_errno(),
01763 nl_geterror());
01764 return NIC_FAIL;
01765 }
01766
01767 return NIC_OK;
01768
01769 nla_put_failure:
01770
01771 eprintf(NIC_ERR, "nic_addr_send append attr failed - out of memory?");
01772
01773 nlmsg_free(msg);
01774
01775 return NIC_FAIL;
01776 }
01777
01778 NIC_Res_t nic_add_address( NIC_t nic, IPaddr_t ipa)
01779 {
01780 if( ( ipa == 0L ) || (nic == 0L) )
01781 return NIC_FAIL;
01782 ipa->nla.ifa.ifa_index = nic->l.ifi.ifi_index;
01783 return nic_addr_send( ipa, NIC_ADD_ADDRESS );
01784 }
01785
01786 NIC_Res_t nic_remove_address( NIC_t nic, IPaddr_t ipa)
01787 {
01788 if( ( ipa == 0L ) || (nic == 0L) )
01789 return NIC_FAIL;
01790 ipa->nla.ifa.ifa_index = nic->l.ifi.ifi_index;
01791 return nic_addr_send( ipa, NIC_ADD_ADDRESS );
01792 }
01793
01794 NIC_Res_t nic_add_addresses( NIC_t nic, IPaddr_list_t *head )
01795 {
01796 IPaddr_list_node_t *n;
01797 NIC_Res_t r;
01798
01799 STAILQ_FOREACH(n,head,link)
01800 {
01801 if((r = nic_add_address(nic, n->addr)) == NIC_FAIL)
01802 return r;
01803 }
01804 return NIC_OK;
01805 }
01806
01807 NIC_Res_t nic_remove_addresses( NIC_t nic, IPaddr_list_t *head )
01808 {
01809 IPaddr_list_node_t *n;
01810 NIC_Res_t r;
01811
01812 STAILQ_FOREACH(n,head,link)
01813 {
01814 if((r = nic_remove_address(nic, n->addr)) == NIC_FAIL)
01815 return r;
01816 }
01817 return NIC_OK;
01818 }
01819
01820 void nic_addr_free(void *ipa)
01821 {
01822 if (ipa)
01823 free(ipa);
01824 }
01825
01826 struct nic_route_s
01827 {
01828 NLH_t nh;
01829
01830 struct nic_rt_s
01831 {
01832 struct nlmsghdr hdr;
01833 struct rtmsg rtm;
01834
01835
01836
01837
01838
01839
01840
01841
01842
01843
01844
01845
01846
01847
01848
01849
01850 ip_addr_t dst;
01851 ip_addr_t gw;
01852 ip_addr_t src;
01853 ip_addr_t prefsrc;
01854 int32_t oif;
01855 uint32_t priority;
01856 uint32_t protoinfo;
01857 uint32_t flow;
01858 uint32_t session;
01859 uint32_t mp_algo;
01860 struct rta_cacheinfo cacheinfo;
01861 char iif [ IFNAMSIZ ];
01862 uint32_t metrics[ __RTAX_MAX ];
01863
01864 struct nic_rtnh_s
01865 {
01866 struct rtnexthop rtnh;
01867 ip_addr_t gw;
01868 } *hops;
01869 uint32_t n_hops;
01870
01871 enum rt_a_e
01872 {
01873 NIC_RT_DST = 1,
01874 NIC_RT_SRC = 2,
01875 NIC_RT_IIF = 8,
01876 NIC_RT_OIF = 16,
01877 NIC_RT_GATEWAY = 32,
01878 NIC_RT_PRIORITY = 64,
01879 NIC_RT_PREFSRC = 128,
01880 NIC_RT_METRICS = 256,
01881 NIC_RT_MULTIPATH= 512,
01882 NIC_RT_PROTOINFO=1024,
01883 NIC_RT_FLOW =2048,
01884 NIC_RT_CACHEINFO=4096,
01885 NIC_RT_SESSION =8192,
01886 NIC_RT_MP_ALGO= 16384
01887 } have, change;
01888
01889 enum rtax_e
01890 {
01891 NIC_RTAX_LOCK = (1<<RTAX_LOCK),
01892 NIC_RTAX_MTU = (1<<RTAX_MTU),
01893 NIC_RTAX_WINDOW = (1<<RTAX_WINDOW),
01894 NIC_RTAX_RTT = (1<<RTAX_RTT),
01895 NIC_RTAX_RTTVAR = (1<<RTAX_RTTVAR),
01896 NIC_RTAX_SSTHRESH = (1<<RTAX_SSTHRESH),
01897 NIC_RTAX_CWND = (1<<RTAX_CWND),
01898 NIC_RTAX_ADVMSS = (1<<RTAX_ADVMSS),
01899 NIC_RTAX_REORDERING=(1<<RTAX_REORDERING),
01900 NIC_RTAX_HOPLIMIT =(1<<RTAX_HOPLIMIT),
01901 NIC_RTAX_INITCWND =(1<<RTAX_INITCWND),
01902 NIC_RTAX_FEATURES =(1<<RTAX_FEATURES)
01903 } have_metrics, change_metrics;
01904 } rt;
01905 };
01906
01907 typedef struct nic_route_s RT_t;
01908
01909 static struct nla_policy nic_route_policy[RTA_MAX+1] = {
01910 [RTA_IIF] = { .type = NLA_STRING,
01911 .maxlen = IFNAMSIZ, },
01912 [RTA_OIF] = { .type = NLA_U32 },
01913 [RTA_PRIORITY] = { .type = NLA_U32 },
01914 [RTA_FLOW] = { .type = NLA_U32 },
01915 [RTA_MP_ALGO] = { .type = NLA_U32 },
01916 [RTA_CACHEINFO] = { .minlen = sizeof(struct rta_cacheinfo) },
01917 [RTA_METRICS] = { .type = NLA_NESTED },
01918 [RTA_MULTIPATH] = { .type = NLA_NESTED },
01919 };
01920
01921 static int nic_route_comparator( const void *p1, const void *p2 )
01922 {
01923 const RT_t *rt1 = p1, *rt2 = p2;
01924
01925 if( rt1->rt.rtm.rtm_table != rt2->rt.rtm.rtm_table )
01926 return
01927 ( (rt1->rt.rtm.rtm_table > rt2->rt.rtm.rtm_table )
01928 ? 1
01929 : -1
01930 );
01931
01932 if ( rt1->rt.rtm.rtm_family != rt2->rt.rtm.rtm_family )
01933 return
01934 ( ( rt1->rt.rtm.rtm_family > rt2->rt.rtm.rtm_family )
01935 ? 1
01936 : -1
01937 );
01938
01939 if ( rt1->rt.rtm.rtm_type != rt2->rt.rtm.rtm_type )
01940 return
01941 ( ( rt1->rt.rtm.rtm_type > rt2->rt.rtm.rtm_type )
01942 ? 1
01943 : -1
01944 );
01945
01946 if ( rt1->rt.rtm.rtm_scope != rt2->rt.rtm.rtm_scope )
01947 return
01948 ( ( rt1->rt.rtm.rtm_scope > rt2->rt.rtm.rtm_scope )
01949 ? 1
01950 : -1
01951 );
01952
01953 if ( rt1->rt.rtm.rtm_protocol != rt2->rt.rtm.rtm_protocol )
01954 return
01955 ( ( rt1->rt.rtm.rtm_protocol > rt2->rt.rtm.rtm_protocol )
01956 ? 1
01957 : -1
01958 );
01959
01960 if( rt1->rt.have & NIC_RT_OIF )
01961 {
01962 if( ( rt2->rt.have & NIC_RT_OIF ) == 0 )
01963 return 1;
01964 else
01965 {
01966 if( rt1->rt.oif != rt2->rt.oif )
01967 return
01968 ( (rt1->rt.oif > rt2->rt.oif)
01969 ? 1
01970 : -1
01971 );
01972 }
01973 }else
01974 if( rt2->rt.have & NIC_RT_OIF )
01975 return -1;
01976
01977 if( rt1->rt.have & NIC_RT_IIF )
01978 {
01979 if( ( rt2->rt.have & NIC_RT_IIF ) == 0 )
01980 return 1;
01981 else
01982 {
01983 int c = strcmp(&(rt1->rt.iif[0]),&(rt2->rt.iif[0]));
01984 if( c != 0 )
01985 return c;
01986 }
01987 }else
01988 if( rt2->rt.have & NIC_RT_OIF )
01989 return -1;
01990
01991 if( rt1->rt.have & NIC_RT_DST )
01992 {
01993 if( (rt2->rt.have & NIC_RT_DST) == 0 )
01994 return 1;
01995 else
01996 {
01997
01998 if( rt1->rt.dst.sa_family != rt2->rt.dst.sa_family )
01999 return
02000 ( ( rt1->rt.dst.sa_family > rt2->rt.dst.sa_family )
02001 ? 1
02002 : -1
02003 );
02004
02005 if( rt1->rt.rtm.rtm_dst_len != rt2->rt.rtm.rtm_dst_len )
02006 return
02007 ( ( rt1->rt.rtm.rtm_dst_len > rt2->rt.rtm.rtm_dst_len )
02008 ? 1
02009 : -1
02010 );
02011
02012 uint8_t
02013 *ap1 = IP_ADDR( &(rt1->rt.dst) ),
02014 *ap2 = IP_ADDR( &(rt2->rt.dst) ),
02015 pfx1 = rt1->rt.rtm.rtm_dst_len;
02016
02017 if( pfx1 == 0 )
02018 pfx1 = IP_ADDR_SIZE( &(rt1->rt.dst) );
02019
02020 int cr = memcmp( ap1, ap2,
02021 pfx1 / 8
02022 );
02023 if ( cr != 0 )
02024 return cr;
02025 uint8_t
02026 v1 = ((uint8_t*)IP_ADDR( &(rt1->rt.dst) ))[ pfx1 / 8 ]
02027 & ( ( 1 << ( pfx1 % 8 ) ) - 1),
02028 v2 = ((uint8_t*)IP_ADDR( &(rt2->rt.dst) ))[ pfx1 / 8 ]
02029 & ( ( 1 << ( pfx1 % 8 ) ) - 1);
02030
02031 if( v1 != v2 )
02032 return
02033 (
02034 (v1 > v2)
02035 ? 1
02036 : -1
02037 );
02038
02039 if( rt1->rt.have & NIC_RT_PRIORITY )
02040 {
02041 if( (rt2->rt.have & NIC_RT_PRIORITY) == 0 )
02042 return -1;
02043
02044 if( rt1->rt.priority != rt2->rt.priority )
02045 return
02046 ( (rt1->rt.priority > rt2->rt.priority)
02047 ? -1
02048 : 1
02049 );
02050 }
02051 }
02052 }else
02053 if( rt2->rt.have & NIC_RT_DST )
02054 return -1;
02055
02056 if( rt1->rt.have & NIC_RT_SRC )
02057 {
02058 if( (rt2->rt.have & NIC_RT_SRC) == 0 )
02059 return 1;
02060 else
02061 {
02062 if( rt1->rt.src.sa_family != rt2->rt.src.sa_family )
02063 return
02064 ( ( rt1->rt.src.sa_family > rt2->rt.src.sa_family )
02065 ? 1
02066 : -1
02067 );
02068
02069 if( rt1->rt.rtm.rtm_src_len != rt2->rt.rtm.rtm_src_len )
02070 return
02071 ( ( rt1->rt.rtm.rtm_src_len > rt2->rt.rtm.rtm_src_len )
02072 ? 1
02073 : -1
02074 );
02075
02076 uint8_t
02077 *ap1 = IP_ADDR( &(rt1->rt.src) ),
02078 *ap2 = IP_ADDR( &(rt2->rt.src) ),
02079 pfx1 = rt1->rt.rtm.rtm_src_len;
02080
02081 if( pfx1 == 0 )
02082 pfx1 = IP_ADDR_SIZE( &(rt1->rt.src) );
02083
02084 int cr = memcmp( ap1, ap2,
02085 rt1->rt.rtm.rtm_src_len / 8
02086 );
02087 if ( cr != 0 )
02088 return cr;
02089 uint8_t
02090 v1 = ((uint8_t*)IP_ADDR( &(rt1->rt.src) ))[ pfx1 / 8 ]
02091 & ( ( 1 << ( rt1->rt.rtm.rtm_src_len % 8 ) ) - 1),
02092 v2 = ((uint8_t*)IP_ADDR( &(rt2->rt.src) ))[ pfx1 / 8 ]
02093 & ( ( 1 << ( pfx1 % 8 ) ) - 1);
02094
02095 if( v1 != v2 )
02096 return
02097 (
02098 (v1 > v2)
02099 ? 1
02100 : -1
02101 );
02102
02103 if( rt1->rt.have & NIC_RT_PRIORITY )
02104 {
02105 if( (rt2->rt.have & NIC_RT_PRIORITY) == 0 )
02106 return -1;
02107
02108 if( rt1->rt.priority != rt2->rt.priority )
02109 return
02110 ( (rt1->rt.priority > rt2->rt.priority)
02111 ? 1
02112 : -1
02113 );
02114 }
02115 }
02116 }else
02117 if (rt2->rt.have & NIC_RT_SRC)
02118 return -1;
02119
02120 if ( rt1->rt.have & NIC_RT_GATEWAY )
02121 {
02122 if((rt2->rt.have & NIC_RT_GATEWAY)==0)
02123 return 1;
02124 {
02125
02126 if( rt1->rt.gw.sa_family != rt2->rt.gw.sa_family )
02127 return
02128 ( ( rt1->rt.gw.sa_family > rt2->rt.gw.sa_family )
02129 ? 1
02130 : -1
02131 );
02132
02133 uint8_t
02134 *ap1 = IP_ADDR( &(rt1->rt.gw) ),
02135 *ap2 = IP_ADDR( &(rt2->rt.gw) );
02136
02137 int cr = memcmp( ap1, ap2,
02138 IP_ADDR_SIZE(&(rt1->rt.gw))
02139 );
02140
02141 if( cr != 0 )
02142 return cr;
02143 }
02144 }else
02145 if (rt2->rt.have & NIC_RT_GATEWAY)
02146 return -1;
02147
02148 if ( rt1->rt.have & NIC_RT_PREFSRC )
02149 {
02150 if((rt2->rt.have & NIC_RT_PREFSRC)==0)
02151 return 1;
02152 {
02153
02154 if( rt1->rt.prefsrc.sa_family != rt2->rt.prefsrc.sa_family )
02155 return
02156 ( ( rt1->rt.prefsrc.sa_family > rt2->rt.prefsrc.sa_family )
02157 ? 1
02158 : -1
02159 );
02160
02161 uint8_t
02162 *ap1 = IP_ADDR( &(rt1->rt.prefsrc) ),
02163 *ap2 = IP_ADDR( &(rt2->rt.prefsrc) );
02164
02165 int cr = memcmp( ap1, ap2,
02166 IP_ADDR_SIZE(&(rt1->rt.prefsrc))
02167 );
02168
02169 if( cr != 0 )
02170 return cr;
02171 }
02172 } else
02173 if (rt2->rt.have & NIC_RT_PREFSRC)
02174 return -1;
02175 return 0;
02176 }
02177
02178 static int nic_get_routes(NLH_t nh, RT_t *rt)
02179 {
02180 RT_t srt, *rtp=0;
02181 struct nic_rt_s *rta=0;
02182 int n_routes = 0;
02183
02184 if(nh == 0)
02185 return 0;
02186
02187 if( rt )
02188 {
02189 srt = *rt;
02190 rtp = rt;
02191 rta = &(rt->rt);
02192 memset(&(rta->hdr),'\0',sizeof(struct nlmsghdr));
02193 rta->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ATOMIC | NLM_F_MATCH;
02194 }else
02195 {
02196 memset(&srt, '\0', sizeof(RT_t));
02197 srt.nh = nh;
02198 rtp = &srt;
02199 rta = &(rtp->rt);
02200 rta->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
02201 }
02202
02203 rta->hdr.nlmsg_type = RTM_GETROUTE;
02204
02205 struct nl_msg *msg = nlmsg_build(&(rta->hdr));
02206
02207 if( msg == 0L )
02208 {
02209 eprintf(NIC_ERR, "nic_get_routes: out of memory" );
02210 return n_routes;
02211 }
02212
02213 if( nlmsg_append(msg, &(rta->rtm), sizeof(struct rtmsg), 1) < 0 )
02214 {
02215 eprintf(NIC_ERR,"nic_get_routes: nlmsg_append failed: %d %s\n",
02216 nl_get_errno(), nl_geterror());
02217 goto nla_put_failure;
02218 }
02219
02220 if( rta->rtm.rtm_dst_len && rta->dst.sa_family
02221 &&(rta->have & NIC_RT_DST)
02222 )
02223 NLA_PUT(msg, RTA_DST,
02224 IP_ADDR_SIZE(&(rta->dst)),
02225 IP_ADDR(&(rta->dst))
02226 );
02227
02228 if( (rta->have & NIC_RT_OIF) && (rta->oif > -1) )
02229 NLA_PUT_U32(msg, RTA_OIF, rta->oif);
02230
02231 if( rta->gw.sa_family
02232 &&(rta->have & NIC_RT_GATEWAY)
02233 )
02234 NLA_PUT(msg, RTA_GATEWAY,
02235 IP_ADDR_SIZE(&(rta->gw)),
02236 IP_ADDR(&(rta->gw))
02237 );
02238
02239 if( rta->rtm.rtm_src_len && rta->src.sa_family
02240 &&(rta->have & NIC_RT_SRC)
02241 )
02242 NLA_PUT(msg, RTA_SRC,
02243 IP_ADDR_SIZE(&(rta->src)),
02244 IP_ADDR(&(rta->src))
02245 );
02246
02247 if( (rta->have & NIC_RT_IIF) && (rta->iif[0] != '\0') )
02248 NLA_PUT_STRING(msg, RTA_IIF, &(rta->iif[0]));
02249
02250 if ( nl_send_auto_complete( nh->nl, nlmsg_hdr(msg) ) < 0 )
02251 {
02252 eprintf(NIC_ERR,"nic_get_routes: send failed: %d %s\n",
02253 nl_get_errno(), nl_geterror());
02254 goto nla_put_failure;
02255 }
02256
02257 char abuf[64];
02258 struct RT_t *buf =0;
02259 struct nlmsghdr *hdr = (struct nlmsghdr *)buf;
02260 struct sockaddr_nl kernel;
02261 int rlen = 0;
02262 int remaining = 0;
02263
02264 do
02265 {
02266 if ( (rlen = nl_recv( nh->nl, &kernel, (void*)&buf)) > 0 )
02267 {
02268 if( rlen < (sizeof(struct nlmsghdr) + sizeof(struct rtmsg)) )
02269 goto rta_return;
02270
02271 hdr = (struct nlmsghdr*)buf;
02272 remaining = rlen;
02273
02274 if( hdr->nlmsg_type != RTM_NEWROUTE )
02275 goto rta_return;
02276
02277 do
02278 {
02279 memset(rta, '\0', sizeof(struct nic_rt_s));
02280
02281 memcpy(rta, hdr, sizeof(struct nlmsghdr));
02282
02283 struct nl_attr *tb[__RTA_MAX];
02284 int i;
02285 for (i=0; i < __RTA_MAX; i++) tb[i]=0;
02286
02287 int err =
02288 nlmsg_parse((struct nlmsghdr*)hdr, sizeof(struct rtmsg),
02289 (void*)tb, RTA_MAX, nic_route_policy);
02290 if ( err < 0 )
02291 {
02292 eprintf(NIC_ERR,"nic_get_routes: nl_parse failed: %d %s",
02293 err, nl_geterror());
02294 goto rta_return;
02295 }
02296
02297 rta->rtm = *((struct rtmsg*)nlmsg_data((struct nlmsghdr*)hdr));
02298
02299 eprintf(NIC_DEBUG, "\n"
02300 "table: %d\ndst_len: %d\nsrc_len: %d\n"
02301 "scope: %d\ntype: %d\nprotocol: %d",
02302 rta->rtm.rtm_table, rta->rtm.rtm_dst_len,
02303 rta->rtm.rtm_src_len, rta->rtm.rtm_scope,
02304 rta->rtm.rtm_type, rta->rtm.rtm_protocol);
02305
02306 if ( tb[RTA_DST] )
02307 {
02308 rta->dst =
02309 ip_addr_binary
02310 ( nla_data((void*)tb[RTA_DST]),
02311 nla_len((void*)tb[RTA_DST])
02312 );
02313 rta->have |= NIC_RT_DST;
02314 eprintf(NIC_DEBUG, "nic route: dst: %s/%d",
02315 ip_text_addr(&(rta->dst),abuf,64),
02316 rta->rtm.rtm_dst_len);
02317 }
02318
02319 if ( tb[RTA_OIF] )
02320 {
02321 rta->oif = nla_get_u32( (void*) tb[RTA_OIF] );
02322 rta->have |= NIC_RT_OIF ;
02323 eprintf(NIC_DEBUG, "nic route: oif: %d", rta->oif);
02324 }
02325
02326 if ( tb[RTA_GATEWAY] )
02327 {
02328 rta->gw =
02329 ip_addr_binary
02330 ( nla_data((void*)tb[RTA_GATEWAY]),
02331 nla_len((void*)tb[RTA_GATEWAY])
02332 );
02333 rta->have |= NIC_RT_GATEWAY;
02334 eprintf(NIC_DEBUG, "nic route: gw: %s",
02335 ip_text_addr(&(rta->gw),abuf,64));
02336 }
02337
02338 if ( tb[RTA_SRC] )
02339 {
02340 rta->src =
02341 ip_addr_binary
02342 ( nla_data((void*)tb[RTA_SRC]),
02343 nla_len((void*)tb[RTA_SRC])
02344 );
02345 rta->have |= NIC_RT_SRC;
02346 eprintf(NIC_DEBUG, "nic route: src: %s/%d",
02347 ip_text_addr(&(rta->src),abuf,64),
02348 rta->rtm.rtm_src_len);
02349 }
02350
02351 if ( tb[RTA_IIF] )
02352 {
02353 memcpy( &(rta->iif),
02354 nla_data( (void*) tb[RTA_IIF] ),
02355 nla_len((void*) tb[RTA_IIF] )
02356 );
02357 rta->have |= NIC_RT_IIF ;
02358 eprintf(NIC_DEBUG, "nic route: iif: %s", rta->iif);
02359 }
02360
02361 if ( tb[RTA_PREFSRC] )
02362 {
02363 rta->prefsrc =
02364 ip_addr_binary
02365 ( nla_data((void*)tb[RTA_PREFSRC]),
02366 nla_len((void*)tb[RTA_PREFSRC])
02367 );
02368 rta->have |= NIC_RT_PREFSRC;
02369 eprintf(NIC_DEBUG, "nic route: prefsrc: %s",
02370 ip_text_addr(&(rta->prefsrc),abuf,64));
02371 }
02372
02373 if ( tb[RTA_PRIORITY] )
02374 {
02375 rta->priority = nla_get_u32( (void*)tb[RTA_PRIORITY]);
02376 rta->have |= NIC_RT_PRIORITY;
02377 eprintf(NIC_DEBUG,"nic route: priority: %d", rta->priority);
02378 }
02379
02380 if ( tb[RTA_PROTOINFO] )
02381 {
02382 rta->protoinfo = nla_get_u32( (void*)tb[RTA_PROTOINFO]);
02383 rta->have |= NIC_RT_PROTOINFO;
02384 eprintf(NIC_DEBUG, "nic route: protoinfo: %x", rta->protoinfo);
02385 }
02386
02387 if ( tb[RTA_FLOW] )
02388 {
02389 rta->flow = nla_get_u32( (void*)tb[RTA_FLOW]);
02390 rta->have |= NIC_RT_FLOW;
02391 eprintf(NIC_DEBUG, "nic route: flow: %x", rta->flow);
02392 }
02393
02394 if ( tb[RTA_CACHEINFO] )
02395 {
02396 memcpy( &(rta->cacheinfo),
02397 nla_data((void*)tb[RTA_CACHEINFO]),
02398 sizeof(struct rta_cacheinfo)
02399 );
02400 rta->have |= NIC_RT_CACHEINFO;
02401 eprintf(NIC_DEBUG, "nic route: have cacheinfo");
02402 }
02403
02404 if ( tb[RTA_SESSION] )
02405 {
02406 rta->session = nla_get_u32( (void*)tb[RTA_SESSION]);
02407 rta->have |= NIC_RT_SESSION;
02408 eprintf(NIC_DEBUG, "nic route: session: %d", rta->session);
02409 }
02410
02411 if ( tb[RTA_MP_ALGO] )
02412 {
02413 rta->mp_algo = nla_get_u32( (void*)tb[RTA_MP_ALGO]);
02414 rta->have |= NIC_RT_MP_ALGO;
02415 eprintf(NIC_DEBUG, "nic route: mp algorithm: %x", rta->mp_algo);
02416 }
02417
02418 if ( tb[RTA_METRICS] )
02419 {
02420 struct nlattr *rtax_tb [ __RTAX_MAX ];
02421 int m;
02422 for(m=0; m < __RTAX_MAX; m++) rtax_tb[m] = 0L;
02423
02424 err = nla_parse_nested( rtax_tb, RTAX_MAX, (void*)tb[RTA_METRICS], 0L);
02425 if( err < 0 )
02426 {
02427 eprintf(NIC_ERR, "nic route: parse of RTAX metrics failed - %d %s",
02428 nl_get_errno(), nl_geterror());
02429
02430 }else
02431 {
02432 for( m = 0; m < __RTAX_MAX ; m++ )
02433 {
02434 if( rtax_tb [ m ] )
02435 {
02436 rta->metrics[ m ] = nla_get_u32( (void*) rtax_tb [ m ] );
02437 rta->have_metrics |= 1<<(m+1);
02438 }
02439 }
02440 }
02441 }
02442
02443 if ( tb[RTA_MULTIPATH] )
02444 {
02445 size_t rtnh_len = nla_len((void*)tb[RTA_MULTIPATH]);
02446
02447 struct rtnexthop
02448 *rtnhs = nla_data((void*)tb[RTA_MULTIPATH]),
02449 *rtnhe = (struct rtnexthop*)(((unsigned long)rtnhs) + rtnh_len),
02450 *rtnh = rtnhs;
02451
02452 while( rtnh < rtnhe )
02453 {
02454 rta->n_hops += 1;
02455 rtnh = RTNH_NEXT(rtnh);
02456 }
02457
02458 rta->hops = calloc(rta->n_hops, sizeof(struct nic_rtnh_s));
02459
02460 if( rta->hops == 0L )
02461 {
02462 eprintf(NIC_ERR, "nic route: parse of route next hops failed - out of memory.");
02463
02464 }else
02465 {
02466 struct nic_rtnh_s *nic_rtnh = rta->hops;
02467 for(rtnh = rtnhs; rtnh < rtnhe; rtnh = RTNH_NEXT(rtnh), nic_rtnh++ )
02468 {
02469 nic_rtnh->rtnh = *rtnh;
02470 if( rtnh->rtnh_len > sizeof(struct rtnexthop) )
02471 {
02472 struct nlattr *rtnhtb[ __RTA_MAX ];
02473 nla_parse((void*)rtnhtb, RTA_MAX, (struct nlattr *) RTNH_DATA(rtnh),
02474 rtnh->rtnh_len - sizeof(struct rtnexthop), NULL
02475 );
02476 if ( rtnhtb[RTA_GATEWAY] )
02477 {
02478 nic_rtnh->gw =
02479 ip_addr_binary
02480 ( nla_data( (void*) rtnhtb[RTA_GATEWAY] ),
02481 nla_len ( (void*) rtnhtb[RTA_GATEWAY] )
02482 );
02483 }
02484 }
02485 }
02486 }
02487 }
02488
02489 n_routes++;
02490
02491 RT_t **prt=0, *trt=0L, *frt=rt, *nrt = 0L;
02492
02493 if( rt == 0 )
02494 {
02495 nrt = calloc(1, sizeof(struct nic_route_s));
02496 if( nrt == 0L )
02497 {
02498 eprintf(NIC_ERR, "nic_get_routes: out of memory.");
02499 goto rta_return;
02500 }
02501 *nrt= *rtp;
02502 eprintf(NIC_DEBUG," new route %p - rta: %p rtp->nh: %p", nrt, rta, nrt->nh);
02503 trt = rtp;
02504 rtp = nrt;
02505 nrt = trt;
02506 trt = 0;
02507 }
02508
02509 if( (nh->nic_route_tree == 0L)
02510 ||((prt = tfind(rtp, &(nh->nic_route_tree), nic_route_comparator)) == 0L)
02511 )
02512 {
02513 tsearch(rtp, &(nh->nic_route_tree), nic_route_comparator);
02514 eprintf(NIC_DEBUG," route tsearch %p - nh: %p", rtp, rtp->nh);
02515 }
02516
02517 if( prt != 0L )
02518 {
02519 trt = *prt;
02520 *trt = *rtp;
02521 frt = trt;
02522 eprintf(NIC_DEBUG," route found %p - freeing %p", trt, rtp);
02523 if( nrt )
02524 free(rtp);
02525 }
02526
02527 if( rt == 0L )
02528 rtp = &srt;
02529 else
02530 if( nic_route_comparator( frt , rtp ) == 0 )
02531 goto rta_return;
02532
02533 hdr = nlmsg_next( hdr, &remaining );
02534
02535 } while ( remaining > 0 );
02536
02537 }else
02538 {
02539 eprintf(NIC_ERR,"nic_get_routes: netlink recv failed: %s %d\n",
02540 nl_get_errno(), nl_geterror());
02541 goto rta_return;
02542 }
02543 } while ( (hdr->nlmsg_type == RTM_NEWROUTE) && (remaining > 0) );
02544
02545 rta_return:
02546 if( buf )
02547 free(buf);
02548 nlmsg_free(msg);
02549 return n_routes;
02550
02551 nla_put_failure:
02552 nlmsg_free(msg);
02553 return n_routes;
02554 }
02555
02556 struct nic_route_cbarg
02557 {
02558 IProute_handler_t cb;
02559 void *arg;
02560 };
02561
02562 static void nic_route_twalker( const void *p, const VISIT which, const int depth )
02563 {
02564 struct nic_route_s *route, *const*app=p;
02565 struct nic_route_cbarg *cb;
02566
02567 if( (app == 0L) || ((route = *app) == 0L)
02568 ||(route->nh == 0) || (route->nh->nic_route_foreach_arg == 0 )
02569 ||( (which != postorder) && (which != leaf) )
02570 ) return;
02571
02572 cb = route->nh->nic_route_foreach_arg;
02573
02574 cb->cb( route->nh, route, cb->arg );
02575 }
02576
02577 void nic_route_foreach(NLH_t nh, IProute_handler_t handler, void *arg)
02578 {
02579 struct nic_route_cbarg cb = { handler, arg };
02580
02581 if ( nh->nic_route_foreach_arg )
02582 return;
02583
02584 nh->nic_route_foreach_arg = &cb;
02585
02586 nic_get_routes(nh, 0L);
02587
02588 if( nh->nic_route_tree )
02589 twalk( nh->nic_route_tree, nic_route_twalker);
02590
02591 nh->nic_route_foreach_arg = 0L;
02592 }
02593
02594 int32_t nic_route_get_table(IProute_t rt)
02595 {
02596 if( rt == 0L ) return 0;
02597 return rt->rt.rtm.rtm_table;
02598 }
02599
02600 void nic_route_set_table(IProute_t rt, uint8_t table)
02601 {
02602 if(rt == 0L) return;
02603 rt->rt.rtm.rtm_table = table;
02604 }
02605
02606 char *nic_route_get_table_name( int32_t table, char *buf, int len )
02607 {
02608 return rtnl_route_table2str( table, buf, len );
02609 }
02610
02611 extern
02612 int32_t nic_route_get_table_number( char *table )
02613 {
02614 return rtnl_route_str2table( table );
02615 }
02616
02617 uint8_t nic_route_get_family( IProute_t rt)
02618 {
02619 if( rt == 0L ) return 0;
02620
02621 return rt->rt.rtm.rtm_family;
02622 }
02623
02624 uint8_t nic_route_get_scope(IProute_t rt)
02625 {
02626 if( rt == 0L ) return 0;
02627 return rt->rt.rtm.rtm_scope;
02628 }
02629
02630 void nic_route_set_scope(IProute_t rt, uint8_t scope)
02631 {
02632 if( rt == 0L ) return;
02633 rt->rt.rtm.rtm_scope = scope;
02634 }
02635
02636 uint32_t nic_route_get_flags( IProute_t rt )
02637 {
02638 if( rt == 0L ) return 0;
02639 return rt->rt.rtm.rtm_flags;
02640 }
02641
02642 void nic_route_set_flags(IProute_t rt, uint32_t flags)
02643 {
02644 if( rt == 0L ) return;
02645 rt->rt.rtm.rtm_flags = flags;
02646 }
02647
02648 uint8_t nic_route_get_dst_len( IProute_t rt )
02649 {
02650 if( rt == 0L ) return 0;
02651 return rt->rt.rtm.rtm_dst_len;
02652 }
02653
02654 void nic_route_set_dst_len( IProute_t rt, uint8_t dst_len )
02655 {
02656 if( rt == 0L ) return;
02657 rt->rt.rtm.rtm_dst_len = dst_len;
02658 }
02659
02660 uint8_t nic_route_get_src_len( IProute_t rt )
02661 {
02662 if( rt == 0L ) return 0;
02663 return rt->rt.rtm.rtm_src_len;
02664 }
02665
02666 void nic_route_set_src_len( IProute_t rt, uint8_t src_len )
02667 {
02668 if( rt == 0L ) return;
02669 rt->rt.rtm.rtm_src_len = src_len;
02670 }
02671
02672 uint8_t nic_route_get_type( IProute_t rt)
02673 {
02674 if( rt == 0L ) return 0;
02675 return rt->rt.rtm.rtm_type;
02676 }
02677
02678 void nic_route_set_type( IProute_t rt, uint8_t type )
02679 {
02680 if( rt == 0L ) return;
02681 rt->rt.rtm.rtm_type = type;
02682 }
02683
02684 uint8_t nic_route_get_protocol( IProute_t rt)
02685 {
02686 if( rt == 0L ) return 0;
02687 return rt->rt.rtm.rtm_protocol;
02688 }
02689
02690 void nic_route_set_protocol( IProute_t rt, uint8_t protocol )
02691 {
02692 if( rt == 0L ) return;
02693 rt->rt.rtm.rtm_protocol = protocol;
02694 }
02695
02696 uint8_t nic_route_get_tos( IProute_t rt)
02697 {
02698 if( rt == 0L ) return 0;
02699 return rt->rt.rtm.rtm_tos;
02700 }
02701
02702 void nic_route_set_tos( IProute_t rt, uint8_t tos )
02703 {
02704 if( rt == 0L ) return;
02705 rt->rt.rtm.rtm_protocol = tos;
02706 }
02707
02708 ip_addr_t nic_route_get_dst( IProute_t rt )
02709 {
02710 ip_addr_t ip;
02711 memset(&ip,'\0',sizeof(ip));
02712 if( ( rt == 0L )
02713 ||((rt->rt.have & NIC_RT_DST)==0)
02714 ) return ip;
02715 return rt->rt.dst;
02716 }
02717
02718 void nic_route_set_dst( IProute_t rt, ip_addr_t ip)
02719 {
02720 if( rt == 0L ) return;
02721 rt->rt.dst = ip;
02722 rt->rt.have |= NIC_RT_DST;
02723 }
02724
02725 ip_addr_t nic_route_get_gateway( IProute_t rt )
02726 {
02727 ip_addr_t ip;
02728 memset(&ip,'\0',sizeof(ip));
02729 if( ( rt == 0L )
02730 ||((rt->rt.have & NIC_RT_GATEWAY)==0)
02731 ) return ip;
02732 return rt->rt.gw;
02733 }
02734
02735 void nic_route_set_gateway( IProute_t rt, ip_addr_t ip)
02736 {
02737 if( rt == 0L ) return;
02738 rt->rt.gw = ip;
02739 rt->rt.have |= NIC_RT_GATEWAY;
02740 }
02741
02742 ip_addr_t nic_route_get_src( IProute_t rt )
02743 {
02744 ip_addr_t ip;
02745 memset(&ip,'\0',sizeof(ip));
02746 if( ( rt == 0L )
02747 ||((rt->rt.have & NIC_RT_SRC)==0)
02748 ) return ip;
02749 return rt->rt.src;
02750 }
02751
02752 void nic_route_set_src( IProute_t rt, ip_addr_t ip)
02753 {
02754 if( rt == 0L ) return;
02755 rt->rt.src = ip;
02756 rt->rt.have |= NIC_RT_SRC;
02757 }
02758
02759 ip_addr_t nic_route_get_prefsrc( IProute_t rt )
02760 {
02761 ip_addr_t ip;
02762 memset(&ip,'\0',sizeof(ip));
02763 if( ( rt == 0L )
02764 ||((rt->rt.have & NIC_RT_PREFSRC)==0)
02765 ) return ip;
02766 return rt->rt.prefsrc;
02767 }
02768
02769 void nic_route_set_prefsrc( IProute_t rt, ip_addr_t ip)
02770 {
02771 if( rt == 0L ) return;
02772 rt->rt.prefsrc = ip;
02773 rt->rt.have |= NIC_RT_PREFSRC;
02774 }
02775
02776 int16_t nic_route_get_oif( IProute_t rt )
02777 {
02778 if( ( rt == 0L )
02779 ||((rt->rt.have & NIC_RT_OIF)==0)
02780 ) return -1;
02781
02782 return rt->rt.oif;
02783 }
02784
02785 void nic_route_set_oif( IProute_t rt, uint16_t oif)
02786 {
02787 if( rt == 0L ) return ;
02788
02789 rt->rt.oif = oif;
02790 rt->rt.have |= NIC_RT_OIF;
02791 }
02792
02793 NIC_if_name_t nic_route_get_iif( IProute_t rt )
02794 {
02795 NIC_if_name_t nil = { { '\0' } };
02796 if( ( rt == 0L )
02797 ||((rt->rt.have & NIC_RT_IIF) == 0 )
02798 ) return nil;
02799
02800 return *((NIC_if_name_t*)&(rt->rt.iif[0]));
02801 }
02802
02803 void nic_route_set_iif( IProute_t rt, char *iif )
02804 {
02805 if( rt == 0 ) return;
02806
02807 strncpy(&(rt->rt.iif[0]), iif, IFNAMSIZ);
02808 rt->rt.have |= NIC_RT_IIF;
02809 }
02810
02811 uint32_t nic_route_get_priority( IProute_t rt )
02812 {
02813 if( ( rt == 0L )
02814 ||((rt->rt.have & NIC_RT_PRIORITY) == 0 )
02815 ) return 0;
02816
02817 return rt->rt.priority;
02818 }
02819
02820 void nic_route_set_priority( IProute_t rt, uint32_t priority)
02821 {
02822 if( rt == 0L ) return;
02823
02824 rt->rt.priority = priority;
02825 rt->rt.have |= NIC_RT_PRIORITY;
02826 }
02827
02828 extern
02829 uint32_t nic_route_get_protoinfo(IProute_t rt)
02830 {
02831 if( ( rt == 0L )
02832 ||((rt->rt.have & NIC_RT_PROTOINFO) == 0 )
02833 ) return 0;
02834
02835 return rt->rt.protoinfo;
02836 }
02837
02838 extern
02839 void nic_route_set_protoinfo(IProute_t rt, uint32_t protoinfo)
02840 {
02841 if( rt == 0L ) return;
02842 rt->rt.protoinfo = protoinfo;
02843 rt->rt.have |= NIC_RT_PROTOINFO;
02844 }
02845
02846 uint32_t nic_route_get_session(IProute_t rt)
02847 {
02848 if( ( rt == 0L )
02849 ||((rt->rt.have & NIC_RT_SESSION) == 0 )
02850 ) return 0;
02851
02852 return rt->rt.session;
02853 }
02854
02855 extern
02856 void nic_route_set_session(IProute_t rt, uint32_t session)
02857 {
02858 if( rt == 0L ) return;
02859 rt->rt.session = session;
02860 rt->rt.have |= NIC_RT_SESSION;
02861 }
02862
02863 uint32_t nic_route_get_flow(IProute_t rt)
02864 {
02865 if( ( rt == 0L )
02866 ||((rt->rt.have & NIC_RT_FLOW) == 0 )
02867 ) return 0;
02868
02869 return rt->rt.flow;
02870 }
02871
02872 void nic_route_set_flow(IProute_t rt, uint32_t flow)
02873 {
02874 if( rt == 0L ) return;
02875 rt->rt.flow = flow;
02876 rt->rt.have |= NIC_RT_FLOW;
02877 }
02878
02879 uint32_t nic_route_get_mp_algo(IProute_t rt)
02880 {
02881 if( ( rt == 0L )
02882 ||((rt->rt.have & NIC_RT_MP_ALGO) == 0 )
02883 ) return 0;
02884
02885 return rt->rt.mp_algo;
02886 }
02887
02888 void nic_route_set_mp_algo(IProute_t rt, uint32_t mp_algo)
02889 {
02890 if( rt == 0L ) return;
02891 rt->rt.mp_algo = mp_algo;
02892 rt->rt.have |= NIC_RT_MP_ALGO;
02893 }
02894
02895 IProute_t nic_route_new
02896 ( NLH_t nh,
02897 int16_t oif,
02898 ip_addr_t *dst,
02899 uint8_t dst_len,
02900 ip_addr_t *gw,
02901 int8_t type,
02902 int8_t protocol,
02903 int8_t scope,
02904 int32_t priority,
02905 int32_t table,
02906 char* iif,
02907 ip_addr_t *src,
02908 uint8_t src_len
02909 )
02910 {
02911 if( ( dst && (dst->sa_family != AF_INET) && (dst->sa_family != AF_INET6))
02912 ||( gw && (gw->sa_family != AF_INET) && (gw->sa_family != AF_INET6))
02913 ||( src && (src->sa_family != AF_INET) && (src->sa_family != AF_INET6))
02914 )
02915 return 0L;
02916
02917 IProute_t rt = calloc(1, sizeof(struct nic_route_s));
02918
02919 if(rt == 0L)
02920 return rt;
02921
02922 rt->nh = nh;
02923
02924
02925 if ( dst == 0L )
02926 {
02927 dst_len = 0;
02928 table = RT_TABLE_MAIN;
02929 }else
02930 {
02931 rt->rt.rtm.rtm_dst_len = dst_len;
02932 rt->rt.dst = *dst;
02933 rt->rt.rtm.rtm_family = dst->sa_family;
02934 rt->rt.have |= NIC_RT_DST;
02935 }
02936
02937 if( gw )
02938 {
02939 rt->rt.gw = *gw;
02940 rt->rt.have |= NIC_RT_GATEWAY;
02941 if( rt->rt.rtm.rtm_family == 0 )
02942 rt->rt.rtm.rtm_family = rt->rt.gw.sa_family;
02943 }
02944
02945 if( scope == -1 )
02946 rt->rt.rtm.rtm_scope = RT_SCOPE_UNIVERSE;
02947 else
02948 rt->rt.rtm.rtm_scope = scope;
02949
02950 if( table == -1 )
02951 rt->rt.rtm.rtm_table = RT_TABLE_LOCAL;
02952 else
02953 rt->rt.rtm.rtm_table = table;
02954
02955 if( type == -1 )
02956 rt->rt.rtm.rtm_type = RTN_UNICAST;
02957
02958 if( protocol == -1 )
02959 rt->rt.rtm.rtm_protocol = RTPROT_BOOT;
02960
02961 if( oif > -1 )
02962 {
02963 rt->rt.oif = oif;
02964 rt->rt.have |= NIC_RT_OIF;
02965 }
02966
02967 if( iif )
02968 {
02969 strncpy(&(rt->rt.iif[0]), iif, IFNAMSIZ);
02970 rt->rt.have |= NIC_RT_IIF;
02971 }
02972
02973 if( src && src_len )
02974 {
02975 rt->rt.src = *src;
02976 rt->rt.have |= NIC_RT_SRC;
02977 if( rt->rt.rtm.rtm_family == 0 )
02978 rt->rt.rtm.rtm_family = rt->rt.src.sa_family;
02979 }
02980
02981 if( priority > -1 )
02982 {
02983 rt->rt.priority = priority;
02984 rt->rt.have |= NIC_RT_PRIORITY;
02985 }
02986 return rt;
02987 }
02988
02989 static NIC_Res_t nic_route_msg( IProute_t rt, char *fn, char *tag, uint32_t msg_type, uint32_t msg_flags)
02990 {
02991 NLH_t nh = rt->nh;
02992
02993
02994 struct nl_msg *msg = nlmsg_build_simple(msg_type, msg_flags) ;
02995 if( msg == 0L )
02996 {
02997 eprintf(NIC_ERR,"%s: failed to %s route - out of memory.", tag, fn);
02998 return NIC_FAIL;
02999 }
03000
03001 if ( nlmsg_append(msg, &(rt->rt.rtm), sizeof(struct rtmsg), 1) < 0 )
03002 goto nla_put_failure;
03003
03004 if( rt->rt.have & NIC_RT_OIF )
03005 NLA_PUT_U32(msg, RTA_OIF, rt->rt.oif);
03006
03007 if ( rt->rt.have & NIC_RT_DST )
03008 NLA_PUT(msg, RTA_DST, IP_ADDR_SIZE(&(rt->rt.dst)), IP_ADDR(&(rt->rt.dst)));
03009
03010 if ( rt->rt.have & NIC_RT_GATEWAY )
03011 NLA_PUT(msg, RTA_GATEWAY, IP_ADDR_SIZE(&(rt->rt.gw)), IP_ADDR(&(rt->rt.gw)));
03012
03013 if( rt->rt.have & NIC_RT_IIF )
03014 NLA_PUT_STRING(msg, RTA_IIF, &(rt->rt.iif[0]));
03015
03016 if ( rt->rt.have & NIC_RT_SRC )
03017 NLA_PUT(msg, RTA_SRC, IP_ADDR_SIZE(&(rt->rt.src)), IP_ADDR(&(rt->rt.src)));
03018
03019 if ( rt->rt.have & NIC_RT_PREFSRC )
03020 NLA_PUT(msg, RTA_SRC, IP_ADDR_SIZE(&(rt->rt.prefsrc)), IP_ADDR(&(rt->rt.prefsrc)));
03021
03022 if ( rt->rt.have & NIC_RT_PRIORITY )
03023 NLA_PUT_U32(msg, RTA_PRIORITY, rt->rt.priority);
03024
03025 if ( rt->rt.have & NIC_RT_FLOW )
03026 NLA_PUT_U32(msg, RTA_FLOW, rt->rt.flow);
03027
03028 if ( rt->rt.have & NIC_RT_SESSION )
03029 NLA_PUT_U32(msg, RTA_SESSION, rt->rt.session);
03030
03031 if ( rt->rt.have & NIC_RT_MP_ALGO )
03032 NLA_PUT_U32(msg, RTA_MP_ALGO, rt->rt.mp_algo);
03033
03034 if( nl_send_auto_complete(rt->nh->nl, nlmsg_hdr(msg)) < 0 )
03035 {
03036 eprintf(NIC_ERR,"%s: send failed - %d %s", tag, nl_get_errno(),
03037 nl_geterror());
03038 return NIC_FAIL;
03039 }
03040
03041 nlmsg_free(msg);
03042
03043 if( nl_wait_for_ack(rt->nh->nl) < 0 )
03044 {
03045 eprintf(NIC_ERR,"%s: failed - %d: %s", tag, nl_get_errno(),
03046 nl_geterror());
03047 return NIC_FAIL;
03048 }
03049
03050 return NIC_OK;
03051
03052 nla_put_failure:
03053
03054 eprintf(NIC_ERR,"%s: failed to %s route - out of memory.", tag, fn);
03055 nlmsg_free(msg);
03056 return NIC_FAIL;
03057 }
03058
03059 NIC_Res_t nic_add_route( IProute_t rt )
03060 {
03061 if (rt == 0L) return NIC_FAIL;
03062
03063 return nic_route_msg( rt, "nic_add_route", "add", RTM_NEWROUTE, NLM_F_CREATE | NLM_F_REPLACE);
03064 }
03065
03066 NIC_Res_t nic_update_route( IProute_t rt )
03067 {
03068 if (rt == 0L) return NIC_FAIL;
03069
03070 return nic_route_msg( rt, "nic_update_route", "update", RTM_NEWROUTE, NLM_F_REPLACE);
03071 }
03072
03073 NIC_Res_t nic_remove_route( IProute_t rt )
03074 {
03075 if (rt == 0L) return NIC_FAIL;
03076
03077 return nic_route_msg( rt, "nic_remove_route", "remove", RTM_DELROUTE, 0);
03078 }
03079
03080 IProute_list_t *nic_route_list_new( IProute_t rt1, ... )
03081 {
03082 va_list va;
03083 NLH_t nh = rt1->nh;
03084 va_start(va, rt1);
03085
03086 IProute_list_t *head = calloc(1,sizeof(IProute_list_t));
03087 IProute_list_node_t *n;
03088 IProute_t rt;
03089
03090 if( head == 0 )
03091 {
03092 va_end(va);
03093 eprintf(NIC_ERR, "out of memory" );
03094 return 0;
03095 }
03096 rt=rt1;
03097 STAILQ_INIT(head);
03098 do
03099 {
03100 n = calloc(1,sizeof(IProute_list_node_t));
03101 if ( n == 0L )
03102 {
03103 va_end(va);
03104 free(head);
03105 eprintf(NIC_ERR, "out of memory");
03106 return 0L;
03107 }
03108 n->route = rt;
03109 STAILQ_INSERT_TAIL( head, n, link );
03110 }while( (rt = va_arg(va, IProute_t)) != 0) ;
03111 va_end(va);
03112 return(head);
03113 }
03114
03115 void nic_route_list_free( IProute_list_t *head )
03116 {
03117 IProute_list_node_t *n, *a;
03118
03119 if ( !STAILQ_EMPTY(head) )
03120 {
03121 n = STAILQ_FIRST( head );
03122 do
03123 {
03124 a = STAILQ_NEXT(n, link);
03125 nic_route_free(n->route);
03126 free(n);
03127 n = a;
03128 }while (n);
03129 }
03130 }
03131
03132 NIC_Res_t nic_add_routes( IProute_list_t *head )
03133 {
03134 IProute_list_node_t *n;
03135 NIC_Res_t r;
03136 STAILQ_FOREACH(n,head,link)
03137 {
03138 if((r=nic_add_route(n->route)) == NIC_FAIL)
03139 return r;
03140 }
03141 return NIC_OK;
03142 }
03143
03144 NIC_Res_t nic_remove_routes( IProute_list_t *head )
03145 {
03146 IProute_list_node_t *n;
03147 NIC_Res_t r;
03148 STAILQ_FOREACH(n,head,link)
03149 {
03150 if((r=nic_remove_route(n->route))==NIC_FAIL)
03151 return r;
03152 }
03153 return NIC_OK;
03154 }
03155
03156 NIC_Res_t nic_update_routes( IProute_list_t *head )
03157 {
03158 IProute_list_node_t *n;
03159 NIC_Res_t r;
03160 STAILQ_FOREACH(n,head,link)
03161 {
03162 if((r=nic_update_route(n->route))==NIC_FAIL)
03163 return r;
03164 }
03165 return NIC_OK;
03166 }
03167
03168 void nic_route_free(void *rtp)
03169 {
03170 IProute_t rt = rtp;
03171
03172 if (!rt)
03173 return;
03174
03175 if( rt->nh->nic_route_tree )
03176 tdelete(rt, &(rt->nh->nic_route_tree), nic_route_comparator);
03177
03178 if( rt->rt.hops )
03179 free(rt->rt.hops);
03180
03181 free(rt);
03182 }
03183
03184 extern
03185 NIC_Res_t
03186 nic_set_hostname
03187 ( NLH_t nh,
03188 char *hostname
03189 )
03190 {
03191 return sethostname(hostname, strlen(hostname)) == 0 ? NIC_OK : NIC_FAIL;
03192 }
03193
03194 NIC_Res_t
03195 nic_configure
03196 (
03197 NLH_t nh,
03198 NIC_t nic,
03199 IPaddr_list_t *addresses,
03200 IProute_list_t *routes,
03201 IPaddr_list_t *dns_servers,
03202 char *search_list,
03203 char *host_name
03204 )
03205 {
03206 if ( addresses && ( nic_add_addresses( nic, addresses ) == NIC_FAIL ))
03207 {
03208 eprintf(NIC_ERR, "nic_configure: failed to add addresses.");
03209 return NIC_FAIL;
03210 }
03211
03212 if ( routes && ( nic_add_routes( routes ) == NIC_FAIL ))
03213 {
03214 eprintf(NIC_ERR, "nic_configure: failed to add routes.");
03215 return NIC_FAIL;
03216 }
03217
03218 return NIC_OK;
03219 }
03220
03221
03222
03223