2017-11-19 15:05:11 +01:00
// SPDX-License-Identifier: GPL-2.0
2017-01-01 00:00:00 +01:00
/* Copyright (C) 2007-2017 B.A.T.M.A.N. contributors:
2010-12-13 11:19:28 +00: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-03 20:40:48 +01:00
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
2010-12-13 11:19:28 +00:00
*/
2015-04-17 19:40:28 +02:00
# include "icmp_socket.h"
2010-12-13 11:19:28 +00:00
# include "main.h"
2015-04-17 19:40:28 +02:00
# include <linux/atomic.h>
# include <linux/compiler.h>
2010-12-13 11:19:28 +00:00
# include <linux/debugfs.h>
2015-04-17 19:40:28 +02:00
# include <linux/errno.h>
# include <linux/etherdevice.h>
# include <linux/export.h>
# include <linux/fcntl.h>
# include <linux/fs.h>
2017-11-19 17:12:02 +01:00
# include <linux/gfp.h>
2015-04-17 19:40:28 +02:00
# 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 11:19:28 +00:00
# include <linux/slab.h>
2015-04-17 19:40:28 +02:00
# include <linux/spinlock.h>
# include <linux/stddef.h>
# include <linux/string.h>
# include <linux/uaccess.h>
# include <linux/wait.h>
2017-12-21 10:17:41 +01:00
# include <uapi/linux/batadv_packet.h>
2015-04-17 19:40:28 +02:00
2010-12-13 11:19:28 +00:00
# include "hard-interface.h"
2016-05-15 23:48:31 +02:00
# include "log.h"
2015-04-17 19:40:28 +02:00
# include "originator.h"
# include "send.h"
2010-12-13 11:19:28 +00:00
2012-06-05 22:31:31 +02:00
static struct batadv_socket_client * batadv_socket_client_hash [ 256 ] ;
2010-12-13 11:19:28 +00:00
2012-06-05 22:31:31 +02:00
static void batadv_socket_add_packet ( struct batadv_socket_client * socket_client ,
2013-10-22 22:50:09 +02:00
struct batadv_icmp_header * icmph ,
2012-05-12 18:33:59 +02:00
size_t icmp_len ) ;
2010-12-13 11:19:28 +00:00
2017-12-02 19:51:53 +01:00
/**
* batadv_socket_init ( ) - Initialize soft interface independent socket data
*/
2012-05-12 02:09:33 +02:00
void batadv_socket_init ( void )
2010-12-13 11:19:28 +00:00
{
2012-05-12 18:33:59 +02:00
memset ( batadv_socket_client_hash , 0 , sizeof ( batadv_socket_client_hash ) ) ;
2010-12-13 11:19:28 +00:00
}
2012-05-12 18:33:59 +02:00
static int batadv_socket_open ( struct inode * inode , struct file * file )
2010-12-13 11:19:28 +00:00
{
unsigned int i ;
2012-06-05 22:31:31 +02:00
struct batadv_socket_client * socket_client ;
2010-12-13 11:19:28 +00:00
2012-08-20 23:37:26 +02:00
if ( ! try_module_get ( THIS_MODULE ) )
return - EBUSY ;
2010-12-13 11:19:28 +00:00
nonseekable_open ( inode , file ) ;
2011-05-14 23:14:54 +02:00
socket_client = kmalloc ( sizeof ( * socket_client ) , GFP_KERNEL ) ;
2012-08-20 23:37:26 +02:00
if ( ! socket_client ) {
module_put ( THIS_MODULE ) ;
2010-12-13 11:19:28 +00:00
return - ENOMEM ;
2012-08-20 23:37:26 +02:00
}
2010-12-13 11:19:28 +00:00
2012-05-12 18:33:59 +02: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 11:19:28 +00:00
break ;
}
}
2012-05-12 18:33:59 +02:00
if ( i = = ARRAY_SIZE ( batadv_socket_client_hash ) ) {
2012-03-07 09:07:45 +01:00
pr_err ( " Error - can't add another packet client: maximum number of clients reached \n " ) ;
2010-12-13 11:19:28 +00:00
kfree ( socket_client ) ;
2012-08-20 23:37:26 +02:00
module_put ( THIS_MODULE ) ;
2010-12-13 11:19:28 +00: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 18:33:59 +02:00
static int batadv_socket_release ( struct inode * inode , struct file * file )
2010-12-13 11:19:28 +00:00
{
2015-12-18 23:33:31 +08:00
struct batadv_socket_client * client = file - > private_data ;
struct batadv_socket_packet * packet , * tmp ;
2010-12-13 11:19:28 +00:00
2015-12-18 23:33:31 +08:00
spin_lock_bh ( & client - > lock ) ;
2010-12-13 11:19:28 +00:00
/* for all packets in the queue ... */
2015-12-18 23:33:31 +08:00
list_for_each_entry_safe ( packet , tmp , & client - > queue_list , list ) {
list_del ( & packet - > list ) ;
kfree ( packet ) ;
2010-12-13 11:19:28 +00:00
}
2015-12-18 23:33:31 +08:00
batadv_socket_client_hash [ client - > index ] = NULL ;
spin_unlock_bh ( & client - > lock ) ;
2010-12-13 11:19:28 +00:00
2015-12-18 23:33:31 +08:00
kfree ( client ) ;
2012-08-20 23:37:26 +02:00
module_put ( THIS_MODULE ) ;
2010-12-13 11:19:28 +00:00
return 0 ;
}
2012-05-12 18:33:59 +02:00
static ssize_t batadv_socket_read ( struct file * file , char __user * buf ,
size_t count , loff_t * ppos )
2010-12-13 11:19:28 +00:00
{
2012-06-05 22:31:31 +02:00
struct batadv_socket_client * socket_client = file - > private_data ;
struct batadv_socket_packet * socket_packet ;
2010-12-13 11:19:28 +00:00
size_t packet_len ;
int error ;
2017-08-23 21:52:13 +02:00
if ( ( file - > f_flags & O_NONBLOCK ) & & socket_client - > queue_len = = 0 )
2010-12-13 11:19:28 +00:00
return - EAGAIN ;
2017-08-23 21:52:13 +02:00
if ( ! buf | | count < sizeof ( struct batadv_icmp_packet ) )
2010-12-13 11:19:28 +00: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-05 22:31:31 +02:00
struct batadv_socket_packet , list ) ;
2010-12-13 11:19:28 +00:00
list_del ( & socket_packet - > list ) ;
socket_client - > queue_len - - ;
spin_unlock_bh ( & socket_client - > lock ) ;
2011-12-10 15:28:36 +01:00
packet_len = min ( count , socket_packet - > icmp_len ) ;
error = copy_to_user ( buf , & socket_packet - > icmp_packet , packet_len ) ;
2010-12-13 11:19:28 +00:00
kfree ( socket_packet ) ;
if ( error )
return - EFAULT ;
return packet_len ;
}
2012-05-12 18:33:59 +02:00
static ssize_t batadv_socket_write ( struct file * file , const char __user * buff ,
size_t len , loff_t * off )
2010-12-13 11:19:28 +00:00
{
2012-06-05 22:31:31 +02: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 11:19:28 +00:00
struct sk_buff * skb ;
2013-10-22 22:50:09 +02:00
struct batadv_icmp_packet_rr * icmp_packet_rr ;
struct batadv_icmp_header * icmp_header ;
2012-06-05 22:31:31 +02:00
struct batadv_orig_node * orig_node = NULL ;
struct batadv_neigh_node * neigh_node = NULL ;
2012-06-05 22:31:30 +02:00
size_t packet_len = sizeof ( struct batadv_icmp_packet ) ;
2015-05-26 18:34:26 +02:00
u8 * addr ;
2010-12-13 11:19:28 +00:00
2013-10-22 22:50:09 +02:00
if ( len < sizeof ( struct batadv_icmp_header ) ) {
2012-06-03 22:19:22 +02:00
batadv_dbg ( BATADV_DBG_BATMAN , bat_priv ,
2012-05-12 13:48:58 +02:00
" Error - can't send packet from char device: invalid packet size \n " ) ;
2010-12-13 11:19:28 +00:00
return - EINVAL ;
}
2012-05-12 13:48:54 +02:00
primary_if = batadv_primary_if_get_selected ( bat_priv ) ;
2011-04-20 15:40:58 +02:00
if ( ! primary_if ) {
len = - EFAULT ;
goto out ;
}
2010-12-13 11:19:28 +00:00
2013-10-22 22:50:09 +02:00
if ( len > = BATADV_ICMP_MAX_PACKET_SIZE )
packet_len = BATADV_ICMP_MAX_PACKET_SIZE ;
else
packet_len = len ;
2010-12-13 11:19:28 +00:00
2013-04-02 22:28:44 +02:00
skb = netdev_alloc_skb_ip_align ( NULL , packet_len + ETH_HLEN ) ;
2011-04-20 15:40:58 +02:00
if ( ! skb ) {
len = - ENOMEM ;
goto out ;
}
2010-12-13 11:19:28 +00:00
2013-07-29 17:56:44 +02:00
skb - > priority = TC_PRIO_CONTROL ;
2013-04-02 22:28:44 +02: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 14:29:21 +02:00
icmp_header = skb_put ( skb , packet_len ) ;
2010-12-13 11:19:28 +00:00
2013-10-22 22:50:09 +02:00
if ( copy_from_user ( icmp_header , buff , packet_len ) ) {
2010-12-13 11:19:28 +00:00
len = - EFAULT ;
goto free_skb ;
}
2013-12-02 20:38:31 +01:00
if ( icmp_header - > packet_type ! = BATADV_ICMP ) {
2012-06-03 22:19:22 +02:00
batadv_dbg ( BATADV_DBG_BATMAN , bat_priv ,
2012-05-12 13:48:58 +02:00
" Error - can't send packet from char device: got bogus packet type (expected: BAT_ICMP) \n " ) ;
2010-12-13 11:19:28 +00:00
len = - EINVAL ;
goto free_skb ;
}
2013-10-22 22:50:09 +02: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-13 19:14:47 +01:00
neigh_node = batadv_orig_router_get ( orig_node ,
BATADV_IF_DEFAULT ) ;
2013-10-22 22:50:09 +02: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 00:42:11 +01: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-22 22:50:09 +02:00
break ;
default :
2012-06-03 22:19:22 +02:00
batadv_dbg ( BATADV_DBG_BATMAN , bat_priv ,
2013-10-22 22:50:09 +02:00
" Error - can't send packet from char device: got unknown message type \n " ) ;
2010-12-13 11:19:28 +00:00
len = - EINVAL ;
goto free_skb ;
}
2013-10-22 22:50:09 +02:00
icmp_header - > uid = socket_client - > index ;
2010-12-13 11:19:28 +00:00
2013-12-02 20:38:31 +01:00
if ( icmp_header - > version ! = BATADV_COMPAT_VERSION ) {
2013-10-22 22:50:09 +02:00
icmp_header - > msg_type = BATADV_PARAMETER_PROBLEM ;
2013-12-02 20:38:31 +01:00
icmp_header - > version = BATADV_COMPAT_VERSION ;
2013-10-22 22:50:09 +02:00
batadv_socket_add_packet ( socket_client , icmp_header ,
2012-05-12 18:33:59 +02:00
packet_len ) ;
2010-12-13 11:19:28 +00:00
goto free_skb ;
}
2014-01-22 00:42:11 +01:00
ether_addr_copy ( icmp_header - > orig , primary_if - > net_dev - > dev_addr ) ;
2010-12-13 11:19:28 +00:00
2016-01-16 16:40:15 +08:00
batadv_send_unicast_skb ( skb , neigh_node ) ;
2010-12-13 11:19:28 +00:00
goto out ;
dst_unreach :
2013-10-22 22:50:09 +02:00
icmp_header - > msg_type = BATADV_DESTINATION_UNREACHABLE ;
batadv_socket_add_packet ( socket_client , icmp_header , packet_len ) ;
2010-12-13 11:19:28 +00:00
free_skb :
kfree_skb ( skb ) ;
out :
2011-04-20 15:40:58 +02:00
if ( primary_if )
2016-01-17 11:01:10 +01:00
batadv_hardif_put ( primary_if ) ;
2011-02-10 14:33:53 +00:00
if ( neigh_node )
2016-01-17 11:01:11 +01:00
batadv_neigh_node_put ( neigh_node ) ;
2011-02-10 14:33:53 +00:00
if ( orig_node )
2016-01-17 11:01:09 +01:00
batadv_orig_node_put ( orig_node ) ;
2010-12-13 11:19:28 +00:00
return len ;
}
2012-05-12 18:33:59 +02:00
static unsigned int batadv_socket_poll ( struct file * file , poll_table * wait )
2010-12-13 11:19:28 +00:00
{
2012-06-05 22:31:31 +02:00
struct batadv_socket_client * socket_client = file - > private_data ;
2010-12-13 11:19:28 +00:00
poll_wait ( file , & socket_client - > queue_wait , wait ) ;
if ( socket_client - > queue_len > 0 )
return POLLIN | POLLRDNORM ;
return 0 ;
}
2012-05-12 18:33:59 +02:00
static const struct file_operations batadv_fops = {
2010-12-13 11:19:28 +00:00
. owner = THIS_MODULE ,
2012-05-12 18:33:59 +02:00
. open = batadv_socket_open ,
. release = batadv_socket_release ,
. read = batadv_socket_read ,
. write = batadv_socket_write ,
. poll = batadv_socket_poll ,
2010-12-13 11:19:28 +00:00
. llseek = no_llseek ,
} ;
2017-12-02 19:51:53 +01:00
/**
* batadv_socket_setup ( ) - Create debugfs " socket " file
* @ bat_priv : the bat priv with all the soft interface information
*
* Return : 0 on success or negative error number in case of failure
*/
2012-06-05 22:31:31 +02:00
int batadv_socket_setup ( struct batadv_priv * bat_priv )
2010-12-13 11:19:28 +00:00
{
struct dentry * d ;
if ( ! bat_priv - > debug_dir )
goto err ;
2016-09-01 10:25:12 +02:00
d = debugfs_create_file ( BATADV_ICMP_SOCKET , 0600 , bat_priv - > debug_dir ,
bat_priv , & batadv_fops ) ;
2012-05-05 13:27:28 +02:00
if ( ! d )
2010-12-13 11:19:28 +00:00
goto err ;
return 0 ;
err :
2012-05-05 13:27:28 +02:00
return - ENOMEM ;
2010-12-13 11:19:28 +00:00
}
2013-10-22 22:50:09 +02:00
/**
2017-12-02 19:51:47 +01:00
* batadv_socket_add_packet ( ) - schedule an icmp packet to be sent to
2015-05-31 10:10:20 +02:00
* userspace on an icmp socket .
2013-10-22 22:50:09 +02: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-05 22:31:31 +02:00
static void batadv_socket_add_packet ( struct batadv_socket_client * socket_client ,
2013-10-22 22:50:09 +02:00
struct batadv_icmp_header * icmph ,
2012-05-12 18:33:59 +02:00
size_t icmp_len )
2010-12-13 11:19:28 +00:00
{
2012-06-05 22:31:31 +02:00
struct batadv_socket_packet * socket_packet ;
2013-10-22 22:50:09 +02:00
size_t len ;
2010-12-13 11:19:28 +00:00
2011-05-14 23:14:54 +02:00
socket_packet = kmalloc ( sizeof ( * socket_packet ) , GFP_ATOMIC ) ;
2010-12-13 11:19:28 +00:00
if ( ! socket_packet )
return ;
2013-10-22 22:50:09 +02: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 11:19:28 +00:00
INIT_LIST_HEAD ( & socket_packet - > list ) ;
2013-10-22 22:50:09 +02:00
memcpy ( & socket_packet - > icmp_packet , icmph , len ) ;
socket_packet - > icmp_len = len ;
2010-12-13 11:19:28 +00:00
spin_lock_bh ( & socket_client - > lock ) ;
/* while waiting for the lock the socket_client could have been
2012-05-12 02:09:43 +02:00
* deleted
*/
2013-10-22 22:50:09 +02:00
if ( ! batadv_socket_client_hash [ icmph - > uid ] ) {
2010-12-13 11:19:28 +00: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-05 22:31:31 +02:00
struct batadv_socket_packet ,
list ) ;
2010-12-13 11:19:28 +00: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-22 22:50:09 +02:00
/**
2017-12-02 19:51:47 +01:00
* batadv_socket_receive_packet ( ) - schedule an icmp packet to be received
2013-10-22 22:50:09 +02:00
* 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 02:09:33 +02:00
size_t icmp_len )
2010-12-13 11:19:28 +00:00
{
2012-06-05 22:31:31 +02:00
struct batadv_socket_client * hash ;
2010-12-13 11:19:28 +00:00
2013-10-22 22:50:09 +02:00
hash = batadv_socket_client_hash [ icmph - > uid ] ;
2010-12-13 11:19:28 +00:00
if ( hash )
2013-10-22 22:50:09 +02:00
batadv_socket_add_packet ( hash , icmph , icmp_len ) ;
2010-12-13 11:19:28 +00:00
}