Common router id.
diff --git a/zebra/router-id.c b/zebra/router-id.c
new file mode 100644
index 0000000..3052e56
--- /dev/null
+++ b/zebra/router-id.c
@@ -0,0 +1,265 @@
+/*
+ * Router ID for zebra daemon.
+ *
+ * Copyright (C) 2004 James R. Leu 
+ *
+ * This file is part of Quagga routing suite.
+ *
+ * Quagga is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * Quagga is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "vty.h"
+#include "sockunion.h"
+#include "prefix.h"
+#include "stream.h"
+#include "command.h"
+#include "memory.h"
+#include "ioctl.h"
+#include "connected.h"
+#include "network.h"
+#include "log.h"
+#include "table.h"
+#include "rib.h"
+
+#include "zebra/zserv.h"
+
+static struct list rid_all_sorted_list;
+static struct list rid_lo_sorted_list;
+static struct prefix rid_user_assigned;
+
+/* master zebra server structure */
+extern struct zebra_t zebrad;
+
+static struct connected *
+router_id_find_node (struct list *l, struct connected *ifc)
+{
+  struct listnode *node;
+  struct connected *c;
+
+  for (node = l->head; node; node = node->next)
+    {
+      c = (struct connected *) getdata (node);
+      if (prefix_same (ifc->address, c->address))
+	return c;
+    }
+  return NULL;
+}
+
+static int
+router_id_bad_address (struct connected *ifc)
+{
+  struct prefix n;
+
+  if (ifc->address->family != AF_INET)
+    return 1;
+
+  n.u.prefix4.s_addr = htonl (INADDR_LOOPBACK);
+  n.prefixlen = 8;
+  n.family = AF_INET;
+
+  if (prefix_match (&n, ifc->address))
+    return 1;
+
+  return 0;
+}
+
+void
+router_id_get (struct prefix *p)
+{
+  struct listnode *node;
+  struct connected *c;
+
+  p->u.prefix4.s_addr = 0;
+  p->family = AF_INET;
+  p->prefixlen = 32;
+
+  if (rid_user_assigned.u.prefix4.s_addr)
+    p->u.prefix4.s_addr = rid_user_assigned.u.prefix4.s_addr;
+  else if (!list_isempty (&rid_lo_sorted_list))
+    {
+      node = listtail (&rid_lo_sorted_list);
+      c = getdata (node);
+      p->u.prefix4.s_addr = c->address->u.prefix4.s_addr;
+    }
+  else if (!list_isempty (&rid_all_sorted_list))
+    {
+      node = listtail (&rid_all_sorted_list);
+      c = getdata (node);
+      p->u.prefix4.s_addr = c->address->u.prefix4.s_addr;
+    }
+}
+
+static void
+router_id_set (struct prefix *p)
+{
+  struct prefix p2;
+  struct listnode *node;
+  struct zserv *client;
+
+  rid_user_assigned.u.prefix4.s_addr = p->u.prefix4.s_addr;
+
+  router_id_get (&p2);
+  for (node = listhead (zebrad.client_list); node; nextnode (node))
+    if ((client = getdata (node)) != NULL)
+      zsend_router_id_update (client, &p2);
+}
+
+void
+router_id_add_address (struct connected *ifc)
+{
+  struct list *l = NULL;
+  struct listnode *node;
+  struct prefix before;
+  struct prefix after;
+  struct zserv *client;
+
+  if (router_id_bad_address (ifc))
+    return;
+
+  router_id_get (&before);
+
+  if (!strncmp (ifc->ifp->name, "lo", 2)
+      || !strncmp (ifc->ifp->name, "dummy", 5))
+    l = &rid_lo_sorted_list;
+  else
+    l = &rid_all_sorted_list;
+  
+  if (!router_id_find_node (l, ifc))
+    listnode_add (l, ifc);
+
+  router_id_get (&after);
+
+  if (prefix_same (&before, &after))
+    return;
+
+  for (node = listhead (zebrad.client_list); node; nextnode (node))
+    if ((client = getdata (node)) != NULL)
+      zsend_router_id_update (client, &after);
+}
+
+void
+router_id_del_address (struct connected *ifc)
+{
+  struct connected *c;
+  struct list *l;
+  struct prefix after;
+  struct prefix before;
+  struct listnode *node;
+  struct zserv *client;
+
+  if (router_id_bad_address (ifc))
+    return;
+
+  router_id_get (&before);
+
+  if (!strncmp (ifc->ifp->name, "lo", 2)
+      || !strncmp (ifc->ifp->name, "dummy", 5))
+    l = &rid_lo_sorted_list;
+  else
+    l = &rid_all_sorted_list;
+
+  if ((c = router_id_find_node (l, ifc)))
+    listnode_delete (l, c);
+
+  router_id_get (&after);
+
+  if (prefix_same (&before, &after))
+    return;
+
+  for (node = listhead (zebrad.client_list); node; nextnode (node))
+    if ((client = getdata (node)) != NULL)
+      zsend_router_id_update (client, &after);
+}
+
+void
+router_id_write (struct vty *vty)
+{
+  if (rid_user_assigned.u.prefix4.s_addr)
+    vty_out (vty, "router-id %s%s", inet_ntoa (rid_user_assigned.u.prefix4),
+	     VTY_NEWLINE);
+}
+
+DEFUN (router_id,
+       router_id_cmd,
+       "router-id A.B.C.D",
+       "Manually set the router-id\n"
+       "IP address to use for router-id\n")
+{
+  struct prefix rid;
+
+  rid.u.prefix4.s_addr = inet_addr (argv[0]);
+  if (!rid.u.prefix4.s_addr)
+    return CMD_WARNING;
+
+  rid.prefixlen = 32;
+  rid.family = AF_INET;
+
+  router_id_set (&rid);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_router_id,
+       no_router_id_cmd,
+       "no router-id",
+       NO_STR
+       "Remove the manually configured router-id\n")
+{
+  struct prefix rid;
+
+  rid.u.prefix4.s_addr = 0;
+  rid.prefixlen = 0;
+  rid.family = AF_INET;
+
+  router_id_set (&rid);
+
+  return CMD_SUCCESS;
+}
+
+int
+router_id_cmp (void *a, void *b)
+{
+  unsigned int A, B;
+
+  A = ((struct connected *) a)->address->u.prefix4.s_addr;
+  B = ((struct connected *) b)->address->u.prefix4.s_addr;
+
+  if (A > B)
+    return 1;
+  else if (A < B)
+    return -1;
+  return 0;
+}
+
+void
+router_id_init (void)
+{
+  install_element (CONFIG_NODE, &router_id_cmd);
+  install_element (CONFIG_NODE, &no_router_id_cmd);
+
+  memset (&rid_all_sorted_list, 0, sizeof (rid_all_sorted_list));
+  memset (&rid_lo_sorted_list, 0, sizeof (rid_lo_sorted_list));
+  memset (&rid_user_assigned, 0, sizeof (rid_user_assigned));
+
+  rid_all_sorted_list.cmp = router_id_cmp;
+  rid_lo_sorted_list.cmp = router_id_cmp;
+
+  rid_user_assigned.family = AF_INET;
+  rid_user_assigned.prefixlen = 32;
+}