patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / net / atm / mpoa_proc.c
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 <asm/uaccess.h>
12 #include <linux/atmmpc.h>
13 #include <linux/atm.h>
14 #include "mpc.h"
15 #include "mpoa_caches.h"
16
17 /*
18  * mpoa_proc.c: Implementation MPOA client's proc
19  * file system statistics 
20  */
21
22 #if 1
23 #define dprintk printk   /* debug */
24 #else
25 #define dprintk(format,args...)
26 #endif
27
28 #define STAT_FILE_NAME "mpc"     /* Our statistic file's name */
29
30 extern struct mpoa_client *mpcs;
31 extern struct proc_dir_entry *atm_proc_root;  /* from proc.c. */
32
33 static ssize_t proc_mpc_read(struct file *file, char __user *buff,
34                              size_t count, loff_t *pos);
35
36 static ssize_t proc_mpc_write(struct file *file, const char __user *buff,
37                               size_t nbytes, loff_t *ppos);
38
39 static int parse_qos(const char *buff, int len);
40
41 /*
42  *   Define allowed FILE OPERATIONS
43  */
44 static struct file_operations mpc_file_operations = {
45         .owner =        THIS_MODULE,
46         .read =         proc_mpc_read,
47         .write =        proc_mpc_write,
48 };
49
50 static int print_header(char *buff,struct mpoa_client *mpc){
51         if(mpc != NULL){
52                 return sprintf(buff,"\nInterface %d:\n\n",mpc->dev_num);  
53           
54         }
55         return 0;
56 }
57
58 /*
59  * Returns the state of an ingress cache entry as a string
60  */
61 static const char *ingress_state_string(int state){
62         switch(state) {
63         case INGRESS_RESOLVING:
64                 return "resolving  ";
65                 break;
66         case INGRESS_RESOLVED:
67                 return "resolved   ";
68                 break;
69         case INGRESS_INVALID:
70                 return "invalid    ";
71                 break;
72         case INGRESS_REFRESHING:
73                 return "refreshing ";
74                 break;
75         default:
76                return "";
77         }
78 }
79
80 /*
81  * Returns the state of an egress cache entry as a string
82  */
83 static const char *egress_state_string(int state){
84         switch(state) {
85         case EGRESS_RESOLVED:
86                 return "resolved   ";
87                 break;
88         case EGRESS_PURGE:
89                 return "purge      ";
90                 break;
91         case EGRESS_INVALID:
92                 return "invalid    ";
93                 break;
94         default:
95                return "";
96         }
97 }
98
99 /*
100  * READING function - called when the /proc/atm/mpoa file is read from.
101  */
102 static ssize_t proc_mpc_read(struct file *file, char __user *buff,
103                              size_t count, loff_t *pos){
104         unsigned long page = 0;
105         unsigned char *temp;
106         int length = 0;
107         int i = 0;
108         struct mpoa_client *mpc = mpcs;
109         in_cache_entry *in_entry;
110         eg_cache_entry *eg_entry;
111         struct timeval now;
112         unsigned char ip_string[16];
113         if(count == 0)
114                 return 0;
115         page = get_zeroed_page(GFP_KERNEL);
116         if(!page)
117                 return -ENOMEM;
118         atm_mpoa_disp_qos((char *)page, &length);
119         while(mpc != NULL){
120                 length += print_header((char *)page + length, mpc);
121                 length += sprintf((char *)page + length,"Ingress Entries:\nIP address      State      Holding time  Packets fwded  VPI  VCI\n");
122                 in_entry = mpc->in_cache;
123                 do_gettimeofday(&now);
124                 while(in_entry != NULL){
125                         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]);
126                         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);
127                         if(in_entry->shortcut)
128                                 length += sprintf((char *)page + length,"   %-3d  %-3d",in_entry->shortcut->vpi,in_entry->shortcut->vci);
129                         length += sprintf((char *)page + length,"\n");
130                         in_entry = in_entry->next;
131                 }
132                 length += sprintf((char *)page + length,"\n");
133                 eg_entry = mpc->eg_cache;
134                 length += sprintf((char *)page + length,"Egress Entries:\nIngress MPC ATM addr\nCache-id        State      Holding time  Packets recvd  Latest IP addr   VPI VCI\n");
135                 while(eg_entry != NULL){
136                   for(i=0;i<ATM_ESA_LEN;i++){
137                           length += sprintf((char *)page + length,"%02x",eg_entry->ctrl_info.in_MPC_data_ATM_addr[i]);}  
138                         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                         
140                         /* latest IP address */
141                         temp = (unsigned char *)&eg_entry->latest_ip_addr;
142                         sprintf(ip_string, "%d.%d.%d.%d", temp[0], temp[1], temp[2], temp[3]);
143                         length += sprintf((char *)page + length, "%-16s", ip_string);
144
145                         if(eg_entry->shortcut)
146                                 length += sprintf((char *)page + length," %-3d %-3d",eg_entry->shortcut->vpi,eg_entry->shortcut->vci);
147                         length += sprintf((char *)page + length,"\n");
148                         eg_entry = eg_entry->next;
149                 }
150                 length += sprintf((char *)page + length,"\n");
151                 mpc = mpc->next;
152         }
153
154         if (*pos >= length) length = 0;
155         else {
156           if ((count + *pos) > length) count = length - *pos;
157           if (copy_to_user(buff, (char *)page , count)) {
158                   free_page(page);
159                   return -EFAULT;
160           }
161           *pos += count;
162         }
163
164         free_page(page);
165         return length;
166 }
167
168 static ssize_t proc_mpc_write(struct file *file, const char __user *buff,
169                               size_t nbytes, loff_t *ppos)
170 {
171         int incoming, error, retval;
172         char *page, c;
173         const char __user *tmp;
174
175         if (nbytes == 0) return 0;
176         if (nbytes >= PAGE_SIZE) nbytes = PAGE_SIZE-1;
177
178         error = verify_area(VERIFY_READ, buff, nbytes);
179         if (error) return error;
180
181         page = (char *)__get_free_page(GFP_KERNEL);
182         if (page == NULL) return -ENOMEM;
183
184         incoming = 0;
185         tmp = buff;
186         while(incoming < nbytes){
187                 if (get_user(c, tmp++)) return -EFAULT;
188                 incoming++;
189                 if (c == '\0' || c == '\n')
190                         break;
191         }
192
193         retval = copy_from_user(page, buff, incoming);
194         if (retval != 0) {
195                 printk("mpoa: proc_mpc_write: copy_from_user() failed\n");
196                 return -EFAULT;
197         }
198
199         *ppos += incoming;
200
201         page[incoming] = '\0';
202         retval = parse_qos(page, incoming);
203         if (retval == 0)
204                 printk("mpoa: proc_mpc_write: could not parse '%s'\n", page);
205
206         free_page((unsigned long)page);
207         
208         return nbytes;
209 }
210
211 static int parse_qos(const char *buff, int len)
212 {
213         /* possible lines look like this
214          * add 130.230.54.142 tx=max_pcr,max_sdu rx=max_pcr,max_sdu
215          */
216         
217         int pos, i;
218         uint32_t ipaddr;
219         unsigned char ip[4]; 
220         char cmd[4], temp[256];
221         const char *tmp, *prev;
222         struct atm_qos qos; 
223         int value[5];
224         
225         memset(&qos, 0, sizeof(struct atm_qos));
226         strlcpy(cmd, buff, sizeof(cmd));
227         if( strncmp(cmd,"add", 3) &&  strncmp(cmd,"del", 3))
228                 return 0;  /* not add or del */
229
230         pos = 4;
231         /* next parse ip */
232         prev = buff + pos;
233         for (i = 0; i < 3; i++) {
234                 tmp = strchr(prev, '.');
235                 if (tmp == NULL) return 0;
236                 memset(temp, '\0', 256);
237                 memcpy(temp, prev, tmp-prev);
238                 ip[i] = (char)simple_strtoul(temp, NULL, 0);
239                 tmp ++; 
240                 prev = tmp;
241         }
242         tmp = strchr(prev, ' ');
243         if (tmp == NULL) return 0;
244         memset(temp, '\0', 256);
245         memcpy(temp, prev, tmp-prev);
246         ip[i] = (char)simple_strtoul(temp, NULL, 0);
247         ipaddr = *(uint32_t *)ip;
248                 
249         if(!strncmp(cmd, "del", 3))
250                  return atm_mpoa_delete_qos(atm_mpoa_search_qos(ipaddr));
251
252         /* next transmit values */
253         tmp = strstr(buff, "tx=");
254         if(tmp == NULL) return 0;
255         tmp += 3;
256         prev = tmp;
257         for( i = 0; i < 1; i++){
258                  tmp = strchr(prev, ',');
259                  if (tmp == NULL) return 0;
260                  memset(temp, '\0', 256);
261                  memcpy(temp, prev, tmp-prev);
262                  value[i] = (int)simple_strtoul(temp, NULL, 0);
263                  tmp ++; 
264                  prev = tmp;
265         }
266         tmp = strchr(prev, ' ');
267         if (tmp == NULL) return 0;
268         memset(temp, '\0', 256);
269         memcpy(temp, prev, tmp-prev);
270         value[i] = (int)simple_strtoul(temp, NULL, 0);
271         qos.txtp.traffic_class = ATM_CBR;
272         qos.txtp.max_pcr = value[0];
273         qos.txtp.max_sdu = value[1];
274
275         /* next receive values */
276         tmp = strstr(buff, "rx=");
277         if(tmp == NULL) return 0;
278         if (strstr(buff, "rx=tx")) { /* rx == tx */
279                 qos.rxtp.traffic_class = qos.txtp.traffic_class;
280                 qos.rxtp.max_pcr = qos.txtp.max_pcr;
281                 qos.rxtp.max_cdv = qos.txtp.max_cdv;
282                 qos.rxtp.max_sdu = qos.txtp.max_sdu;
283         } else {
284                 tmp += 3;
285                 prev = tmp;
286                 for( i = 0; i < 1; i++){
287                         tmp = strchr(prev, ',');
288                         if (tmp == NULL) return 0;
289                         memset(temp, '\0', 256);
290                         memcpy(temp, prev, tmp-prev);
291                         value[i] = (int)simple_strtoul(temp, NULL, 0);
292                         tmp ++; 
293                         prev = tmp;
294                 }
295                 tmp = strchr(prev, '\0');
296                 if (tmp == NULL) return 0;
297                 memset(temp, '\0', 256);
298                 memcpy(temp, prev, tmp-prev);
299                 value[i] = (int)simple_strtoul(temp, NULL, 0);
300                 qos.rxtp.traffic_class = ATM_CBR;
301                 qos.rxtp.max_pcr = value[0];
302                 qos.rxtp.max_sdu = value[1];
303         }
304         qos.aal = ATM_AAL5;
305         dprintk("mpoa: mpoa_proc.c: parse_qos(): setting qos paramameters to tx=%d,%d rx=%d,%d\n",
306                 qos.txtp.max_pcr,
307                 qos.txtp.max_sdu,
308                 qos.rxtp.max_pcr,
309                 qos.rxtp.max_sdu
310                 );
311
312         atm_mpoa_add_qos(ipaddr, &qos);
313         return 1;
314 }
315
316 /*
317  * INITIALIZATION function - called when module is initialized/loaded.
318  */
319 int mpc_proc_init(void)
320 {
321         struct proc_dir_entry *p;
322
323         p = create_proc_entry(STAT_FILE_NAME, 0, atm_proc_root);
324         if (!p) {
325                 printk(KERN_ERR "Unable to initialize /proc/atm/%s\n", STAT_FILE_NAME);
326                 return -ENOMEM;
327         }
328         p->proc_fops = &mpc_file_operations;
329         p->owner = THIS_MODULE;
330         return 0;
331 }
332
333 /*
334  * DELETING function - called when module is removed.
335  */
336 void mpc_proc_clean(void)
337 {
338         remove_proc_entry(STAT_FILE_NAME,atm_proc_root);
339 }
340
341
342 #endif /* CONFIG_PROC_FS */
343
344
345
346
347
348