struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, struct rtattr *tab) { struct qdisc_rate_table *rtab; for (rtab = qdisc_rtab_list; rtab; rtab = rtab->next) { if (memcmp(&rtab->rate, r, sizeof(struct tc_ratespec)) == 0) { rtab->refcnt++; return rtab; } } if (tab == NULL || r->rate == 0 || r->cell_log == 0 || RTA_PAYLOAD(tab) != 1024) return NULL; rtab = kmalloc(sizeof(*rtab), GFP_KERNEL); if (rtab) { rtab->rate = *r; rtab->refcnt = 1; memcpy(rtab->data, RTA_DATA(tab), 1024); rtab->next = qdisc_rtab_list; qdisc_rtab_list = rtab; } return rtab; }
static int fq_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstats) { struct tc_fq_qd_stats *st; if (xstats == NULL) return 0; if (RTA_PAYLOAD(xstats) < sizeof(*st)) return -1; st = RTA_DATA(xstats); fprintf(f, " %u flows (%u inactive, %u throttled)", st->flows, st->inactive_flows, st->throttled_flows); if (st->time_next_delayed_flow > 0) fprintf(f, ", next packet delay %llu ns", st->time_next_delayed_flow); fprintf(f, "\n %llu gc, %llu highprio", st->gc_flows, st->highprio_packets); if (st->tcp_retrans) fprintf(f, ", %llu retrans", st->tcp_retrans); fprintf(f, ", %llu throttled", st->throttled); if (st->flows_plimit) fprintf(f, ", %llu flows_plimit", st->flows_plimit); if (st->pkts_too_long || st->allocation_errors) fprintf(f, "\n %llu too long pkts, %llu alloc errors\n", st->pkts_too_long, st->allocation_errors); return 0; }
static int tcf_ipt_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a, int ovr, int bind) { struct ipt_entry_target *t; unsigned h; struct rtattr *tb[TCA_IPT_MAX]; struct tcf_ipt *p; int ret = 0; u32 index = 0; u32 hook = 0; if (NULL == a || NULL == rta || (rtattr_parse(tb, TCA_IPT_MAX, RTA_DATA(rta), RTA_PAYLOAD(rta)) < 0)) { return -1; } if (tb[TCA_IPT_INDEX - 1]) { index = *(u32 *) RTA_DATA(tb[TCA_IPT_INDEX - 1]); DPRINTK("ipt index %d\n", index); } if (index && (p = tcf_hash_lookup(index)) != NULL) { a->priv = (void *) p; spin_lock(&p->lock); if (bind) { p->bindcnt += 1; p->refcnt += 1; } if (ovr) { goto override; } spin_unlock(&p->lock); return ret; }
/* * convert interface address from binary to text */ int inet_ntop_tc_addr(struct tcmsg *tcm, struct rtattr *tca, char *saddr, int slen) { int af = -1; unsigned char *addr = (unsigned char *)RTA_DATA(tca); int len = RTA_PAYLOAD(tca); switch(ntohs(TC_H_MIN(tcm->tcm_info))) { case ETH_P_IP: af = AF_INET; if(len < 4) return(2); break; case ETH_P_IPV6: af = AF_INET6; if(len < 16) return(2); break; } if(!inet_ntop(af, addr, saddr, slen)) return(1); return(0); }
int print_linkinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = (FILE*)arg; struct ifinfomsg *ifi = NLMSG_DATA(n); struct rtattr * tb[IFLA_MAX+1]; int len = n->nlmsg_len; unsigned m_flag = 0; if (n->nlmsg_type != RTM_NEWLINK && n->nlmsg_type != RTM_DELLINK) return 0; len -= NLMSG_LENGTH(sizeof(*ifi)); if (len < 0) return -1; if (filter.ifindex && ifi->ifi_index != filter.ifindex) return 0; if (filter.up && !(ifi->ifi_flags&IFF_UP)) return 0; parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len); if (tb[IFLA_IFNAME] == NULL) { fprintf(stderr, "BUG: device with ifindex %d has nil ifname\n", ifi->ifi_index); } if (filter.label && (!filter.family || filter.family == AF_PACKET) && fnmatch(filter.label, RTA_DATA(tb[IFLA_IFNAME]), 0)) return 0; if (tb[IFLA_GROUP]) { int group = *(int*)RTA_DATA(tb[IFLA_GROUP]); if (filter.group != -1 && group != filter.group) return -1; } if (tb[IFLA_MASTER]) { int master = *(int*)RTA_DATA(tb[IFLA_MASTER]); if (filter.master > 0 && master != filter.master) return -1; } else if (filter.master > 0) return -1; if (filter.kind) { if (tb[IFLA_LINKINFO]) { char *kind = parse_link_kind(tb[IFLA_LINKINFO]); if (strcmp(kind, filter.kind)) return -1; } else { return -1; } } if (n->nlmsg_type == RTM_DELLINK) fprintf(fp, "Deleted "); fprintf(fp, "%d: ", ifi->ifi_index); color_fprintf(fp, COLOR_IFNAME, "%s", tb[IFLA_IFNAME] ? rta_getattr_str(tb[IFLA_IFNAME]) : "<nil>"); if (tb[IFLA_LINK]) { SPRINT_BUF(b1); int iflink = *(int*)RTA_DATA(tb[IFLA_LINK]); if (iflink == 0) fprintf(fp, "@NONE: "); else { if (tb[IFLA_LINK_NETNSID]) fprintf(fp, "@if%d: ", iflink); else { fprintf(fp, "@%s: ", ll_idx_n2a(iflink, b1)); m_flag = ll_index_to_flags(iflink); m_flag = !(m_flag & IFF_UP); } } } else { fprintf(fp, ": "); } print_link_flags(fp, ifi->ifi_flags, m_flag); if (tb[IFLA_MTU]) fprintf(fp, "mtu %u ", *(int*)RTA_DATA(tb[IFLA_MTU])); if (tb[IFLA_QDISC]) fprintf(fp, "qdisc %s ", rta_getattr_str(tb[IFLA_QDISC])); if (tb[IFLA_MASTER]) { SPRINT_BUF(b1); fprintf(fp, "master %s ", ll_idx_n2a(*(int*)RTA_DATA(tb[IFLA_MASTER]), b1)); } if (tb[IFLA_PHYS_PORT_ID]) { SPRINT_BUF(b1); fprintf(fp, "portid %s ", hexstring_n2a(RTA_DATA(tb[IFLA_PHYS_PORT_ID]), RTA_PAYLOAD(tb[IFLA_PHYS_PORT_ID]), b1, sizeof(b1))); } if (tb[IFLA_OPERSTATE]) print_operstate(fp, rta_getattr_u8(tb[IFLA_OPERSTATE])); if (do_link && tb[IFLA_LINKMODE]) print_linkmode(fp, tb[IFLA_LINKMODE]); if (tb[IFLA_GROUP]) { SPRINT_BUF(b1); int group = *(int*)RTA_DATA(tb[IFLA_GROUP]); fprintf(fp, "group %s ", rtnl_group_n2a(group, b1, sizeof(b1))); } if (filter.showqueue) print_queuelen(fp, tb); if (!filter.family || filter.family == AF_PACKET || show_details) { SPRINT_BUF(b1); fprintf(fp, "%s", _SL_); fprintf(fp, " link/%s ", ll_type_n2a(ifi->ifi_type, b1, sizeof(b1))); if (tb[IFLA_ADDRESS]) { color_fprintf(fp, COLOR_MAC, "%s", ll_addr_n2a(RTA_DATA(tb[IFLA_ADDRESS]), RTA_PAYLOAD(tb[IFLA_ADDRESS]), ifi->ifi_type, b1, sizeof(b1))); } if (tb[IFLA_BROADCAST]) { if (ifi->ifi_flags&IFF_POINTOPOINT) fprintf(fp, " peer "); else fprintf(fp, " brd "); fprintf(fp, "%s", ll_addr_n2a(RTA_DATA(tb[IFLA_BROADCAST]), RTA_PAYLOAD(tb[IFLA_BROADCAST]), ifi->ifi_type, b1, sizeof(b1))); } } if (tb[IFLA_LINK_NETNSID]) { int id = *(int*)RTA_DATA(tb[IFLA_LINK_NETNSID]); if (id >= 0) fprintf(fp, " link-netnsid %d", id); else fprintf(fp, " link-netnsid unknown"); } if (tb[IFLA_PROMISCUITY] && show_details) fprintf(fp, " promiscuity %u ", *(int*)RTA_DATA(tb[IFLA_PROMISCUITY])); if (tb[IFLA_LINKINFO] && show_details) print_linktype(fp, tb[IFLA_LINKINFO]); if (do_link && tb[IFLA_AF_SPEC] && show_details) print_af_spec(fp, tb[IFLA_AF_SPEC]); if ((do_link || show_details) && tb[IFLA_IFALIAS]) { fprintf(fp, "%s alias %s", _SL_, rta_getattr_str(tb[IFLA_IFALIAS])); } if (do_link && show_stats) { fprintf(fp, "%s", _SL_); __print_link_stats(fp, tb); } if ((do_link || show_details) && tb[IFLA_VFINFO_LIST] && tb[IFLA_NUM_VF]) { struct rtattr *i, *vflist = tb[IFLA_VFINFO_LIST]; int rem = RTA_PAYLOAD(vflist); for (i = RTA_DATA(vflist); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) print_vfinfo(fp, i); } fprintf(fp, "\n"); fflush(fp); return 1; }
int handle_rtm_newroute(const struct nlmsghdr *nl){ const struct rtmsg *rt = NLMSG_DATA(nl); struct rtattr *ra; void *as,*ad,*ag; int rlen,oif; route *r,**prev; size_t flen; oif = -1; if((r = create_route()) == NULL){ return -1; } switch( (r->family = rt->rtm_family) ){ case AF_INET:{ flen = sizeof(uint32_t); as = &((struct sockaddr_in *)&r->sss)->sin_addr; ad = &((struct sockaddr_in *)&r->ssd)->sin_addr; ag = &((struct sockaddr_in *)&r->ssg)->sin_addr; break;}case AF_INET6:{ flen = sizeof(uint32_t) * 4; as = &((struct sockaddr_in6 *)&r->sss)->sin6_addr; ad = &((struct sockaddr_in6 *)&r->ssd)->sin6_addr; ag = &((struct sockaddr_in6 *)&r->ssg)->sin6_addr; break;}case AF_BRIDGE:{ // FIXME wtf is a bridge route diagnostic("got a bridge route hrmmm FIXME"); return -1; // FIXME break;}default:{ flen = 0; break;} } r->maskbits = rt->rtm_dst_len; if(flen == 0 || flen > sizeof(r->sss.__ss_padding)){ diagnostic("Unknown route family %u",rt->rtm_family); return -1; } rlen = nl->nlmsg_len - NLMSG_LENGTH(sizeof(*rt)); ra = (struct rtattr *)((char *)(NLMSG_DATA(nl)) + sizeof(*rt)); memset(&r->ssg,0,sizeof(r->ssg)); memset(&r->ssd,0,sizeof(r->ssd)); memset(&r->sss,0,sizeof(r->sss)); while(RTA_OK(ra,rlen)){ switch(ra->rta_type){ case RTA_DST:{ if(RTA_PAYLOAD(ra) != flen){ diagnostic("Expected %zu dst bytes, got %zu", flen,RTA_PAYLOAD(ra)); break; } if(r->ssd.ss_family){ diagnostic("Got two destinations for route"); break; } memcpy(ad,RTA_DATA(ra),flen); r->ssd.ss_family = r->family; break;}case RTA_PREFSRC: case RTA_SRC:{ // FIXME do we not want to prefer PREFSRC? if(RTA_PAYLOAD(ra) != flen){ diagnostic("Expected %zu src bytes, got %zu", flen,RTA_PAYLOAD(ra)); break; } if(r->sss.ss_family){ diagnostic("Got two sources for route"); break; } memcpy(as,RTA_DATA(ra),flen); r->sss.ss_family = r->family; break;}case RTA_IIF:{ if(RTA_PAYLOAD(ra) != sizeof(int)){ diagnostic("Expected %zu iiface bytes, got %zu", sizeof(int),RTA_PAYLOAD(ra)); break; } // we don't use RTA_OIF: iif = *(int *)RTA_DATA(ra); break;}case RTA_OIF:{ if(RTA_PAYLOAD(ra) != sizeof(int)){ diagnostic("Expected %zu oiface bytes, got %zu", sizeof(int),RTA_PAYLOAD(ra)); break; } oif = *(int *)RTA_DATA(ra); break;}case RTA_GATEWAY:{ if(RTA_PAYLOAD(ra) != flen){ diagnostic("Expected %zu gw bytes, got %zu", flen,RTA_PAYLOAD(ra)); break; } if(r->ssg.ss_family){ diagnostic("Got two gateways for route"); break; } // We get 0.0.0.0 as the gateway when there's no 'via' if(memcmp(ag,RTA_DATA(ra),flen)){ memcpy(ag,RTA_DATA(ra),flen); r->ssg.ss_family = r->family; } break;}case RTA_PRIORITY:{ break;}case RTA_METRICS:{ break;}case RTA_MULTIPATH:{ // break;}case RTA_PROTOINFO:{ // unused break;}case RTA_FLOW:{ break;}case RTA_CACHEINFO:{ // break;}case RTA_SESSION:{ // unused // break;}case RTA_MP_ALGO:{ // unused break;}case RTA_TABLE:{ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) break;}case RTA_MARK:{ #endif break;}case RTA_MFC_STATS:{ break;}case RTA_VIA:{ break;}case RTA_NEWDST:{ break;}case RTA_PREF:{ break;}case RTA_ENCAP_TYPE:{ break;}case RTA_ENCAP:{ break;}case RTA_EXPIRES:{ break;}case RTA_PAD:{ break;}default:{ diagnostic("Unknown rtatype %u",ra->rta_type); break;}} ra = RTA_NEXT(ra,rlen); } if(rlen){ diagnostic("%d excess bytes on newlink message",rlen); } if((r->iface = iface_by_idx(oif)) == NULL){ diagnostic("Unknown output interface %d on %s",oif,r->iface->name); goto err; } { char str[INET6_ADDRSTRLEN],via[INET6_ADDRSTRLEN]; inet_ntop(rt->rtm_family,ad,str,sizeof(str)); inet_ntop(rt->rtm_family,ag,via,sizeof(via)); diagnostic("[%s] new route to %s/%u %ls%ls%s", r->iface->name,str,r->maskbits, rt->rtm_type == RTN_LOCAL ? L"(local)" : rt->rtm_type == RTN_BROADCAST ? L"(broadcast)" : rt->rtm_type == RTN_UNREACHABLE ? L"(unreachable)" : rt->rtm_type == RTN_ANYCAST ? L"(anycast)" : rt->rtm_type == RTN_UNICAST ? L"(unicast)" : rt->rtm_type == RTN_MULTICAST ? L"(multicast)" : rt->rtm_type == RTN_BLACKHOLE ? L"(blackhole)" : rt->rtm_type == RTN_MULTICAST ? L"(multicast)" : L"", r->ssg.ss_family ? L" via " : L"", r->ssg.ss_family ? via : ""); } // We're not interest in blackholes, unreachables, prohibits, NATs yet if(rt->rtm_type != RTN_UNICAST && rt->rtm_type != RTN_LOCAL && rt->rtm_type != RTN_BROADCAST && rt->rtm_type != RTN_ANYCAST && rt->rtm_type != RTN_MULTICAST){ free_route(r); return 0; } assert(r->iface); if(!r->sss.ss_family){ struct routepath rp; if(get_router(r->sss.ss_family,ad,&rp) == 0){ if(r->sss.ss_family == AF_INET){ memcpy(as,rp.src,4); }else if(r->sss.ss_family == AF_INET6){ memcpy(as,rp.src,16); }else{ assert(0); } }else{ // FIXME vicious hackery! if(r->family == AF_INET6){ memcpy(as,r->iface->ip6defsrc,flen); r->sss.ss_family = AF_INET6; } } } if(r->family == AF_INET){ lock_interface(r->iface); if(add_route4(r->iface,ad,r->ssg.ss_family ? ag : NULL, r->sss.ss_family ? as : NULL, r->maskbits)){ unlock_interface(r->iface); diagnostic("Couldn't add route to %s",r->iface->name); goto err; } if(r->ssg.ss_family){ send_arp_req(r->iface,r->iface->bcast,ag,as); } unlock_interface(r->iface); pthread_mutex_lock(&route_lock); prev = &ip_table4; // Order most-specific (largest maskbits) to least-specific (0 maskbits) while(*prev){ if(r->maskbits > (*prev)->maskbits){ break; } prev = &(*prev)->next; } r->next = *prev; *prev = r; if(r->sss.ss_family){ while( *(prev = &(*prev)->next) ){ assert((*prev)->maskbits < r->maskbits); if(!((*prev)->sss.ss_family)){ memcpy(&(*prev)->sss,&r->sss,sizeof(r->sss)); } } } pthread_mutex_unlock(&route_lock); }else if(r->family == AF_INET6){ lock_interface(r->iface); if(add_route6(r->iface,ad,r->ssg.ss_family ? ag : NULL,r->sss.ss_family ? as : NULL,r->maskbits)){ unlock_interface(r->iface); diagnostic("Couldn't add route to %s",r->iface->name); goto err; } unlock_interface(r->iface); pthread_mutex_lock(&route_lock); prev = &ip_table6; // Order most-specific (largest maskbits) to least-specific (0 maskbits) while(*prev){ if(r->maskbits > (*prev)->maskbits){ break; } prev = &(*prev)->next; } r->next = *prev; *prev = r; // FIXME set less-specific sources pthread_mutex_unlock(&route_lock); } return 0; err: free_route(r); return -1; }
int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = arg; struct ndmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr * tb[NDA_MAX+1]; if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH) { fprintf(stderr, "Not RTM_NEWNEIGH: %08x %08x %08x\n", n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); return 0; } len -= NLMSG_LENGTH(sizeof(*r)); if (len < 0) { fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); return -1; } if (r->ndm_family != AF_BRIDGE) return 0; if (filter_index && filter_index != r->ndm_ifindex) return 0; parse_rtattr(tb, NDA_MAX, NDA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r))); if (n->nlmsg_type == RTM_DELNEIGH) fprintf(fp, "Deleted "); if (tb[NDA_LLADDR]) { SPRINT_BUF(b1); fprintf(fp, "%s ", ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]), RTA_PAYLOAD(tb[NDA_LLADDR]), ll_index_to_type(r->ndm_ifindex), b1, sizeof(b1))); } if (!filter_index && r->ndm_ifindex) fprintf(fp, "dev %s ", ll_index_to_name(r->ndm_ifindex)); if (tb[NDA_DST]) { SPRINT_BUF(abuf); fprintf(fp, "dst %s ", format_host(AF_INET, RTA_PAYLOAD(tb[NDA_DST]), RTA_DATA(tb[NDA_DST]), abuf, sizeof(abuf))); } if (show_stats && tb[NDA_CACHEINFO]) { struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]); int hz = get_user_hz(); fprintf(fp, " used %d/%d", ci->ndm_used/hz, ci->ndm_updated/hz); } if (r->ndm_flags & NTF_SELF) fprintf(fp, "self "); if (r->ndm_flags & NTF_MASTER) fprintf(fp, "master "); fprintf(fp, "%s\n", state_n2a(r->ndm_state)); return 0; }
struct tcf_police * tcf_police_locate(struct rtattr *rta, struct rtattr *est) { unsigned h; struct tcf_police *p; struct rtattr *tb[TCA_POLICE_MAX]; struct tc_police *parm; if (rtattr_parse(tb, TCA_POLICE_MAX, RTA_DATA(rta), RTA_PAYLOAD(rta)) < 0) return NULL; if (tb[TCA_POLICE_TBF-1] == NULL) return NULL; parm = RTA_DATA(tb[TCA_POLICE_TBF-1]); if (parm->index && (p = tcf_police_lookup(parm->index)) != NULL) { p->refcnt++; return p; } p = kmalloc(sizeof(*p), GFP_KERNEL); if (p == NULL) return NULL; memset(p, 0, sizeof(*p)); p->refcnt = 1; spin_lock_init(&p->lock); p->stats.lock = &p->lock; if (parm->rate.rate) { if ((p->R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE-1])) == NULL) goto failure; if (parm->peakrate.rate && (p->P_tab = qdisc_get_rtab(&parm->peakrate, tb[TCA_POLICE_PEAKRATE-1])) == NULL) goto failure; } if (tb[TCA_POLICE_RESULT-1]) p->result = *(int*)RTA_DATA(tb[TCA_POLICE_RESULT-1]); #ifdef CONFIG_NET_ESTIMATOR if (tb[TCA_POLICE_AVRATE-1]) p->ewma_rate = *(u32*)RTA_DATA(tb[TCA_POLICE_AVRATE-1]); #endif p->toks = p->burst = parm->burst; p->mtu = parm->mtu; if (p->mtu == 0) { p->mtu = ~0; if (p->R_tab) p->mtu = 255<<p->R_tab->rate.cell_log; } if (p->P_tab) p->ptoks = L2T_P(p, p->mtu); PSCHED_GET_TIME(p->t_c); p->index = parm->index ? : tcf_police_new_index(); p->action = parm->action; #ifdef CONFIG_NET_ESTIMATOR if (est) qdisc_new_estimator(&p->stats, est); #endif h = tcf_police_hash(p->index); write_lock_bh(&police_lock); p->next = tcf_police_ht[h]; tcf_police_ht[h] = p; write_unlock_bh(&police_lock); return p; failure: if (p->R_tab) qdisc_put_rtab(p->R_tab); kfree(p); return NULL; }
int xfrm_policy_print(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { struct rtattr * tb[XFRMA_MAX+1]; struct rtattr * rta; struct xfrm_userpolicy_info *xpinfo = NULL; struct xfrm_user_polexpire *xpexp = NULL; struct xfrm_userpolicy_id *xpid = NULL; __u8 ptype = XFRM_POLICY_TYPE_MAIN; FILE *fp = (FILE*)arg; int len = n->nlmsg_len; if (n->nlmsg_type != XFRM_MSG_NEWPOLICY && n->nlmsg_type != XFRM_MSG_DELPOLICY && n->nlmsg_type != XFRM_MSG_UPDPOLICY && n->nlmsg_type != XFRM_MSG_POLEXPIRE) { fprintf(stderr, "Not a policy: %08x %08x %08x\n", n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); return 0; } if (n->nlmsg_type == XFRM_MSG_DELPOLICY) { xpid = NLMSG_DATA(n); len -= NLMSG_SPACE(sizeof(*xpid)); } else if (n->nlmsg_type == XFRM_MSG_POLEXPIRE) { xpexp = NLMSG_DATA(n); xpinfo = &xpexp->pol; len -= NLMSG_SPACE(sizeof(*xpexp)); } else { xpexp = NULL; xpinfo = NLMSG_DATA(n); len -= NLMSG_SPACE(sizeof(*xpinfo)); } if (len < 0) { fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); return -1; } if (n->nlmsg_type == XFRM_MSG_DELPOLICY) rta = XFRMPID_RTA(xpid); else if (n->nlmsg_type == XFRM_MSG_POLEXPIRE) rta = XFRMPEXP_RTA(xpexp); else rta = XFRMP_RTA(xpinfo); parse_rtattr(tb, XFRMA_MAX, rta, len); if (tb[XFRMA_POLICY_TYPE]) { struct xfrm_userpolicy_type *upt; if (RTA_PAYLOAD(tb[XFRMA_POLICY_TYPE]) < sizeof(*upt)) { fprintf(stderr, "too short XFRMA_POLICY_TYPE len\n"); return -1; } upt = (struct xfrm_userpolicy_type *)RTA_DATA(tb[XFRMA_POLICY_TYPE]); ptype = upt->type; } if (xpinfo && !xfrm_policy_filter_match(xpinfo, ptype)) return 0; if (n->nlmsg_type == XFRM_MSG_DELPOLICY) fprintf(fp, "Deleted "); else if (n->nlmsg_type == XFRM_MSG_UPDPOLICY) fprintf(fp, "Updated "); else if (n->nlmsg_type == XFRM_MSG_POLEXPIRE) fprintf(fp, "Expired "); if (n->nlmsg_type == XFRM_MSG_DELPOLICY) { //xfrm_policy_id_print(); if (!tb[XFRMA_POLICY]) { fprintf(stderr, "Buggy XFRM_MSG_DELPOLICY: no XFRMA_POLICY\n"); return -1; } if (RTA_PAYLOAD(tb[XFRMA_POLICY]) < sizeof(*xpinfo)) { fprintf(stderr, "Buggy XFRM_MSG_DELPOLICY: too short XFRMA_POLICY len\n"); return -1; } xpinfo = (struct xfrm_userpolicy_info *)RTA_DATA(tb[XFRMA_POLICY]); } xfrm_policy_info_print(xpinfo, tb, fp, NULL, NULL); if (n->nlmsg_type == XFRM_MSG_POLEXPIRE) { fprintf(fp, "\t"); fprintf(fp, "hard %u", xpexp->hard); fprintf(fp, "%s", _SL_); } if (oneline) fprintf(fp, "\n"); fflush(fp); return 0; }
/* Return value becomes exitcode. It's okay to not return at all */ int ipaddr_list_or_flush(int argc, char **argv, int flush) { static const char option[] ALIGN1 = "to\0""scope\0""up\0""label\0""dev\0"; struct nlmsg_list *linfo = NULL; struct nlmsg_list *ainfo = NULL; struct nlmsg_list *l; struct rtnl_handle rth; char *filter_dev = NULL; int no_link = 0; ipaddr_reset_filter(oneline); filter.showqueue = 1; if (filter.family == AF_UNSPEC) filter.family = preferred_family; if (flush) { if (argc <= 0) { bb_error_msg_and_die(bb_msg_requires_arg, "flush"); } if (filter.family == AF_PACKET) { bb_error_msg_and_die("cannot flush link addresses"); } } while (argc > 0) { const int option_num = index_in_strings(option, *argv); switch (option_num) { case 0: /* to */ NEXT_ARG(); get_prefix(&filter.pfx, *argv, filter.family); if (filter.family == AF_UNSPEC) { filter.family = filter.pfx.family; } break; case 1: /* scope */ { uint32_t scope = 0; NEXT_ARG(); filter.scopemask = -1; if (rtnl_rtscope_a2n(&scope, *argv)) { if (strcmp(*argv, "all") != 0) { invarg(*argv, "scope"); } scope = RT_SCOPE_NOWHERE; filter.scopemask = 0; } filter.scope = scope; break; } case 2: /* up */ filter.up = 1; break; case 3: /* label */ NEXT_ARG(); filter.label = *argv; break; case 4: /* dev */ NEXT_ARG(); default: if (filter_dev) { duparg2("dev", *argv); } filter_dev = *argv; } argv++; argc--; } xrtnl_open(&rth); xrtnl_wilddump_request(&rth, preferred_family, RTM_GETLINK); xrtnl_dump_filter(&rth, store_nlmsg, &linfo); if (filter_dev) { filter.ifindex = xll_name_to_index(filter_dev); } if (flush) { char flushb[4096-512]; filter.flushb = flushb; filter.flushp = 0; filter.flushe = sizeof(flushb); filter.rth = &rth; for (;;) { xrtnl_wilddump_request(&rth, filter.family, RTM_GETADDR); filter.flushed = 0; xrtnl_dump_filter(&rth, print_addrinfo, stdout); if (filter.flushed == 0) { return 0; } if (flush_update() < 0) return 1; } } if (filter.family != AF_PACKET) { xrtnl_wilddump_request(&rth, filter.family, RTM_GETADDR); xrtnl_dump_filter(&rth, store_nlmsg, &ainfo); } if (filter.family && filter.family != AF_PACKET) { struct nlmsg_list **lp; lp=&linfo; if (filter.oneline) no_link = 1; while ((l=*lp)!=NULL) { int ok = 0; struct ifinfomsg *ifi = NLMSG_DATA(&l->h); struct nlmsg_list *a; for (a=ainfo; a; a=a->next) { struct nlmsghdr *n = &a->h; struct ifaddrmsg *ifa = NLMSG_DATA(n); if (ifa->ifa_index != ifi->ifi_index || (filter.family && filter.family != ifa->ifa_family)) continue; if ((filter.scope^ifa->ifa_scope)&filter.scopemask) continue; if ((filter.flags^ifa->ifa_flags)&filter.flagmask) continue; if (filter.pfx.family || filter.label) { struct rtattr *tb[IFA_MAX+1]; memset(tb, 0, sizeof(tb)); parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(n)); if (!tb[IFA_LOCAL]) tb[IFA_LOCAL] = tb[IFA_ADDRESS]; if (filter.pfx.family && tb[IFA_LOCAL]) { inet_prefix dst; memset(&dst, 0, sizeof(dst)); dst.family = ifa->ifa_family; memcpy(&dst.data, RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_LOCAL])); if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen)) continue; } if (filter.label) { SPRINT_BUF(b1); const char *label; if (tb[IFA_LABEL]) label = RTA_DATA(tb[IFA_LABEL]); else label = ll_idx_n2a(ifa->ifa_index, b1); if (fnmatch(filter.label, label, 0) != 0) continue; } } ok = 1; break; } if (!ok) *lp = l->next; else lp = &l->next; } } for (l = linfo; l; l = l->next) { if (no_link || print_linkinfo(NULL, &l->h, stdout) == 0) { struct ifinfomsg *ifi = NLMSG_DATA(&l->h); if (filter.family != AF_PACKET) print_selected_addrinfo(ifi->ifi_index, ainfo, stdout); } fflush(stdout); /* why? */ } return 0; }
// Source-compatible with the BSD function. int getifaddrs(ifaddrs** result) { // Simplify cleanup for callers. *result = NULL; // Create a netlink socket. ScopedFd fd(socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)); if (fd.get() < 0) { return -1; } // Ask for the address information. addrReq_struct addrRequest; memset(&addrRequest, 0, sizeof(addrRequest)); addrRequest.netlinkHeader.nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH; addrRequest.netlinkHeader.nlmsg_type = RTM_GETADDR; addrRequest.netlinkHeader.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(addrRequest))); addrRequest.msg.ifa_family = AF_UNSPEC; // All families. addrRequest.msg.ifa_index = 0; // All interfaces. if (!sendNetlinkMessage(fd.get(), &addrRequest, addrRequest.netlinkHeader.nlmsg_len)) { return -1; } // Read the responses. LocalArray<0> buf(65536); // We don't necessarily have std::vector. ssize_t bytesRead; while ((bytesRead = recvNetlinkMessage(fd.get(), &buf[0], buf.size())) > 0) { nlmsghdr* hdr = reinterpret_cast<nlmsghdr*>(&buf[0]); for (; NLMSG_OK(hdr, (unsigned int)bytesRead); hdr = NLMSG_NEXT(hdr, bytesRead)) { switch (hdr->nlmsg_type) { case NLMSG_DONE: { return 0; } case NLMSG_ERROR: { return -1; } case RTM_NEWADDR: { ifaddrmsg* address = reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(hdr)); rtattr* rta = IFA_RTA(address); size_t ifaPayloadLength = IFA_PAYLOAD(hdr); while (RTA_OK(rta, ifaPayloadLength)) { if (rta->rta_type == IFA_LOCAL) { unsigned char family = address->ifa_family; if (family == AF_INET || family == AF_INET6) { *result = new ifaddrs(*result); if (!(*result)->setNameAndFlagsByIndex(address->ifa_index)) { return -1; } (*result)->setAddress(family, RTA_DATA(rta), RTA_PAYLOAD(rta)); (*result)->setNetmask(family, address->ifa_prefixlen); } } rta = RTA_NEXT(rta, ifaPayloadLength); } } break; } } } // We only get here if recv fails before we see a NLMSG_DONE. return -1; }
extern int ipaddr_list_or_flush(int argc, char **argv, int flush) { const char *option[] = { "to", "scope", "up", "label", "dev", 0 }; struct nlmsg_list *linfo = NULL; struct nlmsg_list *ainfo = NULL; struct nlmsg_list *l; struct rtnl_handle rth; char *filter_dev = NULL; int no_link = 0; ipaddr_reset_filter(oneline); filter.showqueue = 1; if (filter.family == AF_UNSPEC) filter.family = preferred_family; if (flush) { if (argc <= 0) { fprintf(stderr, "Flush requires arguments.\n"); return -1; } if (filter.family == AF_PACKET) { fprintf(stderr, "Cannot flush link addresses.\n"); return -1; } } while (argc > 0) { const unsigned short option_num = compare_string_array(option, *argv); switch (option_num) { case 0: /* to */ NEXT_ARG(); get_prefix(&filter.pfx, *argv, filter.family); if (filter.family == AF_UNSPEC) { filter.family = filter.pfx.family; } break; case 1: /* scope */ { int scope = 0; NEXT_ARG(); filter.scopemask = -1; if (rtnl_rtscope_a2n(&scope, *argv)) { if (strcmp(*argv, "all") != 0) { invarg("invalid \"scope\"\n", *argv); } scope = RT_SCOPE_NOWHERE; filter.scopemask = 0; } filter.scope = scope; break; } case 2: /* up */ filter.up = 1; break; case 3: /* label */ NEXT_ARG(); filter.label = *argv; break; case 4: /* dev */ NEXT_ARG(); default: if (filter_dev) { duparg2("dev", *argv); } filter_dev = *argv; } argv++; argc--; } if (rtnl_open(&rth, 0) < 0) exit(1); if (rtnl_wilddump_request(&rth, preferred_family, RTM_GETLINK) < 0) { bb_perror_msg_and_die("Cannot send dump request"); } if (rtnl_dump_filter(&rth, store_nlmsg, &linfo, NULL, NULL) < 0) { bb_error_msg_and_die("Dump terminated"); } if (filter_dev) { filter.ifindex = ll_name_to_index(filter_dev); if (filter.ifindex <= 0) { bb_error_msg("Device \"%s\" does not exist.", filter_dev); return -1; } } if (flush) { int round = 0; char flushb[4096-512]; filter.flushb = flushb; filter.flushp = 0; filter.flushe = sizeof(flushb); filter.rth = &rth; for (;;) { if (rtnl_wilddump_request(&rth, filter.family, RTM_GETADDR) < 0) { perror("Cannot send dump request"); exit(1); } filter.flushed = 0; if (rtnl_dump_filter(&rth, print_addrinfo, stdout, NULL, NULL) < 0) { fprintf(stderr, "Flush terminated\n"); exit(1); } if (filter.flushed == 0) { #if 0 if (round == 0) fprintf(stderr, "Nothing to flush.\n"); #endif fflush(stdout); return 0; } round++; if (flush_update() < 0) exit(1); } } if (filter.family != AF_PACKET) { if (rtnl_wilddump_request(&rth, filter.family, RTM_GETADDR) < 0) { bb_perror_msg_and_die("Cannot send dump request"); } if (rtnl_dump_filter(&rth, store_nlmsg, &ainfo, NULL, NULL) < 0) { bb_error_msg_and_die("Dump terminated"); } } if (filter.family && filter.family != AF_PACKET) { struct nlmsg_list **lp; lp=&linfo; if (filter.oneline) no_link = 1; while ((l=*lp)!=NULL) { int ok = 0; struct ifinfomsg *ifi = NLMSG_DATA(&l->h); struct nlmsg_list *a; for (a=ainfo; a; a=a->next) { struct nlmsghdr *n = &a->h; struct ifaddrmsg *ifa = NLMSG_DATA(n); if (ifa->ifa_index != ifi->ifi_index || (filter.family && filter.family != ifa->ifa_family)) continue; if ((filter.scope^ifa->ifa_scope)&filter.scopemask) continue; if ((filter.flags^ifa->ifa_flags)&filter.flagmask) continue; if (filter.pfx.family || filter.label) { struct rtattr *tb[IFA_MAX+1]; memset(tb, 0, sizeof(tb)); parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(n)); if (!tb[IFA_LOCAL]) tb[IFA_LOCAL] = tb[IFA_ADDRESS]; if (filter.pfx.family && tb[IFA_LOCAL]) { inet_prefix dst; memset(&dst, 0, sizeof(dst)); dst.family = ifa->ifa_family; memcpy(&dst.data, RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_LOCAL])); if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen)) continue; } if (filter.label) { SPRINT_BUF(b1); const char *label; if (tb[IFA_LABEL]) label = RTA_DATA(tb[IFA_LABEL]); else label = ll_idx_n2a(ifa->ifa_index, b1); if (fnmatch(filter.label, label, 0) != 0) continue; } } ok = 1; break; } if (!ok) *lp = l->next; else lp = &l->next; } } for (l=linfo; l; l = l->next) { if (no_link || print_linkinfo(NULL, &l->h, stdout) == 0) { struct ifinfomsg *ifi = NLMSG_DATA(&l->h); if (filter.family != AF_PACKET) print_selected_addrinfo(ifi->ifi_index, ainfo, stdout); } fflush(stdout); } exit(0); }
int parse_ematch(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) { begin_argc = ematch_argc = *argc_p; begin_argv = ematch_argv = *argv_p; if (ematch_parse()) { int err = em_parse_error(EINVAL, NULL, NULL, NULL, "Parse error"); free_ematch_err(); return err; } free_ematch_err(); /* undo look ahead by parser */ ematch_argc++; ematch_argv--; if (ematch_root) { struct rtattr *tail, *tail_list; struct tcf_ematch_tree_hdr hdr = { .nmatches = flatten_tree(ematch_root, ematch_root), .progid = TCF_EM_PROG_TC }; tail = NLMSG_TAIL(n); addattr_l(n, MAX_MSG, tca_id, NULL, 0); addattr_l(n, MAX_MSG, TCA_EMATCH_TREE_HDR, &hdr, sizeof(hdr)); tail_list = NLMSG_TAIL(n); addattr_l(n, MAX_MSG, TCA_EMATCH_TREE_LIST, NULL, 0); if (parse_tree(n, ematch_root) < 0) return -1; tail_list->rta_len = (void*) NLMSG_TAIL(n) - (void*) tail_list; tail->rta_len = (void*) NLMSG_TAIL(n) - (void*) tail; } *argc_p = ematch_argc; *argv_p = ematch_argv; return 0; } static int print_ematch_seq(FILE *fd, struct rtattr **tb, int start, int prefix) { int n, i = start; struct tcf_ematch_hdr *hdr; int dlen; void *data; for (;;) { if (tb[i] == NULL) return -1; dlen = RTA_PAYLOAD(tb[i]) - sizeof(*hdr); data = (void *) RTA_DATA(tb[i]) + sizeof(*hdr); if (dlen < 0) return -1; hdr = RTA_DATA(tb[i]); if (hdr->flags & TCF_EM_INVERT) fprintf(fd, "NOT "); if (hdr->kind == 0) { __u32 ref; if (dlen < sizeof(__u32)) return -1; ref = *(__u32 *) data; fprintf(fd, "(\n"); for (n = 0; n <= prefix; n++) fprintf(fd, " "); if (print_ematch_seq(fd, tb, ref + 1, prefix + 1) < 0) return -1; for (n = 0; n < prefix; n++) fprintf(fd, " "); fprintf(fd, ") "); } else { struct ematch_util *e; e = get_ematch_kind_num(hdr->kind); if (e == NULL) fprintf(fd, "[unknown ematch %d]\n", hdr->kind); else { fprintf(fd, "%s(", e->kind); if (e->print_eopt(fd, hdr, data, dlen) < 0) return -1; fprintf(fd, ")\n"); } if (hdr->flags & TCF_EM_REL_MASK) for (n = 0; n < prefix; n++) fprintf(fd, " "); } switch (hdr->flags & TCF_EM_REL_MASK) { case TCF_EM_REL_AND: fprintf(fd, "AND "); break; case TCF_EM_REL_OR: fprintf(fd, "OR "); break; default: return 0; } i++; } return 0; }
static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, int p_numLinks) { struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr); struct ifaddrs *l_interface = findInterface(l_info->ifa_index, p_resultList, p_numLinks); if(l_info->ifa_family == AF_PACKET) { return 0; } size_t l_nameSize = 0; size_t l_addrSize = 0; int l_addedNetmask = 0; size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg)); struct rtattr *l_rta; for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) { size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); switch(l_rta->rta_type) { case IFA_ADDRESS: case IFA_LOCAL: if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask) { // make room for netmask l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize)); l_addedNetmask = 1; } case IFA_BROADCAST: l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize)); break; case IFA_LABEL: l_nameSize += NLMSG_ALIGN(l_rtaSize + 1); break; default: break; } } struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize); if (l_entry == NULL) { return -1; } memset(l_entry, 0, sizeof(struct ifaddrs)); l_entry->ifa_name = (l_interface ? l_interface->ifa_name : ""); char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs); char *l_addr = l_name + l_nameSize; l_entry->ifa_flags = l_info->ifa_flags; if(l_interface) { l_entry->ifa_flags |= l_interface->ifa_flags; } l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg)); for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) { void *l_rtaData = RTA_DATA(l_rta); size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); switch(l_rta->rta_type) { case IFA_ADDRESS: case IFA_BROADCAST: case IFA_LOCAL: { size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize); makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize); if(l_info->ifa_family == AF_INET6) { if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData)) { ((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index; } } if(l_rta->rta_type == IFA_ADDRESS) { // apparently in a point-to-point network IFA_ADDRESS contains the dest address and IFA_LOCAL contains the local address if(l_entry->ifa_addr) { l_entry->ifa_dstaddr = (struct sockaddr *)l_addr; } else { l_entry->ifa_addr = (struct sockaddr *)l_addr; } } else if(l_rta->rta_type == IFA_LOCAL) { if(l_entry->ifa_addr) { l_entry->ifa_dstaddr = l_entry->ifa_addr; } l_entry->ifa_addr = (struct sockaddr *)l_addr; } else { l_entry->ifa_broadaddr = (struct sockaddr *)l_addr; } l_addr += NLMSG_ALIGN(l_addrLen); break; } case IFA_LABEL: strncpy(l_name, l_rtaData, l_rtaDataSize); l_name[l_rtaDataSize] = '\0'; l_entry->ifa_name = l_name; break; default: break; } } if(l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6)) { unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128); unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen); char l_mask[16] = {0}; unsigned i; for(i=0; i<(l_prefix/8); ++i) { l_mask[i] = 0xff; } if(l_prefix % 8) { l_mask[i] = 0xff << (8 - (l_prefix % 8)); } makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8); l_entry->ifa_netmask = (struct sockaddr *)l_addr; } addToEnd(p_resultList, l_entry); return 0; }
static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList) { struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr); size_t l_nameSize = 0; size_t l_addrSize = 0; size_t l_dataSize = 0; size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg)); struct rtattr *l_rta; for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) { size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); switch(l_rta->rta_type) { case IFLA_ADDRESS: case IFLA_BROADCAST: l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize)); break; case IFLA_IFNAME: l_nameSize += NLMSG_ALIGN(l_rtaSize + 1); break; case IFLA_STATS: l_dataSize += NLMSG_ALIGN(l_rtaSize); break; default: break; } } struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + sizeof(int) + l_nameSize + l_addrSize + l_dataSize); if (l_entry == NULL) { return -1; } memset(l_entry, 0, sizeof(struct ifaddrs)); l_entry->ifa_name = ""; char *l_index = ((char *)l_entry) + sizeof(struct ifaddrs); char *l_name = l_index + sizeof(int); char *l_addr = l_name + l_nameSize; char *l_data = l_addr + l_addrSize; // save the interface index so we can look it up when handling the addresses. memcpy(l_index, &l_info->ifi_index, sizeof(int)); l_entry->ifa_flags = l_info->ifi_flags; l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg)); for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) { void *l_rtaData = RTA_DATA(l_rta); size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); switch(l_rta->rta_type) { case IFLA_ADDRESS: case IFLA_BROADCAST: { size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize); makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize); ((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index; ((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type; if(l_rta->rta_type == IFLA_ADDRESS) { l_entry->ifa_addr = (struct sockaddr *)l_addr; } else { l_entry->ifa_broadaddr = (struct sockaddr *)l_addr; } l_addr += NLMSG_ALIGN(l_addrLen); break; } case IFLA_IFNAME: strncpy(l_name, l_rtaData, l_rtaDataSize); l_name[l_rtaDataSize] = '\0'; l_entry->ifa_name = l_name; break; case IFLA_STATS: memcpy(l_data, l_rtaData, l_rtaDataSize); l_entry->ifa_data = l_data; break; default: break; } } addToEnd(p_resultList, l_entry); return 0; }
static int fq_pie_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) { struct rtattr *tb[TCA_FQ_PIE_MAX + 1]; unsigned limit; unsigned flows; unsigned tupdate; unsigned target; unsigned alpha; unsigned beta; unsigned ecn; unsigned quantum; unsigned bytemode; SPRINT_BUF(b1); if (opt == NULL) return 0; parse_rtattr_nested(tb, TCA_FQ_PIE_MAX, opt); if (tb[TCA_FQ_PIE_LIMIT] && RTA_PAYLOAD(tb[TCA_FQ_PIE_LIMIT]) >= sizeof(__u32)) { limit = rta_getattr_u32(tb[TCA_FQ_PIE_LIMIT]); fprintf(f, "limit %up ", limit); } if (tb[TCA_FQ_PIE_FLOWS] && RTA_PAYLOAD(tb[TCA_FQ_PIE_FLOWS]) >= sizeof(__u32)) { flows = rta_getattr_u32(tb[TCA_FQ_PIE_FLOWS]); fprintf(f, "flows %u ", flows); } if (tb[TCA_FQ_PIE_QUANTUM] && RTA_PAYLOAD(tb[TCA_FQ_PIE_QUANTUM]) >= sizeof(__u32)) { quantum = rta_getattr_u32(tb[TCA_FQ_PIE_QUANTUM]); fprintf(f, "quantum %u ", quantum); } if (tb[TCA_FQ_PIE_TARGET] && RTA_PAYLOAD(tb[TCA_FQ_PIE_TARGET]) >= sizeof(__u32)) { target = rta_getattr_u32(tb[TCA_FQ_PIE_TARGET]); fprintf(f, "target %s ", sprint_time(target, b1)); } if (tb[TCA_FQ_PIE_TUPDATE] && RTA_PAYLOAD(tb[TCA_FQ_PIE_TUPDATE]) >= sizeof(__u32)) { tupdate = rta_getattr_u32(tb[TCA_FQ_PIE_TUPDATE]); fprintf(f, "tupdate %s ", sprint_time(tupdate, b1)); } if (tb[TCA_FQ_PIE_ALPHA] && RTA_PAYLOAD(tb[TCA_FQ_PIE_ALPHA]) >= sizeof(__u32)) { alpha = rta_getattr_u32(tb[TCA_FQ_PIE_ALPHA]); fprintf(f, "alpha %u ", alpha); } if (tb[TCA_FQ_PIE_BETA] && RTA_PAYLOAD(tb[TCA_FQ_PIE_BETA]) >= sizeof(__u32)) { beta = rta_getattr_u32(tb[TCA_FQ_PIE_BETA]); fprintf(f, "beta %u ", beta); } if (tb[TCA_FQ_PIE_ECN] && RTA_PAYLOAD(tb[TCA_FQ_PIE_ECN]) >= sizeof(__u32)) { ecn = rta_getattr_u32(tb[TCA_FQ_PIE_ECN]); if (ecn) fprintf(f, "ecn "); } if (tb[TCA_FQ_PIE_BYTEMODE] && RTA_PAYLOAD(tb[TCA_FQ_PIE_BYTEMODE]) >= sizeof(__u32)) { bytemode = rta_getattr_u32(tb[TCA_FQ_PIE_BYTEMODE]); if (bytemode) fprintf(f, "bytemode "); } return 0; }
static int print_addrinfo(struct sockaddr_nl ATTRIBUTE_UNUSED *who, struct nlmsghdr *n, void ATTRIBUTE_UNUSED *arg) { FILE *fp = (FILE*)arg; struct ifaddrmsg *ifa = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr * rta_tb[IFA_MAX+1]; char abuf[256]; SPRINT_BUF(b1); if (n->nlmsg_type != RTM_NEWADDR && n->nlmsg_type != RTM_DELADDR) return 0; len -= NLMSG_LENGTH(sizeof(*ifa)); if (len < 0) { bb_error_msg("wrong nlmsg len %d", len); return -1; } if (filter.flushb && n->nlmsg_type != RTM_NEWADDR) return 0; memset(rta_tb, 0, sizeof(rta_tb)); parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa))); if (!rta_tb[IFA_LOCAL]) rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS]; if (!rta_tb[IFA_ADDRESS]) rta_tb[IFA_ADDRESS] = rta_tb[IFA_LOCAL]; if (filter.ifindex && filter.ifindex != ifa->ifa_index) return 0; if ((filter.scope^ifa->ifa_scope)&filter.scopemask) return 0; if ((filter.flags^ifa->ifa_flags)&filter.flagmask) return 0; if (filter.label) { const char *label; if (rta_tb[IFA_LABEL]) label = RTA_DATA(rta_tb[IFA_LABEL]); else label = ll_idx_n2a(ifa->ifa_index, b1); if (fnmatch(filter.label, label, 0) != 0) return 0; } if (filter.pfx.family) { if (rta_tb[IFA_LOCAL]) { inet_prefix dst; memset(&dst, 0, sizeof(dst)); dst.family = ifa->ifa_family; memcpy(&dst.data, RTA_DATA(rta_tb[IFA_LOCAL]), RTA_PAYLOAD(rta_tb[IFA_LOCAL])); if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen)) return 0; } } if (filter.flushb) { struct nlmsghdr *fn; if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) { if (flush_update()) return -1; } fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp)); memcpy(fn, n, n->nlmsg_len); fn->nlmsg_type = RTM_DELADDR; fn->nlmsg_flags = NLM_F_REQUEST; fn->nlmsg_seq = ++filter.rth->seq; filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb; filter.flushed++; return 0; } if (n->nlmsg_type == RTM_DELADDR) fprintf(fp, "Deleted "); if (filter.oneline) fprintf(fp, "%u: %s", ifa->ifa_index, ll_index_to_name(ifa->ifa_index)); if (ifa->ifa_family == AF_INET) fprintf(fp, " inet "); else if (ifa->ifa_family == AF_INET6) fprintf(fp, " inet6 "); else fprintf(fp, " family %d ", ifa->ifa_family); if (rta_tb[IFA_LOCAL]) { fprintf(fp, "%s", rt_addr_n2a(ifa->ifa_family, RTA_PAYLOAD(rta_tb[IFA_LOCAL]), RTA_DATA(rta_tb[IFA_LOCAL]), abuf, sizeof(abuf))); if (rta_tb[IFA_ADDRESS] == NULL || memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_LOCAL]), 4) == 0) { fprintf(fp, "/%d ", ifa->ifa_prefixlen); } else { fprintf(fp, " peer %s/%d ", rt_addr_n2a(ifa->ifa_family, RTA_PAYLOAD(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_ADDRESS]), abuf, sizeof(abuf)), ifa->ifa_prefixlen); } } if (rta_tb[IFA_BROADCAST]) { fprintf(fp, "brd %s ", rt_addr_n2a(ifa->ifa_family, RTA_PAYLOAD(rta_tb[IFA_BROADCAST]), RTA_DATA(rta_tb[IFA_BROADCAST]), abuf, sizeof(abuf))); } if (rta_tb[IFA_ANYCAST]) { fprintf(fp, "any %s ", rt_addr_n2a(ifa->ifa_family, RTA_PAYLOAD(rta_tb[IFA_ANYCAST]), RTA_DATA(rta_tb[IFA_ANYCAST]), abuf, sizeof(abuf))); } fprintf(fp, "scope %s ", rtnl_rtscope_n2a(ifa->ifa_scope, b1, sizeof(b1))); if (ifa->ifa_flags&IFA_F_SECONDARY) { ifa->ifa_flags &= ~IFA_F_SECONDARY; fprintf(fp, "secondary "); } if (ifa->ifa_flags&IFA_F_TENTATIVE) { ifa->ifa_flags &= ~IFA_F_TENTATIVE; fprintf(fp, "tentative "); } if (ifa->ifa_flags&IFA_F_DEPRECATED) { ifa->ifa_flags &= ~IFA_F_DEPRECATED; fprintf(fp, "deprecated "); } if (!(ifa->ifa_flags&IFA_F_PERMANENT)) { fprintf(fp, "dynamic "); } else ifa->ifa_flags &= ~IFA_F_PERMANENT; if (ifa->ifa_flags) fprintf(fp, "flags %02x ", ifa->ifa_flags); if (rta_tb[IFA_LABEL]) fprintf(fp, "%s", (char*)RTA_DATA(rta_tb[IFA_LABEL])); if (rta_tb[IFA_CACHEINFO]) { struct ifa_cacheinfo *ci = RTA_DATA(rta_tb[IFA_CACHEINFO]); char buf[128]; fputc(_SL_, fp); if (ci->ifa_valid == 0xFFFFFFFFU) sprintf(buf, "valid_lft forever"); else sprintf(buf, "valid_lft %dsec", ci->ifa_valid); if (ci->ifa_prefered == 0xFFFFFFFFU) sprintf(buf+strlen(buf), " preferred_lft forever"); else sprintf(buf+strlen(buf), " preferred_lft %dsec", ci->ifa_prefered); fprintf(fp, " %s", buf); } fputc('\n', fp); fflush(fp); return 0; }
static void bond_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) { unsigned ifindex; if (!tb) return; if (tb[IFLA_BOND_MODE]) { const char *mode = get_name(mode_tbl, rta_getattr_u8(tb[IFLA_BOND_MODE])); fprintf(f, "mode %s ", mode); } if (tb[IFLA_BOND_ACTIVE_SLAVE] && (ifindex = rta_getattr_u32(tb[IFLA_BOND_ACTIVE_SLAVE]))) { char buf[IFNAMSIZ]; const char *n = if_indextoname(ifindex, buf); if (n) fprintf(f, "active_slave %s ", n); else fprintf(f, "active_slave %u ", ifindex); } if (tb[IFLA_BOND_MIIMON]) fprintf(f, "miimon %u ", rta_getattr_u32(tb[IFLA_BOND_MIIMON])); if (tb[IFLA_BOND_UPDELAY]) fprintf(f, "updelay %u ", rta_getattr_u32(tb[IFLA_BOND_UPDELAY])); if (tb[IFLA_BOND_DOWNDELAY]) fprintf(f, "downdelay %u ", rta_getattr_u32(tb[IFLA_BOND_DOWNDELAY])); if (tb[IFLA_BOND_USE_CARRIER]) fprintf(f, "use_carrier %u ", rta_getattr_u8(tb[IFLA_BOND_USE_CARRIER])); if (tb[IFLA_BOND_ARP_INTERVAL]) fprintf(f, "arp_interval %u ", rta_getattr_u32(tb[IFLA_BOND_ARP_INTERVAL])); if (tb[IFLA_BOND_ARP_IP_TARGET]) { struct rtattr *iptb[BOND_MAX_ARP_TARGETS + 1]; char buf[INET_ADDRSTRLEN]; int i; parse_rtattr_nested(iptb, BOND_MAX_ARP_TARGETS, tb[IFLA_BOND_ARP_IP_TARGET]); if (iptb[0]) fprintf(f, "arp_ip_target "); for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) { if (iptb[i]) fprintf(f, "%s", rt_addr_n2a(AF_INET, RTA_PAYLOAD(iptb[i]), RTA_DATA(iptb[i]), buf, INET_ADDRSTRLEN)); if (i < BOND_MAX_ARP_TARGETS-1 && iptb[i+1]) fprintf(f, ","); } if (iptb[0]) fprintf(f, " "); } if (tb[IFLA_BOND_ARP_VALIDATE]) { const char *arp_validate = get_name(arp_validate_tbl, rta_getattr_u32(tb[IFLA_BOND_ARP_VALIDATE])); fprintf(f, "arp_validate %s ", arp_validate); } if (tb[IFLA_BOND_ARP_ALL_TARGETS]) { const char *arp_all_targets = get_name(arp_all_targets_tbl, rta_getattr_u32(tb[IFLA_BOND_ARP_ALL_TARGETS])); fprintf(f, "arp_all_targets %s ", arp_all_targets); } if (tb[IFLA_BOND_PRIMARY] && (ifindex = rta_getattr_u32(tb[IFLA_BOND_PRIMARY]))) { char buf[IFNAMSIZ]; const char *n = if_indextoname(ifindex, buf); if (n) fprintf(f, "primary %s ", n); else fprintf(f, "primary %u ", ifindex); } if (tb[IFLA_BOND_PRIMARY_RESELECT]) { const char *primary_reselect = get_name(primary_reselect_tbl, rta_getattr_u8(tb[IFLA_BOND_PRIMARY_RESELECT])); fprintf(f, "primary_reselect %s ", primary_reselect); } if (tb[IFLA_BOND_FAIL_OVER_MAC]) { const char *fail_over_mac = get_name(fail_over_mac_tbl, rta_getattr_u8(tb[IFLA_BOND_FAIL_OVER_MAC])); fprintf(f, "fail_over_mac %s ", fail_over_mac); } if (tb[IFLA_BOND_XMIT_HASH_POLICY]) { const char *xmit_hash_policy = get_name(xmit_hash_policy_tbl, rta_getattr_u8(tb[IFLA_BOND_XMIT_HASH_POLICY])); fprintf(f, "xmit_hash_policy %s ", xmit_hash_policy); } if (tb[IFLA_BOND_RESEND_IGMP]) fprintf(f, "resend_igmp %u ", rta_getattr_u32(tb[IFLA_BOND_RESEND_IGMP])); if (tb[IFLA_BOND_NUM_PEER_NOTIF]) fprintf(f, "num_grat_arp %u ", rta_getattr_u8(tb[IFLA_BOND_NUM_PEER_NOTIF])); if (tb[IFLA_BOND_ALL_SLAVES_ACTIVE]) fprintf(f, "all_slaves_active %u ", rta_getattr_u8(tb[IFLA_BOND_ALL_SLAVES_ACTIVE])); if (tb[IFLA_BOND_MIN_LINKS]) fprintf(f, "min_links %u ", rta_getattr_u32(tb[IFLA_BOND_MIN_LINKS])); if (tb[IFLA_BOND_LP_INTERVAL]) fprintf(f, "lp_interval %u ", rta_getattr_u32(tb[IFLA_BOND_LP_INTERVAL])); if (tb[IFLA_BOND_PACKETS_PER_SLAVE]) fprintf(f, "packets_per_slave %u ", rta_getattr_u32(tb[IFLA_BOND_PACKETS_PER_SLAVE])); if (tb[IFLA_BOND_AD_LACP_RATE]) { const char *lacp_rate = get_name(lacp_rate_tbl, rta_getattr_u8(tb[IFLA_BOND_AD_LACP_RATE])); fprintf(f, "lacp_rate %s ", lacp_rate); } if (tb[IFLA_BOND_AD_SELECT]) { const char *ad_select = get_name(ad_select_tbl, rta_getattr_u8(tb[IFLA_BOND_AD_SELECT])); fprintf(f, "ad_select %s ", ad_select); } if (tb[IFLA_BOND_AD_INFO]) { struct rtattr *adtb[IFLA_BOND_AD_INFO_MAX + 1]; parse_rtattr_nested(adtb, IFLA_BOND_AD_INFO_MAX, tb[IFLA_BOND_AD_INFO]); if (adtb[IFLA_BOND_AD_INFO_AGGREGATOR]) fprintf(f, "ad_aggregator %d ", rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_AGGREGATOR])); if (adtb[IFLA_BOND_AD_INFO_NUM_PORTS]) fprintf(f, "ad_num_ports %d ", rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_NUM_PORTS])); if (adtb[IFLA_BOND_AD_INFO_ACTOR_KEY]) fprintf(f, "ad_actor_key %d ", rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_ACTOR_KEY])); if (adtb[IFLA_BOND_AD_INFO_PARTNER_KEY]) fprintf(f, "ad_partner_key %d ", rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_PARTNER_KEY])); if (adtb[IFLA_BOND_AD_INFO_PARTNER_MAC]) { unsigned char *p = RTA_DATA(adtb[IFLA_BOND_AD_INFO_PARTNER_MAC]); SPRINT_BUF(b); fprintf(f, "ad_partner_mac %s ", ll_addr_n2a(p, ETH_ALEN, 0, b, sizeof(b))); } } if (tb[IFLA_BOND_AD_ACTOR_SYS_PRIO]) { fprintf(f, "ad_actor_sys_prio %u ", rta_getattr_u16(tb[IFLA_BOND_AD_ACTOR_SYS_PRIO])); } if (tb[IFLA_BOND_AD_USER_PORT_KEY]) { fprintf(f, "ad_user_port_key %u ", rta_getattr_u16(tb[IFLA_BOND_AD_USER_PORT_KEY])); } if (tb[IFLA_BOND_AD_ACTOR_SYSTEM]) { /* We assume the l2 address is an Ethernet MAC address */ SPRINT_BUF(b1); fprintf(f, "ad_actor_system %s ", ll_addr_n2a(RTA_DATA(tb[IFLA_BOND_AD_ACTOR_SYSTEM]), RTA_PAYLOAD(tb[IFLA_BOND_AD_ACTOR_SYSTEM]), 1 /*ARPHDR_ETHER*/, b1, sizeof(b1))); } if (tb[IFLA_BOND_TLB_DYNAMIC_LB]) { fprintf(f, "tlb_dynamic_lb %u ", rta_getattr_u8(tb[IFLA_BOND_TLB_DYNAMIC_LB])); } }
static int print_linkinfo(struct sockaddr_nl ATTRIBUTE_UNUSED *who, const struct nlmsghdr *n, void ATTRIBUTE_UNUSED *arg) { FILE *fp = (FILE*)arg; struct ifinfomsg *ifi = NLMSG_DATA(n); struct rtattr * tb[IFLA_MAX+1]; int len = n->nlmsg_len; unsigned m_flag = 0; if (n->nlmsg_type != RTM_NEWLINK && n->nlmsg_type != RTM_DELLINK) return 0; len -= NLMSG_LENGTH(sizeof(*ifi)); if (len < 0) return -1; if (filter.ifindex && ifi->ifi_index != filter.ifindex) return 0; if (filter.up && !(ifi->ifi_flags&IFF_UP)) return 0; memset(tb, 0, sizeof(tb)); parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len); if (tb[IFLA_IFNAME] == NULL) { bb_error_msg("nil ifname"); return -1; } if (filter.label && (!filter.family || filter.family == AF_PACKET) && fnmatch(filter.label, RTA_DATA(tb[IFLA_IFNAME]), 0) ) { return 0; } if (n->nlmsg_type == RTM_DELLINK) fprintf(fp, "Deleted "); fprintf(fp, "%d: %s", ifi->ifi_index, tb[IFLA_IFNAME] ? (char*)RTA_DATA(tb[IFLA_IFNAME]) : "<nil>"); if (tb[IFLA_LINK]) { SPRINT_BUF(b1); int iflink = *(int*)RTA_DATA(tb[IFLA_LINK]); if (iflink == 0) fprintf(fp, "@NONE: "); else { fprintf(fp, "@%s: ", ll_idx_n2a(iflink, b1)); m_flag = ll_index_to_flags(iflink); m_flag = !(m_flag & IFF_UP); } } else { fprintf(fp, ": "); } print_link_flags(fp, ifi->ifi_flags, m_flag); if (tb[IFLA_MTU]) fprintf(fp, "mtu %u ", *(int*)RTA_DATA(tb[IFLA_MTU])); if (tb[IFLA_QDISC]) fprintf(fp, "qdisc %s ", (char*)RTA_DATA(tb[IFLA_QDISC])); #ifdef IFLA_MASTER if (tb[IFLA_MASTER]) { SPRINT_BUF(b1); fprintf(fp, "master %s ", ll_idx_n2a(*(int*)RTA_DATA(tb[IFLA_MASTER]), b1)); } #endif if (filter.showqueue) print_queuelen((char*)RTA_DATA(tb[IFLA_IFNAME])); if (!filter.family || filter.family == AF_PACKET) { SPRINT_BUF(b1); fprintf(fp, "%c link/%s ", _SL_, ll_type_n2a(ifi->ifi_type, b1, sizeof(b1))); if (tb[IFLA_ADDRESS]) { fprintf(fp, "%s", ll_addr_n2a(RTA_DATA(tb[IFLA_ADDRESS]), RTA_PAYLOAD(tb[IFLA_ADDRESS]), ifi->ifi_type, b1, sizeof(b1))); } if (tb[IFLA_BROADCAST]) { if (ifi->ifi_flags&IFF_POINTOPOINT) fprintf(fp, " peer "); else fprintf(fp, " brd "); fprintf(fp, "%s", ll_addr_n2a(RTA_DATA(tb[IFLA_BROADCAST]), RTA_PAYLOAD(tb[IFLA_BROADCAST]), ifi->ifi_type, b1, sizeof(b1))); } } fputc('\n', fp); fflush(fp); return 0; }
/* XXX This function should be componentized in a library, little variances * are repeating themselves. See the same function in xipad.c. */ static int print_addr(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = (FILE*)arg; struct rtmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr *tb[RTA_MAX+1]; const struct xia_xid *dst; __u32 table; UNUSED(who); if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) { fprintf(stderr, "Not a route: %08x %08x %08x\n", n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); return 0; } if (r->rtm_family != AF_XIA) { /* fprintf(stderr, "Wrong rtm_family %d\n", r->rtm_family); */ return 0; } len -= NLMSG_LENGTH(sizeof(*r)); if (len < 0) { fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); return -1; } if (r->rtm_dst_len != sizeof(struct xia_xid)) { fprintf(stderr, "BUG: wrong rtm_dst_len %d\n", r->rtm_dst_len); return -1; } /* XXX Doesn't the kernel provide similar function? */ parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); table = rtnl_get_table(r, tb); /* Filter happens here. */ if (table != XRTABLE_LOCAL_INDEX) return 0; if (!tb[RTA_DST] || RTA_PAYLOAD(tb[RTA_DST]) != sizeof(struct xia_xid) || r->rtm_dst_len != sizeof(struct xia_xid)) return -1; dst = (const struct xia_xid *)RTA_DATA(tb[RTA_DST]); if (dst->xid_type != filter.xid_type) return 0; if (n->nlmsg_type == RTM_DELROUTE) fprintf(fp, "Deleted "); fprintf(fp, "to "); /* XXX It got to use @fp! */ print_xia_xid(dst); fprintf(fp, "\n"); assert(!r->rtm_src_len); assert(!(r->rtm_flags & RTM_F_CLONED)); fprintf(fp, "flags ["); if (r->rtm_flags & RTNH_F_DEAD) fprintf(fp, "dead "); if (r->rtm_flags & RTNH_F_ONLINK) fprintf(fp, "onlink "); if (r->rtm_flags & RTNH_F_PERVASIVE) fprintf(fp, "pervasive "); if (r->rtm_flags & RTM_F_NOTIFY) fprintf(fp, "notify "); fprintf(fp, "]"); fprintf(fp, "\n\n"); fflush(fp); return 0; }
/* * With an existing policy of nlmsg, make new nlmsg for deleting the policy * and store it to buffer. */ static int xfrm_policy_keep(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { struct xfrm_buffer *xb = (struct xfrm_buffer *)arg; struct rtnl_handle *rth = xb->rth; struct xfrm_userpolicy_info *xpinfo = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr *tb[XFRMA_MAX+1]; __u8 ptype = XFRM_POLICY_TYPE_MAIN; struct nlmsghdr *new_n; struct xfrm_userpolicy_id *xpid; if (n->nlmsg_type != XFRM_MSG_NEWPOLICY) { fprintf(stderr, "Not a policy: %08x %08x %08x\n", n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); return 0; } len -= NLMSG_LENGTH(sizeof(*xpinfo)); if (len < 0) { fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); return -1; } parse_rtattr(tb, XFRMA_MAX, XFRMP_RTA(xpinfo), len); if (tb[XFRMA_POLICY_TYPE]) { struct xfrm_userpolicy_type *upt; if (RTA_PAYLOAD(tb[XFRMA_POLICY_TYPE]) < sizeof(*upt)) { fprintf(stderr, "too short XFRMA_POLICY_TYPE len\n"); return -1; } upt = (struct xfrm_userpolicy_type *)RTA_DATA(tb[XFRMA_POLICY_TYPE]); ptype = upt->type; } if (!xfrm_policy_filter_match(xpinfo, ptype)) return 0; if (xb->offset > xb->size) { fprintf(stderr, "Policy buffer overflow\n"); return -1; } new_n = (struct nlmsghdr *)(xb->buf + xb->offset); new_n->nlmsg_len = NLMSG_LENGTH(sizeof(*xpid)); new_n->nlmsg_flags = NLM_F_REQUEST; new_n->nlmsg_type = XFRM_MSG_DELPOLICY; new_n->nlmsg_seq = ++rth->seq; xpid = NLMSG_DATA(new_n); memcpy(&xpid->sel, &xpinfo->sel, sizeof(xpid->sel)); xpid->dir = xpinfo->dir; xpid->index = xpinfo->index; xb->offset += new_n->nlmsg_len; xb->nlmsg_count ++; return 0; }
/* XXX This function should be componentized in a library, little variances * are repeating themselves. See the same function in xipad.c. */ static int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = (FILE*)arg; struct rtmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr *tb[RTA_MAX+1]; const struct xia_xid *dst; __u32 table; UNUSED(who); if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) { fprintf(stderr, "Not a route: %08x %08x %08x\n", n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); return 0; } if (r->rtm_family != AF_XIA) { /* fprintf(stderr, "Wrong rtm_family %d\n", r->rtm_family); */ return 0; } len -= NLMSG_LENGTH(sizeof(*r)); if (len < 0) { fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); return -1; } if (r->rtm_dst_len != sizeof(struct xia_xid)) { fprintf(stderr, "BUG: wrong rtm_dst_len %d\n", r->rtm_dst_len); return -1; } /* XXX Doesn't the kernel provide similar function? */ parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); table = rtnl_get_table(r, tb); /* Filter happens here. */ if (table != XRTABLE_MAIN_INDEX) return 0; if (!tb[RTA_DST] || RTA_PAYLOAD(tb[RTA_DST]) != sizeof(struct xia_xid) || r->rtm_dst_len != sizeof(struct xia_xid)) return -1; dst = (const struct xia_xid *)RTA_DATA(tb[RTA_DST]); if (dst->xid_type != filter.xid_type) return 0; if (n->nlmsg_type == RTM_DELROUTE) fprintf(fp, "Deleted "); fprintf(fp, "to "); /* XXX It got to use @fp! */ print_xia_xid(dst); fprintf(fp, "\n"); if (tb[RTA_MULTIPATH]) { struct rtnl_xia_hid_hdw_addrs *rtha = RTA_DATA(tb[RTA_MULTIPATH]); int len = RTA_PAYLOAD(tb[RTA_MULTIPATH]); char ha[MAX_ADDR_LEN]; while (RTHA_OK(rtha, len)) { /* We only have a header, nothing else. */ assert(rtha->hha_len == sizeof(*rtha)); assert(!lladdr_ntop(rtha->hha_ha, rtha->hha_addr_len, ha, sizeof(ha))); fprintf(fp, "lladdr: %s\tdev: %s\n", ha, ll_index_to_name(rtha->hha_ifindex)); len -= NLMSG_ALIGN(rtha->hha_len); rtha = RTHA_NEXT(rtha); } } assert(!r->rtm_src_len); /* XXX It should go to be printed out in flags. */ assert(!(r->rtm_flags & RTM_F_CLONED)); /* XXX This should become a function, and removed mixed flags, that is, * it doesn't make sense to have RTNH_F_* and RTM_F_* together. */ fprintf(fp, "flags ["); if (r->rtm_flags & RTNH_F_DEAD) fprintf(fp, "dead "); if (r->rtm_flags & RTNH_F_ONLINK) fprintf(fp, "onlink "); if (r->rtm_flags & RTNH_F_PERVASIVE) fprintf(fp, "pervasive "); if (r->rtm_flags & RTM_F_NOTIFY) fprintf(fp, "notify "); fprintf(fp, "]"); fprintf(fp, "\n\n"); fflush(fp); return 0; }
static int get_response(struct nlmsghdr *n, void *arg) { struct genlmsghdr *ghdr; struct l2tp_data *data = arg; struct l2tp_parm *p = &data->config; struct rtattr *attrs[L2TP_ATTR_MAX + 1]; struct rtattr *nla_stats; int len; /* Validate message and parse attributes */ if (n->nlmsg_type == NLMSG_ERROR) return -EBADMSG; ghdr = NLMSG_DATA(n); len = n->nlmsg_len - NLMSG_LENGTH(sizeof(*ghdr)); if (len < 0) return -1; parse_rtattr(attrs, L2TP_ATTR_MAX, (void *)ghdr + GENL_HDRLEN, len); if (attrs[L2TP_ATTR_PW_TYPE]) p->pw_type = rta_getattr_u16(attrs[L2TP_ATTR_PW_TYPE]); if (attrs[L2TP_ATTR_ENCAP_TYPE]) p->encap = rta_getattr_u16(attrs[L2TP_ATTR_ENCAP_TYPE]); if (attrs[L2TP_ATTR_OFFSET]) p->offset = rta_getattr_u16(attrs[L2TP_ATTR_OFFSET]); if (attrs[L2TP_ATTR_DATA_SEQ]) p->data_seq = rta_getattr_u16(attrs[L2TP_ATTR_DATA_SEQ]); if (attrs[L2TP_ATTR_CONN_ID]) p->tunnel_id = rta_getattr_u32(attrs[L2TP_ATTR_CONN_ID]); if (attrs[L2TP_ATTR_PEER_CONN_ID]) p->peer_tunnel_id = rta_getattr_u32(attrs[L2TP_ATTR_PEER_CONN_ID]); if (attrs[L2TP_ATTR_SESSION_ID]) p->session_id = rta_getattr_u32(attrs[L2TP_ATTR_SESSION_ID]); if (attrs[L2TP_ATTR_PEER_SESSION_ID]) p->peer_session_id = rta_getattr_u32(attrs[L2TP_ATTR_PEER_SESSION_ID]); if (attrs[L2TP_ATTR_L2SPEC_TYPE]) p->l2spec_type = rta_getattr_u8(attrs[L2TP_ATTR_L2SPEC_TYPE]); if (attrs[L2TP_ATTR_L2SPEC_LEN]) p->l2spec_len = rta_getattr_u8(attrs[L2TP_ATTR_L2SPEC_LEN]); p->udp_csum = !!attrs[L2TP_ATTR_UDP_CSUM]; if (attrs[L2TP_ATTR_COOKIE]) memcpy(p->cookie, RTA_DATA(attrs[L2TP_ATTR_COOKIE]), p->cookie_len = RTA_PAYLOAD(attrs[L2TP_ATTR_COOKIE])); if (attrs[L2TP_ATTR_PEER_COOKIE]) memcpy(p->peer_cookie, RTA_DATA(attrs[L2TP_ATTR_PEER_COOKIE]), p->peer_cookie_len = RTA_PAYLOAD(attrs[L2TP_ATTR_PEER_COOKIE])); p->recv_seq = !!attrs[L2TP_ATTR_RECV_SEQ]; p->send_seq = !!attrs[L2TP_ATTR_SEND_SEQ]; if (attrs[L2TP_ATTR_RECV_TIMEOUT]) p->reorder_timeout = rta_getattr_u64(attrs[L2TP_ATTR_RECV_TIMEOUT]); if (attrs[L2TP_ATTR_IP_SADDR]) { p->local_ip.family = AF_INET; p->local_ip.data[0] = rta_getattr_u32(attrs[L2TP_ATTR_IP_SADDR]); p->local_ip.bytelen = 4; p->local_ip.bitlen = -1; } if (attrs[L2TP_ATTR_IP_DADDR]) { p->peer_ip.family = AF_INET; p->peer_ip.data[0] = rta_getattr_u32(attrs[L2TP_ATTR_IP_DADDR]); p->peer_ip.bytelen = 4; p->peer_ip.bitlen = -1; } if (attrs[L2TP_ATTR_IP6_SADDR]) { p->local_ip.family = AF_INET6; memcpy(&p->local_ip.data, RTA_DATA(attrs[L2TP_ATTR_IP6_SADDR]), p->local_ip.bytelen = 16); p->local_ip.bitlen = -1; } if (attrs[L2TP_ATTR_IP6_DADDR]) { p->peer_ip.family = AF_INET6; memcpy(&p->peer_ip.data, RTA_DATA(attrs[L2TP_ATTR_IP6_DADDR]), p->peer_ip.bytelen = 16); p->peer_ip.bitlen = -1; } if (attrs[L2TP_ATTR_UDP_SPORT]) p->local_udp_port = rta_getattr_u16(attrs[L2TP_ATTR_UDP_SPORT]); if (attrs[L2TP_ATTR_UDP_DPORT]) p->peer_udp_port = rta_getattr_u16(attrs[L2TP_ATTR_UDP_DPORT]); if (attrs[L2TP_ATTR_MTU]) p->mtu = rta_getattr_u16(attrs[L2TP_ATTR_MTU]); if (attrs[L2TP_ATTR_IFNAME]) p->ifname = rta_getattr_str(attrs[L2TP_ATTR_IFNAME]); nla_stats = attrs[L2TP_ATTR_STATS]; if (nla_stats) { struct rtattr *tb[L2TP_ATTR_STATS_MAX + 1]; parse_rtattr_nested(tb, L2TP_ATTR_STATS_MAX, nla_stats); if (tb[L2TP_ATTR_TX_PACKETS]) data->stats.data_tx_packets = rta_getattr_u64(tb[L2TP_ATTR_TX_PACKETS]); if (tb[L2TP_ATTR_TX_BYTES]) data->stats.data_tx_bytes = rta_getattr_u64(tb[L2TP_ATTR_TX_BYTES]); if (tb[L2TP_ATTR_TX_ERRORS]) data->stats.data_tx_errors = rta_getattr_u64(tb[L2TP_ATTR_TX_ERRORS]); if (tb[L2TP_ATTR_RX_PACKETS]) data->stats.data_rx_packets = rta_getattr_u64(tb[L2TP_ATTR_RX_PACKETS]); if (tb[L2TP_ATTR_RX_BYTES]) data->stats.data_rx_bytes = rta_getattr_u64(tb[L2TP_ATTR_RX_BYTES]); if (tb[L2TP_ATTR_RX_ERRORS]) data->stats.data_rx_errors = rta_getattr_u64(tb[L2TP_ATTR_RX_ERRORS]); if (tb[L2TP_ATTR_RX_SEQ_DISCARDS]) data->stats.data_rx_oos_discards = rta_getattr_u64(tb[L2TP_ATTR_RX_SEQ_DISCARDS]); if (tb[L2TP_ATTR_RX_OOS_PACKETS]) data->stats.data_rx_oos_packets = rta_getattr_u64(tb[L2TP_ATTR_RX_OOS_PACKETS]); } return 0; }
int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = (FILE*)arg; struct rtmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; int host_len = -1; __u32 table; struct rtattr * tb[FRA_MAX+1]; char abuf[256]; SPRINT_BUF(b1); if (n->nlmsg_type != RTM_NEWRULE && n->nlmsg_type != RTM_DELRULE) return 0; len -= NLMSG_LENGTH(sizeof(*r)); if (len < 0) return -1; parse_rtattr(tb, FRA_MAX, RTM_RTA(r), len); if (r->rtm_family == AF_INET) host_len = 32; else if (r->rtm_family == AF_INET6) host_len = 128; else if (r->rtm_family == AF_DECnet) host_len = 16; else if (r->rtm_family == AF_IPX) host_len = 80; if (n->nlmsg_type == RTM_DELRULE) fprintf(fp, "Deleted "); if (tb[FRA_PRIORITY]) fprintf(fp, "%u:\t", *(unsigned*)RTA_DATA(tb[FRA_PRIORITY])); else fprintf(fp, "0:\t"); if (r->rtm_flags & FIB_RULE_INVERT) fprintf(fp, "not "); if (tb[FRA_SRC]) { if (r->rtm_src_len != host_len) { fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family, RTA_PAYLOAD(tb[FRA_SRC]), RTA_DATA(tb[FRA_SRC]), abuf, sizeof(abuf)), r->rtm_src_len ); } else { fprintf(fp, "from %s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[FRA_SRC]), RTA_DATA(tb[FRA_SRC]), abuf, sizeof(abuf)) ); } } else if (r->rtm_src_len) { fprintf(fp, "from 0/%d ", r->rtm_src_len); } else { fprintf(fp, "from all "); } if (tb[FRA_DST]) { if (r->rtm_dst_len != host_len) { fprintf(fp, "to %s/%u ", rt_addr_n2a(r->rtm_family, RTA_PAYLOAD(tb[FRA_DST]), RTA_DATA(tb[FRA_DST]), abuf, sizeof(abuf)), r->rtm_dst_len ); } else { fprintf(fp, "to %s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[FRA_DST]), RTA_DATA(tb[FRA_DST]), abuf, sizeof(abuf))); } } else if (r->rtm_dst_len) { fprintf(fp, "to 0/%d ", r->rtm_dst_len); } if (r->rtm_tos) { SPRINT_BUF(b1); fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1))); } if (tb[FRA_FWMARK] || tb[FRA_FWMASK]) { __u32 mark = 0, mask = 0; if (tb[FRA_FWMARK]) mark = *(__u32*)RTA_DATA(tb[FRA_FWMARK]); if (tb[FRA_FWMASK] && (mask = *(__u32*)RTA_DATA(tb[FRA_FWMASK])) != 0xFFFFFFFF) fprintf(fp, "fwmark 0x%x/0x%x ", mark, mask); else fprintf(fp, "fwmark 0x%x ", mark); } if (tb[FRA_IFNAME]) { fprintf(fp, "iif %s ", (char*)RTA_DATA(tb[FRA_IFNAME])); if (r->rtm_flags & FIB_RULE_DEV_DETACHED) fprintf(fp, "[detached] "); } table = rtm_get_table(r, tb); if (table) fprintf(fp, "lookup %s ", rtnl_rttable_n2a(table, b1, sizeof(b1))); if (tb[FRA_FLOW]) { __u32 to = *(__u32*)RTA_DATA(tb[FRA_FLOW]); __u32 from = to>>16; to &= 0xFFFF; if (from) { fprintf(fp, "realms %s/", rtnl_rtrealm_n2a(from, b1, sizeof(b1))); } fprintf(fp, "%s ", rtnl_rtrealm_n2a(to, b1, sizeof(b1))); } if (r->rtm_type == RTN_NAT) { if (tb[RTA_GATEWAY]) { fprintf(fp, "map-to %s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[RTA_GATEWAY]), RTA_DATA(tb[RTA_GATEWAY]), abuf, sizeof(abuf))); } else fprintf(fp, "masquerade"); } else if (r->rtm_type == FR_ACT_GOTO) { fprintf(fp, "goto "); if (tb[FRA_GOTO]) fprintf(fp, "%u", *(__u32 *) RTA_DATA(tb[FRA_GOTO])); else fprintf(fp, "none"); if (r->rtm_flags & FIB_RULE_UNRESOLVED) fprintf(fp, " [unresolved]"); } else if (r->rtm_type == FR_ACT_NOP) fprintf(fp, "nop"); else if (r->rtm_type != RTN_UNICAST) fprintf(fp, "%s", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1))); fprintf(fp, "\n"); fflush(fp); return 0; }
int nl_send(struct nl_handle *hnd, struct iovec *iov, int iovlen) { struct sockaddr_nl sa = { .nl_family = AF_NETLINK, }; struct msghdr msg = { .msg_name = &sa, .msg_namelen = sizeof(sa), .msg_iov = iov, .msg_iovlen = iovlen, }; struct nlmsghdr *src = iov->iov_base; src->nlmsg_seq = ++hnd->seq; if (sendmsg(hnd->fd, &msg, 0) < 0) return errno; return 0; } int nl_recv(struct nl_handle *hnd, struct nlmsg_entry **dest, int is_dump) { struct sockaddr_nl sa = { .nl_family = AF_NETLINK, }; struct iovec iov; struct msghdr msg = { .msg_name = &sa, .msg_namelen = sizeof(sa), .msg_iov = &iov, .msg_iovlen = 1, }; char buf[16384]; int len, err; struct nlmsghdr *n; struct nlmsg_entry *ptr = NULL; /* GCC false positive */ struct nlmsg_entry *entry; *dest = NULL; while (1) { iov.iov_base = buf; iov.iov_len = sizeof(buf); len = recvmsg(hnd->fd, &msg, 0); if (len < 0) return errno; if (!len) return EPIPE; if (sa.nl_pid) { /* not from the kernel */ continue; } for (n = (struct nlmsghdr *)buf; NLMSG_OK(n, len); n = NLMSG_NEXT(n, len)) { if (n->nlmsg_pid != hnd->pid || n->nlmsg_seq != hnd->seq) continue; if (is_dump && n->nlmsg_type == NLMSG_DONE) return 0; if (n->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *nlerr = (struct nlmsgerr *)NLMSG_DATA(n); err = -nlerr->error; goto err_out; } entry = malloc(n->nlmsg_len + sizeof(void *)); if (!entry) { err = ENOMEM; goto err_out; } entry->next = NULL; memcpy(&entry->h, n, n->nlmsg_len); if (!*dest) *dest = entry; else ptr->next = entry; ptr = entry; if (!is_dump) return 0; } } err_out: nlmsg_free(*dest); *dest = NULL; return err; } int nl_exchange(struct nl_handle *hnd, struct nlmsghdr *src, struct nlmsg_entry **dest) { struct iovec iov = { .iov_base = src, .iov_len = src->nlmsg_len, }; int is_dump; int err; is_dump = !!(src->nlmsg_flags & NLM_F_DUMP); err = nl_send(hnd, &iov, 1); if (err) return err; return nl_recv(hnd, dest, is_dump); } /* The original payload is not freed. Returns 0 in case of error, length * of *dest otherwise. *dest is newly allocated. */ int nla_add_str(void *orig, int orig_len, int nla_type, const char *str, void **dest) { struct nlattr *nla; int len = strlen(str) + 1; int size; size = NLA_ALIGN(orig_len) + NLA_HDRLEN + NLA_ALIGN(len); *dest = calloc(size, 1); if (!*dest) return 0; if (orig_len) memcpy(*dest, orig, orig_len); nla = *dest + NLA_ALIGN(orig_len); nla->nla_len = NLA_HDRLEN + len; nla->nla_type = nla_type; memcpy(nla + 1, str, len); return size; } int rtnl_open(struct nl_handle *hnd) { return nl_open(hnd, NETLINK_ROUTE); } int rtnl_dump(struct nl_handle *hnd, int family, int type, struct nlmsg_entry **dest) { struct { struct nlmsghdr n; struct ifinfomsg i; } req; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = sizeof(req); req.n.nlmsg_type = type; req.n.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; req.i.ifi_family = family; return nl_exchange(hnd, &req.n, dest); } void rtnl_parse(struct rtattr *tb[], int max, struct rtattr *rta, int len) { memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); while (RTA_OK(rta, len)) { if (rta->rta_type <= max) tb[rta->rta_type] = rta; rta = RTA_NEXT(rta, len); } } void rtnl_parse_nested(struct rtattr *tb[], int max, struct rtattr *rta) { rtnl_parse(tb, max, RTA_DATA(rta), RTA_PAYLOAD(rta)); } int genl_open(struct nl_handle *hnd) { return nl_open(hnd, NETLINK_GENERIC); } int genl_request(struct nl_handle *hnd, int type, int cmd, void *payload, int payload_len, struct nlmsg_entry **dest) { struct { struct nlmsghdr n; struct genlmsghdr g; } req; struct iovec iov[2]; int err; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = sizeof(req) + payload_len; req.n.nlmsg_type = type; req.n.nlmsg_flags = NLM_F_REQUEST; req.g.cmd = cmd; req.g.version = 1; iov[0].iov_base = &req; iov[0].iov_len = sizeof(req); iov[1].iov_base = payload; iov[1].iov_len = payload_len; err = nl_send(hnd, iov, 2); if (err) return err; return nl_recv(hnd, dest, 0); } unsigned int genl_family_id(struct nl_handle *hnd, const char *name) { unsigned int res = 0; struct nlattr *nla; int len; struct nlmsg_entry *dest; void *ptr; len = nla_add_str(NULL, 0, CTRL_ATTR_FAMILY_NAME, name, &ptr); if (!len) return 0; if (genl_request(hnd, GENL_ID_CTRL, CTRL_CMD_GETFAMILY, ptr, len, &dest)) { free(ptr); return 0; } free(ptr); len = dest->h.nlmsg_len - NLMSG_HDRLEN - GENL_HDRLEN; ptr = (void *)&dest->h + NLMSG_HDRLEN + GENL_HDRLEN; while (len > NLA_HDRLEN) { nla = ptr; if (nla->nla_type == CTRL_ATTR_FAMILY_ID && nla->nla_len >= NLA_HDRLEN + 2) { res = *(uint16_t *)(nla + 1); break; } ptr += NLMSG_ALIGN(nla->nla_len); len -= NLMSG_ALIGN(nla->nla_len); } nlmsg_free(dest); return res; }
/* Parse netlink message to set options */ static int netem_change(struct Qdisc *sch, struct rtattr *opt) { struct netem_sched_data *q = qdisc_priv(sch); struct tc_netem_qopt *qopt; int ret; if (opt == NULL || RTA_PAYLOAD(opt) < sizeof(*qopt)) return -EINVAL; qopt = RTA_DATA(opt); ret = set_fifo_limit(q->qdisc, qopt->limit); if (ret) { pr_debug("netem: can't set fifo limit\n"); return ret; } q->latency = qopt->latency; q->jitter = qopt->jitter; q->limit = qopt->limit; q->gap = qopt->gap; q->counter = 0; q->loss = qopt->loss; q->duplicate = qopt->duplicate; /* for compatibility with earlier versions. * if gap is set, need to assume 100% probability */ if (q->gap) q->reorder = ~0; /* Handle nested options after initial queue options. * Should have put all options in nested format but too late now. */ if (RTA_PAYLOAD(opt) > sizeof(*qopt)) { struct rtattr *tb[TCA_NETEM_MAX]; if (rtattr_parse(tb, TCA_NETEM_MAX, RTA_DATA(opt) + sizeof(*qopt), RTA_PAYLOAD(opt) - sizeof(*qopt))) return -EINVAL; if (tb[TCA_NETEM_CORR-1]) { ret = get_correlation(sch, tb[TCA_NETEM_CORR-1]); if (ret) return ret; } if (tb[TCA_NETEM_DELAY_DIST-1]) { ret = get_dist_table(sch, tb[TCA_NETEM_DELAY_DIST-1]); if (ret) return ret; } if (tb[TCA_NETEM_REORDER-1]) { ret = get_reorder(sch, tb[TCA_NETEM_REORDER-1]); if (ret) return ret; } if (tb[TCA_NETEM_CORRUPT-1]) { ret = get_corrupt(sch, tb[TCA_NETEM_CORRUPT-1]); if (ret) return ret; } } return 0; }
static void ipaddr_filter(struct nlmsg_chain *linfo, struct nlmsg_chain *ainfo) { struct nlmsg_list *l, **lp; lp = &linfo->head; while ( (l = *lp) != NULL) { int ok = 0; int missing_net_address = 1; struct ifinfomsg *ifi = NLMSG_DATA(&l->h); struct nlmsg_list *a; for (a = ainfo->head; a; a = a->next) { struct nlmsghdr *n = &a->h; struct ifaddrmsg *ifa = NLMSG_DATA(n); struct rtattr *tb[IFA_MAX + 1]; unsigned int ifa_flags; if (ifa->ifa_index != ifi->ifi_index) continue; missing_net_address = 0; if (filter.family && filter.family != ifa->ifa_family) continue; if ((filter.scope^ifa->ifa_scope)&filter.scopemask) continue; parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(n)); ifa_flags = get_ifa_flags(ifa, tb[IFA_FLAGS]); if ((filter.flags ^ ifa_flags) & filter.flagmask) continue; if (filter.pfx.family || filter.label) { if (!tb[IFA_LOCAL]) tb[IFA_LOCAL] = tb[IFA_ADDRESS]; if (filter.pfx.family && tb[IFA_LOCAL]) { inet_prefix dst; memset(&dst, 0, sizeof(dst)); dst.family = ifa->ifa_family; memcpy(&dst.data, RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_LOCAL])); if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen)) continue; } if (filter.label) { SPRINT_BUF(b1); const char *label; if (tb[IFA_LABEL]) label = RTA_DATA(tb[IFA_LABEL]); else label = ll_idx_n2a(ifa->ifa_index, b1); if (fnmatch(filter.label, label, 0) != 0) continue; } } ok = 1; break; } if (missing_net_address && (filter.family == AF_UNSPEC || filter.family == AF_PACKET)) ok = 1; if (!ok) { *lp = l->next; free(l); } else lp = &l->next; } }
/* ====================================================================== */ int getifaddrs(struct ifaddrs **ifap) { int sd; struct nlmsg_list *nlmsg_list, *nlmsg_end, *nlm; /* - - - - - - - - - - - - - - - */ int icnt; size_t dlen, xlen, nlen; uint32_t max_ifindex = 0; pid_t pid = getpid(); int seq; int result; int build ; /* 0 or 1 */ /* ---------------------------------- */ /* initialize */ icnt = dlen = xlen = nlen = 0; nlmsg_list = nlmsg_end = NULL; if (ifap) *ifap = NULL; /* ---------------------------------- */ /* open socket and bind */ sd = nl_open(); if (sd < 0) return -1; /* ---------------------------------- */ /* gather info */ if ((seq = nl_getlist(sd, 0, RTM_GETLINK, &nlmsg_list, &nlmsg_end)) < 0){ free_nlmsglist(nlmsg_list); nl_close(sd); return -1; } if ((seq = nl_getlist(sd, seq+1, RTM_GETADDR, &nlmsg_list, &nlmsg_end)) < 0){ free_nlmsglist(nlmsg_list); nl_close(sd); return -1; } /* ---------------------------------- */ /* Estimate size of result buffer and fill it */ for (build=0; build<=1; build++){ struct ifaddrs *ifl = NULL, *ifa = NULL; struct nlmsghdr *nlh, *nlh0; void *data = NULL, *xdata = NULL, *ifdata = NULL; char *ifname = NULL, **iflist = NULL; uint16_t *ifflist = NULL; struct rtmaddr_ifamap ifamap; if (build){ ifa = data = calloc(1, NLMSG_ALIGN(sizeof(struct ifaddrs[icnt])) + dlen + xlen + nlen); ifdata = calloc(1, NLMSG_ALIGN(sizeof(char *[max_ifindex+1])) + NLMSG_ALIGN(sizeof(uint16_t [max_ifindex+1]))); if (ifap != NULL) *ifap = (ifdata != NULL) ? ifa : NULL; else{ free_data(data, ifdata); result = 0; break; } if (data == NULL || ifdata == NULL){ free_data(data, ifdata); result = -1; break; } ifl = NULL; data += NLMSG_ALIGN(sizeof(struct ifaddrs)) * icnt; xdata = data + dlen; ifname = xdata + xlen; iflist = ifdata; ifflist = ((void *)iflist) + NLMSG_ALIGN(sizeof(char *[max_ifindex+1])); } for (nlm=nlmsg_list; nlm; nlm=nlm->nlm_next){ int nlmlen = nlm->size; if (!(nlh0 = nlm->nlh)) continue; for (nlh = nlh0; NLMSG_OK(nlh, nlmlen); nlh=NLMSG_NEXT(nlh,nlmlen)){ struct ifinfomsg *ifim = NULL; struct ifaddrmsg *ifam = NULL; struct rtattr *rta; size_t nlm_struct_size = 0; sa_family_t nlm_family = 0; uint32_t nlm_scope = 0, nlm_index = 0; #ifndef IFA_NETMASK size_t sockaddr_size = 0; uint32_t nlm_prefixlen = 0; #endif size_t rtasize; memset(&ifamap, 0, sizeof(ifamap)); /* check if the message is what we want */ if (nlh->nlmsg_pid != pid || nlh->nlmsg_seq != nlm->seq) continue; if (nlh->nlmsg_type == NLMSG_DONE){ break; /* ok */ } switch (nlh->nlmsg_type){ case RTM_NEWLINK: ifim = (struct ifinfomsg *)NLMSG_DATA(nlh); nlm_struct_size = sizeof(*ifim); nlm_family = ifim->ifi_family; nlm_scope = 0; nlm_index = ifim->ifi_index; nlm_prefixlen = 0; if (build) ifflist[nlm_index] = ifa->ifa_flags = ifim->ifi_flags; break; case RTM_NEWADDR: ifam = (struct ifaddrmsg *)NLMSG_DATA(nlh); nlm_struct_size = sizeof(*ifam); nlm_family = ifam->ifa_family; nlm_scope = ifam->ifa_scope; nlm_index = ifam->ifa_index; nlm_prefixlen = ifam->ifa_prefixlen; if (build) ifa->ifa_flags = ifflist[nlm_index]; break; default: continue; } if (!build){ if (max_ifindex < nlm_index) max_ifindex = nlm_index; } else { if (ifl != NULL) ifl->ifa_next = ifa; } rtasize = NLMSG_PAYLOAD(nlh, nlmlen) - NLMSG_ALIGN(nlm_struct_size); for (rta = (struct rtattr *)(((char *)NLMSG_DATA(nlh)) + NLMSG_ALIGN(nlm_struct_size)); RTA_OK(rta, rtasize); rta = RTA_NEXT(rta, rtasize)){ struct sockaddr **sap = NULL; void *rtadata = RTA_DATA(rta); size_t rtapayload = RTA_PAYLOAD(rta); socklen_t sa_len; switch(nlh->nlmsg_type){ case RTM_NEWLINK: switch(rta->rta_type){ case IFLA_ADDRESS: case IFLA_BROADCAST: if (build){ sap = (rta->rta_type == IFLA_ADDRESS) ? &ifa->ifa_addr : &ifa->ifa_broadaddr; *sap = (struct sockaddr *)data; } sa_len = ifa_sa_len(AF_PACKET, rtapayload); if (rta->rta_type == IFLA_ADDRESS) sockaddr_size = NLMSG_ALIGN(sa_len); if (!build){ dlen += NLMSG_ALIGN(sa_len); } else { memset(*sap, 0, sa_len); ifa_make_sockaddr(AF_PACKET, *sap, rtadata,rtapayload, 0,0); ((struct sockaddr_ll *)*sap)->sll_ifindex = nlm_index; ((struct sockaddr_ll *)*sap)->sll_hatype = ifim->ifi_type; data += NLMSG_ALIGN(sa_len); } break; case IFLA_IFNAME:/* Name of Interface */ if (!build) nlen += NLMSG_ALIGN(rtapayload + 1); else{ ifa->ifa_name = ifname; if (iflist[nlm_index] == NULL) iflist[nlm_index] = ifa->ifa_name; strncpy(ifa->ifa_name, rtadata, rtapayload); ifa->ifa_name[rtapayload] = '\0'; ifname += NLMSG_ALIGN(rtapayload + 1); } break; case IFLA_STATS:/* Statistics of Interface */ if (!build) xlen += NLMSG_ALIGN(rtapayload); else{ ifa->ifa_data = xdata; memcpy(ifa->ifa_data, rtadata, rtapayload); xdata += NLMSG_ALIGN(rtapayload); } break; case IFLA_UNSPEC: break; case IFLA_MTU: break; case IFLA_LINK: break; case IFLA_QDISC: break; } break; case RTM_NEWADDR: if (nlm_family == AF_PACKET) break; switch(rta->rta_type){ case IFA_ADDRESS: ifamap.address = rtadata; ifamap.address_len = rtapayload; break; case IFA_LOCAL: ifamap.local = rtadata; ifamap.local_len = rtapayload; break; case IFA_BROADCAST: ifamap.broadcast = rtadata; ifamap.broadcast_len = rtapayload; break; #ifdef HAVE_IFADDRS_IFA_ANYCAST case IFA_ANYCAST: ifamap.anycast = rtadata; ifamap.anycast_len = rtapayload; break; #endif case IFA_LABEL: if (!build) nlen += NLMSG_ALIGN(rtapayload + 1); else{ ifa->ifa_name = ifname; if (iflist[nlm_index] == NULL) iflist[nlm_index] = ifname; strncpy(ifa->ifa_name, rtadata, rtapayload); ifa->ifa_name[rtapayload] = '\0'; ifname += NLMSG_ALIGN(rtapayload + 1); } break; case IFA_UNSPEC: break; case IFA_CACHEINFO: break; } } } if (nlh->nlmsg_type == RTM_NEWADDR && nlm_family != AF_PACKET) { if (!ifamap.local) { ifamap.local = ifamap.address; ifamap.local_len = ifamap.address_len; } if (!ifamap.address) { ifamap.address = ifamap.local; ifamap.address_len = ifamap.local_len; } if (ifamap.address_len != ifamap.local_len || (ifamap.address != NULL && memcmp(ifamap.address, ifamap.local, ifamap.address_len))) { /* p2p; address is peer and local is ours */ ifamap.broadcast = ifamap.address; ifamap.broadcast_len = ifamap.address_len; ifamap.address = ifamap.local; ifamap.address_len = ifamap.local_len; } if (ifamap.address) { #ifndef IFA_NETMASK sockaddr_size = NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.address_len)); #endif if (!build) dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.address_len)); else { ifa->ifa_addr = (struct sockaddr *)data; ifa_make_sockaddr(nlm_family, ifa->ifa_addr, ifamap.address, ifamap.address_len, nlm_scope, nlm_index); data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.address_len)); } } #ifdef IFA_NETMASK if (ifamap.netmask) { if (!build) dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.netmask_len)); else { ifa->ifa_netmask = (struct sockaddr *)data; ifa_make_sockaddr(nlm_family, ifa->ifa_netmask, ifamap.netmask, ifamap.netmask_len, nlm_scope, nlm_index); data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.netmask_len)); } } #endif if (ifamap.broadcast) { if (!build) dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.broadcast_len)); else { ifa->ifa_broadaddr = (struct sockaddr *)data; ifa_make_sockaddr(nlm_family, ifa->ifa_broadaddr, ifamap.broadcast, ifamap.broadcast_len, nlm_scope, nlm_index); data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.broadcast_len)); } } #ifdef HAVE_IFADDRS_IFA_ANYCAST if (ifamap.anycast) { if (!build) dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.anycast_len)); else { ifa->ifa_anycast = (struct sockaddr *)data; ifa_make_sockaddr(nlm_family, ifa->ifa_anyaddr, ifamap.anycast, ifamap.anycast_len, nlm_scope, nlm_index); data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.anycast_len)); } } #endif } if (!build){ #ifndef IFA_NETMASK dlen += sockaddr_size; #endif icnt++; } else { if (ifa->ifa_name == NULL) ifa->ifa_name = iflist[nlm_index]; #ifndef IFA_NETMASK if (ifa->ifa_addr && ifa->ifa_addr->sa_family != AF_UNSPEC && ifa->ifa_addr->sa_family != AF_PACKET){ ifa->ifa_netmask = (struct sockaddr *)data; ifa_make_sockaddr_mask(ifa->ifa_addr->sa_family, ifa->ifa_netmask, nlm_prefixlen); } data += sockaddr_size; #endif ifl = ifa++; } } } if (!build){ if (icnt == 0 && (dlen + nlen + xlen == 0)){ if (ifap != NULL) *ifap = NULL; break; /* cannot found any addresses */ } } else free_data(NULL, ifdata); } /* ---------------------------------- */ /* Finalize */ free_nlmsglist(nlmsg_list); nl_close(sd); return 0; }
int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = arg; struct ifaddrmsg *ifa = NLMSG_DATA(n); int len = n->nlmsg_len; int deprecated = 0; /* Use local copy of ifa_flags to not interfere with filtering code */ unsigned int ifa_flags; struct rtattr * rta_tb[IFA_MAX+1]; char abuf[256]; SPRINT_BUF(b1); if (n->nlmsg_type != RTM_NEWADDR && n->nlmsg_type != RTM_DELADDR) return 0; len -= NLMSG_LENGTH(sizeof(*ifa)); if (len < 0) { fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); return -1; } if (filter.flushb && n->nlmsg_type != RTM_NEWADDR) return 0; parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa))); ifa_flags = get_ifa_flags(ifa, rta_tb[IFA_FLAGS]); if (!rta_tb[IFA_LOCAL]) rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS]; if (!rta_tb[IFA_ADDRESS]) rta_tb[IFA_ADDRESS] = rta_tb[IFA_LOCAL]; if (filter.ifindex && filter.ifindex != ifa->ifa_index) return 0; if ((filter.scope^ifa->ifa_scope)&filter.scopemask) return 0; if ((filter.flags ^ ifa_flags) & filter.flagmask) return 0; if (filter.label) { SPRINT_BUF(b1); const char *label; if (rta_tb[IFA_LABEL]) label = RTA_DATA(rta_tb[IFA_LABEL]); else label = ll_idx_n2a(ifa->ifa_index, b1); if (fnmatch(filter.label, label, 0) != 0) return 0; } if (filter.pfx.family) { if (rta_tb[IFA_LOCAL]) { inet_prefix dst; memset(&dst, 0, sizeof(dst)); dst.family = ifa->ifa_family; memcpy(&dst.data, RTA_DATA(rta_tb[IFA_LOCAL]), RTA_PAYLOAD(rta_tb[IFA_LOCAL])); if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen)) return 0; } } if (filter.family && filter.family != ifa->ifa_family) return 0; if (filter.flushb) { struct nlmsghdr *fn; if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) { if (flush_update()) return -1; } fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp)); memcpy(fn, n, n->nlmsg_len); fn->nlmsg_type = RTM_DELADDR; fn->nlmsg_flags = NLM_F_REQUEST; fn->nlmsg_seq = ++rth.seq; filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb; filter.flushed++; if (show_stats < 2) return 0; } if (n->nlmsg_type == RTM_DELADDR) fprintf(fp, "Deleted "); if (filter.oneline || filter.flushb) fprintf(fp, "%u: %s", ifa->ifa_index, ll_index_to_name(ifa->ifa_index)); if (ifa->ifa_family == AF_INET) fprintf(fp, " inet "); else if (ifa->ifa_family == AF_INET6) fprintf(fp, " inet6 "); else if (ifa->ifa_family == AF_DECnet) fprintf(fp, " dnet "); else if (ifa->ifa_family == AF_IPX) fprintf(fp, " ipx "); else fprintf(fp, " family %d ", ifa->ifa_family); if (rta_tb[IFA_LOCAL]) { if (ifa->ifa_family == AF_INET) color_fprintf(fp, COLOR_INET, "%s", format_host(ifa->ifa_family, RTA_PAYLOAD(rta_tb[IFA_LOCAL]), RTA_DATA(rta_tb[IFA_LOCAL]), abuf, sizeof(abuf))); else if (ifa->ifa_family == AF_INET6) color_fprintf(fp, COLOR_INET6, "%s", format_host(ifa->ifa_family, RTA_PAYLOAD(rta_tb[IFA_LOCAL]), RTA_DATA(rta_tb[IFA_LOCAL]), abuf, sizeof(abuf))); else fprintf(fp, "%s", format_host(ifa->ifa_family, RTA_PAYLOAD(rta_tb[IFA_LOCAL]), RTA_DATA(rta_tb[IFA_LOCAL]), abuf, sizeof(abuf))); if (rta_tb[IFA_ADDRESS] == NULL || memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_LOCAL]), ifa->ifa_family == AF_INET ? 4 : 16) == 0) { fprintf(fp, "/%d ", ifa->ifa_prefixlen); } else { fprintf(fp, " peer %s/%d ", format_host(ifa->ifa_family, RTA_PAYLOAD(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_ADDRESS]), abuf, sizeof(abuf)), ifa->ifa_prefixlen); } } if (rta_tb[IFA_BROADCAST]) { fprintf(fp, "brd %s ", format_host(ifa->ifa_family, RTA_PAYLOAD(rta_tb[IFA_BROADCAST]), RTA_DATA(rta_tb[IFA_BROADCAST]), abuf, sizeof(abuf))); } if (rta_tb[IFA_ANYCAST]) { fprintf(fp, "any %s ", format_host(ifa->ifa_family, RTA_PAYLOAD(rta_tb[IFA_ANYCAST]), RTA_DATA(rta_tb[IFA_ANYCAST]), abuf, sizeof(abuf))); } fprintf(fp, "scope %s ", rtnl_rtscope_n2a(ifa->ifa_scope, b1, sizeof(b1))); if (ifa_flags & IFA_F_SECONDARY) { ifa_flags &= ~IFA_F_SECONDARY; if (ifa->ifa_family == AF_INET6) fprintf(fp, "temporary "); else fprintf(fp, "secondary "); } if (ifa_flags & IFA_F_TENTATIVE) { ifa_flags &= ~IFA_F_TENTATIVE; fprintf(fp, "tentative "); } if (ifa_flags & IFA_F_DEPRECATED) { ifa_flags &= ~IFA_F_DEPRECATED; deprecated = 1; fprintf(fp, "deprecated "); } if (ifa_flags & IFA_F_HOMEADDRESS) { ifa_flags &= ~IFA_F_HOMEADDRESS; fprintf(fp, "home "); } if (ifa_flags & IFA_F_NODAD) { ifa_flags &= ~IFA_F_NODAD; fprintf(fp, "nodad "); } if (ifa_flags & IFA_F_MANAGETEMPADDR) { ifa_flags &= ~IFA_F_MANAGETEMPADDR; fprintf(fp, "mngtmpaddr "); } if (ifa_flags & IFA_F_NOPREFIXROUTE) { ifa_flags &= ~IFA_F_NOPREFIXROUTE; fprintf(fp, "noprefixroute "); } if (ifa_flags & IFA_F_MCAUTOJOIN) { ifa_flags &= ~IFA_F_MCAUTOJOIN; fprintf(fp, "autojoin "); } if (!(ifa_flags & IFA_F_PERMANENT)) { fprintf(fp, "dynamic "); } else ifa_flags &= ~IFA_F_PERMANENT; if (ifa_flags & IFA_F_DADFAILED) { ifa_flags &= ~IFA_F_DADFAILED; fprintf(fp, "dadfailed "); } if (ifa_flags) fprintf(fp, "flags %02x ", ifa_flags); if (rta_tb[IFA_LABEL]) fprintf(fp, "%s", rta_getattr_str(rta_tb[IFA_LABEL])); if (rta_tb[IFA_CACHEINFO]) { struct ifa_cacheinfo *ci = RTA_DATA(rta_tb[IFA_CACHEINFO]); fprintf(fp, "%s", _SL_); fprintf(fp, " valid_lft "); if (ci->ifa_valid == INFINITY_LIFE_TIME) fprintf(fp, "forever"); else fprintf(fp, "%usec", ci->ifa_valid); fprintf(fp, " preferred_lft "); if (ci->ifa_prefered == INFINITY_LIFE_TIME) fprintf(fp, "forever"); else { if (deprecated) fprintf(fp, "%dsec", ci->ifa_prefered); else fprintf(fp, "%usec", ci->ifa_prefered); } } fprintf(fp, "\n"); fflush(fp); return 0; }
static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) { if (!tb) return; if (tb[IFLA_BR_FORWARD_DELAY]) fprintf(f, "forward_delay %u ", rta_getattr_u32(tb[IFLA_BR_FORWARD_DELAY])); if (tb[IFLA_BR_HELLO_TIME]) fprintf(f, "hello_time %u ", rta_getattr_u32(tb[IFLA_BR_HELLO_TIME])); if (tb[IFLA_BR_MAX_AGE]) fprintf(f, "max_age %u ", rta_getattr_u32(tb[IFLA_BR_MAX_AGE])); if (tb[IFLA_BR_AGEING_TIME]) fprintf(f, "ageing_time %u ", rta_getattr_u32(tb[IFLA_BR_AGEING_TIME])); if (tb[IFLA_BR_STP_STATE]) fprintf(f, "stp_state %u ", rta_getattr_u32(tb[IFLA_BR_STP_STATE])); if (tb[IFLA_BR_PRIORITY]) fprintf(f, "priority %u ", rta_getattr_u16(tb[IFLA_BR_PRIORITY])); if (tb[IFLA_BR_VLAN_FILTERING]) fprintf(f, "vlan_filtering %u ", rta_getattr_u8(tb[IFLA_BR_VLAN_FILTERING])); if (tb[IFLA_BR_VLAN_PROTOCOL]) { SPRINT_BUF(b1); fprintf(f, "vlan_protocol %s ", ll_proto_n2a(rta_getattr_u16(tb[IFLA_BR_VLAN_PROTOCOL]), b1, sizeof(b1))); } if (tb[IFLA_BR_BRIDGE_ID]) { char bridge_id[32]; br_dump_bridge_id(RTA_DATA(tb[IFLA_BR_BRIDGE_ID]), bridge_id, sizeof(bridge_id)); fprintf(f, "bridge_id %s ", bridge_id); } if (tb[IFLA_BR_ROOT_ID]) { char root_id[32]; br_dump_bridge_id(RTA_DATA(tb[IFLA_BR_BRIDGE_ID]), root_id, sizeof(root_id)); fprintf(f, "designated_root %s ", root_id); } if (tb[IFLA_BR_ROOT_PORT]) fprintf(f, "root_port %u ", rta_getattr_u16(tb[IFLA_BR_ROOT_PORT])); if (tb[IFLA_BR_ROOT_PATH_COST]) fprintf(f, "root_path_cost %u ", rta_getattr_u32(tb[IFLA_BR_ROOT_PATH_COST])); if (tb[IFLA_BR_TOPOLOGY_CHANGE]) fprintf(f, "topology_change %u ", rta_getattr_u8(tb[IFLA_BR_TOPOLOGY_CHANGE])); if (tb[IFLA_BR_TOPOLOGY_CHANGE_DETECTED]) fprintf(f, "topology_change_detected %u ", rta_getattr_u8(tb[IFLA_BR_TOPOLOGY_CHANGE_DETECTED])); if (tb[IFLA_BR_HELLO_TIMER]) { struct timeval tv; __jiffies_to_tv(&tv, rta_getattr_u64(tb[IFLA_BR_HELLO_TIMER])); fprintf(f, "hello_timer %4i.%.2i ", (int)tv.tv_sec, (int)tv.tv_usec/10000); } if (tb[IFLA_BR_TCN_TIMER]) { struct timeval tv; __jiffies_to_tv(&tv, rta_getattr_u64(tb[IFLA_BR_TCN_TIMER])); fprintf(f, "tcn_timer %4i.%.2i ", (int)tv.tv_sec, (int)tv.tv_usec/10000); } if (tb[IFLA_BR_TOPOLOGY_CHANGE_TIMER]) { unsigned long jiffies; struct timeval tv; jiffies = rta_getattr_u64(tb[IFLA_BR_TOPOLOGY_CHANGE_TIMER]); __jiffies_to_tv(&tv, jiffies); fprintf(f, "topology_change_timer %4i.%.2i ", (int)tv.tv_sec, (int)tv.tv_usec/10000); } if (tb[IFLA_BR_GC_TIMER]) { struct timeval tv; __jiffies_to_tv(&tv, rta_getattr_u64(tb[IFLA_BR_GC_TIMER])); fprintf(f, "gc_timer %4i.%.2i ", (int)tv.tv_sec, (int)tv.tv_usec/10000); } if (tb[IFLA_BR_VLAN_DEFAULT_PVID]) fprintf(f, "vlan_default_pvid %u ", rta_getattr_u16(tb[IFLA_BR_VLAN_DEFAULT_PVID])); if (tb[IFLA_BR_GROUP_FWD_MASK]) fprintf(f, "group_fwd_mask %#x ", rta_getattr_u16(tb[IFLA_BR_GROUP_FWD_MASK])); if (tb[IFLA_BR_GROUP_ADDR]) { SPRINT_BUF(mac); fprintf(f, "group_address %s ", ll_addr_n2a(RTA_DATA(tb[IFLA_BR_GROUP_ADDR]), RTA_PAYLOAD(tb[IFLA_BR_GROUP_ADDR]), 1 /*ARPHDR_ETHER*/, mac, sizeof(mac))); } if (tb[IFLA_BR_MCAST_SNOOPING]) fprintf(f, "mcast_snooping %u ", rta_getattr_u8(tb[IFLA_BR_MCAST_SNOOPING])); if (tb[IFLA_BR_MCAST_ROUTER]) fprintf(f, "mcast_router %u ", rta_getattr_u8(tb[IFLA_BR_MCAST_ROUTER])); if (tb[IFLA_BR_MCAST_QUERY_USE_IFADDR]) fprintf(f, "mcast_query_use_ifaddr %u ", rta_getattr_u8(tb[IFLA_BR_MCAST_QUERY_USE_IFADDR])); if (tb[IFLA_BR_MCAST_QUERIER]) fprintf(f, "mcast_querier %u ", rta_getattr_u8(tb[IFLA_BR_MCAST_QUERIER])); if (tb[IFLA_BR_MCAST_HASH_ELASTICITY]) fprintf(f, "mcast_hash_elasticity %u ", rta_getattr_u32(tb[IFLA_BR_MCAST_HASH_ELASTICITY])); if (tb[IFLA_BR_MCAST_HASH_MAX]) fprintf(f, "mcast_hash_max %u ", rta_getattr_u32(tb[IFLA_BR_MCAST_HASH_MAX])); if (tb[IFLA_BR_MCAST_LAST_MEMBER_CNT]) fprintf(f, "mcast_last_member_count %u ", rta_getattr_u32(tb[IFLA_BR_MCAST_LAST_MEMBER_CNT])); if (tb[IFLA_BR_MCAST_STARTUP_QUERY_CNT]) fprintf(f, "mcast_startup_query_count %u ", rta_getattr_u32(tb[IFLA_BR_MCAST_STARTUP_QUERY_CNT])); if (tb[IFLA_BR_MCAST_LAST_MEMBER_INTVL]) fprintf(f, "mcast_last_member_interval %llu ", rta_getattr_u64(tb[IFLA_BR_MCAST_LAST_MEMBER_INTVL])); if (tb[IFLA_BR_MCAST_MEMBERSHIP_INTVL]) fprintf(f, "mcast_membership_interval %llu ", rta_getattr_u64(tb[IFLA_BR_MCAST_MEMBERSHIP_INTVL])); if (tb[IFLA_BR_MCAST_QUERIER_INTVL]) fprintf(f, "mcast_querier_interval %llu ", rta_getattr_u64(tb[IFLA_BR_MCAST_QUERIER_INTVL])); if (tb[IFLA_BR_MCAST_QUERY_INTVL]) fprintf(f, "mcast_query_interval %llu ", rta_getattr_u64(tb[IFLA_BR_MCAST_QUERY_INTVL])); if (tb[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL]) fprintf(f, "mcast_query_response_interval %llu ", rta_getattr_u64(tb[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL])); if (tb[IFLA_BR_MCAST_STARTUP_QUERY_INTVL]) fprintf(f, "mcast_startup_query_interval %llu ", rta_getattr_u64(tb[IFLA_BR_MCAST_STARTUP_QUERY_INTVL])); if (tb[IFLA_BR_NF_CALL_IPTABLES]) fprintf(f, "nf_call_iptables %u ", rta_getattr_u8(tb[IFLA_BR_NF_CALL_IPTABLES])); if (tb[IFLA_BR_NF_CALL_IP6TABLES]) fprintf(f, "nf_call_ip6tables %u ", rta_getattr_u8(tb[IFLA_BR_NF_CALL_IP6TABLES])); if (tb[IFLA_BR_NF_CALL_ARPTABLES]) fprintf(f, "nf_call_arptables %u ", rta_getattr_u8(tb[IFLA_BR_NF_CALL_ARPTABLES])); }