5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2009 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 ***************************/
28 /* Per scheduler (which usually means per thread) data. We put per scheduler
29 data here for accessing without locking. SILC Schedule dictates that
30 tasks are dispatched in one thread, hence the per scheduler context. */
32 SilcSchedule schedule; /* The scheduler */
33 SilcPacketEngine engine; /* Packet engine */
34 SilcDList inbufs; /* Data inbut buffer list */
35 SilcUInt32 stream_count; /* Number of streams using this */
36 } *SilcPacketEngineContext;
39 struct SilcPacketEngineStruct {
40 SilcMutex lock; /* Engine lock */
41 SilcRng rng; /* RNG for engine */
42 SilcHashTable contexts; /* Per scheduler contexts */
43 const SilcPacketCallbacks *callbacks; /* Packet callbacks */
44 void *callback_context; /* Context for callbacks */
45 SilcList streams; /* All streams in engine */
46 SilcList packet_pool; /* Free list for received packets */
47 SilcHashTable udp_remote; /* UDP remote streams, or NULL */
48 unsigned int local_is_router : 1;
51 /* Packet processor context */
52 typedef struct SilcPacketProcessStruct {
53 SilcPacketType *types; /* Packets to process */
54 const SilcPacketCallbacks *callbacks; /* Callbacks or NULL */
55 void *callback_context;
56 SilcInt32 priority; /* Priority */
59 /* UDP remote stream tuple */
61 char *remote_ip; /* Remote IP address */
62 SilcUInt16 remote_port; /* Remote port */
63 } *SilcPacketRemoteUDP;
66 struct SilcPacketStreamStruct {
67 struct SilcPacketStreamStruct *next;
68 SilcPacketEngineContext sc; /* Per scheduler context */
69 SilcStream stream; /* Underlaying stream */
70 SilcMutex lock; /* Packet stream lock */
71 SilcDList process; /* Packet processors, or NULL */
72 SilcPacketRemoteUDP remote_udp; /* UDP remote stream tuple, or NULL */
73 void *stream_context; /* Stream context */
74 SilcBufferStruct outbuf; /* Out buffer */
75 SilcBuffer inbuf; /* Inbuf from inbuf list or NULL */
76 SilcCipher send_key[2]; /* Sending key */
77 SilcHmac send_hmac[2]; /* Sending HMAC */
78 SilcCipher receive_key[2]; /* Receiving key */
79 SilcHmac receive_hmac[2]; /* Receiving HMAC */
80 unsigned char *src_id; /* Source ID */
81 unsigned char *dst_id; /* Destination ID */
82 SilcUInt32 send_psn; /* Sending sequence */
83 SilcUInt32 receive_psn; /* Receiving sequence */
84 SilcAtomic32 refcnt; /* Reference counter */
85 SilcUInt8 sid; /* Security ID, set if IV included */
86 unsigned int src_id_len : 6;
87 unsigned int src_id_type : 2;
88 unsigned int dst_id_len : 6;
89 unsigned int dst_id_type : 2;
90 unsigned int is_router : 1; /* Set if router stream */
91 unsigned int destroyed : 1; /* Set if destroyed */
92 unsigned int iv_included : 1; /* Set if IV included */
93 unsigned int udp : 1; /* UDP remote stream */
96 /* Initial size of stream buffers */
97 #define SILC_PACKET_DEFAULT_SIZE 1024
99 /* Header length without source and destination ID's. */
100 #define SILC_PACKET_HEADER_LEN 10
102 /* Minimum length of SILC Packet Header. */
103 #define SILC_PACKET_MIN_HEADER_LEN 16
104 #define SILC_PACKET_MIN_HEADER_LEN_IV 32 + 1
106 /* Maximum padding length */
107 #define SILC_PACKET_MAX_PADLEN 128
109 /* Default padding length */
110 #define SILC_PACKET_DEFAULT_PADLEN 16
112 /* Minimum packet length */
113 #define SILC_PACKET_MIN_LEN (SILC_PACKET_HEADER_LEN + 1)
115 /* Returns true length of the packet. */
116 #define SILC_PACKET_LENGTH(__packetdata, __ret_truelen, __ret_paddedlen) \
118 SILC_GET16_MSB((__ret_truelen), (__packetdata)); \
119 (__ret_paddedlen) = (__ret_truelen) + (SilcUInt8)(__packetdata)[4]; \
122 /* Calculates the data length with given header length. This macro
123 can be used to check whether the data_len with header_len exceeds
124 SILC_PACKET_MAX_LEN. If it does, this returns the new data_len
125 so that the SILC_PACKET_MAX_LEN is not exceeded. If the data_len
126 plus header_len fits SILC_PACKET_MAX_LEN the returned data length
127 is the data_len given as argument. */
128 #define SILC_PACKET_DATALEN(data_len, header_len) \
129 ((data_len + header_len) > SILC_PACKET_MAX_LEN ? \
130 data_len - ((data_len + header_len) - SILC_PACKET_MAX_LEN) : data_len)
132 /* Calculates the length of the padding in the packet. */
133 #define SILC_PACKET_PADLEN(__packetlen, __blocklen, __padlen) \
135 __padlen = (SILC_PACKET_DEFAULT_PADLEN - (__packetlen) % \
136 ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN)); \
138 __padlen += ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN); \
141 /* Returns the length of the padding up to the maximum length, which
143 #define SILC_PACKET_PADLEN_MAX(__packetlen, __blocklen, __padlen) \
145 __padlen = (SILC_PACKET_MAX_PADLEN - (__packetlen) % \
146 ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN)); \
150 #define SILC_PACKET_CALLBACK_EOS(s) \
152 (s)->sc->engine->callbacks->eos((s)->sc->engine, s, \
153 (s)->sc->engine->callback_context, \
154 (s)->stream_context); \
158 #define SILC_PACKET_CALLBACK_ERROR(s, err) \
160 (s)->sc->engine->callbacks->error((s)->sc->engine, s, err, \
161 (s)->sc->engine->callback_context, \
162 (s)->stream_context); \
165 static SilcBool silc_packet_dispatch(SilcPacket packet);
166 static void silc_packet_read_process(SilcPacketStream stream);
167 static inline SilcBool silc_packet_send_raw(SilcPacketStream stream,
169 SilcPacketFlags flags,
170 SilcIdType src_id_type,
171 unsigned char *src_id,
172 SilcUInt32 src_id_len,
173 SilcIdType dst_id_type,
174 unsigned char *dst_id,
175 SilcUInt32 dst_id_len,
176 const unsigned char *data,
181 /************************ Static utility functions **************************/
183 /* Injects packet to new stream created with silc_packet_stream_add_remote. */
185 SILC_TASK_CALLBACK(silc_packet_stream_inject_packet)
187 SilcPacket packet = context;
188 SilcPacketStream stream = packet->stream;
190 SILC_LOG_DEBUG(("Injecting packet %p to stream %p", packet, packet->stream));
192 silc_mutex_lock(stream->lock);
193 if (!stream->destroyed)
194 silc_packet_dispatch(packet);
195 silc_mutex_unlock(stream->lock);
196 silc_packet_stream_unref(stream);
199 /* Write data to the stream. Must be called with ps->lock locked. Unlocks
200 the lock inside this function, unless no_unlock is TRUE. Unlocks always
201 in case it returns FALSE. */
203 static inline SilcBool silc_packet_stream_write(SilcPacketStream ps,
211 stream = ((SilcPacketStream)ps->stream)->stream;
215 if (ps->udp && silc_socket_stream_is_udp(stream, &connected)) {
217 /* Connectionless UDP stream */
218 while (silc_buffer_len(&ps->outbuf) > 0) {
219 i = silc_net_udp_send(stream, ps->remote_udp->remote_ip,
220 ps->remote_udp->remote_port,
221 ps->outbuf.data, silc_buffer_len(&ps->outbuf));
222 if (silc_unlikely(i == -2)) {
224 silc_buffer_reset(&ps->outbuf);
225 SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_WRITE);
229 if (silc_unlikely(i == -1)) {
230 /* Cannot write now, write later. */
232 silc_mutex_unlock(ps->lock);
237 silc_buffer_pull(&ps->outbuf, i);
240 silc_buffer_reset(&ps->outbuf);
242 silc_mutex_unlock(ps->lock);
248 /* Write the data to the stream */
249 while (silc_buffer_len(&ps->outbuf) > 0) {
250 i = silc_stream_write(stream, ps->outbuf.data,
251 silc_buffer_len(&ps->outbuf));
252 if (silc_unlikely(i == 0)) {
254 silc_buffer_reset(&ps->outbuf);
255 silc_mutex_unlock(ps->lock);
256 SILC_PACKET_CALLBACK_EOS(ps);
260 if (silc_unlikely(i == -2)) {
262 silc_buffer_reset(&ps->outbuf);
263 silc_mutex_unlock(ps->lock);
264 SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_WRITE);
268 if (silc_unlikely(i == -1)) {
269 /* Cannot write now, write later. */
271 silc_mutex_unlock(ps->lock);
276 silc_buffer_pull(&ps->outbuf, i);
279 silc_buffer_reset(&ps->outbuf);
281 silc_mutex_unlock(ps->lock);
286 /* Reads data from stream. Must be called with ps->lock locked. If this
287 returns FALSE the lock has been unlocked. If this returns packet stream
288 to `ret_ps' its lock has been acquired and `ps' lock has been unlocked.
289 It is returned if the stream is UDP and remote UDP stream exists for
290 the sender of the packet. */
292 static inline SilcBool silc_packet_stream_read(SilcPacketStream ps,
293 SilcPacketStream *ret_ps)
295 SilcStream stream = ps->stream;
300 /* Get inbuf. If there is already some data for this stream in the buffer
301 we already have it. Otherwise get the current one from list, it will
305 silc_dlist_start(ps->sc->inbufs);
306 inbuf = silc_dlist_get(ps->sc->inbufs);
308 /* Allocate new data input buffer */
309 inbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE * 65);
311 silc_mutex_unlock(ps->lock);
314 silc_buffer_reset(inbuf);
315 silc_dlist_add(ps->sc->inbufs, inbuf);
319 /* Make sure there is enough room to read */
320 if (SILC_PACKET_DEFAULT_SIZE * 2 > silc_buffer_taillen(inbuf))
321 silc_buffer_realloc(inbuf, silc_buffer_truelen(inbuf) +
322 (SILC_PACKET_DEFAULT_SIZE * 2));
324 if (silc_socket_stream_is_udp(stream, &connected)) {
326 /* Connectionless UDP stream, read one UDP packet */
327 char remote_ip[64], tuple[64];
329 SilcPacketStream remote;
331 ret = silc_net_udp_receive(stream, remote_ip, sizeof(remote_ip),
332 &remote_port, inbuf->tail,
333 silc_buffer_taillen(inbuf));
335 if (silc_unlikely(ret < 0)) {
336 silc_mutex_unlock(ps->lock);
338 /* Cannot read now, do it later. */
343 silc_buffer_reset(inbuf);
344 SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_READ);
348 /* See if remote packet stream exist for this sender */
349 silc_snprintf(tuple, sizeof(tuple), "%d%s", remote_port, remote_ip);
350 silc_mutex_lock(ps->sc->engine->lock);
351 if (silc_hash_table_find(ps->sc->engine->udp_remote, tuple, NULL,
353 silc_mutex_unlock(ps->sc->engine->lock);
354 SILC_LOG_DEBUG(("UDP packet from %s:%d for stream %p", remote_ip,
355 remote_port, remote));
356 silc_mutex_unlock(ps->lock);
357 silc_mutex_lock(remote->lock);
361 silc_mutex_unlock(ps->sc->engine->lock);
364 if (!ps->remote_udp) {
365 ps->remote_udp = silc_calloc(1, sizeof(*ps->remote_udp));
366 if (silc_unlikely(!ps->remote_udp)) {
367 silc_mutex_unlock(ps->lock);
368 SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_NO_MEMORY);
373 /* Save sender IP and port */
374 silc_free(ps->remote_udp->remote_ip);
375 ps->remote_udp->remote_ip = strdup(remote_ip);
376 ps->remote_udp->remote_port = remote_port;
378 silc_buffer_pull_tail(inbuf, ret);
383 /* Read data from the stream */
384 ret = silc_stream_read(stream, inbuf->tail, silc_buffer_taillen(inbuf));
385 if (silc_unlikely(ret <= 0)) {
386 silc_mutex_unlock(ps->lock);
389 silc_buffer_reset(inbuf);
390 SILC_PACKET_CALLBACK_EOS(ps);
395 /* Cannot read now, do it later. */
400 silc_buffer_reset(inbuf);
401 SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_READ);
405 silc_buffer_pull_tail(inbuf, ret);
409 /* Our stream IO notifier callback. */
411 static void silc_packet_stream_io(SilcStream stream, SilcStreamStatus status,
414 SilcPacketStream remote = NULL, ps = context;
416 silc_mutex_lock(ps->lock);
418 if (silc_unlikely(ps->destroyed)) {
419 silc_mutex_unlock(ps->lock);
424 case SILC_STREAM_CAN_READ:
425 /* Reading is locked also with stream->lock because we may be reading
426 at the same time other thread is writing to same underlaying stream. */
427 SILC_LOG_DEBUG(("Reading data from stream %p, ps %p", ps->stream, ps));
429 /* Read data from stream */
430 if (!silc_packet_stream_read(ps, &remote))
433 /* Now process the data */
434 silc_packet_stream_ref(ps);
436 silc_packet_read_process(ps);
437 silc_mutex_unlock(ps->lock);
439 silc_packet_read_process(remote);
440 silc_mutex_unlock(remote->lock);
442 silc_packet_stream_unref(ps);
445 case SILC_STREAM_CAN_WRITE:
446 SILC_LOG_DEBUG(("Writing pending data to stream %p, ps %p",
449 if (silc_unlikely(!silc_buffer_headlen(&ps->outbuf))) {
450 silc_mutex_unlock(ps->lock);
454 /* Write pending data to stream */
455 silc_packet_stream_write(ps, FALSE);
459 silc_mutex_unlock(ps->lock);
464 /* Allocate packet */
466 static SilcPacket silc_packet_alloc(SilcPacketEngine engine)
470 SILC_LOG_DEBUG(("Packet pool count %d",
471 silc_list_count(engine->packet_pool)));
473 silc_mutex_lock(engine->lock);
475 /* Get packet from freelist or allocate new one. */
476 packet = silc_list_get(engine->packet_pool);
480 silc_mutex_unlock(engine->lock);
482 packet = silc_calloc(1, sizeof(*packet));
483 if (silc_unlikely(!packet))
486 SILC_LOG_DEBUG(("Allocating new packet %p", packet));
488 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
489 if (silc_unlikely(!tmp)) {
493 silc_buffer_set(&packet->buffer, tmp, SILC_PACKET_DEFAULT_SIZE);
494 silc_buffer_reset(&packet->buffer);
499 SILC_LOG_DEBUG(("Get packet %p", packet));
501 /* Delete from freelist */
502 silc_list_del(engine->packet_pool, packet);
504 silc_mutex_unlock(engine->lock);
509 /* UDP remote stream hash table destructor */
511 static void silc_packet_engine_hash_destr(void *key, void *context,
517 /* Per scheduler context hash table destructor */
519 static void silc_packet_engine_context_destr(void *key, void *context,
522 SilcPacketEngineContext sc = context;
525 silc_dlist_start(sc->inbufs);
526 while ((buffer = silc_dlist_get(sc->inbufs))) {
527 silc_buffer_clear(buffer);
528 silc_buffer_free(buffer);
529 silc_dlist_del(sc->inbufs, buffer);
532 silc_dlist_uninit(sc->inbufs);
537 /******************************** Packet API ********************************/
539 /* Allocate new packet engine */
542 silc_packet_engine_start(SilcRng rng, SilcBool router,
543 const SilcPacketCallbacks *callbacks,
544 void *callback_context)
546 SilcPacketEngine engine;
551 SILC_LOG_DEBUG(("Starting new packet engine"));
555 if (!callbacks->packet_receive || !callbacks->eos || !callbacks->error)
558 engine = silc_calloc(1, sizeof(*engine));
562 engine->contexts = silc_hash_table_alloc(0, silc_hash_ptr, NULL, NULL, NULL,
563 silc_packet_engine_context_destr,
565 if (!engine->contexts) {
571 engine->local_is_router = router;
572 engine->callbacks = callbacks;
573 engine->callback_context = callback_context;
574 silc_list_init(engine->streams, struct SilcPacketStreamStruct, next);
575 silc_mutex_alloc(&engine->lock);
577 /* Allocate packet free list */
578 silc_list_init(engine->packet_pool, struct SilcPacketStruct, next);
579 for (i = 0; i < 5; i++) {
580 packet = silc_calloc(1, sizeof(*packet));
582 silc_packet_engine_stop(engine);
586 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
588 silc_packet_engine_stop(engine);
591 silc_buffer_set(&packet->buffer, tmp, SILC_PACKET_DEFAULT_SIZE);
592 silc_buffer_reset(&packet->buffer);
594 silc_list_add(engine->packet_pool, packet);
596 silc_list_start(engine->packet_pool);
601 /* Stop packet engine */
603 void silc_packet_engine_stop(SilcPacketEngine engine)
607 SILC_LOG_DEBUG(("Stopping packet engine"));
612 /* Free packet free list */
613 silc_list_start(engine->packet_pool);
614 while ((packet = silc_list_get(engine->packet_pool))) {
615 silc_buffer_purge(&packet->buffer);
619 silc_hash_table_free(engine->contexts);
620 silc_mutex_free(engine->lock);
624 static const char * const packet_error[] = {
625 "Cannot read from stream",
626 "Cannot write to stream",
628 "Packet decryption failed",
630 "Packet is malformed",
631 "System out of memory",
634 /* Return packet error string */
636 const char *silc_packet_error_string(SilcPacketError error)
638 if (error < SILC_PACKET_ERR_READ || error > SILC_PACKET_ERR_NO_MEMORY)
639 return "<invalid error code>";
640 return packet_error[error];
643 /* Return list of packet streams in the engine */
645 SilcDList silc_packet_engine_get_streams(SilcPacketEngine engine)
650 list = silc_dlist_init();
654 silc_mutex_lock(engine->lock);
655 silc_list_start(engine->streams);
656 while ((ps = silc_list_get(engine->streams))) {
657 silc_packet_stream_ref(ps);
658 silc_dlist_add(list, ps);
660 silc_mutex_unlock(engine->lock);
665 /* Free list returned by silc_packet_engine_get_streams */
667 void silc_packet_engine_free_streams_list(SilcDList streams)
671 silc_dlist_start(streams);
672 while ((ps = silc_dlist_get(streams)))
673 silc_packet_stream_unref(ps);
675 silc_dlist_uninit(streams);
678 /* Create new packet stream */
680 SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
681 SilcSchedule schedule,
688 SILC_LOG_DEBUG(("Creating new packet stream"));
690 if (!engine || !stream)
693 ps = silc_calloc(1, sizeof(*ps));
698 silc_atomic_init32(&ps->refcnt, 1);
699 silc_mutex_alloc(&ps->lock);
701 /* Allocate out buffer */
702 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
704 silc_packet_stream_destroy(ps);
707 silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
708 silc_buffer_reset(&ps->outbuf);
710 /* Initialize packet procesors list */
711 ps->process = silc_dlist_init();
714 silc_packet_stream_destroy(ps);
718 silc_mutex_lock(engine->lock);
720 /* Add per scheduler context */
721 if (!silc_hash_table_find(engine->contexts, schedule, NULL,
723 ps->sc = silc_calloc(1, sizeof(*ps->sc));
725 silc_mutex_unlock(engine->lock);
727 silc_packet_stream_destroy(ps);
730 ps->sc->engine = engine;
731 ps->sc->schedule = schedule;
733 /* Allocate data input buffer */
734 inbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE * 65);
738 silc_mutex_unlock(engine->lock);
740 silc_packet_stream_destroy(ps);
743 silc_buffer_reset(inbuf);
745 ps->sc->inbufs = silc_dlist_init();
746 if (!ps->sc->inbufs) {
747 silc_buffer_free(inbuf);
750 silc_mutex_unlock(engine->lock);
752 silc_packet_stream_destroy(ps);
755 silc_dlist_add(ps->sc->inbufs, inbuf);
757 /* Add to per scheduler context hash table */
758 if (!silc_hash_table_add(engine->contexts, schedule, ps->sc)) {
759 silc_buffer_free(inbuf);
760 silc_dlist_del(ps->sc->inbufs, inbuf);
763 silc_mutex_unlock(engine->lock);
765 silc_packet_stream_destroy(ps);
769 ps->sc->stream_count++;
771 /* Add the packet stream to engine */
772 silc_list_add(engine->streams, ps);
774 /* If this is UDP stream, allocate UDP remote stream hash table */
775 if (!engine->udp_remote && silc_socket_stream_is_udp(stream, NULL))
776 engine->udp_remote = silc_hash_table_alloc(0, silc_hash_string, NULL,
777 silc_hash_string_compare, NULL,
778 silc_packet_engine_hash_destr,
781 silc_mutex_unlock(engine->lock);
783 /* Set IO notifier callback. This schedules this stream for I/O. */
784 if (!silc_stream_set_notifier(ps->stream, schedule,
785 silc_packet_stream_io, ps)) {
786 SILC_LOG_DEBUG(("Cannot set stream notifier for packet stream"));
788 silc_packet_stream_destroy(ps);
792 SILC_LOG_DEBUG(("Created packet stream %p", ps));
797 /* Add new remote packet stream for UDP packet streams */
799 SilcPacketStream silc_packet_stream_add_remote(SilcPacketStream stream,
800 const char *remote_ip,
801 SilcUInt16 remote_port,
804 SilcPacketEngine engine = stream->sc->engine;
809 SILC_LOG_DEBUG(("Adding UDP remote %s:%d to packet stream %p",
810 remote_ip, remote_port, stream));
812 if (!stream || !remote_ip || !remote_port)
815 if (!silc_socket_stream_is_udp(stream->stream, NULL)) {
816 SILC_LOG_ERROR(("Stream is not UDP stream, cannot add remote IP"));
820 ps = silc_calloc(1, sizeof(*ps));
825 silc_atomic_init32(&ps->refcnt, 1);
826 silc_mutex_alloc(&ps->lock);
828 /* Set the UDP packet stream as underlaying stream */
829 silc_packet_stream_ref(stream);
830 ps->stream = (SilcStream)stream;
833 /* Allocate out buffer */
834 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
836 silc_packet_stream_destroy(ps);
839 silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
840 silc_buffer_reset(&ps->outbuf);
842 /* Initialize packet procesors list */
843 ps->process = silc_dlist_init();
845 silc_packet_stream_destroy(ps);
849 /* Add to engine with this IP and port pair */
850 tuple = silc_format("%d%s", remote_port, remote_ip);
851 silc_mutex_lock(engine->lock);
852 if (!tuple || !silc_hash_table_add(engine->udp_remote, tuple, ps)) {
853 silc_mutex_unlock(engine->lock);
854 silc_packet_stream_destroy(ps);
857 silc_mutex_unlock(engine->lock);
859 /* Save remote IP and port pair */
860 ps->remote_udp = silc_calloc(1, sizeof(*ps->remote_udp));
861 if (!ps->remote_udp) {
862 silc_packet_stream_destroy(ps);
865 ps->remote_udp->remote_port = remote_port;
866 ps->remote_udp->remote_ip = strdup(remote_ip);
867 if (!ps->remote_udp->remote_ip) {
868 silc_packet_stream_destroy(ps);
873 /* Inject packet to the new stream */
875 silc_packet_stream_ref(ps);
876 silc_schedule_task_add_timeout(silc_stream_get_schedule(stream->stream),
877 silc_packet_stream_inject_packet, packet,
884 /* Destroy packet stream */
886 void silc_packet_stream_destroy(SilcPacketStream stream)
888 SilcPacketEngine engine;
893 if (silc_atomic_sub_int32(&stream->refcnt, 1) > 0) {
894 if (stream->destroyed)
896 stream->destroyed = TRUE;
898 SILC_LOG_DEBUG(("Marking packet stream %p destroyed", stream));
900 /* Close the underlaying stream */
901 if (!stream->udp && stream->stream)
902 silc_stream_close(stream->stream);
906 SILC_LOG_DEBUG(("Destroying packet stream %p", stream));
909 /* Delete from engine */
911 engine = stream->sc->engine;
912 silc_mutex_lock(engine->lock);
913 silc_list_del(engine->streams, stream);
915 /* Remove per scheduler context, if it is not used anymore */
916 stream->sc->stream_count--;
917 if (!stream->sc->stream_count)
918 silc_hash_table_del(engine->contexts, stream->sc->schedule);
920 silc_mutex_unlock(engine->lock);
923 /* Destroy the underlaying stream */
925 silc_stream_destroy(stream->stream);
927 /* Delete from UDP remote hash table */
929 engine = stream->sc->engine;
930 silc_snprintf(tuple, sizeof(tuple), "%d%s",
931 stream->remote_udp->remote_port,
932 stream->remote_udp->remote_ip);
933 silc_mutex_lock(engine->lock);
934 silc_hash_table_del(engine->udp_remote, tuple);
935 silc_mutex_unlock(engine->lock);
937 silc_free(stream->remote_udp->remote_ip);
938 silc_free(stream->remote_udp);
940 /* Unreference the underlaying packet stream */
941 silc_packet_stream_unref((SilcPacketStream)stream->stream);
944 /* Clear and free buffers */
945 silc_buffer_clear(&stream->outbuf);
946 silc_buffer_purge(&stream->outbuf);
948 if (stream->process) {
950 silc_dlist_start(stream->process);
951 while ((p = silc_dlist_get(stream->process))) {
954 silc_dlist_del(stream->process, p);
956 silc_dlist_uninit(stream->process);
959 /* Destroy ciphers and HMACs */
960 if (stream->send_key[0])
961 silc_cipher_free(stream->send_key[0]);
962 if (stream->receive_key[0])
963 silc_cipher_free(stream->receive_key[0]);
964 if (stream->send_hmac[0])
965 silc_hmac_free(stream->send_hmac[0]);
966 if (stream->receive_hmac[0])
967 silc_hmac_free(stream->receive_hmac[0]);
968 if (stream->send_key[1])
969 silc_cipher_free(stream->send_key[1]);
970 if (stream->receive_key[1])
971 silc_cipher_free(stream->receive_key[1]);
972 if (stream->send_hmac[1])
973 silc_hmac_free(stream->send_hmac[1]);
974 if (stream->receive_hmac[1])
975 silc_hmac_free(stream->receive_hmac[1]);
978 silc_free(stream->src_id);
979 silc_free(stream->dst_id);
981 silc_atomic_uninit32(&stream->refcnt);
982 silc_mutex_free(stream->lock);
986 /* Return TRUE if the stream is valid */
988 SilcBool silc_packet_stream_is_valid(SilcPacketStream stream)
990 return stream->destroyed == FALSE;
993 /* Marks as router stream */
995 void silc_packet_stream_set_router(SilcPacketStream stream)
997 stream->is_router = TRUE;
1000 /* Mark to include IV in ciphertext */
1002 void silc_packet_stream_set_iv_included(SilcPacketStream stream)
1004 stream->iv_included = TRUE;
1007 /* Links `callbacks' to `stream' for specified packet types */
1009 static SilcBool silc_packet_stream_link_va(SilcPacketStream stream,
1010 const SilcPacketCallbacks *callbacks,
1011 void *callback_context,
1012 int priority, va_list ap)
1014 SilcPacketProcess p, e;
1015 SilcInt32 packet_type;
1018 SILC_LOG_DEBUG(("Linking callbacks %p to stream %p", callbacks, stream));
1022 if (!callbacks->packet_receive)
1025 p = silc_calloc(1, sizeof(*p));
1029 p->priority = priority;
1030 p->callbacks = callbacks;
1031 p->callback_context = callback_context;
1033 silc_mutex_lock(stream->lock);
1035 if (!stream->process) {
1036 stream->process = silc_dlist_init();
1037 if (!stream->process) {
1038 silc_mutex_unlock(stream->lock);
1044 /* According to priority set the procesor to correct position. First
1045 entry has the highest priority */
1046 silc_dlist_start(stream->process);
1047 while ((e = silc_dlist_get(stream->process)) != SILC_LIST_END) {
1048 if (p->priority > e->priority) {
1049 silc_dlist_insert(stream->process, p);
1054 silc_dlist_add(stream->process, p);
1056 /* Get packet types to process */
1059 packet_type = va_arg(ap, SilcInt32);
1061 if (packet_type == SILC_PACKET_ANY)
1064 if (packet_type == -1)
1067 p->types = silc_realloc(p->types, sizeof(*p->types) * (i + 1));
1069 silc_mutex_unlock(stream->lock);
1073 p->types[i - 1] = (SilcPacketType)packet_type;
1077 p->types[i - 1] = 0;
1079 silc_mutex_unlock(stream->lock);
1081 silc_packet_stream_ref(stream);
1086 /* Links `callbacks' to `stream' for specified packet types */
1088 SilcBool silc_packet_stream_link(SilcPacketStream stream,
1089 const SilcPacketCallbacks *callbacks,
1090 void *callback_context,
1096 va_start(ap, priority);
1097 ret = silc_packet_stream_link_va(stream, callbacks, callback_context,
1104 /* Unlinks `callbacks' from `stream'. */
1106 void silc_packet_stream_unlink(SilcPacketStream stream,
1107 const SilcPacketCallbacks *callbacks,
1108 void *callback_context)
1110 SilcPacketProcess p;
1112 SILC_LOG_DEBUG(("Unlinking callbacks %p from stream %p",
1113 callbacks, stream));
1115 silc_mutex_lock(stream->lock);
1117 silc_dlist_start(stream->process);
1118 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END)
1119 if (p->callbacks == callbacks &&
1120 p->callback_context == callback_context) {
1121 silc_dlist_del(stream->process, p);
1122 silc_free(p->types);
1127 if (!silc_dlist_count(stream->process)) {
1128 silc_dlist_uninit(stream->process);
1129 stream->process = NULL;
1132 silc_mutex_unlock(stream->lock);
1134 silc_packet_stream_unref(stream);
1137 /* Returns TRUE if stream is UDP stream */
1139 SilcBool silc_packet_stream_is_udp(SilcPacketStream stream)
1141 return stream->udp || silc_socket_stream_is_udp(stream->stream, NULL);
1144 /* Return packet sender IP and port for UDP packet stream */
1146 SilcBool silc_packet_get_sender(SilcPacket packet,
1147 const char **sender_ip,
1148 SilcUInt16 *sender_port)
1150 if (!packet->stream->remote_udp)
1153 *sender_ip = packet->stream->remote_udp->remote_ip;
1154 *sender_port = packet->stream->remote_udp->remote_port;
1159 /* Reference packet stream */
1161 void silc_packet_stream_ref(SilcPacketStream stream)
1163 silc_atomic_add_int32(&stream->refcnt, 1);
1164 SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
1165 silc_atomic_get_int32(&stream->refcnt) - 1,
1166 silc_atomic_get_int32(&stream->refcnt)));
1169 /* Unreference packet stream */
1171 void silc_packet_stream_unref(SilcPacketStream stream)
1173 SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
1174 silc_atomic_get_int32(&stream->refcnt),
1175 silc_atomic_get_int32(&stream->refcnt) - 1));
1176 if (silc_atomic_sub_int32(&stream->refcnt, 1) > 0)
1178 silc_atomic_add_int32(&stream->refcnt, 1);
1179 silc_packet_stream_destroy(stream);
1184 SilcPacketEngine silc_packet_get_engine(SilcPacketStream stream)
1186 return stream->sc->engine;
1189 /* Set application context for packet stream */
1191 void silc_packet_set_context(SilcPacketStream stream, void *stream_context)
1193 silc_mutex_lock(stream->lock);
1194 stream->stream_context = stream_context;
1195 silc_mutex_unlock(stream->lock);
1198 /* Return application context from packet stream */
1200 void *silc_packet_get_context(SilcPacketStream stream)
1203 silc_mutex_lock(stream->lock);
1204 context = stream->stream_context;
1205 silc_mutex_unlock(stream->lock);
1209 /* Change underlaying stream */
1211 void silc_packet_stream_set_stream(SilcPacketStream ps,
1215 silc_stream_set_notifier(ps->stream, ps->sc->schedule, NULL, NULL);
1216 ps->stream = stream;
1217 silc_stream_set_notifier(ps->stream, ps->sc->schedule, silc_packet_stream_io,
1221 /* Return underlaying stream */
1223 SilcStream silc_packet_stream_get_stream(SilcPacketStream stream)
1225 return stream->stream;
1230 SilcBool silc_packet_set_keys(SilcPacketStream stream, SilcCipher send_key,
1231 SilcCipher receive_key, SilcHmac send_hmac,
1232 SilcHmac receive_hmac, SilcBool rekey)
1234 SILC_LOG_DEBUG(("Setting new keys to packet stream %p", stream));
1236 /* If doing rekey, send REKEY_DONE packet */
1238 /* This will take stream lock. */
1239 if (!silc_packet_send_raw(stream, SILC_PACKET_REKEY_DONE, 0,
1240 stream->src_id_type, stream->src_id,
1241 stream->src_id_len, stream->dst_id_type,
1242 stream->dst_id, stream->dst_id_len,
1243 NULL, 0, stream->send_key[0],
1244 stream->send_hmac[0]))
1247 /* Write the packet to the stream */
1248 if (!silc_packet_stream_write(stream, TRUE))
1251 silc_mutex_lock(stream->lock);
1254 /* In case IV Included is set, save the old keys */
1255 if (stream->iv_included) {
1256 if (stream->send_key[1] && send_key) {
1257 silc_cipher_free(stream->send_key[1]);
1258 stream->send_key[1] = stream->send_key[0];
1260 if (stream->receive_key[1] && receive_key) {
1261 silc_cipher_free(stream->receive_key[1]);
1262 stream->receive_key[1] = stream->receive_key[0];
1264 if (stream->send_hmac[1] && send_hmac) {
1265 silc_hmac_free(stream->send_hmac[1]);
1266 stream->send_hmac[1] = stream->send_hmac[0];
1268 if (stream->receive_hmac[1] && receive_hmac) {
1269 silc_hmac_free(stream->receive_hmac[1]);
1270 stream->receive_hmac[1] = stream->receive_hmac[0];
1273 if (stream->send_key[0] && send_key)
1274 silc_cipher_free(stream->send_key[0]);
1275 if (stream->receive_key[0] && receive_key)
1276 silc_cipher_free(stream->receive_key[0]);
1277 if (stream->send_hmac[0] && send_hmac)
1278 silc_hmac_free(stream->send_hmac[0]);
1279 if (stream->receive_hmac[0] && receive_hmac)
1280 silc_hmac_free(stream->receive_hmac[0]);
1285 stream->send_key[0] = send_key;
1287 stream->receive_key[0] = receive_key;
1289 stream->send_hmac[0] = send_hmac;
1291 stream->receive_hmac[0] = receive_hmac;
1293 silc_mutex_unlock(stream->lock);
1297 /* Return current ciphers from packet stream */
1299 SilcBool silc_packet_get_keys(SilcPacketStream stream,
1300 SilcCipher *send_key,
1301 SilcCipher *receive_key,
1302 SilcHmac *send_hmac,
1303 SilcHmac *receive_hmac)
1305 if (!stream->send_key[0] && !stream->receive_key[0] &&
1306 !stream->send_hmac[0] && !stream->receive_hmac[0])
1309 silc_mutex_lock(stream->lock);
1312 *send_key = stream->send_key[0];
1314 *receive_key = stream->receive_key[0];
1316 *send_hmac = stream->send_hmac[0];
1318 *receive_hmac = stream->receive_hmac[0];
1320 silc_mutex_unlock(stream->lock);
1325 /* Set SILC IDs to packet stream */
1327 SilcBool silc_packet_set_ids(SilcPacketStream stream,
1328 SilcIdType src_id_type, const void *src_id,
1329 SilcIdType dst_id_type, const void *dst_id)
1332 unsigned char tmp[32];
1335 if (!src_id && !dst_id)
1338 silc_mutex_lock(stream->lock);
1341 SILC_LOG_DEBUG(("Setting source ID to packet stream %p", stream));
1343 if (!silc_id_id2str(src_id, src_id_type, tmp, sizeof(tmp), &len)) {
1344 silc_mutex_unlock(stream->lock);
1347 tmp_id = silc_memdup(tmp, len);
1349 silc_mutex_unlock(stream->lock);
1352 silc_free(stream->src_id);
1353 stream->src_id = tmp_id;
1354 stream->src_id_type = src_id_type;
1355 stream->src_id_len = len;
1359 SILC_LOG_DEBUG(("Setting destination ID to packet stream %p", stream));
1361 if (!silc_id_id2str(dst_id, dst_id_type, tmp, sizeof(tmp), &len)) {
1362 silc_mutex_unlock(stream->lock);
1365 tmp_id = silc_memdup(tmp, len);
1367 silc_mutex_unlock(stream->lock);
1370 silc_free(stream->dst_id);
1371 stream->dst_id = tmp_id;
1372 stream->dst_id_type = dst_id_type;
1373 stream->dst_id_len = len;
1376 silc_mutex_unlock(stream->lock);
1381 /* Return IDs from the packet stream */
1383 SilcBool silc_packet_get_ids(SilcPacketStream stream,
1384 SilcBool *src_id_set, SilcID *src_id,
1385 SilcBool *dst_id_set, SilcID *dst_id)
1387 if (src_id && stream->src_id)
1388 if (!silc_id_str2id2(stream->src_id, stream->src_id_len,
1389 stream->src_id_type, src_id))
1392 if (stream->src_id && src_id_set)
1395 if (dst_id && stream->dst_id)
1396 if (!silc_id_str2id2(stream->dst_id, stream->dst_id_len,
1397 stream->dst_id_type, dst_id))
1400 if (stream->dst_id && dst_id_set)
1406 /* Adds Security ID (SID) */
1408 SilcBool silc_packet_set_sid(SilcPacketStream stream, SilcUInt8 sid)
1410 if (!stream->iv_included)
1413 SILC_LOG_DEBUG(("Set packet stream %p SID to %d", stream, sid));
1421 void silc_packet_free(SilcPacket packet)
1423 SilcPacketStream stream = packet->stream;
1425 SILC_LOG_DEBUG(("Freeing packet %p", packet));
1427 /* Check for double free */
1428 SILC_ASSERT(packet->stream != NULL);
1430 packet->stream = NULL;
1431 packet->src_id = packet->dst_id = NULL;
1432 silc_buffer_reset(&packet->buffer);
1434 silc_mutex_lock(stream->sc->engine->lock);
1436 /* Put the packet back to freelist */
1437 silc_list_add(stream->sc->engine->packet_pool, packet);
1438 if (silc_list_count(stream->sc->engine->packet_pool) == 1)
1439 silc_list_start(stream->sc->engine->packet_pool);
1441 silc_mutex_unlock(stream->sc->engine->lock);
1444 /****************************** Packet Sending ******************************/
1446 /* Prepare outgoing data buffer for packet sending. Returns the
1447 pointer to that buffer into the `packet'. */
1449 static inline SilcBool silc_packet_send_prepare(SilcPacketStream stream,
1454 unsigned char *oldptr;
1455 unsigned int mac_len = hmac ? silc_hmac_len(hmac) : 0;
1459 /* Allocate more space if needed */
1460 if (silc_unlikely(silc_buffer_taillen(&stream->outbuf) < totlen)) {
1461 if (!silc_buffer_realloc(&stream->outbuf,
1462 silc_buffer_truelen(&stream->outbuf) + totlen))
1466 /* Pull data area for the new packet, and return pointer to the start of
1467 the data area and save the pointer in to the `packet'. MAC is pulled
1468 later after it's computed. */
1469 oldptr = silc_buffer_pull_tail(&stream->outbuf, totlen);
1470 silc_buffer_set(packet, oldptr, totlen);
1471 silc_buffer_push_tail(packet, mac_len);
1476 /* Increments counter when encrypting in counter mode. */
1478 static inline void silc_packet_send_ctr_increment(SilcPacketStream stream,
1480 unsigned char *ret_iv)
1482 unsigned char *iv = silc_cipher_get_iv(cipher);
1483 SilcUInt32 pc1, pc2;
1485 /* Reset block counter */
1486 memset(iv + 12, 0, 4);
1488 /* If IV Included flag, return the 64-bit IV for inclusion in packet */
1489 if (stream->iv_included) {
1491 ret_iv[0] = silc_rng_get_byte_fast(stream->sc->engine->rng);
1492 ret_iv[1] = ret_iv[0] + iv[4];
1493 ret_iv[2] = ret_iv[0] ^ ret_iv[1];
1494 ret_iv[3] = ret_iv[0] + ret_iv[2];
1496 /* Increment 32-bit packet counter */
1497 SILC_GET32_MSB(pc1, iv + 8);
1499 SILC_PUT32_MSB(pc1, ret_iv + 4);
1501 SILC_LOG_HEXDUMP(("IV"), ret_iv, 8);
1503 /* Set new nonce to counter block */
1504 memcpy(iv + 4, ret_iv, 8);
1506 /* Increment 64-bit packet counter */
1507 SILC_GET32_MSB(pc1, iv + 4);
1508 SILC_GET32_MSB(pc2, iv + 8);
1511 SILC_PUT32_MSB(pc1, iv + 4);
1512 SILC_PUT32_MSB(pc2, iv + 8);
1515 SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1518 /* Internal routine to assemble outgoing packet. Assembles and encryptes
1519 the packet. The silc_packet_stream_write needs to be called to send it
1520 after this returns TRUE. */
1522 static inline SilcBool silc_packet_send_raw(SilcPacketStream stream,
1523 SilcPacketType type,
1524 SilcPacketFlags flags,
1525 SilcIdType src_id_type,
1526 unsigned char *src_id,
1527 SilcUInt32 src_id_len,
1528 SilcIdType dst_id_type,
1529 unsigned char *dst_id,
1530 SilcUInt32 dst_id_len,
1531 const unsigned char *data,
1532 SilcUInt32 data_len,
1536 unsigned char tmppad[SILC_PACKET_MAX_PADLEN], iv[33], psn[4];
1537 int block_len = (cipher ? silc_cipher_get_block_len(cipher) : 0);
1538 int i, enclen, truelen, padlen = 0, ivlen = 0, psnlen = 0;
1540 SilcBufferStruct packet;
1542 SILC_LOG_DEBUG(("Sending packet %s (%d) flags %d, src %d dst %d, "
1543 "data len %d", silc_get_packet_name(type), stream->send_psn,
1544 flags, src_id_type, dst_id_type, data_len));
1546 /* Get the true length of the packet. This is saved as payload length
1547 into the packet header. This does not include the length of the
1549 data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
1550 src_id_len + dst_id_len));
1551 enclen = truelen = (data_len + SILC_PACKET_HEADER_LEN +
1552 src_id_len + dst_id_len);
1554 /* If using CTR mode, increment the counter */
1555 ctr = (cipher && silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR);
1557 silc_packet_send_ctr_increment(stream, cipher, iv + 1);
1559 /* If IV is included, the SID, IV and sequence number is added to packet */
1560 if (stream->iv_included && cipher) {
1561 psnlen = sizeof(psn);
1563 iv[0] = stream->sid;
1566 /* If IV is included, the SID, IV and sequence number is added to packet */
1567 if (stream->iv_included && cipher) {
1568 psnlen = sizeof(psn);
1569 ivlen = block_len + 1;
1570 iv[0] = stream->sid;
1571 memcpy(iv + 1, silc_cipher_get_iv(cipher), block_len);
1575 /* We automatically figure out the packet structure from the packet
1576 type and flags, and calculate correct length. Private messages with
1577 private keys and channel messages are special packets as their
1578 payload is encrypted already. */
1579 if (type == SILC_PACKET_PRIVATE_MESSAGE &&
1580 flags & SILC_PACKET_FLAG_PRIVMSG_KEY) {
1581 /* Padding is calculated from header + IDs */
1583 SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1584 psnlen), block_len, padlen);
1586 /* Length to encrypt, header + IDs + padding. */
1587 enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1590 } else if (type == SILC_PACKET_CHANNEL_MESSAGE) {
1591 if (stream->sc->engine->local_is_router && stream->is_router) {
1592 /* Channel messages between routers are encrypted as normal packets.
1593 Padding is calculated from true length of the packet. */
1595 SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
1597 enclen += padlen + psnlen;
1599 /* Padding is calculated from header + IDs */
1601 SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1602 psnlen), block_len, padlen);
1604 /* Length to encrypt, header + IDs + padding. */
1605 enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1609 /* Padding is calculated from true length of the packet */
1610 if (flags & SILC_PACKET_FLAG_LONG_PAD)
1611 SILC_PACKET_PADLEN_MAX(truelen + psnlen, block_len, padlen);
1613 SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
1615 enclen += padlen + psnlen;
1618 /* Remove implementation specific flags */
1619 flags &= ~(SILC_PACKET_FLAG_LONG_PAD);
1621 /* Get random padding */
1622 for (i = 0; i < padlen; i++) tmppad[i] =
1623 silc_rng_get_byte_fast(stream->sc->engine->rng);
1625 silc_mutex_lock(stream->lock);
1627 /* Get packet pointer from the outgoing buffer */
1628 if (silc_unlikely(!silc_packet_send_prepare(stream, truelen + padlen + ivlen
1629 + psnlen, hmac, &packet))) {
1630 silc_mutex_unlock(stream->lock);
1634 SILC_PUT32_MSB(stream->send_psn, psn);
1636 /* Create the packet. This creates the SILC header, adds padding, and
1637 the actual packet data. */
1638 i = silc_buffer_format(&packet,
1639 SILC_STR_DATA(iv, ivlen),
1640 SILC_STR_DATA(psn, psnlen),
1641 SILC_STR_UI_SHORT(truelen),
1642 SILC_STR_UI_CHAR(flags),
1643 SILC_STR_UI_CHAR(type),
1644 SILC_STR_UI_CHAR(padlen),
1645 SILC_STR_UI_CHAR(0),
1646 SILC_STR_UI_CHAR(src_id_len),
1647 SILC_STR_UI_CHAR(dst_id_len),
1648 SILC_STR_UI_CHAR(src_id_type),
1649 SILC_STR_DATA(src_id, src_id_len),
1650 SILC_STR_UI_CHAR(dst_id_type),
1651 SILC_STR_DATA(dst_id, dst_id_len),
1652 SILC_STR_DATA(tmppad, padlen),
1653 SILC_STR_DATA(data, data_len),
1655 if (silc_unlikely(i < 0)) {
1656 silc_mutex_unlock(stream->lock);
1660 SILC_LOG_HEXDUMP(("Assembled packet, len %d", silc_buffer_len(&packet)),
1661 silc_buffer_data(&packet), silc_buffer_len(&packet));
1663 /* Encrypt the packet */
1664 if (silc_likely(cipher)) {
1665 SILC_LOG_DEBUG(("Encrypting packet"));
1666 silc_cipher_set_iv(cipher, NULL);
1667 if (silc_unlikely(!silc_cipher_encrypt(cipher, packet.data + ivlen,
1668 packet.data + ivlen, enclen,
1670 SILC_LOG_ERROR(("Packet encryption failed"));
1671 silc_mutex_unlock(stream->lock);
1677 if (silc_likely(hmac)) {
1680 /* MAC is computed from the entire encrypted packet data, and put
1681 to the end of the packet. */
1682 silc_hmac_init(hmac);
1683 silc_hmac_update(hmac, psn, sizeof(psn));
1684 silc_hmac_update(hmac, packet.data, silc_buffer_len(&packet));
1685 silc_hmac_final(hmac, packet.tail, &mac_len);
1686 silc_buffer_pull_tail(&packet, mac_len);
1693 /* Sends a packet */
1695 SilcBool silc_packet_send(SilcPacketStream stream,
1696 SilcPacketType type, SilcPacketFlags flags,
1697 const unsigned char *data, SilcUInt32 data_len)
1701 ret = silc_packet_send_raw(stream, type, flags,
1702 stream->src_id_type,
1705 stream->dst_id_type,
1709 stream->send_key[0],
1710 stream->send_hmac[0]);
1712 /* Write the packet to the stream */
1713 return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1716 /* Sends a packet, extended routine */
1718 SilcBool silc_packet_send_ext(SilcPacketStream stream,
1719 SilcPacketType type, SilcPacketFlags flags,
1720 SilcIdType src_id_type, void *src_id,
1721 SilcIdType dst_id_type, void *dst_id,
1722 const unsigned char *data, SilcUInt32 data_len,
1723 SilcCipher cipher, SilcHmac hmac)
1725 unsigned char src_id_data[32], dst_id_data[32];
1726 SilcUInt32 src_id_len, dst_id_len;
1730 if (!silc_id_id2str(src_id, src_id_type, src_id_data,
1731 sizeof(src_id_data), &src_id_len))
1734 if (!silc_id_id2str(dst_id, dst_id_type, dst_id_data,
1735 sizeof(dst_id_data), &dst_id_len))
1738 ret = silc_packet_send_raw(stream, type, flags,
1739 src_id ? src_id_type : stream->src_id_type,
1740 src_id ? src_id_data : stream->src_id,
1741 src_id ? src_id_len : stream->src_id_len,
1742 dst_id ? dst_id_type : stream->dst_id_type,
1743 dst_id ? dst_id_data : stream->dst_id,
1744 dst_id ? dst_id_len : stream->dst_id_len,
1746 cipher ? cipher : stream->send_key[0],
1747 hmac ? hmac : stream->send_hmac[0]);
1749 /* Write the packet to the stream */
1750 return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1753 /* Sends packet after formatting the arguments to buffer */
1755 SilcBool silc_packet_send_va(SilcPacketStream stream,
1756 SilcPacketType type, SilcPacketFlags flags, ...)
1758 SilcBufferStruct buf;
1762 va_start(va, flags);
1764 memset(&buf, 0, sizeof(buf));
1765 if (silc_buffer_format_vp(&buf, va) < 0) {
1770 ret = silc_packet_send(stream, type, flags, silc_buffer_data(&buf),
1771 silc_buffer_len(&buf));
1773 silc_buffer_purge(&buf);
1779 /* Sends packet after formatting the arguments to buffer, extended routine */
1781 SilcBool silc_packet_send_va_ext(SilcPacketStream stream,
1782 SilcPacketType type, SilcPacketFlags flags,
1783 SilcIdType src_id_type, void *src_id,
1784 SilcIdType dst_id_type, void *dst_id,
1785 SilcCipher cipher, SilcHmac hmac, ...)
1787 SilcBufferStruct buf;
1793 memset(&buf, 0, sizeof(buf));
1794 if (silc_buffer_format_vp(&buf, va) < 0) {
1799 ret = silc_packet_send_ext(stream, type, flags, src_id_type, src_id,
1800 dst_id_type, dst_id, silc_buffer_data(&buf),
1801 silc_buffer_len(&buf), cipher, hmac);
1803 silc_buffer_purge(&buf);
1809 /***************************** Packet Receiving *****************************/
1811 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. */
1813 static inline SilcBool silc_packet_check_mac(SilcHmac hmac,
1814 const unsigned char *data,
1815 SilcUInt32 data_len,
1816 const unsigned char *packet_mac,
1817 const unsigned char *packet_seq,
1818 SilcUInt32 sequence)
1821 if (silc_likely(hmac)) {
1822 unsigned char mac[32], psn[4];
1825 SILC_LOG_DEBUG(("Verifying MAC"));
1827 /* Compute HMAC of packet */
1828 silc_hmac_init(hmac);
1831 SILC_PUT32_MSB(sequence, psn);
1832 silc_hmac_update(hmac, psn, 4);
1834 silc_hmac_update(hmac, packet_seq, 4);
1836 silc_hmac_update(hmac, data, data_len);
1837 silc_hmac_final(hmac, mac, &mac_len);
1839 /* Compare the MAC's */
1840 if (silc_unlikely(memcmp(packet_mac, mac, mac_len))) {
1841 SILC_LOG_DEBUG(("MAC failed"));
1845 SILC_LOG_DEBUG(("MAC is Ok"));
1851 /* Increments/sets counter when decrypting in counter mode. */
1853 static inline void silc_packet_receive_ctr_increment(SilcPacketStream stream,
1855 unsigned char *packet_iv)
1857 SilcUInt32 pc1, pc2;
1859 /* If IV Included flag, set the IV from packet to block counter. */
1860 if (stream->iv_included) {
1861 memcpy(iv + 4, packet_iv, 8);
1863 /* Increment 64-bit packet counter. */
1864 SILC_GET32_MSB(pc1, iv + 4);
1865 SILC_GET32_MSB(pc2, iv + 8);
1868 SILC_PUT32_MSB(pc1, iv + 4);
1869 SILC_PUT32_MSB(pc2, iv + 8);
1872 /* Reset block counter */
1873 memset(iv + 12, 0, 4);
1875 SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1878 /* Return special packet's encrypted length */
1880 static inline int silc_packet_special_len(unsigned char *data)
1882 return (((SilcUInt8)data[4] + (SilcUInt8)data[6] +
1883 (SilcUInt8)data[7] + SILC_PACKET_HEADER_LEN));
1886 /* Decrypts SILC packet. Handles both normal and special packet decryption.
1887 Return 0 when packet is normal and 1 when it it special, -1 on error. */
1889 static inline int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
1890 SilcUInt32 sequence, SilcBuffer buffer,
1893 if (normal == TRUE) {
1894 if (silc_likely(cipher)) {
1895 /* Decrypt rest of the packet */
1896 SILC_LOG_DEBUG(("Decrypting the packet"));
1897 if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1899 silc_buffer_len(buffer), NULL)))
1905 /* Decrypt rest of the header plus padding */
1906 if (silc_likely(cipher)) {
1908 SilcUInt32 block_len = silc_cipher_get_block_len(cipher);
1910 SILC_LOG_DEBUG(("Decrypting the header"));
1912 /* Padding length + src id len + dst id len + header length - 16
1913 bytes already decrypted, gives the rest of the encrypted packet */
1914 silc_buffer_push(buffer, block_len);
1915 len = silc_packet_special_len(buffer->data) - block_len;
1916 silc_buffer_pull(buffer, block_len);
1918 if (silc_unlikely(len > silc_buffer_len(buffer))) {
1919 SILC_LOG_ERROR(("Garbage in header of packet, bad packet length, "
1923 if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1924 buffer->data, len, NULL)))
1932 /* Parses the packet. This is called when a whole packet is ready to be
1933 parsed. The buffer sent must be already decrypted before calling this
1936 static inline SilcBool silc_packet_parse(SilcPacket packet)
1938 SilcBuffer buffer = &packet->buffer;
1939 SilcUInt8 padlen = (SilcUInt8)buffer->data[4];
1940 SilcUInt8 src_id_len, dst_id_len, src_id_type, dst_id_type;
1943 SILC_LOG_DEBUG(("Parsing incoming packet"));
1945 /* Parse the buffer. This parses the SILC header of the packet. */
1946 ret = silc_buffer_unformat(buffer,
1949 SILC_STR_UI_CHAR(&src_id_len),
1950 SILC_STR_UI_CHAR(&dst_id_len),
1951 SILC_STR_UI_CHAR(&src_id_type),
1953 if (silc_unlikely(ret == -1)) {
1954 if (!packet->stream->udp &&
1955 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1956 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1960 if (silc_unlikely(src_id_len > SILC_PACKET_MAX_ID_LEN ||
1961 dst_id_len > SILC_PACKET_MAX_ID_LEN)) {
1962 if (!packet->stream->udp &&
1963 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1964 SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
1965 packet->src_id_len, packet->dst_id_len));
1969 ret = silc_buffer_unformat(buffer,
1971 SILC_STR_DATA(&packet->src_id, src_id_len),
1972 SILC_STR_UI_CHAR(&dst_id_type),
1973 SILC_STR_DATA(&packet->dst_id, dst_id_len),
1974 SILC_STR_OFFSET(padlen),
1976 if (silc_unlikely(ret == -1)) {
1977 if (!packet->stream->udp &&
1978 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1979 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1983 if (silc_unlikely(src_id_type > SILC_ID_CHANNEL ||
1984 dst_id_type > SILC_ID_CHANNEL)) {
1985 if (!packet->stream->udp &&
1986 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1987 SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
1988 src_id_type, dst_id_type));
1992 packet->src_id_len = src_id_len;
1993 packet->dst_id_len = dst_id_len;
1994 packet->src_id_type = src_id_type;
1995 packet->dst_id_type = dst_id_type;
1997 SILC_LOG_HEXDUMP(("Parsed packet, len %d", silc_buffer_headlen(buffer) +
1998 silc_buffer_len(buffer)), buffer->head,
1999 silc_buffer_headlen(buffer) + silc_buffer_len(buffer));
2001 SILC_LOG_DEBUG(("Incoming packet type: %d (%s), flags %d", packet->type,
2002 silc_get_packet_name(packet->type), packet->flags));
2007 /* Dispatch packet to application. Called with stream->lock locked.
2008 Returns FALSE if the stream was destroyed while dispatching a packet. */
2010 static SilcBool silc_packet_dispatch(SilcPacket packet)
2012 SilcPacketStream stream = packet->stream;
2013 SilcPacketProcess p;
2014 SilcBool default_sent = FALSE;
2017 /* Dispatch packet to all packet processors that want it */
2019 if (silc_likely(!stream->process)) {
2020 /* Send to default processor as no others exist */
2021 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
2022 silc_mutex_unlock(stream->lock);
2023 if (silc_unlikely(!stream->sc->engine->callbacks->
2024 packet_receive(stream->sc->engine, stream, packet,
2025 stream->sc->engine->callback_context,
2026 stream->stream_context)))
2027 silc_packet_free(packet);
2028 silc_mutex_lock(stream->lock);
2029 return stream->destroyed == FALSE;
2032 silc_dlist_start(stream->process);
2033 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END) {
2035 /* If priority is 0 or less, we send to default processor first
2036 because default processor has 0 priority */
2037 if (!default_sent && p->priority <= 0) {
2038 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
2039 default_sent = TRUE;
2040 silc_mutex_unlock(stream->lock);
2041 if (stream->sc->engine->callbacks->
2042 packet_receive(stream->sc->engine, stream, packet,
2043 stream->sc->engine->callback_context,
2044 stream->stream_context)) {
2045 silc_mutex_lock(stream->lock);
2046 return stream->destroyed == FALSE;
2048 silc_mutex_lock(stream->lock);
2051 /* Send to processor */
2053 /* Send all packet types */
2054 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
2055 silc_mutex_unlock(stream->lock);
2056 if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
2057 p->callback_context,
2058 stream->stream_context)) {
2059 silc_mutex_lock(stream->lock);
2060 return stream->destroyed == FALSE;
2062 silc_mutex_lock(stream->lock);
2064 /* Send specific types */
2065 for (pt = p->types; *pt; pt++) {
2066 if (*pt != packet->type)
2068 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
2069 silc_mutex_unlock(stream->lock);
2070 if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
2071 p->callback_context,
2072 stream->stream_context)) {
2073 silc_mutex_lock(stream->lock);
2074 return stream->destroyed == FALSE;
2076 silc_mutex_lock(stream->lock);
2082 if (!default_sent) {
2083 /* Send to default processor as it has not been sent yet */
2084 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
2085 silc_mutex_unlock(stream->lock);
2086 if (stream->sc->engine->callbacks->
2087 packet_receive(stream->sc->engine, stream, packet,
2088 stream->sc->engine->callback_context,
2089 stream->stream_context)) {
2090 silc_mutex_lock(stream->lock);
2091 return stream->destroyed == FALSE;
2093 silc_mutex_lock(stream->lock);
2096 /* If we got here, no one wanted the packet, so drop it */
2097 silc_packet_free(packet);
2098 return stream->destroyed == FALSE;
2101 /* Process incoming data and parse packets. Called with stream->lock
2104 static void silc_packet_read_process(SilcPacketStream stream)
2110 SilcUInt8 sid, flags, type;
2111 SilcUInt16 packetlen;
2112 SilcUInt32 paddedlen, mac_len, block_len, ivlen, psnlen;
2113 unsigned char tmp[SILC_PACKET_MIN_HEADER_LEN], *header;
2114 unsigned char iv[SILC_CIPHER_MAX_IV_SIZE], *packet_seq = NULL;
2118 /* Get inbuf. If there is already some data for this stream in the buffer
2119 we already have it. Otherwise get the current one from list, it will
2120 include the data. */
2121 inbuf = stream->inbuf;
2123 silc_dlist_start(stream->sc->inbufs);
2124 inbuf = silc_dlist_get(stream->sc->inbufs);
2127 /* Parse the packets from the data */
2128 while (silc_buffer_len(inbuf) > 0) {
2130 cipher = stream->receive_key[0];
2131 hmac = stream->receive_hmac[0];
2134 if (silc_unlikely(silc_buffer_len(inbuf) <
2135 (stream->iv_included ? SILC_PACKET_MIN_HEADER_LEN_IV :
2136 SILC_PACKET_MIN_HEADER_LEN))) {
2137 SILC_LOG_DEBUG(("Partial packet in queue, waiting for the rest"));
2138 silc_dlist_del(stream->sc->inbufs, inbuf);
2139 stream->inbuf = inbuf;
2143 if (silc_likely(hmac))
2144 mac_len = silc_hmac_len(hmac);
2148 /* Decrypt first block of the packet to get the length field out */
2149 if (silc_likely(cipher)) {
2150 block_len = silc_cipher_get_block_len(cipher);
2152 if (stream->iv_included) {
2153 /* SID, IV and sequence number is included in the ciphertext */
2154 sid = (SilcUInt8)inbuf->data[0];
2156 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR) {
2157 /* Set the CTR mode IV from packet to counter block */
2158 memcpy(iv, silc_cipher_get_iv(cipher), block_len);
2159 silc_packet_receive_ctr_increment(stream, iv, inbuf->data + 1);
2162 /* Get IV from packet */
2163 memcpy(iv, inbuf->data + 1, block_len);
2164 ivlen = block_len + 1;
2168 /* Check SID, and get correct decryption key */
2169 if (sid != stream->sid) {
2170 /* If SID is recent get the previous key and use it */
2171 if (sid > 0 && stream->sid > 0 && stream->sid - 1 == sid &&
2172 stream->receive_key[1] && !stream->receive_hmac[1]) {
2173 cipher = stream->receive_key[1];
2174 hmac = stream->receive_hmac[1];
2176 /* The SID is unknown, drop rest of the data in buffer */
2177 SILC_LOG_DEBUG(("Unknown Security ID %d in packet, expected %d",
2179 silc_mutex_unlock(stream->lock);
2180 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_UNKNOWN_SID);
2181 silc_mutex_lock(stream->lock);
2186 memcpy(iv, silc_cipher_get_iv(cipher), block_len);
2188 /* If using CTR mode, increment the counter */
2189 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR)
2190 silc_packet_receive_ctr_increment(stream, iv, NULL);
2193 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR)
2194 silc_cipher_set_iv(cipher, NULL);
2195 silc_cipher_decrypt(cipher, inbuf->data + ivlen, tmp, block_len, iv);
2198 if (stream->iv_included) {
2199 /* Take sequence number from packet */
2200 packet_seq = header;
2204 /* Unencrypted packet */
2205 block_len = SILC_PACKET_MIN_HEADER_LEN;
2206 header = inbuf->data;
2209 /* Get packet length and full packet length with padding */
2210 SILC_PACKET_LENGTH(header, packetlen, paddedlen);
2212 /* Parse packet header */
2213 flags = (SilcPacketFlags)header[2];
2214 type = (SilcPacketType)header[3];
2216 if (stream->sc->engine->local_is_router) {
2217 if (type == SILC_PACKET_PRIVATE_MESSAGE &&
2218 (flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
2220 else if (type != SILC_PACKET_CHANNEL_MESSAGE ||
2221 (type == SILC_PACKET_CHANNEL_MESSAGE &&
2222 stream->is_router == TRUE))
2225 if (type == SILC_PACKET_PRIVATE_MESSAGE &&
2226 (flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
2228 else if (type != SILC_PACKET_CHANNEL_MESSAGE)
2232 /* Padding sanity checks */
2233 if (cipher && silc_cipher_get_mode(cipher) != SILC_CIPHER_MODE_CTR &&
2234 ((normal && paddedlen % block_len != 0) ||
2235 (!normal && silc_packet_special_len(header) % block_len != 0))) {
2236 SILC_LOG_DEBUG(("Packet length %d not multiple by cipher block length",
2238 silc_mutex_unlock(stream->lock);
2239 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2240 silc_mutex_lock(stream->lock);
2241 memset(tmp, 0, sizeof(tmp));
2245 if (silc_buffer_len(inbuf) < paddedlen + ivlen + mac_len) {
2246 SILC_LOG_DEBUG(("Received partial packet, waiting for the rest "
2248 paddedlen + mac_len - silc_buffer_len(inbuf)));
2249 memset(tmp, 0, sizeof(tmp));
2250 silc_dlist_del(stream->sc->inbufs, inbuf);
2251 stream->inbuf = inbuf;
2255 /* Check MAC of the packet */
2256 if (silc_unlikely(!silc_packet_check_mac(hmac, inbuf->data,
2258 inbuf->data + ivlen +
2259 paddedlen, packet_seq,
2260 stream->receive_psn))) {
2261 silc_mutex_unlock(stream->lock);
2262 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MAC_FAILED);
2263 silc_mutex_lock(stream->lock);
2264 memset(tmp, 0, sizeof(tmp));
2269 if (silc_unlikely(packetlen < SILC_PACKET_MIN_LEN)) {
2270 if (!stream->udp && !silc_socket_stream_is_udp(stream->stream, NULL))
2271 SILC_LOG_ERROR(("Received too short packet"));
2272 silc_mutex_unlock(stream->lock);
2273 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2274 silc_mutex_lock(stream->lock);
2275 memset(tmp, 0, sizeof(tmp));
2280 packet = silc_packet_alloc(stream->sc->engine);
2281 if (silc_unlikely(!packet)) {
2282 silc_mutex_unlock(stream->lock);
2283 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2284 silc_mutex_lock(stream->lock);
2285 memset(tmp, 0, sizeof(tmp));
2288 packet->stream = stream;
2289 packet->flags = flags;
2290 packet->type = type;
2292 /* Allocate more space to packet buffer, if needed */
2293 if (silc_unlikely(silc_buffer_truelen(&packet->buffer) < paddedlen)) {
2294 if (!silc_buffer_realloc(&packet->buffer,
2295 silc_buffer_truelen(&packet->buffer) +
2297 silc_buffer_truelen(&packet->buffer)))) {
2298 silc_mutex_unlock(stream->lock);
2299 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2300 silc_mutex_lock(stream->lock);
2301 silc_packet_free(packet);
2302 memset(tmp, 0, sizeof(tmp));
2307 SILC_LOG_HEXDUMP(("Incoming packet (%d) len %d",
2308 stream->receive_psn, paddedlen + ivlen + mac_len),
2309 inbuf->data, paddedlen + ivlen + mac_len);
2311 /* Put the decrypted part, and rest of the encrypted data, and decrypt */
2312 silc_buffer_pull_tail(&packet->buffer, paddedlen);
2313 silc_buffer_put(&packet->buffer, header, block_len - psnlen);
2314 silc_buffer_pull(&packet->buffer, block_len - psnlen);
2315 silc_buffer_put(&packet->buffer, (inbuf->data + ivlen +
2316 psnlen + (block_len - psnlen)),
2317 paddedlen - ivlen - psnlen - (block_len - psnlen));
2318 if (silc_likely(cipher)) {
2319 silc_cipher_set_iv(cipher, iv);
2320 ret = silc_packet_decrypt(cipher, hmac, stream->receive_psn,
2321 &packet->buffer, normal);
2322 if (silc_unlikely(ret < 0)) {
2323 silc_mutex_unlock(stream->lock);
2324 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_DECRYPTION_FAILED);
2325 silc_mutex_lock(stream->lock);
2326 silc_packet_free(packet);
2327 memset(tmp, 0, sizeof(tmp));
2331 stream->receive_psn++;
2333 silc_buffer_push(&packet->buffer, block_len);
2335 /* Pull the packet from inbuf thus we'll get the next one in the inbuf. */
2336 silc_buffer_pull(inbuf, paddedlen + mac_len);
2338 /* Parse the packet */
2339 if (silc_unlikely(!silc_packet_parse(packet))) {
2340 silc_mutex_unlock(stream->lock);
2341 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2342 silc_mutex_lock(stream->lock);
2343 silc_packet_free(packet);
2344 memset(tmp, 0, sizeof(tmp));
2348 /* Dispatch the packet to application */
2349 if (!silc_packet_dispatch(packet))
2354 /* Add inbuf back to free list, if we owned it. */
2355 if (stream->inbuf) {
2356 silc_dlist_add(stream->sc->inbufs, inbuf);
2357 stream->inbuf = NULL;
2360 silc_buffer_reset(inbuf);
2363 /****************************** Packet Waiting ******************************/
2365 /* Packet wait receive callback */
2367 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2368 SilcPacketStream stream,
2370 void *callback_context,
2371 void *stream_context);
2373 /* Packet waiting callbacks */
2374 static const SilcPacketCallbacks silc_packet_wait_cbs =
2376 silc_packet_wait_packet_receive, NULL, NULL
2379 /* Packet waiting context */
2381 SilcMutex wait_lock;
2383 SilcList packet_queue;
2384 unsigned char id[28];
2385 unsigned int id_type : 2;
2386 unsigned int id_len : 5;
2387 unsigned int stopped : 1;
2390 /* Packet wait receive callback */
2393 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2394 SilcPacketStream stream,
2396 void *callback_context,
2397 void *stream_context)
2399 SilcPacketWait pw = callback_context;
2401 /* If source ID is specified check for it */
2403 if (pw->id_type != packet->src_id_type ||
2404 memcmp(pw->id, packet->src_id, pw->id_len))
2408 /* Signal the waiting thread for a new packet */
2409 silc_mutex_lock(pw->wait_lock);
2411 if (silc_unlikely(pw->stopped)) {
2412 silc_mutex_unlock(pw->wait_lock);
2416 silc_list_add(pw->packet_queue, packet);
2417 silc_cond_broadcast(pw->wait_cond);
2419 silc_mutex_unlock(pw->wait_lock);
2424 /* Initialize packet waiting */
2426 void *silc_packet_wait_init(SilcPacketStream stream,
2427 const SilcID *source_id, ...)
2433 pw = silc_calloc(1, sizeof(*pw));
2437 /* Allocate mutex and conditional variable */
2438 if (!silc_mutex_alloc(&pw->wait_lock)) {
2442 if (!silc_cond_alloc(&pw->wait_cond)) {
2443 silc_mutex_free(pw->wait_lock);
2448 /* Link to the packet stream for the requested packet types */
2449 va_start(ap, source_id);
2450 ret = silc_packet_stream_link_va(stream, &silc_packet_wait_cbs, pw,
2454 silc_cond_free(pw->wait_cond);
2455 silc_mutex_free(pw->wait_lock);
2460 /* Initialize packet queue */
2461 silc_list_init(pw->packet_queue, struct SilcPacketStruct, next);
2465 silc_id_id2str(SILC_ID_GET_ID(*source_id), source_id->type, pw->id,
2466 sizeof(pw->id), &id_len);
2467 pw->id_type = source_id->type;
2468 pw->id_len = id_len;
2474 /* Uninitialize packet waiting */
2476 void silc_packet_wait_uninit(void *waiter, SilcPacketStream stream)
2478 SilcPacketWait pw = waiter;
2481 /* Signal any threads to stop waiting */
2482 silc_mutex_lock(pw->wait_lock);
2484 silc_cond_broadcast(pw->wait_cond);
2485 silc_mutex_unlock(pw->wait_lock);
2486 silc_thread_yield();
2488 /* Re-acquire lock and free resources */
2489 silc_mutex_lock(pw->wait_lock);
2490 silc_packet_stream_unlink(stream, &silc_packet_wait_cbs, pw);
2492 /* Free any remaining packets */
2493 silc_list_start(pw->packet_queue);
2494 while ((packet = silc_list_get(pw->packet_queue)) != SILC_LIST_END)
2495 silc_packet_free(packet);
2497 silc_mutex_unlock(pw->wait_lock);
2498 silc_cond_free(pw->wait_cond);
2499 silc_mutex_free(pw->wait_lock);
2503 /* Blocks thread until a packet has been received. */
2505 int silc_packet_wait(void *waiter, int timeout, SilcPacket *return_packet)
2507 SilcPacketWait pw = waiter;
2508 SilcBool ret = FALSE;
2510 silc_mutex_lock(pw->wait_lock);
2512 /* Wait here until packet has arrived */
2513 while (silc_list_count(pw->packet_queue) == 0) {
2514 if (silc_unlikely(pw->stopped)) {
2515 silc_mutex_unlock(pw->wait_lock);
2518 ret = silc_cond_timedwait(pw->wait_cond, pw->wait_lock, timeout);
2522 silc_list_start(pw->packet_queue);
2523 *return_packet = silc_list_get(pw->packet_queue);
2524 silc_list_del(pw->packet_queue, *return_packet);
2526 silc_mutex_unlock(pw->wait_lock);
2528 return ret == TRUE ? 1 : 0;
2531 /************************** Packet Stream Wrapper ***************************/
2533 /* Packet stream wrapper receive callback */
2535 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2536 SilcPacketStream stream,
2538 void *callback_context,
2539 void *stream_context);
2541 const SilcStreamOps silc_packet_stream_ops;
2543 /* Packet stream wrapper context */
2545 const SilcStreamOps *ops;
2546 SilcPacketStream stream;
2548 void *waiter; /* Waiter context in blocking mode */
2549 SilcPacketWrapCoder coder;
2550 void *coder_context;
2552 SilcStreamNotifier callback;
2555 SilcPacketType type;
2556 SilcPacketFlags flags;
2557 unsigned int closed : 1;
2558 unsigned int blocking : 1;
2559 unsigned int read_more : 1;
2560 } *SilcPacketWrapperStream;
2562 /* Packet wrapper callbacks */
2563 static const SilcPacketCallbacks silc_packet_wrap_cbs =
2565 silc_packet_wrap_packet_receive, NULL, NULL
2568 /* Packet stream wrapper receive callback, non-blocking mode */
2571 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2572 SilcPacketStream stream,
2574 void *callback_context,
2575 void *stream_context)
2577 SilcPacketWrapperStream pws = callback_context;
2579 if (pws->closed || !pws->callback)
2582 silc_mutex_lock(pws->lock);
2583 silc_list_add(pws->in_queue, packet);
2584 silc_mutex_unlock(pws->lock);
2586 /* Call notifier callback */
2587 pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2592 /* Task callback to notify more data is available for reading */
2594 SILC_TASK_CALLBACK(silc_packet_wrap_read_more)
2596 SilcPacketWrapperStream pws = context;
2598 if (pws->closed || !pws->callback)
2601 /* Call notifier callback */
2602 pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2605 /* Read SILC packet */
2607 int silc_packet_wrap_read(SilcStream stream, unsigned char *buf,
2610 SilcPacketWrapperStream pws = stream;
2612 SilcBool read_more = FALSE;
2618 if (pws->blocking) {
2619 /* Block until packet is received */
2620 if ((silc_packet_wait(pws->waiter, 0, &packet)) < 0)
2625 /* Non-blocking mode */
2626 silc_mutex_lock(pws->lock);
2627 if (!silc_list_count(pws->in_queue)) {
2628 silc_mutex_unlock(pws->lock);
2632 silc_list_start(pws->in_queue);
2633 packet = silc_list_get(pws->in_queue);
2634 silc_list_del(pws->in_queue, packet);
2635 silc_mutex_unlock(pws->lock);
2638 /* Call decoder if set */
2639 if (pws->coder && !pws->read_more)
2640 pws->coder(stream, SILC_STREAM_CAN_READ, &packet->buffer,
2641 pws->coder_context);
2643 len = silc_buffer_len(&packet->buffer);
2644 if (len > buf_len) {
2650 memcpy(buf, packet->buffer.data, len);
2652 if (read_more && !pws->blocking) {
2653 /* More data will be available (in blocking mode not supported). */
2654 silc_buffer_pull(&packet->buffer, len);
2655 silc_list_insert(pws->in_queue, NULL, packet);
2656 silc_schedule_task_add_timeout(pws->stream->sc->schedule,
2657 silc_packet_wrap_read_more, pws, 0, 0);
2658 pws->read_more = TRUE;
2662 pws->read_more = FALSE;
2663 silc_packet_free(packet);
2667 /* Write SILC packet */
2669 int silc_packet_wrap_write(SilcStream stream, const unsigned char *data,
2670 SilcUInt32 data_len)
2672 SilcPacketWrapperStream pws = stream;
2673 SilcBool ret = FALSE;
2675 /* Call encoder if set */
2677 silc_buffer_reset(pws->encbuf);
2678 ret = pws->coder(stream, SILC_STREAM_CAN_WRITE, pws->encbuf,
2679 pws->coder_context);
2682 /* Send the SILC packet */
2684 if (!silc_packet_send_va(pws->stream, pws->type, pws->flags,
2685 SILC_STR_DATA(silc_buffer_data(pws->encbuf),
2686 silc_buffer_len(pws->encbuf)),
2687 SILC_STR_DATA(data, data_len),
2691 if (!silc_packet_send(pws->stream, pws->type, pws->flags, data, data_len))
2700 SilcBool silc_packet_wrap_close(SilcStream stream)
2702 SilcPacketWrapperStream pws = stream;
2707 if (pws->blocking) {
2708 /* Close packet waiter */
2709 silc_packet_wait_uninit(pws->waiter, pws->stream);
2713 silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2720 /* Destroy wrapper stream */
2722 void silc_packet_wrap_destroy(SilcStream stream)
2725 SilcPacketWrapperStream pws = stream;
2728 SILC_LOG_DEBUG(("Destroying wrapped packet stream %p", pws));
2730 silc_stream_close(stream);
2731 silc_list_start(pws->in_queue);
2732 while ((packet = silc_list_get(pws->in_queue)))
2733 silc_packet_free(packet);
2735 silc_mutex_free(pws->lock);
2737 silc_buffer_free(pws->encbuf);
2738 silc_packet_stream_unref(pws->stream);
2743 /* Link stream to receive packets */
2745 SilcBool silc_packet_wrap_notifier(SilcStream stream,
2746 SilcSchedule schedule,
2747 SilcStreamNotifier callback,
2750 SilcPacketWrapperStream pws = stream;
2752 if (pws->closed || pws->blocking)
2755 /* Link to receive packets */
2757 silc_packet_stream_link(pws->stream, &silc_packet_wrap_cbs, pws,
2758 100000, pws->type, -1);
2760 silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2762 pws->callback = callback;
2763 pws->context = context;
2768 /* Return schedule */
2770 SilcSchedule silc_packet_wrap_get_schedule(SilcStream stream)
2775 /* Wraps packet stream into SilcStream. */
2777 SilcStream silc_packet_stream_wrap(SilcPacketStream stream,
2778 SilcPacketType type,
2779 SilcPacketFlags flags,
2780 SilcBool blocking_mode,
2781 SilcPacketWrapCoder coder,
2784 SilcPacketWrapperStream pws;
2786 pws = silc_calloc(1, sizeof(*pws));
2790 SILC_LOG_DEBUG(("Wrapping packet stream %p to stream %p", stream, pws));
2792 pws->ops = &silc_packet_stream_ops;
2793 pws->stream = stream;
2796 pws->blocking = blocking_mode;
2798 pws->coder_context = context;
2800 /* Allocate small amount for encoder buffer. */
2802 pws->encbuf = silc_buffer_alloc(8);
2804 if (pws->blocking) {
2805 /* Blocking mode. Use packet waiter to do the thing. */
2806 pws->waiter = silc_packet_wait_init(pws->stream, NULL, pws->type, -1);
2812 /* Non-blocking mode */
2813 silc_mutex_alloc(&pws->lock);
2814 silc_list_init(pws->in_queue, struct SilcPacketStruct, next);
2817 silc_packet_stream_ref(stream);
2819 return (SilcStream)pws;
2822 const SilcStreamOps silc_packet_stream_ops =
2824 silc_packet_wrap_read,
2825 silc_packet_wrap_write,
2826 silc_packet_wrap_close,
2827 silc_packet_wrap_destroy,
2828 silc_packet_wrap_notifier,
2829 silc_packet_wrap_get_schedule,