aboutsummaryrefslogtreecommitdiff
path: root/drivers/staging/batman-adv/routing.c
diff options
context:
space:
mode:
authorSimon Wunderlich <siwu@hrz.tu-chemnitz.de>2010-01-02 11:30:48 +0100
committerGreg Kroah-Hartman <gregkh@suse.de>2010-03-03 16:42:36 -0800
commite70171957a3ac67fd62af0c66efe7b7749121899 (patch)
treeec02d2965afac6384ab0fd29607c4062f93bf134 /drivers/staging/batman-adv/routing.c
parentc4bf05d3960981a4291bcc9580f3d73eb4dcbe84 (diff)
Staging: batman-adv: receive packets directly using skbs
This patch removes the (ugly and racy) packet receiving thread and the kernel socket usage. Instead, packets are received directly by registering the ethernet type and handling skbs instead of self-allocated buffers. Some consequences and comments: * we don't copy the payload data when forwarding/sending/receiving data anymore. This should boost performance. * packets from/to different interfaces can be (theoretically) processed simultaneously. Only the big originator hash lock might be in the way. * no more polling or sleeping/wakeup/scheduling issues when receiving packets * this might introduce new race conditions. * aggregation and vis code still use packet buffers and are not (yet) converted. * all spinlocks were converted to irqsave/restore versions to solve some lifelock issues when preempted. This might be overkill, some of these locks might be reverted later. * skb copies are only done if neccesary to avoid overhead performance differences: * we made some "benchmarks" with intel laptops. * bandwidth on Gigabit Ethernet increased from ~500 MBit/s to ~920 MBit/s * ping latency decresed from ~2ms to ~0.2 ms I did some tests on my 9 node qemu environment and could confirm that usual sending/receiving, forwarding, vis, batctl ping etc works. Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de> Acked-by: Sven Eckelmann <sven.eckelmann@gmx.de> Acked-by: Marek Lindner <lindner_marek@yahoo.de> Acked-by: Linus Lüssing <linus.luessing@web.de> Signed-off-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/batman-adv/routing.c')
-rw-r--r--drivers/staging/batman-adv/routing.c563
1 files changed, 244 insertions, 319 deletions
diff --git a/drivers/staging/batman-adv/routing.c b/drivers/staging/batman-adv/routing.c
index f8464cad30b..e0d093f5d52 100644
--- a/drivers/staging/batman-adv/routing.c
+++ b/drivers/staging/batman-adv/routing.c
@@ -36,15 +36,16 @@
DECLARE_WAIT_QUEUE_HEAD(thread_wait);
-static atomic_t data_ready_cond;
atomic_t exit_cond;
+
void slide_own_bcast_window(struct batman_if *batman_if)
{
HASHIT(hashit);
struct orig_node *orig_node;
TYPE_OF_WORD *word;
+ unsigned long flags;
- spin_lock(&orig_hash_lock);
+ spin_lock_irqsave(&orig_hash_lock, flags);
while (hash_iterate(orig_hash, &hashit)) {
orig_node = hashit.bucket->data;
@@ -55,7 +56,7 @@ void slide_own_bcast_window(struct batman_if *batman_if)
bit_packet_count(word);
}
- spin_unlock(&orig_hash_lock);
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
}
static void update_HNA(struct orig_node *orig_node,
@@ -365,10 +366,9 @@ static char count_real_packets(struct ethhdr *ethhdr,
}
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)
+ struct batman_packet *batman_packet,
+ unsigned char *hna_buff, int hna_buff_len,
+ struct batman_if *if_incoming)
{
struct batman_if *batman_if;
struct orig_node *orig_neigh_node, *orig_node;
@@ -566,95 +566,118 @@ void receive_bat_packet(struct ethhdr *ethhdr,
0, hna_buff_len, if_incoming);
}
-
-static int receive_raw_packet(struct socket *raw_sock,
- unsigned char *packet_buff, int packet_buff_len)
+int recv_bat_packet(struct sk_buff *skb,
+ struct batman_if *batman_if)
{
- struct kvec iov;
- struct msghdr msg;
+ struct ethhdr *ethhdr;
+ unsigned long flags;
- iov.iov_base = packet_buff;
- iov.iov_len = packet_buff_len;
+ /* drop packet if it has not necessary minimum size */
+ if (skb_headlen(skb) < sizeof(struct batman_packet))
+ return NET_RX_DROP;
- msg.msg_flags = MSG_DONTWAIT; /* non-blocking */
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
- msg.msg_control = NULL;
+ ethhdr = (struct ethhdr *)skb_mac_header(skb);
- return kernel_recvmsg(raw_sock, &msg, &iov, 1, packet_buff_len,
- MSG_DONTWAIT);
-}
-
-static void recv_bat_packet(struct ethhdr *ethhdr,
- unsigned char *packet_buff,
- int result,
- struct batman_if *batman_if)
-{
/* packet with broadcast indication but unicast recipient */
if (!is_bcast(ethhdr->h_dest))
- return;
+ return NET_RX_DROP;
/* packet with broadcast sender address */
if (is_bcast(ethhdr->h_source))
- return;
-
- /* drop packet if it has not at least one batman packet as payload */
- if (result < sizeof(struct ethhdr) + sizeof(struct batman_packet))
- return;
-
- spin_lock(&orig_hash_lock);
+ return NET_RX_DROP;
+
+ spin_lock_irqsave(&orig_hash_lock, flags);
+ /* TODO: we use headlen instead of "length", because
+ * only this data is paged in. */
+ /* TODO: is another skb_copy needed here? there will be
+ * written on the data, but nobody (?) should further use
+ * this data */
receive_aggr_bat_packet(ethhdr,
- packet_buff + sizeof(struct ethhdr),
- result - sizeof(struct ethhdr),
+ skb->data,
+ skb_headlen(skb),
batman_if);
- spin_unlock(&orig_hash_lock);
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
+
+ kfree_skb(skb);
+ return NET_RX_SUCCESS;
}
-static void recv_my_icmp_packet(struct ethhdr *ethhdr,
- struct icmp_packet *icmp_packet,
- unsigned char *packet_buff,
- int result)
+static int recv_my_icmp_packet(struct sk_buff *skb)
{
struct orig_node *orig_node;
+ struct icmp_packet *icmp_packet;
+ struct ethhdr *ethhdr;
+ struct sk_buff *skb_old;
+ struct batman_if *batman_if;
+ int ret;
+ unsigned long flags;
+ uint8_t dstaddr[ETH_ALEN];
+
+ icmp_packet = (struct icmp_packet *) skb->data;
+ ethhdr = (struct ethhdr *) skb_mac_header(skb);
/* add data to device queue */
if (icmp_packet->msg_type != ECHO_REQUEST) {
bat_device_receive_packet(icmp_packet);
- return;
+ return NET_RX_DROP;
}
/* answer echo request (ping) */
/* get routing information */
- spin_lock(&orig_hash_lock);
+ spin_lock_irqsave(&orig_hash_lock, flags);
orig_node = ((struct orig_node *)hash_find(orig_hash,
icmp_packet->orig));
+ ret = NET_RX_DROP;
if ((orig_node != NULL) &&
(orig_node->batman_if != NULL) &&
(orig_node->router != NULL)) {
+
+ /* don't lock while sending the packets ... we therefore
+ * copy the required data before sending */
+ batman_if = orig_node->batman_if;
+ memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
+
+ /* create a copy of the skb, if needed, to modify it. */
+ skb_old = NULL;
+ if (!skb_clone_writable(skb, sizeof(struct icmp_packet))) {
+ skb_old = skb;
+ skb = skb_copy(skb, GFP_ATOMIC);
+ if (!skb)
+ return NET_RX_DROP;
+ icmp_packet = (struct icmp_packet *) skb->data;
+ kfree_skb(skb_old);
+ }
+
memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN);
memcpy(icmp_packet->orig, ethhdr->h_dest, ETH_ALEN);
icmp_packet->msg_type = ECHO_REPLY;
icmp_packet->ttl = TTL;
- send_raw_packet(packet_buff + sizeof(struct ethhdr),
- result - sizeof(struct ethhdr),
- orig_node->batman_if,
- orig_node->router->addr);
- }
+ send_skb_packet(skb, batman_if, dstaddr);
+ ret = NET_RX_SUCCESS;
- spin_unlock(&orig_hash_lock);
- return;
+ } else
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
+
+ return ret;
}
-static void recv_icmp_ttl_exceeded(struct icmp_packet *icmp_packet,
- struct ethhdr *ethhdr,
- unsigned char *packet_buff,
- int result,
- struct batman_if *batman_if)
+static int recv_icmp_ttl_exceeded(struct sk_buff *skb)
{
unsigned char src_str[ETH_STR_LEN], dst_str[ETH_STR_LEN];
struct orig_node *orig_node;
+ struct icmp_packet *icmp_packet;
+ struct ethhdr *ethhdr;
+ struct sk_buff *skb_old;
+ struct batman_if *batman_if;
+ int ret;
+ unsigned long flags;
+ uint8_t dstaddr[ETH_ALEN];
+
+ icmp_packet = (struct icmp_packet *) skb->data;
+ ethhdr = (struct ethhdr *) skb_mac_header(skb);
addr_to_string(src_str, icmp_packet->orig);
addr_to_string(dst_str, icmp_packet->dst);
@@ -663,74 +686,93 @@ static void recv_icmp_ttl_exceeded(struct icmp_packet *icmp_packet,
/* send TTL exceeded if packet is an echo request (traceroute) */
if (icmp_packet->msg_type != ECHO_REQUEST)
- return;
+ return NET_RX_DROP;
/* get routing information */
- spin_lock(&orig_hash_lock);
+ spin_lock_irqsave(&orig_hash_lock, flags);
orig_node = ((struct orig_node *)
hash_find(orig_hash, icmp_packet->orig));
+ ret = NET_RX_DROP;
if ((orig_node != NULL) &&
(orig_node->batman_if != NULL) &&
(orig_node->router != NULL)) {
+
+ /* don't lock while sending the packets ... we therefore
+ * copy the required data before sending */
+ batman_if = orig_node->batman_if;
+ memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
+
+ /* create a copy of the skb, if needed, to modify it. */
+ if (!skb_clone_writable(skb, sizeof(struct icmp_packet))) {
+ skb_old = skb;
+ skb = skb_copy(skb, GFP_ATOMIC);
+ if (!skb)
+ return NET_RX_DROP;
+ icmp_packet = (struct icmp_packet *) skb->data;
+ kfree_skb(skb_old);
+ }
+
memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN);
memcpy(icmp_packet->orig, ethhdr->h_dest, ETH_ALEN);
icmp_packet->msg_type = TTL_EXCEEDED;
icmp_packet->ttl = TTL;
- send_raw_packet(packet_buff + sizeof(struct ethhdr),
- result - sizeof(struct ethhdr),
- orig_node->batman_if,
- orig_node->router->addr);
+ send_skb_packet(skb, batman_if, dstaddr);
+ ret = NET_RX_SUCCESS;
- }
+ } else
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
- spin_unlock(&orig_hash_lock);
+ return ret;
}
-
-static void recv_icmp_packet(struct ethhdr *ethhdr,
- unsigned char *packet_buff,
- int result,
- struct batman_if *batman_if)
+int recv_icmp_packet(struct sk_buff *skb)
{
struct icmp_packet *icmp_packet;
+ struct ethhdr *ethhdr;
struct orig_node *orig_node;
+ struct sk_buff *skb_old;
+ struct batman_if *batman_if;
+ int hdr_size = sizeof(struct icmp_packet);
+ int ret;
+ unsigned long flags;
+ uint8_t dstaddr[ETH_ALEN];
+
+ /* drop packet if it has not necessary minimum size */
+ if (skb_headlen(skb) < hdr_size)
+ return NET_RX_DROP;
+
+ ethhdr = (struct ethhdr *)skb_mac_header(skb);
/* packet with unicast indication but broadcast recipient */
if (is_bcast(ethhdr->h_dest))
- return;
+ return NET_RX_DROP;
/* packet with broadcast sender address */
if (is_bcast(ethhdr->h_source))
- return;
+ return NET_RX_DROP;
/* not for me */
if (!is_my_mac(ethhdr->h_dest))
- return;
+ return NET_RX_DROP;
- /* drop packet if it has not necessary minimum size */
- if (result < sizeof(struct ethhdr) + sizeof(struct icmp_packet))
- return;
-
- icmp_packet = (struct icmp_packet *)
- (packet_buff + sizeof(struct ethhdr));
+ icmp_packet = (struct icmp_packet *) skb->data;
/* packet for me */
if (is_my_mac(icmp_packet->dst))
- recv_my_icmp_packet(ethhdr, icmp_packet, packet_buff, result);
+ return recv_my_icmp_packet(skb);
/* TTL exceeded */
- if (icmp_packet->ttl < 2) {
- recv_icmp_ttl_exceeded(icmp_packet, ethhdr, packet_buff, result,
- batman_if);
- return;
+ if (icmp_packet->ttl < 2)
+ return recv_icmp_ttl_exceeded(skb);
- }
+ ret = NET_RX_DROP;
/* get routing information */
- spin_lock(&orig_hash_lock);
+ spin_lock_irqsave(&orig_hash_lock, flags);
orig_node = ((struct orig_node *)
hash_find(orig_hash, icmp_packet->dst));
@@ -738,133 +780,169 @@ static void recv_icmp_packet(struct ethhdr *ethhdr,
(orig_node->batman_if != NULL) &&
(orig_node->router != NULL)) {
+ /* don't lock while sending the packets ... we therefore
+ * copy the required data before sending */
+ batman_if = orig_node->batman_if;
+ memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
+
+ /* create a copy of the skb, if needed, to modify it. */
+ if (!skb_clone_writable(skb, sizeof(struct icmp_packet))) {
+ skb_old = skb;
+ skb = skb_copy(skb, GFP_ATOMIC);
+ if (!skb)
+ return NET_RX_DROP;
+ icmp_packet = (struct icmp_packet *) skb->data;
+ kfree_skb(skb_old);
+ }
+
/* decrement ttl */
icmp_packet->ttl--;
/* route it */
- send_raw_packet(packet_buff + sizeof(struct ethhdr),
- result - sizeof(struct ethhdr),
- orig_node->batman_if,
- orig_node->router->addr);
- }
- spin_unlock(&orig_hash_lock);
+ send_skb_packet(skb, batman_if, dstaddr);
+ ret = NET_RX_SUCCESS;
+
+ } else
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
+
+ return ret;
}
-static void recv_unicast_packet(struct ethhdr *ethhdr,
- unsigned char *packet_buff,
- int result,
- struct batman_if *batman_if)
+int recv_unicast_packet(struct sk_buff *skb)
{
struct unicast_packet *unicast_packet;
unsigned char src_str[ETH_STR_LEN], dst_str[ETH_STR_LEN];
struct orig_node *orig_node;
- int hdr_size = sizeof(struct ethhdr) + sizeof(struct unicast_packet);
+ struct ethhdr *ethhdr;
+ struct batman_if *batman_if;
+ struct sk_buff *skb_old;
+ uint8_t dstaddr[ETH_ALEN];
+ int hdr_size = sizeof(struct unicast_packet);
+ int ret;
+ unsigned long flags;
+
+ /* drop packet if it has not necessary minimum size */
+ if (skb_headlen(skb) < hdr_size)
+ return NET_RX_DROP;
+
+ ethhdr = (struct ethhdr *) skb_mac_header(skb);
/* packet with unicast indication but broadcast recipient */
if (is_bcast(ethhdr->h_dest))
- return;
+ return NET_RX_DROP;
/* packet with broadcast sender address */
if (is_bcast(ethhdr->h_source))
- return;
+ return NET_RX_DROP;
/* not for me */
if (!is_my_mac(ethhdr->h_dest))
- return;
-
- /* drop packet if it has not necessary minimum size */
- if (result < hdr_size)
- return;
+ return NET_RX_DROP;
- unicast_packet = (struct unicast_packet *)
- (packet_buff + sizeof(struct ethhdr));
+ unicast_packet = (struct unicast_packet *) skb->data;
/* packet for me */
if (is_my_mac(unicast_packet->dest)) {
- interface_rx(soft_device, packet_buff + hdr_size,
- result - hdr_size);
- return;
-
+ interface_rx(skb, hdr_size);
+ return NET_RX_SUCCESS;
}
/* TTL exceeded */
if (unicast_packet->ttl < 2) {
- addr_to_string(src_str, ((struct ethhdr *)
- (unicast_packet + 1))->h_source);
- addr_to_string(dst_str, unicast_packet->dest);
+ addr_to_string(src_str, ethhdr->h_source);
+ addr_to_string(dst_str, ethhdr->h_dest);
printk(KERN_WARNING "batman-adv:Warning - can't send packet from %s to %s: ttl exceeded\n", src_str, dst_str);
- return;
+ return NET_RX_DROP;
}
+ ret = NET_RX_DROP;
/* get routing information */
- spin_lock(&orig_hash_lock);
+ spin_lock_irqsave(&orig_hash_lock, flags);
orig_node = ((struct orig_node *)
hash_find(orig_hash, unicast_packet->dest));
if ((orig_node != NULL) &&
(orig_node->batman_if != NULL) &&
(orig_node->router != NULL)) {
+
+ /* don't lock while sending the packets ... we therefore
+ * copy the required data before sending */
+ batman_if = orig_node->batman_if;
+ memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
+
+ /* create a copy of the skb, if needed, to modify it. */
+ if (!skb_clone_writable(skb, sizeof(struct unicast_packet))) {
+ skb_old = skb;
+ skb = skb_copy(skb, GFP_ATOMIC);
+ if (!skb)
+ return NET_RX_DROP;
+ unicast_packet = (struct unicast_packet *) skb->data;
+ kfree_skb(skb_old);
+ }
/* decrement ttl */
unicast_packet->ttl--;
/* route it */
- send_raw_packet(packet_buff + sizeof(struct ethhdr),
- result - sizeof(struct ethhdr),
- orig_node->batman_if,
- orig_node->router->addr);
- }
- spin_unlock(&orig_hash_lock);
+ send_skb_packet(skb, batman_if, dstaddr);
+ ret = NET_RX_SUCCESS;
+
+ } else
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
+
+ return ret;
}
-static void recv_bcast_packet(struct ethhdr *ethhdr,
- unsigned char *packet_buff,
- int result,
- struct batman_if *batman_if)
+int recv_bcast_packet(struct sk_buff *skb)
{
struct orig_node *orig_node;
struct bcast_packet *bcast_packet;
- int hdr_size = sizeof(struct ethhdr) + sizeof(struct bcast_packet);
+ struct ethhdr *ethhdr;
+ int hdr_size = sizeof(struct bcast_packet);
+ unsigned long flags;
+
+ /* drop packet if it has not necessary minimum size */
+ if (skb_headlen(skb) < hdr_size)
+ return NET_RX_DROP;
+
+ ethhdr = (struct ethhdr *)skb_mac_header(skb);
/* packet with broadcast indication but unicast recipient */
if (!is_bcast(ethhdr->h_dest))
- return;
+ return NET_RX_DROP;
/* packet with broadcast sender address */
if (is_bcast(ethhdr->h_source))
- return;
-
- /* drop packet if it has not necessary minimum size */
- if (result < hdr_size)
- return;
+ return NET_RX_DROP;
/* ignore broadcasts sent by myself */
if (is_my_mac(ethhdr->h_source))
- return;
+ return NET_RX_DROP;
- bcast_packet = (struct bcast_packet *)
- (packet_buff + sizeof(struct ethhdr));
+ bcast_packet = (struct bcast_packet *) skb->data;
/* ignore broadcasts originated by myself */
if (is_my_mac(bcast_packet->orig))
- return;
+ return NET_RX_DROP;
- spin_lock(&orig_hash_lock);
+ spin_lock_irqsave(&orig_hash_lock, flags);
orig_node = ((struct orig_node *)
hash_find(orig_hash, bcast_packet->orig));
if (orig_node == NULL) {
- spin_unlock(&orig_hash_lock);
- return;
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
+ return NET_RX_DROP;
}
/* check flood history */
if (get_bit_status(orig_node->bcast_bits,
orig_node->last_bcast_seqno,
ntohs(bcast_packet->seqno))) {
- spin_unlock(&orig_hash_lock);
- return;
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
+ return NET_RX_DROP;
}
/* mark broadcast in flood history */
@@ -873,211 +951,58 @@ static void recv_bcast_packet(struct ethhdr *ethhdr,
orig_node->last_bcast_seqno, 1))
orig_node->last_bcast_seqno = ntohs(bcast_packet->seqno);
- spin_unlock(&orig_hash_lock);
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
+
+ /* rebroadcast packet */
+ add_bcast_packet_to_list(skb);
/* broadcast for me */
- interface_rx(soft_device, packet_buff + hdr_size, result - hdr_size);
+ interface_rx(skb, hdr_size);
- /* rebroadcast packet */
- add_bcast_packet_to_list(packet_buff + sizeof(struct ethhdr),
- result - sizeof(struct ethhdr));
+ return NET_RX_SUCCESS;
}
-static void recv_vis_packet(struct ethhdr *ethhdr,
- unsigned char *packet_buff,
- int result)
+int recv_vis_packet(struct sk_buff *skb)
{
struct vis_packet *vis_packet;
- int hdr_size = sizeof(struct ethhdr) + sizeof(struct vis_packet);
- int vis_info_len;
+ struct ethhdr *ethhdr;
+ int hdr_size = sizeof(struct vis_packet);
+ int ret;
- /* drop if too short. */
- if (result < hdr_size)
- return;
+ if (skb_headlen(skb) < hdr_size)
+ return NET_RX_DROP;
+
+ vis_packet = (struct vis_packet *) skb->data;
+ ethhdr = (struct ethhdr *)skb_mac_header(skb);
/* not for me */
if (!is_my_mac(ethhdr->h_dest))
- return;
-
- vis_packet = (struct vis_packet *)(packet_buff + sizeof(struct ethhdr));
- vis_info_len = result - hdr_size;
+ return NET_RX_DROP;
/* ignore own packets */
if (is_my_mac(vis_packet->vis_orig))
- return;
+ return NET_RX_DROP;
if (is_my_mac(vis_packet->sender_orig))
- return;
+ return NET_RX_DROP;
switch (vis_packet->vis_type) {
case VIS_TYPE_SERVER_SYNC:
- receive_server_sync_packet(vis_packet, vis_info_len);
+ /* TODO: handle fragmented skbs properly */
+ receive_server_sync_packet(vis_packet, skb_headlen(skb));
+ ret = NET_RX_SUCCESS;
break;
case VIS_TYPE_CLIENT_UPDATE:
- receive_client_update_packet(vis_packet, vis_info_len);
+ /* TODO: handle fragmented skbs properly */
+ receive_client_update_packet(vis_packet, skb_headlen(skb));
+ ret = NET_RX_SUCCESS;
break;
default: /* ignore unknown packet */
+ ret = NET_RX_DROP;
break;
}
-}
-
-static int recv_one_packet(struct batman_if *batman_if,
- unsigned char *packet_buff)
-{
- int result;
- struct ethhdr *ethhdr;
- struct batman_packet *batman_packet;
-
- result = receive_raw_packet(batman_if->raw_sock, packet_buff,
- PACKBUFF_SIZE);
- if (result <= 0)
- return result;
-
- if (result < sizeof(struct ethhdr) + 2)
- return 0;
-
- ethhdr = (struct ethhdr *)packet_buff;
- batman_packet = (struct batman_packet *)
- (packet_buff + sizeof(struct ethhdr));
-
- if (batman_packet->version != COMPAT_VERSION) {
- bat_dbg(DBG_BATMAN,
- "Drop packet: incompatible batman version (%i)\n",
- batman_packet->version);
- return 0;
- }
-
- switch (batman_packet->packet_type) {
- /* batman originator packet */
- case BAT_PACKET:
- recv_bat_packet(ethhdr, packet_buff, result, batman_if);
- break;
-
- /* batman icmp packet */
- case BAT_ICMP:
- recv_icmp_packet(ethhdr, packet_buff, result, batman_if);
- break;
-
- /* unicast packet */
- case BAT_UNICAST:
- recv_unicast_packet(ethhdr, packet_buff, result, batman_if);
- break;
-
- /* broadcast packet */
- case BAT_BCAST:
- recv_bcast_packet(ethhdr,
- packet_buff, result, batman_if);
- break;
-
- /* vis packet */
- case BAT_VIS:
- recv_vis_packet(ethhdr, packet_buff, result);
- break;
- }
- return 0;
-}
-
-
-static int discard_one_packet(struct batman_if *batman_if,
- unsigned char *packet_buff)
-{
- int result = -EAGAIN;
-
- if (batman_if->raw_sock) {
- result = receive_raw_packet(batman_if->raw_sock,
- packet_buff,
- PACKBUFF_SIZE);
- }
- return result;
-}
-
-
-static bool is_interface_active(struct batman_if *batman_if)
-{
- if (batman_if->if_active != IF_ACTIVE)
- return false;
-
- return true;
-}
-
-static void service_interface(struct batman_if *batman_if,
- unsigned char *packet_buff)
-
-{
- int result;
-
- do {
- if (is_interface_active(batman_if))
- result = recv_one_packet(batman_if, packet_buff);
- else
- result = discard_one_packet(batman_if, packet_buff);
- } while (result >= 0);
-
- /* we perform none blocking reads, so EAGAIN indicates there
- are no more packets to read. Anything else is a real
- error.*/
-
- if ((result < 0) && (result != -EAGAIN))
- printk(KERN_ERR "batman-adv:Could not receive packet from interface %s: %i\n", batman_if->dev, result);
-}
-
-static void service_interfaces(unsigned char *packet_buffer)
-{
- struct batman_if *batman_if;
- rcu_read_lock();
- list_for_each_entry_rcu(batman_if, &if_list, list) {
- rcu_read_unlock();
- service_interface(batman_if, packet_buffer);
- rcu_read_lock();
- }
- rcu_read_unlock();
-}
-
-
-int packet_recv_thread(void *data)
-{
- unsigned char *packet_buff;
-
- atomic_set(&data_ready_cond, 0);
- atomic_set(&exit_cond, 0);
- packet_buff = kmalloc(PACKBUFF_SIZE, GFP_KERNEL);
- if (!packet_buff) {
- printk(KERN_ERR"batman-adv:Could allocate memory for the packet buffer. :(\n");
- return -1;
- }
-
- while ((!kthread_should_stop()) && (!atomic_read(&exit_cond))) {
-
- wait_event_interruptible(thread_wait,
- (atomic_read(&data_ready_cond) ||
- atomic_read(&exit_cond)));
-
- atomic_set(&data_ready_cond, 0);
-
- if (kthread_should_stop() || atomic_read(&exit_cond))
- break;
-
- service_interfaces(packet_buff);
- }
- kfree(packet_buff);
-
- /* do not exit until kthread_stop() is actually called,
- * otherwise it will wait for us forever. */
- while (!kthread_should_stop())
- schedule();
-
- return 0;
-}
-
-void batman_data_ready(struct sock *sk, int len)
-{
- void (*data_ready)(struct sock *, int) = sk->sk_user_data;
-
- data_ready(sk, len);
-
- atomic_set(&data_ready_cond, 1);
- wake_up_interruptible(&thread_wait);
+ return ret;
}