aboutsummaryrefslogtreecommitdiff
path: root/drivers/staging/batman-adv/routing.c
diff options
context:
space:
mode:
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;
}