Added silc_packet_set_keys.
[silc.git] / lib / silccore / silcpacket.c
index 05ca279d86bd42b83a182422bf7af8812f7d78f2..022ee1c5f8e2da6f464bf52c5596c5435eb90b1f 100644 (file)
@@ -151,15 +151,44 @@ do {                                                                      \
                                (s)->stream_context);                   \
 } while(0)
 
+static void silc_packet_dispatch(SilcPacket packet);
+static void silc_packet_read_process(SilcPacketStream stream);
+static inline SilcBool silc_packet_send_raw(SilcPacketStream stream,
+                                           SilcPacketType type,
+                                           SilcPacketFlags flags,
+                                           SilcIdType src_id_type,
+                                           unsigned char *src_id,
+                                           SilcUInt32 src_id_len,
+                                           SilcIdType dst_id_type,
+                                           unsigned char *dst_id,
+                                           SilcUInt32 dst_id_len,
+                                           const unsigned char *data,
+                                           SilcUInt32 data_len,
+                                           SilcCipher cipher,
+                                           SilcHmac hmac);
 
 /************************ Static utility functions **************************/
 
-static void silc_packet_read_process(SilcPacketStream stream);
+/* Injects packet to new stream created with silc_packet_stream_add_remote. */
+
+SILC_TASK_CALLBACK(silc_packet_stream_inject_packet)
+{
+  SilcPacket packet = context;
+  SilcPacketStream stream = packet->stream;
+
+  SILC_LOG_DEBUG(("Injecting packet %p to stream %p", packet, packet->stream));
+
+  silc_mutex_lock(stream->lock);
+  silc_packet_dispatch(packet);
+  silc_mutex_unlock(stream->lock);
+}
 
 /* Write data to the stream.  Must be called with ps->lock locked.  Unlocks
-   the lock inside this function. */
+   the lock inside this function, unless no_unlock is TRUE.  Unlocks always
+   in case it returns FALSE. */
 
-static inline SilcBool silc_packet_stream_write(SilcPacketStream ps)
+static inline SilcBool silc_packet_stream_write(SilcPacketStream ps,
+                                               SilcBool no_unlock)
 {
   SilcStream stream;
   SilcBool connected;
@@ -180,14 +209,14 @@ static inline SilcBool silc_packet_stream_write(SilcPacketStream ps)
        if (i == -2) {
          /* Error */
          silc_buffer_reset(&ps->outbuf);
-         silc_mutex_unlock(ps->lock);
          SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_WRITE);
          return FALSE;
        }
 
        if (i == -1) {
          /* Cannot write now, write later. */
-         silc_mutex_unlock(ps->lock);
+         if (!no_unlock)
+           silc_mutex_unlock(ps->lock);
          return TRUE;
        }
 
@@ -196,7 +225,8 @@ static inline SilcBool silc_packet_stream_write(SilcPacketStream ps)
       }
 
       silc_buffer_reset(&ps->outbuf);
-      silc_mutex_unlock(ps->lock);
+      if (!no_unlock)
+       silc_mutex_unlock(ps->lock);
 
       return TRUE;
     }
@@ -224,7 +254,8 @@ static inline SilcBool silc_packet_stream_write(SilcPacketStream ps)
 
     if (i == -1) {
       /* Cannot write now, write later. */
-      silc_mutex_unlock(ps->lock);
+      if (!no_unlock)
+       silc_mutex_unlock(ps->lock);
       return TRUE;
     }
 
@@ -233,7 +264,8 @@ static inline SilcBool silc_packet_stream_write(SilcPacketStream ps)
   }
 
   silc_buffer_reset(&ps->outbuf);
-  silc_mutex_unlock(ps->lock);
+  if (!no_unlock)
+    silc_mutex_unlock(ps->lock);
 
   return TRUE;
 }
@@ -328,6 +360,7 @@ static inline SilcBool silc_packet_stream_read(SilcPacketStream ps,
       }
 
       /* Save sender IP and port */
+      silc_free(ps->remote_udp->remote_ip);
       ps->remote_udp->remote_ip = strdup(remote_ip);
       ps->remote_udp->remote_port = remote_port;
 
@@ -392,7 +425,7 @@ static void silc_packet_stream_io(SilcStream stream, SilcStreamStatus status,
     }
 
     /* Write pending data to stream */
-    silc_packet_stream_write(ps);
+    silc_packet_stream_write(ps, FALSE);
     break;
 
   case SILC_STREAM_CAN_READ:
@@ -611,7 +644,8 @@ SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
 
 SilcPacketStream silc_packet_stream_add_remote(SilcPacketStream stream,
                                               const char *remote_ip,
-                                              SilcUInt16 remote_port)
+                                              SilcUInt16 remote_port,
+                                              SilcPacket packet)
 {
   SilcPacketEngine engine = stream->engine;
   SilcPacketStream ps;
@@ -688,6 +722,14 @@ SilcPacketStream silc_packet_stream_add_remote(SilcPacketStream stream,
     return NULL;
   }
 
+  if (packet) {
+    /* Inject packet to the new stream */
+    packet->stream = ps;
+    silc_schedule_task_add_timeout(silc_stream_get_schedule(stream->stream),
+                                  silc_packet_stream_inject_packet, packet,
+                                  0, 0);
+  }
+
   return ps;
 }
 
@@ -736,10 +778,20 @@ void silc_packet_stream_destroy(SilcPacketStream stream)
   silc_buffer_purge(&stream->inbuf);
   silc_buffer_purge(&stream->outbuf);
 
+  if (stream->process) {
+    SilcPacketProcess p;
+    silc_dlist_start(stream->process);
+    while ((p = silc_dlist_get(stream->process))) {
+      silc_free(p->types);
+      silc_free(p);
+      silc_dlist_del(stream->process, p);
+    }
+    silc_dlist_uninit(stream->process);
+  }
+
   /* XXX */
 
   silc_atomic_uninit8(&stream->refcnt);
-  silc_dlist_uninit(stream->process);
   silc_mutex_free(stream->lock);
   silc_free(stream);
 }
@@ -872,6 +924,7 @@ void silc_packet_stream_unlink(SilcPacketStream stream,
     if (p->callbacks == callbacks &&
        p->callback_context == callback_context) {
       silc_dlist_del(stream->process, p);
+      silc_free(p->types);
       silc_free(p);
       break;
     }
@@ -886,17 +939,24 @@ void silc_packet_stream_unlink(SilcPacketStream stream,
   silc_packet_stream_unref(stream);
 }
 
+/* Returns TRUE if stream is UDP stream */
+
+SilcBool silc_packet_stream_is_udp(SilcPacketStream stream)
+{
+  return stream->udp || silc_socket_stream_is_udp(stream->stream, NULL);
+}
+
 /* Return packet sender IP and port for UDP packet stream */
 
-SilcBool silc_packet_stream_get_sender(SilcPacketStream stream,
-                                      const char **sender_ip,
-                                      SilcUInt16 *sender_port)
+SilcBool silc_packet_get_sender(SilcPacket packet,
+                               const char **sender_ip,
+                               SilcUInt16 *sender_port)
 {
-  if (!stream->remote_udp)
+  if (!packet->stream->remote_udp)
     return FALSE;
 
-  *sender_ip = stream->remote_udp->remote_ip;
-  *sender_port = stream->remote_udp->remote_port;
+  *sender_ip = packet->stream->remote_udp->remote_ip;
+  *sender_port = packet->stream->remote_udp->remote_port;
 
   return TRUE;
 }
@@ -962,104 +1022,97 @@ SilcStream silc_packet_stream_get_stream(SilcPacketStream stream)
   return stream->stream;
 }
 
-/* Set ciphers for packet stream */
+/* Set keys. */
 
-void silc_packet_set_ciphers(SilcPacketStream stream, SilcCipher send,
-                            SilcCipher receive)
+SilcBool silc_packet_set_keys(SilcPacketStream stream, SilcCipher send_key,
+                              SilcCipher receive_key, SilcHmac send_hmac,
+                              SilcHmac receive_hmac, SilcBool rekey)
 {
-  SILC_LOG_DEBUG(("Setting new ciphers to packet stream"));
+  SILC_LOG_DEBUG(("Setting new keys to packet stream %p", stream));
+
+  /* If doing rekey, send REKEY_DONE packet */
+  if (rekey) {
+    /* This will take stream lock. */
+    if (!silc_packet_send_raw(stream, SILC_PACKET_REKEY_DONE, 0,
+                             stream->src_id_type, stream->src_id,
+                             stream->src_id_len, stream->dst_id_type,
+                             stream->dst_id, stream->dst_id_len,
+                             NULL, 0, stream->send_key[0],
+                             stream->send_hmac[0]))
+      return FALSE;
 
-  silc_mutex_lock(stream->lock);
+    /* Write the packet to the stream */
+    if (!silc_packet_stream_write(stream, TRUE))
+      return FALSE;
+  } else {
+    silc_mutex_lock(stream->lock);
+  }
 
-  /* In case IV Included is set, save the old key */
+  /* In case IV Included is set, save the old keys */
   if (stream->iv_included) {
-    if (stream->send_key[1]) {
+    if (stream->send_key[1] && send_key) {
       silc_cipher_free(stream->send_key[1]);
       stream->send_key[1] = stream->send_key[0];
     }
-    if (stream->receive_key[1]) {
+    if (stream->receive_key[1] && receive_key) {
       silc_cipher_free(stream->receive_key[1]);
       stream->receive_key[1] = stream->receive_key[0];
     }
-  } else {
-    if (stream->send_key[0])
-      silc_cipher_free(stream->send_key[0]);
-    if (stream->send_key[1])
-      silc_cipher_free(stream->receive_key[0]);
-  }
-
-  stream->send_key[0] = send;
-  stream->receive_key[0] = receive;
-
-  silc_mutex_unlock(stream->lock);
-}
-
-/* Return current ciphers from packet stream */
-
-SilcBool silc_packet_get_ciphers(SilcPacketStream stream, SilcCipher *send,
-                                SilcCipher *receive)
-{
-  if (!stream->send_key[0] && !stream->receive_key[0])
-    return FALSE;
-
-  silc_mutex_lock(stream->lock);
-
-  if (send)
-    *send = stream->send_key[0];
-  if (receive)
-    *receive = stream->receive_key[0];
-
-  silc_mutex_unlock(stream->lock);
-
-  return TRUE;
-}
-
-/* Set HMACs for packet stream */
-
-void silc_packet_set_hmacs(SilcPacketStream stream, SilcHmac send,
-                          SilcHmac receive)
-{
-  SILC_LOG_DEBUG(("Setting new HMACs to packet stream"));
-
-  silc_mutex_lock(stream->lock);
-
-  /* In case IV Included is set, save the old HMAC */
-  if (stream->iv_included) {
-    if (stream->send_hmac[1]) {
+    if (stream->send_hmac[1] && send_hmac) {
       silc_hmac_free(stream->send_hmac[1]);
       stream->send_hmac[1] = stream->send_hmac[0];
     }
-    if (stream->receive_hmac[1]) {
+    if (stream->receive_hmac[1] && receive_hmac) {
       silc_hmac_free(stream->receive_hmac[1]);
       stream->receive_hmac[1] = stream->receive_hmac[0];
     }
   } else {
-    if (stream->send_hmac[0])
+    if (stream->send_key[0] && send_key)
+      silc_cipher_free(stream->send_key[0]);
+    if (stream->send_key[1] && receive_key)
+      silc_cipher_free(stream->receive_key[0]);
+    if (stream->send_hmac[0] && send_hmac)
       silc_hmac_free(stream->send_hmac[0]);
-    if (stream->receive_hmac[0])
+    if (stream->receive_hmac[0] && receive_hmac)
       silc_hmac_free(stream->receive_hmac[0]);
   }
 
-  stream->send_hmac[0] = send;
-  stream->receive_hmac[0] = receive;
+  /* Set keys */
+  if (send_key)
+    stream->send_key[0] = send_key;
+  if (receive_key)
+    stream->receive_key[0] = receive_key;
+  if (send_hmac)
+    stream->send_hmac[0] = send_hmac;
+  if (receive_hmac)
+    stream->receive_hmac[0] = receive_hmac;
 
   silc_mutex_unlock(stream->lock);
+  return TRUE;
 }
 
-/* Return current HMACs from packet stream */
+/* Return current ciphers from packet stream */
 
-SilcBool silc_packet_get_hmacs(SilcPacketStream stream, SilcHmac *send,
-                              SilcHmac *receive)
+SilcBool silc_packet_get_keys(SilcPacketStream stream,
+                             SilcCipher *send_key,
+                             SilcCipher *receive_key,
+                             SilcHmac *send_hmac,
+                             SilcHmac *receive_hmac)
 {
-  if (!stream->send_hmac[0] && !stream->receive_hmac[0])
+  if (!stream->send_key[0] && !stream->receive_key[0] &&
+      !stream->send_hmac[0] && !stream->receive_hmac[0])
     return FALSE;
 
   silc_mutex_lock(stream->lock);
 
-  if (send)
-    *send = stream->send_hmac[0];
-  if (receive)
-    *receive = stream->receive_hmac[0];
+  if (send_key)
+    *send_key = stream->send_key[0];
+  if (receive_key)
+    *receive_key = stream->receive_key[0];
+  if (send_hmac)
+    *send_hmac = stream->send_hmac[0];
+  if (receive_hmac)
+    *receive_hmac = stream->receive_hmac[0];
 
   silc_mutex_unlock(stream->lock);
 
@@ -1160,10 +1213,10 @@ void silc_packet_free(SilcPacket packet)
 /* Prepare outgoing data buffer for packet sending.  Returns the
    pointer to that buffer into the `packet'. */
 
-static SilcBool silc_packet_send_prepare(SilcPacketStream stream,
-                                        SilcUInt32 totlen,
-                                        SilcHmac hmac,
-                                        SilcBuffer packet)
+static inline SilcBool silc_packet_send_prepare(SilcPacketStream stream,
+                                               SilcUInt32 totlen,
+                                               SilcHmac hmac,
+                                               SilcBuffer packet)
 {
   unsigned char *oldptr;
   unsigned int mac_len = hmac ? silc_hmac_len(hmac) : 0;
@@ -1187,21 +1240,23 @@ static SilcBool silc_packet_send_prepare(SilcPacketStream stream,
   return TRUE;
 }
 
-/* Internal routine to send packet */
-
-static SilcBool silc_packet_send_raw(SilcPacketStream stream,
-                                    SilcPacketType type,
-                                    SilcPacketFlags flags,
-                                    SilcIdType src_id_type,
-                                    unsigned char *src_id,
-                                    SilcUInt32 src_id_len,
-                                    SilcIdType dst_id_type,
-                                    unsigned char *dst_id,
-                                    SilcUInt32 dst_id_len,
-                                    const unsigned char *data,
-                                    SilcUInt32 data_len,
-                                    SilcCipher cipher,
-                                    SilcHmac hmac)
+/* Internal routine to assemble outgoing packet.  Assembles and encryptes
+   the packet.  The silc_packet_stream_write needs to be called to send it
+   after this returns TRUE. */
+
+static inline SilcBool silc_packet_send_raw(SilcPacketStream stream,
+                                           SilcPacketType type,
+                                           SilcPacketFlags flags,
+                                           SilcIdType src_id_type,
+                                           unsigned char *src_id,
+                                           SilcUInt32 src_id_len,
+                                           SilcIdType dst_id_type,
+                                           unsigned char *dst_id,
+                                           SilcUInt32 dst_id_len,
+                                           const unsigned char *data,
+                                           SilcUInt32 data_len,
+                                           SilcCipher cipher,
+                                           SilcHmac hmac)
 {
   unsigned char tmppad[SILC_PACKET_MAX_PADLEN], iv[33], psn[4];
   int block_len = (cipher ? silc_cipher_get_block_len(cipher) : 0);
@@ -1324,8 +1379,7 @@ static SilcBool silc_packet_send_raw(SilcPacketStream stream,
     stream->send_psn++;
   }
 
-  /* Write the packet to the stream */
-  return silc_packet_stream_write(stream);
+  return TRUE;
 }
 
 /* Sends a packet */
@@ -1334,16 +1388,21 @@ SilcBool silc_packet_send(SilcPacketStream stream,
                          SilcPacketType type, SilcPacketFlags flags,
                          const unsigned char *data, SilcUInt32 data_len)
 {
-  return silc_packet_send_raw(stream, type, flags,
-                             stream->src_id_type,
-                             stream->src_id,
-                             stream->src_id_len,
-                             stream->dst_id_type,
-                             stream->dst_id,
-                             stream->dst_id_len,
-                             data, data_len,
-                             stream->send_key[0],
-                             stream->send_hmac[0]);
+  SilcBool ret;
+
+  ret = silc_packet_send_raw(stream, type, flags,
+                            stream->src_id_type,
+                            stream->src_id,
+                            stream->src_id_len,
+                            stream->dst_id_type,
+                            stream->dst_id,
+                            stream->dst_id_len,
+                            data, data_len,
+                            stream->send_key[0],
+                            stream->send_hmac[0]);
+
+  /* Write the packet to the stream */
+  return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
 }
 
 /* Sends a packet, extended routine */
@@ -1357,6 +1416,7 @@ SilcBool silc_packet_send_ext(SilcPacketStream stream,
 {
   unsigned char src_id_data[32], dst_id_data[32];
   SilcUInt32 src_id_len, dst_id_len;
+  SilcBool ret;
 
   if (src_id)
     if (!silc_id_id2str(src_id, src_id_type, src_id_data,
@@ -1367,16 +1427,19 @@ SilcBool silc_packet_send_ext(SilcPacketStream stream,
                        sizeof(dst_id_data), &dst_id_len))
       return FALSE;
 
-  return silc_packet_send_raw(stream, type, flags,
-                             src_id ? src_id_type : stream->src_id_type,
-                             src_id ? src_id_data : stream->src_id,
-                             src_id ? src_id_len : stream->src_id_len,
-                             dst_id ? dst_id_type : stream->dst_id_type,
-                             dst_id ? dst_id_data : stream->dst_id,
-                             dst_id ? dst_id_len : stream->dst_id_len,
-                             data, data_len,
-                             cipher ? cipher : stream->send_key[0],
-                             hmac ? hmac : stream->send_hmac[0]);
+  ret = silc_packet_send_raw(stream, type, flags,
+                            src_id ? src_id_type : stream->src_id_type,
+                            src_id ? src_id_data : stream->src_id,
+                            src_id ? src_id_len : stream->src_id_len,
+                            dst_id ? dst_id_type : stream->dst_id_type,
+                            dst_id ? dst_id_data : stream->dst_id,
+                            dst_id ? dst_id_len : stream->dst_id_len,
+                            data, data_len,
+                            cipher ? cipher : stream->send_key[0],
+                            hmac ? hmac : stream->send_hmac[0]);
+
+  /* Write the packet to the stream */
+  return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
 }
 
 /* Sends packet after formatting the arguments to buffer */
@@ -1439,12 +1502,12 @@ SilcBool silc_packet_send_va_ext(SilcPacketStream stream,
 
 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. */
 
-static SilcBool silc_packet_check_mac(SilcHmac hmac,
-                                     const unsigned char *data,
-                                     SilcUInt32 data_len,
-                                     const unsigned char *packet_mac,
-                                     const unsigned char *packet_seq,
-                                     SilcUInt32 sequence)
+static inline SilcBool silc_packet_check_mac(SilcHmac hmac,
+                                            const unsigned char *data,
+                                            SilcUInt32 data_len,
+                                            const unsigned char *packet_mac,
+                                            const unsigned char *packet_seq,
+                                            SilcUInt32 sequence)
 {
   /* Check MAC */
   if (hmac) {
@@ -1480,9 +1543,9 @@ static SilcBool silc_packet_check_mac(SilcHmac hmac,
 /* Decrypts SILC packet.  Handles both normal and special packet decryption.
    Return 0 when packet is normal and 1 when it it special, -1 on error. */
 
-static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
-                              SilcUInt32 sequence, SilcBuffer buffer,
-                              SilcBool normal)
+static inline int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
+                                     SilcUInt32 sequence, SilcBuffer buffer,
+                                     SilcBool normal)
 {
   if (normal == TRUE) {
     if (cipher) {
@@ -1528,7 +1591,7 @@ static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
    parsed. The buffer sent must be already decrypted before calling this
    function. */
 
-static SilcBool silc_packet_parse(SilcPacket packet)
+static inline SilcBool silc_packet_parse(SilcPacket packet)
 {
   SilcBuffer buffer = &packet->buffer;
   SilcUInt8 padlen = (SilcUInt8)buffer->data[4];
@@ -1546,14 +1609,18 @@ static SilcBool silc_packet_parse(SilcPacket packet)
                             SILC_STR_UI_CHAR(&src_id_type),
                             SILC_STR_END);
   if (ret == -1) {
-    SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
+    if (!packet->stream->udp &&
+       !silc_socket_stream_is_udp(packet->stream->stream, NULL))
+      SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
     return FALSE;
   }
 
   if (src_id_len > SILC_PACKET_MAX_ID_LEN ||
       dst_id_len > SILC_PACKET_MAX_ID_LEN) {
-    SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
-                   packet->src_id_len, packet->dst_id_len));
+    if (!packet->stream->udp &&
+       !silc_socket_stream_is_udp(packet->stream->stream, NULL))
+      SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
+                     packet->src_id_len, packet->dst_id_len));
     return FALSE;
   }
 
@@ -1565,14 +1632,18 @@ static SilcBool silc_packet_parse(SilcPacket packet)
                             SILC_STR_OFFSET(padlen),
                             SILC_STR_END);
   if (ret == -1) {
-    SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
+    if (!packet->stream->udp &&
+       !silc_socket_stream_is_udp(packet->stream->stream, NULL))
+      SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
     return FALSE;
   }
 
   if (src_id_type > SILC_ID_CHANNEL ||
       dst_id_type > SILC_ID_CHANNEL) {
-    SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
-                   src_id_type, dst_id_type));
+    if (!packet->stream->udp &&
+       !silc_socket_stream_is_udp(packet->stream->stream, NULL))
+      SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
+                     src_id_type, dst_id_type));
     return FALSE;
   }
 
@@ -1600,15 +1671,6 @@ static void silc_packet_dispatch(SilcPacket packet)
   SilcBool default_sent = FALSE;
   SilcPacketType *pt;
 
-  /* Parse the packet */
-  if (!silc_packet_parse(packet)) {
-    silc_mutex_unlock(stream->lock);
-    SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
-    silc_mutex_lock(stream->lock);
-    silc_packet_free(packet);
-    return;
-  }
-
   /* Dispatch packet to all packet processors that want it */
 
   if (!stream->process) {
@@ -1779,7 +1841,8 @@ static void silc_packet_read_process(SilcPacketStream stream)
 
     /* Sanity checks */
     if (packetlen < SILC_PACKET_MIN_LEN) {
-      SILC_LOG_ERROR(("Received too short packet"));
+      if (!stream->udp && !silc_socket_stream_is_udp(stream->stream, NULL))
+       SILC_LOG_ERROR(("Received too short packet"));
       silc_mutex_unlock(stream->lock);
       SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
       silc_mutex_lock(stream->lock);
@@ -1888,6 +1951,16 @@ static void silc_packet_read_process(SilcPacketStream stream)
     /* Pull the packet from inbuf thus we'll get the next one in the inbuf. */
     silc_buffer_pull(&stream->inbuf, paddedlen + mac_len);
 
+    /* Parse the packet */
+    if (!silc_packet_parse(packet)) {
+      silc_mutex_unlock(stream->lock);
+      SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
+      silc_mutex_lock(stream->lock);
+      silc_packet_free(packet);
+      memset(tmp, 0, sizeof(tmp));
+      return;
+    }
+
     /* Dispatch the packet to application */
     silc_packet_dispatch(packet);
   }