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 .read
= proc_mpc_read
,
47 .write
= proc_mpc_write
,
50 static int print_header(char *buff
,struct mpoa_client
*mpc
){
52 return sprintf(buff
,"\nInterface %d:\n\n",mpc
->dev_num
);
59 * Returns the state of an ingress cache entry as a string
61 static const char *ingress_state_string(int state
){
63 case INGRESS_RESOLVING
:
66 case INGRESS_RESOLVED
:
72 case INGRESS_REFRESHING
:
81 * Returns the state of an egress cache entry as a string
83 static const char *egress_state_string(int state
){
100 * READING function - called when the /proc/atm/mpoa file is read from.
102 static ssize_t
proc_mpc_read(struct file
*file
, char *buff
,
103 size_t count
, loff_t
*pos
){
104 unsigned long page
= 0;
108 struct mpoa_client
*mpc
= mpcs
;
109 in_cache_entry
*in_entry
;
110 eg_cache_entry
*eg_entry
;
112 unsigned char ip_string
[16];
115 page
= get_zeroed_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 if (copy_to_user(buff
, (char *)page
, count
)) {
168 static ssize_t
proc_mpc_write(struct file
*file
, const char *buff
,
169 size_t nbytes
, loff_t
*ppos
)
171 int incoming
, error
, retval
;
175 if (nbytes
== 0) return 0;
176 if (nbytes
>= PAGE_SIZE
) nbytes
= PAGE_SIZE
-1;
178 error
= verify_area(VERIFY_READ
, buff
, nbytes
);
179 if (error
) return error
;
181 page
= (char *)__get_free_page(GFP_KERNEL
);
182 if (page
== NULL
) return -ENOMEM
;
186 while(incoming
< nbytes
){
187 if (get_user(c
, tmp
++)) return -EFAULT
;
189 if (c
== '\0' || c
== '\n')
193 retval
= copy_from_user(page
, buff
, incoming
);
195 printk("mpoa: proc_mpc_write: copy_from_user() failed\n");
201 page
[incoming
] = '\0';
202 retval
= parse_qos(page
, incoming
);
204 printk("mpoa: proc_mpc_write: could not parse '%s'\n", page
);
206 free_page((unsigned long)page
);
211 static int parse_qos(const char *buff
, int len
)
213 /* possible lines look like this
214 * add 130.230.54.142 tx=max_pcr,max_sdu rx=max_pcr,max_sdu
220 char cmd
[4], temp
[256];
221 const char *tmp
, *prev
;
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 */
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);
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
;
249 if(!strncmp(cmd
, "del", 3))
250 return atm_mpoa_delete_qos(atm_mpoa_search_qos(ipaddr
));
252 /* next transmit values */
253 tmp
= strstr(buff
, "tx=");
254 if(tmp
== NULL
) return 0;
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);
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];
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
;
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);
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];
305 dprintk("mpoa: mpoa_proc.c: parse_qos(): setting qos paramameters to tx=%d,%d rx=%d,%d\n",
312 atm_mpoa_add_qos(ipaddr
, &qos
);
317 * INITIALIZATION function - called when module is initialized/loaded.
319 int mpc_proc_init(void)
321 struct proc_dir_entry
*p
;
323 p
= create_proc_entry(STAT_FILE_NAME
, 0, atm_proc_root
);
325 printk(KERN_ERR
"Unable to initialize /proc/atm/%s\n", STAT_FILE_NAME
);
328 p
->proc_fops
= &mpc_file_operations
;
329 p
->owner
= THIS_MODULE
;
334 * DELETING function - called when module is removed.
336 void mpc_proc_clean(void)
338 remove_proc_entry(STAT_FILE_NAME
,atm_proc_root
);
342 #endif /* CONFIG_PROC_FS */