1 #include <linux/config.h>
4 #include <linux/errno.h>
5 #include <linux/kernel.h>
6 #include <linux/string.h>
8 #include <linux/module.h>
9 #include <linux/proc_fs.h>
10 #include <linux/time.h>
11 #include <asm/uaccess.h>
12 #include <linux/atmmpc.h>
13 #include <linux/atm.h>
15 #include "mpoa_caches.h"
18 * mpoa_proc.c: Implementation MPOA client's proc
19 * file system statistics
23 #define dprintk printk /* debug */
25 #define dprintk(format,args...)
28 #define STAT_FILE_NAME "mpc" /* Our statistic file's name */
30 extern struct mpoa_client *mpcs;
31 extern struct proc_dir_entry *atm_proc_root; /* from proc.c. */
33 static ssize_t proc_mpc_read(struct file *file, char *buff,
34 size_t count, loff_t *pos);
36 static ssize_t proc_mpc_write(struct file *file, const char *buff,
37 size_t nbytes, loff_t *ppos);
39 static int parse_qos(const char *buff, int len);
42 * Define allowed FILE OPERATIONS
44 static struct file_operations mpc_file_operations = {
46 write: proc_mpc_write,
49 static int print_header(char *buff,struct mpoa_client *mpc){
51 return sprintf(buff,"\nInterface %d:\n\n",mpc->dev_num);
58 * Returns the state of an ingress cache entry as a string
60 static const char *ingress_state_string(int state){
62 case INGRESS_RESOLVING:
65 case INGRESS_RESOLVED:
71 case INGRESS_REFRESHING:
80 * Returns the state of an egress cache entry as a string
82 static const char *egress_state_string(int state){
99 * READING function - called when the /proc/atm/mpoa file is read from.
101 static ssize_t proc_mpc_read(struct file *file, char *buff,
102 size_t count, loff_t *pos){
103 unsigned long page = 0;
107 struct mpoa_client *mpc = mpcs;
108 in_cache_entry *in_entry;
109 eg_cache_entry *eg_entry;
111 unsigned char ip_string[16];
114 page = get_free_page(GFP_KERNEL);
117 atm_mpoa_disp_qos((char *)page, &length);
119 length += print_header((char *)page + length, mpc);
120 length += sprintf((char *)page + length,"Ingress Entries:\nIP address State Holding time Packets fwded VPI VCI\n");
121 in_entry = mpc->in_cache;
122 do_gettimeofday(&now);
123 while(in_entry != NULL){
124 temp = (unsigned char *)&in_entry->ctrl_info.in_dst_ip; sprintf(ip_string,"%d.%d.%d.%d", temp[0], temp[1], temp[2], temp[3]);
125 length += sprintf((char *)page + length,"%-16s%s%-14lu%-12u", ip_string, ingress_state_string(in_entry->entry_state), (in_entry->ctrl_info.holding_time-(now.tv_sec-in_entry->tv.tv_sec)), in_entry->packets_fwded);
126 if(in_entry->shortcut)
127 length += sprintf((char *)page + length," %-3d %-3d",in_entry->shortcut->vpi,in_entry->shortcut->vci);
128 length += sprintf((char *)page + length,"\n");
129 in_entry = in_entry->next;
131 length += sprintf((char *)page + length,"\n");
132 eg_entry = mpc->eg_cache;
133 length += sprintf((char *)page + length,"Egress Entries:\nIngress MPC ATM addr\nCache-id State Holding time Packets recvd Latest IP addr VPI VCI\n");
134 while(eg_entry != NULL){
135 for(i=0;i<ATM_ESA_LEN;i++){
136 length += sprintf((char *)page + length,"%02x",eg_entry->ctrl_info.in_MPC_data_ATM_addr[i]);}
137 length += sprintf((char *)page + length,"\n%-16lu%s%-14lu%-15u",(unsigned long) ntohl(eg_entry->ctrl_info.cache_id), egress_state_string(eg_entry->entry_state), (eg_entry->ctrl_info.holding_time-(now.tv_sec-eg_entry->tv.tv_sec)), eg_entry->packets_rcvd);
139 /* latest IP address */
140 temp = (unsigned char *)&eg_entry->latest_ip_addr;
141 sprintf(ip_string, "%d.%d.%d.%d", temp[0], temp[1], temp[2], temp[3]);
142 length += sprintf((char *)page + length, "%-16s", ip_string);
144 if(eg_entry->shortcut)
145 length += sprintf((char *)page + length," %-3d %-3d",eg_entry->shortcut->vpi,eg_entry->shortcut->vci);
146 length += sprintf((char *)page + length,"\n");
147 eg_entry = eg_entry->next;
149 length += sprintf((char *)page + length,"\n");
153 if (*pos >= length) length = 0;
155 if ((count + *pos) > length) count = length - *pos;
156 if (copy_to_user(buff, (char *)page , count)) {
167 static ssize_t proc_mpc_write(struct file *file, const char *buff,
168 size_t nbytes, loff_t *ppos)
170 int incoming, error, retval;
174 if (nbytes == 0) return 0;
175 if (nbytes >= PAGE_SIZE) nbytes = PAGE_SIZE-1;
177 error = verify_area(VERIFY_READ, buff, nbytes);
178 if (error) return error;
180 page = (char *)__get_free_page(GFP_KERNEL);
181 if (page == NULL) return -ENOMEM;
185 while(incoming < nbytes){
186 if (get_user(c, tmp++)) return -EFAULT;
188 if (c == '\0' || c == '\n')
192 retval = copy_from_user(page, buff, incoming);
194 printk("mpoa: proc_mpc_write: copy_from_user() failed\n");
200 page[incoming] = '\0';
201 retval = parse_qos(page, incoming);
203 printk("mpoa: proc_mpc_write: could not parse '%s'\n", page);
205 free_page((unsigned long)page);
210 static int parse_qos(const char *buff, int len)
212 /* possible lines look like this
213 * add 130.230.54.142 tx=max_pcr,max_sdu rx=max_pcr,max_sdu
219 char cmd[4], temp[256];
220 const char *tmp, *prev;
224 memset(&qos, 0, sizeof(struct atm_qos));
225 strncpy(cmd, buff, 3);
226 if( strncmp(cmd,"add", 3) && strncmp(cmd,"del", 3))
227 return 0; /* not add or del */
232 for (i = 0; i < 3; i++) {
233 tmp = strchr(prev, '.');
234 if (tmp == NULL) return 0;
235 memset(temp, '\0', 256);
236 memcpy(temp, prev, tmp-prev);
237 ip[i] = (char)simple_strtoul(temp, NULL, 0);
241 tmp = strchr(prev, ' ');
242 if (tmp == NULL) return 0;
243 memset(temp, '\0', 256);
244 memcpy(temp, prev, tmp-prev);
245 ip[i] = (char)simple_strtoul(temp, NULL, 0);
246 ipaddr = *(uint32_t *)ip;
248 if(!strncmp(cmd, "del", 3))
249 return atm_mpoa_delete_qos(atm_mpoa_search_qos(ipaddr));
251 /* next transmit values */
252 tmp = strstr(buff, "tx=");
253 if(tmp == NULL) return 0;
256 for( i = 0; i < 1; i++){
257 tmp = strchr(prev, ',');
258 if (tmp == NULL) return 0;
259 memset(temp, '\0', 256);
260 memcpy(temp, prev, tmp-prev);
261 value[i] = (int)simple_strtoul(temp, NULL, 0);
265 tmp = strchr(prev, ' ');
266 if (tmp == NULL) return 0;
267 memset(temp, '\0', 256);
268 memcpy(temp, prev, tmp-prev);
269 value[i] = (int)simple_strtoul(temp, NULL, 0);
270 qos.txtp.traffic_class = ATM_CBR;
271 qos.txtp.max_pcr = value[0];
272 qos.txtp.max_sdu = value[1];
274 /* next receive values */
275 tmp = strstr(buff, "rx=");
276 if(tmp == NULL) return 0;
277 if (strstr(buff, "rx=tx")) { /* rx == tx */
278 qos.rxtp.traffic_class = qos.txtp.traffic_class;
279 qos.rxtp.max_pcr = qos.txtp.max_pcr;
280 qos.rxtp.max_cdv = qos.txtp.max_cdv;
281 qos.rxtp.max_sdu = qos.txtp.max_sdu;
285 for( i = 0; i < 1; i++){
286 tmp = strchr(prev, ',');
287 if (tmp == NULL) return 0;
288 memset(temp, '\0', 256);
289 memcpy(temp, prev, tmp-prev);
290 value[i] = (int)simple_strtoul(temp, NULL, 0);
294 tmp = strchr(prev, '\0');
295 if (tmp == NULL) return 0;
296 memset(temp, '\0', 256);
297 memcpy(temp, prev, tmp-prev);
298 value[i] = (int)simple_strtoul(temp, NULL, 0);
299 qos.rxtp.traffic_class = ATM_CBR;
300 qos.rxtp.max_pcr = value[0];
301 qos.rxtp.max_sdu = value[1];
304 dprintk("mpoa: mpoa_proc.c: parse_qos(): setting qos paramameters to tx=%d,%d rx=%d,%d\n",
311 atm_mpoa_add_qos(ipaddr, &qos);
316 * INITIALIZATION function - called when module is initialized/loaded.
318 int mpc_proc_init(void)
320 struct proc_dir_entry *p;
322 p = create_proc_entry(STAT_FILE_NAME, 0, atm_proc_root);
324 printk(KERN_ERR "Unable to initialize /proc/atm/%s\n", STAT_FILE_NAME);
327 p->proc_fops = &mpc_file_operations;
328 p->owner = THIS_MODULE;
333 * DELETING function - called when module is removed.
335 void mpc_proc_clean(void)
337 remove_proc_entry(STAT_FILE_NAME,atm_proc_root);
341 #endif /* CONFIG_PROC_FS */