Index: uspace/app/meson.build
===================================================================
--- uspace/app/meson.build	(revision bb4d0b520c39e20a5f604e8fbd4e96fa93516fc0)
+++ uspace/app/meson.build	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
@@ -74,4 +74,6 @@
 	'nterm',
 	'ofw',
+	'pcapcat',
+	'pcapctl',
 	'pci',
 	'ping',
Index: uspace/app/pcapcat/doc/doxygroups.h
===================================================================
--- uspace/app/pcapcat/doc/doxygroups.h	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
+++ uspace/app/pcapcat/doc/doxygroups.h	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
@@ -0,0 +1,4 @@
+/** @addtogroup pcapcat pcapcat
+ * @brief Command-line utility for printing files of PCAP format.
+ * @ingroup apps
+ */
Index: uspace/app/pcapcat/eth_parser.c
===================================================================
--- uspace/app/pcapcat/eth_parser.c	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
+++ uspace/app/pcapcat/eth_parser.c	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2024 Nataliia Korop
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup pcapcat
+ * @{
+ */
+/** @file Implementation of functions for parsing PCAP file of LinkType 1 (LINKTYPE_ETHERNET).
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <str.h>
+#include <pcap.h>
+#include "eth_parser.h"
+
+#define ETH_ADDR_SIZE       6
+#define IPV4_ADDR_SIZE      4
+#define TCP_PORT_SIZE       2
+
+#define ETHER_TYPE_ARP      0x0806
+#define ETHER_TYPE_IP4      0x0800
+#define ETHER_TYPE_IP6      0x86DD
+
+#define BYTE_SIZE           8
+#define HDR_SIZE_COEF       4
+#define LOWER_4_BITS        0xf
+
+#define IP_PROTOCOL_TCP     0x06
+#define IP_PROTOCOL_UDP     0x11
+#define IP_PROTOCOL_ICMP    0x01
+
+#define TCP_TEXT            "TCP"
+#define IP_TEXT             "IP"
+#define MAC_TEXT            "MAC"
+#define ARP_TEXT            "ARP"
+#define IPV4_TEXT           "IPv4"
+#define IPV6_TEXT           "IPv6"
+#define MALFORMED_PACKET    "packet is malformed.\n"
+
+#define PRINT_IP(msg, ip_addr, spaces) printf("%s %s: %d.%d.%d.%d%s", msg, IP_TEXT, ip_addr[0], ip_addr[1], ip_addr[2], ip_addr[3], spaces)
+#define PRINT_MAC(msg, mac, spaces) printf("%s %s: %02x:%02x:%02x:%02x:%02x:%02x%s", msg, MAC_TEXT, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], spaces)
+#define BIG_END_16(buffer, idx) buffer[idx] << BYTE_SIZE | buffer[idx + 1]
+
+/** Offsets of interesting fields in packet. */
+
+#define ARP_SENDER_MAC      22
+#define ARP_SENDER_IP       28
+#define ARP_TARGET_MAC      32
+#define ARP_TARGET_IP       38
+
+#define TCP_SRC_PORT        34
+#define TCP_DST_PORT        36
+
+#define IP_HEADER_LEN       14
+#define IP_TOTAL_LEN        16
+#define IP_PROTOCOL         23
+#define IP_SRC_ADDR         26
+#define IP_DST_ADDR         30
+
+/** Read count bytes from char buffer.
+ *  @param buffer       of bytes to read from.
+ *  @param start_idx    index of the first byte to read.
+ *  @param count        number of byte to read.
+ *  @param dst          destination buffer.
+ */
+static void read_from_buffer(unsigned char *buffer, size_t start_idx, size_t count, uint8_t *dst)
+{
+	for (size_t i = start_idx; i < start_idx + count; ++i) {
+		dst[i - start_idx] = buffer[i];
+	}
+}
+
+/** Parse ARP packet and print out addresses.
+ *  @param buffer   ARP packet.
+ *  @param size     Size of the packet.
+ */
+static void parse_arp(unsigned char *buffer, size_t size)
+{
+	if (size < ARP_TARGET_IP + IPV4_ADDR_SIZE) {
+		printf("%s %s", ARP_TEXT, MALFORMED_PACKET);
+		return;
+	}
+
+	uint8_t sender_mac[ETH_ADDR_SIZE];
+	uint8_t sender_ip[IPV4_ADDR_SIZE];
+	uint8_t target_mac[ETH_ADDR_SIZE];
+	uint8_t target_ip[IPV4_ADDR_SIZE];
+
+	read_from_buffer(buffer, ARP_SENDER_MAC, ETH_ADDR_SIZE, sender_mac);
+	read_from_buffer(buffer, ARP_SENDER_IP, IPV4_ADDR_SIZE, sender_ip);
+	read_from_buffer(buffer, ARP_TARGET_MAC, ETH_ADDR_SIZE, target_mac);
+	read_from_buffer(buffer, ARP_TARGET_IP, IPV4_ADDR_SIZE, target_ip);
+
+	PRINT_MAC("Sender", sender_mac, ", ");
+	PRINT_IP("Sender", sender_ip, "  ");
+	PRINT_MAC("Target", target_mac, ", ");
+	PRINT_IP("Target", target_ip, "\n");
+}
+
+/** Parce TCP and print ports.
+ *  @param buffer   TCP segment.
+ *  @param size     of the buffer.
+ */
+static void parse_tcp(unsigned char *buffer, size_t size)
+{
+	if (size < TCP_DST_PORT + TCP_PORT_SIZE) {
+		printf("%s %s\n", TCP_TEXT, MALFORMED_PACKET);
+		return;
+	}
+
+	uint16_t src_port = BIG_END_16(buffer, TCP_SRC_PORT);
+	uint16_t dst_port = BIG_END_16(buffer, TCP_DST_PORT);
+	printf("      [%s] source port: %d, destination port: %d\n", TCP_TEXT, src_port, dst_port);
+}
+
+/** Parse IP and print interesting parts.
+ *  @param buffer   IP packet.
+ *  @param size     size of the buffer.
+ *  @param verbose  verbosity flag.
+ */
+static void parse_ip(unsigned char *buffer, size_t size, bool verbose)
+{
+	uint16_t total_length;
+	uint8_t header_length;
+	uint16_t payload_length;
+	uint8_t ip_protocol;
+	uint8_t src_ip[IPV4_ADDR_SIZE];
+	uint8_t dst_ip[IPV4_ADDR_SIZE];
+
+	if (size < IP_DST_ADDR + IPV4_ADDR_SIZE) {
+		printf("%s %s", IP_TEXT, MALFORMED_PACKET);
+		return;
+	}
+
+	header_length = (buffer[IP_HEADER_LEN] & LOWER_4_BITS) * HDR_SIZE_COEF;
+	total_length = BIG_END_16(buffer, IP_TOTAL_LEN);
+	payload_length = total_length - header_length;
+	ip_protocol = buffer[IP_PROTOCOL];
+
+	read_from_buffer(buffer, IP_SRC_ADDR, IPV4_ADDR_SIZE, src_ip);
+	read_from_buffer(buffer, IP_DST_ADDR, IPV4_ADDR_SIZE, dst_ip);
+
+	printf("%s header: %dB, payload: %dB, protocol: 0x%x, ", IP_TEXT, header_length, payload_length, ip_protocol);
+	PRINT_IP("Source", src_ip, ", ");
+	PRINT_IP("Destination", dst_ip, "\n");
+
+	if (verbose && ip_protocol == IP_PROTOCOL_TCP) {
+		parse_tcp(buffer, size);
+	}
+}
+
+/** Parse ethernnet frame based on eth_type of the frame.
+ *  @param data         Ethernet frame.
+ *  @param size         Size of the frame.
+ *  @param verbose_flag Verbosity flag.
+ */
+static void parse_eth_frame(void *data, size_t size, bool verbose_flag)
+{
+	unsigned char *buffer = (unsigned char *)data;
+
+	size_t eth_type_offset = 12;
+	uint16_t protocol = BIG_END_16(buffer, eth_type_offset);
+
+	switch (protocol) {
+	case ETHER_TYPE_ARP:
+		printf("[%s] ", ARP_TEXT);
+		parse_arp(buffer, size);
+		break;
+	case ETHER_TYPE_IP4:
+		printf("[%s] ", IPV4_TEXT);
+		parse_ip(buffer, size, verbose_flag);
+		break;
+	case ETHER_TYPE_IP6:
+		printf("[%s]\n", IPV6_TEXT);
+		break;
+	default:
+		printf("[0x%x]\n", protocol);
+		break;
+	}
+}
+
+/** Parse file header of PCAP file.
+ *  @param hdr  PCAP header structure.
+ */
+void eth_parse_header(pcap_file_header_t *hdr)
+{
+	printf("LinkType: %d\n", hdr->additional);
+	printf("Magic number:  0x%x\n", hdr->magic_number);
+}
+
+/** Parse PCAP file.
+ *  @param pcap_file    file of PCAP format with dumped packets.
+ *  @param count        number of packets to be parsed and printed from file (if -1 all packets are printed).
+ *  @param verbose_flag verbosity flag.
+ */
+void eth_parse_frames(FILE *pcap_file, int count, bool verbose_flag)
+{
+	pcap_packet_header_t hdr;
+
+	size_t read_bytes = fread(&hdr, 1, sizeof(pcap_packet_header_t), pcap_file);
+	int packet_index = 1;
+	while (read_bytes > 0) {
+		if (read_bytes < sizeof(pcap_packet_header_t)) {
+			printf("Error: Could not read enough bytes (read %zu bytes)\n", read_bytes);
+			return;
+		}
+
+		printf("%04d) ", packet_index++);
+
+		void *data = malloc(hdr.captured_length);
+		read_bytes = fread(data, 1, (size_t)hdr.captured_length, pcap_file);
+		if (read_bytes < (size_t)hdr.captured_length) {
+			printf("Error: Could not read enough bytes (read %zu bytes)\n", read_bytes);
+			return;
+		}
+		parse_eth_frame(data, (size_t)hdr.captured_length, verbose_flag);
+		free(data);
+
+		//Read first count packets from file.
+		if (count != -1 && count == packet_index - 1) {
+			return;
+		}
+
+		memset(&hdr, 0, sizeof(pcap_packet_header_t));
+		read_bytes = fread(&hdr, 1, sizeof(pcap_packet_header_t), pcap_file);
+	}
+}
+
+/** @}
+ */
Index: uspace/app/pcapcat/eth_parser.h
===================================================================
--- uspace/app/pcapcat/eth_parser.h	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
+++ uspace/app/pcapcat/eth_parser.h	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2024 Nataliia Korop
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup pcapcat
+ * @{
+ */
+/** @file Functions for parsing PCAP file of LinkType 1 (LINKTYPE_ETHERNET).
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <str.h>
+#include <pcap.h>
+
+extern void eth_parse_frames(FILE *, int, bool);
+extern void eth_parse_header(pcap_file_header_t *);
+
+/** @}
+ */
Index: uspace/app/pcapcat/linktype_parser.h
===================================================================
--- uspace/app/pcapcat/linktype_parser.h	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
+++ uspace/app/pcapcat/linktype_parser.h	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2024 Nataliia Korop
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup pcapcat
+ * @{
+ */
+/** @file Structure for parsing PCAP file.
+ */
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <str.h>
+#include <pcap.h>
+
+typedef struct {
+	uint32_t linktype;
+	void (*parse_file_header)(pcap_file_header_t *);
+	void (*parse_packets)(FILE *, int, bool);
+} linktype_parser_t;
+
+/** @}
+ */
Index: uspace/app/pcapcat/main.c
===================================================================
--- uspace/app/pcapcat/main.c	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
+++ uspace/app/pcapcat/main.c	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2024 Nataliia Korop
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <str.h>
+#include <getopt.h>
+#include <io/log.h>
+#include <pcap.h>
+
+#include "linktype_parser.h"
+#include "eth_parser.h"
+
+#define NAME "pcapcat"
+
+static const linktype_parser_t eth_parser = {
+	.parse_packets = &eth_parse_frames,
+	.parse_file_header = &eth_parse_header,
+	.linktype = PCAP_LINKTYPE_ETHERNET
+};
+
+static const linktype_parser_t parsers[1] = { eth_parser };
+
+static int parse_file(const char *file_path, int packet_count, bool verbose_flag)
+{
+	FILE *f = fopen(file_path, "rb");
+	if (f == NULL) {
+		printf("File %s does not exist.\n", file_path);
+		return 1;
+	}
+
+	pcap_file_header_t hdr;
+	memset(&hdr, 0, sizeof(pcap_file_header_t));
+
+	size_t bytes_read = fread(&hdr, 1, sizeof(pcap_file_header_t), f);
+	if (bytes_read < sizeof(pcap_file_header_t)) {
+		printf("Error: Could not read enough bytes (read %zu bytes)\n", bytes_read);
+		fclose(f);
+		return 1;
+	}
+
+	int parser_count = sizeof(parsers) / sizeof(linktype_parser_t);
+	int parser_index = -1;
+	for (int i = 0; i < parser_count; ++i) {
+		if (parsers[i].linktype == hdr.additional) {
+			parser_index = i;
+			break;
+		}
+	}
+
+	if (parser_index == -1) {
+		printf("There is no parser for Linktype %d.\n", hdr.additional);
+		return 1;
+	}
+
+	parsers[parser_index].parse_file_header(&hdr);
+	parsers[parser_index].parse_packets(f, packet_count, verbose_flag);
+
+	fclose(f);
+	return 0;
+}
+
+static void usage()
+{
+	printf("HelenOS cat utility for PCAP file format.\n"
+	    "Can run during dumping process.\n"
+	    "Usage:\n"
+	    NAME " <filename>\n"
+	    "\tPrint all packets from file <filename>.\n"
+	    NAME " --count= | -c <number> <filename>\n"
+	    "\tPrint first <number> packets from <filename>.\n"
+	    NAME " --verbose | -v <filename>\n"
+	    "\tPrint verbose description (with TCP ports) of packets.\n");
+}
+
+static struct option options[] = {
+	{ "count", required_argument, 0, 'c' },
+	{ "verbose", no_argument, 0, 'v' },
+	{ 0, 0, 0, 0 }
+};
+
+int main(int argc, char *argv[])
+{
+	int ret = 0;
+	int idx = 0;
+	int count = -1;
+	bool verbose = false;
+	const char *filename = "";
+	if (argc == 1) {
+		usage();
+		return 0;
+	}
+
+	while (ret != -1) {
+		ret = getopt_long(argc, argv, "c:v", options, &idx);
+		switch (ret) {
+		case 'c':
+			count = atoi(optarg);
+			break;
+		case 'v':
+			verbose = true;
+			break;
+		case '?':
+			printf("Unknown option or missing argument.\n");
+			return 1;
+		default:
+			break;
+		}
+	}
+
+	if (optind < argc) {
+		filename = argv[optind];
+	}
+
+	int ret_val = parse_file(filename, count, verbose);
+
+	return ret_val;
+}
Index: uspace/app/pcapcat/meson.build
===================================================================
--- uspace/app/pcapcat/meson.build	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
+++ uspace/app/pcapcat/meson.build	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
@@ -0,0 +1,29 @@
+#
+# Copyright (c) 2024 Nataliia Korop
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+deps = ['pcap']
+src = files('main.c', 'eth_parser.c')
Index: uspace/app/pcapctl/doc/doxygroups.h
===================================================================
--- uspace/app/pcapctl/doc/doxygroups.h	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
+++ uspace/app/pcapctl/doc/doxygroups.h	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
@@ -0,0 +1,4 @@
+/** @addtogroup pcapctl pcapctl
+ * @brief Command-line utility for dumping packets.
+ * @ingroup apps
+ */
Index: uspace/app/pcapctl/main.c
===================================================================
--- uspace/app/pcapctl/main.c	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
+++ uspace/app/pcapctl/main.c	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2023 Nataliia Korop
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup pcapctl
+ * @{
+ */
+/** @file pcapctl command-line utility.
+ */
+
+#include <stdio.h>
+#include <str.h>
+#include <errno.h>
+#include <arg_parse.h>
+#include <getopt.h>
+#include <vfs/vfs.h>
+
+#include "pcapdump_client.h"
+
+#define NAME 				"pcapctl"
+#define DEFAULT_DEV_NUM 	0
+#define DECIMAL_SYSTEM 		10
+
+/* Default writer operations for dumper, must be consistent with array defined in /uspace/lib/pcap/pcap_dumper.c */
+#define DEFAULT_FILE_OPS 	0
+#define SHORT_FILE_OPS 		1
+#define APPEND_FILE_OPS 	2
+#define USB_FILE_OPS 		3
+
+/** Create async session and send start request.
+ *  @param dev_number index of the device that can dump packets.
+ *  @param name of the output buffer.
+ *  @param ops_index index of the writer operations for the dumper.
+ *  @return EOK if all parameters are valid and start request was sent successfully, error code otherwise.
+ */
+static errno_t start_dumping(int *dev_number, const char *name, int *ops_index)
+{
+	pcapctl_sess_t *sess = NULL;
+	errno_t rc = pcapctl_dump_open(dev_number, &sess);
+	if (rc != EOK) {
+		return 1;
+	}
+
+	rc = pcapctl_is_valid_ops_number(ops_index, sess);
+	if (rc != EOK) {
+		printf("Wrong number of ops: %d.\n", *ops_index);
+		pcapctl_dump_close(sess);
+		return rc;
+	}
+
+	rc = pcapctl_dump_start(name, ops_index, sess);
+	if (rc != EOK) {
+		if (rc == EBUSY) {
+			printf("Dumping for device %d is in progress, stop to start dumping to file %s.\n", *dev_number, name);
+		}
+		printf("Starting the dumping was not successful.\n");
+	}
+	pcapctl_dump_close(sess);
+	return EOK;
+}
+
+/** Create async session and send stop dumping request.
+ *  @param dev_numbe index of the device on which the dumping will be stopped.
+ *  @return EOK if request was sent successfully, error code otherwise.
+ */
+static errno_t stop_dumping(int *dev_number)
+{
+	pcapctl_sess_t *sess = NULL;
+	errno_t rc = pcapctl_dump_open(dev_number, &sess);
+	if (rc != EOK) {
+		return 1;
+	}
+	rc = pcapctl_dump_stop(sess);
+	if (rc != EOK) {
+		printf("Stoping the dumping was not successful.\n");
+	}
+	pcapctl_dump_close(sess);
+	return EOK;
+}
+
+/** Print devices that can dump packets. */
+static void list_devs(void)
+{
+	pcapctl_list();
+}
+
+/**
+ * Array of supported commandline options
+ */
+static const struct option opts[] = {
+	{ "append", required_argument, 0, 'A' }, /* file as argument and ops 0 if not exist and 2 if exists */
+	{ "new", required_argument, 0, 'N' }, /* file name as argument */
+	{ "truncated", required_argument, 0, 'T' }, /* file as an argument with device 0 and dump truncated packets (for debugging purposes) */
+	{ "usb", required_argument, 0, 'U' }, /* dump usb packets (not fully implemnted) */
+	{ "device", required_argument, 0, 'd' },
+	{ "list", no_argument, 0, 'l' },
+	{ "help", no_argument, 0, 'h' },
+	{ "outfile", required_argument, 0, 'o' },
+	{ "start", no_argument, 0, 'r' },
+	{ "stop", no_argument, 0, 't' },
+	{ "ops", required_argument, 0, 'p' },
+	{ "force", no_argument, 0, 'f' },
+	{ 0, 0, 0, 0 }
+};
+
+/** Check if the file exists.
+ *  @param path of the file to check.
+ *  @return true if exists, false otherwise.
+ */
+static bool file_exists(const char *path)
+{
+	vfs_stat_t stats;
+	if (vfs_stat_path(path, &stats) != EOK) {
+		return false;
+	} else {
+		return true;
+	}
+}
+
+static void usage(void)
+{
+	printf("HelenOS Packet Dumping utility.\n"
+	    "Usage:\n"
+	    NAME " --list | -l \n"
+	    "\tList of devices\n"
+	    NAME " --new= | -N <outfile>\n"
+	    "\tStart dumping with ops - 0, on device - 0\n"
+	    NAME " --append= | -A <outfile>\n"
+	    "\tContinue dumping on device - 0 to already existing file\n"
+	    NAME " --truncated= | -T <outfile>\n"
+	    "\tStart dumping truncated packets to file on device - 0\n"
+	    NAME " --start | -r --device= | -d <device number from list> --outfile= | -o <outfile> --ops= | p <ops index>\n"
+	    "\tPackets dumped from device will be written to <outfile>\n"
+	    NAME " --stop | -t --device= | -d <device number from list>\n"
+	    "\tDumping from <device> stops\n"
+	    NAME " --start | -r --outfile= | -o <outfile>\n"
+	    "\tPackets dumped from the 0. device from the list will be written to <outfile>\n"
+	    NAME " --help | -h\n"
+	    "\tShow this application help.\n"
+	    NAME " --force | -f"
+	    "\tTo open existing file and write to it.\n");
+}
+
+int main(int argc, char *argv[])
+{
+	bool start = false;
+	bool stop = false;
+	int dev_number = DEFAULT_DEV_NUM;
+	int ops_number = DEFAULT_FILE_OPS;
+	bool forced = false;
+	const char *output_file_name = "";
+	int idx = 0;
+	int ret = 0;
+	if (argc == 1) {
+		usage();
+		return 0;
+	}
+	while (ret != -1) {
+		ret = getopt_long(argc, argv, "A:N:T:U:d:lho:rtp:f", opts, &idx);
+		switch (ret) {
+		case 'd':
+			char *rest;
+			long dev_result = strtol(optarg, &rest, DECIMAL_SYSTEM);
+			dev_number = (int)dev_result;
+			errno_t rc = pcapctl_is_valid_device(&dev_number);
+			if (rc != EOK) {
+				printf("Device with index %d not found\n", dev_number);
+				return 1;
+			}
+			break;
+		case 'A':
+			start = true;
+			output_file_name = optarg;
+			if (file_exists(output_file_name)) {
+				ops_number = APPEND_FILE_OPS;
+			}
+			break;
+		case 'N':
+			start = true;
+			output_file_name = optarg;
+			break;
+		case 'T':
+			start = true;
+			output_file_name = optarg;
+			ops_number = SHORT_FILE_OPS;
+			break;
+		case 'U':
+			start = true;
+			output_file_name = optarg;
+			ops_number = USB_FILE_OPS;
+			break;
+		case 'l':
+			list_devs();
+			return 0;
+		case 'h':
+			usage();
+			return 0;
+		case 'o':
+			output_file_name = optarg;
+			break;
+		case 'r':
+			start = true;
+			break;
+		case 't':
+			stop = true;
+			break;
+		case 'p':
+			char *ops_inval;
+			long ops_result = strtol(optarg, &ops_inval, DECIMAL_SYSTEM);
+			ops_number = (int)ops_result;
+			break;
+		case 'f':
+			forced = true;
+			break;
+		}
+	}
+
+	if (!str_cmp(output_file_name, "") && start) {
+		printf("Dumping destination was not specified. Specify with --outfile | -o\n");
+		return 1;
+	}
+
+	if (start) {
+
+		if (file_exists(output_file_name) && !forced && ops_number != 2) {
+			printf("File %s already exists. If you want to overwrite it, then use flag --force.\n", output_file_name);
+			return 0;
+		}
+
+		printf("Start dumping on device - %d, ops - %d.\n", dev_number, ops_number);
+
+		/* start with dev number and name */
+		start_dumping(&dev_number, output_file_name, &ops_number);
+	} else if (stop) {
+		/* stop with dev number */
+		printf("Stop dumping on device - %d.\n", dev_number);
+		stop_dumping(&dev_number);
+	} else {
+		usage();
+		return 1;
+	}
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/app/pcapctl/meson.build
===================================================================
--- uspace/app/pcapctl/meson.build	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
+++ uspace/app/pcapctl/meson.build	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
@@ -0,0 +1,29 @@
+#
+# Copyright (c) 2023 Nataliia Korop
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+deps = ['pcap']
+src = files('main.c')
