diff -rbBNu bridge-utils/Makefile bridge-utils.cli/Makefile
--- bridge-utils/Makefile	Sun Jan  6 13:33:29 2002
+++ bridge-utils.cli/Makefile	Wed Jan  9 13:07:39 2002
@@ -1,4 +1,4 @@
-all:				brctl/brctl brctl/brctld misc/bidi
+all:				brctl/brctl brctl/brdlg brctl/brctld misc/bidi
 
 clean:
 				make -C brctl clean
@@ -9,6 +9,9 @@
 				rm -f *~
 
 brctl/brctl:			brctl/brctl.c brctl/brctl.h brctl/brctl_cmd.c brctl/brctl_disp.c libbridge/libbridge.a libbridge/libbridge.h
+				make -C brctl
+
+brctl/brdlg:			brctl/brdlg.c brctl/brctl.h brctl/cli.c brctl/cli.h libbridge/libbridge.a
 				make -C brctl
 
 brctl/brctld:			brctl/brctld.c brctl/brctl.h brctl/brctl_cmd.c brctl/brctl_disp.c libbridge/libbridge.a libbridge/libbridge.h
diff -rbBNu bridge-utils/brctl/Makefile bridge-utils.cli/brctl/Makefile
--- bridge-utils/brctl/Makefile	Fri Jun 22 22:59:02 2001
+++ bridge-utils.cli/brctl/Makefile	Wed Jan  9 16:25:12 2002
@@ -1,20 +1,32 @@
-all:			brctl brctld
+INDENT_OPTIONS = -br -ce -ss -pcs -cli2 -cbi0 -ts2 # this style is OK for me, you are wellcome to change
+
+all:			brctl brdlg brctld
 
 brctl:			brctl.o brctl_cmd.o brctl_disp.o ../libbridge/libbridge.a
 			gcc -Wall -g -o brctl brctl.o brctl_cmd.o brctl_disp.o ../libbridge/libbridge.a
 
+brdlg:			brdlg.o brctl_cmd.o brctl_disp.o cli.o ../libbridge/libbridge.a
+			gcc -Wall -g -lreadline -o $@ brdlg.o brctl_cmd.o brctl_disp.o cli.o ../libbridge/libbridge.a
+
 brctld:			brctld.o brctl_cmd.o brctl_disp.o ../libbridge/libbridge.a
 			gcc -Wall -g -o brctld brctld.o brctl_cmd.o brctl_disp.o ../libbridge/libbridge.a
 
 clean:
 			rm -f *.o
 			rm -f brctl
+			rm -f brdlg
 			rm -f brctld
 			rm -f core
+			rm -f *~
+			rm -f *.bak
+			rm -f make.depend*
 
-brctl.o:		brctl.c brctl.h
+brctl.o:		brctl.c brctl.h cli.h
 			gcc -I../libbridge -Wall -c -g -o brctl.o brctl.c
 
+brdlg.o:		brdlg.c brctl.h
+			gcc -I../libbridge -Wall -c -g -o $@ brdlg.c
+			
 brctld.o:		brctld.c brctl.h
 			gcc -I../libbridge -Wall -c -g -o brctld.o brctld.c
 
@@ -23,3 +35,14 @@
 
 brctl_disp.o:		brctl_disp.c brctl.h
 			gcc -I../libbridge -Wall -c -g -o brctl_disp.o brctl_disp.c
+
+indent:
+			indent $(INDENT_OPTIONS) brdlg.c
+			indent $(INDENT_OPTIONS) cli.c
+
+depend:
+			echo "# DO NOT DELETE THIS LINE -- make  depend  depends  on it." > make.depend
+			makedepend -- -I../libbridge -- brctl.c brdlg.c brctld.c brctl_cmd.c brctl_disp.c  -f make.depend
+
+-include make.depend
+
diff -rbBNu bridge-utils/brctl/brdlg.c bridge-utils.cli/brctl/brdlg.c
--- bridge-utils/brctl/brdlg.c	Thu Jan  1 02:00:00 1970
+++ bridge-utils.cli/brctl/brdlg.c	Wed Jan  9 16:34:06 2002
@@ -0,0 +1,524 @@
+/************************************************************************
+ * RSTP library - Rapid Spanning Tree (802.1t, 802.1w)
+ * Copyright (C) 2001-2003 Optical Access
+ * Author: Alex Rozin
+ *
+ * This file is part of RSTP library.
+ *
+ * RSTP library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; version 2.1
+ *
+ * RSTP library 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 Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with RSTP library; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ **********************************************************************/
+
+/*
+ * Copyright (C) 2000 Lennert Buytenhek
+ *
+ * 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 the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <asm/param.h>
+#include <signal.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <readline/readline.h>
+
+#include "libbridge.h"
+#include "brctl.h"
+
+#include "cli.h"
+
+#define MAX_TIMEOUT	45
+#define ASSERT_ARGC(X)				\
+	if (argc < X) {				\
+	  printf ("too few arguments :(\n");	\
+	  return 0;				\
+	}
+
+
+char shutdown_flag = 0;
+
+static int
+dummy_show_args (int argc, char **argv)
+{
+	int iii;
+	printf ("ardc=%d\n", argc);
+	for (iii = 0; iii < argc; iii++)
+		printf ("argv[%d]='%s'\n", iii, argv[iii]);
+	return 0;
+}
+
+static void
+_bridge_show (struct bridge *br)
+{
+	printf ("%s\t\t", br->ifname);
+	br_dump_bridge_id ((unsigned char *) &br->info.bridge_id);
+	printf ("\t%s\t\t", br->info.stp_enabled ? "yes" : "no");
+	br_dump_interface_list (br);
+}
+
+static int
+show_bridge (int argc, char **argv)
+{
+	struct bridge *br;
+
+	/* dummy_show_args (2, argv); */
+	printf ("bridge name\tbridge id\t\tSTP enabled\tinterfaces\n");
+
+	if (!strcmp (argv[1], "all")) {
+		for (br = bridge_list; br; br = br->next) {
+			_bridge_show (br);
+		}
+	} else {
+		br = br_find_bridge (argv[1]);
+		if (!br) {
+			printf ("bridge %s doesn't exist!\n", argv[1]);
+			return 0;
+		}
+		_bridge_show (br);
+	}
+	return 0;
+}
+
+static int
+show_stp (int argc, char **argv)
+{
+	struct bridge *br;
+
+	if (!strcmp (argv[1], "all")) {
+		for (br = bridge_list; br; br = br->next) {
+			br_dump_info (br);
+		}
+	} else {
+		br = br_find_bridge (argv[1]);
+		if (!br) {
+			printf ("bridge %s doesn't exist!\n", argv[1]);
+			return 0;
+		}
+		br_dump_info (br);
+	}
+	return 0;
+}
+
+static int
+add_bridge (int argc, char **argv)
+{
+	int err;
+
+	/* dummy_show_args (argc, argv); */
+	ASSERT_ARGC (2);
+	err = br_add_bridge (argv[1]);
+	if (err)
+		printf ("device %s already exists; can't create "
+						"bridge with the same name\n", argv[1]);
+	err = br_refresh ();
+	if (err)
+		printf ("can't refresh bridge list\n");
+	return 0;
+}
+
+static int
+delete_bridge (int argc, char **argv)
+{
+	int err;
+
+	/* dummy_show_args (argc, argv); */
+	ASSERT_ARGC (2);
+	err = br_del_bridge (argv[1]);
+	if (err)
+		printf ("device %s %s\n", argv[1],
+						ENXIO == err ?
+						"doesn't exist; can't delete it" :
+						"is still up; can't delete it");
+	err = br_refresh ();
+	if (err)
+		printf ("can't refresh bridge list\n");
+	return 0;
+}
+
+static int
+add_if (int argc, char **argv)
+{
+	struct bridge *br;
+	int ifindex, err;
+
+	/* dummy_show_args (argc, argv); */
+	ASSERT_ARGC (2);
+	br = br_find_bridge (argv[1]);
+	if (!br) {
+		printf ("bridge '%s' doesn't exist\n", argv[1]);
+		return 0;
+	}
+
+	ifindex = if_nametoindex (argv[2]);
+	if (!ifindex) {
+		printf ("interface %s does not exist!\n", argv[2]);
+		return 0;
+	}
+
+	if ((err = br_add_interface (br, ifindex)) == 0)
+		return 0;
+
+	switch (err) {
+		case EBUSY:
+		printf ("device %s is already a member of a bridge; "
+						"can't enslave it to bridge %s.\n", argv[2], br->ifname);
+		break;
+		case ELOOP:
+		printf ("device %s is a bridge device itself; "
+						"can't enslave a bridge device to a bridge device.\n", argv[2]);
+		break;
+		default:
+		perror ("br_add_interface");
+		break;
+	}
+
+	return 0;
+}
+
+static int
+delete_if (int argc, char **argv)
+{
+	struct bridge *br;
+	int ifindex, err;
+
+	/* dummy_show_args (argc, argv); */
+	ASSERT_ARGC (2);
+	br = br_find_bridge (argv[1]);
+	if (!br) {
+		printf ("bridge '%s' doesn't exist\n", argv[1]);
+		return 0;
+	}
+
+	ifindex = if_nametoindex (argv[2]);
+	if (!ifindex) {
+		printf ("interface %s does not exist!\n", argv[2]);
+		return 0;
+	}
+
+	if ((err = br_del_interface (br, ifindex)) == 0)
+		return 0;
+
+	switch (err) {
+		case EINVAL:
+		printf ("device %s is not a slave of %s\n", argv[2], br->ifname);
+		break;
+		default:
+		perror ("br_del_interface");
+		break;
+	}
+
+	return 0;
+}
+
+static int
+set_stp (int argc, char **argv)
+{
+	struct bridge *br;
+	int stp;
+
+	stp = !strcmp (argv[1], "on") ||
+		!strcmp (argv[1], "yes") || !strcmp (argv[1], "enable");
+
+	printf ("stp will be %sabled on bridges:\n", stp ? "en" : "dis");
+	if (!strcmp (argv[2], "all")) {
+		for (br = bridge_list; br; br = br->next) {
+			printf ("\t'%s'\n", br->ifname);
+			br_set_stp_state (br, stp);
+		}
+	} else {
+		br = br_find_bridge (argv[2]);
+		if (!br) {
+			printf ("bridge %s doesn't exist!\n", argv[2]);
+			return 0;
+		}
+		printf ("\t'%s'\n", br->ifname);
+		br_set_stp_state (br, stp);
+	}
+	return 0;
+}
+
+static int
+stp_br_prio (int argc, char **argv)
+{
+	struct bridge *br;
+	long br_prio = 32768L;
+
+	if (strlen (argv[1]) > 2 &&
+			(!strncmp (argv[1], "0x", 2) || !strncmp (argv[1], "0X", 2))) {
+		br_prio = strtoul (argv[1] + 2, 0, 16);
+	} else {
+		br_prio = strtoul (argv[1], 0, 10);
+	}
+
+	if (!br_prio) {
+		printf ("Warning: newPriority=0, are you sure ?\n");
+	}
+
+	printf ("accepted: priority %ld 0x%lX\n", br_prio, br_prio);
+	if (!strcmp (argv[2], "all")) {
+		for (br = bridge_list; br; br = br->next) {
+			br_set_bridge_priority (br, br_prio);
+			printf ("set for bridge '%s'\n", br->ifname);
+		}
+	} else {
+		br = br_find_bridge (argv[2]);
+		if (!br) {
+			printf ("bridge %s doesn't exist!\n", argv[2]);
+			return 0;
+		}
+		br_set_bridge_priority (br, br_prio);
+		printf ("set for bridge '%s'\n", br->ifname);
+	}
+
+	return 0;
+}
+
+static void
+_port_prio_set (long prt_prio, struct bridge *br, char *port_name)
+{
+	struct port *p;
+
+	if (!strcmp (port_name, "all")) {
+		for (p = br->firstport; p; p = p->next) {
+			printf ("\t\tport '%d'\n", p->index);
+			br_set_port_priority (p, prt_prio);
+		}
+	} else {
+		p = br_find_port (br, port_name);
+		if (!p) {
+			printf ("\t\tcan't find port '%s' on bridge '%s'\n",
+							port_name, br->ifname);
+		}
+		printf ("\t\tport '%d'\n", p->index);
+		br_set_port_priority (p, prt_prio);
+	}
+}
+
+static int
+stp_prt_prio (int argc, char **argv)
+{
+	struct bridge *br;
+	long prt_prio = 32768L;
+
+	if (strlen (argv[1]) > 2 &&
+			(!strncmp (argv[1], "0x", 2) || !strncmp (argv[1], "0X", 2))) {
+		prt_prio = strtoul (argv[1] + 2, 0, 16);
+	} else {
+		prt_prio = strtoul (argv[1], 0, 10);
+	}
+
+	if (!prt_prio) {
+		printf ("Warning: newPriority=0, are you sure ?\n");
+	}
+
+	printf ("accepted: priority %ld 0x%lX\n", prt_prio, prt_prio);
+	if (!strcmp (argv[2], "all")) {
+		for (br = bridge_list; br; br = br->next) {
+			printf ("\tset for bridge '%s'\n", br->ifname);
+			_port_prio_set (prt_prio, br, argv[3]);
+		}
+	} else {
+		br = br_find_bridge (argv[2]);
+		if (!br) {
+			printf ("\tbridge %s doesn't exist!\n", argv[2]);
+			return 0;
+		}
+		printf ("\tset for bridge '%s'\n", br->ifname);
+		_port_prio_set (prt_prio, br, argv[3]);
+	}
+
+	return 0;
+}
+
+static CMD_DSCR_T lang[] = {
+	THE_COMMAND ("add bridge", "add new bridge")
+		PARAM_STRING ("bridge name", NULL)
+		THE_FUNC (add_bridge)
+
+		THE_COMMAND ("add if", "add new interface")
+		PARAM_STRING ("bridge name", NULL)
+		PARAM_STRING ("device name", "eth0")
+		THE_FUNC (add_if)
+
+		THE_COMMAND ("delete bridge", "delete existing bridge")
+		PARAM_STRING ("bridge name", NULL)
+		THE_FUNC (delete_bridge)
+
+		THE_COMMAND ("delete if", "delete existing interface from bridge")
+		PARAM_STRING ("bridge name", NULL)
+		PARAM_STRING ("device name", "eth0")
+		THE_FUNC (delete_if)
+
+		THE_COMMAND ("show bridge", "show bridge[s]")
+		PARAM_STRING ("bridge name", "all")
+		THE_FUNC (show_bridge)
+
+		THE_COMMAND ("show stp", "show stp on bridge[s]")
+		PARAM_STRING ("bridge name", "all")
+		THE_FUNC (show_stp)
+
+		THE_COMMAND ("show macs", "show show a list of mac addrs")
+		PARAM_STRING ("bridge name", "all")
+		THE_FUNC (dummy_show_args)
+
+		THE_COMMAND ("stp state", "set {dis,en}able stp")
+		PARAM_ENUM ("state of the stp")
+		PARAM_ENUM_SEL ("enable", "enable stp")
+		PARAM_ENUM_SEL ("disable", "disable stp")
+		PARAM_ENUM_DEFAULT ("enable")
+		PARAM_STRING ("bridge name", "all")
+		THE_FUNC (set_stp)
+
+		THE_COMMAND ("stp priority", "set stp bridge priority")
+		PARAM_NUMBER ("priority", 0, 61440, "0x8000")
+		PARAM_STRING ("bridge name", "all")
+		THE_FUNC (stp_br_prio)
+
+		THE_COMMAND ("stp port priority ", "set stp bridge priority")
+		PARAM_NUMBER ("priority", 0, 240, "128")
+		PARAM_STRING ("bridge name", "all")
+		PARAM_STRING ("port name", "all")
+		THE_FUNC (stp_prt_prio)
+
+	END_OF_LANG
+};
+
+char *
+get_prompt (void)
+{
+	static char prompt[MAX_CLI_PROMT];
+	snprintf (prompt,
+						MAX_CLI_PROMT - 1, "%s brdlg > ", UT_sprint_time_stamp ());
+	return prompt;
+}
+
+void
+brdlg_start (void)
+{
+	int err;
+
+	err = br_init ();
+	if (err) {
+		printf ("cannot init err=%d\n", err);
+		exit (-err);
+	}
+	rl_init ();
+	cli_register_language (lang);
+}
+
+void
+brdlg_shutdown (void)
+{
+	rl_shutdown ();
+	printf ("\n");
+}
+
+int
+brdlg_loop (void)
+{
+	fd_set readfds;
+	int rc, numfds, kkk, timout = 0;
+	struct timeval tv;
+	struct timeval now, earliest;
+
+	//rl_callback_handler_install (get_prompt (), rl_read_cli);
+	gettimeofday (&earliest, NULL);
+	earliest.tv_sec++;
+
+	do {
+		numfds = -1;
+		FD_ZERO (&readfds);
+
+		kkk = 0;										/* stdin for commands */
+		FD_SET (kkk, &readfds);
+		if (kkk > numfds)
+			numfds = kkk;
+
+		if (numfds < 0)
+			numfds = 0;
+		else
+			numfds++;
+
+		gettimeofday (&now, 0);
+		tv.tv_usec = 0;
+		tv.tv_sec = 0;
+
+		if (now.tv_sec < earliest.tv_sec) {	/* we must wait more than 1 sec. */
+			tv.tv_sec = 1;
+			tv.tv_usec = 0;
+		} else if (now.tv_sec == earliest.tv_sec) {
+			if (now.tv_usec < earliest.tv_usec) {
+				if (earliest.tv_usec < now.tv_usec)
+					tv.tv_usec = 0;
+				else
+					tv.tv_usec = earliest.tv_usec - now.tv_usec;
+			}
+		}
+
+		rc = select (numfds, &readfds, NULL, NULL, &tv);
+		if (rc < 0) {								// Error
+			if (EINTR == errno)
+				continue;								// don't break
+			printf ("FATAL_MODE:select failed: %s\n", strerror (errno));
+			return -2;
+		}
+
+		if (!rc) {									/* Timeout expired */
+			gettimeofday (&earliest, NULL);
+			/* printf ("time sec.\n"); */
+			if (++timout > MAX_TIMEOUT) {
+				printf ("\n%s: timeout expired :(\n\n", get_prompt ());
+				return -3;
+			}
+
+			earliest.tv_sec++;
+			continue;
+		}
+
+		timout = 0;
+
+		if (FD_ISSET (0, &readfds)) {
+			rl_callback_read_char ();
+		}
+
+	} while (!shutdown_flag);
+	return 0;
+
+}
+
+int
+main (int argc, char **argv)
+{
+	brdlg_start ();
+	brdlg_loop ();
+	brdlg_shutdown ();
+
+	return 0;
+}
diff -rbBNu bridge-utils/brctl/cli.c bridge-utils.cli/brctl/cli.c
--- bridge-utils/brctl/cli.c	Thu Jan  1 02:00:00 1970
+++ bridge-utils.cli/brctl/cli.c	Wed Jan  9 16:34:06 2002
@@ -0,0 +1,524 @@
+/************************************************************************ 
+ * RSTP library - Rapid Spanning Tree (802.1t, 802.1w) 
+ * Copyright (C) 2001-2003 Optical Access 
+ * Author: Alex Rozin 
+ * 
+ * This file is part of RSTP library. 
+ * 
+ * RSTP library is free software; you can redistribute it and/or modify it 
+ * under the terms of the GNU Lesser General Public License as published by the 
+ * Free Software Foundation; version 2.1 
+ * 
+ * RSTP library 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 Lesser 
+ * General Public License for more details. 
+ * 
+ * You should have received a copy of the GNU Lesser General Public License 
+ * along with RSTP library; see the file COPYING.  If not, write to the Free 
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 
+ * 02111-1307, USA. 
+ **********************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <time.h>
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#include "cli.h"
+
+static CMD_DSCR_T *TheList = 0;
+
+static int
+cli_parse_parms (const char *line, int skip_words, char **argv)
+{
+	static char pool[MAX_CLI_BUFF];
+	register char *ptr;
+	register int argc = 0, iii;
+
+	ptr = strchr (line, '\n');
+	if (ptr)
+		*ptr = '\0';
+	memcpy (pool, line, MAX_CLI_BUFF);
+	pool[MAX_CLI_BUFF - 1] = '\0';
+
+	for (iii = 0; iii < MAXPARAMNUM; iii++) {
+		ptr = strtok (iii ? NULL : pool, "\t\n ");
+		if (!ptr)
+			break;
+		if (skip_words-- <= 0) {
+			/* printf ("\targv[%d]='%s' skip_words=%d\n", argc, ptr, skip_words); */
+			argv[argc++] = ptr;
+		} else {
+			/* printf ("\tskip '%s' skip_words now %d\n", ptr, skip_words); */
+		}
+	}
+
+	return argc;
+}
+
+int
+cli_count_words (char *line)
+{
+	static char pool[MAX_CLI_CMD_NAME];
+	register char *ptr = NULL;
+	register int cnt;
+
+	ptr = strchr (line, '\n');
+	if (ptr)
+		*ptr = '\0';
+	memcpy (pool, line, MAX_CLI_BUFF);
+	pool[MAX_CLI_BUFF - 1] = '\0';
+
+	for (cnt = 0;; cnt++) {
+		ptr = strtok (cnt ? NULL : pool, "\t\n ");
+		if (!ptr) {
+			break;
+		}
+	}
+
+	return cnt - 1;
+}
+
+void
+cli_register_language (const CMD_DSCR_T * cmd_list)
+{
+	TheList = (CMD_DSCR_T *) cmd_list;
+}
+
+static int
+help_on_param (int iii, CMD_PAR_DSCR_T * par, int cry_on_empty)
+{
+	register int kkk;
+
+	if (!par->param_help) {
+		if (cry_on_empty)
+			printf ("absent parameter #%d\n", iii);
+		return 1;
+	}
+
+	printf ("    arg%2d: %s", iii + 1, par->param_help);
+	switch (par->param_type) {
+		case CMD_PAR_NUMBER:
+		printf ("; integer in [%ld, %ld]", par->number_limits.min,
+						par->number_limits.max);
+		break;
+		case CMD_PAR_STRING:
+		break;
+		case CMD_PAR_BOOL_YN:
+		case CMD_PAR_ENUM:
+		printf ("\n");
+		for (kkk = 0; par->string_selector[kkk].string_value; kkk++) {
+			printf ("           %-20s\t%s\n",
+							par->string_selector[kkk].string_value,
+							par->string_selector[kkk].string_help);
+		}
+		break;
+	}
+
+	if (par->default_value) {
+		printf ("           default '%s'", par->default_value);
+	}
+	printf (" \n");
+	return 0;
+}
+
+void
+help_on_command (CMD_DSCR_T * reg, char brief)
+{
+	register CMD_PAR_DSCR_T *par;
+	register int iii;
+
+	if (brief) {
+		printf ("%-20s %s\n", reg->cmd_name, reg->cmd_help);
+		return;
+	}
+	printf ("%s: %s\n", reg->cmd_name, reg->cmd_help);
+	for (iii = 0; iii < 2 + strlen (reg->cmd_name) + strlen (reg->cmd_help);
+			 iii++)
+		printf ("-");
+
+	printf ("\n");
+	if (reg->param->param_help)
+		printf ("  arguments:\n  ----------\n");
+	for (iii = 0, par = reg->param;; iii++, par++) {
+		if (!par->param_help)
+			break;
+		help_on_param (iii + 1, par, 0);
+	}
+	if (reg->param->param_help)
+		printf ("\n");
+}
+
+static int
+cli_dummy (int argc, char **argv)
+{
+	return 0;
+}
+
+static CMD_DSCR_T stdcmd[] = {
+	THE_COMMAND ("exit", "'shutdown'")
+		THE_FUNC (cli_dummy)
+
+		THE_COMMAND ("?", "help")
+		THE_FUNC (cli_dummy)
+
+	END_OF_LANG
+};
+
+static char *
+get_commnad_name (int list_index)
+{
+	register CMD_DSCR_T *reg;
+
+	if (list_index < 2 && list_index >= 0) {
+		return stdcmd[list_index].cmd_name;
+	}
+
+	list_index -= 2;
+	reg = TheList + list_index;
+	if (reg->cmd_name && *reg->cmd_name)
+		return reg->cmd_name;
+	return NULL;
+}
+
+static int
+find_command (const char *line, char forHelp, CMD_DSCR_T ** reg_ptr)
+{
+	register CMD_DSCR_T *reg;
+	register int iii = 0;
+
+	for (reg = stdcmd; reg->cmd_name; reg++) {
+		if (!strncasecmp (reg->cmd_name, line, strlen (line))) {
+			*reg_ptr = reg;
+			iii++;
+			if (forHelp)
+				help_on_command (reg, 1);
+		}
+	}
+
+	for (reg = TheList; reg->cmd_name; reg++) {
+		if (!strncasecmp (reg->cmd_name, line, strlen (line))) {
+			*reg_ptr = reg;
+			iii++;
+			if (forHelp)
+				help_on_command (reg, 1);
+		}
+	}
+
+	return iii;
+}
+
+void
+usage (void)
+{
+	CMD_DSCR_T *reg;
+
+	if (!TheList) {
+		printf ("Sorry, command list hasn't been registered\n");
+		return;
+	}
+
+	printf ("List of possible commands:\n");
+	for (reg = TheList; reg->cmd_name; reg++) {
+		help_on_command (reg, 1);
+	}
+
+	printf ("'standard' commands:\n");
+	for (reg = stdcmd; reg->cmd_name; reg++) {
+		help_on_command (reg, 1);
+	}
+}
+
+void
+cli_debug_dump_args (char *title, int argc, char **argv)
+{
+	int iii;
+	printf ("in %s argc=%d\n", title, argc);
+	for (iii = 0; iii < argc; iii++)
+		printf ("\targv[%d]='%s'\n", iii, argv[iii]);
+	printf ("\n");
+}
+
+
+static int
+count_command_paramms (CMD_DSCR_T * reg)
+{
+	register int iii;
+	register CMD_PAR_DSCR_T *par;
+
+	for (iii = 0, par = reg->param;; iii++, par++) {
+		if (!par->param_help)
+			break;
+	}
+	return iii;
+}
+
+static void
+cli_help_brosed_line (int argc, char **argv, const char *line)
+{
+	char pool[MAX_CLI_BUFF];
+	CMD_DSCR_T *reg;
+	int iii, nf;
+
+	printf ("\n");
+#if 0
+	cli_debug_dump_args ("cli_help_brosed_line", argc, argv);
+#endif
+
+	memset (pool, 0, MAX_CLI_BUFF);
+	for (iii = 0; iii < argc; iii++) {
+		if (iii)
+			strcat (pool, " ");
+		strcat (pool, argv[iii]);
+		nf = find_command (pool, 0, &reg);
+		if (1 == nf) {
+			nf = count_command_paramms (reg);
+			iii++;
+#if 0
+			printf ("iii=%d argc=%d nf=%d\n", iii, argc, nf);
+#endif
+			nf = strlen (line);
+			if (nf && ' ' == line[nf - 1])
+				argc++;
+			if (iii < argc) {
+				iii = argc - iii - 1;
+				if (!help_on_param (iii + 1, reg->param + iii, 1)) {
+					return;
+				}
+			}
+			help_on_command (reg, 0);
+			return;
+		} else if (!nf) {
+			printf ("\nunknown <%s>\n", pool);
+			usage ();
+			return;
+		}
+	}
+	find_command (pool, 1, &reg);
+}
+
+void
+cli_help (int argc, char **argv, const char *line)
+{
+#if 0
+	cli_debug_dump_args ("cli_help", argc, argv);
+#endif
+	if (argc > 1)
+		cli_help_brosed_line (argc - 1, argv + 1, line);
+	else
+		usage ();
+}
+
+static void
+cli_set_defaults (CMD_DSCR_T * reg, char **argv)
+{
+	register int iii;
+	register CMD_PAR_DSCR_T *par;
+
+	for (iii = 0, par = reg->param;; iii++, par++) {
+		if (!par->param_help)
+			break;
+		argv[iii + 1] = par->default_value;
+	}
+}
+
+static int
+cli_call_callback (CMD_DSCR_T * reg, const char *line, int *argc, char **argv)
+{
+	int cnt;
+
+	if (reg->clbk) {
+		cnt = cli_count_words (reg->cmd_name);
+		/* printf ("cli_count_words returned %d\n", cnt); */
+		cli_set_defaults (reg, argv);
+		*argc = cli_parse_parms (line, cnt, argv);
+		return (*reg->clbk) (*argc, argv);
+	}
+	printf ("<Empty command !>\n");
+	return 0;
+}
+
+int
+cli_execute_command (const char *line)
+{
+	CMD_DSCR_T *reg;
+	int argc, nf;
+	char *argv[MAXPARAMNUM];
+
+	if ('\n' == *line || !*line)
+		return 0;
+
+	/* check "common commands" */
+	if ('q' == *line || !strncasecmp ("ex", line, 2)) {
+		return 4;
+	}
+
+	if ('?' == *line || 'h' == *line) {
+		argc = cli_parse_parms (line, 0, argv);
+		cli_help (argc, argv, line);
+		return 0;
+	}
+
+	if (!TheList) {
+		printf ("Sorry, command list hasn't been registered\n");
+		return -11;
+	}
+
+	for (reg = TheList; reg->cmd_name; reg++) {
+		if (!strncasecmp (reg->cmd_name, line, strlen (reg->cmd_name))) {
+			return cli_call_callback (reg, line, &argc, argv);
+		}
+	}
+
+	nf = find_command (line, 0, &reg);
+	if (1 == nf)
+		return cli_call_callback (reg, line, &argc, argv);
+
+	printf ("unknown command: <%s>", line);
+	usage ();
+	return 0;
+}
+
+extern char shutdown_flag;
+
+char
+read_cli (void)
+{
+	if (!rl_line_buffer) {
+		return 1;
+	}
+
+	if (*rl_line_buffer != 0) {
+		add_history (rl_line_buffer);
+ /** printf ("\n try to call <%s>\n", rl_line_buffer); **/
+
+		if (0 != cli_execute_command (rl_line_buffer)) {
+			printf ("Goodbye, I'm a gonner\n");
+			rl_callback_handler_remove ();
+			return 2;
+		}
+	}
+
+	return 0;
+}
+
+void
+rl_read_cli (void)
+{
+	shutdown_flag |= read_cli ();
+	rl_callback_handler_install (get_prompt (), rl_read_cli);
+}
+
+char *
+UT_sprint_time_stamp (void)
+{
+	time_t clock;
+	struct tm *local_tm;
+	static char time_str[20];
+
+	time (&clock);
+	local_tm = localtime (&clock);
+	strftime (time_str, 20 - 1, "%H:%M:%S", local_tm);
+	return time_str;
+}
+
+int complete_status;
+
+/* To disable readline's filename completion */
+int
+cli_completion_entry_fucntion (int ignore, int invoking_key)
+{
+	return 0;
+}
+
+char *
+command_generator (char *text, int state)
+{
+	static int list_index, len;
+	char *name, dlen;
+
+/****
+  printf (" state=%d list_index=%d rl_line_buffer'%s' text'%s'\n",
+          state, list_index, rl_line_buffer, text);
+****/
+
+	dlen = strlen (rl_line_buffer) - strlen (text);
+	if (!state) {
+		list_index = 0;
+		len = strlen (rl_line_buffer);
+/****
+    printf ("\tlen=%d text<%s>\n", len, text);
+****/
+	}
+
+	for (;;) {
+		name = get_commnad_name (list_index);
+		if (!name)
+			break;
+		list_index++;
+		if (!strncmp (rl_line_buffer, name, len)) {
+/****
+      printf (" find <%s> => return '%s'\n", name, name + dlen);
+****/
+			return strdup (name + dlen);
+		}
+	}
+
+	return ((char *) NULL);
+}
+
+int
+cli_inline_help (void)
+{
+	int argc;
+	char *argv[MAXPARAMNUM];
+
+	if (!*rl_line_buffer) {
+		usage ();
+	} else {
+		argc = cli_parse_parms (rl_line_buffer, 0, argv);
+		cli_help_brosed_line (argc, argv, (const char *) rl_line_buffer);
+	}
+
+	rl_on_new_line ();
+	return 0;
+
+}
+
+char **
+cli_private_completion (char *text, int start, int end)
+{
+	char **matches = NULL;
+
+	matches = completion_matches (text, command_generator);
+
+	return matches;
+}
+
+void
+rl_init ()
+{
+	/* disable completion */
+#if 0
+	rl_bind_key ('\t', rl_insert);
+#else
+	rl_callback_handler_install (get_prompt (), rl_read_cli);
+	rl_bind_key ('?', cli_inline_help);
+	rl_completion_entry_function = cli_completion_entry_fucntion;
+	rl_attempted_completion_function = (CPPFunction *) cli_private_completion;
+	rl_completion_append_character = '\0';
+#endif
+}
+
+void
+rl_shutdown ()
+{
+	rl_initialize ();
+}
diff -rbBNu bridge-utils/brctl/cli.h bridge-utils.cli/brctl/cli.h
--- bridge-utils/brctl/cli.h	Thu Jan  1 02:00:00 1970
+++ bridge-utils.cli/brctl/cli.h	Wed Jan  9 13:05:50 2002
@@ -0,0 +1,90 @@
+/************************************************************************ 
+ * RSTP library - Rapid Spanning Tree (802.1t, 802.1w) 
+ * Copyright (C) 2001-2003 Optical Access 
+ * Author: Alex Rozin 
+ * 
+ * This file is part of RSTP library. 
+ * 
+ * RSTP library is free software; you can redistribute it and/or modify it 
+ * under the terms of the GNU Lesser General Public License as published by the 
+ * Free Software Foundation; version 2.1 
+ * 
+ * RSTP library 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 Lesser 
+ * General Public License for more details. 
+ * 
+ * You should have received a copy of the GNU Lesser General Public License 
+ * along with RSTP library; see the file COPYING.  If not, write to the Free 
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 
+ * 02111-1307, USA. 
+ **********************************************************************/
+
+#ifndef _CLI_API__
+#define _CLI_API__
+
+#define MAX_CLI_BUFF	80
+#define MAX_CLI_CMD_NAME 44
+#define MAXPARAMNUM     6
+#define MAXPARAMLEN     40
+#define MAX_CLI_PROMT	24
+#define MAX_SELECTOR	12
+
+typedef int CLI_CMD_CLBK (int argc, char** argv);
+
+typedef enum {
+  CMD_PAR_NUMBER,
+  CMD_PAR_STRING,
+  CMD_PAR_BOOL_YN,
+  CMD_PAR_ENUM,
+} CMD_PARAM_TYPE_T;
+
+typedef struct cmd_par_number_limits_s {
+  unsigned long min;
+  unsigned long max;
+} CMD_PAR_LIMITS;
+
+typedef struct cmd_par_string_selector_s {
+  char* string_value;
+  char* string_help;
+} CMD_PAR_SELECTOR;
+
+typedef struct cmd_par_dscr_s {
+  char*			param_help;
+  CMD_PARAM_TYPE_T	param_type;
+  CMD_PAR_LIMITS	number_limits;
+  CMD_PAR_SELECTOR	string_selector[MAX_SELECTOR];
+  char*			default_value;
+} CMD_PAR_DSCR_T;
+
+typedef struct cmd_dscr_s {
+  char*			cmd_name;
+  char*			cmd_help;
+  CMD_PAR_DSCR_T	param[MAXPARAMNUM];
+  CLI_CMD_CLBK*		clbk;
+} CMD_DSCR_T;
+
+#define THE_COMMAND(x, y)	{x, y, {
+#define PARAM_NUMBER(x,zmin,zmax,def)	{x,CMD_PAR_NUMBER, {zmin, zmax}, {}, def},
+#define PARAM_STRING(x, def)		{x,CMD_PAR_STRING, {},           {}, def},
+#define PARAM_ENUM(x) 			{x,CMD_PAR_ENUM,   {},           {
+#define PARAM_ENUM_SEL(x, y)		{x, y},
+#define PARAM_ENUM_DEFAULT(def)		}, def},
+#define PARAM_BOOL(x,yesd,nod,def)	{x, CMD_PAR_ENUM,  {}, {{"y",yesd},{"n",nod}},def}
+#define THE_FUNC(x)			}, &x}, 
+#define END_OF_LANG	{NULL,NULL}
+
+char *get_prompt (void); /* this function not from the lib ! */
+
+void cli_debug_dump_args (char* title, int argc, char** argv);
+
+void cli_register_language (const CMD_DSCR_T* cmd_list);
+void usage (void);
+int cli_execute_command (const char* line);
+void rl_read_cli (void);
+void rl_init (void);
+void rl_shutdown (void);
+char* UT_sprint_time_stamp (void);
+
+#endif /* _CLI_API__ */
+
diff -rbBNu bridge-utils/libbridge/if_index.c bridge-utils.cli/libbridge/if_index.c
--- bridge-utils/libbridge/if_index.c	Fri Jun 22 22:59:03 2001
+++ bridge-utils.cli/libbridge/if_index.c	Wed Jan  9 14:36:21 2002
@@ -212,7 +212,7 @@
      list.  This ioctl is not present in kernels before version 2.1.50.  */
   struct ifreq ifr;
   int fd;
-  static int siocgifname_works_not;
+  static int siocgifname_works_not = 0; /* Alex: I had to fix it for brdlg */
 
   if (!siocgifname_works_not)
     {
