xref: /openbmc/linux/net/batman-adv/main.c (revision 08157984)
1 /*
2  * Copyright (C) 2007-2012 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 "bat_sysfs.h"
24 #include "bat_debugfs.h"
25 #include "routing.h"
26 #include "send.h"
27 #include "originator.h"
28 #include "soft-interface.h"
29 #include "icmp_socket.h"
30 #include "translation-table.h"
31 #include "hard-interface.h"
32 #include "gateway_client.h"
33 #include "bridge_loop_avoidance.h"
34 #include "vis.h"
35 #include "hash.h"
36 #include "bat_algo.h"
37 
38 
39 /* List manipulations on hardif_list have to be rtnl_lock()'ed,
40  * list traversals just rcu-locked */
41 struct list_head hardif_list;
42 char bat_routing_algo[20] = "BATMAN IV";
43 static struct hlist_head bat_algo_list;
44 
45 unsigned char broadcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
46 
47 struct workqueue_struct *bat_event_workqueue;
48 
49 static int __init batman_init(void)
50 {
51 	INIT_LIST_HEAD(&hardif_list);
52 	INIT_HLIST_HEAD(&bat_algo_list);
53 
54 	bat_iv_init();
55 
56 	/* the name should not be longer than 10 chars - see
57 	 * http://lwn.net/Articles/23634/ */
58 	bat_event_workqueue = create_singlethread_workqueue("bat_events");
59 
60 	if (!bat_event_workqueue)
61 		return -ENOMEM;
62 
63 	bat_socket_init();
64 	debugfs_init();
65 
66 	register_netdevice_notifier(&hard_if_notifier);
67 
68 	pr_info("B.A.T.M.A.N. advanced %s (compatibility version %i) loaded\n",
69 		SOURCE_VERSION, COMPAT_VERSION);
70 
71 	return 0;
72 }
73 
74 static void __exit batman_exit(void)
75 {
76 	debugfs_destroy();
77 	unregister_netdevice_notifier(&hard_if_notifier);
78 	hardif_remove_interfaces();
79 
80 	flush_workqueue(bat_event_workqueue);
81 	destroy_workqueue(bat_event_workqueue);
82 	bat_event_workqueue = NULL;
83 
84 	rcu_barrier();
85 }
86 
87 int mesh_init(struct net_device *soft_iface)
88 {
89 	struct bat_priv *bat_priv = netdev_priv(soft_iface);
90 
91 	spin_lock_init(&bat_priv->forw_bat_list_lock);
92 	spin_lock_init(&bat_priv->forw_bcast_list_lock);
93 	spin_lock_init(&bat_priv->tt_changes_list_lock);
94 	spin_lock_init(&bat_priv->tt_req_list_lock);
95 	spin_lock_init(&bat_priv->tt_roam_list_lock);
96 	spin_lock_init(&bat_priv->tt_buff_lock);
97 	spin_lock_init(&bat_priv->gw_list_lock);
98 	spin_lock_init(&bat_priv->vis_hash_lock);
99 	spin_lock_init(&bat_priv->vis_list_lock);
100 
101 	INIT_HLIST_HEAD(&bat_priv->forw_bat_list);
102 	INIT_HLIST_HEAD(&bat_priv->forw_bcast_list);
103 	INIT_HLIST_HEAD(&bat_priv->gw_list);
104 	INIT_LIST_HEAD(&bat_priv->tt_changes_list);
105 	INIT_LIST_HEAD(&bat_priv->tt_req_list);
106 	INIT_LIST_HEAD(&bat_priv->tt_roam_list);
107 
108 	if (originator_init(bat_priv) < 1)
109 		goto err;
110 
111 	if (tt_init(bat_priv) < 1)
112 		goto err;
113 
114 	tt_local_add(soft_iface, soft_iface->dev_addr, NULL_IFINDEX);
115 
116 	if (vis_init(bat_priv) < 1)
117 		goto err;
118 
119 	if (bla_init(bat_priv) < 1)
120 		goto err;
121 
122 	atomic_set(&bat_priv->gw_reselect, 0);
123 	atomic_set(&bat_priv->mesh_state, MESH_ACTIVE);
124 	goto end;
125 
126 err:
127 	mesh_free(soft_iface);
128 	return -1;
129 
130 end:
131 	return 0;
132 }
133 
134 void mesh_free(struct net_device *soft_iface)
135 {
136 	struct bat_priv *bat_priv = netdev_priv(soft_iface);
137 
138 	atomic_set(&bat_priv->mesh_state, MESH_DEACTIVATING);
139 
140 	purge_outstanding_packets(bat_priv, NULL);
141 
142 	vis_quit(bat_priv);
143 
144 	gw_node_purge(bat_priv);
145 	originator_free(bat_priv);
146 
147 	tt_free(bat_priv);
148 
149 	bla_free(bat_priv);
150 
151 	atomic_set(&bat_priv->mesh_state, MESH_INACTIVE);
152 }
153 
154 void inc_module_count(void)
155 {
156 	try_module_get(THIS_MODULE);
157 }
158 
159 void dec_module_count(void)
160 {
161 	module_put(THIS_MODULE);
162 }
163 
164 int is_my_mac(const uint8_t *addr)
165 {
166 	const struct hard_iface *hard_iface;
167 
168 	rcu_read_lock();
169 	list_for_each_entry_rcu(hard_iface, &hardif_list, list) {
170 		if (hard_iface->if_status != IF_ACTIVE)
171 			continue;
172 
173 		if (compare_eth(hard_iface->net_dev->dev_addr, addr)) {
174 			rcu_read_unlock();
175 			return 1;
176 		}
177 	}
178 	rcu_read_unlock();
179 	return 0;
180 }
181 
182 static struct bat_algo_ops *bat_algo_get(char *name)
183 {
184 	struct bat_algo_ops *bat_algo_ops = NULL, *bat_algo_ops_tmp;
185 	struct hlist_node *node;
186 
187 	hlist_for_each_entry(bat_algo_ops_tmp, node, &bat_algo_list, list) {
188 		if (strcmp(bat_algo_ops_tmp->name, name) != 0)
189 			continue;
190 
191 		bat_algo_ops = bat_algo_ops_tmp;
192 		break;
193 	}
194 
195 	return bat_algo_ops;
196 }
197 
198 int bat_algo_register(struct bat_algo_ops *bat_algo_ops)
199 {
200 	struct bat_algo_ops *bat_algo_ops_tmp;
201 	int ret = -1;
202 
203 	bat_algo_ops_tmp = bat_algo_get(bat_algo_ops->name);
204 	if (bat_algo_ops_tmp) {
205 		pr_info("Trying to register already registered routing algorithm: %s\n",
206 			bat_algo_ops->name);
207 		goto out;
208 	}
209 
210 	/* all algorithms must implement all ops (for now) */
211 	if (!bat_algo_ops->bat_iface_enable ||
212 	    !bat_algo_ops->bat_iface_disable ||
213 	    !bat_algo_ops->bat_primary_iface_set ||
214 	    !bat_algo_ops->bat_ogm_update_mac ||
215 	    !bat_algo_ops->bat_ogm_schedule ||
216 	    !bat_algo_ops->bat_ogm_emit ||
217 	    !bat_algo_ops->bat_ogm_receive) {
218 		pr_info("Routing algo '%s' does not implement required ops\n",
219 			bat_algo_ops->name);
220 		goto out;
221 	}
222 
223 	INIT_HLIST_NODE(&bat_algo_ops->list);
224 	hlist_add_head(&bat_algo_ops->list, &bat_algo_list);
225 	ret = 0;
226 
227 out:
228 	return ret;
229 }
230 
231 int bat_algo_select(struct bat_priv *bat_priv, char *name)
232 {
233 	struct bat_algo_ops *bat_algo_ops;
234 	int ret = -1;
235 
236 	bat_algo_ops = bat_algo_get(name);
237 	if (!bat_algo_ops)
238 		goto out;
239 
240 	bat_priv->bat_algo_ops = bat_algo_ops;
241 	ret = 0;
242 
243 out:
244 	return ret;
245 }
246 
247 int bat_algo_seq_print_text(struct seq_file *seq, void *offset)
248 {
249 	struct bat_algo_ops *bat_algo_ops;
250 	struct hlist_node *node;
251 
252 	seq_printf(seq, "Available routing algorithms:\n");
253 
254 	hlist_for_each_entry(bat_algo_ops, node, &bat_algo_list, list) {
255 		seq_printf(seq, "%s\n", bat_algo_ops->name);
256 	}
257 
258 	return 0;
259 }
260 
261 static int param_set_ra(const char *val, const struct kernel_param *kp)
262 {
263 	struct bat_algo_ops *bat_algo_ops;
264 
265 	bat_algo_ops = bat_algo_get((char *)val);
266 	if (!bat_algo_ops) {
267 		pr_err("Routing algorithm '%s' is not supported\n", val);
268 		return -EINVAL;
269 	}
270 
271 	return param_set_copystring(val, kp);
272 }
273 
274 static const struct kernel_param_ops param_ops_ra = {
275 	.set = param_set_ra,
276 	.get = param_get_string,
277 };
278 
279 static struct kparam_string __param_string_ra = {
280 	.maxlen = sizeof(bat_routing_algo),
281 	.string = bat_routing_algo,
282 };
283 
284 module_param_cb(routing_algo, &param_ops_ra, &__param_string_ra, 0644);
285 module_init(batman_init);
286 module_exit(batman_exit);
287 
288 MODULE_LICENSE("GPL");
289 
290 MODULE_AUTHOR(DRIVER_AUTHOR);
291 MODULE_DESCRIPTION(DRIVER_DESC);
292 MODULE_SUPPORTED_DEVICE(DRIVER_DEVICE);
293 MODULE_VERSION(SOURCE_VERSION);
294