diff -urN quagga-0.99.8-orig/bgpd/bgp_network.c quagga-0.99.8/bgpd/bgp_network.c
--- quagga-0.99.8-orig/bgpd/bgp_network.c	Sun Aug 12 15:35:09 2007
+++ quagga-0.99.8/bgpd/bgp_network.c	Sun Aug 12 16:02:26 2007
@@ -22,6 +22,7 @@
 
 #include "thread.h"
 #include "sockunion.h"
+#include "sockopt.h"
 #include "memory.h"
 #include "log.h"
 #include "if.h"
@@ -38,6 +39,34 @@
 extern struct zebra_privs_t bgpd_privs;
 
 
+#if defined(HAVE_TCP_MD5SIG)
+/*
+ * Set MD5 key for the socket, for the given IPv4 peer address.
+ * If the password is NULL or zero-length, the option will be disabled.
+ */
+int
+bgp_md5_set (int sock, struct sockaddr_in *sin, const char *password)
+{
+  int ret, en;
+
+  if ( bgpd_privs.change (ZPRIVS_RAISE) )
+    zlog_err ("bgp_md5_set: could not raise privs");
+
+  ret = sockopt_tcp_signature (sock, sin, password);
+  en  = errno;
+
+  if (bgpd_privs.change (ZPRIVS_LOWER) )
+    zlog_err ("bgp_md5_set: could not lower privs");
+
+  if (ret < 0)
+    zlog (NULL, LOG_WARNING, "can't set TCP_MD5SIG option on socket %d: %s",
+	  sock, safe_strerror (en));
+
+  return ret;
+}
+
+#endif /* HAVE_TCP_MD5SIG */
+
 /* Accept bgp connection. */
 static int
 bgp_accept (struct thread *thread)
@@ -238,6 +267,12 @@
   sockopt_reuseaddr (peer->fd);
   sockopt_reuseport (peer->fd);
 
+#ifdef HAVE_TCP_MD5SIG
+  if (CHECK_FLAG (peer->flags, PEER_FLAG_PASSWORD))
+    if (sockunion_family (&peer->su) == AF_INET)
+      bgp_md5_set (peer->fd, &peer->su.sin, peer->password);
+#endif /* HAVE_TCP_MD5SIG */
+
   /* Bind socket. */
   bgp_bind (peer);
 
@@ -346,6 +381,10 @@
 	  continue;
 	}
 
+#ifdef HAVE_TCP_MD5SIG
+      bm->sock = sock;
+#endif /* HAVE_TCP_MD5SIG */
+
       thread_add_read (master, bgp_accept, bgp, sock);
     }
   while ((ainfo = ainfo->ai_next) != NULL);
@@ -406,6 +445,9 @@
       close (sock);
       return ret;
     }
+#ifdef HAVE_TCP_MD5SIG
+  bm->sock = sock;
+#endif /* HAVE_TCP_MD5SIG */
 
   thread_add_read (bm->master, bgp_accept, bgp, sock);
 
diff -urN quagga-0.99.8-orig/bgpd/bgp_network.h quagga-0.99.8/bgpd/bgp_network.h
--- quagga-0.99.8-orig/bgpd/bgp_network.h	Sun Aug 12 15:35:08 2007
+++ quagga-0.99.8/bgpd/bgp_network.h	Sun Aug 12 16:02:49 2007
@@ -21,6 +21,10 @@
 #ifndef _QUAGGA_BGP_NETWORK_H
 #define _QUAGGA_BGP_NETWORK_H
 
+#if defined(HAVE_TCP_MD5SIG) 
+extern int bgp_md5_set (int, struct sockaddr_in *, const char *);
+#endif /* HAVE_TCP_MD5SIG */
+
 extern int bgp_socket (struct bgp *, unsigned short);
 extern int bgp_connect (struct peer *);
 extern void bgp_getsockname (struct peer *);
diff -urN quagga-0.99.8-orig/bgpd/bgp_vty.c quagga-0.99.8/bgpd/bgp_vty.c
--- quagga-0.99.8-orig/bgpd/bgp_vty.c	Sun Aug 12 15:35:09 2007
+++ quagga-0.99.8/bgpd/bgp_vty.c	Sun Aug 12 15:35:15 2007
@@ -1479,6 +1479,46 @@
        "AS number used as local AS\n"
        "Do not prepend local-as to updates from ebgp peers\n")
 
+#ifdef HAVE_TCP_MD5SIG
+DEFUN (neighbor_password,
+       neighbor_password_cmd,
+       NEIGHBOR_CMD2 "password LINE",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Set a password\n"
+       "The password\n")
+{
+  struct peer *peer;
+  int ret;
+
+  peer = peer_and_group_lookup_vty (vty, argv[0]);
+  if (! peer)
+    return CMD_WARNING;
+
+  ret = peer_password_set (peer, argv[1]);
+  return bgp_vty_return (vty, ret);
+}
+
+DEFUN (no_neighbor_password,
+       no_neighbor_password_cmd,
+       NO_NEIGHBOR_CMD2 "password",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Set a password\n")
+{
+  struct peer *peer;
+  int ret;
+
+  peer = peer_and_group_lookup_vty (vty, argv[0]);
+  if (! peer)
+    return CMD_WARNING;
+
+  ret = peer_password_unset (peer);
+  return bgp_vty_return (vty, ret);
+}
+#endif /* HAVE_TCP_MD5SIG */
+
 DEFUN (neighbor_activate,
        neighbor_activate_cmd,
        NEIGHBOR_CMD2 "activate",
@@ -8893,6 +8933,12 @@
   install_element (BGP_NODE, &no_neighbor_local_as_cmd);
   install_element (BGP_NODE, &no_neighbor_local_as_val_cmd);
   install_element (BGP_NODE, &no_neighbor_local_as_val2_cmd);
+
+#ifdef HAVE_TCP_MD5SIG
+  /* "neighbor password" commands. */
+  install_element (BGP_NODE, &neighbor_password_cmd);
+  install_element (BGP_NODE, &no_neighbor_password_cmd);
+#endif /* HAVE_TCP_MD5SIG */
 
   /* "neighbor activate" commands. */
   install_element (BGP_NODE, &neighbor_activate_cmd);
diff -urN quagga-0.99.8-orig/bgpd/bgpd.c quagga-0.99.8/bgpd/bgpd.c
--- quagga-0.99.8-orig/bgpd/bgpd.c	Sun Aug 12 15:35:09 2007
+++ quagga-0.99.8/bgpd/bgpd.c	Sun Aug 12 16:02:16 2007
@@ -788,6 +788,7 @@
   peer->status = Idle;
   peer->ostatus = Idle;
   peer->weight = 0;
+  peer->password = NULL;
   peer->bgp = bgp;
   peer = peer_lock (peer); /* initial reference */
 
@@ -1202,6 +1203,20 @@
   peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE;
   bgp_stop (peer);
   bgp_fsm_change_status (peer, Deleted);
+
+#ifdef HAVE_TCP_MD5SIG
+  /* Password configuration */
+  if (peer->password)
+    {
+      free (peer->password);
+      peer->password = NULL;
+
+      if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)
+          && sockunion_family (&peer->su) == AF_INET)
+       bgp_md5_set (bm->sock, &peer->su.sin, NULL);
+    }
+#endif /* HAVE_TCP_MD5SIG */
+ 
   bgp_timer_set (peer); /* stops all timers for Deleted */
   
   /* Delete from all peer list. */
@@ -1417,6 +1432,27 @@
   else
     peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
 
+#ifdef HAVE_TCP_MD5SIG
+  /* password apply */
+  if (CHECK_FLAG (conf->flags, PEER_FLAG_PASSWORD))
+    {
+      if (peer->password)
+	free (peer->password);
+      peer->password = strdup (conf->password);
+
+      if (sockunion_family (&peer->su) == AF_INET)
+	bgp_md5_set (bm->sock, &peer->su.sin, peer->password);
+    }
+  else if (peer->password)
+    {
+      free (peer->password);
+      peer->password = NULL;
+
+      if (sockunion_family (&peer->su) == AF_INET)
+        bgp_md5_set (bm->sock, &peer->su.sin, NULL);
+    }
+#endif /* HAVE_TCP_MD5SIG */
+
   /* maximum-prefix */
   peer->pmax[afi][safi] = conf->pmax[afi][safi];
   peer->pmax_threshold[afi][safi] = conf->pmax_threshold[afi][safi];
@@ -3379,6 +3415,125 @@
   return 0;
 }
 
+#ifdef HAVE_TCP_MD5SIG
+/* Set password for authenticating with the peer. */
+int
+peer_password_set (struct peer *peer, const char *password)
+{
+  struct peer_group *group;
+  struct listnode *nn, *nnode;
+  int len = password ? strlen(password) : 0;
+
+  if ((len < PEER_PASSWORD_MINLEN) || (len > PEER_PASSWORD_MAXLEN))
+    return BGP_ERR_INVALID_VALUE;
+
+  if (peer->password && strcmp (peer->password, password) == 0
+      && ! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+	return 0;
+
+  SET_FLAG (peer->flags, PEER_FLAG_PASSWORD);
+  if (peer->password)
+    free (peer->password);
+  peer->password = strdup (password);
+
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    {
+      if (peer->status == Established)
+          bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+      else
+        BGP_EVENT_ADD (peer, BGP_Stop);
+
+      if (sockunion_family (&peer->su) == AF_INET)
+	bgp_md5_set (bm->sock, &peer->su.sin, peer->password);
+      return 0;
+    }
+
+  group = peer->group;
+  /* #42# LIST_LOOP (group->peer, peer, nn) */
+  for (ALL_LIST_ELEMENTS (group->peer, nn, nnode, peer))
+    {
+      if (peer->password && strcmp (peer->password, password) == 0)
+	continue;
+
+      SET_FLAG (peer->flags, PEER_FLAG_PASSWORD);
+      if (peer->password)
+        free (peer->password);
+      peer->password = strdup (password);
+
+      if (peer->status == Established)
+        bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+      else
+        BGP_EVENT_ADD (peer, BGP_Stop);
+
+      if (sockunion_family (&peer->su) == AF_INET)
+	bgp_md5_set (bm->sock, &peer->su.sin, peer->password);
+    }
+
+  return 0;
+}
+
+int
+peer_password_unset (struct peer *peer)
+{
+  struct peer_group *group;
+  struct listnode *nn, *nnode;
+
+  if (! CHECK_FLAG (peer->flags, PEER_FLAG_PASSWORD)
+      && ! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    return 0;
+
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    {
+      if (peer_group_active (peer)
+	  && CHECK_FLAG (peer->group->conf->flags, PEER_FLAG_PASSWORD))
+	return BGP_ERR_PEER_GROUP_HAS_THE_FLAG;
+
+      if (peer->status == Established)
+        bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+      else
+        BGP_EVENT_ADD (peer, BGP_Stop);
+
+      if (sockunion_family (&peer->su) == AF_INET)
+	bgp_md5_set (bm->sock, &peer->su.sin, NULL);
+
+      UNSET_FLAG (peer->flags, PEER_FLAG_PASSWORD);
+      if (peer->password)
+	free (peer->password);
+      peer->password = NULL;
+
+      return 0;
+    }
+
+  UNSET_FLAG (peer->flags, PEER_FLAG_PASSWORD);
+  if (peer->password)
+    free (peer->password);
+  peer->password = NULL;
+
+  group = peer->group;
+  /* #42# LIST_LOOP (group->peer, peer, nn) */
+  for (ALL_LIST_ELEMENTS (group->peer, nn, nnode, peer))
+    {
+      if (! CHECK_FLAG (peer->flags, PEER_FLAG_PASSWORD))
+	continue;
+
+      if (peer->status == Established)
+        bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+      else
+        BGP_EVENT_ADD (peer, BGP_Stop);
+
+      if (sockunion_family (&peer->su) == AF_INET)
+	bgp_md5_set (bm->sock, &peer->su.sin, NULL);
+
+      UNSET_FLAG (peer->flags, PEER_FLAG_PASSWORD);
+      if (peer->password)
+        free (peer->password);
+      peer->password = NULL;
+    }
+
+  return 0;
+}
+#endif /* HAVE_TCP_MD5SIG */
+
 /* Set distribute list to the peer. */
 int
 peer_distribute_set (struct peer *peer, afi_t afi, safi_t safi, int direct, 
@@ -4416,6 +4571,16 @@
 	    ! CHECK_FLAG (g_peer->flags, PEER_FLAG_SHUTDOWN))
 	  vty_out (vty, " neighbor %s shutdown%s", addr, VTY_NEWLINE);
 
+#ifdef HAVE_TCP_MD5SIG
+      /* Password. */
+      if (CHECK_FLAG (peer->flags, PEER_FLAG_PASSWORD))
+	if (! peer_group_active (peer)
+	    || ! CHECK_FLAG (g_peer->flags, PEER_FLAG_PASSWORD)
+	    || strcmp (peer->password, g_peer->password) != 0)
+	  vty_out (vty, " neighbor %s password %s%s", addr, peer->password,
+		   VTY_NEWLINE);
+#endif /* HAVE_TCP_MD5SIG */
+
       /* BGP port. */
       if (peer->port != BGP_PORT_DEFAULT)
 	vty_out (vty, " neighbor %s port %d%s", addr, peer->port, 
@@ -4951,6 +5116,9 @@
   bm->port = BGP_PORT_DEFAULT;
   bm->master = thread_master_create ();
   bm->start_time = time (NULL);
+#ifdef HAVE_TCP_MD5SIG
+  bm->sock = -1;
+#endif /* HAVE_TCP_MD5SIG */
 }
 
 
diff -urN quagga-0.99.8-orig/bgpd/bgpd.h quagga-0.99.8/bgpd/bgpd.h
--- quagga-0.99.8-orig/bgpd/bgpd.h	Sun Aug 12 15:35:08 2007
+++ quagga-0.99.8/bgpd/bgpd.h	Sun Aug 12 16:01:09 2007
@@ -52,6 +52,11 @@
 #define BGP_OPT_NO_FIB                   (1 << 0)
 #define BGP_OPT_MULTIPLE_INSTANCE        (1 << 1)
 #define BGP_OPT_CONFIG_CISCO             (1 << 2)
+
+#ifdef HAVE_TCP_MD5SIG
+  /* bgp receive socket */
+  int sock;
+#endif /* HAVE_TCP_MD5SIG */
 };
 
 /* BGP instance structure.  */
@@ -349,6 +354,7 @@
 
   /* NSF mode (graceful restart) */
   u_char nsf[AFI_MAX][SAFI_MAX];
+#define PEER_FLAG_PASSWORD                  (1 << 9) /* password */
 
   /* Per AF configuration flags. */
   u_int32_t af_flags[AFI_MAX][SAFI_MAX];
@@ -370,6 +376,9 @@
 #define PEER_FLAG_MAX_PREFIX_WARNING        (1 << 15) /* maximum prefix warning-only */
 #define PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED   (1 << 16) /* leave link-local nexthop unchanged */ 
 
+  /* MD5 password */
+  char *password;
+
   /* default-originate route-map.  */
   struct
   {
@@ -525,6 +534,13 @@
 #define PEER_RMAP_TYPE_EXPORT         (1 << 7) /* neighbor route-map export */
 };
 
+#if defined(HAVE_TCP_MD5SIG)
+
+#define PEER_PASSWORD_MINLEN	(1)
+#define PEER_PASSWORD_MAXLEN	(80)
+
+#endif /* HAVE_TCP_MD5SIG */
+
 /* This structure's member directly points incoming packet data
    stream. */
 struct bgp_nlri
@@ -912,6 +928,11 @@
 extern int peer_route_map_unset (struct peer *, afi_t, safi_t, int);
 
 extern int peer_unsuppress_map_set (struct peer *, afi_t, safi_t, const char *);
+#ifdef HAVE_TCP_MD5SIG
+extern int peer_password_set (struct peer *, const char *);
+extern int peer_password_unset (struct peer *);
+#endif /* HAVE_TCP_MD5SIG */
+
 extern int peer_unsuppress_map_unset (struct peer *, afi_t, safi_t);
 
 extern int peer_maximum_prefix_set (struct peer *, afi_t, safi_t, u_int32_t, u_char, int, u_int16_t);
diff -urN quagga-0.99.8-orig/lib/sockopt.c quagga-0.99.8/lib/sockopt.c
--- quagga-0.99.8-orig/lib/sockopt.c	Sun Aug 12 15:35:09 2007
+++ quagga-0.99.8/lib/sockopt.c	Sun Aug 12 16:02:34 2007
@@ -451,3 +451,36 @@
 
   iph->ip_id = ntohs(iph->ip_id);
 }
+
+#if defined(HAVE_TCP_MD5SIG)
+int
+sockopt_tcp_signature (int sock, struct sockaddr_in *sin, const char *password)
+{
+  int keylen = password ? strlen(password) : 0;
+
+#if defined(GNU_LINUX)
+
+  struct tcp_md5sig md5sig;
+
+  bzero ((char *)&md5sig, sizeof(md5sig));
+  memcpy (&md5sig.tcpm_addr, sin, sizeof(*sin));
+  md5sig.tcpm_keylen = keylen;
+  if (keylen)
+    memcpy (md5sig.tcpm_key, password, keylen);
+
+  return setsockopt (sock, IPPROTO_TCP, TCP_MD5SIG, &md5sig, sizeof md5sig);
+
+#else /* !GNU_LINUX */
+
+  int enable = keylen ? (TCP_SIG_SPI_BASE + sin->sin_port) : 0;
+
+  /*
+   * XXX Need to do PF_KEY operation here to add/remove an SA entry,
+   * and add/remove an SP entry for this peer's packet flows also.
+   */
+  return setsockopt (sock, IPPROTO_TCP, TCP_MD5SIG, &enable,
+		     sizeof(enable));
+
+#endif /* !GNU_LINUX */
+}
+#endif /* HAVE_TCP_MD5SIG */
diff -urN quagga-0.99.8-orig/lib/sockopt.h quagga-0.99.8/lib/sockopt.h
--- quagga-0.99.8-orig/lib/sockopt.h	Sun Aug 12 15:35:09 2007
+++ quagga-0.99.8/lib/sockopt.h	Sun Aug 12 16:02:40 2007
@@ -96,4 +96,32 @@
 extern void sockopt_iphdrincl_swab_htosys (struct ip *iph);
 extern void sockopt_iphdrincl_swab_systoh (struct ip *iph);
 
+#if defined(HAVE_TCP_MD5SIG)
+
+#if defined(GNU_LINUX) && !defined(TCP_MD5SIG)
+
+/* XXX these will come from <linux/tcp.h> eventually */
+
+#define TCP_MD5SIG		14
+#define TCP_MD5SIG_MAXKEYLEN	80
+
+struct tcp_md5sig {
+        struct sockaddr_storage tcpm_addr;      /* address associated */
+        __u16   __tcpm_pad1;                            /* zero */
+        __u16   tcpm_keylen;                            /* key length */
+        __u32   __tcpm_pad2;                            /* zero */
+        __u8    tcpm_key[TCP_MD5SIG_MAXKEYLEN];         /* key (binary) */
+};
+
+#endif /* defined(GNU_LINUX) && !defined(TCP_MD5SIG) */
+
+#if !defined(GNU_LINUX) && !defined(TCP_SIG_SPI_BASE)
+#define TCP_SIG_SPI_BASE 1000 /* XXX this will go away */
+#endif
+
+extern int sockopt_tcp_signature(int sock, struct sockaddr_in *sin,
+                                 const char *password);
+
+#endif /* HAVE_TCP_MD5SIG */
+
 #endif /*_ZEBRA_SOCKOPT_H */
