0001
0002 #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
0003
0004 #ifdef CONFIG_PROC_FS
0005 #include <linux/errno.h>
0006 #include <linux/kernel.h>
0007 #include <linux/string.h>
0008 #include <linux/mm.h>
0009 #include <linux/module.h>
0010 #include <linux/proc_fs.h>
0011 #include <linux/ktime.h>
0012 #include <linux/seq_file.h>
0013 #include <linux/uaccess.h>
0014 #include <linux/atmmpc.h>
0015 #include <linux/atm.h>
0016 #include <linux/gfp.h>
0017 #include "mpc.h"
0018 #include "mpoa_caches.h"
0019
0020
0021
0022
0023
0024
0025 #if 1
0026 #define dprintk(format, args...) \
0027 printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args)
0028 #else
0029 #define dprintk(format, args...) \
0030 do { if (0) \
0031 printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args);\
0032 } while (0)
0033 #endif
0034
0035 #if 0
0036 #define ddprintk(format, args...) \
0037 printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args)
0038 #else
0039 #define ddprintk(format, args...) \
0040 do { if (0) \
0041 printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args);\
0042 } while (0)
0043 #endif
0044
0045 #define STAT_FILE_NAME "mpc"
0046
0047 extern struct mpoa_client *mpcs;
0048 extern struct proc_dir_entry *atm_proc_root;
0049
0050 static int proc_mpc_open(struct inode *inode, struct file *file);
0051 static ssize_t proc_mpc_write(struct file *file, const char __user *buff,
0052 size_t nbytes, loff_t *ppos);
0053
0054 static int parse_qos(const char *buff);
0055
0056 static const struct proc_ops mpc_proc_ops = {
0057 .proc_open = proc_mpc_open,
0058 .proc_read = seq_read,
0059 .proc_lseek = seq_lseek,
0060 .proc_write = proc_mpc_write,
0061 .proc_release = seq_release,
0062 };
0063
0064
0065
0066
0067 static const char *ingress_state_string(int state)
0068 {
0069 switch (state) {
0070 case INGRESS_RESOLVING:
0071 return "resolving ";
0072 case INGRESS_RESOLVED:
0073 return "resolved ";
0074 case INGRESS_INVALID:
0075 return "invalid ";
0076 case INGRESS_REFRESHING:
0077 return "refreshing ";
0078 }
0079
0080 return "";
0081 }
0082
0083
0084
0085
0086 static const char *egress_state_string(int state)
0087 {
0088 switch (state) {
0089 case EGRESS_RESOLVED:
0090 return "resolved ";
0091 case EGRESS_PURGE:
0092 return "purge ";
0093 case EGRESS_INVALID:
0094 return "invalid ";
0095 }
0096
0097 return "";
0098 }
0099
0100
0101
0102
0103
0104 static void *mpc_start(struct seq_file *m, loff_t *pos)
0105 {
0106 loff_t l = *pos;
0107 struct mpoa_client *mpc;
0108
0109 if (!l--)
0110 return SEQ_START_TOKEN;
0111 for (mpc = mpcs; mpc; mpc = mpc->next)
0112 if (!l--)
0113 return mpc;
0114 return NULL;
0115 }
0116
0117 static void *mpc_next(struct seq_file *m, void *v, loff_t *pos)
0118 {
0119 struct mpoa_client *p = v;
0120 (*pos)++;
0121 return v == SEQ_START_TOKEN ? mpcs : p->next;
0122 }
0123
0124 static void mpc_stop(struct seq_file *m, void *v)
0125 {
0126 }
0127
0128
0129
0130
0131 static int mpc_show(struct seq_file *m, void *v)
0132 {
0133 struct mpoa_client *mpc = v;
0134 int i;
0135 in_cache_entry *in_entry;
0136 eg_cache_entry *eg_entry;
0137 time64_t now;
0138 unsigned char ip_string[16];
0139
0140 if (v == SEQ_START_TOKEN) {
0141 atm_mpoa_disp_qos(m);
0142 return 0;
0143 }
0144
0145 seq_printf(m, "\nInterface %d:\n\n", mpc->dev_num);
0146 seq_printf(m, "Ingress Entries:\nIP address State Holding time Packets fwded VPI VCI\n");
0147 now = ktime_get_seconds();
0148
0149 for (in_entry = mpc->in_cache; in_entry; in_entry = in_entry->next) {
0150 unsigned long seconds_delta = now - in_entry->time;
0151
0152 sprintf(ip_string, "%pI4", &in_entry->ctrl_info.in_dst_ip);
0153 seq_printf(m, "%-16s%s%-14lu%-12u",
0154 ip_string,
0155 ingress_state_string(in_entry->entry_state),
0156 in_entry->ctrl_info.holding_time -
0157 seconds_delta,
0158 in_entry->packets_fwded);
0159 if (in_entry->shortcut)
0160 seq_printf(m, " %-3d %-3d",
0161 in_entry->shortcut->vpi,
0162 in_entry->shortcut->vci);
0163 seq_printf(m, "\n");
0164 }
0165
0166 seq_printf(m, "\n");
0167 seq_printf(m, "Egress Entries:\nIngress MPC ATM addr\nCache-id State Holding time Packets recvd Latest IP addr VPI VCI\n");
0168 for (eg_entry = mpc->eg_cache; eg_entry; eg_entry = eg_entry->next) {
0169 unsigned char *p = eg_entry->ctrl_info.in_MPC_data_ATM_addr;
0170 unsigned long seconds_delta = now - eg_entry->time;
0171
0172 for (i = 0; i < ATM_ESA_LEN; i++)
0173 seq_printf(m, "%02x", p[i]);
0174 seq_printf(m, "\n%-16lu%s%-14lu%-15u",
0175 (unsigned long)ntohl(eg_entry->ctrl_info.cache_id),
0176 egress_state_string(eg_entry->entry_state),
0177 (eg_entry->ctrl_info.holding_time - seconds_delta),
0178 eg_entry->packets_rcvd);
0179
0180
0181 sprintf(ip_string, "%pI4", &eg_entry->latest_ip_addr);
0182 seq_printf(m, "%-16s", ip_string);
0183
0184 if (eg_entry->shortcut)
0185 seq_printf(m, " %-3d %-3d",
0186 eg_entry->shortcut->vpi,
0187 eg_entry->shortcut->vci);
0188 seq_printf(m, "\n");
0189 }
0190 seq_printf(m, "\n");
0191 return 0;
0192 }
0193
0194 static const struct seq_operations mpc_op = {
0195 .start = mpc_start,
0196 .next = mpc_next,
0197 .stop = mpc_stop,
0198 .show = mpc_show
0199 };
0200
0201 static int proc_mpc_open(struct inode *inode, struct file *file)
0202 {
0203 return seq_open(file, &mpc_op);
0204 }
0205
0206 static ssize_t proc_mpc_write(struct file *file, const char __user *buff,
0207 size_t nbytes, loff_t *ppos)
0208 {
0209 char *page, *p;
0210 unsigned int len;
0211
0212 if (nbytes == 0)
0213 return 0;
0214
0215 if (nbytes >= PAGE_SIZE)
0216 nbytes = PAGE_SIZE-1;
0217
0218 page = (char *)__get_free_page(GFP_KERNEL);
0219 if (!page)
0220 return -ENOMEM;
0221
0222 for (p = page, len = 0; len < nbytes; p++, len++) {
0223 if (get_user(*p, buff++)) {
0224 free_page((unsigned long)page);
0225 return -EFAULT;
0226 }
0227 if (*p == '\0' || *p == '\n')
0228 break;
0229 }
0230
0231 *p = '\0';
0232
0233 if (!parse_qos(page))
0234 printk("mpoa: proc_mpc_write: could not parse '%s'\n", page);
0235
0236 free_page((unsigned long)page);
0237
0238 return len;
0239 }
0240
0241 static int parse_qos(const char *buff)
0242 {
0243
0244
0245
0246 unsigned char ip[4];
0247 int tx_pcr, tx_sdu, rx_pcr, rx_sdu;
0248 __be32 ipaddr;
0249 struct atm_qos qos;
0250
0251 memset(&qos, 0, sizeof(struct atm_qos));
0252
0253 if (sscanf(buff, "del %hhu.%hhu.%hhu.%hhu",
0254 ip, ip+1, ip+2, ip+3) == 4) {
0255 ipaddr = *(__be32 *)ip;
0256 return atm_mpoa_delete_qos(atm_mpoa_search_qos(ipaddr));
0257 }
0258
0259 if (sscanf(buff, "add %hhu.%hhu.%hhu.%hhu tx=%d,%d rx=tx",
0260 ip, ip+1, ip+2, ip+3, &tx_pcr, &tx_sdu) == 6) {
0261 rx_pcr = tx_pcr;
0262 rx_sdu = tx_sdu;
0263 } else if (sscanf(buff, "add %hhu.%hhu.%hhu.%hhu tx=%d,%d rx=%d,%d",
0264 ip, ip+1, ip+2, ip+3, &tx_pcr, &tx_sdu, &rx_pcr, &rx_sdu) != 8)
0265 return 0;
0266
0267 ipaddr = *(__be32 *)ip;
0268 qos.txtp.traffic_class = ATM_CBR;
0269 qos.txtp.max_pcr = tx_pcr;
0270 qos.txtp.max_sdu = tx_sdu;
0271 qos.rxtp.traffic_class = ATM_CBR;
0272 qos.rxtp.max_pcr = rx_pcr;
0273 qos.rxtp.max_sdu = rx_sdu;
0274 qos.aal = ATM_AAL5;
0275 dprintk("parse_qos(): setting qos parameters to tx=%d,%d rx=%d,%d\n",
0276 qos.txtp.max_pcr, qos.txtp.max_sdu,
0277 qos.rxtp.max_pcr, qos.rxtp.max_sdu);
0278
0279 atm_mpoa_add_qos(ipaddr, &qos);
0280 return 1;
0281 }
0282
0283
0284
0285
0286 int mpc_proc_init(void)
0287 {
0288 struct proc_dir_entry *p;
0289
0290 p = proc_create(STAT_FILE_NAME, 0, atm_proc_root, &mpc_proc_ops);
0291 if (!p) {
0292 pr_err("Unable to initialize /proc/atm/%s\n", STAT_FILE_NAME);
0293 return -ENOMEM;
0294 }
0295 return 0;
0296 }
0297
0298
0299
0300
0301 void mpc_proc_clean(void)
0302 {
0303 remove_proc_entry(STAT_FILE_NAME, atm_proc_root);
0304 }
0305
0306 #endif