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 #ifdef SUPPORT_OPTIC_ONT 261 /** 262 * Notify session skip CSM. 263 * 264 * @param session The CoAP session. 265 */ 266 void coap_session_skip_csm(coap_session_t *session); 267 #endif 268 269 /** 270 * Notify session that it has just connected or reconnected. 271 * 272 * @param session The CoAP session. 273 */ 274 void coap_session_connected(coap_session_t *session); 275 276 /** 277 * Refresh the session's current Identity Hint (PSK). 278 * Note: A copy of @p psk_hint is maintained in the session by libcoap. 279 * 280 * @param session The current coap_session_t object. 281 * @param psk_hint If NULL, the Identity Hint will revert to the 282 * initial Identity Hint used at session setup. 283 * 284 * @return @c 1 if successful, else @c 0. 285 */ 286 int coap_session_refresh_psk_hint(coap_session_t *session, 287 const coap_bin_const_t *psk_hint); 288 289 /** 290 * Refresh the session's current pre-shared key (PSK). 291 * Note: A copy of @p psk_key is maintained in the session by libcoap. 292 * 293 * @param session The current coap_session_t object. 294 * @param psk_key If NULL, the pre-shared key will revert to the 295 * initial pre-shared key used at session setup. 296 * 297 * @return @c 1 if successful, else @c 0. 298 */ 299 int coap_session_refresh_psk_key(coap_session_t *session, 300 const coap_bin_const_t *psk_key); 301 302 /** 303 * Refresh the session's current pre-shared identity (PSK). 304 * Note: A copy of @p psk_identity is maintained in the session by libcoap. 305 * 306 * @param session The current coap_session_t object. 307 * @param psk_identity If NULL, the pre-shared identity will revert to the 308 * initial pre-shared key used as session setup. 309 * 310 * @return @c 1 if successful, else @c 0. 311 */ 312 int coap_session_refresh_psk_identity(coap_session_t *session, 313 const coap_bin_const_t *psk_identity); 314 315 #if COAP_SERVER_SUPPORT 316 /** 317 * Creates a new server session for the specified endpoint. 318 * @param ctx The CoAP context. 319 * @param ep An endpoint where an incoming connection request is pending. 320 * 321 * @return A new CoAP session or NULL if failed. Call coap_session_release to 322 * add to unused queue. 323 */ 324 coap_session_t *coap_new_server_session( 325 coap_context_t *ctx, 326 coap_endpoint_t *ep 327 ); 328 #endif /* COAP_SERVER_SUPPORT */ 329 330 /** 331 * Layer function interface for layer below session accept/connect being 332 * established. This function initiates a CSM request for reliable protocols, 333 * or coap_session_connect() for un-reliable protocols. 334 * 335 * @param session Session that the lower layer accept/connect was done on. 336 * 337 */ 338 void coap_session_establish(coap_session_t *session); 339 340 /** 341 * Send a pdu according to the session's protocol. This function returns 342 * the number of bytes that have been transmitted, or a value less than zero 343 * on error. 344 * 345 * @param session Session to send pdu on. 346 * @param pdu The pdu to send. 347 * 348 * @return The number of bytes written on success, or a value 349 * less than zero on error. 350 */ 351 ssize_t coap_session_send_pdu(coap_session_t *session, coap_pdu_t *pdu); 352 353 ssize_t coap_session_delay_pdu(coap_session_t *session, coap_pdu_t *pdu, 354 coap_queue_t *node); 355 356 #if COAP_SERVER_SUPPORT 357 /** 358 * Lookup the server session for the packet received on an endpoint, or create 359 * a new one. 360 * 361 * @param endpoint Active endpoint the packet was received on. 362 * @param packet Received packet. 363 * @param now The current time in ticks. 364 * @return The CoAP session or @c NULL if error. 365 */ 366 coap_session_t *coap_endpoint_get_session(coap_endpoint_t *endpoint, 367 const coap_packet_t *packet, coap_tick_t now); 368 #endif /* COAP_SERVER_SUPPORT */ 369 370 /** 371 * Get maximum acceptable receive PDU size 372 * 373 * @param session The CoAP session. 374 * @return maximum PDU size, not including header (but including token). 375 */ 376 size_t coap_session_max_pdu_rcv_size(const coap_session_t *session); 377 378 /** 379 * Create a new DTLS session for the @p session. 380 * Note: the @p session is released if no DTLS server session can be created. 381 * 382 * @ingroup dtls_internal 383 * 384 * @param session Session to add DTLS session to 385 * @param now The current time in ticks. 386 * 387 * @return CoAP session or @c NULL if error. 388 */ 389 coap_session_t *coap_session_new_dtls_session(coap_session_t *session, 390 coap_tick_t now); 391 392 void coap_session_free(coap_session_t *session); 393 void coap_session_mfree(coap_session_t *session); 394 395 #define COAP_SESSION_REF(s) ((s)->ref 396 397 /* RFC7252 */ 398 #define COAP_ACK_TIMEOUT(s) ((s)->ack_timeout) 399 #define COAP_ACK_RANDOM_FACTOR(s) ((s)->ack_random_factor) 400 #define COAP_MAX_RETRANSMIT(s) ((s)->max_retransmit) 401 #define COAP_NSTART(s) ((s)->nstart) 402 #define COAP_DEFAULT_LEISURE(s) ((s)->default_leisure) 403 #define COAP_PROBING_RATE(s) ((s)->probing_rate) 404 /* RFC9177 */ 405 #define COAP_MAX_PAYLOADS(s) ((s)->max_payloads) 406 #define COAP_NON_MAX_RETRANSMIT(s) ((s)->non_max_retransmit) 407 #define COAP_NON_TIMEOUT(s) ((s)->non_timeout) 408 #define COAP_NON_TIMEOUT_TICKS(s) \ 409 (COAP_NON_TIMEOUT(s).integer_part * COAP_TICKS_PER_SECOND + \ 410 COAP_NON_TIMEOUT(s).fractional_part * COAP_TICKS_PER_SECOND / 1000) 411 #define COAP_NON_RECEIVE_TIMEOUT(s) ((s)->non_receive_timeout) 412 #define COAP_NON_PROBING_WAIT_BASE(s) ((s)->non_probing_wait_base) 413 #define COAP_NON_PARTIAL_TIMEOUT(s) ((s)->non_partial_timeout) 414 415 /** 416 * The DEFAULT_LEISURE definition for the session (s). 417 * 418 * RFC 7252, Section 4.8 419 * Initial value 5.0 seconds 420 */ 421 #define COAP_DEFAULT_LEISURE_TICKS(s) \ 422 (COAP_DEFAULT_LEISURE(s).integer_part * COAP_TICKS_PER_SECOND + \ 423 COAP_DEFAULT_LEISURE(s).fractional_part * COAP_TICKS_PER_SECOND / 1000) 424 /** 425 * The MAX_TRANSMIT_SPAN definition for the session (s). 426 * 427 * RFC 7252, Section 4.8.2 Calculation of MAX_TRAMSMIT_SPAN 428 * ACK_TIMEOUT * ((2 ** (MAX_RETRANSMIT)) - 1) * ACK_RANDOM_FACTOR 429 */ 430 #define COAP_MAX_TRANSMIT_SPAN(s) \ 431 (((s)->ack_timeout.integer_part * 1000 + (s)->ack_timeout.fractional_part) * \ 432 ((1 << ((s)->max_retransmit)) -1) * \ 433 ((s)->ack_random_factor.integer_part * 1000 + \ 434 (s)->ack_random_factor.fractional_part) \ 435 / 1000000) 436 437 /** 438 * The MAX_TRANSMIT_WAIT definition for the session (s). 439 * 440 * RFC 7252, Section 4.8.2 Calculation of MAX_TRAMSMIT_WAIT 441 * ACK_TIMEOUT * ((2 ** (MAX_RETRANSMIT + 1)) - 1) * ACK_RANDOM_FACTOR 442 */ 443 #define COAP_MAX_TRANSMIT_WAIT(s) \ 444 (((s)->ack_timeout.integer_part * 1000 + (s)->ack_timeout.fractional_part) * \ 445 ((1 << ((s)->max_retransmit + 1)) -1) * \ 446 ((s)->ack_random_factor.integer_part * 1000 + \ 447 (s)->ack_random_factor.fractional_part) \ 448 / 1000000) 449 450 #define COAP_MAX_TRANSMIT_WAIT_TICKS(s) \ 451 (COAP_MAX_TRANSMIT_WAIT(s) * COAP_TICKS_PER_SECOND) 452 453 /** 454 * The PROCESSING_DELAY definition for the session (s). 455 * 456 * RFC 7252, Section 4.8.2 Calculation of PROCESSING_DELAY 457 * PROCESSING_DELAY set to ACK_TIMEOUT 458 */ 459 #define COAP_PROCESSING_DELAY(s) \ 460 (((s)->ack_timeout.integer_part * 1000 + (s)->ack_timeout.fractional_part + \ 461 500) / 1000) 462 463 /** 464 * The MAX_RTT definition for the session (s). 465 * 466 * RFC 7252, Section 4.8.2 Calculation of MAX_RTT 467 * (2 * MAX_LATENCY) + PROCESSING_DELAY 468 */ 469 #define COAP_MAX_RTT(s) \ 470 ((2 * COAP_DEFAULT_MAX_LATENCY) + COAP_PROCESSING_DELAY(s)) 471 472 /** 473 * The EXCHANGE_LIFETIME definition for the session (s). 474 * 475 * RFC 7252, Section 4.8.2 Calculation of EXCHANGE_LIFETIME 476 * MAX_TRANSMIT_SPAN + (2 * MAX_LATENCY) + PROCESSING_DELAY 477 */ 478 #define COAP_EXCHANGE_LIFETIME(s) \ 479 (COAP_MAX_TRANSMIT_SPAN(s) + (2 * COAP_DEFAULT_MAX_LATENCY) + \ 480 COAP_PROCESSING_DELAY(s)) 481 482 /** 483 * The NON_LIFETIME definition for the session (s). 484 * 485 * RFC 7252, Section 4.8.2 Calculation of NON_LIFETIME 486 * MAX_TRANSMIT_SPAN + MAX_LATENCY 487 */ 488 #define COAP_NON_LIFETIME(s) \ 489 (COAP_MAX_TRANSMIT_SPAN(s) + COAP_DEFAULT_MAX_LATENCY) 490 491 /** 492 * The NON_RECEIVE_TIMEOUT definition for the session (s). 493 * 494 * RFC9177 Section 6.2 495 * 2 * NON_TIMEOUT 496 */ 497 #define COAP_NON_RECEIVE_TIMEOUT_TICKS(s) ( \ 498 COAP_NON_RECEIVE_TIMEOUT(s).integer_part * COAP_TICKS_PER_SECOND + \ 499 COAP_NON_RECEIVE_TIMEOUT(s).fractional_part * COAP_TICKS_PER_SECOND / 1000) 500 501 /** 502 * The NON_PROBING_WAIT definition for the session (s). 503 * 504 * RFC9177 Section 6.2 505 * NON_PROBING_WAIT = NON_TIMEOUT * ((2 ** NON_MAX_RETRANSMIT) - 1) * 506 * ACK_RANDOM_FACTOR + (2 * MAX_LATENCY) + NON_TIMEOUT_RANDOM 507 * Default is 247-248 seconds 508 */ 509 #define COAP_NON_PROBING_WAIT(s) \ 510 coap_add_fixed_fixed(COAP_NON_PROBING_WAIT_BASE(s), \ 511 COAP_NON_TIMEOUT_RANDOM(s)) 512 513 #define COAP_NON_PROBING_WAIT_TICKS(s) \ 514 (COAP_NON_PROBING_WAIT(s).integer_part * COAP_TICKS_PER_SECOND + \ 515 COAP_NON_PROBING_WAIT(s).fractional_part * COAP_TICKS_PER_SECOND / 1000) 516 517 /** 518 * The NON_PARTIAL_TIMEOUT definition for the session (s). 519 * 520 * RFC9177 Section 6.2 521 * Initial value EXCHANGE_LIFETIME (247 seconds) 522 */ 523 #define COAP_NON_PARTIAL_TIMEOUT_TICKS(s) \ 524 (COAP_NON_PARTIAL_TIMEOUT(s).integer_part * COAP_TICKS_PER_SECOND + \ 525 COAP_NON_PARTIAL_TIMEOUT(s).fractional_part * COAP_TICKS_PER_SECOND / 1000) 526 527 /** 528 * The NON_TIMEOUT_RANDOM definition for the session (s). 529 * 530 * RFC9177 Section 6.2 531 * Default is 2-3 seconds 532 */ 533 #define COAP_NON_TIMEOUT_RANDOM(s) \ 534 coap_get_non_timeout_random(s) 535 536 /** @} */ 537 538 #define SESSIONS_ADD(e, obj) \ 539 HASH_ADD(hh, (e), addr_hash, sizeof((obj)->addr_hash), (obj)) 540 541 #define SESSIONS_DELETE(e, obj) \ 542 HASH_DELETE(hh, (e), (obj)) 543 544 #define SESSIONS_ITER(e, el, rtmp) \ 545 HASH_ITER(hh, (e), el, rtmp) 546 547 #define SESSIONS_ITER_SAFE(e, el, rtmp) \ 548 for ((el) = (e); (el) && ((rtmp) = (el)->hh.next, 1); (el) = (rtmp)) 549 550 #define SESSIONS_FIND(e, k, res) { \ 551 HASH_FIND(hh, (e), &(k), sizeof(k), (res)); \ 552 } 553 554 #endif /* COAP_SESSION_INTERNAL_H_ */ 555