updates.
[silc.git] / apps / silcd / packet_send.c
index 160209085866f8f5e452582535fa7f140fc8dc34..019df0699a68c825613d772a9ab75ff9b2794593 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2001 Pekka Riikonen
+  Copyright (C) 1997 - 2002 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -78,7 +78,7 @@ void silc_server_packet_send(SilcServer server,
                             SilcPacketType type, 
                             SilcPacketFlags flags,
                             unsigned char *data, 
-                            uint32 data_len,
+                            SilcUInt32 data_len,
                             bool force_send)
 {
   void *dst_id = NULL;
@@ -133,15 +133,18 @@ void silc_server_packet_send_dest(SilcServer server,
                                  void *dst_id,
                                  SilcIdType dst_id_type,
                                  unsigned char *data, 
-                                 uint32 data_len,
+                                 SilcUInt32 data_len,
                                  bool force_send)
 {
   SilcPacketContext packetdata;
+  const SilcBufferStruct packet;
   SilcIDListData idata = (SilcIDListData)sock->user_data;
   SilcCipher cipher = NULL;
   SilcHmac hmac = NULL;
+  SilcUInt32 sequence = 0;
   unsigned char *dst_id_data = NULL;
-  uint32 dst_id_len = 0;
+  SilcUInt32 dst_id_len = 0;
+  int block_len = 0;
 
   /* If disconnecting, ignore the data */
   if (SILC_IS_DISCONNECTING(sock))
@@ -158,6 +161,13 @@ void silc_server_packet_send_dest(SilcServer server,
     dst_id_len = silc_id_get_len(dst_id, dst_id_type);
   }
 
+  if (idata) {
+    cipher = idata->send_key;
+    hmac = idata->hmac_send;
+    sequence = idata->psn_send++;
+    block_len = silc_cipher_get_block_len(cipher);
+  }
+
   /* Set the packet context pointers */
   packetdata.type = type;
   packetdata.flags = flags;
@@ -167,43 +177,30 @@ void silc_server_packet_send_dest(SilcServer server,
   packetdata.dst_id = dst_id_data;
   packetdata.dst_id_len = dst_id_len;
   packetdata.dst_id_type = dst_id_type;
+  data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
+                                           packetdata.src_id_len + 
+                                           packetdata.dst_id_len));
   packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
     packetdata.src_id_len + dst_id_len;
-  packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
-
-  /* Prepare outgoing data buffer for packet sending */
-  silc_packet_send_prepare(sock, 
-                          SILC_PACKET_HEADER_LEN +
-                          packetdata.src_id_len + 
-                          packetdata.dst_id_len,
-                          packetdata.padlen,
-                          data_len);
-
-  SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
-
-  packetdata.buffer = sock->outbuf;
-
-  /* Put the data to the buffer */
-  if (data && data_len)
-    silc_buffer_put(sock->outbuf, data, data_len);
+  packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen, block_len);
 
   /* Create the outgoing packet */
-  silc_packet_assemble(&packetdata);
-
-  if (idata) {
-    cipher = idata->send_key;
-    hmac = idata->hmac_send;
+  if (!silc_packet_assemble(&packetdata, NULL, cipher, hmac, sock,
+                            data, data_len, (const SilcBuffer)&packet)) {
+    SILC_LOG_ERROR(("Cannot assemble packet"));
+    goto out;
   }
 
   /* Encrypt the packet */
-  silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
+  silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&packet, packet.len);
 
-  SILC_LOG_HEXDUMP(("Outgoing packet, len %d", sock->outbuf->len),
-                  sock->outbuf->data, sock->outbuf->len);
+  SILC_LOG_HEXDUMP(("Outgoing packet (%d), len %d", sequence, packet.len),
+                  packet.data, packet.len);
 
   /* Now actually send the packet */
   silc_server_packet_send_real(server, sock, force_send);
 
+ out:
   if (packetdata.src_id)
     silc_free(packetdata.src_id);
   if (packetdata.dst_id)
@@ -227,17 +224,20 @@ void silc_server_packet_send_srcdest(SilcServer server,
                                     void *dst_id,
                                     SilcIdType dst_id_type,
                                     unsigned char *data, 
-                                    uint32 data_len,
+                                    SilcUInt32 data_len,
                                     bool force_send)
 {
   SilcPacketContext packetdata;
+  const SilcBufferStruct packet;
   SilcIDListData idata;
   SilcCipher cipher = NULL;
   SilcHmac hmac = NULL;
+  SilcUInt32 sequence = 0;
   unsigned char *dst_id_data = NULL;
-  uint32 dst_id_len = 0;
+  SilcUInt32 dst_id_len = 0;
   unsigned char *src_id_data = NULL;
-  uint32 src_id_len = 0;
+  SilcUInt32 src_id_len = 0;
+  int block_len = 0;
 
   SILC_LOG_DEBUG(("Sending packet, type %d", type));
 
@@ -254,6 +254,13 @@ void silc_server_packet_send_srcdest(SilcServer server,
     src_id_len = silc_id_get_len(src_id, src_id_type);
   }
 
+  if (idata) {
+    cipher = idata->send_key;
+    hmac = idata->hmac_send;
+    sequence = idata->psn_send++;
+    block_len = silc_cipher_get_block_len(cipher);
+  }
+
   /* Set the packet context pointers */
   packetdata.type = type;
   packetdata.flags = flags;
@@ -263,43 +270,30 @@ void silc_server_packet_send_srcdest(SilcServer server,
   packetdata.dst_id = dst_id_data;
   packetdata.dst_id_len = dst_id_len;
   packetdata.dst_id_type = dst_id_type;
+  data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
+                                           packetdata.src_id_len + 
+                                           dst_id_len));
   packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
     packetdata.src_id_len + dst_id_len;
-  packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
-
-  /* Prepare outgoing data buffer for packet sending */
-  silc_packet_send_prepare(sock, 
-                          SILC_PACKET_HEADER_LEN +
-                          packetdata.src_id_len + 
-                          packetdata.dst_id_len,
-                          packetdata.padlen,
-                          data_len);
-
-  SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
-
-  packetdata.buffer = sock->outbuf;
-
-  /* Put the data to the buffer */
-  if (data && data_len)
-    silc_buffer_put(sock->outbuf, data, data_len);
+  packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen, block_len);
 
   /* Create the outgoing packet */
-  silc_packet_assemble(&packetdata);
-
-  if (idata) {
-    cipher = idata->send_key;
-    hmac = idata->hmac_send;
+  if (!silc_packet_assemble(&packetdata, NULL, cipher, hmac, sock, data,
+                            data_len, (const SilcBuffer)&packet)) {
+    SILC_LOG_ERROR(("Cannot assemble packe"));
+    goto out;
   }
 
   /* Encrypt the packet */
-  silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
+  silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&packet, packet.len);
 
-  SILC_LOG_HEXDUMP(("Outgoing packet, len %d", sock->outbuf->len),
-                  sock->outbuf->data, sock->outbuf->len);
+  SILC_LOG_HEXDUMP(("Outgoing packet (%d), len %d", sequence, packet.len),
+                   packet.data, packet.len);
 
   /* Now actually send the packet */
   silc_server_packet_send_real(server, sock, force_send);
 
+ out:
   if (packetdata.src_id)
     silc_free(packetdata.src_id);
   if (packetdata.dst_id)
@@ -325,16 +319,23 @@ void silc_server_packet_broadcast(SilcServer server,
      not allowed to send the packet. */
   id = silc_id_str2id(packet->src_id, packet->src_id_len, packet->src_id_type);
   if (id && !SILC_ID_SERVER_COMPARE(id, server->router->id)) {
+    const SilcBufferStruct p;
+
     idata = (SilcIDListData)sock->user_data;
 
     silc_buffer_push(buffer, buffer->data - buffer->head);
-    silc_packet_send_prepare(sock, 0, 0, buffer->len); 
-    silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
-    silc_packet_encrypt(idata->send_key, idata->hmac_send, 
-                       sock->outbuf, sock->outbuf->len);
+    if (!silc_packet_send_prepare(sock, 0, 0, buffer->len, idata->hmac_send,
+                                  (const SilcBuffer)&p)) {
+      SILC_LOG_ERROR(("Cannot send packet"));
+      silc_free(id);
+      return;
+    }
+    silc_buffer_put((SilcBuffer)&p, buffer->data, buffer->len);
+    silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
+                       (SilcBuffer)&p, p.len);
 
-    SILC_LOG_HEXDUMP(("Broadcasted packet, len %d", sock->outbuf->len),
-                    sock->outbuf->data, sock->outbuf->len);
+    SILC_LOG_HEXDUMP(("Broadcasted packet (%d), len %d", idata->psn_send - 1,
+                     p.len), p.data, p.len);
 
     /* Now actually send the packet */
     silc_server_packet_send_real(server, sock, TRUE);
@@ -355,6 +356,7 @@ void silc_server_packet_route(SilcServer server,
                              SilcPacketContext *packet)
 {
   SilcBuffer buffer = packet->buffer;
+  const SilcBufferStruct p;
   SilcIDListData idata;
 
   SILC_LOG_DEBUG(("Routing received packet"));
@@ -362,18 +364,97 @@ void silc_server_packet_route(SilcServer server,
   idata = (SilcIDListData)sock->user_data;
 
   silc_buffer_push(buffer, buffer->data - buffer->head);
-  silc_packet_send_prepare(sock, 0, 0, buffer->len); 
-  silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
-  silc_packet_encrypt(idata->send_key, idata->hmac_send, 
-                     sock->outbuf, sock->outbuf->len);
+  if (!silc_packet_send_prepare(sock, 0, 0, buffer->len, idata->hmac_send,
+                                (const SilcBuffer)&p)) {
+    SILC_LOG_ERROR(("Cannot send packet"));
+    return;
+  }
+  silc_buffer_put((SilcBuffer)&p, buffer->data, buffer->len);
+  silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
+                     (SilcBuffer)&p, p.len);
 
-  SILC_LOG_HEXDUMP(("Routed packet, len %d", sock->outbuf->len),
-                  sock->outbuf->data, sock->outbuf->len);
+  SILC_LOG_HEXDUMP(("Routed packet (%d), len %d", idata->psn_send - 1, 
+                  p.len), p.data, p.len);
 
   /* Now actually send the packet */
   silc_server_packet_send_real(server, sock, TRUE);
 }
 
+/* This routine can be used to send a packet to table of clients provided
+   in `clients'. If `route' is FALSE the packet is routed only to local
+   clients (for server locally connected, and for router local cell). */
+
+void silc_server_packet_send_clients(SilcServer server,
+                                    SilcClientEntry *clients,
+                                    SilcUInt32 clients_count,
+                                    SilcPacketType type, 
+                                    SilcPacketFlags flags,
+                                    bool route,
+                                    unsigned char *data, 
+                                    SilcUInt32 data_len,
+                                    bool force_send)
+{
+  SilcSocketConnection sock = NULL;
+  SilcClientEntry client = NULL;
+  SilcServerEntry *routed = NULL;
+  SilcUInt32 routed_count = 0;
+  bool gone = FALSE;
+  int i, k;
+
+  SILC_LOG_DEBUG(("Sending packet to list of clients"));
+
+  /* Send to all clients in table */
+  for (i = 0; i < clients_count; i++) {
+    client = clients[i];
+
+    /* If client has router set it is not locally connected client and
+       we will route the message to the router set in the client. Though,
+       send locally connected server in all cases. */
+    if (server->server_type == SILC_ROUTER && client->router && 
+       ((!route && client->router->router == server->id_entry) || route)) {
+
+      /* Check if we have sent the packet to this route already */
+      for (k = 0; k < routed_count; k++)
+       if (routed[k] == client->router)
+         break;
+      if (k < routed_count)
+       continue;
+
+      /* Route only once to router */
+      sock = (SilcSocketConnection)client->router->connection;
+      if (sock->type == SILC_SOCKET_TYPE_ROUTER) {
+       if (gone)
+         continue;
+       gone = TRUE;
+      }
+
+      /* Send the packet */
+      silc_server_packet_send_dest(server, sock, type, flags,
+                                  client->router->id, SILC_ID_SERVER,
+                                  data, data_len, force_send);
+
+      /* Mark this route routed already */
+      routed = silc_realloc(routed, sizeof(*routed) * (routed_count + 1));
+      routed[routed_count++] = client->router;
+      continue;
+    }
+
+    if (client->router)
+      continue;
+
+    /* Send to locally connected client */
+    sock = (SilcSocketConnection)client->connection;
+    if (!sock)
+      continue;
+
+    silc_server_packet_send_dest(server, sock, type, flags,
+                                client->id, SILC_ID_CLIENT,
+                                data, data_len, force_send);
+  }
+
+  silc_free(routed);
+}
+
 /* Internal routine to actually create the channel packet and send it
    to network. This is common function in channel message sending. If
    `channel_message' is TRUE this encrypts the message as it is strictly
@@ -385,38 +466,50 @@ silc_server_packet_send_to_channel_real(SilcServer server,
                                        SilcPacketContext *packet,
                                        SilcCipher cipher,
                                        SilcHmac hmac,
+                                       SilcUInt32 sequence,
                                        unsigned char *data,
-                                       uint32 data_len,
-                                       int channel_message,
+                                       SilcUInt32 data_len,
+                                       bool channel_message,
                                        bool force_send)
 {
+  int block_len;
+  const SilcBufferStruct p;
+
+  if (!sock)
+    return;
+
+  data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
+                                           packet->src_id_len + 
+                                           packet->dst_id_len));
   packet->truelen = data_len + SILC_PACKET_HEADER_LEN + 
     packet->src_id_len + packet->dst_id_len;
 
-  /* Prepare outgoing data buffer for packet sending */
-  silc_packet_send_prepare(sock, 
-                          SILC_PACKET_HEADER_LEN +
-                          packet->src_id_len + 
-                          packet->dst_id_len,
-                          packet->padlen,
-                          data_len);
-
-  packet->buffer = sock->outbuf;
+  block_len = cipher ? silc_cipher_get_block_len(cipher) : 0;
+  if (channel_message)
+    packet->padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
+                                        packet->src_id_len +
+                                        packet->dst_id_len), block_len);
+  else
+    packet->padlen = SILC_PACKET_PADLEN(packet->truelen, block_len);
 
   /* Put the data to buffer, assemble and encrypt the packet. The packet
      is encrypted with normal session key shared with the client, unless
      the `channel_message' is TRUE. */
-  silc_buffer_put(sock->outbuf, data, data_len);
-  silc_packet_assemble(packet);
+  if (!silc_packet_assemble(packet, NULL, cipher, hmac, sock, data,
+                            data_len, (const SilcBuffer)&p)) {
+    SILC_LOG_ERROR(("Cannot assemble packet"));
+    return;
+  }
+
   if (channel_message)
-    silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN + 
-                       packet->src_id_len + packet->dst_id_len +
-                       packet->padlen);
+    silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&p, 
+                       SILC_PACKET_HEADER_LEN + packet->src_id_len + 
+                       packet->dst_id_len + packet->padlen);
   else
-    silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
+    silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&p, p.len);
     
-  SILC_LOG_HEXDUMP(("Channel packet, len %d", sock->outbuf->len),
-                  sock->outbuf->data, sock->outbuf->len);
+  SILC_LOG_HEXDUMP(("Channel packet (%d), len %d", sequence, p.len),
+                  p.data, p.len);
 
   /* Now actually send the packet */
   silc_server_packet_send_real(server, sock, force_send);
@@ -429,7 +522,8 @@ silc_server_packet_send_to_channel_real(SilcServer server,
    If `route' is FALSE then the packet is sent only locally and will not
    be routed anywhere (for router locally means cell wide). If `sender'
    is provided then the packet is not sent to that connection since it
-   originally came from it. */
+   originally came from it. If `send_to_clients' is FALSE then the
+   packet is not sent clients, only servers. */
 
 void silc_server_packet_send_to_channel(SilcServer server,
                                        SilcSocketConnection sender,
@@ -437,7 +531,7 @@ void silc_server_packet_send_to_channel(SilcServer server,
                                        SilcPacketType type,
                                        bool route,
                                        unsigned char *data,
-                                       uint32 data_len,
+                                       SilcUInt32 data_len,
                                        bool force_send)
 {
   SilcSocketConnection sock = NULL;
@@ -447,7 +541,7 @@ void silc_server_packet_send_to_channel(SilcServer server,
   SilcChannelClientEntry chl;
   SilcHashTableList htl;
   SilcIDListData idata;
-  uint32 routed_count = 0;
+  SilcUInt32 routed_count = 0;
   bool gone = FALSE;
   int k;
 
@@ -465,9 +559,6 @@ void silc_server_packet_send_to_channel(SilcServer server,
   packetdata.dst_id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
   packetdata.dst_id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
   packetdata.dst_id_type = SILC_ID_CHANNEL;
-  packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
-    packetdata.src_id_len + packetdata.dst_id_len;
-  packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
 
   /* If there are global users in the channel we will send the message
      first to our router for further routing. */
@@ -481,11 +572,12 @@ void silc_server_packet_send_to_channel(SilcServer server,
     idata = (SilcIDListData)router;
     
     if (sock != sender) {
-      SILC_LOG_DEBUG(("Sending channel message to router for routing"));
+      SILC_LOG_DEBUG(("Sending packet to router for routing"));
       
       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
                                              idata->send_key, 
                                              idata->hmac_send, 
+                                             idata->psn_send++,
                                              data, data_len, FALSE, 
                                              force_send);
     }
@@ -521,7 +613,8 @@ void silc_server_packet_send_to_channel(SilcServer server,
       if (sender && sock == sender)
        continue;
 
-      /* Route only once to router */
+      /* Route only once to router. Protocol prohibits sending channel
+        messages to more than one router. */
       if (sock->type == SILC_SOCKET_TYPE_ROUTER) {
        if (gone)
          continue;
@@ -532,6 +625,7 @@ void silc_server_packet_send_to_channel(SilcServer server,
       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
                                              idata->send_key, 
                                              idata->hmac_send, 
+                                             idata->psn_send++,
                                              data, data_len, FALSE, 
                                              force_send);
 
@@ -549,17 +643,19 @@ void silc_server_packet_send_to_channel(SilcServer server,
     sock = (SilcSocketConnection)client->connection;
     idata = (SilcIDListData)client;
     
-    if (sender && sock == sender)
+    if (!sock || (sender && sock == sender))
       continue;
 
-      /* Send the packet */
+    /* Send the packet */
     silc_server_packet_send_to_channel_real(server, sock, &packetdata,
                                            idata->send_key, 
                                            idata->hmac_send, 
+                                           idata->psn_send++, 
                                            data, data_len, FALSE, 
                                            force_send);
   }
 
+  silc_hash_table_list_reset(&htl);
   silc_free(routed);
   silc_free(packetdata.src_id);
   silc_free(packetdata.dst_id);
@@ -585,32 +681,18 @@ silc_server_packet_relay_to_channel_encrypt(SilcServer server,
       sock->type == SILC_SOCKET_TYPE_ROUTER &&
       !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY) &&
       channel->channel_key) {
-    SilcBuffer chp;
-    uint32 iv_len, i;
-    uint16 dlen, flags;
-
-    iv_len = silc_cipher_get_block_len(channel->channel_key);
-    if (channel->iv[0] == '\0')
-      for (i = 0; i < iv_len; i++) channel->iv[i] = 
-                                    silc_rng_get_byte(server->rng);
-    else
-      silc_hash_make(server->md5hash, channel->iv, iv_len, channel->iv);
-    
-    /* Encode new payload. This encrypts it also. */
-    SILC_GET16_MSB(flags, data);
-    SILC_GET16_MSB(dlen, data + 2);
+    SilcUInt32 mac_len = silc_hmac_len(channel->hmac);
+    SilcUInt32 iv_len = silc_cipher_get_block_len(channel->channel_key);
 
-    if (dlen > data_len) {
+    if (data_len <= mac_len + iv_len) {
       SILC_LOG_WARNING(("Corrupted channel message, cannot relay it"));
       return FALSE;
     }
 
-    chp = silc_channel_message_payload_encode(flags, dlen, data + 4,
-                                             iv_len, channel->iv,
-                                             channel->channel_key,
-                                             channel->hmac);
-    memcpy(data, chp->data, chp->len);
-    silc_buffer_free(chp);
+    memcpy(channel->iv, data + (data_len - iv_len), iv_len);
+    silc_channel_message_payload_encrypt(data, data_len - iv_len - mac_len,
+                                        data_len, channel->iv, iv_len,
+                                        channel->channel_key, channel->hmac);
   }
 
   return TRUE;
@@ -628,20 +710,19 @@ silc_server_packet_relay_to_channel_encrypt(SilcServer server,
 void silc_server_packet_relay_to_channel(SilcServer server,
                                         SilcSocketConnection sender_sock,
                                         SilcChannelEntry channel,
-                                        void *sender
+                                        void *sender_id,
                                         SilcIdType sender_type,
-                                        void *sender_entry,
+                                        SilcClientEntry sender_entry,
                                         unsigned char *data,
-                                        uint32 data_len,
+                                        SilcUInt32 data_len,
                                         bool force_send)
 {
-  bool found = FALSE;
   SilcSocketConnection sock = NULL;
   SilcPacketContext packetdata;
   SilcClientEntry client = NULL;
   SilcServerEntry *routed = NULL;
   SilcChannelClientEntry chl;
-  uint32 routed_count = 0;
+  SilcUInt32 routed_count = 0;
   SilcIDListData idata;
   SilcHashTableList htl;
   bool gone = FALSE;
@@ -661,15 +742,12 @@ void silc_server_packet_relay_to_channel(SilcServer server,
   /* Set the packet context pointers. */
   packetdata.flags = 0;
   packetdata.type = SILC_PACKET_CHANNEL_MESSAGE;
-  packetdata.src_id = silc_id_id2str(sender, sender_type);
-  packetdata.src_id_len = silc_id_get_len(sender, sender_type);
+  packetdata.src_id = silc_id_id2str(sender_id, sender_type);
+  packetdata.src_id_len = silc_id_get_len(sender_id, sender_type);
   packetdata.src_id_type = sender_type;
   packetdata.dst_id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
   packetdata.dst_id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
   packetdata.dst_id_type = SILC_ID_CHANNEL;
-  packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
-                                         packetdata.src_id_len +
-                                         packetdata.dst_id_len));
 
   /* If there are global users in the channel we will send the message
      first to our router for further routing. */
@@ -689,6 +767,7 @@ void silc_server_packet_relay_to_channel(SilcServer server,
       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
                                              idata->send_key, 
                                              idata->hmac_send, 
+                                             idata->psn_send++, 
                                              data, data_len, TRUE, 
                                              force_send);
     }
@@ -697,59 +776,35 @@ void silc_server_packet_relay_to_channel(SilcServer server,
   routed = silc_calloc(silc_hash_table_count(channel->user_list), 
                       sizeof(*routed));
 
-  /* Mark that to the route the original sender if from is not routed */
-  if (sender_type == SILC_ID_CLIENT) {
-    client = (SilcClientEntry)sender_entry;
-    if (client->router) {
-      routed[routed_count++] = client->router;
-      SILC_LOG_DEBUG(("************* router %s", 
-                     silc_id_render(client->router->id, SILC_ID_SERVER)));
-    }
-  }
+  /* Assure we won't route the message back to the sender's way. */
+  if (sender_entry->router)
+    routed[routed_count++] = sender_entry->router;
 
   /* Send the message to clients on the channel's client list. */
   silc_hash_table_list(channel->user_list, &htl);
   while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
     client = chl->client;
-    if (!client)
+    if (!client || client == sender_entry || 
+       chl->mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES)
       continue;
 
-    /* Do not send to the sender */
-    if (!found && client == sender_entry) {
-      found = TRUE;
-      continue;
-    }
-
     /* If the client has set router it means that it is not locally
        connected client and we will route the packet further. */
     if (server->server_type == SILC_ROUTER && client->router) {
 
-      /* Sender maybe server as well so we want to make sure that
-        we won't send the message to the server it came from. */
-      if (!found && SILC_ID_SERVER_COMPARE(client->router->id, sender)) {
-       found = TRUE;
-       routed[routed_count++] = client->router;
-       continue;
-      }
-
       /* Check if we have sent the packet to this route already */
       for (k = 0; k < routed_count; k++)
        if (routed[k] == client->router)
          break;
       if (k < routed_count)
        continue;
-       
+
       /* Get data used in packet header encryption, keys and stuff. */
       sock = (SilcSocketConnection)client->router->connection;
       idata = (SilcIDListData)client->router;
 
-      /* Do not send to the sender. Check first whether the true
-        sender's router is same as this client's router. Also check
-        if the sender socket is the same as this client's router
+      /* Check if the sender socket is the same as this client's router
         socket. */
-      if (sender_entry &&
-         ((SilcClientEntry)sender_entry)->router == client->router)
-       continue;
       if (sender_sock && sock == sender_sock)
        continue;
 
@@ -760,63 +815,60 @@ void silc_server_packet_relay_to_channel(SilcServer server,
       /* Mark this route routed already. */
       routed[routed_count++] = client->router;
        
-      /* If the remote connection is router then we'll decrypt the
-        channel message and re-encrypt it with the session key shared
-        between us and the remote router. This is done because the
-        channel keys are cell specific and we have different channel
-        key than the remote router has. */
       if (sock->type == SILC_SOCKET_TYPE_ROUTER) {
+       /* The remote connection is router then we'll decrypt the
+          channel message and re-encrypt it with the session key shared
+          between us and the remote router. This is done because the
+          channel keys are cell specific and we have different channel
+          key than the remote router has. */
+
+       /* Route only once to router. Protocol prohibits sending channel
+          messages to more than one router. */
        if (gone)
          continue;
+       gone = TRUE;
 
        SILC_LOG_DEBUG(("Remote is router, encrypt with session key"));
-       gone = TRUE;
 
        /* If private key mode is not set then decrypt the packet
           and re-encrypt it */
-       if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
-         unsigned char *tmp = silc_calloc(data_len, sizeof(*data));
+       if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY) && 
+           channel->channel_key) {
+         unsigned char tmp[SILC_PACKET_MAX_LEN];
+
+         if (data_len > SILC_PACKET_MAX_LEN)
+           data_len = SILC_PACKET_MAX_LEN;
          memcpy(tmp, data, data_len);
 
          /* Decrypt the channel message (we don't check the MAC) */
-         if (channel->channel_key &&
-             !silc_channel_message_payload_decrypt(tmp, data_len, 
-                                                   channel->channel_key,
-                                                   NULL)) {
-           memset(tmp, 0, data_len);
-           silc_free(tmp);
-           continue;
-         }
+         silc_channel_message_payload_decrypt(tmp, data_len,
+                                              channel->channel_key, NULL);
 
          /* Now re-encrypt and send it to the router */
-         silc_server_packet_send_srcdest(server, sock, 
+         silc_server_packet_send_srcdest(server, sock,
                                          SILC_PACKET_CHANNEL_MESSAGE, 0,
-                                         sender, sender_type,
+                                         sender_id, sender_type,
                                          channel->id, SILC_ID_CHANNEL,
                                          tmp, data_len, force_send);
-
-         /* Free the copy of the channel message */
-         memset(tmp, 0, data_len);
-         silc_free(tmp);
        } else {
          /* Private key mode is set, we don't have the channel key, so
             just re-encrypt the entire packet and send it to the router. */
-         silc_server_packet_send_srcdest(server, sock, 
+         silc_server_packet_send_srcdest(server, sock,
                                          SILC_PACKET_CHANNEL_MESSAGE, 0,
-                                         sender, sender_type,
+                                         sender_id, sender_type,
                                          channel->id, SILC_ID_CHANNEL,
                                          data, data_len, force_send);
        }
-       continue;
+      } else {
+       /* Send the packet to normal server */
+       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+                                               idata->send_key,
+                                               idata->hmac_send,
+                                               idata->psn_send++,
+                                               data, data_len, TRUE,
+                                               force_send);
       }
 
-      /* Send the packet (to normal server) */
-      silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                             idata->send_key, 
-                                             idata->hmac_send, 
-                                             data, data_len, TRUE, 
-                                             force_send);
-
       continue;
     }
 
@@ -827,7 +879,7 @@ void silc_server_packet_relay_to_channel(SilcServer server,
     sock = (SilcSocketConnection)client->connection;
     idata = (SilcIDListData)client;
 
-    if (sender_sock && sock == sender_sock)
+    if (!sock || (sender_sock && sock == sender_sock))
       continue;
 
     SILC_LOG_DEBUG(("Sending packet to client ID(%s) %s (%s)", 
@@ -838,10 +890,12 @@ void silc_server_packet_relay_to_channel(SilcServer server,
     silc_server_packet_send_to_channel_real(server, sock, &packetdata,
                                            idata->send_key, 
                                            idata->hmac_send, 
+                                           idata->psn_send++, 
                                            data, data_len, TRUE, 
                                            force_send);
   }
 
+  silc_hash_table_list_reset(&htl);
   silc_free(routed);
   silc_free(packetdata.src_id);
   silc_free(packetdata.dst_id);
@@ -859,7 +913,7 @@ void silc_server_packet_send_local_channel(SilcServer server,
                                           SilcPacketType type,
                                           SilcPacketFlags flags,
                                           unsigned char *data,
-                                          uint32 data_len,
+                                          SilcUInt32 data_len,
                                           bool force_send)
 {
   SilcChannelClientEntry chl;
@@ -880,6 +934,7 @@ void silc_server_packet_send_local_channel(SilcServer server,
                                   force_send);
     }
   }
+  silc_hash_table_list_reset(&htl);
 }
 
 /* Routine used to send (relay, route) private messages to some destination.
@@ -892,38 +947,34 @@ void silc_server_send_private_message(SilcServer server,
                                      SilcSocketConnection dst_sock,
                                      SilcCipher cipher,
                                      SilcHmac hmac,
+                                     SilcUInt32 sequence,
                                      SilcPacketContext *packet)
 {
   SilcBuffer buffer = packet->buffer;
+  const SilcBufferStruct p;
+
+  silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len 
+                  + packet->dst_id_len + packet->padlen);
+  if (!silc_packet_send_prepare(dst_sock, 0, 0, buffer->len, hmac,
+                                (const SilcBuffer)&p)) {
+    SILC_LOG_ERROR(("Cannot send packet"));
+    return;
+  }
+  silc_buffer_put((SilcBuffer)&p, buffer->data, buffer->len);
 
   /* Re-encrypt and send if private messge key does not exist */
   if (!(packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY)) {
-
-    silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len 
-                    + packet->dst_id_len + packet->padlen);
-    silc_packet_send_prepare(dst_sock, 0, 0, buffer->len);
-    silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
-    
     /* Re-encrypt packet */
-    silc_packet_encrypt(cipher, hmac, dst_sock->outbuf, buffer->len);
-    
-    /* Send the packet */
-    silc_server_packet_send_real(server, dst_sock, FALSE);
-
+    silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&p, buffer->len);
   } else {
     /* Key exist so encrypt just header and send it */
-    silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len 
-                    + packet->dst_id_len + packet->padlen);
-    silc_packet_send_prepare(dst_sock, 0, 0, buffer->len);
-    silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
-
-    /* Encrypt header */
-    silc_packet_encrypt(cipher, hmac, dst_sock->outbuf, 
+    silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&p, 
                        SILC_PACKET_HEADER_LEN + packet->src_id_len + 
                        packet->dst_id_len + packet->padlen);
-
-    silc_server_packet_send_real(server, dst_sock, FALSE);
   }
+
+  /* Send the packet */
+  silc_server_packet_send_real(server, dst_sock, FALSE);
 }
 
 /* Sends current motd to client */
@@ -931,13 +982,14 @@ void silc_server_send_private_message(SilcServer server,
 void silc_server_send_motd(SilcServer server,
                           SilcSocketConnection sock)
 {
-  char *motd;
-  uint32 motd_len;
+  char *motd, *motd_file = NULL;
+  SilcUInt32 motd_len;
 
-  if (server->config && server->config->motd && 
-      server->config->motd->motd_file) {
+  if (server->config)
+    motd_file = server->config->server_info->motd_file;
 
-    motd = silc_file_read(server->config->motd->motd_file, &motd_len);
+  if (motd_file) {
+    motd = silc_file_readfile(motd_file, &motd_len);
     if (!motd)
       return;
 
@@ -975,7 +1027,7 @@ void silc_server_send_notify(SilcServer server,
                             SilcSocketConnection sock,
                             bool broadcast,
                             SilcNotifyType type,
-                            uint32 argc, ...)
+                            SilcUInt32 argc, ...)
 {
   va_list ap;
   SilcBuffer packet;
@@ -1005,7 +1057,7 @@ void silc_server_send_notify_args(SilcServer server,
                                  SilcSocketConnection sock,
                                  bool broadcast,
                                  SilcNotifyType type,
-                                 uint32 argc,
+                                 SilcUInt32 argc,
                                  SilcBuffer args)
 {
   SilcBuffer packet;
@@ -1045,7 +1097,8 @@ void silc_server_send_notify_nick_change(SilcServer server,
                                         SilcSocketConnection sock,
                                         bool broadcast,
                                         SilcClientID *old_id,
-                                        SilcClientID *new_id)
+                                        SilcClientID *new_id,
+                                        const char *nickname)
 {
   SilcBuffer idp1, idp2;
 
@@ -1054,7 +1107,8 @@ void silc_server_send_notify_nick_change(SilcServer server,
 
   silc_server_send_notify(server, sock, broadcast, 
                          SILC_NOTIFY_TYPE_NICK_CHANGE,
-                         2, idp1->data, idp1->len, idp2->data, idp2->len);
+                         3, idp1->data, idp1->len, idp2->data, idp2->len,
+                         nickname, nickname ? strlen(nickname) : 0);
   silc_buffer_free(idp1);
   silc_buffer_free(idp2);
 }
@@ -1105,9 +1159,10 @@ void silc_server_send_notify_cmode(SilcServer server,
                                   SilcSocketConnection sock,
                                   bool broadcast,
                                   SilcChannelEntry channel,
-                                  uint32 mode_mask,
+                                  SilcUInt32 mode_mask,
                                   void *id, SilcIdType id_type,
-                                  char *cipher, char *hmac)
+                                  char *cipher, char *hmac,
+                                  char *passphrase)
 {
   SilcBuffer idp;
   unsigned char mode[4];
@@ -1117,22 +1172,24 @@ void silc_server_send_notify_cmode(SilcServer server,
 
   silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id,
                               SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_CMODE_CHANGE,
-                              4, idp->data, idp->len,
+                              5, idp->data, idp->len,
                               mode, 4,
                               cipher, cipher ? strlen(cipher) : 0,
-                              hmac, hmac ? strlen(hmac) : 0);
+                              hmac, hmac ? strlen(hmac) : 0,
+                              passphrase, passphrase ? 
+                              strlen(passphrase) : 0);
   silc_buffer_free(idp);
 }
 
 /* Sends CUMODE_CHANGE notify type. This tells that `client_id' changed the
-   `target' client's mode on `channel'. The Notify packet is always
+   `target' client's mode on `channel'. The notify packet is always
    destined to the channel. */
 
 void silc_server_send_notify_cumode(SilcServer server,
                                    SilcSocketConnection sock,
                                    bool broadcast,
                                    SilcChannelEntry channel,
-                                   uint32 mode_mask,
+                                   SilcUInt32 mode_mask,
                                    void *id, SilcIdType id_type,
                                    SilcClientID *target)
 {
@@ -1162,7 +1219,7 @@ void silc_server_send_notify_signoff(SilcServer server,
                                     SilcSocketConnection sock,
                                     bool broadcast,
                                     SilcClientID *client_id,
-                                    char *message)
+                                    const char *message)
 {
   SilcBuffer idp;
 
@@ -1174,7 +1231,7 @@ void silc_server_send_notify_signoff(SilcServer server,
   silc_buffer_free(idp);
 }
 
-/* Sends TOPIC_SET notify type. This tells that `client_id' changed
+/* Sends TOPIC_SET notify type. This tells that `id' changed
    the `channel's topic to `topic'. The Notify packet is always destined
    to the channel. This function is used to send the topic set notifies
    between routers. */
@@ -1183,17 +1240,18 @@ void silc_server_send_notify_topic_set(SilcServer server,
                                       SilcSocketConnection sock,
                                       bool broadcast,
                                       SilcChannelEntry channel,
-                                      SilcClientID *client_id,
+                                      void *id, SilcIdType id_type,
                                       char *topic)
 {
   SilcBuffer idp;
 
-  idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
-  silc_server_send_notify(server, sock, broadcast,
-                         SILC_NOTIFY_TYPE_TOPIC_SET,
-                         topic ? 2 : 1, 
-                         idp->data, idp->len, 
-                         topic, topic ? strlen(topic) : 0);
+  idp = silc_id_payload_encode(id, id_type);
+  silc_server_send_notify_dest(server, sock, broadcast,
+                              (void *)channel->id, SILC_ID_CHANNEL,
+                              SILC_NOTIFY_TYPE_TOPIC_SET,
+                              topic ? 2 : 1, 
+                              idp->data, idp->len, 
+                              topic, topic ? strlen(topic) : 0);
   silc_buffer_free(idp);
 }
 
@@ -1207,16 +1265,21 @@ void silc_server_send_notify_kicked(SilcServer server,
                                    bool broadcast,
                                    SilcChannelEntry channel,
                                    SilcClientID *client_id,
+                                   SilcClientID *kicker,
                                    char *comment)
 {
-  SilcBuffer idp;
+  SilcBuffer idp1;
+  SilcBuffer idp2;
 
-  idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+  idp1 = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+  idp2 = silc_id_payload_encode((void *)kicker, SILC_ID_CLIENT);
   silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id,
-                              SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_KICKED,
-                              comment ? 2 : 1, idp->data, idp->len,
-                              comment, comment ? strlen(comment) : 0);
-  silc_buffer_free(idp);
+                              SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_KICKED, 3,
+                              idp1->data, idp1->len,
+                              comment, comment ? strlen(comment) : 0,
+                              idp2->data, idp2->len);
+  silc_buffer_free(idp1);
+  silc_buffer_free(idp2);
 }
 
 /* Send KILLED notify type. This tells that the `client_id' client was
@@ -1227,16 +1290,21 @@ void silc_server_send_notify_killed(SilcServer server,
                                    SilcSocketConnection sock,
                                    bool broadcast,
                                    SilcClientID *client_id,
-                                   char *comment)
+                                   const char *comment,
+                                   void *killer, SilcIdType killer_type)
 {
-  SilcBuffer idp;
+  SilcBuffer idp1;
+  SilcBuffer idp2;
 
-  idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+  idp1 = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
+  idp2 = silc_id_payload_encode(killer, killer_type);
   silc_server_send_notify_dest(server, sock, broadcast, (void *)client_id,
                               SILC_ID_CLIENT, SILC_NOTIFY_TYPE_KILLED,
-                              comment ? 2 : 1, idp->data, idp->len,
-                              comment, comment ? strlen(comment) : 0);
-  silc_buffer_free(idp);
+                              3, idp1->data, idp1->len,
+                              comment, comment ? strlen(comment) : 0,
+                              idp2->data, idp2->len);
+  silc_buffer_free(idp1);
+  silc_buffer_free(idp2);
 }
 
 /* Sends UMODE_CHANGE notify type. This tells that `client_id' client's
@@ -1247,7 +1315,7 @@ void silc_server_send_notify_umode(SilcServer server,
                                   SilcSocketConnection sock,
                                   bool broadcast,
                                   SilcClientID *client_id,
-                                  uint32 mode_mask)
+                                  SilcUInt32 mode_mask)
 {
   SilcBuffer idp;
   unsigned char mode[4];
@@ -1318,7 +1386,7 @@ void silc_server_send_notify_dest(SilcServer server,
                                  void *dest_id,
                                  SilcIdType dest_id_type,
                                  SilcNotifyType type,
-                                 uint32 argc, ...)
+                                 SilcUInt32 argc, ...)
 {
   va_list ap;
   SilcBuffer packet;
@@ -1344,9 +1412,9 @@ void silc_server_send_notify_dest(SilcServer server,
 void silc_server_send_notify_to_channel(SilcServer server,
                                        SilcSocketConnection sender,
                                        SilcChannelEntry channel,
-                                       unsigned char route_notify,
+                                       bool route_notify,
                                        SilcNotifyType type,
-                                       uint32 argc, ...)
+                                       SilcUInt32 argc, ...)
 {
   va_list ap;
   SilcBuffer packet;
@@ -1372,23 +1440,23 @@ void silc_server_send_notify_on_channels(SilcServer server,
                                         SilcClientEntry sender,
                                         SilcClientEntry client,
                                         SilcNotifyType type,
-                                        uint32 argc, ...)
+                                        SilcUInt32 argc, ...)
 {
   int k;
   SilcSocketConnection sock = NULL;
   SilcPacketContext packetdata;
   SilcClientEntry c;
   SilcClientEntry *sent_clients = NULL;
-  uint32 sent_clients_count = 0;
+  SilcUInt32 sent_clients_count = 0;
   SilcServerEntry *routed = NULL;
-  uint32 routed_count = 0;
+  SilcUInt32 routed_count = 0;
   SilcHashTableList htl, htl2;
   SilcChannelEntry channel;
   SilcChannelClientEntry chl, chl2;
   SilcIDListData idata;
   SilcBuffer packet;
   unsigned char *data;
-  uint32 data_len;
+  SilcUInt32 data_len;
   bool force_send = FALSE;
   va_list ap;
 
@@ -1442,18 +1510,24 @@ void silc_server_send_notify_on_channels(SilcServer server,
        /* Get data used in packet header encryption, keys and stuff. */
        sock = (SilcSocketConnection)c->router->connection;
        idata = (SilcIDListData)c->router;
-       
+
+       {
+         SILC_LOG_DEBUG(("*****************"));
+         SILC_LOG_DEBUG(("client->router->id %s",
+                         silc_id_render(c->router->id, SILC_ID_SERVER)));
+         SILC_LOG_DEBUG(("client->router->connection->user_data->id %s",
+                         silc_id_render(((SilcServerEntry)sock->user_data)->id, SILC_ID_SERVER)));
+       }
+
        packetdata.dst_id = silc_id_id2str(c->router->id, SILC_ID_SERVER);
        packetdata.dst_id_len = silc_id_get_len(c->router->id, SILC_ID_SERVER);
        packetdata.dst_id_type = SILC_ID_SERVER;
-       packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
-         packetdata.src_id_len + packetdata.dst_id_len;
-       packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
 
        /* Send the packet */
        silc_server_packet_send_to_channel_real(server, sock, &packetdata,
                                                idata->send_key, 
                                                idata->hmac_send, 
+                                               idata->psn_send++, 
                                                data, data_len, FALSE, 
                                                force_send);
        
@@ -1476,17 +1550,18 @@ void silc_server_send_notify_on_channels(SilcServer server,
        sock = (SilcSocketConnection)c->connection;
        idata = (SilcIDListData)c;
        
+        if (!sock)
+          continue;
+
        packetdata.dst_id = silc_id_id2str(c->id, SILC_ID_CLIENT);
        packetdata.dst_id_len = silc_id_get_len(c->id, SILC_ID_CLIENT);
        packetdata.dst_id_type = SILC_ID_CLIENT;
-       packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
-         packetdata.src_id_len + packetdata.dst_id_len;
-       packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
 
        /* Send the packet */
        silc_server_packet_send_to_channel_real(server, sock, &packetdata,
                                                idata->send_key, 
                                                idata->hmac_send, 
+                                               idata->psn_send++, 
                                                data, data_len, FALSE, 
                                                force_send);
 
@@ -1498,11 +1573,14 @@ void silc_server_send_notify_on_channels(SilcServer server,
        sent_clients[sent_clients_count++] = c;
       }
     }
+    silc_hash_table_list_reset(&htl2);
   }
 
+  silc_hash_table_list_reset(&htl);
   silc_free(routed);
   silc_free(sent_clients);
   silc_free(packetdata.src_id);
+  silc_buffer_free(packet);
   va_end(ap);
 }
 
@@ -1516,7 +1594,7 @@ void silc_server_send_new_id(SilcServer server,
                             SilcSocketConnection sock,
                             bool broadcast,
                             void *id, SilcIdType id_type, 
-                            uint32 id_len)
+                            SilcUInt32 id_len)
 {
   SilcBuffer idp;
 
@@ -1538,21 +1616,20 @@ void silc_server_send_new_id(SilcServer server,
 }
 
 /* Send New Channel Payload to notify about newly created channel in the
-   SILC network. Normal server nevers sends this packet. Router uses this
-   to notify other routers in the network about new channel. This packet
-   is broadcasted. */
+   SILC network. Router uses this to notify other routers in the network 
+   about new channel. This packet is broadcasted by router. */
 
 void silc_server_send_new_channel(SilcServer server,
                                  SilcSocketConnection sock,
                                  bool broadcast,
                                  char *channel_name,
                                  void *channel_id, 
-                                 uint32 channel_id_len,
-                                 uint32 mode)
+                                 SilcUInt32 channel_id_len,
+                                 SilcUInt32 mode)
 {
   SilcBuffer packet;
   unsigned char *cid;
-  uint32 name_len = strlen(channel_name);
+  SilcUInt32 name_len = strlen(channel_name);
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -1570,7 +1647,8 @@ void silc_server_send_new_channel(SilcServer server,
 
   /* Send to backup routers if this is being broadcasted to primary
      router. */
-  if (server->router && server->router->connection &&
+  if (server->server_type == SILC_ROUTER &&
+      server->router && server->router->connection &&
       sock == server->router->connection && broadcast)
     silc_server_backup_send(server, NULL, SILC_PACKET_NEW_CHANNEL, 0,
                            packet->data, packet->len, FALSE, TRUE);
@@ -1595,9 +1673,9 @@ void silc_server_send_channel_key(SilcServer server,
 {
   SilcBuffer packet;
   unsigned char *chid;
-  uint32 tmp_len;
+  SilcUInt32 tmp_len;
  
-  SILC_LOG_DEBUG(("Start"));
+  SILC_LOG_DEBUG(("Sending key to channel %s", channel->channel_name));
  
   chid = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
   if (!chid)
@@ -1612,7 +1690,8 @@ void silc_server_send_channel_key(SilcServer server,
                                            channel->key_len / 8, channel->key);
   silc_server_packet_send_to_channel(server, sender, channel, 
                                     SILC_PACKET_CHANNEL_KEY,
-                                     route, packet->data, packet->len, FALSE);
+                                     route, packet->data, packet->len, 
+                                    FALSE);
   silc_buffer_free(packet);
   silc_free(chid);
 }
@@ -1623,8 +1702,8 @@ void silc_server_send_channel_key(SilcServer server,
 void silc_server_send_command(SilcServer server, 
                              SilcSocketConnection sock,
                              SilcCommand command, 
-                             uint16 ident,
-                             uint32 argc, ...)
+                             SilcUInt16 ident,
+                             SilcUInt32 argc, ...)
 {
   SilcBuffer packet;
   va_list ap;
@@ -1638,6 +1717,57 @@ void silc_server_send_command(SilcServer server,
   va_end(ap);
 }
 
+/* Generic function to send any command reply. The arguments must be sent
+   already encoded into correct form in correct order. */
+
+void silc_server_send_command_reply(SilcServer server, 
+                                   SilcSocketConnection sock,
+                                   SilcCommand command, 
+                                   SilcCommandStatus status,
+                                   SilcCommandStatus error,
+                                   SilcUInt16 ident,
+                                   SilcUInt32 argc, ...)
+{
+  SilcBuffer packet;
+  va_list ap;
+
+  va_start(ap, argc);
+
+  packet = silc_command_reply_payload_encode_vap(command, status, error,
+                                                ident, argc, ap);
+  silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
+                         packet->data, packet->len, TRUE);
+  silc_buffer_free(packet);
+  va_end(ap);
+}
+
+/* Generic function to send any command reply. The arguments must be sent
+   already encoded into correct form in correct order. */
+
+void silc_server_send_dest_command_reply(SilcServer server, 
+                                        SilcSocketConnection sock,
+                                        void *dst_id,
+                                        SilcIdType dst_id_type,
+                                        SilcCommand command, 
+                                        SilcCommandStatus status,
+                                        SilcCommandStatus error,
+                                        SilcUInt16 ident,
+                                        SilcUInt32 argc, ...)
+{
+  SilcBuffer packet;
+  va_list ap;
+
+  va_start(ap, argc);
+
+  packet = silc_command_reply_payload_encode_vap(command, status, error,
+                                                ident, argc, ap);
+  silc_server_packet_send_dest(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
+                              dst_id, dst_id_type, packet->data, 
+                              packet->len, TRUE);
+  silc_buffer_free(packet);
+  va_end(ap);
+}
+
 /* Send the heartbeat packet. */
 
 void silc_server_send_heartbeat(SilcServer server,
@@ -1654,17 +1784,23 @@ void silc_server_relay_packet(SilcServer server,
                              SilcSocketConnection dst_sock,
                              SilcCipher cipher,
                              SilcHmac hmac,
+                             SilcUInt32 sequence,
                              SilcPacketContext *packet,
                              bool force_send)
 {
+  const SilcBufferStruct p;
+
   silc_buffer_push(packet->buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len 
                   + packet->dst_id_len + packet->padlen);
+  if (!silc_packet_send_prepare(dst_sock, 0, 0, packet->buffer->len, hmac,
+                                (const SilcBuffer)&p)) {
+    SILC_LOG_ERROR(("Cannot send packet"));
+    return;
+  }
+  silc_buffer_put((SilcBuffer)&p, packet->buffer->data, packet->buffer->len);
 
-  silc_packet_send_prepare(dst_sock, 0, 0, packet->buffer->len);
-  silc_buffer_put(dst_sock->outbuf, packet->buffer->data, packet->buffer->len);
-  
   /* Re-encrypt packet */
-  silc_packet_encrypt(cipher, hmac, dst_sock->outbuf, packet->buffer->len);
+  silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&p, p.len);
   
   /* Send the packet */
   silc_server_packet_send_real(server, dst_sock, force_send);
@@ -1677,7 +1813,7 @@ void silc_server_relay_packet(SilcServer server,
 
 void silc_server_send_connection_auth_request(SilcServer server,
                                              SilcSocketConnection sock,
-                                             uint16 conn_type,
+                                             SilcUInt16 conn_type,
                                              SilcAuthMethod auth_meth)
 {
   SilcBuffer packet;
@@ -1704,12 +1840,7 @@ void silc_server_packet_queue_purge(SilcServer server,
   if (sock && SILC_IS_OUTBUF_PENDING(sock) && 
       (SILC_IS_DISCONNECTED(sock) == FALSE)) {
     server->stat.packets_sent++;
-
-    if (sock->outbuf->data - sock->outbuf->head)
-      silc_buffer_push(sock->outbuf, sock->outbuf->data - sock->outbuf->head);
-
     silc_packet_send(sock, TRUE);
-
     SILC_SET_CONNECTION_FOR_INPUT(server->schedule, sock->sock);
     SILC_UNSET_OUTBUF_PENDING(sock);
     silc_buffer_clear(sock->outbuf);