Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes...
[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 #define BAT_ATTR(_name, _mode, _show, _store)   \
32 struct bat_attribute bat_attr_##_name = {       \
33         .attr = {.name = __stringify(_name),    \
34                  .mode = _mode },               \
35         .show   = _show,                        \
36         .store  = _store,                       \
37 };
38
39 static ssize_t show_aggr_ogms(struct kobject *kobj, struct attribute *attr,
40                              char *buff)
41 {
42         struct device *dev = to_dev(kobj->parent);
43         struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev));
44         int aggr_status = atomic_read(&bat_priv->aggregation_enabled);
45
46         return sprintf(buff, "%s\n",
47                        aggr_status == 0 ? "disabled" : "enabled");
48 }
49
50 static ssize_t store_aggr_ogms(struct kobject *kobj, struct attribute *attr,
51                               char *buff, size_t count)
52 {
53         struct device *dev = to_dev(kobj->parent);
54         struct net_device *net_dev = to_net_dev(dev);
55         struct bat_priv *bat_priv = netdev_priv(net_dev);
56         int aggr_tmp = -1;
57
58         if (((count == 2) && (buff[0] == '1')) ||
59             (strncmp(buff, "enable", 6) == 0))
60                 aggr_tmp = 1;
61
62         if (((count == 2) && (buff[0] == '0')) ||
63             (strncmp(buff, "disable", 7) == 0))
64                 aggr_tmp = 0;
65
66         if (aggr_tmp < 0) {
67                 if (buff[count - 1] == '\n')
68                         buff[count - 1] = '\0';
69
70                 bat_info(net_dev,
71                          "Invalid parameter for 'aggregate OGM' setting"
72                          "received: %s\n", buff);
73                 return -EINVAL;
74         }
75
76         if (atomic_read(&bat_priv->aggregation_enabled) == aggr_tmp)
77                 return count;
78
79         bat_info(net_dev, "Changing aggregation from: %s to: %s\n",
80                  atomic_read(&bat_priv->aggregation_enabled) == 1 ?
81                  "enabled" : "disabled", aggr_tmp == 1 ? "enabled" :
82                  "disabled");
83
84         atomic_set(&bat_priv->aggregation_enabled, (unsigned)aggr_tmp);
85         return count;
86 }
87
88 static ssize_t show_bond(struct kobject *kobj, struct attribute *attr,
89                              char *buff)
90 {
91         struct device *dev = to_dev(kobj->parent);
92         struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev));
93         int bond_status = atomic_read(&bat_priv->bonding_enabled);
94
95         return sprintf(buff, "%s\n",
96                        bond_status == 0 ? "disabled" : "enabled");
97 }
98
99 static ssize_t store_bond(struct kobject *kobj, struct attribute *attr,
100                           char *buff, size_t count)
101 {
102         struct device *dev = to_dev(kobj->parent);
103         struct net_device *net_dev = to_net_dev(dev);
104         struct bat_priv *bat_priv = netdev_priv(net_dev);
105         int bonding_enabled_tmp = -1;
106
107         if (((count == 2) && (buff[0] == '1')) ||
108             (strncmp(buff, "enable", 6) == 0))
109                 bonding_enabled_tmp = 1;
110
111         if (((count == 2) && (buff[0] == '0')) ||
112             (strncmp(buff, "disable", 7) == 0))
113                 bonding_enabled_tmp = 0;
114
115         if (bonding_enabled_tmp < 0) {
116                 if (buff[count - 1] == '\n')
117                         buff[count - 1] = '\0';
118
119                 bat_err(net_dev,
120                         "Invalid parameter for 'bonding' setting received: "
121                         "%s\n", buff);
122                 return -EINVAL;
123         }
124
125         if (atomic_read(&bat_priv->bonding_enabled) == bonding_enabled_tmp)
126                 return count;
127
128         bat_info(net_dev, "Changing bonding from: %s to: %s\n",
129                  atomic_read(&bat_priv->bonding_enabled) == 1 ?
130                  "enabled" : "disabled",
131                  bonding_enabled_tmp == 1 ? "enabled" : "disabled");
132
133         atomic_set(&bat_priv->bonding_enabled, (unsigned)bonding_enabled_tmp);
134         return count;
135 }
136
137 static ssize_t show_vis_mode(struct kobject *kobj, struct attribute *attr,
138                              char *buff)
139 {
140         struct device *dev = to_dev(kobj->parent);
141         struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev));
142         int vis_mode = atomic_read(&bat_priv->vis_mode);
143
144         return sprintf(buff, "%s\n",
145                        vis_mode == VIS_TYPE_CLIENT_UPDATE ?
146                                                         "client" : "server");
147 }
148
149 static ssize_t store_vis_mode(struct kobject *kobj, struct attribute *attr,
150                               char *buff, size_t count)
151 {
152         struct device *dev = to_dev(kobj->parent);
153         struct net_device *net_dev = to_net_dev(dev);
154         struct bat_priv *bat_priv = netdev_priv(net_dev);
155         unsigned long val;
156         int ret, vis_mode_tmp = -1;
157
158         ret = strict_strtoul(buff, 10, &val);
159
160         if (((count == 2) && (!ret) && (val == VIS_TYPE_CLIENT_UPDATE)) ||
161             (strncmp(buff, "client", 6) == 0) ||
162             (strncmp(buff, "off", 3) == 0))
163                 vis_mode_tmp = VIS_TYPE_CLIENT_UPDATE;
164
165         if (((count == 2) && (!ret) && (val == VIS_TYPE_SERVER_SYNC)) ||
166             (strncmp(buff, "server", 6) == 0))
167                 vis_mode_tmp = VIS_TYPE_SERVER_SYNC;
168
169         if (vis_mode_tmp < 0) {
170                 if (buff[count - 1] == '\n')
171                         buff[count - 1] = '\0';
172
173                 bat_info(net_dev,
174                          "Invalid parameter for 'vis mode' setting received: "
175                          "%s\n", buff);
176                 return -EINVAL;
177         }
178
179         if (atomic_read(&bat_priv->vis_mode) == vis_mode_tmp)
180                 return count;
181
182         bat_info(net_dev, "Changing vis mode from: %s to: %s\n",
183                  atomic_read(&bat_priv->vis_mode) == VIS_TYPE_CLIENT_UPDATE ?
184                  "client" : "server", vis_mode_tmp == VIS_TYPE_CLIENT_UPDATE ?
185                  "client" : "server");
186
187         atomic_set(&bat_priv->vis_mode, (unsigned)vis_mode_tmp);
188         return count;
189 }
190
191 static ssize_t show_orig_interval(struct kobject *kobj, struct attribute *attr,
192                                  char *buff)
193 {
194         struct device *dev = to_dev(kobj->parent);
195         struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev));
196
197         return sprintf(buff, "%i\n",
198                        atomic_read(&bat_priv->orig_interval));
199 }
200
201 static ssize_t store_orig_interval(struct kobject *kobj, struct attribute *attr,
202                                   char *buff, size_t count)
203 {
204         struct device *dev = to_dev(kobj->parent);
205         struct net_device *net_dev = to_net_dev(dev);
206         struct bat_priv *bat_priv = netdev_priv(net_dev);
207         unsigned long orig_interval_tmp;
208         int ret;
209
210         ret = strict_strtoul(buff, 10, &orig_interval_tmp);
211         if (ret) {
212                 bat_info(net_dev, "Invalid parameter for 'orig_interval' "
213                          "setting received: %s\n", buff);
214                 return -EINVAL;
215         }
216
217         if (orig_interval_tmp < JITTER * 2) {
218                 bat_info(net_dev, "New originator interval too small: %li "
219                          "(min: %i)\n", orig_interval_tmp, JITTER * 2);
220                 return -EINVAL;
221         }
222
223         if (atomic_read(&bat_priv->orig_interval) == orig_interval_tmp)
224                 return count;
225
226         bat_info(net_dev, "Changing originator interval from: %i to: %li\n",
227                  atomic_read(&bat_priv->orig_interval),
228                  orig_interval_tmp);
229
230         atomic_set(&bat_priv->orig_interval, orig_interval_tmp);
231         return count;
232 }
233
234 #ifdef CONFIG_BATMAN_ADV_DEBUG
235 static ssize_t show_log_level(struct kobject *kobj, struct attribute *attr,
236                              char *buff)
237 {
238         struct device *dev = to_dev(kobj->parent);
239         struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev));
240         int log_level = atomic_read(&bat_priv->log_level);
241
242         return sprintf(buff, "%d\n", log_level);
243 }
244
245 static ssize_t store_log_level(struct kobject *kobj, struct attribute *attr,
246                               char *buff, size_t count)
247 {
248         struct device *dev = to_dev(kobj->parent);
249         struct net_device *net_dev = to_net_dev(dev);
250         struct bat_priv *bat_priv = netdev_priv(net_dev);
251         unsigned long log_level_tmp;
252         int ret;
253
254         ret = strict_strtoul(buff, 10, &log_level_tmp);
255         if (ret) {
256                 bat_info(net_dev, "Invalid parameter for 'log_level' "
257                          "setting received: %s\n", buff);
258                 return -EINVAL;
259         }
260
261         if (log_level_tmp > 3) {
262                 bat_info(net_dev, "New log level too big: %li "
263                          "(max: %i)\n", log_level_tmp, 3);
264                 return -EINVAL;
265         }
266
267         if (atomic_read(&bat_priv->log_level) == log_level_tmp)
268                 return count;
269
270         bat_info(net_dev, "Changing log level from: %i to: %li\n",
271                  atomic_read(&bat_priv->log_level),
272                  log_level_tmp);
273
274         atomic_set(&bat_priv->log_level, (unsigned)log_level_tmp);
275         return count;
276 }
277 #endif
278
279 static BAT_ATTR(aggregated_ogms, S_IRUGO | S_IWUSR,
280                 show_aggr_ogms, store_aggr_ogms);
281 static BAT_ATTR(bonding, S_IRUGO | S_IWUSR, show_bond, store_bond);
282 static BAT_ATTR(vis_mode, S_IRUGO | S_IWUSR, show_vis_mode, store_vis_mode);
283 static BAT_ATTR(orig_interval, S_IRUGO | S_IWUSR,
284                 show_orig_interval, store_orig_interval);
285 #ifdef CONFIG_BATMAN_ADV_DEBUG
286 static BAT_ATTR(log_level, S_IRUGO | S_IWUSR, show_log_level, store_log_level);
287 #endif
288
289 static struct bat_attribute *mesh_attrs[] = {
290         &bat_attr_aggregated_ogms,
291         &bat_attr_bonding,
292         &bat_attr_vis_mode,
293         &bat_attr_orig_interval,
294 #ifdef CONFIG_BATMAN_ADV_DEBUG
295         &bat_attr_log_level,
296 #endif
297         NULL,
298 };
299
300 int sysfs_add_meshif(struct net_device *dev)
301 {
302         struct kobject *batif_kobject = &dev->dev.kobj;
303         struct bat_priv *bat_priv = netdev_priv(dev);
304         struct bat_attribute **bat_attr;
305         int err;
306
307         /* FIXME: should be done in the general mesh setup
308                   routine as soon as we have it */
309         atomic_set(&bat_priv->aggregation_enabled, 1);
310         atomic_set(&bat_priv->bonding_enabled, 0);
311         atomic_set(&bat_priv->vis_mode, VIS_TYPE_CLIENT_UPDATE);
312         atomic_set(&bat_priv->orig_interval, 1000);
313         atomic_set(&bat_priv->log_level, 0);
314
315         bat_priv->primary_if = NULL;
316         bat_priv->num_ifaces = 0;
317
318         bat_priv->mesh_obj = kobject_create_and_add(SYSFS_IF_MESH_SUBDIR,
319                                                     batif_kobject);
320         if (!bat_priv->mesh_obj) {
321                 bat_err(dev, "Can't add sysfs directory: %s/%s\n", dev->name,
322                         SYSFS_IF_MESH_SUBDIR);
323                 goto out;
324         }
325
326         for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr) {
327                 err = sysfs_create_file(bat_priv->mesh_obj,
328                                         &((*bat_attr)->attr));
329                 if (err) {
330                         bat_err(dev, "Can't add sysfs file: %s/%s/%s\n",
331                                 dev->name, SYSFS_IF_MESH_SUBDIR,
332                                 ((*bat_attr)->attr).name);
333                         goto rem_attr;
334                 }
335         }
336
337         return 0;
338
339 rem_attr:
340         for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr)
341                 sysfs_remove_file(bat_priv->mesh_obj, &((*bat_attr)->attr));
342
343         kobject_put(bat_priv->mesh_obj);
344         bat_priv->mesh_obj = NULL;
345 out:
346         return -ENOMEM;
347 }
348
349 void sysfs_del_meshif(struct net_device *dev)
350 {
351         struct bat_priv *bat_priv = netdev_priv(dev);
352         struct bat_attribute **bat_attr;
353
354         for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr)
355                 sysfs_remove_file(bat_priv->mesh_obj, &((*bat_attr)->attr));
356
357         kobject_put(bat_priv->mesh_obj);
358         bat_priv->mesh_obj = NULL;
359 }
360
361 static ssize_t show_mesh_iface(struct kobject *kobj, struct attribute *attr,
362                                char *buff)
363 {
364         struct device *dev = to_dev(kobj->parent);
365         struct net_device *net_dev = to_net_dev(dev);
366         struct batman_if *batman_if = get_batman_if_by_netdev(net_dev);
367
368         if (!batman_if)
369                 return 0;
370
371         return sprintf(buff, "%s\n",
372                        batman_if->if_status == IF_NOT_IN_USE ?
373                                                         "none" : "bat0");
374 }
375
376 static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr,
377                                 char *buff, size_t count)
378 {
379         struct device *dev = to_dev(kobj->parent);
380         struct net_device *net_dev = to_net_dev(dev);
381         struct batman_if *batman_if = get_batman_if_by_netdev(net_dev);
382         int status_tmp = -1;
383
384         if (!batman_if)
385                 return count;
386
387         if (strncmp(buff, "none", 4) == 0)
388                 status_tmp = IF_NOT_IN_USE;
389
390         if (strncmp(buff, "bat0", 4) == 0)
391                 status_tmp = IF_I_WANT_YOU;
392
393         if (status_tmp < 0) {
394                 if (buff[count - 1] == '\n')
395                         buff[count - 1] = '\0';
396
397                 pr_err("Invalid parameter for 'mesh_iface' setting received: "
398                        "%s\n", buff);
399                 return -EINVAL;
400         }
401
402         if ((batman_if->if_status == status_tmp) ||
403             ((status_tmp == IF_I_WANT_YOU) &&
404              (batman_if->if_status != IF_NOT_IN_USE)))
405                 return count;
406
407         if (status_tmp == IF_I_WANT_YOU)
408                 status_tmp = hardif_enable_interface(batman_if);
409         else
410                 hardif_disable_interface(batman_if);
411
412         return (status_tmp < 0 ? status_tmp : count);
413 }
414
415 static ssize_t show_iface_status(struct kobject *kobj, struct attribute *attr,
416                                  char *buff)
417 {
418         struct device *dev = to_dev(kobj->parent);
419         struct net_device *net_dev = to_net_dev(dev);
420         struct batman_if *batman_if = get_batman_if_by_netdev(net_dev);
421
422         if (!batman_if)
423                 return 0;
424
425         switch (batman_if->if_status) {
426         case IF_TO_BE_REMOVED:
427                 return sprintf(buff, "disabling\n");
428         case IF_INACTIVE:
429                 return sprintf(buff, "inactive\n");
430         case IF_ACTIVE:
431                 return sprintf(buff, "active\n");
432         case IF_TO_BE_ACTIVATED:
433                 return sprintf(buff, "enabling\n");
434         case IF_NOT_IN_USE:
435         default:
436                 return sprintf(buff, "not in use\n");
437         }
438 }
439
440 static BAT_ATTR(mesh_iface, S_IRUGO | S_IWUSR,
441                 show_mesh_iface, store_mesh_iface);
442 static BAT_ATTR(iface_status, S_IRUGO, show_iface_status, NULL);
443
444 static struct bat_attribute *batman_attrs[] = {
445         &bat_attr_mesh_iface,
446         &bat_attr_iface_status,
447         NULL,
448 };
449
450 int sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev)
451 {
452         struct kobject *hardif_kobject = &dev->dev.kobj;
453         struct bat_attribute **bat_attr;
454         int err;
455
456         *hardif_obj = kobject_create_and_add(SYSFS_IF_BAT_SUBDIR,
457                                                     hardif_kobject);
458
459         if (!*hardif_obj) {
460                 bat_err(dev, "Can't add sysfs directory: %s/%s\n", dev->name,
461                         SYSFS_IF_BAT_SUBDIR);
462                 goto out;
463         }
464
465         for (bat_attr = batman_attrs; *bat_attr; ++bat_attr) {
466                 err = sysfs_create_file(*hardif_obj, &((*bat_attr)->attr));
467                 if (err) {
468                         bat_err(dev, "Can't add sysfs file: %s/%s/%s\n",
469                                 dev->name, SYSFS_IF_BAT_SUBDIR,
470                                 ((*bat_attr)->attr).name);
471                         goto rem_attr;
472                 }
473         }
474
475         return 0;
476
477 rem_attr:
478         for (bat_attr = batman_attrs; *bat_attr; ++bat_attr)
479                 sysfs_remove_file(*hardif_obj, &((*bat_attr)->attr));
480 out:
481         return -ENOMEM;
482 }
483
484 void sysfs_del_hardif(struct kobject **hardif_obj)
485 {
486         kobject_put(*hardif_obj);
487         *hardif_obj = NULL;
488 }