Merged silc_1_1_branch to trunk.
[silc.git] / lib / silccore / silcpacket.c
1 /*
2
3   silcpacket.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2007 Pekka Riikonen
8
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.
12
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.
17
18 */
19 /*
20  * Created: Fri Jul 25 18:52:14 1997
21  */
22 /* $Id$ */
23
24 #include "silc.h"
25
26 /************************** Types and definitions ***************************/
27
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. */
31 typedef struct {
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;
37
38 /* Packet engine */
39 struct SilcPacketEngineStruct {
40   SilcMutex lock;                        /* Engine lock */
41   SilcRng rng;                           /* RNG for engine */
42   SilcHashTable contexts;                /* Per scheduler contexts */
43   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;
49 };
50
51 /* Packet processor context */
52 typedef struct SilcPacketProcessStruct {
53   SilcPacketType *types;                 /* Packets to process */
54   SilcPacketCallbacks *callbacks;        /* Callbacks or NULL */
55   void *callback_context;
56   SilcInt32 priority;                    /* Priority */
57 } *SilcPacketProcess;
58
59 /* UDP remote stream tuple */
60 typedef struct {
61   char *remote_ip;                       /* Remote IP address */
62   SilcUInt16 remote_port;                /* Remote port */
63 } *SilcPacketRemoteUDP;
64
65 /* Packet stream */
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   SilcAtomic8 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 */
94 };
95
96 /* Initial size of stream buffers */
97 #define SILC_PACKET_DEFAULT_SIZE  1024
98
99 /* Header length without source and destination ID's. */
100 #define SILC_PACKET_HEADER_LEN 10
101
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
105
106 /* Maximum padding length */
107 #define SILC_PACKET_MAX_PADLEN 128
108
109 /* Default padding length */
110 #define SILC_PACKET_DEFAULT_PADLEN 16
111
112 /* Minimum packet length */
113 #define SILC_PACKET_MIN_LEN (SILC_PACKET_HEADER_LEN + 1)
114
115 /* Returns true length of the packet. */
116 #define SILC_PACKET_LENGTH(__packetdata, __ret_truelen, __ret_paddedlen) \
117 do {                                                                     \
118   SILC_GET16_MSB((__ret_truelen), (__packetdata));                       \
119   (__ret_paddedlen) = (__ret_truelen) + (SilcUInt8)(__packetdata)[4];    \
120 } while(0)
121
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)
131
132 /* Calculates the length of the padding in the packet. */
133 #define SILC_PACKET_PADLEN(__packetlen, __blocklen, __padlen)               \
134 do {                                                                        \
135   __padlen = (SILC_PACKET_DEFAULT_PADLEN - (__packetlen) %                  \
136               ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN));  \
137   if (__padlen < 8)                                                         \
138     __padlen += ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN); \
139 } while(0)
140
141 /* Returns the length of the padding up to the maximum length, which
142    is 128 bytes.*/
143 #define SILC_PACKET_PADLEN_MAX(__packetlen, __blocklen, __padlen)          \
144 do {                                                                       \
145   __padlen = (SILC_PACKET_MAX_PADLEN - (__packetlen) %                     \
146               ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN)); \
147 } while(0)
148
149 /* EOS callback */
150 #define SILC_PACKET_CALLBACK_EOS(s)                                     \
151 do {                                                                    \
152   (s)->sc->engine->callbacks->eos((s)->sc->engine, s,                   \
153                                   (s)->sc->engine->callback_context,    \
154                                   (s)->stream_context);                 \
155 } while(0)
156
157 /* Error callback */
158 #define SILC_PACKET_CALLBACK_ERROR(s, err)                              \
159 do {                                                                    \
160   (s)->sc->engine->callbacks->error((s)->sc->engine, s, err,            \
161                                     (s)->sc->engine->callback_context,  \
162                                     (s)->stream_context);               \
163 } while(0)
164
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,
168                                             SilcPacketType type,
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,
177                                             SilcUInt32 data_len,
178                                             SilcCipher cipher,
179                                             SilcHmac hmac);
180
181 /************************ Static utility functions **************************/
182
183 /* Injects packet to new stream created with silc_packet_stream_add_remote. */
184
185 SILC_TASK_CALLBACK(silc_packet_stream_inject_packet)
186 {
187   SilcPacket packet = context;
188   SilcPacketStream stream = packet->stream;
189
190   SILC_LOG_DEBUG(("Injecting packet %p to stream %p", packet, packet->stream));
191
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);
197 }
198
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. */
202
203 static inline SilcBool silc_packet_stream_write(SilcPacketStream ps,
204                                                 SilcBool no_unlock)
205 {
206   SilcStream stream;
207   SilcBool connected;
208   int i;
209
210   if (ps->udp)
211     stream = ((SilcPacketStream)ps->stream)->stream;
212   else
213     stream = ps->stream;
214
215   if (ps->udp && silc_socket_stream_is_udp(stream, &connected)) {
216     if (!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)) {
223           /* Error */
224           silc_buffer_reset(&ps->outbuf);
225           SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_WRITE);
226           return FALSE;
227         }
228
229         if (silc_unlikely(i == -1)) {
230           /* Cannot write now, write later. */
231           if (!no_unlock)
232             silc_mutex_unlock(ps->lock);
233           return TRUE;
234         }
235
236         /* Wrote data */
237         silc_buffer_pull(&ps->outbuf, i);
238       }
239
240       silc_buffer_reset(&ps->outbuf);
241       if (!no_unlock)
242         silc_mutex_unlock(ps->lock);
243
244       return TRUE;
245     }
246   }
247
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)) {
253       /* EOS */
254       silc_buffer_reset(&ps->outbuf);
255       silc_mutex_unlock(ps->lock);
256       SILC_PACKET_CALLBACK_EOS(ps);
257       return FALSE;
258     }
259
260     if (silc_unlikely(i == -2)) {
261       /* Error */
262       silc_buffer_reset(&ps->outbuf);
263       silc_mutex_unlock(ps->lock);
264       SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_WRITE);
265       return FALSE;
266     }
267
268     if (silc_unlikely(i == -1)) {
269       /* Cannot write now, write later. */
270       if (!no_unlock)
271         silc_mutex_unlock(ps->lock);
272       return TRUE;
273     }
274
275     /* Wrote data */
276     silc_buffer_pull(&ps->outbuf, i);
277   }
278
279   silc_buffer_reset(&ps->outbuf);
280   if (!no_unlock)
281     silc_mutex_unlock(ps->lock);
282
283   return TRUE;
284 }
285
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. */
291
292 static inline SilcBool silc_packet_stream_read(SilcPacketStream ps,
293                                                SilcPacketStream *ret_ps)
294 {
295   SilcStream stream = ps->stream;
296   SilcBuffer inbuf;
297   SilcBool connected;
298   int ret;
299
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
302      include the data. */
303   inbuf = ps->inbuf;
304   if (!inbuf) {
305     silc_dlist_start(ps->sc->inbufs);
306     inbuf = silc_dlist_get(ps->sc->inbufs);
307     if (!inbuf) {
308       /* Allocate new data input buffer */
309       inbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE * 65);
310       if (!inbuf) {
311         silc_mutex_unlock(ps->lock);
312         return FALSE;
313       }
314       silc_buffer_reset(inbuf);
315       silc_dlist_add(ps->sc->inbufs, inbuf);
316     }
317   }
318
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));
323
324   if (silc_socket_stream_is_udp(stream, &connected)) {
325     if (!connected) {
326       /* Connectionless UDP stream, read one UDP packet */
327       char remote_ip[64], tuple[64];
328       int remote_port;
329       SilcPacketStream remote;
330
331       ret = silc_net_udp_receive(stream, remote_ip, sizeof(remote_ip),
332                                  &remote_port, inbuf->tail,
333                                  silc_buffer_taillen(inbuf));
334
335       if (silc_unlikely(ret < 0)) {
336         silc_mutex_unlock(ps->lock);
337         if (ret == -1) {
338           /* Cannot read now, do it later. */
339           silc_buffer_pull(inbuf, silc_buffer_len(inbuf));
340           return FALSE;
341         }
342
343         /* Error */
344         silc_buffer_reset(inbuf);
345         SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_READ);
346         return FALSE;
347       }
348
349       /* See if remote packet stream exist for this sender */
350       silc_snprintf(tuple, sizeof(tuple), "%d%s", remote_port, remote_ip);
351       silc_mutex_lock(ps->sc->engine->lock);
352       if (silc_hash_table_find(ps->sc->engine->udp_remote, tuple, NULL,
353                                (void *)&remote)) {
354         silc_mutex_unlock(ps->sc->engine->lock);
355         SILC_LOG_DEBUG(("UDP packet from %s:%d for stream %p", remote_ip,
356                         remote_port, remote));
357         silc_mutex_unlock(ps->lock);
358         silc_mutex_lock(remote->lock);
359         *ret_ps = remote;
360         return TRUE;
361       }
362       silc_mutex_unlock(ps->sc->engine->lock);
363
364       /* Unknown sender */
365       if (!ps->remote_udp) {
366         ps->remote_udp = silc_calloc(1, sizeof(*ps->remote_udp));
367         if (silc_unlikely(!ps->remote_udp)) {
368           silc_mutex_unlock(ps->lock);
369           SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_NO_MEMORY);
370           return FALSE;
371         }
372       }
373
374       /* Save sender IP and port */
375       silc_free(ps->remote_udp->remote_ip);
376       ps->remote_udp->remote_ip = strdup(remote_ip);
377       ps->remote_udp->remote_port = remote_port;
378
379       silc_buffer_pull_tail(inbuf, ret);
380       return TRUE;
381     }
382   }
383
384   /* Read data from the stream */
385   ret = silc_stream_read(stream, inbuf->tail, silc_buffer_taillen(inbuf));
386   if (silc_unlikely(ret <= 0)) {
387     silc_mutex_unlock(ps->lock);
388     if (ret == 0) {
389       /* EOS */
390       silc_buffer_reset(inbuf);
391       SILC_PACKET_CALLBACK_EOS(ps);
392       return FALSE;
393     }
394
395     if (ret == -1) {
396       /* Cannot read now, do it later. */
397       silc_buffer_pull(inbuf, silc_buffer_len(inbuf));
398       return FALSE;
399     }
400
401     /* Error */
402     silc_buffer_reset(inbuf);
403     SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_READ);
404     return FALSE;
405   }
406
407   silc_buffer_pull_tail(inbuf, ret);
408   return TRUE;
409 }
410
411 /* Our stream IO notifier callback. */
412
413 static void silc_packet_stream_io(SilcStream stream, SilcStreamStatus status,
414                                   void *context)
415 {
416   SilcPacketStream remote = NULL, ps = context;
417
418   silc_mutex_lock(ps->lock);
419
420   if (silc_unlikely(ps->destroyed)) {
421     silc_mutex_unlock(ps->lock);
422     return;
423   }
424
425   switch (status) {
426   case SILC_STREAM_CAN_READ:
427     /* Reading is locked also with stream->lock because we may be reading
428        at the same time other thread is writing to same underlaying stream. */
429     SILC_LOG_DEBUG(("Reading data from stream %p, ps %p", ps->stream, ps));
430
431     /* Read data from stream */
432     if (!silc_packet_stream_read(ps, &remote))
433       return;
434
435     /* Now process the data */
436     silc_packet_stream_ref(ps);
437     if (!remote) {
438       silc_packet_read_process(ps);
439       silc_mutex_unlock(ps->lock);
440     } else {
441       silc_packet_read_process(remote);
442       silc_mutex_unlock(remote->lock);
443     }
444     silc_packet_stream_unref(ps);
445     break;
446
447   case SILC_STREAM_CAN_WRITE:
448     SILC_LOG_DEBUG(("Writing pending data to stream %p, ps %p",
449                     ps->stream, ps));
450
451     if (silc_unlikely(!silc_buffer_headlen(&ps->outbuf))) {
452       silc_mutex_unlock(ps->lock);
453       return;
454     }
455
456     /* Write pending data to stream */
457     silc_packet_stream_write(ps, FALSE);
458     break;
459
460   default:
461     silc_mutex_unlock(ps->lock);
462     break;
463   }
464 }
465
466 /* Allocate packet */
467
468 static SilcPacket silc_packet_alloc(SilcPacketEngine engine)
469 {
470   SilcPacket packet;
471
472   SILC_LOG_DEBUG(("Packet pool count %d",
473                   silc_list_count(engine->packet_pool)));
474
475   silc_mutex_lock(engine->lock);
476
477   /* Get packet from freelist or allocate new one. */
478   packet = silc_list_get(engine->packet_pool);
479   if (!packet) {
480     void *tmp;
481
482     silc_mutex_unlock(engine->lock);
483
484     packet = silc_calloc(1, sizeof(*packet));
485     if (silc_unlikely(!packet))
486       return NULL;
487
488     SILC_LOG_DEBUG(("Allocating new packet %p", packet));
489
490     tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
491     if (silc_unlikely(!tmp)) {
492       silc_free(packet);
493       return NULL;
494     }
495     silc_buffer_set(&packet->buffer, tmp, SILC_PACKET_DEFAULT_SIZE);
496     silc_buffer_reset(&packet->buffer);
497
498     return packet;
499   }
500
501   SILC_LOG_DEBUG(("Get packet %p", packet));
502
503   /* Delete from freelist */
504   silc_list_del(engine->packet_pool, packet);
505
506   silc_mutex_unlock(engine->lock);
507
508   return packet;
509 }
510
511 /* UDP remote stream hash table destructor */
512
513 static void silc_packet_engine_hash_destr(void *key, void *context,
514                                           void *user_context)
515 {
516   silc_free(key);
517 }
518
519 /* Per scheduler context hash table destructor */
520
521 static void silc_packet_engine_context_destr(void *key, void *context,
522                                              void *user_context)
523 {
524   SilcPacketEngineContext sc = context;
525   SilcBuffer buffer;
526
527   silc_dlist_start(sc->inbufs);
528   while ((buffer = silc_dlist_get(sc->inbufs))) {
529     silc_buffer_clear(buffer);
530     silc_buffer_free(buffer);
531     silc_dlist_del(sc->inbufs, buffer);
532   }
533
534   silc_dlist_uninit(sc->inbufs);
535   silc_free(sc);
536 }
537
538
539 /******************************** Packet API ********************************/
540
541 /* Allocate new packet engine */
542
543 SilcPacketEngine
544 silc_packet_engine_start(SilcRng rng, SilcBool router,
545                          SilcPacketCallbacks *callbacks,
546                          void *callback_context)
547 {
548   SilcPacketEngine engine;
549   SilcPacket packet;
550   int i;
551   void *tmp;
552
553   SILC_LOG_DEBUG(("Starting new packet engine"));
554
555   if (!callbacks)
556     return NULL;
557   if (!callbacks->packet_receive || !callbacks->eos || !callbacks->error)
558     return NULL;
559
560   engine = silc_calloc(1, sizeof(*engine));
561   if (!engine)
562     return NULL;
563
564   engine->contexts = silc_hash_table_alloc(0, silc_hash_ptr, NULL, NULL, NULL,
565                                            silc_packet_engine_context_destr,
566                                            engine, TRUE);
567   if (!engine->contexts) {
568     silc_free(engine);
569     return NULL;
570   }
571
572   engine->rng = rng;
573   engine->local_is_router = router;
574   engine->callbacks = callbacks;
575   engine->callback_context = callback_context;
576   silc_list_init(engine->streams, struct SilcPacketStreamStruct, next);
577   silc_mutex_alloc(&engine->lock);
578
579   /* Allocate packet free list */
580   silc_list_init(engine->packet_pool, struct SilcPacketStruct, next);
581   for (i = 0; i < 5; i++) {
582     packet = silc_calloc(1, sizeof(*packet));
583     if (!packet) {
584       silc_packet_engine_stop(engine);
585       return NULL;
586     }
587
588     tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
589     if (!tmp) {
590       silc_packet_engine_stop(engine);
591       return NULL;
592     }
593     silc_buffer_set(&packet->buffer, tmp, SILC_PACKET_DEFAULT_SIZE);
594     silc_buffer_reset(&packet->buffer);
595
596     silc_list_add(engine->packet_pool, packet);
597   }
598   silc_list_start(engine->packet_pool);
599
600   return engine;
601 }
602
603 /* Stop packet engine */
604
605 void silc_packet_engine_stop(SilcPacketEngine engine)
606 {
607   SilcPacket packet;
608
609   SILC_LOG_DEBUG(("Stopping packet engine"));
610
611   if (!engine)
612     return;
613
614   /* Free packet free list */
615   silc_list_start(engine->packet_pool);
616   while ((packet = silc_list_get(engine->packet_pool))) {
617     silc_buffer_purge(&packet->buffer);
618     silc_free(packet);
619   }
620
621   silc_hash_table_free(engine->contexts);
622   silc_mutex_free(engine->lock);
623   silc_free(engine);
624 }
625
626 static const char *packet_error[] = {
627   "Cannot read from stream",
628   "Cannot write to stream",
629   "Packet MAC failed",
630   "Packet decryption failed",
631   "Unknown SID",
632   "Packet is malformed",
633   "System out of memory",
634 };
635
636 /* Return packet error string */
637
638 const char *silc_packet_error_string(SilcPacketError error)
639 {
640   if (error < SILC_PACKET_ERR_READ || error > SILC_PACKET_ERR_NO_MEMORY)
641     return "<invalid error code>";
642   return packet_error[error];
643 }
644
645 /* Return list of packet streams in the engine */
646
647 SilcDList silc_packet_engine_get_streams(SilcPacketEngine engine)
648 {
649   SilcDList list;
650   SilcPacketStream ps;
651
652   list = silc_dlist_init();
653   if (!list)
654     return NULL;
655
656   silc_mutex_lock(engine->lock);
657   silc_list_start(engine->streams);
658   while ((ps = silc_list_get(engine->streams))) {
659     silc_packet_stream_ref(ps);
660     silc_dlist_add(list, ps);
661   }
662   silc_mutex_unlock(engine->lock);
663
664   return list;
665 }
666
667 /* Free list returned by silc_packet_engine_get_streams */
668
669 void silc_packet_engine_free_streams_list(SilcDList streams)
670 {
671   SilcPacketStream ps;
672
673   silc_dlist_start(streams);
674   while ((ps = silc_dlist_get(streams)))
675     silc_packet_stream_unref(ps);
676
677   silc_dlist_uninit(streams);
678 }
679
680 /* Create new packet stream */
681
682 SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
683                                            SilcSchedule schedule,
684                                            SilcStream stream)
685 {
686   SilcPacketStream ps;
687   SilcBuffer inbuf;
688   void *tmp;
689
690   SILC_LOG_DEBUG(("Creating new packet stream"));
691
692   if (!engine || !stream)
693     return NULL;
694
695   ps = silc_calloc(1, sizeof(*ps));
696   if (!ps)
697     return NULL;
698
699   ps->stream = stream;
700   silc_atomic_init8(&ps->refcnt, 1);
701   silc_mutex_alloc(&ps->lock);
702
703   /* Allocate out buffer */
704   tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
705   if (!tmp) {
706     silc_packet_stream_destroy(ps);
707     return NULL;
708   }
709   silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
710   silc_buffer_reset(&ps->outbuf);
711
712   /* Initialize packet procesors list */
713   ps->process = silc_dlist_init();
714   if (!ps->process) {
715     silc_packet_stream_destroy(ps);
716     return NULL;
717   }
718
719   silc_mutex_lock(engine->lock);
720
721   /* Add per scheduler context */
722   if (!silc_hash_table_find(engine->contexts, schedule, NULL,
723                             (void *)&ps->sc)) {
724     ps->sc = silc_calloc(1, sizeof(*ps->sc));
725     if (!ps->sc) {
726       silc_packet_stream_destroy(ps);
727       silc_mutex_unlock(engine->lock);
728       return NULL;
729     }
730     ps->sc->engine = engine;
731     ps->sc->schedule = schedule;
732
733     /* Allocate data input buffer */
734     inbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE * 65);
735     if (!inbuf) {
736       silc_free(ps->sc);
737       ps->sc = NULL;
738       silc_packet_stream_destroy(ps);
739       silc_mutex_unlock(engine->lock);
740       return NULL;
741     }
742     silc_buffer_reset(inbuf);
743
744     ps->sc->inbufs = silc_dlist_init();
745     if (!ps->sc->inbufs) {
746       silc_buffer_free(inbuf);
747       silc_free(ps->sc);
748       ps->sc = NULL;
749       silc_packet_stream_destroy(ps);
750       silc_mutex_unlock(engine->lock);
751       return NULL;
752     }
753     silc_dlist_add(ps->sc->inbufs, inbuf);
754
755     /* Add to per scheduler context hash table */
756     if (!silc_hash_table_add(engine->contexts, schedule, ps->sc)) {
757       silc_buffer_free(inbuf);
758       silc_dlist_del(ps->sc->inbufs, inbuf);
759       silc_free(ps->sc);
760       ps->sc = NULL;
761       silc_packet_stream_destroy(ps);
762       silc_mutex_unlock(engine->lock);
763       return NULL;
764     }
765   }
766   ps->sc->stream_count++;
767
768   /* Add the packet stream to engine */
769   silc_list_add(engine->streams, ps);
770
771   /* If this is UDP stream, allocate UDP remote stream hash table */
772   if (!engine->udp_remote && silc_socket_stream_is_udp(stream, NULL))
773     engine->udp_remote = silc_hash_table_alloc(0, silc_hash_string, NULL,
774                                                silc_hash_string_compare, NULL,
775                                                silc_packet_engine_hash_destr,
776                                                NULL, TRUE);
777
778   silc_mutex_unlock(engine->lock);
779
780   /* Set IO notifier callback.  This schedules this stream for I/O. */
781   if (!silc_stream_set_notifier(ps->stream, schedule,
782                                 silc_packet_stream_io, ps)) {
783     SILC_LOG_DEBUG(("Cannot set stream notifier for packet stream"));
784     silc_packet_stream_destroy(ps);
785     return NULL;
786   }
787
788   return ps;
789 }
790
791 /* Add new remote packet stream for UDP packet streams */
792
793 SilcPacketStream silc_packet_stream_add_remote(SilcPacketStream stream,
794                                                const char *remote_ip,
795                                                SilcUInt16 remote_port,
796                                                SilcPacket packet)
797 {
798   SilcPacketEngine engine = stream->sc->engine;
799   SilcPacketStream ps;
800   char *tuple;
801   void *tmp;
802
803   SILC_LOG_DEBUG(("Adding UDP remote %s:%d to packet stream %p",
804                   remote_ip, remote_port, stream));
805
806   if (!stream || !remote_ip || !remote_port)
807     return NULL;
808
809   if (!silc_socket_stream_is_udp(stream->stream, NULL)) {
810     SILC_LOG_ERROR(("Stream is not UDP stream, cannot add remote IP"));
811     return NULL;
812   }
813
814   ps = silc_calloc(1, sizeof(*ps));
815   if (!ps)
816     return NULL;
817   ps->sc = stream->sc;
818
819   silc_atomic_init8(&ps->refcnt, 1);
820   silc_mutex_alloc(&ps->lock);
821
822   /* Set the UDP packet stream as underlaying stream */
823   silc_packet_stream_ref(stream);
824   ps->stream = (SilcStream)stream;
825   ps->udp = TRUE;
826
827   /* Allocate out buffer */
828   tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
829   if (!tmp) {
830     silc_packet_stream_destroy(ps);
831     return NULL;
832   }
833   silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
834   silc_buffer_reset(&ps->outbuf);
835
836   /* Initialize packet procesors list */
837   ps->process = silc_dlist_init();
838   if (!ps->process) {
839     silc_packet_stream_destroy(ps);
840     return NULL;
841   }
842
843   /* Add to engine with this IP and port pair */
844   tuple = silc_format("%d%s", remote_port, remote_ip);
845   silc_mutex_lock(engine->lock);
846   if (!tuple || !silc_hash_table_add(engine->udp_remote, tuple, ps)) {
847     silc_mutex_unlock(engine->lock);
848     silc_packet_stream_destroy(ps);
849     return NULL;
850   }
851   silc_mutex_unlock(engine->lock);
852
853   /* Save remote IP and port pair */
854   ps->remote_udp = silc_calloc(1, sizeof(*ps->remote_udp));
855   if (!ps->remote_udp) {
856     silc_packet_stream_destroy(ps);
857     return NULL;
858   }
859   ps->remote_udp->remote_port = remote_port;
860   ps->remote_udp->remote_ip = strdup(remote_ip);
861   if (!ps->remote_udp->remote_ip) {
862     silc_packet_stream_destroy(ps);
863     return NULL;
864   }
865
866   if (packet) {
867     /* Inject packet to the new stream */
868     packet->stream = ps;
869     silc_packet_stream_ref(ps);
870     silc_schedule_task_add_timeout(silc_stream_get_schedule(stream->stream),
871                                    silc_packet_stream_inject_packet, packet,
872                                    0, 0);
873   }
874
875   return ps;
876 }
877
878 /* Destroy packet stream */
879
880 void silc_packet_stream_destroy(SilcPacketStream stream)
881 {
882   SilcPacketEngine engine;
883
884   if (!stream)
885     return;
886
887   if (silc_atomic_sub_int8(&stream->refcnt, 1) > 0) {
888     stream->destroyed = TRUE;
889
890     /* Close the underlaying stream */
891     if (!stream->udp && stream->stream)
892       silc_stream_close(stream->stream);
893     return;
894   }
895
896   SILC_LOG_DEBUG(("Destroying packet stream %p", stream));
897
898   if (!stream->udp) {
899     /* Delete from engine */
900     engine = stream->sc->engine;
901     silc_mutex_lock(engine->lock);
902     silc_list_del(engine->streams, stream);
903
904     /* Remove per scheduler context, if it is not used anymore */
905     if (stream->sc) {
906       stream->sc->stream_count--;
907       if (!stream->sc->stream_count)
908         silc_hash_table_del(engine->contexts, stream->sc->schedule);
909     }
910     silc_mutex_unlock(engine->lock);
911
912     /* Destroy the underlaying stream */
913     if (stream->stream)
914       silc_stream_destroy(stream->stream);
915   } else {
916     /* Delete from UDP remote hash table */
917     char tuple[64];
918     engine = stream->sc->engine;
919     silc_snprintf(tuple, sizeof(tuple), "%d%s",
920                   stream->remote_udp->remote_port,
921                   stream->remote_udp->remote_ip);
922     silc_mutex_lock(engine->lock);
923     silc_hash_table_del(engine->udp_remote, tuple);
924     silc_mutex_unlock(engine->lock);
925
926     silc_free(stream->remote_udp->remote_ip);
927     silc_free(stream->remote_udp);
928
929     /* Unreference the underlaying packet stream */
930     silc_packet_stream_unref((SilcPacketStream)stream->stream);
931   }
932
933   /* Clear and free buffers */
934   silc_buffer_clear(&stream->outbuf);
935   silc_buffer_purge(&stream->outbuf);
936
937   if (stream->process) {
938     SilcPacketProcess p;
939     silc_dlist_start(stream->process);
940     while ((p = silc_dlist_get(stream->process))) {
941       silc_free(p->types);
942       silc_free(p);
943       silc_dlist_del(stream->process, p);
944     }
945     silc_dlist_uninit(stream->process);
946   }
947
948   /* Destroy ciphers and HMACs */
949   if (stream->send_key[0])
950     silc_cipher_free(stream->send_key[0]);
951   if (stream->receive_key[0])
952     silc_cipher_free(stream->receive_key[0]);
953   if (stream->send_hmac[0])
954     silc_hmac_free(stream->send_hmac[0]);
955   if (stream->receive_hmac[0])
956     silc_hmac_free(stream->receive_hmac[0]);
957   if (stream->send_key[1])
958     silc_cipher_free(stream->send_key[1]);
959   if (stream->receive_key[1])
960     silc_cipher_free(stream->receive_key[1]);
961   if (stream->send_hmac[1])
962     silc_hmac_free(stream->send_hmac[1]);
963   if (stream->receive_hmac[1])
964     silc_hmac_free(stream->receive_hmac[1]);
965
966   /* Free IDs */
967   silc_free(stream->src_id);
968   silc_free(stream->dst_id);
969
970   silc_atomic_uninit8(&stream->refcnt);
971   silc_mutex_free(stream->lock);
972   silc_free(stream);
973 }
974
975 /* Return TRUE if the stream is valid */
976
977 SilcBool silc_packet_stream_is_valid(SilcPacketStream stream)
978 {
979   return stream->destroyed == FALSE;
980 }
981
982 /* Marks as router stream */
983
984 void silc_packet_stream_set_router(SilcPacketStream stream)
985 {
986   stream->is_router = TRUE;
987 }
988
989 /* Mark to include IV in ciphertext */
990
991 void silc_packet_stream_set_iv_included(SilcPacketStream stream)
992 {
993   stream->iv_included = TRUE;
994 }
995
996 /* Links `callbacks' to `stream' for specified packet types */
997
998 static SilcBool silc_packet_stream_link_va(SilcPacketStream stream,
999                                            SilcPacketCallbacks *callbacks,
1000                                            void *callback_context,
1001                                            int priority, va_list ap)
1002 {
1003   SilcPacketProcess p, e;
1004   SilcInt32 packet_type;
1005   int i;
1006
1007   SILC_LOG_DEBUG(("Linking callbacks %p to stream %p", callbacks, stream));
1008
1009   if (!callbacks)
1010     return FALSE;
1011   if (!callbacks->packet_receive)
1012     return FALSE;
1013
1014   p = silc_calloc(1, sizeof(*p));
1015   if (!p)
1016     return FALSE;
1017
1018   p->priority = priority;
1019   p->callbacks = callbacks;
1020   p->callback_context = callback_context;
1021
1022   silc_mutex_lock(stream->lock);
1023
1024   if (!stream->process) {
1025     stream->process = silc_dlist_init();
1026     if (!stream->process) {
1027       silc_mutex_unlock(stream->lock);
1028       return FALSE;
1029     }
1030   }
1031
1032   /* According to priority set the procesor to correct position.  First
1033      entry has the highest priority */
1034   silc_dlist_start(stream->process);
1035   while ((e = silc_dlist_get(stream->process)) != SILC_LIST_END) {
1036     if (p->priority > e->priority) {
1037       silc_dlist_insert(stream->process, p);
1038       break;
1039     }
1040   }
1041   if (!e)
1042     silc_dlist_add(stream->process, p);
1043
1044   /* Get packet types to process */
1045   i = 1;
1046   while (1) {
1047     packet_type = va_arg(ap, SilcInt32);
1048
1049     if (packet_type == SILC_PACKET_ANY)
1050       break;
1051
1052     if (packet_type == -1)
1053       break;
1054
1055     p->types = silc_realloc(p->types, sizeof(*p->types) * (i + 1));
1056     if (!p->types) {
1057       silc_mutex_unlock(stream->lock);
1058       return FALSE;
1059     }
1060
1061     p->types[i - 1] = (SilcPacketType)packet_type;
1062     i++;
1063   }
1064   if (p->types)
1065     p->types[i - 1] = 0;
1066
1067   silc_mutex_unlock(stream->lock);
1068
1069   silc_packet_stream_ref(stream);
1070
1071   return TRUE;
1072 }
1073
1074 /* Links `callbacks' to `stream' for specified packet types */
1075
1076 SilcBool silc_packet_stream_link(SilcPacketStream stream,
1077                                  SilcPacketCallbacks *callbacks,
1078                                  void *callback_context,
1079                                  int priority, ...)
1080 {
1081   va_list ap;
1082   SilcBool ret;
1083
1084   va_start(ap, priority);
1085   ret = silc_packet_stream_link_va(stream, callbacks, callback_context,
1086                                    priority, ap);
1087   va_end(ap);
1088
1089   return ret;
1090 }
1091
1092 /* Unlinks `callbacks' from `stream'. */
1093
1094 void silc_packet_stream_unlink(SilcPacketStream stream,
1095                                SilcPacketCallbacks *callbacks,
1096                                void *callback_context)
1097 {
1098   SilcPacketProcess p;
1099
1100   SILC_LOG_DEBUG(("Unlinking callbacks %p from stream %p",
1101                   callbacks, stream));
1102
1103   silc_mutex_lock(stream->lock);
1104
1105   silc_dlist_start(stream->process);
1106   while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END)
1107     if (p->callbacks == callbacks &&
1108         p->callback_context == callback_context) {
1109       silc_dlist_del(stream->process, p);
1110       silc_free(p->types);
1111       silc_free(p);
1112       break;
1113     }
1114
1115   if (!silc_dlist_count(stream->process)) {
1116     silc_dlist_uninit(stream->process);
1117     stream->process = NULL;
1118   }
1119
1120   silc_mutex_unlock(stream->lock);
1121
1122   silc_packet_stream_unref(stream);
1123 }
1124
1125 /* Returns TRUE if stream is UDP stream */
1126
1127 SilcBool silc_packet_stream_is_udp(SilcPacketStream stream)
1128 {
1129   return stream->udp || silc_socket_stream_is_udp(stream->stream, NULL);
1130 }
1131
1132 /* Return packet sender IP and port for UDP packet stream */
1133
1134 SilcBool silc_packet_get_sender(SilcPacket packet,
1135                                 const char **sender_ip,
1136                                 SilcUInt16 *sender_port)
1137 {
1138   if (!packet->stream->remote_udp)
1139     return FALSE;
1140
1141   *sender_ip = packet->stream->remote_udp->remote_ip;
1142   *sender_port = packet->stream->remote_udp->remote_port;
1143
1144   return TRUE;
1145 }
1146
1147 /* Reference packet stream */
1148
1149 void silc_packet_stream_ref(SilcPacketStream stream)
1150 {
1151   silc_atomic_add_int8(&stream->refcnt, 1);
1152   SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
1153                   silc_atomic_get_int8(&stream->refcnt) - 1,
1154                   silc_atomic_get_int8(&stream->refcnt)));
1155 }
1156
1157 /* Unreference packet stream */
1158
1159 void silc_packet_stream_unref(SilcPacketStream stream)
1160 {
1161   SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
1162                   silc_atomic_get_int8(&stream->refcnt),
1163                   silc_atomic_get_int8(&stream->refcnt) - 1));
1164   if (silc_atomic_sub_int8(&stream->refcnt, 1) > 0)
1165     return;
1166   silc_atomic_add_int8(&stream->refcnt, 1);
1167   silc_packet_stream_destroy(stream);
1168 }
1169
1170 /* Return engine */
1171
1172 SilcPacketEngine silc_packet_get_engine(SilcPacketStream stream)
1173 {
1174   return stream->sc->engine;
1175 }
1176
1177 /* Set application context for packet stream */
1178
1179 void silc_packet_set_context(SilcPacketStream stream, void *stream_context)
1180 {
1181   silc_mutex_lock(stream->lock);
1182   stream->stream_context = stream_context;
1183   silc_mutex_unlock(stream->lock);
1184 }
1185
1186 /* Return application context from packet stream */
1187
1188 void *silc_packet_get_context(SilcPacketStream stream)
1189 {
1190   void *context;
1191   silc_mutex_lock(stream->lock);
1192   context = stream->stream_context;
1193   silc_mutex_unlock(stream->lock);
1194   return context;
1195 }
1196
1197 /* Change underlaying stream */
1198
1199 void silc_packet_stream_set_stream(SilcPacketStream ps,
1200                                    SilcStream stream)
1201 {
1202   if (ps->stream)
1203     silc_stream_set_notifier(ps->stream, ps->sc->schedule, NULL, NULL);
1204   ps->stream = stream;
1205   silc_stream_set_notifier(ps->stream, ps->sc->schedule, silc_packet_stream_io,
1206                            ps);
1207 }
1208
1209 /* Return underlaying stream */
1210
1211 SilcStream silc_packet_stream_get_stream(SilcPacketStream stream)
1212 {
1213   return stream->stream;
1214 }
1215
1216 /* Set keys. */
1217
1218 SilcBool silc_packet_set_keys(SilcPacketStream stream, SilcCipher send_key,
1219                               SilcCipher receive_key, SilcHmac send_hmac,
1220                               SilcHmac receive_hmac, SilcBool rekey)
1221 {
1222   SILC_LOG_DEBUG(("Setting new keys to packet stream %p", stream));
1223
1224   /* If doing rekey, send REKEY_DONE packet */
1225   if (rekey) {
1226     /* This will take stream lock. */
1227     if (!silc_packet_send_raw(stream, SILC_PACKET_REKEY_DONE, 0,
1228                               stream->src_id_type, stream->src_id,
1229                               stream->src_id_len, stream->dst_id_type,
1230                               stream->dst_id, stream->dst_id_len,
1231                               NULL, 0, stream->send_key[0],
1232                               stream->send_hmac[0]))
1233       return FALSE;
1234
1235     /* Write the packet to the stream */
1236     if (!silc_packet_stream_write(stream, TRUE))
1237       return FALSE;
1238   } else {
1239     silc_mutex_lock(stream->lock);
1240   }
1241
1242   /* In case IV Included is set, save the old keys */
1243   if (stream->iv_included) {
1244     if (stream->send_key[1] && send_key) {
1245       silc_cipher_free(stream->send_key[1]);
1246       stream->send_key[1] = stream->send_key[0];
1247     }
1248     if (stream->receive_key[1] && receive_key) {
1249       silc_cipher_free(stream->receive_key[1]);
1250       stream->receive_key[1] = stream->receive_key[0];
1251     }
1252     if (stream->send_hmac[1] && send_hmac) {
1253       silc_hmac_free(stream->send_hmac[1]);
1254       stream->send_hmac[1] = stream->send_hmac[0];
1255     }
1256     if (stream->receive_hmac[1] && receive_hmac) {
1257       silc_hmac_free(stream->receive_hmac[1]);
1258       stream->receive_hmac[1] = stream->receive_hmac[0];
1259     }
1260   } else {
1261     if (stream->send_key[0] && send_key)
1262       silc_cipher_free(stream->send_key[0]);
1263     if (stream->receive_key[0] && receive_key)
1264       silc_cipher_free(stream->receive_key[0]);
1265     if (stream->send_hmac[0] && send_hmac)
1266       silc_hmac_free(stream->send_hmac[0]);
1267     if (stream->receive_hmac[0] && receive_hmac)
1268       silc_hmac_free(stream->receive_hmac[0]);
1269   }
1270
1271   /* Set keys */
1272   if (send_key)
1273     stream->send_key[0] = send_key;
1274   if (receive_key)
1275     stream->receive_key[0] = receive_key;
1276   if (send_hmac)
1277     stream->send_hmac[0] = send_hmac;
1278   if (receive_hmac)
1279     stream->receive_hmac[0] = receive_hmac;
1280
1281   silc_mutex_unlock(stream->lock);
1282   return TRUE;
1283 }
1284
1285 /* Return current ciphers from packet stream */
1286
1287 SilcBool silc_packet_get_keys(SilcPacketStream stream,
1288                               SilcCipher *send_key,
1289                               SilcCipher *receive_key,
1290                               SilcHmac *send_hmac,
1291                               SilcHmac *receive_hmac)
1292 {
1293   if (!stream->send_key[0] && !stream->receive_key[0] &&
1294       !stream->send_hmac[0] && !stream->receive_hmac[0])
1295     return FALSE;
1296
1297   silc_mutex_lock(stream->lock);
1298
1299   if (send_key)
1300     *send_key = stream->send_key[0];
1301   if (receive_key)
1302     *receive_key = stream->receive_key[0];
1303   if (send_hmac)
1304     *send_hmac = stream->send_hmac[0];
1305   if (receive_hmac)
1306     *receive_hmac = stream->receive_hmac[0];
1307
1308   silc_mutex_unlock(stream->lock);
1309
1310   return TRUE;
1311 }
1312
1313 /* Set SILC IDs to packet stream */
1314
1315 SilcBool silc_packet_set_ids(SilcPacketStream stream,
1316                              SilcIdType src_id_type, const void *src_id,
1317                              SilcIdType dst_id_type, const void *dst_id)
1318 {
1319   SilcUInt32 len;
1320   unsigned char tmp[32];
1321
1322   if (!src_id && !dst_id)
1323     return FALSE;
1324
1325   silc_mutex_lock(stream->lock);
1326
1327   if (src_id) {
1328     SILC_LOG_DEBUG(("Setting source ID to packet stream %p", stream));
1329
1330     silc_free(stream->src_id);
1331     if (!silc_id_id2str(src_id, src_id_type, tmp, sizeof(tmp), &len)) {
1332       silc_mutex_unlock(stream->lock);
1333       return FALSE;
1334     }
1335     stream->src_id = silc_memdup(tmp, len);
1336     if (!stream->src_id) {
1337       silc_mutex_unlock(stream->lock);
1338       return FALSE;
1339     }
1340     stream->src_id_type = src_id_type;
1341     stream->src_id_len = len;
1342   }
1343
1344   if (dst_id) {
1345     SILC_LOG_DEBUG(("Setting destination ID to packet stream %p", stream));
1346
1347     silc_free(stream->dst_id);
1348     if (!silc_id_id2str(dst_id, dst_id_type, tmp, sizeof(tmp), &len)) {
1349       silc_mutex_unlock(stream->lock);
1350       return FALSE;
1351     }
1352     stream->dst_id = silc_memdup(tmp, len);
1353     if (!stream->dst_id) {
1354       silc_mutex_unlock(stream->lock);
1355       return FALSE;
1356     }
1357     stream->dst_id_type = dst_id_type;
1358     stream->dst_id_len = len;
1359   }
1360
1361   silc_mutex_unlock(stream->lock);
1362
1363   return TRUE;
1364 }
1365
1366 /* Return IDs from the packet stream */
1367
1368 SilcBool silc_packet_get_ids(SilcPacketStream stream,
1369                              SilcBool *src_id_set, SilcID *src_id,
1370                              SilcBool *dst_id_set, SilcID *dst_id)
1371 {
1372   if (src_id && stream->src_id)
1373     if (!silc_id_str2id2(stream->src_id, stream->src_id_len,
1374                          stream->src_id_type, src_id))
1375       return FALSE;
1376
1377   if (stream->src_id && src_id_set)
1378     *src_id_set = TRUE;
1379
1380   if (dst_id && stream->dst_id)
1381     if (!silc_id_str2id2(stream->dst_id, stream->dst_id_len,
1382                          stream->dst_id_type, dst_id))
1383       return FALSE;
1384
1385   if (stream->dst_id && dst_id_set)
1386     *dst_id_set = TRUE;
1387
1388   return TRUE;
1389 }
1390
1391 /* Adds Security ID (SID) */
1392
1393 SilcBool silc_packet_set_sid(SilcPacketStream stream, SilcUInt8 sid)
1394 {
1395   if (!stream->iv_included)
1396     return FALSE;
1397
1398   SILC_LOG_DEBUG(("Set packet stream %p SID to %d", stream, sid));
1399
1400   stream->sid = sid;
1401   return TRUE;
1402 }
1403
1404 /* Free packet */
1405
1406 void silc_packet_free(SilcPacket packet)
1407 {
1408   SilcPacketStream stream = packet->stream;
1409
1410   SILC_LOG_DEBUG(("Freeing packet %p", packet));
1411
1412   /* Check for double free */
1413   SILC_ASSERT(packet->stream != NULL);
1414
1415   packet->stream = NULL;
1416   packet->src_id = packet->dst_id = NULL;
1417   silc_buffer_reset(&packet->buffer);
1418
1419   silc_mutex_lock(stream->sc->engine->lock);
1420
1421   /* Put the packet back to freelist */
1422   silc_list_add(stream->sc->engine->packet_pool, packet);
1423   if (silc_list_count(stream->sc->engine->packet_pool) == 1)
1424     silc_list_start(stream->sc->engine->packet_pool);
1425
1426   silc_mutex_unlock(stream->sc->engine->lock);
1427 }
1428
1429 /****************************** Packet Sending ******************************/
1430
1431 /* Prepare outgoing data buffer for packet sending.  Returns the
1432    pointer to that buffer into the `packet'. */
1433
1434 static inline SilcBool silc_packet_send_prepare(SilcPacketStream stream,
1435                                                 SilcUInt32 totlen,
1436                                                 SilcHmac hmac,
1437                                                 SilcBuffer packet)
1438 {
1439   unsigned char *oldptr;
1440   unsigned int mac_len = hmac ? silc_hmac_len(hmac) : 0;
1441
1442   totlen += mac_len;
1443
1444   /* Allocate more space if needed */
1445   if (silc_unlikely(silc_buffer_taillen(&stream->outbuf) < totlen)) {
1446     if (!silc_buffer_realloc(&stream->outbuf,
1447                              silc_buffer_truelen(&stream->outbuf) + totlen))
1448       return FALSE;
1449   }
1450
1451   /* Pull data area for the new packet, and return pointer to the start of
1452      the data area and save the pointer in to the `packet'.  MAC is pulled
1453      later after it's computed. */
1454   oldptr = silc_buffer_pull_tail(&stream->outbuf, totlen);
1455   silc_buffer_set(packet, oldptr, totlen);
1456   silc_buffer_push_tail(packet, mac_len);
1457
1458   return TRUE;
1459 }
1460
1461 /* Increments counter when encrypting in counter mode. */
1462
1463 static inline void silc_packet_send_ctr_increment(SilcPacketStream stream,
1464                                                   SilcCipher cipher,
1465                                                   unsigned char *ret_iv)
1466 {
1467   unsigned char *iv = silc_cipher_get_iv(cipher);
1468   SilcUInt32 pc1, pc2;
1469
1470   /* Increment 64-bit packet counter */
1471   SILC_GET32_MSB(pc1, iv + 4);
1472   SILC_GET32_MSB(pc2, iv + 8);
1473   if (++pc2 == 0)
1474     ++pc1;
1475   SILC_PUT32_MSB(pc1, iv + 4);
1476   SILC_PUT32_MSB(pc2, iv + 8);
1477
1478   /* Reset block counter */
1479   memset(iv + 12, 0, 4);
1480
1481   /* If IV Included flag, return the 64-bit IV for inclusion in packet */
1482   if (stream->iv_included) {
1483     /* Get new nonce */
1484     ret_iv[0] = silc_rng_get_byte_fast(stream->sc->engine->rng);
1485     ret_iv[1] = ret_iv[0] + iv[4];
1486     ret_iv[2] = ret_iv[0] ^ ret_iv[1];
1487     ret_iv[3] = ret_iv[0] + ret_iv[2];
1488     SILC_PUT32_MSB(pc2, ret_iv + 4);
1489     SILC_LOG_HEXDUMP(("IV"), ret_iv, 8);
1490
1491     /* Set new nonce to counter block */
1492     memcpy(iv + 4, ret_iv, 4);
1493   }
1494
1495   SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1496 }
1497
1498 /* Internal routine to assemble outgoing packet.  Assembles and encryptes
1499    the packet.  The silc_packet_stream_write needs to be called to send it
1500    after this returns TRUE. */
1501
1502 static inline SilcBool silc_packet_send_raw(SilcPacketStream stream,
1503                                             SilcPacketType type,
1504                                             SilcPacketFlags flags,
1505                                             SilcIdType src_id_type,
1506                                             unsigned char *src_id,
1507                                             SilcUInt32 src_id_len,
1508                                             SilcIdType dst_id_type,
1509                                             unsigned char *dst_id,
1510                                             SilcUInt32 dst_id_len,
1511                                             const unsigned char *data,
1512                                             SilcUInt32 data_len,
1513                                             SilcCipher cipher,
1514                                             SilcHmac hmac)
1515 {
1516   unsigned char tmppad[SILC_PACKET_MAX_PADLEN], iv[33], psn[4];
1517   int block_len = (cipher ? silc_cipher_get_block_len(cipher) : 0);
1518   int i, enclen, truelen, padlen = 0, ivlen = 0, psnlen = 0;
1519   SilcBool ctr;
1520   SilcBufferStruct packet;
1521
1522   SILC_LOG_DEBUG(("Sending packet %s (%d) flags %d, src %d dst %d, "
1523                   "data len %d", silc_get_packet_name(type), stream->send_psn,
1524                   flags, src_id_type, dst_id_type, data_len));
1525
1526   /* Get the true length of the packet. This is saved as payload length
1527      into the packet header.  This does not include the length of the
1528      padding. */
1529   data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
1530                                             src_id_len + dst_id_len));
1531   enclen = truelen = (data_len + SILC_PACKET_HEADER_LEN +
1532                       src_id_len + dst_id_len);
1533
1534   /* If using CTR mode, increment the counter */
1535   ctr = (cipher && silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR);
1536   if (ctr) {
1537     silc_packet_send_ctr_increment(stream, cipher, iv + 1);
1538
1539     /* If IV is included, the SID, IV and sequence number is added to packet */
1540     if (stream->iv_included && cipher) {
1541       psnlen = sizeof(psn);
1542       ivlen = 8 + 1;
1543       iv[0] = stream->sid;
1544     }
1545   } else {
1546     /* If IV is included, the SID, IV and sequence number is added to packet */
1547     if (stream->iv_included && cipher) {
1548       psnlen = sizeof(psn);
1549       ivlen = block_len + 1;
1550       iv[0] = stream->sid;
1551       memcpy(iv + 1, silc_cipher_get_iv(cipher), block_len);
1552     }
1553   }
1554
1555   /* We automatically figure out the packet structure from the packet
1556      type and flags, and calculate correct length.  Private messages with
1557      private keys and channel messages are special packets as their
1558      payload is encrypted already. */
1559   if (type == SILC_PACKET_PRIVATE_MESSAGE &&
1560       flags & SILC_PACKET_FLAG_PRIVMSG_KEY) {
1561     /* Padding is calculated from header + IDs */
1562     if (!ctr)
1563       SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1564                           psnlen), block_len, padlen);
1565
1566     /* Length to encrypt, header + IDs + padding. */
1567     enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1568               padlen + psnlen);
1569
1570   } else if (type == SILC_PACKET_CHANNEL_MESSAGE) {
1571     if (stream->sc->engine->local_is_router && stream->is_router) {
1572       /* Channel messages between routers are encrypted as normal packets.
1573          Padding is calculated from true length of the packet. */
1574       if (!ctr)
1575         SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
1576
1577       enclen += padlen + psnlen;
1578     } else {
1579       /* Padding is calculated from header + IDs */
1580       if (!ctr)
1581         SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1582                             psnlen), block_len, padlen);
1583
1584       /* Length to encrypt, header + IDs + padding. */
1585       enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1586                 padlen + psnlen);
1587     }
1588   } else {
1589     /* Padding is calculated from true length of the packet */
1590     if (flags & SILC_PACKET_FLAG_LONG_PAD)
1591       SILC_PACKET_PADLEN_MAX(truelen + psnlen, block_len, padlen);
1592     else if (!ctr)
1593       SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
1594
1595     enclen += padlen + psnlen;
1596   }
1597
1598   /* Remove implementation specific flags */
1599   flags &= ~(SILC_PACKET_FLAG_LONG_PAD);
1600
1601   /* Get random padding */
1602   for (i = 0; i < padlen; i++) tmppad[i] =
1603     silc_rng_get_byte_fast(stream->sc->engine->rng);
1604
1605   silc_mutex_lock(stream->lock);
1606
1607   /* Get packet pointer from the outgoing buffer */
1608   if (silc_unlikely(!silc_packet_send_prepare(stream, truelen + padlen + ivlen
1609                                               + psnlen, hmac, &packet))) {
1610     silc_mutex_unlock(stream->lock);
1611     return FALSE;
1612   }
1613
1614   SILC_PUT32_MSB(stream->send_psn, psn);
1615
1616   /* Create the packet.  This creates the SILC header, adds padding, and
1617      the actual packet data. */
1618   i = silc_buffer_format(&packet,
1619                          SILC_STR_DATA(iv, ivlen),
1620                          SILC_STR_DATA(psn, psnlen),
1621                          SILC_STR_UI_SHORT(truelen),
1622                          SILC_STR_UI_CHAR(flags),
1623                          SILC_STR_UI_CHAR(type),
1624                          SILC_STR_UI_CHAR(padlen),
1625                          SILC_STR_UI_CHAR(0),
1626                          SILC_STR_UI_CHAR(src_id_len),
1627                          SILC_STR_UI_CHAR(dst_id_len),
1628                          SILC_STR_UI_CHAR(src_id_type),
1629                          SILC_STR_DATA(src_id, src_id_len),
1630                          SILC_STR_UI_CHAR(dst_id_type),
1631                          SILC_STR_DATA(dst_id, dst_id_len),
1632                          SILC_STR_DATA(tmppad, padlen),
1633                          SILC_STR_DATA(data, data_len),
1634                          SILC_STR_END);
1635   if (silc_unlikely(i < 0)) {
1636     silc_mutex_unlock(stream->lock);
1637     return FALSE;
1638   }
1639
1640   SILC_LOG_HEXDUMP(("Assembled packet, len %d", silc_buffer_len(&packet)),
1641                    silc_buffer_data(&packet), silc_buffer_len(&packet));
1642
1643   /* Encrypt the packet */
1644   if (silc_likely(cipher)) {
1645     SILC_LOG_DEBUG(("Encrypting packet"));
1646     silc_cipher_set_iv(cipher, NULL);
1647     if (silc_unlikely(!silc_cipher_encrypt(cipher, packet.data + ivlen,
1648                                            packet.data + ivlen, enclen,
1649                                            NULL))) {
1650       SILC_LOG_ERROR(("Packet encryption failed"));
1651       silc_mutex_unlock(stream->lock);
1652       return FALSE;
1653     }
1654   }
1655
1656   /* Compute HMAC */
1657   if (silc_likely(hmac)) {
1658     SilcUInt32 mac_len;
1659
1660     /* MAC is computed from the entire encrypted packet data, and put
1661        to the end of the packet. */
1662     silc_hmac_init(hmac);
1663     silc_hmac_update(hmac, psn, sizeof(psn));
1664     silc_hmac_update(hmac, packet.data, silc_buffer_len(&packet));
1665     silc_hmac_final(hmac, packet.tail, &mac_len);
1666     silc_buffer_pull_tail(&packet, mac_len);
1667     stream->send_psn++;
1668   }
1669
1670   return TRUE;
1671 }
1672
1673 /* Sends a packet */
1674
1675 SilcBool silc_packet_send(SilcPacketStream stream,
1676                           SilcPacketType type, SilcPacketFlags flags,
1677                           const unsigned char *data, SilcUInt32 data_len)
1678 {
1679   SilcBool ret;
1680
1681   ret = silc_packet_send_raw(stream, type, flags,
1682                              stream->src_id_type,
1683                              stream->src_id,
1684                              stream->src_id_len,
1685                              stream->dst_id_type,
1686                              stream->dst_id,
1687                              stream->dst_id_len,
1688                              data, data_len,
1689                              stream->send_key[0],
1690                              stream->send_hmac[0]);
1691
1692   /* Write the packet to the stream */
1693   return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1694 }
1695
1696 /* Sends a packet, extended routine */
1697
1698 SilcBool silc_packet_send_ext(SilcPacketStream stream,
1699                               SilcPacketType type, SilcPacketFlags flags,
1700                               SilcIdType src_id_type, void *src_id,
1701                               SilcIdType dst_id_type, void *dst_id,
1702                               const unsigned char *data, SilcUInt32 data_len,
1703                               SilcCipher cipher, SilcHmac hmac)
1704 {
1705   unsigned char src_id_data[32], dst_id_data[32];
1706   SilcUInt32 src_id_len, dst_id_len;
1707   SilcBool ret;
1708
1709   if (src_id)
1710     if (!silc_id_id2str(src_id, src_id_type, src_id_data,
1711                         sizeof(src_id_data), &src_id_len))
1712       return FALSE;
1713   if (dst_id)
1714     if (!silc_id_id2str(dst_id, dst_id_type, dst_id_data,
1715                         sizeof(dst_id_data), &dst_id_len))
1716       return FALSE;
1717
1718   ret = silc_packet_send_raw(stream, type, flags,
1719                              src_id ? src_id_type : stream->src_id_type,
1720                              src_id ? src_id_data : stream->src_id,
1721                              src_id ? src_id_len : stream->src_id_len,
1722                              dst_id ? dst_id_type : stream->dst_id_type,
1723                              dst_id ? dst_id_data : stream->dst_id,
1724                              dst_id ? dst_id_len : stream->dst_id_len,
1725                              data, data_len,
1726                              cipher ? cipher : stream->send_key[0],
1727                              hmac ? hmac : stream->send_hmac[0]);
1728
1729   /* Write the packet to the stream */
1730   return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1731 }
1732
1733 /* Sends packet after formatting the arguments to buffer */
1734
1735 SilcBool silc_packet_send_va(SilcPacketStream stream,
1736                              SilcPacketType type, SilcPacketFlags flags, ...)
1737 {
1738   SilcBufferStruct buf;
1739   SilcBool ret;
1740   va_list va;
1741
1742   va_start(va, flags);
1743
1744   memset(&buf, 0, sizeof(buf));
1745   if (silc_buffer_format_vp(&buf, va) < 0) {
1746     va_end(va);
1747     return FALSE;
1748   }
1749
1750   ret = silc_packet_send(stream, type, flags, silc_buffer_data(&buf),
1751                          silc_buffer_len(&buf));
1752
1753   silc_buffer_purge(&buf);
1754   va_end(va);
1755
1756   return ret;
1757 }
1758
1759 /* Sends packet after formatting the arguments to buffer, extended routine */
1760
1761 SilcBool silc_packet_send_va_ext(SilcPacketStream stream,
1762                                  SilcPacketType type, SilcPacketFlags flags,
1763                                  SilcIdType src_id_type, void *src_id,
1764                                  SilcIdType dst_id_type, void *dst_id,
1765                                  SilcCipher cipher, SilcHmac hmac, ...)
1766 {
1767   SilcBufferStruct buf;
1768   SilcBool ret;
1769   va_list va;
1770
1771   va_start(va, hmac);
1772
1773   memset(&buf, 0, sizeof(buf));
1774   if (silc_buffer_format_vp(&buf, va) < 0) {
1775     va_end(va);
1776     return FALSE;
1777   }
1778
1779   ret = silc_packet_send_ext(stream, type, flags, src_id_type, src_id,
1780                              dst_id_type, dst_id, silc_buffer_data(&buf),
1781                              silc_buffer_len(&buf), cipher, hmac);
1782
1783   silc_buffer_purge(&buf);
1784   va_end(va);
1785
1786   return TRUE;
1787 }
1788
1789 /***************************** Packet Receiving *****************************/
1790
1791 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. */
1792
1793 static inline SilcBool silc_packet_check_mac(SilcHmac hmac,
1794                                              const unsigned char *data,
1795                                              SilcUInt32 data_len,
1796                                              const unsigned char *packet_mac,
1797                                              const unsigned char *packet_seq,
1798                                              SilcUInt32 sequence)
1799 {
1800   /* Check MAC */
1801   if (silc_likely(hmac)) {
1802     unsigned char mac[32], psn[4];
1803     SilcUInt32 mac_len;
1804
1805     SILC_LOG_DEBUG(("Verifying MAC"));
1806
1807     /* Compute HMAC of packet */
1808     silc_hmac_init(hmac);
1809
1810     if (!packet_seq) {
1811       SILC_PUT32_MSB(sequence, psn);
1812       silc_hmac_update(hmac, psn, 4);
1813     } else
1814       silc_hmac_update(hmac, packet_seq, 4);
1815
1816     silc_hmac_update(hmac, data, data_len);
1817     silc_hmac_final(hmac, mac, &mac_len);
1818
1819     /* Compare the MAC's */
1820     if (silc_unlikely(memcmp(packet_mac, mac, mac_len))) {
1821       SILC_LOG_DEBUG(("MAC failed"));
1822       return FALSE;
1823     }
1824
1825     SILC_LOG_DEBUG(("MAC is Ok"));
1826   }
1827
1828   return TRUE;
1829 }
1830
1831 /* Increments/sets counter when decrypting in counter mode. */
1832
1833 static inline void silc_packet_receive_ctr_increment(SilcPacketStream stream,
1834                                                      unsigned char *iv,
1835                                                      unsigned char *packet_iv)
1836 {
1837   SilcUInt32 pc1, pc2;
1838
1839   /* If IV Included flag, set the IV from packet to block counter. */
1840   if (stream->iv_included) {
1841     memcpy(iv + 4, packet_iv, 8);
1842   } else {
1843     /* Increment 64-bit packet counter. */
1844     SILC_GET32_MSB(pc1, iv + 4);
1845     SILC_GET32_MSB(pc2, iv + 8);
1846     if (++pc2 == 0)
1847       ++pc1;
1848     SILC_PUT32_MSB(pc1, iv + 4);
1849     SILC_PUT32_MSB(pc2, iv + 8);
1850   }
1851
1852   /* Reset block counter */
1853   memset(iv + 12, 0, 4);
1854
1855   SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1856 }
1857
1858 /* Decrypts SILC packet.  Handles both normal and special packet decryption.
1859    Return 0 when packet is normal and 1 when it it special, -1 on error. */
1860
1861 static inline int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
1862                                       SilcUInt32 sequence, SilcBuffer buffer,
1863                                       SilcBool normal)
1864 {
1865   if (normal == TRUE) {
1866     if (silc_likely(cipher)) {
1867       /* Decrypt rest of the packet */
1868       SILC_LOG_DEBUG(("Decrypting the packet"));
1869       if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1870                                              buffer->data,
1871                                              silc_buffer_len(buffer), NULL)))
1872         return -1;
1873     }
1874     return 0;
1875
1876   } else {
1877     /* Decrypt rest of the header plus padding */
1878     if (silc_likely(cipher)) {
1879       SilcUInt16 len;
1880       SilcUInt32 block_len = silc_cipher_get_block_len(cipher);
1881
1882       SILC_LOG_DEBUG(("Decrypting the header"));
1883
1884       /* Padding length + src id len + dst id len + header length - 16
1885          bytes already decrypted, gives the rest of the encrypted packet */
1886       silc_buffer_push(buffer, block_len);
1887       len = (((SilcUInt8)buffer->data[4] + (SilcUInt8)buffer->data[6] +
1888               (SilcUInt8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
1889              block_len);
1890       silc_buffer_pull(buffer, block_len);
1891
1892       if (silc_unlikely(len > silc_buffer_len(buffer))) {
1893         SILC_LOG_ERROR(("Garbage in header of packet, bad packet length, "
1894                         "packet dropped"));
1895         return -1;
1896       }
1897       if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1898                                              buffer->data, len, NULL)))
1899         return -1;
1900     }
1901
1902     return 1;
1903   }
1904 }
1905
1906 /* Parses the packet. This is called when a whole packet is ready to be
1907    parsed. The buffer sent must be already decrypted before calling this
1908    function. */
1909
1910 static inline SilcBool silc_packet_parse(SilcPacket packet)
1911 {
1912   SilcBuffer buffer = &packet->buffer;
1913   SilcUInt8 padlen = (SilcUInt8)buffer->data[4];
1914   SilcUInt8 src_id_len, dst_id_len, src_id_type, dst_id_type;
1915   int ret;
1916
1917   SILC_LOG_DEBUG(("Parsing incoming packet"));
1918
1919   /* Parse the buffer.  This parses the SILC header of the packet. */
1920   ret = silc_buffer_unformat(buffer,
1921                              SILC_STR_ADVANCE,
1922                              SILC_STR_OFFSET(6),
1923                              SILC_STR_UI_CHAR(&src_id_len),
1924                              SILC_STR_UI_CHAR(&dst_id_len),
1925                              SILC_STR_UI_CHAR(&src_id_type),
1926                              SILC_STR_END);
1927   if (silc_unlikely(ret == -1)) {
1928     if (!packet->stream->udp &&
1929         !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1930       SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1931     return FALSE;
1932   }
1933
1934   if (silc_unlikely(src_id_len > SILC_PACKET_MAX_ID_LEN ||
1935                     dst_id_len > SILC_PACKET_MAX_ID_LEN)) {
1936     if (!packet->stream->udp &&
1937         !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1938       SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
1939                       packet->src_id_len, packet->dst_id_len));
1940     return FALSE;
1941   }
1942
1943   ret = silc_buffer_unformat(buffer,
1944                              SILC_STR_ADVANCE,
1945                              SILC_STR_DATA(&packet->src_id, src_id_len),
1946                              SILC_STR_UI_CHAR(&dst_id_type),
1947                              SILC_STR_DATA(&packet->dst_id, dst_id_len),
1948                              SILC_STR_OFFSET(padlen),
1949                              SILC_STR_END);
1950   if (silc_unlikely(ret == -1)) {
1951     if (!packet->stream->udp &&
1952         !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1953       SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1954     return FALSE;
1955   }
1956
1957   if (silc_unlikely(src_id_type > SILC_ID_CHANNEL ||
1958                     dst_id_type > SILC_ID_CHANNEL)) {
1959     if (!packet->stream->udp &&
1960         !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1961       SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
1962                       src_id_type, dst_id_type));
1963     return FALSE;
1964   }
1965
1966   packet->src_id_len = src_id_len;
1967   packet->dst_id_len = dst_id_len;
1968   packet->src_id_type = src_id_type;
1969   packet->dst_id_type = dst_id_type;
1970
1971   SILC_LOG_HEXDUMP(("Parsed packet, len %d", silc_buffer_headlen(buffer) +
1972                    silc_buffer_len(buffer)), buffer->head,
1973                    silc_buffer_headlen(buffer) + silc_buffer_len(buffer));
1974
1975   SILC_LOG_DEBUG(("Incoming packet type: %d (%s), flags %d", packet->type,
1976                   silc_get_packet_name(packet->type), packet->flags));
1977
1978   return TRUE;
1979 }
1980
1981 /* Dispatch packet to application.  Called with stream->lock locked.
1982    Returns FALSE if the stream was destroyed while dispatching a packet. */
1983
1984 static SilcBool silc_packet_dispatch(SilcPacket packet)
1985 {
1986   SilcPacketStream stream = packet->stream;
1987   SilcPacketProcess p;
1988   SilcBool default_sent = FALSE;
1989   SilcPacketType *pt;
1990
1991   /* Dispatch packet to all packet processors that want it */
1992
1993   if (silc_likely(!stream->process)) {
1994     /* Send to default processor as no others exist */
1995     SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1996     silc_mutex_unlock(stream->lock);
1997     if (silc_unlikely(!stream->sc->engine->callbacks->
1998                       packet_receive(stream->sc->engine, stream, packet,
1999                                      stream->sc->engine->callback_context,
2000                                      stream->stream_context)))
2001       silc_packet_free(packet);
2002     silc_mutex_lock(stream->lock);
2003     return stream->destroyed == FALSE;
2004   }
2005
2006   silc_dlist_start(stream->process);
2007   while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END) {
2008
2009     /* If priority is 0 or less, we send to default processor first
2010        because default processor has 0 priority */
2011     if (!default_sent && p->priority <= 0) {
2012       SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
2013       default_sent = TRUE;
2014       silc_mutex_unlock(stream->lock);
2015       if (stream->sc->engine->callbacks->
2016           packet_receive(stream->sc->engine, stream, packet,
2017                          stream->sc->engine->callback_context,
2018                          stream->stream_context)) {
2019         silc_mutex_lock(stream->lock);
2020         return stream->destroyed == FALSE;
2021       }
2022       silc_mutex_lock(stream->lock);
2023     }
2024
2025     /* Send to processor */
2026     if (!p->types) {
2027       /* Send all packet types */
2028       SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
2029       silc_mutex_unlock(stream->lock);
2030       if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
2031                                        p->callback_context,
2032                                        stream->stream_context)) {
2033         silc_mutex_lock(stream->lock);
2034         return stream->destroyed == FALSE;
2035       }
2036       silc_mutex_lock(stream->lock);
2037     } else {
2038       /* Send specific types */
2039       for (pt = p->types; *pt; pt++) {
2040         if (*pt != packet->type)
2041           continue;
2042         SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
2043         silc_mutex_unlock(stream->lock);
2044         if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
2045                                          p->callback_context,
2046                                          stream->stream_context)) {
2047           silc_mutex_lock(stream->lock);
2048           return stream->destroyed == FALSE;
2049         }
2050         silc_mutex_lock(stream->lock);
2051         break;
2052       }
2053     }
2054   }
2055
2056   if (!default_sent) {
2057     /* Send to default processor as it has not been sent yet */
2058     SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
2059     silc_mutex_unlock(stream->lock);
2060     if (stream->sc->engine->callbacks->
2061         packet_receive(stream->sc->engine, stream, packet,
2062                        stream->sc->engine->callback_context,
2063                        stream->stream_context)) {
2064       silc_mutex_lock(stream->lock);
2065       return stream->destroyed == FALSE;
2066     }
2067     silc_mutex_lock(stream->lock);
2068   }
2069
2070   /* If we got here, no one wanted the packet, so drop it */
2071   silc_packet_free(packet);
2072   return stream->destroyed == FALSE;
2073 }
2074
2075 /* Process incoming data and parse packets.  Called with stream->lock
2076    locked. */
2077
2078 static void silc_packet_read_process(SilcPacketStream stream)
2079 {
2080   SilcBuffer inbuf;
2081   SilcCipher cipher;
2082   SilcHmac hmac;
2083   SilcPacket packet;
2084   SilcUInt8 sid;
2085   SilcUInt16 packetlen;
2086   SilcUInt32 paddedlen, mac_len, block_len, ivlen, psnlen;
2087   unsigned char tmp[SILC_PACKET_MIN_HEADER_LEN], *header;
2088   unsigned char iv[SILC_CIPHER_MAX_IV_SIZE], *packet_seq = NULL;
2089   SilcBool normal;
2090   int ret;
2091
2092   /* Get inbuf.  If there is already some data for this stream in the buffer
2093      we already have it.  Otherwise get the current one from list, it will
2094      include the data. */
2095   inbuf = stream->inbuf;
2096   if (!inbuf) {
2097     silc_dlist_start(stream->sc->inbufs);
2098     inbuf = silc_dlist_get(stream->sc->inbufs);
2099   }
2100
2101   /* Parse the packets from the data */
2102   while (silc_buffer_len(inbuf) > 0) {
2103     ivlen = psnlen = 0;
2104     cipher = stream->receive_key[0];
2105     hmac = stream->receive_hmac[0];
2106     normal = FALSE;
2107
2108     if (silc_unlikely(silc_buffer_len(inbuf) <
2109                       (stream->iv_included ? SILC_PACKET_MIN_HEADER_LEN_IV :
2110                        SILC_PACKET_MIN_HEADER_LEN))) {
2111       SILC_LOG_DEBUG(("Partial packet in queue, waiting for the rest"));
2112       silc_dlist_del(stream->sc->inbufs, inbuf);
2113       stream->inbuf = inbuf;
2114       return;
2115     }
2116
2117     if (silc_likely(hmac))
2118       mac_len = silc_hmac_len(hmac);
2119     else
2120       mac_len = 0;
2121
2122     /* Decrypt first block of the packet to get the length field out */
2123     if (silc_likely(cipher)) {
2124       block_len = silc_cipher_get_block_len(cipher);
2125
2126       if (stream->iv_included) {
2127         /* SID, IV and sequence number is included in the ciphertext */
2128         sid = (SilcUInt8)inbuf->data[0];
2129
2130         if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR) {
2131           /* Set the CTR mode IV from packet to counter block */
2132           memcpy(iv, silc_cipher_get_iv(cipher), block_len);
2133           silc_packet_receive_ctr_increment(stream, iv, inbuf->data + 1);
2134           ivlen = 8 + 1;
2135         } else {
2136           /* Get IV from packet */
2137           memcpy(iv, inbuf->data + 1, block_len);
2138           ivlen = block_len + 1;
2139         }
2140         psnlen = 4;
2141
2142         /* Check SID, and get correct decryption key */
2143         if (sid != stream->sid) {
2144           /* If SID is recent get the previous key and use it */
2145           if (sid > 0 && stream->sid > 0 && stream->sid - 1 == sid &&
2146               stream->receive_key[1] && !stream->receive_hmac[1]) {
2147             cipher = stream->receive_key[1];
2148             hmac = stream->receive_hmac[1];
2149           } else {
2150             /* The SID is unknown, drop rest of the data in buffer */
2151             SILC_LOG_DEBUG(("Unknown Security ID %d in packet, expected %d",
2152                             sid, stream->sid));
2153             silc_mutex_unlock(stream->lock);
2154             SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_UNKNOWN_SID);
2155             silc_mutex_lock(stream->lock);
2156             goto out;
2157           }
2158         }
2159       } else {
2160         memcpy(iv, silc_cipher_get_iv(cipher), block_len);
2161
2162         /* If using CTR mode, increment the counter */
2163         if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR)
2164           silc_packet_receive_ctr_increment(stream, iv, NULL);
2165       }
2166
2167       if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR)
2168         silc_cipher_set_iv(cipher, NULL);
2169       silc_cipher_decrypt(cipher, inbuf->data + ivlen, tmp, block_len, iv);
2170
2171       header = tmp;
2172       if (stream->iv_included) {
2173         /* Take sequence number from packet */
2174         packet_seq = header;
2175         header += 4;
2176       }
2177     } else {
2178       /* Unencrypted packet */
2179       block_len = SILC_PACKET_MIN_HEADER_LEN;
2180       header = inbuf->data;
2181     }
2182
2183     /* Get packet length and full packet length with padding */
2184     SILC_PACKET_LENGTH(header, packetlen, paddedlen);
2185
2186     /* Sanity checks */
2187     if (silc_unlikely(packetlen < SILC_PACKET_MIN_LEN)) {
2188       if (!stream->udp && !silc_socket_stream_is_udp(stream->stream, NULL))
2189         SILC_LOG_ERROR(("Received too short packet"));
2190       silc_mutex_unlock(stream->lock);
2191       SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2192       silc_mutex_lock(stream->lock);
2193       memset(tmp, 0, sizeof(tmp));
2194       goto out;
2195     }
2196
2197     if (silc_buffer_len(inbuf) < paddedlen + ivlen + mac_len) {
2198       SILC_LOG_DEBUG(("Received partial packet, waiting for the rest "
2199                       "(%d bytes)",
2200                       paddedlen + mac_len - silc_buffer_len(inbuf)));
2201       memset(tmp, 0, sizeof(tmp));
2202       silc_dlist_del(stream->sc->inbufs, inbuf);
2203       stream->inbuf = inbuf;
2204       return;
2205     }
2206
2207     /* Check MAC of the packet */
2208     if (silc_unlikely(!silc_packet_check_mac(hmac, inbuf->data,
2209                                              paddedlen + ivlen,
2210                                              inbuf->data + ivlen +
2211                                              paddedlen, packet_seq,
2212                                              stream->receive_psn))) {
2213       silc_mutex_unlock(stream->lock);
2214       SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MAC_FAILED);
2215       silc_mutex_lock(stream->lock);
2216       memset(tmp, 0, sizeof(tmp));
2217       goto out;
2218     }
2219
2220     /* Get packet */
2221     packet = silc_packet_alloc(stream->sc->engine);
2222     if (silc_unlikely(!packet)) {
2223       silc_mutex_unlock(stream->lock);
2224       SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2225       silc_mutex_lock(stream->lock);
2226       memset(tmp, 0, sizeof(tmp));
2227       goto out;
2228     }
2229     packet->stream = stream;
2230
2231     /* Allocate more space to packet buffer, if needed */
2232     if (silc_unlikely(silc_buffer_truelen(&packet->buffer) < paddedlen)) {
2233       if (!silc_buffer_realloc(&packet->buffer,
2234                                silc_buffer_truelen(&packet->buffer) +
2235                                (paddedlen -
2236                                 silc_buffer_truelen(&packet->buffer)))) {
2237         silc_mutex_unlock(stream->lock);
2238         SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2239         silc_mutex_lock(stream->lock);
2240         silc_packet_free(packet);
2241         memset(tmp, 0, sizeof(tmp));
2242         goto out;
2243       }
2244     }
2245
2246     /* Parse packet header */
2247     packet->flags = (SilcPacketFlags)header[2];
2248     packet->type = (SilcPacketType)header[3];
2249
2250     if (stream->sc->engine->local_is_router) {
2251       if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
2252           (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
2253         normal = FALSE;
2254       else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE ||
2255                (packet->type == SILC_PACKET_CHANNEL_MESSAGE &&
2256                 stream->is_router == TRUE))
2257         normal = TRUE;
2258     } else {
2259       if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
2260           (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
2261         normal = FALSE;
2262       else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE)
2263         normal = TRUE;
2264     }
2265
2266     SILC_LOG_HEXDUMP(("Incoming packet (%d) len %d",
2267                       stream->receive_psn, paddedlen + ivlen + mac_len),
2268                      inbuf->data, paddedlen + ivlen + mac_len);
2269
2270     /* Put the decrypted part, and rest of the encrypted data, and decrypt */
2271     silc_buffer_pull_tail(&packet->buffer, paddedlen);
2272     silc_buffer_put(&packet->buffer, header, block_len - psnlen);
2273     silc_buffer_pull(&packet->buffer, block_len - psnlen);
2274     silc_buffer_put(&packet->buffer, (inbuf->data + ivlen +
2275                                       psnlen + (block_len - psnlen)),
2276                     paddedlen - ivlen - psnlen - (block_len - psnlen));
2277     if (silc_likely(cipher)) {
2278       silc_cipher_set_iv(cipher, iv);
2279       ret = silc_packet_decrypt(cipher, hmac, stream->receive_psn,
2280                                 &packet->buffer, normal);
2281       if (silc_unlikely(ret < 0)) {
2282         silc_mutex_unlock(stream->lock);
2283         SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_DECRYPTION_FAILED);
2284         silc_mutex_lock(stream->lock);
2285         silc_packet_free(packet);
2286         memset(tmp, 0, sizeof(tmp));
2287         goto out;
2288       }
2289
2290       stream->receive_psn++;
2291     }
2292     silc_buffer_push(&packet->buffer, block_len);
2293
2294     /* Pull the packet from inbuf thus we'll get the next one in the inbuf. */
2295     silc_buffer_pull(inbuf, paddedlen + mac_len);
2296
2297     /* Parse the packet */
2298     if (silc_unlikely(!silc_packet_parse(packet))) {
2299       silc_mutex_unlock(stream->lock);
2300       SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2301       silc_mutex_lock(stream->lock);
2302       silc_packet_free(packet);
2303       memset(tmp, 0, sizeof(tmp));
2304       goto out;
2305     }
2306
2307     /* Dispatch the packet to application */
2308     if (!silc_packet_dispatch(packet))
2309       break;
2310   }
2311
2312  out:
2313   /* Add inbuf back to free list, if we owned it. */
2314   if (stream->inbuf) {
2315     silc_dlist_add(stream->sc->inbufs, inbuf);
2316     stream->inbuf = NULL;
2317   }
2318
2319   silc_buffer_reset(inbuf);
2320 }
2321
2322 /****************************** Packet Waiting ******************************/
2323
2324 /* Packet wait receive callback */
2325 static SilcBool
2326 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2327                                 SilcPacketStream stream,
2328                                 SilcPacket packet,
2329                                 void *callback_context,
2330                                 void *stream_context);
2331
2332 /* Packet waiting callbacks */
2333 static SilcPacketCallbacks silc_packet_wait_cbs =
2334 {
2335   silc_packet_wait_packet_receive, NULL, NULL
2336 };
2337
2338 /* Packet waiting context */
2339 typedef struct {
2340   SilcMutex wait_lock;
2341   SilcCond wait_cond;
2342   SilcList packet_queue;
2343   unsigned char id[28];
2344   unsigned int id_type     : 2;
2345   unsigned int id_len      : 5;
2346   unsigned int stopped     : 1;
2347 } *SilcPacketWait;
2348
2349 /* Packet wait receive callback */
2350
2351 static SilcBool
2352 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2353                                 SilcPacketStream stream,
2354                                 SilcPacket packet,
2355                                 void *callback_context,
2356                                 void *stream_context)
2357 {
2358   SilcPacketWait pw = callback_context;
2359
2360   /* If source ID is specified check for it */
2361   if (pw->id_len) {
2362     if (pw->id_type != packet->src_id_type ||
2363         memcmp(pw->id, packet->src_id, pw->id_len))
2364       return FALSE;
2365   }
2366
2367   /* Signal the waiting thread for a new packet */
2368   silc_mutex_lock(pw->wait_lock);
2369
2370   if (silc_unlikely(pw->stopped)) {
2371     silc_mutex_unlock(pw->wait_lock);
2372     return FALSE;
2373   }
2374
2375   silc_list_add(pw->packet_queue, packet);
2376   silc_cond_broadcast(pw->wait_cond);
2377
2378   silc_mutex_unlock(pw->wait_lock);
2379
2380   return TRUE;
2381 }
2382
2383 /* Initialize packet waiting */
2384
2385 void *silc_packet_wait_init(SilcPacketStream stream,
2386                             const SilcID *source_id, ...)
2387 {
2388   SilcPacketWait pw;
2389   SilcBool ret;
2390   va_list ap;
2391
2392   pw = silc_calloc(1, sizeof(*pw));
2393   if (!pw)
2394     return NULL;
2395
2396   /* Allocate mutex and conditional variable */
2397   if (!silc_mutex_alloc(&pw->wait_lock)) {
2398     silc_free(pw);
2399     return NULL;
2400   }
2401   if (!silc_cond_alloc(&pw->wait_cond)) {
2402     silc_mutex_free(pw->wait_lock);
2403     silc_free(pw);
2404     return NULL;
2405   }
2406
2407   /* Link to the packet stream for the requested packet types */
2408   va_start(ap, source_id);
2409   ret = silc_packet_stream_link_va(stream, &silc_packet_wait_cbs, pw,
2410                                    10000000, ap);
2411   va_end(ap);
2412   if (!ret) {
2413     silc_cond_free(pw->wait_cond);
2414     silc_mutex_free(pw->wait_lock);
2415     silc_free(pw);
2416     return NULL;
2417   }
2418
2419   /* Initialize packet queue */
2420   silc_list_init(pw->packet_queue, struct SilcPacketStruct, next);
2421
2422   if (source_id) {
2423     SilcUInt32 id_len;
2424     silc_id_id2str(SILC_ID_GET_ID(*source_id), source_id->type, pw->id,
2425                    sizeof(pw->id), &id_len);
2426     pw->id_type = source_id->type;
2427     pw->id_len = id_len;
2428   }
2429
2430   return (void *)pw;
2431 }
2432
2433 /* Uninitialize packet waiting */
2434
2435 void silc_packet_wait_uninit(void *waiter, SilcPacketStream stream)
2436 {
2437   SilcPacketWait pw = waiter;
2438   SilcPacket packet;
2439
2440   /* Signal any threads to stop waiting */
2441   silc_mutex_lock(pw->wait_lock);
2442   pw->stopped = TRUE;
2443   silc_cond_broadcast(pw->wait_cond);
2444   silc_mutex_unlock(pw->wait_lock);
2445   silc_thread_yield();
2446
2447   /* Re-acquire lock and free resources */
2448   silc_mutex_lock(pw->wait_lock);
2449   silc_packet_stream_unlink(stream, &silc_packet_wait_cbs, pw);
2450
2451   /* Free any remaining packets */
2452   silc_list_start(pw->packet_queue);
2453   while ((packet = silc_list_get(pw->packet_queue)) != SILC_LIST_END)
2454     silc_packet_free(packet);
2455
2456   silc_mutex_unlock(pw->wait_lock);
2457   silc_cond_free(pw->wait_cond);
2458   silc_mutex_free(pw->wait_lock);
2459   silc_free(pw);
2460 }
2461
2462 /* Blocks thread until a packet has been received. */
2463
2464 int silc_packet_wait(void *waiter, int timeout, SilcPacket *return_packet)
2465 {
2466   SilcPacketWait pw = waiter;
2467   SilcBool ret = FALSE;
2468
2469   silc_mutex_lock(pw->wait_lock);
2470
2471   /* Wait here until packet has arrived */
2472   while (silc_list_count(pw->packet_queue) == 0) {
2473     if (silc_unlikely(pw->stopped)) {
2474       silc_mutex_unlock(pw->wait_lock);
2475       return -1;
2476     }
2477     ret = silc_cond_timedwait(pw->wait_cond, pw->wait_lock, timeout);
2478   }
2479
2480   /* Return packet */
2481   silc_list_start(pw->packet_queue);
2482   *return_packet = silc_list_get(pw->packet_queue);
2483   silc_list_del(pw->packet_queue, *return_packet);
2484
2485   silc_mutex_unlock(pw->wait_lock);
2486
2487   return ret == TRUE ? 1 : 0;
2488 }
2489
2490 /************************** Packet Stream Wrapper ***************************/
2491
2492 /* Packet stream wrapper receive callback */
2493 static SilcBool
2494 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2495                                 SilcPacketStream stream,
2496                                 SilcPacket packet,
2497                                 void *callback_context,
2498                                 void *stream_context);
2499
2500 const SilcStreamOps silc_packet_stream_ops;
2501
2502 /* Packet stream wrapper context */
2503 typedef struct {
2504   const SilcStreamOps *ops;
2505   SilcPacketStream stream;
2506   SilcMutex lock;
2507   void *waiter;                   /* Waiter context in blocking mode */
2508   SilcPacketWrapCoder coder;
2509   void *coder_context;
2510   SilcBuffer encbuf;
2511   SilcStreamNotifier callback;
2512   void *context;
2513   SilcList in_queue;
2514   SilcPacketType type;
2515   SilcPacketFlags flags;
2516   unsigned int closed        : 1;
2517   unsigned int blocking      : 1;
2518   unsigned int read_more     : 1;
2519 } *SilcPacketWrapperStream;
2520
2521 /* Packet wrapper callbacks */
2522 static SilcPacketCallbacks silc_packet_wrap_cbs =
2523 {
2524   silc_packet_wrap_packet_receive, NULL, NULL
2525 };
2526
2527 /* Packet stream wrapper receive callback, non-blocking mode */
2528
2529 static SilcBool
2530 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2531                                 SilcPacketStream stream,
2532                                 SilcPacket packet,
2533                                 void *callback_context,
2534                                 void *stream_context)
2535 {
2536   SilcPacketWrapperStream pws = callback_context;
2537
2538   if (pws->closed || !pws->callback)
2539     return FALSE;
2540
2541   silc_mutex_lock(pws->lock);
2542   silc_list_add(pws->in_queue, packet);
2543   silc_mutex_unlock(pws->lock);
2544
2545   /* Call notifier callback */
2546   pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2547
2548   return TRUE;
2549 }
2550
2551 /* Task callback to notify more data is available for reading */
2552
2553 SILC_TASK_CALLBACK(silc_packet_wrap_read_more)
2554 {
2555   SilcPacketWrapperStream pws = context;
2556
2557   if (pws->closed || !pws->callback)
2558     return;
2559
2560   /* Call notifier callback */
2561   pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2562 }
2563
2564 /* Read SILC packet */
2565
2566 int silc_packet_wrap_read(SilcStream stream, unsigned char *buf,
2567                           SilcUInt32 buf_len)
2568 {
2569   SilcPacketWrapperStream pws = stream;
2570   SilcPacket packet;
2571   SilcBool read_more = FALSE;
2572   int len;
2573
2574   if (pws->closed)
2575     return -2;
2576
2577   if (pws->blocking) {
2578     /* Block until packet is received */
2579     if ((silc_packet_wait(pws->waiter, 0, &packet)) < 0)
2580       return -2;
2581     if (pws->closed)
2582       return -2;
2583   } else {
2584     /* Non-blocking mode */
2585     silc_mutex_lock(pws->lock);
2586     if (!silc_list_count(pws->in_queue)) {
2587       silc_mutex_unlock(pws->lock);
2588       return -1;
2589     }
2590
2591     silc_list_start(pws->in_queue);
2592     packet = silc_list_get(pws->in_queue);
2593     silc_list_del(pws->in_queue, packet);
2594     silc_mutex_unlock(pws->lock);
2595   }
2596
2597   /* Call decoder if set */
2598   if (pws->coder && !pws->read_more)
2599     pws->coder(stream, SILC_STREAM_CAN_READ, &packet->buffer,
2600                pws->coder_context);
2601
2602   len = silc_buffer_len(&packet->buffer);
2603   if (len > buf_len) {
2604     len = buf_len;
2605     read_more = TRUE;
2606   }
2607
2608   /* Read data */
2609   memcpy(buf, packet->buffer.data, len);
2610
2611   if (read_more && !pws->blocking) {
2612     /* More data will be available (in blocking mode not supported). */
2613     silc_buffer_pull(&packet->buffer, len);
2614     silc_list_insert(pws->in_queue, NULL, packet);
2615     silc_schedule_task_add_timeout(pws->stream->sc->schedule,
2616                                    silc_packet_wrap_read_more, pws, 0, 0);
2617     pws->read_more = TRUE;
2618     return len;
2619   }
2620
2621   pws->read_more = FALSE;
2622   silc_packet_free(packet);
2623   return len;
2624 }
2625
2626 /* Write SILC packet */
2627
2628 int silc_packet_wrap_write(SilcStream stream, const unsigned char *data,
2629                            SilcUInt32 data_len)
2630 {
2631   SilcPacketWrapperStream pws = stream;
2632   SilcBool ret = FALSE;
2633
2634   /* Call encoder if set */
2635   if (pws->coder) {
2636     silc_buffer_reset(pws->encbuf);
2637     ret = pws->coder(stream, SILC_STREAM_CAN_WRITE, pws->encbuf,
2638                      pws->coder_context);
2639   }
2640
2641   /* Send the SILC packet */
2642   if (ret) {
2643     if (!silc_packet_send_va(pws->stream, pws->type, pws->flags,
2644                              SILC_STR_DATA(silc_buffer_data(pws->encbuf),
2645                                            silc_buffer_len(pws->encbuf)),
2646                              SILC_STR_DATA(data, data_len),
2647                              SILC_STR_END))
2648       return -2;
2649   } else {
2650     if (!silc_packet_send(pws->stream, pws->type, pws->flags, data, data_len))
2651       return -2;
2652   }
2653
2654   return data_len;
2655 }
2656
2657 /* Close stream */
2658
2659 SilcBool silc_packet_wrap_close(SilcStream stream)
2660 {
2661   SilcPacketWrapperStream pws = stream;
2662
2663   if (pws->closed)
2664     return TRUE;
2665
2666   if (pws->blocking) {
2667     /* Close packet waiter */
2668     silc_packet_wait_uninit(pws->waiter, pws->stream);
2669   } else {
2670     /* Unlink */
2671     if (pws->callback)
2672       silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2673   }
2674   pws->closed = TRUE;
2675
2676   return TRUE;
2677 }
2678
2679 /* Destroy wrapper stream */
2680
2681 void silc_packet_wrap_destroy(SilcStream stream)
2682
2683 {
2684   SilcPacketWrapperStream pws = stream;
2685   SilcPacket packet;
2686
2687   SILC_LOG_DEBUG(("Destroying wrapped packet stream %p", pws));
2688
2689   silc_stream_close(stream);
2690   silc_list_start(pws->in_queue);
2691   while ((packet = silc_list_get(pws->in_queue)))
2692     silc_packet_free(packet);
2693   if (pws->lock)
2694     silc_mutex_free(pws->lock);
2695   if (pws->encbuf)
2696     silc_buffer_free(pws->encbuf);
2697   silc_packet_stream_unref(pws->stream);
2698
2699   silc_free(pws);
2700 }
2701
2702 /* Link stream to receive packets */
2703
2704 SilcBool silc_packet_wrap_notifier(SilcStream stream,
2705                                    SilcSchedule schedule,
2706                                    SilcStreamNotifier callback,
2707                                    void *context)
2708 {
2709   SilcPacketWrapperStream pws = stream;
2710
2711   if (pws->closed || pws->blocking)
2712     return FALSE;
2713
2714   /* Link to receive packets */
2715   if (callback)
2716     silc_packet_stream_link(pws->stream, &silc_packet_wrap_cbs, pws,
2717                             100000, pws->type, -1);
2718   else
2719     silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2720
2721   pws->callback = callback;
2722   pws->context = context;
2723
2724   return TRUE;
2725 }
2726
2727 /* Return schedule */
2728
2729 SilcSchedule silc_packet_wrap_get_schedule(SilcStream stream)
2730 {
2731   return NULL;
2732 }
2733
2734 /* Wraps packet stream into SilcStream. */
2735
2736 SilcStream silc_packet_stream_wrap(SilcPacketStream stream,
2737                                    SilcPacketType type,
2738                                    SilcPacketFlags flags,
2739                                    SilcBool blocking_mode,
2740                                    SilcPacketWrapCoder coder,
2741                                    void *context)
2742 {
2743   SilcPacketWrapperStream pws;
2744
2745   pws = silc_calloc(1, sizeof(*pws));
2746   if (!pws)
2747     return NULL;
2748
2749   SILC_LOG_DEBUG(("Wrapping packet stream %p to stream %p", stream, pws));
2750
2751   pws->ops = &silc_packet_stream_ops;
2752   pws->stream = stream;
2753   pws->type = type;
2754   pws->flags = flags;
2755   pws->blocking = blocking_mode;
2756   pws->coder = coder;
2757   pws->coder_context = context;
2758
2759   /* Allocate small amount for encoder buffer. */
2760   if (pws->coder)
2761     pws->encbuf = silc_buffer_alloc(8);
2762
2763   if (pws->blocking) {
2764     /* Blocking mode.  Use packet waiter to do the thing. */
2765     pws->waiter = silc_packet_wait_init(pws->stream, NULL, pws->type, -1);
2766     if (!pws->waiter) {
2767       silc_free(pws);
2768       return NULL;
2769     }
2770   } else {
2771     /* Non-blocking mode */
2772     silc_mutex_alloc(&pws->lock);
2773     silc_list_init(pws->in_queue, struct SilcPacketStruct, next);
2774   }
2775
2776   silc_packet_stream_ref(stream);
2777
2778   return (SilcStream)pws;
2779 }
2780
2781 const SilcStreamOps silc_packet_stream_ops =
2782 {
2783   silc_packet_wrap_read,
2784   silc_packet_wrap_write,
2785   silc_packet_wrap_close,
2786   silc_packet_wrap_destroy,
2787   silc_packet_wrap_notifier,
2788   silc_packet_wrap_get_schedule,
2789 };