diff --git a/abi/include/abi/ipc/interfaces.h b/abi/include/abi/ipc/interfaces.h index fb72d49da4..1781a52c37 100644 --- a/abi/include/abi/ipc/interfaces.h +++ b/abi/include/abi/ipc/interfaces.h @@ -205,7 +205,9 @@ typedef enum { INTERFACE_SYSTEM = FOURCC_COMPACT('s', 's', 't', 'm') | IFACE_EXCHANGE_SERIALIZE, INTERFACE_SYSTEM_CB = - FOURCC_COMPACT('s', 's', 't', 'm') | IFACE_EXCHANGE_SERIALIZE | IFACE_MOD_CALLBACK + FOURCC_COMPACT('s', 's', 't', 'm') | IFACE_EXCHANGE_SERIALIZE | IFACE_MOD_CALLBACK, + INTERFACE_PCAP_CONTROL = + FOURCC_COMPACT('p', 'c', 't', 'l') | IFACE_EXCHANGE_SERIALIZE, } iface_t; #endif diff --git a/uspace/app/meson.build b/uspace/app/meson.build index 7505a71473..25f9d14aa6 100644 --- a/uspace/app/meson.build +++ b/uspace/app/meson.build @@ -71,6 +71,8 @@ apps = [ 'nic', 'nterm', 'ofw', + 'pcapcat', + 'pcapctl', 'pci', 'ping', 'pkg', diff --git a/uspace/app/pcapcat/doc/doxygroups.h b/uspace/app/pcapcat/doc/doxygroups.h new file mode 100644 index 0000000000..1402226765 --- /dev/null +++ b/uspace/app/pcapcat/doc/doxygroups.h @@ -0,0 +1,4 @@ +/** @addtogroup pcapcat pcapcat + * @brief Command-line utility for printing files of PCAP format. + * @ingroup apps + */ diff --git a/uspace/app/pcapcat/eth_parser.c b/uspace/app/pcapcat/eth_parser.c new file mode 100644 index 0000000000..fb4a0b8f14 --- /dev/null +++ b/uspace/app/pcapcat/eth_parser.c @@ -0,0 +1,258 @@ +/* + * 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 +#include +#include +#include +#include +#include +#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); + } +} + +/** @} + */ \ No newline at end of file diff --git a/uspace/app/pcapcat/eth_parser.h b/uspace/app/pcapcat/eth_parser.h new file mode 100644 index 0000000000..0288a0bdf9 --- /dev/null +++ b/uspace/app/pcapcat/eth_parser.h @@ -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 +#include +#include +#include +#include +#include +#include +#include + +extern void eth_parse_frames(FILE *, int, bool); +extern void eth_parse_header(pcap_file_header_t *); + +/** @} + */ \ No newline at end of file diff --git a/uspace/app/pcapcat/linktype_parser.h b/uspace/app/pcapcat/linktype_parser.h new file mode 100644 index 0000000000..d361d27f09 --- /dev/null +++ b/uspace/app/pcapcat/linktype_parser.h @@ -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 +#include +#include +#include + +typedef struct { + uint32_t linktype; + void (*parse_file_header)(pcap_file_header_t *); + void (*parse_packets)(FILE *, int, bool); +} linktype_parser_t; + +/** @} + */ diff --git a/uspace/app/pcapcat/main.c b/uspace/app/pcapcat/main.c new file mode 100644 index 0000000000..8fad8f71a0 --- /dev/null +++ b/uspace/app/pcapcat/main.c @@ -0,0 +1,152 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "linktype_parser.h" +#include "eth_parser.h" + +#define NAME "pcapcat" + +static const linktype_parser_t eth_parser = { + .parse_packets = ð_parse_frames, + .parse_file_header = ð_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 " \n" + "\tPrint all packets from file .\n" + NAME " --count= | -c \n" + "\tPrint first packets from .\n" + NAME " --verbose | -v \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; +} \ No newline at end of file diff --git a/uspace/app/pcapcat/meson.build b/uspace/app/pcapcat/meson.build new file mode 100644 index 0000000000..6de8726c41 --- /dev/null +++ b/uspace/app/pcapcat/meson.build @@ -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') \ No newline at end of file diff --git a/uspace/app/pcapctl/doc/doxygroups.h b/uspace/app/pcapctl/doc/doxygroups.h new file mode 100644 index 0000000000..1fe7582026 --- /dev/null +++ b/uspace/app/pcapctl/doc/doxygroups.h @@ -0,0 +1,4 @@ +/** @addtogroup pcapctl pcapctl + * @brief Command-line utility for dumping packets. + * @ingroup apps + */ diff --git a/uspace/app/pcapctl/main.c b/uspace/app/pcapctl/main.c new file mode 100644 index 0000000000..6d8be1d6e2 --- /dev/null +++ b/uspace/app/pcapctl/main.c @@ -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 +#include +#include +#include +#include +#include + +#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' }, /* todo: 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 \n" + "\tStart dumping with ops - 0, on device - 0\n" + NAME " --append= | -A \n" + "\tContinue dumping on device - 0 to already existing file\n" + NAME " --truncated= | -T \n" + "\tStart dumping truncated packets to file on device - 0\n" + NAME " --start | -r --device= | -d --outfile= | -o --ops= | p \n" + "\tPackets dumped from device will be written to \n" + NAME " --stop | -t --device= | -d \n" + "\tDumping from stops\n" + NAME " --start | -r --outfile= | -o \n" + "\tPackets dumped from the 0. device from the list will be written to \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; +} + +/** @} + */ diff --git a/uspace/app/pcapctl/meson.build b/uspace/app/pcapctl/meson.build new file mode 100644 index 0000000000..e9d54819e1 --- /dev/null +++ b/uspace/app/pcapctl/meson.build @@ -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') \ No newline at end of file diff --git a/uspace/drv/nic/e1k/e1k.c b/uspace/drv/nic/e1k/e1k.c index ccc86d61dd..e2658adb87 100644 --- a/uspace/drv/nic/e1k/e1k.c +++ b/uspace/drv/nic/e1k/e1k.c @@ -174,6 +174,7 @@ typedef struct { /** Lock for EEPROM access */ fibril_mutex_t eeprom_lock; + } e1000_t; /** Global mutex for work with shared irq structure */ @@ -1191,6 +1192,7 @@ static void e1000_receive_frames(nic_t *nic) nic_frame_t *frame = nic_alloc_frame(nic, frame_size); if (frame != NULL) { memcpy(frame->data, e1000->rx_frame_virt[next_tail], frame_size); + nic_received_frame(nic, frame); } else { ddf_msg(LVL_ERROR, "Memory allocation failed. Frame dropped."); @@ -2200,14 +2202,14 @@ errno_t e1000_dev_add(ddf_dev_t *dev) if (rc != EOK) goto err_fun_bind; - rc = ddf_fun_add_to_category(fun, DEVICE_CATEGORY_NIC); - if (rc != EOK) - goto err_add_to_cat; - + rc = nic_fun_add_to_cats(fun); + if (rc != EOK) { + ddf_msg(LVL_ERROR, "Failed adding function to categories"); + ddf_fun_unbind(fun); + return rc; + } return EOK; -err_add_to_cat: - ddf_fun_unbind(fun); err_fun_bind: err_rx_structure: e1000_uninitialize_rx_structure(nic); @@ -2387,7 +2389,6 @@ static void e1000_send_frame(nic_t *nic, void *data, size_t size) } memcpy(e1000->tx_frame_virt[tdt], data, size); - tx_descriptor_addr->phys_addr = PTR_TO_U64(e1000->tx_frame_phys[tdt]); tx_descriptor_addr->length = size; diff --git a/uspace/drv/nic/e1k/meson.build b/uspace/drv/nic/e1k/meson.build index 847cb2e8c7..d6980678f7 100644 --- a/uspace/drv/nic/e1k/meson.build +++ b/uspace/drv/nic/e1k/meson.build @@ -26,5 +26,5 @@ # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # -deps = [ 'nic' ] +deps = [ 'nic' , 'pcap' ] src = files('e1k.c') diff --git a/uspace/drv/nic/ne2k/ne2k.c b/uspace/drv/nic/ne2k/ne2k.c index f3962854f2..206cc5d768 100644 --- a/uspace/drv/nic/ne2k/ne2k.c +++ b/uspace/drv/nic/ne2k/ne2k.c @@ -43,6 +43,7 @@ #include #include #include +#include #include "dp8390.h" #define NAME "ne2k" @@ -449,10 +450,10 @@ static errno_t ne2k_dev_add(ddf_dev_t *dev) return rc; } - rc = ddf_fun_add_to_category(fun, DEVICE_CATEGORY_NIC); + rc = nic_fun_add_to_cats(fun); if (rc != EOK) { + ddf_msg(LVL_ERROR, "Failed adding function to categories"); ddf_fun_unbind(fun); - ddf_fun_destroy(fun); return rc; } @@ -496,6 +497,7 @@ int main(int argc, char *argv[]) nic_driver_init(NAME); nic_driver_implement(&ne2k_driver_ops, &ne2k_dev_ops, &ne2k_nic_iface); + ddf_log_init(NAME); return ddf_driver_main(&ne2k_driver); } diff --git a/uspace/drv/nic/rtl8139/driver.c b/uspace/drv/nic/rtl8139/driver.c index 22cf8426af..22cf5f3295 100644 --- a/uspace/drv/nic/rtl8139/driver.c +++ b/uspace/drv/nic/rtl8139/driver.c @@ -1312,10 +1312,12 @@ errno_t rtl8139_dev_add(ddf_dev_t *dev) ddf_msg(LVL_ERROR, "Failed binding device function"); goto err_fun_create; } - rc = ddf_fun_add_to_category(fun, DEVICE_CATEGORY_NIC); + + rc = nic_fun_add_to_cats(fun); if (rc != EOK) { - ddf_msg(LVL_ERROR, "Failed adding function to category"); - goto err_fun_bind; + ddf_msg(LVL_ERROR, "Failed adding function to categories"); + ddf_fun_unbind(fun); + return rc; } ddf_msg(LVL_NOTE, "The %s device has been successfully initialized.", @@ -1323,8 +1325,8 @@ errno_t rtl8139_dev_add(ddf_dev_t *dev) return EOK; -err_fun_bind: - ddf_fun_unbind(fun); + // err_fun_bind: + // ddf_fun_unbind(fun); err_fun_create: ddf_fun_destroy(fun); err_srv: diff --git a/uspace/drv/nic/rtl8169/driver.c b/uspace/drv/nic/rtl8169/driver.c index 6ccf5295d1..7cc8571f09 100644 --- a/uspace/drv/nic/rtl8169/driver.c +++ b/uspace/drv/nic/rtl8169/driver.c @@ -460,18 +460,19 @@ static errno_t rtl8169_dev_add(ddf_dev_t *dev) goto err_fun_create; } - rc = ddf_fun_add_to_category(fun, DEVICE_CATEGORY_NIC); + rc = nic_fun_add_to_cats(fun); if (rc != EOK) { - ddf_msg(LVL_ERROR, "Failed adding function to category"); - goto err_fun_bind; + ddf_msg(LVL_ERROR, "Failed adding function to categories"); + ddf_fun_unbind(fun); + return rc; } ddf_msg(LVL_NOTE, "The %s device has been successfully initialized.", ddf_dev_get_name(dev)); return EOK; -err_fun_bind: - ddf_fun_unbind(fun); + // err_fun_bind: + // ddf_fun_unbind(fun); err_fun_create: ddf_fun_destroy(fun); err_srv: diff --git a/uspace/drv/nic/virtio-net/virtio-net.c b/uspace/drv/nic/virtio-net/virtio-net.c index 84db8ea49b..fa5d9889a5 100644 --- a/uspace/drv/nic/virtio-net/virtio-net.c +++ b/uspace/drv/nic/virtio-net/virtio-net.c @@ -427,10 +427,11 @@ static errno_t virtio_net_dev_add(ddf_dev_t *dev) goto destroy; } - rc = ddf_fun_add_to_category(fun, DEVICE_CATEGORY_NIC); + rc = nic_fun_add_to_cats(fun); if (rc != EOK) { - ddf_msg(LVL_ERROR, "Failed adding function to category"); - goto unbind; + ddf_msg(LVL_ERROR, "Failed adding function to categories"); + ddf_fun_unbind(fun); + return rc; } ddf_msg(LVL_NOTE, "The %s device has been successfully initialized.", @@ -438,8 +439,8 @@ static errno_t virtio_net_dev_add(ddf_dev_t *dev) return EOK; -unbind: - ddf_fun_unbind(fun); + // unbind: + // ddf_fun_unbind(fun); destroy: ddf_fun_destroy(fun); uninitialize: diff --git a/uspace/lib/c/include/ipc/services.h b/uspace/lib/c/include/ipc/services.h index 34ed1531f1..0b3f591e18 100644 --- a/uspace/lib/c/include/ipc/services.h +++ b/uspace/lib/c/include/ipc/services.h @@ -66,7 +66,6 @@ typedef enum { #define SERVICE_NAME_TCP "net/tcp" #define SERVICE_NAME_VBD "vbd" #define SERVICE_NAME_VOLSRV "volsrv" - #endif /** @} diff --git a/uspace/lib/meson.build b/uspace/lib/meson.build index f3b92ee22b..3dd3dc7ffe 100644 --- a/uspace/lib/meson.build +++ b/uspace/lib/meson.build @@ -82,6 +82,7 @@ libs = [ 'minix', 'nettl', 'ofw', + 'pcap', 'pcm', 'pcut', 'pixconv', diff --git a/uspace/lib/nic/include/nic.h b/uspace/lib/nic/include/nic.h index fe832c71d0..14367f4bc4 100644 --- a/uspace/lib/nic/include/nic.h +++ b/uspace/lib/nic/include/nic.h @@ -43,6 +43,7 @@ #include #include #include +#include #define DEVICE_CATEGORY_NIC "nic" @@ -277,6 +278,11 @@ extern uint64_t nic_query_mcast_hash(nic_t *); extern void nic_sw_period_start(nic_t *); extern void nic_sw_period_stop(nic_t *); +/* pcapdump interface */ +extern pcap_dumper_t *nic_get_pcap_dumper(nic_t *); + +extern errno_t nic_fun_add_to_cats(ddf_fun_t *fun); + #endif // __NIC_H__ /** @} diff --git a/uspace/lib/nic/include/nic_driver.h b/uspace/lib/nic/include/nic_driver.h index 019741ab4f..9abc3d6060 100644 --- a/uspace/lib/nic/include/nic_driver.h +++ b/uspace/lib/nic/include/nic_driver.h @@ -45,6 +45,7 @@ #include #include #include +#include #include "nic.h" #include "nic_rx_control.h" @@ -194,6 +195,10 @@ struct nic { * The implementation is optional. */ poll_request_handler on_poll_request; + + /** Packets dumper. */ + pcap_dumper_t dumper; + /** Data specific for particular driver */ void *specific; }; diff --git a/uspace/lib/nic/include/nic_impl.h b/uspace/lib/nic/include/nic_impl.h index d09de679c1..72a43e121c 100644 --- a/uspace/lib/nic/include/nic_impl.h +++ b/uspace/lib/nic/include/nic_impl.h @@ -86,8 +86,6 @@ extern void nic_default_handler_impl(ddf_fun_t *dev_fun, ipc_call_t *call); extern errno_t nic_open_impl(ddf_fun_t *fun); extern void nic_close_impl(ddf_fun_t *fun); -extern void nic_device_added_impl(ddf_dev_t *dev); - #endif /** @} diff --git a/uspace/lib/nic/meson.build b/uspace/lib/nic/meson.build index 5241065dad..0ec1788cd8 100644 --- a/uspace/lib/nic/meson.build +++ b/uspace/lib/nic/meson.build @@ -26,7 +26,7 @@ # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # -deps = [ 'drv' ] +deps = [ 'drv' , 'pcap' ] c_args = [ '-DLIBNIC_INTERNAL', ] src = files( 'src/nic_driver.c', diff --git a/uspace/lib/nic/src/nic_driver.c b/uspace/lib/nic/src/nic_driver.c index ba11079988..6f502a5112 100644 --- a/uspace/lib/nic/src/nic_driver.c +++ b/uspace/lib/nic/src/nic_driver.c @@ -46,6 +46,7 @@ #include #include #include +#include #include "nic_driver.h" #include "nic_ev.h" @@ -521,6 +522,7 @@ void nic_received_frame(nic_t *nic_data, nic_frame_t *frame) * Note: this function must not lock main lock, because loopback driver * calls it inside send_frame handler (with locked main lock) */ + pcapdump_packet(nic_get_pcap_dumper(nic_data), frame->data, frame->size); fibril_rwlock_read_lock(&nic_data->rxc_lock); nic_frame_type_t frame_type; bool check = nic_rxc_check(&nic_data->rx_control, frame->data, @@ -559,6 +561,7 @@ void nic_received_frame(nic_t *nic_data, nic_frame_t *frame) } fibril_rwlock_write_unlock(&nic_data->stats_lock); } + //pcapdump_packet(nic_get_pcap_dumper(nic_data), frame->data, frame->size); nic_release_frame(nic_data, frame); } @@ -647,6 +650,11 @@ nic_t *nic_create_and_bind(ddf_dev_t *device) nic_data->dev = device; + errno_t pcap_rc = pcapdump_init(nic_get_pcap_dumper(nic_data)); + if (pcap_rc != EOK) { + printf("Failed creating pcapdump port\n"); + } + return nic_data; } @@ -1132,5 +1140,10 @@ void nic_sw_period_stop(nic_t *nic_data) nic_data->sw_poll_info.running = 0; } +pcap_dumper_t *nic_get_pcap_dumper(nic_t *nic_data) +{ + return &nic_data->dumper; +} + /** @} */ diff --git a/uspace/lib/nic/src/nic_impl.c b/uspace/lib/nic/src/nic_impl.c index d3595471be..5dac2d92dd 100644 --- a/uspace/lib/nic/src/nic_impl.c +++ b/uspace/lib/nic/src/nic_impl.c @@ -39,6 +39,7 @@ #include #include #include +#include #include "nic_driver.h" #include "nic_ev.h" #include "nic_impl.h" @@ -178,7 +179,7 @@ errno_t nic_send_frame_impl(ddf_fun_t *fun, void *data, size_t size) fibril_rwlock_read_unlock(&nic_data->main_lock); return EBUSY; } - + pcapdump_packet(nic_get_pcap_dumper(nic_data), data, size); nic_data->send_frame(nic_data, data, size); fibril_rwlock_read_unlock(&nic_data->main_lock); return EOK; @@ -842,5 +843,19 @@ void nic_close_impl(ddf_fun_t *fun) { } +errno_t nic_fun_add_to_cats(ddf_fun_t *fun) +{ + errno_t rc; + rc = ddf_fun_add_to_category(fun, DEVICE_CATEGORY_NIC); + if (rc != EOK) + return rc; + + rc = ddf_fun_add_to_category(fun, "pcap"); + if (rc != EOK) { + return rc; + } + return EOK; +} + /** @} */ diff --git a/uspace/lib/pcap/doc/doxygoups.h b/uspace/lib/pcap/doc/doxygoups.h new file mode 100644 index 0000000000..fe5d716a84 --- /dev/null +++ b/uspace/lib/pcap/doc/doxygoups.h @@ -0,0 +1,3 @@ +/** @addtogroup libpcap libpcap + * @ingroup libs + */ diff --git a/uspace/lib/pcap/include/pcap.h b/uspace/lib/pcap/include/pcap.h new file mode 100644 index 0000000000..9a76b9e1b7 --- /dev/null +++ b/uspace/lib/pcap/include/pcap.h @@ -0,0 +1,104 @@ +/* + * 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 libpcap + * @{ + */ +/** + * @file + * @brief Headers and functions for PCAP format and packets to be dumped. + */ + +#ifndef PCAP_H_ +#define PCAP_H_ + +#include +#include +#include +#include +#include +#include + +#define PCAP_MAGIC_MICRO 0xA1B2C3D4 /** Sets time in seconds and microseconds in packet records. */ +#define PCAP_MAGIC_NANO 0xA1B23C4D /** Sets time in seconds and nanoseconds in packet records. */ +#define PCAP_MAJOR_VERSION 0x0002 /** Major version of the PCAP format. */ +#define PCAP_MINOR_VERSION 0x0004 /** Miner version of the PCAP format. */ +#define PCAP_SNAP_LEN 0x00040000 /** Maximum number of bytes that can be captured for one packet record. */ + +#define PCAP_LINKTYPE_ETHERNET 1 /* IEEE 802.3 Ethernet */ +#define PCAP_LINKTYPE_IP_RAW 101 /* Raw IP packet */ +#define PCAP_LINKTYPE_IEEE802_11_RADIO 127 +#define PCAP_LINKTYPE_USB_LINUX_MMAPPED 220 + +/** Header of the .pcap file. */ +typedef struct { + uint32_t magic_number; + uint16_t major_v; + uint16_t minor_v; + uint32_t reserved1; + uint32_t reserved2; + uint32_t snaplen; + uint32_t additional; /** The LinkType and additional information field is in the form */ +} pcap_file_header_t; + +/** Header of the packet to be dumped to .pcap file. */ +typedef struct pcap_packet_header { + uint32_t seconds_stamp; + uint32_t magic_stamp; + uint32_t captured_length; + uint32_t original_length; +} pcap_packet_header_t; + +typedef struct pcap_writer pcap_writer_t; + +/** Writing operations for destination buffer. */ +typedef struct { + errno_t (*open)(pcap_writer_t *, const char *); + size_t (*write_u32)(pcap_writer_t *, uint32_t); + size_t (*write_u16)(pcap_writer_t *, uint16_t); + size_t (*write_buffer)(pcap_writer_t *, const void *, size_t); + void (*close)(pcap_writer_t *); +} pcap_writer_ops_t; + +/** Structure for writing data to the destination buffer. */ +struct pcap_writer { + /** Writing buffer. */ + void *data; + /** Writing operations for working with the buffer. */ + pcap_writer_ops_t *ops; +}; + +extern void pcap_writer_add_header(pcap_writer_t *writer, uint32_t linktype); +extern void pcap_writer_add_packet(pcap_writer_t *writer, const void *captured_packet, size_t size); +extern void pcap_set_time(pcap_packet_header_t *header); + +#endif + +/** @} + */ diff --git a/uspace/lib/pcap/include/pcap_dumper.h b/uspace/lib/pcap/include/pcap_dumper.h new file mode 100644 index 0000000000..ccc97c6087 --- /dev/null +++ b/uspace/lib/pcap/include/pcap_dumper.h @@ -0,0 +1,60 @@ +/* + * 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 libpcap + * @{ + */ +/** @file Pcap dumper. Structure is a part of every device that is in category PCAP and can dump packets. + */ + +#ifndef PCAP_IFACE_H_ +#define PCAP_IFACE_H_ + +#include +#include +#include "pcap.h" + +/** Packet dumper structure that is responsible for dumping packets. */ +typedef struct pcap_dumper { + fibril_mutex_t mutex; + /** Flag that indicates, whether the packet should be dumped or ignored. */ + bool to_dump; + /** Writer structure that is responsible for writing data to the destination buffer. */ + pcap_writer_t writer; +} pcap_dumper_t; + +extern errno_t pcap_dumper_start(pcap_dumper_t *, const char *); +extern void pcap_dumper_stop(pcap_dumper_t *); +extern int pcap_dumper_get_ops_number(void); +extern errno_t pcap_dumper_set_ops(pcap_dumper_t *, int); +extern void pcap_dumper_add_packet(pcap_dumper_t *, const void *data, size_t size); + +#endif + +/** @} + */ diff --git a/uspace/lib/pcap/include/pcapdump_client.h b/uspace/lib/pcap/include/pcapdump_client.h new file mode 100644 index 0000000000..11569efff4 --- /dev/null +++ b/uspace/lib/pcap/include/pcapdump_client.h @@ -0,0 +1,64 @@ +/* + * 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 libpcap + * @{ + */ +/** + * @file Client side of the IPC communication for pcapctl. + * + */ + +#ifndef _PCAPDUMP_CLIENT_H_ +#define _PCAPDUMP_CLIENT_H_ + +#include +#include +#include +#include +#include + +/** IPC session structure for pcapctl utility. */ +typedef struct { + async_sess_t *sess; +} pcapctl_sess_t; + +extern errno_t pcapctl_dump_open(int *, pcapctl_sess_t **); +extern errno_t pcapctl_dump_close(pcapctl_sess_t *); + +extern errno_t pcapctl_dump_start(const char *, int *, pcapctl_sess_t *); +extern errno_t pcapctl_dump_stop(pcapctl_sess_t *); +extern errno_t pcapctl_list(void); +extern errno_t pcapctl_is_valid_device(int *); +extern errno_t pcapctl_is_valid_ops_number(int *, pcapctl_sess_t *); + +#endif + +/** @} + */ diff --git a/uspace/lib/pcap/include/pcapdump_drv_iface.h b/uspace/lib/pcap/include/pcapdump_drv_iface.h new file mode 100644 index 0000000000..768bf1ef5c --- /dev/null +++ b/uspace/lib/pcap/include/pcapdump_drv_iface.h @@ -0,0 +1,50 @@ +/* + * 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 libpcap + * @{ + */ +/** + * @file Driver interface. Functions that are used in drivers that can dump packets. + * + */ + +#ifndef _PCAPDUMP_DRV_IFACE_H_ +#define _PCAPDUMP_DRV_IFACE_H_ + +#include +#include "pcap_dumper.h" + +extern errno_t pcapdump_init(pcap_dumper_t *); +extern void pcapdump_packet(pcap_dumper_t *, const void *, size_t); + +#endif + +/** @} + */ diff --git a/uspace/lib/pcap/include/pcapdump_ipc.h b/uspace/lib/pcap/include/pcapdump_ipc.h new file mode 100644 index 0000000000..50d0030bfb --- /dev/null +++ b/uspace/lib/pcap/include/pcapdump_ipc.h @@ -0,0 +1,53 @@ +/* + * 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 libpcap + * @{ + */ +/** + * @file IPC requests defined for pcap category. + * + */ + +#ifndef _PCAPDUMP_IPC_H_ +#define _PCAPDUMP_IPC_H_ + +#include + +/** IPC requests for INTERFACE_PCAP_CONTROL interface. */ +typedef enum { + PCAP_CONTROL_SET_START = IPC_FIRST_USER_METHOD, + PCAP_CONTROL_SET_STOP, + PCAP_CONTROL_GET_OPS_NUM, +} pcap_request_t; + +#endif + +/** @} + */ diff --git a/uspace/lib/pcap/include/pcapdump_srv.h b/uspace/lib/pcap/include/pcapdump_srv.h new file mode 100644 index 0000000000..168e2c9363 --- /dev/null +++ b/uspace/lib/pcap/include/pcapdump_srv.h @@ -0,0 +1,47 @@ +/* + * 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 libpcap + * @{ + */ +/** + * @file Server side of the IPC communication for dumping packets framework. + * + */ + +#ifndef _PCAPDUMP_IFACE_H_ +#define _PCAPDUMP_IFACE_H_ + +#include + +extern void pcapdump_conn(ipc_call_t *, void *); +#endif + +/** @} + */ diff --git a/uspace/lib/pcap/meson.build b/uspace/lib/pcap/meson.build new file mode 100644 index 0000000000..fb7c890a30 --- /dev/null +++ b/uspace/lib/pcap/meson.build @@ -0,0 +1,35 @@ +# +# 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. +# + +src = files( + 'src/pcap.c', + 'src/pcap_dumper.c', + 'src/pcapdump_srv.c', + 'src/pcapdump_client.c', + 'src/pcapdump_drv_iface.c', +) diff --git a/uspace/lib/pcap/src/pcap.c b/uspace/lib/pcap/src/pcap.c new file mode 100644 index 0000000000..a8700a0695 --- /dev/null +++ b/uspace/lib/pcap/src/pcap.c @@ -0,0 +1,90 @@ +/* + * 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 libpcap + * @{ + */ +/** + * @file + * @brief Headers and functions for .pcap file and packets to be dumped + */ + +#include "pcap.h" + +/** Set time in seconds and microseconds for the packet header . + * + * @param header Header of the packet to be dumped. + * + */ +void pcap_set_time(pcap_packet_header_t *header) +{ + struct timespec ts; + getrealtime(&ts); + header->seconds_stamp = (uint32_t)ts.tv_sec; + header->magic_stamp = (uint32_t)ts.tv_sec / 1000; +} + +/** Add pcap file header to the new .pcap file. + * + * @param writer Writer that has destination buffer and ops to write to destination buffer. + * @param linktype Linktype for the file header. + */ +void pcap_writer_add_header(pcap_writer_t *writer, uint32_t linktype) +{ + pcap_file_header_t file_header = { (uint32_t)PCAP_MAGIC_MICRO, PCAP_MAJOR_VERSION, PCAP_MINOR_VERSION, + 0x00000000, 0x00000000, (uint32_t)PCAP_SNAP_LEN, linktype }; + writer->ops->write_buffer(writer, &file_header, sizeof(file_header)); +} + +/** Add packet to the .pcap file. + * + * @param writer Writer that has destination buffer and ops to write to destination buffer. + * @param captured_packet Packet to be dumped + * @param size Size of the captured packet + * + */ +void pcap_writer_add_packet(pcap_writer_t *writer, const void *captured_packet, size_t size) +{ + + pcap_packet_header_t pcap_packet; + pcap_set_time(&pcap_packet); + pcap_packet.original_length = size; + + if (PCAP_SNAP_LEN < size) { + pcap_packet.captured_length = PCAP_SNAP_LEN; + } else { + pcap_packet.captured_length = size; + } + writer->ops->write_buffer(writer, &pcap_packet, sizeof(pcap_packet)); + writer->ops->write_buffer(writer, captured_packet, pcap_packet.captured_length); + +} + +/** @} + */ diff --git a/uspace/lib/pcap/src/pcap_dumper.c b/uspace/lib/pcap/src/pcap_dumper.c new file mode 100644 index 0000000000..560b809265 --- /dev/null +++ b/uspace/lib/pcap/src/pcap_dumper.c @@ -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 libpcap + * @{ + */ +/** @file Pcap dumper. Structure is a part of every device that is in category PCAP and can dump packets. + */ + +#include +#include +#include +#include "pcap_dumper.h" + +#define SHORT_OPS_BYTE_COUNT 0x3C + +/** Initialize writing to .pcap file. + * + * @param writer Interface for writing data. + * @param filename Name of the file for dumping packets. + * @return EOK on success, otherwise an error code. + * + */ +static errno_t pcap_writer_to_file_init(pcap_writer_t *writer, const char *filename) +{ + /** For overwriting file if already exists. */ + writer->data = fopen(filename, "w"); + if (writer->data == NULL) { + return EINVAL; + } + fclose(writer->data); + + writer->data = fopen(filename, "a"); + if (writer->data == NULL) { + return EINVAL; + } + pcap_writer_add_header(writer, (uint32_t)PCAP_LINKTYPE_ETHERNET); + + return EOK; +} + +/** Open file for appending to the end of it. + * @param writer Interface for writing data. + * @param filename Path to the file. + * @return EOK on success, error code otherwise. + */ +static errno_t pcap_writer_to_file_init_append(pcap_writer_t *writer, const char *filename) +{ + writer->data = fopen(filename, "a"); + if (writer->data == NULL) { + return EINVAL; + } + + return EOK; +} + +/** Initialize file for dumping usb packets. + * @param writer Interface for writing data. + * @param filename Path to the file. + * @return EOK on success, error code otherwise. + */ +static errno_t pcap_writer_to_file_usb_init(pcap_writer_t *writer, const char *filename) +{ + /** For overwriting file if already exists. */ + writer->data = fopen(filename, "w"); + if (writer->data == NULL) { + return EINVAL; + } + fclose(writer->data); + + writer->data = fopen(filename, "a"); + if (writer->data == NULL) { + return EINVAL; + } + pcap_writer_add_header(writer, (uint32_t)PCAP_LINKTYPE_USB_LINUX_MMAPPED); + + return EOK; +} + +/** Write 4B to the file. + * @param writer Interface for writing data. + * @param data Bytes to write. + * @return Size of successfully witten data. + */ +static size_t pcap_file_w32(pcap_writer_t *writer, uint32_t data) +{ + return fwrite(&data, 1, 4, (FILE *)writer->data); +} + +/** Write 2B to the file. + * @param writer Interface for writing data. + * @param data Bytes to write. + * @return Size of successfully witten data. + */ +static size_t pcap_file_w16(pcap_writer_t *writer, uint16_t data) +{ + return fwrite(&data, 1, 2, (FILE *)writer->data); +} + +/** Write block of bytes to the file. + * @param writer Interface for writing data. + * @param data Bytes to write. + * @param size Size of block of bytes. + * @return Size of successfully witten data. + */ +static size_t pcap_file_wbuffer(pcap_writer_t *writer, const void *data, size_t size) +{ + assert(writer->data); + return fwrite(data, 1, size, (FILE *)writer->data); +} + +/** Close file for writing. + * @param writer Interaface for writing data. + */ +static void pcap_file_close(pcap_writer_t *writer) +{ + fclose((FILE *)writer->data); + writer->data = NULL; +} + +/** Write <= 60B of block of bytes. + * @param writer Interface for writing data. + * @param data Bytes to write. + * @param size Size of block of bytes. + * @return Size of successfully witten data. + */ +static size_t pcap_short_file_wbuffer(pcap_writer_t *writer, const void *data, size_t size) +{ + return fwrite(data, 1, size < SHORT_OPS_BYTE_COUNT ? size : SHORT_OPS_BYTE_COUNT, (FILE *)writer->data); +} + +/** Standard writer operations for writing data to a newly created file. */ +static const pcap_writer_ops_t file_ops = { + .open = &pcap_writer_to_file_init, + .write_u32 = &pcap_file_w32, + .write_u16 = &pcap_file_w16, + .write_buffer = &pcap_file_wbuffer, + .close = &pcap_file_close +}; + +/** Truncated writer operations. Only first 60 bytes of the packet are written. */ +static const pcap_writer_ops_t short_file_ops = { + .open = &pcap_writer_to_file_init, + .write_u32 = &pcap_file_w32, + .write_u16 = &pcap_file_w16, + .write_buffer = &pcap_short_file_wbuffer, + .close = &pcap_file_close + +}; + +/** Append writer operations. Instead of creating new file open existing file and append packets. */ +static const pcap_writer_ops_t append_file_ops = { + .open = &pcap_writer_to_file_init_append, + .write_u32 = &pcap_file_w32, + .write_u16 = &pcap_file_w16, + .write_buffer = &pcap_file_wbuffer, + .close = &pcap_file_close +}; + +/** USB writer operations. Writing USB packets to the file. */ +static const pcap_writer_ops_t usb_file_ops = { + .open = &pcap_writer_to_file_usb_init, + .write_u32 = &pcap_file_w32, + .write_u16 = &pcap_file_w16, + .write_buffer = &pcap_file_wbuffer, + .close = &pcap_file_close +}; + +/** Default array of operations. Must be consistens with constants in /uspace/app/pcapctl/main.c */ +static pcap_writer_ops_t ops[4] = { file_ops, short_file_ops, append_file_ops, usb_file_ops }; + +/** Get number of writer operations in @ref ops */ +int pcap_dumper_get_ops_number(void) +{ + return (int)(sizeof(ops) / sizeof(pcap_writer_ops_t)); +} + +/** Open destination buffer for writing and set flag for dumping. + * @param dumper Structure responsible for dumping packets. Part of the driver. + * @param name Name of the destination buffer to dump packets to. + * @return EOK if successful, erro code otherwise. + */ +errno_t pcap_dumper_start(pcap_dumper_t *dumper, const char *name) +{ + fibril_mutex_lock(&dumper->mutex); + + errno_t rc = dumper->writer.ops->open(&dumper->writer, name); + if (rc == EOK) { + dumper->to_dump = true; + } + + fibril_mutex_unlock(&dumper->mutex); + return rc; +} + +/** Set writer options for the writer. + * @param dumper Structure responsible for dumping packets. Part of the driver. + * @param index Index of the writer operations from array @ref ops. + * @return EOK if successful, erro code otherwise. + */ +errno_t pcap_dumper_set_ops(pcap_dumper_t *dumper, int index) +{ + fibril_mutex_lock(&dumper->mutex); + dumper->writer.ops = &ops[index]; + fibril_mutex_unlock(&dumper->mutex); + return EOK; +} + +/** Write packet to destination buffer. + * @param dumper Structure responsible for dumping packets. Part of the driver. + * @param data Packet data to write. + * @param size Size of the packet. + */ +void pcap_dumper_add_packet(pcap_dumper_t *dumper, const void *data, size_t size) +{ + fibril_mutex_lock(&dumper->mutex); + + if (!dumper->to_dump) { + fibril_mutex_unlock(&dumper->mutex); + return; + } + + pcap_writer_add_packet(&dumper->writer, data, size); + fibril_mutex_unlock(&dumper->mutex); +} + +/** Close destination buffer for writing and unset flag for dumping. + * @param dumper Structure responsible for dumping packets. Part of the driver. + */ +void pcap_dumper_stop(pcap_dumper_t *dumper) +{ + fibril_mutex_lock(&dumper->mutex); + + /** If want to stop, when already stopped, do nothing */ + if (!dumper->to_dump) { + fibril_mutex_unlock(&dumper->mutex); + return; + } + dumper->to_dump = false; + dumper->writer.ops->close(&dumper->writer); + fibril_mutex_unlock(&dumper->mutex); +} + +/** @} + */ diff --git a/uspace/lib/pcap/src/pcapdump_client.c b/uspace/lib/pcap/src/pcapdump_client.c new file mode 100644 index 0000000000..8925d77597 --- /dev/null +++ b/uspace/lib/pcap/src/pcapdump_client.c @@ -0,0 +1,264 @@ +/* + * 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 libpcap + * @{ + */ +/** @file Client side of the pcapctl. Functions are called from the app pcapctl. + */ + +#include +#include +#include +#include +#include +#include +#include "pcapdump_client.h" +#include "pcapdump_ipc.h" + +/** Finish an async exchange on the pcapctl session + * + * @param exch Exchange to be finished + */ +static void pcapctl_dump_exchange_end(async_exch_t *exch) +{ + async_exchange_end(exch); +} + +/** Get service based on the index of the device. + * @param index of the device. + * @param svc placeholder for service ide. + * @return EOK if successful, error code otherwise. + */ +static errno_t pcapctl_cat_get_svc(int *index, service_id_t *svc) +{ + errno_t rc; + category_id_t pcap_cat; + size_t count; + service_id_t *pcap_svcs = NULL; + + rc = loc_category_get_id("pcap", &pcap_cat, 0); + if (rc != EOK) { + fprintf(stderr, "Error resolving category 'pcap'.\n"); + return rc; + } + + rc = loc_category_get_svcs(pcap_cat, &pcap_svcs, &count); + if (rc != EOK) { + fprintf(stderr, "Error resolving list of pcap services.\n"); + free(pcap_svcs); + return rc; + } + if (*index < (int)count) { + *svc = pcap_svcs[*index]; + free(pcap_svcs); + return EOK; + } + + return ENOENT; +} + +/** Check if the index is an index of valid device. + * @param index to check. + * @return EOK if device is valid, error code otherwise. + */ +errno_t pcapctl_is_valid_device(int *index) +{ + errno_t rc; + category_id_t pcap_cat; + size_t count; + service_id_t *pcap_svcs = NULL; + + rc = loc_category_get_id("pcap", &pcap_cat, 0); + if (rc != EOK) { + fprintf(stderr, "Error resolving category pcap.\n"); + return rc; + } + + rc = loc_category_get_svcs(pcap_cat, &pcap_svcs, &count); + if (rc != EOK) { + fprintf(stderr, "Error resolving list of pcap services.\n"); + free(pcap_svcs); + return rc; + } + if (*index + 1 > (int)count || *index < 0) { + return EINVAL; + } + return EOK; +} + +/** Check if the index is an index of valid writer operations. + * @param index to check. + * @param sess pcapctl session for IPC communictaion. + */ +errno_t pcapctl_is_valid_ops_number(int *index, pcapctl_sess_t *sess) +{ + async_exch_t *exch = async_exchange_begin(sess->sess); + ipc_call_t answer; + aid_t req = async_send_0(exch, PCAP_CONTROL_GET_OPS_NUM, &answer); + + async_exchange_end(exch); + + errno_t retval; + async_wait_for(req, &retval); + + if (retval != EOK) { + return retval; + } + + int ops_count = (int)ipc_get_arg1(&answer); + if (*index + 1 > ops_count || *index < 0) { + return EINVAL; + } + return EOK; +} + +/** Get all devices that can dump packets. */ +errno_t pcapctl_list(void) +{ + errno_t rc; + category_id_t pcap_cat; + size_t count; + service_id_t *pcap_svcs = NULL; + + rc = loc_category_get_id("pcap", &pcap_cat, 0); + if (rc != EOK) { + fprintf(stderr, "Error resolving category pcap.\n"); + return rc; + } + + rc = loc_category_get_svcs(pcap_cat, &pcap_svcs, &count); + if (rc != EOK) { + fprintf(stderr, "Error resolving list of pcap services.\n"); + free(pcap_svcs); + return rc; + } + + fprintf(stdout, "Devices:\n"); + for (unsigned i = 0; i < count; ++i) { + char *name = NULL; + loc_service_get_name(pcap_svcs[i], &name); + fprintf(stdout, "%d. %s\n", i, name); + } + free(pcap_svcs); + return EOK; +} + +/** Start pcapctl IPC session. + * @param index index of the device which can dump packets. + * @param rsess placeholder for the session. + * @return EOK if successful, error code otherwise. + */ +errno_t pcapctl_dump_open(int *index, pcapctl_sess_t **rsess) +{ + errno_t rc; + service_id_t svc; + pcapctl_sess_t *sess = calloc(1, sizeof(pcapctl_sess_t)); + if (sess == NULL) + return ENOMEM; + + if (*index == -1) { + *index = 0; + } + + rc = pcapctl_cat_get_svc(index, &svc); + if (rc != EOK) { + fprintf(stderr, "Error finding the device with index: %d\n", *index); + goto error; + } + + async_sess_t *new_session = loc_service_connect(svc, INTERFACE_PCAP_CONTROL, 0); + if (new_session == NULL) { + fprintf(stderr, "Error connecting to service.\n"); + rc = EREFUSED; + goto error; + } + + sess->sess = new_session; + *rsess = sess; + return EOK; +error: + pcapctl_dump_close(sess); + return rc; +} + +/** Close pcapctl IPC session. + * @param sess Session to close. + * @return EOK if successful, error code otherwise. + */ +errno_t pcapctl_dump_close(pcapctl_sess_t *sess) +{ + free(sess); + return EOK; +} + +/** Send start request via IPC to start dumping. + * + * @param name Name of the destination buffer to dump packets to. + * @param sess Session that is used for communication. + * @return EOK on success or an error code. + */ +errno_t pcapctl_dump_start(const char *name, int *ops_index, pcapctl_sess_t *sess) +{ + errno_t rc; + async_exch_t *exch = async_exchange_begin(sess->sess); + + size_t size = str_size(name); + aid_t req = async_send_1(exch, PCAP_CONTROL_SET_START, *ops_index, NULL); + + rc = async_data_write_start(exch, name, size); + + pcapctl_dump_exchange_end(exch); + + if (rc != EOK) { + async_forget(req); + return rc; + } + + errno_t retval; + async_wait_for(req, &retval); + return retval; +} + +/** Send stop request via IPC to start dumping. + * + * @param sess Session that is used for communication. + * @return EOK on success or an error code. + */ +errno_t pcapctl_dump_stop(pcapctl_sess_t *sess) +{ + errno_t rc; + async_exch_t *exch = async_exchange_begin(sess->sess); + rc = async_req_0_0(exch, PCAP_CONTROL_SET_STOP); + + pcapctl_dump_exchange_end(exch); + return rc; +} + +/** @} + */ diff --git a/uspace/lib/pcap/src/pcapdump_drv_iface.c b/uspace/lib/pcap/src/pcapdump_drv_iface.c new file mode 100644 index 0000000000..eb2cd68928 --- /dev/null +++ b/uspace/lib/pcap/src/pcapdump_drv_iface.c @@ -0,0 +1,106 @@ +/* + * 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 libpcap + * @{ + */ +/** + * @file Functions that are called inside driver that can dump packets/ + * + */ + +#include +#include +#include +#include +#include +#include + +#include "pcapdump_srv.h" +#include "pcapdump_drv_iface.h" + +#define NAME "pcap" + +/** Initialize interface for dumping packets. + * @param dumper Device dumping interface. + * @return EOK if successful, error code otherwise. + */ +static errno_t pcapdump_drv_dumper_init(pcap_dumper_t *dumper) +{ + fibril_mutex_initialize(&dumper->mutex); + dumper->to_dump = false; + dumper->writer.ops = NULL; + + errno_t rc = log_init(NAME); + if (rc != EOK) { + printf("%s : Failed to initialize log.\n", NAME); + return 1; + } + return EOK; +} + +/** Initialize driver dumping functionality. + * @param dumper Dumping interface of the driver. + * @return EOK if successful, error code otherwise. + */ +errno_t pcapdump_init(pcap_dumper_t *dumper) +{ + port_id_t port; + errno_t rc; + + rc = pcapdump_drv_dumper_init(dumper); + if (rc != EOK) { + log_msg(LOG_DEFAULT, LVL_DEBUG, "Failed initializing pcap dumper: %s", str_error(rc)); + return rc; + } + + rc = async_create_port(INTERFACE_PCAP_CONTROL, pcapdump_conn, dumper, &port); + if (rc != EOK) { + log_msg(LOG_DEFAULT, LVL_DEBUG, "Failed creating port for pcap dumper: %s", str_error(rc)); + return rc; + } + return EOK; +} + +/** Dumping function for driver. + * + * Called every time, the packet is sent/recieved by the device. + * + * @param dumper Dumping interface. + * @param data The packet + * @param size Size of the packet. + * + */ +void pcapdump_packet(pcap_dumper_t *dumper, const void *data, size_t size) +{ + if (dumper == NULL) { + return; + } + pcap_dumper_add_packet(dumper, data, size); +} diff --git a/uspace/lib/pcap/src/pcapdump_srv.c b/uspace/lib/pcap/src/pcapdump_srv.c new file mode 100644 index 0000000000..c465463e6a --- /dev/null +++ b/uspace/lib/pcap/src/pcapdump_srv.c @@ -0,0 +1,152 @@ +/* + * 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 libpcap + * @{ + */ +/** + * @file + * @brief Server side of the pcapctl + */ + +#include +#include +#include +#include +#include +#include + +#include "pcap_dumper.h" +#include "pcapdump_srv.h" +#include "pcapdump_ipc.h" + +/** Start dumping. + * @param icall IPC call with request to start. + * @param dumper Dumping interface of the driver. + */ +static void pcapdump_start_srv(ipc_call_t *icall, pcap_dumper_t *dumper) +{ + char *data; + size_t size; + int ops_index = (int)ipc_get_arg1(icall); + errno_t rc = async_data_write_accept((void **) &data, true, 0, 0, 0, &size); + if (rc != EOK) { + async_answer_0(icall, rc); + return; + } + + assert(str_length(data) == size && "Data were damaged during transmission.\n"); + + // Deadlock solution when trying to start dump while dumping (to the same device) + if (dumper->to_dump) { + free(data); + log_msg(LOG_DEFAULT, LVL_ERROR, "Trying to start dumping while dumping.\n"); + async_answer_0(icall, EBUSY); + return; + } + + rc = pcap_dumper_set_ops(dumper, ops_index); + if (rc != EOK) { + log_msg(LOG_DEFAULT, LVL_DEBUG, "Setting ops for dumper was not successful.\n"); + free(data); + async_answer_0(icall, EOK); + return; + } + + rc = pcap_dumper_start(dumper, (const char *)data); + free(data); + if (rc != EOK) { + log_msg(LOG_DEFAULT, LVL_DEBUG, "Starting the dumping was not successful.\n"); + } + async_answer_0(icall, EOK); +} + +/** Stop dumping + * @param icall IPC call with request to stop. + * @param dumper Dumping interface of the driver. + */ +static void pcapdump_stop_srv(ipc_call_t *icall, pcap_dumper_t *dumper) +{ + pcap_dumper_stop(dumper); + async_answer_0(icall, EOK); +} + +/** Get number of accessibke writer operations. + * @param icall IPC call with request to get number of accessible writer operations. + */ +static void pcapdump_get_ops_num_srv(ipc_call_t *icall) +{ + size_t count = pcap_dumper_get_ops_number(); + + log_msg(LOG_DEFAULT, LVL_NOTE, "Getting number of ops.\n"); + + async_answer_1(icall, EOK, count); +} + +/** Callback connection function. Accepts requests and processes them. + * @param icall IPC call with request. + * @param arg Dumping interface of the driver. + */ +void pcapdump_conn(ipc_call_t *icall, void *arg) +{ + pcap_dumper_t *dumper = (pcap_dumper_t *)arg; + + assert((dumper != NULL) && "pcapdump requires pcap dumper\n"); + + /* Accept connection */ + async_accept_0(icall); + + while (true) { + ipc_call_t call; + async_get_call(&call); + sysarg_t method = ipc_get_imethod(&call); + if (!method) { + /* The other side has hung up */ + async_answer_0(&call, EOK); + break; + } + switch (method) { + case PCAP_CONTROL_SET_START: + pcapdump_start_srv(&call, dumper); + break; + case PCAP_CONTROL_SET_STOP: + pcapdump_stop_srv(&call, dumper); + break; + case PCAP_CONTROL_GET_OPS_NUM: + pcapdump_get_ops_num_srv(&call); + break; + default: + async_answer_0(&call, EINVAL); + break; + } + } +} + +/** @} + */ diff --git a/uspace/srv/locsrv/locsrv.c b/uspace/srv/locsrv/locsrv.c index 16cc0cbcc6..b3e1f647c2 100644 --- a/uspace/srv/locsrv/locsrv.c +++ b/uspace/srv/locsrv/locsrv.c @@ -1392,6 +1392,8 @@ static bool loc_init(void) cat = category_new("pci"); categ_dir_add_cat(&cdir, cat); + cat = category_new("pcap"); + categ_dir_add_cat(&cdir, cat); return true; } diff --git a/uspace/srv/net/ethip/ethip.c b/uspace/srv/net/ethip/ethip.c index 5029d55be0..1d3f2c883c 100644 --- a/uspace/srv/net/ethip/ethip.c +++ b/uspace/srv/net/ethip/ethip.c @@ -52,6 +52,7 @@ #include "std.h" #define NAME "ethip" +/** Interface for dumping packets */ static errno_t ethip_open(iplink_srv_t *srv); static errno_t ethip_close(iplink_srv_t *srv); @@ -196,7 +197,6 @@ static errno_t ethip_send(iplink_srv_t *srv, iplink_sdu_t *sdu) rc = eth_pdu_encode(&frame, &data, &size); if (rc != EOK) return rc; - rc = ethip_nic_send(nic, data, size); free(data); diff --git a/uspace/srv/net/ethip/meson.build b/uspace/srv/net/ethip/meson.build index d1577d8193..886f2e8b9b 100644 --- a/uspace/srv/net/ethip/meson.build +++ b/uspace/srv/net/ethip/meson.build @@ -26,7 +26,7 @@ # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # -deps = [ 'drv' ] +deps = [ 'drv' , 'pcap' ] src = files( 'arp.c', 'atrans.c', diff --git a/uspace/srv/net/inetsrv/inetsrv.c b/uspace/srv/net/inetsrv/inetsrv.c index 8e93324eea..e42883e789 100644 --- a/uspace/srv/net/inetsrv/inetsrv.c +++ b/uspace/srv/net/inetsrv/inetsrv.c @@ -211,7 +211,6 @@ errno_t inet_route_packet(inet_dgram_t *dgram, uint8_t proto, uint8_t ttl, log_msg(LOG_DEFAULT, LVL_DEBUG, "dgram to be routed"); /* Route packet using source/destination addresses */ - rc = inet_find_dir(&dgram->src, &dgram->dest, dgram->tos, &dir); if (rc != EOK) return rc; @@ -546,7 +545,6 @@ errno_t inet_recv_packet(inet_packet_t *packet) dgram.tos = packet->tos; dgram.data = packet->data; dgram.size = packet->size; - return inet_recv_dgram_local(&dgram, packet->proto); } else { /* It is a fragment, queue it for reassembly */ diff --git a/uspace/srv/net/inetsrv/meson.build b/uspace/srv/net/inetsrv/meson.build index 9b3600d426..c69af77187 100644 --- a/uspace/srv/net/inetsrv/meson.build +++ b/uspace/srv/net/inetsrv/meson.build @@ -26,7 +26,8 @@ # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # -deps = [ 'inet', 'sif' ] +deps = [ 'inet', 'sif', 'pcap' ] + src = files( 'addrobj.c', 'icmp.c',