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