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, + * + * 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 + +#ifdef __KERNEL__ +/* for macrology */ +#include +#include +#include +#endif + +#include /* 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 + +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 #include +#ifdef CONFIG_MAGNET +#include +#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 #include +#ifdef CONFIG_MAGNET +#include +#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 +#if defined (CONFIG_MAGNET) +#include +#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 #include +#if defined (CONFIG_MAGNET) +#include +#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 +#ifdef CONFIG_MAGNET +#include +#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 #include +#ifdef CONFIG_MAGNET +#include +#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 +#include +#include + +/* 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 \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 +#include + +#include +#include +#include +#include +#include +#include + +/* 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 [-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 +#include +#include + +#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 \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, + * + * 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 + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include + +/* + 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; +}