Merge git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-fixes
[pandora-kernel.git] / drivers / staging / batman-adv / bat_sysfs.c
1 /*
2  * Copyright (C) 2010 B.A.T.M.A.N. contributors:
3  *
4  * Marek Lindner
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of version 2 of the GNU General Public
8  * License as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18  * 02110-1301, USA
19  *
20  */
21
22 #include "main.h"
23 #include "bat_sysfs.h"
24 #include "translation-table.h"
25 #include "originator.h"
26 #include "hard-interface.h"
27 #include "vis.h"
28
29 #define to_dev(obj)     container_of(obj, struct device, kobj)
30
31 struct bat_attribute {
32         struct attribute attr;
33         ssize_t (*show)(struct kobject *kobj, struct attribute *attr,
34                         char *buf);
35         ssize_t (*store)(struct kobject *kobj, struct attribute *attr,
36                          char *buf, size_t count);
37 };
38
39 struct hardif_attribute {
40         struct attribute attr;
41         ssize_t (*show)(struct kobject *kobj, struct attribute *attr,
42                         char *buf);
43         ssize_t (*store)(struct kobject *kobj, struct attribute *attr,
44                          char *buf, size_t count);
45 };
46
47 #define BAT_ATTR(_name, _mode, _show, _store)   \
48 struct bat_attribute bat_attr_##_name = {       \
49         .attr = {.name = __stringify(_name),    \
50                  .mode = _mode },               \
51         .show   = _show,                        \
52         .store  = _store,                       \
53 };
54
55 #define BAT_BIN_ATTR(_name, _mode, _read, _write)       \
56 struct bin_attribute bat_attr_##_name = {               \
57         .attr = { .name = __stringify(_name),           \
58                   .mode = _mode, },                     \
59         .read = _read,                                  \
60         .write = _write,                                \
61 };
62
63 #define HARDIF_ATTR(_name, _mode, _show, _store)        \
64 struct hardif_attribute hardif_attr_##_name = {         \
65         .attr = {.name = __stringify(_name),            \
66                  .mode = _mode },                       \
67         .show   = _show,                                \
68         .store  = _store,                               \
69 };
70
71 static ssize_t show_aggr_ogm(struct kobject *kobj, struct attribute *attr,
72                              char *buff)
73 {
74         struct device *dev = to_dev(kobj->parent);
75         struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev));
76         int aggr_status = atomic_read(&bat_priv->aggregation_enabled);
77
78         return sprintf(buff, "status: %s\ncommands: enable, disable, 0, 1\n",
79                        aggr_status == 0 ? "disabled" : "enabled");
80 }
81
82 static ssize_t store_aggr_ogm(struct kobject *kobj, struct attribute *attr,
83                               char *buff, size_t count)
84 {
85         struct device *dev = to_dev(kobj->parent);
86         struct net_device *net_dev = to_net_dev(dev);
87         struct bat_priv *bat_priv = netdev_priv(net_dev);
88         int aggr_tmp = -1;
89
90         if (((count == 2) && (buff[0] == '1')) ||
91             (strncmp(buff, "enable", 6) == 0))
92                 aggr_tmp = 1;
93
94         if (((count == 2) && (buff[0] == '0')) ||
95             (strncmp(buff, "disable", 7) == 0))
96                 aggr_tmp = 0;
97
98         if (aggr_tmp < 0) {
99                 if (buff[count - 1] == '\n')
100                         buff[count - 1] = '\0';
101
102                 printk(KERN_INFO "batman-adv:Invalid parameter for 'aggregate OGM' setting on mesh %s received: %s\n",
103                        net_dev->name, buff);
104                 return -EINVAL;
105         }
106
107         if (atomic_read(&bat_priv->aggregation_enabled) == aggr_tmp)
108                 return count;
109
110         printk(KERN_INFO "batman-adv:Changing aggregation from: %s to: %s on mesh: %s\n",
111                atomic_read(&bat_priv->aggregation_enabled) == 1 ?
112                "enabled" : "disabled", aggr_tmp == 1 ? "enabled" : "disabled",
113                net_dev->name);
114
115         atomic_set(&bat_priv->aggregation_enabled, (unsigned)aggr_tmp);
116         return count;
117 }
118
119 static ssize_t show_vis_mode(struct kobject *kobj, struct attribute *attr,
120                              char *buff)
121 {
122         struct device *dev = to_dev(kobj->parent);
123         struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev));
124         int vis_mode = atomic_read(&bat_priv->vis_mode);
125
126         return sprintf(buff, "status: %s\ncommands: client, server, %d, %d\n",
127                        vis_mode == VIS_TYPE_CLIENT_UPDATE ?
128                                                         "client" : "server",
129                        VIS_TYPE_SERVER_SYNC, VIS_TYPE_CLIENT_UPDATE);
130 }
131
132 static ssize_t store_vis_mode(struct kobject *kobj, struct attribute *attr,
133                               char *buff, size_t count)
134 {
135         struct device *dev = to_dev(kobj->parent);
136         struct net_device *net_dev = to_net_dev(dev);
137         struct bat_priv *bat_priv = netdev_priv(net_dev);
138         unsigned long val;
139         int ret, vis_mode_tmp = -1;
140
141         ret = strict_strtoul(buff, 10, &val);
142
143         if (((count == 2) && (!ret) && (val == VIS_TYPE_CLIENT_UPDATE)) ||
144             (strncmp(buff, "client", 6) == 0))
145                 vis_mode_tmp = VIS_TYPE_CLIENT_UPDATE;
146
147         if (((count == 2) && (!ret) && (val == VIS_TYPE_SERVER_SYNC)) ||
148             (strncmp(buff, "server", 6) == 0))
149                 vis_mode_tmp = VIS_TYPE_SERVER_SYNC;
150
151         if (vis_mode_tmp < 0) {
152                 if (buff[count - 1] == '\n')
153                         buff[count - 1] = '\0';
154
155                 printk(KERN_INFO "batman-adv:Invalid parameter for 'vis mode' setting on mesh %s received: %s\n",
156                        net_dev->name, buff);
157                 return -EINVAL;
158         }
159
160         if (atomic_read(&bat_priv->vis_mode) == vis_mode_tmp)
161                 return count;
162
163         printk(KERN_INFO "batman-adv:Changing vis mode from: %s to: %s on mesh: %s\n",
164                atomic_read(&bat_priv->vis_mode) == VIS_TYPE_CLIENT_UPDATE ?
165                "client" : "server", vis_mode_tmp == VIS_TYPE_CLIENT_UPDATE ?
166                "client" : "server", net_dev->name);
167
168         atomic_set(&bat_priv->vis_mode, (unsigned)vis_mode_tmp);
169         return count;
170 }
171
172 static ssize_t show_orig_interval(struct kobject *kobj, struct attribute *attr,
173                                  char *buff)
174 {
175         struct device *dev = to_dev(kobj->parent);
176         struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev));
177
178         return sprintf(buff, "status: %i\n",
179                        atomic_read(&bat_priv->orig_interval));
180 }
181
182 static ssize_t store_orig_interval(struct kobject *kobj, struct attribute *attr,
183                                   char *buff, size_t count)
184 {
185         struct device *dev = to_dev(kobj->parent);
186         struct net_device *net_dev = to_net_dev(dev);
187         struct bat_priv *bat_priv = netdev_priv(net_dev);
188         unsigned long orig_interval_tmp;
189         int ret;
190
191         ret = strict_strtoul(buff, 10, &orig_interval_tmp);
192         if (ret) {
193                 printk(KERN_INFO "batman-adv:Invalid parameter for 'orig_interval' setting on mesh %s received: %s\n",
194                        net_dev->name, buff);
195                 return -EINVAL;
196         }
197
198         if (orig_interval_tmp <= JITTER * 2) {
199                 printk(KERN_INFO "batman-adv:New originator interval too small: %li (min: %i)\n",
200                        orig_interval_tmp, JITTER * 2);
201                 return -EINVAL;
202         }
203
204         if (atomic_read(&bat_priv->orig_interval) == orig_interval_tmp)
205                 return count;
206
207         printk(KERN_INFO "batman-adv:Changing originator interval from: %i to: %li on mesh: %s\n",
208                atomic_read(&bat_priv->orig_interval),
209                orig_interval_tmp, net_dev->name);
210
211         atomic_set(&bat_priv->orig_interval, orig_interval_tmp);
212         return count;
213 }
214
215 static BAT_ATTR(aggregate_ogm, S_IRUGO | S_IWUSR,
216                 show_aggr_ogm, store_aggr_ogm);
217 static BAT_ATTR(vis_mode, S_IRUGO | S_IWUSR, show_vis_mode, store_vis_mode);
218 static BAT_ATTR(orig_interval, S_IRUGO | S_IWUSR,
219                 show_orig_interval, store_orig_interval);
220
221 static struct bat_attribute *mesh_attrs[] = {
222         &bat_attr_aggregate_ogm,
223         &bat_attr_vis_mode,
224         &bat_attr_orig_interval,
225         NULL,
226 };
227
228 static ssize_t transtable_local_read(struct kobject *kobj,
229                                struct bin_attribute *bin_attr,
230                                char *buff, loff_t off, size_t count)
231 {
232         struct device *dev = to_dev(kobj->parent);
233         struct net_device *net_dev = to_net_dev(dev);
234
235         return hna_local_fill_buffer_text(net_dev, buff, count, off);
236 }
237
238 static ssize_t transtable_global_read(struct kobject *kobj,
239                                struct bin_attribute *bin_attr,
240                                char *buff, loff_t off, size_t count)
241 {
242         struct device *dev = to_dev(kobj->parent);
243         struct net_device *net_dev = to_net_dev(dev);
244
245         return hna_global_fill_buffer_text(net_dev, buff, count, off);
246 }
247
248 static ssize_t originators_read(struct kobject *kobj,
249                                struct bin_attribute *bin_attr,
250                                char *buff, loff_t off, size_t count)
251 {
252         struct device *dev = to_dev(kobj->parent);
253         struct net_device *net_dev = to_net_dev(dev);
254
255         return orig_fill_buffer_text(net_dev, buff, count, off);
256 }
257
258 static ssize_t vis_data_read(struct kobject *kobj,
259                              struct bin_attribute *bin_attr,
260                              char *buff, loff_t off, size_t count)
261 {
262         struct device *dev = to_dev(kobj->parent);
263         struct net_device *net_dev = to_net_dev(dev);
264
265         return vis_fill_buffer_text(net_dev, buff, count, off);
266 }
267
268 static BAT_BIN_ATTR(transtable_local, S_IRUGO, transtable_local_read, NULL);
269 static BAT_BIN_ATTR(transtable_global, S_IRUGO, transtable_global_read, NULL);
270 static BAT_BIN_ATTR(originators, S_IRUGO, originators_read, NULL);
271 static BAT_BIN_ATTR(vis_data, S_IRUGO, vis_data_read, NULL);
272
273 static struct bin_attribute *mesh_bin_attrs[] = {
274         &bat_attr_transtable_local,
275         &bat_attr_transtable_global,
276         &bat_attr_originators,
277         &bat_attr_vis_data,
278         NULL,
279 };
280
281 int sysfs_add_meshif(struct net_device *dev)
282 {
283         struct kobject *batif_kobject = &dev->dev.kobj;
284         struct bat_priv *bat_priv = netdev_priv(dev);
285         struct bat_attribute **bat_attr;
286         struct bin_attribute **bin_attr;
287         int err;
288
289         /* FIXME: should be done in the general mesh setup
290                   routine as soon as we have it */
291         atomic_set(&bat_priv->aggregation_enabled, 1);
292         atomic_set(&bat_priv->vis_mode, VIS_TYPE_CLIENT_UPDATE);
293         atomic_set(&bat_priv->orig_interval, 1000);
294         bat_priv->primary_if = NULL;
295         bat_priv->num_ifaces = 0;
296
297         bat_priv->mesh_obj = kobject_create_and_add(SYSFS_IF_MESH_SUBDIR,
298                                                     batif_kobject);
299         if (!bat_priv->mesh_obj) {
300                 printk(KERN_ERR "batman-adv:Can't add sysfs directory: %s/%s\n",
301                        dev->name, SYSFS_IF_MESH_SUBDIR);
302                 goto out;
303         }
304
305         for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr) {
306                 err = sysfs_create_file(bat_priv->mesh_obj,
307                                         &((*bat_attr)->attr));
308                 if (err) {
309                         printk(KERN_ERR "batman-adv:Can't add sysfs file: %s/%s/%s\n",
310                                dev->name, SYSFS_IF_MESH_SUBDIR,
311                                ((*bat_attr)->attr).name);
312                         goto rem_attr;
313                 }
314         }
315
316         for (bin_attr = mesh_bin_attrs; *bin_attr; ++bin_attr) {
317                 err = sysfs_create_bin_file(bat_priv->mesh_obj, (*bin_attr));
318                 if (err) {
319                         printk(KERN_ERR "batman-adv:Can't add sysfs file: %s/%s/%s\n",
320                                dev->name, SYSFS_IF_MESH_SUBDIR,
321                                ((*bin_attr)->attr).name);
322                         goto rem_bin_attr;
323                 }
324         }
325
326         return 0;
327
328 rem_bin_attr:
329         for (bin_attr = mesh_bin_attrs; *bin_attr; ++bin_attr)
330                 sysfs_remove_bin_file(bat_priv->mesh_obj, (*bin_attr));
331 rem_attr:
332         for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr)
333                 sysfs_remove_file(bat_priv->mesh_obj, &((*bat_attr)->attr));
334
335         kobject_put(bat_priv->mesh_obj);
336         bat_priv->mesh_obj = NULL;
337 out:
338         return -ENOMEM;
339 }
340
341 void sysfs_del_meshif(struct net_device *dev)
342 {
343         struct bat_priv *bat_priv = netdev_priv(dev);
344         struct bat_attribute **bat_attr;
345         struct bin_attribute **bin_attr;
346
347         for (bin_attr = mesh_bin_attrs; *bin_attr; ++bin_attr)
348                 sysfs_remove_bin_file(bat_priv->mesh_obj, (*bin_attr));
349
350         for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr)
351                 sysfs_remove_file(bat_priv->mesh_obj, &((*bat_attr)->attr));
352
353         kobject_put(bat_priv->mesh_obj);
354         bat_priv->mesh_obj = NULL;
355 }
356
357 static ssize_t show_mesh_iface(struct kobject *kobj, struct attribute *attr,
358                                char *buff)
359 {
360         struct device *dev = to_dev(kobj->parent);
361         struct net_device *net_dev = to_net_dev(dev);
362         struct batman_if *batman_if = get_batman_if_by_netdev(net_dev);
363
364         if (!batman_if)
365                 return 0;
366
367         return sprintf(buff, "status: %s\ncommands: none, bat0\n",
368                        batman_if->if_status == IF_NOT_IN_USE ?
369                                                         "none" : "bat0");
370 }
371
372 static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr,
373                                 char *buff, size_t count)
374 {
375         struct device *dev = to_dev(kobj->parent);
376         struct net_device *net_dev = to_net_dev(dev);
377         struct batman_if *batman_if = get_batman_if_by_netdev(net_dev);
378         int status_tmp = -1;
379
380         if (!batman_if)
381                 return count;
382
383         if (strncmp(buff, "none", 4) == 0)
384                 status_tmp = IF_NOT_IN_USE;
385
386         if (strncmp(buff, "bat0", 4) == 0)
387                 status_tmp = IF_I_WANT_YOU;
388
389         if (status_tmp < 0) {
390                 if (buff[count - 1] == '\n')
391                         buff[count - 1] = '\0';
392
393                 printk(KERN_ERR "batman-adv:Invalid parameter for 'mesh_iface' setting received: %s\n",
394                        buff);
395                 return -EINVAL;
396         }
397
398         if ((batman_if->if_status == status_tmp) ||
399             ((status_tmp == IF_I_WANT_YOU) &&
400              (batman_if->if_status != IF_NOT_IN_USE)))
401                 return count;
402
403         if (status_tmp == IF_I_WANT_YOU)
404                 status_tmp = hardif_enable_interface(batman_if);
405         else
406                 hardif_disable_interface(batman_if);
407
408         return (status_tmp < 0 ? status_tmp : count);
409 }
410
411 static ssize_t show_iface_status(struct kobject *kobj, struct attribute *attr,
412                                  char *buff)
413 {
414         struct device *dev = to_dev(kobj->parent);
415         struct net_device *net_dev = to_net_dev(dev);
416         struct batman_if *batman_if = get_batman_if_by_netdev(net_dev);
417
418         if (!batman_if)
419                 return 0;
420
421         switch (batman_if->if_status) {
422         case IF_TO_BE_REMOVED:
423                 return sprintf(buff, "disabling\n");
424         case IF_INACTIVE:
425                 return sprintf(buff, "inactive\n");
426         case IF_ACTIVE:
427                 return sprintf(buff, "active\n");
428         case IF_TO_BE_ACTIVATED:
429                 return sprintf(buff, "enabling\n");
430         case IF_NOT_IN_USE:
431         default:
432                 return sprintf(buff, "not in use\n");
433         }
434 }
435
436 static HARDIF_ATTR(mesh_iface, S_IRUGO | S_IWUSR,
437                    show_mesh_iface, store_mesh_iface);
438 static HARDIF_ATTR(iface_status, S_IRUGO, show_iface_status, NULL);
439
440 static struct hardif_attribute *batman_attrs[] = {
441         &hardif_attr_mesh_iface,
442         &hardif_attr_iface_status,
443         NULL,
444 };
445
446 int sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev)
447 {
448         struct kobject *hardif_kobject = &dev->dev.kobj;
449         struct hardif_attribute **hardif_attr;
450         int err;
451
452         *hardif_obj = kobject_create_and_add(SYSFS_IF_BAT_SUBDIR,
453                                                     hardif_kobject);
454
455         if (!*hardif_obj) {
456                 printk(KERN_ERR "batman-adv:Can't add sysfs directory: %s/%s\n",
457                        dev->name, SYSFS_IF_BAT_SUBDIR);
458                 goto out;
459         }
460
461         for (hardif_attr = batman_attrs; *hardif_attr; ++hardif_attr) {
462                 err = sysfs_create_file(*hardif_obj, &((*hardif_attr)->attr));
463                 if (err) {
464                         printk(KERN_ERR "batman-adv:Can't add sysfs file: %s/%s/%s\n",
465                                dev->name, SYSFS_IF_BAT_SUBDIR,
466                                ((*hardif_attr)->attr).name);
467                         goto rem_attr;
468                 }
469         }
470
471         return 0;
472
473 rem_attr:
474         for (hardif_attr = batman_attrs; *hardif_attr; ++hardif_attr)
475                 sysfs_remove_file(*hardif_obj, &((*hardif_attr)->attr));
476 out:
477         return -ENOMEM;
478 }
479
480 void sysfs_del_hardif(struct kobject **hardif_obj)
481 {
482         kobject_put(*hardif_obj);
483         *hardif_obj = NULL;
484 }