18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright (C) 2007-2020 B.A.T.M.A.N. contributors: 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Marek Lindner 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include "icmp_socket.h" 88c2ecf20Sopenharmony_ci#include "main.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/atomic.h> 118c2ecf20Sopenharmony_ci#include <linux/compiler.h> 128c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 138c2ecf20Sopenharmony_ci#include <linux/errno.h> 148c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 158c2ecf20Sopenharmony_ci#include <linux/eventpoll.h> 168c2ecf20Sopenharmony_ci#include <linux/export.h> 178c2ecf20Sopenharmony_ci#include <linux/fcntl.h> 188c2ecf20Sopenharmony_ci#include <linux/fs.h> 198c2ecf20Sopenharmony_ci#include <linux/gfp.h> 208c2ecf20Sopenharmony_ci#include <linux/if_ether.h> 218c2ecf20Sopenharmony_ci#include <linux/kernel.h> 228c2ecf20Sopenharmony_ci#include <linux/list.h> 238c2ecf20Sopenharmony_ci#include <linux/module.h> 248c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 258c2ecf20Sopenharmony_ci#include <linux/pkt_sched.h> 268c2ecf20Sopenharmony_ci#include <linux/poll.h> 278c2ecf20Sopenharmony_ci#include <linux/printk.h> 288c2ecf20Sopenharmony_ci#include <linux/sched.h> /* for linux/wait.h */ 298c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 308c2ecf20Sopenharmony_ci#include <linux/slab.h> 318c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 328c2ecf20Sopenharmony_ci#include <linux/stddef.h> 338c2ecf20Sopenharmony_ci#include <linux/string.h> 348c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 358c2ecf20Sopenharmony_ci#include <linux/wait.h> 368c2ecf20Sopenharmony_ci#include <uapi/linux/batadv_packet.h> 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#include "debugfs.h" 398c2ecf20Sopenharmony_ci#include "hard-interface.h" 408c2ecf20Sopenharmony_ci#include "log.h" 418c2ecf20Sopenharmony_ci#include "originator.h" 428c2ecf20Sopenharmony_ci#include "send.h" 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic struct batadv_socket_client *batadv_socket_client_hash[256]; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic void batadv_socket_add_packet(struct batadv_socket_client *socket_client, 478c2ecf20Sopenharmony_ci struct batadv_icmp_header *icmph, 488c2ecf20Sopenharmony_ci size_t icmp_len); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci/** 518c2ecf20Sopenharmony_ci * batadv_socket_init() - Initialize soft interface independent socket data 528c2ecf20Sopenharmony_ci */ 538c2ecf20Sopenharmony_civoid batadv_socket_init(void) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci memset(batadv_socket_client_hash, 0, sizeof(batadv_socket_client_hash)); 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic int batadv_socket_open(struct inode *inode, struct file *file) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci unsigned int i; 618c2ecf20Sopenharmony_ci struct batadv_socket_client *socket_client; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci if (!try_module_get(THIS_MODULE)) 648c2ecf20Sopenharmony_ci return -EBUSY; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci batadv_debugfs_deprecated(file, ""); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci stream_open(inode, file); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci socket_client = kmalloc(sizeof(*socket_client), GFP_KERNEL); 718c2ecf20Sopenharmony_ci if (!socket_client) { 728c2ecf20Sopenharmony_ci module_put(THIS_MODULE); 738c2ecf20Sopenharmony_ci return -ENOMEM; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(batadv_socket_client_hash); i++) { 778c2ecf20Sopenharmony_ci if (!batadv_socket_client_hash[i]) { 788c2ecf20Sopenharmony_ci batadv_socket_client_hash[i] = socket_client; 798c2ecf20Sopenharmony_ci break; 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci if (i == ARRAY_SIZE(batadv_socket_client_hash)) { 848c2ecf20Sopenharmony_ci pr_err("Error - can't add another packet client: maximum number of clients reached\n"); 858c2ecf20Sopenharmony_ci kfree(socket_client); 868c2ecf20Sopenharmony_ci module_put(THIS_MODULE); 878c2ecf20Sopenharmony_ci return -EXFULL; 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&socket_client->queue_list); 918c2ecf20Sopenharmony_ci socket_client->queue_len = 0; 928c2ecf20Sopenharmony_ci socket_client->index = i; 938c2ecf20Sopenharmony_ci socket_client->bat_priv = inode->i_private; 948c2ecf20Sopenharmony_ci spin_lock_init(&socket_client->lock); 958c2ecf20Sopenharmony_ci init_waitqueue_head(&socket_client->queue_wait); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci file->private_data = socket_client; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci return 0; 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic int batadv_socket_release(struct inode *inode, struct file *file) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci struct batadv_socket_client *client = file->private_data; 1058c2ecf20Sopenharmony_ci struct batadv_socket_packet *packet, *tmp; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci spin_lock_bh(&client->lock); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci /* for all packets in the queue ... */ 1108c2ecf20Sopenharmony_ci list_for_each_entry_safe(packet, tmp, &client->queue_list, list) { 1118c2ecf20Sopenharmony_ci list_del(&packet->list); 1128c2ecf20Sopenharmony_ci kfree(packet); 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci batadv_socket_client_hash[client->index] = NULL; 1168c2ecf20Sopenharmony_ci spin_unlock_bh(&client->lock); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci kfree(client); 1198c2ecf20Sopenharmony_ci module_put(THIS_MODULE); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci return 0; 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic ssize_t batadv_socket_read(struct file *file, char __user *buf, 1258c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci struct batadv_socket_client *socket_client = file->private_data; 1288c2ecf20Sopenharmony_ci struct batadv_socket_packet *socket_packet; 1298c2ecf20Sopenharmony_ci size_t packet_len; 1308c2ecf20Sopenharmony_ci int error; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci if ((file->f_flags & O_NONBLOCK) && socket_client->queue_len == 0) 1338c2ecf20Sopenharmony_ci return -EAGAIN; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci if (!buf || count < sizeof(struct batadv_icmp_packet)) 1368c2ecf20Sopenharmony_ci return -EINVAL; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci error = wait_event_interruptible(socket_client->queue_wait, 1398c2ecf20Sopenharmony_ci socket_client->queue_len); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (error) 1428c2ecf20Sopenharmony_ci return error; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci spin_lock_bh(&socket_client->lock); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci socket_packet = list_first_entry(&socket_client->queue_list, 1478c2ecf20Sopenharmony_ci struct batadv_socket_packet, list); 1488c2ecf20Sopenharmony_ci list_del(&socket_packet->list); 1498c2ecf20Sopenharmony_ci socket_client->queue_len--; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci spin_unlock_bh(&socket_client->lock); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci packet_len = min(count, socket_packet->icmp_len); 1548c2ecf20Sopenharmony_ci error = copy_to_user(buf, &socket_packet->icmp_packet, packet_len); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci kfree(socket_packet); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (error) 1598c2ecf20Sopenharmony_ci return -EFAULT; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci return packet_len; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic ssize_t batadv_socket_write(struct file *file, const char __user *buff, 1658c2ecf20Sopenharmony_ci size_t len, loff_t *off) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci struct batadv_socket_client *socket_client = file->private_data; 1688c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv = socket_client->bat_priv; 1698c2ecf20Sopenharmony_ci struct batadv_hard_iface *primary_if = NULL; 1708c2ecf20Sopenharmony_ci struct sk_buff *skb; 1718c2ecf20Sopenharmony_ci struct batadv_icmp_packet_rr *icmp_packet_rr; 1728c2ecf20Sopenharmony_ci struct batadv_icmp_header *icmp_header; 1738c2ecf20Sopenharmony_ci struct batadv_orig_node *orig_node = NULL; 1748c2ecf20Sopenharmony_ci struct batadv_neigh_node *neigh_node = NULL; 1758c2ecf20Sopenharmony_ci size_t packet_len = sizeof(struct batadv_icmp_packet); 1768c2ecf20Sopenharmony_ci u8 *addr; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci if (len < sizeof(struct batadv_icmp_header)) { 1798c2ecf20Sopenharmony_ci batadv_dbg(BATADV_DBG_BATMAN, bat_priv, 1808c2ecf20Sopenharmony_ci "Error - can't send packet from char device: invalid packet size\n"); 1818c2ecf20Sopenharmony_ci return -EINVAL; 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci primary_if = batadv_primary_if_get_selected(bat_priv); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci if (!primary_if) { 1878c2ecf20Sopenharmony_ci len = -EFAULT; 1888c2ecf20Sopenharmony_ci goto out; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci if (len >= BATADV_ICMP_MAX_PACKET_SIZE) 1928c2ecf20Sopenharmony_ci packet_len = BATADV_ICMP_MAX_PACKET_SIZE; 1938c2ecf20Sopenharmony_ci else 1948c2ecf20Sopenharmony_ci packet_len = len; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci skb = netdev_alloc_skb_ip_align(NULL, packet_len + ETH_HLEN); 1978c2ecf20Sopenharmony_ci if (!skb) { 1988c2ecf20Sopenharmony_ci len = -ENOMEM; 1998c2ecf20Sopenharmony_ci goto out; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci skb->priority = TC_PRIO_CONTROL; 2038c2ecf20Sopenharmony_ci skb_reserve(skb, ETH_HLEN); 2048c2ecf20Sopenharmony_ci icmp_header = skb_put(skb, packet_len); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci if (copy_from_user(icmp_header, buff, packet_len)) { 2078c2ecf20Sopenharmony_ci len = -EFAULT; 2088c2ecf20Sopenharmony_ci goto free_skb; 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci if (icmp_header->packet_type != BATADV_ICMP) { 2128c2ecf20Sopenharmony_ci batadv_dbg(BATADV_DBG_BATMAN, bat_priv, 2138c2ecf20Sopenharmony_ci "Error - can't send packet from char device: got bogus packet type (expected: BAT_ICMP)\n"); 2148c2ecf20Sopenharmony_ci len = -EINVAL; 2158c2ecf20Sopenharmony_ci goto free_skb; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci switch (icmp_header->msg_type) { 2198c2ecf20Sopenharmony_ci case BATADV_ECHO_REQUEST: 2208c2ecf20Sopenharmony_ci if (len < sizeof(struct batadv_icmp_packet)) { 2218c2ecf20Sopenharmony_ci batadv_dbg(BATADV_DBG_BATMAN, bat_priv, 2228c2ecf20Sopenharmony_ci "Error - can't send packet from char device: invalid packet size\n"); 2238c2ecf20Sopenharmony_ci len = -EINVAL; 2248c2ecf20Sopenharmony_ci goto free_skb; 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) 2288c2ecf20Sopenharmony_ci goto dst_unreach; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci orig_node = batadv_orig_hash_find(bat_priv, icmp_header->dst); 2318c2ecf20Sopenharmony_ci if (!orig_node) 2328c2ecf20Sopenharmony_ci goto dst_unreach; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci neigh_node = batadv_orig_router_get(orig_node, 2358c2ecf20Sopenharmony_ci BATADV_IF_DEFAULT); 2368c2ecf20Sopenharmony_ci if (!neigh_node) 2378c2ecf20Sopenharmony_ci goto dst_unreach; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (!neigh_node->if_incoming) 2408c2ecf20Sopenharmony_ci goto dst_unreach; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (neigh_node->if_incoming->if_status != BATADV_IF_ACTIVE) 2438c2ecf20Sopenharmony_ci goto dst_unreach; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci icmp_packet_rr = (struct batadv_icmp_packet_rr *)icmp_header; 2468c2ecf20Sopenharmony_ci if (packet_len == sizeof(*icmp_packet_rr)) { 2478c2ecf20Sopenharmony_ci addr = neigh_node->if_incoming->net_dev->dev_addr; 2488c2ecf20Sopenharmony_ci ether_addr_copy(icmp_packet_rr->rr[0], addr); 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci break; 2528c2ecf20Sopenharmony_ci default: 2538c2ecf20Sopenharmony_ci batadv_dbg(BATADV_DBG_BATMAN, bat_priv, 2548c2ecf20Sopenharmony_ci "Error - can't send packet from char device: got unknown message type\n"); 2558c2ecf20Sopenharmony_ci len = -EINVAL; 2568c2ecf20Sopenharmony_ci goto free_skb; 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci icmp_header->uid = socket_client->index; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (icmp_header->version != BATADV_COMPAT_VERSION) { 2628c2ecf20Sopenharmony_ci icmp_header->msg_type = BATADV_PARAMETER_PROBLEM; 2638c2ecf20Sopenharmony_ci icmp_header->version = BATADV_COMPAT_VERSION; 2648c2ecf20Sopenharmony_ci batadv_socket_add_packet(socket_client, icmp_header, 2658c2ecf20Sopenharmony_ci packet_len); 2668c2ecf20Sopenharmony_ci goto free_skb; 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci ether_addr_copy(icmp_header->orig, primary_if->net_dev->dev_addr); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci batadv_send_unicast_skb(skb, neigh_node); 2728c2ecf20Sopenharmony_ci goto out; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_cidst_unreach: 2758c2ecf20Sopenharmony_ci icmp_header->msg_type = BATADV_DESTINATION_UNREACHABLE; 2768c2ecf20Sopenharmony_ci batadv_socket_add_packet(socket_client, icmp_header, packet_len); 2778c2ecf20Sopenharmony_cifree_skb: 2788c2ecf20Sopenharmony_ci kfree_skb(skb); 2798c2ecf20Sopenharmony_ciout: 2808c2ecf20Sopenharmony_ci if (primary_if) 2818c2ecf20Sopenharmony_ci batadv_hardif_put(primary_if); 2828c2ecf20Sopenharmony_ci if (neigh_node) 2838c2ecf20Sopenharmony_ci batadv_neigh_node_put(neigh_node); 2848c2ecf20Sopenharmony_ci if (orig_node) 2858c2ecf20Sopenharmony_ci batadv_orig_node_put(orig_node); 2868c2ecf20Sopenharmony_ci return len; 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic __poll_t batadv_socket_poll(struct file *file, poll_table *wait) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci struct batadv_socket_client *socket_client = file->private_data; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci poll_wait(file, &socket_client->queue_wait, wait); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci if (socket_client->queue_len > 0) 2968c2ecf20Sopenharmony_ci return EPOLLIN | EPOLLRDNORM; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci return 0; 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic const struct file_operations batadv_fops = { 3028c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 3038c2ecf20Sopenharmony_ci .open = batadv_socket_open, 3048c2ecf20Sopenharmony_ci .release = batadv_socket_release, 3058c2ecf20Sopenharmony_ci .read = batadv_socket_read, 3068c2ecf20Sopenharmony_ci .write = batadv_socket_write, 3078c2ecf20Sopenharmony_ci .poll = batadv_socket_poll, 3088c2ecf20Sopenharmony_ci .llseek = no_llseek, 3098c2ecf20Sopenharmony_ci}; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci/** 3128c2ecf20Sopenharmony_ci * batadv_socket_setup() - Create debugfs "socket" file 3138c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information 3148c2ecf20Sopenharmony_ci */ 3158c2ecf20Sopenharmony_civoid batadv_socket_setup(struct batadv_priv *bat_priv) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci debugfs_create_file(BATADV_ICMP_SOCKET, 0600, bat_priv->debug_dir, 3188c2ecf20Sopenharmony_ci bat_priv, &batadv_fops); 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci/** 3228c2ecf20Sopenharmony_ci * batadv_socket_add_packet() - schedule an icmp packet to be sent to 3238c2ecf20Sopenharmony_ci * userspace on an icmp socket. 3248c2ecf20Sopenharmony_ci * @socket_client: the socket this packet belongs to 3258c2ecf20Sopenharmony_ci * @icmph: pointer to the header of the icmp packet 3268c2ecf20Sopenharmony_ci * @icmp_len: total length of the icmp packet 3278c2ecf20Sopenharmony_ci */ 3288c2ecf20Sopenharmony_cistatic void batadv_socket_add_packet(struct batadv_socket_client *socket_client, 3298c2ecf20Sopenharmony_ci struct batadv_icmp_header *icmph, 3308c2ecf20Sopenharmony_ci size_t icmp_len) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci struct batadv_socket_packet *socket_packet; 3338c2ecf20Sopenharmony_ci size_t len; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci socket_packet = kmalloc(sizeof(*socket_packet), GFP_ATOMIC); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci if (!socket_packet) 3388c2ecf20Sopenharmony_ci return; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci len = icmp_len; 3418c2ecf20Sopenharmony_ci /* check the maximum length before filling the buffer */ 3428c2ecf20Sopenharmony_ci if (len > sizeof(socket_packet->icmp_packet)) 3438c2ecf20Sopenharmony_ci len = sizeof(socket_packet->icmp_packet); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&socket_packet->list); 3468c2ecf20Sopenharmony_ci memcpy(&socket_packet->icmp_packet, icmph, len); 3478c2ecf20Sopenharmony_ci socket_packet->icmp_len = len; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci spin_lock_bh(&socket_client->lock); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci /* while waiting for the lock the socket_client could have been 3528c2ecf20Sopenharmony_ci * deleted 3538c2ecf20Sopenharmony_ci */ 3548c2ecf20Sopenharmony_ci if (!batadv_socket_client_hash[icmph->uid]) { 3558c2ecf20Sopenharmony_ci spin_unlock_bh(&socket_client->lock); 3568c2ecf20Sopenharmony_ci kfree(socket_packet); 3578c2ecf20Sopenharmony_ci return; 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci list_add_tail(&socket_packet->list, &socket_client->queue_list); 3618c2ecf20Sopenharmony_ci socket_client->queue_len++; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci if (socket_client->queue_len > 100) { 3648c2ecf20Sopenharmony_ci socket_packet = list_first_entry(&socket_client->queue_list, 3658c2ecf20Sopenharmony_ci struct batadv_socket_packet, 3668c2ecf20Sopenharmony_ci list); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci list_del(&socket_packet->list); 3698c2ecf20Sopenharmony_ci kfree(socket_packet); 3708c2ecf20Sopenharmony_ci socket_client->queue_len--; 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci spin_unlock_bh(&socket_client->lock); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci wake_up(&socket_client->queue_wait); 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci/** 3798c2ecf20Sopenharmony_ci * batadv_socket_receive_packet() - schedule an icmp packet to be received 3808c2ecf20Sopenharmony_ci * locally and sent to userspace. 3818c2ecf20Sopenharmony_ci * @icmph: pointer to the header of the icmp packet 3828c2ecf20Sopenharmony_ci * @icmp_len: total length of the icmp packet 3838c2ecf20Sopenharmony_ci */ 3848c2ecf20Sopenharmony_civoid batadv_socket_receive_packet(struct batadv_icmp_header *icmph, 3858c2ecf20Sopenharmony_ci size_t icmp_len) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci struct batadv_socket_client *hash; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci hash = batadv_socket_client_hash[icmph->uid]; 3908c2ecf20Sopenharmony_ci if (hash) 3918c2ecf20Sopenharmony_ci batadv_socket_add_packet(hash, icmph, icmp_len); 3928c2ecf20Sopenharmony_ci} 393