updates.
[silc.git] / apps / silcd / packet_send.c
index ac8f117c50e9dd3ca7f42bd852030d17698268d2..814758b82a4806190b4805b4d2bcf4f8c8657f98 100644 (file)
@@ -35,6 +35,11 @@ int silc_server_packet_send_real(SilcServer server,
 {
   int ret;
 
+  /* If rekey protocol is active we must assure that all packets are
+     sent through packet queue. */
+  if (SILC_SERVER_IS_REKEY(sock))
+    force_send = FALSE;
+
   /* Send the packet */
   ret = silc_packet_send(sock, force_send);
   if (ret != -2)
@@ -65,7 +70,7 @@ void silc_server_packet_send(SilcServer server,
                             SilcPacketType type, 
                             SilcPacketFlags flags,
                             unsigned char *data, 
-                            unsigned int data_len,
+                            uint32 data_len,
                             int force_send)
 {
   void *dst_id = NULL;
@@ -107,7 +112,7 @@ void silc_server_packet_send_dest(SilcServer server,
                                  void *dst_id,
                                  SilcIdType dst_id_type,
                                  unsigned char *data, 
-                                 unsigned int data_len,
+                                 uint32 data_len,
                                  int force_send)
 {
   SilcPacketContext packetdata;
@@ -115,7 +120,7 @@ void silc_server_packet_send_dest(SilcServer server,
   SilcCipher cipher = NULL;
   SilcHmac hmac = NULL;
   unsigned char *dst_id_data = NULL;
-  unsigned int dst_id_len = 0;
+  uint32 dst_id_len = 0;
 
   SILC_LOG_DEBUG(("Sending packet, type %d", type));
 
@@ -139,7 +144,6 @@ void silc_server_packet_send_dest(SilcServer server,
   packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
     packetdata.src_id_len + dst_id_len;
   packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
-  packetdata.rng = server->rng;
 
   /* Prepare outgoing data buffer for packet sending */
   silc_packet_send_prepare(sock, 
@@ -162,7 +166,103 @@ void silc_server_packet_send_dest(SilcServer server,
 
   if (idata) {
     cipher = idata->send_key;
-    hmac = idata->hmac;
+    hmac = idata->hmac_send;
+  }
+
+  /* Encrypt the packet */
+  silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
+
+  SILC_LOG_HEXDUMP(("Outgoing packet, len %d", sock->outbuf->len),
+                  sock->outbuf->data, sock->outbuf->len);
+
+  /* Now actually send the packet */
+  silc_server_packet_send_real(server, sock, force_send);
+
+  if (packetdata.src_id)
+    silc_free(packetdata.src_id);
+  if (packetdata.dst_id)
+    silc_free(packetdata.dst_id);
+}
+
+/* Assembles a new packet to be sent out to network. This doesn't actually
+   send the packet but creates the packet and fills the outgoing data
+   buffer and marks the packet ready to be sent to network. However, If 
+   argument force_send is TRUE the packet is sent immediately and not put 
+   to queue. Normal case is that the packet is not sent immediately. 
+   The source and destination information is sent as argument for this
+   function. */
+
+void silc_server_packet_send_srcdest(SilcServer server,
+                                    SilcSocketConnection sock, 
+                                    SilcPacketType type, 
+                                    SilcPacketFlags flags,
+                                    void *src_id,
+                                    SilcIdType src_id_type,
+                                    void *dst_id,
+                                    SilcIdType dst_id_type,
+                                    unsigned char *data, 
+                                    uint32 data_len,
+                                    int force_send)
+{
+  SilcPacketContext packetdata;
+  SilcIDListData idata;
+  SilcCipher cipher = NULL;
+  SilcHmac hmac = NULL;
+  unsigned char *dst_id_data = NULL;
+  uint32 dst_id_len = 0;
+  unsigned char *src_id_data = NULL;
+  uint32 src_id_len = 0;
+
+  SILC_LOG_DEBUG(("Sending packet, type %d", type));
+
+  /* Get data used in the packet sending, keys and stuff */
+  idata = (SilcIDListData)sock->user_data;
+
+  if (dst_id) {
+    dst_id_data = silc_id_id2str(dst_id, dst_id_type);
+    dst_id_len = silc_id_get_len(dst_id_type);
+  }
+
+  if (src_id) {
+    src_id_data = silc_id_id2str(src_id, src_id_type);
+    src_id_len = silc_id_get_len(src_id_type);
+  }
+
+  /* Set the packet context pointers */
+  packetdata.type = type;
+  packetdata.flags = flags;
+  packetdata.src_id = src_id_data;
+  packetdata.src_id_len = src_id_len;
+  packetdata.src_id_type = src_id_type;
+  packetdata.dst_id = dst_id_data;
+  packetdata.dst_id_len = dst_id_len;
+  packetdata.dst_id_type = dst_id_type;
+  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);
+
+  /* Create the outgoing packet */
+  silc_packet_assemble(&packetdata);
+
+  if (idata) {
+    cipher = idata->send_key;
+    hmac = idata->hmac_send;
   }
 
   /* Encrypt the packet */
@@ -204,7 +304,7 @@ void silc_server_packet_broadcast(SilcServer server,
     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, 
+    silc_packet_encrypt(idata->send_key, idata->hmac_send
                        sock->outbuf, sock->outbuf->len);
 
     SILC_LOG_HEXDUMP(("Broadcasted packet, len %d", sock->outbuf->len),
@@ -238,7 +338,7 @@ void silc_server_packet_route(SilcServer server,
   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, 
+  silc_packet_encrypt(idata->send_key, idata->hmac_send
                      sock->outbuf, sock->outbuf->len);
 
   SILC_LOG_HEXDUMP(("Routed packet, len %d", sock->outbuf->len),
@@ -260,7 +360,7 @@ silc_server_packet_send_to_channel_real(SilcServer server,
                                        SilcCipher cipher,
                                        SilcHmac hmac,
                                        unsigned char *data,
-                                       unsigned int data_len,
+                                       uint32 data_len,
                                        int channel_message,
                                        int force_send)
 {
@@ -310,7 +410,7 @@ void silc_server_packet_send_to_channel(SilcServer server,
                                        SilcPacketType type,
                                        unsigned char route,
                                        unsigned char *data,
-                                       unsigned int data_len,
+                                       uint32 data_len,
                                        int force_send)
 {
   SilcSocketConnection sock = NULL;
@@ -319,7 +419,7 @@ void silc_server_packet_send_to_channel(SilcServer server,
   SilcServerEntry *routed = NULL;
   SilcChannelClientEntry chl;
   SilcIDListData idata;
-  unsigned int routed_count = 0;
+  uint32 routed_count = 0;
 
   /* This doesn't send channel message packets */
   if (type == SILC_PACKET_CHANNEL_MESSAGE)
@@ -336,7 +436,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_CHANNEL_LEN;
   packetdata.dst_id_type = SILC_ID_CHANNEL;
-  packetdata.rng = server->rng;
   packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
     packetdata.src_id_len + packetdata.dst_id_len;
   packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
@@ -356,7 +455,8 @@ void silc_server_packet_send_to_channel(SilcServer server,
       SILC_LOG_DEBUG(("Sending channel message to router for routing"));
       
       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                             idata->send_key, idata->hmac, 
+                                             idata->send_key, 
+                                             idata->hmac_send, 
                                              data, data_len, FALSE, 
                                              force_send);
     }
@@ -390,7 +490,8 @@ void silc_server_packet_send_to_channel(SilcServer server,
 
       /* Send the packet */
       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                             idata->send_key, idata->hmac, 
+                                             idata->send_key, 
+                                             idata->hmac_send, 
                                              data, data_len, FALSE, 
                                              force_send);
 
@@ -419,7 +520,8 @@ void silc_server_packet_send_to_channel(SilcServer server,
 
       /* Send the packet */
       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                             idata->send_key, idata->hmac, 
+                                             idata->send_key, 
+                                             idata->hmac_send, 
                                              data, data_len, FALSE, 
                                              force_send);
     }
@@ -431,6 +533,50 @@ void silc_server_packet_send_to_channel(SilcServer server,
   silc_free(packetdata.dst_id);
 }
 
+/* This checks whether the relayed packet came from router. If it did
+   then we'll need to encrypt it with the channel key. This is called
+   from the silc_server_packet_relay_to_channel. */
+
+static void
+silc_server_packet_relay_to_channel_encrypt(SilcServer server,
+                                           SilcSocketConnection sock,
+                                           SilcChannelEntry channel,
+                                           unsigned char *data,
+                                           unsigned int data_len)
+{
+  /* If we are router and the packet came from router and private key
+     has not been set for the channel then we must encrypt the packet
+     as it was decrypted with the session key shared between us and the
+     router which sent it. This is so, because cells does not share the
+     same channel key. */
+  if (server->server_type == SILC_ROUTER &&
+      sock->type == SILC_SOCKET_TYPE_ROUTER &&
+      !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY) &&
+      channel->channel_key) {
+    SilcBuffer chp;
+    uint32 iv_len, i;
+    uint16 data_len, 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(data_len, data + 2);
+    chp = silc_channel_message_payload_encode(flags, data_len, 
+                                             data + 4,
+                                             iv_len, channel->iv,
+                                             channel->channel_key,
+                                             channel->hmac);
+    memcpy(data, chp->data, chp->len);
+    silc_buffer_free(chp);
+  }
+}
+
 /* This routine is explicitly used to relay messages to some channel.
    Packets sent with this function we have received earlier and are
    totally encrypted. This just sends the packet to all clients on
@@ -445,17 +591,18 @@ void silc_server_packet_relay_to_channel(SilcServer server,
                                         SilcChannelEntry channel,
                                         void *sender, 
                                         SilcIdType sender_type,
+                                        void *sender_entry,
                                         unsigned char *data,
-                                        unsigned int data_len,
+                                        uint32 data_len,
                                         int force_send)
 {
-  int found = FALSE;
+  bool found = FALSE;
   SilcSocketConnection sock = NULL;
   SilcPacketContext packetdata;
   SilcClientEntry client = NULL;
   SilcServerEntry *routed = NULL;
   SilcChannelClientEntry chl;
-  unsigned int routed_count = 0;
+  uint32 routed_count = 0;
   SilcIDListData idata;
 
   SILC_LOG_DEBUG(("Relaying packet to channel"));
@@ -469,11 +616,18 @@ void silc_server_packet_relay_to_channel(SilcServer server,
   packetdata.dst_id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
   packetdata.dst_id_len = SILC_ID_CHANNEL_LEN;
   packetdata.dst_id_type = SILC_ID_CHANNEL;
-  packetdata.rng = server->rng;
   packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
                                          packetdata.src_id_len +
                                          packetdata.dst_id_len));
 
+  /* This encrypts the packet, if needed. It will be encrypted if
+     it came from the router thus it needs to be encrypted with the
+     channel key. If the channel key does not exist, then we know we
+     don't have a single local user on the channel. */
+  silc_server_packet_relay_to_channel_encrypt(server, sender_sock,
+                                             channel, data,
+                                             data_len);
+
   /* If there are global users in the channel we will send the message
      first to our router for further routing. */
   if (server->server_type == SILC_SERVER && !server->standalone &&
@@ -492,7 +646,8 @@ void silc_server_packet_relay_to_channel(SilcServer server,
       SILC_LOG_DEBUG(("Sending channel message to router for routing"));
 
       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                             idata->send_key, idata->hmac, 
+                                             idata->send_key, 
+                                             idata->hmac_send, 
                                              data, data_len, TRUE, 
                                              force_send);
     }
@@ -506,7 +661,8 @@ void silc_server_packet_relay_to_channel(SilcServer server,
     if (client) {
 
       /* If sender is one on the channel do not send it the packet. */
-      if (!found && !SILC_ID_CLIENT_COMPARE(client->id, sender)) {
+      if (!found && sender_type == SILC_ID_CLIENT &&
+         !SILC_ID_CLIENT_COMPARE(client->id, sender)) {
        found = TRUE;
        continue;
       }
@@ -534,6 +690,13 @@ void silc_server_packet_relay_to_channel(SilcServer server,
        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
+          socket. */
+       if (sender_entry && 
+           ((SilcClientEntry)sender_entry)->router == client->router)
+         continue;
        if (sender_sock && sock == sender_sock)
          continue;
 
@@ -541,12 +704,6 @@ void silc_server_packet_relay_to_channel(SilcServer server,
                        silc_id_render(client->id, SILC_ID_CLIENT),
                        sock->hostname, sock->ip));
 
-       /* Send the packet */
-       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                               idata->send_key, idata->hmac, 
-                                               data, data_len, TRUE, 
-                                               force_send);
-       
        /* We want to make sure that the packet is routed to same router
           only once. Mark this route as sent route. */
        k = routed_count;
@@ -554,6 +711,61 @@ void silc_server_packet_relay_to_channel(SilcServer server,
        routed[k] = client->router;
        routed_count++;
        
+       /* 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) {
+
+         /* 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));
+           memcpy(tmp, data, data_len);
+
+           /* Decrypt the channel message (we don't check the MAC) */
+           /* XXX this could be optimized and removed all together by
+              taking a copy of the original data before encrypting it
+              and thus would not required decrypting. */
+           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;
+           }
+
+           /* Now re-encrypt and send it to the router */
+           silc_server_packet_send_srcdest(server, sock, 
+                                           SILC_PACKET_CHANNEL_MESSAGE, 0,
+                                           sender, 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_PACKET_CHANNEL_MESSAGE, 0,
+                                           sender, sender_type,
+                                           channel->id, SILC_ID_CHANNEL,
+                                           data, data_len, force_send);
+         }
+         continue;
+       }
+
+       /* 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;
       }
 
@@ -573,7 +785,8 @@ void silc_server_packet_relay_to_channel(SilcServer server,
 
       /* Send the packet */
       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                             idata->send_key, idata->hmac, 
+                                             idata->send_key, 
+                                             idata->hmac_send, 
                                              data, data_len, TRUE, 
                                              force_send);
     }
@@ -595,7 +808,7 @@ void silc_server_packet_send_local_channel(SilcServer server,
                                           SilcPacketType type,
                                           SilcPacketFlags flags,
                                           unsigned char *data,
-                                          unsigned int data_len,
+                                          uint32 data_len,
                                           int force_send)
 {
   SilcChannelClientEntry chl;
@@ -631,7 +844,7 @@ void silc_server_send_private_message(SilcServer server,
 {
   SilcBuffer buffer = packet->buffer;
 
-  /* Send and re-encrypt if private messge key does not exist */
+  /* Re-encrypt and send if private messge key does not exist */
   if ((packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY) == FALSE) {
 
     silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len 
@@ -646,11 +859,17 @@ void silc_server_send_private_message(SilcServer server,
     silc_server_packet_send_real(server, dst_sock, FALSE);
 
   } else {
-    /* Key exist so just send it */
+    /* 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_HEADER_LEN + packet->src_id_len + 
+                       packet->dst_id_len + packet->padlen);
+
     silc_server_packet_send_real(server, dst_sock, FALSE);
   }
 }
@@ -661,7 +880,7 @@ void silc_server_send_motd(SilcServer server,
                           SilcSocketConnection sock)
 {
   char *motd;
-  int motd_len;
+  uint32 motd_len;
 
   if (server->config && server->config->motd && 
       server->config->motd->motd_file) {
@@ -704,7 +923,7 @@ void silc_server_send_notify(SilcServer server,
                             SilcSocketConnection sock,
                             int broadcast,
                             SilcNotifyType type,
-                            unsigned int argc, ...)
+                            uint32 argc, ...)
 {
   va_list ap;
   SilcBuffer packet;
@@ -712,7 +931,27 @@ void silc_server_send_notify(SilcServer server,
   va_start(ap, argc);
 
   packet = silc_notify_payload_encode(type, argc, ap);
-  silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY, 0, 
+  silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY, 
+                         broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
+                         packet->data, packet->len, FALSE);
+  silc_buffer_free(packet);
+}
+
+/* Sends notify message and gets the arguments from the `args' Argument
+   Payloads. */
+
+void silc_server_send_notify_args(SilcServer server,
+                                 SilcSocketConnection sock,
+                                 int broadcast,
+                                 SilcNotifyType type,
+                                 uint32 argc,
+                                 SilcBuffer args)
+{
+  SilcBuffer packet;
+
+  packet = silc_notify_payload_encode_args(type, argc, args);
+  silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY, 
+                         broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
                          packet->data, packet->len, FALSE);
   silc_buffer_free(packet);
 }
@@ -725,7 +964,7 @@ void silc_server_send_notify_channel_change(SilcServer server,
                                            int broadcast,
                                            SilcChannelID *old_id,
                                            SilcChannelID *new_id,
-                                           unsigned int id_len)
+                                           uint32 id_len)
 {
   SilcBuffer idp1, idp2;
 
@@ -747,7 +986,7 @@ void silc_server_send_notify_nick_change(SilcServer server,
                                         int broadcast,
                                         SilcClientID *old_id,
                                         SilcClientID *new_id,
-                                        unsigned int id_len)
+                                        uint32 id_len)
 {
   SilcBuffer idp1, idp2;
 
@@ -769,7 +1008,7 @@ void silc_server_send_notify_join(SilcServer server,
                                  int broadcast,
                                  SilcChannelEntry channel,
                                  SilcClientID *client_id,
-                                 unsigned int client_id_len)
+                                 uint32 client_id_len)
 {
   SilcBuffer idp1, idp2;
 
@@ -790,7 +1029,7 @@ void silc_server_send_notify_leave(SilcServer server,
                                   int broadcast,
                                   SilcChannelEntry channel,
                                   SilcClientID *client_id,
-                                  unsigned int client_id_len)
+                                  uint32 client_id_len)
 {
   SilcBuffer idp;
 
@@ -809,20 +1048,23 @@ void silc_server_send_notify_cmode(SilcServer server,
                                   SilcSocketConnection sock,
                                   int broadcast,
                                   SilcChannelEntry channel,
-                                  unsigned int mode_mask,
-                                  SilcClientID *client_id,
-                                  unsigned int client_id_len)
+                                  uint32 mode_mask,
+                                  void *id, SilcIdType id_type,
+                                  uint32 id_len,
+                                  char *cipher, char *hmac)
 {
   SilcBuffer idp;
   unsigned char mode[4];
 
-  idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+  idp = silc_id_payload_encode((void *)id, id_type);
   SILC_PUT32_MSB(mode_mask, mode);
 
   silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id,
                               SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_CMODE_CHANGE,
-                              2, idp->data, idp->len,
-                              mode, 4);
+                              4, idp->data, idp->len,
+                              mode, 4,
+                              cipher, cipher ? strlen(cipher) : 0,
+                              hmac, hmac ? strlen(hmac) : 0);
   silc_buffer_free(idp);
 }
 
@@ -834,16 +1076,16 @@ void silc_server_send_notify_cumode(SilcServer server,
                                    SilcSocketConnection sock,
                                    int broadcast,
                                    SilcChannelEntry channel,
-                                   unsigned int mode_mask,
-                                   SilcClientID *client_id,
-                                   unsigned int client_id_len,
+                                   uint32 mode_mask,
+                                   void *id, SilcIdType id_type,
+                                   uint32 id_len,
                                    SilcClientID *target,
-                                   unsigned int target_len)
+                                   uint32 target_len)
 {
   SilcBuffer idp1, idp2;
   unsigned char mode[4];
 
-  idp1 = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+  idp1 = silc_id_payload_encode((void *)id, id_type);
   idp2 = silc_id_payload_encode((void *)target, SILC_ID_CLIENT);
   SILC_PUT32_MSB(mode_mask, mode);
 
@@ -866,7 +1108,7 @@ void silc_server_send_notify_signoff(SilcServer server,
                                     SilcSocketConnection sock,
                                     int broadcast,
                                     SilcClientID *client_id,
-                                    unsigned int client_id_len,
+                                    uint32 client_id_len,
                                     char *message)
 {
   SilcBuffer idp;
@@ -879,24 +1121,6 @@ void silc_server_send_notify_signoff(SilcServer server,
   silc_buffer_free(idp);
 }
 
-/* Sends SERVER_SIGNOFF notify type. This tells that `server_id' server
-   has quit SILC network. */
-
-void silc_server_send_notify_server_signoff(SilcServer server,
-                                           SilcSocketConnection sock,
-                                           int broadcast,
-                                           SilcServerID *server_id,
-                                           unsigned int server_id_len)
-{
-  SilcBuffer idp;
-
-  idp = silc_id_payload_encode((void *)server_id, SILC_ID_SERVER);
-  silc_server_send_notify(server, sock, broadcast,
-                         SILC_NOTIFY_TYPE_SERVER_SIGNOFF,
-                         1, idp->data, idp->len);
-  silc_buffer_free(idp);
-}
-
 /* Sends TOPIC_SET notify type. This tells that `client_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
@@ -907,7 +1131,7 @@ void silc_server_send_notify_topic_set(SilcServer server,
                                       int broadcast,
                                       SilcChannelEntry channel,
                                       SilcClientID *client_id,
-                                      unsigned int client_id_len,
+                                      uint32 client_id_len,
                                       char *topic)
 {
   SilcBuffer idp;
@@ -921,6 +1145,123 @@ void silc_server_send_notify_topic_set(SilcServer server,
   silc_buffer_free(idp);
 }
 
+/* Send KICKED notify type. This tells that the `client_id' on `channel'
+   was kicked off the channel.  The `comment' may indicate the reason
+   for the kicking. This function is used only between server and router
+   traffic. */
+
+void silc_server_send_notify_kicked(SilcServer server,
+                                   SilcSocketConnection sock,
+                                   int broadcast,
+                                   SilcChannelEntry channel,
+                                   SilcClientID *client_id,
+                                   uint32 client_id_len,
+                                   char *comment)
+{
+  SilcBuffer idp;
+
+  idp = silc_id_payload_encode((void *)client_id, 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);
+}
+
+/* Send KILLED notify type. This tells that the `client_id' client was
+   killed from the network.  The `comment' may indicate the reason
+   for the killing. */
+
+void silc_server_send_notify_killed(SilcServer server,
+                                   SilcSocketConnection sock,
+                                   int broadcast,
+                                   SilcClientID *client_id,
+                                   uint32 client_id_len,
+                                   char *comment)
+{
+  SilcBuffer idp;
+
+  idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+  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);
+}
+
+/* Sends UMODE_CHANGE notify type. This tells that `client_id' client's
+   user mode in the SILC Network was changed. This function is used to
+   send the packet between routers as broadcast packet. */
+
+void silc_server_send_notify_umode(SilcServer server,
+                                  SilcSocketConnection sock,
+                                  int broadcast,
+                                  SilcClientID *client_id,
+                                  uint32 client_id_len,
+                                  uint32 mode_mask)
+{
+  SilcBuffer idp;
+  unsigned char mode[4];
+
+  idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+  SILC_PUT32_MSB(mode_mask, mode);
+
+  silc_server_send_notify(server, sock, broadcast,
+                         SILC_NOTIFY_TYPE_UMODE_CHANGE, 2,
+                         idp->data, idp->len, 
+                         mode, 4);
+  silc_buffer_free(idp);
+}
+
+/* Sends BAN notify type. This tells that ban has been either `add'ed
+   or `del'eted on the `channel. This function is used to send the packet
+   between routers as broadcast packet. */
+
+void silc_server_send_notify_ban(SilcServer server,
+                                SilcSocketConnection sock,
+                                int broadcast,
+                                SilcChannelEntry channel,
+                                char *add, char *del)
+{
+  SilcBuffer idp;
+
+  idp = silc_id_payload_encode((void *)channel->id, SILC_ID_CHANNEL);
+  silc_server_send_notify(server, sock, broadcast,
+                         SILC_NOTIFY_TYPE_BAN, 3,
+                         idp->data, idp->len,
+                         add, add ? strlen(add) : 0,
+                         del, del ? strlen(del) : 0);
+  silc_buffer_free(idp);
+}
+
+/* Sends INVITE notify type. This tells that invite has been either `add'ed
+   or `del'eted on the `channel.  The sender of the invite is the `client_id'.
+   This function is used to send the packet between routers as broadcast
+   packet. */
+
+void silc_server_send_notify_invite(SilcServer server,
+                                   SilcSocketConnection sock,
+                                   int broadcast,
+                                   SilcChannelEntry channel,
+                                   SilcClientID *client_id,
+                                   uint32 client_id_len,
+                                   char *add, char *del)
+{
+  SilcBuffer idp, idp2;
+
+  idp = silc_id_payload_encode((void *)channel->id, SILC_ID_CHANNEL);
+  idp2 = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+  silc_server_send_notify(server, sock, broadcast,
+                         SILC_NOTIFY_TYPE_INVITE, 5,
+                         idp->data, idp->len,
+                         channel->channel_name, strlen(channel->channel_name),
+                         idp2->data, idp2->len,
+                         add, add ? strlen(add) : 0,
+                         del, del ? strlen(del) : 0);
+  silc_buffer_free(idp);
+  silc_buffer_free(idp2);
+}
+
 /* Sends notify message destined to specific entity. */
 
 void silc_server_send_notify_dest(SilcServer server,
@@ -929,7 +1270,7 @@ void silc_server_send_notify_dest(SilcServer server,
                                  void *dest_id,
                                  SilcIdType dest_id_type,
                                  SilcNotifyType type,
-                                 unsigned int argc, ...)
+                                 uint32 argc, ...)
 {
   va_list ap;
   SilcBuffer packet;
@@ -944,7 +1285,7 @@ void silc_server_send_notify_dest(SilcServer server,
 }
 
 /* Sends notify message to a channel. The notify message sent is 
-   distributed to all clients on the channel. If `router_notify' is TRUE
+   distributed to all clients on the channel. If `route_notify' is TRUE
    then the notify may be routed to primary route or to some other routers.
    If FALSE it is assured that the notify is sent only locally. If `sender'
    is provided then the packet is not sent to that connection since it
@@ -955,7 +1296,7 @@ void silc_server_send_notify_to_channel(SilcServer server,
                                        SilcChannelEntry channel,
                                        unsigned char route_notify,
                                        SilcNotifyType type,
-                                       unsigned int argc, ...)
+                                       uint32 argc, ...)
 {
   va_list ap;
   SilcBuffer packet;
@@ -969,31 +1310,33 @@ void silc_server_send_notify_to_channel(SilcServer server,
   silc_buffer_free(packet);
 }
 
-/* Send notify message to all clients the client has joined. It is quaranteed
+/* Send notify message to all channels the client has joined. It is quaranteed
    that the message is sent only once to a client (ie. if a client is joined
    on two same channel it will receive only one notify message). Also, this
    sends only to local clients (locally connected if we are server, and to
-   local servers if we are router). */
+   local servers if we are router). If `sender' is provided the packet is
+   not sent to that client at all. */
 
 void silc_server_send_notify_on_channels(SilcServer server,
+                                        SilcClientEntry sender,
                                         SilcClientEntry client,
                                         SilcNotifyType type,
-                                        unsigned int argc, ...)
+                                        uint32 argc, ...)
 {
   int k;
   SilcSocketConnection sock = NULL;
   SilcPacketContext packetdata;
   SilcClientEntry c;
   SilcClientEntry *sent_clients = NULL;
-  unsigned int sent_clients_count = 0;
+  uint32 sent_clients_count = 0;
   SilcServerEntry *routed = NULL;
-  unsigned int routed_count = 0;
+  uint32 routed_count = 0;
   SilcChannelEntry channel;
   SilcChannelClientEntry chl, chl2;
   SilcIDListData idata;
   SilcBuffer packet;
   unsigned char *data;
-  unsigned int data_len;
+  uint32 data_len;
   int force_send = FALSE;
   va_list ap;
 
@@ -1013,7 +1356,6 @@ void silc_server_send_notify_on_channels(SilcServer server,
   packetdata.src_id = silc_id_id2str(server->id, SILC_ID_SERVER);
   packetdata.src_id_len = SILC_ID_SERVER_LEN;
   packetdata.src_id_type = SILC_ID_SERVER;
-  packetdata.rng = server->rng;
 
   silc_list_start(client->channels);
   while ((chl = silc_list_get(client->channels)) != SILC_LIST_END) {
@@ -1024,6 +1366,9 @@ void silc_server_send_notify_on_channels(SilcServer server,
     while ((chl2 = silc_list_get(channel->user_list)) != SILC_LIST_END) {
       c = chl2->client;
       
+      if (sender && c == sender)
+       continue;
+
       /* Check if we have sent the packet to this client already */
       for (k = 0; k < sent_clients_count; k++)
        if (sent_clients[k] == c)
@@ -1055,7 +1400,8 @@ void silc_server_send_notify_on_channels(SilcServer server,
 
        /* Send the packet */
        silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                               idata->send_key, idata->hmac, 
+                                               idata->send_key, 
+                                               idata->hmac_send, 
                                                data, data_len, FALSE, 
                                                force_send);
        
@@ -1090,7 +1436,8 @@ void silc_server_send_notify_on_channels(SilcServer server,
 
        /* Send the packet */
        silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                               idata->send_key, idata->hmac, 
+                                               idata->send_key, 
+                                               idata->hmac_send, 
                                                data, data_len, FALSE, 
                                                force_send);
 
@@ -1122,7 +1469,7 @@ void silc_server_send_new_id(SilcServer server,
                             SilcSocketConnection sock,
                             int broadcast,
                             void *id, SilcIdType id_type, 
-                            unsigned int id_len)
+                            uint32 id_len)
 {
   SilcBuffer idp;
 
@@ -1145,11 +1492,12 @@ void silc_server_send_new_channel(SilcServer server,
                                  int broadcast,
                                  char *channel_name,
                                  void *channel_id, 
-                                 unsigned int channel_id_len)
+                                 uint32 channel_id_len,
+                                 uint32 mode)
 {
   SilcBuffer packet;
   unsigned char *cid;
-  unsigned int name_len = strlen(channel_name);
+  uint32 name_len = strlen(channel_name);
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -1157,15 +1505,9 @@ void silc_server_send_new_channel(SilcServer server,
   if (!cid)
     return;
 
-  packet = silc_buffer_alloc(2 + 2 + name_len + channel_id_len);
-  silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
-  silc_buffer_format(packet,
-                    SILC_STR_UI_SHORT(name_len),
-                    SILC_STR_UI_XNSTRING(channel_name, name_len),
-                    SILC_STR_UI_SHORT(channel_id_len),
-                    SILC_STR_UI_XNSTRING(cid, channel_id_len),
-                    SILC_STR_END);
-
+  /* Encode the channel payload */
+  packet = silc_channel_payload_encode(channel_name, name_len,
+                                      cid, channel_id_len, mode);
 
   silc_server_packet_send(server, sock, SILC_PACKET_NEW_CHANNEL, 
                          broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, 
@@ -1191,7 +1533,7 @@ void silc_server_send_channel_key(SilcServer server,
 {
   SilcBuffer packet;
   unsigned char *chid;
-  unsigned int tmp_len;
+  uint32 tmp_len;
  
   SILC_LOG_DEBUG(("Start"));
  
@@ -1218,7 +1560,7 @@ void silc_server_send_channel_key(SilcServer server,
 void silc_server_send_command(SilcServer server, 
                              SilcSocketConnection sock,
                              SilcCommand command, 
-                             unsigned int argc, ...)
+                             uint32 argc, ...)
 {
   SilcBuffer packet;
   va_list ap;
@@ -1239,3 +1581,50 @@ void silc_server_send_heartbeat(SilcServer server,
   silc_server_packet_send(server, sock, SILC_PACKET_HEARTBEAT, 0,
                          NULL, 0, FALSE);
 }
+
+/* Generic function to relay packet we've received. This is used to relay
+   packets to a client but generally can be used to other purposes as well. */
+
+void silc_server_relay_packet(SilcServer server,
+                             SilcSocketConnection dst_sock,
+                             SilcCipher cipher,
+                             SilcHmac hmac,
+                             SilcPacketContext *packet,
+                             int force_send)
+{
+  silc_buffer_push(packet->buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len 
+                  + packet->dst_id_len + packet->padlen);
+
+  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);
+  
+  /* Send the packet */
+  silc_server_packet_send_real(server, dst_sock, force_send);
+
+  silc_buffer_pull(packet->buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len 
+                  + packet->dst_id_len + packet->padlen);
+}
+
+/* Routine used to send the connection authentication packet. */
+
+void silc_server_send_connection_auth_request(SilcServer server,
+                                             SilcSocketConnection sock,
+                                             uint16 conn_type,
+                                             SilcAuthMethod auth_meth)
+{
+  SilcBuffer packet;
+
+  packet = silc_buffer_alloc(4);
+  silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+  silc_buffer_format(packet,
+                    SILC_STR_UI_SHORT(conn_type),
+                    SILC_STR_UI_SHORT(auth_meth),
+                    SILC_STR_END);
+
+  silc_server_packet_send(server, sock, SILC_PACKET_CONNECTION_AUTH_REQUEST,
+                         0, packet->data, packet->len, FALSE);
+  silc_buffer_free(packet);
+}