static int sample_nl_cb(struct nl_msg *msg, void *arg) { struct nlmsghdr *nlh = nlmsg_hdr(msg); struct nlattr *attrs_echo[SAMPLE_ECHO_ATTR_MAX + 1]; struct nlattr *attrs_info[SAMPLE_INFO_ATTR_MAX + 1]; struct sample_nla sn; if (genlmsg_parse(nlh, 0, attrs_echo, SAMPLE_ECHO_ATTR_MAX, sample_echo_policy) != 0){ return -1; } if (!attrs_echo[SAMPLE_ECHO_ATTR_INFO] || !attrs_echo[SAMPLE_ECHO_ATTR_DATA]){ elog("attrs null\n"); return -1; } strncpy(sn.data, nla_get_string(attrs_echo[SAMPLE_ECHO_ATTR_DATA]), sizeof(sn.data)); if(nla_parse_nested(attrs_info, SAMPLE_INFO_ATTR_MAX, attrs_echo[SAMPLE_ECHO_ATTR_INFO], sample_info_policy)) return -1; sn.info.x = nla_get_u32(attrs_info[SAMPLE_INFO_ATTR_X]); sn.info.y = nla_get_u32(attrs_info[SAMPLE_INFO_ATTR_Y]); sample_nl_dump(&sn); return NL_OK; }
// valid interface callback handler static int iface_handler(struct nl_msg *msg, void *arg) { struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (tb_msg[NL80211_ATTR_WIPHY]) { char wiphy[IFNAMSIZ]; sprintf(wiphy, "phy%d", nla_get_u32(tb_msg[NL80211_ATTR_WIPHY])); // If selected physical interface matches the result, search for a monitor interface and copy the name if(strcmp(phy_name, wiphy) == 0) { if (tb_msg[NL80211_ATTR_IFTYPE] && tb_msg[NL80211_ATTR_IFNAME]) { // If the interface type is monitor if(nla_get_u32(tb_msg[NL80211_ATTR_IFTYPE]) == 6) strcpy(IF_name, nla_get_string(tb_msg[NL80211_ATTR_IFNAME])); } } } return NL_SKIP; }
static int get_devices_handler(struct nl_msg *n, void *arg) { struct nlmsghdr *nlh = nlmsg_hdr(n); struct nlattr *attrs[NFC_ATTR_MAX + 1]; char *name; uint32_t idx, protocols; bool powered; DBG(""); genlmsg_parse(nlh, 0, attrs, NFC_ATTR_MAX, NULL); if (!attrs[NFC_ATTR_DEVICE_INDEX] || !attrs[NFC_ATTR_DEVICE_NAME] || !attrs[NFC_ATTR_PROTOCOLS]) { nl_perror(NLE_MISSING_ATTR, "NFC_CMD_GET_DEVICE"); return NL_STOP; } idx = nla_get_u32(attrs[NFC_ATTR_DEVICE_INDEX]); name = nla_get_string(attrs[NFC_ATTR_DEVICE_NAME]); protocols = nla_get_u32(attrs[NFC_ATTR_PROTOCOLS]); if (!attrs[NFC_ATTR_DEVICE_POWERED]) powered = false; else powered = nla_get_u8(attrs[NFC_ATTR_DEVICE_POWERED]); __near_manager_adapter_add(idx, name, protocols, powered); return NL_SKIP; }
static int ipvs_daemon_parse_cb(struct nl_msg *msg, void *arg) { struct nlmsghdr *nlh = nlmsg_hdr(msg); struct nlattr *attrs[IPVS_CMD_ATTR_MAX + 1]; struct nlattr *daemon_attrs[IPVS_DAEMON_ATTR_MAX + 1]; ipvs_daemon_t *u = (ipvs_daemon_t *)arg; int i = 0; /* We may get two daemons. If we've already got one, this is the second */ if (u[0].state) i = 1; if (genlmsg_parse(nlh, 0, attrs, IPVS_CMD_ATTR_MAX, ipvs_cmd_policy) != 0) return -1; if (nla_parse_nested(daemon_attrs, IPVS_DAEMON_ATTR_MAX, attrs[IPVS_CMD_ATTR_DAEMON], ipvs_daemon_policy)) return -1; if (!(daemon_attrs[IPVS_DAEMON_ATTR_STATE] && daemon_attrs[IPVS_DAEMON_ATTR_MCAST_IFN] && daemon_attrs[IPVS_DAEMON_ATTR_SYNC_ID])) return -1; u[i].state = nla_get_u32(daemon_attrs[IPVS_DAEMON_ATTR_STATE]); strncpy(u[i].mcast_ifn, nla_get_string(daemon_attrs[IPVS_DAEMON_ATTR_MCAST_IFN]), IP_VS_IFNAME_MAXLEN); u[i].syncid = nla_get_u32(daemon_attrs[IPVS_DAEMON_ATTR_SYNC_ID]); return NL_OK; }
static int _list(struct nl_msg *nl_msg, void *arg) { struct nlmsghdr *nlh = nlmsg_hdr(nl_msg); struct nlattr *info[TIPC_NLA_MAX + 1]; struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1]; genlmsg_parse(nlh, 0, info, TIPC_NLA_MAX, NULL); if (!info[TIPC_NLA_BEARER]) { log_err("no bearer received from kernel\n"); return NL_STOP; } if (nla_parse_nested(attrs, TIPC_NLA_BEARER_MAX, info[TIPC_NLA_BEARER], NULL)) { log_err("parsing nested bearer properties\n"); return NL_STOP; } if (!attrs[TIPC_NLA_BEARER_NAME]) { log_err("no bearer name received from kernel\n"); return NL_STOP; } printf("%s\n", nla_get_string(attrs[TIPC_NLA_BEARER_NAME])); return NL_OK; }
static int ipvs_daemon_parse_cb(struct nl_msg *msg, void *arg) { struct nlmsghdr *nlh = nlmsg_hdr(msg); struct nlattr *attrs[IPVS_CMD_ATTR_MAX + 1]; struct nlattr *daemon_attrs[IPVS_DAEMON_ATTR_MAX + 1]; ipvs_daemon_t *u = (ipvs_daemon_t *)arg; struct nlattr *a; int i = 0; /* We may get two daemons. If we've already got one, this is the second */ if (u[0].state) i = 1; if (genlmsg_parse(nlh, 0, attrs, IPVS_CMD_ATTR_MAX, ipvs_cmd_policy) != 0) return -1; if (nla_parse_nested(daemon_attrs, IPVS_DAEMON_ATTR_MAX, attrs[IPVS_CMD_ATTR_DAEMON], ipvs_daemon_policy)) return -1; if (!(daemon_attrs[IPVS_DAEMON_ATTR_STATE] && daemon_attrs[IPVS_DAEMON_ATTR_MCAST_IFN] && daemon_attrs[IPVS_DAEMON_ATTR_SYNC_ID])) return -1; u[i].state = nla_get_u32(daemon_attrs[IPVS_DAEMON_ATTR_STATE]); strncpy(u[i].mcast_ifn, nla_get_string(daemon_attrs[IPVS_DAEMON_ATTR_MCAST_IFN]), IP_VS_IFNAME_MAXLEN); u[i].syncid = nla_get_u32(daemon_attrs[IPVS_DAEMON_ATTR_SYNC_ID]); a = daemon_attrs[IPVS_DAEMON_ATTR_SYNC_MAXLEN]; if (a) u[i].sync_maxlen = nla_get_u16(a); a = daemon_attrs[IPVS_DAEMON_ATTR_MCAST_PORT]; if (a) u[i].mcast_port = nla_get_u16(a); a = daemon_attrs[IPVS_DAEMON_ATTR_MCAST_TTL]; if (a) u[i].mcast_ttl = nla_get_u8(a); a = daemon_attrs[IPVS_DAEMON_ATTR_MCAST_GROUP]; if (a) { u[i].mcast_af = AF_INET; u[i].mcast_group.ip = nla_get_u32(a); } else { a = daemon_attrs[IPVS_DAEMON_ATTR_MCAST_GROUP6]; if (a) { u[i].mcast_af = AF_INET6; memcpy(&u[i].mcast_group.in6, nla_data(a), sizeof(u[i].mcast_group.in6)); } } return NL_OK; }
static iz_res_t list_response(struct iz_cmd *cmd, struct genlmsghdr *ghdr, struct nlattr **attrs) { char * dev_name; char * phy_name = NULL; uint32_t dev_index; unsigned char hw_addr[IEEE802154_ADDR_LEN]; uint16_t short_addr; uint16_t pan_id; char * dev_type_str; /* Check for mandatory attributes */ if (!attrs[IEEE802154_ATTR_DEV_NAME] || !attrs[IEEE802154_ATTR_DEV_INDEX] || !attrs[IEEE802154_ATTR_HW_ADDR] || !attrs[IEEE802154_ATTR_SHORT_ADDR] || !attrs[IEEE802154_ATTR_PAN_ID]) return IZ_STOP_ERR; /* Get attribute values from the message */ dev_name = nla_get_string(attrs[IEEE802154_ATTR_DEV_NAME]); dev_index = nla_get_u32(attrs[IEEE802154_ATTR_DEV_INDEX]); nla_memcpy(hw_addr, attrs[IEEE802154_ATTR_HW_ADDR], IEEE802154_ADDR_LEN); short_addr = nla_get_u16(attrs[IEEE802154_ATTR_SHORT_ADDR]); pan_id = nla_get_u16(attrs[IEEE802154_ATTR_PAN_ID]); if (attrs[IEEE802154_ATTR_PHY_NAME]) phy_name = nla_get_string(attrs[IEEE802154_ATTR_PHY_NAME]); /* Display information about interface */ printf("%s\n", dev_name); dev_type_str = "IEEE 802.15.4 MAC interface"; printf(" link: %s\n", dev_type_str); if (phy_name) printf(" phy %s\n", phy_name); printf(" hw %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", hw_addr[0], hw_addr[1], hw_addr[2], hw_addr[3], hw_addr[4], hw_addr[5], hw_addr[6], hw_addr[7]); printf(" pan 0x%04hx short 0x%04hx\n", pan_id, short_addr); return (cmd->flags & NLM_F_MULTI) ? IZ_CONT_OK : IZ_STOP_OK; }
static int get_ifinfo_cb(struct nl_msg *msg, void *arg) { struct nlt_ifinfo *ifinfo = (struct nlt_ifinfo *) arg; struct nlt_msg r; nlt_parse(msg, &r); if (r.cmd != NL80211_CMD_NEW_INTERFACE) return NL_OK; if (ifinfo->ifname != NULL) { printf("! if info != 0\n"); if (!r.attribs[NL80211_ATTR_IFNAME]) return NL_OK; const char *cbname = nla_get_string(r.attribs[NL80211_ATTR_IFNAME]); printf("Callback name %s\n", cbname); if (strcmp(ifinfo->ifname, nla_get_string(r.attribs[NL80211_ATTR_IFNAME])) != 0) return NL_OK; } if (r.attribs[NL80211_ATTR_IFNAME]) { if (ifinfo->ifname == NULL) ifinfo->ifname = strdup(nla_get_string(r.attribs[NL80211_ATTR_IFNAME])); } if (r.attribs[NL80211_ATTR_IFINDEX]) ifinfo->ifindex = nla_get_u32(r.attribs[NL80211_ATTR_IFINDEX]); if (r.attribs[NL80211_ATTR_IFTYPE]) ifinfo->iftype = nla_get_u32(r.attribs[NL80211_ATTR_IFTYPE]); return NL_OK; }
static int print_iface_handler(struct nl_msg *msg, void *arg) { struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct nlattr *tb_msg[NL802154_ATTR_MAX + 1]; unsigned int *wpan_phy = arg; const char *indent = ""; nla_parse(tb_msg, NL802154_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (wpan_phy && tb_msg[NL802154_ATTR_WPAN_PHY]) { unsigned int thiswpan_phy = nla_get_u32(tb_msg[NL802154_ATTR_WPAN_PHY]); indent = "\t"; if (*wpan_phy != thiswpan_phy) printf("phy#%d\n", thiswpan_phy); *wpan_phy = thiswpan_phy; } if (tb_msg[NL802154_ATTR_IFNAME]) printf("%sInterface %s\n", indent, nla_get_string(tb_msg[NL802154_ATTR_IFNAME])); else printf("%sUnnamed/non-netdev interface\n", indent); if (tb_msg[NL802154_ATTR_IFINDEX]) printf("%s\tifindex %d\n", indent, nla_get_u32(tb_msg[NL802154_ATTR_IFINDEX])); if (tb_msg[NL802154_ATTR_WPAN_DEV]) printf("%s\twpan_dev 0x%llx\n", indent, (unsigned long long)nla_get_u64(tb_msg[NL802154_ATTR_WPAN_DEV])); if (tb_msg[NL802154_ATTR_EXTENDED_ADDR]) printf("%s\textended_addr 0x%016" PRIx64 "\n", indent, le64toh(nla_get_u64(tb_msg[NL802154_ATTR_EXTENDED_ADDR]))); if (tb_msg[NL802154_ATTR_SHORT_ADDR]) printf("%s\tshort_addr 0x%04x\n", indent, le16toh(nla_get_u16(tb_msg[NL802154_ATTR_SHORT_ADDR]))); if (tb_msg[NL802154_ATTR_PAN_ID]) printf("%s\tpan_id 0x%04x\n", indent, le16toh(nla_get_u16(tb_msg[NL802154_ATTR_PAN_ID]))); if (tb_msg[NL802154_ATTR_IFTYPE]) printf("%s\ttype %s\n", indent, iftype_name(nla_get_u32(tb_msg[NL802154_ATTR_IFTYPE]))); if (tb_msg[NL802154_ATTR_MAX_FRAME_RETRIES]) printf("%s\tmax_frame_retries %d\n", indent, nla_get_s8(tb_msg[NL802154_ATTR_MAX_FRAME_RETRIES])); if (tb_msg[NL802154_ATTR_MIN_BE]) printf("%s\tmin_be %d\n", indent, nla_get_u8(tb_msg[NL802154_ATTR_MIN_BE])); if (tb_msg[NL802154_ATTR_MAX_BE]) printf("%s\tmax_be %d\n", indent, nla_get_u8(tb_msg[NL802154_ATTR_MAX_BE])); if (tb_msg[NL802154_ATTR_MAX_CSMA_BACKOFFS]) printf("%s\tmax_csma_backoffs %d\n", indent, nla_get_u8(tb_msg[NL802154_ATTR_MAX_CSMA_BACKOFFS])); if (tb_msg[NL802154_ATTR_LBT_MODE]) printf("%s\tlbt %d\n", indent, nla_get_u8(tb_msg[NL802154_ATTR_LBT_MODE])); if (tb_msg[NL802154_ATTR_ACKREQ_DEFAULT]) printf("%s\tackreq_default %d\n", indent, nla_get_u8(tb_msg[NL802154_ATTR_ACKREQ_DEFAULT])); return NL_SKIP; }
static int cb_handler(struct nl_msg * msg, void * arg) { * (int*) arg = 123; // cbarg struct nlmsghdr * hdr = nlmsg_hdr(msg); struct genlmsghdr * gnlh = nlmsg_data(hdr); int valid = genlmsg_validate(hdr, 0, DEMO_ATTR_MAX, demo_gnl_policy); printf("valid %d %s\n", valid, valid ? "ERROR" : "OK"); // one way struct nlattr * attrs[DEMO_ATTR_MAX + 1]; if (genlmsg_parse(hdr, 0, attrs, DEMO_ATTR_MAX, demo_gnl_policy) < 0) { printf("genlsmg_parse ERROR\n"); } else { printf("genlsmg_parse OK\n"); printf("attr1 %s\n", nla_get_string(attrs[DEMO_ATTR1_STRING])); printf("attr2 %x\n", nla_get_u16(attrs[DEMO_ATTR2_UINT16])); struct attr_custom * cp = (struct attr_custom *) nla_data(attrs[DEMO_ATTR3_CUSTOM]); printf("attr3 %d %ld %f %lf\n", cp->a, cp->b, cp->c,cp->d); } // another way printf("gnlh->cmd %d\n", gnlh->cmd); //--- DEMO_CMD_ECHO int remaining = genlmsg_attrlen(gnlh, 0); struct nlattr * attr = genlmsg_attrdata(gnlh, 0); while (nla_ok(attr, remaining)) { printf("remaining %d\n", remaining); printf("attr @ %p\n", attr); // nla_get_string(attr) attr = nla_next(attr, &remaining); } nl_msg_dump(msg, stderr); return NL_STOP; }
static int print_phy_handler(struct nl_msg *msg, void *arg) { struct nlattr *tb_msg[NL802154_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); int rem_page, i, ret; int64_t phy_id = -1; bool print_name = true; struct nlattr *nl_page; enum nl802154_cca_modes cca_mode; nla_parse(tb_msg, NL802154_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (tb_msg[NL802154_ATTR_WPAN_PHY]) { if (nla_get_u32(tb_msg[NL802154_ATTR_WPAN_PHY]) == phy_id) print_name = false; phy_id = nla_get_u32(tb_msg[NL802154_ATTR_WPAN_PHY]); } if (print_name && tb_msg[NL802154_ATTR_WPAN_PHY_NAME]) printf("wpan_phy %s\n", nla_get_string(tb_msg[NL802154_ATTR_WPAN_PHY_NAME])); /* TODO remove this handling it's deprecated */ if (tb_msg[NL802154_ATTR_CHANNELS_SUPPORTED]) { unsigned char page = 0; unsigned long channel; printf("supported channels:\n"); nla_for_each_nested(nl_page, tb_msg[NL802154_ATTR_CHANNELS_SUPPORTED], rem_page) { channel = nla_get_u32(nl_page); if (channel) { printf("\tpage %d: ", page); for (i = 0; i <= 31; i++) { if (channel & 0x1) printf("%d,", i); channel >>= 1; } /* TODO hack use sprintf here */ printf("\b \b\n"); } page++; } }
static iz_res_t event_response(struct iz_cmd *cmd, struct genlmsghdr *ghdr, struct nlattr **attrs) { const char *iface = nla_get_string(attrs[IEEE802154_ATTR_DEV_NAME]); if (cmd->argv[1] && (!iface || strcmp(cmd->argv[1], iface))) return IZ_CONT_OK; if (!iface) iface = "?????"; if (ghdr->cmd < __IEEE802154_CMD_MAX) fprintf(stdout, "%s: %s (%i)\n", iface, iz_cmd_names[ghdr->cmd], ghdr->cmd); else fprintf(stdout, "%s: UNKNOWN (%i)\n", iface, ghdr->cmd); fflush(stdout); return IZ_CONT_OK; }
static int nfc_netlink_event_adapter(struct genlmsghdr *gnlh, bool add) { struct nlattr *attrs[NFC_ATTR_MAX + 1]; uint32_t idx; DBG(""); nla_parse(attrs, NFC_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (!attrs[NFC_ATTR_DEVICE_INDEX]) { near_error("Missing device index"); return -ENODEV; } idx = nla_get_u32(attrs[NFC_ATTR_DEVICE_INDEX]); if (add && (!attrs[NFC_ATTR_DEVICE_NAME] || !attrs[NFC_ATTR_PROTOCOLS])) { near_error("Missing attributes"); return -EINVAL; } if (add) { char *name; uint32_t protocols; bool powered; name = nla_get_string(attrs[NFC_ATTR_DEVICE_NAME]); protocols = nla_get_u32(attrs[NFC_ATTR_PROTOCOLS]); if (!attrs[NFC_ATTR_DEVICE_POWERED]) powered = false; else powered = nla_get_u8(attrs[NFC_ATTR_DEVICE_POWERED]); return __near_manager_adapter_add(idx, name, protocols, powered); } else { __near_manager_adapter_remove(idx); } return 0; }
static int port_stats_iterator(struct nl_msg *msg, void *arg) { of_list_port_stats_entry_t *list = arg; struct nlmsghdr *nlh = nlmsg_hdr(msg); struct nlattr *attrs[OVS_VPORT_ATTR_MAX+1]; if (genlmsg_parse(nlh, sizeof(struct ovs_header), attrs, OVS_VPORT_ATTR_MAX, NULL) < 0) { abort(); } assert(attrs[OVS_VPORT_ATTR_PORT_NO]); assert(attrs[OVS_VPORT_ATTR_STATS]); uint32_t port_no = nla_get_u32(attrs[OVS_VPORT_ATTR_PORT_NO]); char *ifname = nla_get_string(attrs[OVS_VPORT_ATTR_NAME]); uint32_t vport_type = nla_get_u32(attrs[OVS_VPORT_ATTR_TYPE]); struct ovs_vport_stats *port_stats = nla_data(attrs[OVS_VPORT_ATTR_STATS]); of_port_stats_entry_t entry[1]; of_port_stats_entry_init(entry, list->version, -1, 1); if (of_list_port_stats_entry_append_bind(list, entry) < 0) { /* TODO needs fix in indigo core */ LOG_ERROR("too many port stats replies"); return NL_STOP; } of_port_stats_entry_port_no_set(entry, port_no); struct rtnl_link *link; if ((vport_type == OVS_VPORT_TYPE_NETDEV || vport_type == OVS_VPORT_TYPE_INTERNAL) && (link = rtnl_link_get_by_name(link_cache, ifname))) { /* Get interface stats from NETLINK_ROUTE */ of_port_stats_entry_rx_packets_set(entry, rtnl_link_get_stat(link, RTNL_LINK_RX_PACKETS)); of_port_stats_entry_tx_packets_set(entry, rtnl_link_get_stat(link, RTNL_LINK_TX_PACKETS)); of_port_stats_entry_rx_bytes_set(entry, rtnl_link_get_stat(link, RTNL_LINK_RX_BYTES)); of_port_stats_entry_tx_bytes_set(entry, rtnl_link_get_stat(link, RTNL_LINK_TX_BYTES)); of_port_stats_entry_rx_dropped_set(entry, rtnl_link_get_stat(link, RTNL_LINK_RX_DROPPED)); of_port_stats_entry_tx_dropped_set(entry, rtnl_link_get_stat(link, RTNL_LINK_TX_DROPPED)); of_port_stats_entry_rx_errors_set(entry, rtnl_link_get_stat(link, RTNL_LINK_RX_ERRORS)); of_port_stats_entry_tx_errors_set(entry, rtnl_link_get_stat(link, RTNL_LINK_TX_ERRORS)); of_port_stats_entry_rx_frame_err_set(entry, rtnl_link_get_stat(link, RTNL_LINK_RX_FRAME_ERR)); of_port_stats_entry_rx_over_err_set(entry, rtnl_link_get_stat(link, RTNL_LINK_RX_OVER_ERR)); of_port_stats_entry_rx_crc_err_set(entry, rtnl_link_get_stat(link, RTNL_LINK_RX_CRC_ERR)); of_port_stats_entry_collisions_set(entry, rtnl_link_get_stat(link, RTNL_LINK_COLLISIONS)); rtnl_link_put(link); } else { /* Use more limited stats from the datapath */ of_port_stats_entry_rx_packets_set(entry, port_stats->rx_packets); of_port_stats_entry_tx_packets_set(entry, port_stats->tx_packets); of_port_stats_entry_rx_bytes_set(entry, port_stats->rx_bytes); of_port_stats_entry_tx_bytes_set(entry, port_stats->tx_bytes); of_port_stats_entry_rx_dropped_set(entry, port_stats->rx_dropped); of_port_stats_entry_tx_dropped_set(entry, port_stats->tx_dropped); of_port_stats_entry_rx_errors_set(entry, port_stats->rx_errors); of_port_stats_entry_tx_errors_set(entry, port_stats->tx_errors); of_port_stats_entry_rx_frame_err_set(entry, 0); of_port_stats_entry_rx_over_err_set(entry, 0); of_port_stats_entry_rx_crc_err_set(entry, 0); of_port_stats_entry_collisions_set(entry, 0); } return NL_OK; }
static int print_iface_handler(struct nl_msg *msg, void *arg) { struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; unsigned int *wiphy = arg; const char *indent = ""; nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (wiphy && tb_msg[NL80211_ATTR_WIPHY]) { unsigned int thiswiphy = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY]); indent = "\t"; if (*wiphy != thiswiphy) printf("phy#%d\n", thiswiphy); *wiphy = thiswiphy; } if (tb_msg[NL80211_ATTR_IFNAME]) printf("%sInterface %s\n", indent, nla_get_string(tb_msg[NL80211_ATTR_IFNAME])); else printf("%sUnnamed/non-netdev interface\n", indent); if (tb_msg[NL80211_ATTR_IFINDEX]) printf("%s\tifindex %d\n", indent, nla_get_u32(tb_msg[NL80211_ATTR_IFINDEX])); if (tb_msg[NL80211_ATTR_WDEV]) printf("%s\twdev 0x%llx\n", indent, (unsigned long long)nla_get_u64(tb_msg[NL80211_ATTR_WDEV])); if (tb_msg[NL80211_ATTR_MAC]) { char mac_addr[20]; mac_addr_n2a(mac_addr, nla_data(tb_msg[NL80211_ATTR_MAC])); printf("%s\taddr %s\n", indent, mac_addr); } if (tb_msg[NL80211_ATTR_SSID]) { printf("%s\tssid ", indent); print_ssid_escaped(nla_len(tb_msg[NL80211_ATTR_SSID]), nla_data(tb_msg[NL80211_ATTR_SSID])); printf("\n"); } if (tb_msg[NL80211_ATTR_IFTYPE]) printf("%s\ttype %s\n", indent, iftype_name(nla_get_u32(tb_msg[NL80211_ATTR_IFTYPE]))); if (!wiphy && tb_msg[NL80211_ATTR_WIPHY]) printf("%s\twiphy %d\n", indent, nla_get_u32(tb_msg[NL80211_ATTR_WIPHY])); if (tb_msg[NL80211_ATTR_WIPHY_FREQ]) { uint32_t freq = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_FREQ]); printf("%s\tchannel %d (%d MHz)", indent, ieee80211_frequency_to_channel(freq), freq); if (tb_msg[NL80211_ATTR_CHANNEL_WIDTH]) { printf(", width: %s", channel_width_name(nla_get_u32(tb_msg[NL80211_ATTR_CHANNEL_WIDTH]))); if (tb_msg[NL80211_ATTR_CENTER_FREQ1]) printf(", center1: %d MHz", nla_get_u32(tb_msg[NL80211_ATTR_CENTER_FREQ1])); if (tb_msg[NL80211_ATTR_CENTER_FREQ2]) printf(", center2: %d MHz", nla_get_u32(tb_msg[NL80211_ATTR_CENTER_FREQ2])); } else if (tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { enum nl80211_channel_type channel_type; channel_type = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); printf(" %s", channel_type_name(channel_type)); } printf("\n"); } return NL_SKIP; }
static void copy_cacheinfo_into_route(struct rta_cacheinfo *ci, struct rtnl_route *route) { struct rtnl_rtcacheinfo nci = { .rtci_clntref = ci->rta_clntref, .rtci_last_use = ci->rta_lastuse, .rtci_expires = ci->rta_expires, .rtci_error = ci->rta_error, .rtci_used = ci->rta_used, .rtci_id = ci->rta_id, .rtci_ts = ci->rta_ts, .rtci_tsage = ci->rta_tsage, }; rtnl_route_set_cacheinfo(route, &nci); } static int route_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, struct nlmsghdr *nlh, struct nl_parser_param *pp) { struct rtmsg *rtm; struct rtnl_route *route; struct nlattr *tb[RTA_MAX + 1]; struct nl_addr *src = NULL, *dst = NULL, *addr; int err; route = rtnl_route_alloc(); if (!route) { err = nl_errno(ENOMEM); goto errout; } route->ce_msgtype = nlh->nlmsg_type; err = nlmsg_parse(nlh, sizeof(struct rtmsg), tb, RTA_MAX, route_policy); if (err < 0) goto errout; rtm = nlmsg_data(nlh); rtnl_route_set_family(route, rtm->rtm_family); rtnl_route_set_tos(route, rtm->rtm_tos); rtnl_route_set_table(route, rtm->rtm_table); rtnl_route_set_type(route, rtm->rtm_type); rtnl_route_set_scope(route, rtm->rtm_scope); rtnl_route_set_protocol(route, rtm->rtm_protocol); rtnl_route_set_flags(route, rtm->rtm_flags); if (tb[RTA_DST]) { dst = nla_get_addr(tb[RTA_DST], rtm->rtm_family); if (dst == NULL) goto errout_errno; } else { dst = nl_addr_alloc(0); nl_addr_set_family(dst, rtm->rtm_family); } nl_addr_set_prefixlen(dst, rtm->rtm_dst_len); err = rtnl_route_set_dst(route, dst); if (err < 0) goto errout; nl_addr_put(dst); if (tb[RTA_SRC]) { src = nla_get_addr(tb[RTA_SRC], rtm->rtm_family); if (src == NULL) goto errout_errno; } else if (rtm->rtm_src_len) src = nl_addr_alloc(0); if (src) { nl_addr_set_prefixlen(src, rtm->rtm_src_len); rtnl_route_set_src(route, src); nl_addr_put(src); } if (tb[RTA_IIF]) rtnl_route_set_iif(route, nla_get_string(tb[RTA_IIF])); if (tb[RTA_OIF]) rtnl_route_set_oif(route, nla_get_u32(tb[RTA_OIF])); if (tb[RTA_GATEWAY]) { addr = nla_get_addr(tb[RTA_GATEWAY], route->rt_family); if (addr == NULL) goto errout_errno; rtnl_route_set_gateway(route, addr); nl_addr_put(addr); } if (tb[RTA_PRIORITY]) rtnl_route_set_prio(route, nla_get_u32(tb[RTA_PRIORITY])); if (tb[RTA_PREFSRC]) { addr = nla_get_addr(tb[RTA_PREFSRC], route->rt_family); if (addr == NULL) goto errout_errno; rtnl_route_set_pref_src(route, addr); nl_addr_put(addr); } if (tb[RTA_METRICS]) { struct nlattr *mtb[RTAX_MAX + 1]; int i; err = nla_parse_nested(mtb, RTAX_MAX, tb[RTA_METRICS], NULL); if (err < 0) goto errout; for (i = 1; i <= RTAX_MAX; i++) { if (mtb[i] && nla_len(mtb[i]) >= sizeof(uint32_t)) { uint32_t m = nla_get_u32(mtb[i]); if (rtnl_route_set_metric(route, i, m) < 0) goto errout_errno; } } } if (tb[RTA_MULTIPATH]) { struct rtnl_nexthop *nh; struct rtnexthop *rtnh = nla_data(tb[RTA_MULTIPATH]); size_t tlen = nla_len(tb[RTA_MULTIPATH]); while (tlen >= sizeof(*rtnh) && tlen >= rtnh->rtnh_len) { nh = rtnl_route_nh_alloc(); if (!nh) goto errout; rtnl_route_nh_set_weight(nh, rtnh->rtnh_hops); rtnl_route_nh_set_ifindex(nh, rtnh->rtnh_ifindex); rtnl_route_nh_set_flags(nh, rtnh->rtnh_flags); if (rtnh->rtnh_len > sizeof(*rtnh)) { struct nlattr *ntb[RTA_MAX + 1]; nla_parse(ntb, RTA_MAX, (struct nlattr *) RTNH_DATA(rtnh), rtnh->rtnh_len - sizeof(*rtnh), route_policy); if (ntb[RTA_GATEWAY]) { nh->rtnh_gateway = nla_get_addr( ntb[RTA_GATEWAY], route->rt_family); nh->rtnh_mask = NEXTHOP_HAS_GATEWAY; } } rtnl_route_add_nexthop(route, nh); tlen -= RTNH_ALIGN(rtnh->rtnh_len); rtnh = RTNH_NEXT(rtnh); } } if (tb[RTA_FLOW]) rtnl_route_set_realms(route, nla_get_u32(tb[RTA_FLOW])); if (tb[RTA_CACHEINFO]) copy_cacheinfo_into_route(nla_data(tb[RTA_CACHEINFO]), route); if (tb[RTA_MP_ALGO]) rtnl_route_set_mp_algo(route, nla_get_u32(tb[RTA_MP_ALGO])); err = pp->pp_cb((struct nl_object *) route, pp); if (err < 0) goto errout; err = P_ACCEPT; errout: rtnl_route_put(route); return err; errout_errno: err = nl_get_errno(); goto errout; } static int route_request_update(struct nl_cache *c, struct nl_handle *h) { return nl_rtgen_request(h, RTM_GETROUTE, AF_UNSPEC, NLM_F_DUMP); } /** * @name Cache Management * @{ */ /** * Build a route cache holding all routes currently configured in the kernel * @arg handle netlink handle * * Allocates a new cache, initializes it properly and updates it to * contain all routes currently configured in the kernel. * * @note The caller is responsible for destroying and freeing the * cache after using it. * @return The cache or NULL if an error has occured. */ struct nl_cache *rtnl_route_alloc_cache(struct nl_handle *handle) { struct nl_cache *cache; cache = nl_cache_alloc(&rtnl_route_ops); if (!cache) return NULL; if (handle && nl_cache_refill(handle, cache) < 0) { free(cache); return NULL; } return cache; } /** @} */ /** * @name Route Addition * @{ */ static struct nl_msg *build_route_msg(struct rtnl_route *tmpl, int cmd, int flags) { struct nl_msg *msg; struct nl_addr *addr; int scope, i, oif, nmetrics = 0; struct nlattr *metrics; struct rtmsg rtmsg = { .rtm_family = rtnl_route_get_family(tmpl), .rtm_dst_len = rtnl_route_get_dst_len(tmpl), .rtm_src_len = rtnl_route_get_src_len(tmpl), .rtm_tos = rtnl_route_get_tos(tmpl), .rtm_table = rtnl_route_get_table(tmpl), .rtm_type = rtnl_route_get_type(tmpl), .rtm_protocol = rtnl_route_get_protocol(tmpl), .rtm_flags = rtnl_route_get_flags(tmpl), }; if (rtmsg.rtm_family == AF_UNSPEC) { nl_error(EINVAL, "Cannot build route message, address " \ "family is unknown."); return NULL; } scope = rtnl_route_get_scope(tmpl); if (scope == RT_SCOPE_NOWHERE) { if (rtmsg.rtm_type == RTN_LOCAL) scope = RT_SCOPE_HOST; else { /* XXX Change to UNIVERSE if gw || nexthops */ scope = RT_SCOPE_LINK; } } rtmsg.rtm_scope = scope; msg = nlmsg_alloc_simple(cmd, flags); if (msg == NULL) return NULL; if (nlmsg_append(msg, &rtmsg, sizeof(rtmsg), NLMSG_ALIGNTO) < 0) goto nla_put_failure; addr = rtnl_route_get_dst(tmpl); if (addr) NLA_PUT_ADDR(msg, RTA_DST, addr); addr = rtnl_route_get_src(tmpl); if (addr) NLA_PUT_ADDR(msg, RTA_SRC, addr); addr = rtnl_route_get_gateway(tmpl); if (addr) NLA_PUT_ADDR(msg, RTA_GATEWAY, addr); addr = rtnl_route_get_pref_src(tmpl); if (addr) NLA_PUT_ADDR(msg, RTA_PREFSRC, addr); NLA_PUT_U32(msg, RTA_PRIORITY, rtnl_route_get_prio(tmpl)); oif = rtnl_route_get_oif(tmpl); if (oif != RTNL_LINK_NOT_FOUND) NLA_PUT_U32(msg, RTA_OIF, oif); for (i = 1; i <= RTAX_MAX; i++) if (rtnl_route_get_metric(tmpl, i) != UINT_MAX) nmetrics++; if (nmetrics > 0) { unsigned int val; metrics = nla_nest_start(msg, RTA_METRICS); if (metrics == NULL) goto nla_put_failure; for (i = 1; i <= RTAX_MAX; i++) { val = rtnl_route_get_metric(tmpl, i); if (val != UINT_MAX) NLA_PUT_U32(msg, i, val); } nla_nest_end(msg, metrics); } #if 0 RTA_IIF, RTA_MULTIPATH, RTA_PROTOINFO, RTA_FLOW, RTA_CACHEINFO, RTA_SESSION, RTA_MP_ALGO, #endif return msg; nla_put_failure: nlmsg_free(msg); return NULL; } struct nl_msg *rtnl_route_build_add_request(struct rtnl_route *tmpl, int flags) { return build_route_msg(tmpl, RTM_NEWROUTE, NLM_F_CREATE | flags); } int rtnl_route_add(struct nl_handle *handle, struct rtnl_route *route, int flags) { struct nl_msg *msg; int err; msg = rtnl_route_build_add_request(route, flags); if (!msg) return nl_get_errno(); err = nl_send_auto_complete(handle, msg); nlmsg_free(msg); if (err < 0) return err; return nl_wait_for_ack(handle); } struct nl_msg *rtnl_route_build_del_request(struct rtnl_route *tmpl, int flags) { return build_route_msg(tmpl, RTM_DELROUTE, flags); } int rtnl_route_del(struct nl_handle *handle, struct rtnl_route *route, int flags) { struct nl_msg *msg; int err; msg = rtnl_route_build_del_request(route, flags); if (!msg) return nl_get_errno(); err = nl_send_auto_complete(handle, msg); nlmsg_free(msg); if (err < 0) return err; return nl_wait_for_ack(handle); } /** @} */ static struct nl_af_group route_groups[] = { { AF_INET, RTNLGRP_IPV4_ROUTE }, { AF_INET6, RTNLGRP_IPV6_ROUTE }, { AF_DECnet, RTNLGRP_DECnet_ROUTE }, { END_OF_GROUP_LIST }, }; static struct nl_cache_ops rtnl_route_ops = { .co_name = "route/route", .co_hdrsize = sizeof(struct rtmsg), .co_msgtypes = { { RTM_NEWROUTE, NL_ACT_NEW, "new" }, { RTM_DELROUTE, NL_ACT_DEL, "del" }, { RTM_GETROUTE, NL_ACT_GET, "get" }, END_OF_MSGTYPES_LIST, }, .co_protocol = NETLINK_ROUTE, .co_groups = route_groups, .co_request_update = route_request_update, .co_msg_parser = route_msg_parser, .co_obj_ops = &route_obj_ops, }; static void __init route_init(void) { nl_cache_mngt_register(&rtnl_route_ops); } static void __exit route_exit(void) { nl_cache_mngt_unregister(&rtnl_route_ops); }
static int ipvs_services_parse_cb(struct nl_msg *msg, void *arg) { struct nlmsghdr *nlh = nlmsg_hdr(msg); struct nlattr *attrs[IPVS_CMD_ATTR_MAX + 1]; struct nlattr *svc_attrs[IPVS_SVC_ATTR_MAX + 1]; struct ip_vs_get_services **getp = (struct ip_vs_get_services **)arg; struct ip_vs_get_services *get = (struct ip_vs_get_services *)*getp; struct ip_vs_flags flags; int i = get->num_services; if (genlmsg_parse(nlh, 0, attrs, IPVS_CMD_ATTR_MAX, ipvs_cmd_policy) != 0) return -1; if (!attrs[IPVS_CMD_ATTR_SERVICE]) return -1; if (nla_parse_nested(svc_attrs, IPVS_SVC_ATTR_MAX, attrs[IPVS_CMD_ATTR_SERVICE], ipvs_service_policy)) return -1; memset(&(get->entrytable[i]), 0, sizeof(get->entrytable[i])); if (!(svc_attrs[IPVS_SVC_ATTR_AF] && (svc_attrs[IPVS_SVC_ATTR_FWMARK] || (svc_attrs[IPVS_SVC_ATTR_PROTOCOL] && svc_attrs[IPVS_SVC_ATTR_ADDR] && svc_attrs[IPVS_SVC_ATTR_PORT])) && svc_attrs[IPVS_SVC_ATTR_SCHED_NAME] && svc_attrs[IPVS_SVC_ATTR_NETMASK] && svc_attrs[IPVS_SVC_ATTR_TIMEOUT] && svc_attrs[IPVS_SVC_ATTR_FLAGS])) return -1; get->entrytable[i].af = nla_get_u16(svc_attrs[IPVS_SVC_ATTR_AF]); if (svc_attrs[IPVS_SVC_ATTR_FWMARK]) get->entrytable[i].fwmark = nla_get_u32(svc_attrs[IPVS_SVC_ATTR_FWMARK]); else { get->entrytable[i].protocol = nla_get_u16(svc_attrs[IPVS_SVC_ATTR_PROTOCOL]); memcpy(&(get->entrytable[i].addr), nla_data(svc_attrs[IPVS_SVC_ATTR_ADDR]), sizeof(get->entrytable[i].addr)); get->entrytable[i].port = nla_get_u16(svc_attrs[IPVS_SVC_ATTR_PORT]); } strncpy(get->entrytable[i].sched_name, nla_get_string(svc_attrs[IPVS_SVC_ATTR_SCHED_NAME]), IP_VS_SCHEDNAME_MAXLEN); if (svc_attrs[IPVS_SVC_ATTR_PE_NAME]) strncpy(get->entrytable[i].pe_name, nla_get_string(svc_attrs[IPVS_SVC_ATTR_PE_NAME]), IP_VS_PENAME_MAXLEN); get->entrytable[i].netmask = nla_get_u32(svc_attrs[IPVS_SVC_ATTR_NETMASK]); get->entrytable[i].timeout = nla_get_u32(svc_attrs[IPVS_SVC_ATTR_TIMEOUT]); nla_memcpy(&flags, svc_attrs[IPVS_SVC_ATTR_FLAGS], sizeof(flags)); get->entrytable[i].flags = flags.flags & flags.mask; if (ipvs_parse_stats(&(get->entrytable[i].stats), svc_attrs[IPVS_SVC_ATTR_STATS]) != 0) return -1; get->entrytable[i].num_dests = 0; i++; get->num_services = i; get = realloc(get, sizeof(*get) + sizeof(ipvs_service_entry_t) * (get->num_services + 1)); *getp = get; return 0; }
static int nl80211_freqlist_cb(struct nl_msg *msg, void *arg) { struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = (struct genlmsghdr *) nlmsg_data(nlmsg_hdr(msg)); struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1]; struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1]; struct nlattr *nl_band, *nl_freq; int rem_band, rem_freq, num_freq = 0; uint32_t freq; struct nl80211_channel_block *chanb = (struct nl80211_channel_block *) arg; nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (!tb_msg[NL80211_ATTR_WIPHY_BANDS]) { return NL_SKIP; } if (tb_msg[NL80211_ATTR_WIPHY_NAME]) { if (strcmp(nla_get_string(tb_msg[NL80211_ATTR_WIPHY_NAME]), chanb->phyname) != 0) { return NL_SKIP; } } // Count the number of channels for (nl_band = (struct nlattr *) nla_data(tb_msg[NL80211_ATTR_WIPHY_BANDS]), rem_band = nla_len(tb_msg[NL80211_ATTR_WIPHY_BANDS]); nla_ok(nl_band, rem_band); nl_band = (struct nlattr *) nla_next(nl_band, &rem_band)) { nla_parse(tb_band, NL80211_BAND_ATTR_MAX, (struct nlattr *) nla_data(nl_band), nla_len(nl_band), NULL); for (nl_freq = (struct nlattr *) nla_data(tb_band[NL80211_BAND_ATTR_FREQS]), rem_freq = nla_len(tb_band[NL80211_BAND_ATTR_FREQS]); nla_ok(nl_freq, rem_freq); nl_freq = (struct nlattr *) nla_next(nl_freq, &rem_freq)) { nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, (struct nlattr *) nla_data(nl_freq), nla_len(nl_freq), NULL); if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) continue; if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) continue; num_freq++; } } chanb->nfreqs = num_freq; chanb->channel_list = malloc(sizeof(int) * num_freq); num_freq = 0; // Assemble a return for (nl_band = (struct nlattr *) nla_data(tb_msg[NL80211_ATTR_WIPHY_BANDS]), rem_band = nla_len(tb_msg[NL80211_ATTR_WIPHY_BANDS]); nla_ok(nl_band, rem_band); nl_band = (struct nlattr *) nla_next(nl_band, &rem_band)) { nla_parse(tb_band, NL80211_BAND_ATTR_MAX, (struct nlattr *) nla_data(nl_band), nla_len(nl_band), NULL); for (nl_freq = (struct nlattr *) nla_data(tb_band[NL80211_BAND_ATTR_FREQS]), rem_freq = nla_len(tb_band[NL80211_BAND_ATTR_FREQS]); nla_ok(nl_freq, rem_freq); nl_freq = (struct nlattr *) nla_next(nl_freq, &rem_freq)) { nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, (struct nlattr *) nla_data(nl_freq), nla_len(nl_freq), NULL); if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) continue; if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) continue; freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); chanb->channel_list[num_freq++] = FreqToChan(freq); } } return NL_SKIP; }
static int netlink_msg_handler(struct nl_msg *msg, void *arg) { struct nlmsghdr *hdr; struct tcmsg *tcm; struct nlattr *attrs[TCA_MAX+1]; struct nlattr *stat_attrs[TCA_STATS_MAX+1]; struct qdisc_handler *h; char qdisc[IFNAMSIZ] = {0}; int qdisc_l = 0; char ifname[IFNAMSIZ] = {0}; int ifname_l = 0; struct timeval current_time = {0}; double time; char *ret = NULL; struct gnet_stats_basic *sb; struct gnet_stats_queue *q; struct options *opt = arg; struct recordset rset = {0}; hdr = nlmsg_hdr(msg); tcm = nlmsg_data(hdr); if(!has_iface(opt, tcm->tcm_ifindex)) return NL_SKIP; if((ret = rtnl_link_i2name(opt->cache, tcm->tcm_ifindex, ifname, IFNAMSIZ)) == NULL) return NL_SKIP; // No length checking in netlink library. if((ifname_l = 1 + strnlen(ifname, IFNAMSIZ)) >= IFNAMSIZ) { ifname[IFNAMSIZ-1] = '\0'; ifname_l = IFNAMSIZ; } gettimeofday(¤t_time, NULL); time = (double)current_time.tv_usec / 1000000 + (double) current_time.tv_sec; add_record_double(&rset, "time", sizeof("time"), time); add_record_str(&rset, "iface", sizeof("iface"), ifname, ifname_l); nlmsg_parse(hdr, sizeof(*tcm), attrs, TCA_MAX, tca_policy); if(attrs[TCA_KIND]) { qdisc_l = nla_len(attrs[TCA_KIND]); memcpy(qdisc, nla_get_string(attrs[TCA_KIND]), qdisc_l); add_record_str(&rset, "qdisc", sizeof("qdisc"), qdisc, qdisc_l); } add_record_hex(&rset, "handle", sizeof("handle"), tcm->tcm_handle >> 16); if(attrs[TCA_STATS2]) { nla_parse_nested(stat_attrs, TCA_STATS_MAX, attrs[TCA_STATS2], tca_stats_policy); if(stat_attrs[TCA_STATS_BASIC]) { sb = nla_data(stat_attrs[TCA_STATS_BASIC]); add_record_uint(&rset, "bytes", sizeof("bytes"), sb->bytes); add_record_uint(&rset, "packets", sizeof("packets"), sb->packets); } if(stat_attrs[TCA_STATS_QUEUE]) { q = nla_data(stat_attrs[TCA_STATS_QUEUE]); add_record_uint(&rset, "drops", sizeof("drops"), q->drops); add_record_uint(&rset, "qlen", sizeof("qlen"), q->qlen); add_record_uint(&rset, "backlog", sizeof("backlog"), q->backlog); add_record_uint(&rset, "overlimits", sizeof("overlimits"), q->overlimits); add_record_uint(&rset, "requeues", sizeof("requeues"), q->requeues); } if(stat_attrs[TCA_STATS_APP]) { h = find_qdisc_handler(qdisc); if(h) h->parse_stats(stat_attrs[TCA_STATS_APP], &rset); } } opt->formatter->format(opt->formatter, &rset); clear_records(&rset); if(!opt->run_length || current_time.tv_sec < opt->start_time.tv_sec + opt->run_length) return NL_OK; else return NL_STOP; }