Example #1
0
int print_qdisc(const struct sockaddr_nl *who,
		       struct nlmsghdr *n,
		       void *arg)
{
	FILE *fp = (FILE*)arg;
	struct tcmsg *t = NLMSG_DATA(n);
	int len = n->nlmsg_len;
	struct rtattr * tb[TCA_MAX+1];
	struct qdisc_util *q;
	char abuf[256];

	if (n->nlmsg_type != RTM_NEWQDISC && n->nlmsg_type != RTM_DELQDISC) {
		fprintf(stderr, "Not a qdisc\n");
		return 0;
	}
	len -= NLMSG_LENGTH(sizeof(*t));
	if (len < 0) {
		fprintf(stderr, "Wrong len %d\n", len);
		return -1;
	}

	if (filter_ifindex && filter_ifindex != t->tcm_ifindex)
		return 0;

	memset(tb, 0, sizeof(tb));
	parse_rtattr(tb, TCA_MAX, TCA_RTA(t), len);

	if (tb[TCA_KIND] == NULL) {
		fprintf(stderr, "print_qdisc: NULL kind\n");
		return -1;
	}

	if (n->nlmsg_type == RTM_DELQDISC)
		fprintf(fp, "deleted ");

	fprintf(fp, "qdisc %s %x: ", rta_getattr_str(tb[TCA_KIND]), t->tcm_handle>>16);
	if (filter_ifindex == 0)
		fprintf(fp, "dev %s ", ll_index_to_name(t->tcm_ifindex));
	if (t->tcm_parent == TC_H_ROOT)
		fprintf(fp, "root ");
	else if (t->tcm_parent) {
		print_tc_classid(abuf, sizeof(abuf), t->tcm_parent);
		fprintf(fp, "parent %s ", abuf);
	}
	if (t->tcm_info != 1) {
		fprintf(fp, "refcnt %d ", t->tcm_info);
	}
	/* pfifo_fast is generic enough to warrant the hardcoding --JHS */

	if (0 == strcmp("pfifo_fast", RTA_DATA(tb[TCA_KIND])))
		q = get_qdisc_kind("prio");
	else
		q = get_qdisc_kind(RTA_DATA(tb[TCA_KIND]));

	if (tb[TCA_OPTIONS]) {
		if (q)
			q->print_qopt(q, fp, tb[TCA_OPTIONS]);
		else
			fprintf(fp, "[cannot parse qdisc parameters]");
	}
	fprintf(fp, "\n");
	if (show_details && tb[TCA_STAB]) {
		print_size_table(fp, " ", tb[TCA_STAB]);
		fprintf(fp, "\n");
	}
	if (show_stats) {
		struct rtattr *xstats = NULL;

		if (tb[TCA_STATS] || tb[TCA_STATS2] || tb[TCA_XSTATS]) {
			print_tcstats_attr(fp, tb, " ", &xstats);
			fprintf(fp, "\n");
		}

		if (q && xstats && q->print_xstats) {
			q->print_xstats(q, fp, xstats);
			fprintf(fp, "\n");
		}
	}
	fflush(fp);
	return 0;
}
Example #2
0
int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
{
	FILE *fp = (FILE*)arg;
	struct ndmsg *r = NLMSG_DATA(n);
	int len = n->nlmsg_len;
	struct rtattr * tb[NDA_MAX+1];
	char abuf[256];

	if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH &&
	    n->nlmsg_type != RTM_GETNEIGH) {
		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 (filter.flushb && n->nlmsg_type != RTM_NEWNEIGH)
		return 0;

	if (filter.family && filter.family != r->ndm_family)
		return 0;
	if (filter.index && filter.index != r->ndm_ifindex)
		return 0;
	if (!(filter.state&r->ndm_state) &&
	    !(r->ndm_flags & NTF_PROXY) &&
	    (r->ndm_state || !(filter.state&0x100)) &&
             (r->ndm_family != AF_DECnet))
		return 0;

	parse_rtattr(tb, NDA_MAX, NDA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));

	if (tb[NDA_DST]) {
		if (filter.pfx.family) {
			inet_prefix dst;
			memset(&dst, 0, sizeof(dst));
			dst.family = r->ndm_family;
			memcpy(&dst.data, RTA_DATA(tb[NDA_DST]), RTA_PAYLOAD(tb[NDA_DST]));
			if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen))
				return 0;
		}
	}
	if (filter.unused_only && tb[NDA_CACHEINFO]) {
		struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]);
		if (ci->ndm_refcnt)
			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_DELNEIGH;
		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_DELNEIGH)
		fprintf(fp, "delete ");
	else if (n->nlmsg_type == RTM_GETNEIGH)
		fprintf(fp, "miss ");
	if (tb[NDA_DST]) {
		fprintf(fp, "%s ",
			format_host(r->ndm_family,
				    RTA_PAYLOAD(tb[NDA_DST]),
				    RTA_DATA(tb[NDA_DST]),
				    abuf, sizeof(abuf)));
	}
	if (!filter.index && r->ndm_ifindex)
		fprintf(fp, "dev %s ", ll_index_to_name(r->ndm_ifindex));
	if (tb[NDA_LLADDR]) {
		SPRINT_BUF(b1);
		fprintf(fp, "lladdr %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 (r->ndm_flags & NTF_ROUTER) {
		fprintf(fp, " router");
	}
	if (r->ndm_flags & NTF_PROXY) {
		fprintf(fp, " proxy");
	}
	if (tb[NDA_CACHEINFO] && show_stats) {
		struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]);
		int hz = get_user_hz();

		if (ci->ndm_refcnt)
			printf(" ref %d", ci->ndm_refcnt);
		fprintf(fp, " used %d/%d/%d", ci->ndm_used/hz,
		       ci->ndm_confirmed/hz, ci->ndm_updated/hz);
	}

	if (tb[NDA_PROBES] && show_stats) {
		__u32 p = rta_getattr_u32(tb[NDA_PROBES]);
		fprintf(fp, " probes %u", p);
	}

	if (r->ndm_state) {
		int nud = r->ndm_state;
		fprintf(fp, " ");

#define PRINT_FLAG(f) if (nud & NUD_##f) { \
	nud &= ~NUD_##f; fprintf(fp, #f "%s", nud ? "," : ""); }
		PRINT_FLAG(INCOMPLETE);
		PRINT_FLAG(REACHABLE);
		PRINT_FLAG(STALE);
		PRINT_FLAG(DELAY);
		PRINT_FLAG(PROBE);
		PRINT_FLAG(FAILED);
		PRINT_FLAG(NOARP);
		PRINT_FLAG(PERMANENT);
#undef PRINT_FLAG
	}
	fprintf(fp, "\n");

	fflush(fp);
	return 0;
}
Example #3
0
int print_route(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];
	char abuf[256];
	int host_len;
	__u32 table;
	SPRINT_BUF(b1);
	static int hz;

	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 (filter.flushb && n->nlmsg_type != RTM_NEWROUTE)
		return 0;
	len -= NLMSG_LENGTH(sizeof(*r));
	if (len < 0) {
		fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
		return -1;
	}

	host_len = af_bit_len(r->rtm_family);

	parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
	table = rtm_get_table(r, tb);

	if (!filter_nlmsg(n, tb, host_len))
		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_DELROUTE;
		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_DELROUTE)
		fprintf(fp, "Deleted ");
	if ((r->rtm_type != RTN_UNICAST || show_details > 0) && !filter.type)
		fprintf(fp, "%s ", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1)));

	if (tb[RTA_DST]) {
		if (r->rtm_dst_len != host_len) {
			fprintf(fp, "%s/%u ", rt_addr_n2a(r->rtm_family,
						       RTA_PAYLOAD(tb[RTA_DST]),
						       RTA_DATA(tb[RTA_DST]),
						       abuf, sizeof(abuf)),
				r->rtm_dst_len
				);
		} else {
			fprintf(fp, "%s ", format_host(r->rtm_family,
						       RTA_PAYLOAD(tb[RTA_DST]),
						       RTA_DATA(tb[RTA_DST]),
						       abuf, sizeof(abuf))
				);
		}
	} else if (r->rtm_dst_len) {
		fprintf(fp, "0/%d ", r->rtm_dst_len);
	} else {
		fprintf(fp, "default ");
	}
	if (tb[RTA_SRC]) {
		if (r->rtm_src_len != host_len) {
			fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family,
						       RTA_PAYLOAD(tb[RTA_SRC]),
						       RTA_DATA(tb[RTA_SRC]),
						       abuf, sizeof(abuf)),
				r->rtm_src_len
				);
		} else {
			fprintf(fp, "from %s ", format_host(r->rtm_family,
						       RTA_PAYLOAD(tb[RTA_SRC]),
						       RTA_DATA(tb[RTA_SRC]),
						       abuf, sizeof(abuf))
				);
		}
	} else if (r->rtm_src_len) {
		fprintf(fp, "from 0/%u ", r->rtm_src_len);
	}
	if (tb[RTA_NEWDST]) {
		fprintf(fp, "as to %s ", format_host(r->rtm_family,
						  RTA_PAYLOAD(tb[RTA_NEWDST]),
						  RTA_DATA(tb[RTA_NEWDST]),
						  abuf, sizeof(abuf))
			);
	}

	if (tb[RTA_ENCAP])
		lwt_print_encap(fp, tb[RTA_ENCAP_TYPE], tb[RTA_ENCAP]);

	if (r->rtm_tos && filter.tosmask != -1) {
		SPRINT_BUF(b1);
		fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1)));
	}

	if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len) {
		fprintf(fp, "via %s ",
			format_host(r->rtm_family,
				    RTA_PAYLOAD(tb[RTA_GATEWAY]),
				    RTA_DATA(tb[RTA_GATEWAY]),
				    abuf, sizeof(abuf)));
	}
	if (tb[RTA_VIA]) {
		size_t len = RTA_PAYLOAD(tb[RTA_VIA]) - 2;
		struct rtvia *via = RTA_DATA(tb[RTA_VIA]);
		fprintf(fp, "via %s %s ",
			family_name(via->rtvia_family),
			format_host(via->rtvia_family, len, via->rtvia_addr,
				    abuf, sizeof(abuf)));
	}
	if (tb[RTA_OIF] && filter.oifmask != -1)
		fprintf(fp, "dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF])));

	if (table && (table != RT_TABLE_MAIN || show_details > 0) && !filter.tb)
		fprintf(fp, " table %s ", rtnl_rttable_n2a(table, b1, sizeof(b1)));
	if (!(r->rtm_flags&RTM_F_CLONED)) {
		if ((r->rtm_protocol != RTPROT_BOOT || show_details > 0) && filter.protocolmask != -1)
			fprintf(fp, " proto %s ", rtnl_rtprot_n2a(r->rtm_protocol, b1, sizeof(b1)));
		if ((r->rtm_scope != RT_SCOPE_UNIVERSE || show_details > 0) && filter.scopemask != -1)
			fprintf(fp, " scope %s ", rtnl_rtscope_n2a(r->rtm_scope, b1, sizeof(b1)));
	}
	if (tb[RTA_PREFSRC] && filter.rprefsrc.bitlen != host_len) {
		/* Do not use format_host(). It is our local addr
		   and symbolic name will not be useful.
		 */
		fprintf(fp, " src %s ",
			rt_addr_n2a(r->rtm_family,
				    RTA_PAYLOAD(tb[RTA_PREFSRC]),
				    RTA_DATA(tb[RTA_PREFSRC]),
				    abuf, sizeof(abuf)));
	}
	if (tb[RTA_PRIORITY])
		fprintf(fp, " metric %u ", rta_getattr_u32(tb[RTA_PRIORITY]));
	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 & RTNH_F_OFFLOAD)
		fprintf(fp, "offload ");
	if (r->rtm_flags & RTM_F_NOTIFY)
		fprintf(fp, "notify ");
	if (r->rtm_flags & RTNH_F_LINKDOWN)
		fprintf(fp, "linkdown ");
	if (tb[RTA_MARK]) {
		unsigned int mark = *(unsigned int*)RTA_DATA(tb[RTA_MARK]);
		if (mark) {
			if (mark >= 16)
				fprintf(fp, " mark 0x%x", mark);
			else
				fprintf(fp, " mark %u", mark);
		}
	}

	if (tb[RTA_FLOW] && filter.realmmask != ~0U) {
		__u32 to = rta_getattr_u32(tb[RTA_FLOW]);
		__u32 from = to>>16;
		to &= 0xFFFF;
		fprintf(fp, "realm%s ", from ? "s" : "");
		if (from) {
			fprintf(fp, "%s/",
				rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
		}
		fprintf(fp, "%s ",
			rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
	}
Example #4
0
int print_qdisc(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
{
	FILE *fp = (FILE*)arg;
	struct tcmsg *t = NLMSG_DATA(n);
	int len = n->nlmsg_len;
	struct rtattr * tb[TCA_MAX+1];
	struct qdisc_util *q;
	char abuf[256];

	if (n->nlmsg_type != RTM_NEWQDISC && n->nlmsg_type != RTM_DELQDISC) {
		fprintf(stderr, "Not a qdisc\n");
		return 0;
	}
	len -= NLMSG_LENGTH(sizeof(*t));
	if (len < 0) {
		fprintf(stderr, "Wrong len %d\n", len);
		return -1;
	}

	if (filter_ifindex && filter_ifindex != t->tcm_ifindex)
		return 0;

	memset(tb, 0, sizeof(tb));
	parse_rtattr(tb, TCA_MAX, TCA_RTA(t), len);

	if (tb[TCA_KIND] == NULL) {
		fprintf(stderr, "NULL kind\n");
		return -1;
	}

	if (n->nlmsg_type == RTM_DELQDISC)
		fprintf(fp, "deleted ");

	fprintf(fp, "qdisc %s %x: ", (char*)RTA_DATA(tb[TCA_KIND]), t->tcm_handle>>16);
	if (filter_ifindex == 0)
		fprintf(fp, "dev %s ", ll_index_to_name(t->tcm_ifindex));
	if (t->tcm_parent == TC_H_ROOT)
		fprintf(fp, "root ");
	else if (t->tcm_parent) {
		print_tc_classid(abuf, sizeof(abuf), t->tcm_parent);
		fprintf(fp, "parent %s ", abuf);
	}
	if (t->tcm_info != 1) {
		fprintf(fp, "refcnt %d ", t->tcm_info);
	}
	if ((q = get_qdisc_kind(RTA_DATA(tb[TCA_KIND]))) != NULL)
		q->print_qopt(q, fp, tb[TCA_OPTIONS]);
	else
		fprintf(fp, "[UNKNOWN]");
	fprintf(fp, "\n");
	if (show_stats) {
		if (tb[TCA_STATS]) {
			if (RTA_PAYLOAD(tb[TCA_STATS]) < sizeof(struct tc_stats))
				fprintf(fp, "statistics truncated");
			else {
				struct tc_stats st;
				memcpy(&st, RTA_DATA(tb[TCA_STATS]), sizeof(st));
				print_tcstats(fp, &st);
				fprintf(fp, "\n");
			}
		}
		if (q && tb[TCA_XSTATS]) {
			q->print_xstats(q, fp, tb[TCA_XSTATS]);
			fprintf(fp, "\n");
		}
		fprintf(fp, "\n ");
	}
	fflush(fp);
	return 0;
}
Example #5
0
static int print_route(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];
	char abuf[256];
	inet_prefix dst;
	inet_prefix src;
	int host_len = -1;
	SPRINT_BUF(b1);
	

	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 (filter.flushb && n->nlmsg_type != RTM_NEWROUTE)
		return 0;
	len -= NLMSG_LENGTH(sizeof(*r));
	if (len < 0) {
		bb_error_msg("wrong nlmsg len %d", len);
		return -1;
	}

	if (r->rtm_family == AF_INET6)
		host_len = 128;
	else if (r->rtm_family == AF_INET)
		host_len = 32;

	if (r->rtm_family == AF_INET6) {
		if (filter.tb) {
			if (filter.tb < 0) {
				if (!(r->rtm_flags&RTM_F_CLONED)) {
					return 0;
				}
			} else {
				if (r->rtm_flags&RTM_F_CLONED) {
					return 0;
				}
				if (filter.tb == RT_TABLE_LOCAL) {
					if (r->rtm_type != RTN_LOCAL) {
						return 0;
					}
				} else if (filter.tb == RT_TABLE_MAIN) {
					if (r->rtm_type == RTN_LOCAL) {
						return 0;
					}
				} else {
					return 0;
				}
			}
		}
	} else {
		if (filter.tb > 0 && filter.tb != r->rtm_table) {
			return 0;
		}
	}
	if (filter.rdst.family &&
	    (r->rtm_family != filter.rdst.family || filter.rdst.bitlen > r->rtm_dst_len)) {
		return 0;
	}
	if (filter.mdst.family &&
	    (r->rtm_family != filter.mdst.family ||
	     (filter.mdst.bitlen >= 0 && filter.mdst.bitlen < r->rtm_dst_len))) {
		return 0;
	}
	if (filter.rsrc.family &&
	    (r->rtm_family != filter.rsrc.family || filter.rsrc.bitlen > r->rtm_src_len)) {
		return 0;
	}
	if (filter.msrc.family &&
	    (r->rtm_family != filter.msrc.family ||
	     (filter.msrc.bitlen >= 0 && filter.msrc.bitlen < r->rtm_src_len))) {
		return 0;
	}

	memset(tb, 0, sizeof(tb));
	parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);

	if (filter.rdst.family && inet_addr_match(&dst, &filter.rdst, filter.rdst.bitlen))
		return 0;
	if (filter.mdst.family && filter.mdst.bitlen >= 0 &&
	    inet_addr_match(&dst, &filter.mdst, r->rtm_dst_len))
		return 0;

	if (filter.rsrc.family && inet_addr_match(&src, &filter.rsrc, filter.rsrc.bitlen))
		return 0;
	if (filter.msrc.family && filter.msrc.bitlen >= 0 &&
	    inet_addr_match(&src, &filter.msrc, r->rtm_src_len))
		return 0;

	if (filter.flushb &&
	    r->rtm_family == AF_INET6 &&
	    r->rtm_dst_len == 0 &&
	    r->rtm_type == RTN_UNREACHABLE &&
	    tb[RTA_PRIORITY] &&
	    *(int*)RTA_DATA(tb[RTA_PRIORITY]) == -1)
		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_DELROUTE;
		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_DELROUTE) {
		fprintf(fp, "Deleted ");
	}
	if (r->rtm_type != RTN_UNICAST && !filter.type) {
		fprintf(fp, "%s ", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1)));
	}

	if (tb[RTA_DST]) {
		if (r->rtm_dst_len != host_len) {
			fprintf(fp, "%s/%u ", rt_addr_n2a(r->rtm_family,
							 RTA_PAYLOAD(tb[RTA_DST]),
							 RTA_DATA(tb[RTA_DST]),
							 abuf, sizeof(abuf)),
				r->rtm_dst_len
				);
		} else {
			fprintf(fp, "%s ", format_host(r->rtm_family,
						       RTA_PAYLOAD(tb[RTA_DST]),
						       RTA_DATA(tb[RTA_DST]),
						       abuf, sizeof(abuf))
				);
		}
	} else if (r->rtm_dst_len) {
		fprintf(fp, "0/%d ", r->rtm_dst_len);
	} else {
		fprintf(fp, "default ");
	}
	if (tb[RTA_SRC]) {
		if (r->rtm_src_len != host_len) {
			fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family,
							 RTA_PAYLOAD(tb[RTA_SRC]),
							 RTA_DATA(tb[RTA_SRC]),
							 abuf, sizeof(abuf)),
				r->rtm_src_len
				);
		} else {
			fprintf(fp, "from %s ", format_host(r->rtm_family,
						       RTA_PAYLOAD(tb[RTA_SRC]),
						       RTA_DATA(tb[RTA_SRC]),
						       abuf, sizeof(abuf))
				);
		}
	} else if (r->rtm_src_len) {
		fprintf(fp, "from 0/%u ", r->rtm_src_len);
	}
	if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len) {
		fprintf(fp, "via %s ", 
			format_host(r->rtm_family,
				    RTA_PAYLOAD(tb[RTA_GATEWAY]),
				    RTA_DATA(tb[RTA_GATEWAY]),
				    abuf, sizeof(abuf)));
	}
	if (tb[RTA_OIF] && filter.oifmask != -1) {
		fprintf(fp, "dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF])));
	}

	if (tb[RTA_PREFSRC] && filter.rprefsrc.bitlen != host_len) {
		/* Do not use format_host(). It is our local addr
		   and symbolic name will not be useful.
		 */
		fprintf(fp, " src %s ", 
			rt_addr_n2a(r->rtm_family,
				    RTA_PAYLOAD(tb[RTA_PREFSRC]),
				    RTA_DATA(tb[RTA_PREFSRC]),
				    abuf, sizeof(abuf)));
	}
	if (tb[RTA_PRIORITY]) {
		fprintf(fp, " metric %d ", *(__u32*)RTA_DATA(tb[RTA_PRIORITY]));
	}
	if (r->rtm_family == AF_INET6) {
		struct rta_cacheinfo *ci = NULL;
		if (tb[RTA_CACHEINFO]) {
			ci = RTA_DATA(tb[RTA_CACHEINFO]);
		}
		if ((r->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) {
			static int hz;
			if (!hz) {
				hz = get_hz();
			}
			if (r->rtm_flags & RTM_F_CLONED) {
				fprintf(fp, "%s    cache ", _SL_);
			}
			if (ci->rta_expires) {
				fprintf(fp, " expires %dsec", ci->rta_expires/hz);
			}
			if (ci->rta_error != 0) {
				fprintf(fp, " error %d", ci->rta_error);
			}
		} else if (ci) {
			if (ci->rta_error != 0)
				fprintf(fp, " error %d", ci->rta_error);
		}
	}
	if (tb[RTA_IIF] && filter.iifmask != -1) {
		fprintf(fp, " iif %s", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_IIF])));
	}
	fprintf(fp, "\n");
	fflush(fp);
	return 0;
}
Example #6
0
int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
		   void *arg)
{
	FILE *fp = (FILE*)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)));

	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) {
		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]) {
		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]),
			   ifa->ifa_family == AF_INET ? 4 : 16) == 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)));
	ifa_flags = ifa->ifa_flags;
	if (ifa->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->ifa_flags&IFA_F_TENTATIVE) {
		ifa_flags &= ~IFA_F_TENTATIVE;
		fprintf(fp, "tentative ");
	}
	if (ifa->ifa_flags&IFA_F_DEPRECATED) {
		ifa_flags &= ~IFA_F_DEPRECATED;
		deprecated = 1;
		fprintf(fp, "deprecated ");
	}
	if (ifa->ifa_flags&IFA_F_HOMEADDRESS) {
		ifa_flags &= ~IFA_F_HOMEADDRESS;
		fprintf(fp, "home ");
	}
	if (ifa->ifa_flags&IFA_F_NODAD) {
		ifa_flags &= ~IFA_F_NODAD;
		fprintf(fp, "nodad ");
	}
	if (!(ifa->ifa_flags&IFA_F_PERMANENT)) {
		fprintf(fp, "dynamic ");
	} else
		ifa_flags &= ~IFA_F_PERMANENT;
	if (ifa->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;
}
Example #7
0
int print_route(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];
	char abuf[256];
	inet_prefix dst;
	inet_prefix src;
	inet_prefix prefsrc;
	inet_prefix via;
	int host_len = -1;
	static int ip6_multiple_tables;
	__u32 table;
	SPRINT_BUF(b1);
	static int hz;

	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 (filter.flushb && n->nlmsg_type != RTM_NEWROUTE)
		return 0;
	len -= NLMSG_LENGTH(sizeof(*r));
	if (len < 0) {
		fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
		return -1;
	}

	if (r->rtm_family == AF_INET6)
		host_len = 128;
	else if (r->rtm_family == AF_INET)
		host_len = 32;
	else if (r->rtm_family == AF_DECnet)
		host_len = 16;
	else if (r->rtm_family == AF_IPX)
		host_len = 80;

	parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
	table = rtm_get_table(r, tb);

	if (r->rtm_family == AF_INET6 && table != RT_TABLE_MAIN)
		ip6_multiple_tables = 1;

	if (filter.cloned == !(r->rtm_flags&RTM_F_CLONED))
		return 0;

	if (r->rtm_family == AF_INET6 && !ip6_multiple_tables) {
		if (filter.tb) {
			if (filter.tb == RT_TABLE_LOCAL) {
				if (r->rtm_type != RTN_LOCAL)
					return 0;
			} else if (filter.tb == RT_TABLE_MAIN) {
				if (r->rtm_type == RTN_LOCAL)
					return 0;
			} else {
				return 0;
			}
		}
	} else {
		if (filter.tb > 0 && filter.tb != table)
			return 0;
	}
	if ((filter.protocol^r->rtm_protocol)&filter.protocolmask)
		return 0;
	if ((filter.scope^r->rtm_scope)&filter.scopemask)
		return 0;
	if ((filter.type^r->rtm_type)&filter.typemask)
		return 0;
	if ((filter.tos^r->rtm_tos)&filter.tosmask)
		return 0;
	if (filter.rdst.family &&
	    (r->rtm_family != filter.rdst.family || filter.rdst.bitlen > r->rtm_dst_len))
		return 0;
	if (filter.mdst.family &&
	    (r->rtm_family != filter.mdst.family ||
	     (filter.mdst.bitlen >= 0 && filter.mdst.bitlen < r->rtm_dst_len)))
		return 0;
	if (filter.rsrc.family &&
	    (r->rtm_family != filter.rsrc.family || filter.rsrc.bitlen > r->rtm_src_len))
		return 0;
	if (filter.msrc.family &&
	    (r->rtm_family != filter.msrc.family ||
	     (filter.msrc.bitlen >= 0 && filter.msrc.bitlen < r->rtm_src_len)))
		return 0;
	if (filter.rvia.family && r->rtm_family != filter.rvia.family)
		return 0;
	if (filter.rprefsrc.family && r->rtm_family != filter.rprefsrc.family)
		return 0;

	memset(&dst, 0, sizeof(dst));
	dst.family = r->rtm_family;
	if (tb[RTA_DST])
		memcpy(&dst.data, RTA_DATA(tb[RTA_DST]), (r->rtm_dst_len+7)/8);
	if (filter.rsrc.family || filter.msrc.family) {
		memset(&src, 0, sizeof(src));
		src.family = r->rtm_family;
		if (tb[RTA_SRC])
			memcpy(&src.data, RTA_DATA(tb[RTA_SRC]), (r->rtm_src_len+7)/8);
	}
	if (filter.rvia.bitlen>0) {
		memset(&via, 0, sizeof(via));
		via.family = r->rtm_family;
		if (tb[RTA_GATEWAY])
			memcpy(&via.data, RTA_DATA(tb[RTA_GATEWAY]), host_len/8);
	}
	if (filter.rprefsrc.bitlen>0) {
		memset(&prefsrc, 0, sizeof(prefsrc));
		prefsrc.family = r->rtm_family;
		if (tb[RTA_PREFSRC])
			memcpy(&prefsrc.data, RTA_DATA(tb[RTA_PREFSRC]), host_len/8);
	}

	if (filter.rdst.family && inet_addr_match(&dst, &filter.rdst, filter.rdst.bitlen))
		return 0;
	if (filter.mdst.family && filter.mdst.bitlen >= 0 &&
	    inet_addr_match(&dst, &filter.mdst, r->rtm_dst_len))
		return 0;

	if (filter.rsrc.family && inet_addr_match(&src, &filter.rsrc, filter.rsrc.bitlen))
		return 0;
	if (filter.msrc.family && filter.msrc.bitlen >= 0 &&
	    inet_addr_match(&src, &filter.msrc, r->rtm_src_len))
		return 0;

	if (filter.rvia.family && inet_addr_match(&via, &filter.rvia, filter.rvia.bitlen))
		return 0;
	if (filter.rprefsrc.family && inet_addr_match(&prefsrc, &filter.rprefsrc, filter.rprefsrc.bitlen))
		return 0;
	if (filter.realmmask) {
		__u32 realms = 0;
		if (tb[RTA_FLOW])
			realms = *(__u32*)RTA_DATA(tb[RTA_FLOW]);
		if ((realms^filter.realm)&filter.realmmask)
			return 0;
	}
	if (filter.iifmask) {
		int iif = 0;
		if (tb[RTA_IIF])
			iif = *(int*)RTA_DATA(tb[RTA_IIF]);
		if ((iif^filter.iif)&filter.iifmask)
			return 0;
	}
	if (filter.oifmask) {
		int oif = 0;
		if (tb[RTA_OIF])
			oif = *(int*)RTA_DATA(tb[RTA_OIF]);
		if ((oif^filter.oif)&filter.oifmask)
			return 0;
	}
	if (filter.flushb &&
	    r->rtm_family == AF_INET6 &&
	    r->rtm_dst_len == 0 &&
	    r->rtm_type == RTN_UNREACHABLE &&
	    tb[RTA_PRIORITY] &&
	    *(int*)RTA_DATA(tb[RTA_PRIORITY]) == -1)
		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_DELROUTE;
		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_DELROUTE)
		fprintf(fp, "Deleted ");
	if (r->rtm_type != RTN_UNICAST && !filter.type)
		fprintf(fp, "%s ", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1)));

	if (tb[RTA_DST]) {
		if (r->rtm_dst_len != host_len) {
			fprintf(fp, "%s/%u ", rt_addr_n2a(r->rtm_family,
							 RTA_PAYLOAD(tb[RTA_DST]),
							 RTA_DATA(tb[RTA_DST]),
							 abuf, sizeof(abuf)),
				r->rtm_dst_len
				);
		} else {
			fprintf(fp, "%s ", format_host(r->rtm_family,
						       RTA_PAYLOAD(tb[RTA_DST]),
						       RTA_DATA(tb[RTA_DST]),
						       abuf, sizeof(abuf))
				);
		}
	} else if (r->rtm_dst_len) {
		fprintf(fp, "0/%d ", r->rtm_dst_len);
	} else {
		fprintf(fp, "default ");
	}
	if (tb[RTA_SRC]) {
		if (r->rtm_src_len != host_len) {
			fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family,
							 RTA_PAYLOAD(tb[RTA_SRC]),
							 RTA_DATA(tb[RTA_SRC]),
							 abuf, sizeof(abuf)),
				r->rtm_src_len
				);
		} else {
			fprintf(fp, "from %s ", format_host(r->rtm_family,
						       RTA_PAYLOAD(tb[RTA_SRC]),
						       RTA_DATA(tb[RTA_SRC]),
						       abuf, sizeof(abuf))
				);
		}
	} else if (r->rtm_src_len) {
		fprintf(fp, "from 0/%u ", r->rtm_src_len);
	}
	if (r->rtm_tos && filter.tosmask != -1) {
		SPRINT_BUF(b1);
		fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1)));
	}

	if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len) {
		fprintf(fp, "via %s ",
			format_host(r->rtm_family,
				    RTA_PAYLOAD(tb[RTA_GATEWAY]),
				    RTA_DATA(tb[RTA_GATEWAY]),
				    abuf, sizeof(abuf)));
	}
	if (tb[RTA_OIF] && filter.oifmask != -1)
		fprintf(fp, "dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF])));

	if (!(r->rtm_flags&RTM_F_CLONED)) {
		if (table != RT_TABLE_MAIN && !filter.tb)
			fprintf(fp, " table %s ", rtnl_rttable_n2a(table, b1, sizeof(b1)));
		if (r->rtm_protocol != RTPROT_BOOT && filter.protocolmask != -1)
			fprintf(fp, " proto %s ", rtnl_rtprot_n2a(r->rtm_protocol, b1, sizeof(b1)));
		if (r->rtm_scope != RT_SCOPE_UNIVERSE && filter.scopemask != -1)
			fprintf(fp, " scope %s ", rtnl_rtscope_n2a(r->rtm_scope, b1, sizeof(b1)));
	}
	if (tb[RTA_PREFSRC] && filter.rprefsrc.bitlen != host_len) {
		/* Do not use format_host(). It is our local addr
		   and symbolic name will not be useful.
		 */
		fprintf(fp, " src %s ",
			rt_addr_n2a(r->rtm_family,
				    RTA_PAYLOAD(tb[RTA_PREFSRC]),
				    RTA_DATA(tb[RTA_PREFSRC]),
				    abuf, sizeof(abuf)));
	}
	if (tb[RTA_PRIORITY])
		fprintf(fp, " metric %d ", *(__u32*)RTA_DATA(tb[RTA_PRIORITY]));
	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 ");

	if (tb[RTA_FLOW] && filter.realmmask != ~0U) {
		__u32 to = *(__u32*)RTA_DATA(tb[RTA_FLOW]);
		__u32 from = to>>16;
		to &= 0xFFFF;
		fprintf(fp, "realm%s ", from ? "s" : "");
		if (from) {
			fprintf(fp, "%s/",
				rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
		}
		fprintf(fp, "%s ",
			rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
	}
Example #8
0
int print_netconf(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl,
		  struct nlmsghdr *n, void *arg)
{
	FILE *fp = (FILE*)arg;
	struct netconfmsg *ncm = NLMSG_DATA(n);
	int len = n->nlmsg_len;
	struct rtattr *tb[NETCONFA_MAX+1];

	if (n->nlmsg_type == NLMSG_ERROR)
		return -1;
	if (n->nlmsg_type != RTM_NEWNETCONF) {
		fprintf(stderr, "Not RTM_NEWNETCONF: %08x %08x %08x\n",
			n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);

		return -1;
	}
	len -= NLMSG_SPACE(sizeof(*ncm));
	if (len < 0) {
		fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
		return -1;
	}

	if (filter.family && filter.family != ncm->ncm_family)
		return 0;

	parse_rtattr(tb, NETCONFA_MAX, NETCONF_RTA(ncm),
		     NLMSG_PAYLOAD(n, sizeof(*ncm)));

	switch (ncm->ncm_family) {
	case AF_INET:
		fprintf(fp, "ipv4 ");
		break;
	case AF_INET6:
		fprintf(fp, "ipv6 ");
		break;
	default:
		fprintf(fp, "unknown ");
		break;
	}

	if (tb[NETCONFA_IFINDEX]) {
		int *ifindex = (int *)RTA_DATA(tb[NETCONFA_IFINDEX]);

		switch (*ifindex) {
		case NETCONFA_IFINDEX_ALL:
			fprintf(fp, "all ");
			break;
		case NETCONFA_IFINDEX_DEFAULT:
			fprintf(fp, "default ");
			break;
		default:
			fprintf(fp, "dev %s ", ll_index_to_name(*ifindex));
			break;
		}
	}

	if (tb[NETCONFA_FORWARDING])
		fprintf(fp, "forwarding %s ",
			*(int *)RTA_DATA(tb[NETCONFA_FORWARDING])?"on":"off");
	if (tb[NETCONFA_RP_FILTER]) {
		int rp_filter = *(int *)RTA_DATA(tb[NETCONFA_RP_FILTER]);

		if (rp_filter == 0)
			fprintf(fp, "rp_filter off ");
		else if (rp_filter == 1)
			fprintf(fp, "rp_filter strict ");
		else if (rp_filter == 2)
			fprintf(fp, "rp_filter loose ");
		else
			fprintf(fp, "rp_filter unknown mode ");
	}
	if (tb[NETCONFA_MC_FORWARDING])
		fprintf(fp, "mc_forwarding %d ",
			*(int *)RTA_DATA(tb[NETCONFA_MC_FORWARDING]));

	if (tb[NETCONFA_PROXY_NEIGH])
		fprintf(fp, "proxy_neigh %s ",
			*(int *)RTA_DATA(tb[NETCONFA_PROXY_NEIGH])?"on":"off");

	fprintf(fp, "\n");
	fflush(fp);
	return 0;
}
Example #9
0
static int print_ntable(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
{
	FILE *fp = (FILE*)arg;
	struct ndtmsg *ndtm = NLMSG_DATA(n);
	int len = n->nlmsg_len;
	struct rtattr *tb[NDTA_MAX+1];
	struct rtattr *tpb[NDTPA_MAX+1];
	int ret;

	if (n->nlmsg_type != RTM_NEWNEIGHTBL) {
		fprintf(stderr, "Not NEIGHTBL: %08x %08x %08x\n",
			n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
		return 0;
	}
	len -= NLMSG_LENGTH(sizeof(*ndtm));
	if (len < 0) {
		fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
		return -1;
	}

	if (preferred_family && preferred_family != ndtm->ndtm_family)
		return 0;

	parse_rtattr(tb, NDTA_MAX, NDTA_RTA(ndtm),
		     n->nlmsg_len - NLMSG_LENGTH(sizeof(*ndtm)));

	if (tb[NDTA_NAME]) {
		const char *name = rta_getattr_str(tb[NDTA_NAME]);

		if (strlen(filter.name) > 0 && strcmp(filter.name, name))
			return 0;
	}
	if (tb[NDTA_PARMS]) {
		parse_rtattr(tpb, NDTPA_MAX, RTA_DATA(tb[NDTA_PARMS]),
			     RTA_PAYLOAD(tb[NDTA_PARMS]));

		if (tpb[NDTPA_IFINDEX]) {
			__u32 ifindex = rta_getattr_u32(tpb[NDTPA_IFINDEX]);

			if (filter.index && filter.index != ifindex)
				return 0;
		} else {
			if (filter.index && filter.index != NONE_DEV)
				return 0;
		}
	}

	if (ndtm->ndtm_family == AF_INET)
		fprintf(fp, "inet ");
	else if (ndtm->ndtm_family == AF_INET6)
		fprintf(fp, "inet6 ");
	else if (ndtm->ndtm_family == AF_DECnet)
		fprintf(fp, "dnet ");
	else
		fprintf(fp, "(%d) ", ndtm->ndtm_family);

	if (tb[NDTA_NAME]) {
		const char *name = rta_getattr_str(tb[NDTA_NAME]);
		fprintf(fp, "%s ", name);
	}

	fprintf(fp, "%s", _SL_);

	ret = (tb[NDTA_THRESH1] || tb[NDTA_THRESH2] || tb[NDTA_THRESH3] ||
	       tb[NDTA_GC_INTERVAL]);
	if (ret)
		fprintf(fp, "    ");

	if (tb[NDTA_THRESH1]) {
		__u32 thresh1 = rta_getattr_u32(tb[NDTA_THRESH1]);
		fprintf(fp, "thresh1 %u ", thresh1);
	}
	if (tb[NDTA_THRESH2]) {
		__u32 thresh2 = rta_getattr_u32(tb[NDTA_THRESH2]);
		fprintf(fp, "thresh2 %u ", thresh2);
	}
	if (tb[NDTA_THRESH3]) {
		__u32 thresh3 = rta_getattr_u32(tb[NDTA_THRESH3]);
		fprintf(fp, "thresh3 %u ", thresh3);
	}
	if (tb[NDTA_GC_INTERVAL]) {
		unsigned long long gc_int = rta_getattr_u64(tb[NDTA_GC_INTERVAL]);
		fprintf(fp, "gc_int %llu ", gc_int);
	}

	if (ret)
		fprintf(fp, "%s", _SL_);

	if (tb[NDTA_CONFIG] && show_stats) {
		struct ndt_config *ndtc = RTA_DATA(tb[NDTA_CONFIG]);

		fprintf(fp, "    ");
		fprintf(fp, "config ");

		fprintf(fp, "key_len %u ", ndtc->ndtc_key_len);
		fprintf(fp, "entry_size %u ", ndtc->ndtc_entry_size);
		fprintf(fp, "entries %u ", ndtc->ndtc_entries);

		fprintf(fp, "%s", _SL_);
		fprintf(fp, "        ");

		fprintf(fp, "last_flush %s ",
			ntable_strtime_delta(ndtc->ndtc_last_flush));
		fprintf(fp, "last_rand %s ",
			ntable_strtime_delta(ndtc->ndtc_last_rand));

		fprintf(fp, "%s", _SL_);
		fprintf(fp, "        ");

		fprintf(fp, "hash_rnd %u ", ndtc->ndtc_hash_rnd);
		fprintf(fp, "hash_mask %08x ", ndtc->ndtc_hash_mask);

		fprintf(fp, "hash_chain_gc %u ", ndtc->ndtc_hash_chain_gc);
		fprintf(fp, "proxy_qlen %u ", ndtc->ndtc_proxy_qlen);

		fprintf(fp, "%s", _SL_);
	}

	if (tb[NDTA_PARMS]) {
		if (tpb[NDTPA_IFINDEX]) {
			__u32 ifindex = rta_getattr_u32(tpb[NDTPA_IFINDEX]);

			fprintf(fp, "    ");
			fprintf(fp, "dev %s ", ll_index_to_name(ifindex));
			fprintf(fp, "%s", _SL_);
		}

		fprintf(fp, "    ");

		if (tpb[NDTPA_REFCNT]) {
			__u32 refcnt = rta_getattr_u32(tpb[NDTPA_REFCNT]);
			fprintf(fp, "refcnt %u ", refcnt);
		}
		if (tpb[NDTPA_REACHABLE_TIME]) {
			unsigned long long reachable = rta_getattr_u64(tpb[NDTPA_REACHABLE_TIME]);
			fprintf(fp, "reachable %llu ", reachable);
		}
		if (tpb[NDTPA_BASE_REACHABLE_TIME]) {
			unsigned long long breachable = rta_getattr_u64(tpb[NDTPA_BASE_REACHABLE_TIME]);
			fprintf(fp, "base_reachable %llu ", breachable);
		}
		if (tpb[NDTPA_RETRANS_TIME]) {
			unsigned long long retrans = rta_getattr_u64(tpb[NDTPA_RETRANS_TIME]);
			fprintf(fp, "retrans %llu ", retrans);
		}

		fprintf(fp, "%s", _SL_);

		fprintf(fp, "    ");

		if (tpb[NDTPA_GC_STALETIME]) {
			unsigned long long gc_stale = rta_getattr_u64(tpb[NDTPA_GC_STALETIME]);
			fprintf(fp, "gc_stale %llu ", gc_stale);
		}
		if (tpb[NDTPA_DELAY_PROBE_TIME]) {
			unsigned long long delay_probe = rta_getattr_u64(tpb[NDTPA_DELAY_PROBE_TIME]);
			fprintf(fp, "delay_probe %llu ", delay_probe);
		}
		if (tpb[NDTPA_QUEUE_LEN]) {
			__u32 queue = rta_getattr_u32(tpb[NDTPA_QUEUE_LEN]);
			fprintf(fp, "queue %u ", queue);
		}

		fprintf(fp, "%s", _SL_);

		fprintf(fp, "    ");

		if (tpb[NDTPA_APP_PROBES]) {
			__u32 aprobe = rta_getattr_u32(tpb[NDTPA_APP_PROBES]);
			fprintf(fp, "app_probes %u ", aprobe);
		}
		if (tpb[NDTPA_UCAST_PROBES]) {
			__u32 uprobe = rta_getattr_u32(tpb[NDTPA_UCAST_PROBES]);
			fprintf(fp, "ucast_probes %u ", uprobe);
		}
		if (tpb[NDTPA_MCAST_PROBES]) {
			__u32 mprobe = rta_getattr_u32(tpb[NDTPA_MCAST_PROBES]);
			fprintf(fp, "mcast_probes %u ", mprobe);
		}

		fprintf(fp, "%s", _SL_);

		fprintf(fp, "    ");

		if (tpb[NDTPA_ANYCAST_DELAY]) {
			unsigned long long anycast_delay = rta_getattr_u64(tpb[NDTPA_ANYCAST_DELAY]);
			fprintf(fp, "anycast_delay %llu ", anycast_delay);
		}
		if (tpb[NDTPA_PROXY_DELAY]) {
			unsigned long long proxy_delay = rta_getattr_u64(tpb[NDTPA_PROXY_DELAY]);
			fprintf(fp, "proxy_delay %llu ", proxy_delay);
		}
		if (tpb[NDTPA_PROXY_QLEN]) {
			__u32 pqueue = rta_getattr_u32(tpb[NDTPA_PROXY_QLEN]);
			fprintf(fp, "proxy_queue %u ", pqueue);
		}
		if (tpb[NDTPA_LOCKTIME]) {
			unsigned long long locktime = rta_getattr_u64(tpb[NDTPA_LOCKTIME]);
			fprintf(fp, "locktime %llu ", locktime);
		}

		fprintf(fp, "%s", _SL_);
	}

	if (tb[NDTA_STATS] && show_stats) {
		struct ndt_stats *ndts = RTA_DATA(tb[NDTA_STATS]);

		fprintf(fp, "    ");
		fprintf(fp, "stats ");

		fprintf(fp, "allocs %llu ",
			(unsigned long long) ndts->ndts_allocs);
		fprintf(fp, "destroys %llu ",
			(unsigned long long) ndts->ndts_destroys);
		fprintf(fp, "hash_grows %llu ",
			(unsigned long long) ndts->ndts_hash_grows);

		fprintf(fp, "%s", _SL_);
		fprintf(fp, "        ");

		fprintf(fp, "res_failed %llu ",
			(unsigned long long) ndts->ndts_res_failed);
		fprintf(fp, "lookups %llu ",
			(unsigned long long) ndts->ndts_lookups);
		fprintf(fp, "hits %llu ",
			(unsigned long long) ndts->ndts_hits);

		fprintf(fp, "%s", _SL_);
		fprintf(fp, "        ");

		fprintf(fp, "rcv_probes_mcast %llu ",
			(unsigned long long) ndts->ndts_rcv_probes_mcast);
		fprintf(fp, "rcv_probes_ucast %llu ",
			(unsigned long long) ndts->ndts_rcv_probes_ucast);

		fprintf(fp, "%s", _SL_);
		fprintf(fp, "        ");

		fprintf(fp, "periodic_gc_runs %llu ",
			(unsigned long long) ndts->ndts_periodic_gc_runs);
		fprintf(fp, "forced_gc_runs %llu ",
			(unsigned long long) ndts->ndts_forced_gc_runs);

		fprintf(fp, "%s", _SL_);
	}

	fprintf(fp, "\n");

	fflush(fp);
	return 0;
}
Example #10
0
static void print_tunnel(struct ip_tunnel_parm *p)
{
	struct ip_tunnel_6rd ip6rd;
	char s1[1024];
	char s2[1024];

	memset(&ip6rd, 0, sizeof(ip6rd));

	/* Do not use format_host() for local addr,
	 * symbolic name will not be useful.
	 */
	printf("%s: %s/ip remote %s local %s",
	       p->name,
	       tnl_strproto(p->iph.protocol),
	       p->iph.daddr ? format_host_r(AF_INET, 4, &p->iph.daddr, s1, sizeof(s1)) : "any",
	       p->iph.saddr ? rt_addr_n2a_r(AF_INET, 4, &p->iph.saddr, s2, sizeof(s2)) : "any");

	if (p->iph.protocol == IPPROTO_IPV6 && (p->i_flags & SIT_ISATAP)) {
		struct ip_tunnel_prl prl[16];
		int i;

		memset(prl, 0, sizeof(prl));
		prl[0].datalen = sizeof(prl) - sizeof(prl[0]);
		prl[0].addr = htonl(INADDR_ANY);

		if (!tnl_prl_ioctl(SIOCGETPRL, p->name, prl))
			for (i = 1; i < ARRAY_SIZE(prl); i++) {
				if (prl[i].addr != htonl(INADDR_ANY)) {
					printf(" %s %s ",
					       (prl[i].flags & PRL_DEFAULT) ? "pdr" : "pr",
					       format_host(AF_INET, 4, &prl[i].addr));
				}
			}
	}

	if (p->link) {
		const char *n = ll_index_to_name(p->link);

		if (n)
			printf(" dev %s", n);
	}

	if (p->iph.ttl)
		printf(" ttl %d", p->iph.ttl);
	else
		printf(" ttl inherit");

	if (p->iph.tos) {
		SPRINT_BUF(b1);
		printf(" tos");
		if (p->iph.tos & 1)
			printf(" inherit");
		if (p->iph.tos & ~1)
			printf("%c%s ", p->iph.tos & 1 ? '/' : ' ',
			       rtnl_dsfield_n2a(p->iph.tos & ~1, b1, sizeof(b1)));
	}

	if (!(p->iph.frag_off & htons(IP_DF)))
		printf(" nopmtudisc");

	if (p->iph.protocol == IPPROTO_IPV6 && !tnl_ioctl_get_6rd(p->name, &ip6rd) && ip6rd.prefixlen) {
		printf(" 6rd-prefix %s/%u",
		       inet_ntop(AF_INET6, &ip6rd.prefix, s1, sizeof(s1)),
		       ip6rd.prefixlen);
		if (ip6rd.relay_prefix) {
			printf(" 6rd-relay_prefix %s/%u",
			       format_host(AF_INET, 4, &ip6rd.relay_prefix),
			       ip6rd.relay_prefixlen);
		}
	}

	if ((p->i_flags & GRE_KEY) && (p->o_flags & GRE_KEY) && p->o_key == p->i_key)
		printf(" key %u", ntohl(p->i_key));
	else if ((p->i_flags | p->o_flags) & GRE_KEY) {
		if (p->i_flags & GRE_KEY)
			printf(" ikey %u", ntohl(p->i_key));
		if (p->o_flags & GRE_KEY)
			printf(" okey %u", ntohl(p->o_key));
	}

	if (p->i_flags & GRE_SEQ)
		printf("%s  Drop packets out of sequence.", _SL_);
	if (p->i_flags & GRE_CSUM)
		printf("%s  Checksum in received packet is required.", _SL_);
	if (p->o_flags & GRE_SEQ)
		printf("%s  Sequence packets on output.", _SL_);
	if (p->o_flags & GRE_CSUM)
		printf("%s  Checksum output packets.", _SL_);
}
Example #11
0
static int vlan_modify(int cmd, int argc, char **argv)
{
	struct {
		struct nlmsghdr	n;
		struct ifinfomsg	ifm;
		char			buf[1024];
	} req = {
		.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
		.n.nlmsg_flags = NLM_F_REQUEST,
		.n.nlmsg_type = cmd,
		.ifm.ifi_family = PF_BRIDGE,
	};
	char *d = NULL;
	short vid = -1;
	short vid_end = -1;
	struct rtattr *afspec;
	struct bridge_vlan_info vinfo = {};
	unsigned short flags = 0;

	while (argc > 0) {
		if (strcmp(*argv, "dev") == 0) {
			NEXT_ARG();
			d = *argv;
		} else if (strcmp(*argv, "vid") == 0) {
			char *p;

			NEXT_ARG();
			p = strchr(*argv, '-');
			if (p) {
				*p = '\0';
				p++;
				vid = atoi(*argv);
				vid_end = atoi(p);
				vinfo.flags |= BRIDGE_VLAN_INFO_RANGE_BEGIN;
			} else {
				vid = atoi(*argv);
			}
		} else if (strcmp(*argv, "self") == 0) {
			flags |= BRIDGE_FLAGS_SELF;
		} else if (strcmp(*argv, "master") == 0) {
			flags |= BRIDGE_FLAGS_MASTER;
		} else if (strcmp(*argv, "pvid") == 0) {
			vinfo.flags |= BRIDGE_VLAN_INFO_PVID;
		} else if (strcmp(*argv, "untagged") == 0) {
			vinfo.flags |= BRIDGE_VLAN_INFO_UNTAGGED;
		} else {
			if (matches(*argv, "help") == 0) {
				NEXT_ARG();
			}
		}
		argc--; argv++;
	}

	if (d == NULL || vid == -1) {
		fprintf(stderr, "Device and VLAN ID are required arguments.\n");
		return -1;
	}

	req.ifm.ifi_index = ll_name_to_index(d);
	if (req.ifm.ifi_index == 0) {
		fprintf(stderr, "Cannot find bridge device \"%s\"\n", d);
		return -1;
	}

	if (vid >= 4096) {
		fprintf(stderr, "Invalid VLAN ID \"%hu\"\n", vid);
		return -1;
	}

	if (vinfo.flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
		if (vid_end == -1 || vid_end >= 4096 || vid >= vid_end) {
			fprintf(stderr, "Invalid VLAN range \"%hu-%hu\"\n",
				vid, vid_end);
			return -1;
		}
		if (vinfo.flags & BRIDGE_VLAN_INFO_PVID) {
			fprintf(stderr,
				"pvid cannot be configured for a vlan range\n");
			return -1;
		}
	}

	afspec = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC);

	if (flags)
		addattr16(&req.n, sizeof(req), IFLA_BRIDGE_FLAGS, flags);

	vinfo.vid = vid;
	if (vid_end != -1) {
		/* send vlan range start */
		addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo,
			  sizeof(vinfo));
		vinfo.flags &= ~BRIDGE_VLAN_INFO_RANGE_BEGIN;

		/* Now send the vlan range end */
		vinfo.flags |= BRIDGE_VLAN_INFO_RANGE_END;
		vinfo.vid = vid_end;
		addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo,
			  sizeof(vinfo));
	} else {
		addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo,
			  sizeof(vinfo));
	}

	addattr_nest_end(&req.n, afspec);

	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
		return -1;

	return 0;
}

/* In order to use this function for both filtering and non-filtering cases
 * we need to make it a tristate:
 * return -1 - if filtering we've gone over so don't continue
 * return  0 - skip entry and continue (applies to range start or to entries
 *             which are less than filter_vlan)
 * return  1 - print the entry and continue
 */
static int filter_vlan_check(struct bridge_vlan_info *vinfo)
{
	/* if we're filtering we should stop on the first greater entry */
	if (filter_vlan && vinfo->vid > filter_vlan &&
	    !(vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END))
		return -1;
	if ((vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) ||
	    vinfo->vid < filter_vlan)
		return 0;

	return 1;
}

static void print_vlan_port(FILE *fp, int ifi_index)
{
	if (jw_global) {
		jsonw_pretty(jw_global, 1);
		jsonw_name(jw_global,
			   ll_index_to_name(ifi_index));
		jsonw_start_array(jw_global);
	} else {
		fprintf(fp, "%s",
			ll_index_to_name(ifi_index));
	}
}

static void start_json_vlan_flags_array(bool *vlan_flags)
{
	if (*vlan_flags)
		return;
	jsonw_name(jw_global, "flags");
	jsonw_start_array(jw_global);
	*vlan_flags = true;
}

static int print_vlan(const struct sockaddr_nl *who,
		      struct nlmsghdr *n,
		      void *arg)
{
	FILE *fp = arg;
	struct ifinfomsg *ifm = NLMSG_DATA(n);
	int len = n->nlmsg_len;
	struct rtattr *tb[IFLA_MAX+1];
	bool vlan_flags;

	if (n->nlmsg_type != RTM_NEWLINK) {
		fprintf(stderr, "Not RTM_NEWLINK: %08x %08x %08x\n",
			n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
		return 0;
	}

	len -= NLMSG_LENGTH(sizeof(*ifm));
	if (len < 0) {
		fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
		return -1;
	}

	if (ifm->ifi_family != AF_BRIDGE)
		return 0;

	if (filter_index && filter_index != ifm->ifi_index)
		return 0;

	parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifm), len);

	/* if AF_SPEC isn't there, vlan table is not preset for this port */
	if (!tb[IFLA_AF_SPEC]) {
		if (!filter_vlan)
			fprintf(fp, "%s\tNone\n",
				ll_index_to_name(ifm->ifi_index));
		return 0;
	} else {
		struct rtattr *i, *list = tb[IFLA_AF_SPEC];
		int rem = RTA_PAYLOAD(list);
		__u16 last_vid_start = 0;

		if (!filter_vlan)
			print_vlan_port(fp, ifm->ifi_index);

		for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
			struct bridge_vlan_info *vinfo;
			int vcheck_ret;

			if (i->rta_type != IFLA_BRIDGE_VLAN_INFO)
				continue;

			vinfo = RTA_DATA(i);

			if (!(vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END))
				last_vid_start = vinfo->vid;
			vcheck_ret = filter_vlan_check(vinfo);
			if (vcheck_ret == -1)
				break;
			else if (vcheck_ret == 0)
				continue;

			if (filter_vlan)
				print_vlan_port(fp, ifm->ifi_index);
			if (jw_global) {
				jsonw_start_object(jw_global);
				jsonw_uint_field(jw_global, "vlan",
						 last_vid_start);
				if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN)
					continue;
			} else {
				fprintf(fp, "\t %hu", last_vid_start);
			}
			if (last_vid_start != vinfo->vid) {
				if (jw_global)
					jsonw_uint_field(jw_global, "vlanEnd",
							 vinfo->vid);
				else
					fprintf(fp, "-%hu", vinfo->vid);
			}
			if (vinfo->flags & BRIDGE_VLAN_INFO_PVID) {
				if (jw_global) {
					start_json_vlan_flags_array(&vlan_flags);
					jsonw_string(jw_global, "PVID");
				} else {
					fprintf(fp, " PVID");
				}
			}
			if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED) {
				if (jw_global) {
					start_json_vlan_flags_array(&vlan_flags);
					jsonw_string(jw_global,
						     "Egress Untagged");
				} else {
					fprintf(fp, " Egress Untagged");
				}
			}
			if (vlan_flags) {
				jsonw_end_array(jw_global);
				vlan_flags = false;
			}

			if (jw_global)
				jsonw_end_object(jw_global);
			else
				fprintf(fp, "\n");
		}
	}
	if (!filter_vlan) {
		if (jw_global)
			jsonw_end_array(jw_global);
		else
			fprintf(fp, "\n");

	}
	fflush(fp);
	return 0;
}