From patchwork Tue May 3 09:00:48 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sven Eckelmann X-Patchwork-Id: 16039 X-Patchwork-Delegate: mareklindner@neomailbox.ch Return-Path: X-Original-To: patchwork@open-mesh.org Delivered-To: patchwork@open-mesh.org Received: from open-mesh.org (localhost [IPv6:::1]) by open-mesh.org (Postfix) with ESMTP id 7038482546; Tue, 3 May 2016 11:00:57 +0200 (CEST) Authentication-Results: open-mesh.org; dmarc=none header.from=open-mesh.com Authentication-Results: open-mesh.org; dkim=fail reason="verification failed; unprotected key" header.d=open-mesh-com.20150623.gappssmtp.com header.i=@open-mesh-com.20150623.gappssmtp.com header.b=RcKNcj5g; dkim-adsp=none (unprotected policy); dkim-atps=neutral Received-SPF: Neutral (access neither permitted nor denied) identity=mailfrom; client-ip=2a00:1450:400c:c09::22a; helo=mail-wm0-x22a.google.com; envelope-from=sven.eckelmann@open-mesh.com; receiver=b.a.t.m.a.n@lists.open-mesh.org Authentication-Results: open-mesh.org; dmarc=none header.from=open-mesh.com Received: from mail-wm0-x22a.google.com (mail-wm0-x22a.google.com [IPv6:2a00:1450:400c:c09::22a]) by open-mesh.org (Postfix) with ESMTPS id CC8EE82511 for ; Tue, 3 May 2016 11:00:55 +0200 (CEST) Received: by mail-wm0-x22a.google.com with SMTP id e201so136911089wme.0 for ; Tue, 03 May 2016 02:00:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=open-mesh-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=+uX7k3MvSpJiAPu3IMWpRfpw/3vdJgx/ukE7qxpxNSg=; b=RcKNcj5gyp8W2HOvESBL1e9yaCvYN7rCuCFchX31RIuP1p7m5KO4GqQAdLx+QgFW1s bWolDborehF/hadTMJQxZWPSc8dbAKKqbks2Jf+vuZcI4WJvmtkrzyP/VfEBzbgxezHx lvTHB/rX+PVZaSRgIv3HfHQNo8U7FfwGXurc/MAlMWyqujIEQikdQrCKnaaZSWjrgIYi nXJVQUiD/P8RtHqMa3V3+G839QhzavQmm0MZe1phN94sNH1tMO7JARpMGmzIbseG3VnG 8dM67fzlR/rmi1kdrzMek/d7SybYe0dpesp7EijuwvS/j+g4rsSkvhbFC/Kxe9/sUjt4 Lxlw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=+uX7k3MvSpJiAPu3IMWpRfpw/3vdJgx/ukE7qxpxNSg=; b=j5xV/Xmk0bXzILUCyZs0sc1lA2U6gnz3am2IjUFjJD+gWZ7M4zVBqUfHrqkfQGZweb RsE4v2Us0blAtmrhn6F0nyNifzPZaKeDxO+Chwvh1G7LxAYL5jVGPWhKcdRlctrVygjg +KljV1w5yFbR2dk/9Mtu/Xd0ea+TesNxXPcMfb5QChsSBgLcWgoZieIeDvDRkA+6FExC R2BFDwQMM+8hJzDbMXXh0/0D6UctqXK11rEOWSeUaqIz3VdFaH8zGYQOk7KWlLzy4pyz t3NI0glTLpcgplqq78VnhLB2AUjMR1mTztlhAlmXkNuVk9mMcXRHfkGFyS2QpjpvR9Dp wEtQ== X-Gm-Message-State: AOPr4FUDeS4ggnaGWwX7QlRhzxU3QaR23SUb/el4D4GlkR8ghicEWuR18hK6W2MpdhpcTPs9 X-Received: by 10.28.31.6 with SMTP id f6mr22666375wmf.69.1462266055441; Tue, 03 May 2016 02:00:55 -0700 (PDT) Received: from sven-desktop.home.narfation.org (p579E6B06.dip0.t-ipconnect.de. [87.158.107.6]) by smtp.gmail.com with ESMTPSA id jp2sm2655200wjc.16.2016.05.03.02.00.54 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 03 May 2016 02:00:55 -0700 (PDT) From: Sven Eckelmann X-Google-Original-From: Sven Eckelmann To: b.a.t.m.a.n@lists.open-mesh.org Date: Tue, 3 May 2016 11:00:48 +0200 Message-Id: <1462266049-13531-1-git-send-email-sven@open-mesh.com> X-Mailer: git-send-email 2.8.1 In-Reply-To: <1894217.a7ufKNXfSr@bentobox> References: <1894217.a7ufKNXfSr@bentobox> Cc: Sven Eckelmann , Antonio Quartulli Subject: [B.A.T.M.A.N.] [PATCH v3 2/3] batman-adv: use another ICMP packet when sending command from userspace X-BeenThere: b.a.t.m.a.n@lists.open-mesh.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: The list for a Better Approach To Mobile Ad-hoc Networking List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: The list for a Better Approach To Mobile Ad-hoc Networking Errors-To: b.a.t.m.a.n-bounces@lists.open-mesh.org Sender: "B.A.T.M.A.N" From: Antonio Quartulli In the current code a real batadv ICMP packet is used to communicate from userspace to the module which ICMP operation should be start (the operation to start depends on the size of the received packet). This worked good so far because the same packet was used to perform the only two available ICMP operations and the very same packet received from userspace was also sent over the wire to perform the operation itself. As soon as we add new and different ICMP operations this model will not work well anymore. To improve this feature make the userspace use a proper packet type to tell the kernel module which operation to start. The module will then arrange the rest by itself. Signed-off-by: Antonio Quartulli Signed-off-by: Sven Eckelmann --- v3: - Rebase on current master version - inform batctl about problems finding the remote originator v2: - Rebase on current master version --- net/batman-adv/icmp_socket.c | 212 +++++++++++++++++++++++++------------------ net/batman-adv/icmp_socket.h | 5 +- net/batman-adv/packet.h | 15 +++ net/batman-adv/types.h | 2 + 4 files changed, 140 insertions(+), 94 deletions(-) diff --git a/net/batman-adv/icmp_socket.c b/net/batman-adv/icmp_socket.c index 777aea1..7284510 100644 --- a/net/batman-adv/icmp_socket.c +++ b/net/batman-adv/icmp_socket.c @@ -52,8 +52,7 @@ static struct batadv_socket_client *batadv_socket_client_hash[256]; static void batadv_socket_add_packet(struct batadv_socket_client *socket_client, - struct batadv_icmp_header *icmph, - size_t icmp_len); + void *icmp_buffer, size_t icmp_len); void batadv_socket_init(void) { @@ -157,7 +156,7 @@ static ssize_t batadv_socket_read(struct file *file, char __user *buf, spin_unlock_bh(&socket_client->lock); packet_len = min(count, socket_packet->icmp_len); - error = copy_to_user(buf, &socket_packet->icmp_packet, packet_len); + error = copy_to_user(buf, &socket_packet->packet, packet_len); kfree(socket_packet); @@ -167,73 +166,90 @@ static ssize_t batadv_socket_read(struct file *file, char __user *buf, return packet_len; } -static ssize_t batadv_socket_write(struct file *file, const char __user *buff, - size_t len, loff_t *off) +/** + * batadv_socket_write_user - Parse batadv_icmp_user_packet + * @bat_priv: the bat priv with all the icmp socket information + * @socket_client: layer2 icmp socket client data + * @primary_if: the selected primary interface + * @buff: buffer of user data + * @len: length of the data in buff + * + * Return: Number of read bytes from buff or < 0 on errors + */ +static ssize_t +batadv_socket_write_user(struct batadv_priv *bat_priv, + struct batadv_socket_client *socket_client, + struct batadv_hard_iface *primary_if, + const char __user *buff, size_t len) +{ + struct batadv_icmp_user_packet icmp_user_packet; + + if (copy_from_user(&icmp_user_packet, buff, len)) + return -EFAULT; + + /* no command supported yet! */ + len = -EINVAL; + + return len; +} + +/** + * batadv_socket_write_raw - Parse batadv_icmp_packet/batadv_icmp_packet_rr + * @bat_priv: the bat priv with all the icmp socket information + * @socket_client: layer2 icmp socket client data + * @primary_if: the selected primary interface + * @buff: buffer of user data + * @len: length of the data in buff + * + * Return: Number of read bytes from buff or < 0 on errors + */ +static ssize_t +batadv_socket_write_raw(struct batadv_priv *bat_priv, + struct batadv_socket_client *socket_client, + struct batadv_hard_iface *primary_if, + const char __user *buff, size_t len) { - 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; struct sk_buff *skb; - struct batadv_icmp_packet_rr *icmp_packet_rr; - struct batadv_icmp_header *icmp_header; + struct batadv_icmp_packet_rr icmp_packet, *icmp_buff; struct batadv_orig_node *orig_node = NULL; struct batadv_neigh_node *neigh_node = NULL; - size_t packet_len = sizeof(struct batadv_icmp_packet); + size_t packet_len; u8 *addr; - if (len < sizeof(struct batadv_icmp_header)) { + if (len != sizeof(struct batadv_icmp_packet_rr) && + 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"); return -EINVAL; } - primary_if = batadv_primary_if_get_selected(bat_priv); - - if (!primary_if) { - len = -EFAULT; - goto out; - } - - if (len >= BATADV_ICMP_MAX_PACKET_SIZE) - packet_len = BATADV_ICMP_MAX_PACKET_SIZE; - else - packet_len = len; - - skb = netdev_alloc_skb_ip_align(NULL, packet_len + ETH_HLEN); - if (!skb) { - len = -ENOMEM; - goto out; - } + packet_len = len; + if (copy_from_user(&icmp_packet, buff, len)) + return -EFAULT; - skb->priority = TC_PRIO_CONTROL; - skb_reserve(skb, ETH_HLEN); - icmp_header = (struct batadv_icmp_header *)skb_put(skb, packet_len); + icmp_packet.uid = socket_client->index; - if (copy_from_user(icmp_header, buff, packet_len)) { - len = -EFAULT; - goto free_skb; + /* if the compat version does not match, return an error now */ + if (icmp_packet.version != BATADV_COMPAT_VERSION) { + icmp_packet.msg_type = BATADV_PARAMETER_PROBLEM; + icmp_packet.version = BATADV_COMPAT_VERSION; + batadv_socket_add_packet(socket_client, &icmp_packet, + packet_len); + return len; } - if (icmp_header->packet_type != BATADV_ICMP) { + if (icmp_packet.packet_type != BATADV_ICMP) { batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "Error - can't send packet from char device: got bogus packet type (expected: BAT_ICMP)\n"); - len = -EINVAL; - goto free_skb; + return -EINVAL; } - switch (icmp_header->msg_type) { + switch (icmp_packet.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); + orig_node = batadv_orig_hash_find(bat_priv, icmp_packet.dst); if (!orig_node) goto dst_unreach; @@ -248,47 +264,68 @@ static ssize_t batadv_socket_write(struct file *file, const char __user *buff, if (neigh_node->if_incoming->if_status != BATADV_IF_ACTIVE) goto dst_unreach; - icmp_packet_rr = (struct batadv_icmp_packet_rr *)icmp_header; - 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); - } - break; default: batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "Error - can't send packet from char device: got unknown message type\n"); - len = -EINVAL; - goto free_skb; + return -EINVAL; } - icmp_header->uid = socket_client->index; + skb = netdev_alloc_skb_ip_align(NULL, packet_len + ETH_HLEN); + if (!skb) + return -ENOMEM; - if (icmp_header->version != BATADV_COMPAT_VERSION) { - icmp_header->msg_type = BATADV_PARAMETER_PROBLEM; - icmp_header->version = BATADV_COMPAT_VERSION; - batadv_socket_add_packet(socket_client, icmp_header, - packet_len); - goto free_skb; - } + skb->priority = TC_PRIO_CONTROL; + skb_reserve(skb, ETH_HLEN); + icmp_buff = (struct batadv_icmp_packet_rr *)skb_put(skb, packet_len); + memcpy(icmp_buff, &icmp_packet, packet_len); - ether_addr_copy(icmp_header->orig, primary_if->net_dev->dev_addr); + ether_addr_copy(icmp_buff->orig, primary_if->net_dev->dev_addr); + + switch (icmp_packet.msg_type) { + case BATADV_ECHO_REQUEST: + if (len == sizeof(struct batadv_icmp_packet_rr)) { + addr = neigh_node->if_incoming->net_dev->dev_addr; + ether_addr_copy(icmp_packet.rr[0], addr); + } + break; + } batadv_send_unicast_skb(skb, neigh_node); goto out; dst_unreach: - icmp_header->msg_type = BATADV_DESTINATION_UNREACHABLE; - batadv_socket_add_packet(socket_client, icmp_header, packet_len); -free_skb: - kfree_skb(skb); + icmp_packet.msg_type = BATADV_DESTINATION_UNREACHABLE; + batadv_socket_add_packet(socket_client, &icmp_packet, packet_len); out: - if (primary_if) - batadv_hardif_put(primary_if); if (neigh_node) batadv_neigh_node_put(neigh_node); if (orig_node) batadv_orig_node_put(orig_node); + + return len; +} + +static ssize_t batadv_socket_write(struct file *file, const char __user *buff, + size_t len, loff_t *off) +{ + struct batadv_socket_client *socket_client = file->private_data; + struct batadv_priv *bat_priv = socket_client->bat_priv; + struct batadv_hard_iface *primary_if; + + primary_if = batadv_primary_if_get_selected(bat_priv); + if (!primary_if) + return -EFAULT; + + if (len == sizeof(struct batadv_icmp_user_packet)) + len = batadv_socket_write_user(bat_priv, socket_client, + primary_if, buff, len); + else + len = batadv_socket_write_raw(bat_priv, socket_client, + primary_if, buff, len); + + batadv_hardif_put(primary_if); + return len; } @@ -336,36 +373,29 @@ err: * batadv_socket_add_packet - schedule an icmp packet to be sent to * userspace on an icmp socket. * @socket_client: the socket this packet belongs to - * @icmph: pointer to the header of the icmp packet + * @icmp_buffer: pointer to the icmp packet * @icmp_len: total length of the icmp packet */ static void batadv_socket_add_packet(struct batadv_socket_client *socket_client, - struct batadv_icmp_header *icmph, - size_t icmp_len) + void *icmp_buffer, size_t icmp_len) { struct batadv_socket_packet *socket_packet; - size_t len; - - socket_packet = kmalloc(sizeof(*socket_packet), GFP_ATOMIC); + struct batadv_icmp_packet *icmp_packet; + icmp_packet = (struct batadv_icmp_packet *)icmp_buffer; + socket_packet = kmalloc(sizeof(*socket_packet) + icmp_len, GFP_ATOMIC); if (!socket_packet) return; - len = icmp_len; - /* check the maximum length before filling the buffer */ - if (len > sizeof(socket_packet->icmp_packet)) - len = sizeof(socket_packet->icmp_packet); - - INIT_LIST_HEAD(&socket_packet->list); - memcpy(&socket_packet->icmp_packet, icmph, len); - socket_packet->icmp_len = len; + memcpy(socket_packet->packet, icmp_packet, icmp_len); + socket_packet->icmp_len = icmp_len; spin_lock_bh(&socket_client->lock); /* while waiting for the lock the socket_client could have been * deleted */ - if (!batadv_socket_client_hash[icmph->uid]) { + if (!batadv_socket_client_hash[icmp_packet->uid]) { spin_unlock_bh(&socket_client->lock); kfree(socket_packet); return; @@ -392,15 +422,17 @@ static void batadv_socket_add_packet(struct batadv_socket_client *socket_client, /** * 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_buffer: pointer to the the icmp packet * @icmp_len: total length of the icmp packet */ -void batadv_socket_receive_packet(struct batadv_icmp_header *icmph, - size_t icmp_len) +void batadv_socket_receive_packet(void *icmp_buffer, size_t icmp_len) { struct batadv_socket_client *hash; + struct batadv_icmp_packet *icmp; + + icmp = (struct batadv_icmp_packet *)icmp_buffer; - hash = batadv_socket_client_hash[icmph->uid]; + hash = batadv_socket_client_hash[icmp->uid]; if (hash) - batadv_socket_add_packet(hash, icmph, icmp_len); + batadv_socket_add_packet(hash, icmp_buffer, icmp_len); } diff --git a/net/batman-adv/icmp_socket.h b/net/batman-adv/icmp_socket.h index 618d5de..0043b44 100644 --- a/net/batman-adv/icmp_socket.h +++ b/net/batman-adv/icmp_socket.h @@ -22,13 +22,10 @@ #include -struct batadv_icmp_header; - #define BATADV_ICMP_SOCKET "socket" void batadv_socket_init(void); int batadv_socket_setup(struct batadv_priv *bat_priv); -void batadv_socket_receive_packet(struct batadv_icmp_header *icmph, - size_t icmp_len); +void batadv_socket_receive_packet(void *icmp_buffer, size_t icmp_len); #endif /* _NET_BATMAN_ADV_ICMP_SOCKET_H_ */ diff --git a/net/batman-adv/packet.h b/net/batman-adv/packet.h index 372128d..459836a 100644 --- a/net/batman-adv/packet.h +++ b/net/batman-adv/packet.h @@ -285,6 +285,21 @@ struct batadv_elp_packet { #define BATADV_ELP_HLEN sizeof(struct batadv_elp_packet) /** + * struct batadv_icmp_user_packet - used to start an ICMP operation from + * userspace + * @dst: destination node + * @version: compat version used by userspace + * @cmd_type: the command to start + * @arg1: possible argument for the command + */ +struct batadv_icmp_user_packet { + u8 dst[ETH_ALEN]; + u8 version; + u8 cmd_type; + u32 arg1; +}; + +/** * struct batadv_icmp_header - common members among all the ICMP packets * @packet_type: batman-adv packet type, part of the general header * @version: batman-adv protocol version, part of the genereal header diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 6a577f4..bc9bb9a 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -995,11 +995,13 @@ struct batadv_socket_client { * @list: list node for batadv_socket_client::queue_list * @icmp_len: size of the layer2 icmp packet * @icmp_packet: layer2 icmp packet + * @packet: payload of layer2 icmp packet */ struct batadv_socket_packet { struct list_head list; size_t icmp_len; u8 icmp_packet[BATADV_ICMP_MAX_PACKET_SIZE]; + u8 packet[0]; }; #ifdef CONFIG_BATMAN_ADV_BLA