Monitor time patch from Masahide NAKAMURA
diff --git a/include/utils.h b/include/utils.h
index ddbf97c..f27aa54 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -14,6 +14,7 @@
 extern int show_raw;
 extern int resolve_hosts;
 extern int oneline;
+extern int timestamp;
 extern char * _SL_;
 
 #ifndef IPPROTO_ESP
@@ -126,4 +127,6 @@
 	return __iproute2_user_hz_internal;
 }
 
+int print_timestamp(FILE *fp);
+
 #endif /* __UTILS_H__ */
diff --git a/ip/ip.c b/ip/ip.c
index 6358ec4..3d632ef 100644
--- a/ip/ip.c
+++ b/ip/ip.c
@@ -31,6 +31,7 @@
 int show_stats = 0;
 int resolve_hosts = 0;
 int oneline = 0;
+int timestamp = 0;
 char * _SL_ = NULL;
 
 static void usage(void) __attribute__((noreturn));
@@ -42,7 +43,8 @@
 "where  OBJECT := { link | addr | route | rule | neigh | tunnel |\n"
 "                   maddr | mroute | monitor | xfrm }\n"
 "       OPTIONS := { -V[ersion] | -s[tatistics] | -r[esolve] |\n"
-"                    -f[amily] { inet | inet6 | ipx | dnet | link } | -o[neline] }\n");
+"                    -f[amily] { inet | inet6 | ipx | dnet | link } |\n"
+"                    -o[neline] | -t[imestamp] }\n");
 	exit(-1);
 }
 
@@ -102,6 +104,8 @@
 			++resolve_hosts;
 		} else if (matches(opt, "-oneline") == 0) {
 			++oneline;
+		} else if (matches(opt, "-timestamp") == 0) {
+			++timestamp;
 #if 0
 		} else if (matches(opt, "-numeric") == 0) {
 			rtnl_names_numeric++;
diff --git a/ip/ipmonitor.c b/ip/ipmonitor.c
index cdaeb6f..819f9f6 100644
--- a/ip/ipmonitor.c
+++ b/ip/ipmonitor.c
@@ -38,6 +38,9 @@
 {
 	FILE *fp = (FILE*)arg;
 
+	if (timestamp)
+		print_timestamp(fp);
+
 	if (n->nlmsg_type == RTM_NEWROUTE || n->nlmsg_type == RTM_DELROUTE) {
 		print_route(who, n, arg);
 		return 0;
diff --git a/ip/xfrm_monitor.c b/ip/xfrm_monitor.c
index 21001a6..7edb21f 100644
--- a/ip/xfrm_monitor.c
+++ b/ip/xfrm_monitor.c
@@ -63,7 +63,7 @@
 	}
 
 	parse_rtattr(tb, XFRMA_MAX, XFRMACQ_RTA(xacq), len);
-	
+
 	family = xacq->sel.family;
 	if (family == AF_UNSPEC)
 		family = xacq->policy.sel.family;
@@ -107,92 +107,24 @@
 	return 0;
 }
 
-static int xfrm_state_expire_print(const struct sockaddr_nl *who,
-				   struct nlmsghdr *n, void *arg)
-{
-	FILE *fp = (FILE*)arg;
-	struct xfrm_user_expire *xexp = NLMSG_DATA(n);
-	int len = n->nlmsg_len;
-	struct rtattr * tb[XFRMA_MAX+1];
-
-	if (n->nlmsg_type != XFRM_MSG_EXPIRE) {
-		fprintf(stderr, "Not an expire: %08x %08x %08x\n",
-			n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
-		return 0;
-	}
-
-	len -= NLMSG_LENGTH(sizeof(*xexp));
-	if (len < 0) {
-		fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
-		return -1;
-	}
-
-	parse_rtattr(tb, XFRMA_MAX, XFRMEXP_RTA(xexp), len);
-
-	fprintf(fp, "Expired ");
-
-	xfrm_state_info_print(&xexp->state, tb, fp, NULL, NULL);
-
-	fprintf(fp, "\t");
-	fprintf(fp, "hard %u", xexp->hard);
-	fprintf(fp, "%s", _SL_);
-
-	if (oneline)
-		fprintf(fp, "\n");
-
-	return 0;
-}
-
-static int xfrm_policy_expire_print(const struct sockaddr_nl *who,
-				    struct nlmsghdr *n, void *arg)
-{
-	FILE *fp = (FILE*)arg;
-	struct xfrm_user_polexpire *xpexp = NLMSG_DATA(n);
-	int len = n->nlmsg_len;
-	struct rtattr * tb[XFRMA_MAX+1];
-
-	if (n->nlmsg_type != XFRM_MSG_POLEXPIRE) {
-		fprintf(stderr, "Not a polexpire: %08x %08x %08x\n",
-			n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
-		return 0;
-	}
-
-	len -= NLMSG_LENGTH(sizeof(*xpexp));
-	if (len < 0) {
-		fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
-		return -1;
-	}
-
-	parse_rtattr(tb, XFRMA_MAX, XFRMPEXP_RTA(xpexp), len);
-
-	fprintf(fp, "Expired ");
-	xfrm_policy_info_print(&xpexp->pol, tb, fp, NULL, NULL);
-
-	fprintf(fp, "\t");
-	fprintf(fp, "hard %u", xpexp->hard);
-	fprintf(fp, "%s", _SL_);
-
-	if (oneline)
-		fprintf(fp, "\n");
-
-	return 0;
-}
-
 static int xfrm_accept_msg(const struct sockaddr_nl *who,
 			   struct nlmsghdr *n, void *arg)
 {
 	FILE *fp = (FILE*)arg;
 
+	if (timestamp)
+		print_timestamp(fp);
+
 	if (n->nlmsg_type == XFRM_MSG_ACQUIRE) {
 		xfrm_acquire_print(who, n, arg);
 		return 0;
 	}
 	if (n->nlmsg_type == XFRM_MSG_EXPIRE) {
-		xfrm_state_expire_print(who, n, arg);
+		xfrm_state_print(who, n, arg);
 		return 0;
 	}
 	if (n->nlmsg_type == XFRM_MSG_POLEXPIRE) {
-		xfrm_policy_expire_print(who, n, arg);
+		xfrm_policy_print(who, n, arg);
 		return 0;
 	}
 	if (n->nlmsg_type == XFRM_MSG_FLUSHSA) {
diff --git a/ip/xfrm_policy.c b/ip/xfrm_policy.c
index 04caf18..bea0162 100644
--- a/ip/xfrm_policy.c
+++ b/ip/xfrm_policy.c
@@ -335,18 +335,32 @@
 		      void *arg)
 {
 	FILE *fp = (FILE*)arg;
-	struct xfrm_userpolicy_info *xpinfo = NLMSG_DATA(n);
+	struct xfrm_userpolicy_info *xpinfo;
+	struct xfrm_user_polexpire *xpexp;
 	int len = n->nlmsg_len;
 	struct rtattr * tb[XFRMA_MAX+1];
+	struct rtattr * rta;
 
 	if (n->nlmsg_type != XFRM_MSG_NEWPOLICY &&
-	    n->nlmsg_type != XFRM_MSG_DELPOLICY) {
+	    n->nlmsg_type != XFRM_MSG_DELPOLICY &&
+	    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;
 	}
 
-	len -= NLMSG_LENGTH(sizeof(*xpinfo));
+	if (n->nlmsg_type == XFRM_MSG_POLEXPIRE) {
+		xpexp = NLMSG_DATA(n);
+		xpinfo = &xpexp->pol;
+
+		len -= NLMSG_LENGTH(sizeof(*xpexp));
+	} else {
+		xpexp = NULL;
+		xpinfo = NLMSG_DATA(n);
+
+		len -= NLMSG_LENGTH(sizeof(*xpinfo));
+	}
+
 	if (len < 0) {
 		fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
 		return -1;
@@ -355,13 +369,26 @@
 	if (!xfrm_policy_filter_match(xpinfo))
 		return 0;
 
-	parse_rtattr(tb, XFRMA_MAX, XFRMP_RTA(xpinfo), len);
+	if (n->nlmsg_type == XFRM_MSG_POLEXPIRE)
+		rta = XFRMPEXP_RTA(xpexp);
+	else
+		rta = XFRMP_RTA(xpinfo);
+
+	parse_rtattr(tb, XFRMA_MAX, rta, len);
 
 	if (n->nlmsg_type == XFRM_MSG_DELPOLICY)
 		fprintf(fp, "Deleted ");
+	else if (n->nlmsg_type == XFRM_MSG_POLEXPIRE)
+		fprintf(fp, "Expired ");
 
 	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");
 
diff --git a/ip/xfrm_state.c b/ip/xfrm_state.c
index a02fd4e..64065c8 100644
--- a/ip/xfrm_state.c
+++ b/ip/xfrm_state.c
@@ -555,18 +555,32 @@
 		     void *arg)
 {
 	FILE *fp = (FILE*)arg;
-	struct xfrm_usersa_info *xsinfo = NLMSG_DATA(n);
+	struct xfrm_usersa_info *xsinfo;
+	struct xfrm_user_expire *xexp;
 	int len = n->nlmsg_len;
 	struct rtattr * tb[XFRMA_MAX+1];
+	struct rtattr * rta;
 
 	if (n->nlmsg_type != XFRM_MSG_NEWSA &&
-	    n->nlmsg_type != XFRM_MSG_DELSA) {
+	    n->nlmsg_type != XFRM_MSG_DELSA &&
+	    n->nlmsg_type != XFRM_MSG_EXPIRE) {
 		fprintf(stderr, "Not a state: %08x %08x %08x\n",
 			n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
 		return 0;
 	}
 
-	len -= NLMSG_LENGTH(sizeof(*xsinfo));
+	if (n->nlmsg_type == XFRM_MSG_EXPIRE) {
+		xexp = NLMSG_DATA(n);
+		xsinfo = &xexp->state;
+
+		len -= NLMSG_LENGTH(sizeof(*xexp));
+	} else {
+		xexp = NULL;
+		xsinfo = NLMSG_DATA(n);
+
+		len -= NLMSG_LENGTH(sizeof(*xsinfo));
+	}
+
 	if (len < 0) {
 		fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
 		return -1;
@@ -575,13 +589,26 @@
 	if (!xfrm_state_filter_match(xsinfo))
 		return 0;
 
-	parse_rtattr(tb, XFRMA_MAX, XFRMS_RTA(xsinfo), len);
+	if (n->nlmsg_type == XFRM_MSG_EXPIRE)
+		rta = XFRMEXP_RTA(xexp);
+	else
+		rta = XFRMS_RTA(xsinfo);
+
+	parse_rtattr(tb, XFRMA_MAX, rta, len);
 
 	if (n->nlmsg_type == XFRM_MSG_DELSA)
 		fprintf(fp, "Deleted ");
+	else if (n->nlmsg_type == XFRM_MSG_EXPIRE)
+		fprintf(fp, "Expired ");
 
 	xfrm_state_info_print(xsinfo, tb, fp, NULL, NULL);
 
+	if (n->nlmsg_type == XFRM_MSG_EXPIRE) {
+		fprintf(fp, "\t");
+		fprintf(fp, "hard %u", xexp->hard);
+		fprintf(fp, "%s", _SL_);
+	}
+
 	if (oneline)
 		fprintf(fp, "\n");
 
diff --git a/lib/utils.c b/lib/utils.c
index df8795a..5954502 100644
--- a/lib/utils.c
+++ b/lib/utils.c
@@ -27,6 +27,9 @@
 #include <resolv.h>
 #include <asm/types.h>
 #include <linux/pkt_sched.h>
+#include <time.h>
+#include <sys/time.h>
+
 
 #include "utils.h"
 
@@ -557,3 +560,17 @@
 		memset(buf+cnt, 0, blen-cnt);
 	return buf;
 }
+
+int print_timestamp(FILE *fp)
+{
+	struct timeval tv;
+	char *tstr;
+
+	memset(&tv, 0, sizeof(tv));
+	gettimeofday(&tv, NULL);
+
+	tstr = asctime(localtime(&tv.tv_sec));
+	tstr[strlen(tstr)-1] = 0;
+	fprintf(fp, "Timestamp: %s %lu usec\n", tstr, tv.tv_usec);
+	return 0;
+}