diff -PBbruw linux/Documentation/Configure.help sockinst/Documentation/Configure.help
--- linux/Documentation/Configure.help	Tue Sep  5 13:57:51 2000
+++ sockinst/Documentation/Configure.help	Tue Jan 23 14:33:42 2001
@@ -1807,6 +1807,33 @@
   You can say Y here if you want to get additional messages useful in
   debugging the netfilter code.
+MAGNeT Network Instrumentation (EXPERIMENTAL)
+CONFIG_SOCKINST
+  MAGNeT: the Monitor for Application Generated Network Traffic.
+
+  This is kernel-side code which instruments the Linux network
+  subsystem.  It records incomming and outgoing packets at various
+  levels in the network stack(s), and records some pertinant details
+  of the packets (timestamps, etc).  It is of use only to protocol
+  designers, researchers, and implementors, and should be disabled
+  by all normal people.  Say N here.
+
+  See Documentation/magnet.txt for information on how to use MAGNeT.
+
+MAGNeT Extended Instrumentation
+CONFIG_SOCKINST_EXTENDED
+  This enables MAGNeT to store extended information (ie, the entire
+  TCP state snapshot) with each data point.  This significantly adds
+  to the overhead of the instrumentation, and thus should not normally
+  be used.  Its here if you really need it.
+
+MAGNeT: Socket Calls Only
+CONFIG_SOCKINST_SOCK_ONLY
+  For the absolute mininum of instrumentation overhead.  This tells
+  MAGNeT to only record application socket send() and recv() calls.
+  Thus, individual protocols (TCP, IP, etc) will NOT be monitored if
+  you say Y here.
+
 IP: connection tracking (required for masq/NAT)
 CONFIG_IP_NF_CONNTRACK
   Connection tracking keeps a record of what packets have passed
diff -PBbruw linux/Documentation/magnet.txt magnet/Documentation/magnet.txt
--- linux/Documentation/magnet.txt	Wed Dec 31 17:00:00 1969
+++ magnet/Documentation/magnet.txt	Tue Jan 23 14:34:28 2001
@@ -0,0 +1,84 @@
+MAGNet - Monitor for Application Generated Network Traffic
+----------------------------------------------------------
+
+MAGNeT is a research tool created by Los Alamos National Laboratory's RADIANT
+(Research and Development in Advanced Networking Technology) team.  The purpose
+of MAGNeT is to obtain an understanding of the actual network traffic patterns
+as that traffic traverses the networking stack in the kernel.  While
+traditional traffic monitoring solutions (ie, network sniffers) are capable of
+reporting traffic on the wire, this may or may not reflect the actual traffic
+patterns that applications generate -- for example, several small packets might
+be queued up by TCP before being sent across the network.  MAGNeT is the first
+tool designed to show application-level rather then wire-level traffic.
+
+This is accomplished by a small bit of code in the Linux kernel.  At strategic
+points in the processing of network traffic (for example, when the TCP code
+hands a packet of data to the IP layer, or when the kernel socket code hands
+data from the TCP layer to the running application), a quick routine is run
+to add a timestamp to a permament, non-swappable kernel circular buffer.  Since
+this buffer space is guarenteed to be in memory, the marking has minimal impact
+on networking performance.  To read the recorded data, an user-level
+application simply mmaps() the kernel circular buffer and reads out of it as it
+is updated.
+
+This architecture allows MAGNeT to be used for any type of BSD Socket-based
+communication.  Currently, general socket calls (read(), write(), etc) and the
+TCP and IP layers are instrumented.  Additionally, the TCP and IP run-time
+state snapshots can be optionally recorded at each timestamp. (This, of course,
+results in much more data being moved around, and thus a bigger performance
+impact)  In this mode, MAGNeT can be used by protocol designers and
+implementors to debug the workings of their protocol under known conditions.
+
+MAGNeT currently consists of the following:
+
+include/linux/magnet.h -
+		    Header file to describe MAGNeT data types, for both kernel
+		    and user-level programs.  Also defines kernel function
+		    prototypes.
+
+net/magnet/magnet.c -
+		    The code to maintain the kernel circular buffer and
+		    preform MAGNeT initialization and tear-down.
+
+net/magnet/magnet-read.c -
+		    Sample user-level program to read MAGNeT data from the
+		    kernel buffer.  This sample program works by mmapping a
+		    pre-existing file and transferring filesize bytes of data
+		    from the kernel to the file.  Rather simple, but usable.
+
+net/magnet/magnet-parse.c -
+		    Program to read binary data collected from the kernel
+		    buffer (ie, by magnet-read.c) and display the data in a
+		    human-readable form.  The timestamps reported are the CPU
+		    cycle counter (which ticks once per CPU clock/instruction).
+
+net/magnet/mkmagnet.c -
+		    Simple program to create the files which magnet-read.c
+		    reads kernel data into.
+
+The following kernel compilation options are avaliable:
+
+CONFIG_MAGNET
+	Compile in the base MAGNeT code
+
+CONFIG_MAGNET_EXTENDED
+	Compile extended MAGNeT data (protocol state snapshots, etc)
+
+CONFIG_MAGNET_SOCK_ONLY
+	Normally, MAGNeT records data for all protocols for which MAGNeT is
+	implemented (currently, sockets, TCP, and IP).  This option limits
+	MAGNeT reporting to only socket-layer activities.
+
+A linux system running with MAGNeT installed has two special files:
+
+/proc/net/magnet -
+		 Displaying this file displays various information about the
+		 currently running MAGNeT version, including size of data
+		 packets, size of the kernel buffer, and other pertainent
+		 details.
+
+/dev/magnet -
+	    A special device file must be created to perform the mmap()ing from
+	    the kernel to user-level space.  /proc/net/magnet contains the
+	    name and major/minor mode numbers this special file requires.
+
diff -PBbruw linux/include/linux/magnet.h magnet/include/linux/magnet.h
--- linux/include/linux/magnet.h	Wed Dec 31 17:00:00 1969
+++ magnet/include/linux/magnet.h	Tue Jan 23 14:36:35 2001
@@ -0,0 +1,257 @@
+/*
+ * MAGNET	Monitor for Application Generated Network Traffic
+ *              - Define basic data structures for socket instrumentation
+ *
+ * Version:	@(#)magnet.h	0.1.0	2001/02/17
+ *
+ * Author:	Jeff Hay, <jrhay@lanl.gov>
+ *
+ * Fixes:
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ */
+#ifndef _MAGNET_H
+#define _MAGNET_H
+
+#include <asm/timex.h>
+
+#ifdef __KERNEL__
+/* for macrology */
+#include <net/sock.h>
+#include <linux/tcp.h>
+#include <linux/ip.h>
+#endif
+
+#include <asm/page.h>  /* Need PAGE_SIZE definition (for user-mode apps) */
+#define SI_DATA_SIZE 64*PAGE_SIZE /* System-wide magnet data buffer */
+
+/* Per-protocol/event storage area buffers */
+
+enum {  /* Defined magnet event types */
+  MAGNET_LOST = 0,     /* Lost data.  "size" = # records lost */
+
+  MAGNET_SOCK = 0xF,          /* Default - socket operations */
+  MAGNET_SOCK_SEND = 0x1,     /* Recevied message from application */
+  MAGNET_SOCK_RECV = 0x2,     /* Sent message to application */
+
+  MAGNET_TCP = 0xF0,          /* TCP Protocol event */
+  MAGNET_TCP_SSOCK = 0x10,    /* Received message from socket */
+  MAGNET_TCP_RSOCK = 0x20,    /* Sent message to socket */
+  MAGNET_TCP_SIP   = 0x30,    /* Received message from IP layer */
+  MAGNET_TCP_RIP   = 0x40,    /* Sent message to IP layer */
+
+  MAGNET_IP = 0xF00,          /* IP Protocol event */
+  MAGNET_IP_SEND = 0x100,     /* Sent message to network device */
+  MAGNET_IP_RECV = 0x200,     /* Received message from network device */
+
+  MAGNET_UNKNOWN = 0x1000   /* Unknown Protocol - max value */
+};
+#define MAX_MAGNET_EVENT MAGNET_UNKNOWN
+
+#ifdef CONFIG_MAGNET_EXTENDED
+
+/* Data and routines for extended instrumentation.  This significantly adds
+   to the space magnet packets take up in memory, but provides very detailed
+   reporting about the current running state.  Use as needed.
+   Ideally, this would be a run-time-selectable thing, rather then a build-time
+   select.
+
+  (data storage sizes in here need to be made platform-generic for both
+   kernel and user space routines.....) */
+
+
+/***
+// Extended SOCK-type information
+***/
+struct magnet_sock {
+	pid_t   pid;
+	char    name[11];
+}; /* struct magnet_sock */
+
+#ifdef __KERNEL__
+extern __inline__ struct magnet_sock magnet_no_data(void)
+{
+	struct magnet_sock sock;
+
+	memset((void *)&sock, '\0', sizeof(struct magnet_sock));
+	if (current == NULL)
+	  {
+	    sock.pid = 0;
+	    return sock;
+	  }
+	sock.pid = current->pid;
+
+// This doesn't work.  Things just freeze.  Not fun.  Don't do it.
+//	if (current->mm != NULL)
+//		access_process_vm(current, current->mm->arg_start, sock.name, 1, 0);
+// (It is supposed to get the PID's command line as an identifier... ah well..)
+	return sock;
+}
+
+/***
+// Dummy extended type for "No extended information"
+***/
+#define MAGNET_NO_DATA (union magnet_ext_data) magnet_no_data()
+#endif
+
+/***
+// Extended TCP-type information
+***/
+struct magnet_tcp { /* data from "struct tcp_opt" in include/net/sock.h */
+
+	unsigned short  source;         /* TCP source port number            */
+	unsigned short  dest;           /* TCP destination port number       */
+
+	unsigned long	snd_wnd;	/* The window we expect to receive   */
+
+	unsigned long	srtt;		/* smothed round trip time << 3	     */
+  	unsigned long	rto;		/* retransmit timeout		     */
+
+  	unsigned long	packets_out;	/* Packets which are "in flight"     */
+  	unsigned long	retrans_out;	/* Retransmitted packets out	     */
+
+  	unsigned long	snd_ssthresh;	/* Slow start size threshold	     */
+  	unsigned long	snd_cwnd;	/* Sending congestion window	     */
+
+  	unsigned long	rcv_wnd;	/* Current receiver window	     */
+  	unsigned long	write_seq;	/* Tail+1 of data in tcp send buffer */
+  	unsigned long	copied_seq;	/* Head of yet unread data	     */
+
+	unsigned short  fin:1,syn:1,rst:1,psh:1,ack:1,urg:1,ece:1,cwr:1; /* TCP flags*/
+}; /* struct magnet_tcp */
+
+#ifdef __KERNEL__
+ extern __inline__ struct magnet_tcp magnet_tcp_data(
+	struct tcp_opt *tp, struct sk_buff *skb)
+{
+	struct magnet_tcp tcp;
+	struct tcphdr *head;
+
+	memset((void *)&tcp, '\0', sizeof(struct magnet_tcp));
+	if (tp != NULL) {
+	  tcp.snd_wnd = tp->snd_wnd; tcp.srtt = tp->srtt; tcp.rto = tp->rto;
+	  tcp.packets_out = tp->packets_out; tcp.retrans_out = tp->retrans_out;
+	  tcp.snd_ssthresh = tp->snd_ssthresh; tcp.snd_cwnd = tp->snd_cwnd;
+	  tcp.write_seq = tp->write_seq; tcp.copied_seq = tp->copied_seq;
+	}
+
+#if 0
+	/* Weird bug here -- even after the NULL checks, dereferencing head->
+	   will consistaintly fail the first time data comes in; works fine
+	   after that.... dunno why... */
+	if (skb != NULL) {
+	  head = skb->h.th;
+	  if (head != NULL) {
+	    tcp.source = head->source;
+	    tcp.dest = head->dest;
+	    tcp.fin = head->fin; tcp.syn = head->syn; tcp.psh = head->psh;
+	    tcp.ack = head->ack; tcp.urg = head->urg; tcp.ece = head->ece;
+	    tcp.cwr = head->cwr;
+	  }
+	}
+#endif
+
+	return tcp;
+}
+#define MAGNET_TCP_DATA (union magnet_ext_data) magnet_tcp_data(tp, skb)
+#endif
+
+/***
+// Extended IP-type information
+***/
+
+struct magnet_ip {
+	unsigned char	version;
+	unsigned char	tos;
+	unsigned short	id;
+	unsigned short	frag_off;
+	unsigned char	ttl;
+	unsigned char	protocol;
+}; /* struct magnet_ip */
+
+#ifdef __KERNEL__
+extern __inline__ struct magnet_ip magnet_ip_data(struct iphdr *iph)
+{
+	struct magnet_ip ip;
+
+	memset((void *)&ip, '\0', sizeof(struct magnet_ip));
+	if (iph != NULL) {
+	  ip.version = iph->version; ip.tos = iph->tos;
+	  ip.id = iph->id; ip.frag_off = iph->frag_off;
+	  ip.ttl = iph->ttl; ip.protocol = iph->protocol;
+	}
+	return ip;
+
+}
+#define MAGNET_IP_DATA (union magnet_ext_data) magnet_ip_data(iph)
+#endif
+
+/***
+// Declaration of magnet extended data type
+***/
+
+union magnet_ext_data { /* Stores data for different events */
+	struct magnet_sock sock;
+	struct magnet_tcp tcp;
+	struct magnet_ip ip;
+};
+
+#else // not defined CONFIG_MAGNET_EXTENDED
+
+union magnet_ext_data { int dummy; } magnet_false_data;
+#define MAGNET_IP_DATA magnet_false_data
+#define MAGNET_TCP_DATA magnet_false_data
+#define MAGNET_NO_DATA magnet_false_data
+
+#endif // defined CONFIG_MAGNET_EXTENDED
+
+struct magnet_data {
+	void *sockid;
+	unsigned long long timestamp;   /* Time of event (cycle counter) */
+	unsigned int event;             /* Kind of event */
+	unsigned int size;              /* Size (in bytes) of event */
+	union magnet_ext_data data;   /* Event-specific data */
+}; /* struct magnet_data */
+
+
+#ifdef __KERNEL__
+
+/*
+  Data structures and routines to do shared memory with user-space progs
+*/
+
+#include <linux/proc_fs.h>
+
+extern int magnet_open(struct inode *inode, struct file *file);
+extern int magnet_close(struct inode *inode, struct file *file);
+extern int magnet_mmap(struct file *file, struct vm_area_struct *vma);
+extern struct page * magnet_nopage(struct vm_area_struct *vma,
+				     unsigned long address,
+				     int no_share);
+
+/*
+   Routines to access magnet_buffers
+*/
+
+/* Copy data to the system-wide socket buffer */
+extern  __inline__ void magnet_copy(void *data, int len);
+
+/* Add an event to a per-socket queue */
+extern __inline__ void magnet_add(struct sock *sk,
+				    unsigned int si_event,
+				    unsigned int si_size,
+				    union magnet_ext_data data);
+
+/* Initialize this socket's instrumentation interface */
+extern __inline__ int magnet_setup(void);
+extern __inline__ void magnet_init(void);
+
+/* Teardown this socket's instrumentation ineterface */
+extern __inline__ void magnet_destroy(void);
+
+#endif /* __KERNEL__ */
+
+#endif	/* _MAGNET_H */
diff -PBbruw linux/mm/memory.c magnet/mm/memory.c
--- linux/mm/memory.c	Fri Sep  1 14:51:10 2000
+++ magnet/mm/memory.c	Wed Oct 18 08:41:01 2000
@@ -383,9 +383,12 @@
 /*
- * Do a quick page-table lookup for a single page.
+ * Do a quick page-table lookup for a single page. We have already verified
+ * access type, and done a fault in. But, kswapd might have stolen the page
+ * in the meantime. Return an indication of whether we should retry the fault
+ * in. Writability test is superfluous but conservative.
  */
-static struct page * follow_page(unsigned long address)
+static struct page * follow_page(unsigned long address, int writeacc, int *ret)
 {
 	pgd_t *pgd;
 	pmd_t *pmd;
@@ -429,6 +432,7 @@
 	struct page *		map;
 	int			i;
 	int			datain = (rw == READ);
+	int			failed;
 	/* Make sure the iobuf is not already mapped somewhere. */
 	if (iobuf->nr_pages)
@@ -468,18 +472,21 @@
 			}
 			if (((datain) && (!(vma->vm_flags & VM_WRITE))) ||
 					(!(vma->vm_flags & VM_READ))) {
-				err = -EACCES;
 				goto out_unlock;
 			}
 		}
+faultin:
 		if (handle_mm_fault(current->mm, vma, ptr, datain) <= 0)
 			goto out_unlock;
 		spin_lock(&mm->page_table_lock);
-		map = follow_page(ptr);
-		if (!map) {
+		map = follow_page(ptr, datain, &failed);
+		if (failed) {
+			/*
+			 * Page got stolen before we could lock it down.
+			 * Retry.
+			 */
 			spin_unlock(&mm->page_table_lock);
-			dprintk (KERN_ERR "Missing page in map_user_kiobuf\n");
-			goto out_unlock;
+			goto faultin;
 		}
 		map = get_page_map(map);
 		if (map)
diff -PBbruw linux/net/Config.in magnet/net/Config.in
--- linux/net/Config.in	Mon Jun 19 14:45:51 2000
+++ magnet/net/Config.in	Wed Jan 10 10:26:22 2001
@@ -17,6 +17,12 @@
    bool '  Network packet filtering debugging' CONFIG_NETFILTER_DEBUG
 fi
 bool 'Socket Filtering'  CONFIG_FILTER
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   bool 'MAGNeT: Socket Instrumentation interface' CONFIG_MAGNET
+fi
+if [ "$CONFIG_MAGNET" = "y" ]; then
+   source net/magnet/Config.in
+fi
 tristate 'Unix domain sockets' CONFIG_UNIX
 bool 'TCP/IP networking' CONFIG_INET
 if [ "$CONFIG_INET" = "y" ]; then
diff -PBbruw linux/net/Makefile magnet/net/Makefile
--- linux/net/Makefile	Sun Aug  6 12:23:41 2000
+++ magnet/net/Makefile	Mon Oct 23 10:51:43 2000
@@ -10,7 +10,8 @@
 MOD_SUB_DIRS := ipv4
 ALL_SUB_DIRS := 802 ax25 bridge core ethernet ipv4 ipv6 ipx unix appletalk \
 		netrom rose lapb x25 wanrouter netlink sched packet sunrpc \
-		econet irda decnet atm khttpd ipv4/netfilter ipv6/netfilter
+		econet irda decnet atm khttpd ipv4/netfilter ipv6/netfilter \
+		magnet
 SUB_DIRS     := core ethernet
 ifeq ($(CONFIG_NET),y)
@@ -192,6 +193,10 @@
   ifeq ($(CONFIG_ECONET),m)
   MOD_SUB_DIRS += econet
   endif
+endif
+
+ifeq ($(CONFIG_MAGNET),y)
+SUB_DIRS += magnet
 endif
 # We must attach netsyms.o to socket.o, as otherwise there is nothing
diff -PBbruw linux/net/README magnet/net/README
--- linux/net/README	Fri Feb 18 15:51:22 2000
+++ magnet/net/README	Thu Jan 11 16:21:09 2001
@@ -21,5 +21,6 @@
 wanrouter		gene@compuserve.com, jaspreet@sangoma and dm@sangoma.com
 unix			alan@lxorguk.ukuu.org.uk
 x25			g4klx@g4klx.demon.co.uk
+magnet			jrhay@lanl.gov
diff -PBbruw linux/net/core/sock.c magnet/net/core/sock.c
--- linux/net/core/sock.c	Fri Aug 18 11:26:25 2000
+++ magnet/net/core/sock.c	Tue Sep 12 15:45:29 2000
@@ -579,6 +579,9 @@
 		sock_lock_init(sk);
 	}
+	/* MAGNET: This is where we'd call the per-socket magnet_setup()
+	   function, if we had one... */
+
 	return sk;
 }
@@ -587,6 +590,9 @@
 #ifdef CONFIG_FILTER
 	struct sk_filter *filter;
 #endif
+
+	/* MAGNET: This is where we'd call the per-socket magnet_destroy()
+	   function, if we had one... */
 	if (sk->destruct)
 		sk->destruct(sk);
diff -PBbruw linux/net/ipv4/ip_input.c magnet/net/ipv4/ip_input.c
--- linux/net/ipv4/ip_input.c	Tue Aug 22 09:59:00 2000
+++ magnet/net/ipv4/ip_input.c	Tue Jan  9 13:03:34 2001
@@ -144,6 +144,10 @@
 #include <linux/mroute.h>
 #include <linux/netlink.h>
+#ifdef CONFIG_MAGNET
+#include <linux/magnet.h>
+#endif
+
 /*
  *	SNMP management statistics
  */
@@ -240,6 +244,12 @@
 		struct sock *raw_sk = raw_v4_htable[hash];
 		struct inet_protocol *ipprot;
 		int flag;
+
+#ifdef CONFIG_MAGNET
+		/* Mark IP hand-off to the upper layer protocol */
+		magnet_add(raw_sk, MAGNET_IP_RECV, skb->len,
+			     MAGNET_IP_DATA);
+#endif
 		/* If there maybe a raw socket we must check - if not we
 		 * don't care less
diff -PBbruw linux/net/ipv4/ip_output.c magnet/net/ipv4/ip_output.c
--- linux/net/ipv4/ip_output.c	Thu Sep  7 09:32:01 2000
+++ magnet/net/ipv4/ip_output.c	Fri Sep 15 13:23:35 2000
@@ -77,6 +77,10 @@
 #include <linux/mroute.h>
 #include <linux/netlink.h>
+#ifdef CONFIG_MAGNET
+#include <linux/magnet.h>
+#endif
+
 /*
  *      Shall we try to damage output packets if routing dev changes?
  */
@@ -149,6 +153,11 @@
 		ip_options_build(skb, opt, daddr, rt, 0);
 	}
 	ip_send_check(iph);
+
+#ifdef CONFIG_MAGNET
+	/* Mark IP hand-off to the physical layer */
+	magnet_add(sk, MAGNET_IP_SEND, skb->len, MAGNET_IP_DATA);
+#endif
 	/* Send it out. */
 	return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
diff -PBbruw linux/net/ipv4/tcp.c magnet/net/ipv4/tcp.c
--- linux/net/ipv4/tcp.c	Fri Aug 18 11:26:25 2000
+++ magnet/net/ipv4/tcp.c	Fri Oct 27 17:11:39 2000
@@ -426,6 +426,10 @@
 #include <asm/uaccess.h>
+#if defined (CONFIG_MAGNET)
+#include <linux/magnet.h>
+#endif
+
 int sysctl_tcp_fin_timeout = TCP_FIN_TIMEOUT;
 struct tcp_mib	tcp_statistics[NR_CPUS*2];
@@ -1531,6 +1538,11 @@
 		err = 0;
 		if (!(flags&MSG_TRUNC)) {
+#ifdef CONFIG_MAGNET
+			/* Mark the TCP hand-off to Socket */
+			magnet_add(sk,MAGNET_TCP_RSOCK,used,MAGNET_TCP_DATA);
+#endif
+
 			err = memcpy_toiovec(msg->msg_iov, ((unsigned char *)skb->h.th) + skb->h.th->doff*4 + offset, used);
 			if (err) {
 				/* Exception. Bailout! */
diff -PBbruw linux/net/ipv4/tcp_ipv4.c magnet/net/ipv4/tcp_ipv4.c
--- linux/net/ipv4/tcp_ipv4.c	Fri Aug 18 11:26:25 2000
+++ magnet/net/ipv4/tcp_ipv4.c	Thu Oct 26 14:59:03 2000
@@ -63,6 +63,10 @@
 #include <linux/stddef.h>
 #include <linux/ipsec.h>
+#if defined (CONFIG_MAGNET)
+#include <linux/magnet.h>
+#endif
+
 extern int sysctl_ip_dynaddr;
 /* Check TCP sequence numbers in ICMP packets. */
@@ -1623,6 +1627,9 @@
 	struct tcphdr *th;
 	struct sock *sk;
 	int ret;
+#ifdef CONFIG_MAGNET
+	struct tcp_opt *tp = NULL;
+#endif
 	if (skb->pkt_type!=PACKET_HOST)
 		goto discard_it;
@@ -1658,6 +1665,13 @@
 	if (!sk)
 		goto no_tcp_socket;
+
+
+#ifdef CONFIG_MAGNET
+	/* Mark TCP receive from IP layer */
+	tp = &(sk->tp_pinfo.af_tcp);
+	magnet_add(sk, MAGNET_TCP_SIP, len, MAGNET_TCP_DATA);
+#endif
 process:
 	if(!ipsec_sk_policy(sk,skb))
diff -PBbruw linux/net/ipv4/tcp_output.c magnet/net/ipv4/tcp_output.c
--- linux/net/ipv4/tcp_output.c	Fri Aug 18 11:26:25 2000
+++ magnet/net/ipv4/tcp_output.c	Tue Nov 14 10:29:20 2000
@@ -40,6 +40,10 @@
 #include <linux/smp_lock.h>
+#ifdef CONFIG_MAGNET
+#include <linux/magnet.h>
+#endif
+
 /* People can turn this off for buggy TCP's found in printers etc. */
 int sysctl_tcp_retrans_collapse = 1;
@@ -279,6 +283,10 @@
 		TCP_INC_STATS(TcpOutSegs);
+#ifdef CONFIG_MAGNET
+		/* Mark TCP hand-off to the IP layer */
+		magnet_add(sk, MAGNET_TCP_RIP, skb->len, MAGNET_TCP_DATA);
+#endif
 		err = tp->af_specific->queue_xmit(skb);
 		if (err <= 0)
 			return err;
@@ -309,6 +317,11 @@
 void tcp_send_skb(struct sock *sk, struct sk_buff *skb, int force_queue, unsigned cur_mss)
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+
+#ifdef CONFIG_MAGNET
+	/* Mark the socket hand-off to TCP */
+	magnet_add(sk,MAGNET_TCP_SSOCK,skb->len,MAGNET_TCP_DATA);
+#endif
 	/* Advance write_seq and place onto the write_queue. */
 	tp->write_seq = TCP_SKB_CB(skb)->end_seq;
diff -PBbruw linux/net/socket.c magnet/net/socket.c
--- linux/net/socket.c	Mon Aug 28 13:04:42 2000
+++ magnet/net/socket.c	Fri Sep 15 14:55:02 2000
@@ -86,6 +86,10 @@
 #include <net/scm.h>
 #include <linux/netfilter.h>
+#ifdef CONFIG_MAGNET
+#include <linux/magnet.h>
+#endif
+
 static int sock_no_open(struct inode *irrelevant, struct file *dontcare);
 static loff_t sock_lseek(struct file *file, loff_t offset, int whence);
 static ssize_t sock_read(struct file *file, char *buf,
@@ -507,6 +511,10 @@
 	err = scm_send(sock, msg, &scm);
 	if (err >= 0) {
+#ifdef CONFIG_MAGNET
+		magnet_add(sock->sk, MAGNET_SOCK_SEND, size,
+			     MAGNET_NO_DATA);
+#endif
 		err = sock->ops->sendmsg(sock, msg, size, &scm);
 		scm_destroy(&scm);
 	}
@@ -520,6 +528,10 @@
 	memset(&scm, 0, sizeof(scm));
 	size = sock->ops->recvmsg(sock, msg, size, flags, &scm);
+#ifdef CONFIG_MAGNET
+	magnet_add(sock->sk, MAGNET_SOCK_RECV, size,
+		     MAGNET_NO_DATA);
+#endif
 	if (size >= 0)
 		scm_recv(sock, msg, &scm, flags);
@@ -1704,6 +1716,14 @@
 #ifdef CONFIG_WAN_ROUTER
 	wanrouter_init();
+#endif
+
+	/*
+	 *     Socket Instrumentation Interface.
+	 */
+
+#ifdef CONFIG_MAGNET
+	magnet_init();
 #endif
 	/*
diff -PBbruw linux/net/magnet/Config.in magnet/net/magnet/Config.in
--- linux/net/magnet/Config.in	Wed Dec 31 17:00:00 1969
+++ magnet/net/magnet/Config.in	Wed Jan 10 10:28:22 2001
@@ -0,0 +1,5 @@
+#
+# MAGNeT configuration
+#
+bool '    MAGNeT: Enable Extended Instrumentation' CONFIG_MAGNET_EXTENDED
+bool '    MAGNeT: Instrument only socket calls (no protocol stack)' CONFIG_MAGNET_SOCK_ONLY
diff -PBbruw linux/net/magnet/Makefile magnet/net/magnet/Makefile
--- linux/net/magnet/Makefile	Wed Dec 31 17:00:00 1969
+++ magnet/net/magnet/Makefile	Tue Sep 12 09:50:18 2000
@@ -0,0 +1,18 @@
+#
+# Makefile for the socket instrumentation interface.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now in the main makefile...
+
+O_TARGET :=
+MOD_LIST_NAME :=
+
+O_OBJS  :=
+OX_OBJS := magnet.o
+
+M_OBJS :=
+
+include $(TOPDIR)/Rules.make
diff -PBbruw linux/net/magnet/magnet-parse.c magnet/net/magnet/magnet-parse.c
--- linux/net/magnet/magnet-parse.c	Wed Dec 31 17:00:00 1969
+++ magnet/net/magnet/magnet-parse.c	Thu Jan 11 14:36:02 2001
@@ -0,0 +1,296 @@
+/*
+  MAGNeT - Monitor for Application-Generated Network Traffic
+         - MAGNeT data file to ASCII text convertor
+	 - Written by Jeff Hay, jrhay@lanl.gov
+*/
+
+/* This is an application, distributed with the kernel source.  Therefore, its
+   likely to be built with the default kernel Makefiles, which define the
+   __KERNEL__ flag.  Undo this nonsense for this program... */
+#ifdef __KERNEL__
+#undef __KERNEL__
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <linux/magnet.h>
+
+/* Translate a  event code to a human-readable name */
+char *magnet_event_name(int event)
+{
+	char *name;
+
+	switch (event) {
+	case MAGNET_LOST: name = "Lost";
+		break;
+
+	case MAGNET_SOCK: name = "Socket";
+		break;
+	case MAGNET_SOCK_SEND: name = "Send";
+		break;
+	case MAGNET_SOCK_RECV: name = "Receive";
+		break;
+
+	case MAGNET_TCP: name = "TCP";
+		break;
+	case MAGNET_TCP_SSOCK: name = "Ap->TCP";
+		break;
+ 	case MAGNET_TCP_RSOCK: name = "TCP->Ap";
+		break;
+	case MAGNET_TCP_SIP: name = "IP->TCP";
+		break;
+	case MAGNET_TCP_RIP: name = "TCP->IP";
+		break;
+
+	case MAGNET_IP: name = "IP";
+		break;
+	case MAGNET_IP_SEND: name = "IP->net";
+		break;
+	case MAGNET_IP_RECV: name = "net->IP";
+		break;
+
+	default:
+		name = "Unknown";
+	}
+
+	return name;
+} /* magnet_event_name() */
+
+/* Print extended event data in human-readable form */
+char *magnet_extended_data(int event, union magnet_ext_data data)
+{
+
+#ifdef CONFIG_MAGNET_EXTENDED
+	static char databuf[1024];
+	int count;
+
+	count = 0;
+	if (event & MAGNET_SOCK) {
+		count += sprintf(databuf, "pid=%d,name=%s",
+				 data.sock.pid, data.sock.name);
+		/* Socket Events */
+	} else if (event & MAGNET_TCP) {
+		/* TCP Events */
+		count += sprintf(databuf,
+#if 0
+				 "source=%u,dest=%u,"
+				 "fin=%u,rst=%u,psh=%u,ack=%u,urg=%u,ece=%u,"
+				 "cwr=%u"
+#endif
+				 "snd_wnd=%lu,srtt=%lu,rto=%lu,packets_out=%lu"
+				 "retrans_out=%lu,snd_ssthresh=%lu,"
+				 "snd_cwnd=%lu,rcv_wnd=%lu,write_seq=%lu,"
+				 "copied_seq=%lu",
+#if 0
+				 data.tcp.source,data.tcp.dest,
+				 data.tcp.fin,data.tcp.rst,data.tcp.psh,
+				 data.tcp.ack,data.tcp.urg,data.tcp.ece,
+				 data.tcp.cwr,
+#endif
+				 data.tcp.snd_wnd,data.tcp.srtt,data.tcp.rto,
+				 data.tcp.packets_out,data.tcp.retrans_out,
+				 data.tcp.snd_ssthresh,data.tcp.snd_cwnd,
+				 data.tcp.rcv_wnd,data.tcp.write_seq,
+				 data.tcp.copied_seq);
+	} else if (event & MAGNET_IP) {
+		/* IP Events */
+		count += sprintf(databuf,
+				 "version=%u,tos=%u,id=%u,frag_off=%u,"
+				 "ttl=%u,protocol=%u",
+				 data.ip.version,data.ip.tos, data.ip.id,
+				 data.ip.frag_off,data.ip.ttl,
+				 data.ip.protocol);
+	}
+
+	databuf[count] = '\0';
+
+	return databuf;
+#else
+	char *databuf = "";
+	return databuf;
+#endif // defined CONFIG_MAGNET_EXTENDED
+
+} /* magnet_extended_data() */
+
+/* Report what we know  */
+int magnet_parse(void *si_data, int *datalen, char *buf, int len)
+{
+	struct magnet_data *sicurrent;
+	char *name;
+	int count, outlen, offset;
+	int error = 0;
+
+	len = len - 1;
+	outlen = offset = 0;
+	while (((*datalen - offset) >= sizeof(struct magnet_data)) &&
+	       (outlen < len))  {
+		sicurrent = (struct magnet_data *)(si_data+offset);
+		count = snprintf(buf+outlen, len-outlen,
+				 "%llu\t%p\t%6u\t%s\t%s\n",
+				 sicurrent->timestamp,
+				 sicurrent->sockid,
+				 sicurrent->size,
+				 (name = magnet_event_name(sicurrent->event)),
+				 magnet_extended_data(sicurrent->event,
+						      sicurrent->data)
+			);
+		if (!strcmp(name, "Unknown")) {
+			fprintf(stderr,
+		     "Error: Unknown MAGNeT Event Type Found in Data File!\n");
+			return -1 * offset;
+		}
+
+		if ((outlen+count) <= len)
+		{ /* Make sure we only output complete lines */
+			outlen += count;
+			offset += sizeof(struct magnet_data);
+		}
+		else
+			*datalen = offset;
+	}
+
+	if (outlen > 0)
+		buf[outlen] = '\0';
+	*datalen = offset;
+
+	if (error > 0)
+		outlen = -1 * outlen;
+
+	return outlen;
+} /* magnet_parse() */
+
+void hexprint(void *buffer, int buflen, int From, int To, int Mark)
+/* Prints a "hex dump" of a specified region of memory.  Each line of the dump
+   contains 16 bytes of data, with an offset, hex values, and text translation,
+   and looks something like:
+   "864: D9 CA 28 DA AB 87 48 D9 10 0C 93 C3 80 36 EE C3  || ..(...H......6.."
+
+   The dump proceeds from byte "From" to byte "To" of buffer.  If Mark
+   is non-zero, then the byte at abs(Mark) is specially indicated.  If
+   From is less then 0, or greater then buflen, From is forced to zero.
+   If To is less then or equal to zero, less then or equal to From, or
+   greater then buflen, it too is forced to zero.  If the value of Mark
+   is outside the range formed by From and To, Mark is forced to zero.
+   Byte counting starts at zero.
+*/
+
+{
+	int count, out;
+	char letter;
+	char hex[45], text[17];
+
+	/* Error Checking - make sure we're all within our boundries */
+	if ((From < 0) || (From > buflen))
+		From = 0;
+	if ((To <= 0) || (To > buflen) || (To <= From))
+		To = buflen;
+	Mark = abs(Mark);
+	if ((Mark < From) || (Mark > To))
+		Mark = 0;
+
+	hex[0] = '\0';
+	text[0] = '\0';
+	out = 0;
+	for(count=From; count <= To; count++) {
+		/* Print hex value of the next byte,
+		   and store that value in 'letter' */
+		sprintf(hex, "%s%2.2X ", hex,
+			(((char *)buffer)[count] & 0x0FF));
+		letter = ((char *)buffer)[count];
+
+		/* If 'letter' is within printable ASCII character range,
+		   print it; otherwise, print a '.' */
+		if ((letter >= ' ') && (letter <= '~'))
+			sprintf(text, "%s%c", text, letter);
+		else
+			sprintf(text, "%s.", text);
+
+		/* If we've processed an output-line worth, print the line,
+		   Marking the Mark byte, if requested */
+		out++;
+		if ((out % 16) == 0) {
+			if ((Mark > 0) && (Mark < (count+1))) {
+				printf("%d: %s *| %s (%d)\n",
+				       (count-15), hex, text,
+				       16 - (count - Mark));
+				Mark = 0;
+			}
+			else
+				printf("%d: %s || %s\n",
+				       (count-15), hex, text);
+			hex[0] = '\0';
+			text[0] = '\0';
+		}
+	}
+	/* Print remaining information (processed, but not a full line) */
+	printf("%d: %-48s || %-16s\n", (count-(count%16)), hex, text);
+
+	return;
+} /* hexprint() */
+
+
+int main(int argc, char *argv[]) {
+  FILE *infile;
+  struct magnet_data* si_data; /* Shared memory region */
+  unsigned long long bytes;
+  unsigned long long outcount;
+  char outbuf[4096];
+  int count, error, offset;
+
+
+  printf("%s: MAGNeT Data File Reader\n\n", argv[0]);
+
+  if (argc < 2) {
+    fprintf(stderr," syntax: %s <MAGNeT data file> \n\n", argv[0]);
+    return -1;
+  }
+
+  if ((infile = fopen(argv[1], "r")) == NULL) {
+    fprintf(stderr,"%s: Unable to read input file \"%s\"\n",argv[0],argv[1]);
+    return -2;
+  }
+
+  if ((si_data=malloc(SI_DATA_SIZE)) == NULL) {
+    fprintf(stderr, "%s: Can not allocate read buffer\n", argv[0]);
+    return -3;
+  }
+
+  bytes=0;
+  outcount=0;
+  count = 0;
+  while ((count = fread(((void*)si_data)+count,
+			1, SI_DATA_SIZE-count, infile)) > 0) {
+    bytes += count;
+    if ((error=magnet_parse(si_data, &count, outbuf, sizeof(outbuf))) > 0)
+      {
+	outcount++;
+	printf("%s\n", outbuf);
+	if (count < SI_DATA_SIZE)
+	  memcpy(si_data, ((void *)si_data)+count, SI_DATA_SIZE-count);
+	count = SI_DATA_SIZE-count;
+      }
+    else
+      {
+	printf("ERROR - <%llu>: %s -- ERROR\n", outcount, outbuf);
+	printf("Error at position %llu\n", (bytes + abs(error)));
+	offset = (-1 * error);
+
+	printf("Union Size: %d\n", sizeof(union magnet_ext_data));
+	hexprint((void *)si_data, SI_DATA_SIZE,
+		 offset - sizeof(struct magnet_data), offset-1, 0);
+	printf("\n");
+	hexprint((void *)si_data, SI_DATA_SIZE,
+		 offset, offset+sizeof(struct magnet_data)-1,error);
+	printf("\n");
+	hexprint((void *)si_data, SI_DATA_SIZE,
+		 offset + sizeof(struct magnet_data),
+		 offset + 2*sizeof(struct magnet_data)-1, 0);
+	printf("\n");
+	return -4;
+      }
+  }
+
+  free(si_data);
+  fclose(infile);
+  return 0;
+} /* main() */
diff -PBbruw linux/net/magnet/magnet-read.c magnet/net/magnet/magnet-read.c
--- linux/net/magnet/magnet-read.c	Wed Dec 31 17:00:00 1969
+++ magnet/net/magnet/magnet-read.c	Thu Jan 11 14:10:49 2001
@@ -0,0 +1,181 @@
+/*
+  MAGNeT - Monitor for Application-Generated Network Traffic
+         - User-mode monitor information reader
+	 - Written Nov 2000, Jeff Hay, jrhay@lanl.gov
+*/
+
+/* This is an application, distributed with the kernel source.  Therefore, its
+   likely to be built with the default kernel Makefiles, which define the
+   __KERNEL__ flag.  Undo this nonsense for this program... */
+#ifdef __KERNEL__
+#undef __KERNEL__
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <linux/magnet.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+/* Global (ie, syrnconization, etc) variables */
+int fileout;
+int magnet, sleepwatch;
+struct magnet_data *kernel_data;
+struct magnet_data *save_data;
+
+/* Computes a default time to sleep (in ms) between reading instrumentation
+   data from the kernel, along with high- and low-water marks (used for dynamic
+   adjustment of sleep time, if requested) */
+unsigned int get_sleeptime(unsigned int *high_water,
+			   unsigned int *low_water)
+{
+	unsigned int num_packets, packet_size, net_speed, pkts_second;
+	unsigned int data_rate, drain_rate, sleep_time;
+
+
+	/* Initial Sleep time calculation */
+	packet_size = 1;  /* 1-byte packets (worst-case estimation) */
+	net_speed = 100;  /* 100 Mbs network */
+	pkts_second = (net_speed * 1000000) / (packet_size * 8);
+	data_rate = pkts_second * sizeof(struct magnet_data) * 4;
+	drain_rate = data_rate / (int)(SI_DATA_SIZE); /* Drain this quickly */
+	printf("Max network rate: %d packets/second.\n", pkts_second);
+	printf("   Max data rate: %d bytes/second.\n", data_rate);
+	printf("Kernel buffer will be drained %d times per second\n",
+	       drain_rate);
+	sleep_time = 1000000 / drain_rate;
+	printf("\n");
+
+	if ((high_water != NULL) && (low_water != NULL)) {
+		/* high and low water marks */
+		num_packets = ((int)(SI_DATA_SIZE)) /
+			sizeof(struct magnet_data);
+		*low_water = num_packets / 4;
+		*high_water = 3 * *low_water;
+		printf("High-water mark: %d packets\n", *high_water);
+		printf("Low-Water mark: %d packets\n", *low_water);
+	}
+
+	return sleep_time;
+} /* get_sleeptime() */
+
+void read_kernel_data(int maxwrite) {
+	unsigned int num_packets, sleep_time, high_water, low_water;
+	struct magnet_data *current, *out_data;
+	int count, sleepcount;
+	struct timeval timeout;
+	int written;
+
+	printf("Memory area successfully mapped\n");
+	sleep_time = get_sleeptime(&high_water, &low_water);
+	printf("Recording started; Reading maximum of %d bytes\n", maxwrite);
+
+	num_packets = ((int)(SI_DATA_SIZE)) / sizeof(struct magnet_data);
+	count = 0;
+	current = kernel_data;
+	written = 0;
+	out_data = save_data;
+	while ((maxwrite <= 0) || (written < maxwrite)) {
+		timeout.tv_sec = 0;
+		timeout.tv_usec = sleep_time;
+		select(0, NULL, NULL, NULL, &timeout);
+
+		sleepcount = 0;
+		while (current->timestamp != 0) {
+			memcpy(out_data++, current,
+			       sizeof(struct magnet_data));
+			written += sizeof(struct magnet_data);
+
+			current->timestamp = 0;
+			current++;
+			if (++count >= num_packets) {
+				current = kernel_data;
+				count = 0;
+			}
+			sleepcount++;
+		}
+
+		if ((sleepwatch) && (sleepcount > 0)) {
+			if (sleepcount >= high_water)
+				sleep_time /= 2;
+			else if (sleepcount <= low_water)
+				sleep_time *= 2;
+		}
+  }
+
+  printf("syncing mmap file\n");
+  msync(save_data, maxwrite, MS_SYNC);
+  return;
+} /* read_kernel_data() */
+
+int main(int argc, char *argv[]) {
+  struct stat outstat;
+
+  printf("%s: Monitor for Application Generated Network Traffic\n\n", argv[0]);
+
+  if (argc < 3) {
+    fprintf(stderr, " syntax: %s <magnet file> <output file> [-d]\n\n",
+	    argv[0]);
+    fprintf(stderr, " \"-d\" = Dynamic Sleep Time Adjustment enabled\n");
+    return -1;
+  }
+
+  sleepwatch = 0;
+  if ((argc > 3) && (!strcmp(argv[3], "-d"))) {
+    sleepwatch = 1;
+  }
+
+  if ((fileout = open(argv[2], O_RDWR|O_NDELAY)) <= 0) {
+	  fprintf(stderr, "%s: Can not open output file \"%s\"\n",
+		  argv[0], argv[2]);
+	  fprintf(stderr, "%s: Is the file created?  If not, try mkmagnet\n",
+		  argv[0]);
+	  return -2;
+  }
+  if (fstat(fileout, &outstat) != 0) {
+	  fprintf(stderr, "%s: Can not stat output file \"%s\"\n",
+		  argv[0], argv[2]);
+	  return -2;
+  }
+  if (outstat.st_size <= 0) {
+	  fprintf(stderr, "%s: Output file must be non-zero length\n",
+		  argv[0]);
+	  return -3;
+  }
+
+  if (!(magnet = open(argv[1], O_RDONLY))) {
+    fprintf(stderr, "%s: \"%s\" is not a valid MAGNeT device file\n",
+	    argv[0], argv[1]);
+    return -1;
+  }
+  printf("\tRecording %d bytes of data\n", (int)outstat.st_size);
+
+  /* Map the shared memory region into our own space */
+  if ((kernel_data = (struct magnet_data *)
+       mmap(NULL,SI_DATA_SIZE,PROT_READ,MAP_PRIVATE,magnet,0)) == NULL) {
+	  perror("Can not map kernel instrumentation data");
+	  return -1;
+  }
+
+  if ((save_data = (struct magnet_data *)
+       mmap(NULL,outstat.st_size,PROT_WRITE,MAP_SHARED,fileout,0)) == NULL) {
+	  perror("Can not mmap output file");
+	  return -1;
+  }
+  mlock(save_data, outstat.st_size);
+
+  read_kernel_data(outstat.st_size);
+
+  printf("Closing shared memory\n");
+  munmap(kernel_data, SI_DATA_SIZE);
+  munmap(save_data, outstat.st_size);
+  munlock(save_data, outstat.st_size);
+  close(magnet);
+  close(fileout);
+
+  exit(0);
+} /* main() */
diff -PBbruw linux/net/magnet/mkmagnet.c magnet/net/magnet/mkmagnet.c
--- linux/net/magnet/mkmagnet.c	Wed Dec 31 17:00:00 1969
+++ magnet/net/magnet/mkmagnet.c	Thu Jan 11 14:07:51 2001
@@ -0,0 +1,67 @@
+/*
+  MAGNeT - Monitor for Application-Generated Network Traffic
+         - MAGNeT storage file creator
+	 - Written by Jeff Hay, jrhay@lanl.gov
+*/
+
+/* This is an application, distributed with the kernel source.  Therefore, its
+   likely to be built with the default kernel Makefiles, which define the
+   __KERNEL__ flag.  Undo this nonsense for this program... */
+#ifdef __KERNEL__
+#undef __KERNEL__
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define BufferSize 1024*1024
+
+int main(int argc, char *argv[])
+{
+  FILE *OutFile;
+  int FinalSize = 0, Steps = 0;
+  void *DataSpace;
+
+  printf("%s: MAGNeT Data Storage File Maker\n\n", argv[0]);
+
+  if (argc < 3) {
+    fprintf(stderr," syntax: %s <new data file name>  <file bytes>\n",
+	    argv[0]);
+    return -1;
+  }
+
+  if ((FinalSize = atoi(argv[2])) <= 0) {
+    fprintf(stderr, "%s: \"%s\" is not a valid file byte count; aborting.\n",
+	    argv[0], argv[1]);
+    return -2;
+  }
+
+  if (!(OutFile = fopen(argv[1], "wb"))) {
+    fprintf(stderr, "%s: Can not open \"%s\" for writing/creating\n",
+	    argv[0], argv[1]);
+    return -1;
+  }
+
+  if ((DataSpace = calloc(BufferSize, 1)) == NULL) {
+    fprintf(stderr, "%s: Out of Memory; Can not create data store!\n",
+	    argv[0]);
+    return -3;
+  }
+  printf("\tGenerating space for %d bytes of data\n", FinalSize);
+
+  Steps = 0;
+  while (FinalSize > (BufferSize)) {
+    Steps++;
+    FinalSize -= BufferSize;
+  }
+
+  while (Steps-- > 0) {
+    fwrite(DataSpace, BufferSize, 1, OutFile);
+  }
+  fwrite(DataSpace, FinalSize, 1, OutFile);
+
+  fclose(OutFile);
+  free(DataSpace);
+  return 0;
+} /* main() */
diff -PBbruw linux/net/magnet/magnet.c magnet/net/magnet/magnet.c
--- linux/net/magnet/magnet.c	Wed Dec 31 17:00:00 1969
+++ magnet/net/magnet/magnet.c	Tue Jan 23 14:37:16 2001
@@ -0,0 +1,252 @@
+/*
+ * MAGNET	 Monitor for Application Generated Network Traffic
+ *
+ * Version:	@(#)magnet.c	0.1.0	2001/02/17
+ *
+ * Author:	Jeff Hay, <jrhay@lanl.gov>
+ *
+ * Fixes:
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/mm.h>
+
+#include <asm/page.h>
+#include <net/sock.h>
+
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/fs.h>
+#include <asm/io.h>
+#include <linux/miscdevice.h>
+#include <linux/wrapper.h>
+
+#include <linux/magnet.h>
+
+#include <linux/smp_lock.h>
+
+/*
+  mmap() structures to facilitate user/kernel shared memory
+*/
+
+static struct file_operations magnet_fops = {
+  mmap:    magnet_mmap,
+  open:    magnet_open,
+  release: magnet_close
+};
+
+// This corresponds with a /dev/magnet device with
+// major number 10, minor MISC_DYNAMIC_MINOR (normally 63)
+static struct miscdevice magnet_device = {
+  minor:  MISC_DYNAMIC_MINOR,
+  name:   "magnet",
+  fops:   &magnet_fops
+};
+
+/*
+  Globbal Magnet Variables
+*/
+
+/* Global socket instrumentation variables */
+char *magnet_data;                           /* kernel-space magnet buffer */
+char *si_data_offs;                            /* where kernelspace is in buffer */
+unsigned int si_lost_pkts;                     /* Info overwritten before user-level read */
+
+/*
+   Routines to access magnet data
+*/
+extern int magnet_procread(char *buf, char **extbuf, off_t offset, int len)
+{
+	len = 0;
+        len = sprintf(buf+len, "MAGNeT: Monitor for Application Generated Network Traffic\n");
+	len += sprintf(buf+len, "Research tool created by Los Alamos National Laboratory's RADIANT Team\n");
+	len += sprintf(buf+len, "(http://www.lanl.gov/radiant)\n\n");
+	len += sprintf(buf+len, "      MAGNeT Device Name: /dev/%s\n", magnet_device.name);
+	len += sprintf(buf+len, "    MAGNeT Device Number: 10, %d\n", magnet_device.minor);
+	len += sprintf(buf+len, "  Kernel Memory Reserved: %ld Kb (%ld pages)\n",
+		       (SI_DATA_SIZE / 1024), (SI_DATA_SIZE / PAGE_SIZE));
+	len += sprintf(buf+len, "        Data packet size: %d bytes\n",sizeof(struct magnet_data));
+	len += sprintf(buf+len, "Extended Instrumentation: ");
+#ifdef CONFIG_MAGNET_EXTENDED
+	len += sprintf(buf+len, "on\n");
+#else
+	len += sprintf(buf+len, "off\n");
+#endif
+	len += sprintf(buf+len, "   Instrument All Events: ");
+#ifdef CONFIG_MAGNET_SOCK_ONLY
+	len += sprintf(buf+len, "off\n");
+#else
+	len += sprintf(buf+len, "on\n");
+#endif
+	len += sprintf(buf+len, "\n");
+        return len;
+}
+
+__inline__ void magnet_add(struct sock *sk,
+			     unsigned int si_event,
+			     unsigned int si_size,
+			     union magnet_ext_data data)
+{
+	unsigned int datasize = sizeof(struct magnet_data);
+	struct magnet_data *sicurrent;
+	unsigned long long currenttime;
+
+
+	currenttime = get_cycles();
+
+	if ((magnet_data == NULL) || (si_size < 1))
+		return;
+
+#ifdef CONFIG_MAGNET_SOCK_ONLY
+	if ((si_event & MAGNET_SOCK) == 0) /* mask out all non-socket calls */
+		return;
+#endif
+
+	sicurrent = (struct magnet_data *)si_data_offs;
+	if (sicurrent->timestamp == 0) {
+		if (si_lost_pkts > 0) {
+			sicurrent->sockid = NULL;
+			sicurrent->event  = MAGNET_LOST;
+			sicurrent->size   = si_lost_pkts+1;
+			si_lost_pkts      = 0;
+		} else {
+			sicurrent->sockid = sk;
+			sicurrent->event  = si_event;
+			sicurrent->size   = si_size;
+#ifdef CONFIG_MAGNET_EXTENDED
+			sicurrent->data   = data;
+#endif
+		}
+		/* Write timestamp last as a signal to user-space program */
+		sicurrent->timestamp = currenttime;
+
+		si_data_offs += datasize;
+		if (si_data_offs >= (magnet_data + SI_DATA_SIZE - datasize - 1)) {
+			si_data_offs = magnet_data;
+		}
+
+	} else {
+		si_lost_pkts++;
+	}
+
+	return;
+}
+
+
+/* Initialize socket instrumentation interface */
+int magnet_setup()
+{
+	struct page *page;
+	int error;
+
+	/* Initialize kernel-space pointer into buffer */
+	si_data_offs = magnet_data;
+
+	/* Create /proc/net/magnet file for reporting misc. status */
+	proc_net_create("magnet", S_IFREG | S_IRUGO, magnet_procread);
+
+	/* Pin down our buffer's pages, so it can't be swapped out */
+	for (page = virt_to_page(magnet_data);
+	     page < virt_to_page(magnet_data + SI_DATA_SIZE);
+	     page++)
+		mem_map_reserve(page);
+
+	/* Register as a misc char device for doing mmap's */
+	error = misc_register(&magnet_device);
+
+	return error;
+}
+
+/* Called at boot-time when socket code is being initialized */
+void magnet_init()
+{
+	printk(KERN_INFO "NET4: MAGNeT: Socket Instrumentation Interface for NET4.0\n");
+	if ((magnet_data = (char *)__get_free_pages(
+		GFP_ATOMIC, get_order(SI_DATA_SIZE))) == NULL)
+		printk(KERN_ERR "NET4: MAGNeT: No memory for instrumentation buffer\n");
+	else
+		magnet_setup();
+	return;
+}
+
+/* Teardown socket instrumentation interface
+   (this is never called in the current implementation.  Code listed here
+    to make converting this to a module "easy"....)
+*/
+void magnet_destroy()
+{
+	struct page *page;
+
+	/* disable mmap()ing of buffer space */
+	misc_deregister(&magnet_device);
+
+	/* un-pin buffer space */
+	for (page = virt_to_page(magnet_data);
+	     page < virt_to_page(magnet_data + SI_DATA_SIZE);
+	     page++)
+		mem_map_unreserve(page);
+
+	/* remove /proc information hook */
+	proc_net_remove("magnet");
+	return;
+}
+
+/*
+  mmap() shared-memory routines
+*/
+
+int magnet_open(struct inode *inode, struct file *file)
+{
+	/* Do nothing; this is just a dummy procedure to make the
+	   VFS happy... */
+//	printk(KERN_INFO "magnet: opening mmap file\n");
+	return 0;
+}
+
+int magnet_close(struct inode *inode, struct file *file)
+{
+	/* Do nothing; this is just a dummy procedure to make the
+	   VFS happy... */
+//	printk(KERN_INFO "magnet: closing mmap file\n");
+	return 0;
+}
+
+int magnet_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	/* Set up the shared memory to user-level process */
+	unsigned long size = (unsigned long)(vma->vm_end - vma->vm_start);
+
+	/* First, make sure we're within bounds */
+	if (size > SI_DATA_SIZE)
+		return -EINVAL;
+
+	lock_kernel();
+	/* Step through our buffer a page at a time, and remap each page
+	   into the user-mode address space */
+	if (remap_page_range(vma->vm_start,
+			     virt_to_phys(magnet_data),
+			     size, PAGE_SHARED)) {
+		printk(KERN_ERR "MAGNeT: remapping failed\n");
+		return -EAGAIN;
+	}
+
+        /* Don't swap this VMA out! */
+	vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
+
+	/* Clear the memory so user doesn't read old information */
+	memset(magnet_data, 0, size);
+	si_lost_pkts = 0;
+
+	unlock_kernel();
+
+	/* Success! */
+	return 0;
+}