• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * coap_session_internal.h -- Structures, Enums & Functions that are not
3  * exposed to application programming
4  *
5  * Copyright (C) 2010-2023 Olaf Bergmann <bergmann@tzi.org>
6  *
7  * SPDX-License-Identifier: BSD-2-Clause
8  *
9  * This file is part of the CoAP library libcoap. Please see README for terms
10  * of use.
11  */
12 
13 /**
14  * @file coap_session_internal.h
15  * @brief CoAP session internal information
16  */
17 
18 #ifndef COAP_SESSION_INTERNAL_H_
19 #define COAP_SESSION_INTERNAL_H_
20 
21 #include "coap_internal.h"
22 #include "coap_io_internal.h"
23 #include "coap_ws_internal.h"
24 
25 #define COAP_DEFAULT_SESSION_TIMEOUT 300
26 #define COAP_PARTIAL_SESSION_TIMEOUT_TICKS (30 * COAP_TICKS_PER_SECOND)
27 #define COAP_DEFAULT_MAX_HANDSHAKE_SESSIONS 100
28 
29 /**
30  * @ingroup internal_api
31  * @defgroup session_internal Sessions
32  * Internal API for handling Sessions
33  * @{
34  */
35 
36 /**
37  * Only used for servers for hashing incoming packets. Cannot have local IP
38  * address as this may be an initial multicast and subsequent unicast address
39  */
40 struct coap_addr_hash_t {
41   coap_address_t remote;       /**< remote address and port */
42   uint16_t lport;              /**< local port */
43   coap_proto_t proto;          /**< CoAP protocol */
44 };
45 
46 typedef enum {
47   COAP_OSCORE_B_2_NONE = 0,
48   COAP_OSCORE_B_2_STEP_1,
49   COAP_OSCORE_B_2_STEP_2,
50   COAP_OSCORE_B_2_STEP_3,
51   COAP_OSCORE_B_2_STEP_4,
52   COAP_OSCORE_B_2_STEP_5,
53 } COAP_OSCORE_B_2_STEP;
54 
55 /**
56  * coap_ext_token_check_t values
57  */
58 typedef enum coap_ext_token_check_t {
59   COAP_EXT_T_NOT_CHECKED = 0, /**< Not checked */
60   COAP_EXT_T_CHECKED,         /**< Token size valid */
61   COAP_EXT_T_CHECKING,        /**< Token size check request sent */
62 } coap_ext_token_check_t;
63 
64 /**
65  * Abstraction of virtual session that can be attached to coap_context_t
66  * (client) or coap_endpoint_t (server).
67  */
68 struct coap_session_t {
69   coap_proto_t proto;               /**< protocol used */
70   coap_session_type_t type;         /**< client or server side socket */
71   coap_session_state_t state;       /**< current state of relationship with
72                                          peer */
73   unsigned ref;                     /**< reference count from queues */
74   size_t tls_overhead;              /**< overhead of TLS layer */
75   size_t mtu;                       /**< path or CSM mtu (xmt) */
76   size_t csm_rcv_mtu;               /**< CSM mtu (rcv) */
77   coap_addr_hash_t addr_hash;  /**< Address hash for server incoming packets */
78   UT_hash_handle hh;
79   coap_addr_tuple_t addr_info;      /**< remote/local address info */
80   int ifindex;                      /**< interface index */
81   coap_socket_t sock;               /**< socket object for the session, if
82                                          any */
83 #if COAP_SERVER_SUPPORT
84   coap_endpoint_t *endpoint;        /**< session's endpoint */
85 #endif /* COAP_SERVER_SUPPORT */
86   coap_context_t *context;          /**< session's context */
87   void *tls;                        /**< security parameters */
88   uint16_t tx_mid;                  /**< the last message id that was used in
89                                          this session */
90   uint8_t con_active;               /**< Active CON request sent */
91   uint8_t csm_block_supported;      /**< CSM TCP blocks supported */
92   coap_mid_t last_ping_mid;         /**< the last keepalive message id that was
93                                          used in this session */
94   coap_queue_t *delayqueue;         /**< list of delayed messages waiting to
95                                          be sent */
96   coap_lg_xmit_t *lg_xmit;          /**< list of large transmissions */
97 #if COAP_CLIENT_SUPPORT
98   coap_lg_crcv_t *lg_crcv;       /**< Client list of expected large receives */
99 #endif /* COAP_CLIENT_SUPPORT */
100 #if COAP_SERVER_SUPPORT
101   coap_lg_srcv_t *lg_srcv;       /**< Server list of expected large receives */
102 #endif /* COAP_SERVER_SUPPORT */
103   size_t partial_write;             /**< if > 0 indicates number of bytes
104                                          already written from the pdu at the
105                                          head of sendqueue */
106   uint8_t read_header[8];           /**< storage space for header of incoming
107                                          message header */
108   size_t partial_read;              /**< if > 0 indicates number of bytes
109                                         already read for an incoming message */
110   coap_pdu_t *partial_pdu;          /**< incomplete incoming pdu */
111   coap_tick_t last_rx_tx;
112   coap_tick_t last_tx_rst;
113   coap_tick_t last_ping;
114   coap_tick_t last_pong;
115   coap_tick_t csm_tx;
116   coap_dtls_cpsk_t cpsk_setup_data; /**< client provided PSK initial setup
117                                          data */
118   coap_bin_const_t *psk_identity;   /**< If client, this field contains the
119                                       current identity for server; When this
120                                       field is NULL, the current identity is
121                                       contained in cpsk_setup_data
122 
123                                       If server, this field contains the client
124                                       provided identity.
125 
126                                       Value maintained internally */
127   coap_bin_const_t *psk_key;        /**< If client, this field contains the
128                                       current pre-shared key for server;
129                                       When this field is NULL, the current
130                                       key is contained in cpsk_setup_data
131 
132                                       If server, this field contains the
133                                       client's current key.
134 
135                                       Value maintained internally */
136   coap_bin_const_t *psk_hint;       /**< If client, this field contains the
137                                       server provided identity hint.
138 
139                                       If server, this field contains the
140                                       current hint for the client; When this
141                                       field is NULL, the current hint is
142                                       contained in context->spsk_setup_data
143 
144                                       Value maintained internally */
145   void *app;                        /**< application-specific data */
146   coap_fixed_point_t ack_timeout;   /**< timeout waiting for ack
147                                          (default 2.0 secs) */
148   coap_fixed_point_t ack_random_factor; /**< ack random factor backoff (default
149                                              1.5) */
150   uint16_t max_retransmit;          /**< maximum re-transmit count
151                                          (default 4) */
152   uint16_t nstart;                  /**< maximum concurrent confirmable xmits
153                                          (default 1) */
154   coap_fixed_point_t default_leisure; /**< Mcast leisure time
155                                            (default 5.0 secs) */
156   uint32_t probing_rate;            /**< Max transfer wait when remote is not
157                                          respoding (default 1 byte/sec) */
158 #if COAP_Q_BLOCK_SUPPORT
159   uint16_t max_payloads;            /**< maximum Q-BlockX payloads before delay
160                                          (default 10) */
161   uint16_t non_max_retransmit;      /**< maximum Q-BlockX non re-transmit count
162                                          (default 4) */
163   coap_fixed_point_t non_timeout;   /**< Q-BlockX timeout waiting for response
164                                          (default 2.0 secs) */
165   coap_fixed_point_t non_receive_timeout;  /**< Q-BlockX receive timeout before
166                                          requesting missing packets.
167                                          (default 4.0 secs) */
168   coap_fixed_point_t non_probing_wait_base; /**< Q-BlockX max wait time base
169                                               while probing
170                                              (default 247.0 secs) */
171   coap_fixed_point_t non_partial_timeout; /**< Q-BlockX time to wait before
172                                            discarding partial data for a body.
173                                            (default 247.0 secs) */
174 #endif /* COAP_Q_BLOCK_SUPPORT */
175   unsigned int dtls_timeout_count;      /**< dtls setup retry counter */
176   int dtls_event;                       /**< Tracking any (D)TLS events on this
177                                              session */
178   uint32_t tx_rtag;               /**< Next Request-Tag number to use */
179   uint8_t csm_bert_rem_support;  /**< CSM TCP BERT blocks supported (remote) */
180   uint8_t csm_bert_loc_support;  /**< CSM TCP BERT blocks supported (local) */
181   uint8_t block_mode;             /**< Zero or more COAP_BLOCK_ or'd options */
182   uint8_t doing_first;            /**< Set if doing client's first request */
183   uint8_t proxy_session;        /**< Set if this is an ongoing proxy session */
184   uint8_t delay_recursive;        /**< Set if in coap_client_delay_first() */
185   uint8_t no_observe_cancel;      /**< Set if do not cancel observe on session
186                                        close */
187 #if COAP_OSCORE_SUPPORT
188   uint8_t oscore_encryption;      /**< OSCORE is used for this session  */
189   COAP_OSCORE_B_2_STEP b_2_step;  /**< Appendix B.2 negotiation step */
190   oscore_recipient_ctx_t *recipient_ctx; /**< OSCORE recipient context
191                                               for session */
192   oscore_association_t *associations; /**< OSCORE set of response
193                                            associations */
194   uint64_t oscore_r2;             /**< R2 for RFC8613 Appendix B.2 */
195 #endif /* COAP_OSCORE_SUPPORT */
196 #if COAP_WS_SUPPORT
197   coap_ws_state_t *ws;            /**< WS state */
198   coap_str_const_t *ws_host;      /**< Host to use in WS Request */
199 #endif /* COAP_WS_SUPPORT */
200   volatile uint8_t max_token_checked; /**< Check for max token size
201                                            coap_ext_token_check_t */
202   uint16_t remote_test_mid;       /**< mid used for checking remote
203                                        support */
204   uint32_t max_token_size;        /**< Largest token size supported RFC8974 */
205   uint64_t tx_token;              /**< Next token number to use */
206   coap_bin_const_t *last_token;   /** last token used to make a request */
207   coap_bin_const_t *echo;         /**< Echo value to send with next request */
208   coap_mid_t last_ack_mid;        /**< The last ACK mid that has been
209                                        been processed */
210   coap_mid_t last_con_mid;        /**< The last CON mid that has been
211                                        been processed */
212 };
213 
214 #if COAP_SERVER_SUPPORT
215 /**
216  * Abstraction of virtual endpoint that can be attached to coap_context_t. The
217  * keys (port, bind_addr) must uniquely identify this endpoint.
218  */
219 struct coap_endpoint_t {
220   struct coap_endpoint_t *next;
221   coap_context_t *context;        /**< endpoint's context */
222   coap_proto_t proto;             /**< protocol used on this interface */
223   uint16_t default_mtu;           /**< default mtu for this interface */
224   coap_socket_t sock;             /**< socket object for the interface, if
225                                        any */
226   coap_address_t bind_addr;       /**< local interface address */
227   coap_session_t *sessions;       /**< hash table or list of active sessions */
228 };
229 #endif /* COAP_SERVER_SUPPORT */
230 
231 coap_fixed_point_t coap_multi_fixed_fixed(coap_fixed_point_t fp1,
232                                           coap_fixed_point_t fp2);
233 
234 coap_fixed_point_t coap_multi_fixed_uint(coap_fixed_point_t fp1,
235                                          uint32_t u2);
236 
237 coap_fixed_point_t coap_add_fixed_fixed(coap_fixed_point_t fp1,
238                                         coap_fixed_point_t fp2);
239 
240 coap_fixed_point_t coap_add_fixed_uint(coap_fixed_point_t fp1,
241                                        uint32_t u2);
242 
243 coap_fixed_point_t coap_sub_fixed_uint(coap_fixed_point_t fp1,
244                                        uint32_t u2);
245 
246 coap_fixed_point_t coap_div_fixed_uint(coap_fixed_point_t fp1, uint32_t u2);
247 
248 coap_fixed_point_t coap_get_non_timeout_random(coap_session_t *session);
249 
250 coap_tick_t coap_get_non_timeout_random_ticks(coap_session_t *session);
251 
252 
253 /**
254  * Notify session transport has just connected and CSM exchange can now start.
255  *
256  * @param session The CoAP session.
257  */
258 void coap_session_send_csm(coap_session_t *session);
259 
260 /**
261  * Notify session that it has just connected or reconnected.
262  *
263  * @param session The CoAP session.
264  */
265 void coap_session_connected(coap_session_t *session);
266 
267 /**
268  * Refresh the session's current Identity Hint (PSK).
269  * Note: A copy of @p psk_hint is maintained in the session by libcoap.
270  *
271  * @param session  The current coap_session_t object.
272  * @param psk_hint If NULL, the Identity Hint will revert to the
273  *                 initial Identity Hint used at session setup.
274  *
275  * @return @c 1 if successful, else @c 0.
276  */
277 int coap_session_refresh_psk_hint(coap_session_t *session,
278                                   const coap_bin_const_t *psk_hint);
279 
280 /**
281  * Refresh the session's current pre-shared key (PSK).
282  * Note: A copy of @p psk_key is maintained in the session by libcoap.
283  *
284  * @param session  The current coap_session_t object.
285  * @param psk_key  If NULL, the pre-shared key will revert to the
286  *                 initial pre-shared key used at session setup.
287  *
288  * @return @c 1 if successful, else @c 0.
289  */
290 int coap_session_refresh_psk_key(coap_session_t *session,
291                                  const coap_bin_const_t *psk_key);
292 
293 /**
294  * Refresh the session's current pre-shared identity (PSK).
295  * Note: A copy of @p psk_identity is maintained in the session by libcoap.
296  *
297  * @param session  The current coap_session_t object.
298  * @param psk_identity  If NULL, the pre-shared identity will revert to the
299  *                 initial pre-shared key used as session setup.
300  *
301  * @return @c 1 if successful, else @c 0.
302  */
303 int coap_session_refresh_psk_identity(coap_session_t *session,
304                                       const coap_bin_const_t *psk_identity);
305 
306 #if COAP_SERVER_SUPPORT
307 /**
308  * Creates a new server session for the specified endpoint.
309  * @param ctx The CoAP context.
310  * @param ep An endpoint where an incoming connection request is pending.
311  *
312  * @return A new CoAP session or NULL if failed. Call coap_session_release to
313  * add to unused queue.
314  */
315 coap_session_t *coap_new_server_session(
316     coap_context_t *ctx,
317     coap_endpoint_t *ep
318 );
319 #endif /* COAP_SERVER_SUPPORT */
320 
321 /**
322  * Layer function interface for layer below session accept/connect being
323  * established. This function initiates a CSM request for reliable protocols,
324  * or coap_session_connect() for un-reliable protocols.
325  *
326  * @param session Session that the lower layer accept/connect was done on.
327  *
328  */
329 void coap_session_establish(coap_session_t *session);
330 
331 /**
332  * Send a pdu according to the session's protocol. This function returns
333  * the number of bytes that have been transmitted, or a value less than zero
334  * on error.
335  *
336  * @param session          Session to send pdu on.
337  * @param pdu              The pdu to send.
338  *
339  * @return                 The number of bytes written on success, or a value
340  *                         less than zero on error.
341  */
342 ssize_t coap_session_send_pdu(coap_session_t *session, coap_pdu_t *pdu);
343 
344 ssize_t coap_session_delay_pdu(coap_session_t *session, coap_pdu_t *pdu,
345                                coap_queue_t *node);
346 
347 #if COAP_SERVER_SUPPORT
348 /**
349  * Lookup the server session for the packet received on an endpoint, or create
350  * a new one.
351  *
352  * @param endpoint Active endpoint the packet was received on.
353  * @param packet Received packet.
354  * @param now The current time in ticks.
355  * @return The CoAP session or @c NULL if error.
356  */
357 coap_session_t *coap_endpoint_get_session(coap_endpoint_t *endpoint,
358                                           const coap_packet_t *packet, coap_tick_t now);
359 #endif /* COAP_SERVER_SUPPORT */
360 
361 /**
362  * Get maximum acceptable receive PDU size
363  *
364  * @param session The CoAP session.
365  * @return maximum PDU size, not including header (but including token).
366  */
367 size_t coap_session_max_pdu_rcv_size(const coap_session_t *session);
368 
369 /**
370  * Create a new DTLS session for the @p session.
371  * Note: the @p session is released if no DTLS server session can be created.
372  *
373  * @ingroup dtls_internal
374  *
375  * @param session   Session to add DTLS session to
376  * @param now       The current time in ticks.
377  *
378  * @return CoAP session or @c NULL if error.
379  */
380 coap_session_t *coap_session_new_dtls_session(coap_session_t *session,
381                                               coap_tick_t now);
382 
383 void coap_session_free(coap_session_t *session);
384 void coap_session_mfree(coap_session_t *session);
385 
386 #define COAP_SESSION_REF(s) ((s)->ref
387 
388 /* RFC7252 */
389 #define COAP_ACK_TIMEOUT(s) ((s)->ack_timeout)
390 #define COAP_ACK_RANDOM_FACTOR(s) ((s)->ack_random_factor)
391 #define COAP_MAX_RETRANSMIT(s) ((s)->max_retransmit)
392 #define COAP_NSTART(s) ((s)->nstart)
393 #define COAP_DEFAULT_LEISURE(s) ((s)->default_leisure)
394 #define COAP_PROBING_RATE(s) ((s)->probing_rate)
395 /* RFC9177 */
396 #define COAP_MAX_PAYLOADS(s) ((s)->max_payloads)
397 #define COAP_NON_MAX_RETRANSMIT(s) ((s)->non_max_retransmit)
398 #define COAP_NON_TIMEOUT(s) ((s)->non_timeout)
399 #define COAP_NON_TIMEOUT_TICKS(s) \
400   (COAP_NON_TIMEOUT(s).integer_part * COAP_TICKS_PER_SECOND + \
401    COAP_NON_TIMEOUT(s).fractional_part * COAP_TICKS_PER_SECOND / 1000)
402 #define COAP_NON_RECEIVE_TIMEOUT(s) ((s)->non_receive_timeout)
403 #define COAP_NON_PROBING_WAIT_BASE(s) ((s)->non_probing_wait_base)
404 #define COAP_NON_PARTIAL_TIMEOUT(s) ((s)->non_partial_timeout)
405 
406 /**
407  * The DEFAULT_LEISURE definition for the session (s).
408  *
409  * RFC 7252, Section 4.8
410  * Initial value 5.0 seconds
411  */
412 #define COAP_DEFAULT_LEISURE_TICKS(s) \
413   (COAP_DEFAULT_LEISURE(s).integer_part * COAP_TICKS_PER_SECOND + \
414    COAP_DEFAULT_LEISURE(s).fractional_part * COAP_TICKS_PER_SECOND / 1000)
415 /**
416  * The MAX_TRANSMIT_SPAN definition for the session (s).
417  *
418  * RFC 7252, Section 4.8.2 Calculation of MAX_TRAMSMIT_SPAN
419  *  ACK_TIMEOUT * ((2 ** (MAX_RETRANSMIT)) - 1) * ACK_RANDOM_FACTOR
420  */
421 #define COAP_MAX_TRANSMIT_SPAN(s) \
422   (((s)->ack_timeout.integer_part * 1000 + (s)->ack_timeout.fractional_part) * \
423    ((1 << ((s)->max_retransmit)) -1) * \
424    ((s)->ack_random_factor.integer_part * 1000 + \
425     (s)->ack_random_factor.fractional_part) \
426    / 1000000)
427 
428 /**
429  * The MAX_TRANSMIT_WAIT definition for the session (s).
430  *
431  * RFC 7252, Section 4.8.2 Calculation of MAX_TRAMSMIT_WAIT
432  *  ACK_TIMEOUT * ((2 ** (MAX_RETRANSMIT + 1)) - 1) * ACK_RANDOM_FACTOR
433  */
434 #define COAP_MAX_TRANSMIT_WAIT(s) \
435   (((s)->ack_timeout.integer_part * 1000 + (s)->ack_timeout.fractional_part) * \
436    ((1 << ((s)->max_retransmit + 1)) -1) * \
437    ((s)->ack_random_factor.integer_part * 1000 + \
438     (s)->ack_random_factor.fractional_part) \
439    / 1000000)
440 
441 #define COAP_MAX_TRANSMIT_WAIT_TICKS(s) \
442   (COAP_MAX_TRANSMIT_WAIT(s) * COAP_TICKS_PER_SECOND)
443 
444 /**
445  * The PROCESSING_DELAY definition for the session (s).
446  *
447  * RFC 7252, Section 4.8.2 Calculation of PROCESSING_DELAY
448  *  PROCESSING_DELAY set to ACK_TIMEOUT
449  */
450 #define COAP_PROCESSING_DELAY(s) \
451   (((s)->ack_timeout.integer_part * 1000 + (s)->ack_timeout.fractional_part + \
452     500) / 1000)
453 
454 /**
455  * The MAX_RTT definition for the session (s).
456  *
457  * RFC 7252, Section 4.8.2 Calculation of MAX_RTT
458  *  (2 * MAX_LATENCY) + PROCESSING_DELAY
459  */
460 #define COAP_MAX_RTT(s) \
461   ((2 * COAP_DEFAULT_MAX_LATENCY) + COAP_PROCESSING_DELAY(s))
462 
463 /**
464  * The EXCHANGE_LIFETIME definition for the session (s).
465  *
466  * RFC 7252, Section 4.8.2 Calculation of EXCHANGE_LIFETIME
467  *  MAX_TRANSMIT_SPAN + (2 * MAX_LATENCY) + PROCESSING_DELAY
468  */
469 #define COAP_EXCHANGE_LIFETIME(s) \
470   (COAP_MAX_TRANSMIT_SPAN(s) + (2 * COAP_DEFAULT_MAX_LATENCY) + \
471    COAP_PROCESSING_DELAY(s))
472 
473 /**
474  * The NON_LIFETIME definition for the session (s).
475  *
476  * RFC 7252, Section 4.8.2 Calculation of NON_LIFETIME
477  *  MAX_TRANSMIT_SPAN + MAX_LATENCY
478  */
479 #define COAP_NON_LIFETIME(s) \
480   (COAP_MAX_TRANSMIT_SPAN(s) + COAP_DEFAULT_MAX_LATENCY)
481 
482 /**
483  * The NON_RECEIVE_TIMEOUT definition for the session (s).
484  *
485  * RFC9177 Section 6.2
486  * 2 * NON_TIMEOUT
487  */
488 #define COAP_NON_RECEIVE_TIMEOUT_TICKS(s) ( \
489                                             COAP_NON_RECEIVE_TIMEOUT(s).integer_part * COAP_TICKS_PER_SECOND + \
490                                             COAP_NON_RECEIVE_TIMEOUT(s).fractional_part * COAP_TICKS_PER_SECOND / 1000)
491 
492 /**
493  * The NON_PROBING_WAIT definition for the session (s).
494  *
495  * RFC9177 Section 6.2
496  *  NON_PROBING_WAIT = NON_TIMEOUT * ((2 ** NON_MAX_RETRANSMIT) - 1) *
497  *  ACK_RANDOM_FACTOR + (2 * MAX_LATENCY) + NON_TIMEOUT_RANDOM
498  * Default is 247-248 seconds
499  */
500 #define COAP_NON_PROBING_WAIT(s) \
501   coap_add_fixed_fixed(COAP_NON_PROBING_WAIT_BASE(s), \
502                        COAP_NON_TIMEOUT_RANDOM(s))
503 
504 #define COAP_NON_PROBING_WAIT_TICKS(s) \
505   (COAP_NON_PROBING_WAIT(s).integer_part * COAP_TICKS_PER_SECOND + \
506    COAP_NON_PROBING_WAIT(s).fractional_part * COAP_TICKS_PER_SECOND / 1000)
507 
508 /**
509  * The NON_PARTIAL_TIMEOUT definition for the session (s).
510  *
511  * RFC9177 Section 6.2
512  * Initial value EXCHANGE_LIFETIME (247 seconds)
513  */
514 #define COAP_NON_PARTIAL_TIMEOUT_TICKS(s) \
515   (COAP_NON_PARTIAL_TIMEOUT(s).integer_part * COAP_TICKS_PER_SECOND + \
516    COAP_NON_PARTIAL_TIMEOUT(s).fractional_part * COAP_TICKS_PER_SECOND / 1000)
517 
518 /**
519  * The NON_TIMEOUT_RANDOM definition for the session (s).
520  *
521  * RFC9177 Section 6.2
522  * Default is 2-3 seconds
523  */
524 #define COAP_NON_TIMEOUT_RANDOM(s) \
525   coap_get_non_timeout_random(s)
526 
527 /** @} */
528 
529 #define SESSIONS_ADD(e, obj) \
530   HASH_ADD(hh, (e), addr_hash, sizeof((obj)->addr_hash), (obj))
531 
532 #define SESSIONS_DELETE(e, obj) \
533   HASH_DELETE(hh, (e), (obj))
534 
535 #define SESSIONS_ITER(e, el, rtmp)  \
536   HASH_ITER(hh, (e), el, rtmp)
537 
538 #define SESSIONS_ITER_SAFE(e, el, rtmp) \
539   for ((el) = (e); (el) && ((rtmp) = (el)->hh.next, 1); (el) = (rtmp))
540 
541 #define SESSIONS_FIND(e, k, res) {                     \
542     HASH_FIND(hh, (e), &(k), sizeof(k), (res)); \
543   }
544 
545 #endif /* COAP_SESSION_INTERNAL_H_ */
546