2017-11-19 21:05:11 +07:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2017-01-01 06:00:00 +07:00
|
|
|
/* Copyright (C) 2007-2017 B.A.T.M.A.N. contributors:
|
2010-12-13 18:19:28 +07:00
|
|
|
*
|
|
|
|
* 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
|
2013-11-04 02:40:48 +07:00
|
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
2010-12-13 18:19:28 +07:00
|
|
|
*/
|
|
|
|
|
2015-04-18 00:40:28 +07:00
|
|
|
#include "icmp_socket.h"
|
2010-12-13 18:19:28 +07:00
|
|
|
#include "main.h"
|
2015-04-18 00:40:28 +07:00
|
|
|
|
|
|
|
#include <linux/atomic.h>
|
|
|
|
#include <linux/compiler.h>
|
2010-12-13 18:19:28 +07:00
|
|
|
#include <linux/debugfs.h>
|
2015-04-18 00:40:28 +07:00
|
|
|
#include <linux/errno.h>
|
|
|
|
#include <linux/etherdevice.h>
|
|
|
|
#include <linux/export.h>
|
|
|
|
#include <linux/fcntl.h>
|
|
|
|
#include <linux/fs.h>
|
|
|
|
#include <linux/if_ether.h>
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/list.h>
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/netdevice.h>
|
|
|
|
#include <linux/pkt_sched.h>
|
|
|
|
#include <linux/poll.h>
|
|
|
|
#include <linux/printk.h>
|
|
|
|
#include <linux/sched.h> /* for linux/wait.h */
|
|
|
|
#include <linux/skbuff.h>
|
2010-12-13 18:19:28 +07:00
|
|
|
#include <linux/slab.h>
|
2015-04-18 00:40:28 +07:00
|
|
|
#include <linux/spinlock.h>
|
|
|
|
#include <linux/stddef.h>
|
|
|
|
#include <linux/string.h>
|
|
|
|
#include <linux/uaccess.h>
|
|
|
|
#include <linux/wait.h>
|
|
|
|
|
2010-12-13 18:19:28 +07:00
|
|
|
#include "hard-interface.h"
|
2016-05-16 04:48:31 +07:00
|
|
|
#include "log.h"
|
2015-04-18 00:40:28 +07:00
|
|
|
#include "originator.h"
|
|
|
|
#include "packet.h"
|
|
|
|
#include "send.h"
|
2010-12-13 18:19:28 +07:00
|
|
|
|
2012-06-06 03:31:31 +07:00
|
|
|
static struct batadv_socket_client *batadv_socket_client_hash[256];
|
2010-12-13 18:19:28 +07:00
|
|
|
|
2012-06-06 03:31:31 +07:00
|
|
|
static void batadv_socket_add_packet(struct batadv_socket_client *socket_client,
|
2013-10-23 03:50:09 +07:00
|
|
|
struct batadv_icmp_header *icmph,
|
2012-05-12 23:33:59 +07:00
|
|
|
size_t icmp_len);
|
2010-12-13 18:19:28 +07:00
|
|
|
|
2012-05-12 07:09:33 +07:00
|
|
|
void batadv_socket_init(void)
|
2010-12-13 18:19:28 +07:00
|
|
|
{
|
2012-05-12 23:33:59 +07:00
|
|
|
memset(batadv_socket_client_hash, 0, sizeof(batadv_socket_client_hash));
|
2010-12-13 18:19:28 +07:00
|
|
|
}
|
|
|
|
|
2012-05-12 23:33:59 +07:00
|
|
|
static int batadv_socket_open(struct inode *inode, struct file *file)
|
2010-12-13 18:19:28 +07:00
|
|
|
{
|
|
|
|
unsigned int i;
|
2012-06-06 03:31:31 +07:00
|
|
|
struct batadv_socket_client *socket_client;
|
2010-12-13 18:19:28 +07:00
|
|
|
|
2012-08-21 04:37:26 +07:00
|
|
|
if (!try_module_get(THIS_MODULE))
|
|
|
|
return -EBUSY;
|
|
|
|
|
2010-12-13 18:19:28 +07:00
|
|
|
nonseekable_open(inode, file);
|
|
|
|
|
2011-05-15 04:14:54 +07:00
|
|
|
socket_client = kmalloc(sizeof(*socket_client), GFP_KERNEL);
|
2012-08-21 04:37:26 +07:00
|
|
|
if (!socket_client) {
|
|
|
|
module_put(THIS_MODULE);
|
2010-12-13 18:19:28 +07:00
|
|
|
return -ENOMEM;
|
2012-08-21 04:37:26 +07:00
|
|
|
}
|
2010-12-13 18:19:28 +07:00
|
|
|
|
2012-05-12 23:33:59 +07:00
|
|
|
for (i = 0; i < ARRAY_SIZE(batadv_socket_client_hash); i++) {
|
|
|
|
if (!batadv_socket_client_hash[i]) {
|
|
|
|
batadv_socket_client_hash[i] = socket_client;
|
2010-12-13 18:19:28 +07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-12 23:33:59 +07:00
|
|
|
if (i == ARRAY_SIZE(batadv_socket_client_hash)) {
|
2012-03-07 15:07:45 +07:00
|
|
|
pr_err("Error - can't add another packet client: maximum number of clients reached\n");
|
2010-12-13 18:19:28 +07:00
|
|
|
kfree(socket_client);
|
2012-08-21 04:37:26 +07:00
|
|
|
module_put(THIS_MODULE);
|
2010-12-13 18:19:28 +07:00
|
|
|
return -EXFULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
INIT_LIST_HEAD(&socket_client->queue_list);
|
|
|
|
socket_client->queue_len = 0;
|
|
|
|
socket_client->index = i;
|
|
|
|
socket_client->bat_priv = inode->i_private;
|
|
|
|
spin_lock_init(&socket_client->lock);
|
|
|
|
init_waitqueue_head(&socket_client->queue_wait);
|
|
|
|
|
|
|
|
file->private_data = socket_client;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-05-12 23:33:59 +07:00
|
|
|
static int batadv_socket_release(struct inode *inode, struct file *file)
|
2010-12-13 18:19:28 +07:00
|
|
|
{
|
2015-12-18 22:33:31 +07:00
|
|
|
struct batadv_socket_client *client = file->private_data;
|
|
|
|
struct batadv_socket_packet *packet, *tmp;
|
2010-12-13 18:19:28 +07:00
|
|
|
|
2015-12-18 22:33:31 +07:00
|
|
|
spin_lock_bh(&client->lock);
|
2010-12-13 18:19:28 +07:00
|
|
|
|
|
|
|
/* for all packets in the queue ... */
|
2015-12-18 22:33:31 +07:00
|
|
|
list_for_each_entry_safe(packet, tmp, &client->queue_list, list) {
|
|
|
|
list_del(&packet->list);
|
|
|
|
kfree(packet);
|
2010-12-13 18:19:28 +07:00
|
|
|
}
|
|
|
|
|
2015-12-18 22:33:31 +07:00
|
|
|
batadv_socket_client_hash[client->index] = NULL;
|
|
|
|
spin_unlock_bh(&client->lock);
|
2010-12-13 18:19:28 +07:00
|
|
|
|
2015-12-18 22:33:31 +07:00
|
|
|
kfree(client);
|
2012-08-21 04:37:26 +07:00
|
|
|
module_put(THIS_MODULE);
|
2010-12-13 18:19:28 +07:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-05-12 23:33:59 +07:00
|
|
|
static ssize_t batadv_socket_read(struct file *file, char __user *buf,
|
|
|
|
size_t count, loff_t *ppos)
|
2010-12-13 18:19:28 +07:00
|
|
|
{
|
2012-06-06 03:31:31 +07:00
|
|
|
struct batadv_socket_client *socket_client = file->private_data;
|
|
|
|
struct batadv_socket_packet *socket_packet;
|
2010-12-13 18:19:28 +07:00
|
|
|
size_t packet_len;
|
|
|
|
int error;
|
|
|
|
|
2017-08-24 02:52:13 +07:00
|
|
|
if ((file->f_flags & O_NONBLOCK) && socket_client->queue_len == 0)
|
2010-12-13 18:19:28 +07:00
|
|
|
return -EAGAIN;
|
|
|
|
|
2017-08-24 02:52:13 +07:00
|
|
|
if (!buf || count < sizeof(struct batadv_icmp_packet))
|
2010-12-13 18:19:28 +07:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (!access_ok(VERIFY_WRITE, buf, count))
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
error = wait_event_interruptible(socket_client->queue_wait,
|
|
|
|
socket_client->queue_len);
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
return error;
|
|
|
|
|
|
|
|
spin_lock_bh(&socket_client->lock);
|
|
|
|
|
|
|
|
socket_packet = list_first_entry(&socket_client->queue_list,
|
2012-06-06 03:31:31 +07:00
|
|
|
struct batadv_socket_packet, list);
|
2010-12-13 18:19:28 +07:00
|
|
|
list_del(&socket_packet->list);
|
|
|
|
socket_client->queue_len--;
|
|
|
|
|
|
|
|
spin_unlock_bh(&socket_client->lock);
|
|
|
|
|
2011-12-10 21:28:36 +07:00
|
|
|
packet_len = min(count, socket_packet->icmp_len);
|
|
|
|
error = copy_to_user(buf, &socket_packet->icmp_packet, packet_len);
|
2010-12-13 18:19:28 +07:00
|
|
|
|
|
|
|
kfree(socket_packet);
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
return packet_len;
|
|
|
|
}
|
|
|
|
|
2012-05-12 23:33:59 +07:00
|
|
|
static ssize_t batadv_socket_write(struct file *file, const char __user *buff,
|
|
|
|
size_t len, loff_t *off)
|
2010-12-13 18:19:28 +07:00
|
|
|
{
|
2012-06-06 03:31:31 +07:00
|
|
|
struct batadv_socket_client *socket_client = file->private_data;
|
|
|
|
struct batadv_priv *bat_priv = socket_client->bat_priv;
|
|
|
|
struct batadv_hard_iface *primary_if = NULL;
|
2010-12-13 18:19:28 +07:00
|
|
|
struct sk_buff *skb;
|
2013-10-23 03:50:09 +07:00
|
|
|
struct batadv_icmp_packet_rr *icmp_packet_rr;
|
|
|
|
struct batadv_icmp_header *icmp_header;
|
2012-06-06 03:31:31 +07:00
|
|
|
struct batadv_orig_node *orig_node = NULL;
|
|
|
|
struct batadv_neigh_node *neigh_node = NULL;
|
2012-06-06 03:31:30 +07:00
|
|
|
size_t packet_len = sizeof(struct batadv_icmp_packet);
|
2015-05-26 23:34:26 +07:00
|
|
|
u8 *addr;
|
2010-12-13 18:19:28 +07:00
|
|
|
|
2013-10-23 03:50:09 +07:00
|
|
|
if (len < sizeof(struct batadv_icmp_header)) {
|
2012-06-04 03:19:22 +07:00
|
|
|
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
|
2012-05-12 18:48:58 +07:00
|
|
|
"Error - can't send packet from char device: invalid packet size\n");
|
2010-12-13 18:19:28 +07:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2012-05-12 18:48:54 +07:00
|
|
|
primary_if = batadv_primary_if_get_selected(bat_priv);
|
2011-04-20 20:40:58 +07:00
|
|
|
|
|
|
|
if (!primary_if) {
|
|
|
|
len = -EFAULT;
|
|
|
|
goto out;
|
|
|
|
}
|
2010-12-13 18:19:28 +07:00
|
|
|
|
2013-10-23 03:50:09 +07:00
|
|
|
if (len >= BATADV_ICMP_MAX_PACKET_SIZE)
|
|
|
|
packet_len = BATADV_ICMP_MAX_PACKET_SIZE;
|
|
|
|
else
|
|
|
|
packet_len = len;
|
2010-12-13 18:19:28 +07:00
|
|
|
|
2013-04-03 03:28:44 +07:00
|
|
|
skb = netdev_alloc_skb_ip_align(NULL, packet_len + ETH_HLEN);
|
2011-04-20 20:40:58 +07:00
|
|
|
if (!skb) {
|
|
|
|
len = -ENOMEM;
|
|
|
|
goto out;
|
|
|
|
}
|
2010-12-13 18:19:28 +07:00
|
|
|
|
2013-07-29 22:56:44 +07:00
|
|
|
skb->priority = TC_PRIO_CONTROL;
|
2013-04-03 03:28:44 +07:00
|
|
|
skb_reserve(skb, ETH_HLEN);
|
networking: make skb_put & friends return void pointers
It seems like a historic accident that these return unsigned char *,
and in many places that means casts are required, more often than not.
Make these functions (skb_put, __skb_put and pskb_put) return void *
and remove all the casts across the tree, adding a (u8 *) cast only
where the unsigned char pointer was used directly, all done with the
following spatch:
@@
expression SKB, LEN;
typedef u8;
identifier fn = { skb_put, __skb_put };
@@
- *(fn(SKB, LEN))
+ *(u8 *)fn(SKB, LEN)
@@
expression E, SKB, LEN;
identifier fn = { skb_put, __skb_put };
type T;
@@
- E = ((T *)(fn(SKB, LEN)))
+ E = fn(SKB, LEN)
which actually doesn't cover pskb_put since there are only three
users overall.
A handful of stragglers were converted manually, notably a macro in
drivers/isdn/i4l/isdn_bsdcomp.c and, oddly enough, one of the many
instances in net/bluetooth/hci_sock.c. In the former file, I also
had to fix one whitespace problem spatch introduced.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-06-16 19:29:21 +07:00
|
|
|
icmp_header = skb_put(skb, packet_len);
|
2010-12-13 18:19:28 +07:00
|
|
|
|
2013-10-23 03:50:09 +07:00
|
|
|
if (copy_from_user(icmp_header, buff, packet_len)) {
|
2010-12-13 18:19:28 +07:00
|
|
|
len = -EFAULT;
|
|
|
|
goto free_skb;
|
|
|
|
}
|
|
|
|
|
2013-12-03 02:38:31 +07:00
|
|
|
if (icmp_header->packet_type != BATADV_ICMP) {
|
2012-06-04 03:19:22 +07:00
|
|
|
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
|
2012-05-12 18:48:58 +07:00
|
|
|
"Error - can't send packet from char device: got bogus packet type (expected: BAT_ICMP)\n");
|
2010-12-13 18:19:28 +07:00
|
|
|
len = -EINVAL;
|
|
|
|
goto free_skb;
|
|
|
|
}
|
|
|
|
|
2013-10-23 03:50:09 +07:00
|
|
|
switch (icmp_header->msg_type) {
|
|
|
|
case BATADV_ECHO_REQUEST:
|
|
|
|
if (len < sizeof(struct batadv_icmp_packet)) {
|
|
|
|
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
|
|
|
|
"Error - can't send packet from char device: invalid packet size\n");
|
|
|
|
len = -EINVAL;
|
|
|
|
goto free_skb;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
|
|
|
|
goto dst_unreach;
|
|
|
|
|
|
|
|
orig_node = batadv_orig_hash_find(bat_priv, icmp_header->dst);
|
|
|
|
if (!orig_node)
|
|
|
|
goto dst_unreach;
|
|
|
|
|
2013-11-14 01:14:47 +07:00
|
|
|
neigh_node = batadv_orig_router_get(orig_node,
|
|
|
|
BATADV_IF_DEFAULT);
|
2013-10-23 03:50:09 +07:00
|
|
|
if (!neigh_node)
|
|
|
|
goto dst_unreach;
|
|
|
|
|
|
|
|
if (!neigh_node->if_incoming)
|
|
|
|
goto dst_unreach;
|
|
|
|
|
|
|
|
if (neigh_node->if_incoming->if_status != BATADV_IF_ACTIVE)
|
|
|
|
goto dst_unreach;
|
|
|
|
|
|
|
|
icmp_packet_rr = (struct batadv_icmp_packet_rr *)icmp_header;
|
2014-01-22 06:42:11 +07:00
|
|
|
if (packet_len == sizeof(*icmp_packet_rr)) {
|
|
|
|
addr = neigh_node->if_incoming->net_dev->dev_addr;
|
|
|
|
ether_addr_copy(icmp_packet_rr->rr[0], addr);
|
|
|
|
}
|
2013-10-23 03:50:09 +07:00
|
|
|
|
|
|
|
break;
|
|
|
|
default:
|
2012-06-04 03:19:22 +07:00
|
|
|
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
|
2013-10-23 03:50:09 +07:00
|
|
|
"Error - can't send packet from char device: got unknown message type\n");
|
2010-12-13 18:19:28 +07:00
|
|
|
len = -EINVAL;
|
|
|
|
goto free_skb;
|
|
|
|
}
|
|
|
|
|
2013-10-23 03:50:09 +07:00
|
|
|
icmp_header->uid = socket_client->index;
|
2010-12-13 18:19:28 +07:00
|
|
|
|
2013-12-03 02:38:31 +07:00
|
|
|
if (icmp_header->version != BATADV_COMPAT_VERSION) {
|
2013-10-23 03:50:09 +07:00
|
|
|
icmp_header->msg_type = BATADV_PARAMETER_PROBLEM;
|
2013-12-03 02:38:31 +07:00
|
|
|
icmp_header->version = BATADV_COMPAT_VERSION;
|
2013-10-23 03:50:09 +07:00
|
|
|
batadv_socket_add_packet(socket_client, icmp_header,
|
2012-05-12 23:33:59 +07:00
|
|
|
packet_len);
|
2010-12-13 18:19:28 +07:00
|
|
|
goto free_skb;
|
|
|
|
}
|
|
|
|
|
2014-01-22 06:42:11 +07:00
|
|
|
ether_addr_copy(icmp_header->orig, primary_if->net_dev->dev_addr);
|
2010-12-13 18:19:28 +07:00
|
|
|
|
2016-01-16 15:40:15 +07:00
|
|
|
batadv_send_unicast_skb(skb, neigh_node);
|
2010-12-13 18:19:28 +07:00
|
|
|
goto out;
|
|
|
|
|
|
|
|
dst_unreach:
|
2013-10-23 03:50:09 +07:00
|
|
|
icmp_header->msg_type = BATADV_DESTINATION_UNREACHABLE;
|
|
|
|
batadv_socket_add_packet(socket_client, icmp_header, packet_len);
|
2010-12-13 18:19:28 +07:00
|
|
|
free_skb:
|
|
|
|
kfree_skb(skb);
|
|
|
|
out:
|
2011-04-20 20:40:58 +07:00
|
|
|
if (primary_if)
|
2016-01-17 17:01:10 +07:00
|
|
|
batadv_hardif_put(primary_if);
|
2011-02-10 21:33:53 +07:00
|
|
|
if (neigh_node)
|
2016-01-17 17:01:11 +07:00
|
|
|
batadv_neigh_node_put(neigh_node);
|
2011-02-10 21:33:53 +07:00
|
|
|
if (orig_node)
|
2016-01-17 17:01:09 +07:00
|
|
|
batadv_orig_node_put(orig_node);
|
2010-12-13 18:19:28 +07:00
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2012-05-12 23:33:59 +07:00
|
|
|
static unsigned int batadv_socket_poll(struct file *file, poll_table *wait)
|
2010-12-13 18:19:28 +07:00
|
|
|
{
|
2012-06-06 03:31:31 +07:00
|
|
|
struct batadv_socket_client *socket_client = file->private_data;
|
2010-12-13 18:19:28 +07:00
|
|
|
|
|
|
|
poll_wait(file, &socket_client->queue_wait, wait);
|
|
|
|
|
|
|
|
if (socket_client->queue_len > 0)
|
|
|
|
return POLLIN | POLLRDNORM;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-05-12 23:33:59 +07:00
|
|
|
static const struct file_operations batadv_fops = {
|
2010-12-13 18:19:28 +07:00
|
|
|
.owner = THIS_MODULE,
|
2012-05-12 23:33:59 +07:00
|
|
|
.open = batadv_socket_open,
|
|
|
|
.release = batadv_socket_release,
|
|
|
|
.read = batadv_socket_read,
|
|
|
|
.write = batadv_socket_write,
|
|
|
|
.poll = batadv_socket_poll,
|
2010-12-13 18:19:28 +07:00
|
|
|
.llseek = no_llseek,
|
|
|
|
};
|
|
|
|
|
2012-06-06 03:31:31 +07:00
|
|
|
int batadv_socket_setup(struct batadv_priv *bat_priv)
|
2010-12-13 18:19:28 +07:00
|
|
|
{
|
|
|
|
struct dentry *d;
|
|
|
|
|
|
|
|
if (!bat_priv->debug_dir)
|
|
|
|
goto err;
|
|
|
|
|
2016-09-01 15:25:12 +07:00
|
|
|
d = debugfs_create_file(BATADV_ICMP_SOCKET, 0600, bat_priv->debug_dir,
|
|
|
|
bat_priv, &batadv_fops);
|
2012-05-05 18:27:28 +07:00
|
|
|
if (!d)
|
2010-12-13 18:19:28 +07:00
|
|
|
goto err;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err:
|
2012-05-05 18:27:28 +07:00
|
|
|
return -ENOMEM;
|
2010-12-13 18:19:28 +07:00
|
|
|
}
|
|
|
|
|
2013-10-23 03:50:09 +07:00
|
|
|
/**
|
2016-03-11 22:36:19 +07:00
|
|
|
* batadv_socket_add_packet - schedule an icmp packet to be sent to
|
2015-05-31 15:10:20 +07:00
|
|
|
* userspace on an icmp socket.
|
2013-10-23 03:50:09 +07:00
|
|
|
* @socket_client: the socket this packet belongs to
|
|
|
|
* @icmph: pointer to the header of the icmp packet
|
|
|
|
* @icmp_len: total length of the icmp packet
|
|
|
|
*/
|
2012-06-06 03:31:31 +07:00
|
|
|
static void batadv_socket_add_packet(struct batadv_socket_client *socket_client,
|
2013-10-23 03:50:09 +07:00
|
|
|
struct batadv_icmp_header *icmph,
|
2012-05-12 23:33:59 +07:00
|
|
|
size_t icmp_len)
|
2010-12-13 18:19:28 +07:00
|
|
|
{
|
2012-06-06 03:31:31 +07:00
|
|
|
struct batadv_socket_packet *socket_packet;
|
2013-10-23 03:50:09 +07:00
|
|
|
size_t len;
|
2010-12-13 18:19:28 +07:00
|
|
|
|
2011-05-15 04:14:54 +07:00
|
|
|
socket_packet = kmalloc(sizeof(*socket_packet), GFP_ATOMIC);
|
2010-12-13 18:19:28 +07:00
|
|
|
|
|
|
|
if (!socket_packet)
|
|
|
|
return;
|
|
|
|
|
2013-10-23 03:50:09 +07:00
|
|
|
len = icmp_len;
|
|
|
|
/* check the maximum length before filling the buffer */
|
|
|
|
if (len > sizeof(socket_packet->icmp_packet))
|
|
|
|
len = sizeof(socket_packet->icmp_packet);
|
|
|
|
|
2010-12-13 18:19:28 +07:00
|
|
|
INIT_LIST_HEAD(&socket_packet->list);
|
2013-10-23 03:50:09 +07:00
|
|
|
memcpy(&socket_packet->icmp_packet, icmph, len);
|
|
|
|
socket_packet->icmp_len = len;
|
2010-12-13 18:19:28 +07:00
|
|
|
|
|
|
|
spin_lock_bh(&socket_client->lock);
|
|
|
|
|
|
|
|
/* while waiting for the lock the socket_client could have been
|
2012-05-12 07:09:43 +07:00
|
|
|
* deleted
|
|
|
|
*/
|
2013-10-23 03:50:09 +07:00
|
|
|
if (!batadv_socket_client_hash[icmph->uid]) {
|
2010-12-13 18:19:28 +07:00
|
|
|
spin_unlock_bh(&socket_client->lock);
|
|
|
|
kfree(socket_packet);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
list_add_tail(&socket_packet->list, &socket_client->queue_list);
|
|
|
|
socket_client->queue_len++;
|
|
|
|
|
|
|
|
if (socket_client->queue_len > 100) {
|
|
|
|
socket_packet = list_first_entry(&socket_client->queue_list,
|
2012-06-06 03:31:31 +07:00
|
|
|
struct batadv_socket_packet,
|
|
|
|
list);
|
2010-12-13 18:19:28 +07:00
|
|
|
|
|
|
|
list_del(&socket_packet->list);
|
|
|
|
kfree(socket_packet);
|
|
|
|
socket_client->queue_len--;
|
|
|
|
}
|
|
|
|
|
|
|
|
spin_unlock_bh(&socket_client->lock);
|
|
|
|
|
|
|
|
wake_up(&socket_client->queue_wait);
|
|
|
|
}
|
|
|
|
|
2013-10-23 03:50:09 +07:00
|
|
|
/**
|
|
|
|
* batadv_socket_receive_packet - schedule an icmp packet to be received
|
|
|
|
* locally and sent to userspace.
|
|
|
|
* @icmph: pointer to the header of the icmp packet
|
|
|
|
* @icmp_len: total length of the icmp packet
|
|
|
|
*/
|
|
|
|
void batadv_socket_receive_packet(struct batadv_icmp_header *icmph,
|
2012-05-12 07:09:33 +07:00
|
|
|
size_t icmp_len)
|
2010-12-13 18:19:28 +07:00
|
|
|
{
|
2012-06-06 03:31:31 +07:00
|
|
|
struct batadv_socket_client *hash;
|
2010-12-13 18:19:28 +07:00
|
|
|
|
2013-10-23 03:50:09 +07:00
|
|
|
hash = batadv_socket_client_hash[icmph->uid];
|
2010-12-13 18:19:28 +07:00
|
|
|
if (hash)
|
2013-10-23 03:50:09 +07:00
|
|
|
batadv_socket_add_packet(hash, icmph, icmp_len);
|
2010-12-13 18:19:28 +07:00
|
|
|
}
|