Staging: batman-adv: receive packets directly using skbs
[firefly-linux-kernel-4.4.55.git] / drivers / staging / batman-adv / routing.c
index f8464cad30b7ce711ad939e9c1d5f00ce8dd5a86..e0d093f5d52443810ef616a7548e8f11982147af 100644 (file)
 
 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;
 }