blob: 5a7b042873e12df585b2468ec12c700dc4c56f29 [file] [log] [blame]
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001/*
Sven Eckelmann567db7b2012-01-01 00:41:38 +01002 * Copyright (C) 2010-2012 B.A.T.M.A.N. contributors:
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00003 *
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 "gateway_common.h"
28#include "gateway_client.h"
29#include "vis.h"
30
Sven Eckelmann3d222bb2011-06-05 10:20:19 +020031static struct net_device *kobj_to_netdev(struct kobject *obj)
32{
33 struct device *dev = container_of(obj->parent, struct device, kobj);
34 return to_net_dev(dev);
35}
36
37static struct bat_priv *kobj_to_batpriv(struct kobject *obj)
38{
39 struct net_device *net_dev = kobj_to_netdev(obj);
40 return netdev_priv(net_dev);
41}
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000042
Antonio Quartullic6bda682011-04-26 18:26:01 +020043#define UEV_TYPE_VAR "BATTYPE="
44#define UEV_ACTION_VAR "BATACTION="
45#define UEV_DATA_VAR "BATDATA="
46
47static char *uev_action_str[] = {
48 "add",
49 "del",
50 "change"
51};
52
53static char *uev_type_str[] = {
54 "gw"
55};
56
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000057/* Use this, if you have customized show and store functions */
58#define BAT_ATTR(_name, _mode, _show, _store) \
59struct bat_attribute bat_attr_##_name = { \
60 .attr = {.name = __stringify(_name), \
61 .mode = _mode }, \
62 .show = _show, \
63 .store = _store, \
64};
65
Marek Lindnerf245c382012-03-11 06:17:51 +080066#define BAT_ATTR_SIF_STORE_BOOL(_name, _post_func) \
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000067ssize_t store_##_name(struct kobject *kobj, struct attribute *attr, \
68 char *buff, size_t count) \
69{ \
70 struct net_device *net_dev = kobj_to_netdev(kobj); \
71 struct bat_priv *bat_priv = netdev_priv(net_dev); \
72 return __store_bool_attr(buff, count, _post_func, attr, \
73 &bat_priv->_name, net_dev); \
74}
75
Marek Lindnerf245c382012-03-11 06:17:51 +080076#define BAT_ATTR_SIF_SHOW_BOOL(_name) \
77ssize_t show_##_name(struct kobject *kobj, \
78 struct attribute *attr, char *buff) \
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000079{ \
80 struct bat_priv *bat_priv = kobj_to_batpriv(kobj); \
81 return sprintf(buff, "%s\n", \
82 atomic_read(&bat_priv->_name) == 0 ? \
83 "disabled" : "enabled"); \
84} \
85
Marek Lindnerf245c382012-03-11 06:17:51 +080086/* Use this, if you are going to turn a [name] in the soft-interface
87 * (bat_priv) on or off */
88#define BAT_ATTR_SIF_BOOL(_name, _mode, _post_func) \
89 static BAT_ATTR_SIF_STORE_BOOL(_name, _post_func) \
90 static BAT_ATTR_SIF_SHOW_BOOL(_name) \
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000091 static BAT_ATTR(_name, _mode, show_##_name, store_##_name)
92
93
Marek Lindnerf245c382012-03-11 06:17:51 +080094#define BAT_ATTR_SIF_STORE_UINT(_name, _min, _max, _post_func) \
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000095ssize_t store_##_name(struct kobject *kobj, struct attribute *attr, \
Marek Lindnerf245c382012-03-11 06:17:51 +080096 char *buff, size_t count) \
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000097{ \
98 struct net_device *net_dev = kobj_to_netdev(kobj); \
99 struct bat_priv *bat_priv = netdev_priv(net_dev); \
100 return __store_uint_attr(buff, count, _min, _max, _post_func, \
101 attr, &bat_priv->_name, net_dev); \
102}
103
Marek Lindnerf245c382012-03-11 06:17:51 +0800104#define BAT_ATTR_SIF_SHOW_UINT(_name) \
105ssize_t show_##_name(struct kobject *kobj, \
106 struct attribute *attr, char *buff) \
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000107{ \
108 struct bat_priv *bat_priv = kobj_to_batpriv(kobj); \
109 return sprintf(buff, "%i\n", atomic_read(&bat_priv->_name)); \
110} \
111
Marek Lindnerf245c382012-03-11 06:17:51 +0800112/* Use this, if you are going to set [name] in the soft-interface
113 * (bat_priv) to an unsigned integer value */
114#define BAT_ATTR_SIF_UINT(_name, _mode, _min, _max, _post_func) \
115 static BAT_ATTR_SIF_STORE_UINT(_name, _min, _max, _post_func) \
116 static BAT_ATTR_SIF_SHOW_UINT(_name) \
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000117 static BAT_ATTR(_name, _mode, show_##_name, store_##_name)
118
119
Linus Luessing9d853f62012-03-11 06:17:52 +0800120#define BAT_ATTR_HIF_STORE_UINT(_name, _min, _max, _post_func) \
121ssize_t store_##_name(struct kobject *kobj, struct attribute *attr, \
122 char *buff, size_t count) \
123{ \
124 struct net_device *net_dev = kobj_to_netdev(kobj); \
Sven Eckelmann95638772012-05-12 02:09:31 +0200125 struct hard_iface *hard_iface; \
Linus Luessing9d853f62012-03-11 06:17:52 +0800126 ssize_t length; \
127 \
Sven Eckelmann95638772012-05-12 02:09:31 +0200128 hard_iface = batadv_hardif_get_by_netdev(net_dev); \
Linus Luessing9d853f62012-03-11 06:17:52 +0800129 if (!hard_iface) \
130 return 0; \
131 \
132 length = __store_uint_attr(buff, count, _min, _max, _post_func, \
133 attr, &hard_iface->_name, net_dev); \
134 \
135 hardif_free_ref(hard_iface); \
136 return length; \
137}
138
139#define BAT_ATTR_HIF_SHOW_UINT(_name) \
140ssize_t show_##_name(struct kobject *kobj, \
141 struct attribute *attr, char *buff) \
142{ \
143 struct net_device *net_dev = kobj_to_netdev(kobj); \
Sven Eckelmann95638772012-05-12 02:09:31 +0200144 struct hard_iface *hard_iface; \
Linus Luessing9d853f62012-03-11 06:17:52 +0800145 ssize_t length; \
146 \
Sven Eckelmann95638772012-05-12 02:09:31 +0200147 hard_iface = batadv_hardif_get_by_netdev(net_dev); \
Linus Luessing9d853f62012-03-11 06:17:52 +0800148 if (!hard_iface) \
149 return 0; \
150 \
151 length = sprintf(buff, "%i\n", atomic_read(&hard_iface->_name));\
152 \
153 hardif_free_ref(hard_iface); \
154 return length; \
155}
156
157/* Use this, if you are going to set [name] in hard_iface to an
158 * unsigned integer value*/
159#define BAT_ATTR_HIF_UINT(_name, _mode, _min, _max, _post_func) \
160 static BAT_ATTR_HIF_STORE_UINT(_name, _min, _max, _post_func) \
161 static BAT_ATTR_HIF_SHOW_UINT(_name) \
162 static BAT_ATTR(_name, _mode, show_##_name, store_##_name)
163
164
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000165static int store_bool_attr(char *buff, size_t count,
166 struct net_device *net_dev,
Sven Eckelmann747e4222011-05-14 23:14:50 +0200167 const char *attr_name, atomic_t *attr)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000168{
169 int enabled = -1;
170
171 if (buff[count - 1] == '\n')
172 buff[count - 1] = '\0';
173
174 if ((strncmp(buff, "1", 2) == 0) ||
175 (strncmp(buff, "enable", 7) == 0) ||
176 (strncmp(buff, "enabled", 8) == 0))
177 enabled = 1;
178
179 if ((strncmp(buff, "0", 2) == 0) ||
180 (strncmp(buff, "disable", 8) == 0) ||
181 (strncmp(buff, "disabled", 9) == 0))
182 enabled = 0;
183
184 if (enabled < 0) {
185 bat_info(net_dev,
186 "%s: Invalid parameter received: %s\n",
187 attr_name, buff);
188 return -EINVAL;
189 }
190
191 if (atomic_read(attr) == enabled)
192 return count;
193
194 bat_info(net_dev, "%s: Changing from: %s to: %s\n", attr_name,
195 atomic_read(attr) == 1 ? "enabled" : "disabled",
196 enabled == 1 ? "enabled" : "disabled");
197
Eric Dumazet95c96172012-04-15 05:58:06 +0000198 atomic_set(attr, (unsigned int)enabled);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000199 return count;
200}
201
202static inline ssize_t __store_bool_attr(char *buff, size_t count,
203 void (*post_func)(struct net_device *),
204 struct attribute *attr,
205 atomic_t *attr_store, struct net_device *net_dev)
206{
207 int ret;
208
Sven Eckelmann747e4222011-05-14 23:14:50 +0200209 ret = store_bool_attr(buff, count, net_dev, attr->name, attr_store);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000210 if (post_func && ret)
211 post_func(net_dev);
212
213 return ret;
214}
215
Sven Eckelmann747e4222011-05-14 23:14:50 +0200216static int store_uint_attr(const char *buff, size_t count,
217 struct net_device *net_dev, const char *attr_name,
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000218 unsigned int min, unsigned int max, atomic_t *attr)
219{
220 unsigned long uint_val;
221 int ret;
222
Sven Eckelmann25a92b12011-09-30 13:32:01 +0200223 ret = kstrtoul(buff, 10, &uint_val);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000224 if (ret) {
225 bat_info(net_dev,
226 "%s: Invalid parameter received: %s\n",
227 attr_name, buff);
228 return -EINVAL;
229 }
230
231 if (uint_val < min) {
232 bat_info(net_dev, "%s: Value is too small: %lu min: %u\n",
233 attr_name, uint_val, min);
234 return -EINVAL;
235 }
236
237 if (uint_val > max) {
238 bat_info(net_dev, "%s: Value is too big: %lu max: %u\n",
239 attr_name, uint_val, max);
240 return -EINVAL;
241 }
242
243 if (atomic_read(attr) == uint_val)
244 return count;
245
246 bat_info(net_dev, "%s: Changing from: %i to: %lu\n",
247 attr_name, atomic_read(attr), uint_val);
248
249 atomic_set(attr, uint_val);
250 return count;
251}
252
Sven Eckelmann747e4222011-05-14 23:14:50 +0200253static inline ssize_t __store_uint_attr(const char *buff, size_t count,
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000254 int min, int max,
255 void (*post_func)(struct net_device *),
Sven Eckelmann747e4222011-05-14 23:14:50 +0200256 const struct attribute *attr,
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000257 atomic_t *attr_store, struct net_device *net_dev)
258{
259 int ret;
260
Sven Eckelmann747e4222011-05-14 23:14:50 +0200261 ret = store_uint_attr(buff, count, net_dev, attr->name,
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000262 min, max, attr_store);
263 if (post_func && ret)
264 post_func(net_dev);
265
266 return ret;
267}
268
269static ssize_t show_vis_mode(struct kobject *kobj, struct attribute *attr,
270 char *buff)
271{
272 struct bat_priv *bat_priv = kobj_to_batpriv(kobj);
273 int vis_mode = atomic_read(&bat_priv->vis_mode);
274
275 return sprintf(buff, "%s\n",
276 vis_mode == VIS_TYPE_CLIENT_UPDATE ?
277 "client" : "server");
278}
279
280static ssize_t store_vis_mode(struct kobject *kobj, struct attribute *attr,
281 char *buff, size_t count)
282{
283 struct net_device *net_dev = kobj_to_netdev(kobj);
284 struct bat_priv *bat_priv = netdev_priv(net_dev);
285 unsigned long val;
286 int ret, vis_mode_tmp = -1;
287
Sven Eckelmann25a92b12011-09-30 13:32:01 +0200288 ret = kstrtoul(buff, 10, &val);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000289
290 if (((count == 2) && (!ret) && (val == VIS_TYPE_CLIENT_UPDATE)) ||
291 (strncmp(buff, "client", 6) == 0) ||
292 (strncmp(buff, "off", 3) == 0))
293 vis_mode_tmp = VIS_TYPE_CLIENT_UPDATE;
294
295 if (((count == 2) && (!ret) && (val == VIS_TYPE_SERVER_SYNC)) ||
296 (strncmp(buff, "server", 6) == 0))
297 vis_mode_tmp = VIS_TYPE_SERVER_SYNC;
298
299 if (vis_mode_tmp < 0) {
300 if (buff[count - 1] == '\n')
301 buff[count - 1] = '\0';
302
303 bat_info(net_dev,
Sven Eckelmann86ceb362012-03-07 09:07:45 +0100304 "Invalid parameter for 'vis mode' setting received: %s\n",
305 buff);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000306 return -EINVAL;
307 }
308
309 if (atomic_read(&bat_priv->vis_mode) == vis_mode_tmp)
310 return count;
311
312 bat_info(net_dev, "Changing vis mode from: %s to: %s\n",
313 atomic_read(&bat_priv->vis_mode) == VIS_TYPE_CLIENT_UPDATE ?
314 "client" : "server", vis_mode_tmp == VIS_TYPE_CLIENT_UPDATE ?
315 "client" : "server");
316
Eric Dumazet95c96172012-04-15 05:58:06 +0000317 atomic_set(&bat_priv->vis_mode, (unsigned int)vis_mode_tmp);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000318 return count;
319}
320
Marek Lindnerea3d2fd2011-11-29 00:15:37 +0800321static ssize_t show_bat_algo(struct kobject *kobj, struct attribute *attr,
322 char *buff)
323{
324 struct bat_priv *bat_priv = kobj_to_batpriv(kobj);
325 return sprintf(buff, "%s\n", bat_priv->bat_algo_ops->name);
326}
327
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000328static void post_gw_deselect(struct net_device *net_dev)
329{
330 struct bat_priv *bat_priv = netdev_priv(net_dev);
Sven Eckelmann7cf06bc2012-05-12 02:09:29 +0200331 batadv_gw_deselect(bat_priv);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000332}
333
334static ssize_t show_gw_mode(struct kobject *kobj, struct attribute *attr,
335 char *buff)
336{
337 struct bat_priv *bat_priv = kobj_to_batpriv(kobj);
338 int bytes_written;
339
340 switch (atomic_read(&bat_priv->gw_mode)) {
341 case GW_MODE_CLIENT:
342 bytes_written = sprintf(buff, "%s\n", GW_MODE_CLIENT_NAME);
343 break;
344 case GW_MODE_SERVER:
345 bytes_written = sprintf(buff, "%s\n", GW_MODE_SERVER_NAME);
346 break;
347 default:
348 bytes_written = sprintf(buff, "%s\n", GW_MODE_OFF_NAME);
349 break;
350 }
351
352 return bytes_written;
353}
354
355static ssize_t store_gw_mode(struct kobject *kobj, struct attribute *attr,
356 char *buff, size_t count)
357{
358 struct net_device *net_dev = kobj_to_netdev(kobj);
359 struct bat_priv *bat_priv = netdev_priv(net_dev);
360 char *curr_gw_mode_str;
361 int gw_mode_tmp = -1;
362
363 if (buff[count - 1] == '\n')
364 buff[count - 1] = '\0';
365
366 if (strncmp(buff, GW_MODE_OFF_NAME, strlen(GW_MODE_OFF_NAME)) == 0)
367 gw_mode_tmp = GW_MODE_OFF;
368
369 if (strncmp(buff, GW_MODE_CLIENT_NAME,
Sven Eckelmann7c64fd92012-02-28 10:55:36 +0100370 strlen(GW_MODE_CLIENT_NAME)) == 0)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000371 gw_mode_tmp = GW_MODE_CLIENT;
372
373 if (strncmp(buff, GW_MODE_SERVER_NAME,
Sven Eckelmann7c64fd92012-02-28 10:55:36 +0100374 strlen(GW_MODE_SERVER_NAME)) == 0)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000375 gw_mode_tmp = GW_MODE_SERVER;
376
377 if (gw_mode_tmp < 0) {
378 bat_info(net_dev,
Sven Eckelmann86ceb362012-03-07 09:07:45 +0100379 "Invalid parameter for 'gw mode' setting received: %s\n",
380 buff);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000381 return -EINVAL;
382 }
383
384 if (atomic_read(&bat_priv->gw_mode) == gw_mode_tmp)
385 return count;
386
387 switch (atomic_read(&bat_priv->gw_mode)) {
388 case GW_MODE_CLIENT:
389 curr_gw_mode_str = GW_MODE_CLIENT_NAME;
390 break;
391 case GW_MODE_SERVER:
392 curr_gw_mode_str = GW_MODE_SERVER_NAME;
393 break;
394 default:
395 curr_gw_mode_str = GW_MODE_OFF_NAME;
396 break;
397 }
398
399 bat_info(net_dev, "Changing gw mode from: %s to: %s\n",
400 curr_gw_mode_str, buff);
401
Sven Eckelmann7cf06bc2012-05-12 02:09:29 +0200402 batadv_gw_deselect(bat_priv);
Eric Dumazet95c96172012-04-15 05:58:06 +0000403 atomic_set(&bat_priv->gw_mode, (unsigned int)gw_mode_tmp);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000404 return count;
405}
406
407static ssize_t show_gw_bwidth(struct kobject *kobj, struct attribute *attr,
408 char *buff)
409{
410 struct bat_priv *bat_priv = kobj_to_batpriv(kobj);
411 int down, up;
412 int gw_bandwidth = atomic_read(&bat_priv->gw_bandwidth);
413
Sven Eckelmann84d5e5e2012-05-12 02:09:30 +0200414 batadv_gw_bandwidth_to_kbit(gw_bandwidth, &down, &up);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000415 return sprintf(buff, "%i%s/%i%s\n",
416 (down > 2048 ? down / 1024 : down),
417 (down > 2048 ? "MBit" : "KBit"),
418 (up > 2048 ? up / 1024 : up),
419 (up > 2048 ? "MBit" : "KBit"));
420}
421
422static ssize_t store_gw_bwidth(struct kobject *kobj, struct attribute *attr,
423 char *buff, size_t count)
424{
425 struct net_device *net_dev = kobj_to_netdev(kobj);
426
427 if (buff[count - 1] == '\n')
428 buff[count - 1] = '\0';
429
Sven Eckelmann84d5e5e2012-05-12 02:09:30 +0200430 return batadv_gw_bandwidth_set(net_dev, buff, count);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000431}
432
Marek Lindnerf245c382012-03-11 06:17:51 +0800433BAT_ATTR_SIF_BOOL(aggregated_ogms, S_IRUGO | S_IWUSR, NULL);
434BAT_ATTR_SIF_BOOL(bonding, S_IRUGO | S_IWUSR, NULL);
Simon Wunderlich7a5cc242012-01-22 20:00:27 +0100435#ifdef CONFIG_BATMAN_ADV_BLA
Marek Lindnerf245c382012-03-11 06:17:51 +0800436BAT_ATTR_SIF_BOOL(bridge_loop_avoidance, S_IRUGO | S_IWUSR, NULL);
Simon Wunderlich7a5cc242012-01-22 20:00:27 +0100437#endif
Sven Eckelmann95638772012-05-12 02:09:31 +0200438BAT_ATTR_SIF_BOOL(fragmentation, S_IRUGO | S_IWUSR, batadv_update_min_mtu);
Marek Lindnerf245c382012-03-11 06:17:51 +0800439BAT_ATTR_SIF_BOOL(ap_isolation, S_IRUGO | S_IWUSR, NULL);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000440static BAT_ATTR(vis_mode, S_IRUGO | S_IWUSR, show_vis_mode, store_vis_mode);
Marek Lindnerea3d2fd2011-11-29 00:15:37 +0800441static BAT_ATTR(routing_algo, S_IRUGO, show_bat_algo, NULL);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000442static BAT_ATTR(gw_mode, S_IRUGO | S_IWUSR, show_gw_mode, store_gw_mode);
Marek Lindnerf245c382012-03-11 06:17:51 +0800443BAT_ATTR_SIF_UINT(orig_interval, S_IRUGO | S_IWUSR, 2 * JITTER, INT_MAX, NULL);
444BAT_ATTR_SIF_UINT(hop_penalty, S_IRUGO | S_IWUSR, 0, TQ_MAX_VALUE, NULL);
445BAT_ATTR_SIF_UINT(gw_sel_class, S_IRUGO | S_IWUSR, 1, TQ_MAX_VALUE,
446 post_gw_deselect);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000447static BAT_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, show_gw_bwidth,
448 store_gw_bwidth);
449#ifdef CONFIG_BATMAN_ADV_DEBUG
Antonio Quartullief3a4092012-05-09 09:50:45 +0200450BAT_ATTR_SIF_UINT(log_level, S_IRUGO | S_IWUSR, 0, DBG_ALL, NULL);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000451#endif
452
453static struct bat_attribute *mesh_attrs[] = {
454 &bat_attr_aggregated_ogms,
455 &bat_attr_bonding,
Simon Wunderlich7a5cc242012-01-22 20:00:27 +0100456#ifdef CONFIG_BATMAN_ADV_BLA
Simon Wunderlichc8673052012-01-22 20:00:20 +0100457 &bat_attr_bridge_loop_avoidance,
Simon Wunderlich7a5cc242012-01-22 20:00:27 +0100458#endif
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000459 &bat_attr_fragmentation,
Antonio Quartulli59b699c2011-07-07 15:35:36 +0200460 &bat_attr_ap_isolation,
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000461 &bat_attr_vis_mode,
Marek Lindnerea3d2fd2011-11-29 00:15:37 +0800462 &bat_attr_routing_algo,
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000463 &bat_attr_gw_mode,
464 &bat_attr_orig_interval,
465 &bat_attr_hop_penalty,
466 &bat_attr_gw_sel_class,
467 &bat_attr_gw_bandwidth,
468#ifdef CONFIG_BATMAN_ADV_DEBUG
469 &bat_attr_log_level,
470#endif
471 NULL,
472};
473
Sven Eckelmann5853e222012-05-12 02:09:24 +0200474int batadv_sysfs_add_meshif(struct net_device *dev)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000475{
476 struct kobject *batif_kobject = &dev->dev.kobj;
477 struct bat_priv *bat_priv = netdev_priv(dev);
478 struct bat_attribute **bat_attr;
479 int err;
480
481 bat_priv->mesh_obj = kobject_create_and_add(SYSFS_IF_MESH_SUBDIR,
482 batif_kobject);
483 if (!bat_priv->mesh_obj) {
484 bat_err(dev, "Can't add sysfs directory: %s/%s\n", dev->name,
485 SYSFS_IF_MESH_SUBDIR);
486 goto out;
487 }
488
489 for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr) {
490 err = sysfs_create_file(bat_priv->mesh_obj,
491 &((*bat_attr)->attr));
492 if (err) {
493 bat_err(dev, "Can't add sysfs file: %s/%s/%s\n",
494 dev->name, SYSFS_IF_MESH_SUBDIR,
495 ((*bat_attr)->attr).name);
496 goto rem_attr;
497 }
498 }
499
500 return 0;
501
502rem_attr:
503 for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr)
504 sysfs_remove_file(bat_priv->mesh_obj, &((*bat_attr)->attr));
505
506 kobject_put(bat_priv->mesh_obj);
507 bat_priv->mesh_obj = NULL;
508out:
509 return -ENOMEM;
510}
511
Sven Eckelmann5853e222012-05-12 02:09:24 +0200512void batadv_sysfs_del_meshif(struct net_device *dev)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000513{
514 struct bat_priv *bat_priv = netdev_priv(dev);
515 struct bat_attribute **bat_attr;
516
517 for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr)
518 sysfs_remove_file(bat_priv->mesh_obj, &((*bat_attr)->attr));
519
520 kobject_put(bat_priv->mesh_obj);
521 bat_priv->mesh_obj = NULL;
522}
523
524static ssize_t show_mesh_iface(struct kobject *kobj, struct attribute *attr,
525 char *buff)
526{
527 struct net_device *net_dev = kobj_to_netdev(kobj);
Sven Eckelmann95638772012-05-12 02:09:31 +0200528 struct hard_iface *hard_iface = batadv_hardif_get_by_netdev(net_dev);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000529 ssize_t length;
530
Marek Lindnere6c10f42011-02-18 12:33:20 +0000531 if (!hard_iface)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000532 return 0;
533
Marek Lindnere6c10f42011-02-18 12:33:20 +0000534 length = sprintf(buff, "%s\n", hard_iface->if_status == IF_NOT_IN_USE ?
535 "none" : hard_iface->soft_iface->name);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000536
Marek Lindnere6c10f42011-02-18 12:33:20 +0000537 hardif_free_ref(hard_iface);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000538
539 return length;
540}
541
542static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr,
543 char *buff, size_t count)
544{
545 struct net_device *net_dev = kobj_to_netdev(kobj);
Sven Eckelmann95638772012-05-12 02:09:31 +0200546 struct hard_iface *hard_iface = batadv_hardif_get_by_netdev(net_dev);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000547 int status_tmp = -1;
Marek Lindnered75ccb2011-02-10 14:33:51 +0000548 int ret = count;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000549
Marek Lindnere6c10f42011-02-18 12:33:20 +0000550 if (!hard_iface)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000551 return count;
552
553 if (buff[count - 1] == '\n')
554 buff[count - 1] = '\0';
555
556 if (strlen(buff) >= IFNAMSIZ) {
Sven Eckelmann86ceb362012-03-07 09:07:45 +0100557 pr_err("Invalid parameter for 'mesh_iface' setting received: interface name too long '%s'\n",
558 buff);
Marek Lindnere6c10f42011-02-18 12:33:20 +0000559 hardif_free_ref(hard_iface);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000560 return -EINVAL;
561 }
562
563 if (strncmp(buff, "none", 4) == 0)
564 status_tmp = IF_NOT_IN_USE;
565 else
566 status_tmp = IF_I_WANT_YOU;
567
Marek Lindnere6c10f42011-02-18 12:33:20 +0000568 if (hard_iface->if_status == status_tmp)
569 goto out;
570
571 if ((hard_iface->soft_iface) &&
572 (strncmp(hard_iface->soft_iface->name, buff, IFNAMSIZ) == 0))
Marek Lindnered75ccb2011-02-10 14:33:51 +0000573 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000574
Sven Eckelmann3a4375a2011-05-03 13:10:06 +0200575 if (!rtnl_trylock()) {
576 ret = -ERESTARTSYS;
Marek Lindnered75ccb2011-02-10 14:33:51 +0000577 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000578 }
579
Sven Eckelmann3a4375a2011-05-03 13:10:06 +0200580 if (status_tmp == IF_NOT_IN_USE) {
Sven Eckelmann95638772012-05-12 02:09:31 +0200581 batadv_hardif_disable_interface(hard_iface);
Sven Eckelmann3a4375a2011-05-03 13:10:06 +0200582 goto unlock;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000583 }
584
Sven Eckelmann3a4375a2011-05-03 13:10:06 +0200585 /* if the interface already is in use */
586 if (hard_iface->if_status != IF_NOT_IN_USE)
Sven Eckelmann95638772012-05-12 02:09:31 +0200587 batadv_hardif_disable_interface(hard_iface);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000588
Sven Eckelmann95638772012-05-12 02:09:31 +0200589 ret = batadv_hardif_enable_interface(hard_iface, buff);
Sven Eckelmann3a4375a2011-05-03 13:10:06 +0200590
591unlock:
592 rtnl_unlock();
Marek Lindnered75ccb2011-02-10 14:33:51 +0000593out:
Marek Lindnere6c10f42011-02-18 12:33:20 +0000594 hardif_free_ref(hard_iface);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000595 return ret;
596}
597
598static ssize_t show_iface_status(struct kobject *kobj, struct attribute *attr,
599 char *buff)
600{
601 struct net_device *net_dev = kobj_to_netdev(kobj);
Sven Eckelmann95638772012-05-12 02:09:31 +0200602 struct hard_iface *hard_iface = batadv_hardif_get_by_netdev(net_dev);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000603 ssize_t length;
604
Marek Lindnere6c10f42011-02-18 12:33:20 +0000605 if (!hard_iface)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000606 return 0;
607
Marek Lindnere6c10f42011-02-18 12:33:20 +0000608 switch (hard_iface->if_status) {
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000609 case IF_TO_BE_REMOVED:
610 length = sprintf(buff, "disabling\n");
611 break;
612 case IF_INACTIVE:
613 length = sprintf(buff, "inactive\n");
614 break;
615 case IF_ACTIVE:
616 length = sprintf(buff, "active\n");
617 break;
618 case IF_TO_BE_ACTIVATED:
619 length = sprintf(buff, "enabling\n");
620 break;
621 case IF_NOT_IN_USE:
622 default:
623 length = sprintf(buff, "not in use\n");
624 break;
625 }
626
Marek Lindnere6c10f42011-02-18 12:33:20 +0000627 hardif_free_ref(hard_iface);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000628
629 return length;
630}
631
632static BAT_ATTR(mesh_iface, S_IRUGO | S_IWUSR,
633 show_mesh_iface, store_mesh_iface);
634static BAT_ATTR(iface_status, S_IRUGO, show_iface_status, NULL);
635
636static struct bat_attribute *batman_attrs[] = {
637 &bat_attr_mesh_iface,
638 &bat_attr_iface_status,
639 NULL,
640};
641
Sven Eckelmann5853e222012-05-12 02:09:24 +0200642int batadv_sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000643{
644 struct kobject *hardif_kobject = &dev->dev.kobj;
645 struct bat_attribute **bat_attr;
646 int err;
647
648 *hardif_obj = kobject_create_and_add(SYSFS_IF_BAT_SUBDIR,
649 hardif_kobject);
650
651 if (!*hardif_obj) {
652 bat_err(dev, "Can't add sysfs directory: %s/%s\n", dev->name,
653 SYSFS_IF_BAT_SUBDIR);
654 goto out;
655 }
656
657 for (bat_attr = batman_attrs; *bat_attr; ++bat_attr) {
658 err = sysfs_create_file(*hardif_obj, &((*bat_attr)->attr));
659 if (err) {
660 bat_err(dev, "Can't add sysfs file: %s/%s/%s\n",
661 dev->name, SYSFS_IF_BAT_SUBDIR,
662 ((*bat_attr)->attr).name);
663 goto rem_attr;
664 }
665 }
666
667 return 0;
668
669rem_attr:
670 for (bat_attr = batman_attrs; *bat_attr; ++bat_attr)
671 sysfs_remove_file(*hardif_obj, &((*bat_attr)->attr));
672out:
673 return -ENOMEM;
674}
675
Sven Eckelmann5853e222012-05-12 02:09:24 +0200676void batadv_sysfs_del_hardif(struct kobject **hardif_obj)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000677{
678 kobject_put(*hardif_obj);
679 *hardif_obj = NULL;
680}
Antonio Quartullic6bda682011-04-26 18:26:01 +0200681
Sven Eckelmann5853e222012-05-12 02:09:24 +0200682int batadv_throw_uevent(struct bat_priv *bat_priv, enum uev_type type,
683 enum uev_action action, const char *data)
Antonio Quartullic6bda682011-04-26 18:26:01 +0200684{
Sven Eckelmann5346c352012-05-05 13:27:28 +0200685 int ret = -ENOMEM;
Antonio Quartullic6bda682011-04-26 18:26:01 +0200686 struct hard_iface *primary_if = NULL;
687 struct kobject *bat_kobj;
688 char *uevent_env[4] = { NULL, NULL, NULL, NULL };
689
690 primary_if = primary_if_get_selected(bat_priv);
691 if (!primary_if)
692 goto out;
693
694 bat_kobj = &primary_if->soft_iface->dev.kobj;
695
696 uevent_env[0] = kmalloc(strlen(UEV_TYPE_VAR) +
697 strlen(uev_type_str[type]) + 1,
698 GFP_ATOMIC);
699 if (!uevent_env[0])
700 goto out;
701
702 sprintf(uevent_env[0], "%s%s", UEV_TYPE_VAR, uev_type_str[type]);
703
704 uevent_env[1] = kmalloc(strlen(UEV_ACTION_VAR) +
705 strlen(uev_action_str[action]) + 1,
706 GFP_ATOMIC);
707 if (!uevent_env[1])
708 goto out;
709
710 sprintf(uevent_env[1], "%s%s", UEV_ACTION_VAR, uev_action_str[action]);
711
712 /* If the event is DEL, ignore the data field */
713 if (action != UEV_DEL) {
714 uevent_env[2] = kmalloc(strlen(UEV_DATA_VAR) +
715 strlen(data) + 1, GFP_ATOMIC);
716 if (!uevent_env[2])
717 goto out;
718
719 sprintf(uevent_env[2], "%s%s", UEV_DATA_VAR, data);
720 }
721
722 ret = kobject_uevent_env(bat_kobj, KOBJ_CHANGE, uevent_env);
723out:
724 kfree(uevent_env[0]);
725 kfree(uevent_env[1]);
726 kfree(uevent_env[2]);
727
728 if (primary_if)
729 hardif_free_ref(primary_if);
730
731 if (ret)
Sven Eckelmann86ceb362012-03-07 09:07:45 +0100732 bat_dbg(DBG_BATMAN, bat_priv,
733 "Impossible to send uevent for (%s,%s,%s) event (err: %d)\n",
Antonio Quartullic6bda682011-04-26 18:26:01 +0200734 uev_type_str[type], uev_action_str[action],
735 (action == UEV_DEL ? "NULL" : data), ret);
736 return ret;
737}