1 /** @file
2  * @brief Network packet capture definitions
3  *
4  * Definitions for capturing network packets.
5  */
6 
7 /*
8  * Copyright (c) 2021 Intel Corporation
9  *
10  * SPDX-License-Identifier: Apache-2.0
11  */
12 
13 #ifndef ZEPHYR_INCLUDE_NET_CAPTURE_H_
14 #define ZEPHYR_INCLUDE_NET_CAPTURE_H_
15 
16 #include <zephyr/kernel.h>
17 #include <zephyr/device.h>
18 
19 #ifdef __cplusplus
20 extern "C" {
21 #endif
22 
23 /**
24  * @brief Network packet capture support functions
25  * @defgroup net_capture Network packet capture
26  * @since 2.6
27  * @version 0.8.0
28  * @ingroup networking
29  * @{
30  */
31 
32 /** @cond INTERNAL_HIDDEN */
33 
34 struct net_if;
35 struct net_pkt;
36 struct device;
37 
38 struct net_capture_interface_api {
39 	/** Cleanup the setup. This will also disable capturing. After this
40 	 * call, the setup function can be called again.
41 	 */
42 	int (*cleanup)(const struct device *dev);
43 
44 	/** Enable / start capturing data */
45 	int (*enable)(const struct device *dev, struct net_if *iface);
46 
47 	/** Disable / stop capturing data */
48 	int (*disable)(const struct device *dev);
49 
50 	/** Is capturing enabled (returns true) or disabled (returns false).
51 	 */
52 	bool (*is_enabled)(const struct device *dev);
53 
54 	/** Send captured data */
55 	int (*send)(const struct device *dev, struct net_if *iface, struct net_pkt *pkt);
56 };
57 
58 /** @endcond */
59 
60 /**
61  * @brief Setup network packet capturing support.
62  *
63  * @param remote_addr The value tells the tunnel remote/outer endpoint
64  *        IP address. The IP address can be either IPv4 or IPv6 address.
65  *        This address is used to select the network interface where the tunnel
66  *        is created.
67  * @param my_local_addr The local/inner IP address of the tunnel. Can contain
68  *        also port number which is used as UDP source port.
69  * @param peer_addr The peer/inner IP address of the tunnel. Can contain
70  *        also port number which is used as UDP destination port.
71  * @param dev Network capture device. This is returned to the caller.
72  *
73  * @return 0 if ok, <0 if network packet capture setup failed
74  */
75 int net_capture_setup(const char *remote_addr, const char *my_local_addr, const char *peer_addr,
76 		      const struct device **dev);
77 
78 /**
79  * @brief Cleanup network packet capturing support.
80  *
81  * @details This should be called after the capturing is done and resources
82  *          can be released.
83  *
84  * @param dev Network capture device. User must allocate using the
85  *            net_capture_setup() function.
86  *
87  * @return 0 if ok, <0 if network packet capture cleanup failed
88  */
net_capture_cleanup(const struct device * dev)89 static inline int net_capture_cleanup(const struct device *dev)
90 {
91 #if defined(CONFIG_NET_CAPTURE)
92 	const struct net_capture_interface_api *api =
93 		(const struct net_capture_interface_api *)dev->api;
94 
95 	return api->cleanup(dev);
96 #else
97 	ARG_UNUSED(dev);
98 
99 	return -ENOTSUP;
100 #endif
101 }
102 
103 /**
104  * @brief Enable network packet capturing support.
105  *
106  * @details This creates tunnel network interface where all the
107  * captured packets are pushed. The captured network packets are
108  * placed in UDP packets that are sent to tunnel peer.
109  *
110  * @param dev Network capture device
111  * @param iface Network interface we are starting to capture packets.
112  *
113  * @return 0 if ok, <0 if network packet capture enable failed
114  */
net_capture_enable(const struct device * dev,struct net_if * iface)115 static inline int net_capture_enable(const struct device *dev, struct net_if *iface)
116 {
117 #if defined(CONFIG_NET_CAPTURE)
118 	const struct net_capture_interface_api *api =
119 		(const struct net_capture_interface_api *)dev->api;
120 
121 	return api->enable(dev, iface);
122 #else
123 	ARG_UNUSED(dev);
124 	ARG_UNUSED(iface);
125 
126 	return -ENOTSUP;
127 #endif
128 }
129 
130 /**
131  * @brief Is network packet capture enabled or disabled.
132  *
133  * @param dev Network capture device. If set to NULL, then the
134  *            default capture device is used.
135  *
136  * @return True if enabled, False if network capture is disabled.
137  */
net_capture_is_enabled(const struct device * dev)138 static inline bool net_capture_is_enabled(const struct device *dev)
139 {
140 #if defined(CONFIG_NET_CAPTURE)
141 	const struct net_capture_interface_api *api;
142 
143 	if (dev == NULL) {
144 		/* TODO: Go through all capture devices instead of one */
145 		dev = device_get_binding("NET_CAPTURE0");
146 		if (dev == NULL) {
147 			return false;
148 		}
149 	}
150 
151 	api = (const struct net_capture_interface_api *)dev->api;
152 
153 	return api->is_enabled(dev);
154 #else
155 	ARG_UNUSED(dev);
156 
157 	return false;
158 #endif
159 }
160 
161 /**
162  * @brief Disable network packet capturing support.
163  *
164  * @param dev Network capture device
165  *
166  * @return 0 if ok, <0 if network packet capture disable failed
167  */
net_capture_disable(const struct device * dev)168 static inline int net_capture_disable(const struct device *dev)
169 {
170 #if defined(CONFIG_NET_CAPTURE)
171 	const struct net_capture_interface_api *api =
172 		(const struct net_capture_interface_api *)dev->api;
173 
174 	return api->disable(dev);
175 #else
176 	ARG_UNUSED(dev);
177 
178 	return -ENOTSUP;
179 #endif
180 }
181 
182 /** @cond INTERNAL_HIDDEN */
183 
184 /**
185  * @brief Send captured packet.
186  *
187  * @param dev Network capture device
188  * @param iface Network interface the packet is being sent
189  * @param pkt The network packet that is sent
190  *
191  * @return 0 if ok, <0 if network packet capture send failed
192  */
net_capture_send(const struct device * dev,struct net_if * iface,struct net_pkt * pkt)193 static inline int net_capture_send(const struct device *dev, struct net_if *iface,
194 				   struct net_pkt *pkt)
195 {
196 #if defined(CONFIG_NET_CAPTURE)
197 	const struct net_capture_interface_api *api =
198 		(const struct net_capture_interface_api *)dev->api;
199 
200 	return api->send(dev, iface, pkt);
201 #else
202 	ARG_UNUSED(dev);
203 	ARG_UNUSED(iface);
204 	ARG_UNUSED(pkt);
205 
206 	return -ENOTSUP;
207 #endif
208 }
209 
210 /**
211  * @brief Check if the network packet needs to be captured or not.
212  *        This is called for every network packet being sent.
213  *
214  * @param iface Network interface the packet is being sent
215  * @param pkt The network packet that is sent
216  */
217 #if defined(CONFIG_NET_CAPTURE)
218 void net_capture_pkt(struct net_if *iface, struct net_pkt *pkt);
219 #else
net_capture_pkt(struct net_if * iface,struct net_pkt * pkt)220 static inline void net_capture_pkt(struct net_if *iface, struct net_pkt *pkt)
221 {
222 	ARG_UNUSED(iface);
223 	ARG_UNUSED(pkt);
224 }
225 #endif
226 
227 /** @cond INTERNAL_HIDDEN */
228 
229 /**
230  * @brief Special variant for net_capture_pkt() which returns the status
231  *        of the send message.
232  *
233  * @param iface Network interface the packet is being sent
234  * @param pkt The network packet that is sent
235  *
236  * @return 0 if captured packet was handled ok, <0 if the capture failed
237  */
238 #if defined(CONFIG_NET_CAPTURE)
239 int net_capture_pkt_with_status(struct net_if *iface, struct net_pkt *pkt);
240 #else
net_capture_pkt_with_status(struct net_if * iface,struct net_pkt * pkt)241 static inline int net_capture_pkt_with_status(struct net_if *iface, struct net_pkt *pkt)
242 {
243 	ARG_UNUSED(iface);
244 	ARG_UNUSED(pkt);
245 
246 	return -ENOTSUP;
247 }
248 #endif
249 
250 /** @endcond */
251 
252 /** The type and direction of the captured data. */
253 enum net_capture_packet_type {
254 	NET_CAPTURE_HOST,      /**< Packet was sent to us by somebody else */
255 	NET_CAPTURE_BROADCAST, /**< Packet was broadcast by somebody else */
256 	NET_CAPTURE_MULTICAST, /**< Packet was multicast, but not broadcast, by somebody else */
257 	NET_CAPTURE_OTHERHOST, /**< Packet was sent by somebody else to somebody else */
258 	NET_CAPTURE_OUTGOING,  /**< Packet was sent by us */
259 };
260 
261 #define NET_CAPTURE_LL_ADDRLEN 8 /** Maximum length of a link-layer address */
262 
263 /** The context information for cooked mode capture */
264 struct net_capture_cooked {
265 	/** Link-layer address type */
266 	uint16_t hatype;
267 	/** Link-layer address length */
268 	uint16_t halen;
269 	/** Link-layer address */
270 	uint8_t addr[NET_CAPTURE_LL_ADDRLEN];
271 };
272 
273 /**
274  * @brief Initialize cooked mode capture context.
275  *
276  * @param ctx Cooked context struct allocated by user.
277  * @param hatype Link-layer address type
278  * @param halen Link-layer address length (maximum is 8 bytes)
279  * @param addr Link-layer address
280  *
281  * @return 0 if ok, <0 if context initialization failed
282  */
283 #if defined(CONFIG_NET_CAPTURE_COOKED_MODE)
284 int net_capture_cooked_setup(struct net_capture_cooked *ctx,
285 			     uint16_t hatype,
286 			     uint16_t halen,
287 			     uint8_t *addr);
288 #else
net_capture_cooked_setup(struct net_capture_cooked * ctx,uint16_t hatype,uint16_t halen,uint8_t * addr)289 static inline int net_capture_cooked_setup(struct net_capture_cooked *ctx,
290 					   uint16_t hatype,
291 					   uint16_t halen,
292 					   uint8_t *addr)
293 {
294 	ARG_UNUSED(ctx);
295 	ARG_UNUSED(hatype);
296 	ARG_UNUSED(halen);
297 	ARG_UNUSED(addr);
298 
299 	return -ENOTSUP;
300 }
301 #endif
302 
303 /**
304  * @brief Capture arbitrary data from source that does not have an interface.
305  *        This can be used if you do not have a network interface that
306  *        you want to capture from. For example low level modem device
307  *        below PPP containing HDLC frames, CANBUS data or Bluetooth packets etc.
308  *        The data given to this function should only contain full link
309  *        layer packets so that packet boundary is not lost.
310  *
311  * @param ctx Cooked mode capture context.
312  * @param data Data to capture.
313  * @param len Length of the data.
314  * @param type The direction and type of the packet (did we sent it etc).
315  * @param ptype Protocol type id. These are the ETH_P_* types set in ethernet.h
316  */
317 #if defined(CONFIG_NET_CAPTURE_COOKED_MODE)
318 void net_capture_data(struct net_capture_cooked *ctx,
319 		      const uint8_t *data, size_t len,
320 		      enum net_capture_packet_type type,
321 		      uint16_t ptype);
322 #else
net_capture_data(struct net_capture_cooked * ctx,const uint8_t * data,size_t len,enum net_capture_packet_type type,uint16_t ptype)323 static inline void net_capture_data(struct net_capture_cooked *ctx,
324 				    const uint8_t *data, size_t len,
325 				    enum net_capture_packet_type type,
326 				    uint16_t ptype)
327 {
328 	ARG_UNUSED(ctx);
329 	ARG_UNUSED(data);
330 	ARG_UNUSED(len);
331 	ARG_UNUSED(type);
332 	ARG_UNUSED(ptype);
333 }
334 #endif
335 
336 struct net_capture_info {
337 	const struct device *capture_dev;
338 	struct net_if *capture_iface;
339 	struct net_if *tunnel_iface;
340 	struct sockaddr *peer;
341 	struct sockaddr *local;
342 	bool is_enabled;
343 };
344 
345 /**
346  * @typedef net_capture_cb_t
347  * @brief Callback used while iterating over capture devices
348  *
349  * @param info Information about capture device
350  * @param user_data A valid pointer to user data or NULL
351  */
352 typedef void (*net_capture_cb_t)(struct net_capture_info *info, void *user_data);
353 
354 /**
355  * @brief Go through all the capture devices in order to get
356  *        information about them. This is mainly useful in
357  *        net-shell to print data about currently active
358  *        captures.
359  *
360  * @param cb Callback to call for each capture device
361  * @param user_data User supplied data
362  */
363 #if defined(CONFIG_NET_CAPTURE)
364 void net_capture_foreach(net_capture_cb_t cb, void *user_data);
365 #else
net_capture_foreach(net_capture_cb_t cb,void * user_data)366 static inline void net_capture_foreach(net_capture_cb_t cb, void *user_data)
367 {
368 	ARG_UNUSED(cb);
369 	ARG_UNUSED(user_data);
370 }
371 #endif
372 
373 /** @endcond */
374 
375 /**
376  * @}
377  */
378 
379 #ifdef __cplusplus
380 }
381 #endif
382 
383 #endif /* ZEPHYR_INCLUDE_NET_CAPTURE_H_ */
384