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