]>
Commit | Line | Data |
---|---|---|
5beef3c9 AL |
1 | /* |
2 | * Copyright (C) 2007-2009 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 "hard-interface.h" | |
5beef3c9 AL |
24 | #include "soft-interface.h" |
25 | #include "send.h" | |
26 | #include "translation-table.h" | |
27 | #include "routing.h" | |
28 | #include "hash.h" | |
29 | #include "compat.h" | |
30 | ||
31 | #define MIN(x, y) ((x) < (y) ? (x) : (y)) | |
32 | ||
33 | static char avail_ifs; | |
34 | static char active_ifs; | |
35 | ||
36 | static void hardif_free_interface(struct rcu_head *rcu); | |
37 | ||
38 | static struct batman_if *get_batman_if_by_name(char *name) | |
39 | { | |
40 | struct batman_if *batman_if; | |
41 | ||
42 | rcu_read_lock(); | |
43 | list_for_each_entry_rcu(batman_if, &if_list, list) { | |
44 | if (strncmp(batman_if->dev, name, IFNAMSIZ) == 0) | |
45 | goto out; | |
46 | } | |
47 | ||
48 | batman_if = NULL; | |
49 | ||
50 | out: | |
51 | rcu_read_unlock(); | |
52 | return batman_if; | |
53 | } | |
54 | ||
55 | int hardif_min_mtu(void) | |
56 | { | |
57 | struct batman_if *batman_if; | |
58 | /* allow big frames if all devices are capable to do so | |
59 | * (have MTU > 1500 + BAT_HEADER_LEN) */ | |
60 | int min_mtu = ETH_DATA_LEN; | |
61 | ||
62 | rcu_read_lock(); | |
63 | list_for_each_entry_rcu(batman_if, &if_list, list) { | |
64 | if ((batman_if->if_active == IF_ACTIVE) || | |
65 | (batman_if->if_active == IF_TO_BE_ACTIVATED)) | |
66 | min_mtu = MIN(batman_if->net_dev->mtu - BAT_HEADER_LEN, | |
67 | min_mtu); | |
68 | } | |
69 | rcu_read_unlock(); | |
70 | ||
71 | return min_mtu; | |
72 | } | |
73 | ||
74 | static void check_known_mac_addr(uint8_t *addr) | |
75 | { | |
76 | struct batman_if *batman_if; | |
77 | char mac_string[ETH_STR_LEN]; | |
78 | ||
79 | rcu_read_lock(); | |
80 | list_for_each_entry_rcu(batman_if, &if_list, list) { | |
81 | if ((batman_if->if_active != IF_ACTIVE) && | |
82 | (batman_if->if_active != IF_TO_BE_ACTIVATED)) | |
83 | continue; | |
84 | ||
85 | if (!compare_orig(batman_if->net_dev->dev_addr, addr)) | |
86 | continue; | |
87 | ||
88 | addr_to_string(mac_string, addr); | |
bad2239e AL |
89 | printk(KERN_WARNING "batman-adv:The newly added mac address (%s) already exists on: %s\n", |
90 | mac_string, batman_if->dev); | |
91 | printk(KERN_WARNING "batman-adv:It is strongly recommended to keep mac addresses unique to avoid problems!\n"); | |
5beef3c9 AL |
92 | } |
93 | rcu_read_unlock(); | |
94 | } | |
95 | ||
96 | /* adjusts the MTU if a new interface with a smaller MTU appeared. */ | |
97 | void update_min_mtu(void) | |
98 | { | |
99 | int min_mtu; | |
100 | ||
101 | min_mtu = hardif_min_mtu(); | |
102 | if (soft_device->mtu != min_mtu) | |
103 | soft_device->mtu = min_mtu; | |
104 | } | |
105 | ||
106 | /* checks if the interface is up. (returns 1 if it is) */ | |
107 | static int hardif_is_interface_up(char *dev) | |
108 | { | |
109 | struct net_device *net_dev; | |
110 | ||
111 | /** | |
112 | * if we already have an interface in our interface list and | |
113 | * the current interface is not the primary interface and | |
114 | * the primary interface is not up and | |
115 | * the primary interface has never been up - don't activate any | |
116 | * secondary interface ! | |
117 | */ | |
118 | ||
119 | rcu_read_lock(); | |
120 | if ((!list_empty(&if_list)) && | |
121 | strncmp(((struct batman_if *)if_list.next)->dev, dev, IFNAMSIZ) && | |
122 | !(((struct batman_if *)if_list.next)->if_active == IF_ACTIVE) && | |
123 | !(((struct batman_if *)if_list.next)->if_active == IF_TO_BE_ACTIVATED) && | |
124 | (!main_if_was_up())) { | |
125 | rcu_read_unlock(); | |
126 | goto end; | |
127 | } | |
128 | rcu_read_unlock(); | |
129 | ||
130 | #ifdef __NET_NET_NAMESPACE_H | |
131 | net_dev = dev_get_by_name(&init_net, dev); | |
132 | #else | |
133 | net_dev = dev_get_by_name(dev); | |
134 | #endif | |
135 | if (!net_dev) | |
136 | goto end; | |
137 | ||
138 | if (!(net_dev->flags & IFF_UP)) | |
139 | goto failure; | |
140 | ||
141 | dev_put(net_dev); | |
142 | return 1; | |
143 | ||
144 | failure: | |
145 | dev_put(net_dev); | |
146 | end: | |
147 | return 0; | |
148 | } | |
149 | ||
150 | /* deactivates the interface. */ | |
151 | void hardif_deactivate_interface(struct batman_if *batman_if) | |
152 | { | |
153 | if (batman_if->if_active != IF_ACTIVE) | |
154 | return; | |
155 | ||
156 | if (batman_if->raw_sock) | |
157 | sock_release(batman_if->raw_sock); | |
158 | ||
159 | /** | |
160 | * batman_if->net_dev has been acquired by dev_get_by_name() in | |
161 | * proc_interfaces_write() and has to be unreferenced. | |
162 | */ | |
163 | ||
164 | if (batman_if->net_dev) | |
165 | dev_put(batman_if->net_dev); | |
166 | ||
167 | batman_if->raw_sock = NULL; | |
168 | batman_if->net_dev = NULL; | |
169 | ||
170 | batman_if->if_active = IF_INACTIVE; | |
171 | active_ifs--; | |
172 | ||
bad2239e AL |
173 | printk(KERN_INFO "batman-adv:Interface deactivated: %s\n", |
174 | batman_if->dev); | |
5beef3c9 AL |
175 | } |
176 | ||
177 | /* (re)activate given interface. */ | |
178 | static void hardif_activate_interface(struct batman_if *batman_if) | |
179 | { | |
180 | struct sockaddr_ll bind_addr; | |
181 | int retval; | |
182 | ||
183 | if (batman_if->if_active != IF_INACTIVE) | |
184 | return; | |
185 | ||
186 | #ifdef __NET_NET_NAMESPACE_H | |
187 | batman_if->net_dev = dev_get_by_name(&init_net, batman_if->dev); | |
188 | #else | |
189 | batman_if->net_dev = dev_get_by_name(batman_if->dev); | |
190 | #endif | |
191 | if (!batman_if->net_dev) | |
192 | goto dev_err; | |
193 | ||
194 | retval = sock_create_kern(PF_PACKET, SOCK_RAW, | |
195 | __constant_htons(ETH_P_BATMAN), | |
196 | &batman_if->raw_sock); | |
197 | ||
198 | if (retval < 0) { | |
bad2239e | 199 | printk(KERN_ERR "batman-adv:Can't create raw socket: %i\n", |
5beef3c9 AL |
200 | retval); |
201 | goto sock_err; | |
202 | } | |
203 | ||
204 | bind_addr.sll_family = AF_PACKET; | |
205 | bind_addr.sll_ifindex = batman_if->net_dev->ifindex; | |
206 | bind_addr.sll_protocol = 0; /* is set by the kernel */ | |
207 | ||
208 | retval = kernel_bind(batman_if->raw_sock, | |
209 | (struct sockaddr *)&bind_addr, sizeof(bind_addr)); | |
210 | ||
211 | if (retval < 0) { | |
bad2239e | 212 | printk(KERN_ERR "batman-adv:Can't create bind raw socket: %i\n", |
5beef3c9 AL |
213 | retval); |
214 | goto bind_err; | |
215 | } | |
216 | ||
217 | check_known_mac_addr(batman_if->net_dev->dev_addr); | |
218 | ||
219 | batman_if->raw_sock->sk->sk_user_data = | |
220 | batman_if->raw_sock->sk->sk_data_ready; | |
221 | batman_if->raw_sock->sk->sk_data_ready = batman_data_ready; | |
222 | ||
223 | addr_to_string(batman_if->addr_str, batman_if->net_dev->dev_addr); | |
224 | ||
225 | memcpy(((struct batman_packet *)(batman_if->packet_buff))->orig, | |
226 | batman_if->net_dev->dev_addr, ETH_ALEN); | |
227 | memcpy(((struct batman_packet *)(batman_if->packet_buff))->prev_sender, | |
228 | batman_if->net_dev->dev_addr, ETH_ALEN); | |
229 | ||
230 | batman_if->if_active = IF_TO_BE_ACTIVATED; | |
231 | active_ifs++; | |
232 | ||
233 | /* save the mac address if it is our primary interface */ | |
234 | if (batman_if->if_num == 0) | |
235 | set_main_if_addr(batman_if->net_dev->dev_addr); | |
236 | ||
bad2239e AL |
237 | printk(KERN_INFO "batman-adv:Interface activated: %s\n", |
238 | batman_if->dev); | |
5beef3c9 AL |
239 | |
240 | return; | |
241 | ||
242 | bind_err: | |
243 | sock_release(batman_if->raw_sock); | |
244 | sock_err: | |
245 | dev_put(batman_if->net_dev); | |
246 | dev_err: | |
247 | batman_if->raw_sock = NULL; | |
248 | batman_if->net_dev = NULL; | |
249 | } | |
250 | ||
251 | static void hardif_free_interface(struct rcu_head *rcu) | |
252 | { | |
253 | struct batman_if *batman_if = container_of(rcu, struct batman_if, rcu); | |
254 | ||
255 | kfree(batman_if->packet_buff); | |
256 | kfree(batman_if->dev); | |
257 | kfree(batman_if); | |
258 | } | |
259 | ||
260 | /** | |
261 | * called by | |
262 | * - echo '' > /proc/.../interfaces | |
263 | * - modprobe -r batman-adv-core | |
264 | */ | |
265 | /* removes and frees all interfaces */ | |
266 | void hardif_remove_interfaces(void) | |
267 | { | |
268 | struct batman_if *batman_if = NULL; | |
269 | ||
270 | avail_ifs = 0; | |
271 | ||
272 | /* no lock needed - we don't delete somewhere else */ | |
273 | list_for_each_entry(batman_if, &if_list, list) { | |
274 | ||
275 | list_del_rcu(&batman_if->list); | |
276 | ||
277 | /* first deactivate interface */ | |
278 | if (batman_if->if_active != IF_INACTIVE) | |
279 | hardif_deactivate_interface(batman_if); | |
280 | ||
281 | call_rcu(&batman_if->rcu, hardif_free_interface); | |
282 | } | |
283 | } | |
284 | ||
285 | static int resize_orig(struct orig_node *orig_node, int if_num) | |
286 | { | |
287 | void *data_ptr; | |
288 | ||
289 | data_ptr = kmalloc((if_num + 1) * sizeof(TYPE_OF_WORD) * NUM_WORDS, | |
290 | GFP_ATOMIC); | |
291 | if (!data_ptr) { | |
bad2239e | 292 | printk(KERN_ERR "batman-adv:Can't resize orig: out of memory\n"); |
5beef3c9 AL |
293 | return -1; |
294 | } | |
295 | ||
296 | memcpy(data_ptr, orig_node->bcast_own, | |
297 | if_num * sizeof(TYPE_OF_WORD) * NUM_WORDS); | |
298 | kfree(orig_node->bcast_own); | |
299 | orig_node->bcast_own = data_ptr; | |
300 | ||
301 | data_ptr = kmalloc((if_num + 1) * sizeof(uint8_t), GFP_ATOMIC); | |
302 | if (!data_ptr) { | |
bad2239e | 303 | printk(KERN_ERR "batman-adv:Can't resize orig: out of memory\n"); |
5beef3c9 AL |
304 | return -1; |
305 | } | |
306 | ||
307 | memcpy(data_ptr, orig_node->bcast_own_sum, if_num * sizeof(uint8_t)); | |
308 | kfree(orig_node->bcast_own_sum); | |
309 | orig_node->bcast_own_sum = data_ptr; | |
310 | ||
311 | return 0; | |
312 | } | |
313 | ||
314 | ||
315 | /* adds an interface the interface list and activate it, if possible */ | |
316 | int hardif_add_interface(char *dev, int if_num) | |
317 | { | |
318 | struct batman_if *batman_if; | |
319 | struct batman_packet *batman_packet; | |
320 | struct orig_node *orig_node; | |
321 | struct hash_it_t *hashit = NULL; | |
322 | ||
323 | batman_if = kmalloc(sizeof(struct batman_if), GFP_KERNEL); | |
324 | ||
325 | if (!batman_if) { | |
bad2239e | 326 | printk(KERN_ERR "batman-adv:Can't add interface (%s): out of memory\n", dev); |
5beef3c9 AL |
327 | return -1; |
328 | } | |
329 | ||
330 | batman_if->raw_sock = NULL; | |
331 | batman_if->net_dev = NULL; | |
332 | ||
333 | if ((if_num == 0) && (num_hna > 0)) | |
334 | batman_if->packet_len = BAT_PACKET_LEN + num_hna * ETH_ALEN; | |
335 | else | |
336 | batman_if->packet_len = BAT_PACKET_LEN; | |
337 | ||
338 | batman_if->packet_buff = kmalloc(batman_if->packet_len, GFP_KERNEL); | |
339 | ||
340 | if (!batman_if->packet_buff) { | |
bad2239e | 341 | printk(KERN_ERR "batman-adv:Can't add interface packet (%s): out of memory\n", dev); |
5beef3c9 AL |
342 | goto out; |
343 | } | |
344 | ||
345 | batman_if->if_num = if_num; | |
346 | batman_if->dev = dev; | |
347 | batman_if->if_active = IF_INACTIVE; | |
348 | INIT_RCU_HEAD(&batman_if->rcu); | |
349 | ||
bad2239e | 350 | printk(KERN_INFO "batman-adv:Adding interface: %s\n", dev); |
5beef3c9 AL |
351 | avail_ifs++; |
352 | ||
353 | INIT_LIST_HEAD(&batman_if->list); | |
354 | ||
355 | batman_packet = (struct batman_packet *)(batman_if->packet_buff); | |
356 | batman_packet->packet_type = BAT_PACKET; | |
357 | batman_packet->version = COMPAT_VERSION; | |
358 | batman_packet->flags = 0x00; | |
359 | batman_packet->ttl = (batman_if->if_num > 0 ? 2 : TTL); | |
360 | batman_packet->flags = 0; | |
361 | batman_packet->tq = TQ_MAX_VALUE; | |
362 | batman_packet->num_hna = 0; | |
363 | ||
364 | if (batman_if->packet_len != BAT_PACKET_LEN) { | |
365 | unsigned char *hna_buff; | |
366 | int hna_len; | |
367 | ||
368 | hna_buff = batman_if->packet_buff + BAT_PACKET_LEN; | |
369 | hna_len = batman_if->packet_len - BAT_PACKET_LEN; | |
370 | batman_packet->num_hna = hna_local_fill_buffer(hna_buff, | |
371 | hna_len); | |
372 | } | |
373 | ||
374 | atomic_set(&batman_if->seqno, 1); | |
375 | ||
376 | /* resize all orig nodes because orig_node->bcast_own(_sum) depend on | |
377 | * if_num */ | |
378 | spin_lock(&orig_hash_lock); | |
379 | ||
380 | while (NULL != (hashit = hash_iterate(orig_hash, hashit))) { | |
381 | orig_node = hashit->bucket->data; | |
382 | if (resize_orig(orig_node, if_num) == -1) { | |
383 | spin_unlock(&orig_hash_lock); | |
384 | goto out; | |
385 | } | |
386 | } | |
387 | ||
388 | spin_unlock(&orig_hash_lock); | |
389 | ||
390 | if (!hardif_is_interface_up(batman_if->dev)) | |
bad2239e | 391 | printk(KERN_ERR "batman-adv:Not using interface %s (retrying later): interface not active\n", batman_if->dev); |
5beef3c9 AL |
392 | else |
393 | hardif_activate_interface(batman_if); | |
394 | ||
395 | list_add_tail_rcu(&batman_if->list, &if_list); | |
396 | ||
397 | /* begin sending originator messages on that interface */ | |
398 | schedule_own_packet(batman_if); | |
399 | return 1; | |
400 | ||
401 | out: | |
acdfd0e0 | 402 | kfree(batman_if->packet_buff); |
5beef3c9 AL |
403 | kfree(batman_if); |
404 | kfree(dev); | |
405 | return -1; | |
406 | } | |
407 | ||
408 | char hardif_get_active_if_num(void) | |
409 | { | |
410 | return active_ifs; | |
411 | } | |
412 | ||
413 | static int hard_if_event(struct notifier_block *this, | |
bad2239e | 414 | unsigned long event, void *ptr) |
5beef3c9 AL |
415 | { |
416 | struct net_device *dev = (struct net_device *)ptr; | |
417 | struct batman_if *batman_if = get_batman_if_by_name(dev->name); | |
418 | ||
419 | if (!batman_if) | |
420 | goto out; | |
421 | ||
422 | switch (event) { | |
423 | case NETDEV_GOING_DOWN: | |
424 | case NETDEV_DOWN: | |
425 | case NETDEV_UNREGISTER: | |
426 | hardif_deactivate_interface(batman_if); | |
427 | break; | |
428 | case NETDEV_UP: | |
429 | hardif_activate_interface(batman_if); | |
430 | if ((atomic_read(&module_state) == MODULE_INACTIVE) && | |
431 | (hardif_get_active_if_num() > 0)) { | |
432 | activate_module(); | |
433 | } | |
434 | break; | |
435 | /* NETDEV_CHANGEADDR - mac address change - what are we doing here ? */ | |
436 | default: | |
5beef3c9 AL |
437 | break; |
438 | }; | |
439 | ||
440 | update_min_mtu(); | |
441 | ||
442 | out: | |
443 | return NOTIFY_DONE; | |
444 | } | |
445 | ||
446 | struct notifier_block hard_if_notifier = { | |
bad2239e | 447 | .notifier_call = hard_if_event, |
5beef3c9 | 448 | }; |