static void nl_parse_addr_msg(struct nlmsghdr *nlp, struct nl_cb *cb) { struct ifaddrmsg *ifaddr; struct rtattr *rtap; nl_addr_cb addr_cb; size_t len; in_addr_t *addr; struct nl_addr nl_addr; addr = NULL; ifaddr = NLMSG_DATA(nlp); rtap = IFLA_RTA(ifaddr); len = IFLA_PAYLOAD(nlp); for (; RTA_OK(rtap, len); rtap = RTA_NEXT(rtap, len)) { switch (rtap->rta_type) { case IFA_LOCAL: addr = (in_addr_t*)RTA_DATA(rtap); break; default: break; } } if (!addr) { XLOG_ERR("could not get addr for link %u", ifaddr->ifa_index); return; } addr_cb = (nl_addr_cb) cb->parse_cb; nl_addr.ifindex = ifaddr->ifa_index; nl_addr.ifaddr = *addr; addr_cb(&nl_addr , cb->aux); }
void linux_unicast_router::handle_intf_event(bool isnew, nlmsghdr *hdr) { ifinfomsg *ifi = (ifinfomsg *)NLMSG_DATA(hdr); if (isnew) { rtattr *tb[IFLA_MAX + 1]; memset(tb, 0, sizeof(tb)); netlink_msg::parse_rtatable(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(hdr)); if (tb[IFLA_IFNAME] && tb[IFLA_MTU]) { interface_desc desc; desc.index = ifi->ifi_index; desc.name = (const char *)RTA_DATA(tb[IFLA_IFNAME]); desc.mtu = *(int *)RTA_DATA(tb[IFLA_MTU]); desc.flags = ifi->ifi_flags; desc.type = _conv_intf(ifi->ifi_type, ifi->ifi_flags); desc.up = ((ifi->ifi_flags & IFF_UP) == IFF_UP); if (rt_dumping) { _interfaces.push_back(desc); } else { _install_interface(desc); } } } else { g_mrd->lost_interface(ifi->ifi_index); } }
static void test_container(void) { _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL; uint16_t type; uint32_t u32_data; void *data; int r; struct ifinfomsg *ifi; assert_se(sd_rtnl_message_new_link(NULL, &m, RTM_NEWLINK, 0) >= 0); assert_se(sd_rtnl_message_open_container(m, IFLA_LINKINFO) >= 0); assert_se(sd_rtnl_message_open_container(m, IFLA_LINKINFO) == -ENOTSUP); assert_se(sd_rtnl_message_append_string(m, IFLA_INFO_KIND, "kind") >= 0); assert_se(sd_rtnl_message_open_container(m, IFLA_INFO_DATA) >= 0); assert_se(sd_rtnl_message_open_container(m, IFLA_INFO_DATA) == -ENOTSUP); assert_se(sd_rtnl_message_append_u16(m, IFLA_VLAN_ID, 100) >= 0); assert_se(sd_rtnl_message_close_container(m) >= 0); assert_se(sd_rtnl_message_append_string(m, IFLA_INFO_KIND, "kind") >= 0); assert_se(sd_rtnl_message_close_container(m) >= 0); assert_se(sd_rtnl_message_close_container(m) == -EINVAL); assert_se(rtnl_message_seal(NULL, m) >= 0); assert_se(sd_rtnl_message_read(m, &type, &data) >= 0); assert_se(type == IFLA_LINKINFO); assert_se(data == NULL); /* assert_se(sd_rtnl_message_read(m, &type, &data) >= 0); assert_se(type == IFLA_INFO_KIND); assert_se(streq("kind", (char *)data)); assert_se(sd_rtnl_message_read(m, &type, &data) >= 0); assert_se(type == IFLA_INFO_DATA); assert_se(data == NULL); assert_se(sd_rtnl_message_read(m, &type, &data) >= 0); assert_se(type == IFLA_VLAN_ID); assert_se(*(uint16_t *)data == 100); assert_se(sd_rtnl_message_read(m, &type, &data) == 0); assert_se(sd_rtnl_message_exit_container(m) >= 0); assert_se(sd_rtnl_message_read(m, &type, &data) >= 0); assert_se(type == IFLA_INFO_KIND); assert_se(streq("kind", (char *)data)); assert_se(sd_rtnl_message_read(m, &type, &data) == 0); assert_se(sd_rtnl_message_exit_container(m) >= 0); */ ifi = NLMSG_DATA(m->hdr); r = rtnl_message_parse(m, &m->rta_offset_tb, &m->rta_tb_size, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(m->hdr)); if(r < 0) return; assert_se(sd_rtnl_message_read_u32(m, IFLA_LINKINFO, &u32_data) == 0); assert_se(sd_rtnl_message_exit_container(m) == -EINVAL); }
int if_info_save_interface(struct nlmsghdr *hdr, void *arg) { struct rtattr *attrs[IFLA_MAX + 1]; struct ifinfomsg *info = NLMSG_DATA(hdr); parse_rtattrs(attrs, IFLA_MAX, IFLA_RTA(info), IFLA_PAYLOAD(hdr)); return if_info_update_interface(hdr, attrs) ? 0 : -1; }
static void ril_mtu_watch_handle_nlmsg(struct ril_mtu_watch *self, const struct nlmsghdr *hdr, int len) { while (len > 0 && NLMSG_OK(hdr, len)) { if (hdr->nlmsg_type == RTM_NEWLINK) { ril_mtu_watch_handle_ifinfomsg(self, NLMSG_DATA(hdr), IFLA_PAYLOAD(hdr)); } hdr = NLMSG_NEXT(hdr, len); } }
int ll_remember_index(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { int h; struct ifinfomsg *ifi = NLMSG_DATA(n); struct ll_cache *im, **imp; struct rtattr *tb[IFLA_MAX+1]; UNUSED(who); UNUSED(arg); if (n->nlmsg_type != RTM_NEWLINK) return 0; if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi))) return -1; memset(tb, 0, sizeof(tb)); parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n)); if (tb[IFLA_IFNAME] == NULL) return 0; h = ifi->ifi_index & (IDXMAP_SIZE - 1); for (imp = &idx_head[h]; (im=*imp)!=NULL; imp = &im->idx_next) if (im->index == ifi->ifi_index) break; if (im == NULL) { im = malloc(sizeof(*im)); if (im == NULL) return 0; im->idx_next = *imp; im->index = ifi->ifi_index; *imp = im; } im->type = ifi->ifi_type; im->flags = ifi->ifi_flags; if (tb[IFLA_ADDRESS]) { size_t alen; im->alen = alen = RTA_PAYLOAD(tb[IFLA_ADDRESS]); if (alen > sizeof(im->addr)) alen = sizeof(im->addr); memcpy(im->addr, RTA_DATA(tb[IFLA_ADDRESS]), alen); } else { im->alen = 0; memset(im->addr, 0, sizeof(im->addr)); } strcpy(im->name, RTA_DATA(tb[IFLA_IFNAME])); return 0; }
static int handle_link_msg(struct nlmsghdr *nlh, int n) { struct ifinfomsg *ifla_msg = NLMSG_DATA(nlh); struct rtattr *tb[IFLA_MAX]; int atts = parse_rt_attrs(tb, IFLA_MAX, IFLA_RTA(ifla_msg), IFLA_PAYLOAD(nlh)); parse_ifinfomsg(ifla_msg); handle_link_attrs(ifla_msg, tb, nlh->nlmsg_type); return 0; }
rtnetlink::if_addr& rtnetlink::if_addr::operator=(message& msg) { static_cast<data&>(*this) = msg; std::pair<const void*, size_t> pl = msg.payload(); if (msg.type() < 20 || msg.type() > 23 || pl.second < sizeof(::ifaddrmsg)) throw "bad msg type"; const ::ifaddrmsg* ifa = reinterpret_cast<const ifaddrmsg*>(pl.first); _family = ifa->ifa_family; _prefixlen = ifa->ifa_prefixlen; _scope = ifa->ifa_scope; _flags = ifa->ifa_flags; _index = ifa->ifa_index; const ::rtattr* rta = IFLA_RTA(ifa); size_t attrlen = IFLA_PAYLOAD(reinterpret_cast<const ::nlmsghdr*>(_msg->header())); for (; RTA_OK(rta, attrlen); rta = RTA_NEXT(rta, attrlen)) { switch (rta->rta_type) { case IFA_ADDRESS: _address = attr<void>(RTA_DATA(rta), RTA_PAYLOAD(rta)); break; case IFA_LOCAL: _local = attr<void>(RTA_DATA(rta), RTA_PAYLOAD(rta)); break; case IFA_LABEL: _label = attr<char>(RTA_DATA(rta), RTA_PAYLOAD(rta)); break; case IFA_BROADCAST: _broadcast = attr<void>(RTA_DATA(rta), RTA_PAYLOAD(rta)); break; case IFA_ANYCAST: _anycast = attr<void>(RTA_DATA(rta), RTA_PAYLOAD(rta)); break; default: std::cout << "IFA_UNSPEC(" << rta->rta_type << ", " << RTA_PAYLOAD(rta) << ")\n"; } } return *this; }
static void nl_parse_link_msg(struct nlmsghdr *nlp, struct nl_cb *cb) { nl_link_cb link_cb; struct ifinfomsg *ifinfo; struct rtattr *rtap; struct nl_link link; size_t len; memset(&link, 0, sizeof(struct nl_link)); ifinfo = NLMSG_DATA(nlp); rtap = IFLA_RTA(ifinfo); len = IFLA_PAYLOAD(nlp); for (; RTA_OK(rtap, len); rtap = RTA_NEXT(rtap, len)) { switch (rtap->rta_type) { case IFLA_IFNAME: link.ifname = (char *)RTA_DATA(rtap); break; case IFLA_ADDRESS: if (RTA_PAYLOAD(rtap) != sizeof(struct ether_addr)) { XLOG_ERR("invalid ll address for %u", ifinfo->ifi_index); return; } link.ifaddr = (struct ether_addr *)RTA_DATA(rtap); break; default: /* XLOG_DEBUG("attr: %u", rtap->rta_type); */ break; } } if (!link.ifname) { XLOG_ERR("could not get name for link %u", ifinfo->ifi_index); return; } if (!link.ifaddr) { XLOG_ERR("could not get ll addr for link %u", ifinfo->ifi_index); return; } link.ifindex = ifinfo->ifi_index; link.iftype = ifinfo->ifi_type; link.ifflags = ifinfo->ifi_flags; link_cb = (nl_link_cb) cb->parse_cb; link_cb(&link, cb->aux); }
static inline uint8_t process_data ( bt_addresses * addresses, struct nlmsghdr * data, bool add ) { bt_address * address = parse_address ( addresses, NLMSG_DATA ( data ), IFLA_PAYLOAD ( data ) ); if ( address == NULL ) { return 1; } if ( add ) { ; } else { ; } return 0; }
static gboolean is_wireless_status_message (struct nlmsghdr *header) { int rt_attr_len; struct rtattr *rt_attr; rt_attr = IFLA_RTA (NLMSG_DATA (header)); rt_attr_len = IFLA_PAYLOAD (header); while (RT_ATTR_OK (rt_attr, rt_attr_len)) { if (rt_attr->rta_type == IFLA_WIRELESS) return TRUE; rt_attr = RTA_NEXT (rt_attr, rt_attr_len); } return FALSE; }
static void extract_info (struct nlmsghdr *header, char **label) { int rt_attr_len; struct rtattr *rt_attr; rt_attr = IFLA_RTA (NLMSG_DATA (header)); rt_attr_len = IFLA_PAYLOAD (header); while (RT_ATTR_OK (rt_attr, rt_attr_len)) { if (rt_attr->rta_type == IFA_LABEL) { *label = g_strdup ((char *) RTA_DATA (rt_attr)); break; } rt_attr = RTA_NEXT (rt_attr, rt_attr_len); } }
/* iftable_del - Delete an entry from the interface table * @n: netlink message header of a RTM_DELLINK nlmsg * @arg: not used * * Delete an entry from the interface table. * Returns -1 on error, 0 if no matching entry was found or 1 on success. */ static int iftable_del(struct nlmsghdr *n, void *arg) { struct ifinfomsg *ifi_msg = NLMSG_DATA(n); struct rtattr *cb[IFLA_MAX+1]; struct nlif_handle *nlif_handle = (struct nlif_handle *)arg; struct ifindex_map *im, *ima, **imp; unsigned int hash; if (n->nlmsg_type != RTM_DELLINK) { iftb_log(LOG_ERROR, "called with wrong nlmsg_type %u", n->nlmsg_type); return -1; } if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi_msg))) { iftb_log(LOG_ERROR, "short message (%u < %u)", n->nlmsg_len, NLMSG_LENGTH(sizeof(ifi_msg))); return -1; } memset(&cb, 0, sizeof(cb)); rtnl_parse_rtattr(cb, IFLA_MAX, IFLA_RTA(ifi_msg), IFLA_PAYLOAD(n)); /* \todo Really suppress entry */ hash = ifi_msg->ifi_index&0xF; for (ima = NULL, imp = &((nlif_handle->ifindex_map)[hash]); (im=*imp)!=NULL; imp = &im->next, ima=im) { if (im->index == ifi_msg->ifi_index) { iftb_log(LOG_DEBUG, "deleting iftable (ifindex=%u)", im->index); break; } } if (!im) return 0; if (ima) ima->next = *imp; else (nlif_handle->ifindex_map)[hash] = *imp; free(im); return 1; }
static void __if_nameindex_callback(void* context, nlmsghdr* hdr) { if_list** list = reinterpret_cast<if_list**>(context); if (hdr->nlmsg_type == RTM_NEWLINK) { ifinfomsg* ifi = reinterpret_cast<ifinfomsg*>(NLMSG_DATA(hdr)); // Create a new entry and set the interface index. if_list* new_link = new if_list(list); new_link->data.if_index = ifi->ifi_index; // Go through the various bits of information and find the name. rtattr* rta = IFLA_RTA(ifi); size_t rta_len = IFLA_PAYLOAD(hdr); while (RTA_OK(rta, rta_len)) { if (rta->rta_type == IFLA_IFNAME) { new_link->data.if_name = strndup(reinterpret_cast<char*>(RTA_DATA(rta)), RTA_PAYLOAD(rta)); } rta = RTA_NEXT(rta, rta_len); } } }
/* * Parse a RTM_NEWLINK message. */ bool NetlinkEvent::parseIfInfoMessage(const struct nlmsghdr *nh) { struct ifinfomsg *ifi = (struct ifinfomsg *) NLMSG_DATA(nh); if (!checkRtNetlinkLength(nh, sizeof(*ifi))) return false; if ((ifi->ifi_flags & IFF_LOOPBACK) != 0) { return false; } int len = IFLA_PAYLOAD(nh); struct rtattr *rta; for (rta = IFLA_RTA(ifi); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) { switch(rta->rta_type) { case IFLA_IFNAME: asprintf(&mParams[0], "INTERFACE=%s", (char *) RTA_DATA(rta)); mAction = (ifi->ifi_flags & IFF_LOWER_UP) ? NlActionLinkUp : NlActionLinkDown; mSubsystem = strdup("net"); return true; } } return false; }
static void __handle_netlink_response(ifaddrs** out, nlmsghdr* hdr) { if (hdr->nlmsg_type == RTM_NEWLINK) { ifinfomsg* ifi = reinterpret_cast<ifinfomsg*>(NLMSG_DATA(hdr)); // Create a new ifaddr entry, and set the interface index and flags. ifaddrs_storage* new_addr = new ifaddrs_storage(out); new_addr->interface_index = ifi->ifi_index; new_addr->ifa.ifa_flags = ifi->ifi_flags; // Go through the various bits of information and find the name. rtattr* rta = IFLA_RTA(ifi); size_t rta_len = IFLA_PAYLOAD(hdr); while (RTA_OK(rta, rta_len)) { if (rta->rta_type == IFLA_ADDRESS) { if (RTA_PAYLOAD(rta) < sizeof(new_addr->addr)) { new_addr->SetAddress(AF_PACKET, RTA_DATA(rta), RTA_PAYLOAD(rta)); new_addr->SetPacketAttributes(ifi->ifi_index, ifi->ifi_type, RTA_PAYLOAD(rta)); } } else if (rta->rta_type == IFLA_BROADCAST) { if (RTA_PAYLOAD(rta) < sizeof(new_addr->ifa_ifu)) { new_addr->SetBroadcastAddress(AF_PACKET, RTA_DATA(rta), RTA_PAYLOAD(rta)); new_addr->SetPacketAttributes(ifi->ifi_index, ifi->ifi_type, RTA_PAYLOAD(rta)); } } else if (rta->rta_type == IFLA_IFNAME) { if (RTA_PAYLOAD(rta) < sizeof(new_addr->name)) { memcpy(new_addr->name, RTA_DATA(rta), RTA_PAYLOAD(rta)); new_addr->ifa.ifa_name = new_addr->name; } } rta = RTA_NEXT(rta, rta_len); } } else if (hdr->nlmsg_type == RTM_NEWADDR) { ifaddrmsg* msg = reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(hdr)); // We should already know about this from an RTM_NEWLINK message. const ifaddrs_storage* addr = reinterpret_cast<const ifaddrs_storage*>(*out); while (addr != nullptr && addr->interface_index != static_cast<int>(msg->ifa_index)) { addr = reinterpret_cast<const ifaddrs_storage*>(addr->ifa.ifa_next); } // If this is an unknown interface, ignore whatever we're being told about it. if (addr == nullptr) return; // Create a new ifaddr entry and copy what we already know. ifaddrs_storage* new_addr = new ifaddrs_storage(out); // We can just copy the name rather than look for IFA_LABEL. strcpy(new_addr->name, addr->name); new_addr->ifa.ifa_name = new_addr->name; new_addr->ifa.ifa_flags = addr->ifa.ifa_flags; new_addr->interface_index = addr->interface_index; // Go through the various bits of information and find the address // and any broadcast/destination address. rtattr* rta = IFA_RTA(msg); size_t rta_len = IFA_PAYLOAD(hdr); while (RTA_OK(rta, rta_len)) { if (rta->rta_type == IFA_ADDRESS) { if (msg->ifa_family == AF_INET || msg->ifa_family == AF_INET6) { new_addr->SetAddress(msg->ifa_family, RTA_DATA(rta), RTA_PAYLOAD(rta)); new_addr->SetNetmask(msg->ifa_family, msg->ifa_prefixlen); } } else if (rta->rta_type == IFA_BROADCAST) { if (msg->ifa_family == AF_INET || msg->ifa_family == AF_INET6) { new_addr->SetBroadcastAddress(msg->ifa_family, RTA_DATA(rta), RTA_PAYLOAD(rta)); } } rta = RTA_NEXT(rta, rta_len); } } }
static int print_interfaces() { int sock, len; struct nlmsghdr *nlm; struct iovec iov; struct msghdr rtnl_msg; struct sockaddr_nl s_nl; struct { struct nlmsghdr nh; struct rtgenmsg rtgm; } req; char buf[8192]; printf("Network interfaces:\n"); /* open netlink socket */ sock = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); if (sock < 0) { perror("sock"); return 1; } /* initialize request */ memset(&req, 0, sizeof(req)); req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.rtgm)); req.nh.nlmsg_type = RTM_GETLINK; req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; req.nh.nlmsg_seq = 1; req.nh.nlmsg_pid = getpid(); req.rtgm.rtgen_family = AF_PACKET; memset(&s_nl, 0, sizeof(s_nl)); s_nl.nl_family = AF_NETLINK; iov.iov_base = &req; iov.iov_len = req.nh.nlmsg_len; memset(&rtnl_msg, 0, sizeof(rtnl_msg)); rtnl_msg.msg_iov = &iov; rtnl_msg.msg_iovlen = 1; rtnl_msg.msg_name = &s_nl; rtnl_msg.msg_namelen = sizeof(s_nl); /* send request */ len = sendmsg(sock, &rtnl_msg, 0); if (len < 0) { perror("sendmsg"); close(sock); return 1; } int end = 0; while (!end) { iov.iov_base = buf; iov.iov_len = sizeof(buf); memset(&rtnl_msg, 0, sizeof(rtnl_msg)); rtnl_msg.msg_iov = &iov; rtnl_msg.msg_iovlen = 1; rtnl_msg.msg_name = &s_nl; rtnl_msg.msg_namelen = sizeof(s_nl); /* receive response */ len = recvmsg(sock, &rtnl_msg, 0); if (len < 0) { perror("recvmsg"); close(sock); return 1; } /* read response */ nlm = (struct nlmsghdr*)buf; while (NLMSG_OK(nlm, len)) { if (nlm->nlmsg_type == NLMSG_DONE) { end = 1; break; } else if (nlm->nlmsg_type == RTM_NEWLINK) { struct ifinfomsg *ifinfo; struct rtattr *rta; int iflen; ifinfo = NLMSG_DATA(nlm); rta = IFLA_RTA(ifinfo); iflen = IFLA_PAYLOAD(nlm); while (RTA_OK(rta, iflen)) { if (rta->rta_type == IFLA_IFNAME) printf(" %s\n", (char*)RTA_DATA(rta)); rta = RTA_NEXT(rta, iflen); } } nlm = NLMSG_NEXT(nlm, len); } } close(sock); return 0; }
void read_ifaces(void) { struct sockaddr_nl addr; socklen_t addr_len = sizeof(addr); unsigned char buffer[4096]; int sock, len; struct { struct nlmsghdr nlh; struct rtgenmsg g; }req; print_dbg(0, "Searching for network interfaces...\n"); sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (sock < 0) { perror("socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE) failed"); exit(1); } memset(&addr, 0, sizeof(addr)); addr.nl_family = AF_NETLINK; if (bind(sock, (struct sockaddr*)&addr, addr_len) < 0) { perror("bind(AF_NETLINK) failed"); exit(1); } req.nlh.nlmsg_len = sizeof(req); req.nlh.nlmsg_type = RTM_GETLINK; req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST; req.nlh.nlmsg_pid = 0; req.nlh.nlmsg_seq = 1; req.g.rtgen_family = AF_PACKET; if (sendto(sock, (void*)&req, sizeof(req), 0, (struct sockaddr*)&addr, sizeof(addr)) < 0) { perror("inarpd: sendto(RTM_GETLINK) failed"); exit(1); } while(1) { struct nlmsghdr *h = (struct nlmsghdr*)buffer; if ((len = recv(sock, buffer, sizeof(buffer), 0)) < 0) { perror("recv() failed"); exit(1); } while (len > 0) { if (!NLMSG_OK(h, (unsigned) len)) { error("NLMSG 0x%X not OK\n", h->nlmsg_type); break; } print_dbg(2, "NLMSG 0x%X\n", h->nlmsg_type); if (h->nlmsg_type == RTM_NEWLINK) parse_link(NLMSG_DATA(h), IFLA_PAYLOAD(h)); else if (h->nlmsg_type == RTM_NEWADDR) parse_addr(NLMSG_DATA(h), IFA_PAYLOAD(h)); else if (h->nlmsg_type == NLMSG_DONE) { if (req.nlh.nlmsg_type == RTM_GETADDR) { close(sock); return; } req.nlh.nlmsg_type = RTM_GETADDR; if (sendto(sock, (void*)&req, sizeof(req), 0, (struct sockaddr*)&addr, sizeof(addr)) < 0) { perror("inarpd: sendto(RTM_GETADDR)" " failed"); exit(1); } break; } else error("Unknown netlink message type 0x%X\n", h->nlmsg_type); h = NLMSG_NEXT(h, len); } } }
static void rtnl_print_ifinfo(struct nlmsghdr *hdr) { struct ifinfomsg *ifi = NLMSG_DATA(hdr); struct rtattr *attr = IFLA_RTA(ifi); uint32_t attrs_len = IFLA_PAYLOAD(hdr); char flags[256]; char if_addr[64] = {}; char *af_link = "unknown"; if (hdr->nlmsg_len < NLMSG_LENGTH(sizeof(*ifi))) return; if (ifi->ifi_family == AF_UNSPEC) af_link = "unspec"; else if (ifi->ifi_family == AF_BRIDGE) af_link = "bridge"; tprintf(" [ Link Family %d (%s%s%s)", ifi->ifi_family, colorize_start(bold), af_link, colorize_end()); tprintf(", Type %d (%s%s%s)", ifi->ifi_type, colorize_start(bold), device_type2str(ifi->ifi_type), colorize_end()); tprintf(", Index %d", ifi->ifi_index); tprintf(", Flags 0x%x (%s%s%s)", ifi->ifi_flags, colorize_start(bold), rtnl_link_flags2str(ifi->ifi_flags, flags, sizeof(flags)), colorize_end()); tprintf(", Change 0x%x (%s%s%s) ]\n", ifi->ifi_change, colorize_start(bold), rtnl_link_flags2str(ifi->ifi_change, flags, sizeof(flags)), colorize_end()); for (; RTA_OK(attr, attrs_len); attr = RTA_NEXT(attr, attrs_len)) { switch (attr->rta_type) { case IFLA_ADDRESS: rta_fmt(attr, "Address %s", device_addr2str(RTA_DATA(attr), RTA_LEN(attr), ifi->ifi_type, if_addr, sizeof(if_addr))); break; case IFLA_BROADCAST: rta_fmt(attr, "Broadcast %s", device_addr2str(RTA_DATA(attr), RTA_LEN(attr), ifi->ifi_type, if_addr, sizeof(if_addr))); break; case IFLA_IFNAME: rta_fmt(attr, "Name %s%s%s", colorize_start(bold), RTA_STR(attr), colorize_end()); break; case IFLA_MTU: rta_fmt(attr, "MTU %d", RTA_INT(attr)); break; case IFLA_LINK: rta_fmt(attr, "Link %d", RTA_INT(attr)); break; case IFLA_QDISC: rta_fmt(attr, "QDisc %s", RTA_STR(attr)); break; case IFLA_OPERSTATE: { uint8_t st = RTA_UINT8(attr); char states[256]; rta_fmt(attr, "Operation state 0x%x (%s%s%s)", st, colorize_start(bold), rtnl_link_operstate2str(st, states, sizeof(states)), colorize_end()); } break; case IFLA_LINKMODE: { uint8_t mode = RTA_UINT8(attr); char str[32]; rta_fmt(attr, "Mode 0x%x (%s%s%s)", mode, colorize_start(bold), rtnl_link_mode2str(mode, str, sizeof(str)), colorize_end()); } break; case IFLA_GROUP: rta_fmt(attr, "Group %d", RTA_INT(attr)); break; case IFLA_TXQLEN: rta_fmt(attr, "Tx queue len %d", RTA_INT(attr)); break; case IFLA_NET_NS_PID: rta_fmt(attr, "Network namespace pid %d", RTA_INT(attr)); break; case IFLA_NET_NS_FD: rta_fmt(attr, "Network namespace fd %d", RTA_INT(attr)); break; default: rta_fmt(attr, "0x%x", attr->rta_type); break; } } }
static int netlink_receive(struct netlink_fd *fd, struct nlmsghdr *reply) { struct sockaddr_nl nladdr; struct iovec iov; struct msghdr msg = { .msg_name = &nladdr, .msg_namelen = sizeof(nladdr), .msg_iov = &iov, .msg_iovlen = 1, }; int got_reply = FALSE, len; char buf[16*1024]; iov.iov_base = buf; while (!got_reply) { int status; struct nlmsghdr *h; iov.iov_len = sizeof(buf); status = recvmsg(fd->fd, &msg, MSG_DONTWAIT); if (status < 0) { if (errno == EINTR) continue; if (errno == EAGAIN) return reply == NULL; fprintf(stderr, "Netlink overrun\n"); continue; } if (status == 0) { fprintf(stderr, "Netlink returned EOF\n"); return FALSE; } h = (struct nlmsghdr *) buf; while (NLMSG_OK(h, status)) { if (reply != NULL && h->nlmsg_seq == reply->nlmsg_seq) { len = h->nlmsg_len; if (len > reply->nlmsg_len) { fprintf(stderr, "Netlink message " "truncated\n"); len = reply->nlmsg_len; } memcpy(reply, h, len); got_reply = TRUE; } else if (h->nlmsg_type != NLMSG_DONE) { fprintf(stderr, "Unknown NLmsg: 0x%08x, len %d\n", h->nlmsg_type, h->nlmsg_len); } h = NLMSG_NEXT(h, status); } } return TRUE; } static int netlink_send(struct netlink_fd *fd, struct nlmsghdr *req) { struct sockaddr_nl nladdr; struct iovec iov = { .iov_base = (void*) req, .iov_len = req->nlmsg_len }; struct msghdr msg = { .msg_name = &nladdr, .msg_namelen = sizeof(nladdr), .msg_iov = &iov, .msg_iovlen = 1, }; int status; memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; req->nlmsg_seq = ++fd->seq; status = sendmsg(fd->fd, &msg, 0); if (status < 0) { fprintf(stderr, "Cannot talk to rtnetlink\n"); return FALSE; } return TRUE; } static int netlink_talk(struct nlmsghdr *req, size_t replysize, struct nlmsghdr *reply) { struct netlink_fd fd; int ret = FALSE; if (!netlink_open(&fd)) return FALSE; if (reply == NULL) req->nlmsg_flags |= NLM_F_ACK; if (!netlink_send(&fd, req)) goto out; if (reply != NULL) { reply->nlmsg_len = replysize; ret = netlink_receive(&fd, reply); } else { ret = TRUE; } out: netlink_close(&fd); return ret; } int netlink_route_get(struct sockaddr *dst, u_int16_t *mtu, char *ifname) { struct { struct nlmsghdr n; union { struct rtmsg r; struct ifinfomsg i; }; char buf[1024]; } req; struct rtmsg *r = NLMSG_DATA(&req.n); struct rtattr *rta[RTA_MAX+1]; struct rtattr *rtax[RTAX_MAX+1]; struct rtattr *ifla[IFLA_MAX+1]; int index; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_GETROUTE; req.r.rtm_family = dst->sa_family; netlink_add_rtaddr_l(&req.n, sizeof(req), RTA_DST, dst); req.r.rtm_dst_len = 32; if (!netlink_talk(&req.n, sizeof(req), &req.n)) return FALSE; netlink_parse_rtattr(rta, RTA_MAX, RTM_RTA(r), RTM_PAYLOAD(&req.n)); if (mtu != NULL) { if (rta[RTA_METRICS] == NULL) return FALSE; netlink_parse_rtattr(rtax, RTAX_MAX, RTA_DATA(rta[RTA_METRICS]), RTA_PAYLOAD(rta[RTA_METRICS])); if (rtax[RTAX_MTU] == NULL) return FALSE; *mtu = *(int*) RTA_DATA(rtax[RTAX_MTU]); } if (ifname != NULL) { if (rta[RTA_OIF] == NULL) return FALSE; index = *(int*) RTA_DATA(rta[RTA_OIF]); memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_GETLINK; req.i.ifi_index = index; if (!netlink_talk(&req.n, sizeof(req), &req.n)) return FALSE; netlink_parse_rtattr(ifla, IFLA_MAX, IFLA_RTA(r), IFLA_PAYLOAD(&req.n)); if (ifla[IFLA_IFNAME] == NULL) return FALSE; memcpy(ifname, RTA_DATA(ifla[IFLA_IFNAME]), RTA_PAYLOAD(ifla[IFLA_IFNAME])); } return TRUE; }
/* iftable_add - Add/Update an entry to/in the interface table * @n: netlink message header of a RTM_NEWLINK message * @arg: not used * * This function adds/updates an entry in the intrface table. * Returns -1 on error, 1 on success. */ static int iftable_add(struct nlmsghdr *n, void *arg) { unsigned int hash; struct ifinfomsg *ifi_msg = NLMSG_DATA(n); struct ifindex_map *im, **imp; struct rtattr *cb[IFLA_MAX+1]; struct nlif_handle *nlif_handle = (struct nlif_handle *)arg; if (n->nlmsg_type != RTM_NEWLINK) return -1; if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi_msg))) { iftb_log(LOG_ERROR, "short message (%u < %u)", n->nlmsg_len, NLMSG_LENGTH(sizeof(ifi_msg))); return -1; } memset(&cb, 0, sizeof(cb)); rtnl_parse_rtattr(cb, IFLA_MAX, IFLA_RTA(ifi_msg), IFLA_PAYLOAD(n)); if (!cb[IFLA_IFNAME]) { iftb_log(LOG_ERROR, "interface without name?"); return -1; } hash = ifi_msg->ifi_index&0xF; for (imp = &((nlif_handle->ifindex_map)[hash]); (im=*imp)!=NULL; imp = &im->next) { if (im->index == ifi_msg->ifi_index) { iftb_log(LOG_DEBUG, "updating iftable (ifindex=%u)", im->index); break; } } if (!im) { im = malloc(sizeof(*im)); if (!im) { iftb_log(LOG_ERROR, "ENOMEM while allocating ifindex_map"); return 0; } im->next = *imp; im->index = ifi_msg->ifi_index; *imp = im; iftb_log(LOG_DEBUG, "creating new iftable (ifindex=%u)", im->index); } im->type = ifi_msg->ifi_type; im->flags = ifi_msg->ifi_flags; if (cb[IFLA_ADDRESS]) { unsigned int alen; im->alen = alen = RTA_PAYLOAD(cb[IFLA_ADDRESS]); if (alen > sizeof(im->addr)) alen = sizeof(im->addr); memcpy(im->addr, RTA_DATA(cb[IFLA_ADDRESS]), alen); } else { im->alen = 0; memset(im->addr, 0, sizeof(im->addr)); } strcpy(im->name, RTA_DATA(cb[IFLA_IFNAME])); return 1; }
static NOINLINE int check_existence_through_netlink(void) { int iface_len; /* Buffer was 1K, but on linux-3.9.9 it was reported to be too small. * netlink.h: "limit to 8K to avoid MSG_TRUNC when PAGE_SIZE is very large". * Note: on error returns (-1) we exit, no need to free replybuf. */ enum { BUF_SIZE = 8 * 1024 }; char *replybuf = xmalloc(BUF_SIZE); iface_len = strlen(G.iface); while (1) { struct nlmsghdr *mhdr; ssize_t bytes; bytes = recv(netlink_fd, replybuf, BUF_SIZE, MSG_DONTWAIT); if (bytes < 0) { if (errno == EAGAIN) goto ret; if (errno == EINTR) continue; bb_perror_msg("netlink: recv"); return -1; } mhdr = (struct nlmsghdr*)replybuf; while (bytes > 0) { if (!NLMSG_OK(mhdr, bytes)) { bb_error_msg("netlink packet too small or truncated"); return -1; } if (mhdr->nlmsg_type == RTM_NEWLINK || mhdr->nlmsg_type == RTM_DELLINK) { struct rtattr *attr; int attr_len; if (mhdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg))) { bb_error_msg("netlink packet too small or truncated"); return -1; } attr = IFLA_RTA(NLMSG_DATA(mhdr)); attr_len = IFLA_PAYLOAD(mhdr); while (RTA_OK(attr, attr_len)) { if (attr->rta_type == IFLA_IFNAME) { int len = RTA_PAYLOAD(attr); if (len > IFNAMSIZ) len = IFNAMSIZ; if (iface_len <= len && strncmp(G.iface, RTA_DATA(attr), len) == 0 ) { G.iface_exists = (mhdr->nlmsg_type == RTM_NEWLINK); } } attr = RTA_NEXT(attr, attr_len); } } mhdr = NLMSG_NEXT(mhdr, bytes); } } ret: free(replybuf); return G.iface_exists; }
int rtnl_link_status(int fd, char *device, rtnl_callback cb, void *ctx) { int index, len, link_up; int slave_index = -1; struct iovec iov; struct sockaddr_nl sa; struct msghdr msg; struct nlmsghdr *nh; struct ifinfomsg *info = NULL; struct rtattr *tb[IFLA_MAX+1]; index = if_nametoindex(device); if (!rtnl_buf) { rtnl_len = 4096; rtnl_buf = malloc(rtnl_len); if (!rtnl_buf) { pr_err("rtnl: low memory"); return -1; } } iov.iov_base = rtnl_buf; iov.iov_len = rtnl_len; memset(&msg, 0, sizeof(msg)); msg.msg_name = &sa; msg.msg_namelen = sizeof(sa); msg.msg_iov = &iov; msg.msg_iovlen = 1; len = recvmsg(fd, &msg, MSG_PEEK | MSG_TRUNC); if (len < 1) { pr_err("rtnl: recvmsg: %m"); return -1; } if (len > rtnl_len) { free(rtnl_buf); rtnl_len = len; rtnl_buf = malloc(len); if (!rtnl_buf) { pr_err("rtnl: failed to resize to %d bytes", len); return -1; } iov.iov_base = rtnl_buf; iov.iov_len = rtnl_len; } len = recvmsg(fd, &msg, 0); if (len < 1) { pr_err("rtnl: recvmsg: %m"); return -1; } nh = (struct nlmsghdr *) rtnl_buf; for ( ; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) { if (nh->nlmsg_type != RTM_NEWLINK) continue; info = NLMSG_DATA(nh); if (index != info->ifi_index) continue; link_up = info->ifi_flags & IFF_RUNNING ? 1 : 0; pr_debug("interface index %d is %s", index, link_up ? "up" : "down"); rtnl_rtattr_parse(tb, IFLA_MAX, IFLA_RTA(info), IFLA_PAYLOAD(nh)); if (tb[IFLA_LINKINFO]) slave_index = rtnl_linkinfo_parse(tb[IFLA_LINKINFO]); if (cb) cb(ctx, link_up, slave_index); } return 0; }
/* Create a linked list of `struct ifaddrs' structures, one for each network interface on the host machine. If successful, store the list in *IFAP and return 0. On errors, return -1 and set `errno'. */ int getifaddrs (struct ifaddrs **ifap) { struct netlink_handle nh = { 0, 0, 0, NULL, NULL }; struct netlink_res *nlp; struct ifaddrs_storage *ifas; unsigned int i, newlink, newaddr, newaddr_idx; int *map_newlink_data; size_t ifa_data_size = 0; /* Size to allocate for all ifa_data. */ char *ifa_data_ptr; /* Pointer to the unused part of memory for ifa_data. */ int result = 0; if (ifap) *ifap = NULL; if (! __no_netlink_support && __netlink_open (&nh) < 0) { #if __ASSUME_NETLINK_SUPPORT != 0 return -1; #endif } #if __ASSUME_NETLINK_SUPPORT == 0 if (__no_netlink_support) return fallback_getifaddrs (ifap); #endif /* Tell the kernel that we wish to get a list of all active interfaces, collect all data for every interface. */ if (__netlink_request (&nh, RTM_GETLINK) < 0) { result = -1; goto exit_free; } /* Now ask the kernel for all addresses which are assigned to an interface and collect all data for every interface. Since we store the addresses after the interfaces in the list, we will later always find the interface before the corresponding addresses. */ ++nh.seq; if (__netlink_request (&nh, RTM_GETADDR) < 0) { result = -1; goto exit_free; } /* Count all RTM_NEWLINK and RTM_NEWADDR entries to allocate enough memory. */ newlink = newaddr = 0; for (nlp = nh.nlm_list; nlp; nlp = nlp->next) { struct nlmsghdr *nlh; size_t size = nlp->size; if (nlp->nlh == NULL) continue; /* Walk through all entries we got from the kernel and look, which message type they contain. */ for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size)) { /* Check if the message is what we want. */ if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq) continue; if (nlh->nlmsg_type == NLMSG_DONE) break; /* ok */ if (nlh->nlmsg_type == RTM_NEWLINK) { /* A RTM_NEWLINK message can have IFLA_STATS data. We need to know the size before creating the list to allocate enough memory. */ struct ifinfomsg *ifim = (struct ifinfomsg *) NLMSG_DATA (nlh); struct rtattr *rta = IFLA_RTA (ifim); size_t rtasize = IFLA_PAYLOAD (nlh); while (RTA_OK (rta, rtasize)) { size_t rta_payload = RTA_PAYLOAD (rta); if (rta->rta_type == IFLA_STATS) { ifa_data_size += rta_payload; break; } else rta = RTA_NEXT (rta, rtasize); } ++newlink; } else if (nlh->nlmsg_type == RTM_NEWADDR) ++newaddr; } } /* Return if no interface is up. */ if ((newlink + newaddr) == 0) goto exit_free; /* Allocate memory for all entries we have and initialize next pointer. */ ifas = (struct ifaddrs_storage *) calloc (1, (newlink + newaddr) * sizeof (struct ifaddrs_storage) + ifa_data_size); if (ifas == NULL) { result = -1; goto exit_free; } /* Table for mapping kernel index to entry in our list. */ map_newlink_data = alloca (newlink * sizeof (int)); memset (map_newlink_data, '\xff', newlink * sizeof (int)); ifa_data_ptr = (char *) &ifas[newlink + newaddr]; newaddr_idx = 0; /* Counter for newaddr index. */ /* Walk through the list of data we got from the kernel. */ for (nlp = nh.nlm_list; nlp; nlp = nlp->next) { struct nlmsghdr *nlh; size_t size = nlp->size; if (nlp->nlh == NULL) continue; /* Walk through one message and look at the type: If it is our message, we need RTM_NEWLINK/RTM_NEWADDR and stop if we reach the end or we find the end marker (in this case we ignore the following data. */ for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size)) { int ifa_index = 0; /* Check if the message is the one we want */ if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq) continue; if (nlh->nlmsg_type == NLMSG_DONE) break; /* ok */ if (nlh->nlmsg_type == RTM_NEWLINK) { /* We found a new interface. Now extract everything from the interface data we got and need. */ struct ifinfomsg *ifim = (struct ifinfomsg *) NLMSG_DATA (nlh); struct rtattr *rta = IFLA_RTA (ifim); size_t rtasize = IFLA_PAYLOAD (nlh); /* Interfaces are stored in the first "newlink" entries of our list, starting in the order as we got from the kernel. */ ifa_index = map_newlink (ifim->ifi_index - 1, ifas, map_newlink_data, newlink); ifas[ifa_index].ifa.ifa_flags = ifim->ifi_flags; while (RTA_OK (rta, rtasize)) { char *rta_data = RTA_DATA (rta); size_t rta_payload = RTA_PAYLOAD (rta); switch (rta->rta_type) { case IFLA_ADDRESS: if (rta_payload <= sizeof (ifas[ifa_index].addr)) { ifas[ifa_index].addr.sl.sll_family = AF_PACKET; memcpy (ifas[ifa_index].addr.sl.sll_addr, (char *) rta_data, rta_payload); ifas[ifa_index].addr.sl.sll_halen = rta_payload; ifas[ifa_index].addr.sl.sll_ifindex = ifim->ifi_index; ifas[ifa_index].addr.sl.sll_hatype = ifim->ifi_type; ifas[ifa_index].ifa.ifa_addr = &ifas[ifa_index].addr.sa; } break; case IFLA_BROADCAST: if (rta_payload <= sizeof (ifas[ifa_index].broadaddr)) { ifas[ifa_index].broadaddr.sl.sll_family = AF_PACKET; memcpy (ifas[ifa_index].broadaddr.sl.sll_addr, (char *) rta_data, rta_payload); ifas[ifa_index].broadaddr.sl.sll_halen = rta_payload; ifas[ifa_index].broadaddr.sl.sll_ifindex = ifim->ifi_index; ifas[ifa_index].broadaddr.sl.sll_hatype = ifim->ifi_type; ifas[ifa_index].ifa.ifa_broadaddr = &ifas[ifa_index].broadaddr.sa; } break; case IFLA_IFNAME: /* Name of Interface */ if ((rta_payload + 1) <= sizeof (ifas[ifa_index].name)) { ifas[ifa_index].ifa.ifa_name = ifas[ifa_index].name; *(char *) __mempcpy (ifas[ifa_index].name, rta_data, rta_payload) = '\0'; } break; case IFLA_STATS: /* Statistics of Interface */ ifas[ifa_index].ifa.ifa_data = ifa_data_ptr; ifa_data_ptr += rta_payload; memcpy (ifas[ifa_index].ifa.ifa_data, rta_data, rta_payload); break; case IFLA_UNSPEC: break; case IFLA_MTU: break; case IFLA_LINK: break; case IFLA_QDISC: break; default: break; } rta = RTA_NEXT (rta, rtasize); } } else if (nlh->nlmsg_type == RTM_NEWADDR) { struct ifaddrmsg *ifam = (struct ifaddrmsg *) NLMSG_DATA (nlh); struct rtattr *rta = IFA_RTA (ifam); size_t rtasize = IFA_PAYLOAD (nlh); /* New Addresses are stored in the order we got them from the kernel after the interfaces. Theoretically it is possible that we have holes in the interface part of the list, but we always have already the interface for this address. */ ifa_index = newlink + newaddr_idx; ifas[ifa_index].ifa.ifa_flags = ifas[map_newlink (ifam->ifa_index - 1, ifas, map_newlink_data, newlink)].ifa.ifa_flags; if (ifa_index > 0) ifas[ifa_index - 1].ifa.ifa_next = &ifas[ifa_index].ifa; ++newaddr_idx; while (RTA_OK (rta, rtasize)) { char *rta_data = RTA_DATA (rta); size_t rta_payload = RTA_PAYLOAD (rta); switch (rta->rta_type) { case IFA_ADDRESS: { struct sockaddr *sa; if (ifas[ifa_index].ifa.ifa_addr != NULL) { /* In a point-to-poing network IFA_ADDRESS contains the destination address, local address is supplied in IFA_LOCAL attribute. destination address and broadcast address are stored in an union, so it doesn't matter which name we use. */ ifas[ifa_index].ifa.ifa_broadaddr = &ifas[ifa_index].broadaddr.sa; sa = &ifas[ifa_index].broadaddr.sa; } else { ifas[ifa_index].ifa.ifa_addr = &ifas[ifa_index].addr.sa; sa = &ifas[ifa_index].addr.sa; } sa->sa_family = ifam->ifa_family; switch (ifam->ifa_family) { case AF_INET: /* Size must match that of an address for IPv4. */ if (rta_payload == 4) memcpy (&((struct sockaddr_in *) sa)->sin_addr, rta_data, rta_payload); break; case AF_INET6: /* Size must match that of an address for IPv6. */ if (rta_payload == 16) { memcpy (&((struct sockaddr_in6 *) sa)->sin6_addr, rta_data, rta_payload); if (IN6_IS_ADDR_LINKLOCAL (rta_data) || IN6_IS_ADDR_MC_LINKLOCAL (rta_data)) ((struct sockaddr_in6 *) sa)->sin6_scope_id = ifam->ifa_index; } break; default: if (rta_payload <= sizeof (ifas[ifa_index].addr)) memcpy (sa->sa_data, rta_data, rta_payload); break; } } break; case IFA_LOCAL: if (ifas[ifa_index].ifa.ifa_addr != NULL) { /* If ifa_addr is set and we get IFA_LOCAL, assume we have a point-to-point network. Move address to correct field. */ ifas[ifa_index].broadaddr = ifas[ifa_index].addr; ifas[ifa_index].ifa.ifa_broadaddr = &ifas[ifa_index].broadaddr.sa; memset (&ifas[ifa_index].addr, '\0', sizeof (ifas[ifa_index].addr)); } ifas[ifa_index].ifa.ifa_addr = &ifas[ifa_index].addr.sa; ifas[ifa_index].ifa.ifa_addr->sa_family = ifam->ifa_family; switch (ifam->ifa_family) { case AF_INET: /* Size must match that of an address for IPv4. */ if (rta_payload == 4) memcpy (&ifas[ifa_index].addr.s4.sin_addr, rta_data, rta_payload); break; case AF_INET6: /* Size must match that of an address for IPv6. */ if (rta_payload == 16) { memcpy (&ifas[ifa_index].addr.s6.sin6_addr, rta_data, rta_payload); if (IN6_IS_ADDR_LINKLOCAL (rta_data) || IN6_IS_ADDR_MC_LINKLOCAL (rta_data)) ifas[ifa_index].addr.s6.sin6_scope_id = ifam->ifa_index; } break; default: if (rta_payload <= sizeof (ifas[ifa_index].addr)) memcpy (ifas[ifa_index].addr.sa.sa_data, rta_data, rta_payload); break; } break; case IFA_BROADCAST: /* We get IFA_BROADCAST, so IFA_LOCAL was too much. */ if (ifas[ifa_index].ifa.ifa_broadaddr != NULL) memset (&ifas[ifa_index].broadaddr, '\0', sizeof (ifas[ifa_index].broadaddr)); ifas[ifa_index].ifa.ifa_broadaddr = &ifas[ifa_index].broadaddr.sa; ifas[ifa_index].ifa.ifa_broadaddr->sa_family = ifam->ifa_family; switch (ifam->ifa_family) { case AF_INET: /* Size must match that of an address for IPv4. */ if (rta_payload == 4) memcpy (&ifas[ifa_index].broadaddr.s4.sin_addr, rta_data, rta_payload); break; case AF_INET6: /* Size must match that of an address for IPv6. */ if (rta_payload == 16) { memcpy (&ifas[ifa_index].broadaddr.s6.sin6_addr, rta_data, rta_payload); if (IN6_IS_ADDR_LINKLOCAL (rta_data) || IN6_IS_ADDR_MC_LINKLOCAL (rta_data)) ifas[ifa_index].broadaddr.s6.sin6_scope_id = ifam->ifa_index; } break; default: if (rta_payload <= sizeof (ifas[ifa_index].addr)) memcpy (&ifas[ifa_index].broadaddr.sa.sa_data, rta_data, rta_payload); break; } break; case IFA_LABEL: if (rta_payload + 1 <= sizeof (ifas[ifa_index].name)) { ifas[ifa_index].ifa.ifa_name = ifas[ifa_index].name; *(char *) __mempcpy (ifas[ifa_index].name, rta_data, rta_payload) = '\0'; } else abort (); break; case IFA_UNSPEC: break; case IFA_CACHEINFO: break; default: break; } rta = RTA_NEXT (rta, rtasize); } /* If we didn't get the interface name with the address, use the name from the interface entry. */ if (ifas[ifa_index].ifa.ifa_name == NULL) ifas[ifa_index].ifa.ifa_name = ifas[map_newlink (ifam->ifa_index - 1, ifas, map_newlink_data, newlink)].ifa.ifa_name; /* Calculate the netmask. */ if (ifas[ifa_index].ifa.ifa_addr && ifas[ifa_index].ifa.ifa_addr->sa_family != AF_UNSPEC && ifas[ifa_index].ifa.ifa_addr->sa_family != AF_PACKET) { uint32_t max_prefixlen = 0; char *cp = NULL; ifas[ifa_index].ifa.ifa_netmask = &ifas[ifa_index].netmask.sa; switch (ifas[ifa_index].ifa.ifa_addr->sa_family) { case AF_INET: cp = (char *) &ifas[ifa_index].netmask.s4.sin_addr; max_prefixlen = 32; break; case AF_INET6: cp = (char *) &ifas[ifa_index].netmask.s6.sin6_addr; max_prefixlen = 128; break; } ifas[ifa_index].ifa.ifa_netmask->sa_family = ifas[ifa_index].ifa.ifa_addr->sa_family; if (cp != NULL) { char c; unsigned int preflen; if ((max_prefixlen > 0) && (ifam->ifa_prefixlen > max_prefixlen)) preflen = max_prefixlen; else preflen = ifam->ifa_prefixlen; for (i = 0; i < (preflen / 8); i++) *cp++ = 0xff; c = 0xff; c <<= (8 - (preflen % 8)); *cp = c; } } } } } assert (ifa_data_ptr <= (char *) &ifas[newlink + newaddr] + ifa_data_size); if (newaddr_idx > 0) { for (i = 0; i < newlink; ++i) if (map_newlink_data[i] == -1) { /* We have fewer links then we anticipated. Adjust the forward pointer to the first address entry. */ ifas[i - 1].ifa.ifa_next = &ifas[newlink].ifa; } if (i == 0 && newlink > 0) /* No valid link, but we allocated memory. We have to populate the first entry. */ memmove (ifas, &ifas[newlink], sizeof (struct ifaddrs_storage)); } if (ifap != NULL) *ifap = &ifas[0].ifa; exit_free: __netlink_free_handle (&nh); __netlink_close (&nh); return result; }
static struct if_nameindex * if_nameindex_netlink (void) { struct netlink_handle nh = { 0, 0, 0, NULL, NULL }; struct if_nameindex *idx = NULL; if (__no_netlink_support || __netlink_open (&nh) < 0) return NULL; /* Tell the kernel that we wish to get a list of all active interfaces. Collect all data for every interface. */ if (__netlink_request (&nh, RTM_GETLINK) < 0) goto exit_free; /* Count the interfaces. */ unsigned int nifs = 0; for (struct netlink_res *nlp = nh.nlm_list; nlp; nlp = nlp->next) { struct nlmsghdr *nlh; size_t size = nlp->size; if (nlp->nlh == NULL) continue; /* Walk through all entries we got from the kernel and look, which message type they contain. */ for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size)) { /* Check if the message is what we want. */ if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq) continue; if (nlh->nlmsg_type == NLMSG_DONE) break; /* ok */ if (nlh->nlmsg_type == RTM_NEWLINK) ++nifs; } } idx = malloc ((nifs + 1) * sizeof (struct if_nameindex)); if (idx == NULL) { nomem: __set_errno (ENOBUFS); goto exit_free; } /* Add the interfaces. */ nifs = 0; for (struct netlink_res *nlp = nh.nlm_list; nlp; nlp = nlp->next) { struct nlmsghdr *nlh; size_t size = nlp->size; if (nlp->nlh == NULL) continue; /* Walk through all entries we got from the kernel and look, which message type they contain. */ for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size)) { /* Check if the message is what we want. */ if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq) continue; if (nlh->nlmsg_type == NLMSG_DONE) break; /* ok */ if (nlh->nlmsg_type == RTM_NEWLINK) { struct ifinfomsg *ifim = (struct ifinfomsg *) NLMSG_DATA (nlh); struct rtattr *rta = IFLA_RTA (ifim); size_t rtasize = IFLA_PAYLOAD (nlh); idx[nifs].if_index = ifim->ifi_index; while (RTA_OK (rta, rtasize)) { char *rta_data = RTA_DATA (rta); size_t rta_payload = RTA_PAYLOAD (rta); if (rta->rta_type == IFLA_IFNAME) { idx[nifs].if_name = __strndup (rta_data, rta_payload); if (idx[nifs].if_name == NULL) { idx[nifs].if_index = 0; if_freenameindex (idx); idx = NULL; goto nomem; } break; } rta = RTA_NEXT (rta, rtasize); } ++nifs; } } } idx[nifs].if_index = 0; idx[nifs].if_name = NULL; exit_free: __netlink_free_handle (&nh); __netlink_close (&nh); return idx; }
rtnetlink::if_link& rtnetlink::if_link::operator=(message& msg) { static_cast<data&>(*this) = msg; std::pair<const void*, size_t> pl = msg.payload(); if (msg.type() < 16 || msg.type() > 19 || pl.second < sizeof(::ifinfomsg)) throw "bad msg type"; const ::ifinfomsg* ifi = reinterpret_cast<const ifinfomsg*>(pl.first); _type = ifi->ifi_type; _index = ifi->ifi_index; _flags = ifi->ifi_flags; const ::rtattr* rta = IFLA_RTA(ifi); size_t attrlen = IFLA_PAYLOAD(reinterpret_cast<const ::nlmsghdr*>(_msg->header())); for (; RTA_OK(rta, attrlen); rta = RTA_NEXT(rta, attrlen)) { switch (rta->rta_type) { case IFLA_ADDRESS: _address = attr<void>(RTA_DATA(rta), RTA_PAYLOAD(rta)); break; case IFLA_BROADCAST: _bcast_addr = attr<void>(RTA_DATA(rta), RTA_PAYLOAD(rta)); break; case IFLA_IFNAME: _name = attr<char>(RTA_DATA(rta), RTA_PAYLOAD(rta)); break; case IFLA_MTU: ODTONE_ASSERT(sizeof(odtone::uint) == RTA_PAYLOAD(rta)); _mtu = reinterpret_cast<odtone::uint*>(RTA_DATA(rta)); break; case IFLA_LINK: ODTONE_ASSERT(sizeof(odtone::sint) == RTA_PAYLOAD(rta)); _link_type = reinterpret_cast<odtone::sint*>(RTA_DATA(rta)); break; case IFLA_QDISC: _qdisc = attr<char>(RTA_DATA(rta), RTA_PAYLOAD(rta)); break; case IFLA_STATS: ODTONE_ASSERT(sizeof(::rtnl_link_stats) == RTA_PAYLOAD(rta)); _stats = RTA_DATA(rta); break; case IFLA_WIRELESS: std::cout << "IFLA_WIRELESS(" << rta->rta_type << ", " << RTA_PAYLOAD(rta) << ")\n"; // std::cout << "\tcmd: " // << reinterpret_cast<iw_event*>(RTA_DATA(rta))->cmd // << " len: " // << reinterpret_cast<iw_event*>(RTA_DATA(rta))->len // << std::endl; _wifi = attr<void>(RTA_DATA(rta), RTA_PAYLOAD(rta)); break; default: std::cout << "IFLA_UNSPEC(" << rta->rta_type << ", " << RTA_PAYLOAD(rta) << ")\n"; } } return *this; }
/* Function : parse_msg_detail This function prints the details of a RTM* message. @input mlmsghdr : The RTM message */ void parse_msg_detail (struct nlmsghdr* nl_msg) { int rtl; struct ifinfomsg *linfo; struct rtattr *rtap; linfo = (struct ifinfomsg *)NLMSG_DATA(nl_msg); __android_log_print( ANDROID_LOG_INFO, LOG_TAG, "got a new link creation message: family (%d), type (%d), flags(%x) index(%d)\n", linfo->ifi_family, linfo->ifi_type, linfo->ifi_flags, linfo->ifi_index); /* determine the type and name of the link */ rtap = IFLA_RTA(linfo); /* get length of attributes */ rtl = IFLA_PAYLOAD(nl_msg); /* process attributes of the link info message */ for(;RTA_OK(rtap, rtl); rtap=RTA_NEXT(rtap, rtl)) { if (rtap->rta_type == IFLA_IFNAME) { /* get interface name */ strncpy(iface, RTA_DATA(rtap), RTA_PAYLOAD(rtap)); __android_log_print( ANDROID_LOG_INFO, LOG_TAG, "interface %s \n", iface); } else if (rtap->rta_type == IFLA_LINK) { /* link type */ int x = *(int *)RTA_DATA(rtap); __android_log_print( ANDROID_LOG_INFO, LOG_TAG, "interface linktype %x \n", x); } else if (rtap->rta_type == IFLA_LINKMODE) { /* link mode */ int x = *(int *)RTA_DATA(rtap); __android_log_print( ANDROID_LOG_INFO, LOG_TAG, "interface linkmode %x \n", x); } else if (rtap->rta_type == IFLA_OPERSTATE) { /* link type */ int x = *(int *)RTA_DATA(rtap); switch (x) { case (IF_OPER_DOWN): __android_log_print( ANDROID_LOG_INFO, LOG_TAG, "IF_OPER_DOWN"); break; case (IF_OPER_UP): __android_log_print( ANDROID_LOG_INFO, LOG_TAG, "IF_OPER_UP"); break; case (IF_OPER_LOWERLAYERDOWN): __android_log_print( ANDROID_LOG_INFO, LOG_TAG, "IF_OPER_LOWERLAYERDOWN"); break; case (IF_OPER_TESTING): __android_log_print( ANDROID_LOG_INFO, LOG_TAG, "IF_OPER_TESTING"); break; case (IF_OPER_DORMANT): __android_log_print( ANDROID_LOG_INFO, LOG_TAG, "IF_OPER_DORMANT"); break; case (IF_OPER_UNKNOWN): __android_log_print( ANDROID_LOG_INFO, LOG_TAG, "IF_OPER_UNKNOWN"); break; case (IF_OPER_NOTPRESENT): __android_log_print( ANDROID_LOG_INFO, LOG_TAG, "IF_OPER_NOTPRESENT"); break; } __android_log_print( ANDROID_LOG_INFO, LOG_TAG, "interface new operstate %x \n", x); } } }