patch-2.3.15 linux/net/atm/mpoa_proc.c

Next file: linux/net/atm/proc.c
Previous file: linux/net/atm/mpoa_caches.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.14/linux/net/atm/mpoa_proc.c linux/net/atm/mpoa_proc.c
@@ -0,0 +1,391 @@
+#include <linux/config.h>
+
+#ifdef CONFIG_PROC_FS
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/string.h> 
+#include <linux/mm.h>
+#include <linux/proc_fs.h>
+#include <linux/time.h>
+#include <asm/uaccess.h>
+#include <linux/atmmpc.h>
+#include <linux/atm.h>
+#include "mpc.h"
+#include "mpoa_caches.h"
+
+/*
+ * mpoa_proc.c: Implementation MPOA client's proc
+ * file system statistics 
+ */
+
+#if 1
+#define dprintk printk   /* debug */
+#else
+#define dprintk(format,args...)
+#endif
+
+#define STAT_FILE_NAME "mpc"     /* Our statistic file's name */
+
+extern struct mpoa_client *mpcs;
+extern struct proc_dir_entry atm_proc_root;  /* from proc.c. */
+
+static ssize_t proc_mpc_read(struct file *file, char *buff,
+			     size_t count, loff_t *pos);
+
+static ssize_t proc_mpc_write(struct file *file, const char *buff,
+                              size_t nbytes, loff_t *ppos);
+
+static int parse_qos(const char *buff, int len);
+
+/*
+ *   Define allowed FILE OPERATIONS
+ */
+static struct file_operations mpc_file_operations = {
+        NULL,                   /* lseek */
+        proc_mpc_read,          /* read */
+        proc_mpc_write,         /* write */
+        NULL,                   /* readdir */
+        NULL,                   /* poll - default */
+        NULL,                   /* ioctl - default */
+        NULL,                   /* mmap */
+        NULL,                   /* no special open code */
+        NULL,                   /* no special release code */
+        NULL                    /* no fsync */
+};
+
+/*
+ *   Define allowed INODE OPERATIONS
+ */
+static struct inode_operations mpc_inode_operations = {
+        &mpc_file_operations,
+        NULL,                   /* create */
+        NULL,                   /* lookup */
+        NULL,                   /* link */
+        NULL,                   /* unlink */
+        NULL,                   /* symlink */
+        NULL,                   /* mkdir */
+        NULL,                   /* rmdir */
+        NULL,                   /* mknod */
+        NULL,                   /* rename */
+        NULL,                   /* readlink */
+        NULL,                   /* follow_link */
+        NULL,                   /* readpage */
+        NULL,                   /* writepage */
+        NULL,                   /* bmap */
+        NULL,                   /* truncate */
+        NULL                    /* permission */
+};
+
+/*
+ *  Our statistics file
+ */
+static struct proc_dir_entry mpc_stats = {
+        0,                            /* low_ino           */
+	sizeof(STAT_FILE_NAME)-1,     /* name length       */
+	STAT_FILE_NAME,               /* name              */
+	S_IFREG | S_IRUGO,            /* mode              */
+	1,                            /* 1=file            */
+        0,                            /* UID               */
+        0,                            /* GID               */
+        0,                            /* size              */
+        &mpc_inode_operations,        /* inode operations  */
+        NULL                          /* get_info func-ptr */
+
+};  
+
+static int print_header(char *buff,struct mpoa_client *mpc){
+        if(mpc != NULL){
+	        return sprintf(buff,"\nInterface %d:\n\n",mpc->dev_num);  
+	  
+	}
+	return 0;
+}
+
+/*
+ * Returns the state of an ingress cache entry as a string
+ */
+static const char *ingress_state_string(int state){
+        switch(state) {
+	case INGRESS_RESOLVING:
+	        return "resolving  ";
+		break;
+	case INGRESS_RESOLVED:
+                return "resolved   ";
+		break;
+	case INGRESS_INVALID:
+	        return "invalid    ";
+		break;
+	case INGRESS_REFRESHING:
+	        return "refreshing ";
+		break;
+	default:
+	       return "";
+	}
+}
+
+/*
+ * Returns the state of an egress cache entry as a string
+ */
+static const char *egress_state_string(int state){
+        switch(state) {
+	case EGRESS_RESOLVED:
+	        return "resolved   ";
+		break;
+	case EGRESS_PURGE:
+                return "purge      ";
+		break;
+	case EGRESS_INVALID:
+	        return "invalid    ";
+		break;
+	default:
+	       return "";
+	}
+}
+
+/*
+ * READING function - called when the /proc/atm/mpoa file is read from.
+ */
+static ssize_t proc_mpc_read(struct file *file, char *buff,
+			     size_t count, loff_t *pos){
+        unsigned long page = 0;
+	unsigned char *temp;
+        ssize_t length  = 0;
+	int i = 0;
+	struct mpoa_client *mpc = mpcs;
+	in_cache_entry *in_entry;
+	eg_cache_entry *eg_entry;
+	struct timeval now;
+	unsigned char ip_string[16];
+	if(count < 0)
+	        return -EINVAL;
+	if(count == 0)
+	        return 0;
+	page = get_free_page(GFP_KERNEL);
+	if(!page)
+	        return -ENOMEM;
+	atm_mpoa_disp_qos((char *)page, &length);
+	while(mpc != NULL){
+	        length += print_header((char *)page + length, mpc);
+		length += sprintf((char *)page + length,"Ingress Entries:\nIP address      State      Holding time  Packets fwded  VPI  VCI\n");
+		in_entry = mpc->in_cache;
+		do_gettimeofday(&now);
+		while(in_entry != NULL){
+		        temp = (unsigned char *)&in_entry->ctrl_info.in_dst_ip;                        sprintf(ip_string,"%d.%d.%d.%d", temp[0], temp[1], temp[2], temp[3]);
+		        length += sprintf((char *)page + length,"%-16s%s%-14lu%-12u", ip_string, ingress_state_string(in_entry->entry_state), (in_entry->ctrl_info.holding_time-(now.tv_sec-in_entry->tv.tv_sec)), in_entry->packets_fwded);
+			if(in_entry->shortcut)
+			        length += sprintf((char *)page + length,"   %-3d  %-3d",in_entry->shortcut->vpi,in_entry->shortcut->vci);
+			length += sprintf((char *)page + length,"\n");
+			in_entry = in_entry->next;
+		}
+		length += sprintf((char *)page + length,"\n");
+		eg_entry = mpc->eg_cache;
+		length += sprintf((char *)page + length,"Egress Entries:\nIngress MPC ATM addr\nCache-id        State      Holding time  Packets recvd  Latest IP addr   VPI VCI\n");
+		while(eg_entry != NULL){
+		  for(i=0;i<ATM_ESA_LEN;i++){
+		          length += sprintf((char *)page + length,"%02x",eg_entry->ctrl_info.in_MPC_data_ATM_addr[i]);}  
+		        length += sprintf((char *)page + length,"\n%-16lu%s%-14lu%-15u",ntohl(eg_entry->ctrl_info.cache_id), egress_state_string(eg_entry->entry_state), (eg_entry->ctrl_info.holding_time-(now.tv_sec-eg_entry->tv.tv_sec)), eg_entry->packets_rcvd);
+			
+			/* latest IP address */
+			temp = (unsigned char *)&eg_entry->latest_ip_addr;
+			sprintf(ip_string, "%d.%d.%d.%d", temp[0], temp[1], temp[2], temp[3]);
+			length += sprintf((char *)page + length, "%-16s", ip_string);
+
+			if(eg_entry->shortcut)
+			        length += sprintf((char *)page + length," %-3d %-3d",eg_entry->shortcut->vpi,eg_entry->shortcut->vci);
+			length += sprintf((char *)page + length,"\n");
+			eg_entry = eg_entry->next;
+		}
+		length += sprintf((char *)page + length,"\n");
+		mpc = mpc->next;
+	}
+
+	if (*pos >= length) length = 0;
+	else {
+	  if ((count + *pos) > length) count = length - *pos;
+	  copy_to_user(buff, (char *)page , count);
+	  *pos += count;
+	}
+
+ 	free_page(page);
+        return length;
+}
+
+static ssize_t proc_mpc_write(struct file *file, const char *buff,
+                              size_t nbytes, loff_t *ppos)
+{
+        int incoming, error, retval;
+        char *page, c;
+        const char *tmp;
+
+        if (nbytes < 0) return -EINVAL;
+        if (nbytes == 0) return 0;
+        if (nbytes > PAGE_SIZE) nbytes = PAGE_SIZE-1;
+
+        error = verify_area(VERIFY_READ, buff, nbytes);
+        if (error) return error;
+
+        page = (char *)__get_free_page(GFP_KERNEL);
+        if (page == NULL) return -ENOMEM;
+
+        incoming = 0;
+        tmp = buff;
+        while(incoming < nbytes){
+                if (get_user(c, tmp++)) return -EFAULT;
+                incoming++;
+                if (c == '\0' || c == '\n')
+                        break;
+        }
+
+        retval = copy_from_user(page, buff, incoming);
+        if (retval != 0) {
+                printk("mpoa: proc_mpc_write: copy_from_user() failed\n");
+                return -EFAULT;
+        }
+
+        *ppos += incoming;
+
+        page[incoming] = '\0';
+	retval = parse_qos(buff, incoming);
+        if (retval == 0)
+                printk("mpoa: proc_mpc_write: could not parse '%s'\n", page);
+
+        free_page((unsigned long)page);
+        
+        return nbytes;
+}
+
+static int parse_qos(const char *buff, int len)
+{
+        /* possible lines look like this
+         * add 130.230.54.142 tx=max_pcr,max_sdu rx=max_pcr,max_sdu
+         */
+        
+        int pos, i;
+        uint32_t ipaddr;
+        unsigned char ip[4]; 
+        char cmd[4], temp[256];
+        const char *tmp, *prev;
+	struct atm_qos qos; 
+	int value[5];
+        
+        memset(&qos, 0, sizeof(struct atm_qos));
+        strncpy(cmd, buff, 3);
+        if( strncmp(cmd,"add", 3) &&  strncmp(cmd,"del", 3))
+	        return 0;  /* not add or del */
+
+	pos = 4;
+        /* next parse ip */
+        prev = buff + pos;
+        for (i = 0; i < 3; i++) {
+                tmp = strchr(prev, '.');
+                if (tmp == NULL) return 0;
+                memset(temp, '\0', 256);
+                memcpy(temp, prev, tmp-prev);
+                ip[i] = (char)simple_strtoul(temp, NULL, 0);
+		tmp ++; 
+		prev = tmp;
+        }
+	tmp = strchr(prev, ' ');
+        if (tmp == NULL) return 0;
+        memset(temp, '\0', 256);
+        memcpy(temp, prev, tmp-prev);
+        ip[i] = (char)simple_strtoul(temp, NULL, 0);
+        ipaddr = *(uint32_t *)ip;
+                
+	if(!strncmp(cmd, "del", 3))
+	         return atm_mpoa_delete_qos(atm_mpoa_search_qos(ipaddr));
+
+        /* next transmit values */
+	tmp = strstr(buff, "tx=");
+	if(tmp == NULL) return 0;
+	tmp += 3;
+	prev = tmp;
+	for( i = 0; i < 1; i++){
+	         tmp = strchr(prev, ',');
+		 if (tmp == NULL) return 0;
+		 memset(temp, '\0', 256);
+		 memcpy(temp, prev, tmp-prev);
+		 value[i] = (int)simple_strtoul(temp, NULL, 0);
+		 tmp ++; 
+		 prev = tmp;
+	}
+	tmp = strchr(prev, ' ');
+        if (tmp == NULL) return 0;
+	memset(temp, '\0', 256);
+        memcpy(temp, prev, tmp-prev);
+        value[i] = (int)simple_strtoul(temp, NULL, 0);
+	qos.txtp.traffic_class = ATM_CBR;
+	qos.txtp.max_pcr = value[0];
+	qos.txtp.max_sdu = value[1];
+
+        /* next receive values */
+	tmp = strstr(buff, "rx=");
+	if(tmp == NULL) return 0;
+        if (strstr(buff, "rx=tx")) { /* rx == tx */
+                qos.rxtp.traffic_class = qos.txtp.traffic_class;
+                qos.rxtp.max_pcr = qos.txtp.max_pcr;
+                qos.rxtp.max_cdv = qos.txtp.max_cdv;
+                qos.rxtp.max_sdu = qos.txtp.max_sdu;
+        } else {
+                tmp += 3;
+                prev = tmp;
+                for( i = 0; i < 1; i++){
+                        tmp = strchr(prev, ',');
+                        if (tmp == NULL) return 0;
+                        memset(temp, '\0', 256);
+                        memcpy(temp, prev, tmp-prev);
+                        value[i] = (int)simple_strtoul(temp, NULL, 0);
+                        tmp ++; 
+                        prev = tmp;
+                }
+                tmp = strchr(prev, '\0');
+                if (tmp == NULL) return 0;
+                memset(temp, '\0', 256);
+                memcpy(temp, prev, tmp-prev);
+                value[i] = (int)simple_strtoul(temp, NULL, 0);
+                qos.rxtp.traffic_class = ATM_CBR;
+                qos.rxtp.max_pcr = value[0];
+                qos.rxtp.max_sdu = value[1];
+        }
+        qos.aal = ATM_AAL5;
+	dprintk("mpoa: mpoa_proc.c: parse_qos(): setting qos paramameters to tx=%d,%d rx=%d,%d\n",
+		qos.txtp.max_pcr,
+		qos.txtp.max_sdu,
+		qos.rxtp.max_pcr,
+		qos.rxtp.max_sdu
+		);
+
+	atm_mpoa_add_qos(ipaddr, &qos);
+	return 1;
+}
+
+/*
+ * INITIALIZATION function - called when module is initialized/loaded.
+ */
+int mpc_proc_init(void)
+{
+        int retval = 0;
+
+        if ( (retval = proc_register(&atm_proc_root,&mpc_stats)) != 0 ) {
+                printk(KERN_ERR "Unable to initialize /proc/atm/%s\n", STAT_FILE_NAME);
+                return retval;
+        }
+	return 0;
+}
+
+/*
+ * DELETING function - called when module is removed.
+ */
+void mpc_proc_clean(void)
+{
+        proc_unregister(&atm_proc_root,mpc_stats.low_ino);
+}
+
+
+#endif /* CONFIG_PROC_FS */
+
+
+
+
+
+

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)