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 31 extern struct mpoa_client *mpcs; 32 extern struct proc_dir_entry *atm_proc_root; /* from proc.c. */ 33 34 static int proc_mpc_open(struct inode *inode, struct file *file); 35 static ssize_t proc_mpc_write(struct file *file, const char __user *buff, 36 size_t nbytes, loff_t *ppos); 37 38 static int parse_qos(const char *buff); 39 40 /* 41 * Define allowed FILE OPERATIONS 42 */ 43 static 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 */ 55 static 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 */ 77 static 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 97 static 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 110 static 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 117 static 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 */ 124 static 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 181 static struct seq_operations mpc_op = { 182 .start = mpc_start, 183 .next = mpc_next, 184 .stop = mpc_stop, 185 .show = mpc_show 186 }; 187 188 static int proc_mpc_open(struct inode *inode, struct file *file) 189 { 190 return seq_open(file, &mpc_op); 191 } 192 193 static 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 228 static 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 */ 276 int 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 */ 293 void 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