root/net/batman-adv/icmp_socket.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. batadv_socket_init
  2. batadv_socket_open
  3. batadv_socket_release
  4. batadv_socket_read
  5. batadv_socket_write
  6. batadv_socket_poll
  7. batadv_socket_setup
  8. batadv_socket_add_packet
  9. batadv_socket_receive_packet

   1 // SPDX-License-Identifier: GPL-2.0
   2 /* Copyright (C) 2007-2019  B.A.T.M.A.N. contributors:
   3  *
   4  * Marek Lindner
   5  */
   6 
   7 #include "icmp_socket.h"
   8 #include "main.h"
   9 
  10 #include <linux/atomic.h>
  11 #include <linux/compiler.h>
  12 #include <linux/debugfs.h>
  13 #include <linux/errno.h>
  14 #include <linux/etherdevice.h>
  15 #include <linux/eventpoll.h>
  16 #include <linux/export.h>
  17 #include <linux/fcntl.h>
  18 #include <linux/fs.h>
  19 #include <linux/gfp.h>
  20 #include <linux/if_ether.h>
  21 #include <linux/kernel.h>
  22 #include <linux/list.h>
  23 #include <linux/module.h>
  24 #include <linux/netdevice.h>
  25 #include <linux/pkt_sched.h>
  26 #include <linux/poll.h>
  27 #include <linux/printk.h>
  28 #include <linux/sched.h> /* for linux/wait.h */
  29 #include <linux/skbuff.h>
  30 #include <linux/slab.h>
  31 #include <linux/spinlock.h>
  32 #include <linux/stddef.h>
  33 #include <linux/string.h>
  34 #include <linux/uaccess.h>
  35 #include <linux/wait.h>
  36 #include <uapi/linux/batadv_packet.h>
  37 
  38 #include "debugfs.h"
  39 #include "hard-interface.h"
  40 #include "log.h"
  41 #include "originator.h"
  42 #include "send.h"
  43 
  44 static struct batadv_socket_client *batadv_socket_client_hash[256];
  45 
  46 static void batadv_socket_add_packet(struct batadv_socket_client *socket_client,
  47                                      struct batadv_icmp_header *icmph,
  48                                      size_t icmp_len);
  49 
  50 /**
  51  * batadv_socket_init() - Initialize soft interface independent socket data
  52  */
  53 void batadv_socket_init(void)
  54 {
  55         memset(batadv_socket_client_hash, 0, sizeof(batadv_socket_client_hash));
  56 }
  57 
  58 static int batadv_socket_open(struct inode *inode, struct file *file)
  59 {
  60         unsigned int i;
  61         struct batadv_socket_client *socket_client;
  62 
  63         if (!try_module_get(THIS_MODULE))
  64                 return -EBUSY;
  65 
  66         batadv_debugfs_deprecated(file, "");
  67 
  68         stream_open(inode, file);
  69 
  70         socket_client = kmalloc(sizeof(*socket_client), GFP_KERNEL);
  71         if (!socket_client) {
  72                 module_put(THIS_MODULE);
  73                 return -ENOMEM;
  74         }
  75 
  76         for (i = 0; i < ARRAY_SIZE(batadv_socket_client_hash); i++) {
  77                 if (!batadv_socket_client_hash[i]) {
  78                         batadv_socket_client_hash[i] = socket_client;
  79                         break;
  80                 }
  81         }
  82 
  83         if (i == ARRAY_SIZE(batadv_socket_client_hash)) {
  84                 pr_err("Error - can't add another packet client: maximum number of clients reached\n");
  85                 kfree(socket_client);
  86                 module_put(THIS_MODULE);
  87                 return -EXFULL;
  88         }
  89 
  90         INIT_LIST_HEAD(&socket_client->queue_list);
  91         socket_client->queue_len = 0;
  92         socket_client->index = i;
  93         socket_client->bat_priv = inode->i_private;
  94         spin_lock_init(&socket_client->lock);
  95         init_waitqueue_head(&socket_client->queue_wait);
  96 
  97         file->private_data = socket_client;
  98 
  99         return 0;
 100 }
 101 
 102 static int batadv_socket_release(struct inode *inode, struct file *file)
 103 {
 104         struct batadv_socket_client *client = file->private_data;
 105         struct batadv_socket_packet *packet, *tmp;
 106 
 107         spin_lock_bh(&client->lock);
 108 
 109         /* for all packets in the queue ... */
 110         list_for_each_entry_safe(packet, tmp, &client->queue_list, list) {
 111                 list_del(&packet->list);
 112                 kfree(packet);
 113         }
 114 
 115         batadv_socket_client_hash[client->index] = NULL;
 116         spin_unlock_bh(&client->lock);
 117 
 118         kfree(client);
 119         module_put(THIS_MODULE);
 120 
 121         return 0;
 122 }
 123 
 124 static ssize_t batadv_socket_read(struct file *file, char __user *buf,
 125                                   size_t count, loff_t *ppos)
 126 {
 127         struct batadv_socket_client *socket_client = file->private_data;
 128         struct batadv_socket_packet *socket_packet;
 129         size_t packet_len;
 130         int error;
 131 
 132         if ((file->f_flags & O_NONBLOCK) && socket_client->queue_len == 0)
 133                 return -EAGAIN;
 134 
 135         if (!buf || count < sizeof(struct batadv_icmp_packet))
 136                 return -EINVAL;
 137 
 138         if (!access_ok(buf, count))
 139                 return -EFAULT;
 140 
 141         error = wait_event_interruptible(socket_client->queue_wait,
 142                                          socket_client->queue_len);
 143 
 144         if (error)
 145                 return error;
 146 
 147         spin_lock_bh(&socket_client->lock);
 148 
 149         socket_packet = list_first_entry(&socket_client->queue_list,
 150                                          struct batadv_socket_packet, list);
 151         list_del(&socket_packet->list);
 152         socket_client->queue_len--;
 153 
 154         spin_unlock_bh(&socket_client->lock);
 155 
 156         packet_len = min(count, socket_packet->icmp_len);
 157         error = copy_to_user(buf, &socket_packet->icmp_packet, packet_len);
 158 
 159         kfree(socket_packet);
 160 
 161         if (error)
 162                 return -EFAULT;
 163 
 164         return packet_len;
 165 }
 166 
 167 static ssize_t batadv_socket_write(struct file *file, const char __user *buff,
 168                                    size_t len, loff_t *off)
 169 {
 170         struct batadv_socket_client *socket_client = file->private_data;
 171         struct batadv_priv *bat_priv = socket_client->bat_priv;
 172         struct batadv_hard_iface *primary_if = NULL;
 173         struct sk_buff *skb;
 174         struct batadv_icmp_packet_rr *icmp_packet_rr;
 175         struct batadv_icmp_header *icmp_header;
 176         struct batadv_orig_node *orig_node = NULL;
 177         struct batadv_neigh_node *neigh_node = NULL;
 178         size_t packet_len = sizeof(struct batadv_icmp_packet);
 179         u8 *addr;
 180 
 181         if (len < sizeof(struct batadv_icmp_header)) {
 182                 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
 183                            "Error - can't send packet from char device: invalid packet size\n");
 184                 return -EINVAL;
 185         }
 186 
 187         primary_if = batadv_primary_if_get_selected(bat_priv);
 188 
 189         if (!primary_if) {
 190                 len = -EFAULT;
 191                 goto out;
 192         }
 193 
 194         if (len >= BATADV_ICMP_MAX_PACKET_SIZE)
 195                 packet_len = BATADV_ICMP_MAX_PACKET_SIZE;
 196         else
 197                 packet_len = len;
 198 
 199         skb = netdev_alloc_skb_ip_align(NULL, packet_len + ETH_HLEN);
 200         if (!skb) {
 201                 len = -ENOMEM;
 202                 goto out;
 203         }
 204 
 205         skb->priority = TC_PRIO_CONTROL;
 206         skb_reserve(skb, ETH_HLEN);
 207         icmp_header = skb_put(skb, packet_len);
 208 
 209         if (copy_from_user(icmp_header, buff, packet_len)) {
 210                 len = -EFAULT;
 211                 goto free_skb;
 212         }
 213 
 214         if (icmp_header->packet_type != BATADV_ICMP) {
 215                 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
 216                            "Error - can't send packet from char device: got bogus packet type (expected: BAT_ICMP)\n");
 217                 len = -EINVAL;
 218                 goto free_skb;
 219         }
 220 
 221         switch (icmp_header->msg_type) {
 222         case BATADV_ECHO_REQUEST:
 223                 if (len < sizeof(struct batadv_icmp_packet)) {
 224                         batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
 225                                    "Error - can't send packet from char device: invalid packet size\n");
 226                         len = -EINVAL;
 227                         goto free_skb;
 228                 }
 229 
 230                 if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
 231                         goto dst_unreach;
 232 
 233                 orig_node = batadv_orig_hash_find(bat_priv, icmp_header->dst);
 234                 if (!orig_node)
 235                         goto dst_unreach;
 236 
 237                 neigh_node = batadv_orig_router_get(orig_node,
 238                                                     BATADV_IF_DEFAULT);
 239                 if (!neigh_node)
 240                         goto dst_unreach;
 241 
 242                 if (!neigh_node->if_incoming)
 243                         goto dst_unreach;
 244 
 245                 if (neigh_node->if_incoming->if_status != BATADV_IF_ACTIVE)
 246                         goto dst_unreach;
 247 
 248                 icmp_packet_rr = (struct batadv_icmp_packet_rr *)icmp_header;
 249                 if (packet_len == sizeof(*icmp_packet_rr)) {
 250                         addr = neigh_node->if_incoming->net_dev->dev_addr;
 251                         ether_addr_copy(icmp_packet_rr->rr[0], addr);
 252                 }
 253 
 254                 break;
 255         default:
 256                 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
 257                            "Error - can't send packet from char device: got unknown message type\n");
 258                 len = -EINVAL;
 259                 goto free_skb;
 260         }
 261 
 262         icmp_header->uid = socket_client->index;
 263 
 264         if (icmp_header->version != BATADV_COMPAT_VERSION) {
 265                 icmp_header->msg_type = BATADV_PARAMETER_PROBLEM;
 266                 icmp_header->version = BATADV_COMPAT_VERSION;
 267                 batadv_socket_add_packet(socket_client, icmp_header,
 268                                          packet_len);
 269                 goto free_skb;
 270         }
 271 
 272         ether_addr_copy(icmp_header->orig, primary_if->net_dev->dev_addr);
 273 
 274         batadv_send_unicast_skb(skb, neigh_node);
 275         goto out;
 276 
 277 dst_unreach:
 278         icmp_header->msg_type = BATADV_DESTINATION_UNREACHABLE;
 279         batadv_socket_add_packet(socket_client, icmp_header, packet_len);
 280 free_skb:
 281         kfree_skb(skb);
 282 out:
 283         if (primary_if)
 284                 batadv_hardif_put(primary_if);
 285         if (neigh_node)
 286                 batadv_neigh_node_put(neigh_node);
 287         if (orig_node)
 288                 batadv_orig_node_put(orig_node);
 289         return len;
 290 }
 291 
 292 static __poll_t batadv_socket_poll(struct file *file, poll_table *wait)
 293 {
 294         struct batadv_socket_client *socket_client = file->private_data;
 295 
 296         poll_wait(file, &socket_client->queue_wait, wait);
 297 
 298         if (socket_client->queue_len > 0)
 299                 return EPOLLIN | EPOLLRDNORM;
 300 
 301         return 0;
 302 }
 303 
 304 static const struct file_operations batadv_fops = {
 305         .owner = THIS_MODULE,
 306         .open = batadv_socket_open,
 307         .release = batadv_socket_release,
 308         .read = batadv_socket_read,
 309         .write = batadv_socket_write,
 310         .poll = batadv_socket_poll,
 311         .llseek = no_llseek,
 312 };
 313 
 314 /**
 315  * batadv_socket_setup() - Create debugfs "socket" file
 316  * @bat_priv: the bat priv with all the soft interface information
 317  */
 318 void batadv_socket_setup(struct batadv_priv *bat_priv)
 319 {
 320         debugfs_create_file(BATADV_ICMP_SOCKET, 0600, bat_priv->debug_dir,
 321                             bat_priv, &batadv_fops);
 322 }
 323 
 324 /**
 325  * batadv_socket_add_packet() - schedule an icmp packet to be sent to
 326  *  userspace on an icmp socket.
 327  * @socket_client: the socket this packet belongs to
 328  * @icmph: pointer to the header of the icmp packet
 329  * @icmp_len: total length of the icmp packet
 330  */
 331 static void batadv_socket_add_packet(struct batadv_socket_client *socket_client,
 332                                      struct batadv_icmp_header *icmph,
 333                                      size_t icmp_len)
 334 {
 335         struct batadv_socket_packet *socket_packet;
 336         size_t len;
 337 
 338         socket_packet = kmalloc(sizeof(*socket_packet), GFP_ATOMIC);
 339 
 340         if (!socket_packet)
 341                 return;
 342 
 343         len = icmp_len;
 344         /* check the maximum length before filling the buffer */
 345         if (len > sizeof(socket_packet->icmp_packet))
 346                 len = sizeof(socket_packet->icmp_packet);
 347 
 348         INIT_LIST_HEAD(&socket_packet->list);
 349         memcpy(&socket_packet->icmp_packet, icmph, len);
 350         socket_packet->icmp_len = len;
 351 
 352         spin_lock_bh(&socket_client->lock);
 353 
 354         /* while waiting for the lock the socket_client could have been
 355          * deleted
 356          */
 357         if (!batadv_socket_client_hash[icmph->uid]) {
 358                 spin_unlock_bh(&socket_client->lock);
 359                 kfree(socket_packet);
 360                 return;
 361         }
 362 
 363         list_add_tail(&socket_packet->list, &socket_client->queue_list);
 364         socket_client->queue_len++;
 365 
 366         if (socket_client->queue_len > 100) {
 367                 socket_packet = list_first_entry(&socket_client->queue_list,
 368                                                  struct batadv_socket_packet,
 369                                                  list);
 370 
 371                 list_del(&socket_packet->list);
 372                 kfree(socket_packet);
 373                 socket_client->queue_len--;
 374         }
 375 
 376         spin_unlock_bh(&socket_client->lock);
 377 
 378         wake_up(&socket_client->queue_wait);
 379 }
 380 
 381 /**
 382  * batadv_socket_receive_packet() - schedule an icmp packet to be received
 383  *  locally and sent to userspace.
 384  * @icmph: pointer to the header of the icmp packet
 385  * @icmp_len: total length of the icmp packet
 386  */
 387 void batadv_socket_receive_packet(struct batadv_icmp_header *icmph,
 388                                   size_t icmp_len)
 389 {
 390         struct batadv_socket_client *hash;
 391 
 392         hash = batadv_socket_client_hash[icmph->uid];
 393         if (hash)
 394                 batadv_socket_add_packet(hash, icmph, icmp_len);
 395 }

/* [<][>][^][v][top][bottom][index][help] */