Merge with 2.3.48.
[linux-2.6/linux-mips.git] / net / atm / mpoa_proc.c
blobbb6eddfe62f47d07466c664c4914fbd344368d56
1 #include <linux/config.h>
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/proc_fs.h>
9 #include <linux/time.h>
10 #include <asm/uaccess.h>
11 #include <linux/atmmpc.h>
12 #include <linux/atm.h>
13 #include "mpc.h"
14 #include "mpoa_caches.h"
17 * mpoa_proc.c: Implementation MPOA client's proc
18 * file system statistics
21 #if 1
22 #define dprintk printk /* debug */
23 #else
24 #define dprintk(format,args...)
25 #endif
27 #define STAT_FILE_NAME "mpc" /* Our statistic file's name */
29 extern struct mpoa_client *mpcs;
30 extern struct proc_dir_entry *atm_proc_root; /* from proc.c. */
32 static ssize_t proc_mpc_read(struct file *file, char *buff,
33 size_t count, loff_t *pos);
35 static ssize_t proc_mpc_write(struct file *file, const char *buff,
36 size_t nbytes, loff_t *ppos);
38 static int parse_qos(const char *buff, int len);
41 * Define allowed FILE OPERATIONS
43 static struct file_operations mpc_file_operations = {
44 read: proc_mpc_read,
45 write: proc_mpc_write,
48 static int print_header(char *buff,struct mpoa_client *mpc){
49 if(mpc != NULL){
50 return sprintf(buff,"\nInterface %d:\n\n",mpc->dev_num);
53 return 0;
57 * Returns the state of an ingress cache entry as a string
59 static const char *ingress_state_string(int state){
60 switch(state) {
61 case INGRESS_RESOLVING:
62 return "resolving ";
63 break;
64 case INGRESS_RESOLVED:
65 return "resolved ";
66 break;
67 case INGRESS_INVALID:
68 return "invalid ";
69 break;
70 case INGRESS_REFRESHING:
71 return "refreshing ";
72 break;
73 default:
74 return "";
79 * Returns the state of an egress cache entry as a string
81 static const char *egress_state_string(int state){
82 switch(state) {
83 case EGRESS_RESOLVED:
84 return "resolved ";
85 break;
86 case EGRESS_PURGE:
87 return "purge ";
88 break;
89 case EGRESS_INVALID:
90 return "invalid ";
91 break;
92 default:
93 return "";
98 * READING function - called when the /proc/atm/mpoa file is read from.
100 static ssize_t proc_mpc_read(struct file *file, char *buff,
101 size_t count, loff_t *pos){
102 unsigned long page = 0;
103 unsigned char *temp;
104 ssize_t length = 0;
105 int i = 0;
106 struct mpoa_client *mpc = mpcs;
107 in_cache_entry *in_entry;
108 eg_cache_entry *eg_entry;
109 struct timeval now;
110 unsigned char ip_string[16];
111 if(count < 0)
112 return -EINVAL;
113 if(count == 0)
114 return 0;
115 page = get_free_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;
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);
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);
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;
150 length += sprintf((char *)page + length,"\n");
151 mpc = mpc->next;
154 if (*pos >= length) length = 0;
155 else {
156 if ((count + *pos) > length) count = length - *pos;
157 copy_to_user(buff, (char *)page , count);
158 *pos += count;
161 free_page(page);
162 return length;
165 static ssize_t proc_mpc_write(struct file *file, const char *buff,
166 size_t nbytes, loff_t *ppos)
168 int incoming, error, retval;
169 char *page, c;
170 const char *tmp;
172 if (nbytes < 0) return -EINVAL;
173 if (nbytes == 0) return 0;
174 if (nbytes > PAGE_SIZE) nbytes = PAGE_SIZE-1;
176 error = verify_area(VERIFY_READ, buff, nbytes);
177 if (error) return error;
179 page = (char *)__get_free_page(GFP_KERNEL);
180 if (page == NULL) return -ENOMEM;
182 incoming = 0;
183 tmp = buff;
184 while(incoming < nbytes){
185 if (get_user(c, tmp++)) return -EFAULT;
186 incoming++;
187 if (c == '\0' || c == '\n')
188 break;
191 retval = copy_from_user(page, buff, incoming);
192 if (retval != 0) {
193 printk("mpoa: proc_mpc_write: copy_from_user() failed\n");
194 return -EFAULT;
197 *ppos += incoming;
199 page[incoming] = '\0';
200 retval = parse_qos(buff, incoming);
201 if (retval == 0)
202 printk("mpoa: proc_mpc_write: could not parse '%s'\n", page);
204 free_page((unsigned long)page);
206 return nbytes;
209 static int parse_qos(const char *buff, int len)
211 /* possible lines look like this
212 * add 130.230.54.142 tx=max_pcr,max_sdu rx=max_pcr,max_sdu
215 int pos, i;
216 uint32_t ipaddr;
217 unsigned char ip[4];
218 char cmd[4], temp[256];
219 const char *tmp, *prev;
220 struct atm_qos qos;
221 int value[5];
223 memset(&qos, 0, sizeof(struct atm_qos));
224 strncpy(cmd, buff, 3);
225 if( strncmp(cmd,"add", 3) && strncmp(cmd,"del", 3))
226 return 0; /* not add or del */
228 pos = 4;
229 /* next parse ip */
230 prev = buff + pos;
231 for (i = 0; i < 3; i++) {
232 tmp = strchr(prev, '.');
233 if (tmp == NULL) return 0;
234 memset(temp, '\0', 256);
235 memcpy(temp, prev, tmp-prev);
236 ip[i] = (char)simple_strtoul(temp, NULL, 0);
237 tmp ++;
238 prev = tmp;
240 tmp = strchr(prev, ' ');
241 if (tmp == NULL) return 0;
242 memset(temp, '\0', 256);
243 memcpy(temp, prev, tmp-prev);
244 ip[i] = (char)simple_strtoul(temp, NULL, 0);
245 ipaddr = *(uint32_t *)ip;
247 if(!strncmp(cmd, "del", 3))
248 return atm_mpoa_delete_qos(atm_mpoa_search_qos(ipaddr));
250 /* next transmit values */
251 tmp = strstr(buff, "tx=");
252 if(tmp == NULL) return 0;
253 tmp += 3;
254 prev = tmp;
255 for( i = 0; i < 1; i++){
256 tmp = strchr(prev, ',');
257 if (tmp == NULL) return 0;
258 memset(temp, '\0', 256);
259 memcpy(temp, prev, tmp-prev);
260 value[i] = (int)simple_strtoul(temp, NULL, 0);
261 tmp ++;
262 prev = tmp;
264 tmp = strchr(prev, ' ');
265 if (tmp == NULL) return 0;
266 memset(temp, '\0', 256);
267 memcpy(temp, prev, tmp-prev);
268 value[i] = (int)simple_strtoul(temp, NULL, 0);
269 qos.txtp.traffic_class = ATM_CBR;
270 qos.txtp.max_pcr = value[0];
271 qos.txtp.max_sdu = value[1];
273 /* next receive values */
274 tmp = strstr(buff, "rx=");
275 if(tmp == NULL) return 0;
276 if (strstr(buff, "rx=tx")) { /* rx == tx */
277 qos.rxtp.traffic_class = qos.txtp.traffic_class;
278 qos.rxtp.max_pcr = qos.txtp.max_pcr;
279 qos.rxtp.max_cdv = qos.txtp.max_cdv;
280 qos.rxtp.max_sdu = qos.txtp.max_sdu;
281 } else {
282 tmp += 3;
283 prev = tmp;
284 for( i = 0; i < 1; i++){
285 tmp = strchr(prev, ',');
286 if (tmp == NULL) return 0;
287 memset(temp, '\0', 256);
288 memcpy(temp, prev, tmp-prev);
289 value[i] = (int)simple_strtoul(temp, NULL, 0);
290 tmp ++;
291 prev = tmp;
293 tmp = strchr(prev, '\0');
294 if (tmp == NULL) return 0;
295 memset(temp, '\0', 256);
296 memcpy(temp, prev, tmp-prev);
297 value[i] = (int)simple_strtoul(temp, NULL, 0);
298 qos.rxtp.traffic_class = ATM_CBR;
299 qos.rxtp.max_pcr = value[0];
300 qos.rxtp.max_sdu = value[1];
302 qos.aal = ATM_AAL5;
303 dprintk("mpoa: mpoa_proc.c: parse_qos(): setting qos paramameters to tx=%d,%d rx=%d,%d\n",
304 qos.txtp.max_pcr,
305 qos.txtp.max_sdu,
306 qos.rxtp.max_pcr,
307 qos.rxtp.max_sdu
310 atm_mpoa_add_qos(ipaddr, &qos);
311 return 1;
315 * INITIALIZATION function - called when module is initialized/loaded.
317 int mpc_proc_init(void)
319 struct proc_dir_entry *p;
321 p = create_proc_entry(STAT_FILE_NAME, 0, atm_proc_root);
322 if (!p) {
323 printk(KERN_ERR "Unable to initialize /proc/atm/%s\n", STAT_FILE_NAME);
324 return -ENOMEM;
326 p->proc_fops = &mpc_file_operations;
327 return 0;
331 * DELETING function - called when module is removed.
333 void mpc_proc_clean(void)
335 remove_proc_entry(STAT_FILE_NAME,atm_proc_root);
339 #endif /* CONFIG_PROC_FS */