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