提交 5beef3c9 编写于 作者: A Andrew Lunn 提交者: Greg Kroah-Hartman

staging: batman-adv meshing protocol

B.A.T.M.A.N. (better approach to mobile ad-hoc networking) is
a routing protocol for multi-hop ad-hoc mesh networks. The
networks may be wired or wireless. See
http://www.open-mesh.org/ for more information and user space
tools.

This is the first submission for inclusion in staging.
Signed-off-by: NAndrew Lunn <andrew@lunn.ch>
Signed-off-by: NGreg Kroah-Hartman <gregkh@suse.de>
上级 6638db58
......@@ -129,6 +129,8 @@ source "drivers/staging/wlags49_h2/Kconfig"
source "drivers/staging/wlags49_h25/Kconfig"
source "drivers/staging/batman-adv/Kconfig"
source "drivers/staging/strip/Kconfig"
source "drivers/staging/arlan/Kconfig"
......
......@@ -46,6 +46,7 @@ obj-$(CONFIG_IIO) += iio/
obj-$(CONFIG_RAMZSWAP) += ramzswap/
obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/
obj-$(CONFIG_WLAGS49_H25) += wlags49_h25/
obj-$(CONFIG_BATMAN_ADV) += batman-adv/
obj-$(CONFIG_STRIP) += strip/
obj-$(CONFIG_ARLAN) += arlan/
obj-$(CONFIG_WAVELAN) += wavelan/
......
batman-adv 0.2:
* support latest kernels (2.6.20 - 2.6.31)
* temporary routing loops / TTL code bug / ghost entries in originator table fixed
* internal packet queue for packet aggregation & transmission retry (ARQ)
for payload broadcasts added
* interface detection converted to event based handling to avoid timers
* major linux coding style adjustments applied
* all kernel version compatibility functions has been moved to compat.h
* use random ethernet address generator from the kernel
* /sys/module/batman_adv/version to export kernel module version
* vis: secondary interface export for dot draw format + JSON output format added
* many bugs (alignment issues, race conditions, deadlocks, etc) squashed
-- Sat, 07 Nov 2009 15:44:31 +0100
batman-adv 0.1:
* support latest kernels (2.6.20 - 2.6.28)
* LOTS of cleanup: locking, stack usage, memory leaks
* Change Ethertype from 0x0842 to 0x4305
unregistered at IEEE, if you want to sponsor an official Ethertype ($2500)
please contact us
-- Sun, 28 Dec 2008 00:44:31 +0100
batman-adv 0.1-beta:
* layer 2 meshing based on BATMAN TQ algorithm in kernelland
* operates on any ethernet like interface
* supports IPv4, IPv6, DHCP, etc
* is controlled via /proc/net/batman-adv/
* bridging via brctl is supported
* interface watchdog (interfaces can be (de)activated dynamically)
* offers integrated vis server which meshes/syncs with other vis servers in range
-- Mon, 05 May 2008 14:10:04 +0200
#
# B.A.T.M.A.N meshing protocol
#
config BATMAN_ADV
tristate "B.A.T.M.A.N. Advanced Meshing Protocol"
default n
---help---
B.A.T.M.A.N. (better approach to mobile ad-hoc networking) is
a routing protocol for multi-hop ad-hoc mesh networks. The
networks may be wired or wireless. See
http://www.open-mesh.org/ for more information and user space
tools.
config BATMAN_DEBUG
bool "B.A.T.M.A.N. debugging"
depends on BATMAN != n
help
This is an option for use by developers; most people should
say N here. This enables compilation of support for
outputting debugging information to the kernel log. The
output is controlled via the module parameter debug.
#
# Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
#
# Marek Lindner, Simon Wunderlich
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of version 2 of the GNU General Public
# License as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA
#
obj-m += batman-adv.o
batman-adv-objs := main.o proc.o send.o routing.o soft-interface.o device.o translation-table.o bitarray.o hash.o ring_buffer.o vis.o hard-interface.o aggregation.o log.o
[state: 07-11-2009]
BATMAN-ADV
----------
Batman-advanced is a new approach to wireless networking which does no longer
operate on the IP basis. Unlike B.A.T.M.A.N, which exchanges information
using UDP packets and sets routing tables, batman-advanced operates on ISO/OSI
Layer 2 only and uses and routes (or better: bridges) Ethernet Frames. It
emulates a virtual network switch of all nodes participating. Therefore all
nodes appear to be link local, thus all higher operating protocols won't be
affected by any changes within the network. You can run almost any protocol
above B.A.T.M.A.N. Advanced, prominent examples are: IPv4, IPv6, DHCP, IPX.
This is batman-advanced implemented as Linux kernel driver. It does not depend
on any network (other) driver, and can be used on wifi as well as ethernet,
vpn, etc ... (anything with ethernet-style layer 2).
It compiles against and should work with Linux 2.6.20 - 2.6.31. Supporting older
versions is not planned, but it's probably easy to backport it. If you work on a
backport, feel free to contact us. :-)
COMPILE
-------
To compile against your currently installed kernel, just type:
# make
if you want to compile against some other kernel, use:
# make KERNELPATH=/path/to/kernel
USAGE
-----
insmod the batman-adv.ko in your kernel:
# insmod batman-adv.ko
the module is now waiting for activation. You must add some interfaces
on which batman can operate. Each interface must be added separately:
# echo wlan0 > /proc/net/batman-adv/interfaces
( # echo wlan1 > /proc/net/batman-adv/interfaces )
( # echo eth0 > /proc/net/batman-adv/interfaces )
( ... )
Now batman starts broadcasting on this interface.
You can now view the table of originators (mesh participants) with:
# cat /proc/net/batman-adv/originators
The module will create a new interface "bat0", which can be used as a
regular interface:
# ifconfig bat0 inet 192.168.0.1 up
# ping 192.168.0.2
...
If you want topology visualization, your meshnode must be configured
as VIS-server:
# echo "server" > /proc/net/batman-adv/vis
Each node is either configured as "server" or as "client" (default:
"client"). Clients send their topology data to the server next to them,
and server synchronize with other servers. If there is no server
configured (default) within the mesh, no topology information will be
transmitted. With these "synchronizing servers", there can be 1 or
more vis servers sharing the same (or at least very similar) data.
When configured as server, you can get a topology snapshot of your mesh:
# cat /proc/net/batman-adv/vis
This output format is a graphviz formatted text file which can be
processed with graphviz-tools like dot.
The labels are similar/compatible to the ETX metric, 1.0 means perfect
connection (100%), 2.0 means 50%, 3.0 means 33% and so on.
Alternatively, a JSON output format is available. The format can be set
using by writing either "dot_draw" or "json" into the vis_format file.
"dot_draw" is selected by default.
echo "json" > /proc/net/batman-adv/vis_format
In very mobile scenarios, you might want to adjust the originator
interval to a lower value. This will make the mesh more responsive to
topology changes, but will also increase the overhead. Please make sure
that all nodes in your mesh use the same interval. The default value
is 1000 ms (1 second).
# echo 1000 > /proc/net/batman-adv/orig_interval
To deactivate batman, do:
# echo "" > /proc/net/batman-adv/interfaces
BATCTL
------
B.A.T.M.A.N. advanced operates on layer 2 and thus all hosts partici-
pating in the virtual switch are completely transparent for all proto-
cols above layer 2. Therefore the common diagnosis tools do not work as
expected. To overcome these problems batctl was created. At the moment
the batctl contains ping, traceroute, tcpdump and interfaces to the
kernel module settings.
For more information, please see the manpage (man batctl).
batctl is available on http://www.open-mesh.net/
CONTACT
-------
Please send us comments, experiences, questions, anything :)
IRC: #batman on irc.freenode.org
Mailing-list: b.a.t.m.a.n@open-mesh.net
(subscription at https://list.open-mesh.net/mm/listinfo/b.a.t.m.a.n )
You can also contact the Authors:
Marek Lindner <lindner_marek@yahoo.de>
Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
=> proc interface
* implement new interface to add/delete interfaces and setting options
* /proc/sys/net/batman-adv/ as main folder
* in interfaces/ list every available interface of the host
* each interfaces/$iface/ contains the following files:
-> enable (def: 0) [add/remove this interface to batman-adv]
-> ogm_interval (def: 1000) [ogm interval of that interface]
-> context (def: bat0) [later we want to support multiple mesh instances via
-> bat0/bat1/bat2/..]
-> status (read-only) [outputs the interface status from batman's
-> perspective]
* in mesh/batX/ list every available mesh subnet
-> vis_server (def: 0) [enable/disable vis server for that mesh]
-> vis_data (read-only) [outputs the vis data in a raw format]
-> aggregate_ogm (def: 1) [enable/disable ogm aggregation for that mesh]
-> originators (read-only) [outputs the originator table]
-> transtable_global (read-only) [outputs the global translation table]
-> transtable_local (read-only) [outputs the local translation table]
=> vis "raw" data output
* the raw format shall replace dot draw / json to offer a neutral that can
* be converted
* the format (comma seperated entries):
-> "mac" -> mac address of an originator (each line begins with it)
-> "TQ mac value" -> src mac's link quality towards mac address
-> "HNA mac" -> HNA announced by source mac
-> "PRIMARY" -> this is a primary interface
-> "SEC mac" -> secondary mac address of source (requires preceeding
-> PRIMARY)
=> logging
* the log level LOG_TYPE_CRIT, LOG_TYPE_WARN & LOG_TYPE_NOTICE will be
* unified to use printk
* LOG_TYPE_BATMAN & LOG_TYPE_ROUTES will also use printk but only after the
* internal debug level has been raised
* the internal debug level can be modified using a module parameter (debug)
* or at run time via /sys/module/batman-adv/parameters/debug
* make use of printk %pM support instead of converting mac addresses
* manually
=> strip out all backward compatibility support to older kernels
(only found in compat.h)
=> fix checkpatch.pl errors
Please send all patches to:
Marek Lindner <lindner_marek@yahoo.de>
Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Andrew Lunn <andrew@lunn.ch>
b.a.t.m.a.n@lists.open-mesh.net
Greg Kroah-Hartman <gregkh@suse.de>
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#include "main.h"
#include "aggregation.h"
#include "send.h"
#include "routing.h"
/* calculate the size of the hna information for a given packet */
static int hna_len(struct batman_packet *batman_packet)
{
return batman_packet->num_hna * ETH_ALEN;
}
/* return true if new_packet can be aggregated with forw_packet */
static bool can_aggregate_with(struct batman_packet *new_batman_packet,
int packet_len,
unsigned long send_time,
bool directlink,
struct batman_if *if_incoming,
struct forw_packet *forw_packet)
{
struct batman_packet *batman_packet =
(struct batman_packet *)forw_packet->packet_buff;
int aggregated_bytes = forw_packet->packet_len + packet_len;
/**
* we can aggregate the current packet to this aggregated packet
* if:
*
* - the send time is within our MAX_AGGREGATION_MS time
* - the resulting packet wont be bigger than
* MAX_AGGREGATION_BYTES
*/
if (time_before(send_time, forw_packet->send_time) &&
(aggregated_bytes <= MAX_AGGREGATION_BYTES)) {
/**
* check aggregation compatibility
* -> direct link packets are broadcasted on
* their interface only
* -> aggregate packet if the current packet is
* a "global" packet as well as the base
* packet
*/
/* packets without direct link flag and high TTL
* are flooded through the net */
if ((!directlink) &&
(!(batman_packet->flags & DIRECTLINK)) &&
(batman_packet->ttl != 1) &&
/* own packets originating non-primary
* interfaces leave only that interface */
((!forw_packet->own) ||
(forw_packet->if_incoming->if_num == 0)))
return true;
/* if the incoming packet is sent via this one
* interface only - we still can aggregate */
if ((directlink) &&
(new_batman_packet->ttl == 1) &&
(forw_packet->if_incoming == if_incoming))
return true;
}
return false;
}
/* create a new aggregated packet and add this packet to it */
static void new_aggregated_packet(unsigned char *packet_buff,
int packet_len,
unsigned long send_time,
bool direct_link,
struct batman_if *if_incoming,
int own_packet)
{
struct forw_packet *forw_packet_aggr;
forw_packet_aggr = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC);
if (!forw_packet_aggr)
return;
forw_packet_aggr->packet_buff = kmalloc(MAX_AGGREGATION_BYTES,
GFP_ATOMIC);
if (!forw_packet_aggr->packet_buff) {
kfree(forw_packet_aggr);
return;
}
INIT_HLIST_NODE(&forw_packet_aggr->list);
forw_packet_aggr->packet_len = packet_len;
memcpy(forw_packet_aggr->packet_buff,
packet_buff,
forw_packet_aggr->packet_len);
forw_packet_aggr->own = own_packet;
forw_packet_aggr->if_incoming = if_incoming;
forw_packet_aggr->num_packets = 0;
forw_packet_aggr->direct_link_flags = 0;
forw_packet_aggr->send_time = send_time;
/* save packet direct link flag status */
if (direct_link)
forw_packet_aggr->direct_link_flags |= 1;
/* add new packet to packet list */
spin_lock(&forw_bat_list_lock);
hlist_add_head(&forw_packet_aggr->list, &forw_bat_list);
spin_unlock(&forw_bat_list_lock);
/* start timer for this packet */
INIT_DELAYED_WORK(&forw_packet_aggr->delayed_work,
send_outstanding_bat_packet);
queue_delayed_work(bat_event_workqueue,
&forw_packet_aggr->delayed_work,
send_time - jiffies);
}
/* aggregate a new packet into the existing aggregation */
static void aggregate(struct forw_packet *forw_packet_aggr,
unsigned char *packet_buff,
int packet_len,
bool direct_link)
{
memcpy((forw_packet_aggr->packet_buff + forw_packet_aggr->packet_len),
packet_buff, packet_len);
forw_packet_aggr->packet_len += packet_len;
forw_packet_aggr->num_packets++;
/* save packet direct link flag status */
if (direct_link)
forw_packet_aggr->direct_link_flags |=
(1 << forw_packet_aggr->num_packets);
}
void add_bat_packet_to_list(unsigned char *packet_buff, int packet_len,
struct batman_if *if_incoming, char own_packet,
unsigned long send_time)
{
/**
* _aggr -> pointer to the packet we want to aggregate with
* _pos -> pointer to the position in the queue
*/
struct forw_packet *forw_packet_aggr = NULL, *forw_packet_pos = NULL;
struct hlist_node *tmp_node;
struct batman_packet *batman_packet =
(struct batman_packet *)packet_buff;
bool direct_link = batman_packet->flags & DIRECTLINK ? 1 : 0;
/* find position for the packet in the forward queue */
spin_lock(&forw_bat_list_lock);
/* own packets are not to be aggregated */
if ((atomic_read(&aggregation_enabled)) && (!own_packet)) {
hlist_for_each_entry(forw_packet_pos, tmp_node, &forw_bat_list,
list) {
if (can_aggregate_with(batman_packet,
packet_len,
send_time,
direct_link,
if_incoming,
forw_packet_pos)) {
forw_packet_aggr = forw_packet_pos;
break;
}
}
}
/* nothing to aggregate with - either aggregation disabled or no
* suitable aggregation packet found */
if (forw_packet_aggr == NULL) {
/* the following section can run without the lock */
spin_unlock(&forw_bat_list_lock);
new_aggregated_packet(packet_buff, packet_len,
send_time, direct_link,
if_incoming, own_packet);
} else {
aggregate(forw_packet_aggr,
packet_buff, packet_len,
direct_link);
spin_unlock(&forw_bat_list_lock);
}
}
/* unpack the aggregated packets and process them one by one */
void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff,
int packet_len, struct batman_if *if_incoming)
{
struct batman_packet *batman_packet;
int buff_pos = 0;
unsigned char *hna_buff;
batman_packet = (struct batman_packet *)packet_buff;
while (aggregated_packet(buff_pos, packet_len,
batman_packet->num_hna)) {
/* network to host order for our 16bit seqno, and the
orig_interval. */
batman_packet->seqno = ntohs(batman_packet->seqno);
hna_buff = packet_buff + buff_pos + BAT_PACKET_LEN;
receive_bat_packet(ethhdr, batman_packet,
hna_buff, hna_len(batman_packet),
if_incoming);
buff_pos += BAT_PACKET_LEN + hna_len(batman_packet);
batman_packet = (struct batman_packet *)
(packet_buff + buff_pos);
}
}
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#include "main.h"
/* is there another aggregated packet here? */
static inline int aggregated_packet(int buff_pos, int packet_len, int num_hna)
{
int next_buff_pos = buff_pos + BAT_PACKET_LEN + (num_hna * ETH_ALEN);
return (next_buff_pos <= packet_len) &&
(next_buff_pos <= MAX_AGGREGATION_BYTES);
}
void add_bat_packet_to_list(unsigned char *packet_buff, int packet_len,
struct batman_if *if_outgoing, char own_packet,
unsigned long send_time);
void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff,
int packet_len, struct batman_if *if_incoming);
/*
* Copyright (C) 2006-2009 B.A.T.M.A.N. contributors:
*
* Simon Wunderlich, Marek Lindner
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#include "main.h"
#include "bitarray.h"
#include "log.h"
/* returns true if the corresponding bit in the given seq_bits indicates true
* and curr_seqno is within range of last_seqno */
uint8_t get_bit_status(TYPE_OF_WORD *seq_bits, uint16_t last_seqno,
uint16_t curr_seqno)
{
int16_t diff, word_offset, word_num;
diff = last_seqno - curr_seqno;
if (diff < 0 || diff >= TQ_LOCAL_WINDOW_SIZE) {
return 0;
} else {
/* which word */
word_num = (last_seqno - curr_seqno) / WORD_BIT_SIZE;
/* which position in the selected word */
word_offset = (last_seqno - curr_seqno) % WORD_BIT_SIZE;
if (seq_bits[word_num] & 1 << word_offset)
return 1;
else
return 0;
}
}
/* turn corresponding bit on, so we can remember that we got the packet */
void bit_mark(TYPE_OF_WORD *seq_bits, int32_t n)
{
int32_t word_offset, word_num;
/* if too old, just drop it */
if (n < 0 || n >= TQ_LOCAL_WINDOW_SIZE)
return;
/* which word */
word_num = n / WORD_BIT_SIZE;
/* which position in the selected word */
word_offset = n % WORD_BIT_SIZE;
seq_bits[word_num] |= 1 << word_offset; /* turn the position on */
}
/* shift the packet array by n places. */
void bit_shift(TYPE_OF_WORD *seq_bits, int32_t n)
{
int32_t word_offset, word_num;
int32_t i;
if (n <= 0)
return;
word_offset = n % WORD_BIT_SIZE;/* shift how much inside each word */
word_num = n / WORD_BIT_SIZE; /* shift over how much (full) words */
for (i = NUM_WORDS - 1; i > word_num; i--) {
/* going from old to new, so we don't overwrite the data we copy
* from.
*
* left is high, right is low: FEDC BA98 7654 3210
* ^^ ^^
* vvvv
* ^^^^ = from, vvvvv =to, we'd have word_num==1 and
* word_offset==WORD_BIT_SIZE/2 ????? in this example.
* (=24 bits)
*
* our desired output would be: 9876 5432 1000 0000
* */
seq_bits[i] =
(seq_bits[i - word_num] << word_offset) +
/* take the lower port from the left half, shift it left
* to its final position */
(seq_bits[i - word_num - 1] >>
(WORD_BIT_SIZE-word_offset));
/* and the upper part of the right half and shift it left to
* it's position */
/* for our example that would be: word[0] = 9800 + 0076 =
* 9876 */
}
/* now for our last word, i==word_num, we only have the it's "left"
* half. that's the 1000 word in our example.*/
seq_bits[i] = (seq_bits[i - word_num] << word_offset);
/* pad the rest with 0, if there is anything */
i--;
for (; i >= 0; i--)
seq_bits[i] = 0;
}
/* receive and process one packet, returns 1 if received seq_num is considered
* new, 0 if old */
char bit_get_packet(TYPE_OF_WORD *seq_bits, int16_t seq_num_diff,
int8_t set_mark)
{
int i;
/* we already got a sequence number higher than this one, so we just
* mark it. this should wrap around the integer just fine */
if ((seq_num_diff < 0) && (seq_num_diff >= -TQ_LOCAL_WINDOW_SIZE)) {
if (set_mark)
bit_mark(seq_bits, -seq_num_diff);
return 0;
}
/* it seems we missed a lot of packets or the other host restarted */
if ((seq_num_diff > TQ_LOCAL_WINDOW_SIZE) ||
(seq_num_diff < -TQ_LOCAL_WINDOW_SIZE)) {
if (seq_num_diff > TQ_LOCAL_WINDOW_SIZE)
debug_log(LOG_TYPE_BATMAN,
"We missed a lot of packets (%i) !\n",
seq_num_diff-1);
if (-seq_num_diff > TQ_LOCAL_WINDOW_SIZE)
debug_log(LOG_TYPE_BATMAN,
"Other host probably restarted !\n");
for (i = 0; i < NUM_WORDS; i++)
seq_bits[i] = 0;
if (set_mark)
seq_bits[0] = 1; /* we only have the latest packet */
} else {
bit_shift(seq_bits, seq_num_diff);
if (set_mark)
bit_mark(seq_bits, 0);
}
return 1;
}
/* count the hamming weight, how many good packets did we receive? just count
* the 1's. The inner loop uses the Kernighan algorithm, see
* http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan
*/
int bit_packet_count(TYPE_OF_WORD *seq_bits)
{
int i, hamming = 0;
TYPE_OF_WORD word;
for (i = 0; i < NUM_WORDS; i++) {
word = seq_bits[i];
while (word) {
word &= word-1;
hamming++;
}
}
return hamming;
}
/*
* Copyright (C) 2006-2009 B.A.T.M.A.N. contributors:
*
* Simon Wunderlich, Marek Lindner
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
/* you should choose something big, if you don't want to waste cpu */
#define TYPE_OF_WORD unsigned long
#define WORD_BIT_SIZE (sizeof(TYPE_OF_WORD) * 8)
/* returns true if the corresponding bit in the given seq_bits indicates true
* and curr_seqno is within range of last_seqno */
uint8_t get_bit_status(TYPE_OF_WORD *seq_bits, uint16_t last_seqno,
uint16_t curr_seqno);
/* turn corresponding bit on, so we can remember that we got the packet */
void bit_mark(TYPE_OF_WORD *seq_bits, int32_t n);
/* shift the packet array by n places. */
void bit_shift(TYPE_OF_WORD *seq_bits, int32_t n);
/* receive and process one packet, returns 1 if received seq_num is considered
* new, 0 if old */
char bit_get_packet(TYPE_OF_WORD *seq_bits, int16_t seq_num_diff,
int8_t set_mark);
/* count the hamming weight, how many good packets did we receive? */
int bit_packet_count(TYPE_OF_WORD *seq_bits);
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*
* This file contains macros for maintaining compatibility with older versions
* of the Linux kernel.
*/
#include <linux/version.h> /* LINUX_VERSION_CODE */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
#define skb_set_network_header(_skb, _offset) \
do { (_skb)->nh.raw = (_skb)->data + (_offset); } while (0)
#define skb_reset_mac_header(_skb) \
do { (_skb)->mac.raw = (_skb)->data; } while (0)
#define list_first_entry(ptr, type, member) \
list_entry((ptr)->next, type, member)
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
#define device_create(_cls, _parent, _devt, _device, _fmt) \
class_device_create(_cls, _parent, _devt, _device, _fmt)
#define device_destroy(_cls, _device) \
class_device_destroy(_cls, _device)
#else
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)
#define device_create(_cls, _parent, _devt, _device, _fmt) \
device_create_drvdata(_cls, _parent, _devt, _device, _fmt)
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23)
#define cancel_delayed_work_sync(wq) cancel_rearming_delayed_work(wq)
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
#define strict_strtoul(cp, base, res) \
({ \
int ret = 0; \
char *endp; \
*res = simple_strtoul(cp, &endp, base); \
if (cp == endp) \
ret = -EINVAL; \
ret; \
})
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25) */
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#include "main.h"
#include "device.h"
#include "log.h"
#include "send.h"
#include "types.h"
#include "hash.h"
#include "compat.h"
static struct class *batman_class;
static int Major; /* Major number assigned to our device driver */
static const struct file_operations fops = {
.open = bat_device_open,
.release = bat_device_release,
.read = bat_device_read,
.write = bat_device_write,
.poll = bat_device_poll,
};
static struct device_client *device_client_hash[256];
void bat_device_init(void)
{
int i;
for (i = 0; i < 256; i++)
device_client_hash[i] = NULL;
}
int bat_device_setup(void)
{
int tmp_major;
if (Major)
return 1;
/* register our device - kernel assigns a free major number */
tmp_major = register_chrdev(0, DRIVER_DEVICE, &fops);
if (tmp_major < 0) {
debug_log(LOG_TYPE_WARN, "Registering the character device failed with %d\n",
tmp_major);
return 0;
}
batman_class = class_create(THIS_MODULE, "batman-adv");
if (IS_ERR(batman_class)) {
debug_log(LOG_TYPE_WARN, "Could not register class 'batman-adv' \n");
return 0;
}
device_create(batman_class, NULL, MKDEV(tmp_major, 0), NULL,
"batman-adv");
Major = tmp_major;
return 1;
}
void bat_device_destroy(void)
{
if (!Major)
return;
device_destroy(batman_class, MKDEV(Major, 0));
class_destroy(batman_class);
/* Unregister the device */
unregister_chrdev(Major, DRIVER_DEVICE);
Major = 0;
}
int bat_device_open(struct inode *inode, struct file *file)
{
unsigned int i;
struct device_client *device_client;
device_client = kmalloc(sizeof(struct device_client), GFP_KERNEL);
if (!device_client)
return -ENOMEM;
for (i = 0; i < 256; i++) {
if (!device_client_hash[i]) {
device_client_hash[i] = device_client;
break;
}
}
if (device_client_hash[i] != device_client) {
debug_log(LOG_TYPE_WARN, "Error - can't add another packet client: maximum number of clients reached \n");
kfree(device_client);
return -EXFULL;
}
INIT_LIST_HEAD(&device_client->queue_list);
device_client->queue_len = 0;
device_client->index = i;
device_client->lock = __SPIN_LOCK_UNLOCKED(device_client->lock);
init_waitqueue_head(&device_client->queue_wait);
file->private_data = device_client;
inc_module_count();
return 0;
}
int bat_device_release(struct inode *inode, struct file *file)
{
struct device_client *device_client =
(struct device_client *)file->private_data;
struct device_packet *device_packet;
struct list_head *list_pos, *list_pos_tmp;
spin_lock(&device_client->lock);
/* for all packets in the queue ... */
list_for_each_safe(list_pos, list_pos_tmp, &device_client->queue_list) {
device_packet = list_entry(list_pos,
struct device_packet, list);
list_del(list_pos);
kfree(device_packet);
}
device_client_hash[device_client->index] = NULL;
spin_unlock(&device_client->lock);
kfree(device_client);
dec_module_count();
return 0;
}
ssize_t bat_device_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos)
{
struct device_client *device_client =
(struct device_client *)file->private_data;
struct device_packet *device_packet;
int error;
if ((file->f_flags & O_NONBLOCK) && (device_client->queue_len == 0))
return -EAGAIN;
if ((!buf) || (count < sizeof(struct icmp_packet)))
return -EINVAL;
if (!access_ok(VERIFY_WRITE, buf, count))
return -EFAULT;
error = wait_event_interruptible(device_client->queue_wait,
device_client->queue_len);
if (error)
return error;
spin_lock(&device_client->lock);
device_packet = list_first_entry(&device_client->queue_list,
struct device_packet, list);
list_del(&device_packet->list);
device_client->queue_len--;
spin_unlock(&device_client->lock);
error = __copy_to_user(buf, &device_packet->icmp_packet,
sizeof(struct icmp_packet));
kfree(device_packet);
if (error)
return error;
return sizeof(struct icmp_packet);
}
ssize_t bat_device_write(struct file *file, const char __user *buff,
size_t len, loff_t *off)
{
struct device_client *device_client =
(struct device_client *)file->private_data;
struct icmp_packet icmp_packet;
struct orig_node *orig_node;
struct batman_if *batman_if;
if (len < sizeof(struct icmp_packet)) {
debug_log(LOG_TYPE_NOTICE, "Error - can't send packet from char device: invalid packet size\n");
return -EINVAL;
}
if (!access_ok(VERIFY_READ, buff, sizeof(struct icmp_packet)))
return -EFAULT;
if (__copy_from_user(&icmp_packet, buff, sizeof(icmp_packet)))
return -EFAULT;
if (icmp_packet.packet_type != BAT_ICMP) {
debug_log(LOG_TYPE_NOTICE, "Error - can't send packet from char device: got bogus packet type (expected: BAT_ICMP)\n");
return -EINVAL;
}
if (icmp_packet.msg_type != ECHO_REQUEST) {
debug_log(LOG_TYPE_NOTICE, "Error - can't send packet from char device: got bogus message type (expected: ECHO_REQUEST)\n");
return -EINVAL;
}
icmp_packet.uid = device_client->index;
if (icmp_packet.version != COMPAT_VERSION) {
icmp_packet.msg_type = PARAMETER_PROBLEM;
icmp_packet.ttl = COMPAT_VERSION;
bat_device_add_packet(device_client, &icmp_packet);
goto out;
}
if (atomic_read(&module_state) != MODULE_ACTIVE)
goto dst_unreach;
spin_lock(&orig_hash_lock);
orig_node = ((struct orig_node *)hash_find(orig_hash, icmp_packet.dst));
if (!orig_node)
goto unlock;
if (!orig_node->router)
goto unlock;
batman_if = orig_node->batman_if;
if (!batman_if)
goto unlock;
memcpy(icmp_packet.orig,
batman_if->net_dev->dev_addr,
ETH_ALEN);
send_raw_packet((unsigned char *)&icmp_packet,
sizeof(struct icmp_packet),
batman_if, orig_node->router->addr);
spin_unlock(&orig_hash_lock);
goto out;
unlock:
spin_unlock(&orig_hash_lock);
dst_unreach:
icmp_packet.msg_type = DESTINATION_UNREACHABLE;
bat_device_add_packet(device_client, &icmp_packet);
out:
return len;
}
unsigned int bat_device_poll(struct file *file, poll_table *wait)
{
struct device_client *device_client =
(struct device_client *)file->private_data;
poll_wait(file, &device_client->queue_wait, wait);
if (device_client->queue_len > 0)
return POLLIN | POLLRDNORM;
return 0;
}
void bat_device_add_packet(struct device_client *device_client,
struct icmp_packet *icmp_packet)
{
struct device_packet *device_packet;
device_packet = kmalloc(sizeof(struct device_packet), GFP_KERNEL);
if (!device_packet)
return;
INIT_LIST_HEAD(&device_packet->list);
memcpy(&device_packet->icmp_packet, icmp_packet,
sizeof(struct icmp_packet));
spin_lock(&device_client->lock);
/* while waiting for the lock the device_client could have been
* deleted */
if (!device_client_hash[icmp_packet->uid]) {
spin_unlock(&device_client->lock);
kfree(device_packet);
return;
}
list_add_tail(&device_packet->list, &device_client->queue_list);
device_client->queue_len++;
if (device_client->queue_len > 100) {
device_packet = list_first_entry(&device_client->queue_list,
struct device_packet, list);
list_del(&device_packet->list);
kfree(device_packet);
device_client->queue_len--;
}
spin_unlock(&device_client->lock);
wake_up(&device_client->queue_wait);
}
void bat_device_receive_packet(struct icmp_packet *icmp_packet)
{
struct device_client *hash = device_client_hash[icmp_packet->uid];
if (hash)
bat_device_add_packet(hash, icmp_packet);
}
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#include "types.h"
void bat_device_init(void);
int bat_device_setup(void);
void bat_device_destroy(void);
int bat_device_open(struct inode *inode, struct file *file);
int bat_device_release(struct inode *inode, struct file *file);
ssize_t bat_device_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos);
ssize_t bat_device_write(struct file *file, const char __user *buff,
size_t len, loff_t *off);
unsigned int bat_device_poll(struct file *file, poll_table *wait);
void bat_device_add_packet(struct device_client *device_client,
struct icmp_packet *icmp_packet);
void bat_device_receive_packet(struct icmp_packet *icmp_packet);
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#include "main.h"
#include "hard-interface.h"
#include "log.h"
#include "soft-interface.h"
#include "send.h"
#include "translation-table.h"
#include "routing.h"
#include "hash.h"
#include "compat.h"
#define MIN(x, y) ((x) < (y) ? (x) : (y))
static char avail_ifs;
static char active_ifs;
static void hardif_free_interface(struct rcu_head *rcu);
static struct batman_if *get_batman_if_by_name(char *name)
{
struct batman_if *batman_if;
rcu_read_lock();
list_for_each_entry_rcu(batman_if, &if_list, list) {
if (strncmp(batman_if->dev, name, IFNAMSIZ) == 0)
goto out;
}
batman_if = NULL;
out:
rcu_read_unlock();
return batman_if;
}
int hardif_min_mtu(void)
{
struct batman_if *batman_if;
/* allow big frames if all devices are capable to do so
* (have MTU > 1500 + BAT_HEADER_LEN) */
int min_mtu = ETH_DATA_LEN;
rcu_read_lock();
list_for_each_entry_rcu(batman_if, &if_list, list) {
if ((batman_if->if_active == IF_ACTIVE) ||
(batman_if->if_active == IF_TO_BE_ACTIVATED))
min_mtu = MIN(batman_if->net_dev->mtu - BAT_HEADER_LEN,
min_mtu);
}
rcu_read_unlock();
return min_mtu;
}
static void check_known_mac_addr(uint8_t *addr)
{
struct batman_if *batman_if;
char mac_string[ETH_STR_LEN];
rcu_read_lock();
list_for_each_entry_rcu(batman_if, &if_list, list) {
if ((batman_if->if_active != IF_ACTIVE) &&
(batman_if->if_active != IF_TO_BE_ACTIVATED))
continue;
if (!compare_orig(batman_if->net_dev->dev_addr, addr))
continue;
addr_to_string(mac_string, addr);
debug_log(LOG_TYPE_WARN, "The newly added mac address (%s) already exists on: %s\n",
mac_string, batman_if->dev);
debug_log(LOG_TYPE_WARN, "It is strongly recommended to keep mac addresses unique to avoid problems!\n");
}
rcu_read_unlock();
}
/* adjusts the MTU if a new interface with a smaller MTU appeared. */
void update_min_mtu(void)
{
int min_mtu;
min_mtu = hardif_min_mtu();
if (soft_device->mtu != min_mtu)
soft_device->mtu = min_mtu;
}
/* checks if the interface is up. (returns 1 if it is) */
static int hardif_is_interface_up(char *dev)
{
struct net_device *net_dev;
/**
* if we already have an interface in our interface list and
* the current interface is not the primary interface and
* the primary interface is not up and
* the primary interface has never been up - don't activate any
* secondary interface !
*/
rcu_read_lock();
if ((!list_empty(&if_list)) &&
strncmp(((struct batman_if *)if_list.next)->dev, dev, IFNAMSIZ) &&
!(((struct batman_if *)if_list.next)->if_active == IF_ACTIVE) &&
!(((struct batman_if *)if_list.next)->if_active == IF_TO_BE_ACTIVATED) &&
(!main_if_was_up())) {
rcu_read_unlock();
goto end;
}
rcu_read_unlock();
#ifdef __NET_NET_NAMESPACE_H
net_dev = dev_get_by_name(&init_net, dev);
#else
net_dev = dev_get_by_name(dev);
#endif
if (!net_dev)
goto end;
if (!(net_dev->flags & IFF_UP))
goto failure;
dev_put(net_dev);
return 1;
failure:
dev_put(net_dev);
end:
return 0;
}
/* deactivates the interface. */
void hardif_deactivate_interface(struct batman_if *batman_if)
{
if (batman_if->if_active != IF_ACTIVE)
return;
if (batman_if->raw_sock)
sock_release(batman_if->raw_sock);
/**
* batman_if->net_dev has been acquired by dev_get_by_name() in
* proc_interfaces_write() and has to be unreferenced.
*/
if (batman_if->net_dev)
dev_put(batman_if->net_dev);
batman_if->raw_sock = NULL;
batman_if->net_dev = NULL;
batman_if->if_active = IF_INACTIVE;
active_ifs--;
debug_log(LOG_TYPE_NOTICE, "Interface deactivated: %s\n",
batman_if->dev);
}
/* (re)activate given interface. */
static void hardif_activate_interface(struct batman_if *batman_if)
{
struct sockaddr_ll bind_addr;
int retval;
if (batman_if->if_active != IF_INACTIVE)
return;
#ifdef __NET_NET_NAMESPACE_H
batman_if->net_dev = dev_get_by_name(&init_net, batman_if->dev);
#else
batman_if->net_dev = dev_get_by_name(batman_if->dev);
#endif
if (!batman_if->net_dev)
goto dev_err;
retval = sock_create_kern(PF_PACKET, SOCK_RAW,
__constant_htons(ETH_P_BATMAN),
&batman_if->raw_sock);
if (retval < 0) {
debug_log(LOG_TYPE_WARN, "Can't create raw socket: %i\n",
retval);
goto sock_err;
}
bind_addr.sll_family = AF_PACKET;
bind_addr.sll_ifindex = batman_if->net_dev->ifindex;
bind_addr.sll_protocol = 0; /* is set by the kernel */
retval = kernel_bind(batman_if->raw_sock,
(struct sockaddr *)&bind_addr, sizeof(bind_addr));
if (retval < 0) {
debug_log(LOG_TYPE_WARN, "Can't create bind raw socket: %i\n",
retval);
goto bind_err;
}
check_known_mac_addr(batman_if->net_dev->dev_addr);
batman_if->raw_sock->sk->sk_user_data =
batman_if->raw_sock->sk->sk_data_ready;
batman_if->raw_sock->sk->sk_data_ready = batman_data_ready;
addr_to_string(batman_if->addr_str, batman_if->net_dev->dev_addr);
memcpy(((struct batman_packet *)(batman_if->packet_buff))->orig,
batman_if->net_dev->dev_addr, ETH_ALEN);
memcpy(((struct batman_packet *)(batman_if->packet_buff))->prev_sender,
batman_if->net_dev->dev_addr, ETH_ALEN);
batman_if->if_active = IF_TO_BE_ACTIVATED;
active_ifs++;
/* save the mac address if it is our primary interface */
if (batman_if->if_num == 0)
set_main_if_addr(batman_if->net_dev->dev_addr);
debug_log(LOG_TYPE_NOTICE, "Interface activated: %s\n",
batman_if->dev);
return;
bind_err:
sock_release(batman_if->raw_sock);
sock_err:
dev_put(batman_if->net_dev);
dev_err:
batman_if->raw_sock = NULL;
batman_if->net_dev = NULL;
}
static void hardif_free_interface(struct rcu_head *rcu)
{
struct batman_if *batman_if = container_of(rcu, struct batman_if, rcu);
kfree(batman_if->packet_buff);
kfree(batman_if->dev);
kfree(batman_if);
}
/**
* called by
* - echo '' > /proc/.../interfaces
* - modprobe -r batman-adv-core
*/
/* removes and frees all interfaces */
void hardif_remove_interfaces(void)
{
struct batman_if *batman_if = NULL;
avail_ifs = 0;
/* no lock needed - we don't delete somewhere else */
list_for_each_entry(batman_if, &if_list, list) {
list_del_rcu(&batman_if->list);
/* first deactivate interface */
if (batman_if->if_active != IF_INACTIVE)
hardif_deactivate_interface(batman_if);
call_rcu(&batman_if->rcu, hardif_free_interface);
}
}
static int resize_orig(struct orig_node *orig_node, int if_num)
{
void *data_ptr;
data_ptr = kmalloc((if_num + 1) * sizeof(TYPE_OF_WORD) * NUM_WORDS,
GFP_ATOMIC);
if (!data_ptr) {
debug_log(LOG_TYPE_WARN, "Can't resize orig: out of memory\n");
return -1;
}
memcpy(data_ptr, orig_node->bcast_own,
if_num * sizeof(TYPE_OF_WORD) * NUM_WORDS);
kfree(orig_node->bcast_own);
orig_node->bcast_own = data_ptr;
data_ptr = kmalloc((if_num + 1) * sizeof(uint8_t), GFP_ATOMIC);
if (!data_ptr) {
debug_log(LOG_TYPE_WARN, "Can't resize orig: out of memory\n");
return -1;
}
memcpy(data_ptr, orig_node->bcast_own_sum, if_num * sizeof(uint8_t));
kfree(orig_node->bcast_own_sum);
orig_node->bcast_own_sum = data_ptr;
return 0;
}
/* adds an interface the interface list and activate it, if possible */
int hardif_add_interface(char *dev, int if_num)
{
struct batman_if *batman_if;
struct batman_packet *batman_packet;
struct orig_node *orig_node;
struct hash_it_t *hashit = NULL;
batman_if = kmalloc(sizeof(struct batman_if), GFP_KERNEL);
if (!batman_if) {
debug_log(LOG_TYPE_WARN, "Can't add interface (%s): out of memory\n", dev);
return -1;
}
batman_if->raw_sock = NULL;
batman_if->net_dev = NULL;
if ((if_num == 0) && (num_hna > 0))
batman_if->packet_len = BAT_PACKET_LEN + num_hna * ETH_ALEN;
else
batman_if->packet_len = BAT_PACKET_LEN;
batman_if->packet_buff = kmalloc(batman_if->packet_len, GFP_KERNEL);
if (!batman_if->packet_buff) {
debug_log(LOG_TYPE_WARN, "Can't add interface packet (%s): out of memory\n", dev);
goto out;
}
batman_if->if_num = if_num;
batman_if->dev = dev;
batman_if->if_active = IF_INACTIVE;
INIT_RCU_HEAD(&batman_if->rcu);
debug_log(LOG_TYPE_NOTICE, "Adding interface: %s\n", dev);
avail_ifs++;
INIT_LIST_HEAD(&batman_if->list);
batman_packet = (struct batman_packet *)(batman_if->packet_buff);
batman_packet->packet_type = BAT_PACKET;
batman_packet->version = COMPAT_VERSION;
batman_packet->flags = 0x00;
batman_packet->ttl = (batman_if->if_num > 0 ? 2 : TTL);
batman_packet->flags = 0;
batman_packet->tq = TQ_MAX_VALUE;
batman_packet->num_hna = 0;
if (batman_if->packet_len != BAT_PACKET_LEN) {
unsigned char *hna_buff;
int hna_len;
hna_buff = batman_if->packet_buff + BAT_PACKET_LEN;
hna_len = batman_if->packet_len - BAT_PACKET_LEN;
batman_packet->num_hna = hna_local_fill_buffer(hna_buff,
hna_len);
}
atomic_set(&batman_if->seqno, 1);
/* resize all orig nodes because orig_node->bcast_own(_sum) depend on
* if_num */
spin_lock(&orig_hash_lock);
while (NULL != (hashit = hash_iterate(orig_hash, hashit))) {
orig_node = hashit->bucket->data;
if (resize_orig(orig_node, if_num) == -1) {
spin_unlock(&orig_hash_lock);
goto out;
}
}
spin_unlock(&orig_hash_lock);
if (!hardif_is_interface_up(batman_if->dev))
debug_log(LOG_TYPE_WARN, "Not using interface %s (retrying later): interface not active\n", batman_if->dev);
else
hardif_activate_interface(batman_if);
list_add_tail_rcu(&batman_if->list, &if_list);
/* begin sending originator messages on that interface */
schedule_own_packet(batman_if);
return 1;
out:
if (batman_if->packet_buff)
kfree(batman_if->packet_buff);
kfree(batman_if);
kfree(dev);
return -1;
}
char hardif_get_active_if_num(void)
{
return active_ifs;
}
static int hard_if_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
struct net_device *dev = (struct net_device *)ptr;
struct batman_if *batman_if = get_batman_if_by_name(dev->name);
if (!batman_if)
goto out;
switch (event) {
case NETDEV_GOING_DOWN:
case NETDEV_DOWN:
case NETDEV_UNREGISTER:
hardif_deactivate_interface(batman_if);
break;
case NETDEV_UP:
hardif_activate_interface(batman_if);
if ((atomic_read(&module_state) == MODULE_INACTIVE) &&
(hardif_get_active_if_num() > 0)) {
activate_module();
}
break;
/* NETDEV_CHANGEADDR - mac address change - what are we doing here ? */
default:
/* debug_log(LOG_TYPE_CRIT, "hard_if_event: %s %i\n", dev->name, event); */
break;
};
update_min_mtu();
out:
return NOTIFY_DONE;
}
struct notifier_block hard_if_notifier = {
.notifier_call = hard_if_event,
};
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#define IF_INACTIVE 0
#define IF_ACTIVE 1
/* #define IF_TO_BE_DEACTIVATED 2 - not needed anymore */
#define IF_TO_BE_ACTIVATED 3
extern struct notifier_block hard_if_notifier;
void hardif_remove_interfaces(void);
int hardif_add_interface(char *dev, int if_num);
void hardif_deactivate_interface(struct batman_if *batman_if);
char hardif_get_active_if_num(void);
void hardif_check_interfaces_status(void);
void hardif_check_interfaces_status_wq(struct work_struct *work);
int hardif_min_mtu(void);
void update_min_mtu(void);
/*
* Copyright (C) 2006-2009 B.A.T.M.A.N. contributors:
*
* Simon Wunderlich, Marek Lindner
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#include "main.h"
#include "hash.h"
/* clears the hash */
void hash_init(struct hashtable_t *hash)
{
int i;
hash->elements = 0;
for (i = 0 ; i < hash->size; i++)
hash->table[i] = NULL;
}
/* remove the hash structure. if hashdata_free_cb != NULL, this function will be
* called to remove the elements inside of the hash. if you don't remove the
* elements, memory might be leaked. */
void hash_delete(struct hashtable_t *hash, hashdata_free_cb free_cb)
{
struct element_t *bucket, *last_bucket;
int i;
for (i = 0; i < hash->size; i++) {
bucket = hash->table[i];
while (bucket != NULL) {
if (free_cb != NULL)
free_cb(bucket->data);
last_bucket = bucket;
bucket = bucket->next;
kfree(last_bucket);
}
}
hash_destroy(hash);
}
/* free only the hashtable and the hash itself. */
void hash_destroy(struct hashtable_t *hash)
{
kfree(hash->table);
kfree(hash);
}
/* iterate though the hash. first element is selected with iter_in NULL. use
* the returned iterator to access the elements until hash_it_t returns NULL. */
struct hash_it_t *hash_iterate(struct hashtable_t *hash,
struct hash_it_t *iter_in)
{
struct hash_it_t *iter;
if (!hash)
return NULL;
if (iter_in == NULL) {
iter = kmalloc(sizeof(struct hash_it_t), GFP_ATOMIC);
iter->index = -1;
iter->bucket = NULL;
iter->prev_bucket = NULL;
} else {
iter = iter_in;
}
/* sanity checks first (if our bucket got deleted in the last
* iteration): */
if (iter->bucket != NULL) {
if (iter->first_bucket != NULL) {
/* we're on the first element and it got removed after
* the last iteration. */
if ((*iter->first_bucket) != iter->bucket) {
/* there are still other elements in the list */
if ((*iter->first_bucket) != NULL) {
iter->prev_bucket = NULL;
iter->bucket = (*iter->first_bucket);
iter->first_bucket =
&hash->table[iter->index];
return iter;
} else {
iter->bucket = NULL;
}
}
} else if (iter->prev_bucket != NULL) {
/*
* we're not on the first element, and the bucket got
* removed after the last iteration. the last bucket's
* next pointer is not pointing to our actual bucket
* anymore. select the next.
*/
if (iter->prev_bucket->next != iter->bucket)
iter->bucket = iter->prev_bucket;
}
}
/* now as we are sane, select the next one if there is some */
if (iter->bucket != NULL) {
if (iter->bucket->next != NULL) {
iter->prev_bucket = iter->bucket;
iter->bucket = iter->bucket->next;
iter->first_bucket = NULL;
return iter;
}
}
/* if not returned yet, we've reached the last one on the index and have
* to search forward */
iter->index++;
/* go through the entries of the hash table */
while (iter->index < hash->size) {
if ((hash->table[iter->index]) != NULL) {
iter->prev_bucket = NULL;
iter->bucket = hash->table[iter->index];
iter->first_bucket = &hash->table[iter->index];
return iter;
} else {
iter->index++;
}
}
/* nothing to iterate over anymore */
kfree(iter);
return NULL;
}
/* allocates and clears the hash */
struct hashtable_t *hash_new(int size, hashdata_compare_cb compare,
hashdata_choose_cb choose)
{
struct hashtable_t *hash;
hash = kmalloc(sizeof(struct hashtable_t) , GFP_ATOMIC);
if (hash == NULL)
return NULL;
hash->size = size;
hash->table = kmalloc(sizeof(struct element_t *) * size, GFP_ATOMIC);
if (hash->table == NULL) {
kfree(hash);
return NULL;
}
hash_init(hash);
hash->compare = compare;
hash->choose = choose;
return hash;
}
/* adds data to the hashtable. returns 0 on success, -1 on error */
int hash_add(struct hashtable_t *hash, void *data)
{
int index;
struct element_t *bucket, *prev_bucket = NULL;
if (!hash)
return -1;
index = hash->choose(data, hash->size);
bucket = hash->table[index];
while (bucket != NULL) {
if (hash->compare(bucket->data, data))
return -1;
prev_bucket = bucket;
bucket = bucket->next;
}
/* found the tail of the list, add new element */
bucket = kmalloc(sizeof(struct element_t), GFP_ATOMIC);
if (bucket == NULL)
return -1;
bucket->data = data;
bucket->next = NULL;
/* and link it */
if (prev_bucket == NULL)
hash->table[index] = bucket;
else
prev_bucket->next = bucket;
hash->elements++;
return 0;
}
/* finds data, based on the key in keydata. returns the found data on success,
* or NULL on error */
void *hash_find(struct hashtable_t *hash, void *keydata)
{
int index;
struct element_t *bucket;
if (!hash)
return NULL;
index = hash->choose(keydata , hash->size);
bucket = hash->table[index];
while (bucket != NULL) {
if (hash->compare(bucket->data, keydata))
return bucket->data;
bucket = bucket->next;
}
return NULL;
}
/* remove bucket (this might be used in hash_iterate() if you already found the
* bucket you want to delete and don't need the overhead to find it again with
* hash_remove(). But usually, you don't want to use this function, as it
* fiddles with hash-internals. */
void *hash_remove_bucket(struct hashtable_t *hash, struct hash_it_t *hash_it_t)
{
void *data_save;
data_save = hash_it_t->bucket->data;
if (hash_it_t->prev_bucket != NULL)
hash_it_t->prev_bucket->next = hash_it_t->bucket->next;
else if (hash_it_t->first_bucket != NULL)
(*hash_it_t->first_bucket) = hash_it_t->bucket->next;
kfree(hash_it_t->bucket);
hash->elements--;
return data_save;
}
/* removes data from hash, if found. returns pointer do data on success, so you
* can remove the used structure yourself, or NULL on error . data could be the
* structure you use with just the key filled, we just need the key for
* comparing. */
void *hash_remove(struct hashtable_t *hash, void *data)
{
struct hash_it_t hash_it_t;
hash_it_t.index = hash->choose(data, hash->size);
hash_it_t.bucket = hash->table[hash_it_t.index];
hash_it_t.prev_bucket = NULL;
while (hash_it_t.bucket != NULL) {
if (hash->compare(hash_it_t.bucket->data, data)) {
hash_it_t.first_bucket =
(hash_it_t.bucket ==
hash->table[hash_it_t.index] ?
&hash->table[hash_it_t.index] : NULL);
return hash_remove_bucket(hash, &hash_it_t);
}
hash_it_t.prev_bucket = hash_it_t.bucket;
hash_it_t.bucket = hash_it_t.bucket->next;
}
return NULL;
}
/* resize the hash, returns the pointer to the new hash or NULL on
* error. removes the old hash on success. */
struct hashtable_t *hash_resize(struct hashtable_t *hash, int size)
{
struct hashtable_t *new_hash;
struct element_t *bucket;
int i;
/* initialize a new hash with the new size */
new_hash = hash_new(size, hash->compare, hash->choose);
if (new_hash == NULL)
return NULL;
/* copy the elements */
for (i = 0; i < hash->size; i++) {
bucket = hash->table[i];
while (bucket != NULL) {
hash_add(new_hash, bucket->data);
bucket = bucket->next;
}
}
/* remove hash and eventual overflow buckets but not the content
* itself. */
hash_delete(hash, NULL);
return new_hash;
}
/*
* Copyright (C) 2006-2009 B.A.T.M.A.N. contributors:
*
* Simon Wunderlich, Marek Lindner
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#ifndef _BATMAN_HASH_H
#define _BATMAN_HASH_H
typedef int (*hashdata_compare_cb)(void *, void *);
typedef int (*hashdata_choose_cb)(void *, int);
typedef void (*hashdata_free_cb)(void *);
struct element_t {
void *data; /* pointer to the data */
struct element_t *next; /* overflow bucket pointer */
};
struct hash_it_t {
int index;
struct element_t *bucket;
struct element_t *prev_bucket;
struct element_t **first_bucket;
};
struct hashtable_t {
struct element_t **table; /* the hashtable itself, with the buckets */
int elements; /* number of elements registered */
int size; /* size of hashtable */
hashdata_compare_cb compare;/* callback to a compare function. should
* compare 2 element datas for their keys,
* return 0 if same and not 0 if not
* same */
hashdata_choose_cb choose; /* the hashfunction, should return an index
* based on the key in the data of the first
* argument and the size the second */
};
/* clears the hash */
void hash_init(struct hashtable_t *hash);
/* allocates and clears the hash */
struct hashtable_t *hash_new(int size, hashdata_compare_cb compare,
hashdata_choose_cb choose);
/* remove bucket (this might be used in hash_iterate() if you already found the
* bucket you want to delete and don't need the overhead to find it again with
* hash_remove(). But usually, you don't want to use this function, as it
* fiddles with hash-internals. */
void *hash_remove_bucket(struct hashtable_t *hash, struct hash_it_t *hash_it_t);
/* remove the hash structure. if hashdata_free_cb != NULL, this function will be
* called to remove the elements inside of the hash. if you don't remove the
* elements, memory might be leaked. */
void hash_delete(struct hashtable_t *hash, hashdata_free_cb free_cb);
/* free only the hashtable and the hash itself. */
void hash_destroy(struct hashtable_t *hash);
/* adds data to the hashtable. returns 0 on success, -1 on error */
int hash_add(struct hashtable_t *hash, void *data);
/* removes data from hash, if found. returns pointer do data on success, so you
* can remove the used structure yourself, or NULL on error . data could be the
* structure you use with just the key filled, we just need the key for
* comparing. */
void *hash_remove(struct hashtable_t *hash, void *data);
/* finds data, based on the key in keydata. returns the found data on success,
* or NULL on error */
void *hash_find(struct hashtable_t *hash, void *keydata);
/* resize the hash, returns the pointer to the new hash or NULL on
* error. removes the old hash on success */
struct hashtable_t *hash_resize(struct hashtable_t *hash, int size);
/* iterate though the hash. first element is selected with iter_in NULL. use
* the returned iterator to access the elements until hash_it_t returns NULL. */
struct hash_it_t *hash_iterate(struct hashtable_t *hash,
struct hash_it_t *iter_in);
/* print the hash table for debugging */
void hash_debug(struct hashtable_t *hash);
#endif
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#include "main.h"
#include "log.h"
#define LOG_BUF_MASK (log_buf_len-1)
#define LOG_BUF(idx) (log_buf[(idx) & LOG_BUF_MASK])
static char log_buf[LOG_BUF_LEN];
static int log_buf_len = LOG_BUF_LEN;
static unsigned long log_start;
static unsigned long log_end;
uint8_t log_level;
static DEFINE_SPINLOCK(logbuf_lock);
const struct file_operations proc_log_operations = {
.open = log_open,
.release = log_release,
.read = log_read,
.write = log_write,
.poll = log_poll,
};
static DECLARE_WAIT_QUEUE_HEAD(log_wait);
static void emit_log_char(char c)
{
LOG_BUF(log_end) = c;
log_end++;
if (log_end - log_start > log_buf_len)
log_start = log_end - log_buf_len;
}
static int fdebug_log(char *fmt, ...)
{
int printed_len;
char *p;
va_list args;
static char debug_log_buf[256];
unsigned long flags;
spin_lock_irqsave(&logbuf_lock, flags);
va_start(args, fmt);
printed_len = vscnprintf(debug_log_buf, sizeof(debug_log_buf), fmt,
args);
va_end(args);
for (p = debug_log_buf; *p != 0; p++)
emit_log_char(*p);
spin_unlock_irqrestore(&logbuf_lock, flags);
wake_up(&log_wait);
return 0;
}
int debug_log(int type, char *fmt, ...)
{
va_list args;
int retval = 0;
char tmp_log_buf[256];
/* only critical information get into the official kernel log */
if (type == LOG_TYPE_CRIT) {
va_start(args, fmt);
vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args);
printk(KERN_ERR "batman-adv: %s", tmp_log_buf);
va_end(args);
}
if ((type == LOG_TYPE_CRIT) || (log_level & type)) {
va_start(args, fmt);
vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args);
fdebug_log("[%10u] %s", (jiffies / HZ), tmp_log_buf);
va_end(args);
}
return retval;
}
int log_open(struct inode *inode, struct file *file)
{
inc_module_count();
return 0;
}
int log_release(struct inode *inode, struct file *file)
{
dec_module_count();
return 0;
}
ssize_t log_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos)
{
int error, i = 0;
char c;
unsigned long flags;
if ((file->f_flags & O_NONBLOCK) && !(log_end - log_start))
return -EAGAIN;
if ((!buf) || (count < 0))
return -EINVAL;
if (count == 0)
return 0;
if (!access_ok(VERIFY_WRITE, buf, count))
return -EFAULT;
error = wait_event_interruptible(log_wait, (log_start - log_end));
if (error)
return error;
spin_lock_irqsave(&logbuf_lock, flags);
while ((!error) && (log_start != log_end) && (i < count)) {
c = LOG_BUF(log_start);
log_start++;
spin_unlock_irqrestore(&logbuf_lock, flags);
error = __put_user(c, buf);
spin_lock_irqsave(&logbuf_lock, flags);
buf++;
i++;
}
spin_unlock_irqrestore(&logbuf_lock, flags);
if (!error)
return i;
return error;
}
ssize_t log_write(struct file *file, const char __user *buf, size_t count,
loff_t *ppos)
{
return count;
}
unsigned int log_poll(struct file *file, poll_table *wait)
{
poll_wait(file, &log_wait, wait);
if (log_end - log_start)
return POLLIN | POLLRDNORM;
return 0;
}
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
extern const struct file_operations proc_log_operations;
extern uint8_t log_level;
int debug_log(int type, char *fmt, ...);
int log_open(struct inode *inode, struct file *file);
int log_release(struct inode *inode, struct file *file);
ssize_t log_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos);
ssize_t log_write(struct file *file, const char __user *buf, size_t count,
loff_t *ppos);
unsigned int log_poll(struct file *file, poll_table *wait);
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#include "main.h"
#include "proc.h"
#include "log.h"
#include "routing.h"
#include "send.h"
#include "soft-interface.h"
#include "device.h"
#include "translation-table.h"
#include "hard-interface.h"
#include "types.h"
#include "vis.h"
#include "hash.h"
#include "compat.h"
struct list_head if_list;
struct hlist_head forw_bat_list;
struct hlist_head forw_bcast_list;
struct hashtable_t *orig_hash;
DEFINE_SPINLOCK(orig_hash_lock);
DEFINE_SPINLOCK(forw_bat_list_lock);
DEFINE_SPINLOCK(forw_bcast_list_lock);
atomic_t originator_interval;
atomic_t vis_interval;
atomic_t aggregation_enabled;
int16_t num_hna;
int16_t num_ifs;
struct net_device *soft_device;
static struct task_struct *kthread_task;
unsigned char broadcastAddr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
atomic_t module_state;
struct workqueue_struct *bat_event_workqueue;
int init_module(void)
{
int retval;
INIT_LIST_HEAD(&if_list);
INIT_HLIST_HEAD(&forw_bat_list);
INIT_HLIST_HEAD(&forw_bcast_list);
atomic_set(&module_state, MODULE_INACTIVE);
atomic_set(&originator_interval, 1000);
atomic_set(&vis_interval, 1000);/* TODO: raise this later, this is only
* for debugging now. */
atomic_set(&aggregation_enabled, 1);
/* the name should not be longer than 10 chars - see
* http://lwn.net/Articles/23634/ */
bat_event_workqueue = create_singlethread_workqueue("bat_events");
if (!bat_event_workqueue)
return -ENOMEM;
retval = setup_procfs();
if (retval < 0)
return retval;
bat_device_init();
/* initialize layer 2 interface */
soft_device = alloc_netdev(sizeof(struct bat_priv) , "bat%d",
interface_setup);
if (!soft_device) {
debug_log(LOG_TYPE_CRIT, "Unable to allocate the batman interface\n");
goto end;
}
retval = register_netdev(soft_device);
if (retval < 0) {
debug_log(LOG_TYPE_CRIT, "Unable to register the batman interface: %i\n", retval);
goto free_soft_device;
}
register_netdevice_notifier(&hard_if_notifier);
debug_log(LOG_TYPE_CRIT, "B.A.T.M.A.N. advanced %s%s (compatibility version %i) loaded \n",
SOURCE_VERSION, REVISION_VERSION_STR, COMPAT_VERSION);
return 0;
free_soft_device:
free_netdev(soft_device);
soft_device = NULL;
end:
return -ENOMEM;
}
void cleanup_module(void)
{
shutdown_module();
if (soft_device) {
unregister_netdev(soft_device);
soft_device = NULL;
}
unregister_netdevice_notifier(&hard_if_notifier);
cleanup_procfs();
destroy_workqueue(bat_event_workqueue);
bat_event_workqueue = NULL;
}
/* activates the module, creates bat device, starts timer ... */
void activate_module(void)
{
if (originator_init() < 1)
goto err;
if (hna_local_init() < 1)
goto err;
if (hna_global_init() < 1)
goto err;
hna_local_add(soft_device->dev_addr);
if (bat_device_setup() < 1)
goto end;
if (vis_init() < 1)
goto err;
/* (re)start kernel thread for packet processing */
if (!kthread_task) {
kthread_task = kthread_run(packet_recv_thread, NULL, "batman-adv");
if (IS_ERR(kthread_task)) {
debug_log(LOG_TYPE_CRIT, "Unable to start packet receive thread\n");
kthread_task = NULL;
}
}
update_min_mtu();
atomic_set(&module_state, MODULE_ACTIVE);
goto end;
err:
debug_log(LOG_TYPE_CRIT, "Unable to allocate memory for mesh information structures: out of mem ?\n");
shutdown_module();
end:
return;
}
/* shuts down the whole module.*/
void shutdown_module(void)
{
atomic_set(&module_state, MODULE_DEACTIVATING);
purge_outstanding_packets();
flush_workqueue(bat_event_workqueue);
vis_quit();
/* deactivate kernel thread for packet processing (if running) */
if (kthread_task) {
atomic_set(&exit_cond, 1);
wake_up_interruptible(&thread_wait);
kthread_stop(kthread_task);
kthread_task = NULL;
}
originator_free();
hna_local_free();
hna_global_free();
synchronize_net();
bat_device_destroy();
hardif_remove_interfaces();
synchronize_rcu();
atomic_set(&module_state, MODULE_INACTIVE);
}
void inc_module_count(void)
{
try_module_get(THIS_MODULE);
}
void dec_module_count(void)
{
module_put(THIS_MODULE);
}
int addr_to_string(char *buff, uint8_t *addr)
{
return sprintf(buff, "%02x:%02x:%02x:%02x:%02x:%02x",
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
}
/* returns 1 if they are the same originator */
int compare_orig(void *data1, void *data2)
{
return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
}
/* hashfunction to choose an entry in a hash table of given size */
/* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */
int choose_orig(void *data, int32_t size)
{
unsigned char *key = data;
uint32_t hash = 0;
size_t i;
for (i = 0; i < 6; i++) {
hash += key[i];
hash += (hash << 10);
hash ^= (hash >> 6);
}
hash += (hash << 3);
hash ^= (hash >> 11);
hash += (hash << 15);
return hash % size;
}
int is_my_mac(uint8_t *addr)
{
struct batman_if *batman_if;
rcu_read_lock();
list_for_each_entry_rcu(batman_if, &if_list, list) {
if ((batman_if->net_dev) &&
(compare_orig(batman_if->net_dev->dev_addr, addr))) {
rcu_read_unlock();
return 1;
}
}
rcu_read_unlock();
return 0;
}
int is_bcast(uint8_t *addr)
{
return (addr[0] == (uint8_t)0xff) && (addr[1] == (uint8_t)0xff);
}
int is_mcast(uint8_t *addr)
{
return *addr & 0x01;
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_SUPPORTED_DEVICE(DRIVER_DEVICE);
#ifdef REVISION_VERSION
MODULE_VERSION(SOURCE_VERSION "-" REVISION_VERSION);
#else
MODULE_VERSION(SOURCE_VERSION);
#endif
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
/* Kernel Programming */
#define LINUX
#define DRIVER_AUTHOR "Marek Lindner <lindner_marek@yahoo.de>, Simon Wunderlich <siwu@hrz.tu-chemnitz.de>"
#define DRIVER_DESC "B.A.T.M.A.N. advanced"
#define DRIVER_DEVICE "batman-adv"
#define SOURCE_VERSION "0.2.1-beta"
/* B.A.T.M.A.N. parameters */
#define TQ_MAX_VALUE 255
#define JITTER 20
#define TTL 50 /* Time To Live of broadcast messages */
#define MAX_ADDR 16 /* number of interfaces which can be added to
* batman. */
#define PURGE_TIMEOUT 200000 /* purge originators after time in ms if no
* valid packet comes in -> TODO: check
* influence on TQ_LOCAL_WINDOW_SIZE */
#define LOCAL_HNA_TIMEOUT 3600000
#define TQ_LOCAL_WINDOW_SIZE 64 /* sliding packet range of received originator
* messages in squence numbers (should be a
* multiple of our word size) */
#define TQ_GLOBAL_WINDOW_SIZE 5
#define TQ_LOCAL_BIDRECT_SEND_MINIMUM 1
#define TQ_LOCAL_BIDRECT_RECV_MINIMUM 1
#define TQ_TOTAL_BIDRECT_LIMIT 1
#define TQ_HOP_PENALTY 10
#define NUM_WORDS (TQ_LOCAL_WINDOW_SIZE / WORD_BIT_SIZE)
#define PACKBUFF_SIZE 2000
#define LOG_BUF_LEN 8192 /* has to be a power of 2 */
#define ETH_STR_LEN 20
#define MAX_AGGREGATION_BYTES 512 /* should not be bigger than 512 bytes or
* change the size of
* forw_packet->direct_link_flags */
#define MAX_AGGREGATION_MS 100
#define MODULE_INACTIVE 0
#define MODULE_ACTIVE 1
#define MODULE_DEACTIVATING 2
/*
* Logging
*/
#define LOG_TYPE_CRIT 0 /* highest priority for fatal errors such as
* blocked sockets / failed packet delivery /
* programming errors */
#define LOG_TYPE_WARN 1 /* warnings for small errors like wrong user
* input / damaged packets / etc */
#define LOG_TYPE_NOTICE 2 /* notice information for new interfaces /
* changed settings / new originators / etc */
#define LOG_TYPE_BATMAN 4 /* all messages related to routing / flooding /
* broadcasting / etc */
#define LOG_TYPE_ROUTES 8 /* route or hna added / changed / deleted */
#define LOG_TYPE_CRIT_NAME "critical"
#define LOG_TYPE_WARN_NAME "warnings"
#define LOG_TYPE_NOTICE_NAME "notices"
#define LOG_TYPE_BATMAN_NAME "batman"
#define LOG_TYPE_ROUTES_NAME "routes"
/*
* Vis
*/
/* #define VIS_SUBCLUSTERS_DISABLED */
/*
* Kernel headers
*/
#include <linux/mutex.h> /* mutex */
#include <linux/module.h> /* needed by all modules */
#include <linux/netdevice.h> /* netdevice */
#include <linux/if_ether.h> /* ethernet header */
#include <linux/poll.h> /* poll_table */
#include <linux/kthread.h> /* kernel threads */
#include <linux/pkt_sched.h> /* schedule types */
#include <linux/workqueue.h> /* workqueue */
#include <net/sock.h> /* struct sock */
#include <linux/jiffies.h>
#include "types.h"
#ifndef REVISION_VERSION
#define REVISION_VERSION_STR ""
#else
#define REVISION_VERSION_STR " "REVISION_VERSION
#endif
extern struct list_head if_list;
extern struct hlist_head forw_bat_list;
extern struct hlist_head forw_bcast_list;
extern struct hashtable_t *orig_hash;
extern spinlock_t orig_hash_lock;
extern spinlock_t forw_bat_list_lock;
extern spinlock_t forw_bcast_list_lock;
extern atomic_t originator_interval;
extern atomic_t vis_interval;
extern atomic_t aggregation_enabled;
extern int16_t num_hna;
extern int16_t num_ifs;
extern struct net_device *soft_device;
extern unsigned char broadcastAddr[];
extern atomic_t module_state;
extern struct workqueue_struct *bat_event_workqueue;
void activate_module(void);
void shutdown_module(void);
void inc_module_count(void);
void dec_module_count(void);
int addr_to_string(char *buff, uint8_t *addr);
int compare_orig(void *data1, void *data2);
int choose_orig(void *data, int32_t size);
int is_my_mac(uint8_t *addr);
int is_bcast(uint8_t *addr);
int is_mcast(uint8_t *addr);
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#define ETH_P_BATMAN 0x4305 /* unofficial/not registered Ethertype */
#define BAT_PACKET 0x01
#define BAT_ICMP 0x02
#define BAT_UNICAST 0x03
#define BAT_BCAST 0x04
#define BAT_VIS 0x05
/* this file is included by batctl which needs these defines */
#define COMPAT_VERSION 8
#define DIRECTLINK 0x40
#define VIS_SERVER 0x20
/* ICMP message types */
#define ECHO_REPLY 0
#define DESTINATION_UNREACHABLE 3
#define ECHO_REQUEST 8
#define TTL_EXCEEDED 11
#define PARAMETER_PROBLEM 12
/* vis defines */
#define VIS_TYPE_SERVER_SYNC 0
#define VIS_TYPE_CLIENT_UPDATE 1
struct batman_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
uint8_t flags; /* 0x40: DIRECTLINK flag, 0x20 VIS_SERVER flag... */
uint8_t tq;
uint16_t seqno;
uint8_t orig[6];
uint8_t prev_sender[6];
uint8_t ttl;
uint8_t num_hna;
} __attribute__((packed));
#define BAT_PACKET_LEN sizeof(struct batman_packet)
struct icmp_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
uint8_t msg_type; /* see ICMP message types above */
uint8_t ttl;
uint8_t dst[6];
uint8_t orig[6];
uint16_t seqno;
uint8_t uid;
} __attribute__((packed));
struct unicast_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
uint8_t dest[6];
uint8_t ttl;
} __attribute__((packed));
struct bcast_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
uint8_t orig[6];
uint16_t seqno;
} __attribute__((packed));
struct vis_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
uint8_t vis_type; /* which type of vis-participant sent this? */
uint8_t seqno; /* sequence number */
uint8_t entries; /* number of entries behind this struct */
uint8_t ttl; /* TTL */
uint8_t vis_orig[6]; /* originator that informs about its
* neighbours */
uint8_t target_orig[6]; /* who should receive this packet */
uint8_t sender_orig[6]; /* who sent or rebroadcasted this packet */
} __attribute__((packed));
此差异已折叠。
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#define PROC_ROOT_DIR "batman-adv"
#define PROC_FILE_INTERFACES "interfaces"
#define PROC_FILE_ORIG_INTERVAL "orig_interval"
#define PROC_FILE_ORIGINATORS "originators"
#define PROC_FILE_GATEWAYS "gateways"
#define PROC_FILE_LOG "log"
#define PROC_FILE_LOG_LEVEL "log_level"
#define PROC_FILE_TRANST_LOCAL "transtable_local"
#define PROC_FILE_TRANST_GLOBAL "transtable_global"
#define PROC_FILE_VIS "vis"
#define PROC_FILE_VIS_FORMAT "vis_format"
#define PROC_FILE_AGGR "aggregate_ogm"
void cleanup_procfs(void);
int setup_procfs(void);
/* While scanning for vis-entries of a particular vis-originator
* this list collects its interfaces to create a subgraph/cluster
* out of them later
*/
struct vis_if_list {
uint8_t addr[ETH_ALEN];
bool primary;
struct vis_if_list *next;
};
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#include "main.h"
#include "ring_buffer.h"
void ring_buffer_set(uint8_t lq_recv[], uint8_t *lq_index, uint8_t value)
{
lq_recv[*lq_index] = value;
*lq_index = (*lq_index + 1) % TQ_GLOBAL_WINDOW_SIZE;
}
uint8_t ring_buffer_avg(uint8_t lq_recv[])
{
uint8_t *ptr;
uint16_t count = 0, i = 0, sum = 0;
ptr = lq_recv;
while (i < TQ_GLOBAL_WINDOW_SIZE) {
if (*ptr != 0) {
count++;
sum += *ptr;
}
i++;
ptr++;
}
if (count == 0)
return 0;
return (uint8_t)(sum / count);
}
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
void ring_buffer_set(uint8_t lq_recv[], uint8_t *lq_index, uint8_t value);
uint8_t ring_buffer_avg(uint8_t lq_recv[]);
此差异已折叠。
/*
* Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#include "types.h"
extern wait_queue_head_t thread_wait;
extern atomic_t exit_cond;
int originator_init(void);
void free_orig_node(void *data);
void originator_free(void);
void slide_own_bcast_window(struct batman_if *batman_if);
void batman_data_ready(struct sock *sk, int len);
void purge_orig(struct work_struct *work);
int packet_recv_thread(void *data);
void receive_bat_packet(struct ethhdr *ethhdr, struct batman_packet *batman_packet, unsigned char *hna_buff, int hna_buff_len, struct batman_if *if_incoming);
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册