Blame view

RIOT/sys/include/net/gnrc/pktbuf.h 11.4 KB
a752c7ab   elopes   add first test an...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
  /*
   * Copyright (C) 2014 Martine Lenders <mlenders@inf.fu-berlin.de>
   *               2015 Freie Universitรคt Berlin
   *
   * This file is subject to the terms and conditions of the GNU Lesser
   * General Public License v2.1. See the file LICENSE in the top level
   * directory for more details.
   */
  
  /**
   * @defgroup    net_gnrc_pktbuf   Packet buffer
   * @ingroup     net_gnrc
   * @brief       A global network packet buffer.
   *
   * @note    **WARNING!!** Do not store data structures that are not packed
   *          (defined with `__attribute__((packed))`) or enforce alignment in
   *          in any way in here if @ref GNRC_PKTBUF_SIZE > 0. On some RISC architectures
   *          this *will* lead to alignment problems and can potentially result
   *          in segmentation/hard faults and other unexpected behaviour.
   *
   * @{
   *
   * @file
   * @brief   Interface definition for the global network buffer. Network devices
   *          and layers can allocate space for packets here.
   *
   * @author  Martine Lenders <mlenders@inf.fu-berlin.de>
   * @author  Hauke Petersen <hauke.petersen@fu-berlin.de>
   */
  #ifndef NET_GNRC_PKTBUF_H
  #define NET_GNRC_PKTBUF_H
  
  #include <stdbool.h>
  #include <stdlib.h>
  #include <string.h>
  
  #include "cpu_conf.h"
  #include "net/gnrc/pkt.h"
  #include "net/gnrc/neterr.h"
  #include "net/gnrc/nettype.h"
  #include "utlist.h"
  
  #ifdef __cplusplus
  extern "C" {
  #endif
  
  /**
   * @def     GNRC_PKTBUF_SIZE
   * @brief   Maximum size of the static packet buffer.
   *
   * @details The rational here is to have at least space for 4 full-MTU IPv6
   *          packages (2 incoming, 2 outgoing; 2 * 2 * 1280 B = 5 KiB) +
   *          Meta-Data (roughly estimated to 1 KiB; might be smaller). If
   *          @ref GNRC_PKTBUF_SIZE is 0 the packet buffer will use dynamic memory
   *          management to allocate packets.
   */
  #ifndef GNRC_PKTBUF_SIZE
  #define GNRC_PKTBUF_SIZE    (6144)
  #endif  /* GNRC_PKTBUF_SIZE */
  
  /**
   * @brief   Initializes packet buffer module.
   */
  void gnrc_pktbuf_init(void);
  
  /**
   * @brief   Adds a new gnrc_pktsnip_t and its packet to the packet buffer.
   *
   * @warning **Do not** change the fields of the gnrc_pktsnip_t created by this
   *          function externally. This will most likely create memory leaks or
   *          not allowed memory access.
   *
   * @pre size < GNRC_PKTBUF_SIZE
   *
   * @param[in] next      Next gnrc_pktsnip_t in the packet. Leave NULL if you
   *                      want to create a new packet.
   * @param[in] data      Data of the new gnrc_pktsnip_t. If @p data is NULL no data
   *                      will be inserted into `result`.
   * @param[in] size      Length of @p data. If this value is 0 the
   *                      gnrc_pktsnip::data field of the newly created snip will
   *                      be NULL.
   * @param[in] type      Protocol type of the gnrc_pktsnip_t.
   *
   * @return  Pointer to the packet part that represents the new gnrc_pktsnip_t.
   * @return  NULL, if no space is left in the packet buffer.
   */
  gnrc_pktsnip_t *gnrc_pktbuf_add(gnrc_pktsnip_t *next, void *data, size_t size,
                                  gnrc_nettype_t type);
  
  /**
   * @brief   Marks the first @p size bytes in a received packet with a new
   *          packet snip that is appended to the packet.
   *
   * Graphically this can be represented as follows:
   *
   * ~~~~~~~~~~~~~~~~~~~
   * Before                                    After
   * ======                                    =====
   *                                                       (next)
   *  pkt->data                                 result->data <== pkt->data
   *  v                                         v                v
   * +--------------------------------+        +----------------+---------------+
   * +--------------------------------+        +----------------+---------------+
   *  \__________pkt->size___________/          \_result->size_/ \__pkt->size__/
   * ~~~~~~~~~~~~~~~~~~~
   *
   * If `size == pkt->size` then the resulting snip will point to NULL in its
   * gnrc_pktsnip_t::data field and its gnrc_pktsnip_t::size field will be 0.
   *
   * @pre @p pkt != NULL && @p size != 0
   *
   * @param[in] pkt   A received packet.
   * @param[in] size  The size of the new packet snip.
   * @param[in] type  The type of the new packet snip.
   *
   * @return  The new packet snip in @p pkt on success.
   * @return  NULL, if pkt == NULL or size == 0 or size > pkt->size or pkt->data == NULL.
   * @return  NULL, if no space is left in the packet buffer.
   */
  gnrc_pktsnip_t *gnrc_pktbuf_mark(gnrc_pktsnip_t *pkt, size_t size, gnrc_nettype_t type);
  
  /**
   * @brief   Reallocates gnrc_pktsnip_t::data of @p pkt in the packet buffer, without
   *          changing the content.
   *
   * @pre `pkt != NULL`
   * @pre `(pkt->size > 0) <=> (pkt->data != NULL)`
   * @pre gnrc_pktsnip_t::data of @p pkt is in the packet buffer if it is not NULL.
   *
   * @details If enough memory is available behind it or @p size is smaller than
   *          the original size of the packet then gnrc_pktsnip_t::data of @p pkt will
   *          not be moved. Otherwise, it will be moved. If no space is available
   *          nothing happens.
   *
   * @param[in] pkt   A packet part.
   * @param[in] size  The size for @p pkt.
   *
   * @return  0, on success
   * @return  ENOMEM, if no space is left in the packet buffer.
   */
  int gnrc_pktbuf_realloc_data(gnrc_pktsnip_t *pkt, size_t size);
  
  /**
   * @brief   Increases gnrc_pktsnip_t::users of @p pkt atomically.
   *
   * @param[in] pkt   A packet.
   * @param[in] num   Number you want to increment gnrc_pktsnip_t::users of @p pkt by.
   */
  void gnrc_pktbuf_hold(gnrc_pktsnip_t *pkt, unsigned int num);
  
  /**
   * @brief   Decreases gnrc_pktsnip_t::users of @p pkt atomically and removes it if it
   *          reaches 0 and reports a possible error through an error code, if
   *          @ref net_gnrc_neterr is included.
   *
   * @pre All snips of @p pkt must be in the packet buffer.
   *
   * @param[in] pkt   A packet.
   * @param[in] err   An error code.
   */
  void gnrc_pktbuf_release_error(gnrc_pktsnip_t *pkt, uint32_t err);
  
  /**
   * @brief   Decreases gnrc_pktsnip_t::users of @p pkt atomically and removes it if it
   *          reaches 0 and reports @ref GNRC_NETERR_SUCCESS.
   *
   * @param[in] pkt   A packet.
   */
  static inline void gnrc_pktbuf_release(gnrc_pktsnip_t *pkt)
  {
      gnrc_pktbuf_release_error(pkt, GNRC_NETERR_SUCCESS);
  }
  
  /**
   * @brief   Must be called once before there is a write operation in a thread.
   *
   * @details This function duplicates a packet in the packet buffer if
   *          gnrc_pktsnip_t::users of @p pkt > 1.
   *
   * @note    Do *not* call this function in a thread twice on the same packet.
   *
   * @param[in] pkt   The packet you want to write into.
   *
   * @return  The (new) pointer to the pkt.
   * @return  NULL, if gnrc_pktsnip_t::users of @p pkt > 1 and if there is not
   *          enough space in the packet buffer.
   */
  gnrc_pktsnip_t *gnrc_pktbuf_start_write(gnrc_pktsnip_t *pkt);
  
  /**
   * @brief   Create a IOVEC representation of the packet pointed to by *pkt*
   *
   * @pre `(len != NULL)`
   *
   * @details This function will create a new packet snip in the packet buffer,
   *          which points to the given *pkt* and contains a IOVEC representation
   *          of the referenced packet in its data section.
   *
   * @param[in]  pkt  Packet to export as IOVEC
   * @param[out] len  Number of elements in the IOVEC
   *
   * @return  Pointer to the 'IOVEC packet snip'
   * @return  NULL, if packet is empty of the packet buffer is full
   */
  gnrc_pktsnip_t *gnrc_pktbuf_get_iovec(gnrc_pktsnip_t *pkt, size_t *len);
  
  /**
   * @brief   Deletes a snip from a packet and the packet buffer.
   *
   * @param[in] pkt   A packet.
   * @param[in] snip  A snip in the packet.
   *
   * @return  The new reference to @p pkt.
   */
  gnrc_pktsnip_t *gnrc_pktbuf_remove_snip(gnrc_pktsnip_t *pkt, gnrc_pktsnip_t *snip);
  
  /**
   * @brief   Replace a snip from a packet and the packet buffer by another snip.
   *
   * @param[in] pkt   A packet
   * @param[in] old   snip currently in the packet
   * @param[in] add   snip which will replace old
   *
   * @return  The new reference to @p pkt
   */
  gnrc_pktsnip_t *gnrc_pktbuf_replace_snip(gnrc_pktsnip_t *pkt, gnrc_pktsnip_t *old, gnrc_pktsnip_t *add);
  
  /**
   * @brief Duplicates pktsnip chain upto (including) a snip with the given type
   *        as a continuous snip.
   *
   *          Example:
   *              Input:
   *                                                                  buffer
   *              +---------------------------+                      +------+
   *              | size = 8                  | data       +-------->|      |
   *              | type = NETTYPE_IPV6_EXT   |------------+         +------+
   *              +---------------------------+                      .      .
   *                    | next                                       .      .
   *                    v                                            .      .
   *              +---------------------------+                      +------+
   *              | size = 40                 | data    +----------->|      |
   *              | type = NETTYPE_IPV6       |---------+            +------+
   *              +---------------------------+                      .      .
   *                    | next                                       .      .
   *                    v
   *              +---------------------------+                      +------+
   *              | size = 14                 | data +-------------->|      |
   *              | type = NETTYPE_NETIF      |------+               +------+
   *              +---------------------------+                      .      .
   *
   *
   *              Output:
   *                                                                  buffer
   *              +---------------------------+                      +------+
   *              | size = 48                 | data       +-------->|      |
   *              | type = NETTYPE_IPV6       |------------+         |      |
   *              +---------------------------+                      |      |
   *                    |                                            +------+
   *                    |                                            .      .
   *                    | next                                       .      .
   *                    v
   *              +---------------------------+                      +------+
   *              | size = 14                 | data +-------------->|      |
   *              | type = NETTYPE_NETIF      |------+               +------+
   *              +---------------------------+                      .      .
   *
   *        The original snip is keeped as is except `users` decremented.
   *
   * @param[in,out] pkt   The snip to duplicate.
   * @param[in]     type  The type of snip to stop duplication.
   *
   * @return The duplicated snip, if succeeded.
   * @return NULL, if no space is left in the packet buffer.
   */
  gnrc_pktsnip_t *gnrc_pktbuf_duplicate_upto(gnrc_pktsnip_t *pkt, gnrc_nettype_t type);
  
  #ifdef DEVELHELP
  /**
   * @brief   Prints some statistics about the packet buffer to stdout.
   *
   * @note    Only available with DEVELHELP defined.
   *
   * @details Statistics include maximum number of reserved bytes.
   */
  void gnrc_pktbuf_stats(void);
  #endif
  
  /* for testing */
  #ifdef TEST_SUITES
  /**
   * @brief   Checks if packet buffer is empty
   *
   * @return  true, if packet buffer is empty
   * @return  false, if packet buffer is not empty
   */
  bool gnrc_pktbuf_is_empty(void);
  
  /**
   * @brief   Checks if the implementation's internal invariants still uphold
   *
   * @return  true, the packet buffer is sane.
   * @return  false, the packet buffer is insane.
   */
  bool gnrc_pktbuf_is_sane(void);
  #endif
  
  #ifdef __cplusplus
  }
  #endif
  
  #endif /* NET_GNRC_PKTBUF_H */
  /** @} */