Andrew Lunn | 5beef3c | 2009-11-09 21:20:10 +0100 | [diff] [blame^] | 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 "proc.h" |
| 24 | #include "log.h" |
| 25 | #include "routing.h" |
| 26 | #include "send.h" |
| 27 | #include "soft-interface.h" |
| 28 | #include "device.h" |
| 29 | #include "translation-table.h" |
| 30 | #include "hard-interface.h" |
| 31 | #include "types.h" |
| 32 | #include "vis.h" |
| 33 | #include "hash.h" |
| 34 | #include "compat.h" |
| 35 | |
| 36 | struct list_head if_list; |
| 37 | struct hlist_head forw_bat_list; |
| 38 | struct hlist_head forw_bcast_list; |
| 39 | struct hashtable_t *orig_hash; |
| 40 | |
| 41 | DEFINE_SPINLOCK(orig_hash_lock); |
| 42 | DEFINE_SPINLOCK(forw_bat_list_lock); |
| 43 | DEFINE_SPINLOCK(forw_bcast_list_lock); |
| 44 | |
| 45 | atomic_t originator_interval; |
| 46 | atomic_t vis_interval; |
| 47 | atomic_t aggregation_enabled; |
| 48 | int16_t num_hna; |
| 49 | int16_t num_ifs; |
| 50 | |
| 51 | struct net_device *soft_device; |
| 52 | |
| 53 | static struct task_struct *kthread_task; |
| 54 | |
| 55 | unsigned char broadcastAddr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; |
| 56 | atomic_t module_state; |
| 57 | |
| 58 | struct workqueue_struct *bat_event_workqueue; |
| 59 | |
| 60 | int init_module(void) |
| 61 | { |
| 62 | int retval; |
| 63 | |
| 64 | INIT_LIST_HEAD(&if_list); |
| 65 | INIT_HLIST_HEAD(&forw_bat_list); |
| 66 | INIT_HLIST_HEAD(&forw_bcast_list); |
| 67 | |
| 68 | atomic_set(&module_state, MODULE_INACTIVE); |
| 69 | |
| 70 | atomic_set(&originator_interval, 1000); |
| 71 | atomic_set(&vis_interval, 1000);/* TODO: raise this later, this is only |
| 72 | * for debugging now. */ |
| 73 | atomic_set(&aggregation_enabled, 1); |
| 74 | |
| 75 | /* the name should not be longer than 10 chars - see |
| 76 | * http://lwn.net/Articles/23634/ */ |
| 77 | bat_event_workqueue = create_singlethread_workqueue("bat_events"); |
| 78 | |
| 79 | if (!bat_event_workqueue) |
| 80 | return -ENOMEM; |
| 81 | |
| 82 | retval = setup_procfs(); |
| 83 | if (retval < 0) |
| 84 | return retval; |
| 85 | |
| 86 | bat_device_init(); |
| 87 | |
| 88 | /* initialize layer 2 interface */ |
| 89 | soft_device = alloc_netdev(sizeof(struct bat_priv) , "bat%d", |
| 90 | interface_setup); |
| 91 | |
| 92 | if (!soft_device) { |
| 93 | debug_log(LOG_TYPE_CRIT, "Unable to allocate the batman interface\n"); |
| 94 | goto end; |
| 95 | } |
| 96 | |
| 97 | retval = register_netdev(soft_device); |
| 98 | |
| 99 | if (retval < 0) { |
| 100 | debug_log(LOG_TYPE_CRIT, "Unable to register the batman interface: %i\n", retval); |
| 101 | goto free_soft_device; |
| 102 | } |
| 103 | |
| 104 | register_netdevice_notifier(&hard_if_notifier); |
| 105 | |
| 106 | debug_log(LOG_TYPE_CRIT, "B.A.T.M.A.N. advanced %s%s (compatibility version %i) loaded \n", |
| 107 | SOURCE_VERSION, REVISION_VERSION_STR, COMPAT_VERSION); |
| 108 | |
| 109 | return 0; |
| 110 | |
| 111 | free_soft_device: |
| 112 | free_netdev(soft_device); |
| 113 | soft_device = NULL; |
| 114 | end: |
| 115 | return -ENOMEM; |
| 116 | } |
| 117 | |
| 118 | void cleanup_module(void) |
| 119 | { |
| 120 | shutdown_module(); |
| 121 | |
| 122 | if (soft_device) { |
| 123 | unregister_netdev(soft_device); |
| 124 | soft_device = NULL; |
| 125 | } |
| 126 | |
| 127 | unregister_netdevice_notifier(&hard_if_notifier); |
| 128 | cleanup_procfs(); |
| 129 | |
| 130 | destroy_workqueue(bat_event_workqueue); |
| 131 | bat_event_workqueue = NULL; |
| 132 | } |
| 133 | |
| 134 | /* activates the module, creates bat device, starts timer ... */ |
| 135 | void activate_module(void) |
| 136 | { |
| 137 | if (originator_init() < 1) |
| 138 | goto err; |
| 139 | |
| 140 | if (hna_local_init() < 1) |
| 141 | goto err; |
| 142 | |
| 143 | if (hna_global_init() < 1) |
| 144 | goto err; |
| 145 | |
| 146 | hna_local_add(soft_device->dev_addr); |
| 147 | |
| 148 | if (bat_device_setup() < 1) |
| 149 | goto end; |
| 150 | |
| 151 | if (vis_init() < 1) |
| 152 | goto err; |
| 153 | |
| 154 | /* (re)start kernel thread for packet processing */ |
| 155 | if (!kthread_task) { |
| 156 | kthread_task = kthread_run(packet_recv_thread, NULL, "batman-adv"); |
| 157 | |
| 158 | if (IS_ERR(kthread_task)) { |
| 159 | debug_log(LOG_TYPE_CRIT, "Unable to start packet receive thread\n"); |
| 160 | kthread_task = NULL; |
| 161 | } |
| 162 | } |
| 163 | |
| 164 | update_min_mtu(); |
| 165 | atomic_set(&module_state, MODULE_ACTIVE); |
| 166 | goto end; |
| 167 | |
| 168 | err: |
| 169 | debug_log(LOG_TYPE_CRIT, "Unable to allocate memory for mesh information structures: out of mem ?\n"); |
| 170 | shutdown_module(); |
| 171 | end: |
| 172 | return; |
| 173 | } |
| 174 | |
| 175 | /* shuts down the whole module.*/ |
| 176 | void shutdown_module(void) |
| 177 | { |
| 178 | atomic_set(&module_state, MODULE_DEACTIVATING); |
| 179 | |
| 180 | purge_outstanding_packets(); |
| 181 | flush_workqueue(bat_event_workqueue); |
| 182 | |
| 183 | vis_quit(); |
| 184 | |
| 185 | /* deactivate kernel thread for packet processing (if running) */ |
| 186 | if (kthread_task) { |
| 187 | atomic_set(&exit_cond, 1); |
| 188 | wake_up_interruptible(&thread_wait); |
| 189 | kthread_stop(kthread_task); |
| 190 | |
| 191 | kthread_task = NULL; |
| 192 | } |
| 193 | |
| 194 | originator_free(); |
| 195 | |
| 196 | hna_local_free(); |
| 197 | hna_global_free(); |
| 198 | |
| 199 | synchronize_net(); |
| 200 | bat_device_destroy(); |
| 201 | |
| 202 | hardif_remove_interfaces(); |
| 203 | synchronize_rcu(); |
| 204 | atomic_set(&module_state, MODULE_INACTIVE); |
| 205 | } |
| 206 | |
| 207 | void inc_module_count(void) |
| 208 | { |
| 209 | try_module_get(THIS_MODULE); |
| 210 | } |
| 211 | |
| 212 | void dec_module_count(void) |
| 213 | { |
| 214 | module_put(THIS_MODULE); |
| 215 | } |
| 216 | |
| 217 | int addr_to_string(char *buff, uint8_t *addr) |
| 218 | { |
| 219 | return sprintf(buff, "%02x:%02x:%02x:%02x:%02x:%02x", |
| 220 | addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); |
| 221 | } |
| 222 | |
| 223 | /* returns 1 if they are the same originator */ |
| 224 | |
| 225 | int compare_orig(void *data1, void *data2) |
| 226 | { |
| 227 | return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); |
| 228 | } |
| 229 | |
| 230 | /* hashfunction to choose an entry in a hash table of given size */ |
| 231 | /* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */ |
| 232 | int choose_orig(void *data, int32_t size) |
| 233 | { |
| 234 | unsigned char *key = data; |
| 235 | uint32_t hash = 0; |
| 236 | size_t i; |
| 237 | |
| 238 | for (i = 0; i < 6; i++) { |
| 239 | hash += key[i]; |
| 240 | hash += (hash << 10); |
| 241 | hash ^= (hash >> 6); |
| 242 | } |
| 243 | |
| 244 | hash += (hash << 3); |
| 245 | hash ^= (hash >> 11); |
| 246 | hash += (hash << 15); |
| 247 | |
| 248 | return hash % size; |
| 249 | } |
| 250 | |
| 251 | int is_my_mac(uint8_t *addr) |
| 252 | { |
| 253 | struct batman_if *batman_if; |
| 254 | rcu_read_lock(); |
| 255 | list_for_each_entry_rcu(batman_if, &if_list, list) { |
| 256 | if ((batman_if->net_dev) && |
| 257 | (compare_orig(batman_if->net_dev->dev_addr, addr))) { |
| 258 | rcu_read_unlock(); |
| 259 | return 1; |
| 260 | } |
| 261 | } |
| 262 | rcu_read_unlock(); |
| 263 | return 0; |
| 264 | |
| 265 | } |
| 266 | |
| 267 | int is_bcast(uint8_t *addr) |
| 268 | { |
| 269 | return (addr[0] == (uint8_t)0xff) && (addr[1] == (uint8_t)0xff); |
| 270 | } |
| 271 | |
| 272 | int is_mcast(uint8_t *addr) |
| 273 | { |
| 274 | return *addr & 0x01; |
| 275 | } |
| 276 | |
| 277 | MODULE_LICENSE("GPL"); |
| 278 | |
| 279 | MODULE_AUTHOR(DRIVER_AUTHOR); |
| 280 | MODULE_DESCRIPTION(DRIVER_DESC); |
| 281 | MODULE_SUPPORTED_DEVICE(DRIVER_DEVICE); |
| 282 | #ifdef REVISION_VERSION |
| 283 | MODULE_VERSION(SOURCE_VERSION "-" REVISION_VERSION); |
| 284 | #else |
| 285 | MODULE_VERSION(SOURCE_VERSION); |
| 286 | #endif |