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 bool 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   bool cont = TRUE;
336
337   /* Do not process for disconnected connection */
338   if (SILC_IS_DISCONNECTED(sock))
339     return TRUE;
340
341   if (sock->inbuf->len < SILC_PACKET_MIN_HEADER_LEN)
342     return TRUE;
343
344   if (hmac)
345     mac_len = silc_hmac_len(hmac);
346
347   /* Parse the packets from the data */
348   while (sock->inbuf->len > 0 && cont) {
349
350     if (sock->inbuf->len < SILC_PACKET_MIN_HEADER_LEN) {
351       SILC_LOG_DEBUG(("Partial packet in queue, waiting for the rest"));
352       return TRUE;
353     }
354
355     /* Decrypt first 16 bytes of the packet */
356     if (!SILC_IS_INBUF_PENDING(sock) && cipher)
357       silc_cipher_decrypt(cipher, sock->inbuf->data, sock->inbuf->data, 
358                           SILC_PACKET_MIN_HEADER_LEN, cipher->iv);
359
360     /* Get packet lenght and full packet length with padding */
361     SILC_PACKET_LENGTH(sock->inbuf, packetlen, paddedlen);
362
363     /* Sanity checks */
364     if (packetlen < SILC_PACKET_MIN_LEN) {
365       SILC_LOG_DEBUG(("Received invalid packet, dropped"));
366       silc_buffer_clear(sock->inbuf);
367       return FALSE;
368     }
369
370     if (sock->inbuf->len < paddedlen + mac_len) {
371       SILC_LOG_DEBUG(("Received partial packet, waiting for the rest"
372                       "(%d < %d)", sock->inbuf->len, paddedlen + mac_len));
373       SILC_SET_INBUF_PENDING(sock);
374       return TRUE;
375     }
376
377     SILC_UNSET_INBUF_PENDING(sock);
378     parse_ctx = silc_calloc(1, sizeof(*parse_ctx));
379     parse_ctx->packet = silc_packet_context_alloc();
380     parse_ctx->packet->buffer = silc_buffer_alloc(paddedlen + mac_len);
381     parse_ctx->packet->type = sock->inbuf->data[3];
382     parse_ctx->packet->padlen = sock->inbuf->data[4];
383     parse_ctx->packet->sequence = sequence++;
384     parse_ctx->sock = sock;
385     parse_ctx->context = parser_context;
386
387     silc_buffer_pull_tail(parse_ctx->packet->buffer, 
388                           SILC_BUFFER_END(parse_ctx->packet->buffer));
389     silc_buffer_put(parse_ctx->packet->buffer, sock->inbuf->data, 
390                     paddedlen + mac_len);
391
392     SILC_LOG_HEXDUMP(("Incoming packet (%d) (%dB decrypted), len %d", 
393                       sequence - 1, SILC_PACKET_MIN_HEADER_LEN, 
394                       paddedlen + mac_len),
395                      sock->inbuf->data, paddedlen + mac_len);
396
397     /* Check whether this is normal or special packet */
398     if (local_is_router) {
399       if (sock->inbuf->data[3] == SILC_PACKET_PRIVATE_MESSAGE &&
400           (sock->inbuf->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
401         parse_ctx->normal = FALSE;
402       else if (sock->inbuf->data[3] != SILC_PACKET_CHANNEL_MESSAGE || 
403                (sock->inbuf->data[3] == SILC_PACKET_CHANNEL_MESSAGE &&
404                 sock->type == SILC_SOCKET_TYPE_ROUTER))
405         parse_ctx->normal = TRUE;
406     } else {
407       if (sock->inbuf->data[3] == SILC_PACKET_PRIVATE_MESSAGE &&
408           (sock->inbuf->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
409         parse_ctx->normal = FALSE;
410       else if (sock->inbuf->data[3] != SILC_PACKET_CHANNEL_MESSAGE)
411         parse_ctx->normal = TRUE;
412     }
413
414     /* Decrypt rest of the packet */
415     if (cipher)
416       if (silc_packet_decrypt(cipher, hmac, parse_ctx->packet->sequence, 
417                               parse_ctx->packet->buffer, 
418                               parse_ctx->normal) == -1) {
419         SILC_LOG_WARNING(("Packet decryption failed %s:%d [%s]", 
420                           sock->hostname, sock->port,
421                           (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
422                            sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
423                            sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
424                            "Router")));
425       }
426
427     /* Pull the packet from inbuf thus we'll get the next one
428        in the inbuf. */
429     silc_buffer_pull(sock->inbuf, paddedlen + mac_len);
430
431     /* Call the parser */
432     cont = (*parser)(parse_ctx, parser_context);
433   }
434
435   if (cont == FALSE && sock->inbuf->len > 0)
436     return TRUE;
437
438   SILC_LOG_DEBUG(("Clearing inbound buffer"));
439   silc_buffer_clear(sock->inbuf);
440   return TRUE;
441 }
442
443 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. This is called
444    after packet has been totally decrypted and parsed. */
445
446 static int silc_packet_check_mac(SilcHmac hmac, SilcBuffer buffer,
447                                  uint32 sequence)
448 {
449   /* Check MAC */
450   if (hmac) {
451     unsigned char mac[32], psn[4];
452     uint32 mac_len;
453     
454     SILC_LOG_DEBUG(("Verifying MAC"));
455
456     /* Compute HMAC of packet */
457
458     memset(mac, 0, sizeof(mac));
459     silc_hmac_init(hmac);
460     SILC_PUT32_MSB(sequence, psn);
461     silc_hmac_update(hmac, psn, 4);
462     silc_hmac_update(hmac, buffer->data, buffer->len);
463     silc_hmac_final(hmac, mac, &mac_len);
464
465     /* Compare the HMAC's (buffer->tail has the packet's HMAC) */
466     if (memcmp(buffer->tail, mac, mac_len)) {
467       SILC_LOG_ERROR(("MAC failed"));
468       return FALSE;
469     }
470     
471     SILC_LOG_DEBUG(("MAC is Ok"));
472     memset(mac, 0, sizeof(mac));
473   }
474   
475   return TRUE;
476 }
477
478 /* Decrypts rest of the packet (after decrypting just the SILC header).
479    After calling this function the packet is ready to be parsed by calling 
480    silc_packet_parse. If everything goes without errors this returns TRUE,
481    if packet is malformed this returns FALSE. */
482
483 static int silc_packet_decrypt_rest(SilcCipher cipher, SilcHmac hmac,
484                                     SilcBuffer buffer)
485 {
486   if (cipher) {
487
488     /* Pull MAC from packet before decryption */
489     if (hmac) {
490       if ((buffer->len - silc_hmac_len(hmac)) > SILC_PACKET_MIN_LEN) {
491         silc_buffer_push_tail(buffer, silc_hmac_len(hmac));
492       } else {
493         SILC_LOG_DEBUG(("Bad MAC length in packet, packet dropped"));
494         return FALSE;
495       }
496     }
497
498     SILC_LOG_DEBUG(("Decrypting rest of the packet"));
499
500     /* Decrypt rest of the packet */
501     silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN);
502     silc_cipher_decrypt(cipher, buffer->data, buffer->data, buffer->len, 
503                         cipher->iv);
504     silc_buffer_push(buffer, SILC_PACKET_MIN_HEADER_LEN);
505
506     SILC_LOG_HEXDUMP(("Fully decrypted packet, len %d", buffer->len),
507                      buffer->data, buffer->len);
508   }
509
510   return TRUE;
511 }
512
513 /* Decrypts rest of the SILC Packet header that has been decrypted partly
514    already. This decrypts the padding of the packet also. After calling 
515    this function the packet is ready to be parsed by calling function 
516    silc_packet_parse. This is used in special packet reception (protocol
517    defines the way of decrypting special packets). */
518
519 static int silc_packet_decrypt_rest_special(SilcCipher cipher,
520                                             SilcHmac hmac,
521                                             SilcBuffer buffer)
522 {
523   /* Decrypt rest of the header plus padding */
524   if (cipher) {
525     uint16 len;
526
527     /* Pull MAC from packet before decryption */
528     if (hmac) {
529       if ((buffer->len - silc_hmac_len(hmac)) > SILC_PACKET_MIN_LEN) {
530         silc_buffer_push_tail(buffer, silc_hmac_len(hmac));
531       } else {
532         SILC_LOG_DEBUG(("Bad MAC length in packet, packet dropped"));
533         return FALSE;
534       }
535     }
536   
537     SILC_LOG_DEBUG(("Decrypting rest of the header"));
538
539     /* padding length + src id len + dst id len + header length - 16
540        bytes already decrypted, gives the rest of the encrypted packet */
541     len = (((uint8)buffer->data[4] + (uint8)buffer->data[6] + 
542            (uint8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
543            SILC_PACKET_MIN_HEADER_LEN);
544
545     silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN);
546     if (len > buffer->len) {
547       SILC_LOG_DEBUG(("Garbage in header of packet, bad packet length, "
548                       "packet dropped"));
549       return FALSE;
550     }
551     silc_cipher_decrypt(cipher, buffer->data, buffer->data, len, cipher->iv);
552     silc_buffer_push(buffer, SILC_PACKET_MIN_HEADER_LEN);
553     SILC_LOG_HEXDUMP(("packet, len %d", buffer->len), 
554                      buffer->data, buffer->len);
555   }
556
557   return TRUE;
558 }
559
560 /* Decrypts a packet. This assumes that typical SILC packet is the
561    packet to be decrypted and thus checks for normal and special SILC
562    packets and can handle both of them. This also computes and checks
563    the HMAC of the packet. If any other special or customized decryption
564    processing is required this function cannot be used. This returns
565    -1 on error, 0 when packet is normal packet and 1 when the packet
566    is special and requires special processing. 
567
568    The `check_packet' is a callback funtion that this function will 
569    call.  The callback relates to the checking whether the packet is
570    normal packet or special packet and how it should be processed.  If
571    the callback return TRUE the packet is normal and FALSE if the packet
572    is special and requires special procesing. */
573
574 static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
575                                uint32 sequence, SilcBuffer buffer, 
576                                bool normal)
577 {
578   /* If the packet type is not any special type lets decrypt rest
579      of the packet here. */
580   if (normal == TRUE) {
581     /* Normal packet, decrypt rest of the packet */
582     if (!silc_packet_decrypt_rest(cipher, hmac, buffer))
583       return -1;
584
585     /* Check MAC */
586     if (!silc_packet_check_mac(hmac, buffer, sequence))
587       return -1;
588
589     return 0;
590   } else {
591     /* Packet requires special handling, decrypt rest of the header.
592        This only decrypts. */
593     if (!silc_packet_decrypt_rest_special(cipher, hmac, buffer))
594       return -1;
595
596     /* Check MAC */
597     if (!silc_packet_check_mac(hmac, buffer, sequence))
598       return -1;
599
600     return 1;
601   }
602 }
603
604 /* Parses the packet. This is called when a whole packet is ready to be
605    parsed. The buffer sent must be already decrypted before calling this 
606    function. The len argument must be the true length of the packet. This 
607    function returns the type of the packet. The data section of the 
608    buffer is parsed, not head or tail sections. */
609
610 SilcPacketType silc_packet_parse(SilcPacketContext *ctx, SilcCipher cipher)
611 {
612   SilcBuffer buffer = ctx->buffer;
613   uint8 tmp;
614   int len, ret;
615
616   SILC_LOG_DEBUG(("Parsing incoming packet"));
617
618   /* Check the length of the buffer */
619   if (buffer->len < SILC_PACKET_MIN_LEN) {
620     SILC_LOG_ERROR(("Bad packet length: %d, packet dropped", buffer->len));
621     return SILC_PACKET_NONE;
622   }
623
624   /* Parse the buffer. This parses the SILC header of the packet. */
625   len = silc_buffer_unformat(buffer, 
626                              SILC_STR_UI_SHORT(&ctx->truelen),
627                              SILC_STR_UI_CHAR(&ctx->flags),
628                              SILC_STR_UI_CHAR(&ctx->type),
629                              SILC_STR_UI_CHAR(&ctx->padlen),
630                              SILC_STR_UI_CHAR(&tmp),
631                              SILC_STR_UI_CHAR(&ctx->src_id_len),
632                              SILC_STR_UI_CHAR(&ctx->dst_id_len),
633                              SILC_STR_UI_CHAR(&ctx->src_id_type),
634                              SILC_STR_END);
635   if (len == -1 || tmp != 0)
636     return SILC_PACKET_NONE;
637
638   if (ctx->src_id_len > SILC_PACKET_MAX_ID_LEN ||
639       ctx->dst_id_len > SILC_PACKET_MAX_ID_LEN) {
640     SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
641                     ctx->src_id_len, ctx->dst_id_len));
642     return SILC_PACKET_NONE;
643   }
644
645   silc_buffer_pull(buffer, len);
646   ret = silc_buffer_unformat(buffer, 
647                              SILC_STR_UI_XNSTRING_ALLOC(&ctx->src_id,
648                                                         ctx->src_id_len),
649                              SILC_STR_UI_CHAR(&ctx->dst_id_type),
650                              SILC_STR_UI_XNSTRING_ALLOC(&ctx->dst_id,
651                                                         ctx->dst_id_len),
652                              SILC_STR_UI_XNSTRING(NULL, ctx->padlen),
653                              SILC_STR_END);
654   if (ret == -1)
655     return SILC_PACKET_NONE;
656
657   silc_buffer_push(buffer, len);
658
659   SILC_LOG_HEXDUMP(("parsed packet, len %d", ctx->buffer->len), 
660                    ctx->buffer->data, ctx->buffer->len);
661
662   /* Pull SILC header and padding from packet */
663   silc_buffer_pull(buffer, SILC_PACKET_HEADER_LEN +
664                    ctx->src_id_len + ctx->dst_id_len + ctx->padlen);
665
666   SILC_LOG_DEBUG(("Incoming packet type: %d", ctx->type));
667
668   return ctx->type;
669 }
670
671 /* Perform special SILC Packet header parsing. This is required to some
672    packet types that have the data payload encrypted with different key
673    than the header area plus padding of the packet. Hence, this parses
674    the header in a way that it does not take the data area into account
675    and parses the header and padding area only. */
676
677 SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx,
678                                          SilcCipher cipher)
679 {
680   SilcBuffer buffer = ctx->buffer;
681   uint8 tmp;
682   int len, ret;
683
684   SILC_LOG_DEBUG(("Parsing incoming packet"));
685
686   /* Check the length of the buffer */
687   if (buffer->len < SILC_PACKET_MIN_LEN) {
688     SILC_LOG_ERROR(("Bad packet length: %d, packet dropped", buffer->len));
689     return SILC_PACKET_NONE;
690   }
691
692   /* Parse the buffer. This parses the SILC header of the packet. */
693   len = silc_buffer_unformat(buffer, 
694                              SILC_STR_UI_SHORT(&ctx->truelen),
695                              SILC_STR_UI_CHAR(&ctx->flags),
696                              SILC_STR_UI_CHAR(&ctx->type),
697                              SILC_STR_UI_CHAR(&ctx->padlen),
698                              SILC_STR_UI_CHAR(&tmp),
699                              SILC_STR_UI_CHAR(&ctx->src_id_len),
700                              SILC_STR_UI_CHAR(&ctx->dst_id_len),
701                              SILC_STR_UI_CHAR(&ctx->src_id_type),
702                              SILC_STR_END);
703   if (len == -1 || tmp != 0) {
704     SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
705     return SILC_PACKET_NONE;
706   }
707
708   if (ctx->src_id_len > SILC_PACKET_MAX_ID_LEN ||
709       ctx->dst_id_len > SILC_PACKET_MAX_ID_LEN) {
710     SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
711                     ctx->src_id_len, ctx->dst_id_len));
712     return SILC_PACKET_NONE;
713   }
714
715   silc_buffer_pull(buffer, len);
716   ret = silc_buffer_unformat(buffer, 
717                              SILC_STR_UI_XNSTRING_ALLOC(&ctx->src_id,
718                                                         ctx->src_id_len),
719                              SILC_STR_UI_CHAR(&ctx->dst_id_type),
720                              SILC_STR_UI_XNSTRING_ALLOC(&ctx->dst_id,
721                                                         ctx->dst_id_len),
722                              SILC_STR_UI_XNSTRING(NULL, ctx->padlen),
723                              SILC_STR_END);
724   if (ret == -1) {
725     SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
726     return SILC_PACKET_NONE;
727   }
728
729   silc_buffer_push(buffer, len);
730
731   SILC_LOG_HEXDUMP(("parsed packet, len %d", ctx->buffer->len), 
732                    ctx->buffer->data, ctx->buffer->len);
733
734   /* Pull SILC header and padding from packet */
735   silc_buffer_pull(buffer, SILC_PACKET_HEADER_LEN +
736                    ctx->src_id_len + ctx->dst_id_len + ctx->padlen);
737
738   SILC_LOG_DEBUG(("Incoming packet type: %d", ctx->type));
739
740   return ctx->type;
741 }
742
743 /* Allocate packet context */
744
745 SilcPacketContext *silc_packet_context_alloc(void)
746 {
747   SilcPacketContext *ctx = silc_calloc(1, sizeof(*ctx));
748   ctx->users++;
749   return ctx;
750 }
751
752 /* Increse the reference count of the packet context. */
753
754 SilcPacketContext *silc_packet_context_dup(SilcPacketContext *ctx)
755 {
756   ctx->users++;
757   SILC_LOG_DEBUG(("Packet context %p refcnt %d->%d", ctx, ctx->users - 1,
758                   ctx->users));
759   return ctx;
760 }
761
762 /* Decrese the reference count of the packet context and free it only if
763    it is zero. */
764
765 void silc_packet_context_free(SilcPacketContext *ctx)
766 {
767   ctx->users--;
768   SILC_LOG_DEBUG(("Packet context %p refcnt %d->%d", ctx, ctx->users + 1,
769                   ctx->users));
770   if (ctx->users < 1)
771     {
772       if (ctx->buffer)
773         silc_buffer_free(ctx->buffer);
774       if (ctx->src_id)
775         silc_free(ctx->src_id);
776       if (ctx->dst_id)
777         silc_free(ctx->dst_id);
778       silc_free(ctx);
779     }
780 }