diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
commit | fcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch) | |
tree | a57612d1888735a2ec7972891b68c1ac5ec8faea /net/batman-adv | |
parent | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff) |
Diffstat (limited to 'net/batman-adv')
-rw-r--r-- | net/batman-adv/aggregation.c | 293 | ||||
-rw-r--r-- | net/batman-adv/aggregation.h | 46 | ||||
-rw-r--r-- | net/batman-adv/bat_debugfs.c | 359 | ||||
-rw-r--r-- | net/batman-adv/bat_debugfs.h | 33 | ||||
-rw-r--r-- | net/batman-adv/bat_sysfs.c | 674 | ||||
-rw-r--r-- | net/batman-adv/bat_sysfs.h | 44 |
6 files changed, 1449 insertions, 0 deletions
diff --git a/net/batman-adv/aggregation.c b/net/batman-adv/aggregation.c new file mode 100644 index 00000000000..69467fe71ff --- /dev/null +++ b/net/batman-adv/aggregation.c | |||
@@ -0,0 +1,293 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Marek Lindner, Simon Wunderlich | ||
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 "translation-table.h" | ||
24 | #include "aggregation.h" | ||
25 | #include "send.h" | ||
26 | #include "routing.h" | ||
27 | #include "hard-interface.h" | ||
28 | |||
29 | /* return true if new_packet can be aggregated with forw_packet */ | ||
30 | static bool can_aggregate_with(const struct batman_packet *new_batman_packet, | ||
31 | struct bat_priv *bat_priv, | ||
32 | int packet_len, | ||
33 | unsigned long send_time, | ||
34 | bool directlink, | ||
35 | const struct hard_iface *if_incoming, | ||
36 | const struct forw_packet *forw_packet) | ||
37 | { | ||
38 | struct batman_packet *batman_packet = | ||
39 | (struct batman_packet *)forw_packet->skb->data; | ||
40 | int aggregated_bytes = forw_packet->packet_len + packet_len; | ||
41 | struct hard_iface *primary_if = NULL; | ||
42 | bool res = false; | ||
43 | |||
44 | /** | ||
45 | * we can aggregate the current packet to this aggregated packet | ||
46 | * if: | ||
47 | * | ||
48 | * - the send time is within our MAX_AGGREGATION_MS time | ||
49 | * - the resulting packet wont be bigger than | ||
50 | * MAX_AGGREGATION_BYTES | ||
51 | */ | ||
52 | |||
53 | if (time_before(send_time, forw_packet->send_time) && | ||
54 | time_after_eq(send_time + msecs_to_jiffies(MAX_AGGREGATION_MS), | ||
55 | forw_packet->send_time) && | ||
56 | (aggregated_bytes <= MAX_AGGREGATION_BYTES)) { | ||
57 | |||
58 | /** | ||
59 | * check aggregation compatibility | ||
60 | * -> direct link packets are broadcasted on | ||
61 | * their interface only | ||
62 | * -> aggregate packet if the current packet is | ||
63 | * a "global" packet as well as the base | ||
64 | * packet | ||
65 | */ | ||
66 | |||
67 | primary_if = primary_if_get_selected(bat_priv); | ||
68 | if (!primary_if) | ||
69 | goto out; | ||
70 | |||
71 | /* packets without direct link flag and high TTL | ||
72 | * are flooded through the net */ | ||
73 | if ((!directlink) && | ||
74 | (!(batman_packet->flags & DIRECTLINK)) && | ||
75 | (batman_packet->ttl != 1) && | ||
76 | |||
77 | /* own packets originating non-primary | ||
78 | * interfaces leave only that interface */ | ||
79 | ((!forw_packet->own) || | ||
80 | (forw_packet->if_incoming == primary_if))) { | ||
81 | res = true; | ||
82 | goto out; | ||
83 | } | ||
84 | |||
85 | /* if the incoming packet is sent via this one | ||
86 | * interface only - we still can aggregate */ | ||
87 | if ((directlink) && | ||
88 | (new_batman_packet->ttl == 1) && | ||
89 | (forw_packet->if_incoming == if_incoming) && | ||
90 | |||
91 | /* packets from direct neighbors or | ||
92 | * own secondary interface packets | ||
93 | * (= secondary interface packets in general) */ | ||
94 | (batman_packet->flags & DIRECTLINK || | ||
95 | (forw_packet->own && | ||
96 | forw_packet->if_incoming != primary_if))) { | ||
97 | res = true; | ||
98 | goto out; | ||
99 | } | ||
100 | } | ||
101 | |||
102 | out: | ||
103 | if (primary_if) | ||
104 | hardif_free_ref(primary_if); | ||
105 | return res; | ||
106 | } | ||
107 | |||
108 | /* create a new aggregated packet and add this packet to it */ | ||
109 | static void new_aggregated_packet(const unsigned char *packet_buff, | ||
110 | int packet_len, unsigned long send_time, | ||
111 | bool direct_link, | ||
112 | struct hard_iface *if_incoming, | ||
113 | int own_packet) | ||
114 | { | ||
115 | struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); | ||
116 | struct forw_packet *forw_packet_aggr; | ||
117 | unsigned char *skb_buff; | ||
118 | |||
119 | if (!atomic_inc_not_zero(&if_incoming->refcount)) | ||
120 | return; | ||
121 | |||
122 | /* own packet should always be scheduled */ | ||
123 | if (!own_packet) { | ||
124 | if (!atomic_dec_not_zero(&bat_priv->batman_queue_left)) { | ||
125 | bat_dbg(DBG_BATMAN, bat_priv, | ||
126 | "batman packet queue full\n"); | ||
127 | goto out; | ||
128 | } | ||
129 | } | ||
130 | |||
131 | forw_packet_aggr = kmalloc(sizeof(*forw_packet_aggr), GFP_ATOMIC); | ||
132 | if (!forw_packet_aggr) { | ||
133 | if (!own_packet) | ||
134 | atomic_inc(&bat_priv->batman_queue_left); | ||
135 | goto out; | ||
136 | } | ||
137 | |||
138 | if ((atomic_read(&bat_priv->aggregated_ogms)) && | ||
139 | (packet_len < MAX_AGGREGATION_BYTES)) | ||
140 | forw_packet_aggr->skb = dev_alloc_skb(MAX_AGGREGATION_BYTES + | ||
141 | sizeof(struct ethhdr)); | ||
142 | else | ||
143 | forw_packet_aggr->skb = dev_alloc_skb(packet_len + | ||
144 | sizeof(struct ethhdr)); | ||
145 | |||
146 | if (!forw_packet_aggr->skb) { | ||
147 | if (!own_packet) | ||
148 | atomic_inc(&bat_priv->batman_queue_left); | ||
149 | kfree(forw_packet_aggr); | ||
150 | goto out; | ||
151 | } | ||
152 | skb_reserve(forw_packet_aggr->skb, sizeof(struct ethhdr)); | ||
153 | |||
154 | INIT_HLIST_NODE(&forw_packet_aggr->list); | ||
155 | |||
156 | skb_buff = skb_put(forw_packet_aggr->skb, packet_len); | ||
157 | forw_packet_aggr->packet_len = packet_len; | ||
158 | memcpy(skb_buff, packet_buff, packet_len); | ||
159 | |||
160 | forw_packet_aggr->own = own_packet; | ||
161 | forw_packet_aggr->if_incoming = if_incoming; | ||
162 | forw_packet_aggr->num_packets = 0; | ||
163 | forw_packet_aggr->direct_link_flags = NO_FLAGS; | ||
164 | forw_packet_aggr->send_time = send_time; | ||
165 | |||
166 | /* save packet direct link flag status */ | ||
167 | if (direct_link) | ||
168 | forw_packet_aggr->direct_link_flags |= 1; | ||
169 | |||
170 | /* add new packet to packet list */ | ||
171 | spin_lock_bh(&bat_priv->forw_bat_list_lock); | ||
172 | hlist_add_head(&forw_packet_aggr->list, &bat_priv->forw_bat_list); | ||
173 | spin_unlock_bh(&bat_priv->forw_bat_list_lock); | ||
174 | |||
175 | /* start timer for this packet */ | ||
176 | INIT_DELAYED_WORK(&forw_packet_aggr->delayed_work, | ||
177 | send_outstanding_bat_packet); | ||
178 | queue_delayed_work(bat_event_workqueue, | ||
179 | &forw_packet_aggr->delayed_work, | ||
180 | send_time - jiffies); | ||
181 | |||
182 | return; | ||
183 | out: | ||
184 | hardif_free_ref(if_incoming); | ||
185 | } | ||
186 | |||
187 | /* aggregate a new packet into the existing aggregation */ | ||
188 | static void aggregate(struct forw_packet *forw_packet_aggr, | ||
189 | const unsigned char *packet_buff, int packet_len, | ||
190 | bool direct_link) | ||
191 | { | ||
192 | unsigned char *skb_buff; | ||
193 | |||
194 | skb_buff = skb_put(forw_packet_aggr->skb, packet_len); | ||
195 | memcpy(skb_buff, packet_buff, packet_len); | ||
196 | forw_packet_aggr->packet_len += packet_len; | ||
197 | forw_packet_aggr->num_packets++; | ||
198 | |||
199 | /* save packet direct link flag status */ | ||
200 | if (direct_link) | ||
201 | forw_packet_aggr->direct_link_flags |= | ||
202 | (1 << forw_packet_aggr->num_packets); | ||
203 | } | ||
204 | |||
205 | void add_bat_packet_to_list(struct bat_priv *bat_priv, | ||
206 | unsigned char *packet_buff, int packet_len, | ||
207 | struct hard_iface *if_incoming, int own_packet, | ||
208 | unsigned long send_time) | ||
209 | { | ||
210 | /** | ||
211 | * _aggr -> pointer to the packet we want to aggregate with | ||
212 | * _pos -> pointer to the position in the queue | ||
213 | */ | ||
214 | struct forw_packet *forw_packet_aggr = NULL, *forw_packet_pos = NULL; | ||
215 | struct hlist_node *tmp_node; | ||
216 | struct batman_packet *batman_packet = | ||
217 | (struct batman_packet *)packet_buff; | ||
218 | bool direct_link = batman_packet->flags & DIRECTLINK ? 1 : 0; | ||
219 | |||
220 | /* find position for the packet in the forward queue */ | ||
221 | spin_lock_bh(&bat_priv->forw_bat_list_lock); | ||
222 | /* own packets are not to be aggregated */ | ||
223 | if ((atomic_read(&bat_priv->aggregated_ogms)) && (!own_packet)) { | ||
224 | hlist_for_each_entry(forw_packet_pos, tmp_node, | ||
225 | &bat_priv->forw_bat_list, list) { | ||
226 | if (can_aggregate_with(batman_packet, | ||
227 | bat_priv, | ||
228 | packet_len, | ||
229 | send_time, | ||
230 | direct_link, | ||
231 | if_incoming, | ||
232 | forw_packet_pos)) { | ||
233 | forw_packet_aggr = forw_packet_pos; | ||
234 | break; | ||
235 | } | ||
236 | } | ||
237 | } | ||
238 | |||
239 | /* nothing to aggregate with - either aggregation disabled or no | ||
240 | * suitable aggregation packet found */ | ||
241 | if (!forw_packet_aggr) { | ||
242 | /* the following section can run without the lock */ | ||
243 | spin_unlock_bh(&bat_priv->forw_bat_list_lock); | ||
244 | |||
245 | /** | ||
246 | * if we could not aggregate this packet with one of the others | ||
247 | * we hold it back for a while, so that it might be aggregated | ||
248 | * later on | ||
249 | */ | ||
250 | if ((!own_packet) && | ||
251 | (atomic_read(&bat_priv->aggregated_ogms))) | ||
252 | send_time += msecs_to_jiffies(MAX_AGGREGATION_MS); | ||
253 | |||
254 | new_aggregated_packet(packet_buff, packet_len, | ||
255 | send_time, direct_link, | ||
256 | if_incoming, own_packet); | ||
257 | } else { | ||
258 | aggregate(forw_packet_aggr, | ||
259 | packet_buff, packet_len, | ||
260 | direct_link); | ||
261 | spin_unlock_bh(&bat_priv->forw_bat_list_lock); | ||
262 | } | ||
263 | } | ||
264 | |||
265 | /* unpack the aggregated packets and process them one by one */ | ||
266 | void receive_aggr_bat_packet(const struct ethhdr *ethhdr, | ||
267 | unsigned char *packet_buff, int packet_len, | ||
268 | struct hard_iface *if_incoming) | ||
269 | { | ||
270 | struct batman_packet *batman_packet; | ||
271 | int buff_pos = 0; | ||
272 | unsigned char *tt_buff; | ||
273 | |||
274 | batman_packet = (struct batman_packet *)packet_buff; | ||
275 | |||
276 | do { | ||
277 | /* network to host order for our 32bit seqno and the | ||
278 | orig_interval */ | ||
279 | batman_packet->seqno = ntohl(batman_packet->seqno); | ||
280 | batman_packet->tt_crc = ntohs(batman_packet->tt_crc); | ||
281 | |||
282 | tt_buff = packet_buff + buff_pos + BAT_PACKET_LEN; | ||
283 | |||
284 | receive_bat_packet(ethhdr, batman_packet, tt_buff, if_incoming); | ||
285 | |||
286 | buff_pos += BAT_PACKET_LEN + | ||
287 | tt_len(batman_packet->tt_num_changes); | ||
288 | |||
289 | batman_packet = (struct batman_packet *) | ||
290 | (packet_buff + buff_pos); | ||
291 | } while (aggregated_packet(buff_pos, packet_len, | ||
292 | batman_packet->tt_num_changes)); | ||
293 | } | ||
diff --git a/net/batman-adv/aggregation.h b/net/batman-adv/aggregation.h new file mode 100644 index 00000000000..216337bb841 --- /dev/null +++ b/net/batman-adv/aggregation.h | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Marek Lindner, Simon Wunderlich | ||
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 | #ifndef _NET_BATMAN_ADV_AGGREGATION_H_ | ||
23 | #define _NET_BATMAN_ADV_AGGREGATION_H_ | ||
24 | |||
25 | #include "main.h" | ||
26 | |||
27 | /* is there another aggregated packet here? */ | ||
28 | static inline int aggregated_packet(int buff_pos, int packet_len, | ||
29 | int tt_num_changes) | ||
30 | { | ||
31 | int next_buff_pos = buff_pos + BAT_PACKET_LEN + (tt_num_changes * | ||
32 | sizeof(struct tt_change)); | ||
33 | |||
34 | return (next_buff_pos <= packet_len) && | ||
35 | (next_buff_pos <= MAX_AGGREGATION_BYTES); | ||
36 | } | ||
37 | |||
38 | void add_bat_packet_to_list(struct bat_priv *bat_priv, | ||
39 | unsigned char *packet_buff, int packet_len, | ||
40 | struct hard_iface *if_incoming, int own_packet, | ||
41 | unsigned long send_time); | ||
42 | void receive_aggr_bat_packet(const struct ethhdr *ethhdr, | ||
43 | unsigned char *packet_buff, int packet_len, | ||
44 | struct hard_iface *if_incoming); | ||
45 | |||
46 | #endif /* _NET_BATMAN_ADV_AGGREGATION_H_ */ | ||
diff --git a/net/batman-adv/bat_debugfs.c b/net/batman-adv/bat_debugfs.c new file mode 100644 index 00000000000..d0af9bf69e4 --- /dev/null +++ b/net/batman-adv/bat_debugfs.c | |||
@@ -0,0 +1,359 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010-2011 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 | |||
24 | #include <linux/debugfs.h> | ||
25 | |||
26 | #include "bat_debugfs.h" | ||
27 | #include "translation-table.h" | ||
28 | #include "originator.h" | ||
29 | #include "hard-interface.h" | ||
30 | #include "gateway_common.h" | ||
31 | #include "gateway_client.h" | ||
32 | #include "soft-interface.h" | ||
33 | #include "vis.h" | ||
34 | #include "icmp_socket.h" | ||
35 | |||
36 | static struct dentry *bat_debugfs; | ||
37 | |||
38 | #ifdef CONFIG_BATMAN_ADV_DEBUG | ||
39 | #define LOG_BUFF_MASK (log_buff_len-1) | ||
40 | #define LOG_BUFF(idx) (debug_log->log_buff[(idx) & LOG_BUFF_MASK]) | ||
41 | |||
42 | static int log_buff_len = LOG_BUF_LEN; | ||
43 | |||
44 | static void emit_log_char(struct debug_log *debug_log, char c) | ||
45 | { | ||
46 | LOG_BUFF(debug_log->log_end) = c; | ||
47 | debug_log->log_end++; | ||
48 | |||
49 | if (debug_log->log_end - debug_log->log_start > log_buff_len) | ||
50 | debug_log->log_start = debug_log->log_end - log_buff_len; | ||
51 | } | ||
52 | |||
53 | __printf(2, 3) | ||
54 | static int fdebug_log(struct debug_log *debug_log, const char *fmt, ...) | ||
55 | { | ||
56 | va_list args; | ||
57 | static char debug_log_buf[256]; | ||
58 | char *p; | ||
59 | |||
60 | if (!debug_log) | ||
61 | return 0; | ||
62 | |||
63 | spin_lock_bh(&debug_log->lock); | ||
64 | va_start(args, fmt); | ||
65 | vscnprintf(debug_log_buf, sizeof(debug_log_buf), fmt, args); | ||
66 | va_end(args); | ||
67 | |||
68 | for (p = debug_log_buf; *p != 0; p++) | ||
69 | emit_log_char(debug_log, *p); | ||
70 | |||
71 | spin_unlock_bh(&debug_log->lock); | ||
72 | |||
73 | wake_up(&debug_log->queue_wait); | ||
74 | |||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | int debug_log(struct bat_priv *bat_priv, const char *fmt, ...) | ||
79 | { | ||
80 | va_list args; | ||
81 | char tmp_log_buf[256]; | ||
82 | |||
83 | va_start(args, fmt); | ||
84 | vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args); | ||
85 | fdebug_log(bat_priv->debug_log, "[%10lu] %s", | ||
86 | (jiffies / HZ), tmp_log_buf); | ||
87 | va_end(args); | ||
88 | |||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | static int log_open(struct inode *inode, struct file *file) | ||
93 | { | ||
94 | nonseekable_open(inode, file); | ||
95 | file->private_data = inode->i_private; | ||
96 | inc_module_count(); | ||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | static int log_release(struct inode *inode, struct file *file) | ||
101 | { | ||
102 | dec_module_count(); | ||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | static ssize_t log_read(struct file *file, char __user *buf, | ||
107 | size_t count, loff_t *ppos) | ||
108 | { | ||
109 | struct bat_priv *bat_priv = file->private_data; | ||
110 | struct debug_log *debug_log = bat_priv->debug_log; | ||
111 | int error, i = 0; | ||
112 | char c; | ||
113 | |||
114 | if ((file->f_flags & O_NONBLOCK) && | ||
115 | !(debug_log->log_end - debug_log->log_start)) | ||
116 | return -EAGAIN; | ||
117 | |||
118 | if (!buf) | ||
119 | return -EINVAL; | ||
120 | |||
121 | if (count == 0) | ||
122 | return 0; | ||
123 | |||
124 | if (!access_ok(VERIFY_WRITE, buf, count)) | ||
125 | return -EFAULT; | ||
126 | |||
127 | error = wait_event_interruptible(debug_log->queue_wait, | ||
128 | (debug_log->log_start - debug_log->log_end)); | ||
129 | |||
130 | if (error) | ||
131 | return error; | ||
132 | |||
133 | spin_lock_bh(&debug_log->lock); | ||
134 | |||
135 | while ((!error) && (i < count) && | ||
136 | (debug_log->log_start != debug_log->log_end)) { | ||
137 | c = LOG_BUFF(debug_log->log_start); | ||
138 | |||
139 | debug_log->log_start++; | ||
140 | |||
141 | spin_unlock_bh(&debug_log->lock); | ||
142 | |||
143 | error = __put_user(c, buf); | ||
144 | |||
145 | spin_lock_bh(&debug_log->lock); | ||
146 | |||
147 | buf++; | ||
148 | i++; | ||
149 | |||
150 | } | ||
151 | |||
152 | spin_unlock_bh(&debug_log->lock); | ||
153 | |||
154 | if (!error) | ||
155 | return i; | ||
156 | |||
157 | return error; | ||
158 | } | ||
159 | |||
160 | static unsigned int log_poll(struct file *file, poll_table *wait) | ||
161 | { | ||
162 | struct bat_priv *bat_priv = file->private_data; | ||
163 | struct debug_log *debug_log = bat_priv->debug_log; | ||
164 | |||
165 | poll_wait(file, &debug_log->queue_wait, wait); | ||
166 | |||
167 | if (debug_log->log_end - debug_log->log_start) | ||
168 | return POLLIN | POLLRDNORM; | ||
169 | |||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | static const struct file_operations log_fops = { | ||
174 | .open = log_open, | ||
175 | .release = log_release, | ||
176 | .read = log_read, | ||
177 | .poll = log_poll, | ||
178 | .llseek = no_llseek, | ||
179 | }; | ||
180 | |||
181 | static int debug_log_setup(struct bat_priv *bat_priv) | ||
182 | { | ||
183 | struct dentry *d; | ||
184 | |||
185 | if (!bat_priv->debug_dir) | ||
186 | goto err; | ||
187 | |||
188 | bat_priv->debug_log = kzalloc(sizeof(*bat_priv->debug_log), GFP_ATOMIC); | ||
189 | if (!bat_priv->debug_log) | ||
190 | goto err; | ||
191 | |||
192 | spin_lock_init(&bat_priv->debug_log->lock); | ||
193 | init_waitqueue_head(&bat_priv->debug_log->queue_wait); | ||
194 | |||
195 | d = debugfs_create_file("log", S_IFREG | S_IRUSR, | ||
196 | bat_priv->debug_dir, bat_priv, &log_fops); | ||
197 | if (d) | ||
198 | goto err; | ||
199 | |||
200 | return 0; | ||
201 | |||
202 | err: | ||
203 | return 1; | ||
204 | } | ||
205 | |||
206 | static void debug_log_cleanup(struct bat_priv *bat_priv) | ||
207 | { | ||
208 | kfree(bat_priv->debug_log); | ||
209 | bat_priv->debug_log = NULL; | ||
210 | } | ||
211 | #else /* CONFIG_BATMAN_ADV_DEBUG */ | ||
212 | static int debug_log_setup(struct bat_priv *bat_priv) | ||
213 | { | ||
214 | bat_priv->debug_log = NULL; | ||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | static void debug_log_cleanup(struct bat_priv *bat_priv) | ||
219 | { | ||
220 | return; | ||
221 | } | ||
222 | #endif | ||
223 | |||
224 | static int originators_open(struct inode *inode, struct file *file) | ||
225 | { | ||
226 | struct net_device *net_dev = (struct net_device *)inode->i_private; | ||
227 | return single_open(file, orig_seq_print_text, net_dev); | ||
228 | } | ||
229 | |||
230 | static int gateways_open(struct inode *inode, struct file *file) | ||
231 | { | ||
232 | struct net_device *net_dev = (struct net_device *)inode->i_private; | ||
233 | return single_open(file, gw_client_seq_print_text, net_dev); | ||
234 | } | ||
235 | |||
236 | static int softif_neigh_open(struct inode *inode, struct file *file) | ||
237 | { | ||
238 | struct net_device *net_dev = (struct net_device *)inode->i_private; | ||
239 | return single_open(file, softif_neigh_seq_print_text, net_dev); | ||
240 | } | ||
241 | |||
242 | static int transtable_global_open(struct inode *inode, struct file *file) | ||
243 | { | ||
244 | struct net_device *net_dev = (struct net_device *)inode->i_private; | ||
245 | return single_open(file, tt_global_seq_print_text, net_dev); | ||
246 | } | ||
247 | |||
248 | static int transtable_local_open(struct inode *inode, struct file *file) | ||
249 | { | ||
250 | struct net_device *net_dev = (struct net_device *)inode->i_private; | ||
251 | return single_open(file, tt_local_seq_print_text, net_dev); | ||
252 | } | ||
253 | |||
254 | static int vis_data_open(struct inode *inode, struct file *file) | ||
255 | { | ||
256 | struct net_device *net_dev = (struct net_device *)inode->i_private; | ||
257 | return single_open(file, vis_seq_print_text, net_dev); | ||
258 | } | ||
259 | |||
260 | struct bat_debuginfo { | ||
261 | struct attribute attr; | ||
262 | const struct file_operations fops; | ||
263 | }; | ||
264 | |||
265 | #define BAT_DEBUGINFO(_name, _mode, _open) \ | ||
266 | struct bat_debuginfo bat_debuginfo_##_name = { \ | ||
267 | .attr = { .name = __stringify(_name), \ | ||
268 | .mode = _mode, }, \ | ||
269 | .fops = { .owner = THIS_MODULE, \ | ||
270 | .open = _open, \ | ||
271 | .read = seq_read, \ | ||
272 | .llseek = seq_lseek, \ | ||
273 | .release = single_release, \ | ||
274 | } \ | ||
275 | }; | ||
276 | |||
277 | static BAT_DEBUGINFO(originators, S_IRUGO, originators_open); | ||
278 | static BAT_DEBUGINFO(gateways, S_IRUGO, gateways_open); | ||
279 | static BAT_DEBUGINFO(softif_neigh, S_IRUGO, softif_neigh_open); | ||
280 | static BAT_DEBUGINFO(transtable_global, S_IRUGO, transtable_global_open); | ||
281 | static BAT_DEBUGINFO(transtable_local, S_IRUGO, transtable_local_open); | ||
282 | static BAT_DEBUGINFO(vis_data, S_IRUGO, vis_data_open); | ||
283 | |||
284 | static struct bat_debuginfo *mesh_debuginfos[] = { | ||
285 | &bat_debuginfo_originators, | ||
286 | &bat_debuginfo_gateways, | ||
287 | &bat_debuginfo_softif_neigh, | ||
288 | &bat_debuginfo_transtable_global, | ||
289 | &bat_debuginfo_transtable_local, | ||
290 | &bat_debuginfo_vis_data, | ||
291 | NULL, | ||
292 | }; | ||
293 | |||
294 | void debugfs_init(void) | ||
295 | { | ||
296 | bat_debugfs = debugfs_create_dir(DEBUGFS_BAT_SUBDIR, NULL); | ||
297 | if (bat_debugfs == ERR_PTR(-ENODEV)) | ||
298 | bat_debugfs = NULL; | ||
299 | } | ||
300 | |||
301 | void debugfs_destroy(void) | ||
302 | { | ||
303 | if (bat_debugfs) { | ||
304 | debugfs_remove_recursive(bat_debugfs); | ||
305 | bat_debugfs = NULL; | ||
306 | } | ||
307 | } | ||
308 | |||
309 | int debugfs_add_meshif(struct net_device *dev) | ||
310 | { | ||
311 | struct bat_priv *bat_priv = netdev_priv(dev); | ||
312 | struct bat_debuginfo **bat_debug; | ||
313 | struct dentry *file; | ||
314 | |||
315 | if (!bat_debugfs) | ||
316 | goto out; | ||
317 | |||
318 | bat_priv->debug_dir = debugfs_create_dir(dev->name, bat_debugfs); | ||
319 | if (!bat_priv->debug_dir) | ||
320 | goto out; | ||
321 | |||
322 | bat_socket_setup(bat_priv); | ||
323 | debug_log_setup(bat_priv); | ||
324 | |||
325 | for (bat_debug = mesh_debuginfos; *bat_debug; ++bat_debug) { | ||
326 | file = debugfs_create_file(((*bat_debug)->attr).name, | ||
327 | S_IFREG | ((*bat_debug)->attr).mode, | ||
328 | bat_priv->debug_dir, | ||
329 | dev, &(*bat_debug)->fops); | ||
330 | if (!file) { | ||
331 | bat_err(dev, "Can't add debugfs file: %s/%s\n", | ||
332 | dev->name, ((*bat_debug)->attr).name); | ||
333 | goto rem_attr; | ||
334 | } | ||
335 | } | ||
336 | |||
337 | return 0; | ||
338 | rem_attr: | ||
339 | debugfs_remove_recursive(bat_priv->debug_dir); | ||
340 | bat_priv->debug_dir = NULL; | ||
341 | out: | ||
342 | #ifdef CONFIG_DEBUG_FS | ||
343 | return -ENOMEM; | ||
344 | #else | ||
345 | return 0; | ||
346 | #endif /* CONFIG_DEBUG_FS */ | ||
347 | } | ||
348 | |||
349 | void debugfs_del_meshif(struct net_device *dev) | ||
350 | { | ||
351 | struct bat_priv *bat_priv = netdev_priv(dev); | ||
352 | |||
353 | debug_log_cleanup(bat_priv); | ||
354 | |||
355 | if (bat_debugfs) { | ||
356 | debugfs_remove_recursive(bat_priv->debug_dir); | ||
357 | bat_priv->debug_dir = NULL; | ||
358 | } | ||
359 | } | ||
diff --git a/net/batman-adv/bat_debugfs.h b/net/batman-adv/bat_debugfs.h new file mode 100644 index 00000000000..bc9cda3f01e --- /dev/null +++ b/net/batman-adv/bat_debugfs.h | |||
@@ -0,0 +1,33 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010-2011 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 | |||
23 | #ifndef _NET_BATMAN_ADV_DEBUGFS_H_ | ||
24 | #define _NET_BATMAN_ADV_DEBUGFS_H_ | ||
25 | |||
26 | #define DEBUGFS_BAT_SUBDIR "batman_adv" | ||
27 | |||
28 | void debugfs_init(void); | ||
29 | void debugfs_destroy(void); | ||
30 | int debugfs_add_meshif(struct net_device *dev); | ||
31 | void debugfs_del_meshif(struct net_device *dev); | ||
32 | |||
33 | #endif /* _NET_BATMAN_ADV_DEBUGFS_H_ */ | ||
diff --git a/net/batman-adv/bat_sysfs.c b/net/batman-adv/bat_sysfs.c new file mode 100644 index 00000000000..cd15deba60a --- /dev/null +++ b/net/batman-adv/bat_sysfs.c | |||
@@ -0,0 +1,674 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010-2011 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 "gateway_common.h" | ||
28 | #include "gateway_client.h" | ||
29 | #include "vis.h" | ||
30 | |||
31 | static 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 | |||
37 | static 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 | } | ||
42 | |||
43 | #define UEV_TYPE_VAR "BATTYPE=" | ||
44 | #define UEV_ACTION_VAR "BATACTION=" | ||
45 | #define UEV_DATA_VAR "BATDATA=" | ||
46 | |||
47 | static char *uev_action_str[] = { | ||
48 | "add", | ||
49 | "del", | ||
50 | "change" | ||
51 | }; | ||
52 | |||
53 | static char *uev_type_str[] = { | ||
54 | "gw" | ||
55 | }; | ||
56 | |||
57 | /* Use this, if you have customized show and store functions */ | ||
58 | #define BAT_ATTR(_name, _mode, _show, _store) \ | ||
59 | struct bat_attribute bat_attr_##_name = { \ | ||
60 | .attr = {.name = __stringify(_name), \ | ||
61 | .mode = _mode }, \ | ||
62 | .show = _show, \ | ||
63 | .store = _store, \ | ||
64 | }; | ||
65 | |||
66 | #define BAT_ATTR_STORE_BOOL(_name, _post_func) \ | ||
67 | ssize_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 | |||
76 | #define BAT_ATTR_SHOW_BOOL(_name) \ | ||
77 | ssize_t show_##_name(struct kobject *kobj, struct attribute *attr, \ | ||
78 | char *buff) \ | ||
79 | { \ | ||
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 | |||
86 | /* Use this, if you are going to turn a [name] in bat_priv on or off */ | ||
87 | #define BAT_ATTR_BOOL(_name, _mode, _post_func) \ | ||
88 | static BAT_ATTR_STORE_BOOL(_name, _post_func) \ | ||
89 | static BAT_ATTR_SHOW_BOOL(_name) \ | ||
90 | static BAT_ATTR(_name, _mode, show_##_name, store_##_name) | ||
91 | |||
92 | |||
93 | #define BAT_ATTR_STORE_UINT(_name, _min, _max, _post_func) \ | ||
94 | ssize_t store_##_name(struct kobject *kobj, struct attribute *attr, \ | ||
95 | char *buff, size_t count) \ | ||
96 | { \ | ||
97 | struct net_device *net_dev = kobj_to_netdev(kobj); \ | ||
98 | struct bat_priv *bat_priv = netdev_priv(net_dev); \ | ||
99 | return __store_uint_attr(buff, count, _min, _max, _post_func, \ | ||
100 | attr, &bat_priv->_name, net_dev); \ | ||
101 | } | ||
102 | |||
103 | #define BAT_ATTR_SHOW_UINT(_name) \ | ||
104 | ssize_t show_##_name(struct kobject *kobj, struct attribute *attr, \ | ||
105 | char *buff) \ | ||
106 | { \ | ||
107 | struct bat_priv *bat_priv = kobj_to_batpriv(kobj); \ | ||
108 | return sprintf(buff, "%i\n", atomic_read(&bat_priv->_name)); \ | ||
109 | } \ | ||
110 | |||
111 | /* Use this, if you are going to set [name] in bat_priv to unsigned integer | ||
112 | * values only */ | ||
113 | #define BAT_ATTR_UINT(_name, _mode, _min, _max, _post_func) \ | ||
114 | static BAT_ATTR_STORE_UINT(_name, _min, _max, _post_func) \ | ||
115 | static BAT_ATTR_SHOW_UINT(_name) \ | ||
116 | static BAT_ATTR(_name, _mode, show_##_name, store_##_name) | ||
117 | |||
118 | |||
119 | static int store_bool_attr(char *buff, size_t count, | ||
120 | struct net_device *net_dev, | ||
121 | const char *attr_name, atomic_t *attr) | ||
122 | { | ||
123 | int enabled = -1; | ||
124 | |||
125 | if (buff[count - 1] == '\n') | ||
126 | buff[count - 1] = '\0'; | ||
127 | |||
128 | if ((strncmp(buff, "1", 2) == 0) || | ||
129 | (strncmp(buff, "enable", 7) == 0) || | ||
130 | (strncmp(buff, "enabled", 8) == 0)) | ||
131 | enabled = 1; | ||
132 | |||
133 | if ((strncmp(buff, "0", 2) == 0) || | ||
134 | (strncmp(buff, "disable", 8) == 0) || | ||
135 | (strncmp(buff, "disabled", 9) == 0)) | ||
136 | enabled = 0; | ||
137 | |||
138 | if (enabled < 0) { | ||
139 | bat_info(net_dev, | ||
140 | "%s: Invalid parameter received: %s\n", | ||
141 | attr_name, buff); | ||
142 | return -EINVAL; | ||
143 | } | ||
144 | |||
145 | if (atomic_read(attr) == enabled) | ||
146 | return count; | ||
147 | |||
148 | bat_info(net_dev, "%s: Changing from: %s to: %s\n", attr_name, | ||
149 | atomic_read(attr) == 1 ? "enabled" : "disabled", | ||
150 | enabled == 1 ? "enabled" : "disabled"); | ||
151 | |||
152 | atomic_set(attr, (unsigned)enabled); | ||
153 | return count; | ||
154 | } | ||
155 | |||
156 | static inline ssize_t __store_bool_attr(char *buff, size_t count, | ||
157 | void (*post_func)(struct net_device *), | ||
158 | struct attribute *attr, | ||
159 | atomic_t *attr_store, struct net_device *net_dev) | ||
160 | { | ||
161 | int ret; | ||
162 | |||
163 | ret = store_bool_attr(buff, count, net_dev, attr->name, attr_store); | ||
164 | if (post_func && ret) | ||
165 | post_func(net_dev); | ||
166 | |||
167 | return ret; | ||
168 | } | ||
169 | |||
170 | static int store_uint_attr(const char *buff, size_t count, | ||
171 | struct net_device *net_dev, const char *attr_name, | ||
172 | unsigned int min, unsigned int max, atomic_t *attr) | ||
173 | { | ||
174 | unsigned long uint_val; | ||
175 | int ret; | ||
176 | |||
177 | ret = strict_strtoul(buff, 10, &uint_val); | ||
178 | if (ret) { | ||
179 | bat_info(net_dev, | ||
180 | "%s: Invalid parameter received: %s\n", | ||
181 | attr_name, buff); | ||
182 | return -EINVAL; | ||
183 | } | ||
184 | |||
185 | if (uint_val < min) { | ||
186 | bat_info(net_dev, "%s: Value is too small: %lu min: %u\n", | ||
187 | attr_name, uint_val, min); | ||
188 | return -EINVAL; | ||
189 | } | ||
190 | |||
191 | if (uint_val > max) { | ||
192 | bat_info(net_dev, "%s: Value is too big: %lu max: %u\n", | ||
193 | attr_name, uint_val, max); | ||
194 | return -EINVAL; | ||
195 | } | ||
196 | |||
197 | if (atomic_read(attr) == uint_val) | ||
198 | return count; | ||
199 | |||
200 | bat_info(net_dev, "%s: Changing from: %i to: %lu\n", | ||
201 | attr_name, atomic_read(attr), uint_val); | ||
202 | |||
203 | atomic_set(attr, uint_val); | ||
204 | return count; | ||
205 | } | ||
206 | |||
207 | static inline ssize_t __store_uint_attr(const char *buff, size_t count, | ||
208 | int min, int max, | ||
209 | void (*post_func)(struct net_device *), | ||
210 | const struct attribute *attr, | ||
211 | atomic_t *attr_store, struct net_device *net_dev) | ||
212 | { | ||
213 | int ret; | ||
214 | |||
215 | ret = store_uint_attr(buff, count, net_dev, attr->name, | ||
216 | min, max, attr_store); | ||
217 | if (post_func && ret) | ||
218 | post_func(net_dev); | ||
219 | |||
220 | return ret; | ||
221 | } | ||
222 | |||
223 | static ssize_t show_vis_mode(struct kobject *kobj, struct attribute *attr, | ||
224 | char *buff) | ||
225 | { | ||
226 | struct bat_priv *bat_priv = kobj_to_batpriv(kobj); | ||
227 | int vis_mode = atomic_read(&bat_priv->vis_mode); | ||
228 | |||
229 | return sprintf(buff, "%s\n", | ||
230 | vis_mode == VIS_TYPE_CLIENT_UPDATE ? | ||
231 | "client" : "server"); | ||
232 | } | ||
233 | |||
234 | static ssize_t store_vis_mode(struct kobject *kobj, struct attribute *attr, | ||
235 | char *buff, size_t count) | ||
236 | { | ||
237 | struct net_device *net_dev = kobj_to_netdev(kobj); | ||
238 | struct bat_priv *bat_priv = netdev_priv(net_dev); | ||
239 | unsigned long val; | ||
240 | int ret, vis_mode_tmp = -1; | ||
241 | |||
242 | ret = strict_strtoul(buff, 10, &val); | ||
243 | |||
244 | if (((count == 2) && (!ret) && (val == VIS_TYPE_CLIENT_UPDATE)) || | ||
245 | (strncmp(buff, "client", 6) == 0) || | ||
246 | (strncmp(buff, "off", 3) == 0)) | ||
247 | vis_mode_tmp = VIS_TYPE_CLIENT_UPDATE; | ||
248 | |||
249 | if (((count == 2) && (!ret) && (val == VIS_TYPE_SERVER_SYNC)) || | ||
250 | (strncmp(buff, "server", 6) == 0)) | ||
251 | vis_mode_tmp = VIS_TYPE_SERVER_SYNC; | ||
252 | |||
253 | if (vis_mode_tmp < 0) { | ||
254 | if (buff[count - 1] == '\n') | ||
255 | buff[count - 1] = '\0'; | ||
256 | |||
257 | bat_info(net_dev, | ||
258 | "Invalid parameter for 'vis mode' setting received: " | ||
259 | "%s\n", buff); | ||
260 | return -EINVAL; | ||
261 | } | ||
262 | |||
263 | if (atomic_read(&bat_priv->vis_mode) == vis_mode_tmp) | ||
264 | return count; | ||
265 | |||
266 | bat_info(net_dev, "Changing vis mode from: %s to: %s\n", | ||
267 | atomic_read(&bat_priv->vis_mode) == VIS_TYPE_CLIENT_UPDATE ? | ||
268 | "client" : "server", vis_mode_tmp == VIS_TYPE_CLIENT_UPDATE ? | ||
269 | "client" : "server"); | ||
270 | |||
271 | atomic_set(&bat_priv->vis_mode, (unsigned)vis_mode_tmp); | ||
272 | return count; | ||
273 | } | ||
274 | |||
275 | static void post_gw_deselect(struct net_device *net_dev) | ||
276 | { | ||
277 | struct bat_priv *bat_priv = netdev_priv(net_dev); | ||
278 | gw_deselect(bat_priv); | ||
279 | } | ||
280 | |||
281 | static ssize_t show_gw_mode(struct kobject *kobj, struct attribute *attr, | ||
282 | char *buff) | ||
283 | { | ||
284 | struct bat_priv *bat_priv = kobj_to_batpriv(kobj); | ||
285 | int bytes_written; | ||
286 | |||
287 | switch (atomic_read(&bat_priv->gw_mode)) { | ||
288 | case GW_MODE_CLIENT: | ||
289 | bytes_written = sprintf(buff, "%s\n", GW_MODE_CLIENT_NAME); | ||
290 | break; | ||
291 | case GW_MODE_SERVER: | ||
292 | bytes_written = sprintf(buff, "%s\n", GW_MODE_SERVER_NAME); | ||
293 | break; | ||
294 | default: | ||
295 | bytes_written = sprintf(buff, "%s\n", GW_MODE_OFF_NAME); | ||
296 | break; | ||
297 | } | ||
298 | |||
299 | return bytes_written; | ||
300 | } | ||
301 | |||
302 | static ssize_t store_gw_mode(struct kobject *kobj, struct attribute *attr, | ||
303 | char *buff, size_t count) | ||
304 | { | ||
305 | struct net_device *net_dev = kobj_to_netdev(kobj); | ||
306 | struct bat_priv *bat_priv = netdev_priv(net_dev); | ||
307 | char *curr_gw_mode_str; | ||
308 | int gw_mode_tmp = -1; | ||
309 | |||
310 | if (buff[count - 1] == '\n') | ||
311 | buff[count - 1] = '\0'; | ||
312 | |||
313 | if (strncmp(buff, GW_MODE_OFF_NAME, strlen(GW_MODE_OFF_NAME)) == 0) | ||
314 | gw_mode_tmp = GW_MODE_OFF; | ||
315 | |||
316 | if (strncmp(buff, GW_MODE_CLIENT_NAME, | ||
317 | strlen(GW_MODE_CLIENT_NAME)) == 0) | ||
318 | gw_mode_tmp = GW_MODE_CLIENT; | ||
319 | |||
320 | if (strncmp(buff, GW_MODE_SERVER_NAME, | ||
321 | strlen(GW_MODE_SERVER_NAME)) == 0) | ||
322 | gw_mode_tmp = GW_MODE_SERVER; | ||
323 | |||
324 | if (gw_mode_tmp < 0) { | ||
325 | bat_info(net_dev, | ||
326 | "Invalid parameter for 'gw mode' setting received: " | ||
327 | "%s\n", buff); | ||
328 | return -EINVAL; | ||
329 | } | ||
330 | |||
331 | if (atomic_read(&bat_priv->gw_mode) == gw_mode_tmp) | ||
332 | return count; | ||
333 | |||
334 | switch (atomic_read(&bat_priv->gw_mode)) { | ||
335 | case GW_MODE_CLIENT: | ||
336 | curr_gw_mode_str = GW_MODE_CLIENT_NAME; | ||
337 | break; | ||
338 | case GW_MODE_SERVER: | ||
339 | curr_gw_mode_str = GW_MODE_SERVER_NAME; | ||
340 | break; | ||
341 | default: | ||
342 | curr_gw_mode_str = GW_MODE_OFF_NAME; | ||
343 | break; | ||
344 | } | ||
345 | |||
346 | bat_info(net_dev, "Changing gw mode from: %s to: %s\n", | ||
347 | curr_gw_mode_str, buff); | ||
348 | |||
349 | gw_deselect(bat_priv); | ||
350 | atomic_set(&bat_priv->gw_mode, (unsigned)gw_mode_tmp); | ||
351 | return count; | ||
352 | } | ||
353 | |||
354 | static ssize_t show_gw_bwidth(struct kobject *kobj, struct attribute *attr, | ||
355 | char *buff) | ||
356 | { | ||
357 | struct bat_priv *bat_priv = kobj_to_batpriv(kobj); | ||
358 | int down, up; | ||
359 | int gw_bandwidth = atomic_read(&bat_priv->gw_bandwidth); | ||
360 | |||
361 | gw_bandwidth_to_kbit(gw_bandwidth, &down, &up); | ||
362 | return sprintf(buff, "%i%s/%i%s\n", | ||
363 | (down > 2048 ? down / 1024 : down), | ||
364 | (down > 2048 ? "MBit" : "KBit"), | ||
365 | (up > 2048 ? up / 1024 : up), | ||
366 | (up > 2048 ? "MBit" : "KBit")); | ||
367 | } | ||
368 | |||
369 | static ssize_t store_gw_bwidth(struct kobject *kobj, struct attribute *attr, | ||
370 | char *buff, size_t count) | ||
371 | { | ||
372 | struct net_device *net_dev = kobj_to_netdev(kobj); | ||
373 | |||
374 | if (buff[count - 1] == '\n') | ||
375 | buff[count - 1] = '\0'; | ||
376 | |||
377 | return gw_bandwidth_set(net_dev, buff, count); | ||
378 | } | ||
379 | |||
380 | BAT_ATTR_BOOL(aggregated_ogms, S_IRUGO | S_IWUSR, NULL); | ||
381 | BAT_ATTR_BOOL(bonding, S_IRUGO | S_IWUSR, NULL); | ||
382 | BAT_ATTR_BOOL(fragmentation, S_IRUGO | S_IWUSR, update_min_mtu); | ||
383 | static BAT_ATTR(vis_mode, S_IRUGO | S_IWUSR, show_vis_mode, store_vis_mode); | ||
384 | static BAT_ATTR(gw_mode, S_IRUGO | S_IWUSR, show_gw_mode, store_gw_mode); | ||
385 | BAT_ATTR_UINT(orig_interval, S_IRUGO | S_IWUSR, 2 * JITTER, INT_MAX, NULL); | ||
386 | BAT_ATTR_UINT(hop_penalty, S_IRUGO | S_IWUSR, 0, TQ_MAX_VALUE, NULL); | ||
387 | BAT_ATTR_UINT(gw_sel_class, S_IRUGO | S_IWUSR, 1, TQ_MAX_VALUE, | ||
388 | post_gw_deselect); | ||
389 | static BAT_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, show_gw_bwidth, | ||
390 | store_gw_bwidth); | ||
391 | #ifdef CONFIG_BATMAN_ADV_DEBUG | ||
392 | BAT_ATTR_UINT(log_level, S_IRUGO | S_IWUSR, 0, 7, NULL); | ||
393 | #endif | ||
394 | |||
395 | static struct bat_attribute *mesh_attrs[] = { | ||
396 | &bat_attr_aggregated_ogms, | ||
397 | &bat_attr_bonding, | ||
398 | &bat_attr_fragmentation, | ||
399 | &bat_attr_vis_mode, | ||
400 | &bat_attr_gw_mode, | ||
401 | &bat_attr_orig_interval, | ||
402 | &bat_attr_hop_penalty, | ||
403 | &bat_attr_gw_sel_class, | ||
404 | &bat_attr_gw_bandwidth, | ||
405 | #ifdef CONFIG_BATMAN_ADV_DEBUG | ||
406 | &bat_attr_log_level, | ||
407 | #endif | ||
408 | NULL, | ||
409 | }; | ||
410 | |||
411 | int sysfs_add_meshif(struct net_device *dev) | ||
412 | { | ||
413 | struct kobject *batif_kobject = &dev->dev.kobj; | ||
414 | struct bat_priv *bat_priv = netdev_priv(dev); | ||
415 | struct bat_attribute **bat_attr; | ||
416 | int err; | ||
417 | |||
418 | bat_priv->mesh_obj = kobject_create_and_add(SYSFS_IF_MESH_SUBDIR, | ||
419 | batif_kobject); | ||
420 | if (!bat_priv->mesh_obj) { | ||
421 | bat_err(dev, "Can't add sysfs directory: %s/%s\n", dev->name, | ||
422 | SYSFS_IF_MESH_SUBDIR); | ||
423 | goto out; | ||
424 | } | ||
425 | |||
426 | for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr) { | ||
427 | err = sysfs_create_file(bat_priv->mesh_obj, | ||
428 | &((*bat_attr)->attr)); | ||
429 | if (err) { | ||
430 | bat_err(dev, "Can't add sysfs file: %s/%s/%s\n", | ||
431 | dev->name, SYSFS_IF_MESH_SUBDIR, | ||
432 | ((*bat_attr)->attr).name); | ||
433 | goto rem_attr; | ||
434 | } | ||
435 | } | ||
436 | |||
437 | return 0; | ||
438 | |||
439 | rem_attr: | ||
440 | for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr) | ||
441 | sysfs_remove_file(bat_priv->mesh_obj, &((*bat_attr)->attr)); | ||
442 | |||
443 | kobject_put(bat_priv->mesh_obj); | ||
444 | bat_priv->mesh_obj = NULL; | ||
445 | out: | ||
446 | return -ENOMEM; | ||
447 | } | ||
448 | |||
449 | void sysfs_del_meshif(struct net_device *dev) | ||
450 | { | ||
451 | struct bat_priv *bat_priv = netdev_priv(dev); | ||
452 | struct bat_attribute **bat_attr; | ||
453 | |||
454 | for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr) | ||
455 | sysfs_remove_file(bat_priv->mesh_obj, &((*bat_attr)->attr)); | ||
456 | |||
457 | kobject_put(bat_priv->mesh_obj); | ||
458 | bat_priv->mesh_obj = NULL; | ||
459 | } | ||
460 | |||
461 | static ssize_t show_mesh_iface(struct kobject *kobj, struct attribute *attr, | ||
462 | char *buff) | ||
463 | { | ||
464 | struct net_device *net_dev = kobj_to_netdev(kobj); | ||
465 | struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev); | ||
466 | ssize_t length; | ||
467 | |||
468 | if (!hard_iface) | ||
469 | return 0; | ||
470 | |||
471 | length = sprintf(buff, "%s\n", hard_iface->if_status == IF_NOT_IN_USE ? | ||
472 | "none" : hard_iface->soft_iface->name); | ||
473 | |||
474 | hardif_free_ref(hard_iface); | ||
475 | |||
476 | return length; | ||
477 | } | ||
478 | |||
479 | static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr, | ||
480 | char *buff, size_t count) | ||
481 | { | ||
482 | struct net_device *net_dev = kobj_to_netdev(kobj); | ||
483 | struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev); | ||
484 | int status_tmp = -1; | ||
485 | int ret = count; | ||
486 | |||
487 | if (!hard_iface) | ||
488 | return count; | ||
489 | |||
490 | if (buff[count - 1] == '\n') | ||
491 | buff[count - 1] = '\0'; | ||
492 | |||
493 | if (strlen(buff) >= IFNAMSIZ) { | ||
494 | pr_err("Invalid parameter for 'mesh_iface' setting received: " | ||
495 | "interface name too long '%s'\n", buff); | ||
496 | hardif_free_ref(hard_iface); | ||
497 | return -EINVAL; | ||
498 | } | ||
499 | |||
500 | if (strncmp(buff, "none", 4) == 0) | ||
501 | status_tmp = IF_NOT_IN_USE; | ||
502 | else | ||
503 | status_tmp = IF_I_WANT_YOU; | ||
504 | |||
505 | if (hard_iface->if_status == status_tmp) | ||
506 | goto out; | ||
507 | |||
508 | if ((hard_iface->soft_iface) && | ||
509 | (strncmp(hard_iface->soft_iface->name, buff, IFNAMSIZ) == 0)) | ||
510 | goto out; | ||
511 | |||
512 | if (!rtnl_trylock()) { | ||
513 | ret = -ERESTARTSYS; | ||
514 | goto out; | ||
515 | } | ||
516 | |||
517 | if (status_tmp == IF_NOT_IN_USE) { | ||
518 | hardif_disable_interface(hard_iface); | ||
519 | goto unlock; | ||
520 | } | ||
521 | |||
522 | /* if the interface already is in use */ | ||
523 | if (hard_iface->if_status != IF_NOT_IN_USE) | ||
524 | hardif_disable_interface(hard_iface); | ||
525 | |||
526 | ret = hardif_enable_interface(hard_iface, buff); | ||
527 | |||
528 | unlock: | ||
529 | rtnl_unlock(); | ||
530 | out: | ||
531 | hardif_free_ref(hard_iface); | ||
532 | return ret; | ||
533 | } | ||
534 | |||
535 | static ssize_t show_iface_status(struct kobject *kobj, struct attribute *attr, | ||
536 | char *buff) | ||
537 | { | ||
538 | struct net_device *net_dev = kobj_to_netdev(kobj); | ||
539 | struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev); | ||
540 | ssize_t length; | ||
541 | |||
542 | if (!hard_iface) | ||
543 | return 0; | ||
544 | |||
545 | switch (hard_iface->if_status) { | ||
546 | case IF_TO_BE_REMOVED: | ||
547 | length = sprintf(buff, "disabling\n"); | ||
548 | break; | ||
549 | case IF_INACTIVE: | ||
550 | length = sprintf(buff, "inactive\n"); | ||
551 | break; | ||
552 | case IF_ACTIVE: | ||
553 | length = sprintf(buff, "active\n"); | ||
554 | break; | ||
555 | case IF_TO_BE_ACTIVATED: | ||
556 | length = sprintf(buff, "enabling\n"); | ||
557 | break; | ||
558 | case IF_NOT_IN_USE: | ||
559 | default: | ||
560 | length = sprintf(buff, "not in use\n"); | ||
561 | break; | ||
562 | } | ||
563 | |||
564 | hardif_free_ref(hard_iface); | ||
565 | |||
566 | return length; | ||
567 | } | ||
568 | |||
569 | static BAT_ATTR(mesh_iface, S_IRUGO | S_IWUSR, | ||
570 | show_mesh_iface, store_mesh_iface); | ||
571 | static BAT_ATTR(iface_status, S_IRUGO, show_iface_status, NULL); | ||
572 | |||
573 | static struct bat_attribute *batman_attrs[] = { | ||
574 | &bat_attr_mesh_iface, | ||
575 | &bat_attr_iface_status, | ||
576 | NULL, | ||
577 | }; | ||
578 | |||
579 | int sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev) | ||
580 | { | ||
581 | struct kobject *hardif_kobject = &dev->dev.kobj; | ||
582 | struct bat_attribute **bat_attr; | ||
583 | int err; | ||
584 | |||
585 | *hardif_obj = kobject_create_and_add(SYSFS_IF_BAT_SUBDIR, | ||
586 | hardif_kobject); | ||
587 | |||
588 | if (!*hardif_obj) { | ||
589 | bat_err(dev, "Can't add sysfs directory: %s/%s\n", dev->name, | ||
590 | SYSFS_IF_BAT_SUBDIR); | ||
591 | goto out; | ||
592 | } | ||
593 | |||
594 | for (bat_attr = batman_attrs; *bat_attr; ++bat_attr) { | ||
595 | err = sysfs_create_file(*hardif_obj, &((*bat_attr)->attr)); | ||
596 | if (err) { | ||
597 | bat_err(dev, "Can't add sysfs file: %s/%s/%s\n", | ||
598 | dev->name, SYSFS_IF_BAT_SUBDIR, | ||
599 | ((*bat_attr)->attr).name); | ||
600 | goto rem_attr; | ||
601 | } | ||
602 | } | ||
603 | |||
604 | return 0; | ||
605 | |||
606 | rem_attr: | ||
607 | for (bat_attr = batman_attrs; *bat_attr; ++bat_attr) | ||
608 | sysfs_remove_file(*hardif_obj, &((*bat_attr)->attr)); | ||
609 | out: | ||
610 | return -ENOMEM; | ||
611 | } | ||
612 | |||
613 | void sysfs_del_hardif(struct kobject **hardif_obj) | ||
614 | { | ||
615 | kobject_put(*hardif_obj); | ||
616 | *hardif_obj = NULL; | ||
617 | } | ||
618 | |||
619 | int throw_uevent(struct bat_priv *bat_priv, enum uev_type type, | ||
620 | enum uev_action action, const char *data) | ||
621 | { | ||
622 | int ret = -1; | ||
623 | struct hard_iface *primary_if = NULL; | ||
624 | struct kobject *bat_kobj; | ||
625 | char *uevent_env[4] = { NULL, NULL, NULL, NULL }; | ||
626 | |||
627 | primary_if = primary_if_get_selected(bat_priv); | ||
628 | if (!primary_if) | ||
629 | goto out; | ||
630 | |||
631 | bat_kobj = &primary_if->soft_iface->dev.kobj; | ||
632 | |||
633 | uevent_env[0] = kmalloc(strlen(UEV_TYPE_VAR) + | ||
634 | strlen(uev_type_str[type]) + 1, | ||
635 | GFP_ATOMIC); | ||
636 | if (!uevent_env[0]) | ||
637 | goto out; | ||
638 | |||
639 | sprintf(uevent_env[0], "%s%s", UEV_TYPE_VAR, uev_type_str[type]); | ||
640 | |||
641 | uevent_env[1] = kmalloc(strlen(UEV_ACTION_VAR) + | ||
642 | strlen(uev_action_str[action]) + 1, | ||
643 | GFP_ATOMIC); | ||
644 | if (!uevent_env[1]) | ||
645 | goto out; | ||
646 | |||
647 | sprintf(uevent_env[1], "%s%s", UEV_ACTION_VAR, uev_action_str[action]); | ||
648 | |||
649 | /* If the event is DEL, ignore the data field */ | ||
650 | if (action != UEV_DEL) { | ||
651 | uevent_env[2] = kmalloc(strlen(UEV_DATA_VAR) + | ||
652 | strlen(data) + 1, GFP_ATOMIC); | ||
653 | if (!uevent_env[2]) | ||
654 | goto out; | ||
655 | |||
656 | sprintf(uevent_env[2], "%s%s", UEV_DATA_VAR, data); | ||
657 | } | ||
658 | |||
659 | ret = kobject_uevent_env(bat_kobj, KOBJ_CHANGE, uevent_env); | ||
660 | out: | ||
661 | kfree(uevent_env[0]); | ||
662 | kfree(uevent_env[1]); | ||
663 | kfree(uevent_env[2]); | ||
664 | |||
665 | if (primary_if) | ||
666 | hardif_free_ref(primary_if); | ||
667 | |||
668 | if (ret) | ||
669 | bat_dbg(DBG_BATMAN, bat_priv, "Impossible to send " | ||
670 | "uevent for (%s,%s,%s) event (err: %d)\n", | ||
671 | uev_type_str[type], uev_action_str[action], | ||
672 | (action == UEV_DEL ? "NULL" : data), ret); | ||
673 | return ret; | ||
674 | } | ||
diff --git a/net/batman-adv/bat_sysfs.h b/net/batman-adv/bat_sysfs.h new file mode 100644 index 00000000000..a3f75a723c5 --- /dev/null +++ b/net/batman-adv/bat_sysfs.h | |||
@@ -0,0 +1,44 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010-2011 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 | |||
23 | #ifndef _NET_BATMAN_ADV_SYSFS_H_ | ||
24 | #define _NET_BATMAN_ADV_SYSFS_H_ | ||
25 | |||
26 | #define SYSFS_IF_MESH_SUBDIR "mesh" | ||
27 | #define SYSFS_IF_BAT_SUBDIR "batman_adv" | ||
28 | |||
29 | struct bat_attribute { | ||
30 | struct attribute attr; | ||
31 | ssize_t (*show)(struct kobject *kobj, struct attribute *attr, | ||
32 | char *buf); | ||
33 | ssize_t (*store)(struct kobject *kobj, struct attribute *attr, | ||
34 | char *buf, size_t count); | ||
35 | }; | ||
36 | |||
37 | int sysfs_add_meshif(struct net_device *dev); | ||
38 | void sysfs_del_meshif(struct net_device *dev); | ||
39 | int sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev); | ||
40 | void sysfs_del_hardif(struct kobject **hardif_obj); | ||
41 | int throw_uevent(struct bat_priv *bat_priv, enum uev_type type, | ||
42 | enum uev_action action, const char *data); | ||
43 | |||
44 | #endif /* _NET_BATMAN_ADV_SYSFS_H_ */ | ||