diff --git a/.gitignore b/.gitignore
index ec6d288..f9049cb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,3 +23,4 @@ stamp-h1*
 /version.h
 /version.h.tmp
 
+compile
diff --git a/AUTHORS b/AUTHORS
index c3ec5af..b015e81 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,11 +1,11 @@
 
   Matt Kimball <mkimball@xmission.com> is the primary author of mtr.
 
-  Roger Wolff <R.E.Wolff@BitWizard.nl> is currently maintaing mtr. 
+  Roger Wolff <R.E.Wolff@BitWizard.nl> is currently maintaining mtr.
 
 
-  Bug reports and feature requests should be sent to the mtr 
-  mailing list.  See the README file for details.
+  Bug reports and feature requests should be sent as described in
+  the README file.
 
   Thanks to everyone who has provided feedback on mtr.  
 
diff --git a/FORMATS b/FORMATS
index 7cddb55..3e64e17 100644
--- a/FORMATS
+++ b/FORMATS
@@ -11,13 +11,16 @@ The split format is:
 
 The "raw" format is:
 
-hostline|pingline|dnsline|timestampline
+hostline|xmitline|pingline|dnsline|timestampline
 
 hostline:
 h <pos> <host IP>
 
+xmitline:
+x <pos> <seqnum>
+
 pingline:
-p <pos> <pingtime (ms)>
+p <pos> <pingtime (ms)> <seqnum>
 
 dnsline: 
 d <pos> <hostname>
@@ -52,7 +55,7 @@ reply. So in the example above, we'd see a reply from router at
 position 4, then we'd send out 5-9 (and because the max-host is now at
 9, we'll send them out at 1s/9 = 111ms intervals). When the reply from
 host 9 comes back, we'll start probing for host 10-15 (at about 60ms
-intervals). But suppose the network delay upto host 9 is already 200ms
+intervals). But suppose the network delay up to host 9 is already 200ms
 and suppose our destination host is at position 11. Then by the time
 the packet from host 11 comes back, we'll already have sent probe
 packets for position 12, 13, and 14! Those will come back as
diff --git a/Makefile.am b/Makefile.am
index ed06db8..fa9a2dd 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -3,7 +3,8 @@ SUBDIRS = img
 sbin_PROGRAMS = mtr
 man_MANS = mtr.8
 install-exec-hook: 
-	chmod u+s $(DESTDIR)$(sbindir)/mtr
+	`setcap cap_net_raw+ep $(DESTDIR)$(sbindir)/mtr` \
+	|| chmod u+s $(DESTDIR)$(sbindir)/mtr
 
 mtr_SOURCES = mtr.c \
               net.c net.h \
diff --git a/NEWS b/NEWS
index 9d27366..27248dc 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,14 @@
 WHAT'S NEW?
 
+In the git-repo we will start adding things here under the next
+version number, even before it's been released. So don't worry
+if  you see a version number here but can't find the release
+files: It hasn't been released. Doing it this way reduces the
+chance for a manual messup if I just "go ahead and release it"
+without any editing here. 
+
+V0.87
+
 V0.86 Fixed default hostname logic. 
       Fix for NetBSD: 64bit time_t -- Thomas Klausner
       Fix unnecessary runtime dependency on glib from VSYakovetsky through 
@@ -58,7 +67,7 @@ Author: R.E. Wolff <R.E.Wolff@BitWizard.nl> (mostly from patches by others)
 
   v0.74 Martin Pels' patch to allow UDP probes.
         KES reported a build problem. Turns out I need to install gtk-1.2
-        on my development sytem, otherwise my release script causes the
+        on my development system, otherwise my release script causes the
         build to break.
         changed some docs to advertise the new mailing list.
         added documentation for the Mac OS X compilation problem.
@@ -66,7 +75,7 @@ Author: R.E. Wolff <R.E.Wolff@BitWizard.nl> (mostly from patches by others)
         Nico Lichtmaier's cleanup-gtk patch. (now mtr uses a more modern
         dialect of gtk).
 
-  v0.73 Some securty patches. Although MTR drops privileges as soon
+  v0.73 Some security patches. Although MTR drops privileges as soon
         as possible after opening the sockets, it still had some
         sprintf calls, which have now been converted into snprintf.
 
@@ -100,7 +109,7 @@ Author: R.E. Wolff <R.E.Wolff@BitWizard.nl> (mostly from patches by others)
         No changes.
 
   v0.66 Through the Debian bugtracking system a bug report and
-        fix was sent my way, that deals with stupid optmization
+        fix was sent my way, that deals with stupid optimization
         trying to save some 768 bytes of memory, sacrificing "it
         works" on a different architecture... (default char signedness)
 
@@ -115,7 +124,7 @@ Author: R.E. Wolff <R.E.Wolff@BitWizard.nl> (mostly from patches by others)
 
   v0.63 Suggestion by RCW: Add -lm at line 70 of Configure.in.
         On my system no ill effects ensued, so this version released
-        so that he can test if it still works on his sytem.
+        so that he can test if it still works on his system.
 
         Let me add that it's stupid that I have to specify that this
         this program now requires Automake version 1.5 to build, where
@@ -146,7 +155,7 @@ Author: R.E. Wolff <R.E.Wolff@BitWizard.nl> (mostly from patches by others)
         rewrite some things. Now 50 lines of code less, but cleaner
         code. :-)
 
-  v0.58 I don't remember. Fogot to update this. :-( Check the
+  v0.58 I don't remember. Forgot to update this. :-( Check the
         patch.
 
   v0.57 Lots of whitespace cleanups. And a DNS fix: Don't do DNS
@@ -180,7 +189,7 @@ Author: R.E. Wolff <R.E.Wolff@BitWizard.nl> (mostly from patches by others)
   v0.48 Draw names in red (GTK) or bold (Curses) if host doesn't
         respond.
 
-  v0.47 Fixed a (believed-) non-exploitable bufferoverflow.
+  v0.47 Fixed a (believed-) non-exploitable buffer overflow.
         Thanks Damian.
 
   v0.46 Included patch to be able to specify outgoing interface
@@ -191,7 +200,7 @@ Author: R.E. Wolff <R.E.Wolff@BitWizard.nl> (mostly from patches by others)
         switching between numeric / dns names, and some minor
         stuff I forgot. This release serves as a code-sync-release.
         new version with even more new stuff in about two weeks!
-        I'm afraid I don't know how to fix the MaxOS-X compilation
+        I'm afraid I don't know how to fix the MacOS-X compilation
         problems in the source. Help wanted...
 
   v0.44 David Stone adds the "last" column to the gtk version.
@@ -333,7 +342,7 @@ people as it didn't contain any recent changes/news.
         + If hop doesn't respond, draw its name in red (GTK) or bold (curses)
 
 2002-02-09  bodq  <bohdan@vstu.edu.ua>
-        + Added --address option to bind to given IP addess
+        + Added --address option to bind to given IP address
 
 2001-04-15  root  <alane@geeksrus.net>
         + Added this file so that automake won't complain.
diff --git a/README b/README
index f2f6538..a927634 100644
--- a/README
+++ b/README
@@ -6,7 +6,7 @@ WHAT IS MTR?
   As mtr starts, it investigates the network connection between the host
   mtr runs on and a user-specified destination host.  After it
   determines the address of each network hop between the machines, 
-  it sends a sequence ICMP ECHO requests to each one to determine the 
+  it sends a sequence of ICMP ECHO requests to each one to determine the 
   quality of the link to each machine.  As it does this, it prints
   running statistics about each machine.
 
@@ -34,9 +34,9 @@ INSTALLING
   Note that mtr must be suid-root because it requires access to raw IP 
   sockets.  See SECURITY for security information.
 
-  Older versions used to require a non-existant path to GTK for a
+  Older versions used to require a non-existent path to GTK for a
   correct build of a non-gtk version while GTK was installed. This is
-  no longer neccesary. ./configure --WITHOUT_GTK should now work. 
+  no longer necessary. ./configure --without-gtk should now work. 
   If it doesn't, try "make WITHOUT_X11=YES" as the make step. 
 
   On Solaris (and possibly other systems) the "gtk" library may be
@@ -47,7 +47,7 @@ INSTALLING
   you're out of luck when you use the sun LD. That's not quite true, as
   you can move the gtk libraries to /usr/lib instead of leaving them in
   /usr/local/lib.  (when the ld tells you that /usr/local/lib is untrusted
-  and /usr/lib is trusted, and you trust hte gtk libs enough to want them
+  and /usr/lib is trusted, and you trust the gtk libs enough to want them
   in a setuid program, then there is something to say for moving them
   to the "trusted" directory.)
 
@@ -76,18 +76,17 @@ WHERE CAN I GET THE LATEST VERSION OR MORE INFORMATION?
   See the mtr web page at 
          http://www.BitWizard.nl/mtr/ 
 
-  There used to be a mailinglist, but all it got was spam. So
-  when the server was upgraded, the mailing list died. 
+  Bug reports and feature requests should be submitted to the Github
+  bug tracking system.
 
-  Bug reports and feature requests should be submitted to the 
-  bug tracker at launchpad: https://launchpad.net/mtr/+bugs
+  Patches can be submitted by cloning the Github repository and issuing
+  a pull request, or by email to me. Please use unified diffs. Usually
+  the diff is sort of messy, so please check that the diff is clean and
+  doesn't contain too much of your local stuff (for example, I don't
+  want/need the "configure" script that /your/ automake made for you).
 
-  Patches can be submitted by Email to me, or submitted to the 
-  bug tracker. Or you can clone the github repository and issue a pull
-  request. Please use unified diffs. Usually the diff is sort of
-  messy, so please check that the diff is clean and doesn't contain too
-  much of your local stuff (for example, I don't want/need the "configure"
-  script that /your/ automake made for you). 
+  (There used to be a mailinglist, but all it got was spam. So
+  when the server was upgraded, the mailing list died.)
 
 -- REW
 
diff --git a/SECURITY b/SECURITY
index 4ff73a9..a91ebac 100644
--- a/SECURITY
+++ b/SECURITY
@@ -1,12 +1,42 @@
 SECURITY ISSUES RELATED TO MTR
 
+mtr requires extra privileges to send custom packets, and there are
+security implications from granting this.
+
+There are several different ways to provide the privileges:
+
+1. Add limited privileges on systems that support this. (Preferred.)
+2. Run mtr as the root user.
+3. Make mtr a setuid-root binary.
+
+Details:
+
+1. Add limited privileges on systems that support this.
+
+Some operating systems allow binaries to be run with only the subset
+of security privileges that are actually needed.
+
+Linux:
+On Linux, privileges are known as capabilities. The only additional
+capability that mtr needs is cap_net_raw. To give this capability
+to the mtr binary, run the following command as root:
+
+# setcap cap_net_raw+ep mtr
+
+
+2. Run mtr as the root user.
+
 You can limit mtr usage to the root user by not putting a setuid bit
 on the mtr binary. In that case, the security implications are
-minimal. 
+minimal.
 
-Or you can make mtr setuid-root, and the following applies to you....
 
-Since mtr is installed as suid-root, some concern over security is
+3. Make mtr a setuid-root binary.
+
+The mtr binary can be made setuid-root, which is what "make install"
+does by default.
+
+When mtr is installed as suid-root, some concern over security is
 justified.  Since version 0.21, mtr does the following two things
 after it is launched:
 
@@ -19,13 +49,13 @@ process.  Note that no code from GTK+ or curses is executed before
 dropping root privileges.
 
 This should severely limit the possibilities of using mtr to breach
-system security.  This means the worst case scenerio is as follows:
+system security.  This means the worst case scenario is as follows:
 
 Due to some oversight in the mtr code, a malicious user is able to
 overrun one of mtr's internal buffers with binary code that is
 eventually executed.  The malicious user is still not able to read
 from or write to any system files which they wouldn't normally have
-permission to read or write to, repectively.  The only privilege
+permission to read or write to, respectively.  The only privilege
 gained is access to the raw socket descriptors, which would allow
 the malicious user to listen to all ICMP packets arriving at the
 system, and to send forged packets with arbitrary contents.
@@ -39,5 +69,6 @@ have mtr-core always run in "raw" mode, and have the backends interpret
 the output from the mtr-core. Maybe a nice project for a college-level
 student.
 
+
 If you have further questions or comments about security issues,
-please direct them to the mtr mailing list.  See README for details.
+please see the README file for details on how to submit them.
diff --git a/asn.c b/asn.c
index 33622ca..62880dc 100644
--- a/asn.c
+++ b/asn.c
@@ -60,7 +60,7 @@ char fmtinfo[32];
 extern int af;                  /* address family of remote target */
 
 // items width: ASN, Route, Country, Registry, Allocated 
-int iiwidth[] = { 6, 19, 4, 8, 11};	// item len + space
+int iiwidth[] = { 7, 19, 4, 8, 11};	// item len + space
 int iiwidth_len = sizeof(iiwidth)/sizeof((iiwidth)[0]);
 
 typedef char* items_t[ITEMSMAX + 1];
@@ -173,15 +173,19 @@ char* split_txtrec(char *txtrec) {
         }
     }
 
-    char* prev = (*items)[0] = trimsep(txtrec);
+    char* prev = txtrec;
     char* next;
     int i = 0, j;
 
     while ((next = strchr(prev, ITEMSEP)) && (i < ITEMSMAX)) {
-        *next++ = '\0';
-        (*items)[i++] = trimsep(prev);
-        (*items)[i] = prev = trimsep(next);
+        *next = '\0';
+        next++;
+        (*items)[i] = trimsep(prev);
+        prev = next;
+        i++;
     }
+    (*items)[i] = trimsep(prev);
+
     if (i < ITEMSMAX)
         i++;
     for (j = i;  j <= ITEMSMAX; j++)
diff --git a/asn.h b/asn.h
index dd2d440..6566a2e 100644
--- a/asn.h
+++ b/asn.h
@@ -18,15 +18,16 @@
 
 // The autoconf system provides us with the NO_IPINFO define. 
 // Littering the code with #ifndef NO_IPINFO (double negative)
-// does not benefit readabilty. So here we invert the sense of the
+// does not benefit readability. So here we invert the sense of the
 // define. 
 //
-// Similarly, this include file should be included unconditially. 
+// Similarly, this include file should be included unconditionally. 
 // It will evaluate to nothing if we don't need it. 
 
 #ifndef NO_IPINFO
-#define IPINFO
 
+#ifndef IPINFO
+#define IPINFO
 
 extern int ipinfo_no;
 extern int ipinfo_max;
@@ -38,4 +39,5 @@ char *fmt_ipinfo(ip_t *addr);
 int get_iiwidth(void);
 int is_printii(void);
 
-#endif
+#endif /* IPINFO */
+#endif /* NO_IPINFO */
diff --git a/configure.ac b/configure.ac
index d5d1b0e..ab0ae84 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
-AC_INIT([mtr], [0.86])
+AC_INIT([mtr], [0.87])
 AC_CONFIG_SRCDIR([mtr.c])
 AM_INIT_AUTOMAKE([foreign])
 
@@ -20,19 +20,13 @@ AC_CHECK_SIZEOF(unsigned long, 4)
 AC_CHECK_HEADERS(ncurses.h ncurses/curses.h curses.h cursesX.h sys/types.h fcntl.h)
 AC_CHECK_HEADERS(socket.h sys/socket.h sys/xti.h arpa/nameser_compat.h)
 
-# We don't refer to any symbols in termcap, but -lcurses on SunOS does.
-# We have to trust the linker not to mess things up... (It should not
-# pull in anything if we don't refer to anything in the lib). 
-AC_CHECK_LIB(termcap, tgetent)
-AC_CHECK_LIB(tinfo, tgetent)
-
-AC_CHECK_FUNC(initscr, , 
-  AC_CHECK_LIB(ncurses, initscr, , 
-    AC_CHECK_LIB(curses, initscr, , 
-      AC_CHECK_LIB(cursesX, initscr, , 
-	AC_MSG_WARN(Building without curses display support)
-	AC_DEFINE(NO_CURSES, 1, Define if you don't have the curses libraries available.)
-	CURSES_OBJ=))))
+AC_SEARCH_LIBS(initscr, [ncurses curses cursesX], ,
+  AC_MSG_WARN(Building without curses display support)
+  AC_DEFINE(NO_CURSES, 1, [Define if you don't have the curses libraries available.])
+  CURSES_OBJ=)
+
+AC_CHECK_LIB(ncurses, use_default_colors, 
+  AC_DEFINE(HAVE_USE_DEFAULT_COLORS, 1, [Define this if your curses library has the use_default_colors() command.]))
 
 AC_CHECK_FUNCS(attron fcntl)
 
diff --git a/curses.c b/curses.c
index 3904cb1..e60fba0 100644
--- a/curses.c
+++ b/curses.c
@@ -26,7 +26,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-/* MacOSX may need this before scoket.h...*/
+/* MacOSX may need this before socket.h...*/
 #if defined(HAVE_SYS_TYPES_H)
 #include <sys/types.h>
 #else
@@ -700,10 +700,15 @@ void mtr_curses_open(void)
   initscr();
   raw();
   noecho(); 
+  int bg_col = 0;
   start_color();
+#ifdef HAVE_USE_DEFAULT_COLORS
+  if (use_default_colors() == OK)
+    bg_col = -1;
+#endif
   int i;
   for (i = 0; i < 8; i++)
-      init_pair(i+1, i, 0);
+      init_pair(i+1, i, bg_col);
 
   mtr_curses_init();
   mtr_curses_redraw();
diff --git a/display.c b/display.c
index 3545467..584c7a0 100644
--- a/display.c
+++ b/display.c
@@ -38,7 +38,7 @@ extern int DisplayMode;
 #define mtr_curses_open()
 #define mtr_curses_close()
 #define mtr_curses_redraw()
-#define mtr_curses_keyaction()
+#define mtr_curses_keyaction() 0
 #define mtr_curses_clear()
 #else
 #include "mtr-curses.h"
@@ -88,6 +88,9 @@ void display_open(void)
   case DisplayTXT:
     txt_open();
     break;
+  case DisplayJSON:
+    json_open();
+    break;
   case DisplayXML:
     xml_open();
     break;
@@ -106,6 +109,10 @@ void display_open(void)
     break;
   case DisplayGTK:
     gtk_open();
+#ifdef IPINFO
+    if (ipinfo_no >= 0)
+        asn_open();
+#endif
     break;
   }
 }
@@ -120,6 +127,9 @@ void display_close(time_t now)
   case DisplayTXT:
     txt_close();
     break;
+  case DisplayJSON:
+    json_close();
+    break;
   case DisplayXML:
     xml_close();
     break;
@@ -178,11 +188,22 @@ int display_keyaction(void)
 }
 
 
-void display_rawping(int host, int msec) 
+void display_rawxmit(int host, int seq)
+{
+  switch(DisplayMode) {
+  case DisplayRaw:
+    raw_rawxmit (host, seq);
+    break;
+  }
+}
+
+
+void display_rawping(int host, int msec, int seq)
 {
   switch(DisplayMode) {
   case DisplayReport:
   case DisplayTXT:
+  case DisplayJSON:
   case DisplayXML:
   case DisplayCSV:
   case DisplaySplit:
@@ -190,7 +211,7 @@ void display_rawping(int host, int msec)
   case DisplayGTK:
     break;
   case DisplayRaw:
-    raw_rawping (host, msec);
+    raw_rawping (host, msec, seq);
     break;
   }
 }
@@ -201,6 +222,7 @@ void display_rawhost(int host, ip_t *ip_addr)
   switch(DisplayMode) {
   case DisplayReport:
   case DisplayTXT:
+  case DisplayJSON:
   case DisplayXML:
   case DisplayCSV:
   case DisplaySplit:
@@ -219,6 +241,7 @@ void display_loop(void)
   switch(DisplayMode) {
   case DisplayReport:
   case DisplayTXT:
+  case DisplayJSON:
   case DisplayXML:
   case DisplayCSV:
   case DisplaySplit:
@@ -241,6 +264,7 @@ void display_clear(void)
     break;
   case DisplayReport:
   case DisplayTXT:
+  case DisplayJSON:
   case DisplayXML:
   case DisplayCSV:
   case DisplaySplit:
diff --git a/display.h b/display.h
index 6168914..294f618 100644
--- a/display.h
+++ b/display.h
@@ -27,14 +27,15 @@ enum { ActionNone,  ActionQuit,  ActionReset,  ActionDisplay,
 #endif
        ActionScrollDown, ActionScrollUp  };
 enum { DisplayReport, DisplayCurses, DisplayGTK, DisplaySplit, 
-       DisplayRaw,    DisplayXML,    DisplayCSV, DisplayTXT};
+       DisplayRaw,    DisplayXML,    DisplayCSV, DisplayTXT, DisplayJSON};
 
 /*  Prototypes for display.c  */
 void display_detect(int *argc, char ***argv);
 void display_open(void);
 void display_close(time_t now);
 void display_redraw(void);
-void display_rawping(int hostnum, int msec);
+void display_rawxmit(int hostnum, int seq);
+void display_rawping(int hostnum, int msec, int seq);
 void display_rawhost(int hostnum, ip_t *ip_addr);
 int display_keyaction(void);
 void display_loop(void);
diff --git a/dns.c b/dns.c
index 32b83c2..3e7cf4d 100644
--- a/dns.c
+++ b/dns.c
@@ -194,7 +194,7 @@ typedef struct {
    byte databyte_a;
       /* rd:1           recursion desired
        * tc:1           truncated message
-       * aa:1           authoritive answer
+       * aa:1           authoritative answer
        * opcode:4       purpose of message
        * qr:1           response flag
        */
@@ -527,14 +527,9 @@ void dns_open(void)
   }
 #ifdef ENABLE_IPV6
   resfd6 = socket(AF_INET6, SOCK_DGRAM, 0);
-  if (resfd6 == -1) {
-    // consider making removing this warning. For now leave it in to see 
-    // new code activated. -- REW
-    fprintf(stderr,
-            "Unable to allocate IPv6 socket for nameserver communication: %s\n",
-	    strerror(errno));
-    //    exit(-1);
-  }
+  // If this fails, e.g. because the user has runtime-disabled IPV6, 
+  // the error can be ignored: the resfd6 is only used if it is 
+  // not the error return code. -- REW
 #endif
   option = 1;
   if (setsockopt(resfd,SOL_SOCKET,SO_BROADCAST,(char *)&option,sizeof(option))) {
@@ -1148,7 +1143,7 @@ void parserespacket(byte *s, int l)
       }
       for (rr = hp->ancount + hp->nscount + hp->arcount;rr;rr--) {
 	if (c > eob) {
-	  restell("Resolver error: Packet does not contain all specified resouce records.");
+	  restell("Resolver error: Packet does not contain all specified resource records.");
 	  return;
 	}
 	*namestring = '\0';
diff --git a/gtk.c b/gtk.c
index 7faa132..39f4c6e 100644
--- a/gtk.c
+++ b/gtk.c
@@ -33,6 +33,7 @@
 #include "mtr.h"
 #include "net.h"
 #include "dns.h"
+#include "asn.h"
 #include "mtr-gtk.h"
 #include "version.h"
 
@@ -50,17 +51,19 @@ gchar* getSelectedHost(GtkTreePath *path);
 extern char *Hostname;
 extern float WaitTime;
 extern int af;
-static int tag;
+static int ping_timeout_timer;
 static GtkWidget *Pause_Button;
 static GtkWidget *Entry;
 static GtkWidget *main_window;
 
 void gtk_add_ping_timeout (void)
 {
+  if(gtk_toggle_button_get_active((GtkToggleButton *)Pause_Button)){
+    return;
+  }
   int dt;
-
   dt = calc_deltatime (WaitTime);
-  tag = g_timeout_add(dt / 1000, gtk_ping, NULL);
+  ping_timeout_timer = g_timeout_add(dt / 1000, gtk_ping, NULL);
 }
 
 
@@ -113,7 +116,7 @@ gint Pause_clicked(UNUSED GtkWidget *Button, UNUSED gpointer data)
   if (paused) {
     gtk_add_ping_timeout ();
   } else {
-    g_source_remove (tag);
+    g_source_remove (ping_timeout_timer);
   }
   paused = ! paused;
   gtk_redraw();
@@ -138,7 +141,7 @@ gint About_clicked(UNUSED GtkWidget *Button, UNUSED gpointer data)
         "Mike Simons <msimons@moria.simons-clan.com>",
         "Aaron Scarisbrick,",
         "Craig Milo Rogers <Rogers@ISI.EDU>",
-        "Antonio Querubin <tony@aloha.net>",
+        "Antonio Querubin <tony@lavanauts.org>",
         "Russell Nelson <rn-mtr@crynwr.com>",
         "Davin Milun <milun@acm.org>",
         "Josh Martin <jmartin@columbiaservices.net>",
@@ -199,7 +202,7 @@ gint About_clicked(UNUSED GtkWidget *Button, UNUSED gpointer data)
 gint WaitTime_changed(UNUSED GtkAdjustment *Adj, UNUSED GtkWidget *Button) 
 {
   WaitTime = gtk_spin_button_get_value(GTK_SPIN_BUTTON(Button));
-  g_source_remove (tag);
+  g_source_remove (ping_timeout_timer);
   gtk_add_ping_timeout ();
   gtk_redraw();
 
@@ -292,6 +295,9 @@ static GtkWidget *ReportTreeView;
 static GtkListStore *ReportStore;
 
 enum {
+#ifdef IPINFO
+  COL_ASN,
+#endif
   COL_HOSTNAME,
   COL_LOSS,
   COL_RCV,
@@ -345,6 +351,9 @@ void TreeViewCreate(void)
   GtkTreeViewColumn *column;
 
   ReportStore = gtk_list_store_new(N_COLS,
+#ifdef IPINFO
+    G_TYPE_STRING,
+#endif
     G_TYPE_STRING,
     G_TYPE_FLOAT,
     G_TYPE_INT,
@@ -361,7 +370,20 @@ void TreeViewCreate(void)
   
   g_signal_connect(GTK_OBJECT(ReportTreeView), "button_press_event", 
   		    G_CALLBACK(ReportTreeView_clicked),NULL);
-  
+
+#ifdef IPINFO
+  if (is_printii()) {
+    renderer = gtk_cell_renderer_text_new ();
+    column = gtk_tree_view_column_new_with_attributes ("ASN",
+      renderer,
+      "text", COL_ASN,
+      "foreground", COL_COLOR,
+      NULL);
+    gtk_tree_view_column_set_resizable(column, TRUE);
+    gtk_tree_view_append_column (GTK_TREE_VIEW(ReportTreeView), column);
+  }
+#endif
+
   renderer = gtk_cell_renderer_text_new ();
   column = gtk_tree_view_column_new_with_attributes ("Hostname",
     renderer,
@@ -387,7 +409,7 @@ void TreeViewCreate(void)
   g_object_set (G_OBJECT(renderer), "xalign", 1.0, NULL);
   column = gtk_tree_view_column_new_with_attributes ("Snt",
     renderer,
-    "text", 3,
+    "text", COL_SNT,
     "foreground", COL_COLOR,
     NULL);
   gtk_tree_view_column_set_resizable(column, TRUE);
@@ -397,7 +419,7 @@ void TreeViewCreate(void)
   g_object_set (G_OBJECT(renderer), "xalign", 1.0, NULL);
   column = gtk_tree_view_column_new_with_attributes ("Last",
     renderer,
-    "text", 4,
+    "text", COL_LAST,
     "foreground", COL_COLOR,
     NULL);
   gtk_tree_view_column_set_resizable(column, TRUE);
@@ -407,7 +429,7 @@ void TreeViewCreate(void)
   g_object_set (G_OBJECT(renderer), "xalign", 1.0, NULL);
   column = gtk_tree_view_column_new_with_attributes ("Avg",
     renderer,
-    "text", 6,
+    "text", COL_AVG,
     "foreground", COL_COLOR,
     NULL);
   gtk_tree_view_column_set_resizable(column, TRUE);
@@ -417,7 +439,7 @@ void TreeViewCreate(void)
   g_object_set (G_OBJECT(renderer), "xalign", 1.0, NULL);
   column = gtk_tree_view_column_new_with_attributes ("Best",
     renderer,
-    "text", 5,
+    "text", COL_BEST,
     "foreground", COL_COLOR,
     NULL);
   gtk_tree_view_column_set_resizable(column, TRUE);
@@ -427,7 +449,7 @@ void TreeViewCreate(void)
   g_object_set (G_OBJECT(renderer), "xalign", 1.0, NULL);
   column = gtk_tree_view_column_new_with_attributes ("Worst",
     renderer,
-    "text", 7,
+    "text", COL_WORST,
     "foreground", COL_COLOR,
     NULL);
   gtk_tree_view_column_set_resizable(column, TRUE);
@@ -437,7 +459,7 @@ void TreeViewCreate(void)
   g_object_set (G_OBJECT(renderer), "xalign", 1.0, NULL);
   column = gtk_tree_view_column_new_with_attributes ("StDev",
     renderer,
-    "text", 8,
+    "text", COL_STDEV,
     "foreground", COL_COLOR,
     NULL);
   gtk_tree_view_column_set_resizable(column, TRUE);
@@ -477,6 +499,10 @@ void update_tree_row(int row, GtkTreeIter *iter)
     COL_COLOR, net_up(row) ? "black" : "red",
 
     -1);
+#ifdef IPINFO
+  if (is_printii())
+    gtk_list_store_set(ReportStore, iter, COL_ASN, fmt_ipinfo(addr), -1);
+#endif
 }
 
 void gtk_redraw(void)
@@ -577,7 +603,7 @@ gint gtk_ping(UNUSED gpointer data)
   gtk_redraw();
   net_send_batch();
   net_harvest_fds();
-  g_source_remove (tag);
+  g_source_remove (ping_timeout_timer);
   gtk_add_ping_timeout ();
   return TRUE;
 }
diff --git a/mtr.8 b/mtr.8
index 16770c5..8e41b8c 100644
--- a/mtr.8
+++ b/mtr.8
@@ -26,12 +26,18 @@ mtr \- a network diagnostic tool
 .B \-\-curses\c
 ]
 [\c
+.BI \--displaymode \ MODE\c
+]
+[\c
 .B \-\-raw\c
 ]
 [\c
 .B \-\-csv\c
 ]
 [\c
+.B \-\-json\c
+]
+[\c
 .B \-\-split\c
 ]
 [\c
@@ -62,6 +68,9 @@ mtr \- a network diagnostic tool
 .BI \-B \ BITPATTERN\c
 ]
 [\c
+.BI \-G \ GRACEPERIOD\c
+]
+[\c
 .BI \-Q \ TOS\c
 ]
 [\c
@@ -77,6 +86,9 @@ mtr \- a network diagnostic tool
 .BI \-m \ MAX\-TTL\c
 ]
 [\c
+.BI \-U \ MAX\-UNKNOWN\c
+]
+[\c
 .B \-\-udp\c
 ]
 [\c
@@ -86,6 +98,9 @@ mtr \- a network diagnostic tool
 .BI \-P \ PORT\c
 ]
 [\c
+.BI \-L \ LOCALPORT\c
+]
+[\c
 .BI \-Z \ TIMEOUT\c
 ]
 [\c
@@ -116,7 +131,7 @@ route to
 A sudden increase in packet loss or response time is often an indication
 of a bad (or simply overloaded) link. 
 .PP
-The results are usually reported as round-trip-response times in miliseconds 
+The results are usually reported as round-trip-response times in milliseconds
 and the percentage of packetloss. 
 .SH OPTIONS
 .TP
@@ -130,10 +145,10 @@ Print the installed version of mtr.
 Use IPv4 only.
 .TP
 .B \-6
-Use IPv6 only.  (IPV4 may be used for DNS lookups). 
+Use IPv6 only.  (IPV4 may be used for DNS lookups.)
 .TP
 .B \-F \fIFILENAME\fR, \fB\-\-filename \fIFILENAME
-MISSING
+Reads the list of hostnames from the specified file.
 .TP
 .B \-r\fR, \fB\-\-report
 This option puts 
@@ -176,6 +191,12 @@ Use this option to force
 to use the curses based terminal
 interface (if available).
 .TP
+.B -\-displaymode \fIMODE
+Use this option to select the initial display mode: 0 (default)
+selects statistics, 1 selects the stripchart without latency
+information, and 2 selects the stripchart with latency
+information.
+.TP
 .B \-g\fR, \fB\-\-gtk
 Use this option to force
 .B mtr 
@@ -187,14 +208,48 @@ was built for this to work.  See the GTK+ web page at
 for more information about GTK+.
 .TP
 .B \-l\fR, \fB\-\-raw
-Use this option to tell
-.B mtr
-to use the raw output format.  This format is better suited for
+Use the raw output format.  This format is better suited for
 archival of the measurement results.  It could be parsed to 
 be presented into any of the other display methods. 
+.IP
+Example of the raw output format:
+.nf
+h 0 10.1.1.1
+p 0 339
+h 1 46.149.16.4
+p 1 530
+h 2 172.31.1.16
+p 2 531
+h 3 82.221.168.236
+p 3 1523
+h 5 195.130.211.8
+p 5 1603
+h 6 193.4.58.17
+p 6 1127
+h 7 193.4.58.17
+d 7 www.isnic.is
+.fi
 .TP
 .B \-C\fR, \fB\-\-csv
-MISSING
+Use the Comma-Separated-Value (CSV) output format.
+(Note: The separator is actually a semi-colon ';'.)
+.IP
+Example of the CSV output format:
+.nf
+MTR.0.86+git:16e39fc0;1435562787;OK;nic.is;1;r-76520-PROD.greenqloud.internal;288
+MTR.0.86+git:16e39fc0;1435562787;OK;nic.is;2;46.149.16.4;2086
+MTR.0.86+git:16e39fc0;1435562787;OK;nic.is;3;172.31.1.16;600
+MTR.0.86+git:16e39fc0;1435562787;OK;nic.is;4;82.221.168.236;1163
+MTR.0.86+git:16e39fc0;1435562787;OK;nic.is;5;???;0
+MTR.0.86+git:16e39fc0;1435562787;OK;nic.is;6;rix-k2-gw.isnic.is;1654
+MTR.0.86+git:16e39fc0;1435562787;OK;nic.is;7;www.isnic.is;1036
+.fi
+.TP
+.B \-j\fR, \fB\-\-json
+Use this option to tell
+.B mtr
+to use the JSON output format.  This format is better suited for
+automated processing of the measurement results.
 .TP
 .B \-p\fR, \fB\-\-split
 Use this option to set
@@ -244,10 +299,33 @@ Example:
 -o "LSD NBAW  X"
 .TP
 .B \-y \fIn\fR, \fB\-\-ipinfo \fIn
-MISSING
+Displays information about each IP hop.  Valid values for \fIn\fR are:
+.TS
+tab(%);
+ll.
+0%Display AS number (equivalent to \fB-z\fR)
+1%Display IP prefix
+2%Display country code of the origin AS
+3%Display RIR (ripencc, arin, ...)
+4%Display the allocation date of the IP prefix
+.TE
+.br
+
+It is possible to cycle between these fields at runtime (using the \fBy\fR key).
 .TP
 .B \-z\fR, \fB\-\-aslookup
-MISSING
+Displays the Autonomous System (AS) number alongside each hop.  Equivalent to \fB\-\-ipinfo 0\fR.
+.IP
+Example (columns to the right not shown for clarity):
+.nf
+1. AS???   r-76520-PROD.greenqloud.internal
+2. AS51969 46.149.16.4
+3. AS???   172.31.1.16
+4. AS30818 82.221.168.236
+5. ???
+6. AS???   rix-k2-gw.isnic.is
+7. AS1850  www.isnic.is
+.fi
 .TP
 .B \-i \fISECONDS\fR, \fB\-\-interval \fISECONDS
 Use this option to specify the positive number of seconds between ICMP
@@ -271,6 +349,10 @@ Specifies bit pattern to use in payload.  Should be within range 0 - 255.  If
 .I NUM
 is greater than 255, a random pattern is used.
 .TP
+.B \-G \fISECONDS\fR, \fB\-\-graceperiod \fISECONDS
+Use this option to specify the positive number of seconds to wait for responses
+after the final request. The default value is five seconds.
+.TP
 .B \-Q \fINUM\fR, \fB\-\-tos \fINUM
 Specifies value for type of service field in IP header.  Should be within range 0
 - 255.
@@ -296,6 +378,9 @@ Specifies with what TTL to start.  Defaults to 1.
 Specifies the maximum number of hops (max time-to-live value) traceroute will
 probe.  Default is 30.
 .TP
+.B \-U \fINUM\fR, \fB\-\-max-unknown \fINUM
+Specifies the maximum unknown host. Default is 5.
+.TP
 .B \-u\fR, \fB\-\-udp
 Use UDP datagrams instead of ICMP ECHO.
 .TP
@@ -305,7 +390,10 @@ Use TCP SYN packets instead of ICMP ECHO.
 is ignored, since SYN packets can not contain data.
 .TP
 .B \-P \fIPORT\fR, \fB\-\-port \fIPORT
-The target port number for TCP traces.
+The target port number for TCP/SCTP/UDP traces.
+.TP
+.B \-L \fILOCALPORT\fR, \fB\-\-localport \fILOCALPORT
+The source port number for UDP traces.
 .TP
 .B \-Z \fISECONDS\fR, \fB\-\-timeout \fISECONDS
 The number of seconds to keep the TCP socket open before giving up on
@@ -324,7 +412,7 @@ This environment variable allows to specify options, as if they were
 passed on the command line.  It is parsed before reading the actual
 command line options, so that options specified in
 .B MTR_OPTIONS
-are overriden by command-line options.
+are overridden by command-line options.
 
 Example:
 
@@ -365,5 +453,5 @@ GitHub at:
 .BR https://github.com/traviscross/mtr .
 .SH "SEE ALSO"
 traceroute(8),
-ping(8)
+ping(8),
 TCP/IP Illustrated (Stevens, ISBN 0201633469).
diff --git a/mtr.c b/mtr.c
index 417caf6..d748412 100644
--- a/mtr.c
+++ b/mtr.c
@@ -67,6 +67,7 @@ int   PrintHelp = 0;
 int   MaxPing = 10;
 int   ForceMaxPing = 0;
 float WaitTime = 1.0;
+float GraceTime = 5.0;
 char *Hostname = NULL;
 char *InterfaceAddress = NULL;
 char  LocalHostname[128];
@@ -88,8 +89,11 @@ int  fstTTL = 1;                /* default start at first hop */
 /*int maxTTL = MaxHost-1;  */     /* max you can go is 255 hops */
 int   maxTTL = 30;              /* inline with traceroute */
                                 /* end ttl window stuff. */
-int remoteport = 80;            /* for TCP tracing */
-int timeout = 10 * 1000000;     /* for TCP tracing */
+int maxUnknown = 5;				/* stop send package */
+                                /*when larger than this count */
+int remoteport = 0;            /* for TCP tracing */
+int localport = 0;             /* for UDP tracing */
+int tcp_timeout = 10 * 1000000;     /* for TCP tracing */
 
 
 /* default display field(defined by key in net.h) and order */
@@ -258,54 +262,61 @@ void parse_arg (int argc, char **argv)
   int opt;
   int i;
   /* IMPORTANT: when adding or modifying an option:
-       1/ mind the order of options, there is some logic;
-       2/ update the getopt_long call below;
+       0/ try to find a somewhat logical order;
+       1/ add the long option name in "long_options" below;
+       2/ add the short option name in the "getopt_long" call;
        3/ update the man page (use the same order);
-       4/ update the help message showed when using --help.
+       4/ update the help message (see PrintHelp).
    */
   static struct option long_options[] = {
-    { "help", 0, 0, 'h' },
-    { "version", 0, 0, 'v' },
-
-    { "inet", 0, 0, '4' },	/* IPv4 only */
-    { "inet6", 0, 0, '6' },	/* IPv6 only */
-
-    { "filename", 1, 0, 'F' },
-
-    { "report", 0, 0, 'r' },
-    { "report-wide", 0, 0, 'w' },
-    { "xml", 0, 0, 'x' },
-    { "curses", 0, 0, 't' },
-    { "gtk", 0, 0, 'g' },
-    { "raw", 0, 0, 'l' },
-    { "csv", 0, 0, 'C' },
-    { "split", 0, 0, 'p' },     /* BL */
-    				/* maybe above should change to -d 'x' */
-
-    { "no-dns", 0, 0, 'n' },
-    { "show-ips", 0, 0, 'b' },
-    { "order", 1, 0, 'o' },	/* fields to display & their order */
+    /* option name, has argument, NULL, short name */
+    { "help",           0, NULL, 'h' },
+    { "version",        0, NULL, 'v' },
+
+    { "inet",           0, NULL, '4' }, /* IPv4 only */
+    { "inet6",          0, NULL, '6' }, /* IPv6 only */
+
+    { "filename",       1, NULL, 'F' },
+
+    { "report",         0, NULL, 'r' },
+    { "report-wide",    0, NULL, 'w' },
+    { "xml",            0, NULL, 'x' },
+    { "curses",         0, NULL, 't' },
+    { "gtk",            0, NULL, 'g' },
+    { "raw",            0, NULL, 'l' },
+    { "csv",            0, NULL, 'C' },
+    { "json",           0, NULL, 'j' },
+    { "displaymode",    1, NULL, 'd' },
+    { "split",          0, NULL, 'p' }, /* BL */
+                                        /* maybe above should change to -d 'x' */
+
+    { "no-dns",         0, NULL, 'n' },
+    { "show-ips",       0, NULL, 'b' },
+    { "order",          1, NULL, 'o' }, /* fields to display & their order */
 #ifdef IPINFO
-    { "ipinfo", 1, 0, 'y' },    /* IP info lookup */
-    { "aslookup", 0, 0, 'z' },  /* Do AS lookup (--ipinfo 0) */
+    { "ipinfo",         1, NULL, 'y' }, /* IP info lookup */
+    { "aslookup",       0, NULL, 'z' }, /* Do AS lookup (--ipinfo 0) */
 #endif
 
-    { "interval", 1, 0, 'i' },
-    { "report-cycles", 1, 0, 'c' },
-    { "psize", 1, 0, 's' },	/* changed 'p' to 's' to match ping option
-				   overload psize<0, ->rand(min,max) */
-    { "bitpattern", 1, 0, 'B' },/* overload b>255, ->rand(0,255) */
-    { "tos", 1, 0, 'Q' },	/* typeof service (0,255) */
-    { "mpls", 0, 0, 'e' },
-    { "address", 1, 0, 'a' },
-    { "first-ttl", 1, 0, 'f' },	/* -f & -m are borrowed from traceroute */
-    { "max-ttl", 1, 0, 'm' },
-    { "udp", 0, 0, 'u' },	/* UDP (default is ICMP) */
-    { "tcp", 0, 0, 'T' },	/* TCP (default is ICMP) */
-    { "port", 1, 0, 'P' },      /* target port number for TCP */
-    { "timeout", 1, 0, 'Z' },   /* timeout for TCP sockets */
+    { "interval",       1, NULL, 'i' },
+    { "report-cycles",  1, NULL, 'c' },
+    { "psize",          1, NULL, 's' }, /* overload psize<0, ->rand(min,max) */
+    { "bitpattern",     1, NULL, 'B' }, /* overload B>255, ->rand(0,255) */
+    { "tos",            1, NULL, 'Q' }, /* typeof service (0,255) */
+    { "mpls",           0, NULL, 'e' },
+    { "address",        1, NULL, 'a' },
+    { "first-ttl",      1, NULL, 'f' }, /* -f & -m are borrowed from traceroute */
+    { "max-ttl",        1, NULL, 'm' },
+	{ "max-unknown",    1, NULL, 'U' },
+    { "udp",            0, NULL, 'u' }, /* UDP (default is ICMP) */
+    { "tcp",            0, NULL, 'T' }, /* TCP (default is ICMP) */
+    { "sctp",           0, NULL, 'S' }, /* SCTP (default is ICMP) */
+    { "port",           1, NULL, 'P' }, /* target port number for TCP/SCTP/UDP */
+    { "localport",      1, NULL, 'L' }, /* source port number for UDP */
+    { "timeout",        1, NULL, 'Z' }, /* timeout for TCP sockets */
+    { "gracetime",      1, NULL, 'G' }, /* graceperiod for replies after last probe */
 #ifdef SO_MARK
-    { "mark", 1, 0, 'M' },      /* use SO_MARK */
+    { "mark",           1, NULL, 'M' }, /* use SO_MARK */
 #endif
     { 0, 0, 0, 0 }
   };
@@ -313,7 +324,7 @@ void parse_arg (int argc, char **argv)
   opt = 0;
   while(1) {
     opt = getopt_long(argc, argv,
-		      "hv46F:rwxtglCpnbo:y:zi:c:s:B:Q:ea:f:m:uTP:Z:M:", long_options, NULL);
+		      "hv46F:rwxtglCjpnbo:y:zi:c:s:B:Q:ea:f:m:U:uTSP:L:Z:G:M:", long_options, NULL);
     if(opt == -1)
       break;
 
@@ -347,10 +358,16 @@ void parse_arg (int argc, char **argv)
     case 'C':
       DisplayMode = DisplayCSV;
       break;
+    case 'j':
+      DisplayMode = DisplayJSON;
+      break;
     case 'x':
       DisplayMode = DisplayXML;
       break;
 
+    case 'd':
+      display_mode = (atoi (optarg)) % 3;
+      break;
     case 'c':
       MaxPing = atoi (optarg);
       ForceMaxPing = 1;
@@ -402,6 +419,12 @@ void parse_arg (int argc, char **argv)
 	fstTTL = maxTTL;
       }
       break;
+	case 'U':
+		maxUnknown = atoi(optarg);
+		if (maxUnknown < 1) {
+			maxUnknown = 1;
+		}
+		break;
     case 'o':
       /* Check option before passing it on to fld_active. */
       if (strlen (optarg) > MAXFLD) {
@@ -421,6 +444,13 @@ void parse_arg (int argc, char **argv)
       if (bitpattern > 255)
 	bitpattern = -1;
       break;
+    case 'G':
+      GraceTime = atof (optarg);
+      if (GraceTime <= 0.0) {
+        fprintf (stderr, "mtr: wait time must be positive\n");
+        exit (1);
+      }
+      break;
     case 'Q':
       tos = atoi (optarg);
       if (tos > 255 || tos < 0) {
@@ -431,18 +461,30 @@ void parse_arg (int argc, char **argv)
       break;
     case 'u':
       if (mtrtype != IPPROTO_ICMP) {
-        fprintf(stderr, "-u and -T are mutually exclusive.\n");
+        fprintf(stderr, "-u , -T and -S are mutually exclusive.\n");
         exit(EXIT_FAILURE);
       }
       mtrtype = IPPROTO_UDP;
       break;
     case 'T':
       if (mtrtype != IPPROTO_ICMP) {
-        fprintf(stderr, "-u and -T are mutually exclusive.\n");
+        fprintf(stderr, "-u , -T and -S are mutually exclusive.\n");
         exit(EXIT_FAILURE);
       }
+      if (!remoteport) {
+        remoteport = 80;
+      }
       mtrtype = IPPROTO_TCP;
       break;
+    case 'S':
+      if (mtrtype != IPPROTO_ICMP) {
+        fprintf(stderr, "-u , -T and -S are mutually exclusive.\n");
+        exit(EXIT_FAILURE);
+      }
+      if (!remoteport) {
+        remoteport = 80;
+      }
+      mtrtype = IPPROTO_SCTP;
     case 'b':
       show_ips = 1;
       break;
@@ -453,9 +495,16 @@ void parse_arg (int argc, char **argv)
         exit(EXIT_FAILURE);
       }
       break;
+    case 'L':
+      localport = atoi(optarg);
+      if (localport > 65535 || localport < MinPort) {
+        fprintf(stderr, "Illegal local port number.\n");
+        exit(EXIT_FAILURE);
+      }
+      break;
     case 'Z':
-      timeout = atoi(optarg);
-      timeout *= 1000000;
+      tcp_timeout = atoi(optarg);
+      tcp_timeout *= 1000000;
       break;
     case '4':
       af = AF_INET;
@@ -501,6 +550,7 @@ void parse_arg (int argc, char **argv)
 
   if (DisplayMode == DisplayReport ||
       DisplayMode == DisplayTXT ||
+      DisplayMode == DisplayJSON ||
       DisplayMode == DisplayXML ||
       DisplayMode == DisplayRaw ||
       DisplayMode == DisplayCSV)
@@ -571,6 +621,7 @@ int main(int argc, char **argv)
   srand (getpid());
 
   display_detect(&argc, &argv);
+  display_mode = 0;
 
   /* The field options are now in a static array all together,
      but that requires a run-time initialization. */
@@ -598,14 +649,14 @@ int main(int argc, char **argv)
 
   if (PrintHelp) {
        printf("usage: %s [--help] [--version] [-4|-6] [-F FILENAME]\n"
-              "\t\t[--report] [--report-wide]\n"
-              "\t\t[--xml] [--gtk] [--curses] [--raw] [--csv] [--split]\n"
+              "\t\t[--report] [--report-wide] [--displaymode MODE]\n"
+              "\t\t[--xml] [--gtk] [--curses] [--raw] [--csv] [--json] [--split]\n"
               "\t\t[--no-dns] [--show-ips] [-o FIELDS] [-y IPINFO] [--aslookup]\n"
               "\t\t[-i INTERVAL] [-c COUNT] [-s PACKETSIZE] [-B BITPATTERN]\n"
               "\t\t[-Q TOS] [--mpls]\n"
-              "\t\t[-a ADDRESS] [-f FIRST-TTL] [-m MAX-TTL]\n"
-              "\t\t[--udp] [--tcp] [-P PORT] [-Z TIMEOUT]\n"
-              "\t\t[-M MARK] HOSTNAME\n", argv[0]);
+              "\t\t[-a ADDRESS] [-f FIRST-TTL] [-m MAX-TTL] [-U MAX_UNKNOWN]\n"
+              "\t\t[--udp] [--tcp] [--sctp] [-P PORT] [-L LOCALPORT] [-Z TIMEOUT]\n"
+              "\t\t[-G GRACEPERIOD] [-M MARK] HOSTNAME\n", argv[0]);
        printf("See the man page for details.\n");
     exit(0);
   }
@@ -708,11 +759,11 @@ int main(int argc, char **argv)
       }
     }
 
+
     lock(argv[0], stdout);
       display_open();
       dns_open();
 
-      display_mode = 0;
       display_loop();
 
       net_end_transit();
diff --git a/net.c b/net.c
index d43054b..2608ec9 100644
--- a/net.c
+++ b/net.c
@@ -70,6 +70,13 @@ struct TCPHeader {
   uint32 seq;
 };
 
+/* Structure of an SCTP header */
+struct SCTPHeader {
+  uint16 srcport;
+  uint16 dstport;
+  uint32 veri_tag;
+};
+
 /* Structure of an IPv4 UDP pseudoheader.  */
 struct UDPv4PHeader {
   uint32 saddr;
@@ -119,7 +126,7 @@ struct nethost {
   int best;
   int worst;
   int avg;	/* average:  addByMin */
-  int gmean;	/* geometirc mean: addByMin */
+  int gmean;	/* geometric mean: addByMin */
   int jitter;	/* current jitter, defined as t1-t0 addByMin */
 /*int jbest;*/	/* min jitter, of cause it is 0, not needed */
   int javg;	/* avg jitter */
@@ -142,12 +149,6 @@ struct sequence {
 };
 
 
-/* Configuration parameter: How many queries to unknown hosts do we
-   send? (This limits the amount of traffic generated if a host is not
-   reachable) */
-#define MAX_UNKNOWN_HOSTS 5
-
-
 /* BSD-derived kernels use host byte order for the IP length and 
    offset fields when using raw sockets.  We detect this automatically at 
    run-time and do the right thing. */
@@ -202,14 +203,17 @@ static int numhosts = 10;
 
 extern int fstTTL;		/* initial hub(ttl) to ping byMin */
 extern int maxTTL;		/* last hub to ping byMin*/
+extern int maxUnknown;	/* stop ping threshold */
 extern int cpacketsize;		/* packet size used by ping */
 static int packetsize;		/* packet size used by ping */
+static int spacketsize;		/* packet size used by sendto */
 extern int bitpattern;		/* packet bit pattern used by ping */
 extern int tos;			/* type of service set in ping packet*/
 extern int af;			/* address family of remote target */
 extern int mtrtype;		/* type of query packet used */
 extern int remoteport;          /* target port for TCP tracing */
-extern int timeout;             /* timeout for TCP connections */
+extern int localport;  /* source port for UDP tracing */
+extern int tcp_timeout;             /* timeout for TCP connections */
 #ifdef SO_MARK
 extern int mark;		/* SO_MARK to set for ping packet*/
 #endif
@@ -223,32 +227,40 @@ int calc_deltatime (float waittime)
 }
 
 
-/* This doesn't work for odd sz. I don't know enough about this to say
-   that this is wrong. It doesn't seem to cripple mtr though. -- REW */
 int checksum(void *data, int sz) 
 {
-  unsigned short *ch;
-  unsigned int sum;
+  uint16 *ch;
+  uint32 sum;
+  uint16 odd;
 
   sum = 0;
   ch = data;
+  if (sz % 2) {
+    ((char *)&odd)[0] = ((char *)data)[sz - 1];
+    sum = odd;
+  }
   sz = sz / 2;
   while (sz--) {
     sum += *(ch++);
   }
-  
-  sum = (sum >> 16) + (sum & 0xffff);  
+  while (sum >> 16) {
+    sum = (sum >> 16) + (sum & 0xffff);
+  }
 
   return (~sum & 0xffff);  
 }
 
 
 /* Prepend pseudoheader to the udp datagram and calculate checksum */
-int udp_checksum(void *pheader, void *udata, int psize, int dsize)
+int udp_checksum(void *pheader, void *udata, int psize, int dsize, int alt_checksum)
 {
   unsigned int tsize = psize + dsize;
   char csumpacket[tsize];
   memset(csumpacket, (unsigned char) abs(bitpattern), abs(tsize));
+  if (alt_checksum && dsize >= 2) {
+    csumpacket[psize + sizeof(struct UDPHeader)] = 0;
+    csumpacket[psize + sizeof(struct UDPHeader) + 1] = 0;
+  }
 
   struct UDPv4PHeader *prepend = (struct UDPv4PHeader *) csumpacket;
   struct UDPv4PHeader *udppheader = (struct UDPv4PHeader *) pheader;
@@ -271,6 +283,8 @@ int udp_checksum(void *pheader, void *udata, int psize, int dsize)
 
 void save_sequence(int index, int seq)
 {
+  display_rawxmit(index, seq);
+
   sequence[seq].index = index;
   sequence[seq].transit = 1;
   sequence[seq].saved_seq = ++host[index].xmit;
@@ -414,6 +428,123 @@ void net_send_tcp(int index)
   connect(s, (struct sockaddr *) &remote, len);
 }
 
+/*  Attempt to connect to a SCTP port with a TTL */
+void net_send_sctp(int index)
+{
+  int ttl, s;
+  int opt = 1;
+  int port;
+  struct sockaddr_storage local;
+  struct sockaddr_storage remote;
+  struct sockaddr_in *local4 = (struct sockaddr_in *) &local;
+  struct sockaddr_in6 *local6 = (struct sockaddr_in6 *) &local;
+  struct sockaddr_in *remote4 = (struct sockaddr_in *) &remote;
+  struct sockaddr_in6 *remote6 = (struct sockaddr_in6 *) &remote;
+  socklen_t len;
+
+  ttl = index + 1;
+
+  s = socket(af, SOCK_STREAM, IPPROTO_SCTP);
+  if (s < 0) {
+    display_clear();
+    perror("socket()");
+    exit(EXIT_FAILURE);
+  }
+
+  memset(&local, 0, sizeof (local));
+  memset(&remote, 0, sizeof (remote));
+  local.ss_family = af;
+  remote.ss_family = af;
+
+  switch (af) {
+  case AF_INET:
+    addrcpy((void *) &local4->sin_addr, (void *) &ssa4->sin_addr, af);
+    addrcpy((void *) &remote4->sin_addr, (void *) remoteaddress, af);
+    remote4->sin_port = htons(remoteport);
+    len = sizeof (struct sockaddr_in);
+    break;
+#ifdef ENABLE_IPV6
+  case AF_INET6:
+    addrcpy((void *) &local6->sin6_addr, (void *) &ssa6->sin6_addr, af);
+    addrcpy((void *) &remote6->sin6_addr, (void *) remoteaddress, af);
+    remote6->sin6_port = htons(remoteport);
+    len = sizeof (struct sockaddr_in6);
+    break;
+#endif
+  }
+
+  if (bind(s, (struct sockaddr *) &local, len)) {
+    display_clear();
+    perror("bind()");
+    exit(EXIT_FAILURE);
+  }
+
+  if (getsockname(s, (struct sockaddr *) &local, &len)) {
+    display_clear();
+    perror("getsockname()");
+    exit(EXIT_FAILURE);
+  }
+
+  opt = 1;
+  if (ioctl(s, FIONBIO, &opt)) {
+    display_clear();
+    perror("ioctl FIONBIO");
+    exit(EXIT_FAILURE);
+  }
+
+  switch (af) {
+  case AF_INET:
+    if (setsockopt(s, IPPROTO_IP, IP_TTL, &ttl, sizeof (ttl))) {
+      display_clear();
+      perror("setsockopt IP_TTL");
+      exit(EXIT_FAILURE);
+    }
+    if (setsockopt(s, IPPROTO_IP, IP_TOS, &tos, sizeof (tos))) {
+      display_clear();
+      perror("setsockopt IP_TOS");
+      exit(EXIT_FAILURE);
+    }
+    break;
+#ifdef ENABLE_IPV6
+  case AF_INET6:
+    if (setsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof (ttl))) {
+      display_clear();
+      perror("setsockopt IP_TTL");
+      exit(EXIT_FAILURE);
+    }
+    break;
+#endif
+  }
+
+#ifdef SO_MARK
+    if (mark >= 0 && setsockopt( s, SOL_SOCKET, SO_MARK, &mark, sizeof mark ) ) {
+      perror( "setsockopt SO_MARK" );
+      exit( EXIT_FAILURE );
+    }
+#endif
+
+  switch (local.ss_family) {
+  case AF_INET:
+    port = ntohs(local4->sin_port);
+    break;
+#ifdef ENABLE_IPV6
+  case AF_INET6:
+    port = ntohs(local6->sin6_port);
+    break;
+#endif
+  default:
+    display_clear();
+    perror("unknown AF?");
+    exit(EXIT_FAILURE);
+  }
+
+  save_sequence(index, port);
+  gettimeofday(&sequence[port].time, NULL);
+  sequence[port].socket = s;
+
+  connect(s, (struct sockaddr *) &remote, len);
+}
+
 /*  Attempt to find the host at a particular number of hops away  */
 void net_send_query(int index) 
 {
@@ -421,6 +552,11 @@ void net_send_query(int index)
     net_send_tcp(index);
     return;
   }
+  
+  if (mtrtype == IPPROTO_SCTP) {
+    net_send_sctp(index);
+    return;
+  }
 
   /*ok  char packet[sizeof(struct IPHeader) + sizeof(struct ICMPHeader)];*/
   char packet[MAXPACKET];
@@ -428,6 +564,7 @@ void net_send_query(int index)
   struct ICMPHeader *icmp = NULL;
   struct UDPHeader *udp = NULL;
   struct UDPv4PHeader *udpp = NULL;
+  uint16 checksum_result;
   uint16 mypid;
 
   /*ok  int packetsize = sizeof(struct IPHeader) + sizeof(struct ICMPHeader) + datasize;*/
@@ -444,6 +581,9 @@ void net_send_query(int index)
 
   if ( packetsize < MINPACKET ) packetsize = MINPACKET;
   if ( packetsize > MAXPACKET ) packetsize = MAXPACKET;
+  if ( mtrtype == IPPROTO_UDP && remoteport && packetsize < (MINPACKET + 2)) {
+    packetsize = MINPACKET + 2;
+  }
 
   memset(packet, (unsigned char) abs(bitpattern), abs(packetsize));
 
@@ -515,18 +655,27 @@ void net_send_query(int index)
   case IPPROTO_UDP:
     udp = (struct UDPHeader *)(packet + iphsize);
     udp->checksum  = 0;
-    mypid = (uint16)getpid();
-    if (mypid < MinPort)
-      mypid += MinPort;
-
+    if (!localport) {
+      mypid = (uint16)getpid();
+      if (mypid < MinPort)
+        mypid += MinPort;
+    } else {
+      mypid = (uint16)localport;
+    }
     udp->srcport = htons(mypid);
-    udp->length = abs(packetsize) - iphsize;
-    if(!BSDfix)
-      udp->length = htons(udp->length);
- 
-    udp->dstport = new_sequence(index);
-    gettimeofday(&sequence[udp->dstport].time, NULL);
-    udp->dstport = htons(udp->dstport);
+    udp->length = htons(abs(packetsize) - iphsize);
+
+    if (!remoteport) {
+      udp->dstport = new_sequence(index);
+      gettimeofday(&sequence[udp->dstport].time, NULL);
+      udp->dstport = htons(udp->dstport);
+    } else {
+      // keep dstport constant, stuff sequence into the checksum
+      udp->dstport = htons(remoteport);
+      udp->checksum = new_sequence(index);
+      gettimeofday(&sequence[udp->checksum].time, NULL);
+      udp->checksum = htons(udp->checksum);
+    }
     break;
   }
 
@@ -535,13 +684,22 @@ void net_send_query(int index)
     switch ( mtrtype ) {
     case IPPROTO_UDP:
       /* checksum is not mandatory. only calculate if we know ip->saddr */
-      if (ip->saddr) {
+      if (udp->checksum) {
+        udpp = (struct UDPv4PHeader *)(malloc(sizeof(struct UDPv4PHeader)));
+        udpp->saddr = ip->saddr;
+        udpp->daddr = ip->daddr;
+        udpp->protocol = ip->protocol;
+        udpp->len = udp->length;
+        checksum_result = udp_checksum(udpp, udp, sizeof(struct UDPv4PHeader), abs(packetsize) - iphsize, 1);
+        packet[iphsize + sizeof(struct UDPHeader)] = ((char *)&checksum_result)[0];
+        packet[iphsize + sizeof(struct UDPHeader) + 1] = ((char *)&checksum_result)[1];
+      } else if (ip->saddr) {
         udpp = (struct UDPv4PHeader *)(malloc(sizeof(struct UDPv4PHeader)));
         udpp->saddr = ip->saddr;
         udpp->daddr = ip->daddr;
         udpp->protocol = ip->protocol;
         udpp->len = udp->length;
-        udp->checksum = udp_checksum(udpp, udp, sizeof(struct UDPv4PHeader), abs(packetsize) - iphsize);
+        udp->checksum = udp_checksum(udpp, udp, sizeof(struct UDPv4PHeader), abs(packetsize) - iphsize, 0);
       }
       break;
     }
@@ -553,6 +711,9 @@ void net_send_query(int index)
     switch ( mtrtype ) {
     case IPPROTO_UDP:
       /* kernel checksum calculation */
+      if (udp->checksum) {
+        offset = sizeof(struct UDPHeader);
+      }
       if ( setsockopt(sendsock, IPPROTO_IPV6, IPV6_CHECKSUM, &offset, sizeof(offset)) ) {
         perror( "setsockopt IPV6_CHECKSUM" );
         exit( EXIT_FAILURE);
@@ -563,13 +724,15 @@ void net_send_query(int index)
 #endif
   }
 
-  rv = sendto(sendsock, packet, abs(packetsize), 0, 
-	      remotesockaddr, salen);
+  /* sendto() assumes packet length includes the IPv4 header but not the 
+     IPv6 header. */
+  spacketsize = abs(packetsize)	-
+		( ( af == AF_INET ) ? 0 : sizeof (struct ip6_hdr) );
+  rv = sendto(sendsock, packet, spacketsize, 0, remotesockaddr, salen);
   if (first && (rv < 0) && ((errno == EINVAL) || (errno == EMSGSIZE))) {
     /* Try the first packet again using host byte order. */
-    ip->len = abs (packetsize);
-    rv = sendto(sendsock, packet, abs(packetsize), 0, 
-		remotesockaddr, salen);
+    ip->len = spacketsize;
+    rv = sendto(sendsock, packet, spacketsize, 0, remotesockaddr, salen);
     if (rv >= 0) {
       BSDfix = 1;
     }
@@ -686,7 +849,7 @@ void net_process_ping(int seq, struct mplslen mpls, void * addr, struct timeval
   host[index].transit = 0;
 
   net_save_return(index, sequence[seq].saved_seq, totusec);
-  display_rawping(index, totusec);
+  display_rawping(index, totusec, seq);
 }
 
 
@@ -709,6 +872,7 @@ void net_process_return(void)
   struct ICMPHeader *header = NULL;
   struct UDPHeader *udpheader = NULL;
   struct TCPHeader *tcpheader = NULL;
+  struct SCTPHeader *sctpheader = NULL;
   struct timeval now;
   ip_t * fromaddress = NULL;
   int echoreplytype = 0, timeexceededtype = 0, unreachabletype = 0;
@@ -837,7 +1001,11 @@ void net_process_return(void)
         break;
 #endif
       }
-      sequence = ntohs(udpheader->dstport);
+      if (remoteport && remoteport == ntohs(udpheader->dstport)) {
+        sequence = ntohs(udpheader->checksum);
+      } else if (!remoteport) {
+        sequence = ntohs(udpheader->dstport);
+      }
     }
     break;
 
@@ -877,8 +1045,44 @@ void net_process_return(void)
       sequence = ntohs(tcpheader->srcport);
     }
     break;
-  }
+    
+  case IPPROTO_SCTP:
+    if (header->type == timeexceededtype || header->type == unreachabletype) {
+      switch ( af ) {
+      case AF_INET:
 
+        if ((size_t) num < sizeof(struct IPHeader) +
+                           sizeof(struct ICMPHeader) +
+                           sizeof (struct IPHeader) +
+                           sizeof (struct SCTPHeader))
+          return;
+        sctpheader = (struct SCTPHeader *)(packet + sizeof (struct IPHeader) +
+                                                  sizeof (struct ICMPHeader) +
+                                                  sizeof (struct IPHeader));
+
+        if(num > 160)
+          decodempls(num, packet, &mpls, 156);
+
+      break;
+#ifdef ENABLE_IPV6
+      case AF_INET6:
+        if ( num < sizeof (struct ICMPHeader) +
+                   sizeof (struct ip6_hdr) + sizeof (struct SCTPHeader) )
+          return;
+        sctpheader = (struct SCTPHeader *) ( packet +
+                                           sizeof (struct ICMPHeader) +
+                                           sizeof (struct ip6_hdr) );
+
+        if(num > 140)
+          decodempls(num, packet, &mpls, 136);
+
+        break;
+#endif
+      }
+      sequence = ntohs(sctpheader->srcport);
+    }
+    break;
+  }
   if (sequence)
     net_process_ping (sequence, mpls, (void *) fromaddress, now);
 }
@@ -1088,7 +1292,7 @@ int net_send_batch(void)
     /* The second condition in the next "if" statement was added in mtr-0.56, 
 	but I don't remember why. It makes mtr stop skipping sections of unknown
 	hosts. Removed in 0.65. 
-	If the line proves neccesary, it should at least NOT trigger that line 
+	If the line proves necessary, it should at least NOT trigger that line
 	when host[i].addr == 0 */
     if ( ( addrcmp( (void *) &(host[i].addr),
                     (void *) remoteaddress, af ) == 0 )
@@ -1099,8 +1303,8 @@ int net_send_batch(void)
   if (	/* success in reaching target */
      ( addrcmp( (void *) &(host[batch_at].addr),
                 (void *) remoteaddress, af ) == 0 ) ||
-      /* fail in consecuitive MAX_UNKNOWN_HOSTS (firewall?) */
-      (n_unknown > MAX_UNKNOWN_HOSTS) ||
+      /* fail in consecutive maxUnknown (firewall?) */
+      (n_unknown > maxUnknown) ||
       /* or reach limit  */
       (batch_at >= maxTTL-1)) {
     numhosts = batch_at+1;
@@ -1323,11 +1527,84 @@ void net_reset(void)
   gettimeofday(&reset, NULL);
 }
 
+int net_set_interfaceaddress_udp()
+{
+#ifdef ENABLE_IPV6
+  struct sockaddr_storage name_struct;
+#else
+  struct sockaddr_in name_struct;
+#endif
+  struct sockaddr_in *  sa4;
+  struct sockaddr_in6 * sa6;
+  struct sockaddr * name = (struct sockaddr *) &name_struct;
+  struct sockaddr_storage remote;
+  struct sockaddr_in *remote4 = (struct sockaddr_in *) &remote;
+  struct sockaddr_in6 *remote6 = (struct sockaddr_in6 *) &remote;
+  socklen_t len;
+  int s;
+
+  memset(&remote, 0, sizeof (remote));
+  remote.ss_family = af;
+
+  switch (af) {
+  case AF_INET:
+    addrcpy((void *) &remote4->sin_addr, (void *) remoteaddress, af);
+    remote4->sin_port = htons(remoteport);
+    len = sizeof (struct sockaddr_in);
+    break;
+#ifdef ENABLE_IPV6
+  case AF_INET6:
+    addrcpy((void *) &remote6->sin6_addr, (void *) remoteaddress, af);
+    remote6->sin6_port = htons(remoteport);
+    len = sizeof (struct sockaddr_in6);
+    break;
+#endif
+  }
+
+  s = socket (af, SOCK_DGRAM, 0);
+  if (s < 0) {
+    perror("udp socket()");
+    exit(EXIT_FAILURE);
+  }
+
+  if (connect(s, (struct sockaddr *) &remote, len)) {
+    perror("udp connect() failed");
+    exit(EXIT_FAILURE);
+  }
+
+  getsockname(s, name, &len);
+  sockaddrtop( name, localaddr, sizeof localaddr );
+  switch (af) {
+  case AF_INET:
+    sa4 = (struct sockaddr_in *) name;
+    addrcpy((void*)&ssa4->sin_addr, (void *) &(sa4->sin_addr), af );
+    break;
+#ifdef ENABLE_IPV6
+  case AF_INET6:
+    sa6 = (struct sockaddr_in6 *) name;
+    addrcpy((void*)&ssa6->sin6_addr, (void *) &(sa6->sin6_addr), af );
+    break;
+#endif
+  }
+  close(s);
+
+  return 0;
+}
+
 
 int net_set_interfaceaddress (char *InterfaceAddress)
 {
-  int len = 0;
+#ifdef ENABLE_IPV6
+  struct sockaddr_storage name_struct;
+#else
+  struct sockaddr_in name_struct;
+#endif
+  struct sockaddr * name = (struct sockaddr *) &name_struct;
+  socklen_t len = 0;
 
+  if (mtrtype == IPPROTO_UDP && remoteport && !InterfaceAddress) {
+    return net_set_interfaceaddress_udp();
+  }
   if (!InterfaceAddress) return 0; 
 
   sourcesockaddr->sa_family = af;
@@ -1356,6 +1633,8 @@ int net_set_interfaceaddress (char *InterfaceAddress)
     perror("mtr: failed to bind to interface");
       return( 1 );
   }
+  getsockname (sendsock, name, &len);
+  sockaddrtop( name, localaddr, sizeof localaddr );
   return 0; 
 }
 
@@ -1559,7 +1838,7 @@ void net_process_fds(fd_set *writefd)
     }
     if (fd > 0) {
       utime = sequence[at].time.tv_sec * 1000000L + sequence[at].time.tv_usec;
-      if (unow - utime > timeout) {
+      if (unow - utime > tcp_timeout) {
         close(fd);
         sequence[at].socket = 0;
       }
diff --git a/raw.c b/raw.c
index 0e1f4f4..f8e8876 100644
--- a/raw.c
+++ b/raw.c
@@ -47,7 +47,15 @@ static char *addr_to_str(ip_t addr)
 }
 #endif
 
-void raw_rawping (int host, int msec)
+// Log an echo request, or a "ping"
+void raw_rawxmit (int host, int seq)
+{
+  printf ("x %d %d\n", host, seq);
+  fflush (stdout);
+}
+
+// Log an echo reply, or a "pong"
+void raw_rawping (int host, int msec, int seq)
 {
   char *name;
 
@@ -58,7 +66,7 @@ void raw_rawping (int host, int msec)
       printf ("d %d %s\n", host, name);
     }
   }
-  printf ("p %d %d\n", host, msec);
+  printf ("p %d %d %d\n", host, msec, seq);
   fflush (stdout); 
 }
 
diff --git a/raw.h b/raw.h
index 357c8f3..3679f58 100644
--- a/raw.h
+++ b/raw.h
@@ -19,5 +19,6 @@
 */
 
 /*  Prototypes for raw.c  */
-void raw_rawping(int host, int msec);
+void raw_rawxmit(int host, int seq);
+void raw_rawping(int host, int msec, int seq);
 void raw_rawhost(int host, ip_t * addr);
diff --git a/report.c b/report.c
index badb765..b47a855 100644
--- a/report.c
+++ b/report.c
@@ -253,11 +253,104 @@ void txt_open(void)
 
 
 void txt_close(void)
-{ 
+{
   report_close();
 }
 
 
+void json_open(void)
+{
+}
+
+
+void json_close(void)
+{
+  int i, j, at, first, max;
+  ip_t *addr;
+  char name[81];
+
+  printf("{\n");
+  printf("  \"report\": {\n");
+  printf("    \"mtr\": {\n");
+  printf("      \"src\": \"%s\",\n", LocalHostname);
+  printf("      \"dst\": \"%s\",\n", Hostname);
+  printf("      \"tos\": \"0x%X\",\n", tos);
+  if(cpacketsize >= 0) {
+    printf("      \"psize\": \"%d\",\n", cpacketsize);
+  } else {
+    printf("      \"psize\": \"rand(%d-%d)\",\n",MINPACKET, -cpacketsize);
+  }
+  if( bitpattern>=0 ) {
+    printf("      \"bitpattern\": \"0x%02X\",\n", (unsigned char)(bitpattern));
+  } else {
+    printf("      \"bitpattern\": \"rand(0x00-FF)\",\n");
+  }
+  printf("      \"tests\": \"%d\"\n", MaxPing);
+  printf("    },\n");
+
+  printf("    \"hubs\": [");
+
+  max = net_max();
+  at = first = net_min();
+  for(; at < max; at++) {
+    addr = net_addr(at);
+    snprint_addr(name, sizeof(name), addr);
+
+    if(at == first) {
+      printf("{\n");
+    } else {
+      printf("    {\n");
+    }
+    printf("      \"count\": \"%d\",\n", at+1);
+    printf("      \"host\": \"%s\",\n", name);
+    for( i=0; i<MAXFLD; i++ ) {
+      j = fld_index[fld_active[i]];
+
+      /* Commas */
+      if(i + 1 == MAXFLD) {
+        printf("\n");
+      } else if (j > 0 && i != 0) {
+        printf(",\n");
+      }
+
+      if (j <= 0) continue; // Field nr 0, " " shouldn't be printed in this method.
+
+      /* Format value */
+      const char *format;
+      format = data_fields[j].format;
+      if( index(format, 'f') ) {
+        format = "%.2f";
+      } else {
+        format = "%d";
+      }
+
+      /* Format json line */
+      strcpy(name, "      \"%s\": ");
+      strcat(name, format);
+
+      /* Output json line */
+      if(index(data_fields[j].format, 'f')) {
+        /* 1000.0 is a temporay hack for stats usec to ms, impacted net_loss. */
+        printf(name,
+               data_fields[j].title,
+               data_fields[j].net_xxx(at) / 1000.0);
+      } else {
+        printf(name,
+               data_fields[j].title,
+               data_fields[j].net_xxx(at));
+      }
+    }
+    if(at+1 == max) {
+      printf("    }]\n");
+    } else {
+      printf("    },\n");
+    }
+  }
+  printf("  }\n");
+  printf("}\n");
+}
+
+
 
 void xml_open(void)
 {
@@ -294,7 +387,7 @@ void xml_close(void)
     printf("    <HUB COUNT=\"%d\" HOST=\"%s\">\n", at+1, name);
     for( i=0; i<MAXFLD; i++ ) {
       j = fld_index[fld_active[i]];
-      if (j < 0) continue;
+      if (j <= 0) continue; // Field nr 0, " " shouldn't be printed in this method. 
 
       strcpy(name, "        <%s>");
       strcat(name, data_fields[j].format);
@@ -347,27 +440,41 @@ void csv_close(time_t now)
     addr = net_addr(at);
     snprint_addr(name, sizeof(name), addr);
 
-    int last = net_last(at);
+    if (at == net_min()) {
+      printf("Mtr_Version,Start_Time,Status,Host,Hop,Ip,");
+#ifdef IPINFO
+      if(!ipinfo_no) {
+	printf("Asn,");
+      }
+#endif
+      for( i=0; i<MAXFLD; i++ ) {
+	j = fld_index[fld_active[i]];
+	if (j < 0) continue;
+	printf("%s,", data_fields[j].title);
+      }
+      printf("\n");
+    }
+
 #ifdef IPINFO
     if(!ipinfo_no) {
       char* fmtinfo = fmt_ipinfo(addr);
       if (fmtinfo != NULL) fmtinfo = trim(fmtinfo);
-      printf("MTR.%s;%lld;%s;%s;%d;%s;%s;%d", MTR_VERSION, (long long)now, "OK", Hostname,
-             at+1, name, fmtinfo, last);
+      printf("MTR.%s,%lld,%s,%s,%d,%s,%s", MTR_VERSION, (long long)now, "OK", Hostname,
+             at+1, name, fmtinfo);
     } else
 #endif
-      printf("MTR.%s;%lld;%s;%s;%d;%s;%d", MTR_VERSION, (long long)now, "OK", Hostname,
-             at+1, name, last);
+      printf("MTR.%s,%lld,%s,%s,%d,%s", MTR_VERSION, (long long)now, "OK", Hostname,
+             at+1, name);
 
     for( i=0; i<MAXFLD; i++ ) {
-      j = fld_index[fld_active[j]];
+      j = fld_index[fld_active[i]];
       if (j < 0) continue; 
 
       /* 1000.0 is a temporay hack for stats usec to ms, impacted net_loss. */
       if( index( data_fields[j].format, 'f' ) ) {
-	printf( ", %.2f", data_fields[j].net_xxx(at) / 1000.0);
+	printf( ",%.2f", data_fields[j].net_xxx(at) / 1000.0);
       } else {
-	printf( ", %d",   data_fields[j].net_xxx(at) );
+	printf( ",%d",   data_fields[j].net_xxx(at) );
       }
     }
     printf("\n");
diff --git a/report.h b/report.h
index 81c2d81..566be3e 100644
--- a/report.h
+++ b/report.h
@@ -22,6 +22,8 @@ void report_open(void);
 void report_close(void);
 void txt_open(void);
 void txt_close(void);
+void json_open(void);
+void json_close(void);
 void xml_open(void);
 void xml_close(void);
 void csv_open(void);
diff --git a/select.c b/select.c
index 62478f4..ed0ae5e 100644
--- a/select.c
+++ b/select.c
@@ -39,14 +39,14 @@ extern int Interactive;
 extern int MaxPing;
 extern int ForceMaxPing;
 extern float WaitTime;
+extern float GraceTime;
 double dnsinterval;
 extern int mtrtype;
 
 static struct timeval intervaltime;
 int display_offset = 0;
 
-
-#define GRACETIME (5 * 1000*1000)
+#define GRACETIME (GraceTime * 1000*1000)
 
 void select_loop(void) {
   fd_set readfd;
@@ -240,15 +240,12 @@ void select_loop(void) {
 	break;
 #ifdef IPINFO
       case ActionII:
-	if (ipinfo_no >= 0) {
-	  ipinfo_no++;
-          if (ipinfo_no > ipinfo_max)
-            ipinfo_no = 0;
-	}
+	ipinfo_no++;
+	if (ipinfo_no > ipinfo_max)
+	  ipinfo_no = 0;
 	break;
       case ActionAS:
-	if (ipinfo_no >= 0)
-          ipinfo_no = ipinfo_no?0:ipinfo_max;
+	ipinfo_no = ipinfo_no?0:ipinfo_max;
 	break;
 #endif
 
