| /** @file |
| * @brief Network packet capture definitions |
| * |
| * Definitions for capturing network packets. |
| */ |
| |
| /* |
| * Copyright (c) 2021 Intel Corporation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #ifndef ZEPHYR_INCLUDE_NET_CAPTURE_H_ |
| #define ZEPHYR_INCLUDE_NET_CAPTURE_H_ |
| |
| #include <zephyr/kernel.h> |
| #include <zephyr/device.h> |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| /** |
| * @brief Network packet capture support functions |
| * @defgroup net_capture Network packet capture |
| * @ingroup networking |
| * @{ |
| */ |
| |
| /** @cond INTERNAL_HIDDEN */ |
| |
| struct net_if; |
| struct net_pkt; |
| struct device; |
| |
| struct net_capture_interface_api { |
| /** Cleanup the setup. This will also disable capturing. After this |
| * call, the setup function can be called again. |
| */ |
| int (*cleanup)(const struct device *dev); |
| |
| /** Enable / start capturing data */ |
| int (*enable)(const struct device *dev, struct net_if *iface); |
| |
| /** Disable / stop capturing data */ |
| int (*disable)(const struct device *dev); |
| |
| /** Is capturing enabled (returns true) or disabled (returns false). |
| */ |
| bool (*is_enabled)(const struct device *dev); |
| |
| /** Send captured data */ |
| int (*send)(const struct device *dev, struct net_if *iface, struct net_pkt *pkt); |
| }; |
| |
| /** @endcond */ |
| |
| /** |
| * @brief Setup network packet capturing support. |
| * |
| * @param remote_addr The value tells the tunnel remote/outer endpoint |
| * IP address. The IP address can be either IPv4 or IPv6 address. |
| * This address is used to select the network interface where the tunnel |
| * is created. |
| * @param my_local_addr The local/inner IP address of the tunnel. Can contain |
| * also port number which is used as UDP source port. |
| * @param peer_addr The peer/inner IP address of the tunnel. Can contain |
| * also port number which is used as UDP destination port. |
| * @param dev Network capture device. This is returned to the caller. |
| * |
| * @return 0 if ok, <0 if network packet capture setup failed |
| */ |
| int net_capture_setup(const char *remote_addr, const char *my_local_addr, const char *peer_addr, |
| const struct device **dev); |
| |
| /** |
| * @brief Cleanup network packet capturing support. |
| * |
| * @details This should be called after the capturing is done and resources |
| * can be released. |
| * |
| * @param dev Network capture device. User must allocate using the |
| * net_capture_setup() function. |
| * |
| * @return 0 if ok, <0 if network packet capture cleanup failed |
| */ |
| static inline int net_capture_cleanup(const struct device *dev) |
| { |
| #if defined(CONFIG_NET_CAPTURE) |
| const struct net_capture_interface_api *api = |
| (const struct net_capture_interface_api *)dev->api; |
| |
| return api->cleanup(dev); |
| #else |
| ARG_UNUSED(dev); |
| |
| return -ENOTSUP; |
| #endif |
| } |
| |
| /** |
| * @brief Enable network packet capturing support. |
| * |
| * @details This creates tunnel network interface where all the |
| * captured packets are pushed. The captured network packets are |
| * placed in UDP packets that are sent to tunnel peer. |
| * |
| * @param dev Network capture device |
| * @param iface Network interface we are starting to capture packets. |
| * |
| * @return 0 if ok, <0 if network packet capture enable failed |
| */ |
| static inline int net_capture_enable(const struct device *dev, struct net_if *iface) |
| { |
| #if defined(CONFIG_NET_CAPTURE) |
| const struct net_capture_interface_api *api = |
| (const struct net_capture_interface_api *)dev->api; |
| |
| return api->enable(dev, iface); |
| #else |
| ARG_UNUSED(dev); |
| ARG_UNUSED(iface); |
| |
| return -ENOTSUP; |
| #endif |
| } |
| |
| /** |
| * @brief Is network packet capture enabled or disabled. |
| * |
| * @param dev Network capture device. If set to NULL, then the |
| * default capture device is used. |
| * |
| * @return True if enabled, False if network capture is disabled. |
| */ |
| static inline bool net_capture_is_enabled(const struct device *dev) |
| { |
| #if defined(CONFIG_NET_CAPTURE) |
| const struct net_capture_interface_api *api; |
| |
| if (dev == NULL) { |
| /* TODO: Go through all capture devices instead of one */ |
| dev = device_get_binding("NET_CAPTURE0"); |
| if (dev == NULL) { |
| return false; |
| } |
| } |
| |
| api = (const struct net_capture_interface_api *)dev->api; |
| |
| return api->is_enabled(dev); |
| #else |
| ARG_UNUSED(dev); |
| |
| return false; |
| #endif |
| } |
| |
| /** |
| * @brief Disable network packet capturing support. |
| * |
| * @param dev Network capture device |
| * |
| * @return 0 if ok, <0 if network packet capture disable failed |
| */ |
| static inline int net_capture_disable(const struct device *dev) |
| { |
| #if defined(CONFIG_NET_CAPTURE) |
| const struct net_capture_interface_api *api = |
| (const struct net_capture_interface_api *)dev->api; |
| |
| return api->disable(dev); |
| #else |
| ARG_UNUSED(dev); |
| |
| return -ENOTSUP; |
| #endif |
| } |
| |
| /** @cond INTERNAL_HIDDEN */ |
| |
| /** |
| * @brief Send captured packet. |
| * |
| * @param dev Network capture device |
| * @param iface Network interface the packet is being sent |
| * @param pkt The network packet that is sent |
| * |
| * @return 0 if ok, <0 if network packet capture send failed |
| */ |
| static inline int net_capture_send(const struct device *dev, struct net_if *iface, |
| struct net_pkt *pkt) |
| { |
| #if defined(CONFIG_NET_CAPTURE) |
| const struct net_capture_interface_api *api = |
| (const struct net_capture_interface_api *)dev->api; |
| |
| return api->send(dev, iface, pkt); |
| #else |
| ARG_UNUSED(dev); |
| ARG_UNUSED(iface); |
| ARG_UNUSED(pkt); |
| |
| return -ENOTSUP; |
| #endif |
| } |
| |
| /** |
| * @brief Check if the network packet needs to be captured or not. |
| * This is called for every network packet being sent. |
| * |
| * @param iface Network interface the packet is being sent |
| * @param pkt The network packet that is sent |
| */ |
| #if defined(CONFIG_NET_CAPTURE) |
| void net_capture_pkt(struct net_if *iface, struct net_pkt *pkt); |
| #else |
| static inline void net_capture_pkt(struct net_if *iface, struct net_pkt *pkt) |
| { |
| ARG_UNUSED(iface); |
| ARG_UNUSED(pkt); |
| } |
| #endif |
| |
| /** @cond INTERNAL_HIDDEN */ |
| |
| /** |
| * @brief Special variant for net_capture_pkt() which returns the status |
| * of the send message. |
| * |
| * @param iface Network interface the packet is being sent |
| * @param pkt The network packet that is sent |
| * |
| * @return 0 if captured packet was handled ok, <0 if the capture failed |
| */ |
| #if defined(CONFIG_NET_CAPTURE) |
| int net_capture_pkt_with_status(struct net_if *iface, struct net_pkt *pkt); |
| #else |
| static inline int net_capture_pkt_with_status(struct net_if *iface, struct net_pkt *pkt) |
| { |
| ARG_UNUSED(iface); |
| ARG_UNUSED(pkt); |
| |
| return -ENOTSUP; |
| } |
| #endif |
| |
| /** @endcond */ |
| |
| /** The type and direction of the captured data. */ |
| enum net_capture_packet_type { |
| NET_CAPTURE_HOST, /**< Packet was sent to us by somebody else */ |
| NET_CAPTURE_BROADCAST, /**< Packet was broadcast by somebody else */ |
| NET_CAPTURE_MULTICAST, /**< Packet was multicast, but not broadcast, by somebody else */ |
| NET_CAPTURE_OTHERHOST, /**< Packet was sent by somebody else to somebody else */ |
| NET_CAPTURE_OUTGOING, /**< Packet was sent by us */ |
| }; |
| |
| #define NET_CAPTURE_LL_ADDRLEN 8 /** Maximum length of a link-layer address */ |
| |
| /** The context information for cooked mode capture */ |
| struct net_capture_cooked { |
| /** Link-layer address type */ |
| uint16_t hatype; |
| /** Link-layer address length */ |
| uint16_t halen; |
| /** Link-layer address */ |
| uint8_t addr[NET_CAPTURE_LL_ADDRLEN]; |
| }; |
| |
| /** |
| * @brief Initialize cooked mode capture context. |
| * |
| * @param cooked Cooked context struct allocated by user. |
| * @param hatype Link-layer address type |
| * @param halen Link-layer address length (maximum is 8 bytes) |
| * @param addr Link-layer address |
| * |
| * @return 0 if ok, <0 if context initialization failed |
| */ |
| #if defined(CONFIG_NET_CAPTURE_COOKED_MODE) |
| int net_capture_cooked_setup(struct net_capture_cooked *ctx, |
| uint16_t hatype, |
| uint16_t halen, |
| uint8_t *addr); |
| #else |
| static inline int net_capture_cooked_setup(struct net_capture_cooked *ctx, |
| uint16_t hatype, |
| uint16_t halen, |
| uint8_t *addr) |
| { |
| ARG_UNUSED(ctx); |
| ARG_UNUSED(hatype); |
| ARG_UNUSED(halen); |
| ARG_UNUSED(addr); |
| |
| return -ENOTSUP; |
| } |
| #endif |
| |
| /** |
| * @brief Capture arbitrary data from source that does not have an interface. |
| * This can be used if you do not have a network interface that |
| * you want to capture from. For example low level modem device |
| * below PPP containing HDLC frames, CANBUS data or Bluetooth packets etc. |
| * The data given to this function should only contain full link |
| * layer packets so that packet boundary is not lost. |
| * |
| * @param ctx Cooked mode capture context. |
| * @param buf Data to capture. |
| * @param len Length of the data. |
| * @param type The direction and type of the packet (did we sent it etc). |
| * @param ptype Protocol type id. These are the ETH_P_* types set in ethernet.h |
| */ |
| #if defined(CONFIG_NET_CAPTURE_COOKED_MODE) |
| void net_capture_data(struct net_capture_cooked *ctx, |
| const uint8_t *data, size_t len, |
| enum net_capture_packet_type type, |
| uint16_t ptype); |
| #else |
| static inline void net_capture_data(struct net_capture_cooked *ctx, |
| const uint8_t *data, size_t len, |
| enum net_capture_packet_type type, |
| uint16_t ptype) |
| { |
| ARG_UNUSED(ctx); |
| ARG_UNUSED(data); |
| ARG_UNUSED(len); |
| ARG_UNUSED(type); |
| ARG_UNUSED(ptype); |
| } |
| #endif |
| |
| struct net_capture_info { |
| const struct device *capture_dev; |
| struct net_if *capture_iface; |
| struct net_if *tunnel_iface; |
| struct sockaddr *peer; |
| struct sockaddr *local; |
| bool is_enabled; |
| }; |
| |
| /** |
| * @typedef net_capture_cb_t |
| * @brief Callback used while iterating over capture devices |
| * |
| * @param info Information about capture device |
| * @param user_data A valid pointer to user data or NULL |
| */ |
| typedef void (*net_capture_cb_t)(struct net_capture_info *info, void *user_data); |
| |
| /** |
| * @brief Go through all the capture devices in order to get |
| * information about them. This is mainly useful in |
| * net-shell to print data about currently active |
| * captures. |
| * |
| * @param cb Callback to call for each capture device |
| * @param user_data User supplied data |
| */ |
| #if defined(CONFIG_NET_CAPTURE) |
| void net_capture_foreach(net_capture_cb_t cb, void *user_data); |
| #else |
| static inline void net_capture_foreach(net_capture_cb_t cb, void *user_data) |
| { |
| ARG_UNUSED(cb); |
| ARG_UNUSED(user_data); |
| } |
| #endif |
| |
| /** @endcond */ |
| |
| /** |
| * @} |
| */ |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| #endif /* ZEPHYR_INCLUDE_NET_CAPTURE_H_ */ |