199824461SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ 21da177e4SLinus Torvalds 31da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS 41da177e4SLinus Torvalds #include <linux/errno.h> 51da177e4SLinus Torvalds #include <linux/kernel.h> 61da177e4SLinus Torvalds #include <linux/string.h> 71da177e4SLinus Torvalds #include <linux/mm.h> 81da177e4SLinus Torvalds #include <linux/module.h> 91da177e4SLinus Torvalds #include <linux/proc_fs.h> 101da177e4SLinus Torvalds #include <linux/time.h> 111da177e4SLinus Torvalds #include <linux/seq_file.h> 12f1e10049SJoe Perches #include <linux/uaccess.h> 131da177e4SLinus Torvalds #include <linux/atmmpc.h> 141da177e4SLinus Torvalds #include <linux/atm.h> 155a0e3ad6STejun Heo #include <linux/gfp.h> 161da177e4SLinus Torvalds #include "mpc.h" 171da177e4SLinus Torvalds #include "mpoa_caches.h" 181da177e4SLinus Torvalds 191da177e4SLinus Torvalds /* 201da177e4SLinus Torvalds * mpoa_proc.c: Implementation MPOA client's proc 211da177e4SLinus Torvalds * file system statistics 221da177e4SLinus Torvalds */ 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds #if 1 25b50c2ea7SJoe Perches #define dprintk(format, args...) \ 26b50c2ea7SJoe Perches printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args) /* debug */ 271da177e4SLinus Torvalds #else 28f1e10049SJoe Perches #define dprintk(format, args...) \ 29b50c2ea7SJoe Perches do { if (0) \ 30b50c2ea7SJoe Perches printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args);\ 31b50c2ea7SJoe Perches } while (0) 32b50c2ea7SJoe Perches #endif 33b50c2ea7SJoe Perches 34b50c2ea7SJoe Perches #if 0 35b50c2ea7SJoe Perches #define ddprintk(format, args...) \ 36b50c2ea7SJoe Perches printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args) /* debug */ 37b50c2ea7SJoe Perches #else 38b50c2ea7SJoe Perches #define ddprintk(format, args...) \ 39b50c2ea7SJoe Perches do { if (0) \ 40b50c2ea7SJoe Perches printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args);\ 41b50c2ea7SJoe Perches } while (0) 421da177e4SLinus Torvalds #endif 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds #define STAT_FILE_NAME "mpc" /* Our statistic file's name */ 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds extern struct mpoa_client *mpcs; 471da177e4SLinus Torvalds extern struct proc_dir_entry *atm_proc_root; /* from proc.c. */ 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds static int proc_mpc_open(struct inode *inode, struct file *file); 501da177e4SLinus Torvalds static ssize_t proc_mpc_write(struct file *file, const char __user *buff, 511da177e4SLinus Torvalds size_t nbytes, loff_t *ppos); 521da177e4SLinus Torvalds 531da177e4SLinus Torvalds static int parse_qos(const char *buff); 541da177e4SLinus Torvalds 551da177e4SLinus Torvalds /* 561da177e4SLinus Torvalds * Define allowed FILE OPERATIONS 571da177e4SLinus Torvalds */ 589a32144eSArjan van de Ven static const struct file_operations mpc_file_operations = { 591da177e4SLinus Torvalds .owner = THIS_MODULE, 601da177e4SLinus Torvalds .open = proc_mpc_open, 611da177e4SLinus Torvalds .read = seq_read, 621da177e4SLinus Torvalds .llseek = seq_lseek, 631da177e4SLinus Torvalds .write = proc_mpc_write, 641da177e4SLinus Torvalds .release = seq_release, 651da177e4SLinus Torvalds }; 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds /* 681da177e4SLinus Torvalds * Returns the state of an ingress cache entry as a string 691da177e4SLinus Torvalds */ 70f1e10049SJoe Perches static const char *ingress_state_string(int state) 71f1e10049SJoe Perches { 721da177e4SLinus Torvalds switch (state) { 731da177e4SLinus Torvalds case INGRESS_RESOLVING: 741da177e4SLinus Torvalds return "resolving "; 751da177e4SLinus Torvalds case INGRESS_RESOLVED: 761da177e4SLinus Torvalds return "resolved "; 771da177e4SLinus Torvalds case INGRESS_INVALID: 781da177e4SLinus Torvalds return "invalid "; 791da177e4SLinus Torvalds case INGRESS_REFRESHING: 801da177e4SLinus Torvalds return "refreshing "; 811da177e4SLinus Torvalds } 82f1e10049SJoe Perches 83f1e10049SJoe Perches return ""; 841da177e4SLinus Torvalds } 851da177e4SLinus Torvalds 861da177e4SLinus Torvalds /* 871da177e4SLinus Torvalds * Returns the state of an egress cache entry as a string 881da177e4SLinus Torvalds */ 89f1e10049SJoe Perches static const char *egress_state_string(int state) 90f1e10049SJoe Perches { 911da177e4SLinus Torvalds switch (state) { 921da177e4SLinus Torvalds case EGRESS_RESOLVED: 931da177e4SLinus Torvalds return "resolved "; 941da177e4SLinus Torvalds case EGRESS_PURGE: 951da177e4SLinus Torvalds return "purge "; 961da177e4SLinus Torvalds case EGRESS_INVALID: 971da177e4SLinus Torvalds return "invalid "; 981da177e4SLinus Torvalds } 99f1e10049SJoe Perches 100f1e10049SJoe Perches return ""; 1011da177e4SLinus Torvalds } 1021da177e4SLinus Torvalds 1031da177e4SLinus Torvalds /* 1041da177e4SLinus Torvalds * FIXME: mpcs (and per-mpc lists) have no locking whatsoever. 1051da177e4SLinus Torvalds */ 1061da177e4SLinus Torvalds 1071da177e4SLinus Torvalds static void *mpc_start(struct seq_file *m, loff_t *pos) 1081da177e4SLinus Torvalds { 1091da177e4SLinus Torvalds loff_t l = *pos; 1101da177e4SLinus Torvalds struct mpoa_client *mpc; 1111da177e4SLinus Torvalds 1121da177e4SLinus Torvalds if (!l--) 1131da177e4SLinus Torvalds return SEQ_START_TOKEN; 1141da177e4SLinus Torvalds for (mpc = mpcs; mpc; mpc = mpc->next) 1151da177e4SLinus Torvalds if (!l--) 1161da177e4SLinus Torvalds return mpc; 1171da177e4SLinus Torvalds return NULL; 1181da177e4SLinus Torvalds } 1191da177e4SLinus Torvalds 1201da177e4SLinus Torvalds static void *mpc_next(struct seq_file *m, void *v, loff_t *pos) 1211da177e4SLinus Torvalds { 1221da177e4SLinus Torvalds struct mpoa_client *p = v; 1231da177e4SLinus Torvalds (*pos)++; 1241da177e4SLinus Torvalds return v == SEQ_START_TOKEN ? mpcs : p->next; 1251da177e4SLinus Torvalds } 1261da177e4SLinus Torvalds 1271da177e4SLinus Torvalds static void mpc_stop(struct seq_file *m, void *v) 1281da177e4SLinus Torvalds { 1291da177e4SLinus Torvalds } 1301da177e4SLinus Torvalds 1311da177e4SLinus Torvalds /* 1321da177e4SLinus Torvalds * READING function - called when the /proc/atm/mpoa file is read from. 1331da177e4SLinus Torvalds */ 1341da177e4SLinus Torvalds static int mpc_show(struct seq_file *m, void *v) 1351da177e4SLinus Torvalds { 1361da177e4SLinus Torvalds struct mpoa_client *mpc = v; 1371da177e4SLinus Torvalds int i; 1381da177e4SLinus Torvalds in_cache_entry *in_entry; 1391da177e4SLinus Torvalds eg_cache_entry *eg_entry; 1401da177e4SLinus Torvalds struct timeval now; 1411da177e4SLinus Torvalds unsigned char ip_string[16]; 1421da177e4SLinus Torvalds 1431da177e4SLinus Torvalds if (v == SEQ_START_TOKEN) { 1441da177e4SLinus Torvalds atm_mpoa_disp_qos(m); 1451da177e4SLinus Torvalds return 0; 1461da177e4SLinus Torvalds } 1471da177e4SLinus Torvalds 1481da177e4SLinus Torvalds seq_printf(m, "\nInterface %d:\n\n", mpc->dev_num); 1491da177e4SLinus Torvalds seq_printf(m, "Ingress Entries:\nIP address State Holding time Packets fwded VPI VCI\n"); 1501da177e4SLinus Torvalds do_gettimeofday(&now); 1511da177e4SLinus Torvalds 1521da177e4SLinus Torvalds for (in_entry = mpc->in_cache; in_entry; in_entry = in_entry->next) { 153f1e10049SJoe Perches sprintf(ip_string, "%pI4", &in_entry->ctrl_info.in_dst_ip); 1541da177e4SLinus Torvalds seq_printf(m, "%-16s%s%-14lu%-12u", 1551da177e4SLinus Torvalds ip_string, 1561da177e4SLinus Torvalds ingress_state_string(in_entry->entry_state), 157f1e10049SJoe Perches in_entry->ctrl_info.holding_time - 158f1e10049SJoe Perches (now.tv_sec-in_entry->tv.tv_sec), 1591da177e4SLinus Torvalds in_entry->packets_fwded); 1601da177e4SLinus Torvalds if (in_entry->shortcut) 161f1e10049SJoe Perches seq_printf(m, " %-3d %-3d", 162f1e10049SJoe Perches in_entry->shortcut->vpi, 163f1e10049SJoe Perches in_entry->shortcut->vci); 1641da177e4SLinus Torvalds seq_printf(m, "\n"); 1651da177e4SLinus Torvalds } 1661da177e4SLinus Torvalds 1671da177e4SLinus Torvalds seq_printf(m, "\n"); 1681da177e4SLinus Torvalds seq_printf(m, "Egress Entries:\nIngress MPC ATM addr\nCache-id State Holding time Packets recvd Latest IP addr VPI VCI\n"); 1691da177e4SLinus Torvalds for (eg_entry = mpc->eg_cache; eg_entry; eg_entry = eg_entry->next) { 1701da177e4SLinus Torvalds unsigned char *p = eg_entry->ctrl_info.in_MPC_data_ATM_addr; 1711da177e4SLinus Torvalds for (i = 0; i < ATM_ESA_LEN; i++) 1721da177e4SLinus Torvalds seq_printf(m, "%02x", p[i]); 1731da177e4SLinus Torvalds seq_printf(m, "\n%-16lu%s%-14lu%-15u", 1741da177e4SLinus Torvalds (unsigned long)ntohl(eg_entry->ctrl_info.cache_id), 1751da177e4SLinus Torvalds egress_state_string(eg_entry->entry_state), 176f1e10049SJoe Perches (eg_entry->ctrl_info.holding_time - 177f1e10049SJoe Perches (now.tv_sec-eg_entry->tv.tv_sec)), 1781da177e4SLinus Torvalds eg_entry->packets_rcvd); 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds /* latest IP address */ 181f1e10049SJoe Perches sprintf(ip_string, "%pI4", &eg_entry->latest_ip_addr); 1821da177e4SLinus Torvalds seq_printf(m, "%-16s", ip_string); 1831da177e4SLinus Torvalds 1841da177e4SLinus Torvalds if (eg_entry->shortcut) 185f1e10049SJoe Perches seq_printf(m, " %-3d %-3d", 186f1e10049SJoe Perches eg_entry->shortcut->vpi, 187f1e10049SJoe Perches eg_entry->shortcut->vci); 1881da177e4SLinus Torvalds seq_printf(m, "\n"); 1891da177e4SLinus Torvalds } 1901da177e4SLinus Torvalds seq_printf(m, "\n"); 1911da177e4SLinus Torvalds return 0; 1921da177e4SLinus Torvalds } 1931da177e4SLinus Torvalds 19456b3d975SPhilippe De Muyter static const struct seq_operations mpc_op = { 1951da177e4SLinus Torvalds .start = mpc_start, 1961da177e4SLinus Torvalds .next = mpc_next, 1971da177e4SLinus Torvalds .stop = mpc_stop, 1981da177e4SLinus Torvalds .show = mpc_show 1991da177e4SLinus Torvalds }; 2001da177e4SLinus Torvalds 2011da177e4SLinus Torvalds static int proc_mpc_open(struct inode *inode, struct file *file) 2021da177e4SLinus Torvalds { 2031da177e4SLinus Torvalds return seq_open(file, &mpc_op); 2041da177e4SLinus Torvalds } 2051da177e4SLinus Torvalds 2061da177e4SLinus Torvalds static ssize_t proc_mpc_write(struct file *file, const char __user *buff, 2071da177e4SLinus Torvalds size_t nbytes, loff_t *ppos) 2081da177e4SLinus Torvalds { 2091da177e4SLinus Torvalds char *page, *p; 21095c96174SEric Dumazet unsigned int len; 2111da177e4SLinus Torvalds 2121da177e4SLinus Torvalds if (nbytes == 0) 2131da177e4SLinus Torvalds return 0; 2141da177e4SLinus Torvalds 2151da177e4SLinus Torvalds if (nbytes >= PAGE_SIZE) 2161da177e4SLinus Torvalds nbytes = PAGE_SIZE-1; 2171da177e4SLinus Torvalds 2181da177e4SLinus Torvalds page = (char *)__get_free_page(GFP_KERNEL); 2191da177e4SLinus Torvalds if (!page) 2201da177e4SLinus Torvalds return -ENOMEM; 2211da177e4SLinus Torvalds 2221da177e4SLinus Torvalds for (p = page, len = 0; len < nbytes; p++, len++) { 2231da177e4SLinus Torvalds if (get_user(*p, buff++)) { 2241da177e4SLinus Torvalds free_page((unsigned long)page); 2251da177e4SLinus Torvalds return -EFAULT; 2261da177e4SLinus Torvalds } 2271da177e4SLinus Torvalds if (*p == '\0' || *p == '\n') 2281da177e4SLinus Torvalds break; 2291da177e4SLinus Torvalds } 2301da177e4SLinus Torvalds 2311da177e4SLinus Torvalds *p = '\0'; 2321da177e4SLinus Torvalds 2331da177e4SLinus Torvalds if (!parse_qos(page)) 2341da177e4SLinus Torvalds printk("mpoa: proc_mpc_write: could not parse '%s'\n", page); 2351da177e4SLinus Torvalds 2361da177e4SLinus Torvalds free_page((unsigned long)page); 2371da177e4SLinus Torvalds 2381da177e4SLinus Torvalds return len; 2391da177e4SLinus Torvalds } 2401da177e4SLinus Torvalds 2411da177e4SLinus Torvalds static int parse_qos(const char *buff) 2421da177e4SLinus Torvalds { 2431da177e4SLinus Torvalds /* possible lines look like this 2441da177e4SLinus Torvalds * add 130.230.54.142 tx=max_pcr,max_sdu rx=max_pcr,max_sdu 2451da177e4SLinus Torvalds */ 2461da177e4SLinus Torvalds unsigned char ip[4]; 2471da177e4SLinus Torvalds int tx_pcr, tx_sdu, rx_pcr, rx_sdu; 24830d492daSAl Viro __be32 ipaddr; 2491da177e4SLinus Torvalds struct atm_qos qos; 2501da177e4SLinus Torvalds 2511da177e4SLinus Torvalds memset(&qos, 0, sizeof(struct atm_qos)); 2521da177e4SLinus Torvalds 2531da177e4SLinus Torvalds if (sscanf(buff, "del %hhu.%hhu.%hhu.%hhu", 2541da177e4SLinus Torvalds ip, ip+1, ip+2, ip+3) == 4) { 25530d492daSAl Viro ipaddr = *(__be32 *)ip; 2561da177e4SLinus Torvalds return atm_mpoa_delete_qos(atm_mpoa_search_qos(ipaddr)); 2571da177e4SLinus Torvalds } 2581da177e4SLinus Torvalds 2591da177e4SLinus Torvalds if (sscanf(buff, "add %hhu.%hhu.%hhu.%hhu tx=%d,%d rx=tx", 2601da177e4SLinus Torvalds ip, ip+1, ip+2, ip+3, &tx_pcr, &tx_sdu) == 6) { 2611da177e4SLinus Torvalds rx_pcr = tx_pcr; 2621da177e4SLinus Torvalds rx_sdu = tx_sdu; 2631da177e4SLinus Torvalds } else if (sscanf(buff, "add %hhu.%hhu.%hhu.%hhu tx=%d,%d rx=%d,%d", 2641da177e4SLinus Torvalds ip, ip+1, ip+2, ip+3, &tx_pcr, &tx_sdu, &rx_pcr, &rx_sdu) != 8) 2651da177e4SLinus Torvalds return 0; 2661da177e4SLinus Torvalds 26730d492daSAl Viro ipaddr = *(__be32 *)ip; 2681da177e4SLinus Torvalds qos.txtp.traffic_class = ATM_CBR; 2691da177e4SLinus Torvalds qos.txtp.max_pcr = tx_pcr; 2701da177e4SLinus Torvalds qos.txtp.max_sdu = tx_sdu; 2711da177e4SLinus Torvalds qos.rxtp.traffic_class = ATM_CBR; 2721da177e4SLinus Torvalds qos.rxtp.max_pcr = rx_pcr; 2731da177e4SLinus Torvalds qos.rxtp.max_sdu = rx_sdu; 2741da177e4SLinus Torvalds qos.aal = ATM_AAL5; 275b50c2ea7SJoe Perches dprintk("parse_qos(): setting qos paramameters to tx=%d,%d rx=%d,%d\n", 276b50c2ea7SJoe Perches qos.txtp.max_pcr, qos.txtp.max_sdu, 277b50c2ea7SJoe Perches qos.rxtp.max_pcr, qos.rxtp.max_sdu); 2781da177e4SLinus Torvalds 2791da177e4SLinus Torvalds atm_mpoa_add_qos(ipaddr, &qos); 2801da177e4SLinus Torvalds return 1; 2811da177e4SLinus Torvalds } 2821da177e4SLinus Torvalds 2831da177e4SLinus Torvalds /* 2841da177e4SLinus Torvalds * INITIALIZATION function - called when module is initialized/loaded. 2851da177e4SLinus Torvalds */ 2861da177e4SLinus Torvalds int mpc_proc_init(void) 2871da177e4SLinus Torvalds { 2881da177e4SLinus Torvalds struct proc_dir_entry *p; 2891da177e4SLinus Torvalds 29016e297b3SWang Chen p = proc_create(STAT_FILE_NAME, 0, atm_proc_root, &mpc_file_operations); 2911da177e4SLinus Torvalds if (!p) { 29299824461SJoe Perches pr_err("Unable to initialize /proc/atm/%s\n", STAT_FILE_NAME); 2931da177e4SLinus Torvalds return -ENOMEM; 2941da177e4SLinus Torvalds } 2951da177e4SLinus Torvalds return 0; 2961da177e4SLinus Torvalds } 2971da177e4SLinus Torvalds 2981da177e4SLinus Torvalds /* 2991da177e4SLinus Torvalds * DELETING function - called when module is removed. 3001da177e4SLinus Torvalds */ 3011da177e4SLinus Torvalds void mpc_proc_clean(void) 3021da177e4SLinus Torvalds { 3031da177e4SLinus Torvalds remove_proc_entry(STAT_FILE_NAME, atm_proc_root); 3041da177e4SLinus Torvalds } 3051da177e4SLinus Torvalds 3061da177e4SLinus Torvalds #endif /* CONFIG_PROC_FS */ 3071da177e4SLinus Torvalds 3081da177e4SLinus Torvalds 3091da177e4SLinus Torvalds 3101da177e4SLinus Torvalds 3111da177e4SLinus Torvalds 3121da177e4SLinus Torvalds 313