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> 151da177e4SLinus Torvalds #include "mpc.h" 161da177e4SLinus Torvalds #include "mpoa_caches.h" 171da177e4SLinus Torvalds 181da177e4SLinus Torvalds /* 191da177e4SLinus Torvalds * mpoa_proc.c: Implementation MPOA client's proc 201da177e4SLinus Torvalds * file system statistics 211da177e4SLinus Torvalds */ 221da177e4SLinus Torvalds 231da177e4SLinus Torvalds #if 1 24f1e10049SJoe Perches #define dprintk(format, args...) printk(KERN_DEBUG format, ##args) /* debug */ 251da177e4SLinus Torvalds #else 26f1e10049SJoe Perches #define dprintk(format, args...) \ 27f1e10049SJoe Perches do { if (0) printk(KERN_DEBUG format, ##args); } while (0) 281da177e4SLinus Torvalds #endif 291da177e4SLinus Torvalds 301da177e4SLinus Torvalds #define STAT_FILE_NAME "mpc" /* Our statistic file's name */ 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds extern struct mpoa_client *mpcs; 331da177e4SLinus Torvalds extern struct proc_dir_entry *atm_proc_root; /* from proc.c. */ 341da177e4SLinus Torvalds 351da177e4SLinus Torvalds static int proc_mpc_open(struct inode *inode, struct file *file); 361da177e4SLinus Torvalds static ssize_t proc_mpc_write(struct file *file, const char __user *buff, 371da177e4SLinus Torvalds size_t nbytes, loff_t *ppos); 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds static int parse_qos(const char *buff); 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds /* 421da177e4SLinus Torvalds * Define allowed FILE OPERATIONS 431da177e4SLinus Torvalds */ 449a32144eSArjan van de Ven static const struct file_operations mpc_file_operations = { 451da177e4SLinus Torvalds .owner = THIS_MODULE, 461da177e4SLinus Torvalds .open = proc_mpc_open, 471da177e4SLinus Torvalds .read = seq_read, 481da177e4SLinus Torvalds .llseek = seq_lseek, 491da177e4SLinus Torvalds .write = proc_mpc_write, 501da177e4SLinus Torvalds .release = seq_release, 511da177e4SLinus Torvalds }; 521da177e4SLinus Torvalds 531da177e4SLinus Torvalds /* 541da177e4SLinus Torvalds * Returns the state of an ingress cache entry as a string 551da177e4SLinus Torvalds */ 56f1e10049SJoe Perches static const char *ingress_state_string(int state) 57f1e10049SJoe Perches { 581da177e4SLinus Torvalds switch (state) { 591da177e4SLinus Torvalds case INGRESS_RESOLVING: 601da177e4SLinus Torvalds return "resolving "; 611da177e4SLinus Torvalds case INGRESS_RESOLVED: 621da177e4SLinus Torvalds return "resolved "; 631da177e4SLinus Torvalds case INGRESS_INVALID: 641da177e4SLinus Torvalds return "invalid "; 651da177e4SLinus Torvalds case INGRESS_REFRESHING: 661da177e4SLinus Torvalds return "refreshing "; 671da177e4SLinus Torvalds } 68f1e10049SJoe Perches 69f1e10049SJoe Perches return ""; 701da177e4SLinus Torvalds } 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds /* 731da177e4SLinus Torvalds * Returns the state of an egress cache entry as a string 741da177e4SLinus Torvalds */ 75f1e10049SJoe Perches static const char *egress_state_string(int state) 76f1e10049SJoe Perches { 771da177e4SLinus Torvalds switch (state) { 781da177e4SLinus Torvalds case EGRESS_RESOLVED: 791da177e4SLinus Torvalds return "resolved "; 801da177e4SLinus Torvalds case EGRESS_PURGE: 811da177e4SLinus Torvalds return "purge "; 821da177e4SLinus Torvalds case EGRESS_INVALID: 831da177e4SLinus Torvalds return "invalid "; 841da177e4SLinus Torvalds } 85f1e10049SJoe Perches 86f1e10049SJoe Perches return ""; 871da177e4SLinus Torvalds } 881da177e4SLinus Torvalds 891da177e4SLinus Torvalds /* 901da177e4SLinus Torvalds * FIXME: mpcs (and per-mpc lists) have no locking whatsoever. 911da177e4SLinus Torvalds */ 921da177e4SLinus Torvalds 931da177e4SLinus Torvalds static void *mpc_start(struct seq_file *m, loff_t *pos) 941da177e4SLinus Torvalds { 951da177e4SLinus Torvalds loff_t l = *pos; 961da177e4SLinus Torvalds struct mpoa_client *mpc; 971da177e4SLinus Torvalds 981da177e4SLinus Torvalds if (!l--) 991da177e4SLinus Torvalds return SEQ_START_TOKEN; 1001da177e4SLinus Torvalds for (mpc = mpcs; mpc; mpc = mpc->next) 1011da177e4SLinus Torvalds if (!l--) 1021da177e4SLinus Torvalds return mpc; 1031da177e4SLinus Torvalds return NULL; 1041da177e4SLinus Torvalds } 1051da177e4SLinus Torvalds 1061da177e4SLinus Torvalds static void *mpc_next(struct seq_file *m, void *v, loff_t *pos) 1071da177e4SLinus Torvalds { 1081da177e4SLinus Torvalds struct mpoa_client *p = v; 1091da177e4SLinus Torvalds (*pos)++; 1101da177e4SLinus Torvalds return v == SEQ_START_TOKEN ? mpcs : p->next; 1111da177e4SLinus Torvalds } 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds static void mpc_stop(struct seq_file *m, void *v) 1141da177e4SLinus Torvalds { 1151da177e4SLinus Torvalds } 1161da177e4SLinus Torvalds 1171da177e4SLinus Torvalds /* 1181da177e4SLinus Torvalds * READING function - called when the /proc/atm/mpoa file is read from. 1191da177e4SLinus Torvalds */ 1201da177e4SLinus Torvalds static int mpc_show(struct seq_file *m, void *v) 1211da177e4SLinus Torvalds { 1221da177e4SLinus Torvalds struct mpoa_client *mpc = v; 1231da177e4SLinus Torvalds int i; 1241da177e4SLinus Torvalds in_cache_entry *in_entry; 1251da177e4SLinus Torvalds eg_cache_entry *eg_entry; 1261da177e4SLinus Torvalds struct timeval now; 1271da177e4SLinus Torvalds unsigned char ip_string[16]; 1281da177e4SLinus Torvalds 1291da177e4SLinus Torvalds if (v == SEQ_START_TOKEN) { 1301da177e4SLinus Torvalds atm_mpoa_disp_qos(m); 1311da177e4SLinus Torvalds return 0; 1321da177e4SLinus Torvalds } 1331da177e4SLinus Torvalds 1341da177e4SLinus Torvalds seq_printf(m, "\nInterface %d:\n\n", mpc->dev_num); 1351da177e4SLinus Torvalds seq_printf(m, "Ingress Entries:\nIP address State Holding time Packets fwded VPI VCI\n"); 1361da177e4SLinus Torvalds do_gettimeofday(&now); 1371da177e4SLinus Torvalds 1381da177e4SLinus Torvalds for (in_entry = mpc->in_cache; in_entry; in_entry = in_entry->next) { 139f1e10049SJoe Perches sprintf(ip_string, "%pI4", &in_entry->ctrl_info.in_dst_ip); 1401da177e4SLinus Torvalds seq_printf(m, "%-16s%s%-14lu%-12u", 1411da177e4SLinus Torvalds ip_string, 1421da177e4SLinus Torvalds ingress_state_string(in_entry->entry_state), 143f1e10049SJoe Perches in_entry->ctrl_info.holding_time - 144f1e10049SJoe Perches (now.tv_sec-in_entry->tv.tv_sec), 1451da177e4SLinus Torvalds in_entry->packets_fwded); 1461da177e4SLinus Torvalds if (in_entry->shortcut) 147f1e10049SJoe Perches seq_printf(m, " %-3d %-3d", 148f1e10049SJoe Perches in_entry->shortcut->vpi, 149f1e10049SJoe Perches in_entry->shortcut->vci); 1501da177e4SLinus Torvalds seq_printf(m, "\n"); 1511da177e4SLinus Torvalds } 1521da177e4SLinus Torvalds 1531da177e4SLinus Torvalds seq_printf(m, "\n"); 1541da177e4SLinus Torvalds seq_printf(m, "Egress Entries:\nIngress MPC ATM addr\nCache-id State Holding time Packets recvd Latest IP addr VPI VCI\n"); 1551da177e4SLinus Torvalds for (eg_entry = mpc->eg_cache; eg_entry; eg_entry = eg_entry->next) { 1561da177e4SLinus Torvalds unsigned char *p = eg_entry->ctrl_info.in_MPC_data_ATM_addr; 1571da177e4SLinus Torvalds for (i = 0; i < ATM_ESA_LEN; i++) 1581da177e4SLinus Torvalds seq_printf(m, "%02x", p[i]); 1591da177e4SLinus Torvalds seq_printf(m, "\n%-16lu%s%-14lu%-15u", 1601da177e4SLinus Torvalds (unsigned long)ntohl(eg_entry->ctrl_info.cache_id), 1611da177e4SLinus Torvalds egress_state_string(eg_entry->entry_state), 162f1e10049SJoe Perches (eg_entry->ctrl_info.holding_time - 163f1e10049SJoe Perches (now.tv_sec-eg_entry->tv.tv_sec)), 1641da177e4SLinus Torvalds eg_entry->packets_rcvd); 1651da177e4SLinus Torvalds 1661da177e4SLinus Torvalds /* latest IP address */ 167f1e10049SJoe Perches sprintf(ip_string, "%pI4", &eg_entry->latest_ip_addr); 1681da177e4SLinus Torvalds seq_printf(m, "%-16s", ip_string); 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds if (eg_entry->shortcut) 171f1e10049SJoe Perches seq_printf(m, " %-3d %-3d", 172f1e10049SJoe Perches eg_entry->shortcut->vpi, 173f1e10049SJoe Perches eg_entry->shortcut->vci); 1741da177e4SLinus Torvalds seq_printf(m, "\n"); 1751da177e4SLinus Torvalds } 1761da177e4SLinus Torvalds seq_printf(m, "\n"); 1771da177e4SLinus Torvalds return 0; 1781da177e4SLinus Torvalds } 1791da177e4SLinus Torvalds 18056b3d975SPhilippe De Muyter static const struct seq_operations mpc_op = { 1811da177e4SLinus Torvalds .start = mpc_start, 1821da177e4SLinus Torvalds .next = mpc_next, 1831da177e4SLinus Torvalds .stop = mpc_stop, 1841da177e4SLinus Torvalds .show = mpc_show 1851da177e4SLinus Torvalds }; 1861da177e4SLinus Torvalds 1871da177e4SLinus Torvalds static int proc_mpc_open(struct inode *inode, struct file *file) 1881da177e4SLinus Torvalds { 1891da177e4SLinus Torvalds return seq_open(file, &mpc_op); 1901da177e4SLinus Torvalds } 1911da177e4SLinus Torvalds 1921da177e4SLinus Torvalds static ssize_t proc_mpc_write(struct file *file, const char __user *buff, 1931da177e4SLinus Torvalds size_t nbytes, loff_t *ppos) 1941da177e4SLinus Torvalds { 1951da177e4SLinus Torvalds char *page, *p; 1961da177e4SLinus Torvalds unsigned len; 1971da177e4SLinus Torvalds 1981da177e4SLinus Torvalds if (nbytes == 0) 1991da177e4SLinus Torvalds return 0; 2001da177e4SLinus Torvalds 2011da177e4SLinus Torvalds if (nbytes >= PAGE_SIZE) 2021da177e4SLinus Torvalds nbytes = PAGE_SIZE-1; 2031da177e4SLinus Torvalds 2041da177e4SLinus Torvalds page = (char *)__get_free_page(GFP_KERNEL); 2051da177e4SLinus Torvalds if (!page) 2061da177e4SLinus Torvalds return -ENOMEM; 2071da177e4SLinus Torvalds 2081da177e4SLinus Torvalds for (p = page, len = 0; len < nbytes; p++, len++) { 2091da177e4SLinus Torvalds if (get_user(*p, buff++)) { 2101da177e4SLinus Torvalds free_page((unsigned long)page); 2111da177e4SLinus Torvalds return -EFAULT; 2121da177e4SLinus Torvalds } 2131da177e4SLinus Torvalds if (*p == '\0' || *p == '\n') 2141da177e4SLinus Torvalds break; 2151da177e4SLinus Torvalds } 2161da177e4SLinus Torvalds 2171da177e4SLinus Torvalds *p = '\0'; 2181da177e4SLinus Torvalds 2191da177e4SLinus Torvalds if (!parse_qos(page)) 2201da177e4SLinus Torvalds printk("mpoa: proc_mpc_write: could not parse '%s'\n", page); 2211da177e4SLinus Torvalds 2221da177e4SLinus Torvalds free_page((unsigned long)page); 2231da177e4SLinus Torvalds 2241da177e4SLinus Torvalds return len; 2251da177e4SLinus Torvalds } 2261da177e4SLinus Torvalds 2271da177e4SLinus Torvalds static int parse_qos(const char *buff) 2281da177e4SLinus Torvalds { 2291da177e4SLinus Torvalds /* possible lines look like this 2301da177e4SLinus Torvalds * add 130.230.54.142 tx=max_pcr,max_sdu rx=max_pcr,max_sdu 2311da177e4SLinus Torvalds */ 2321da177e4SLinus Torvalds unsigned char ip[4]; 2331da177e4SLinus Torvalds int tx_pcr, tx_sdu, rx_pcr, rx_sdu; 23430d492daSAl Viro __be32 ipaddr; 2351da177e4SLinus Torvalds struct atm_qos qos; 2361da177e4SLinus Torvalds 2371da177e4SLinus Torvalds memset(&qos, 0, sizeof(struct atm_qos)); 2381da177e4SLinus Torvalds 2391da177e4SLinus Torvalds if (sscanf(buff, "del %hhu.%hhu.%hhu.%hhu", 2401da177e4SLinus Torvalds ip, ip+1, ip+2, ip+3) == 4) { 24130d492daSAl Viro ipaddr = *(__be32 *)ip; 2421da177e4SLinus Torvalds return atm_mpoa_delete_qos(atm_mpoa_search_qos(ipaddr)); 2431da177e4SLinus Torvalds } 2441da177e4SLinus Torvalds 2451da177e4SLinus Torvalds if (sscanf(buff, "add %hhu.%hhu.%hhu.%hhu tx=%d,%d rx=tx", 2461da177e4SLinus Torvalds ip, ip+1, ip+2, ip+3, &tx_pcr, &tx_sdu) == 6) { 2471da177e4SLinus Torvalds rx_pcr = tx_pcr; 2481da177e4SLinus Torvalds rx_sdu = tx_sdu; 2491da177e4SLinus Torvalds } else if (sscanf(buff, "add %hhu.%hhu.%hhu.%hhu tx=%d,%d rx=%d,%d", 2501da177e4SLinus Torvalds ip, ip+1, ip+2, ip+3, &tx_pcr, &tx_sdu, &rx_pcr, &rx_sdu) != 8) 2511da177e4SLinus Torvalds return 0; 2521da177e4SLinus Torvalds 25330d492daSAl Viro ipaddr = *(__be32 *)ip; 2541da177e4SLinus Torvalds qos.txtp.traffic_class = ATM_CBR; 2551da177e4SLinus Torvalds qos.txtp.max_pcr = tx_pcr; 2561da177e4SLinus Torvalds qos.txtp.max_sdu = tx_sdu; 2571da177e4SLinus Torvalds qos.rxtp.traffic_class = ATM_CBR; 2581da177e4SLinus Torvalds qos.rxtp.max_pcr = rx_pcr; 2591da177e4SLinus Torvalds qos.rxtp.max_sdu = rx_sdu; 2601da177e4SLinus Torvalds qos.aal = ATM_AAL5; 2611da177e4SLinus Torvalds dprintk("mpoa: mpoa_proc.c: parse_qos(): setting qos paramameters to tx=%d,%d rx=%d,%d\n", 2621da177e4SLinus Torvalds qos.txtp.max_pcr, 2631da177e4SLinus Torvalds qos.txtp.max_sdu, 2641da177e4SLinus Torvalds qos.rxtp.max_pcr, 2651da177e4SLinus Torvalds qos.rxtp.max_sdu 2661da177e4SLinus Torvalds ); 2671da177e4SLinus Torvalds 2681da177e4SLinus Torvalds atm_mpoa_add_qos(ipaddr, &qos); 2691da177e4SLinus Torvalds return 1; 2701da177e4SLinus Torvalds } 2711da177e4SLinus Torvalds 2721da177e4SLinus Torvalds /* 2731da177e4SLinus Torvalds * INITIALIZATION function - called when module is initialized/loaded. 2741da177e4SLinus Torvalds */ 2751da177e4SLinus Torvalds int mpc_proc_init(void) 2761da177e4SLinus Torvalds { 2771da177e4SLinus Torvalds struct proc_dir_entry *p; 2781da177e4SLinus Torvalds 27916e297b3SWang Chen p = proc_create(STAT_FILE_NAME, 0, atm_proc_root, &mpc_file_operations); 2801da177e4SLinus Torvalds if (!p) { 28199824461SJoe Perches pr_err("Unable to initialize /proc/atm/%s\n", STAT_FILE_NAME); 2821da177e4SLinus Torvalds return -ENOMEM; 2831da177e4SLinus Torvalds } 2841da177e4SLinus Torvalds return 0; 2851da177e4SLinus Torvalds } 2861da177e4SLinus Torvalds 2871da177e4SLinus Torvalds /* 2881da177e4SLinus Torvalds * DELETING function - called when module is removed. 2891da177e4SLinus Torvalds */ 2901da177e4SLinus Torvalds void mpc_proc_clean(void) 2911da177e4SLinus Torvalds { 2921da177e4SLinus Torvalds remove_proc_entry(STAT_FILE_NAME, atm_proc_root); 2931da177e4SLinus Torvalds } 2941da177e4SLinus Torvalds 2951da177e4SLinus Torvalds #endif /* CONFIG_PROC_FS */ 2961da177e4SLinus Torvalds 2971da177e4SLinus Torvalds 2981da177e4SLinus Torvalds 2991da177e4SLinus Torvalds 3001da177e4SLinus Torvalds 3011da177e4SLinus Torvalds 302