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];
116 page
= get_free_page(GFP_KERNEL
);
119 atm_mpoa_disp_qos((char *)page
, &length
);
121 length
+= print_header((char *)page
+ length
, mpc
);
122 length
+= sprintf((char *)page
+ length
,"Ingress Entries:\nIP address State Holding time Packets fwded VPI VCI\n");
123 in_entry
= mpc
->in_cache
;
124 do_gettimeofday(&now
);
125 while(in_entry
!= NULL
){
126 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]);
127 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
);
128 if(in_entry
->shortcut
)
129 length
+= sprintf((char *)page
+ length
," %-3d %-3d",in_entry
->shortcut
->vpi
,in_entry
->shortcut
->vci
);
130 length
+= sprintf((char *)page
+ length
,"\n");
131 in_entry
= in_entry
->next
;
133 length
+= sprintf((char *)page
+ length
,"\n");
134 eg_entry
= mpc
->eg_cache
;
135 length
+= sprintf((char *)page
+ length
,"Egress Entries:\nIngress MPC ATM addr\nCache-id State Holding time Packets recvd Latest IP addr VPI VCI\n");
136 while(eg_entry
!= NULL
){
137 for(i
=0;i
<ATM_ESA_LEN
;i
++){
138 length
+= sprintf((char *)page
+ length
,"%02x",eg_entry
->ctrl_info
.in_MPC_data_ATM_addr
[i
]);}
139 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
);
141 /* latest IP address */
142 temp
= (unsigned char *)&eg_entry
->latest_ip_addr
;
143 sprintf(ip_string
, "%d.%d.%d.%d", temp
[0], temp
[1], temp
[2], temp
[3]);
144 length
+= sprintf((char *)page
+ length
, "%-16s", ip_string
);
146 if(eg_entry
->shortcut
)
147 length
+= sprintf((char *)page
+ length
," %-3d %-3d",eg_entry
->shortcut
->vpi
,eg_entry
->shortcut
->vci
);
148 length
+= sprintf((char *)page
+ length
,"\n");
149 eg_entry
= eg_entry
->next
;
151 length
+= sprintf((char *)page
+ length
,"\n");
155 if (*pos
>= length
) length
= 0;
157 if ((count
+ *pos
) > length
) count
= length
- *pos
;
158 if (copy_to_user(buff
, (char *)page
, count
)) {
169 static ssize_t
proc_mpc_write(struct file
*file
, const char *buff
,
170 size_t nbytes
, loff_t
*ppos
)
172 int incoming
, error
, retval
;
176 if (nbytes
< 0) return -EINVAL
;
177 if (nbytes
== 0) return 0;
178 if (nbytes
> PAGE_SIZE
) nbytes
= PAGE_SIZE
-1;
180 error
= verify_area(VERIFY_READ
, buff
, nbytes
);
181 if (error
) return error
;
183 page
= (char *)__get_free_page(GFP_KERNEL
);
184 if (page
== NULL
) return -ENOMEM
;
188 while(incoming
< nbytes
){
189 if (get_user(c
, tmp
++)) return -EFAULT
;
191 if (c
== '\0' || c
== '\n')
195 retval
= copy_from_user(page
, buff
, incoming
);
197 printk("mpoa: proc_mpc_write: copy_from_user() failed\n");
203 page
[incoming
] = '\0';
204 retval
= parse_qos(page
, incoming
);
206 printk("mpoa: proc_mpc_write: could not parse '%s'\n", page
);
208 free_page((unsigned long)page
);
213 static int parse_qos(const char *buff
, int len
)
215 /* possible lines look like this
216 * add 130.230.54.142 tx=max_pcr,max_sdu rx=max_pcr,max_sdu
222 char cmd
[4], temp
[256];
223 const char *tmp
, *prev
;
227 memset(&qos
, 0, sizeof(struct atm_qos
));
228 strncpy(cmd
, buff
, 3);
229 if( strncmp(cmd
,"add", 3) && strncmp(cmd
,"del", 3))
230 return 0; /* not add or del */
235 for (i
= 0; i
< 3; i
++) {
236 tmp
= strchr(prev
, '.');
237 if (tmp
== NULL
) return 0;
238 memset(temp
, '\0', 256);
239 memcpy(temp
, prev
, tmp
-prev
);
240 ip
[i
] = (char)simple_strtoul(temp
, NULL
, 0);
244 tmp
= strchr(prev
, ' ');
245 if (tmp
== NULL
) return 0;
246 memset(temp
, '\0', 256);
247 memcpy(temp
, prev
, tmp
-prev
);
248 ip
[i
] = (char)simple_strtoul(temp
, NULL
, 0);
249 ipaddr
= *(uint32_t *)ip
;
251 if(!strncmp(cmd
, "del", 3))
252 return atm_mpoa_delete_qos(atm_mpoa_search_qos(ipaddr
));
254 /* next transmit values */
255 tmp
= strstr(buff
, "tx=");
256 if(tmp
== NULL
) return 0;
259 for( i
= 0; i
< 1; i
++){
260 tmp
= strchr(prev
, ',');
261 if (tmp
== NULL
) return 0;
262 memset(temp
, '\0', 256);
263 memcpy(temp
, prev
, tmp
-prev
);
264 value
[i
] = (int)simple_strtoul(temp
, NULL
, 0);
268 tmp
= strchr(prev
, ' ');
269 if (tmp
== NULL
) return 0;
270 memset(temp
, '\0', 256);
271 memcpy(temp
, prev
, tmp
-prev
);
272 value
[i
] = (int)simple_strtoul(temp
, NULL
, 0);
273 qos
.txtp
.traffic_class
= ATM_CBR
;
274 qos
.txtp
.max_pcr
= value
[0];
275 qos
.txtp
.max_sdu
= value
[1];
277 /* next receive values */
278 tmp
= strstr(buff
, "rx=");
279 if(tmp
== NULL
) return 0;
280 if (strstr(buff
, "rx=tx")) { /* rx == tx */
281 qos
.rxtp
.traffic_class
= qos
.txtp
.traffic_class
;
282 qos
.rxtp
.max_pcr
= qos
.txtp
.max_pcr
;
283 qos
.rxtp
.max_cdv
= qos
.txtp
.max_cdv
;
284 qos
.rxtp
.max_sdu
= qos
.txtp
.max_sdu
;
288 for( i
= 0; i
< 1; i
++){
289 tmp
= strchr(prev
, ',');
290 if (tmp
== NULL
) return 0;
291 memset(temp
, '\0', 256);
292 memcpy(temp
, prev
, tmp
-prev
);
293 value
[i
] = (int)simple_strtoul(temp
, NULL
, 0);
297 tmp
= strchr(prev
, '\0');
298 if (tmp
== NULL
) return 0;
299 memset(temp
, '\0', 256);
300 memcpy(temp
, prev
, tmp
-prev
);
301 value
[i
] = (int)simple_strtoul(temp
, NULL
, 0);
302 qos
.rxtp
.traffic_class
= ATM_CBR
;
303 qos
.rxtp
.max_pcr
= value
[0];
304 qos
.rxtp
.max_sdu
= value
[1];
307 dprintk("mpoa: mpoa_proc.c: parse_qos(): setting qos paramameters to tx=%d,%d rx=%d,%d\n",
314 atm_mpoa_add_qos(ipaddr
, &qos
);
319 * INITIALIZATION function - called when module is initialized/loaded.
321 int mpc_proc_init(void)
323 struct proc_dir_entry
*p
;
325 p
= create_proc_entry(STAT_FILE_NAME
, 0, atm_proc_root
);
327 printk(KERN_ERR
"Unable to initialize /proc/atm/%s\n", STAT_FILE_NAME
);
330 p
->proc_fops
= &mpc_file_operations
;
331 p
->owner
= THIS_MODULE
;
336 * DELETING function - called when module is removed.
338 void mpc_proc_clean(void)
340 remove_proc_entry(STAT_FILE_NAME
,atm_proc_root
);
344 #endif /* CONFIG_PROC_FS */