5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2006 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
20 * Created: Fri Jul 25 18:52:14 1997
26 /************************** Types and definitions ***************************/
29 struct SilcPacketEngineStruct {
30 SilcRng rng; /* RNG for engine */
31 SilcPacketCallbacks *callbacks; /* Packet callbacks */
32 void *callback_context; /* Context for callbacks */
33 SilcList streams; /* All streams in engine */
34 SilcList packet_pool; /* Free list for received packets */
35 SilcMutex lock; /* Engine lock */
36 SilcBool local_is_router;
39 /* Packet procesor context */
40 typedef struct SilcPacketProcessStruct {
41 SilcInt32 priority; /* Priority */
42 SilcPacketType *types; /* Packets to process */
43 SilcPacketCallbacks *callbacks; /* Callbacks or NULL */
44 void *callback_context;
48 struct SilcPacketStreamStruct {
49 struct SilcPacketStreamStruct *next;
50 SilcPacketEngine engine; /* Packet engine */
51 SilcStream stream; /* Underlaying stream */
52 SilcMutex lock; /* Stream lock */
53 SilcDList process; /* Packet processors, it set */
54 void *stream_context; /* Stream context */
55 SilcBufferStruct inbuf; /* In buffer */
56 SilcBufferStruct outbuf; /* Out buffer */
57 SilcCipher send_key[2]; /* Sending key */
58 SilcHmac send_hmac[2]; /* Sending HMAC */
59 SilcCipher receive_key[2]; /* Receiving key */
60 SilcHmac receive_hmac[2]; /* Receiving HMAC */
61 unsigned char *src_id; /* Source ID */
62 unsigned char *dst_id; /* Destination ID */
63 SilcUInt32 send_psn; /* Sending sequence */
64 SilcUInt32 receive_psn; /* Receiving sequence */
65 SilcAtomic8 refcnt; /* Reference counter */
66 unsigned int src_id_len : 6;
67 unsigned int src_id_type : 2;
68 unsigned int dst_id_len : 6;
69 unsigned int dst_id_type : 2;
70 unsigned int is_router : 1; /* Set if router stream */
71 unsigned int destroyed : 1; /* Set if destroyed */
72 unsigned int iv_included : 1; /* Set if IV included */
73 SilcUInt8 sid; /* Security ID, set if IV included */
76 /* Initial size of stream buffers */
77 #define SILC_PACKET_DEFAULT_SIZE 1024
79 /* Header length without source and destination ID's. */
80 #define SILC_PACKET_HEADER_LEN 10
82 /* Minimum length of SILC Packet Header. */
83 #define SILC_PACKET_MIN_HEADER_LEN 16
84 #define SILC_PACKET_MIN_HEADER_LEN_IV 32 + 1
86 /* Maximum padding length */
87 #define SILC_PACKET_MAX_PADLEN 128
89 /* Default padding length */
90 #define SILC_PACKET_DEFAULT_PADLEN 16
92 /* Minimum packet length */
93 #define SILC_PACKET_MIN_LEN (SILC_PACKET_HEADER_LEN + 1)
95 /* Returns true length of the packet. */
96 #define SILC_PACKET_LENGTH(__packetdata, __ret_truelen, __ret_paddedlen) \
98 SILC_GET16_MSB((__ret_truelen), (__packetdata)); \
99 (__ret_paddedlen) = (__ret_truelen) + (SilcUInt8)(__packetdata)[4]; \
102 /* Calculates the data length with given header length. This macro
103 can be used to check whether the data_len with header_len exceeds
104 SILC_PACKET_MAX_LEN. If it does, this returns the new data_len
105 so that the SILC_PACKET_MAX_LEN is not exceeded. If the data_len
106 plus header_len fits SILC_PACKET_MAX_LEN the returned data length
107 is the data_len given as argument. */
108 #define SILC_PACKET_DATALEN(data_len, header_len) \
109 ((data_len + header_len) > SILC_PACKET_MAX_LEN ? \
110 data_len - ((data_len + header_len) - SILC_PACKET_MAX_LEN) : data_len)
112 /* Calculates the length of the padding in the packet. */
113 #define SILC_PACKET_PADLEN(__packetlen, __blocklen, __padlen) \
115 __padlen = (SILC_PACKET_DEFAULT_PADLEN - (__packetlen) % \
116 ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN)); \
118 __padlen += ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN); \
121 /* Returns the length of the padding up to the maximum length, which
123 #define SILC_PACKET_PADLEN_MAX(__packetlen, __blocklen, __padlen) \
125 __padlen = (SILC_PACKET_MAX_PADLEN - (__packetlen) % \
126 ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN)); \
130 #define SILC_PACKET_CALLBACK_EOS(s) \
132 (s)->engine->callbacks->eos((s)->engine, s, \
133 (s)->engine->callback_context, \
134 (s)->stream_context); \
138 #define SILC_PACKET_CALLBACK_ERROR(s, err) \
140 (s)->engine->callbacks->error((s)->engine, s, err, \
141 (s)->engine->callback_context, \
142 (s)->stream_context); \
146 /************************ Static utility functions **************************/
148 static void silc_packet_read_process(SilcPacketStream stream);
150 /* Our stream IO notifier callback. */
152 static void silc_packet_stream_io(SilcStream stream, SilcStreamStatus status,
155 SilcPacketStream ps = context;
158 silc_mutex_lock(ps->lock);
161 silc_mutex_unlock(ps->lock);
167 case SILC_STREAM_CAN_WRITE:
168 if (!silc_buffer_headlen(&ps->outbuf)) {
169 silc_mutex_unlock(ps->lock);
173 SILC_LOG_DEBUG(("Writing pending data to stream"));
175 /* Write pending data to stream */
176 while (silc_buffer_len(&ps->outbuf) > 0) {
177 ret = silc_stream_write(ps->stream, ps->outbuf.data,
178 silc_buffer_len(&ps->outbuf));
181 silc_buffer_reset(&ps->outbuf);
182 silc_mutex_unlock(ps->lock);
183 SILC_PACKET_CALLBACK_EOS(ps);
189 silc_buffer_reset(&ps->outbuf);
190 silc_mutex_unlock(ps->lock);
191 SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_WRITE);
196 /* Cannot write now, write later. */
197 silc_mutex_unlock(ps->lock);
202 silc_buffer_pull(&ps->outbuf, ret);
205 silc_buffer_reset(&ps->outbuf);
207 silc_mutex_unlock(ps->lock);
210 case SILC_STREAM_CAN_READ:
211 SILC_LOG_DEBUG(("Reading data from stream"));
213 /* Make sure we have fair amount of free space in inbuf */
214 if (silc_buffer_taillen(&ps->inbuf) < SILC_PACKET_DEFAULT_SIZE)
215 if (!silc_buffer_realloc(&ps->inbuf, silc_buffer_truelen(&ps->inbuf) +
216 SILC_PACKET_DEFAULT_SIZE * 2)) {
217 silc_mutex_unlock(ps->lock);
221 /* Read data from stream */
222 ret = silc_stream_read(ps->stream, ps->inbuf.tail,
223 silc_buffer_taillen(&ps->inbuf));
227 silc_buffer_reset(&ps->inbuf);
228 silc_mutex_unlock(ps->lock);
229 SILC_PACKET_CALLBACK_EOS(ps);
235 silc_buffer_reset(&ps->inbuf);
236 silc_mutex_unlock(ps->lock);
237 SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_READ);
242 /* Cannot read now, do it later. */
243 silc_buffer_pull(&ps->inbuf, silc_buffer_len(&ps->inbuf));
244 silc_mutex_unlock(ps->lock);
248 /* Now process the data */
249 silc_buffer_pull_tail(&ps->inbuf, ret);
250 silc_packet_read_process(ps);
252 silc_mutex_unlock(ps->lock);
256 silc_mutex_unlock(ps->lock);
261 /* Allocate packet */
263 static SilcPacket silc_packet_alloc(SilcPacketEngine engine)
267 SILC_LOG_DEBUG(("Packet pool count %d",
268 silc_list_count(engine->packet_pool)));
270 silc_mutex_lock(engine->lock);
272 /* Get packet from freelist or allocate new one. */
273 packet = silc_list_get(engine->packet_pool);
277 silc_mutex_unlock(engine->lock);
279 packet = silc_calloc(1, sizeof(*packet));
283 SILC_LOG_DEBUG(("Allocating new packet %p", packet));
285 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
290 silc_buffer_set(&packet->buffer, tmp, SILC_PACKET_DEFAULT_SIZE);
291 silc_buffer_reset(&packet->buffer);
296 SILC_LOG_DEBUG(("Get packet %p", packet));
298 /* Delete from freelist */
299 silc_list_del(engine->packet_pool, packet);
301 silc_mutex_unlock(engine->lock);
307 /******************************** Packet API ********************************/
309 /* Allocate new packet engine */
312 silc_packet_engine_start(SilcRng rng, SilcBool router,
313 SilcPacketCallbacks *callbacks,
314 void *callback_context)
316 SilcPacketEngine engine;
321 SILC_LOG_DEBUG(("Starting new packet engine"));
325 if (!callbacks->packet_receive || !callbacks->eos || !callbacks->error)
328 engine = silc_calloc(1, sizeof(*engine));
333 engine->local_is_router = router;
334 engine->callbacks = callbacks;
335 engine->callback_context = callback_context;
336 silc_list_init(engine->streams, struct SilcPacketStreamStruct, next);
337 silc_mutex_alloc(&engine->lock);
339 /* Allocate packet free list */
340 silc_list_init(engine->packet_pool, struct SilcPacketStruct, next);
341 for (i = 0; i < 5; i++) {
342 packet = silc_calloc(1, sizeof(*packet));
346 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
349 silc_buffer_set(&packet->buffer, tmp, SILC_PACKET_DEFAULT_SIZE);
350 silc_buffer_reset(&packet->buffer);
352 silc_list_add(engine->packet_pool, packet);
354 silc_list_start(engine->packet_pool);
359 /* Stop packet engine */
361 void silc_packet_engine_stop(SilcPacketEngine engine)
364 SILC_LOG_DEBUG(("Stopping packet engine"));
374 /* Create new packet stream */
376 SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
377 SilcSchedule schedule,
383 SILC_LOG_DEBUG(("Creating new packet stream"));
385 if (!engine || !stream)
388 ps = silc_calloc(1, sizeof(*ps));
394 silc_atomic_init8(&ps->refcnt, 1);
396 /* Allocate buffers */
397 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
400 silc_buffer_set(&ps->inbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
401 silc_buffer_reset(&ps->inbuf);
402 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
405 silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
406 silc_buffer_reset(&ps->outbuf);
408 /* Initialize packet procesors list */
409 ps->process = silc_dlist_init();
411 /* Set IO notifier callback */
412 silc_stream_set_notifier(ps->stream, schedule, silc_packet_stream_io, ps);
414 silc_mutex_alloc(&ps->lock);
417 silc_mutex_lock(engine->lock);
418 silc_list_add(engine->streams, ps);
419 silc_mutex_unlock(engine->lock);
424 /* Destroy packet stream */
426 void silc_packet_stream_destroy(SilcPacketStream stream)
431 if (silc_atomic_get_int8(&stream->refcnt) > 1) {
432 stream->destroyed = TRUE;
436 SILC_LOG_DEBUG(("Destroying packet stream %p", stream));
438 /* Delete from engine */
439 silc_mutex_lock(stream->engine->lock);
440 silc_list_del(stream->engine->streams, stream);
441 silc_mutex_unlock(stream->engine->lock);
443 /* Clear and free buffers */
444 silc_buffer_clear(&stream->inbuf);
445 silc_buffer_clear(&stream->outbuf);
446 silc_buffer_purge(&stream->inbuf);
447 silc_buffer_purge(&stream->outbuf);
451 /* Destroy the underlaying stream */
452 silc_stream_destroy(stream->stream);
454 silc_atomic_uninit8(&stream->refcnt);
455 silc_dlist_uninit(stream->process);
456 silc_mutex_free(stream->lock);
460 /* Marks as router stream */
462 void silc_packet_stream_set_router(SilcPacketStream stream)
464 stream->is_router = TRUE;
467 /* Mark to include IV in ciphertext */
469 void silc_packet_stream_set_iv_included(SilcPacketStream stream)
471 stream->iv_included = TRUE;
474 /* Links `callbacks' to `stream' for specified packet types */
476 static SilcBool silc_packet_stream_link_va(SilcPacketStream stream,
477 SilcPacketCallbacks *callbacks,
478 void *callback_context,
479 int priority, va_list ap)
481 SilcPacketProcess p, e;
482 SilcInt32 packet_type;
485 SILC_LOG_DEBUG(("Linking callbacks %p to stream %p", callbacks, stream));
489 if (!callbacks->packet_receive)
492 p = silc_calloc(1, sizeof(*p));
496 p->priority = priority;
497 p->callbacks = callbacks;
498 p->callback_context = callback_context;
500 silc_mutex_lock(stream->lock);
502 if (!stream->process) {
503 stream->process = silc_dlist_init();
504 if (!stream->process) {
505 silc_mutex_unlock(stream->lock);
510 /* According to priority set the procesor to correct position. First
511 entry has the highest priority */
512 silc_dlist_start(stream->process);
513 while ((e = silc_dlist_get(stream->process)) != SILC_LIST_END) {
514 if (p->priority > e->priority) {
515 silc_dlist_insert(stream->process, p);
520 silc_dlist_add(stream->process, p);
522 /* Get packet types to process */
525 packet_type = va_arg(ap, SilcInt32);
527 if (packet_type == SILC_PACKET_ANY)
530 if (packet_type == -1)
533 p->types = silc_realloc(p->types, sizeof(*p->types) * (i + 1));
535 silc_mutex_unlock(stream->lock);
539 p->types[i - 1] = (SilcPacketType)packet_type;
545 silc_mutex_unlock(stream->lock);
547 silc_packet_stream_ref(stream);
552 /* Links `callbacks' to `stream' for specified packet types */
554 SilcBool silc_packet_stream_link(SilcPacketStream stream,
555 SilcPacketCallbacks *callbacks,
556 void *callback_context,
562 va_start(ap, priority);
563 ret = silc_packet_stream_link_va(stream, callbacks, callback_context,
570 /* Unlinks `callbacks' from `stream'. */
572 void silc_packet_stream_unlink(SilcPacketStream stream,
573 SilcPacketCallbacks *callbacks,
574 void *callback_context)
578 SILC_LOG_DEBUG(("Unlinking callbacks %p from stream %p",
581 silc_mutex_lock(stream->lock);
583 silc_dlist_start(stream->process);
584 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END)
585 if (p->callbacks == callbacks &&
586 p->callback_context == callback_context) {
587 silc_dlist_del(stream->process, p);
592 if (!silc_dlist_count(stream->process)) {
593 silc_dlist_uninit(stream->process);
594 stream->process = NULL;
597 silc_mutex_unlock(stream->lock);
599 silc_packet_stream_unref(stream);
602 /* Reference packet stream */
604 void silc_packet_stream_ref(SilcPacketStream stream)
606 silc_atomic_add_int8(&stream->refcnt, 1);
609 /* Unreference packet stream */
611 void silc_packet_stream_unref(SilcPacketStream stream)
613 if (silc_atomic_sub_int8(&stream->refcnt, 1) == 0)
614 silc_packet_stream_destroy(stream);
619 SilcPacketEngine silc_packet_get_engine(SilcPacketStream stream)
621 return stream->engine;
624 /* Set application context for packet stream */
626 void silc_packet_set_context(SilcPacketStream stream, void *stream_context)
628 silc_mutex_lock(stream->lock);
629 stream->stream_context = stream_context;
630 silc_mutex_unlock(stream->lock);
633 /* Return application context from packet stream */
635 void *silc_packet_get_context(SilcPacketStream stream)
638 silc_mutex_lock(stream->lock);
639 context = stream->stream_context;
640 silc_mutex_unlock(stream->lock);
644 /* Change underlaying stream */
646 void silc_packet_stream_set_stream(SilcPacketStream ps,
648 SilcSchedule schedule)
651 silc_stream_set_notifier(ps->stream, schedule, NULL, NULL);
653 silc_stream_set_notifier(ps->stream, schedule, silc_packet_stream_io, ps);
656 /* Return underlaying stream */
658 SilcStream silc_packet_stream_get_stream(SilcPacketStream stream)
660 return stream->stream;
663 /* Set ciphers for packet stream */
665 void silc_packet_set_ciphers(SilcPacketStream stream, SilcCipher send,
668 SILC_LOG_DEBUG(("Setting new ciphers to packet stream"));
670 silc_mutex_lock(stream->lock);
672 /* In case IV Included is set, save the old key */
673 if (stream->iv_included) {
674 if (stream->send_key[1]) {
675 silc_cipher_free(stream->send_key[1]);
676 stream->send_key[1] = stream->send_key[0];
678 if (stream->receive_key[1]) {
679 silc_cipher_free(stream->receive_key[1]);
680 stream->receive_key[1] = stream->receive_key[0];
683 if (stream->send_key[0])
684 silc_cipher_free(stream->send_key[0]);
685 if (stream->send_key[1])
686 silc_cipher_free(stream->receive_key[0]);
689 stream->send_key[0] = send;
690 stream->receive_key[0] = receive;
692 silc_mutex_unlock(stream->lock);
695 /* Return current ciphers from packet stream */
697 SilcBool silc_packet_get_ciphers(SilcPacketStream stream, SilcCipher *send,
700 if (!stream->send_key[0] && !stream->receive_key[0])
703 silc_mutex_lock(stream->lock);
706 *send = stream->send_key[0];
708 *receive = stream->receive_key[0];
710 silc_mutex_unlock(stream->lock);
715 /* Set HMACs for packet stream */
717 void silc_packet_set_hmacs(SilcPacketStream stream, SilcHmac send,
720 SILC_LOG_DEBUG(("Setting new HMACs to packet stream"));
722 silc_mutex_lock(stream->lock);
724 /* In case IV Included is set, save the old HMAC */
725 if (stream->iv_included) {
726 if (stream->send_hmac[1]) {
727 silc_hmac_free(stream->send_hmac[1]);
728 stream->send_hmac[1] = stream->send_hmac[0];
730 if (stream->receive_hmac[1]) {
731 silc_hmac_free(stream->receive_hmac[1]);
732 stream->receive_hmac[1] = stream->receive_hmac[0];
735 if (stream->send_hmac[0])
736 silc_hmac_free(stream->send_hmac[0]);
737 if (stream->receive_hmac[0])
738 silc_hmac_free(stream->receive_hmac[0]);
741 stream->send_hmac[0] = send;
742 stream->receive_hmac[0] = receive;
744 silc_mutex_unlock(stream->lock);
747 /* Return current HMACs from packet stream */
749 SilcBool silc_packet_get_hmacs(SilcPacketStream stream, SilcHmac *send,
752 if (!stream->send_hmac[0] && !stream->receive_hmac[0])
755 silc_mutex_lock(stream->lock);
758 *send = stream->send_hmac[0];
760 *receive = stream->receive_hmac[0];
762 silc_mutex_unlock(stream->lock);
767 /* Set SILC IDs to packet stream */
769 SilcBool silc_packet_set_ids(SilcPacketStream stream,
770 SilcIdType src_id_type, const void *src_id,
771 SilcIdType dst_id_type, const void *dst_id)
774 unsigned char tmp[32];
776 if (!src_id && !dst_id)
779 SILC_LOG_DEBUG(("Setting new IDs to packet stream"));
781 silc_mutex_lock(stream->lock);
784 silc_free(stream->src_id);
785 if (!silc_id_id2str(src_id, src_id_type, tmp, sizeof(tmp), &len)) {
786 silc_mutex_unlock(stream->lock);
789 stream->src_id = silc_memdup(tmp, len);
790 if (!stream->src_id) {
791 silc_mutex_unlock(stream->lock);
794 stream->src_id_type = src_id_type;
795 stream->src_id_len = len;
799 silc_free(stream->dst_id);
800 if (!silc_id_id2str(dst_id, dst_id_type, tmp, sizeof(tmp), &len)) {
801 silc_mutex_unlock(stream->lock);
804 stream->dst_id = silc_memdup(tmp, len);
805 if (!stream->dst_id) {
806 silc_mutex_unlock(stream->lock);
809 stream->dst_id_type = dst_id_type;
810 stream->dst_id_len = len;
813 silc_mutex_unlock(stream->lock);
818 /* Adds Security ID (SID) */
820 SilcBool silc_packet_set_sid(SilcPacketStream stream, SilcUInt8 sid)
822 if (!stream->iv_included)
825 SILC_LOG_DEBUG(("Set packet stream %p SID to %d", stream, sid));
833 void silc_packet_free(SilcPacket packet)
835 SilcPacketStream stream = packet->stream;
837 SILC_LOG_DEBUG(("Freeing packet %p", packet));
839 #if defined(SILC_DEBUG)
840 /* Check for double free */
841 assert(packet->stream != NULL);
842 #endif /* SILC_DEBUG */
844 silc_mutex_lock(stream->engine->lock);
846 packet->stream = NULL;
847 packet->src_id = packet->dst_id = NULL;
848 silc_buffer_reset(&packet->buffer);
850 /* Put the packet back to freelist */
851 silc_list_add(stream->engine->packet_pool, packet);
852 if (silc_list_count(stream->engine->packet_pool) == 1)
853 silc_list_start(stream->engine->packet_pool);
855 silc_mutex_unlock(stream->engine->lock);
858 /****************************** Packet Sending ******************************/
860 /* Prepare outgoing data buffer for packet sending. Returns the
861 pointer to that buffer into the `packet'. */
863 static SilcBool silc_packet_send_prepare(SilcPacketStream stream,
868 unsigned char *oldptr;
869 unsigned int mac_len = hmac ? silc_hmac_len(hmac) : 0;
873 /* Allocate more space if needed */
874 if (silc_buffer_taillen(&stream->outbuf) < totlen) {
875 if (!silc_buffer_realloc(&stream->outbuf,
876 silc_buffer_truelen(&stream->outbuf) + totlen))
880 /* Pull data area for the new packet, and return pointer to the start of
881 the data area and save the pointer in to the `packet'. MAC is pulled
882 later after it's computed. */
883 oldptr = silc_buffer_pull_tail(&stream->outbuf, totlen);
884 silc_buffer_set(packet, oldptr, totlen);
885 silc_buffer_push_tail(packet, mac_len);
890 /* Internal routine to send packet */
892 static SilcBool silc_packet_send_raw(SilcPacketStream stream,
894 SilcPacketFlags flags,
895 SilcIdType src_id_type,
896 unsigned char *src_id,
897 SilcUInt32 src_id_len,
898 SilcIdType dst_id_type,
899 unsigned char *dst_id,
900 SilcUInt32 dst_id_len,
901 const unsigned char *data,
906 unsigned char tmppad[SILC_PACKET_MAX_PADLEN], iv[33], psn[4];
907 int block_len = (cipher ? silc_cipher_get_block_len(cipher) : 0);
908 int i, enclen, truelen, padlen, ivlen = 0, psnlen = 0;
909 SilcBufferStruct packet;
911 SILC_LOG_DEBUG(("Sending packet %s (%d) flags %d, src %d dst %d,"
912 "data len %d", silc_get_packet_name(type), stream->send_psn,
913 flags, src_id_type, dst_id_type, data_len));
915 /* Get the true length of the packet. This is saved as payload length
916 into the packet header. This does not include the length of the
918 data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
919 src_id_len + dst_id_len));
920 enclen = truelen = (data_len + SILC_PACKET_HEADER_LEN +
921 src_id_len + dst_id_len);
923 /* If IV is included, the SID, IV and sequence number is added to packet */
924 if (stream->iv_included && cipher) {
925 psnlen = sizeof(psn);
926 ivlen = block_len + 1;
928 memcpy(iv + 1, silc_cipher_get_iv(cipher), block_len);
931 /* We automatically figure out the packet structure from the packet
932 type and flags, and calculate correct length. Private messages with
933 private keys and channel messages are special packets as their
934 payload is encrypted already. */
935 if ((type == SILC_PACKET_PRIVATE_MESSAGE &&
936 flags & SILC_PACKET_FLAG_PRIVMSG_KEY) ||
937 type == SILC_PACKET_CHANNEL_MESSAGE) {
939 /* Padding is calculated from header + IDs */
940 SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
941 psnlen), block_len, padlen);
943 /* Length to encrypt, header + IDs + padding. */
944 enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
948 /* Padding is calculated from true length of the packet */
949 if (flags & SILC_PACKET_FLAG_LONG_PAD)
950 SILC_PACKET_PADLEN_MAX(truelen + psnlen, block_len, padlen);
952 SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
954 enclen += padlen + psnlen;
957 /* Remove implementation specific flags */
958 flags &= ~(SILC_PACKET_FLAG_LONG_PAD);
960 /* Get random padding */
961 for (i = 0; i < padlen; i++) tmppad[i] =
962 silc_rng_get_byte_fast(stream->engine->rng);
964 silc_mutex_lock(stream->lock);
966 /* Get packet pointer from the outgoing buffer */
967 if (!silc_packet_send_prepare(stream, truelen + padlen + ivlen + psnlen,
969 silc_mutex_unlock(stream->lock);
973 SILC_PUT32_MSB(stream->send_psn, psn);
975 /* Create the packet. This creates the SILC header, adds padding, and
976 the actual packet data. */
977 i = silc_buffer_format(&packet,
978 SILC_STR_DATA(iv, ivlen),
979 SILC_STR_DATA(psn, psnlen),
980 SILC_STR_UI_SHORT(truelen),
981 SILC_STR_UI_CHAR(flags),
982 SILC_STR_UI_CHAR(type),
983 SILC_STR_UI_CHAR(padlen),
985 SILC_STR_UI_CHAR(src_id_len),
986 SILC_STR_UI_CHAR(dst_id_len),
987 SILC_STR_UI_CHAR(src_id_type),
988 SILC_STR_DATA(src_id, src_id_len),
989 SILC_STR_UI_CHAR(dst_id_type),
990 SILC_STR_DATA(dst_id, dst_id_len),
991 SILC_STR_DATA(tmppad, padlen),
992 SILC_STR_DATA(data, data_len),
995 silc_mutex_unlock(stream->lock);
999 SILC_LOG_HEXDUMP(("Assembled packet, len %d", silc_buffer_len(&packet)),
1000 silc_buffer_data(&packet), silc_buffer_len(&packet));
1002 /* Encrypt the packet */
1004 SILC_LOG_DEBUG(("Encrypting packet"));
1005 if (!silc_cipher_encrypt(cipher, packet.data + ivlen,
1006 packet.data + ivlen, enclen, NULL)) {
1007 SILC_LOG_ERROR(("Packet encryption failed"));
1008 silc_mutex_unlock(stream->lock);
1017 /* MAC is computed from the entire encrypted packet data, and put
1018 to the end of the packet. */
1019 silc_hmac_init(hmac);
1020 silc_hmac_update(hmac, psn, sizeof(psn));
1021 silc_hmac_update(hmac, packet.data, silc_buffer_len(&packet));
1022 silc_hmac_final(hmac, packet.tail, &mac_len);
1023 silc_buffer_pull_tail(&packet, mac_len);
1027 /* Write the packet to the stream */
1028 while (silc_buffer_len(&stream->outbuf) > 0) {
1029 i = silc_stream_write(stream->stream, stream->outbuf.data,
1030 silc_buffer_len(&stream->outbuf));
1033 silc_buffer_reset(&stream->outbuf);
1034 silc_mutex_unlock(stream->lock);
1035 SILC_PACKET_CALLBACK_EOS(stream);
1041 silc_buffer_reset(&stream->outbuf);
1042 silc_mutex_unlock(stream->lock);
1043 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_WRITE);
1048 /* Cannot write now, write later. */
1049 silc_mutex_unlock(stream->lock);
1054 silc_buffer_pull(&stream->outbuf, i);
1056 silc_buffer_reset(&stream->outbuf);
1058 silc_mutex_unlock(stream->lock);
1062 /* Sends a packet */
1064 SilcBool silc_packet_send(SilcPacketStream stream,
1065 SilcPacketType type, SilcPacketFlags flags,
1066 const unsigned char *data, SilcUInt32 data_len)
1068 return silc_packet_send_raw(stream, type, flags,
1069 stream->src_id_type,
1072 stream->dst_id_type,
1076 stream->send_key[0],
1077 stream->send_hmac[0]);
1080 /* Sends a packet, extended routine */
1082 SilcBool silc_packet_send_ext(SilcPacketStream stream,
1083 SilcPacketType type, SilcPacketFlags flags,
1084 SilcIdType src_id_type, void *src_id,
1085 SilcIdType dst_id_type, void *dst_id,
1086 const unsigned char *data, SilcUInt32 data_len,
1087 SilcCipher cipher, SilcHmac hmac)
1089 unsigned char src_id_data[32], dst_id_data[32];
1090 SilcUInt32 src_id_len, dst_id_len;
1093 if (!silc_id_id2str(src_id, src_id_type, src_id_data,
1094 sizeof(src_id_data), &src_id_len))
1097 if (!silc_id_id2str(dst_id, dst_id_type, dst_id_data,
1098 sizeof(dst_id_data), &dst_id_len))
1101 return silc_packet_send_raw(stream, type, flags,
1102 src_id ? src_id_type : stream->src_id_type,
1103 src_id ? src_id_data : stream->src_id,
1104 src_id ? src_id_len : stream->src_id_len,
1105 dst_id ? dst_id_type : stream->dst_id_type,
1106 dst_id ? dst_id_data : stream->dst_id,
1107 dst_id ? dst_id_len : stream->dst_id_len,
1109 cipher ? cipher : stream->send_key[0],
1110 hmac ? hmac : stream->send_hmac[0]);
1114 /***************************** Packet Receiving *****************************/
1116 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. */
1118 static SilcBool silc_packet_check_mac(SilcHmac hmac,
1119 const unsigned char *data,
1120 SilcUInt32 data_len,
1121 const unsigned char *packet_mac,
1122 const unsigned char *packet_seq,
1123 SilcUInt32 sequence)
1127 unsigned char mac[32], psn[4];
1130 SILC_LOG_DEBUG(("Verifying MAC"));
1132 /* Compute HMAC of packet */
1133 silc_hmac_init(hmac);
1136 SILC_PUT32_MSB(sequence, psn);
1137 silc_hmac_update(hmac, psn, 4);
1139 silc_hmac_update(hmac, packet_seq, 4);
1141 silc_hmac_update(hmac, data, data_len);
1142 silc_hmac_final(hmac, mac, &mac_len);
1144 /* Compare the MAC's */
1145 if (memcmp(packet_mac, mac, mac_len)) {
1146 SILC_LOG_DEBUG(("MAC failed"));
1150 SILC_LOG_DEBUG(("MAC is Ok"));
1156 /* Decrypts SILC packet. Handles both normal and special packet decryption.
1157 Return 0 when packet is normal and 1 when it it special, -1 on error. */
1159 static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
1160 SilcUInt32 sequence, SilcBuffer buffer,
1163 if (normal == TRUE) {
1165 /* Decrypt rest of the packet */
1166 SILC_LOG_DEBUG(("Decrypting the packet"));
1167 if (!silc_cipher_decrypt(cipher, buffer->data, buffer->data,
1168 silc_buffer_len(buffer), NULL))
1174 /* Decrypt rest of the header plus padding */
1177 SilcUInt32 block_len = silc_cipher_get_block_len(cipher);
1179 SILC_LOG_DEBUG(("Decrypting the header"));
1181 /* Padding length + src id len + dst id len + header length - 16
1182 bytes already decrypted, gives the rest of the encrypted packet */
1183 silc_buffer_push(buffer, block_len);
1184 len = (((SilcUInt8)buffer->data[4] + (SilcUInt8)buffer->data[6] +
1185 (SilcUInt8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
1187 silc_buffer_pull(buffer, block_len);
1189 if (len > silc_buffer_len(buffer)) {
1190 SILC_LOG_ERROR(("Garbage in header of packet, bad packet length, "
1194 if (!silc_cipher_decrypt(cipher, buffer->data, buffer->data,
1203 /* Parses the packet. This is called when a whole packet is ready to be
1204 parsed. The buffer sent must be already decrypted before calling this
1207 static SilcBool silc_packet_parse(SilcPacket packet)
1209 SilcBuffer buffer = &packet->buffer;
1210 SilcUInt8 padlen = (SilcUInt8)buffer->data[4];
1211 SilcUInt8 src_id_len, dst_id_len, src_id_type, dst_id_type;
1214 SILC_LOG_DEBUG(("Parsing incoming packet"));
1216 /* Parse the buffer. This parses the SILC header of the packet. */
1217 ret = silc_buffer_unformat(buffer,
1220 SILC_STR_UI_CHAR(&src_id_len),
1221 SILC_STR_UI_CHAR(&dst_id_len),
1222 SILC_STR_UI_CHAR(&src_id_type),
1225 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1229 if (src_id_len > SILC_PACKET_MAX_ID_LEN ||
1230 dst_id_len > SILC_PACKET_MAX_ID_LEN) {
1231 SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
1232 packet->src_id_len, packet->dst_id_len));
1236 ret = silc_buffer_unformat(buffer,
1238 SILC_STR_DATA(&packet->src_id, src_id_len),
1239 SILC_STR_UI_CHAR(&dst_id_type),
1240 SILC_STR_DATA(&packet->dst_id, dst_id_len),
1241 SILC_STR_OFFSET(padlen),
1244 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1248 if (src_id_type > SILC_ID_CHANNEL ||
1249 dst_id_type > SILC_ID_CHANNEL) {
1250 SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
1251 src_id_type, dst_id_type));
1255 packet->src_id_len = src_id_len;
1256 packet->dst_id_len = dst_id_len;
1257 packet->src_id_type = src_id_type;
1258 packet->dst_id_type = dst_id_type;
1260 SILC_LOG_HEXDUMP(("Parsed packet, len %d", silc_buffer_headlen(buffer) +
1261 silc_buffer_len(buffer)), buffer->head,
1262 silc_buffer_headlen(buffer) + silc_buffer_len(buffer));
1264 SILC_LOG_DEBUG(("Incoming packet type: %d (%s)", packet->type,
1265 silc_get_packet_name(packet->type)));
1270 /* Dispatch packet to application. Called with stream->lock locked. */
1272 static void silc_packet_dispatch(SilcPacket packet)
1274 SilcPacketStream stream = packet->stream;
1275 SilcPacketProcess p;
1276 SilcBool default_sent = FALSE;
1279 /* Parse the packet */
1280 if (!silc_packet_parse(packet)) {
1281 silc_mutex_unlock(packet->stream->lock);
1282 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
1283 silc_mutex_lock(packet->stream->lock);
1284 silc_packet_free(packet);
1288 /* Dispatch packet to all packet processors that want it */
1290 if (!stream->process) {
1291 /* Send to default processor as no others exist */
1292 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1293 silc_mutex_unlock(packet->stream->lock);
1294 if (!stream->engine->callbacks->
1295 packet_receive(stream->engine, stream, packet,
1296 stream->engine->callback_context,
1297 stream->stream_context))
1298 silc_packet_free(packet);
1299 silc_mutex_lock(packet->stream->lock);
1303 silc_dlist_start(stream->process);
1304 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END) {
1306 /* If priority is 0 or less, we send to default processor first
1307 because default processor has 0 priority */
1308 if (!default_sent && p->priority <= 0) {
1309 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1310 default_sent = TRUE;
1311 silc_mutex_unlock(packet->stream->lock);
1312 if (stream->engine->callbacks->
1313 packet_receive(stream->engine, stream, packet,
1314 stream->engine->callback_context,
1315 stream->stream_context)) {
1316 silc_mutex_lock(packet->stream->lock);
1319 silc_mutex_lock(packet->stream->lock);
1322 /* Send to processor */
1324 /* Send all packet types */
1325 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
1326 silc_mutex_unlock(packet->stream->lock);
1327 if (p->callbacks->packet_receive(stream->engine, stream, packet,
1328 p->callback_context,
1329 stream->stream_context)) {
1330 silc_mutex_lock(packet->stream->lock);
1333 silc_mutex_lock(packet->stream->lock);
1335 /* Send specific types */
1336 for (pt = p->types; *pt; pt++) {
1337 if (*pt != packet->type)
1339 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
1340 silc_mutex_unlock(packet->stream->lock);
1341 if (p->callbacks->packet_receive(stream->engine, stream, packet,
1342 p->callback_context,
1343 stream->stream_context)) {
1344 silc_mutex_lock(packet->stream->lock);
1347 silc_mutex_lock(packet->stream->lock);
1353 if (!default_sent) {
1354 /* Send to default processor as it has not been sent yet */
1355 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1356 silc_mutex_unlock(packet->stream->lock);
1357 if (stream->engine->callbacks->
1358 packet_receive(stream->engine, stream, packet,
1359 stream->engine->callback_context,
1360 stream->stream_context)) {
1361 silc_mutex_lock(packet->stream->lock);
1364 silc_mutex_lock(packet->stream->lock);
1367 /* If we got here, no one wanted the packet, so drop it */
1368 silc_packet_free(packet);
1371 /* Process incoming data and parse packets. Called with stream->lock
1374 static void silc_packet_read_process(SilcPacketStream stream)
1380 SilcUInt16 packetlen;
1381 SilcUInt32 paddedlen, mac_len, block_len, ivlen, psnlen;
1382 unsigned char tmp[SILC_PACKET_MIN_HEADER_LEN], *header;
1383 unsigned char iv[SILC_CIPHER_MAX_IV_SIZE], *packet_seq = NULL;
1384 SilcBool normal = TRUE;
1387 /* Parse the packets from the data */
1388 while (silc_buffer_len(&stream->inbuf) > 0) {
1390 cipher = stream->receive_key[0];
1391 hmac = stream->receive_hmac[0];
1393 if (silc_buffer_len(&stream->inbuf) <
1394 stream->iv_included ? SILC_PACKET_MIN_HEADER_LEN_IV :
1395 SILC_PACKET_MIN_HEADER_LEN) {
1396 SILC_LOG_DEBUG(("Partial packet in queue, waiting for the rest"));
1401 mac_len = silc_hmac_len(hmac);
1405 /* Decrypt first block of the packet to get the length field out */
1407 block_len = silc_cipher_get_block_len(cipher);
1409 if (stream->iv_included) {
1410 /* SID, IV and sequence number is included in the ciphertext */
1411 sid = (SilcUInt8)stream->inbuf.data[0];
1412 memcpy(iv, stream->inbuf.data + 1, block_len);
1413 ivlen = block_len + 1;
1416 /* Check SID, and get correct decryption key */
1417 if (sid != stream->sid) {
1418 /* If SID is recent get the previous key and use it */
1419 if (sid > 0 && stream->sid > 0 && stream->sid - 1 == sid &&
1420 stream->receive_key[1] && !stream->receive_hmac[1]) {
1421 cipher = stream->receive_key[1];
1422 hmac = stream->receive_hmac[1];
1424 /* The SID is unknown, drop rest of the data in buffer */
1425 SILC_LOG_DEBUG(("Unknown Security ID %d in packet, expected %d",
1427 silc_mutex_unlock(stream->lock);
1428 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_UNKNOWN_SID);
1429 silc_mutex_lock(stream->lock);
1430 silc_buffer_reset(&stream->inbuf);
1435 memcpy(iv, silc_cipher_get_iv(cipher), block_len);
1438 silc_cipher_decrypt(cipher, stream->inbuf.data + ivlen, tmp,
1442 if (stream->iv_included) {
1443 /* Take sequence number from packet */
1444 packet_seq = header;
1448 block_len = SILC_PACKET_MIN_HEADER_LEN;
1449 header = stream->inbuf.data;
1452 /* Get packet length and full packet length with padding */
1453 SILC_PACKET_LENGTH(header, packetlen, paddedlen);
1456 if (packetlen < SILC_PACKET_MIN_LEN) {
1457 SILC_LOG_ERROR(("Received too short packet"));
1458 silc_mutex_unlock(stream->lock);
1459 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
1460 silc_mutex_lock(stream->lock);
1461 memset(tmp, 0, sizeof(tmp));
1462 silc_buffer_reset(&stream->inbuf);
1466 if (silc_buffer_len(&stream->inbuf) < paddedlen + ivlen + mac_len) {
1467 SILC_LOG_DEBUG(("Received partial packet, waiting for the rest "
1469 paddedlen + mac_len - silc_buffer_len(&stream->inbuf)));
1470 memset(tmp, 0, sizeof(tmp));
1474 /* Check MAC of the packet */
1475 if (!silc_packet_check_mac(hmac, stream->inbuf.data,
1477 stream->inbuf.data + ivlen + paddedlen,
1478 packet_seq, stream->receive_psn)) {
1479 silc_mutex_unlock(stream->lock);
1480 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MAC_FAILED);
1481 silc_mutex_lock(stream->lock);
1482 memset(tmp, 0, sizeof(tmp));
1483 silc_buffer_reset(&stream->inbuf);
1488 packet = silc_packet_alloc(stream->engine);
1490 silc_mutex_unlock(stream->lock);
1491 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
1492 silc_mutex_lock(stream->lock);
1493 memset(tmp, 0, sizeof(tmp));
1494 silc_buffer_reset(&stream->inbuf);
1498 /* Allocate more space to packet buffer, if needed */
1499 if (silc_buffer_truelen(&packet->buffer) < paddedlen) {
1500 if (!silc_buffer_realloc(&packet->buffer,
1501 silc_buffer_truelen(&packet->buffer) +
1503 silc_buffer_truelen(&packet->buffer)))) {
1504 silc_mutex_unlock(stream->lock);
1505 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
1506 silc_mutex_lock(stream->lock);
1507 silc_packet_free(packet);
1508 memset(tmp, 0, sizeof(tmp));
1509 silc_buffer_reset(&stream->inbuf);
1514 /* Parse packet header */
1515 packet->flags = (SilcPacketFlags)header[2];
1516 packet->type = (SilcPacketType)header[3];
1518 if (stream->engine->local_is_router) {
1519 if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
1520 (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
1522 else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE ||
1523 (packet->type == SILC_PACKET_CHANNEL_MESSAGE &&
1524 stream->is_router == TRUE))
1527 if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
1528 (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
1530 else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE)
1534 SILC_LOG_HEXDUMP(("Incoming packet (%d) len %d",
1535 stream->receive_psn, paddedlen + ivlen + mac_len),
1536 stream->inbuf.data, paddedlen + ivlen + mac_len);
1538 /* Put the decrypted part, and rest of the encrypted data, and decrypt */
1539 silc_buffer_pull_tail(&packet->buffer, paddedlen);
1540 silc_buffer_put(&packet->buffer, header, block_len - psnlen);
1541 silc_buffer_pull(&packet->buffer, block_len - psnlen);
1542 silc_buffer_put(&packet->buffer, (stream->inbuf.data + ivlen +
1543 psnlen + (block_len - psnlen)),
1544 paddedlen - ivlen - psnlen - (block_len - psnlen));
1546 silc_cipher_set_iv(cipher, iv);
1547 ret = silc_packet_decrypt(cipher, hmac, stream->receive_psn,
1548 &packet->buffer, normal);
1550 silc_mutex_unlock(stream->lock);
1551 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_DECRYPTION_FAILED);
1552 silc_mutex_lock(stream->lock);
1553 silc_packet_free(packet);
1554 memset(tmp, 0, sizeof(tmp));
1558 stream->receive_psn++;
1560 silc_buffer_push(&packet->buffer, block_len);
1562 /* Pull the packet from inbuf thus we'll get the next one in the inbuf. */
1563 silc_buffer_pull(&stream->inbuf, paddedlen + mac_len);
1565 /* Dispatch the packet to application */
1566 packet->stream = stream;
1567 silc_packet_dispatch(packet);
1570 silc_buffer_reset(&stream->inbuf);
1574 /****************************** Packet Waiting ******************************/
1576 /* Packet wait receive callback */
1578 silc_packet_wait_packet_receive(SilcPacketEngine engine,
1579 SilcPacketStream stream,
1581 void *callback_context,
1582 void *stream_context);
1584 /* Packet waiting callbacks */
1585 static SilcPacketCallbacks silc_packet_wait_cbs =
1587 silc_packet_wait_packet_receive, NULL, NULL
1590 /* Packet waiting context */
1592 SilcMutex wait_lock;
1594 SilcList packet_queue;
1595 unsigned int stopped : 1;
1598 /* Packet wait receive callback */
1601 silc_packet_wait_packet_receive(SilcPacketEngine engine,
1602 SilcPacketStream stream,
1604 void *callback_context,
1605 void *stream_context)
1607 SilcPacketWait pw = callback_context;
1609 /* Signal the waiting thread for a new packet */
1610 silc_mutex_lock(pw->wait_lock);
1613 silc_mutex_unlock(pw->wait_lock);
1617 silc_list_add(pw->packet_queue, packet);
1618 silc_cond_broadcast(pw->wait_cond);
1620 silc_mutex_unlock(pw->wait_lock);
1625 /* Initialize packet waiting */
1627 void *silc_packet_wait_init(SilcPacketStream stream, ...)
1633 pw = silc_calloc(1, sizeof(*pw));
1637 /* Allocate mutex and conditional variable */
1638 if (!silc_mutex_alloc(&pw->wait_lock)) {
1642 if (!silc_cond_alloc(&pw->wait_cond)) {
1643 silc_mutex_free(pw->wait_lock);
1648 /* Link to the packet stream for the requested packet types */
1649 va_start(ap, stream);
1650 ret = silc_packet_stream_link_va(stream, &silc_packet_wait_cbs, pw,
1654 silc_cond_free(pw->wait_cond);
1655 silc_mutex_free(pw->wait_lock);
1660 /* Initialize packet queue */
1661 silc_list_init(pw->packet_queue, struct SilcPacketStruct, next);
1666 /* Uninitialize packet waiting */
1668 void silc_packet_wait_uninit(void *waiter, SilcPacketStream stream)
1670 SilcPacketWait pw = waiter;
1673 /* Signal any threads to stop waiting */
1674 silc_mutex_lock(pw->wait_lock);
1676 silc_cond_broadcast(pw->wait_cond);
1677 silc_mutex_unlock(pw->wait_lock);
1679 /* Re-acquire lock and free resources */
1680 silc_mutex_lock(pw->wait_lock);
1681 silc_packet_stream_unlink(stream, &silc_packet_wait_cbs, pw);
1683 /* Free any remaining packets */
1684 silc_list_start(pw->packet_queue);
1685 while ((packet = silc_list_get(pw->packet_queue)) != SILC_LIST_END)
1686 silc_packet_free(packet);
1688 silc_mutex_unlock(pw->wait_lock);
1689 silc_cond_free(pw->wait_cond);
1690 silc_mutex_free(pw->wait_lock);
1694 /* Blocks thread until a packet has been received. */
1696 int silc_packet_wait(void *waiter, int timeout, SilcPacket *return_packet)
1698 SilcPacketWait pw = waiter;
1699 SilcBool ret = FALSE;
1701 silc_mutex_lock(pw->wait_lock);
1703 /* Wait here until packet has arrived */
1704 while (silc_list_count(pw->packet_queue) == 0) {
1706 silc_mutex_unlock(pw->wait_lock);
1709 ret = silc_cond_timedwait(pw->wait_cond, pw->wait_lock, timeout);
1713 silc_list_start(pw->packet_queue);
1714 *return_packet = silc_list_get(pw->packet_queue);
1715 silc_list_del(pw->packet_queue, *return_packet);
1717 silc_mutex_unlock(pw->wait_lock);
1719 return ret == TRUE ? 1 : 0;