diff --git a/abi/include/abi/ipc/interfaces.h b/abi/include/abi/ipc/interfaces.h index 54f05d19da..783f69fc0d 100644 --- a/abi/include/abi/ipc/interfaces.h +++ b/abi/include/abi/ipc/interfaces.h @@ -201,7 +201,9 @@ typedef enum { INTERFACE_WNDMGT_CB = FOURCC_COMPACT('w', 'm', 'g', 't') | IFACE_EXCHANGE_SERIALIZE | IFACE_MOD_CALLBACK, INTERFACE_TBARCFG_NOTIFY = - FOURCC_COMPACT('t', 'b', 'c', 'f') | IFACE_EXCHANGE_SERIALIZE + FOURCC_COMPACT('t', 'b', 'c', 'f') | IFACE_EXCHANGE_SERIALIZE, + 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 aa5c9a59f9..349df75e87 100644 --- a/uspace/app/meson.build +++ b/uspace/app/meson.build @@ -70,6 +70,7 @@ apps = [ 'netecho', 'nic', 'nterm', + 'pcapctl', 'ofw', 'pci', 'ping', diff --git a/uspace/app/pcapctl/doc/doxygroups.h b/uspace/app/pcapctl/doc/doxygroups.h new file mode 100644 index 0000000000..64f848ec60 --- /dev/null +++ b/uspace/app/pcapctl/doc/doxygroups.h @@ -0,0 +1,4 @@ +/** @addtogroup pcapctl pcapctl + * @brief Dump network packets + * @ingroup apps + */ diff --git a/uspace/app/pcapctl/main.c b/uspace/app/pcapctl/main.c new file mode 100644 index 0000000000..e81bb8c0bb --- /dev/null +++ b/uspace/app/pcapctl/main.c @@ -0,0 +1,160 @@ +/* + * 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 app + */ + +#include +#include +#include +#include +#include + +#include "pcapctl_dump.h" + +#define NAME "pcapctl" +#define DEFAULT_DEV_NUM 0 + +static errno_t start_dumping(int *dev_number, const char *name) +{ + pcapctl_sess_t *sess = NULL; + errno_t rc = pcapctl_dump_open(dev_number, &sess); + if (rc != EOK) { + return 1; + } + + pcapctl_dump_start(name, sess); + pcapctl_dump_close(sess); + return EOK; +} + +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; + } + pcapctl_dump_stop(sess); + pcapctl_dump_close(sess); + return EOK; +} + +static void list_devs(void) +{ + pcapctl_list(); +} + +/** + * Array of supported commandline options + */ +static const struct option opts[] = { + { "device", required_argument, 0, 'd' }, + { "list", no_argument, 0, 'l' }, + { "help", no_argument, 0, 'h' }, + { "outfile", required_argument, 0, 'f' }, + { "start", no_argument, 0, 'r' }, + { "stop", no_argument, 0, 't' }, + { 0, 0, 0, 0 } +}; + +static void usage(void) +{ + printf("Usage:\n" + NAME " --list | -l \n" + "\tList of devices\n" + NAME " --start | -r --device= | -d --outfile= | -f \n" + "\tPackets dumped from device will be written to \n" + NAME " --stop | -t --device= | -d \n" + "\tDumping from stops\n" + NAME " --start | -s --outfile= | -f \n" + "\tPackets dumped from the 0. device from the list will be written to \n" + NAME " --help | -h\n" + "\tShow this application help.\n"); +} + +int main(int argc, char *argv[]) +{ + bool start = false; + bool stop = false; + int dev_number = DEFAULT_DEV_NUM; + 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, "d:lhf:rt", opts, &idx); + switch (ret) { + case 'd': + char *rest; + long result = strtol(optarg, &rest, 10); + dev_number = (int)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 'l': + list_devs(); + return 0; + case 'h': + usage(); + return 0; + case 'f': + output_file_name = optarg; + break; + case 'r': + start = true; + break; + case 't': + stop = true; + break; + } + } + + printf("%s: HelenOS Packet Dumping utility: device - %d\n", NAME, dev_number); + + if (start) { + // start with dev number and optional..name + start_dumping(&dev_number, output_file_name); + } else if (stop) { + //stop with dev number + stop_dumping(&dev_number); + } + 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 cd8b2f874c..97b80c8b15 100644 --- a/uspace/drv/nic/e1k/e1k.c +++ b/uspace/drv/nic/e1k/e1k.c @@ -48,6 +48,7 @@ #include #include #include +#include #include "e1k.h" #define NAME "e1k" @@ -173,6 +174,7 @@ typedef struct { /** Lock for EEPROM access */ fibril_mutex_t eeprom_lock; + } e1000_t; /** Global mutex for work with shared irq structure */ @@ -1188,6 +1190,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."); @@ -2197,14 +2200,16 @@ 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_add_to_cat: + // ddf_fun_unbind(fun); err_fun_bind: err_rx_structure: e1000_uninitialize_rx_structure(nic); @@ -2364,7 +2369,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 7f7cec7b78..d21231f86e 100644 --- a/uspace/drv/nic/ne2k/ne2k.c +++ b/uspace/drv/nic/ne2k/ne2k.c @@ -42,6 +42,7 @@ #include #include #include +#include #include "dp8390.h" #define NAME "ne2k" @@ -448,10 +449,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; } @@ -481,6 +482,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 659dcc8c38..46b5960b12 100644 --- a/uspace/drv/nic/rtl8139/driver.c +++ b/uspace/drv/nic/rtl8139/driver.c @@ -41,6 +41,7 @@ #include #include #include +#include #include "defs.h" #include "driver.h" @@ -1304,10 +1305,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.", @@ -1315,8 +1318,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 28ddc10eed..e8d580107c 100644 --- a/uspace/drv/nic/rtl8169/driver.c +++ b/uspace/drv/nic/rtl8169/driver.c @@ -457,18 +457,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 fcef69619d..5f4051b75c 100644 --- a/uspace/drv/nic/virtio-net/virtio-net.c +++ b/uspace/drv/nic/virtio-net/virtio-net.c @@ -42,6 +42,7 @@ #include #include +#include #define NAME "virtio-net" @@ -427,10 +428,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 +440,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..e10b592090 100644 --- a/uspace/lib/c/include/ipc/services.h +++ b/uspace/lib/c/include/ipc/services.h @@ -66,7 +66,7 @@ typedef enum { #define SERVICE_NAME_TCP "net/tcp" #define SERVICE_NAME_VBD "vbd" #define SERVICE_NAME_VOLSRV "volsrv" - +#define SERVICE_NAME_DUMPPCAP "dumppcap" #endif /** @} diff --git a/uspace/lib/meson.build b/uspace/lib/meson.build index 9305309bad..30c05d7b31 100644 --- a/uspace/lib/meson.build +++ b/uspace/lib/meson.build @@ -81,6 +81,7 @@ libs = [ 'math', 'minix', 'nettl', + 'pcap', 'ofw', 'pcm', 'pcut', diff --git a/uspace/lib/nic/include/nic.h b/uspace/lib/nic/include/nic.h index fe832c71d0..9fb0b5637f 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_iface_t *nic_get_pcap_iface(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..f99e5a0746 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; + + /** Interface for dumping packets */ + pcap_iface_t pcapdump; + /** 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..1437b86a27 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_iface(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_iface(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_iface(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_iface_t *nic_get_pcap_iface(nic_t *nic_data) +{ + return &nic_data->pcapdump; +} + /** @} */ diff --git a/uspace/lib/nic/src/nic_impl.c b/uspace/lib/nic/src/nic_impl.c index d3595471be..d894d63f69 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_iface(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,24 @@ 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) + goto err_add_to_cat; + + rc = ddf_fun_add_to_category(fun, "pcap"); + if (rc != EOK) { + //ddf_msg(LVL_ERROR, "Failed adding function to category pcap"); + goto err_add_to_cat; + } + return EOK; + +err_add_to_cat: + ddf_fun_unbind(fun); + return rc; +} + /** @} */ 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..1e8089fbb8 --- /dev/null +++ b/uspace/lib/pcap/include/pcap.h @@ -0,0 +1,103 @@ +/* + * 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 file and packets to be dumped + */ + +#ifndef PCAP_H_ +#define PCAP_H_ + +#include +#include +#include +#include +#include +#include + +#define PCAP_MAGIC_MICRO 0xA1B2C3D4 +#define PCAP_MAGIC_NANO 0xA1B23C4D +#define PCAP_MAJOR_VERSION 0x0002 +#define PCAP_MINOR_VERSION 0x0004 +#define PCAP_SNAP_LEN 0x00040000 + +#define PCAP_LINKTYPE_ETHERNET 1 /* IEEE 802.3 Ethernet*/ + +/** 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; + +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; + +typedef struct { + size_t (*write_u32)(struct pcap_writer *, uint32_t); + size_t (*write_u16)(struct pcap_writer *, uint16_t); + size_t (*write_buffer)(struct pcap_writer *, const void *, size_t); + void (*close)(struct pcap_writer *); + +} pcap_writer_ops_t; + +/** Interface for working with .pcap file + */ +typedef struct pcap_writer { + void *data; + pcap_writer_ops_t *ops; +} pcap_writer_t; + +errno_t pcap_writer_to_file_init(pcap_writer_t *writer, const char *filename); + +extern void pcap_writer_add_header(pcap_writer_t *); +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, bool nano); + +#endif + +/** @} + */ diff --git a/uspace/lib/pcap/include/pcap_iface.h b/uspace/lib/pcap/include/pcap_iface.h new file mode 100644 index 0000000000..ca660a3922 --- /dev/null +++ b/uspace/lib/pcap/include/pcap_iface.h @@ -0,0 +1,55 @@ +/* + * 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 interface + */ + +#ifndef PCAP_IFACE_H_ +#define PCAP_IFACE_H_ + +#include +#include "pcap.h" + +typedef struct pcap_iface { + bool to_dump; + errno_t (*init)(const char *); + void (*add_packet)(const void *data, size_t size); + void (*fini)(void); +} pcap_iface_t; + +extern void pcap_close_file(void); +extern errno_t pcap_iface_init(pcap_iface_t *); +extern errno_t pcap_init(const char *); +extern void pcap_add_packet(const void *data, size_t size); + +#endif +/** @} + */ diff --git a/uspace/lib/pcap/include/pcapctl_dump.h b/uspace/lib/pcap/include/pcapctl_dump.h new file mode 100644 index 0000000000..c15c3b66bc --- /dev/null +++ b/uspace/lib/pcap/include/pcapctl_dump.h @@ -0,0 +1,61 @@ +/* + * 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 + * + */ + +#ifndef _PCAPCTL_DUMP_H_ +#define _PCAPCTL_DUMP_H_ + +#include +#include +#include +#include +#include + +typedef struct { + async_sess_t *sess; +} pcapctl_sess_t; + +extern errno_t pcapctl_dump_open(int *, pcapctl_sess_t **rsess); +extern errno_t pcapctl_dump_close(pcapctl_sess_t *sess); +extern errno_t pcapctl_dump_start(const char *, 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 *); + +#endif + +/** @} + */ diff --git a/uspace/lib/pcap/include/pcapdump_iface.h b/uspace/lib/pcap/include/pcapdump_iface.h new file mode 100644 index 0000000000..8d64211652 --- /dev/null +++ b/uspace/lib/pcap/include/pcapdump_iface.h @@ -0,0 +1,56 @@ +/* + * 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 + * + */ + +#ifndef _PCAPDUMP_IFACE_H_ +#define _PCAPDUMP_IFACE_H_ + +#include +#include "pcap_iface.h" + +typedef enum { + PCAP_CONTROL_SET_START = IPC_FIRST_USER_METHOD, + PCAP_CONTROL_SET_STOP, + PCAP_CONTROL_GET_NAME +} pcap_request_t; + +extern errno_t pcapdump_init(pcap_iface_t *); +extern void pcapdump_packet(pcap_iface_t *, const void *, size_t); + +#endif + +/** @} + */ diff --git a/uspace/lib/pcap/meson.build b/uspace/lib/pcap/meson.build new file mode 100644 index 0000000000..bb70637845 --- /dev/null +++ b/uspace/lib/pcap/meson.build @@ -0,0 +1,34 @@ +# +# 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_iface.c', + 'src/pcapdump_iface.c', + 'src/pcapctl_dump.c', +) diff --git a/uspace/lib/pcap/src/pcap.c b/uspace/lib/pcap/src/pcap.c new file mode 100644 index 0000000000..cf8c791c6f --- /dev/null +++ b/uspace/lib/pcap/src/pcap.c @@ -0,0 +1,112 @@ +/* + * 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 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, bool nano) // maybe without bool nano as nano is in pcapng +{ + struct timespec ts; + getrealtime(&ts); + header->seconds_stamp = (uint32_t)ts.tv_sec; + header->magic_stamp = (uint32_t)ts.tv_nsec / 1000; +} + +/** Add pcap file header to the new .pcap file. + * + * @param writer + * + */ +void pcap_writer_add_header(pcap_writer_t *writer) +{ + pcap_file_header_t file_header = { PCAP_MAGIC_MICRO, PCAP_MAJOR_VERSION, PCAP_MINOR_VERSION, + 0x00000000, 0x00000000, (uint32_t)PCAP_SNAP_LEN, (uint32_t)PCAP_LINKTYPE_ETHERNET }; + writer->ops->write_buffer(writer, &file_header, sizeof(file_header)); +} + +/** Add packet to the .pcap file. + * + * @param writer + * @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) +{ + if (!writer->data) + return; + pcap_packet_header_t pcap_packet; + pcap_set_time(&pcap_packet, false); + pcap_packet.original_length = (uint32_t)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); + +} + +/** Initialize writing to .pcap file. + * + * @param writer Interface for working with .pcap file + * @param filename Name of the file for dumping packets + * @return EOK on success or an error code + * + */ +errno_t pcap_writer_to_file_init(pcap_writer_t *writer, const char *filename) +{ + errno_t rc; + writer->data = fopen(filename, "a"); + if (writer->data == NULL) { + rc = EINVAL; + return rc; + } + pcap_writer_add_header(writer); + + rc = EOK; + return rc; +} + +/** @} + */ diff --git a/uspace/lib/pcap/src/pcap_iface.c b/uspace/lib/pcap/src/pcap_iface.c new file mode 100644 index 0000000000..3618eaddbf --- /dev/null +++ b/uspace/lib/pcap/src/pcap_iface.c @@ -0,0 +1,107 @@ +/* + * 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 pcap inteface: Dumping interface for the device which packets we want to dump + */ + +#include +#include "pcap_iface.h" + +static size_t pcap_file_w32(pcap_writer_t *writer, uint32_t data) +{ + return fwrite(&data, 1, 4, (FILE *)writer->data); +} + +static size_t pcap_file_w16(pcap_writer_t *writer, uint16_t data) +{ + return fwrite(&data, 1, 2, (FILE *)writer->data); +} + +static size_t pcap_file_wbuffer(pcap_writer_t *writer, const void *data, size_t size) +{ + return fwrite(data, 1, size, (FILE *)writer->data); +} + +static void pcap_file_close(pcap_writer_t *writer) +{ + fclose((FILE *)writer->data); +} + +static pcap_writer_ops_t file_ops = { + + .write_u32 = &pcap_file_w32, + .write_u16 = &pcap_file_w16, + .write_buffer = &pcap_file_wbuffer, + .close = &pcap_file_close +}; + +static pcap_writer_t pcap_writer = { + .ops = &file_ops, +}; + +errno_t pcap_init(const char *name) +{ + errno_t rc = pcap_writer_to_file_init(&pcap_writer, name); + return rc; +} + +void pcap_add_packet(const void *data, size_t size) +{ + if (pcap_writer.data == NULL) + return; + pcap_writer_add_packet(&pcap_writer, data, size); +} + +void pcap_close_file(void) +{ + pcap_writer.ops->close(&pcap_writer); + pcap_writer.data = NULL; +} + +/** Initialize interface for dumping packets + * + * @param iface Device dumping interface + * + */ +errno_t pcap_iface_init(pcap_iface_t *iface) +{ + + iface->to_dump = false; + iface->add_packet = pcap_add_packet; + iface->init = pcap_init; + iface->fini = pcap_close_file; + + return EOK; +} + +/** @} + */ diff --git a/uspace/lib/pcap/src/pcapctl_dump.c b/uspace/lib/pcap/src/pcapctl_dump.c new file mode 100644 index 0000000000..384a4e31ed --- /dev/null +++ b/uspace/lib/pcap/src/pcapctl_dump.c @@ -0,0 +1,224 @@ +/* + * 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 Client side of the pcapctl. Functions are called from the app pcapctl + */ + +#include +#include +#include +#include +#include +#include +#include "pcapctl_dump.h" +#include "pcapdump_iface.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); +} + +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) { + printf("Error resolving category 'pcap'.\n"); + return rc; + } + + rc = loc_category_get_svcs(pcap_cat, &pcap_svcs, &count); + if (rc != EOK) { + printf("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; +} + +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) { + printf("Error resolving category pcap.\n"); + return rc; + } + + rc = loc_category_get_svcs(pcap_cat, &pcap_svcs, &count); + if (rc != EOK) { + printf("Error resolving list of pcap services.\n"); + free(pcap_svcs); + return rc; + } + if (*index + 1 > (int)count || *index < 0) { + return EINVAL; + } + return EOK; +} + +/** + * + */ +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) { + printf("Error resolving category pcap.\n"); + return rc; + } + + rc = loc_category_get_svcs(pcap_cat, &pcap_svcs, &count); + if (rc != EOK) { + printf("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; +} + +/** + * + */ +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; + + rc = pcapctl_cat_get_svc(index, &svc); + if (rc != EOK) { + printf("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; +} + +/** + * + */ +errno_t pcapctl_dump_close(pcapctl_sess_t *sess) +{ + free(sess); + return EOK; +} + +/** Starting a new session for pcapctl + * + * @param name Name of the file to dump packets to + * @param sess session to start + * @return EOK on success or an error code + */ +errno_t pcapctl_dump_start(const char *name, 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_0(exch, PCAP_CONTROL_SET_START, NULL); + + rc = async_data_write_start(exch, (void *) 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; +} + +/** Finish current session for pcapctl + * + * @param sess Session to finish + * @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_iface.c b/uspace/lib/pcap/src/pcapdump_iface.c new file mode 100644 index 0000000000..0696ad289e --- /dev/null +++ b/uspace/lib/pcap/src/pcapdump_iface.c @@ -0,0 +1,161 @@ +/* + * 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 "pcapdump_iface.h" + +FIBRIL_MUTEX_INITIALIZE(to_dump_mutex); + +static void pcapdump_start_srv(ipc_call_t *icall, pcap_iface_t *iface) +{ + char *data; + size_t size; + errno_t rc = async_data_write_accept((void **) &data, false, 0, 0, 0, &size); + if (rc != EOK) { + async_answer_0(icall, rc); + return; + } + + /** When try to start when already started, close current and starts new */ + if (iface->to_dump == true) { + iface->fini(); + } + iface->init((const char *)data); + + fibril_mutex_lock(&to_dump_mutex); + iface->to_dump = true; + fibril_mutex_unlock(&to_dump_mutex); + + async_answer_0(icall, rc); +} + +static void pcapdump_stop_srv(ipc_call_t *icall, pcap_iface_t *iface) +{ + /** If want to stop, when already stopped, do nothing */ + if (iface->to_dump == false) { + async_answer_0(icall, EOK); + return; + } + + fibril_mutex_lock(&to_dump_mutex); + iface->to_dump = false; + fibril_mutex_unlock(&to_dump_mutex); + + iface->fini(); + async_answer_0(icall, EOK); +} + +static void pcapdump_conn(ipc_call_t *icall, void *arg) +{ + pcap_iface_t *iface = (pcap_iface_t *)arg; + + assert((iface != NULL) && "pcapdump requires pcap interface\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, iface); + break; + case PCAP_CONTROL_SET_STOP: + pcapdump_stop_srv(&call, iface); + break; + default: + async_answer_0(&call, EINVAL); + break; + } + } +} + +errno_t pcapdump_init(pcap_iface_t *iface) +{ + port_id_t port; + errno_t rc; + + rc = pcap_iface_init(iface); + + if (rc != EOK) { + printf("Failed creating pcap interface: %s", str_error(rc)); + return rc; + } + + rc = async_create_port(INTERFACE_PCAP_CONTROL, + pcapdump_conn, iface, &port); + if (rc != EOK) { + return rc; + } + return EOK; +} + +/** Dumping function for driver + * + * Called every time, the packet is sent/recieved by the device + * + * @param iface Dumping interface + * @param data The packet + * @param size Size of the packet + * + */ +void pcapdump_packet(pcap_iface_t *iface, const void *data, size_t size) +{ + + if (iface == NULL) { + return; + } + + if (!iface->to_dump) { + return; + } + + iface->add_packet(data, size); +} + +/** @} + */ 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; }