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