static void find_one_address (struct nl_object *object, void *user_data) { FindAddrInfo *info = user_data; struct rtnl_addr *addr = (struct rtnl_addr *) object; struct nl_addr *local; void *binaddr; if (info->found) return; if (rtnl_addr_get_ifindex (addr) != info->ifindex) return; if (rtnl_addr_get_family (addr) != info->family) return; if (rtnl_addr_get_prefixlen (addr) != info->prefix) return; local = rtnl_addr_get_local (addr); if (nl_addr_get_family (local) != info->family) return; if (nl_addr_get_len (local) != info->addrlen) return; binaddr = nl_addr_get_binary_addr (local); if (binaddr) { if (memcmp (binaddr, info->addr, info->addrlen) == 0) info->found = TRUE; /* Yay, found it */ } }
static void wait_for_no_addresses (NMIP6Manager *self, NMIP6Device *device) { NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (self); guint64 now, end; gboolean has_addrs = TRUE; now = end = g_get_real_time (); end += (G_USEC_PER_SEC * 3); while (has_addrs && now < end) { struct rtnl_addr *rtnladdr; struct nl_addr *nladdr; nl_cache_refill (priv->nlh, priv->addr_cache); for (has_addrs = FALSE, rtnladdr = FIRST_ADDR (priv->addr_cache); rtnladdr; rtnladdr = NEXT_ADDR (rtnladdr)) { nladdr = rtnl_addr_get_local (rtnladdr); if ( rtnl_addr_get_ifindex (rtnladdr) == device->ifindex && nladdr && nl_addr_get_family (nladdr) == AF_INET6) { /* Still IPv6 addresses on the interface */ has_addrs = TRUE; nm_log_dbg (LOGD_IP6, "(%s) waiting for cleared IPv6 addresses", device->iface); g_usleep (100); now = g_get_real_time (); break; } } } }
void add_addr_to_list(struct nl_object *obj, void *data) { char buf[INET6_ADDRSTRLEN+5]; std::list<vaddress> *list = static_cast<std::list<vaddress>*>(data); struct nl_addr *naddr = rtnl_addr_get_local((struct rtnl_addr *) obj); int ifindex = 0; int scope = rtnl_addr_get_scope((struct rtnl_addr *) obj); if (scope == rtnl_str2scope("link")) ifindex = rtnl_addr_get_ifindex((struct rtnl_addr *) obj); if (naddr) { int family = nl_addr_get_family(naddr); nl_addr2str( naddr, buf, sizeof( buf ) ); vaddress vaddr(vaddress::Family(family), vaddress::strip_netmask(std::string(buf)), ifindex, false); list->push_back( vaddr ); } struct nl_addr *baddr = rtnl_addr_get_broadcast((struct rtnl_addr *) obj); if (baddr) { int family = nl_addr_get_family(baddr); nl_addr2str( baddr, buf, sizeof( buf ) ); vaddress vaddr(vaddress::Family(family), vaddress::strip_netmask(std::string(buf)), ifindex, true); list->push_back( vaddr ); } }
static void get_ip(struct nl_object *obj, void *arg) { struct rtnl_addr * addr = (struct rtnl_addr *) obj; struct nl_addr *naddr = rtnl_addr_get_local(addr); int prefixlen = rtnl_addr_get_prefixlen(addr); if ((NULL != naddr) && (prefixlen == *(int*)(arg))) printf("ip is 0x%x\n", *(uint32_t *) (nl_addr_get_binary_addr(naddr))); }
static void check_addresses (NMIP6Device *device) { NMIP6Manager *manager = device->manager; NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager); struct rtnl_addr *rtnladdr; struct nl_addr *nladdr; struct in6_addr *addr; /* Reset address information */ device->has_linklocal = FALSE; device->has_nonlinklocal = FALSE; /* Look for any IPv6 addresses the kernel may have set for the device */ for (rtnladdr = (struct rtnl_addr *) nl_cache_get_first (priv->addr_cache); rtnladdr; rtnladdr = (struct rtnl_addr *) nl_cache_get_next ((struct nl_object *) rtnladdr)) { char buf[INET6_ADDRSTRLEN]; if (rtnl_addr_get_ifindex (rtnladdr) != device->ifindex) continue; nladdr = rtnl_addr_get_local (rtnladdr); if (!nladdr || nl_addr_get_family (nladdr) != AF_INET6) continue; addr = nl_addr_get_binary_addr (nladdr); if (inet_ntop (AF_INET6, addr, buf, INET6_ADDRSTRLEN) > 0) { nm_log_dbg (LOGD_IP6, "(%s): netlink address: %s/%d", device->iface, buf, rtnl_addr_get_prefixlen (rtnladdr)); } if (IN6_IS_ADDR_LINKLOCAL (addr)) { if (device->state == NM_IP6_DEVICE_UNCONFIGURED) device_set_state (device, NM_IP6_DEVICE_GOT_LINK_LOCAL); device->has_linklocal = TRUE; } else { if (device->state == NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT) device_set_state (device, NM_IP6_DEVICE_GOT_ADDRESS); device->has_nonlinklocal = TRUE; } } /* There might be a LL address hanging around on the interface from * before in the initial run, but if it goes away later, make sure we * regress from GOT_LINK_LOCAL back to UNCONFIGURED. */ if ((device->state == NM_IP6_DEVICE_GOT_LINK_LOCAL) && !device->has_linklocal) device_set_state (device, NM_IP6_DEVICE_UNCONFIGURED); nm_log_dbg (LOGD_IP6, "(%s): addresses checked (state %s)", device->iface, state_to_string (device->state)); }
static void match_first_addr(struct nl_object *obj, void *arg) { static int found = 0; struct nl_addr **addr = (struct nl_addr **)arg; if (found) return; *addr = rtnl_addr_get_local((struct rtnl_addr *)obj); nl_addr_get(*addr); /* Found, keep reference */ found = 1; }
TError TNlLink::WaitAddress(int timeout_s) { struct nl_cache *cache; int ret; L() << "Wait for autoconf at " << GetDesc() << std::endl; ret = rtnl_addr_alloc_cache(GetSock(), &cache); if (ret < 0) return Nl->Error(ret, "Cannot allocate addr cache"); do { for (auto obj = nl_cache_get_first(cache); obj; obj = nl_cache_get_next(obj)) { auto addr = (struct rtnl_addr *)obj; if (!rtnl_addr_get_local(addr) || rtnl_addr_get_ifindex(addr) != GetIndex() || rtnl_addr_get_family(addr) != AF_INET6 || rtnl_addr_get_scope(addr) >= RT_SCOPE_LINK || (rtnl_addr_get_flags(addr) & (IFA_F_TENTATIVE | IFA_F_DEPRECATED))) continue; L() << "Got " << TNlAddr(rtnl_addr_get_local(addr)).Format() << " at " << GetDesc() << std::endl; nl_cache_free(cache); return TError::Success(); } usleep(1000000); ret = nl_cache_refill(GetSock(), cache); if (ret < 0) return Nl->Error(ret, "Cannot refill address cache"); } while (--timeout_s > 0); nl_cache_free(cache); return TError(EError::Unknown, "Network autoconf timeout"); }
static void dump_address_change (NMIP6Device *device, struct nlmsghdr *hdr, struct rtnl_addr *rtnladdr) { char *event; struct nl_addr *addr; char addr_str[40] = "none"; event = hdr->nlmsg_type == RTM_NEWADDR ? "new" : "lost"; addr = rtnl_addr_get_local (rtnladdr); if (addr) nl_addr2str (addr, addr_str, 40); nm_log_dbg (LOGD_IP6, "(%s) %s address: %s", device_get_iface (device), event, addr_str); }
static gsize _j4status_nl_section_append_addresses(gchar *str, gsize size, GList *list) { gsize o = 0; GList *addr; for ( addr = list ; addr != NULL ; addr = g_list_next(addr) ) { gchar *p; nl_addr2str(rtnl_addr_get_local(addr->data), str + o, size - o); p = g_utf8_strchr(str + o, -1, '/'); g_assert_nonnull(p); /* We know libnl wrote the prefix length */ *p = '\0'; o += p - str; o += g_snprintf(str + o, size - o, ", "); } return o; }
/** * libnl callback function. Does the real parsing of a record returned by NETLINK. This function * parses ADDRESS related packets * * @param obj Pointer to a struct nl_object response * @param arg Pointer to a struct etherinfo element where the parse result will be saved */ static void callback_nl_address(struct nl_object *obj, void *arg) { struct etherinfo *ethi = (struct etherinfo *) arg; struct nl_addr *addr; char ip_str[66]; int family; if( ethi == NULL ) { return; } addr = rtnl_addr_get_local((struct rtnl_addr *)obj); family = nl_addr_get_family(addr); switch( family ) { case AF_INET: case AF_INET6: memset(&ip_str, 0, 66); inet_ntop(family, nl_addr_get_binary_addr(addr), (char *)&ip_str, 64); if( family == AF_INET ) { struct nl_addr *brdcst = rtnl_addr_get_broadcast((struct rtnl_addr *)obj); char brdcst_str[66]; SET_STR_VALUE(ethi->ipv4_address, ip_str); ethi->ipv4_netmask = rtnl_addr_get_prefixlen((struct rtnl_addr*) obj); if( brdcst ) { memset(&brdcst_str, 0, 66); inet_ntop(family, nl_addr_get_binary_addr(brdcst), (char *)&brdcst_str, 64); SET_STR_VALUE(ethi->ipv4_broadcast, brdcst_str); } } else { ethi->ipv6_addresses = etherinfo_add_ipv6(ethi->ipv6_addresses, ip_str, rtnl_addr_get_prefixlen((struct rtnl_addr*) obj), rtnl_addr_get_scope((struct rtnl_addr*) obj)); } return; default: return; } }
static void nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed) { NMIP6Manager *manager = device->manager; NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager); struct rtnl_addr *rtnladdr; struct nl_addr *nladdr; struct in6_addr *addr; CallbackInfo *info; guint dhcp_opts = IP6_DHCP_OPT_NONE; gboolean found_linklocal = FALSE, found_other = FALSE; nm_log_dbg (LOGD_IP6, "(%s): syncing with netlink (ra_flags 0x%X) (state/target '%s'/'%s')", device->iface, device->ra_flags, state_to_string (device->state), state_to_string (device->target_state)); /* Look for any IPv6 addresses the kernel may have set for the device */ for (rtnladdr = (struct rtnl_addr *) nl_cache_get_first (priv->addr_cache); rtnladdr; rtnladdr = (struct rtnl_addr *) nl_cache_get_next ((struct nl_object *) rtnladdr)) { char buf[INET6_ADDRSTRLEN]; if (rtnl_addr_get_ifindex (rtnladdr) != device->ifindex) continue; nladdr = rtnl_addr_get_local (rtnladdr); if (!nladdr || nl_addr_get_family (nladdr) != AF_INET6) continue; addr = nl_addr_get_binary_addr (nladdr); if (inet_ntop (AF_INET6, addr, buf, INET6_ADDRSTRLEN) > 0) { nm_log_dbg (LOGD_IP6, "(%s): netlink address: %s", device->iface, buf); } if (IN6_IS_ADDR_LINKLOCAL (addr)) { if (device->state == NM_IP6_DEVICE_UNCONFIGURED) device->state = NM_IP6_DEVICE_GOT_LINK_LOCAL; found_linklocal = TRUE; } else { if (device->state < NM_IP6_DEVICE_GOT_ADDRESS) device->state = NM_IP6_DEVICE_GOT_ADDRESS; found_other = TRUE; } } /* There might be a LL address hanging around on the interface from * before in the initial run, but if it goes away later, make sure we * regress from GOT_LINK_LOCAL back to UNCONFIGURED. */ if ((device->state == NM_IP6_DEVICE_GOT_LINK_LOCAL) && !found_linklocal) device->state = NM_IP6_DEVICE_UNCONFIGURED; nm_log_dbg (LOGD_IP6, "(%s): addresses synced (state %s)", device->iface, state_to_string (device->state)); /* We only care about router advertisements if we want a real IPv6 address */ if ( (device->target_state == NM_IP6_DEVICE_GOT_ADDRESS) && (device->ra_flags & IF_RA_RCVD)) { if (device->state < NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT) device->state = NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT; if (device->ra_flags & IF_RA_MANAGED) { dhcp_opts = IP6_DHCP_OPT_MANAGED; nm_log_dbg (LOGD_IP6, "router advertisement deferred to DHCPv6"); } else if (device->ra_flags & IF_RA_OTHERCONF) { dhcp_opts = IP6_DHCP_OPT_OTHERCONF; nm_log_dbg (LOGD_IP6, "router advertisement requests parallel DHCPv6"); } } if (!device->addrconf_complete) { /* Managed mode (ie DHCP only) short-circuits automatic addrconf, so * we don't bother waiting for the device's target state to be reached * when the RA requests managed mode. */ if ( (device->state >= device->target_state) || (dhcp_opts == IP6_DHCP_OPT_MANAGED)) { /* device->finish_addrconf_id may currently be a timeout * rather than an idle, so we remove the existing source. */ if (device->finish_addrconf_id) g_source_remove (device->finish_addrconf_id); nm_log_dbg (LOGD_IP6, "(%s): reached target state or Managed-mode requested (state '%s') (dhcp opts 0x%X)", device->iface, state_to_string (device->state), dhcp_opts); info = callback_info_new (device, dhcp_opts, TRUE); device->finish_addrconf_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, finish_addrconf, info, (GDestroyNotify) g_free); } } else if (config_changed) { if (!device->config_changed_id) { gboolean success = TRUE; /* If for some reason an RA-provided address disappeared, we need * to make sure we fail the connection as it's no longer valid. */ if ( (device->state == NM_IP6_DEVICE_GOT_ADDRESS) && (device->target_state == NM_IP6_DEVICE_GOT_ADDRESS) && !found_other) { nm_log_dbg (LOGD_IP6, "(%s): RA-provided address no longer valid", device->iface); success = FALSE; } info = callback_info_new (device, dhcp_opts, success); device->config_changed_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, emit_config_changed, info, (GDestroyNotify) g_free); } } }
NMIP6Config * nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, int ifindex) { NMIP6ManagerPrivate *priv; NMIP6Device *device; NMIP6Config *config; struct rtnl_addr *rtnladdr; struct nl_addr *nladdr; struct in6_addr *addr; NMIP6Address *ip6addr; struct rtnl_route *rtnlroute; struct nl_addr *nldest, *nlgateway; struct in6_addr *dest, *gateway; gboolean defgw_set = FALSE; struct in6_addr defgw; uint32_t metric; NMIP6Route *ip6route; int i; g_return_val_if_fail (NM_IS_IP6_MANAGER (manager), NULL); g_return_val_if_fail (ifindex > 0, NULL); priv = NM_IP6_MANAGER_GET_PRIVATE (manager); device = (NMIP6Device *) g_hash_table_lookup (priv->devices, GINT_TO_POINTER (ifindex)); if (!device) { nm_log_warn (LOGD_IP6, "(%d): addrconf not started.", ifindex); return NULL; } config = nm_ip6_config_new (); if (!config) { nm_log_err (LOGD_IP6, "(%s): out of memory creating IP6 config object.", device->iface); return NULL; } /* Make sure we refill the route and address caches, otherwise we won't get * up-to-date information here since the netlink route/addr change messages * may be lagging a bit. */ nl_cache_refill (priv->nlh, priv->route_cache); nl_cache_refill (priv->nlh, priv->addr_cache); /* Add routes */ for (rtnlroute = FIRST_ROUTE (priv->route_cache); rtnlroute; rtnlroute = NEXT_ROUTE (rtnlroute)) { /* Make sure it's an IPv6 route for this device */ if (rtnl_route_get_oif (rtnlroute) != device->ifindex) continue; if (rtnl_route_get_family (rtnlroute) != AF_INET6) continue; nldest = rtnl_route_get_dst (rtnlroute); if (!nldest || nl_addr_get_family (nldest) != AF_INET6) continue; dest = nl_addr_get_binary_addr (nldest); nlgateway = rtnl_route_get_gateway (rtnlroute); if (!nlgateway || nl_addr_get_family (nlgateway) != AF_INET6) continue; gateway = nl_addr_get_binary_addr (nlgateway); if (rtnl_route_get_dst_len (rtnlroute) == 0) { /* Default gateway route; don't add to normal routes but to each address */ if (!defgw_set) { memcpy (&defgw, gateway, sizeof (defgw)); defgw_set = TRUE; } continue; } /* Also ignore link-local routes where the destination and gateway are * the same, which apparently get added by the kernel but return -EINVAL * when we try to add them via netlink. */ if (gateway && IN6_ARE_ADDR_EQUAL (dest, gateway)) continue; ip6route = nm_ip6_route_new (); nm_ip6_route_set_dest (ip6route, dest); nm_ip6_route_set_prefix (ip6route, rtnl_route_get_dst_len (rtnlroute)); nm_ip6_route_set_next_hop (ip6route, gateway); rtnl_route_get_metric(rtnlroute, 1, &metric); if (metric != UINT_MAX) nm_ip6_route_set_metric (ip6route, metric); nm_ip6_config_take_route (config, ip6route); } /* Add addresses */ for (rtnladdr = FIRST_ADDR (priv->addr_cache); rtnladdr; rtnladdr = NEXT_ADDR (rtnladdr)) { if (rtnl_addr_get_ifindex (rtnladdr) != device->ifindex) continue; nladdr = rtnl_addr_get_local (rtnladdr); if (!nladdr || nl_addr_get_family (nladdr) != AF_INET6) continue; addr = nl_addr_get_binary_addr (nladdr); ip6addr = nm_ip6_address_new (); nm_ip6_address_set_prefix (ip6addr, rtnl_addr_get_prefixlen (rtnladdr)); nm_ip6_address_set_address (ip6addr, addr); nm_ip6_config_take_address (config, ip6addr); if (defgw_set) nm_ip6_address_set_gateway (ip6addr, &defgw); } /* Add DNS servers */ if (device->rdnss_servers) { NMIP6RDNSS *rdnss = (NMIP6RDNSS *)(device->rdnss_servers->data); for (i = 0; i < device->rdnss_servers->len; i++) nm_ip6_config_add_nameserver (config, &rdnss[i].addr); } /* Add DNS domains */ if (device->dnssl_domains) { NMIP6DNSSL *dnssl = (NMIP6DNSSL *)(device->dnssl_domains->data); for (i = 0; i < device->dnssl_domains->len; i++) nm_ip6_config_add_domain (config, dnssl[i].domain); } return config; }
static void nl_obj_input(struct nl_object *obj, void *arg) { struct _obj { NLHDR_COMMON }; struct _obj *o = (struct _obj *)obj; if( o->ce_msgtype == RTM_NEWLINK || o->ce_msgtype == RTM_DELLINK ) { struct rtnl_link *link = (struct rtnl_link *)obj; struct nl_addr *a = rtnl_link_get_addr(link); char buf[123]; nl_addr2str(a, buf, sizeof(buf)); int ifindex = rtnl_link_get_ifindex(link); bool active = rtnl_link_get_flags(link) & IFF_UP; char *iface = rtnl_link_get_name(link); if( o->ce_msgtype == RTM_NEWLINK ) { struct link_addr *nla = g_hash_table_lookup(nl_runtime.link_addr_cache, &ifindex); if( nla == NULL ) { g_critical("LINK NEW %s %i", iface, ifindex); struct link_addr *nla = link_addr_new(iface, ifindex, active); g_hash_table_insert(nl_runtime.link_addr_cache, &nla->ifindex, nla); }else { g_critical("LINK CHANGE %s %i", iface, ifindex); GHashTableIter iter; gpointer key, value; g_hash_table_iter_init(&iter, nla->addrs); if( active != nla->active ) { while( g_hash_table_iter_next(&iter, &key, &value) ) { struct incident *i; if( active ) { g_critical("LINK UP"); i = incident_new("dionaea.module.nl.addr.new"); }else { g_critical("LINK DOWN"); i = incident_new("dionaea.module.nl.addr.del"); } incident_value_string_set(i, "addr", g_string_new(key)); incident_value_string_set(i, "iface", g_string_new(nla->iface)); incident_value_int_set(i, "scope", nla->ifindex); incident_report(i); incident_free(i); } nla->active = active; } } }else if( o->ce_msgtype == RTM_DELLINK ) { g_critical("LINK DEL %s %i", iface, ifindex); struct link_addr *nla = g_hash_table_lookup(nl_runtime.link_addr_cache, &ifindex); g_hash_table_remove(nl_runtime.link_addr_cache, &ifindex); link_addr_free(nla); } }else if( o->ce_msgtype == RTM_NEWADDR || o->ce_msgtype == RTM_DELADDR ) { char buf[128]; struct rtnl_addr *addr = (struct rtnl_addr *)obj; struct nl_addr *a = rtnl_addr_get_local(addr); int ifindex = rtnl_addr_get_ifindex(addr); nl_addr2str(a, buf, 128); char *slash; if( (slash = strstr(buf, "/")) != NULL) *slash = '\0'; char *saddr = NULL; struct link_addr *nla = g_hash_table_lookup(nl_runtime.link_addr_cache, &ifindex); if( !nla ) return; if( o->ce_msgtype == RTM_NEWADDR ) { if( g_hash_table_lookup(nla->addrs, buf) == NULL ) { g_warning("NEW ADDR %s!", buf); saddr = g_strdup(buf); g_hash_table_insert(nla->addrs, saddr, saddr); if( nla->active ) { struct incident *i = incident_new("dionaea.module.nl.addr.new"); incident_value_string_set(i, "addr", g_string_new(saddr)); incident_value_string_set(i, "iface", g_string_new(nla->iface)); incident_value_int_set(i, "scope", nla->ifindex); incident_report(i); incident_free(i); } } }else if( o->ce_msgtype == RTM_DELADDR ) { if( ( saddr = g_hash_table_lookup(nla->addrs, buf) ) != NULL ) { g_warning("DEL ADDR! %s", buf); if( nla->active ) { struct incident *i = incident_new("dionaea.module.nl.addr.del"); incident_value_string_set(i, "addr", g_string_new(saddr)); incident_value_string_set(i, "iface", g_string_new(nla->iface)); incident_value_int_set(i, "scope", nla->ifindex); incident_report(i); incident_free(i); } g_hash_table_remove(nla->addrs, buf); g_free(saddr); } } } /* struct nl_dump_params dp = { .dp_type = NL_DUMP_STATS, .dp_fd = stdout, .dp_dump_msgtype = 1, }; nl_object_dump(obj, &dp); struct nl_dump_params params = { .dp_type = NL_DUMP_LINE, .dp_fd = stdout, .dp_prefix = 1, }; g_debug("addr cache"); nl_cache_dump(nl_runtime.addr_cache, ¶ms); g_debug("arp cache"); nl_cache_dump(nl_runtime.neigh_cache, ¶ms); g_debug("link cache"); nl_cache_dump(nl_runtime.link_cache, ¶ms); */ }
static void env_dump(struct nl_object *obj, void *arg) { struct nl_dump_params *p = arg; struct rtnl_addr *addr = (struct rtnl_addr *) obj; struct nl_cache *link_cache; struct nl_addr *a; static int index = 0; char buf[128], pfx[32], *s; snprintf(pfx, sizeof(pfx), "ADDR%d", index++); nl_dump_line(p, "%s_FAMILY=%s\n", pfx, nl_af2str(rtnl_addr_get_family(addr), buf, sizeof(buf))); nl_dump_line(p, "%s_LOCAL=%s\n", pfx, nl_addr2str(rtnl_addr_get_local(addr), buf, sizeof(buf))); nl_dump_line(p, "%s_IFINDEX=%u\n", pfx, rtnl_addr_get_ifindex(addr)); link_cache = nl_cache_mngt_require_safe("route/link"); if (link_cache) nl_dump_line(p, "%s_IFNAME=%s\n", pfx, rtnl_link_i2name(link_cache, rtnl_addr_get_ifindex(addr), buf, sizeof(buf))); if ((a = rtnl_addr_get_peer(addr))) nl_dump_line(p, "%s_PEER=%s\n", pfx, nl_addr2str(a, buf, sizeof(buf))); if ((a = rtnl_addr_get_broadcast(addr))) nl_dump_line(p, "%s_BROADCAST=%s\n", pfx, nl_addr2str(a, buf, sizeof(buf))); nl_dump_line(p, "%s_SCOPE=%s\n", pfx, rtnl_scope2str(rtnl_addr_get_scope(addr), buf, sizeof(buf))); if ((s = rtnl_addr_get_label(addr))) nl_dump_line(p, "%s_LABEL=%s\n", pfx, s); rtnl_addr_flags2str(rtnl_addr_get_flags(addr), buf, sizeof(buf)); if (buf[0]) nl_dump_line(p, "%s_FLAGS=%s\n", pfx, buf); nl_dump_line(p, "%s_CACHEINFO_VALID=%u\n", pfx, rtnl_addr_get_valid_lifetime(addr)); if (link_cache) nl_cache_put(link_cache); #if 0 if (addr->ce_mask & ADDR_ATTR_CACHEINFO) { struct rtnl_addr_cacheinfo *ci = &addr->a_cacheinfo; nl_dump_line(p, "ADDR_CACHEINFO_PREFERRED=%u\n", ci->aci_prefered); nl_dump_line(p, "ADDR_CACHEINFO_CREATED=%u\n", ci->aci_cstamp); nl_dump_line(p, "ADDR_CACHEINFO_LASTUPDATE=%u\n", ci->aci_tstamp); } #endif }