1 #include <linux/config.h>
4 #include <linux/errno.h>
5 #include <linux/kernel.h>
6 #include <linux/string.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>
14 #include "mpoa_caches.h"
17 * mpoa_proc.c: Implementation MPOA client's proc
18 * file system statistics
22 #define dprintk printk /* debug */
24 #define dprintk(format,args...)
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
= {
45 write
: proc_mpc_write
,
48 static int print_header(char *buff
,struct mpoa_client
*mpc
){
50 return sprintf(buff
,"\nInterface %d:\n\n",mpc
->dev_num
);
57 * Returns the state of an ingress cache entry as a string
59 static const char *ingress_state_string(int state
){
61 case INGRESS_RESOLVING
:
64 case INGRESS_RESOLVED
:
70 case INGRESS_REFRESHING
:
79 * Returns the state of an egress cache entry as a string
81 static const char *egress_state_string(int state
){
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;
106 struct mpoa_client
*mpc
= mpcs
;
107 in_cache_entry
*in_entry
;
108 eg_cache_entry
*eg_entry
;
110 unsigned char ip_string
[16];
115 page
= get_free_page(GFP_KERNEL
);
118 atm_mpoa_disp_qos((char *)page
, &length
);
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");
154 if (*pos
>= length
) length
= 0;
156 if ((count
+ *pos
) > length
) count
= length
- *pos
;
157 copy_to_user(buff
, (char *)page
, count
);
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
;
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
;
184 while(incoming
< nbytes
){
185 if (get_user(c
, tmp
++)) return -EFAULT
;
187 if (c
== '\0' || c
== '\n')
191 retval
= copy_from_user(page
, buff
, incoming
);
193 printk("mpoa: proc_mpc_write: copy_from_user() failed\n");
199 page
[incoming
] = '\0';
200 retval
= parse_qos(buff
, incoming
);
202 printk("mpoa: proc_mpc_write: could not parse '%s'\n", page
);
204 free_page((unsigned long)page
);
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
218 char cmd
[4], temp
[256];
219 const char *tmp
, *prev
;
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 */
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);
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;
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);
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
;
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);
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];
303 dprintk("mpoa: mpoa_proc.c: parse_qos(): setting qos paramameters to tx=%d,%d rx=%d,%d\n",
310 atm_mpoa_add_qos(ipaddr
, &qos
);
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
);
323 printk(KERN_ERR
"Unable to initialize /proc/atm/%s\n", STAT_FILE_NAME
);
326 p
->proc_fops
= &mpc_file_operations
;
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 */