diff options
Diffstat (limited to 'net/atm/mpoa_proc.c')
-rw-r--r-- | net/atm/mpoa_proc.c | 305 |
1 files changed, 305 insertions, 0 deletions
diff --git a/net/atm/mpoa_proc.c b/net/atm/mpoa_proc.c new file mode 100644 index 000000000000..60834b5a14d6 --- /dev/null +++ b/net/atm/mpoa_proc.c | |||
@@ -0,0 +1,305 @@ | |||
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 <linux/seq_file.h> | ||
12 | #include <asm/uaccess.h> | ||
13 | #include <linux/atmmpc.h> | ||
14 | #include <linux/atm.h> | ||
15 | #include "mpc.h" | ||
16 | #include "mpoa_caches.h" | ||
17 | |||
18 | /* | ||
19 | * mpoa_proc.c: Implementation MPOA client's proc | ||
20 | * file system statistics | ||
21 | */ | ||
22 | |||
23 | #if 1 | ||
24 | #define dprintk printk /* debug */ | ||
25 | #else | ||
26 | #define dprintk(format,args...) | ||
27 | #endif | ||
28 | |||
29 | #define STAT_FILE_NAME "mpc" /* Our statistic file's name */ | ||
30 | |||
31 | extern struct mpoa_client *mpcs; | ||
32 | extern struct proc_dir_entry *atm_proc_root; /* from proc.c. */ | ||
33 | |||
34 | static int proc_mpc_open(struct inode *inode, struct file *file); | ||
35 | static ssize_t proc_mpc_write(struct file *file, const char __user *buff, | ||
36 | size_t nbytes, loff_t *ppos); | ||
37 | |||
38 | static int parse_qos(const char *buff); | ||
39 | |||
40 | /* | ||
41 | * Define allowed FILE OPERATIONS | ||
42 | */ | ||
43 | static struct file_operations mpc_file_operations = { | ||
44 | .owner = THIS_MODULE, | ||
45 | .open = proc_mpc_open, | ||
46 | .read = seq_read, | ||
47 | .llseek = seq_lseek, | ||
48 | .write = proc_mpc_write, | ||
49 | .release = seq_release, | ||
50 | }; | ||
51 | |||
52 | /* | ||
53 | * Returns the state of an ingress cache entry as a string | ||
54 | */ | ||
55 | static const char *ingress_state_string(int state){ | ||
56 | switch(state) { | ||
57 | case INGRESS_RESOLVING: | ||
58 | return "resolving "; | ||
59 | break; | ||
60 | case INGRESS_RESOLVED: | ||
61 | return "resolved "; | ||
62 | break; | ||
63 | case INGRESS_INVALID: | ||
64 | return "invalid "; | ||
65 | break; | ||
66 | case INGRESS_REFRESHING: | ||
67 | return "refreshing "; | ||
68 | break; | ||
69 | default: | ||
70 | return ""; | ||
71 | } | ||
72 | } | ||
73 | |||
74 | /* | ||
75 | * Returns the state of an egress cache entry as a string | ||
76 | */ | ||
77 | static const char *egress_state_string(int state){ | ||
78 | switch(state) { | ||
79 | case EGRESS_RESOLVED: | ||
80 | return "resolved "; | ||
81 | break; | ||
82 | case EGRESS_PURGE: | ||
83 | return "purge "; | ||
84 | break; | ||
85 | case EGRESS_INVALID: | ||
86 | return "invalid "; | ||
87 | break; | ||
88 | default: | ||
89 | return ""; | ||
90 | } | ||
91 | } | ||
92 | |||
93 | /* | ||
94 | * FIXME: mpcs (and per-mpc lists) have no locking whatsoever. | ||
95 | */ | ||
96 | |||
97 | static void *mpc_start(struct seq_file *m, loff_t *pos) | ||
98 | { | ||
99 | loff_t l = *pos; | ||
100 | struct mpoa_client *mpc; | ||
101 | |||
102 | if (!l--) | ||
103 | return SEQ_START_TOKEN; | ||
104 | for (mpc = mpcs; mpc; mpc = mpc->next) | ||
105 | if (!l--) | ||
106 | return mpc; | ||
107 | return NULL; | ||
108 | } | ||
109 | |||
110 | static void *mpc_next(struct seq_file *m, void *v, loff_t *pos) | ||
111 | { | ||
112 | struct mpoa_client *p = v; | ||
113 | (*pos)++; | ||
114 | return v == SEQ_START_TOKEN ? mpcs : p->next; | ||
115 | } | ||
116 | |||
117 | static void mpc_stop(struct seq_file *m, void *v) | ||
118 | { | ||
119 | } | ||
120 | |||
121 | /* | ||
122 | * READING function - called when the /proc/atm/mpoa file is read from. | ||
123 | */ | ||
124 | static int mpc_show(struct seq_file *m, void *v) | ||
125 | { | ||
126 | struct mpoa_client *mpc = v; | ||
127 | unsigned char *temp; | ||
128 | int i; | ||
129 | in_cache_entry *in_entry; | ||
130 | eg_cache_entry *eg_entry; | ||
131 | struct timeval now; | ||
132 | unsigned char ip_string[16]; | ||
133 | |||
134 | if (v == SEQ_START_TOKEN) { | ||
135 | atm_mpoa_disp_qos(m); | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | seq_printf(m, "\nInterface %d:\n\n", mpc->dev_num); | ||
140 | seq_printf(m, "Ingress Entries:\nIP address State Holding time Packets fwded VPI VCI\n"); | ||
141 | do_gettimeofday(&now); | ||
142 | |||
143 | for (in_entry = mpc->in_cache; in_entry; in_entry = in_entry->next) { | ||
144 | temp = (unsigned char *)&in_entry->ctrl_info.in_dst_ip; | ||
145 | sprintf(ip_string,"%d.%d.%d.%d", temp[0], temp[1], temp[2], temp[3]); | ||
146 | seq_printf(m, "%-16s%s%-14lu%-12u", | ||
147 | ip_string, | ||
148 | ingress_state_string(in_entry->entry_state), | ||
149 | in_entry->ctrl_info.holding_time-(now.tv_sec-in_entry->tv.tv_sec), | ||
150 | in_entry->packets_fwded); | ||
151 | if (in_entry->shortcut) | ||
152 | seq_printf(m, " %-3d %-3d",in_entry->shortcut->vpi,in_entry->shortcut->vci); | ||
153 | seq_printf(m, "\n"); | ||
154 | } | ||
155 | |||
156 | seq_printf(m, "\n"); | ||
157 | seq_printf(m, "Egress Entries:\nIngress MPC ATM addr\nCache-id State Holding time Packets recvd Latest IP addr VPI VCI\n"); | ||
158 | for (eg_entry = mpc->eg_cache; eg_entry; eg_entry = eg_entry->next) { | ||
159 | unsigned char *p = eg_entry->ctrl_info.in_MPC_data_ATM_addr; | ||
160 | for(i = 0; i < ATM_ESA_LEN; i++) | ||
161 | seq_printf(m, "%02x", p[i]); | ||
162 | seq_printf(m, "\n%-16lu%s%-14lu%-15u", | ||
163 | (unsigned long)ntohl(eg_entry->ctrl_info.cache_id), | ||
164 | egress_state_string(eg_entry->entry_state), | ||
165 | (eg_entry->ctrl_info.holding_time-(now.tv_sec-eg_entry->tv.tv_sec)), | ||
166 | eg_entry->packets_rcvd); | ||
167 | |||
168 | /* latest IP address */ | ||
169 | temp = (unsigned char *)&eg_entry->latest_ip_addr; | ||
170 | sprintf(ip_string, "%d.%d.%d.%d", temp[0], temp[1], temp[2], temp[3]); | ||
171 | seq_printf(m, "%-16s", ip_string); | ||
172 | |||
173 | if (eg_entry->shortcut) | ||
174 | seq_printf(m, " %-3d %-3d",eg_entry->shortcut->vpi,eg_entry->shortcut->vci); | ||
175 | seq_printf(m, "\n"); | ||
176 | } | ||
177 | seq_printf(m, "\n"); | ||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | static struct seq_operations mpc_op = { | ||
182 | .start = mpc_start, | ||
183 | .next = mpc_next, | ||
184 | .stop = mpc_stop, | ||
185 | .show = mpc_show | ||
186 | }; | ||
187 | |||
188 | static int proc_mpc_open(struct inode *inode, struct file *file) | ||
189 | { | ||
190 | return seq_open(file, &mpc_op); | ||
191 | } | ||
192 | |||
193 | static ssize_t proc_mpc_write(struct file *file, const char __user *buff, | ||
194 | size_t nbytes, loff_t *ppos) | ||
195 | { | ||
196 | char *page, *p; | ||
197 | unsigned len; | ||
198 | |||
199 | if (nbytes == 0) | ||
200 | return 0; | ||
201 | |||
202 | if (nbytes >= PAGE_SIZE) | ||
203 | nbytes = PAGE_SIZE-1; | ||
204 | |||
205 | page = (char *)__get_free_page(GFP_KERNEL); | ||
206 | if (!page) | ||
207 | return -ENOMEM; | ||
208 | |||
209 | for (p = page, len = 0; len < nbytes; p++, len++) { | ||
210 | if (get_user(*p, buff++)) { | ||
211 | free_page((unsigned long)page); | ||
212 | return -EFAULT; | ||
213 | } | ||
214 | if (*p == '\0' || *p == '\n') | ||
215 | break; | ||
216 | } | ||
217 | |||
218 | *p = '\0'; | ||
219 | |||
220 | if (!parse_qos(page)) | ||
221 | printk("mpoa: proc_mpc_write: could not parse '%s'\n", page); | ||
222 | |||
223 | free_page((unsigned long)page); | ||
224 | |||
225 | return len; | ||
226 | } | ||
227 | |||
228 | static int parse_qos(const char *buff) | ||
229 | { | ||
230 | /* possible lines look like this | ||
231 | * add 130.230.54.142 tx=max_pcr,max_sdu rx=max_pcr,max_sdu | ||
232 | */ | ||
233 | unsigned char ip[4]; | ||
234 | int tx_pcr, tx_sdu, rx_pcr, rx_sdu; | ||
235 | uint32_t ipaddr; | ||
236 | struct atm_qos qos; | ||
237 | |||
238 | memset(&qos, 0, sizeof(struct atm_qos)); | ||
239 | |||
240 | if (sscanf(buff, "del %hhu.%hhu.%hhu.%hhu", | ||
241 | ip, ip+1, ip+2, ip+3) == 4) { | ||
242 | ipaddr = *(uint32_t *)ip; | ||
243 | return atm_mpoa_delete_qos(atm_mpoa_search_qos(ipaddr)); | ||
244 | } | ||
245 | |||
246 | if (sscanf(buff, "add %hhu.%hhu.%hhu.%hhu tx=%d,%d rx=tx", | ||
247 | ip, ip+1, ip+2, ip+3, &tx_pcr, &tx_sdu) == 6) { | ||
248 | rx_pcr = tx_pcr; | ||
249 | rx_sdu = tx_sdu; | ||
250 | } else if (sscanf(buff, "add %hhu.%hhu.%hhu.%hhu tx=%d,%d rx=%d,%d", | ||
251 | ip, ip+1, ip+2, ip+3, &tx_pcr, &tx_sdu, &rx_pcr, &rx_sdu) != 8) | ||
252 | return 0; | ||
253 | |||
254 | ipaddr = *(uint32_t *)ip; | ||
255 | qos.txtp.traffic_class = ATM_CBR; | ||
256 | qos.txtp.max_pcr = tx_pcr; | ||
257 | qos.txtp.max_sdu = tx_sdu; | ||
258 | qos.rxtp.traffic_class = ATM_CBR; | ||
259 | qos.rxtp.max_pcr = rx_pcr; | ||
260 | qos.rxtp.max_sdu = rx_sdu; | ||
261 | qos.aal = ATM_AAL5; | ||
262 | dprintk("mpoa: mpoa_proc.c: parse_qos(): setting qos paramameters to tx=%d,%d rx=%d,%d\n", | ||
263 | qos.txtp.max_pcr, | ||
264 | qos.txtp.max_sdu, | ||
265 | qos.rxtp.max_pcr, | ||
266 | qos.rxtp.max_sdu | ||
267 | ); | ||
268 | |||
269 | atm_mpoa_add_qos(ipaddr, &qos); | ||
270 | return 1; | ||
271 | } | ||
272 | |||
273 | /* | ||
274 | * INITIALIZATION function - called when module is initialized/loaded. | ||
275 | */ | ||
276 | int mpc_proc_init(void) | ||
277 | { | ||
278 | struct proc_dir_entry *p; | ||
279 | |||
280 | p = create_proc_entry(STAT_FILE_NAME, 0, atm_proc_root); | ||
281 | if (!p) { | ||
282 | printk(KERN_ERR "Unable to initialize /proc/atm/%s\n", STAT_FILE_NAME); | ||
283 | return -ENOMEM; | ||
284 | } | ||
285 | p->proc_fops = &mpc_file_operations; | ||
286 | p->owner = THIS_MODULE; | ||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | /* | ||
291 | * DELETING function - called when module is removed. | ||
292 | */ | ||
293 | void mpc_proc_clean(void) | ||
294 | { | ||
295 | remove_proc_entry(STAT_FILE_NAME,atm_proc_root); | ||
296 | } | ||
297 | |||
298 | |||
299 | #endif /* CONFIG_PROC_FS */ | ||
300 | |||
301 | |||
302 | |||
303 | |||
304 | |||
305 | |||