Added silc_packet_stream_link, silc_packet_stream_unlink.
[silc.git] / lib / silccore / silcpacket.c
1 /*
2
3   silcpacket.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2006 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 /* Packet engine */
29 struct SilcPacketEngineStruct {
30   SilcRng rng;                           /* RNG for engine */
31   SilcPacketCallbacks *callbacks;        /* Packet callbacks */
32   void *callback_context;                /* Context for callbacks */
33   SilcList streams;                      /* All streams in engine */
34   SilcList packet_pool;                  /* Free list for received packets */
35   SilcMutex lock;                        /* Engine lock */
36   SilcBool local_is_router;
37 };
38
39 /* Packet procesor context */
40 typedef struct SilcPacketProcessStruct {
41   SilcInt32 priority;                    /* Priority */
42   SilcPacketType *types;                 /* Packets to process */
43   SilcPacketCallbacks *callbacks;        /* Callbacks or NULL */
44   void *callback_context;
45 } *SilcPacketProcess;
46
47 /* Packet stream */
48 struct SilcPacketStreamStruct {
49   struct SilcPacketStreamStruct *next;
50   SilcPacketEngine engine;               /* Packet engine */
51   SilcStream stream;                     /* Underlaying stream */
52   SilcMutex lock;                        /* Stream lock */
53   SilcDList process;                     /* Packet processors, it set */
54   SilcHashTable streamers;               /* Valid if streamers exist */
55   void *stream_context;                  /* Stream context */
56   SilcBufferStruct inbuf;                /* In buffer */
57   SilcBufferStruct outbuf;               /* Out buffer */
58   SilcUInt32 send_psn;                   /* Sending sequence */
59   SilcCipher send_key;                   /* Sending key */
60   SilcHmac send_hmac;                    /* Sending HMAC */
61   SilcUInt32 receive_psn;                /* Receiving sequence */
62   SilcCipher receive_key;                /* Receiving key */
63   SilcHmac receive_hmac;                 /* Receiving HMAC */
64   unsigned char *src_id;                 /* Source ID */
65   unsigned char *dst_id;                 /* Destination ID */
66   unsigned int src_id_len  : 6;
67   unsigned int src_id_type : 2;
68   unsigned int dst_id_len  : 6;
69   unsigned int dst_id_type : 2;
70   SilcUInt8 refcnt;                      /* Reference counter */
71   unsigned int is_router   : 1;          /* Set if router stream */
72   unsigned int destroyed   : 1;          /* Set if destroyed */
73 };
74
75 /* Initial size of stream buffers */
76 #define SILC_PACKET_DEFAULT_SIZE  1024
77
78 /* Header length without source and destination ID's. */
79 #define SILC_PACKET_HEADER_LEN 10
80
81 /* Minimum length of SILC Packet Header. This much is decrypted always
82    when packet is received to be able to get all the relevant data out
83    from the header. */
84 #define SILC_PACKET_MIN_HEADER_LEN 16
85
86 /* Maximum padding length */
87 #define SILC_PACKET_MAX_PADLEN 128
88
89 /* Default padding length */
90 #define SILC_PACKET_DEFAULT_PADLEN 16
91
92 /* Minimum packet length */
93 #define SILC_PACKET_MIN_LEN (SILC_PACKET_HEADER_LEN + 1)
94
95
96 /* Macros */
97
98 /* Returns true length of the packet. */
99 #define SILC_PACKET_LENGTH(__packetdata, __ret_truelen, __ret_paddedlen) \
100 do {                                                                     \
101   SILC_GET16_MSB((__ret_truelen), (__packetdata));                       \
102   (__ret_paddedlen) = (__ret_truelen) + (SilcUInt8)(__packetdata)[4];    \
103 } while(0)
104
105 /* Calculates the data length with given header length.  This macro
106    can be used to check whether the data_len with header_len exceeds
107    SILC_PACKET_MAX_LEN.  If it does, this returns the new data_len
108    so that the SILC_PACKET_MAX_LEN is not exceeded.  If the data_len
109    plus header_len fits SILC_PACKET_MAX_LEN the returned data length
110    is the data_len given as argument. */
111 #define SILC_PACKET_DATALEN(data_len, header_len)                         \
112   ((data_len + header_len) > SILC_PACKET_MAX_LEN ?                        \
113    data_len - ((data_len + header_len) - SILC_PACKET_MAX_LEN) : data_len)
114
115 /* Calculates the length of the padding in the packet. */
116 #define SILC_PACKET_PADLEN(__packetlen, __blocklen, __padlen)               \
117 do {                                                                        \
118   __padlen = (SILC_PACKET_DEFAULT_PADLEN - (__packetlen) %                  \
119               ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN));  \
120   if (__padlen < 8)                                                         \
121     __padlen += ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN); \
122 } while(0)
123
124 /* Returns the length of the padding up to the maximum length, which
125    is 128 bytes.*/
126 #define SILC_PACKET_PADLEN_MAX(__packetlen, __blocklen, __padlen)          \
127 do {                                                                       \
128   __padlen = (SILC_PACKET_MAX_PADLEN - (__packetlen) %                     \
129               ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN)); \
130 } while(0)
131
132 /* EOS callback */
133 #define SILC_PACKET_CALLBACK_EOS(s)                                     \
134 do {                                                                    \
135   (s)->engine->callbacks->eos((s)->engine, s,                           \
136                               (s)->engine->callback_context,            \
137                               (s)->stream_context);                     \
138 } while(0)
139
140 /* Error callback */
141 #define SILC_PACKET_CALLBACK_ERROR(s, err)                              \
142 do {                                                                    \
143   (s)->engine->callbacks->error((s)->engine, s, err,                    \
144                                 (s)->engine->callback_context,          \
145                                 (s)->stream_context);                   \
146 } while(0)
147
148
149 /************************ Static utility functions **************************/
150
151 static void silc_packet_read_process(SilcPacketStream stream);
152
153 /* Our stream IO notifier callback. */
154
155 static void silc_packet_stream_io(SilcStream stream, SilcStreamStatus status,
156                                   void *context)
157 {
158   SilcPacketStream ps = context;
159   int ret;
160
161   silc_mutex_lock(ps->lock);
162
163   if (ps->destroyed) {
164     silc_mutex_unlock(ps->lock);
165     return;
166   }
167
168   switch (status) {
169
170   case SILC_STREAM_CAN_WRITE:
171     if (!silc_buffer_headlen(&ps->outbuf)) {
172       silc_mutex_unlock(ps->lock);
173       return;
174     }
175
176     SILC_LOG_DEBUG(("Writing pending data to stream"));
177
178     /* Write pending data to stream */
179     while (silc_buffer_len(&ps->outbuf) > 0) {
180       ret = silc_stream_write(ps->stream, ps->outbuf.data,
181                               silc_buffer_len(&ps->outbuf));
182       if (ret == 0) {
183         /* EOS */
184         silc_buffer_reset(&ps->outbuf);
185         silc_mutex_unlock(ps->lock);
186         SILC_PACKET_CALLBACK_EOS(ps);
187         return;
188       }
189
190       if (ret == -2) {
191         /* Error */
192         silc_buffer_reset(&ps->outbuf);
193         silc_mutex_unlock(ps->lock);
194         SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_WRITE);
195         return;
196       }
197
198       if (ret == -1) {
199         /* Cannot write now, write later. */
200         silc_mutex_unlock(ps->lock);
201         return;
202       }
203
204       /* Wrote data */
205       silc_buffer_pull(&ps->outbuf, ret);
206     }
207
208     silc_buffer_reset(&ps->outbuf);
209
210     silc_mutex_unlock(ps->lock);
211     break;
212
213   case SILC_STREAM_CAN_READ:
214     /* Packet receiving can only happen in one thread for one SilcPacketStream,
215        so locking is not required in packet receiving procedure. */
216     silc_mutex_unlock(ps->lock);
217
218     SILC_LOG_DEBUG(("Reading data from stream"));
219
220     /* Make sure we have fair amount of free space in inbuf */
221     if (silc_buffer_taillen(&ps->inbuf) < SILC_PACKET_DEFAULT_SIZE)
222       if (!silc_buffer_realloc(&ps->inbuf, silc_buffer_truelen(&ps->inbuf) +
223                                SILC_PACKET_DEFAULT_SIZE * 2))
224         return;
225
226     /* Read data from stream */
227     ret = silc_stream_read(ps->stream, ps->inbuf.tail,
228                            silc_buffer_taillen(&ps->inbuf));
229
230     if (ret == 0) {
231       /* EOS */
232       silc_buffer_reset(&ps->inbuf);
233       SILC_PACKET_CALLBACK_EOS(ps);
234       return;
235     }
236
237     if (ret == -2) {
238       /* Error */
239       silc_buffer_reset(&ps->inbuf);
240       SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_READ);
241       return;
242     }
243
244     if (ret == -1) {
245       /* Cannot read now, do it later. */
246       silc_buffer_pull(&ps->inbuf, silc_buffer_len(&ps->inbuf));
247       return;
248     }
249
250     /* Read some data */
251     silc_buffer_pull_tail(&ps->inbuf, ret);
252
253     /* Now process the data */
254     silc_packet_read_process(ps);
255
256     break;
257
258   default:
259     silc_mutex_unlock(ps->lock);
260     break;
261   }
262 }
263
264 /* Allocate packet */
265
266 static SilcPacket silc_packet_alloc(SilcPacketEngine engine)
267 {
268   SilcPacket packet;
269
270   SILC_LOG_DEBUG(("Packet pool count %d",
271                   silc_list_count(engine->packet_pool)));
272
273   silc_mutex_lock(engine->lock);
274
275   /* Get packet from freelist or allocate new one. */
276   packet = silc_list_get(engine->packet_pool);
277   if (!packet) {
278     void *tmp;
279
280     silc_mutex_unlock(engine->lock);
281
282     packet = silc_calloc(1, sizeof(*packet));
283     if (!packet)
284       return NULL;
285
286     SILC_LOG_DEBUG(("Allocating new packet %p", packet));
287
288     tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
289     if (!tmp) {
290       silc_free(packet);
291       return NULL;
292     }
293     silc_buffer_set(&packet->buffer, tmp, SILC_PACKET_DEFAULT_SIZE);
294     silc_buffer_reset(&packet->buffer);
295
296     return packet;
297   }
298
299   SILC_LOG_DEBUG(("Get packet %p", packet));
300
301   /* Delete from freelist */
302   silc_list_del(engine->packet_pool, packet);
303
304   silc_mutex_unlock(engine->lock);
305
306   return packet;
307 }
308
309
310 /******************************** Packet API ********************************/
311
312 /* Allocate new packet engine */
313
314 SilcPacketEngine
315 silc_packet_engine_start(SilcRng rng, SilcBool router,
316                          SilcPacketCallbacks *callbacks,
317                          void *callback_context)
318 {
319   SilcPacketEngine engine;
320   SilcPacket packet;
321   int i;
322   void *tmp;
323
324   SILC_LOG_DEBUG(("Starting new packet engine"));
325
326   if (!callbacks)
327     return NULL;
328   if (!callbacks->packet_receive || !callbacks->eos || !callbacks->error)
329     return NULL;
330
331   engine = silc_calloc(1, sizeof(*engine));
332   if (!engine)
333     return NULL;
334
335   engine->rng = rng;
336   engine->local_is_router = router;
337   engine->callbacks = callbacks;
338   engine->callback_context = callback_context;
339   silc_list_init(engine->streams, struct SilcPacketStreamStruct, next);
340   silc_mutex_alloc(&engine->lock);
341
342   /* Allocate packet free list */
343   silc_list_init(engine->packet_pool, struct SilcPacketStruct, next);
344   for (i = 0; i < 5; i++) {
345     packet = silc_calloc(1, sizeof(*packet));
346     if (!packet)
347       return NULL;
348
349     tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
350     if (!tmp)
351       return NULL;
352     silc_buffer_set(&packet->buffer, tmp, SILC_PACKET_DEFAULT_SIZE);
353     silc_buffer_reset(&packet->buffer);
354
355     silc_list_add(engine->packet_pool, packet);
356   }
357   silc_list_start(engine->packet_pool);
358
359   return engine;
360 }
361
362 /* Stop packet engine */
363
364 void silc_packet_engine_stop(SilcPacketEngine engine)
365 {
366
367   SILC_LOG_DEBUG(("Stopping packet engine"));
368
369   if (!engine)
370     return;
371
372   /* XXX */
373
374   silc_free(engine);
375 }
376
377 /* Create new packet stream */
378
379 SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
380                                            SilcSchedule schedule,
381                                            SilcStream stream)
382 {
383   SilcPacketStream ps;
384   void *tmp;
385
386   SILC_LOG_DEBUG(("Creating new packet stream"));
387
388   if (!engine || !stream)
389     return NULL;
390
391   ps = silc_calloc(1, sizeof(*ps));
392   if (!ps)
393     return NULL;
394
395   ps->engine = engine;
396   ps->stream = stream;
397   ps->refcnt++;
398
399   /* Allocate buffers */
400   tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
401   if (!tmp)
402     return NULL;
403   silc_buffer_set(&ps->inbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
404   silc_buffer_reset(&ps->inbuf);
405   tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
406   if (!tmp)
407     return NULL;
408   silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
409   silc_buffer_reset(&ps->outbuf);
410
411   /* Initialize packet procesors list */
412   ps->process = silc_dlist_init();
413
414   /* Set IO notifier callback */
415   silc_stream_set_notifier(ps->stream, schedule, silc_packet_stream_io, ps);
416
417   silc_mutex_alloc(&ps->lock);
418
419   /* Add to engine */
420   silc_mutex_lock(engine->lock);
421   silc_list_add(engine->streams, ps);
422   silc_mutex_unlock(engine->lock);
423
424   return ps;
425 }
426
427 /* Destroy packet stream */
428
429 void silc_packet_stream_destroy(SilcPacketStream stream)
430 {
431   if (!stream)
432     return;
433
434   if (stream->refcnt > 1) {
435     stream->destroyed = TRUE;
436     return;
437   }
438
439   SILC_LOG_DEBUG(("Destroying packet stream %p", stream));
440
441   /* Delete from engine */
442   silc_mutex_lock(stream->engine->lock);
443   silc_list_del(stream->engine->streams, stream);
444   silc_mutex_unlock(stream->engine->lock);
445
446   /* Clear and free buffers */
447   silc_buffer_clear(&stream->inbuf);
448   silc_buffer_clear(&stream->outbuf);
449   silc_free(silc_buffer_steal(&stream->inbuf, NULL));
450   silc_free(silc_buffer_steal(&stream->outbuf, NULL));
451
452   silc_dlist_uninit(stream->process);
453
454   /* XXX */
455
456   silc_free(stream);
457 }
458
459 /* Marks as router stream */
460
461 void silc_packet_stream_set_router(SilcPacketStream stream)
462 {
463   stream->is_router = TRUE;
464 }
465
466
467 /* Links `callbacks' to `stream' for specified packet types */
468
469 static SilcBool silc_packet_stream_link_va(SilcPacketStream stream,
470                                            SilcPacketCallbacks *callbacks,
471                                            void *callback_context,
472                                            int priority, va_list ap)
473 {
474   SilcPacketProcess p, e;
475   SilcInt32 packet_type;
476   int i;
477
478   SILC_LOG_DEBUG(("Linking callbacks %p to stream %p", callbacks, stream));
479
480   if (!callbacks)
481     return FALSE;
482   if (!callbacks->packet_receive)
483     return FALSE;
484
485   p = silc_calloc(1, sizeof(*p));
486   if (!p)
487     return FALSE;
488
489   p->priority = priority;
490   p->callbacks = callbacks;
491   p->callback_context = callback_context;
492
493   silc_mutex_lock(stream->lock);
494
495   if (!stream->process) {
496     stream->process = silc_dlist_init();
497     if (!stream->process)
498       return FALSE;
499   }
500
501   /* According to priority set the procesor to correct position.  First
502      entry has the highest priority */
503   silc_dlist_start(stream->process);
504   while ((e = silc_dlist_get(stream->process)) != SILC_LIST_END) {
505     if (p->priority > e->priority) {
506       silc_dlist_insert(stream->process, p);
507       break;
508     }
509   }
510   if (!e)
511     silc_dlist_add(stream->process, p);
512
513   /* Get packet types to process */
514   i = 1;
515   while (1) {
516     packet_type = va_arg(ap, SilcInt32);
517
518     if (packet_type == SILC_PACKET_ANY)
519       break;
520
521     if (packet_type == -1)
522       break;
523
524     p->types = silc_realloc(p->types, sizeof(*p->types) * (i + 1));
525     if (!p->types) {
526       silc_mutex_unlock(stream->lock);
527       return FALSE;
528     }
529
530     p->types[i - 1] = (SilcPacketType)packet_type;
531     i++;
532   }
533   if (p->types)
534     p->types[i - 1] = 0;
535
536   silc_mutex_unlock(stream->lock);
537
538   silc_packet_stream_ref(stream);
539
540   return TRUE;
541 }
542
543 /* Links `callbacks' to `stream' for specified packet types */
544
545 SilcBool silc_packet_stream_link(SilcPacketStream stream,
546                                  SilcPacketCallbacks *callbacks,
547                                  void *callback_context,
548                                  int priority, ...)
549 {
550   va_list ap;
551   SilcBool ret;
552
553   va_start(ap, priority);
554   ret = silc_packet_stream_link_va(stream, callbacks, callback_context,
555                                    priority, ap);
556   va_end(ap);
557
558   return ret;
559 }
560
561 /* Unlinks `callbacks' from `stream'. */
562
563 void silc_packet_stream_unlink(SilcPacketStream stream,
564                                SilcPacketCallbacks *callbacks,
565                                void *callback_context)
566 {
567   SilcPacketProcess p;
568
569   SILC_LOG_DEBUG(("Unlinking callbacks %p from stream %p",
570                   callbacks, stream));
571
572   silc_mutex_lock(stream->lock);
573
574   silc_dlist_start(stream->process);
575   while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END)
576     if (p->callbacks == callbacks &&
577         p->callback_context == callback_context) {
578       silc_dlist_del(stream->process, p);
579       silc_free(p);
580       break;
581     }
582
583   if (!silc_dlist_count(stream->process)) {
584     silc_dlist_uninit(stream->process);
585     stream->process = NULL;
586   }
587
588   silc_mutex_unlock(stream->lock);
589
590   silc_packet_stream_unref(stream);
591 }
592
593 /* Reference packet stream */
594
595 void silc_packet_stream_ref(SilcPacketStream stream)
596 {
597   silc_mutex_lock(stream->lock);
598   stream->refcnt++;
599   silc_mutex_unlock(stream->lock);
600 }
601
602 /* Unreference packet stream */
603
604 void silc_packet_stream_unref(SilcPacketStream stream)
605 {
606   silc_mutex_lock(stream->lock);
607   stream->refcnt--;
608   silc_mutex_unlock(stream->lock);
609   if (stream->refcnt == 0)
610     silc_packet_stream_destroy(stream);
611 }
612
613 /* Return engine */
614
615 SilcPacketEngine silc_packet_get_engine(SilcPacketStream stream)
616 {
617   return stream->engine;
618 }
619
620 /* Set application context for packet stream */
621
622 void silc_packet_set_context(SilcPacketStream stream, void *stream_context)
623 {
624   stream->stream_context = stream_context;
625 }
626
627 /* Return application context from packet stream */
628
629 void *silc_packet_get_context(SilcPacketStream stream)
630 {
631   return stream->stream_context;
632 }
633
634 /* Return underlaying stream */
635
636 SilcStream silc_packet_stream_get_stream(SilcPacketStream stream)
637 {
638   return stream->stream;
639 }
640
641 /* Set ciphers for packet stream */
642
643 void silc_packet_set_ciphers(SilcPacketStream stream, SilcCipher send,
644                              SilcCipher receive)
645 {
646   SILC_LOG_DEBUG(("Setting new ciphers to packet stream"));
647   stream->send_key = send;
648   stream->receive_key = receive;
649 }
650
651 /* Return current ciphers from packet stream */
652
653 SilcBool silc_packet_get_ciphers(SilcPacketStream stream, SilcCipher *send,
654                                  SilcCipher *receive)
655 {
656   if (!stream->send_key && !stream->receive_key)
657     return FALSE;
658
659   if (send)
660     *send = stream->send_key;
661   if (receive)
662     *receive = stream->receive_key;
663
664   return TRUE;
665 }
666
667 /* Set HMACs for packet stream */
668
669 void silc_packet_set_hmacs(SilcPacketStream stream, SilcHmac send,
670                            SilcHmac receive)
671 {
672   SILC_LOG_DEBUG(("Setting new HMACs to packet stream"));
673   stream->send_hmac = send;
674   stream->receive_hmac = receive;
675 }
676
677 /* Return current HMACs from packet stream */
678
679 SilcBool silc_packet_get_hmacs(SilcPacketStream stream, SilcHmac *send,
680                                SilcHmac *receive)
681 {
682   if (!stream->send_hmac && !stream->receive_hmac)
683     return FALSE;
684
685   if (send)
686     *send = stream->send_hmac;
687   if (receive)
688     *receive = stream->receive_hmac;
689
690   return TRUE;
691 }
692
693 /* Set SILC IDs to packet stream */
694
695 SilcBool silc_packet_set_ids(SilcPacketStream stream,
696                              SilcIdType src_id_type, const void *src_id,
697                              SilcIdType dst_id_type, const void *dst_id)
698 {
699   SilcUInt32 len;
700   unsigned char tmp[32];
701
702   if (!src_id && !dst_id)
703     return FALSE;
704
705   SILC_LOG_DEBUG(("Setting new IDs to packet stream"));
706
707   if (src_id) {
708     silc_free(stream->src_id);
709     if (!silc_id_id2str(src_id, src_id_type, tmp, sizeof(tmp), &len))
710       return FALSE;
711     stream->src_id = silc_memdup(tmp, len);
712     if (!stream->src_id)
713       return FALSE;
714     stream->src_id_type = src_id_type;
715     stream->src_id_len = len;
716   }
717
718   if (dst_id) {
719     silc_free(stream->dst_id);
720     if (!silc_id_id2str(dst_id, dst_id_type, tmp, sizeof(tmp), &len))
721       return FALSE;
722     stream->dst_id = silc_memdup(tmp, len);
723     if (!stream->dst_id)
724       return FALSE;
725     stream->dst_id_type = dst_id_type;
726     stream->dst_id_len = len;
727   }
728
729   return TRUE;
730 }
731
732 /* Free packet */
733
734 void silc_packet_free(SilcPacket packet)
735 {
736   SilcPacketStream stream = packet->stream;
737
738   SILC_LOG_DEBUG(("Freeing packet %p", packet));
739
740 #if defined(SILC_DEBUG)
741   /* Check for double free */
742   assert(packet->stream != NULL);
743 #endif /* SILC_DEBUG */
744
745   silc_mutex_lock(stream->engine->lock);
746
747   packet->stream = NULL;
748   packet->src_id = packet->dst_id = NULL;
749   silc_buffer_reset(&packet->buffer);
750
751   /* Put the packet back to freelist */
752   silc_list_add(stream->engine->packet_pool, packet);
753
754   silc_mutex_unlock(stream->engine->lock);
755 }
756
757 /* Creates streamer */
758
759 SilcStream silc_packet_streamer_create(SilcPacketStream stream,
760                                        SilcPacketType packet_type,
761                                        SilcPacketFlags packet_flags)
762 {
763   /* XXX TODO */
764   return NULL;
765 }
766
767 /* Destroyes streamer */
768
769 void silc_packet_streamer_destroy(SilcStream stream)
770 {
771
772 }
773
774
775 /****************************** Packet Sending ******************************/
776
777 /* Prepare outgoing data buffer for packet sending.  Returns the
778    pointer to that buffer into the `packet'. */
779
780 static SilcBool silc_packet_send_prepare(SilcPacketStream stream,
781                                          SilcUInt32 totlen,
782                                          SilcHmac hmac,
783                                          SilcBuffer packet)
784 {
785   unsigned char *oldptr;
786   unsigned int mac_len = hmac ? silc_hmac_len(hmac) : 0;
787
788   totlen += mac_len;
789
790   /* Allocate more space if needed */
791   if (silc_buffer_taillen(&stream->outbuf) < totlen) {
792     if (!silc_buffer_realloc(&stream->outbuf,
793                              silc_buffer_truelen(&stream->outbuf) + totlen))
794       return FALSE;
795   }
796
797   /* Pull data area for the new packet, and return pointer to the start of
798      the data area and save the pointer in to the `packet'.  MAC is pulled
799      later after it's computed. */
800   oldptr = silc_buffer_pull_tail(&stream->outbuf, totlen);
801   silc_buffer_set(packet, oldptr, totlen);
802   silc_buffer_push_tail(packet, mac_len);
803
804   return TRUE;
805 }
806
807 /* Internal routine to send packet */
808
809 static SilcBool silc_packet_send_raw(SilcPacketStream stream,
810                                      SilcPacketType type,
811                                      SilcPacketFlags flags,
812                                      SilcIdType src_id_type,
813                                      unsigned char *src_id,
814                                      SilcUInt32 src_id_len,
815                                      SilcIdType dst_id_type,
816                                      unsigned char *dst_id,
817                                      SilcUInt32 dst_id_len,
818                                      const unsigned char *data,
819                                      SilcUInt32 data_len,
820                                      SilcCipher cipher,
821                                      SilcHmac hmac)
822 {
823   unsigned char tmppad[SILC_PACKET_MAX_PADLEN];
824   int block_len = (cipher ? silc_cipher_get_block_len(cipher) : 0);
825   int i, enclen, truelen, padlen;
826   SilcBufferStruct packet;
827
828   SILC_LOG_DEBUG(("Sending packet %s (%d) flags %d, src %d dst %d,"
829                   "data len %d", silc_get_packet_name(type), stream->send_psn,
830                   flags, src_id_type, dst_id_type, data_len));
831
832   /* Get the true length of the packet. This is saved as payload length
833      into the packet header.  This does not include the length of the
834      padding. */
835   data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
836                                             src_id_len + dst_id_len));
837   enclen = truelen = (data_len + SILC_PACKET_HEADER_LEN +
838                       src_id_len + dst_id_len);
839
840   /* We automatically figure out the packet structure from the packet
841      type and flags, and calculate correct length.  Private messages with
842      private keys and channel messages are special packets as their
843      payload is encrypted already. */
844   if ((type == SILC_PACKET_PRIVATE_MESSAGE &&
845        flags & SILC_PACKET_FLAG_PRIVMSG_KEY) ||
846       type == SILC_PACKET_CHANNEL_MESSAGE) {
847
848     /* Padding is calculated from header + IDs */
849     SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
850                         src_id_len +
851                         dst_id_len), block_len, padlen);
852
853     /* Length to encrypt, header + IDs + padding. */
854     enclen = SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len + padlen;
855   } else {
856
857     /* Padding is calculated from true length of the packet */
858     if (flags & SILC_PACKET_FLAG_LONG_PAD)
859       SILC_PACKET_PADLEN_MAX(truelen, block_len, padlen);
860     else
861       SILC_PACKET_PADLEN(truelen, block_len, padlen);
862
863     enclen += padlen;
864   }
865
866   /* Remove implementation specific flags */
867   flags &= ~(SILC_PACKET_FLAG_LONG_PAD);
868
869   /* Get random padding */
870   for (i = 0; i < padlen; i++) tmppad[i] =
871                                  silc_rng_get_byte_fast(stream->engine->rng);
872
873   silc_mutex_lock(stream->lock);
874
875   /* Get packet pointer from the outgoing buffer */
876   if (!silc_packet_send_prepare(stream, truelen + padlen, hmac, &packet)) {
877     silc_mutex_unlock(stream->lock);
878     return FALSE;
879   }
880
881   /* Create the packet.  This creates the SILC header, adds padding, and
882      the actual packet data. */
883   i = silc_buffer_format(&packet,
884                          SILC_STR_UI_SHORT(truelen),
885                          SILC_STR_UI_CHAR(flags),
886                          SILC_STR_UI_CHAR(type),
887                          SILC_STR_UI_CHAR(padlen),
888                          SILC_STR_UI_CHAR(0),
889                          SILC_STR_UI_CHAR(src_id_len),
890                          SILC_STR_UI_CHAR(dst_id_len),
891                          SILC_STR_UI_CHAR(src_id_type),
892                          SILC_STR_UI_XNSTRING(src_id, src_id_len),
893                          SILC_STR_UI_CHAR(dst_id_type),
894                          SILC_STR_UI_XNSTRING(dst_id, dst_id_len),
895                          SILC_STR_UI_XNSTRING(tmppad, padlen),
896                          SILC_STR_UI_XNSTRING(data, data_len),
897                          SILC_STR_END);
898   if (i < 0) {
899     silc_mutex_unlock(stream->lock);
900     return FALSE;
901   }
902
903   SILC_LOG_HEXDUMP(("Assembled packet, len %d", silc_buffer_len(&packet)),
904                    packet.data, silc_buffer_len(&packet));
905
906   /* Encrypt the packet */
907   if (cipher) {
908     SILC_LOG_DEBUG(("Encrypting packet"));
909     if (!silc_cipher_encrypt(cipher, packet.data, packet.data,
910                              enclen, NULL)) {
911       SILC_LOG_ERROR(("Packet encryption failed"));
912       silc_mutex_unlock(stream->lock);
913       return FALSE;
914     }
915   }
916
917   /* Compute HMAC */
918   if (hmac) {
919     unsigned char psn[4];
920     SilcUInt32 mac_len;
921
922     /* MAC is computed from the entire encrypted packet data, and put
923        to the end of the packet. */
924     silc_hmac_init(hmac);
925     SILC_PUT32_MSB(stream->send_psn, psn);
926     silc_hmac_update(hmac, psn, 4);
927     silc_hmac_update(hmac, packet.data, silc_buffer_len(&packet));
928     silc_hmac_final(hmac, packet.tail, &mac_len);
929     silc_buffer_pull_tail(&packet, mac_len);
930     stream->send_psn++;
931   }
932
933   /* Write the packet to the stream */
934   while (silc_buffer_len(&stream->outbuf) > 0) {
935     i = silc_stream_write(stream->stream, stream->outbuf.data,
936                           silc_buffer_len(&stream->outbuf));
937     if (i == 0) {
938       /* EOS */
939       silc_buffer_reset(&stream->outbuf);
940       silc_mutex_unlock(stream->lock);
941       SILC_PACKET_CALLBACK_EOS(stream);
942       return FALSE;
943     }
944
945     if (i == -2) {
946       /* Error */
947       silc_buffer_reset(&stream->outbuf);
948       silc_mutex_unlock(stream->lock);
949       SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_WRITE);
950       return FALSE;
951     }
952
953     if (i == -1) {
954       /* Cannot write now, write later. */
955       silc_mutex_unlock(stream->lock);
956       return TRUE;
957     }
958
959     /* Wrote data */
960     silc_buffer_pull(&stream->outbuf, i);
961   }
962   silc_buffer_reset(&stream->outbuf);
963
964   silc_mutex_unlock(stream->lock);
965   return TRUE;
966 }
967
968 /* Sends a packet */
969
970 SilcBool silc_packet_send(SilcPacketStream stream,
971                           SilcPacketType type, SilcPacketFlags flags,
972                           const unsigned char *data, SilcUInt32 data_len)
973 {
974   return silc_packet_send_raw(stream, type, flags,
975                               stream->src_id_type,
976                               stream->src_id,
977                               stream->src_id_len,
978                               stream->dst_id_type,
979                               stream->dst_id,
980                               stream->dst_id_len,
981                               data, data_len,
982                               stream->send_key,
983                               stream->send_hmac);
984 }
985
986 /* Sends a packet, extended routine */
987
988 SilcBool silc_packet_send_ext(SilcPacketStream stream,
989                               SilcPacketType type, SilcPacketFlags flags,
990                               SilcIdType src_id_type, void *src_id,
991                               SilcIdType dst_id_type, void *dst_id,
992                               const unsigned char *data, SilcUInt32 data_len,
993                               SilcCipher cipher, SilcHmac hmac)
994 {
995   unsigned char src_id_data[32], dst_id_data[32];
996   SilcUInt32 src_id_len, dst_id_len;
997
998   if (src_id)
999     if (!silc_id_id2str(src_id, src_id_type, src_id_data,
1000                         sizeof(src_id_data), &src_id_len))
1001       return FALSE;
1002   if (dst_id)
1003     if (!silc_id_id2str(dst_id, dst_id_type, dst_id_data,
1004                         sizeof(dst_id_data), &dst_id_len))
1005       return FALSE;
1006
1007   return silc_packet_send_raw(stream, type, flags,
1008                               src_id_type,
1009                               src_id_data,
1010                               src_id_len,
1011                               dst_id_type,
1012                               dst_id_data,
1013                               dst_id_len,
1014                               data, data_len,
1015                               cipher,
1016                               hmac);
1017 }
1018
1019
1020 /***************************** Packet Receiving *****************************/
1021
1022 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. */
1023
1024 static SilcBool silc_packet_check_mac(SilcHmac hmac,
1025                                       const unsigned char *data,
1026                                       SilcUInt32 data_len,
1027                                       const unsigned char *packet_mac,
1028                                       SilcUInt32 sequence)
1029 {
1030   /* Check MAC */
1031   if (hmac) {
1032     unsigned char mac[32], psn[4];
1033     SilcUInt32 mac_len;
1034
1035     SILC_LOG_DEBUG(("Verifying MAC"));
1036
1037     /* Compute HMAC of packet */
1038     silc_hmac_init(hmac);
1039     SILC_PUT32_MSB(sequence, psn);
1040     silc_hmac_update(hmac, psn, 4);
1041     silc_hmac_update(hmac, data, data_len);
1042     silc_hmac_final(hmac, mac, &mac_len);
1043
1044     /* Compare the MAC's */
1045     if (memcmp(packet_mac, mac, mac_len)) {
1046       SILC_LOG_DEBUG(("MAC failed"));
1047       return FALSE;
1048     }
1049
1050     SILC_LOG_DEBUG(("MAC is Ok"));
1051   }
1052
1053   return TRUE;
1054 }
1055
1056 /* Decrypts SILC packet.  Handles both normal and special packet decryption.
1057    Return 0 when packet is normal and 1 when it it special, -1 on error. */
1058
1059 static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
1060                                SilcUInt32 sequence, SilcBuffer buffer,
1061                                SilcBool normal)
1062 {
1063   if (normal == TRUE) {
1064     if (cipher) {
1065       /* Decrypt rest of the packet */
1066       SILC_LOG_DEBUG(("Decrypting the packet"));
1067       if (!silc_cipher_decrypt(cipher, buffer->data, buffer->data,
1068                                silc_buffer_len(buffer), NULL))
1069         return -1;
1070     }
1071     return 0;
1072
1073   } else {
1074     /* Decrypt rest of the header plus padding */
1075     if (cipher) {
1076       SilcUInt16 len;
1077       SilcUInt32 block_len = silc_cipher_get_block_len(cipher);
1078
1079       SILC_LOG_DEBUG(("Decrypting the header"));
1080
1081       /* Padding length + src id len + dst id len + header length - 16
1082          bytes already decrypted, gives the rest of the encrypted packet */
1083       silc_buffer_push(buffer, block_len);
1084       len = (((SilcUInt8)buffer->data[4] + (SilcUInt8)buffer->data[6] +
1085               (SilcUInt8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
1086              block_len);
1087       silc_buffer_pull(buffer, block_len);
1088
1089       if (len > silc_buffer_len(buffer)) {
1090         SILC_LOG_ERROR(("Garbage in header of packet, bad packet length, "
1091                         "packet dropped"));
1092         return -1;
1093       }
1094       if (!silc_cipher_decrypt(cipher, buffer->data, buffer->data,
1095                                len, NULL))
1096         return -1;
1097     }
1098
1099     return 1;
1100   }
1101 }
1102
1103 /* Parses the packet. This is called when a whole packet is ready to be
1104    parsed. The buffer sent must be already decrypted before calling this
1105    function. */
1106
1107 static SilcBool silc_packet_parse(SilcPacket packet)
1108 {
1109   SilcBuffer buffer = &packet->buffer;
1110   SilcUInt8 padlen = (SilcUInt8)buffer->data[4];
1111   SilcUInt8 src_id_len, dst_id_len, src_id_type, dst_id_type;
1112   int len, ret;
1113
1114   SILC_LOG_DEBUG(("Parsing incoming packet"));
1115
1116   /* Parse the buffer.  This parses the SILC header of the packet. */
1117   len = silc_buffer_unformat(buffer,
1118                              SILC_STR_OFFSET(6),
1119                              SILC_STR_UI_CHAR(&src_id_len),
1120                              SILC_STR_UI_CHAR(&dst_id_len),
1121                              SILC_STR_UI_CHAR(&src_id_type),
1122                              SILC_STR_END);
1123   if (len == -1) {
1124     SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1125     return FALSE;
1126   }
1127
1128   if (src_id_len > SILC_PACKET_MAX_ID_LEN ||
1129       dst_id_len > SILC_PACKET_MAX_ID_LEN) {
1130     SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
1131                     packet->src_id_len, packet->dst_id_len));
1132     return FALSE;
1133   }
1134
1135   ret = silc_buffer_unformat(buffer,
1136                              SILC_STR_OFFSET(len),
1137                              SILC_STR_UI_XNSTRING(&packet->src_id,
1138                                                   src_id_len),
1139                              SILC_STR_UI_CHAR(&dst_id_type),
1140                              SILC_STR_UI_XNSTRING(&packet->dst_id,
1141                                                   dst_id_len),
1142                              SILC_STR_OFFSET(padlen),
1143                              SILC_STR_END);
1144   if (ret == -1) {
1145     SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1146     return FALSE;
1147   }
1148
1149   if (src_id_type > SILC_ID_CHANNEL ||
1150       dst_id_type > SILC_ID_CHANNEL) {
1151     SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
1152                     src_id_type, dst_id_type));
1153     return FALSE;
1154   }
1155
1156   packet->src_id_len = src_id_len;
1157   packet->dst_id_len = dst_id_len;
1158   packet->src_id_type = src_id_type;
1159   packet->dst_id_type = dst_id_type;
1160
1161   SILC_LOG_HEXDUMP(("Parsed packet, len %d", silc_buffer_len(buffer)),
1162                    buffer->data, silc_buffer_len(buffer));
1163
1164   /* Pull SILC header and padding from packet to get the data payload */
1165   silc_buffer_pull(buffer, SILC_PACKET_HEADER_LEN +
1166                    packet->src_id_len + packet->dst_id_len + padlen);
1167
1168   SILC_LOG_DEBUG(("Incoming packet type: %d (%s)", packet->type,
1169                   silc_get_packet_name(packet->type)));
1170
1171   return TRUE;
1172 }
1173
1174 /* Dispatch packet to application */
1175
1176 static void silc_packet_dispatch(SilcPacket packet)
1177 {
1178   SilcPacketStream stream = packet->stream;
1179   SilcPacketProcess p;
1180   SilcBool default_sent = FALSE;
1181   SilcPacketType *pt;
1182
1183   /* Parse the packet */
1184   if (!silc_packet_parse(packet)) {
1185     SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
1186     silc_packet_free(packet);
1187     return;
1188   }
1189
1190   /* Dispatch packet to all packet processors that want it */
1191
1192   if (!stream->process) {
1193     /* Send to default processor as no others exist */
1194     SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1195     if (!stream->engine->callbacks->
1196         packet_receive(stream->engine, stream, packet,
1197                        stream->engine->callback_context,
1198                        stream->stream_context))
1199       silc_packet_free(packet);
1200     return;
1201   }
1202
1203   silc_dlist_start(stream->process);
1204   while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END) {
1205
1206     /* If priority is 0 or less, we send to default processor first
1207        because default processor has 0 priority */
1208     if (!default_sent && p->priority <= 0) {
1209       SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1210       default_sent = TRUE;
1211       if (stream->engine->callbacks->
1212           packet_receive(stream->engine, stream, packet,
1213                          stream->engine->callback_context,
1214                          stream->stream_context)) {
1215         return;
1216       }
1217     }
1218
1219     /* Send to processor */
1220     if (!p->types) {
1221       /* Send all packet types */
1222       SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
1223       if (p->callbacks->packet_receive(stream->engine, stream, packet,
1224                                        p->callback_context,
1225                                        stream->stream_context))
1226         return;
1227     } else {
1228       /* Send specific types */
1229       for (pt = p->types; *pt; pt++)
1230         if (*pt == packet->type) {
1231           SILC_LOG_DEBUG(("Dispatching packet to %p callbacks",
1232                           p->callbacks));
1233           if (p->callbacks->packet_receive(stream->engine, stream, packet,
1234                                            p->callback_context,
1235                                            stream->stream_context))
1236             return;
1237           break;
1238         }
1239     }
1240   }
1241
1242   if (!default_sent) {
1243     /* Send to default processor as it has not been sent yet */
1244     SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1245     if (stream->engine->callbacks->
1246         packet_receive(stream->engine, stream, packet,
1247                        stream->engine->callback_context,
1248                        stream->stream_context))
1249       return;
1250   }
1251
1252   /* If we got here, no one wanted the packet, so drop it */
1253   silc_packet_free(packet);
1254 }
1255
1256 /* Process incoming data and parse packets. */
1257
1258 static void silc_packet_read_process(SilcPacketStream stream)
1259 {
1260   SilcPacket packet;
1261   SilcUInt16 packetlen;
1262   SilcUInt32 paddedlen, mac_len, block_len;
1263   unsigned char tmp[SILC_PACKET_MIN_HEADER_LEN], *header;
1264   unsigned char iv[SILC_CIPHER_MAX_IV_SIZE];
1265   SilcBool normal = TRUE;
1266   int ret;
1267
1268   /* Parse the packets from the data */
1269   while (silc_buffer_len(&stream->inbuf) > 0) {
1270
1271     if (silc_buffer_len(&stream->inbuf) < SILC_PACKET_MIN_HEADER_LEN) {
1272       SILC_LOG_DEBUG(("Partial packet in queue, waiting for the rest"));
1273       return;
1274     }
1275
1276     if (stream->receive_hmac)
1277       mac_len = silc_hmac_len(stream->receive_hmac);
1278     else
1279       mac_len = 0;
1280
1281     /* Decrypt first block of the packet to get the length field out */
1282     if (stream->receive_key) {
1283       block_len = silc_cipher_get_block_len(stream->receive_key);
1284       memcpy(iv, silc_cipher_get_iv(stream->receive_key), block_len);
1285       silc_cipher_decrypt(stream->receive_key, stream->inbuf.data,
1286                           tmp, block_len, iv);
1287       header = tmp;
1288     } else {
1289       block_len = SILC_PACKET_MIN_HEADER_LEN;
1290       header = stream->inbuf.data;
1291     }
1292
1293     /* Get packet length and full packet length with padding */
1294     SILC_PACKET_LENGTH(header, packetlen, paddedlen);
1295
1296     /* Sanity checks */
1297     if (packetlen < SILC_PACKET_MIN_LEN) {
1298       SILC_LOG_ERROR(("Received too short packet"));
1299       SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
1300       memset(tmp, 0, sizeof(tmp));
1301       silc_buffer_reset(&stream->inbuf);
1302       return;
1303     }
1304
1305     if (silc_buffer_len(&stream->inbuf) < paddedlen + mac_len) {
1306       SILC_LOG_DEBUG(("Received partial packet, waiting for the rest "
1307                       "(%d bytes)",
1308                       paddedlen + mac_len - silc_buffer_len(&stream->inbuf)));
1309       memset(tmp, 0, sizeof(tmp));
1310       return;
1311     }
1312
1313     /* Check MAC of the packet */
1314     if (!silc_packet_check_mac(stream->receive_hmac, stream->inbuf.data,
1315                                paddedlen, stream->inbuf.data + paddedlen,
1316                                stream->receive_psn)) {
1317       SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MAC_FAILED);
1318       memset(tmp, 0, sizeof(tmp));
1319       silc_buffer_reset(&stream->inbuf);
1320       return;
1321     }
1322
1323     /* Get packet */
1324     packet = silc_packet_alloc(stream->engine);
1325     if (!packet) {
1326       SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
1327       memset(tmp, 0, sizeof(tmp));
1328       silc_buffer_reset(&stream->inbuf);
1329       return;
1330     }
1331
1332     /* Allocate more space to packet buffer, if needed */
1333     if (silc_buffer_truelen(&packet->buffer) < paddedlen) {
1334       if (!silc_buffer_realloc(&packet->buffer,
1335                                silc_buffer_truelen(&packet->buffer) +
1336                                (paddedlen -
1337                                 silc_buffer_truelen(&packet->buffer)))) {
1338         SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
1339         silc_packet_free(packet);
1340         memset(tmp, 0, sizeof(tmp));
1341         silc_buffer_reset(&stream->inbuf);
1342         return;
1343       }
1344     }
1345
1346     /* Parse packet header */
1347     packet->flags = (SilcPacketFlags)header[2];
1348     packet->type = (SilcPacketType)header[3];
1349
1350     if (stream->engine->local_is_router) {
1351       if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
1352           (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
1353         normal = FALSE;
1354       else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE ||
1355                (packet->type == SILC_PACKET_CHANNEL_MESSAGE &&
1356                 stream->is_router == TRUE))
1357         normal = TRUE;
1358     } else {
1359       if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
1360           (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
1361         normal = FALSE;
1362       else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE)
1363         normal = TRUE;
1364     }
1365
1366     SILC_LOG_HEXDUMP(("Incoming packet (%d) len %d",
1367                       stream->receive_psn, paddedlen + mac_len),
1368                      stream->inbuf.data, paddedlen + mac_len);
1369
1370     /* Put the decrypted part, and rest of the encrypted data, and decrypt */
1371     silc_buffer_pull_tail(&packet->buffer, paddedlen);
1372     silc_buffer_put(&packet->buffer, header, block_len);
1373     silc_buffer_pull(&packet->buffer, block_len);
1374     silc_buffer_put(&packet->buffer, stream->inbuf.data + block_len,
1375                     paddedlen - block_len);
1376     if (stream->receive_key) {
1377       silc_cipher_set_iv(stream->receive_key, iv);
1378       ret = silc_packet_decrypt(stream->receive_key, stream->receive_hmac,
1379                                 stream->receive_psn, &packet->buffer, normal);
1380       if (ret < 0) {
1381         SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_DECRYPTION_FAILED);
1382         silc_packet_free(packet);
1383         memset(tmp, 0, sizeof(tmp));
1384         return;
1385       }
1386
1387       stream->receive_psn++;
1388     }
1389     silc_buffer_push(&packet->buffer, block_len);
1390
1391     /* Pull the packet from inbuf thus we'll get the next one in the inbuf. */
1392     silc_buffer_pull(&stream->inbuf, paddedlen + mac_len);
1393
1394     /* Dispatch the packet to application */
1395     packet->stream = stream;
1396     silc_packet_dispatch(packet);
1397   }
1398
1399   silc_buffer_reset(&stream->inbuf);
1400 }
1401
1402
1403 /****************************** Packet Waiting ******************************/
1404
1405 /* Packet wait receive callback */
1406 static SilcBool
1407 silc_packet_wait_packet_receive(SilcPacketEngine engine,
1408                                 SilcPacketStream stream,
1409                                 SilcPacket packet,
1410                                 void *callback_context,
1411                                 void *stream_context);
1412
1413 /* Packet waiting callbacks */
1414 static SilcPacketCallbacks silc_packet_wait_cbs =
1415 {
1416   silc_packet_wait_packet_receive, NULL, NULL
1417 };
1418
1419 /* Packet waiting context */
1420 typedef struct {
1421   SilcMutex wait_lock;
1422   SilcCond wait_cond;
1423   SilcList packet_queue;
1424   SilcBool waiting;
1425 } *SilcPacketWait;
1426
1427 /* Packet wait receive callback */
1428
1429 static SilcBool
1430 silc_packet_wait_packet_receive(SilcPacketEngine engine,
1431                                 SilcPacketStream stream,
1432                                 SilcPacket packet,
1433                                 void *callback_context,
1434                                 void *stream_context)
1435 {
1436   SilcPacketWait pw = callback_context;
1437
1438   /* Signal the waiting thread for a new packet */
1439   silc_mutex_lock(pw->wait_lock);
1440
1441   if (!pw->waiting) {
1442     silc_mutex_unlock(pw->wait_lock);
1443     return FALSE;
1444   }
1445
1446   silc_list_add(pw->packet_queue, packet);
1447   silc_cond_broadcast(pw->wait_cond);
1448
1449   silc_mutex_unlock(pw->wait_lock);
1450
1451   return TRUE;
1452 }
1453
1454 /* Initialize packet waiting */
1455
1456 void *silc_packet_wait_init(SilcPacketStream stream, ...)
1457 {
1458   SilcPacketWait pw;
1459   SilcBool ret;
1460   va_list ap;
1461
1462   pw = silc_calloc(1, sizeof(*pw));
1463   if (!pw)
1464     return NULL;
1465
1466   /* Allocate mutex and conditional variable */
1467   if (!silc_mutex_alloc(&pw->wait_lock)) {
1468     silc_free(pw);
1469     return NULL;
1470   }
1471   if (!silc_cond_alloc(&pw->wait_cond)) {
1472     silc_mutex_free(pw->wait_lock);
1473     silc_free(pw);
1474     return NULL;
1475   }
1476
1477   /* Link to the packet stream for the requested packet types */
1478   va_start(ap, stream);
1479   ret = silc_packet_stream_link_va(stream, &silc_packet_wait_cbs, pw,
1480                                    10000000, ap);
1481   va_end(ap);
1482   if (!ret) {
1483     silc_cond_free(pw->wait_cond);
1484     silc_mutex_free(pw->wait_lock);
1485     silc_free(pw);
1486     return NULL;
1487   }
1488
1489   /* Initialize packet queue */
1490   silc_list_init(pw->packet_queue, struct SilcPacketStruct, next);
1491
1492   return (void *)pw;
1493 }
1494
1495 /* Uninitialize packet waiting */
1496
1497 void silc_packet_wait_uninit(void *context, SilcPacketStream stream)
1498 {
1499   SilcPacketWait pw = context;
1500   SilcPacket packet;
1501
1502   silc_mutex_lock(pw->wait_lock);
1503   silc_packet_stream_unlink(stream, &silc_packet_wait_cbs, pw);
1504
1505   /* Free any remaining packets */
1506   silc_list_start(pw->packet_queue);
1507   while ((packet = silc_list_get(pw->packet_queue)) != SILC_LIST_END)
1508     silc_packet_free(packet);
1509
1510   silc_mutex_unlock(pw->wait_lock);
1511
1512   silc_cond_free(pw->wait_cond);
1513   silc_mutex_free(pw->wait_lock);
1514   silc_free(pw);
1515 }
1516
1517 /* Blocks thread until a packet has been received. */
1518
1519 int silc_packet_wait(void *context, int timeout, SilcPacket *return_packet)
1520 {
1521   SilcPacketWait pw = context;
1522   SilcBool ret = FALSE;
1523
1524   silc_mutex_lock(pw->wait_lock);
1525
1526   /* Wait here until packet has arrived */
1527   pw->waiting = TRUE;
1528   while (silc_list_count(pw->packet_queue) == 0)
1529     ret = silc_cond_timedwait(pw->wait_cond, pw->wait_lock, timeout);
1530
1531   /* Return packet */
1532   silc_list_start(pw->packet_queue);
1533   *return_packet = silc_list_get(pw->packet_queue);
1534   silc_list_del(pw->packet_queue, *return_packet);
1535
1536   silc_mutex_unlock(pw->wait_lock);
1537
1538   return ret == TRUE ? 1 : 0;
1539 }