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 SilcHashTable streamers; /* Valid if streamers exist */
55 void *stream_context; /* Stream context */
56 SilcBufferStruct inbuf; /* In buffer */
57 SilcBufferStruct outbuf; /* Out buffer */
58 SilcUInt32 send_psn; /* Sending sequence */
59 SilcCipher send_key; /* Sending key */
60 SilcHmac send_hmac; /* Sending HMAC */
61 SilcUInt32 receive_psn; /* Receiving sequence */
62 SilcCipher receive_key; /* Receiving key */
63 SilcHmac receive_hmac; /* Receiving HMAC */
64 unsigned char *src_id; /* Source ID */
65 unsigned char *dst_id; /* Destination ID */
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 SilcUInt8 refcnt; /* Reference counter */
71 unsigned int is_router : 1; /* Set if router stream */
72 unsigned int destroyed : 1; /* Set if destroyed */
75 /* Initial size of stream buffers */
76 #define SILC_PACKET_DEFAULT_SIZE 1024
78 /* Header length without source and destination ID's. */
79 #define SILC_PACKET_HEADER_LEN 10
81 /* Minimum length of SILC Packet Header. This much is decrypted always
82 when packet is received to be able to get all the relevant data out
84 #define SILC_PACKET_MIN_HEADER_LEN 16
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)
98 /* Returns true length of the packet. */
99 #define SILC_PACKET_LENGTH(__packetdata, __ret_truelen, __ret_paddedlen) \
101 SILC_GET16_MSB((__ret_truelen), (__packetdata)); \
102 (__ret_paddedlen) = (__ret_truelen) + (SilcUInt8)(__packetdata)[4]; \
105 /* Calculates the data length with given header length. This macro
106 can be used to check whether the data_len with header_len exceeds
107 SILC_PACKET_MAX_LEN. If it does, this returns the new data_len
108 so that the SILC_PACKET_MAX_LEN is not exceeded. If the data_len
109 plus header_len fits SILC_PACKET_MAX_LEN the returned data length
110 is the data_len given as argument. */
111 #define SILC_PACKET_DATALEN(data_len, header_len) \
112 ((data_len + header_len) > SILC_PACKET_MAX_LEN ? \
113 data_len - ((data_len + header_len) - SILC_PACKET_MAX_LEN) : data_len)
115 /* Calculates the length of the padding in the packet. */
116 #define SILC_PACKET_PADLEN(__packetlen, __blocklen, __padlen) \
118 __padlen = (SILC_PACKET_DEFAULT_PADLEN - (__packetlen) % \
119 ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN)); \
121 __padlen += ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN); \
124 /* Returns the length of the padding up to the maximum length, which
126 #define SILC_PACKET_PADLEN_MAX(__packetlen, __blocklen, __padlen) \
128 __padlen = (SILC_PACKET_MAX_PADLEN - (__packetlen) % \
129 ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN)); \
133 #define SILC_PACKET_CALLBACK_EOS(s) \
135 (s)->engine->callbacks->eos((s)->engine, s, \
136 (s)->engine->callback_context, \
137 (s)->stream_context); \
141 #define SILC_PACKET_CALLBACK_ERROR(s, err) \
143 (s)->engine->callbacks->error((s)->engine, s, err, \
144 (s)->engine->callback_context, \
145 (s)->stream_context); \
149 /************************ Static utility functions **************************/
151 static void silc_packet_read_process(SilcPacketStream stream);
153 /* Our stream IO notifier callback. */
155 static void silc_packet_stream_io(SilcStream stream, SilcStreamStatus status,
158 SilcPacketStream ps = context;
161 silc_mutex_lock(ps->lock);
164 silc_mutex_unlock(ps->lock);
170 case SILC_STREAM_CAN_WRITE:
171 if (!silc_buffer_headlen(&ps->outbuf)) {
172 silc_mutex_unlock(ps->lock);
176 SILC_LOG_DEBUG(("Writing pending data to stream"));
178 /* Write pending data to stream */
179 while (silc_buffer_len(&ps->outbuf) > 0) {
180 ret = silc_stream_write(ps->stream, ps->outbuf.data,
181 silc_buffer_len(&ps->outbuf));
184 silc_buffer_reset(&ps->outbuf);
185 silc_mutex_unlock(ps->lock);
186 SILC_PACKET_CALLBACK_EOS(ps);
192 silc_buffer_reset(&ps->outbuf);
193 silc_mutex_unlock(ps->lock);
194 SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_WRITE);
199 /* Cannot write now, write later. */
200 silc_mutex_unlock(ps->lock);
205 silc_buffer_pull(&ps->outbuf, ret);
208 silc_buffer_reset(&ps->outbuf);
210 silc_mutex_unlock(ps->lock);
213 case SILC_STREAM_CAN_READ:
214 /* Packet receiving can only happen in one thread for one SilcPacketStream,
215 so locking is not required in packet receiving procedure. */
216 silc_mutex_unlock(ps->lock);
218 SILC_LOG_DEBUG(("Reading data from stream"));
220 /* Make sure we have fair amount of free space in inbuf */
221 if (silc_buffer_taillen(&ps->inbuf) < SILC_PACKET_DEFAULT_SIZE)
222 if (!silc_buffer_realloc(&ps->inbuf, silc_buffer_truelen(&ps->inbuf) +
223 SILC_PACKET_DEFAULT_SIZE * 2))
226 /* Read data from stream */
227 ret = silc_stream_read(ps->stream, ps->inbuf.tail,
228 silc_buffer_taillen(&ps->inbuf));
232 silc_buffer_reset(&ps->inbuf);
233 SILC_PACKET_CALLBACK_EOS(ps);
239 silc_buffer_reset(&ps->inbuf);
240 SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_READ);
245 /* Cannot read now, do it later. */
246 silc_buffer_pull(&ps->inbuf, silc_buffer_len(&ps->inbuf));
251 silc_buffer_pull_tail(&ps->inbuf, ret);
253 /* Now process the data */
254 silc_packet_read_process(ps);
259 silc_mutex_unlock(ps->lock);
264 /* Allocate packet */
266 static SilcPacket silc_packet_alloc(SilcPacketEngine engine)
270 SILC_LOG_DEBUG(("Packet pool count %d",
271 silc_list_count(engine->packet_pool)));
273 silc_mutex_lock(engine->lock);
275 /* Get packet from freelist or allocate new one. */
276 packet = silc_list_get(engine->packet_pool);
280 silc_mutex_unlock(engine->lock);
282 packet = silc_calloc(1, sizeof(*packet));
286 SILC_LOG_DEBUG(("Allocating new packet %p", packet));
288 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
293 silc_buffer_set(&packet->buffer, tmp, SILC_PACKET_DEFAULT_SIZE);
294 silc_buffer_reset(&packet->buffer);
299 SILC_LOG_DEBUG(("Get packet %p", packet));
301 /* Delete from freelist */
302 silc_list_del(engine->packet_pool, packet);
304 silc_mutex_unlock(engine->lock);
310 /******************************** Packet API ********************************/
312 /* Allocate new packet engine */
315 silc_packet_engine_start(SilcRng rng, SilcBool router,
316 SilcPacketCallbacks *callbacks,
317 void *callback_context)
319 SilcPacketEngine engine;
324 SILC_LOG_DEBUG(("Starting new packet engine"));
328 if (!callbacks->packet_receive || !callbacks->eos || !callbacks->error)
331 engine = silc_calloc(1, sizeof(*engine));
336 engine->local_is_router = router;
337 engine->callbacks = callbacks;
338 engine->callback_context = callback_context;
339 silc_list_init(engine->streams, struct SilcPacketStreamStruct, next);
340 silc_mutex_alloc(&engine->lock);
342 /* Allocate packet free list */
343 silc_list_init(engine->packet_pool, struct SilcPacketStruct, next);
344 for (i = 0; i < 5; i++) {
345 packet = silc_calloc(1, sizeof(*packet));
349 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
352 silc_buffer_set(&packet->buffer, tmp, SILC_PACKET_DEFAULT_SIZE);
353 silc_buffer_reset(&packet->buffer);
355 silc_list_add(engine->packet_pool, packet);
357 silc_list_start(engine->packet_pool);
362 /* Stop packet engine */
364 void silc_packet_engine_stop(SilcPacketEngine engine)
367 SILC_LOG_DEBUG(("Stopping packet engine"));
377 /* Create new packet stream */
379 SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
380 SilcSchedule schedule,
386 SILC_LOG_DEBUG(("Creating new packet stream"));
388 if (!engine || !stream)
391 ps = silc_calloc(1, sizeof(*ps));
399 /* Allocate buffers */
400 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
403 silc_buffer_set(&ps->inbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
404 silc_buffer_reset(&ps->inbuf);
405 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
408 silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
409 silc_buffer_reset(&ps->outbuf);
411 /* Initialize packet procesors list */
412 ps->process = silc_dlist_init();
414 /* Set IO notifier callback */
415 silc_stream_set_notifier(ps->stream, schedule, silc_packet_stream_io, ps);
417 silc_mutex_alloc(&ps->lock);
420 silc_mutex_lock(engine->lock);
421 silc_list_add(engine->streams, ps);
422 silc_mutex_unlock(engine->lock);
427 /* Destroy packet stream */
429 void silc_packet_stream_destroy(SilcPacketStream stream)
434 if (stream->refcnt > 1) {
435 stream->destroyed = TRUE;
439 SILC_LOG_DEBUG(("Destroying packet stream %p", stream));
441 /* Delete from engine */
442 silc_mutex_lock(stream->engine->lock);
443 silc_list_del(stream->engine->streams, stream);
444 silc_mutex_unlock(stream->engine->lock);
446 /* Clear and free buffers */
447 silc_buffer_clear(&stream->inbuf);
448 silc_buffer_clear(&stream->outbuf);
449 silc_free(silc_buffer_steal(&stream->inbuf, NULL));
450 silc_free(silc_buffer_steal(&stream->outbuf, NULL));
452 silc_dlist_uninit(stream->process);
459 /* Marks as router stream */
461 void silc_packet_stream_set_router(SilcPacketStream stream)
463 stream->is_router = TRUE;
467 /* Links `callbacks' to `stream' for specified packet types */
469 static SilcBool silc_packet_stream_link_va(SilcPacketStream stream,
470 SilcPacketCallbacks *callbacks,
471 void *callback_context,
472 int priority, va_list ap)
474 SilcPacketProcess p, e;
475 SilcInt32 packet_type;
478 SILC_LOG_DEBUG(("Linking callbacks %p to stream %p", callbacks, stream));
482 if (!callbacks->packet_receive)
485 p = silc_calloc(1, sizeof(*p));
489 p->priority = priority;
490 p->callbacks = callbacks;
491 p->callback_context = callback_context;
493 silc_mutex_lock(stream->lock);
495 if (!stream->process) {
496 stream->process = silc_dlist_init();
497 if (!stream->process)
501 /* According to priority set the procesor to correct position. First
502 entry has the highest priority */
503 silc_dlist_start(stream->process);
504 while ((e = silc_dlist_get(stream->process)) != SILC_LIST_END) {
505 if (p->priority > e->priority) {
506 silc_dlist_insert(stream->process, p);
511 silc_dlist_add(stream->process, p);
513 /* Get packet types to process */
516 packet_type = va_arg(ap, SilcInt32);
518 if (packet_type == SILC_PACKET_ANY)
521 if (packet_type == -1)
524 p->types = silc_realloc(p->types, sizeof(*p->types) * (i + 1));
526 silc_mutex_unlock(stream->lock);
530 p->types[i - 1] = (SilcPacketType)packet_type;
536 silc_mutex_unlock(stream->lock);
538 silc_packet_stream_ref(stream);
543 /* Links `callbacks' to `stream' for specified packet types */
545 SilcBool silc_packet_stream_link(SilcPacketStream stream,
546 SilcPacketCallbacks *callbacks,
547 void *callback_context,
553 va_start(ap, priority);
554 ret = silc_packet_stream_link_va(stream, callbacks, callback_context,
561 /* Unlinks `callbacks' from `stream'. */
563 void silc_packet_stream_unlink(SilcPacketStream stream,
564 SilcPacketCallbacks *callbacks,
565 void *callback_context)
569 SILC_LOG_DEBUG(("Unlinking callbacks %p from stream %p",
572 silc_mutex_lock(stream->lock);
574 silc_dlist_start(stream->process);
575 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END)
576 if (p->callbacks == callbacks &&
577 p->callback_context == callback_context) {
578 silc_dlist_del(stream->process, p);
583 if (!silc_dlist_count(stream->process)) {
584 silc_dlist_uninit(stream->process);
585 stream->process = NULL;
588 silc_mutex_unlock(stream->lock);
590 silc_packet_stream_unref(stream);
593 /* Reference packet stream */
595 void silc_packet_stream_ref(SilcPacketStream stream)
597 silc_mutex_lock(stream->lock);
599 silc_mutex_unlock(stream->lock);
602 /* Unreference packet stream */
604 void silc_packet_stream_unref(SilcPacketStream stream)
606 silc_mutex_lock(stream->lock);
608 silc_mutex_unlock(stream->lock);
609 if (stream->refcnt == 0)
610 silc_packet_stream_destroy(stream);
615 SilcPacketEngine silc_packet_get_engine(SilcPacketStream stream)
617 return stream->engine;
620 /* Set application context for packet stream */
622 void silc_packet_set_context(SilcPacketStream stream, void *stream_context)
624 stream->stream_context = stream_context;
627 /* Return application context from packet stream */
629 void *silc_packet_get_context(SilcPacketStream stream)
631 return stream->stream_context;
634 /* Return underlaying stream */
636 SilcStream silc_packet_stream_get_stream(SilcPacketStream stream)
638 return stream->stream;
641 /* Set ciphers for packet stream */
643 void silc_packet_set_ciphers(SilcPacketStream stream, SilcCipher send,
646 SILC_LOG_DEBUG(("Setting new ciphers to packet stream"));
647 stream->send_key = send;
648 stream->receive_key = receive;
651 /* Return current ciphers from packet stream */
653 SilcBool silc_packet_get_ciphers(SilcPacketStream stream, SilcCipher *send,
656 if (!stream->send_key && !stream->receive_key)
660 *send = stream->send_key;
662 *receive = stream->receive_key;
667 /* Set HMACs for packet stream */
669 void silc_packet_set_hmacs(SilcPacketStream stream, SilcHmac send,
672 SILC_LOG_DEBUG(("Setting new HMACs to packet stream"));
673 stream->send_hmac = send;
674 stream->receive_hmac = receive;
677 /* Return current HMACs from packet stream */
679 SilcBool silc_packet_get_hmacs(SilcPacketStream stream, SilcHmac *send,
682 if (!stream->send_hmac && !stream->receive_hmac)
686 *send = stream->send_hmac;
688 *receive = stream->receive_hmac;
693 /* Set SILC IDs to packet stream */
695 SilcBool silc_packet_set_ids(SilcPacketStream stream,
696 SilcIdType src_id_type, const void *src_id,
697 SilcIdType dst_id_type, const void *dst_id)
700 unsigned char tmp[32];
702 if (!src_id && !dst_id)
705 SILC_LOG_DEBUG(("Setting new IDs to packet stream"));
708 silc_free(stream->src_id);
709 if (!silc_id_id2str(src_id, src_id_type, tmp, sizeof(tmp), &len))
711 stream->src_id = silc_memdup(tmp, len);
714 stream->src_id_type = src_id_type;
715 stream->src_id_len = len;
719 silc_free(stream->dst_id);
720 if (!silc_id_id2str(dst_id, dst_id_type, tmp, sizeof(tmp), &len))
722 stream->dst_id = silc_memdup(tmp, len);
725 stream->dst_id_type = dst_id_type;
726 stream->dst_id_len = len;
734 void silc_packet_free(SilcPacket packet)
736 SilcPacketStream stream = packet->stream;
738 SILC_LOG_DEBUG(("Freeing packet %p", packet));
740 #if defined(SILC_DEBUG)
741 /* Check for double free */
742 assert(packet->stream != NULL);
743 #endif /* SILC_DEBUG */
745 silc_mutex_lock(stream->engine->lock);
747 packet->stream = NULL;
748 packet->src_id = packet->dst_id = NULL;
749 silc_buffer_reset(&packet->buffer);
751 /* Put the packet back to freelist */
752 silc_list_add(stream->engine->packet_pool, packet);
754 silc_mutex_unlock(stream->engine->lock);
757 /* Creates streamer */
759 SilcStream silc_packet_streamer_create(SilcPacketStream stream,
760 SilcPacketType packet_type,
761 SilcPacketFlags packet_flags)
767 /* Destroyes streamer */
769 void silc_packet_streamer_destroy(SilcStream stream)
775 /****************************** Packet Sending ******************************/
777 /* Prepare outgoing data buffer for packet sending. Returns the
778 pointer to that buffer into the `packet'. */
780 static SilcBool silc_packet_send_prepare(SilcPacketStream stream,
785 unsigned char *oldptr;
786 unsigned int mac_len = hmac ? silc_hmac_len(hmac) : 0;
790 /* Allocate more space if needed */
791 if (silc_buffer_taillen(&stream->outbuf) < totlen) {
792 if (!silc_buffer_realloc(&stream->outbuf,
793 silc_buffer_truelen(&stream->outbuf) + totlen))
797 /* Pull data area for the new packet, and return pointer to the start of
798 the data area and save the pointer in to the `packet'. MAC is pulled
799 later after it's computed. */
800 oldptr = silc_buffer_pull_tail(&stream->outbuf, totlen);
801 silc_buffer_set(packet, oldptr, totlen);
802 silc_buffer_push_tail(packet, mac_len);
807 /* Internal routine to send packet */
809 static SilcBool silc_packet_send_raw(SilcPacketStream stream,
811 SilcPacketFlags flags,
812 SilcIdType src_id_type,
813 unsigned char *src_id,
814 SilcUInt32 src_id_len,
815 SilcIdType dst_id_type,
816 unsigned char *dst_id,
817 SilcUInt32 dst_id_len,
818 const unsigned char *data,
823 unsigned char tmppad[SILC_PACKET_MAX_PADLEN];
824 int block_len = (cipher ? silc_cipher_get_block_len(cipher) : 0);
825 int i, enclen, truelen, padlen;
826 SilcBufferStruct packet;
828 SILC_LOG_DEBUG(("Sending packet %s (%d) flags %d, src %d dst %d,"
829 "data len %d", silc_get_packet_name(type), stream->send_psn,
830 flags, src_id_type, dst_id_type, data_len));
832 /* Get the true length of the packet. This is saved as payload length
833 into the packet header. This does not include the length of the
835 data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
836 src_id_len + dst_id_len));
837 enclen = truelen = (data_len + SILC_PACKET_HEADER_LEN +
838 src_id_len + dst_id_len);
840 /* We automatically figure out the packet structure from the packet
841 type and flags, and calculate correct length. Private messages with
842 private keys and channel messages are special packets as their
843 payload is encrypted already. */
844 if ((type == SILC_PACKET_PRIVATE_MESSAGE &&
845 flags & SILC_PACKET_FLAG_PRIVMSG_KEY) ||
846 type == SILC_PACKET_CHANNEL_MESSAGE) {
848 /* Padding is calculated from header + IDs */
849 SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
851 dst_id_len), block_len, padlen);
853 /* Length to encrypt, header + IDs + padding. */
854 enclen = SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len + padlen;
857 /* Padding is calculated from true length of the packet */
858 if (flags & SILC_PACKET_FLAG_LONG_PAD)
859 SILC_PACKET_PADLEN_MAX(truelen, block_len, padlen);
861 SILC_PACKET_PADLEN(truelen, block_len, padlen);
866 /* Remove implementation specific flags */
867 flags &= ~(SILC_PACKET_FLAG_LONG_PAD);
869 /* Get random padding */
870 for (i = 0; i < padlen; i++) tmppad[i] =
871 silc_rng_get_byte_fast(stream->engine->rng);
873 silc_mutex_lock(stream->lock);
875 /* Get packet pointer from the outgoing buffer */
876 if (!silc_packet_send_prepare(stream, truelen + padlen, hmac, &packet)) {
877 silc_mutex_unlock(stream->lock);
881 /* Create the packet. This creates the SILC header, adds padding, and
882 the actual packet data. */
883 i = silc_buffer_format(&packet,
884 SILC_STR_UI_SHORT(truelen),
885 SILC_STR_UI_CHAR(flags),
886 SILC_STR_UI_CHAR(type),
887 SILC_STR_UI_CHAR(padlen),
889 SILC_STR_UI_CHAR(src_id_len),
890 SILC_STR_UI_CHAR(dst_id_len),
891 SILC_STR_UI_CHAR(src_id_type),
892 SILC_STR_UI_XNSTRING(src_id, src_id_len),
893 SILC_STR_UI_CHAR(dst_id_type),
894 SILC_STR_UI_XNSTRING(dst_id, dst_id_len),
895 SILC_STR_UI_XNSTRING(tmppad, padlen),
896 SILC_STR_UI_XNSTRING(data, data_len),
899 silc_mutex_unlock(stream->lock);
903 SILC_LOG_HEXDUMP(("Assembled packet, len %d", silc_buffer_len(&packet)),
904 packet.data, silc_buffer_len(&packet));
906 /* Encrypt the packet */
908 SILC_LOG_DEBUG(("Encrypting packet"));
909 if (!silc_cipher_encrypt(cipher, packet.data, packet.data,
911 SILC_LOG_ERROR(("Packet encryption failed"));
912 silc_mutex_unlock(stream->lock);
919 unsigned char psn[4];
922 /* MAC is computed from the entire encrypted packet data, and put
923 to the end of the packet. */
924 silc_hmac_init(hmac);
925 SILC_PUT32_MSB(stream->send_psn, psn);
926 silc_hmac_update(hmac, psn, 4);
927 silc_hmac_update(hmac, packet.data, silc_buffer_len(&packet));
928 silc_hmac_final(hmac, packet.tail, &mac_len);
929 silc_buffer_pull_tail(&packet, mac_len);
933 /* Write the packet to the stream */
934 while (silc_buffer_len(&stream->outbuf) > 0) {
935 i = silc_stream_write(stream->stream, stream->outbuf.data,
936 silc_buffer_len(&stream->outbuf));
939 silc_buffer_reset(&stream->outbuf);
940 silc_mutex_unlock(stream->lock);
941 SILC_PACKET_CALLBACK_EOS(stream);
947 silc_buffer_reset(&stream->outbuf);
948 silc_mutex_unlock(stream->lock);
949 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_WRITE);
954 /* Cannot write now, write later. */
955 silc_mutex_unlock(stream->lock);
960 silc_buffer_pull(&stream->outbuf, i);
962 silc_buffer_reset(&stream->outbuf);
964 silc_mutex_unlock(stream->lock);
970 SilcBool silc_packet_send(SilcPacketStream stream,
971 SilcPacketType type, SilcPacketFlags flags,
972 const unsigned char *data, SilcUInt32 data_len)
974 return silc_packet_send_raw(stream, type, flags,
986 /* Sends a packet, extended routine */
988 SilcBool silc_packet_send_ext(SilcPacketStream stream,
989 SilcPacketType type, SilcPacketFlags flags,
990 SilcIdType src_id_type, void *src_id,
991 SilcIdType dst_id_type, void *dst_id,
992 const unsigned char *data, SilcUInt32 data_len,
993 SilcCipher cipher, SilcHmac hmac)
995 unsigned char src_id_data[32], dst_id_data[32];
996 SilcUInt32 src_id_len, dst_id_len;
999 if (!silc_id_id2str(src_id, src_id_type, src_id_data,
1000 sizeof(src_id_data), &src_id_len))
1003 if (!silc_id_id2str(dst_id, dst_id_type, dst_id_data,
1004 sizeof(dst_id_data), &dst_id_len))
1007 return silc_packet_send_raw(stream, type, flags,
1020 /***************************** Packet Receiving *****************************/
1022 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. */
1024 static SilcBool silc_packet_check_mac(SilcHmac hmac,
1025 const unsigned char *data,
1026 SilcUInt32 data_len,
1027 const unsigned char *packet_mac,
1028 SilcUInt32 sequence)
1032 unsigned char mac[32], psn[4];
1035 SILC_LOG_DEBUG(("Verifying MAC"));
1037 /* Compute HMAC of packet */
1038 silc_hmac_init(hmac);
1039 SILC_PUT32_MSB(sequence, psn);
1040 silc_hmac_update(hmac, psn, 4);
1041 silc_hmac_update(hmac, data, data_len);
1042 silc_hmac_final(hmac, mac, &mac_len);
1044 /* Compare the MAC's */
1045 if (memcmp(packet_mac, mac, mac_len)) {
1046 SILC_LOG_DEBUG(("MAC failed"));
1050 SILC_LOG_DEBUG(("MAC is Ok"));
1056 /* Decrypts SILC packet. Handles both normal and special packet decryption.
1057 Return 0 when packet is normal and 1 when it it special, -1 on error. */
1059 static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
1060 SilcUInt32 sequence, SilcBuffer buffer,
1063 if (normal == TRUE) {
1065 /* Decrypt rest of the packet */
1066 SILC_LOG_DEBUG(("Decrypting the packet"));
1067 if (!silc_cipher_decrypt(cipher, buffer->data, buffer->data,
1068 silc_buffer_len(buffer), NULL))
1074 /* Decrypt rest of the header plus padding */
1077 SilcUInt32 block_len = silc_cipher_get_block_len(cipher);
1079 SILC_LOG_DEBUG(("Decrypting the header"));
1081 /* Padding length + src id len + dst id len + header length - 16
1082 bytes already decrypted, gives the rest of the encrypted packet */
1083 silc_buffer_push(buffer, block_len);
1084 len = (((SilcUInt8)buffer->data[4] + (SilcUInt8)buffer->data[6] +
1085 (SilcUInt8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
1087 silc_buffer_pull(buffer, block_len);
1089 if (len > silc_buffer_len(buffer)) {
1090 SILC_LOG_ERROR(("Garbage in header of packet, bad packet length, "
1094 if (!silc_cipher_decrypt(cipher, buffer->data, buffer->data,
1103 /* Parses the packet. This is called when a whole packet is ready to be
1104 parsed. The buffer sent must be already decrypted before calling this
1107 static SilcBool silc_packet_parse(SilcPacket packet)
1109 SilcBuffer buffer = &packet->buffer;
1110 SilcUInt8 padlen = (SilcUInt8)buffer->data[4];
1111 SilcUInt8 src_id_len, dst_id_len, src_id_type, dst_id_type;
1114 SILC_LOG_DEBUG(("Parsing incoming packet"));
1116 /* Parse the buffer. This parses the SILC header of the packet. */
1117 len = silc_buffer_unformat(buffer,
1119 SILC_STR_UI_CHAR(&src_id_len),
1120 SILC_STR_UI_CHAR(&dst_id_len),
1121 SILC_STR_UI_CHAR(&src_id_type),
1124 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1128 if (src_id_len > SILC_PACKET_MAX_ID_LEN ||
1129 dst_id_len > SILC_PACKET_MAX_ID_LEN) {
1130 SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
1131 packet->src_id_len, packet->dst_id_len));
1135 ret = silc_buffer_unformat(buffer,
1136 SILC_STR_OFFSET(len),
1137 SILC_STR_UI_XNSTRING(&packet->src_id,
1139 SILC_STR_UI_CHAR(&dst_id_type),
1140 SILC_STR_UI_XNSTRING(&packet->dst_id,
1142 SILC_STR_OFFSET(padlen),
1145 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1149 if (src_id_type > SILC_ID_CHANNEL ||
1150 dst_id_type > SILC_ID_CHANNEL) {
1151 SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
1152 src_id_type, dst_id_type));
1156 packet->src_id_len = src_id_len;
1157 packet->dst_id_len = dst_id_len;
1158 packet->src_id_type = src_id_type;
1159 packet->dst_id_type = dst_id_type;
1161 SILC_LOG_HEXDUMP(("Parsed packet, len %d", silc_buffer_len(buffer)),
1162 buffer->data, silc_buffer_len(buffer));
1164 /* Pull SILC header and padding from packet to get the data payload */
1165 silc_buffer_pull(buffer, SILC_PACKET_HEADER_LEN +
1166 packet->src_id_len + packet->dst_id_len + padlen);
1168 SILC_LOG_DEBUG(("Incoming packet type: %d (%s)", packet->type,
1169 silc_get_packet_name(packet->type)));
1174 /* Dispatch packet to application */
1176 static void silc_packet_dispatch(SilcPacket packet)
1178 SilcPacketStream stream = packet->stream;
1179 SilcPacketProcess p;
1180 SilcBool default_sent = FALSE;
1183 /* Parse the packet */
1184 if (!silc_packet_parse(packet)) {
1185 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
1186 silc_packet_free(packet);
1190 /* Dispatch packet to all packet processors that want it */
1192 if (!stream->process) {
1193 /* Send to default processor as no others exist */
1194 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1195 if (!stream->engine->callbacks->
1196 packet_receive(stream->engine, stream, packet,
1197 stream->engine->callback_context,
1198 stream->stream_context))
1199 silc_packet_free(packet);
1203 silc_dlist_start(stream->process);
1204 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END) {
1206 /* If priority is 0 or less, we send to default processor first
1207 because default processor has 0 priority */
1208 if (!default_sent && p->priority <= 0) {
1209 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1210 default_sent = TRUE;
1211 if (stream->engine->callbacks->
1212 packet_receive(stream->engine, stream, packet,
1213 stream->engine->callback_context,
1214 stream->stream_context)) {
1219 /* Send to processor */
1221 /* Send all packet types */
1222 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
1223 if (p->callbacks->packet_receive(stream->engine, stream, packet,
1224 p->callback_context,
1225 stream->stream_context))
1228 /* Send specific types */
1229 for (pt = p->types; *pt; pt++)
1230 if (*pt == packet->type) {
1231 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks",
1233 if (p->callbacks->packet_receive(stream->engine, stream, packet,
1234 p->callback_context,
1235 stream->stream_context))
1242 if (!default_sent) {
1243 /* Send to default processor as it has not been sent yet */
1244 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1245 if (stream->engine->callbacks->
1246 packet_receive(stream->engine, stream, packet,
1247 stream->engine->callback_context,
1248 stream->stream_context))
1252 /* If we got here, no one wanted the packet, so drop it */
1253 silc_packet_free(packet);
1256 /* Process incoming data and parse packets. */
1258 static void silc_packet_read_process(SilcPacketStream stream)
1261 SilcUInt16 packetlen;
1262 SilcUInt32 paddedlen, mac_len, block_len;
1263 unsigned char tmp[SILC_PACKET_MIN_HEADER_LEN], *header;
1264 unsigned char iv[SILC_CIPHER_MAX_IV_SIZE];
1265 SilcBool normal = TRUE;
1268 /* Parse the packets from the data */
1269 while (silc_buffer_len(&stream->inbuf) > 0) {
1271 if (silc_buffer_len(&stream->inbuf) < SILC_PACKET_MIN_HEADER_LEN) {
1272 SILC_LOG_DEBUG(("Partial packet in queue, waiting for the rest"));
1276 if (stream->receive_hmac)
1277 mac_len = silc_hmac_len(stream->receive_hmac);
1281 /* Decrypt first block of the packet to get the length field out */
1282 if (stream->receive_key) {
1283 block_len = silc_cipher_get_block_len(stream->receive_key);
1284 memcpy(iv, silc_cipher_get_iv(stream->receive_key), block_len);
1285 silc_cipher_decrypt(stream->receive_key, stream->inbuf.data,
1286 tmp, block_len, iv);
1289 block_len = SILC_PACKET_MIN_HEADER_LEN;
1290 header = stream->inbuf.data;
1293 /* Get packet length and full packet length with padding */
1294 SILC_PACKET_LENGTH(header, packetlen, paddedlen);
1297 if (packetlen < SILC_PACKET_MIN_LEN) {
1298 SILC_LOG_ERROR(("Received too short packet"));
1299 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
1300 memset(tmp, 0, sizeof(tmp));
1301 silc_buffer_reset(&stream->inbuf);
1305 if (silc_buffer_len(&stream->inbuf) < paddedlen + mac_len) {
1306 SILC_LOG_DEBUG(("Received partial packet, waiting for the rest "
1308 paddedlen + mac_len - silc_buffer_len(&stream->inbuf)));
1309 memset(tmp, 0, sizeof(tmp));
1313 /* Check MAC of the packet */
1314 if (!silc_packet_check_mac(stream->receive_hmac, stream->inbuf.data,
1315 paddedlen, stream->inbuf.data + paddedlen,
1316 stream->receive_psn)) {
1317 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MAC_FAILED);
1318 memset(tmp, 0, sizeof(tmp));
1319 silc_buffer_reset(&stream->inbuf);
1324 packet = silc_packet_alloc(stream->engine);
1326 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
1327 memset(tmp, 0, sizeof(tmp));
1328 silc_buffer_reset(&stream->inbuf);
1332 /* Allocate more space to packet buffer, if needed */
1333 if (silc_buffer_truelen(&packet->buffer) < paddedlen) {
1334 if (!silc_buffer_realloc(&packet->buffer,
1335 silc_buffer_truelen(&packet->buffer) +
1337 silc_buffer_truelen(&packet->buffer)))) {
1338 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
1339 silc_packet_free(packet);
1340 memset(tmp, 0, sizeof(tmp));
1341 silc_buffer_reset(&stream->inbuf);
1346 /* Parse packet header */
1347 packet->flags = (SilcPacketFlags)header[2];
1348 packet->type = (SilcPacketType)header[3];
1350 if (stream->engine->local_is_router) {
1351 if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
1352 (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
1354 else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE ||
1355 (packet->type == SILC_PACKET_CHANNEL_MESSAGE &&
1356 stream->is_router == TRUE))
1359 if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
1360 (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
1362 else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE)
1366 SILC_LOG_HEXDUMP(("Incoming packet (%d) len %d",
1367 stream->receive_psn, paddedlen + mac_len),
1368 stream->inbuf.data, paddedlen + mac_len);
1370 /* Put the decrypted part, and rest of the encrypted data, and decrypt */
1371 silc_buffer_pull_tail(&packet->buffer, paddedlen);
1372 silc_buffer_put(&packet->buffer, header, block_len);
1373 silc_buffer_pull(&packet->buffer, block_len);
1374 silc_buffer_put(&packet->buffer, stream->inbuf.data + block_len,
1375 paddedlen - block_len);
1376 if (stream->receive_key) {
1377 silc_cipher_set_iv(stream->receive_key, iv);
1378 ret = silc_packet_decrypt(stream->receive_key, stream->receive_hmac,
1379 stream->receive_psn, &packet->buffer, normal);
1381 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_DECRYPTION_FAILED);
1382 silc_packet_free(packet);
1383 memset(tmp, 0, sizeof(tmp));
1387 stream->receive_psn++;
1389 silc_buffer_push(&packet->buffer, block_len);
1391 /* Pull the packet from inbuf thus we'll get the next one in the inbuf. */
1392 silc_buffer_pull(&stream->inbuf, paddedlen + mac_len);
1394 /* Dispatch the packet to application */
1395 packet->stream = stream;
1396 silc_packet_dispatch(packet);
1399 silc_buffer_reset(&stream->inbuf);
1403 /****************************** Packet Waiting ******************************/
1405 /* Packet wait receive callback */
1407 silc_packet_wait_packet_receive(SilcPacketEngine engine,
1408 SilcPacketStream stream,
1410 void *callback_context,
1411 void *stream_context);
1413 /* Packet waiting callbacks */
1414 static SilcPacketCallbacks silc_packet_wait_cbs =
1416 silc_packet_wait_packet_receive, NULL, NULL
1419 /* Packet waiting context */
1421 SilcMutex wait_lock;
1423 SilcList packet_queue;
1427 /* Packet wait receive callback */
1430 silc_packet_wait_packet_receive(SilcPacketEngine engine,
1431 SilcPacketStream stream,
1433 void *callback_context,
1434 void *stream_context)
1436 SilcPacketWait pw = callback_context;
1438 /* Signal the waiting thread for a new packet */
1439 silc_mutex_lock(pw->wait_lock);
1442 silc_mutex_unlock(pw->wait_lock);
1446 silc_list_add(pw->packet_queue, packet);
1447 silc_cond_broadcast(pw->wait_cond);
1449 silc_mutex_unlock(pw->wait_lock);
1454 /* Initialize packet waiting */
1456 void *silc_packet_wait_init(SilcPacketStream stream, ...)
1462 pw = silc_calloc(1, sizeof(*pw));
1466 /* Allocate mutex and conditional variable */
1467 if (!silc_mutex_alloc(&pw->wait_lock)) {
1471 if (!silc_cond_alloc(&pw->wait_cond)) {
1472 silc_mutex_free(pw->wait_lock);
1477 /* Link to the packet stream for the requested packet types */
1478 va_start(ap, stream);
1479 ret = silc_packet_stream_link_va(stream, &silc_packet_wait_cbs, pw,
1483 silc_cond_free(pw->wait_cond);
1484 silc_mutex_free(pw->wait_lock);
1489 /* Initialize packet queue */
1490 silc_list_init(pw->packet_queue, struct SilcPacketStruct, next);
1495 /* Uninitialize packet waiting */
1497 void silc_packet_wait_uninit(void *context, SilcPacketStream stream)
1499 SilcPacketWait pw = context;
1502 silc_mutex_lock(pw->wait_lock);
1503 silc_packet_stream_unlink(stream, &silc_packet_wait_cbs, pw);
1505 /* Free any remaining packets */
1506 silc_list_start(pw->packet_queue);
1507 while ((packet = silc_list_get(pw->packet_queue)) != SILC_LIST_END)
1508 silc_packet_free(packet);
1510 silc_mutex_unlock(pw->wait_lock);
1512 silc_cond_free(pw->wait_cond);
1513 silc_mutex_free(pw->wait_lock);
1517 /* Blocks thread until a packet has been received. */
1519 int silc_packet_wait(void *context, int timeout, SilcPacket *return_packet)
1521 SilcPacketWait pw = context;
1522 SilcBool ret = FALSE;
1524 silc_mutex_lock(pw->wait_lock);
1526 /* Wait here until packet has arrived */
1528 while (silc_list_count(pw->packet_queue) == 0)
1529 ret = silc_cond_timedwait(pw->wait_cond, pw->wait_lock, timeout);
1532 silc_list_start(pw->packet_queue);
1533 *return_packet = silc_list_get(pw->packet_queue);
1534 silc_list_del(pw->packet_queue, *return_packet);
1536 silc_mutex_unlock(pw->wait_lock);
1538 return ret == TRUE ? 1 : 0;