mpoa_proc.c revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2
1#include <linux/config.h> 2 3#ifdef CONFIG_PROC_FS 4#include <linux/errno.h> 5#include <linux/kernel.h> 6#include <linux/string.h> 7#include <linux/mm.h> 8#include <linux/module.h> 9#include <linux/proc_fs.h> 10#include <linux/time.h> 11#include <linux/seq_file.h> 12#include <asm/uaccess.h> 13#include <linux/atmmpc.h> 14#include <linux/atm.h> 15#include "mpc.h" 16#include "mpoa_caches.h" 17 18/* 19 * mpoa_proc.c: Implementation MPOA client's proc 20 * file system statistics 21 */ 22 23#if 1 24#define dprintk printk /* debug */ 25#else 26#define dprintk(format,args...) 27#endif 28 29#define STAT_FILE_NAME "mpc" /* Our statistic file's name */ 30 31extern struct mpoa_client *mpcs; 32extern struct proc_dir_entry *atm_proc_root; /* from proc.c. */ 33 34static int proc_mpc_open(struct inode *inode, struct file *file); 35static ssize_t proc_mpc_write(struct file *file, const char __user *buff, 36 size_t nbytes, loff_t *ppos); 37 38static int parse_qos(const char *buff); 39 40/* 41 * Define allowed FILE OPERATIONS 42 */ 43static struct file_operations mpc_file_operations = { 44 .owner = THIS_MODULE, 45 .open = proc_mpc_open, 46 .read = seq_read, 47 .llseek = seq_lseek, 48 .write = proc_mpc_write, 49 .release = seq_release, 50}; 51 52/* 53 * Returns the state of an ingress cache entry as a string 54 */ 55static const char *ingress_state_string(int state){ 56 switch(state) { 57 case INGRESS_RESOLVING: 58 return "resolving "; 59 break; 60 case INGRESS_RESOLVED: 61 return "resolved "; 62 break; 63 case INGRESS_INVALID: 64 return "invalid "; 65 break; 66 case INGRESS_REFRESHING: 67 return "refreshing "; 68 break; 69 default: 70 return ""; 71 } 72} 73 74/* 75 * Returns the state of an egress cache entry as a string 76 */ 77static const char *egress_state_string(int state){ 78 switch(state) { 79 case EGRESS_RESOLVED: 80 return "resolved "; 81 break; 82 case EGRESS_PURGE: 83 return "purge "; 84 break; 85 case EGRESS_INVALID: 86 return "invalid "; 87 break; 88 default: 89 return ""; 90 } 91} 92 93/* 94 * FIXME: mpcs (and per-mpc lists) have no locking whatsoever. 95 */ 96 97static void *mpc_start(struct seq_file *m, loff_t *pos) 98{ 99 loff_t l = *pos; 100 struct mpoa_client *mpc; 101 102 if (!l--) 103 return SEQ_START_TOKEN; 104 for (mpc = mpcs; mpc; mpc = mpc->next) 105 if (!l--) 106 return mpc; 107 return NULL; 108} 109 110static void *mpc_next(struct seq_file *m, void *v, loff_t *pos) 111{ 112 struct mpoa_client *p = v; 113 (*pos)++; 114 return v == SEQ_START_TOKEN ? mpcs : p->next; 115} 116 117static void mpc_stop(struct seq_file *m, void *v) 118{ 119} 120 121/* 122 * READING function - called when the /proc/atm/mpoa file is read from. 123 */ 124static int mpc_show(struct seq_file *m, void *v) 125{ 126 struct mpoa_client *mpc = v; 127 unsigned char *temp; 128 int i; 129 in_cache_entry *in_entry; 130 eg_cache_entry *eg_entry; 131 struct timeval now; 132 unsigned char ip_string[16]; 133 134 if (v == SEQ_START_TOKEN) { 135 atm_mpoa_disp_qos(m); 136 return 0; 137 } 138 139 seq_printf(m, "\nInterface %d:\n\n", mpc->dev_num); 140 seq_printf(m, "Ingress Entries:\nIP address State Holding time Packets fwded VPI VCI\n"); 141 do_gettimeofday(&now); 142 143 for (in_entry = mpc->in_cache; in_entry; in_entry = in_entry->next) { 144 temp = (unsigned char *)&in_entry->ctrl_info.in_dst_ip; 145 sprintf(ip_string,"%d.%d.%d.%d", temp[0], temp[1], temp[2], temp[3]); 146 seq_printf(m, "%-16s%s%-14lu%-12u", 147 ip_string, 148 ingress_state_string(in_entry->entry_state), 149 in_entry->ctrl_info.holding_time-(now.tv_sec-in_entry->tv.tv_sec), 150 in_entry->packets_fwded); 151 if (in_entry->shortcut) 152 seq_printf(m, " %-3d %-3d",in_entry->shortcut->vpi,in_entry->shortcut->vci); 153 seq_printf(m, "\n"); 154 } 155 156 seq_printf(m, "\n"); 157 seq_printf(m, "Egress Entries:\nIngress MPC ATM addr\nCache-id State Holding time Packets recvd Latest IP addr VPI VCI\n"); 158 for (eg_entry = mpc->eg_cache; eg_entry; eg_entry = eg_entry->next) { 159 unsigned char *p = eg_entry->ctrl_info.in_MPC_data_ATM_addr; 160 for(i = 0; i < ATM_ESA_LEN; i++) 161 seq_printf(m, "%02x", p[i]); 162 seq_printf(m, "\n%-16lu%s%-14lu%-15u", 163 (unsigned long)ntohl(eg_entry->ctrl_info.cache_id), 164 egress_state_string(eg_entry->entry_state), 165 (eg_entry->ctrl_info.holding_time-(now.tv_sec-eg_entry->tv.tv_sec)), 166 eg_entry->packets_rcvd); 167 168 /* latest IP address */ 169 temp = (unsigned char *)&eg_entry->latest_ip_addr; 170 sprintf(ip_string, "%d.%d.%d.%d", temp[0], temp[1], temp[2], temp[3]); 171 seq_printf(m, "%-16s", ip_string); 172 173 if (eg_entry->shortcut) 174 seq_printf(m, " %-3d %-3d",eg_entry->shortcut->vpi,eg_entry->shortcut->vci); 175 seq_printf(m, "\n"); 176 } 177 seq_printf(m, "\n"); 178 return 0; 179} 180 181static struct seq_operations mpc_op = { 182 .start = mpc_start, 183 .next = mpc_next, 184 .stop = mpc_stop, 185 .show = mpc_show 186}; 187 188static int proc_mpc_open(struct inode *inode, struct file *file) 189{ 190 return seq_open(file, &mpc_op); 191} 192 193static ssize_t proc_mpc_write(struct file *file, const char __user *buff, 194 size_t nbytes, loff_t *ppos) 195{ 196 char *page, *p; 197 unsigned len; 198 199 if (nbytes == 0) 200 return 0; 201 202 if (nbytes >= PAGE_SIZE) 203 nbytes = PAGE_SIZE-1; 204 205 page = (char *)__get_free_page(GFP_KERNEL); 206 if (!page) 207 return -ENOMEM; 208 209 for (p = page, len = 0; len < nbytes; p++, len++) { 210 if (get_user(*p, buff++)) { 211 free_page((unsigned long)page); 212 return -EFAULT; 213 } 214 if (*p == '\0' || *p == '\n') 215 break; 216 } 217 218 *p = '\0'; 219 220 if (!parse_qos(page)) 221 printk("mpoa: proc_mpc_write: could not parse '%s'\n", page); 222 223 free_page((unsigned long)page); 224 225 return len; 226} 227 228static int parse_qos(const char *buff) 229{ 230 /* possible lines look like this 231 * add 130.230.54.142 tx=max_pcr,max_sdu rx=max_pcr,max_sdu 232 */ 233 unsigned char ip[4]; 234 int tx_pcr, tx_sdu, rx_pcr, rx_sdu; 235 uint32_t ipaddr; 236 struct atm_qos qos; 237 238 memset(&qos, 0, sizeof(struct atm_qos)); 239 240 if (sscanf(buff, "del %hhu.%hhu.%hhu.%hhu", 241 ip, ip+1, ip+2, ip+3) == 4) { 242 ipaddr = *(uint32_t *)ip; 243 return atm_mpoa_delete_qos(atm_mpoa_search_qos(ipaddr)); 244 } 245 246 if (sscanf(buff, "add %hhu.%hhu.%hhu.%hhu tx=%d,%d rx=tx", 247 ip, ip+1, ip+2, ip+3, &tx_pcr, &tx_sdu) == 6) { 248 rx_pcr = tx_pcr; 249 rx_sdu = tx_sdu; 250 } else if (sscanf(buff, "add %hhu.%hhu.%hhu.%hhu tx=%d,%d rx=%d,%d", 251 ip, ip+1, ip+2, ip+3, &tx_pcr, &tx_sdu, &rx_pcr, &rx_sdu) != 8) 252 return 0; 253 254 ipaddr = *(uint32_t *)ip; 255 qos.txtp.traffic_class = ATM_CBR; 256 qos.txtp.max_pcr = tx_pcr; 257 qos.txtp.max_sdu = tx_sdu; 258 qos.rxtp.traffic_class = ATM_CBR; 259 qos.rxtp.max_pcr = rx_pcr; 260 qos.rxtp.max_sdu = rx_sdu; 261 qos.aal = ATM_AAL5; 262 dprintk("mpoa: mpoa_proc.c: parse_qos(): setting qos paramameters to tx=%d,%d rx=%d,%d\n", 263 qos.txtp.max_pcr, 264 qos.txtp.max_sdu, 265 qos.rxtp.max_pcr, 266 qos.rxtp.max_sdu 267 ); 268 269 atm_mpoa_add_qos(ipaddr, &qos); 270 return 1; 271} 272 273/* 274 * INITIALIZATION function - called when module is initialized/loaded. 275 */ 276int mpc_proc_init(void) 277{ 278 struct proc_dir_entry *p; 279 280 p = create_proc_entry(STAT_FILE_NAME, 0, atm_proc_root); 281 if (!p) { 282 printk(KERN_ERR "Unable to initialize /proc/atm/%s\n", STAT_FILE_NAME); 283 return -ENOMEM; 284 } 285 p->proc_fops = &mpc_file_operations; 286 p->owner = THIS_MODULE; 287 return 0; 288} 289 290/* 291 * DELETING function - called when module is removed. 292 */ 293void mpc_proc_clean(void) 294{ 295 remove_proc_entry(STAT_FILE_NAME,atm_proc_root); 296} 297 298 299#endif /* CONFIG_PROC_FS */ 300 301 302 303 304 305 306