updates.
[silc.git] / lib / silccore / silcpacket.c
1 /*
2
3   silcpacket.c 
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2001 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 "silcincludes.h"
25
26 /******************************************************************************
27
28                           Packet Sending Routines
29
30 ******************************************************************************/
31
32 /* Actually sends the packet. This flushes the connections outgoing data
33    buffer. If data is sent directly to the network this returns the bytes
34    written, if error occured this returns -1 and if the data could not
35    be written directly to the network at this time this returns -2, in
36    which case the data should be queued by the caller and sent at some
37    later time. If `force_send' is TRUE this attempts to write the data
38    directly to the network, if FALSE, this returns -2. */
39
40 int silc_packet_send(SilcSocketConnection sock, bool force_send)
41 {
42   SILC_LOG_DEBUG(("Sending packet to %s:%d [%s]", sock->hostname,
43                   sock->port,  
44                   (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
45                    sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
46                    sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
47                    "Router")));
48
49   /* Send now if forced to do so */
50   if (force_send == TRUE) {
51     int ret;
52
53     SILC_LOG_DEBUG(("Forcing packet send, packet sent immediately"));
54
55     /* Write to network */
56     ret = silc_socket_write(sock);
57
58     if (ret == -1) {
59       SILC_LOG_ERROR(("Error sending packet, dropped"));
60     }
61     if (ret != -2)
62       return ret;
63
64     SILC_LOG_DEBUG(("Could not force the send, packet put to queue"));
65   }  
66
67   SILC_LOG_DEBUG(("Packet in queue"));
68
69   return -2;
70 }
71
72 /* Encrypts a packet. This also creates HMAC of the packet before 
73    encryption and adds the HMAC at the end of the buffer. This assumes
74    that there is enough free space at the end of the buffer to add the
75    computed HMAC. This is the normal way of encrypting packets, if some
76    other process of HMAC computing and encryption is needed this function
77    cannot be used. */
78
79 void silc_packet_encrypt(SilcCipher cipher, SilcHmac hmac, uint32 sequence,
80                          SilcBuffer buffer, uint32 len)
81 {
82   unsigned char mac[32];
83   uint32 mac_len;
84
85   /* Compute HMAC. This assumes that HMAC is created from the entire
86      data area thus this uses the length found in buffer, not the length
87      sent as argument. */
88   if (hmac) {
89     unsigned char psn[4];
90
91     silc_hmac_init(hmac);
92     SILC_PUT32_MSB(sequence, psn);
93     silc_hmac_update(hmac, psn, 4);
94     silc_hmac_update(hmac, buffer->data, buffer->len);
95     silc_hmac_final(hmac, mac, &mac_len);
96     silc_buffer_put_tail(buffer, mac, mac_len);
97     memset(mac, 0, sizeof(mac));
98   }
99
100   /* Encrypt the data area of the packet. */
101   if (cipher) {
102     SILC_LOG_DEBUG(("Encrypting packet, cipher %s, len %d", 
103                     cipher->cipher->name, len));
104     silc_cipher_encrypt(cipher, buffer->data, buffer->data, len, cipher->iv);
105   }
106
107   /* Pull the HMAC into the visible data area in the buffer */
108   if (hmac)
109     silc_buffer_pull_tail(buffer, mac_len);
110 }
111
112 /* Assembles a new packet to be ready for send out. The buffer sent as
113    argument must include the data to be sent and it must not be encrypted. 
114    The packet also must have enough free space so that the SILC header
115    and padding maybe added to the packet. The packet is encrypted after 
116    this function has returned.
117
118    The buffer sent as argument should be something like following:
119
120    --------------------------------------------
121    | head             | data           | tail |
122    --------------------------------------------
123    ^                  ^
124    58 bytes           x bytes
125
126    So that the SILC header and 1 - 16 bytes of padding can fit to
127    the buffer. After assembly the buffer might look like this:
128
129    --------------------------------------------
130    | data                              |      |
131    --------------------------------------------
132    ^                                   ^
133    Start of assembled packet
134
135    Packet construct is as follows:
136
137    n bytes       SILC Header
138       2 bytes     Payload length
139       1 byte      Flags
140       1 byte      Packet type
141       1 byte      Padding length
142       1 byte      RESERVED
143       1 bytes     Source ID Length
144       1 bytes     Destination ID Length
145       1 byte      Source ID Type
146       n bytes     Source ID
147       1 byte      Destination ID Type
148       n bytes     Destination ID
149
150    1 - 16 bytes    Padding
151
152    n bytes        Data payload
153
154    All fields in the packet will be authenticated by MAC. The MAC is
155    not computed here, it must be computed separately before encrypting
156    the packet.
157
158 */
159
160 void silc_packet_assemble(SilcPacketContext *ctx, SilcCipher cipher)
161 {
162   unsigned char tmppad[SILC_PACKET_MAX_PADLEN];
163   int block_len = cipher ? silc_cipher_get_block_len(cipher) : 0;
164   int i;
165
166   SILC_LOG_DEBUG(("Assembling outgoing packet"));
167   
168   /* Get the true length of the packet. This is saved as payload length
169      into the packet header. This does not include the length of the
170      padding. */
171   if (!ctx->truelen)
172     ctx->truelen = ctx->buffer->len + SILC_PACKET_HEADER_LEN + 
173       ctx->src_id_len + ctx->dst_id_len;
174
175   /* Calculate the length of the padding. The padding is calculated from
176      the data that will be encrypted. */
177   if (!ctx->padlen) {
178     if (ctx->long_pad)
179       ctx->padlen = SILC_PACKET_PADLEN_MAX(ctx->truelen);
180     else
181       ctx->padlen = SILC_PACKET_PADLEN(ctx->truelen, block_len);
182   }
183
184   /* Put the start of the data section to the right place. */
185   silc_buffer_push(ctx->buffer, SILC_PACKET_HEADER_LEN + 
186                    ctx->src_id_len + ctx->dst_id_len + ctx->padlen);
187
188   /* Get random padding */
189 #if 1
190   for (i = 0; i < ctx->padlen; i++) tmppad[i] = 
191                                       silc_rng_global_get_byte_fast();
192 #else
193   /* XXX: For testing - to be removed */
194   memset(tmppad, 65, sizeof(tmppad));
195 #endif
196
197   /* Create the packet. This creates the SILC header and adds padding,
198      rest of the buffer remains as it is. */
199   silc_buffer_format(ctx->buffer, 
200                      SILC_STR_UI_SHORT(ctx->truelen),
201                      SILC_STR_UI_CHAR(ctx->flags),
202                      SILC_STR_UI_CHAR(ctx->type),
203                      SILC_STR_UI_CHAR(ctx->padlen),
204                      SILC_STR_UI_CHAR(0),
205                      SILC_STR_UI_CHAR(ctx->src_id_len),
206                      SILC_STR_UI_CHAR(ctx->dst_id_len),
207                      SILC_STR_UI_CHAR(ctx->src_id_type),
208                      SILC_STR_UI_XNSTRING(ctx->src_id, ctx->src_id_len),
209                      SILC_STR_UI_CHAR(ctx->dst_id_type),
210                      SILC_STR_UI_XNSTRING(ctx->dst_id, ctx->dst_id_len),
211                      SILC_STR_UI_XNSTRING(tmppad, ctx->padlen),
212                      SILC_STR_END);
213
214   SILC_LOG_HEXDUMP(("Assembled packet, len %d", ctx->buffer->len), 
215                    ctx->buffer->data, ctx->buffer->len);
216
217   SILC_LOG_DEBUG(("Outgoing packet assembled"));
218 }
219
220 /* Prepare outgoing data buffer for packet sending. This moves the data
221    area so that new packet may be added into it. If needed this allocates
222    more space to the buffer. This handles directly the connection's
223    outgoing buffer in SilcSocketConnection object. */
224
225 void silc_packet_send_prepare(SilcSocketConnection sock,
226                               uint32 header_len,
227                               uint32 padlen,
228                               uint32 data_len)
229 {
230   int totlen, oldlen;
231
232   totlen = header_len + padlen + data_len;
233
234   /* Prepare the outgoing buffer for packet sending. */
235   if (!sock->outbuf) {
236     /* Allocate new buffer. This is done only once per connection. */
237     SILC_LOG_DEBUG(("Allocating outgoing data buffer"));
238     
239     if (totlen > SILC_PACKET_DEFAULT_SIZE)
240       sock->outbuf = silc_buffer_alloc(totlen);
241     else
242       sock->outbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE);
243     silc_buffer_pull_tail(sock->outbuf, totlen);
244     silc_buffer_pull(sock->outbuf, header_len + padlen);
245   } else {
246     if (SILC_IS_OUTBUF_PENDING(sock)) {
247       /* There is some pending data in the buffer. */
248
249       /* Allocate more space if needed */
250       if ((sock->outbuf->end - sock->outbuf->tail) < 
251           (totlen + 20)) {
252         SILC_LOG_DEBUG(("Reallocating outgoing data buffer"));
253         sock->outbuf = silc_buffer_realloc(sock->outbuf, 
254                                            sock->outbuf->truelen +
255                                            (totlen * 2));
256       }
257
258       oldlen = sock->outbuf->len;
259       silc_buffer_pull_tail(sock->outbuf, totlen);
260       silc_buffer_pull(sock->outbuf, header_len + padlen + oldlen);
261     } else {
262       /* Buffer is free for use */
263       silc_buffer_clear(sock->outbuf);
264
265       /* Allocate more space if needed */
266       if ((sock->outbuf->end - sock->outbuf->tail) < (totlen + 20)) {
267         SILC_LOG_DEBUG(("Reallocating outgoing data buffer"));
268         sock->outbuf = silc_buffer_realloc(sock->outbuf, 
269                                            sock->outbuf->truelen + 
270                                            (totlen * 2));
271       }
272
273       silc_buffer_pull_tail(sock->outbuf, totlen);
274       silc_buffer_pull(sock->outbuf, header_len + padlen);
275     }
276   }
277 }
278
279 /******************************************************************************
280
281                          Packet Reception Routines
282
283 ******************************************************************************/
284
285 static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac, 
286                                uint32 sequence, SilcBuffer buffer, 
287                                bool normal);
288
289 /* Receives packet from network and reads the data into connection's
290    incoming data buffer. If the data was read directly this returns the
291    read bytes, if error occured this returns -1, if the data could not
292    be read directly at this time this returns -2 in which case the data
293    should be read again at some later time, or If EOF occured this returns
294    0. */
295
296 int silc_packet_receive(SilcSocketConnection sock)
297 {
298   int ret;
299
300   SILC_LOG_DEBUG(("Receiving packet from %s:%d [%s]", sock->hostname,
301                   sock->port, 
302                   (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
303                    sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
304                    sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
305                    "Router")));
306
307   /* Read some data from connection */
308   ret = silc_socket_read(sock);
309
310   return ret;
311 }
312
313 /* Processes and decrypts the incmoing data, and calls parser callback
314    for each received packet that will handle the actual packet parsing.
315    If more than one packet was received this calls the parser multiple
316    times.  The parser callback will get context SilcPacketParserContext
317    that includes the packet and the `parser_context' sent to this
318    function. 
319    
320    The `local_is_router' indicates whether the caller is router server
321    in which case the receiving process of a certain packet types may
322    be special.  Normal server and client must set it to FALSE.  The
323    SilcPacketParserContext will indicate also whether the received
324    packet was normal or special packet. */
325
326 void silc_packet_receive_process(SilcSocketConnection sock,
327                                  bool local_is_router,
328                                  SilcCipher cipher, SilcHmac hmac,
329                                  uint32 sequence,
330                                  SilcPacketParserCallback parser,
331                                  void *parser_context)
332 {
333   SilcPacketParserContext *parse_ctx;
334   int packetlen, paddedlen, mac_len = 0;
335   int block_len = cipher ? silc_cipher_get_block_len(cipher) : 0;
336   bool cont = TRUE;
337   
338   if (sock->inbuf->len < SILC_PACKET_MIN_HEADER_LEN)
339     return;
340
341   if (hmac)
342     mac_len = silc_hmac_len(hmac);
343
344   /* Parse the packets from the data */
345   while (sock->inbuf->len > 0 && cont) {
346
347     if (sock->inbuf->len < SILC_PACKET_MIN_HEADER_LEN) {
348       SILC_LOG_DEBUG(("Partial packet in queue, waiting for the rest"));
349       return;
350     }
351
352     /* Decrypt first 16 bytes of the packet */
353     if (!SILC_IS_INBUF_PENDING(sock) && cipher)
354       silc_cipher_decrypt(cipher, sock->inbuf->data, sock->inbuf->data, 
355                           SILC_PACKET_MIN_HEADER_LEN, cipher->iv);
356
357     /* Get packet lenght and full packet length with padding */
358     SILC_PACKET_LENGTH(sock->inbuf, packetlen, paddedlen);
359
360     /* Sanity checks */
361     if (packetlen < SILC_PACKET_MIN_LEN) {
362       SILC_LOG_DEBUG(("Received invalid packet, dropped"));
363       silc_buffer_clear(sock->inbuf);
364       return;
365     }
366
367     if (sock->inbuf->len < paddedlen + mac_len) {
368       SILC_LOG_DEBUG(("Received partial packet, waiting for the rest"
369                       "(%d < %d)", sock->inbuf->len, paddedlen + mac_len));
370       SILC_SET_INBUF_PENDING(sock);
371       return;
372     }
373
374     SILC_UNSET_INBUF_PENDING(sock);
375     parse_ctx = silc_calloc(1, sizeof(*parse_ctx));
376     parse_ctx->packet = silc_packet_context_alloc();
377     parse_ctx->packet->buffer = silc_buffer_alloc(paddedlen + mac_len);
378     parse_ctx->packet->padlen = sock->inbuf->data[4];
379     parse_ctx->packet->sequence = sequence++;
380     parse_ctx->sock = sock;
381     parse_ctx->context = parser_context;
382
383     silc_buffer_pull_tail(parse_ctx->packet->buffer, 
384                           SILC_BUFFER_END(parse_ctx->packet->buffer));
385     silc_buffer_put(parse_ctx->packet->buffer, sock->inbuf->data, 
386                     paddedlen + mac_len);
387
388     SILC_LOG_HEXDUMP(("Incoming packet (%d) (%dB decrypted), len %d", 
389                       sequence - 1, block_len, paddedlen + mac_len),
390                      sock->inbuf->data, paddedlen + mac_len);
391
392     /* Check whether this is normal or special packet */
393     if (local_is_router) {
394       if (sock->inbuf->data[3] == SILC_PACKET_PRIVATE_MESSAGE &&
395           (sock->inbuf->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
396         parse_ctx->normal = FALSE;
397       else if (sock->inbuf->data[3] != SILC_PACKET_CHANNEL_MESSAGE || 
398                (sock->inbuf->data[3] == SILC_PACKET_CHANNEL_MESSAGE &&
399                 sock->type == SILC_SOCKET_TYPE_ROUTER))
400         parse_ctx->normal = TRUE;
401     } else {
402       if (sock->inbuf->data[3] == SILC_PACKET_PRIVATE_MESSAGE &&
403           (sock->inbuf->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
404         parse_ctx->normal = FALSE;
405       else if (sock->inbuf->data[3] != SILC_PACKET_CHANNEL_MESSAGE)
406         parse_ctx->normal = TRUE;
407     }
408
409     /* Decrypt rest of the packet */
410     if (cipher)
411       if (silc_packet_decrypt(cipher, hmac, parse_ctx->packet->sequence, 
412                               parse_ctx->packet->buffer, 
413                               parse_ctx->normal) == -1) {
414         SILC_LOG_WARNING(("Packet decryption failed %s:%d [%s]", 
415                           sock->hostname, sock->port,
416                           (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
417                            sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
418                            sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
419                            "Router")));
420       }
421
422     /* Pull the packet from inbuf thus we'll get the next one
423        in the inbuf. */
424     silc_buffer_pull(sock->inbuf, paddedlen + mac_len);
425
426     /* Call the parser */
427     cont = (*parser)(parse_ctx, parser_context);
428   }
429
430   if (cont == FALSE && sock->inbuf->len > 0)
431     return;
432
433   SILC_LOG_DEBUG(("Clearing inbound buffer"));
434   silc_buffer_clear(sock->inbuf);
435 }
436
437 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. This is called
438    after packet has been totally decrypted and parsed. */
439
440 static int silc_packet_check_mac(SilcHmac hmac, SilcBuffer buffer,
441                                  uint32 sequence)
442 {
443   /* Check MAC */
444   if (hmac) {
445     unsigned char mac[32], psn[4];
446     uint32 mac_len;
447     
448     SILC_LOG_DEBUG(("Verifying MAC"));
449
450     /* Compute HMAC of packet */
451
452     memset(mac, 0, sizeof(mac));
453     silc_hmac_init(hmac);
454     SILC_PUT32_MSB(sequence, psn);
455     silc_hmac_update(hmac, psn, 4);
456     silc_hmac_update(hmac, buffer->data, buffer->len);
457     silc_hmac_final(hmac, mac, &mac_len);
458
459     /* Compare the HMAC's (buffer->tail has the packet's HMAC) */
460     if (memcmp(mac, buffer->tail, mac_len)) {
461       SILC_LOG_ERROR(("MAC failed"));
462       return FALSE;
463     }
464     
465     SILC_LOG_DEBUG(("MAC is Ok"));
466     memset(mac, 0, sizeof(mac));
467   }
468   
469   return TRUE;
470 }
471
472 /* Decrypts rest of the packet (after decrypting just the SILC header).
473    After calling this function the packet is ready to be parsed by calling 
474    silc_packet_parse. If everything goes without errors this returns TRUE,
475    if packet is malformed this returns FALSE. */
476
477 static int silc_packet_decrypt_rest(SilcCipher cipher, SilcHmac hmac,
478                                     SilcBuffer buffer)
479 {
480   if (cipher) {
481
482     /* Pull MAC from packet before decryption */
483     if (hmac) {
484       if ((buffer->len - silc_hmac_len(hmac)) > SILC_PACKET_MIN_LEN) {
485         silc_buffer_push_tail(buffer, silc_hmac_len(hmac));
486       } else {
487         SILC_LOG_DEBUG(("Bad MAC length in packet, packet dropped"));
488         return FALSE;
489       }
490     }
491
492     SILC_LOG_DEBUG(("Decrypting rest of the packet"));
493
494     /* Decrypt rest of the packet */
495     silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN);
496     silc_cipher_decrypt(cipher, buffer->data, buffer->data, buffer->len, 
497                         cipher->iv);
498     silc_buffer_push(buffer, SILC_PACKET_MIN_HEADER_LEN);
499
500     SILC_LOG_HEXDUMP(("Fully decrypted packet, len %d", buffer->len),
501                      buffer->data, buffer->len);
502   }
503
504   return TRUE;
505 }
506
507 /* Decrypts rest of the SILC Packet header that has been decrypted partly
508    already. This decrypts the padding of the packet also. After calling 
509    this function the packet is ready to be parsed by calling function 
510    silc_packet_parse. This is used in special packet reception (protocol
511    defines the way of decrypting special packets). */
512
513 static int silc_packet_decrypt_rest_special(SilcCipher cipher,
514                                             SilcHmac hmac,
515                                             SilcBuffer buffer)
516 {
517   /* Decrypt rest of the header plus padding */
518   if (cipher) {
519     uint16 len;
520
521     /* Pull MAC from packet before decryption */
522     if (hmac) {
523       if ((buffer->len - silc_hmac_len(hmac)) > SILC_PACKET_MIN_LEN) {
524         silc_buffer_push_tail(buffer, silc_hmac_len(hmac));
525       } else {
526         SILC_LOG_DEBUG(("Bad MAC length in packet, packet dropped"));
527         return FALSE;
528       }
529     }
530   
531     SILC_LOG_DEBUG(("Decrypting rest of the header"));
532
533     /* padding length + src id len + dst id len + header length - 16
534        bytes already decrypted, gives the rest of the encrypted packet */
535     len = (((uint8)buffer->data[4] + (uint8)buffer->data[6] + 
536            (uint8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
537            SILC_PACKET_MIN_HEADER_LEN);
538
539     silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN);
540     if (len > buffer->len) {
541       SILC_LOG_DEBUG(("Garbage in header of packet, bad packet length, "
542                       "packet dropped"));
543       return FALSE;
544     }
545     silc_cipher_decrypt(cipher, buffer->data, buffer->data, len, cipher->iv);
546     silc_buffer_push(buffer, SILC_PACKET_MIN_HEADER_LEN);
547     SILC_LOG_HEXDUMP(("packet, len %d", buffer->len), 
548                      buffer->data, buffer->len);
549   }
550
551   return TRUE;
552 }
553
554 /* Decrypts a packet. This assumes that typical SILC packet is the
555    packet to be decrypted and thus checks for normal and special SILC
556    packets and can handle both of them. This also computes and checks
557    the HMAC of the packet. If any other special or customized decryption
558    processing is required this function cannot be used. This returns
559    -1 on error, 0 when packet is normal packet and 1 when the packet
560    is special and requires special processing. 
561
562    The `check_packet' is a callback funtion that this function will 
563    call.  The callback relates to the checking whether the packet is
564    normal packet or special packet and how it should be processed.  If
565    the callback return TRUE the packet is normal and FALSE if the packet
566    is special and requires special procesing. */
567
568 static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
569                                uint32 sequence, SilcBuffer buffer, 
570                                bool normal)
571 {
572   /* If the packet type is not any special type lets decrypt rest
573      of the packet here. */
574   if (normal == TRUE) {
575     /* Normal packet, decrypt rest of the packet */
576     if (!silc_packet_decrypt_rest(cipher, hmac, buffer))
577       return -1;
578
579     /* Check MAC */
580     if (!silc_packet_check_mac(hmac, buffer, sequence))
581       return -1;
582
583     return 0;
584   } else {
585     /* Packet requires special handling, decrypt rest of the header.
586        This only decrypts. */
587     if (!silc_packet_decrypt_rest_special(cipher, hmac, buffer))
588       return -1;
589
590     /* Check MAC */
591     if (!silc_packet_check_mac(hmac, buffer, sequence))
592       return -1;
593
594     return 1;
595   }
596 }
597
598 /* Parses the packet. This is called when a whole packet is ready to be
599    parsed. The buffer sent must be already decrypted before calling this 
600    function. The len argument must be the true length of the packet. This 
601    function returns the type of the packet. The data section of the 
602    buffer is parsed, not head or tail sections. */
603
604 SilcPacketType silc_packet_parse(SilcPacketContext *ctx, SilcCipher cipher)
605 {
606   SilcBuffer buffer = ctx->buffer;
607   uint8 tmp;
608   int len, ret;
609
610   SILC_LOG_DEBUG(("Parsing incoming packet"));
611
612   /* Check the length of the buffer */
613   if (buffer->len < SILC_PACKET_MIN_LEN) {
614     SILC_LOG_ERROR(("Bad packet length: %d, packet dropped", buffer->len));
615     return SILC_PACKET_NONE;
616   }
617
618   /* Parse the buffer. This parses the SILC header of the packet. */
619   len = silc_buffer_unformat(buffer, 
620                              SILC_STR_UI_SHORT(&ctx->truelen),
621                              SILC_STR_UI_CHAR(&ctx->flags),
622                              SILC_STR_UI_CHAR(&ctx->type),
623                              SILC_STR_UI_CHAR(&ctx->padlen),
624                              SILC_STR_UI_CHAR(&tmp),
625                              SILC_STR_UI_CHAR(&ctx->src_id_len),
626                              SILC_STR_UI_CHAR(&ctx->dst_id_len),
627                              SILC_STR_UI_CHAR(&ctx->src_id_type),
628                              SILC_STR_END);
629   if (len == -1 || tmp != 0)
630     return SILC_PACKET_NONE;
631
632   if (ctx->src_id_len > SILC_PACKET_MAX_ID_LEN ||
633       ctx->dst_id_len > SILC_PACKET_MAX_ID_LEN) {
634     SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
635                     ctx->src_id_len, ctx->dst_id_len));
636     return SILC_PACKET_NONE;
637   }
638
639   silc_buffer_pull(buffer, len);
640   ret = silc_buffer_unformat(buffer, 
641                              SILC_STR_UI_XNSTRING_ALLOC(&ctx->src_id,
642                                                         ctx->src_id_len),
643                              SILC_STR_UI_CHAR(&ctx->dst_id_type),
644                              SILC_STR_UI_XNSTRING_ALLOC(&ctx->dst_id,
645                                                         ctx->dst_id_len),
646                              SILC_STR_UI_XNSTRING(NULL, ctx->padlen),
647                              SILC_STR_END);
648   if (ret == -1)
649     return SILC_PACKET_NONE;
650
651   silc_buffer_push(buffer, len);
652
653   SILC_LOG_HEXDUMP(("parsed packet, len %d", ctx->buffer->len), 
654                    ctx->buffer->data, ctx->buffer->len);
655
656   /* Pull SILC header and padding from packet */
657   silc_buffer_pull(buffer, SILC_PACKET_HEADER_LEN +
658                    ctx->src_id_len + ctx->dst_id_len + ctx->padlen);
659
660   SILC_LOG_DEBUG(("Incoming packet type: %d", ctx->type));
661
662   return ctx->type;
663 }
664
665 /* Perform special SILC Packet header parsing. This is required to some
666    packet types that have the data payload encrypted with different key
667    than the header area plus padding of the packet. Hence, this parses
668    the header in a way that it does not take the data area into account
669    and parses the header and padding area only. */
670
671 SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx,
672                                          SilcCipher cipher)
673 {
674   SilcBuffer buffer = ctx->buffer;
675   uint8 tmp;
676   int len, ret;
677
678   SILC_LOG_DEBUG(("Parsing incoming packet"));
679
680   /* Check the length of the buffer */
681   if (buffer->len < SILC_PACKET_MIN_LEN) {
682     SILC_LOG_ERROR(("Bad packet length: %d, packet dropped", buffer->len));
683     return SILC_PACKET_NONE;
684   }
685
686   /* Parse the buffer. This parses the SILC header of the packet. */
687   len = silc_buffer_unformat(buffer, 
688                              SILC_STR_UI_SHORT(&ctx->truelen),
689                              SILC_STR_UI_CHAR(&ctx->flags),
690                              SILC_STR_UI_CHAR(&ctx->type),
691                              SILC_STR_UI_CHAR(&ctx->padlen),
692                              SILC_STR_UI_CHAR(&tmp),
693                              SILC_STR_UI_CHAR(&ctx->src_id_len),
694                              SILC_STR_UI_CHAR(&ctx->dst_id_len),
695                              SILC_STR_UI_CHAR(&ctx->src_id_type),
696                              SILC_STR_END);
697   if (len == -1 || tmp != 0) {
698     SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
699     return SILC_PACKET_NONE;
700   }
701
702   if (ctx->src_id_len > SILC_PACKET_MAX_ID_LEN ||
703       ctx->dst_id_len > SILC_PACKET_MAX_ID_LEN) {
704     SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
705                     ctx->src_id_len, ctx->dst_id_len));
706     return SILC_PACKET_NONE;
707   }
708
709   silc_buffer_pull(buffer, len);
710   ret = silc_buffer_unformat(buffer, 
711                              SILC_STR_UI_XNSTRING_ALLOC(&ctx->src_id,
712                                                         ctx->src_id_len),
713                              SILC_STR_UI_CHAR(&ctx->dst_id_type),
714                              SILC_STR_UI_XNSTRING_ALLOC(&ctx->dst_id,
715                                                         ctx->dst_id_len),
716                              SILC_STR_UI_XNSTRING(NULL, ctx->padlen),
717                              SILC_STR_END);
718   if (ret == -1) {
719     SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
720     return SILC_PACKET_NONE;
721   }
722
723   silc_buffer_push(buffer, len);
724
725   SILC_LOG_HEXDUMP(("parsed packet, len %d", ctx->buffer->len), 
726                    ctx->buffer->data, ctx->buffer->len);
727
728   /* Pull SILC header and padding from packet */
729   silc_buffer_pull(buffer, SILC_PACKET_HEADER_LEN +
730                    ctx->src_id_len + ctx->dst_id_len + ctx->padlen);
731
732   SILC_LOG_DEBUG(("Incoming packet type: %d", ctx->type));
733
734   return ctx->type;
735 }
736
737 /* Allocate packet context */
738
739 SilcPacketContext *silc_packet_context_alloc(void)
740 {
741   SilcPacketContext *ctx = silc_calloc(1, sizeof(*ctx));
742   ctx->users++;
743   return ctx;
744 }
745
746 /* Increse the reference count of the packet context. */
747
748 SilcPacketContext *silc_packet_context_dup(SilcPacketContext *ctx)
749 {
750   ctx->users++;
751   SILC_LOG_DEBUG(("Packet context %p refcnt %d->%d", ctx, ctx->users - 1,
752                   ctx->users));
753   return ctx;
754 }
755
756 /* Decrese the reference count of the packet context and free it only if
757    it is zero. */
758
759 void silc_packet_context_free(SilcPacketContext *ctx)
760 {
761   ctx->users--;
762   SILC_LOG_DEBUG(("Packet context %p refcnt %d->%d", ctx, ctx->users + 1,
763                   ctx->users));
764   if (ctx->users < 1)
765     {
766       if (ctx->buffer)
767         silc_buffer_free(ctx->buffer);
768       if (ctx->src_id)
769         silc_free(ctx->src_id);
770       if (ctx->dst_id)
771         silc_free(ctx->dst_id);
772       silc_free(ctx);
773     }
774 }