From 8bd3d51b23e328e91c209dbebe8cfe002b0b0042 Mon Sep 17 00:00:00 2001 From: laforge Date: Tue, 12 Sep 2006 17:37:00 +0000 Subject: move to new directory git-svn-id: https://svn.openpcd.org:2342/trunk@193 6dc7ffe9-61d6-0310-9af1-9938baff3ed1 --- host/Makefile | 24 + host/ausb/Makefile | 21 + host/ausb/ausb.c | 331 +++ host/ausb/ausb.h | 68 + host/ausb/ausb_test.c | 95 + host/ausb/usb.c | 86 + host/ausb/usb.h | 8 + host/benchmark-20060824.txt | 55 + host/opcd_sh.c | 495 +++++ host/opcd_test.c | 199 ++ host/opcd_usb.c | 235 +++ host/opcd_usb.h | 24 + host/zebvty/Makefile | 19 + host/zebvty/buffer.c | 460 ++++ host/zebvty/buffer.h | 100 + host/zebvty/command.c | 3384 ++++++++++++++++++++++++++++++ host/zebvty/command.h | 351 ++++ host/zebvty/vector.c | 186 ++ host/zebvty/vector.h | 62 + host/zebvty/vty.c | 1515 +++++++++++++ host/zebvty/vty.h | 118 ++ host/zebvty/zebvty.h | 5 + openpcd/opcd_test/Makefile | 24 - openpcd/opcd_test/ausb/Makefile | 21 - openpcd/opcd_test/ausb/ausb.c | 331 --- openpcd/opcd_test/ausb/ausb.h | 68 - openpcd/opcd_test/ausb/ausb_test.c | 95 - openpcd/opcd_test/ausb/usb.c | 86 - openpcd/opcd_test/ausb/usb.h | 8 - openpcd/opcd_test/benchmark-20060824.txt | 55 - openpcd/opcd_test/opcd_sh.c | 495 ----- openpcd/opcd_test/opcd_test.c | 199 -- openpcd/opcd_test/opcd_usb.c | 235 --- openpcd/opcd_test/opcd_usb.h | 24 - openpcd/opcd_test/zebvty/Makefile | 19 - openpcd/opcd_test/zebvty/buffer.c | 460 ---- openpcd/opcd_test/zebvty/buffer.h | 100 - openpcd/opcd_test/zebvty/command.c | 3384 ------------------------------ openpcd/opcd_test/zebvty/command.h | 351 ---- openpcd/opcd_test/zebvty/vector.c | 186 -- openpcd/opcd_test/zebvty/vector.h | 62 - openpcd/opcd_test/zebvty/vty.c | 1515 ------------- openpcd/opcd_test/zebvty/vty.h | 118 -- openpcd/opcd_test/zebvty/zebvty.h | 5 - 44 files changed, 7841 insertions(+), 7841 deletions(-) create mode 100644 host/Makefile create mode 100644 host/ausb/Makefile create mode 100644 host/ausb/ausb.c create mode 100644 host/ausb/ausb.h create mode 100644 host/ausb/ausb_test.c create mode 100644 host/ausb/usb.c create mode 100644 host/ausb/usb.h create mode 100644 host/benchmark-20060824.txt create mode 100644 host/opcd_sh.c create mode 100644 host/opcd_test.c create mode 100644 host/opcd_usb.c create mode 100644 host/opcd_usb.h create mode 100644 host/zebvty/Makefile create mode 100644 host/zebvty/buffer.c create mode 100644 host/zebvty/buffer.h create mode 100644 host/zebvty/command.c create mode 100644 host/zebvty/command.h create mode 100644 host/zebvty/vector.c create mode 100644 host/zebvty/vector.h create mode 100644 host/zebvty/vty.c create mode 100644 host/zebvty/vty.h create mode 100644 host/zebvty/zebvty.h delete mode 100644 openpcd/opcd_test/Makefile delete mode 100644 openpcd/opcd_test/ausb/Makefile delete mode 100644 openpcd/opcd_test/ausb/ausb.c delete mode 100644 openpcd/opcd_test/ausb/ausb.h delete mode 100644 openpcd/opcd_test/ausb/ausb_test.c delete mode 100644 openpcd/opcd_test/ausb/usb.c delete mode 100644 openpcd/opcd_test/ausb/usb.h delete mode 100644 openpcd/opcd_test/benchmark-20060824.txt delete mode 100644 openpcd/opcd_test/opcd_sh.c delete mode 100644 openpcd/opcd_test/opcd_test.c delete mode 100644 openpcd/opcd_test/opcd_usb.c delete mode 100644 openpcd/opcd_test/opcd_usb.h delete mode 100644 openpcd/opcd_test/zebvty/Makefile delete mode 100644 openpcd/opcd_test/zebvty/buffer.c delete mode 100644 openpcd/opcd_test/zebvty/buffer.h delete mode 100644 openpcd/opcd_test/zebvty/command.c delete mode 100644 openpcd/opcd_test/zebvty/command.h delete mode 100644 openpcd/opcd_test/zebvty/vector.c delete mode 100644 openpcd/opcd_test/zebvty/vector.h delete mode 100644 openpcd/opcd_test/zebvty/vty.c delete mode 100644 openpcd/opcd_test/zebvty/vty.h delete mode 100644 openpcd/opcd_test/zebvty/zebvty.h diff --git a/host/Makefile b/host/Makefile new file mode 100644 index 0000000..12edce0 --- /dev/null +++ b/host/Makefile @@ -0,0 +1,24 @@ +#!/usr/bin/make +LDFLAGS=-lusb -lcrypt #-lzebvty -Lzebvty/ +CFLAGS=-Wall + +all: opcd_test opcd_sh + +clean: + -rm -f *.o opcd_test + $(MAKE) -C ausb clean + +ausb/libausb.a: + $(MAKE) -C ausb libausb.a + +opcd_test: opcd_test.o opcd_usb.o ausb/libausb.a + $(CC) $(LDFLAGS) -o $@ $^ + +opcd_sh: opcd_sh.o opcd_usb.o ausb/libausb.a zebvty/libzebvty.a + $(CC) $(LDFLAGS) -o $@ $^ + + +%.o: %.c + $(CC) $(CFLAGS) -o $@ -c $< + +.PHONEY: all clean diff --git a/host/ausb/Makefile b/host/ausb/Makefile new file mode 100644 index 0000000..6269739 --- /dev/null +++ b/host/ausb/Makefile @@ -0,0 +1,21 @@ +#include ../../makevars + +OBJS=ausb.o usb.o +CFLAGS+=-fPIC + +all: libausb.a libausb.so + +libausb.a: $(OBJS) + $(AR) r $@ $^ + +libausb.so: $(OBJS) + $(LD) -x --shared -o $@ $^ + +%.o: %.c + $(CC) $(CFLAGS) -o $@ -c $^ + +ausb_test: ausb_test.o ausb.o + $(CC) $(CFLAGS) -lusb -o $@ $^ + +clean: + @rm -f *.o ausb_test libusb.a libausb.a libausb.so diff --git a/host/ausb/ausb.c b/host/ausb/ausb.c new file mode 100644 index 0000000..8b0117f --- /dev/null +++ b/host/ausb/ausb.c @@ -0,0 +1,331 @@ +/* Wrapper/Extension code to libusb-0.1 to support asynchronous requests + * on Linux platforns + * + * (C) 2004-2005 by Harald Welte + * + * Distributed and licensed under the terms of GNU LGPL, Version 2.1 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ausb.h" +#include "usb.h" + +#ifdef DEBUG_AUSB +#define DEBUGP(x, args...) fprintf(stderr, "%s:%s():%u " x, __FILE__, \ + __FUNCTION__, __LINE__, ## args) +#else +#define DEBUGP(x, args...); +#endif + +#define SIGAUSB (SIGRTMIN+1) + +static int ausb_get_fd(ausb_dev_handle *ah) +{ + return *((int *)ah->uh); +} + + +static int kernel_2_5; + +/* FIXME: this has to go */ +static struct ausb_dev_handle *last_handle = NULL; + +static int is_kernel_2_5() +{ + struct utsname uts; + int ret; + + uname(&uts); + + ret = (strncmp(uts.release, "2.5.", 4) == 0) || + (strncmp(uts.release, "2.6.", 4) == 0); + + return ret; +} + +void ausb_dump_urb(struct usbdevfs_urb *uurb) +{ + DEBUGP("urb(%p): type=%u, endpoint=0x%x, status=%d, flags=0x%x, number_of_packets=%d, error_count=%d\n", uurb, uurb->type, uurb->endpoint, uurb->status, uurb->flags, uurb->number_of_packets, uurb->error_count); +} + +void ausb_fill_int_urb(struct usbdevfs_urb *uurb, unsigned char endpoint, + void *buffer, int buffer_length) + +{ + uurb->type = kernel_2_5 ? USBDEVFS_URB_TYPE_INTERRUPT : USBDEVFS_URB_TYPE_BULK; + uurb->endpoint = endpoint; /* | USB_DIR_IN; */ + uurb->flags = kernel_2_5 ? 0 : 1 ; /* USBDEVFS_URB_QUEUE_BULK; */ + uurb->buffer = buffer; + uurb->buffer_length = buffer_length; + uurb->signr = SIGAUSB; + uurb->start_frame = -1; +} + +int ausb_submit_urb(ausb_dev_handle *ah, struct usbdevfs_urb *uurb) +{ + int ret; + + DEBUGP("ah=%p\n", ah); + ausb_dump_urb(uurb); + + /* save ausb_dev_handle in opaque usercontext field */ + uurb->usercontext = ah; + + do { + ret = ioctl(ausb_get_fd(ah), USBDEVFS_SUBMITURB, uurb); + } while (ret < 0 && errno == EINTR); + + return ret; +} + +int ausb_discard_urb(ausb_dev_handle *ah, struct usbdevfs_urb *uurb) +{ + int ret; + + DEBUGP("ah=%p, uurb=%p\n"); + ausb_dump_urb(uurb); + + do { + ret = ioctl(ausb_get_fd(ah), USBDEVFS_DISCARDURB, uurb); + } while (ret < 0 && errno == EINTR); + + return ret; +} + +struct usbdevfs_urb *ausb_get_urb(ausb_dev_handle *ah) +{ + int ret; + struct usbdevfs_urb *uurb; + + DEBUGP("entering\n"); + + do { + ret = ioctl(ausb_get_fd(ah), USBDEVFS_REAPURBNDELAY, &uurb); + } while (ret < 0 && errno == EINTR); + + if (ret < 0 && errno == EAGAIN) { + DEBUGP("ioctl returned %d (errno=%s)\n", ret, + strerror(errno)); + return NULL; + } + + DEBUGP("returning %p\n", uurb); + return uurb; +} + +static void handle_urb(struct usbdevfs_urb *uurb) +{ + struct ausb_dev_handle *ah = uurb->usercontext; + + DEBUGP("called, ah=%p\n", ah); + + if (uurb->type >= AUSB_USBDEVFS_URB_TYPES) { + DEBUGP("unknown uurb type %u\n", uurb->type); + return; + } + + if (!ah) { + DEBUGP("cant't call handler because missing ah ptr\n"); + return; + } + + if (!ah->cb[uurb->type].handler) { + DEBUGP("received URB type %u, but no handler\n", uurb->type); + return; + } + ah->cb[uurb->type].handler(uurb, ah->cb[uurb->type].userdata); +} + +static void sigact_rtmin(int sig, siginfo_t *siginfo, void *v) +{ + int count; + struct usbdevfs_urb *urb; + + if (sig != SIGAUSB) + return; + + //DEBUGP("errno=%d, si_addr=%p\n", siginfo->errno, siginfo->si_addr); + + DEBUGP("last_handle=%p\n", last_handle); + + if (!last_handle) + return; + + for (count = 0; ; count++) { + urb = ausb_get_urb(last_handle); + + if (urb == NULL) { + DEBUGP("ausb_get_urb() returned urb==NULL\n"); + break; + } + + DEBUGP("calling handle_urb(%p)\n", urb); + handle_urb(urb); + } +} + + +int ausb_init(void) +{ + struct sigaction act; + + DEBUGP("entering\n"); + + memset(&act, 0, sizeof(act)); + act.sa_sigaction = sigact_rtmin; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_SIGINFO; + + sigaction(SIGAUSB, &act, NULL); + + kernel_2_5 = is_kernel_2_5(); + + DEBUGP("kernel 2.5+ = %d\n", kernel_2_5); + + usb_init(); + usb_find_busses(); + usb_find_devices(); + return 1; +} + +ausb_dev_handle *ausb_open(struct usb_device *dev) +{ + ausb_dev_handle *dh = malloc(sizeof *dh); + + DEBUGP("entering, dh=%p\n", dh); + + memset(dh, 0, sizeof(*dh)); + + dh->uh = usb_open(dev); + + if (!dh->uh) { + DEBUGP("usb_open() failed\n"); + free(dh); + return NULL; + } + + last_handle = dh; + DEBUGP("last_handle = %p\n", last_handle); + + return dh; +} + +int ausb_register_callback(ausb_dev_handle *ah, unsigned char type, + void (*callback)(struct usbdevfs_urb *uurb, + void *userdata), + void *userdata) +{ + DEBUGP("registering callback for type %u:%p\n", type, callback); + + if (type >= AUSB_USBDEVFS_URB_TYPES) { + errno = EINVAL; + return -1; + } + + if (!kernel_2_5 && type == USBDEVFS_URB_TYPE_INTERRUPT) + type = USBDEVFS_URB_TYPE_BULK; + + ah->cb[type].handler = callback; + ah->cb[type].userdata = userdata; + + return 0; +} + +int ausb_claim_interface(ausb_dev_handle *ah, int interface) +{ + DEBUGP("entering\n"); + return usb_claim_interface(ah->uh, interface); +} + +int ausb_release_interface(ausb_dev_handle *ah, int interface) +{ + DEBUGP("entering\n"); + /* what the hell? */ + if (ah == last_handle) + last_handle = NULL; + return usb_release_interface(ah->uh, interface); +} + +int ausb_set_configuration(ausb_dev_handle *ah, int configuration) +{ + DEBUGP("entering\n"); + return usb_set_configuration(ah->uh, configuration); +} + +int ausb_bulk_write(ausb_dev_handle *ah, int ep, char *bytes, int size, int timeout) +{ + DEBUGP("entering (ah=%p, ep=0x%x, bytes=%p, size=%d, timeout=%d\n", + ah, ep, bytes, size, timeout); + return __usb_bulk_write(ah->uh, ep, bytes, size, timeout); +} + +int ausb_bulk_read(ausb_dev_handle *ah, int ep, char *bytes, int size, int timeout) +{ + DEBUGP("entering (ah=%p, ep=0x%x, bytes=%p, size=%d, timeout=%d\n", + ah, ep, bytes, size, timeout); + return __usb_bulk_read(ah->uh, ep, bytes, size, timeout); +} + +int ausb_clear_halt(ausb_dev_handle *ah, unsigned int ep) +{ + DEBUGP("entering (ah=%p, ep=0x%x)\n", ah, ep); + return usb_clear_halt(ah->uh, ep); +} + +int ausb_reset(ausb_dev_handle *ah) +{ + DEBUGP("entering (ah=%p)\n", ah); + return usb_reset(ah->uh); +} + +int ausb_resetep(ausb_dev_handle *ah, int ep) +{ + DEBUGP("entering (ah=%pm ep=0x%x)\n", ah, ep); + return usb_resetep(ah->uh, ep); +} + +#ifdef LIBUSB_HAS_GET_DRIVER_NP +int ausb_get_driver_np(ausb_dev_handle *ah, int interface, char *name, + unsigned int namelen) +{ + DEBUGP("entering\n"); + return usb_get_driver_np(ah->uh, interface, name, namelen); +} +#endif + +#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP +int ausb_detach_kernel_driver_np(ausb_dev_handle *ah, int interface) +{ + DEBUGP("entering\n"); + return usb_detach_kernel_driver_np(ah->uh, interface); +} +int ausb_reattach_kernel_driver_np(ausb_dev_handle *ah, int interface) +{ + DEBUGP("entering\n"); + return __usb_reattach_kernel_driver_np(ah->uh, interface); +} +#endif + +int ausb_close(struct ausb_dev_handle *ah) +{ + DEBUGP("entering\n"); + + if (ah == last_handle) + last_handle = NULL; + + return usb_close(ah->uh); +} + +void ausb_fini(void) +{ + DEBUGP("entering\n"); + sigaction(SIGAUSB, NULL, NULL); +} diff --git a/host/ausb/ausb.h b/host/ausb/ausb.h new file mode 100644 index 0000000..4d62cac --- /dev/null +++ b/host/ausb/ausb.h @@ -0,0 +1,68 @@ +#ifndef _AUSB_H +#define _AUSB_H + +/* Wrapper/Extension code to libusb-0.1 to support asynchronous requests + * on Linux platforns + * + * (C) 2004 by Harald Welte + * + * Distributed under the terms of GNU LGPL, Version 2.1 + */ + + +#include +#include + +#define AUSB_USBDEVFS_URB_TYPES 4 + +/* structures */ +struct ausb_callback { + void (*handler)(struct usbdevfs_urb *uurb, void *userdata); + void *userdata; +}; + +struct ausb_dev_handle { + usb_dev_handle *uh; + struct ausb_callback cb[AUSB_USBDEVFS_URB_TYPES]; +}; + +typedef struct ausb_dev_handle ausb_dev_handle; + +/* intitialization */ +int ausb_init(void); +ausb_dev_handle *ausb_open(struct usb_device *dev); +int ausb_close(ausb_dev_handle *ah); +int ausb_register_callback(ausb_dev_handle *ah, unsigned char type, + void (*callback)(struct usbdevfs_urb *uurb, + void *userdata), + void *userdata); + +/* asynchronous URB related functions */ +void ausb_dump_urb(struct usbdevfs_urb *uurb); +void ausb_fill_int_urb(struct usbdevfs_urb *uurb, unsigned char endpoint, + void *buffer, int buffer_length); +int ausb_submit_urb(ausb_dev_handle *ah, struct usbdevfs_urb *uurb); +int ausb_discard_urb(ausb_dev_handle *ah, struct usbdevfs_urb *uurb); +struct usbdevfs_urb *ausb_get_urb(ausb_dev_handle *ah); + +/* synchronous functions, mostly wrappers for libusb */ +int ausb_claim_interface(ausb_dev_handle *ah, int interface); +int ausb_release_interface(ausb_dev_handle *ah, int interface); +int ausb_set_configuration(ausb_dev_handle *dev, int configuration); +int ausb_clear_halt(ausb_dev_handle *dev, unsigned int ep); +int ausb_reset(ausb_dev_handle *dev); +int ausb_resetep(ausb_dev_handle *dev, int ep); +int ausb_bulk_write(ausb_dev_handle *ah, int ep, char *bytes, int size, + int timeout); +int ausb_bulk_read(ausb_dev_handle *ah, int ep, char *bytes, int size, + int timeout); +#ifdef LIBUSB_HAS_GET_DRIVER_NP +int ausb_get_driver_np(ausb_dev_handle *ah, int interface, char *name, + unsigned int namelen); +#endif +#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP +int ausb_detach_kernel_driver_np(ausb_dev_handle *dev, int interface); +int ausb_reattach_kernel_driver_np(ausb_dev_handle *dev, int interface); +#endif + +#endif /* _AUSB_H */ diff --git a/host/ausb/ausb_test.c b/host/ausb/ausb_test.c new file mode 100644 index 0000000..f7bfdee --- /dev/null +++ b/host/ausb/ausb_test.c @@ -0,0 +1,95 @@ +#include +#include +#include +#include + +#include "ausb.h" + +#define CJPPA_USB_VENDOR_ID 0x0c4b +#define CJPPA_USB_DEVICE_ID 0x0100 + +static struct usb_device *find_cj_usbdev(int num) +{ + struct usb_bus *busses, *bus; + struct usb_device *dev; + int found = 0; + + busses = usb_get_busses(); + + for (bus = busses; bus; bus = bus->next) { + for (dev = bus->devices; dev; dev = dev->next) { + if (dev->descriptor.idVendor == CJPPA_USB_VENDOR_ID && + dev->descriptor.idProduct == CJPPA_USB_DEVICE_ID) { + found++; + if (found == num) + return dev; + } + } + } + return NULL; +} + +static void int_cb(struct usbdevfs_urb *uurb) +{ + struct ausb_dev_handle *ah = uurb->usercontext; + + fprintf(stdout, __FUNCTION__ " called, "); + + ausb_dump_urb(uurb); + + if (ausb_submit_urb(ah, uurb)) + fprintf(stderr, "unable to resubmit urb\n"); +} + +int main(int argc, char **argv) +{ + struct usb_device *dev; + struct ausb_dev_handle *ah; + struct usbdevfs_urb *uurb; + char buffer[280]; + ausb_init(); + + uurb = malloc(sizeof(*uurb)); + + dev = find_cj_usbdev(1); + + if (!dev) { + fprintf(stderr, "unable to find matching usb device\n"); + exit(1); + } + + ah = ausb_open(dev); + if (!ah) { + fprintf(stderr, "error while opening usb device\n"); + exit(1); + } + + if (ausb_claim_interface(ah, 0)) { + fprintf(stderr, "unable to claim interface\n"); + ausb_close(ah); + exit(1); + } + + if (usb_set_configuration(ah->uh, 1)) { + fprintf(stderr, "unable to set configuration 1\n"); + ausb_close(ah); + exit(1); + } + +#if 1 + ausb_fill_int_urb(uurb, 0x81, buffer, sizeof(buffer)); + if (ausb_submit_urb(ah, uurb)) { + fprintf(stderr, "unable to submit urb\n"); + ausb_close(ah); + exit(1); + } + + while (1) { + sleep(10); + } +#endif + + ausb_close(ah); + + exit(0); +} diff --git a/host/ausb/usb.c b/host/ausb/usb.c new file mode 100644 index 0000000..1f1078d --- /dev/null +++ b/host/ausb/usb.c @@ -0,0 +1,86 @@ +#include +#include +#include +#include +#include +#include +#include + +#define MAX_READ_WRITE 4096 + +#define USB_ERROR_STR(ret, x, args...) return ret + +static int usb_get_fd(usb_dev_handle *uh) +{ + return *((int *)uh); +} + +int __usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int length, + int timeout) +{ + struct usbdevfs_bulktransfer bulk; + int ret, sent = 0; + + /* Ensure the endpoint address is correct */ + ep &= ~USB_ENDPOINT_IN; + + do { + bulk.ep = ep; + bulk.len = length - sent; + if (bulk.len > MAX_READ_WRITE) + bulk.len = MAX_READ_WRITE; + bulk.timeout = timeout; + bulk.data = (unsigned char *)bytes + sent; + + ret = ioctl(usb_get_fd(dev), USBDEVFS_BULK, &bulk); + if (ret < 0) + USB_ERROR_STR(ret, + "error writing to bulk endpoint %d: %s", + ep, strerror(errno)); + + sent += ret; + } while (ret > 0 && sent < length); + + return sent; +} + +int __usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size, + int timeout) +{ + struct usbdevfs_bulktransfer bulk; + int ret, retrieved = 0, requested; + + /* Ensure the endpoint address is correct */ + ep |= USB_ENDPOINT_IN; + + do { + bulk.ep = ep; + requested = size - retrieved; + if (requested > MAX_READ_WRITE) + requested = MAX_READ_WRITE; + bulk.len = requested; + bulk.timeout = timeout; + bulk.data = (unsigned char *)bytes + retrieved; + + ret = ioctl(usb_get_fd(dev), USBDEVFS_BULK, &bulk); + if (ret < 0) + USB_ERROR_STR(ret, + "error reading from bulk endpoint 0x%x: %s", + ep, strerror(errno)); + + retrieved += ret; + } while (ret > 0 && retrieved < size && ret == requested); + + return retrieved; +} + +int __usb_reattach_kernel_driver_np(usb_dev_handle *dev, int interface) +{ + struct usbdevfs_ioctl command; + + command.ifno = interface; + command.ioctl_code = USBDEVFS_CONNECT; + command.data = NULL; + + return ioctl(usb_get_fd(dev), USBDEVFS_IOCTL, &command); +} diff --git a/host/ausb/usb.h b/host/ausb/usb.h new file mode 100644 index 0000000..66be0ee --- /dev/null +++ b/host/ausb/usb.h @@ -0,0 +1,8 @@ +#ifndef _AUSB_USB_H +#define _AUSB_USB_H +int __usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int length, + int timeout); +int __usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int length, + int timeout); +int __usb_reattach_kernel_driver_np(usb_dev_handle *dev, int interface); +#endif diff --git a/host/benchmark-20060824.txt b/host/benchmark-20060824.txt new file mode 100644 index 0000000..9cf2c44 --- /dev/null +++ b/host/benchmark-20060824.txt @@ -0,0 +1,55 @@ +laforge@rama%pts/8 (1:27) kommerz/bitmanufaktur/openpcd/opcd_test > for f in 1 2 4 8 16 32 64 128 255; do ./opcd_test -u $f; done +opcd_test - OpenPCD Test and Debug Program +(C) 2006 by Harald Welte + +starting DATA IN performance test (1 frames of 64 bytes) +TX: (4): f1 00 ff 01 +255 transfers (total 16320 bytes) in 508 miliseconds => 32125 bytes/sec +opcd_test - OpenPCD Test and Debug Program +(C) 2006 by Harald Welte + +starting DATA IN performance test (2 frames of 64 bytes) +TX: (4): f1 00 ff 02 +255 transfers (total 32640 bytes) in 510 miliseconds => 64000 bytes/sec +opcd_test - OpenPCD Test and Debug Program +(C) 2006 by Harald Welte + +starting DATA IN performance test (4 frames of 64 bytes) +TX: (4): f1 00 ff 04 +255 transfers (total 65280 bytes) in 508 miliseconds => 128503 bytes/sec +opcd_test - OpenPCD Test and Debug Program +(C) 2006 by Harald Welte + +starting DATA IN performance test (8 frames of 64 bytes) +TX: (4): f1 00 ff 08 +255 transfers (total 130560 bytes) in 510 miliseconds => 256000 bytes/sec +opcd_test - OpenPCD Test and Debug Program +(C) 2006 by Harald Welte + +starting DATA IN performance test (16 frames of 64 bytes) +TX: (4): f1 00 ff 10 +255 transfers (total 261120 bytes) in 764 miliseconds => 341780 bytes/sec +opcd_test - OpenPCD Test and Debug Program +(C) 2006 by Harald Welte + +starting DATA IN performance test (32 frames of 64 bytes) +TX: (4): f1 00 ff 20 +255 transfers (total 522240 bytes) in 1018 miliseconds => 513005 bytes/sec +opcd_test - OpenPCD Test and Debug Program +(C) 2006 by Harald Welte + +starting DATA IN performance test (64 frames of 64 bytes) +TX: (4): f1 00 ff 40 +255 transfers (total 1044480 bytes) in 2038 miliseconds => 512502 bytes/sec +opcd_test - OpenPCD Test and Debug Program +(C) 2006 by Harald Welte + +starting DATA IN performance test (128 frames of 64 bytes) +TX: (4): f1 00 ff 80 +255 transfers (total 2088960 bytes) in 3568 miliseconds => 585470 bytes/sec +opcd_test - OpenPCD Test and Debug Program +(C) 2006 by Harald Welte + +starting DATA IN performance test (255 frames of 64 bytes) +TX: (4): f1 00 ff ff +255 transfers (total 4161600 bytes) in 6119 miliseconds => 680111 bytes/sec diff --git a/host/opcd_sh.c b/host/opcd_sh.c new file mode 100644 index 0000000..c9b38b4 --- /dev/null +++ b/host/opcd_sh.c @@ -0,0 +1,495 @@ +#include +#include +#include +#include +#include + +#include "zebvty/vty.h" +#include "zebvty/command.h" + +#define MAX_BUFFER_SIZE 2048 +#define MAX_LENC MAX_BUFFER_SIZE +#define MAX_LENR MAX_LENC +#define MAX_COMMAND_SIZE 2048 + +static void strcompact(char *str) +{ + int i, j = 0; + + for (i = 0; i < strlen(str); i++) { + if (!isspace(str[i])) + str[j++] = tolower(str[i]); + } + str[j] = 0; +} + +static int strtobin(char *s, unsigned char *d, unsigned int *len) +{ + long l; + int i, ret; + + if (*s == ':') + s++; + + for (i = 0; i < (strlen(s) >> 1); i++) { + if (i >= MAX_LENC || i >> *len) + return 0; + ret = sscanf(s + (i << 1), "%2lx", &l); + if (ret != 1) + return 0; + d[i] = l & 0xff; + } + *len = i; + + return 1; +} + +DEFUN(rc632_reg_read, + rc632_reg_read_cmd, + "reg_read WORD", + "Read register of RC632\n") +{ +#if 0 + if (send_hex_command(vty, argv[0]) < 0) + return CMD_ERR_NO_MATCH; +#endif + return CMD_SUCCESS; +} + + +#if 0 +static int select_file(struct vty *v, int absolute, int path, + char *selector, unsigned int sellen, + unsigned char *rsp, unsigned int *rlen) +{ + unsigned char cmd[MAX_LENC]; + + cmd[0] = 0x00; + cmd[1] = 0xa4; + if (absolute) { + if (path) + cmd[2] = 0x08; + else + cmd[2] = 0x00; + } else { + if (path) + cmd[2] = 0x09; + else + cmd[2] = 0x02; + } + cmd[3] = 0x00; // FIXME: other templates + + cmd[4] = sellen & 0xff; + + memcpy(cmd[5], selector, sellen); + cmd[5+sellen] = 0x00; + + send_apdu(hCard, v, cmd, 5+cmd[4], rsp, rlen); + parse_selectfile_response(hCard, v, rsp, *rlen); + return CMD_SUCCESS; + +} + +DEFUN(send_7816_select_file_absolute_fid, + send_7816_select_file_absolute_fid_cmd, + "select file absolute fid WORD", + "Selects a file on the ICC\n") +{ + char *file = argv[0]; + unsigned char rsp[MAX_LENR]; + unsigned int lenr = MAX_LENR; + unsigned char selector[255]; + unsigned int sellen = 255; + + if (strtobin(file, selector, &sellen) < 0) + return CMD_ERR_NO_MATCH; + + return select_file(vty, 1, 0, selector, sellen, rsp, &lenr); +} + +DEFUN(send_7816_select_file_absolute_path, + send_7816_select_file_absolute_path_cmd, + "select file absolute path WORD", + "Selects a file on the ICC\n") +{ + char *file = argv[0]; + unsigned char rsp[MAX_LENR]; + unsigned int lenr = MAX_LENR; + unsigned char selector[255]; + unsigned int sellen = 255; + + if (strtobin(file, selector, &sellen) < 0) + return CMD_ERR_NO_MATCH; + + + return select_file(vty, 1, 1, selector, sellen, rsp, &lenr); +} + +DEFUN(send_7816_select_file_relative_fid, + send_7816_select_file_relative_fid_cmd, + "select file absolute fid WORD", + "Selects a file on the ICC\n") +{ + char *file = argv[0]; + unsigned char rsp[MAX_LENR]; + unsigned int lenr = MAX_LENR; + unsigned char selector[255]; + unsigned int sellen = 255; + + if (strtobin(file, selector, &sellen) < 0) + return CMD_ERR_NO_MATCH; + + + return select_file(vty, 0, 0, selector, sellen, rsp, &lenr); +} + + +DEFUN(send_7816_select_file_relative_path, + send_7816_select_file_relative_path_cmd, + "select file relative path WORD", + "Selects a file on the ICC\n") +{ + char *file = argv[0]; + unsigned char rsp[MAX_LENR]; + unsigned int lenr = MAX_LENR; + unsigned char selector[255]; + unsigned int sellen = 255; + + if (strtobin(file, selector, &sellen) < 0) + return CMD_ERR_NO_MATCH; + + + return select_file(vty, 0, 1, selector, sellen, rsp, &lenr); +} + +DEFUN(send_7816_select_dir, + send_7816_select_dir_cmd, + "select directory (MF|PARENT|CHILD) (FID|AID)", + "Selects a directory on the ICC\n") +{ + char *file = argv[1]; + char *type = argv[0]; + char cmd[22]; + char rsp[MAX_LENR]; + int len, lenr = MAX_LENR; + int empty = 0; + + if (!type) + return CMD_ERR_NO_MATCH; + + memset(cmd, 0, sizeof(cmd)); + cmd[1] = 0xa4; + + if (!strcmp(type, "MF")) { + cmd[2] = 0x00; + cmd[3] = 0x00; + cmd[4] = 2; /* length */ + cmd[5] = 0x3f; /* 3ff0 */ + cmd[6] = 0xf0; + empty = 1; + } else if (!strcmp(type, "PARENT")) { + cmd[2] = 0x03; + cmd[3] = 0x00; + cmd[4] = 0x00; + empty = 1; + } else if (!strcmp(file, "CHILD")) { + cmd[2] = 0x01; + cmd[3] = 0x00; + } else { + cmd[2] = 0x00; + cmd[3] = 0x00; + } + + if (!empty) { + len = 16; + /* convert hex string of identifier to bytecode */ + strtobin(file, &cmd[5], &len); + cmd[4] = len & 0xff; + } + send_apdu(hCard, vty, cmd, 5+cmd[4], rsp, &lenr); + parse_selectfile_response(hCard, vty, rsp, lenr); + return CMD_SUCCESS; +} + +DEFUN(send_7816_ls, + send_7816_ls_cmd, + "ls", + "Tries to list all files on a 7816-4 compliant ICC\n") +{ + return CMD_SUCCESS; +} + +DEFUN(send_7816_tree, + send_7816_tree_cmd, + "tree", + "Tries to list a full DF hiararchy tree on a 7816-4 compliant ICC\n") +{ + + return CMD_SUCCESS; +} + +DEFUN(send_7816_read_binary, + send_7816_read_binary_cmd, + "read binary OFFSET LENGTH", + "Read bytes form a previously selected EF\n") +{ + unsigned char cmd[] = { 0x00, 0xb0, 0x00, 0x00, 0x00 }; + unsigned char rsp[MAX_LENR]; // FIXME + unsigned int lenr = MAX_LENR; + + unsigned long datalen; + unsigned long offset; + + offset = strtoul(argv[0], NULL, 0); + if (offset == ULONG_MAX || offset > 0xffff) + return CMD_ERR_NO_MATCH; + + datalen = strtoul(argv[1], NULL, 0); + if (datalen == ULONG_MAX || datalen > 0xff) + return CMD_ERR_NO_MATCH; + + cmd[2] = (offset >> 8) & 0xff; + cmd[3] = offset & 0xff; + cmd[4] = datalen & 0xff; + + send_apdu(hCard, vty, cmd, 5+cmd[4], rsp, &lenr); + if (lenr < 2) + return CMD_SUCCESS; // FIXME + + parse_sw(vty, rsp[lenr-2], rsp[lenr-1]); + + return CMD_SUCCESS; +} + +DEFUN(send_7816_write_binary, + send_7816_write_binary_cmd, + "write binary OFFSET LENGTH DATA", + "Write bytes to a previously selected EF\n") +{ + unsigned char cmd[MAX_LENC]; + unsigned char rsp[MAX_LENR]; + unsigned int lenr; + + unsigned long datalen; + unsigned long offset; + + offset = strtoul(argv[0], NULL, 0); + if (offset == ULONG_MAX || offset > 0xffff) + return CMD_ERR_NO_MATCH; + + datalen = strtoul(argv[1], NULL, 0); + if (datalen == ULONG_MAX || datalen > 0xff) + return CMD_ERR_NO_MATCH; + + memset(cmd, 0, sizeof(cmd)); + + cmd[1] = 0xd0; + cmd[2] = (offset >> 8) & 0xff; + cmd[3] = offset & 0xff; + + if (!strtobin(argv[2], cmd+5, &datalen)) { + vty_out(vty, "command decoding error%s", vty_newline(vty)); + return -1; + } + + cmd[4] = datalen & 0xff; + + send_apdu(hCard, vty, cmd, 5+cmd[4], rsp, &lenr); + if (lenr < 2) + return CMD_SUCCESS; // FIXME + + parse_sw(vty, rsp[lenr-2], rsp[lenr-1]); + + return CMD_SUCCESS; + + return CMD_SUCCESS; +} + +DEFUN(send_7816_update_binary, + send_7816_update_binary_cmd, + "update binary OFFSET LENGTH DATA", + "Update bytes of a previously selected EF\n") +{ + unsigned char cmd[MAX_LENC]; + unsigned char rsp[MAX_LENR]; + unsigned int lenr; + + unsigned long datalen; + unsigned long offset; + + offset = strtoul(argv[0], NULL, 0); + if (offset == ULONG_MAX || offset > 0xffff) + return CMD_ERR_NO_MATCH; + + datalen = strtoul(argv[1], NULL, 0); + if (datalen == ULONG_MAX || datalen > 0xff) + return CMD_ERR_NO_MATCH; + + memset(cmd, 0, sizeof(cmd)); + + cmd[1] = 0xd6; + cmd[2] = (offset >> 8) & 0xff; + cmd[3] = offset & 0xff; + + if (!strtobin(argv[2], cmd+5, &datalen)) { + vty_out(vty, "command decoding error%s", vty_newline(vty)); + return -1; + } + + cmd[4] = datalen & 0xff; + + send_apdu(hCard, vty, cmd, 5+cmd[4], rsp, &lenr); + if (lenr < 2) + return CMD_SUCCESS; // FIXME + + parse_sw(vty, rsp[lenr-2], rsp[lenr-1]); + + return CMD_SUCCESS; +} + +DEFUN(send_7816_erase_binary, + send_7816_erase_binary_cmd, + "erase binary OFFSET LENGTH", + "Erase bytes of a previously selected EF\n") +{ + unsigned char cmd[8] = { 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; + unsigned char rsp[MAX_LENR]; + unsigned int lenr; + + unsigned long datalen; + unsigned long offset; + + offset = strtoul(argv[0], NULL, 0); + if (offset == ULONG_MAX || offset > 0xffff) + return CMD_ERR_NO_MATCH; + + datalen = strtoul(argv[1], NULL, 0); + if (datalen == ULONG_MAX || (offset+datalen > 0xffff)) + return CMD_ERR_NO_MATCH; + + cmd[2] = (offset >> 8) & 0xff; + cmd[3] = offset & 0xff; + cmd[4] = 0x02; + cmd[5] = ((offset+datalen) >> 8) & 0xff; + cmd[6] = (offset+datalen) & 0xff; + + send_apdu(hCard, vty, cmd, 5+cmd[4], rsp, &lenr); + if (lenr < 2) + return CMD_SUCCESS; // FIXME + + parse_sw(vty, rsp[lenr-2], rsp[lenr-1]); + + return CMD_SUCCESS; +} + +DEFUN(send_7816_get_response, + send_7816_get_response_cmd, + "get response LENGTH", + "Get more data from the ICC\n") +{ + unsigned char cmd[6] = { 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00 }; + unsigned char rsp[MAX_LENR]; + unsigned int lenr = MAX_LENR; + + unsigned long length; + + length = strtoul(argv[0], NULL, 0); + if (length == ULONG_MAX || length > 0xff) + return CMD_ERR_NO_MATCH; + + cmd[5] = length & 0xff; + + send_apdu(hCard, vty, cmd, 6, rsp, &lenr); + if (lenr < 2) + return CMD_SUCCESS; // FIXME + + parse_sw(vty, rsp[lenr-2], rsp[lenr-1]); + + return CMD_SUCCESS; + +} +#endif + +DEFUN(rc632, + rc632_cmd, + "rc632", "Commands related to low-level RC632 access\n") +{ + vty->node = RC632_NODE; + return CMD_SUCCESS; +} + +/* dummy */ +static int send_config_write(struct vty *v) +{ + return CMD_SUCCESS; +} + +struct cmd_node rc632_node = { + RC632_NODE, + "%s(rc632)# ", + 1, +}; + +static int opcdshell_init() +{ + cmd_init(1); + vty_init(); + + install_node(&rc632_node, send_config_write); + + install_element(RC632_NODE, &rc632_reg_read_cmd); + +#if 0 + install_element(RC632_NODE, &send_7816_select_file_absolute_fid_cmd); + install_element(RC632_NODE, &send_7816_select_file_absolute_path_cmd); + install_element(RC632_NODE, &send_7816_select_file_relative_fid_cmd); + install_element(RC632_NODE, &send_7816_select_file_relative_path_cmd); + + install_element(RC632_NODE, &send_7816_select_dir_cmd); + install_element(RC632_NODE, &send_7816_ls_cmd); + install_element(RC632_NODE, &send_7816_tree_cmd); + + install_element(RC632_NODE, &send_7816_read_binary_cmd); + install_element(RC632_NODE, &send_7816_write_binary_cmd); + install_element(RC632_NODE, &send_7816_update_binary_cmd); + install_element(RC632_NODE, &send_7816_erase_binary_cmd); + + install_element(RC632_NODE, &send_7816_get_response_cmd); +#endif + + install_default(RC632_NODE); + + install_element(VIEW_NODE, &rc632_cmd); + + return 0; +} + +static int opcdshell(void) +{ + struct vty *v; + + v = vty_create(0); + if (!v) + return -1; + while (1) { + vty_read(v); + } + return 0; +} + + +/*********************************************************************** + * main program, copied from pcsc-lite 'testpcsc.c' + ***********************************************************************/ + +int main(int argc, char **argv) +{ + opcdshell_init(); + + printf("\nopcd_shell (C) 2006 Harald Welte \n\n"); + + opcdshell(); + + return 0; +} diff --git a/host/opcd_test.c b/host/opcd_test.c new file mode 100644 index 0000000..37f3094 --- /dev/null +++ b/host/opcd_test.c @@ -0,0 +1,199 @@ +/* opcd_test - Low-Level test program for OpenPCD + * (C) 2006 by Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#define _GNU_SOURCE +#include +#include + +#include +#include +#include +#include + +#include + +#include "../firmware/include/openpcd.h" +#include "opcd_usb.h" + +static int get_number(const char *optarg, unsigned int min, + unsigned int max, unsigned int *num) +{ + char *endptr; + unsigned long nbr = strtoul(optarg, &endptr, 0); + //fprintf(stderr, "trying to read `%s' as number\n", optarg); + + if (nbr == 0 && optarg == endptr) + return -EINVAL; + + if (nbr < min || nbr > max) + return -ERANGE; + + *num = nbr; + return 0; +} + +static void print_welcome(void) +{ + printf("opcd_test - OpenPCD Test and Debug Program\n" + "(C) 2006 by Harald Welte \n\n"); +} +static void print_help(void) +{ + printf( "\t-l\t--led-set\tled {0,1}\n" + "\t-w\t--reg-write\treg value\n" + "\t-r\t--reg-read\treg\n" + + "\t-s\t--set-bits\treg\tmask\n" + "\t-c\t--clear-bits\treg\tmask\n"); +} + + +static struct option opts[] = { + { "led-set", 1, 0, 'l' }, + { "reg-write", 1, 0, 'w' }, + { "reg-read", 1, 0, 'r' }, + { "fifo-write", 1, 0, 'W' }, + { "fifo-read", 1, 0, 'R' }, + { "set-bits", 1, 0, 's' }, + { "clear-bits", 1, 0, 'c' }, + { "usb-perf", 1, 0, 'u' }, + { "adc-read", 0, 0, 'a' }, + { "adc-loop", 0, 0, 'A' }, + { "ssc-read", 0, 0, 'S' }, + { "loop", 0, 0, 'L' }, + { "help", 0, 0, 'h'}, +}; + +int main(int argc, char **argv) +{ + struct opcd_handle *od; + int c; + static char buf[8192]; + int buf_len = sizeof(buf); + + print_welcome(); + + od = opcd_init(); + + while (1) { + int option_index = 0; + + c = getopt_long(argc, argv, "l:r:w:R:W:s:c:h?u:aASL", opts, + &option_index); + + if (c == -1) + break; + + switch (c) { + unsigned int i,j; + case 'l': + if (get_number(optarg, 1, 2, &i) < 0) + exit(2); + if (get_number(argv[optind], 0, 1, &j) < 0) + exit(2); + printf("setting LED %d to %s\n", i, j ? "on" : "off"); + opcd_send_command(od, OPENPCD_CMD_SET_LED, i, j, 0, NULL); + break; + case 'r': + if (get_number(optarg, 0x00, OPENPCD_REG_MAX, &i) < 0) + exit(2); + printf("reading register 0x%02x: "); + opcd_send_command(od, OPENPCD_CMD_READ_REG, i, 0, 0, NULL); + opcd_recv_reply(od, buf, buf_len); + break; + case 'w': + if (get_number(optarg, 0x00, OPENPCD_REG_MAX, &i) < 0) { + fprintf(stderr, "can't read register\n"); + exit(2); + } + if (get_number(argv[optind], 0x00, 0xff, &j) < 0) { + fprintf(stderr, "can't read value\n"); + exit(2); + } + fprintf(stdout, "setting register 0x%02x to 0x%02x\n", i, j); + opcd_send_command(od, OPENPCD_CMD_WRITE_REG, i, j, 0, NULL); + break; + case 'R': + if (get_number(optarg, 0x00, OPENPCD_REG_MAX, &i) < 0) + exit(2); + opcd_send_command(od, OPENPCD_CMD_READ_FIFO, 0, i, 0, NULL); + opcd_recv_reply(od, buf, buf_len); + break; + case 'W': + fprintf(stderr, "FIFO write not implemented yet\n"); + break; + case 's': + if (get_number(optarg, 0x00, OPENPCD_REG_MAX, &i) < 0) + exit(2); + if (get_number(argv[optind], 0x00, 0xff, &j) < 0) + exit(2); + opcd_send_command(od, OPENPCD_CMD_REG_BITS_SET, i, j, 0, NULL); + break; + case 'c': + if (get_number(optarg, 0x00, OPENPCD_REG_MAX, &i) < 0) + exit(2); + if (get_number(argv[optind], 0x00, 0xff, &j) < 0) + exit(2); + opcd_send_command(od, OPENPCD_CMD_REG_BITS_CLEAR, i, j, 0, NULL); + break; + case 'u': + if (get_number(optarg, 1, 255, &i) < 0) + exit(2); + opcd_usbperf(od, i); + break; + case 'a': + opcd_send_command(od, OPENPCD_CMD_ADC_READ, 0, 1, 0, NULL); + opcd_recv_reply(od, buf, buf_len); + /* FIXME: interpret and print ADC result */ + break; + case 'A': + while (1) { + opcd_send_command(od, OPENPCD_CMD_ADC_READ, 0, 1, 0, NULL); + opcd_recv_reply(od, buf, buf_len); + /* FIXME: interpret and print ADC result */ + } + break; + case 'S': + opcd_send_command(od, OPENPCD_CMD_SSC_READ, 0, 1, 0, NULL); + opcd_recv_reply(od, buf, buf_len); + /* FIXME: interpret and print ADC result */ + break; + case 'L': + while (1) + opcd_recv_reply(od, buf, buf_len); + break; + case 'h': + case '?': + print_help(); + exit(0); + break; + default: + fprintf(stderr, "unknown key `%c'\n", c); + print_help(); + exit(2); + break; + } + } + + sleep(1); + + exit(0); +} diff --git a/host/opcd_usb.c b/host/opcd_usb.c new file mode 100644 index 0000000..d73289d --- /dev/null +++ b/host/opcd_usb.c @@ -0,0 +1,235 @@ +/* opcd_usb - Low-Level USB routines for OpenPCD USB protocol + * + * (C) 2006 by Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "ausb/ausb.h" +#include "../firmware/include/openpcd.h" + +#include "opcd_usb.h" + +const char * +opcd_hexdump(const void *data, unsigned int len) +{ + static char string[65535]; + unsigned char *d = (unsigned char *) data; + unsigned int i, left, ofs; + + string[0] = '\0'; + ofs = snprintf(string, sizeof(string)-1, "(%u): ", len); + + left = sizeof(string) - ofs; + for (i = 0; len--; i += 3) { + if (i >= sizeof(string) -4) + break; + snprintf(string+ofs+i, 4, " %02x", *d++); + } + string[sizeof(string)-1] = '\0'; + return string; +} + +#define OPCD_VENDOR_ID 0x2342 +#define OPCD_PRODUCT_ID 0x0001 +#define OPCD_OUT_EP 0x01 +#define OPCD_IN_EP 0x82 +#define OPCD_INT_EP 0x83 + +static struct usb_device *find_opcd_handle(void) +{ + struct usb_bus *bus; + + for (bus = usb_busses; bus; bus = bus->next) { + struct usb_device *dev; + for (dev = bus->devices; dev; dev = dev->next) { + if (dev->descriptor.idVendor == OPCD_VENDOR_ID + && dev->descriptor.idProduct == OPCD_PRODUCT_ID + && dev->descriptor.iManufacturer == 0 + && dev->descriptor.iProduct == 0 + && dev->descriptor.bNumConfigurations == 1 + && dev->config->bNumInterfaces == 2 + && dev->config->iConfiguration == 0) + return dev; + } + } + return NULL; +} + +static void opcd_dump_hdr(struct openpcd_hdr *hdr) +{ + printf("IRQ: cmd=0x%02x, flags=0x%02x, reg=0x%02x, val=0x%02x\n", + hdr->cmd, hdr->flags, hdr->reg, hdr->val); +} + +static void handle_interrupt(struct usbdevfs_urb *uurb, void *userdata) +{ + struct opcd_handle *od = userdata; + ausb_dev_handle *ah; + struct openpcd_hdr *opcdh; + + if (!uurb) { + fprintf(stderr, "interrupt with no URB?!?\n"); + return; + } + + ah = uurb->usercontext; + + opcdh = (struct openpcd_hdr *)uurb->buffer; + opcd_dump_hdr(opcdh); + + if (ausb_submit_urb(ah, uurb)) + fprintf(stderr, "unable to resubmit interupt urb\n"); +} + +struct opcd_handle *opcd_init(void) +{ + struct opcd_handle *oh; + struct usb_device *dev; + + oh = malloc(sizeof(*oh)); + if (!oh) + return NULL; + + memset(oh, 0, sizeof(*oh)); + + ausb_init(); + + dev = find_opcd_handle(); + if (!dev) { + fprintf(stderr, "Cannot find OpenPCD device. " + "Are you sure it is connected?\n"); + exit(1); + } + + oh->hdl = ausb_open(dev); + if (!oh->hdl) { + fprintf(stderr, "Unable to open usb device: %s\n", + usb_strerror()); + exit(1); + } + + if (ausb_claim_interface(oh->hdl, 0) < 0) { + fprintf(stderr, "Unable to claim usb interface " + "1 of device: %s\n", usb_strerror()); + exit(1); + } + + ausb_fill_int_urb(&oh->int_urb, OPCD_INT_EP, oh->int_buf, + sizeof(oh->int_buf)); + if (ausb_register_callback(oh->hdl, USBDEVFS_URB_TYPE_INTERRUPT, + handle_interrupt, oh)) { + fprintf(stderr, "unable to submit interrupt urb"); + exit(1); + } + + return oh; +} + +void opcd_fini(struct opcd_handle *od) +{ + ausb_discard_urb(od->hdl, &od->int_urb); + ausb_close(od->hdl); +} + +int opcd_recv_reply(struct opcd_handle *od, char *buf, int len) +{ + int ret; + memset(buf, 0, sizeof(buf)); + + ret = ausb_bulk_read(od->hdl, OPCD_IN_EP, buf, len, 100000); + + if (ret < 0) { + fprintf(stderr, "bulk_read returns %d(%s)\n", ret, + usb_strerror()); + return ret; + } + + printf("RX: %s\n", opcd_hexdump(buf, ret)); + opcd_dump_hdr((struct openpcd_hdr *)buf); + + return ret; +} + + +int opcd_send_command(struct opcd_handle *od, u_int8_t cmd, + u_int8_t reg, u_int8_t val, u_int16_t len, + const unsigned char *data) +{ + unsigned char buf[128]; + struct openpcd_hdr *ohdr = (struct openpcd_hdr *)buf; + int cur = 0; + int ret; + + memset(buf, 0, sizeof(buf)); + + ohdr->cmd = cmd; + ohdr->reg = reg; + ohdr->val = val; + if (data && len) + memcpy(ohdr->data, data, len); + + cur = sizeof(*ohdr) + len; + + printf("TX: %s\n", opcd_hexdump(buf, cur)); + + ret = ausb_bulk_write(od->hdl, OPCD_OUT_EP, buf, cur, 0); + if (ret < 0) { + fprintf(stderr, "bulk_write returns %d(%s)\n", ret, + usb_strerror()); + } + + return ret; +} + +int opcd_usbperf(struct opcd_handle *od, unsigned int frames) +{ + int i; + char buf[256*64]; + struct timeval tv_start, tv_stop; + unsigned int num_xfer = 0; + unsigned int diff_msec; + unsigned int transfers = 255; + + printf("starting DATA IN performance test (%u frames of 64 bytes)\n", + frames); + opcd_send_command(od, OPENPCD_CMD_USBTEST_IN, transfers, frames, 0, NULL); + gettimeofday(&tv_start, NULL); + for (i = 0; i < transfers; i++) { + int ret; + ret = ausb_bulk_read(od->hdl, OPCD_IN_EP, buf, sizeof(buf), 0); + if (ret < 0) { + fprintf(stderr, "error receiving data in transaction\n"); + return ret; + } + num_xfer += ret; + } + gettimeofday(&tv_stop, NULL); + diff_msec = (tv_stop.tv_sec - tv_start.tv_sec)*1000; + diff_msec += (tv_stop.tv_usec - tv_start.tv_usec)/1000; + + printf("%u transfers (total %u bytes) in %u miliseconds => %u bytes/sec\n", + i, num_xfer, diff_msec, (num_xfer*1000)/diff_msec); + + return 0; +} diff --git a/host/opcd_usb.h b/host/opcd_usb.h new file mode 100644 index 0000000..e9698f0 --- /dev/null +++ b/host/opcd_usb.h @@ -0,0 +1,24 @@ +#ifndef _OPCD_USB_H +#define _OPCD_USB_H + +#include "ausb/ausb.h" + +#define OPCD_INTBUF_SIZE 64 +struct opcd_handle { + struct ausb_dev_handle *hdl; + struct usbdevfs_urb int_urb; + u_int8_t int_buf[OPCD_INTBUF_SIZE]; +}; + +extern const char *opcd_hexdump(const void *data, unsigned int len); + +extern struct opcd_handle *opcd_init(void); +extern void opcd_fini(struct opcd_handle *od); + +extern int opcd_recv_reply(struct opcd_handle *od, char *buf, int len); +extern int opcd_send_command(struct opcd_handle *od, u_int8_t cmd, + u_int8_t reg, u_int8_t val, u_int16_t len, + const unsigned char *data); +extern int opcd_usbperf(struct opcd_handle *od, unsigned int frames); + +#endif diff --git a/host/zebvty/Makefile b/host/zebvty/Makefile new file mode 100644 index 0000000..dcaf1a2 --- /dev/null +++ b/host/zebvty/Makefile @@ -0,0 +1,19 @@ +#include ../../makevars + +OBJS=vector.o command.o buffer.o vty.o +CFLAGS+=-fPIC +NAME=zebvty + +all: lib$(NAME).a lib$(NAME).so + +lib$(NAME).a: $(OBJS) + $(AR) r $@ $^ + +lib$(NAME).so: $(OBJS) + $(LD) -x --shared -o $@ $^ + +%.o: %.c + $(CC) $(CFLAGS) -o $@ -c $^ + +clean: + @rm -f *.o lib$(NAME).a lib$(NAME).so diff --git a/host/zebvty/buffer.c b/host/zebvty/buffer.c new file mode 100644 index 0000000..0610ebb --- /dev/null +++ b/host/zebvty/buffer.c @@ -0,0 +1,460 @@ +/* + * Buffering of output and input. + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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. + * + * GNU Zebra 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 +#include +#include +#include +#include +#include +#include + +#include "buffer.h" +#include "vty.h" + +/* Buffer master. */ +struct buffer { + /* Data list. */ + struct buffer_data *head; + struct buffer_data *tail; + + /* Size of each buffer_data chunk. */ + size_t size; +}; + +/* Data container. */ +struct buffer_data { + struct buffer_data *next; + + /* Location to add new data. */ + size_t cp; + + /* Pointer to data not yet flushed. */ + size_t sp; + + /* Actual data stream (variable length). */ + unsigned char data[0]; /* real dimension is buffer->size */ +}; + +/* It should always be true that: 0 <= sp <= cp <= size */ + +/* Default buffer size (used if none specified). It is rounded up to the + next page boundery. */ +#define BUFFER_SIZE_DEFAULT 4096 + +#define BUFFER_DATA_FREE(D) free((D)) + +/* Make new buffer. */ +struct buffer *buffer_new(size_t size) +{ + struct buffer *b; + + b = calloc(1, sizeof(struct buffer)); + + if (size) + b->size = size; + else { + static size_t default_size; + if (!default_size) { + long pgsz = sysconf(_SC_PAGESIZE); + default_size = + ((((BUFFER_SIZE_DEFAULT - 1) / pgsz) + 1) * pgsz); + } + b->size = default_size; + } + + return b; +} + +/* Free buffer. */ +void buffer_free(struct buffer *b) +{ + buffer_reset(b); + free(b); +} + +/* Make string clone. */ +char *buffer_getstr(struct buffer *b) +{ + size_t totlen = 0; + struct buffer_data *data; + char *s; + char *p; + + for (data = b->head; data; data = data->next) + totlen += data->cp - data->sp; + if (!(s = malloc(totlen + 1))) + return NULL; + p = s; + for (data = b->head; data; data = data->next) { + memcpy(p, data->data + data->sp, data->cp - data->sp); + p += data->cp - data->sp; + } + *p = '\0'; + return s; +} + +/* Return 1 if buffer is empty. */ +int buffer_empty(struct buffer *b) +{ + return (b->head == NULL); +} + +/* Clear and free all allocated data. */ +void buffer_reset(struct buffer *b) +{ + struct buffer_data *data; + struct buffer_data *next; + + for (data = b->head; data; data = next) { + next = data->next; + BUFFER_DATA_FREE(data); + } + b->head = b->tail = NULL; +} + +/* Add buffer_data to the end of buffer. */ +static struct buffer_data *buffer_add(struct buffer *b) +{ + struct buffer_data *d; + + d = malloc(offsetof(struct buffer_data, data[b->size])); + if (!d) + return NULL; + d->cp = d->sp = 0; + d->next = NULL; + + if (b->tail) + b->tail->next = d; + else + b->head = d; + b->tail = d; + + return d; +} + +/* Write data to buffer. */ +void buffer_put(struct buffer *b, const void *p, size_t size) +{ + struct buffer_data *data = b->tail; + const char *ptr = p; + + /* We use even last one byte of data buffer. */ + while (size) { + size_t chunk; + + /* If there is no data buffer add it. */ + if (data == NULL || data->cp == b->size) + data = buffer_add(b); + + chunk = + ((size <= + (b->size - data->cp)) ? size : (b->size - data->cp)); + memcpy((data->data + data->cp), ptr, chunk); + size -= chunk; + ptr += chunk; + data->cp += chunk; + } +} + +/* Insert character into the buffer. */ +void buffer_putc(struct buffer *b, u_char c) +{ + buffer_put(b, &c, 1); +} + +/* Put string to the buffer. */ +void buffer_putstr(struct buffer *b, const char *c) +{ + buffer_put(b, c, strlen(c)); +} + +/* Keep flushing data to the fd until the buffer is empty or an error is + encountered or the operation would block. */ +buffer_status_t buffer_flush_all(struct buffer *b, int fd) +{ + buffer_status_t ret; + struct buffer_data *head; + size_t head_sp; + + if (!b->head) + return BUFFER_EMPTY; + head_sp = (head = b->head)->sp; + /* Flush all data. */ + while ((ret = buffer_flush_available(b, fd)) == BUFFER_PENDING) { + if ((b->head == head) && (head_sp == head->sp) + && (errno != EINTR)) + /* No data was flushed, so kernel buffer must be full. */ + return ret; + head_sp = (head = b->head)->sp; + } + + return ret; +} + +#if 0 +/* Flush enough data to fill a terminal window of the given scene (used only + by vty telnet interface). */ +buffer_status_t +buffer_flush_window(struct buffer * b, int fd, int width, int height, + int erase_flag, int no_more_flag) +{ + int nbytes; + int iov_alloc; + int iov_index; + struct iovec *iov; + struct iovec small_iov[3]; + char more[] = " --More-- "; + char erase[] = + { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 + }; + struct buffer_data *data; + int column; + + if (!b->head) + return BUFFER_EMPTY; + + if (height < 1) { + zlog_warn + ("%s called with non-positive window height %d, forcing to 1", + __func__, height); + height = 1; + } else if (height >= 2) + height--; + if (width < 1) { + zlog_warn + ("%s called with non-positive window width %d, forcing to 1", + __func__, width); + width = 1; + } + + /* For erase and more data add two to b's buffer_data count. */ + if (b->head->next == NULL) { + iov_alloc = sizeof(small_iov) / sizeof(small_iov[0]); + iov = small_iov; + } else { + iov_alloc = ((height * (width + 2)) / b->size) + 10; + iov = XMALLOC(MTYPE_TMP, iov_alloc * sizeof(*iov)); + } + iov_index = 0; + + /* Previously print out is performed. */ + if (erase_flag) { + iov[iov_index].iov_base = erase; + iov[iov_index].iov_len = sizeof erase; + iov_index++; + } + + /* Output data. */ + column = 1; /* Column position of next character displayed. */ + for (data = b->head; data && (height > 0); data = data->next) { + size_t cp; + + cp = data->sp; + while ((cp < data->cp) && (height > 0)) { + /* Calculate lines remaining and column position after displaying + this character. */ + if (data->data[cp] == '\r') + column = 1; + else if ((data->data[cp] == '\n') || (column == width)) { + column = 1; + height--; + } else + column++; + cp++; + } + iov[iov_index].iov_base = (char *)(data->data + data->sp); + iov[iov_index++].iov_len = cp - data->sp; + data->sp = cp; + + if (iov_index == iov_alloc) + /* This should not ordinarily happen. */ + { + iov_alloc *= 2; + if (iov != small_iov) { + zlog_warn("%s: growing iov array to %d; " + "width %d, height %d, size %lu", + __func__, iov_alloc, width, height, + (u_long) b->size); + iov = + XREALLOC(MTYPE_TMP, iov, + iov_alloc * sizeof(*iov)); + } else { + /* This should absolutely never occur. */ + zlog_err + ("%s: corruption detected: iov_small overflowed; " + "head %p, tail %p, head->next %p", + __func__, b->head, b->tail, b->head->next); + iov = + XMALLOC(MTYPE_TMP, + iov_alloc * sizeof(*iov)); + memcpy(iov, small_iov, sizeof(small_iov)); + } + } + } + + /* In case of `more' display need. */ + if (b->tail && (b->tail->sp < b->tail->cp) && !no_more_flag) { + iov[iov_index].iov_base = more; + iov[iov_index].iov_len = sizeof more; + iov_index++; + } +#ifdef IOV_MAX + /* IOV_MAX are normally defined in , Posix.1g. + example: Solaris2.6 are defined IOV_MAX size at 16. */ + { + struct iovec *c_iov = iov; + nbytes = 0; /* Make sure it's initialized. */ + + while (iov_index > 0) { + int iov_size; + + iov_size = + ((iov_index > IOV_MAX) ? IOV_MAX : iov_index); + if ((nbytes = writev(fd, c_iov, iov_size)) < 0) { + zlog_warn("%s: writev to fd %d failed: %s", + __func__, fd, safe_strerror(errno)); + break; + } + + /* move pointer io-vector */ + c_iov += iov_size; + iov_index -= iov_size; + } + } +#else /* IOV_MAX */ + if ((nbytes = writev(fd, iov, iov_index)) < 0) + zlog_warn("%s: writev to fd %d failed: %s", + __func__, fd, safe_strerror(errno)); +#endif /* IOV_MAX */ + + /* Free printed buffer data. */ + while (b->head && (b->head->sp == b->head->cp)) { + struct buffer_data *del; + if (!(b->head = (del = b->head)->next)) + b->tail = NULL; + BUFFER_DATA_FREE(del); + } + + if (iov != small_iov) + XFREE(MTYPE_TMP, iov); + + return (nbytes < 0) ? BUFFER_ERROR : + (b->head ? BUFFER_PENDING : BUFFER_EMPTY); +} +#endif + +/* This function (unlike other buffer_flush* functions above) is designed +to work with non-blocking sockets. It does not attempt to write out +all of the queued data, just a "big" chunk. It returns 0 if it was +able to empty out the buffers completely, 1 if more flushing is +required later, or -1 on a fatal write error. */ +buffer_status_t buffer_flush_available(struct buffer * b, int fd) +{ + +/* These are just reasonable values to make sure a significant amount of +data is written. There's no need to go crazy and try to write it all +in one shot. */ +#ifdef IOV_MAX +#define MAX_CHUNKS ((IOV_MAX >= 16) ? 16 : IOV_MAX) +#else +#define MAX_CHUNKS 16 +#endif +#define MAX_FLUSH 131072 + + struct buffer_data *d; + size_t written; + struct iovec iov[MAX_CHUNKS]; + size_t iovcnt = 0; + size_t nbyte = 0; + + for (d = b->head; d && (iovcnt < MAX_CHUNKS) && (nbyte < MAX_FLUSH); + d = d->next, iovcnt++) { + iov[iovcnt].iov_base = d->data + d->sp; + nbyte += (iov[iovcnt].iov_len = d->cp - d->sp); + } + + if (!nbyte) + /* No data to flush: should we issue a warning message? */ + return BUFFER_EMPTY; + + /* only place where written should be sign compared */ + if ((ssize_t) (written = writev(fd, iov, iovcnt)) < 0) { + if (ERRNO_IO_RETRY(errno)) + /* Calling code should try again later. */ + return BUFFER_PENDING; + return BUFFER_ERROR; + } + + /* Free printed buffer data. */ + while (written > 0) { + struct buffer_data *d; + if (!(d = b->head)) + break; + if (written < d->cp - d->sp) { + d->sp += written; + return BUFFER_PENDING; + } + + written -= (d->cp - d->sp); + if (!(b->head = d->next)) + b->tail = NULL; + BUFFER_DATA_FREE(d); + } + + return b->head ? BUFFER_PENDING : BUFFER_EMPTY; + +#undef MAX_CHUNKS +#undef MAX_FLUSH +} + +buffer_status_t +buffer_write(struct buffer * b, int fd, const void *p, size_t size) +{ + ssize_t nbytes; + +#if 0 + /* Should we attempt to drain any previously buffered data? This could help reduce latency in pushing out the data if we are stuck in a long-running thread that is preventing the main select loop from calling the flush thread... */ + + if (b->head && (buffer_flush_available(b, fd) == BUFFER_ERROR)) + return BUFFER_ERROR; +#endif + if (b->head) + /* Buffer is not empty, so do not attempt to write the new data. */ + nbytes = 0; + else if ((nbytes = write(fd, p, size)) < 0) { + if (ERRNO_IO_RETRY(errno)) + nbytes = 0; + else + return BUFFER_ERROR; + } + /* Add any remaining data to the buffer. */ + { + size_t written = nbytes; + if (written < size) + buffer_put(b, ((const char *)p) + written, + size - written); + } + return b->head ? BUFFER_PENDING : BUFFER_EMPTY; +} diff --git a/host/zebvty/buffer.h b/host/zebvty/buffer.h new file mode 100644 index 0000000..e564cf9 --- /dev/null +++ b/host/zebvty/buffer.h @@ -0,0 +1,100 @@ +/* + * Buffering to output and input. + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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. + * + * GNU Zebra 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. + */ + +#ifndef _ZEBRA_BUFFER_H +#define _ZEBRA_BUFFER_H + +/* Create a new buffer. Memory will be allocated in chunks of the given + size. If the argument is 0, the library will supply a reasonable + default size suitable for buffering socket I/O. */ +struct buffer *buffer_new(size_t); + +/* Free all data in the buffer. */ +void buffer_reset(struct buffer *); + +/* This function first calls buffer_reset to release all buffered data. + Then it frees the struct buffer itself. */ +void buffer_free(struct buffer *); + +/* Add the given data to the end of the buffer. */ +extern void buffer_put(struct buffer *, const void *, size_t); +/* Add a single character to the end of the buffer. */ +extern void buffer_putc(struct buffer *, u_char); +/* Add a NUL-terminated string to the end of the buffer. */ +extern void buffer_putstr(struct buffer *, const char *); + +/* Combine all accumulated (and unflushed) data inside the buffer into a + single NUL-terminated string allocated using XMALLOC(MTYPE_TMP). Note + that this function does not alter the state of the buffer, so the data + is still inside waiting to be flushed. */ +char *buffer_getstr(struct buffer *); + +/* Returns 1 if there is no pending data in the buffer. Otherwise returns 0. */ +int buffer_empty(struct buffer *); + +typedef enum { + /* An I/O error occurred. The buffer should be destroyed and the + file descriptor should be closed. */ + BUFFER_ERROR = -1, + + /* The data was written successfully, and the buffer is now empty + (there is no pending data waiting to be flushed). */ + BUFFER_EMPTY = 0, + + /* There is pending data in the buffer waiting to be flushed. Please + try flushing the buffer when select indicates that the file descriptor + is writeable. */ + BUFFER_PENDING = 1 +} buffer_status_t; + +/* Try to write this data to the file descriptor. Any data that cannot + be written immediately is added to the buffer queue. */ +extern buffer_status_t buffer_write(struct buffer *, int fd, + const void *, size_t); + +/* This function attempts to flush some (but perhaps not all) of + the queued data to the given file descriptor. */ +extern buffer_status_t buffer_flush_available(struct buffer *, int fd); + +/* The following 2 functions (buffer_flush_all and buffer_flush_window) + are for use in lib/vty.c only. They should not be used elsewhere. */ + +/* Call buffer_flush_available repeatedly until either all data has been + flushed, or an I/O error has been encountered, or the operation would + block. */ +extern buffer_status_t buffer_flush_all(struct buffer *, int fd); + +/* Attempt to write enough data to the given fd to fill a window of the + given width and height (and remove the data written from the buffer). + + If !no_more, then a message saying " --More-- " is appended. + If erase is true, then first overwrite the previous " --More-- " message + with spaces. + + Any write error (including EAGAIN or EINTR) will cause this function + to return -1 (because the logic for handling the erase and more features + is too complicated to retry the write later). +*/ +extern buffer_status_t buffer_flush_window(struct buffer *, int fd, int width, + int height, int erase, int no_more); + +#endif /* _ZEBRA_BUFFER_H */ diff --git a/host/zebvty/command.c b/host/zebvty/command.c new file mode 100644 index 0000000..7f3a6a5 --- /dev/null +++ b/host/zebvty/command.c @@ -0,0 +1,3384 @@ +/* + $Id: command.c,v 1.47 2005/04/25 16:26:42 paul Exp $ + + Command interpreter routine for virtual terminal [aka TeletYpe] + Copyright (C) 1997, 98, 99 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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. + +GNU Zebra 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 "zebvty.h" + +#include +#include +#include +#include +#include +#define _XOPEN_SOURCE +#include +#include +#include +#include +#include + +//#include "memory.h" +//#include "log.h" +//#include +//#include "thread.h" +#include "vector.h" +#include "vty.h" +#include "command.h" +//#include "workqueue.h" + +/* Command vector which includes some level of command lists. Normally + each daemon maintains each own cmdvec. */ +vector cmdvec; + +/* Host information structure. */ +struct host host; + +/* Standard command node structures. */ +struct cmd_node auth_node = { + AUTH_NODE, + "Password: ", +}; + +struct cmd_node view_node = { + VIEW_NODE, + "%s> ", +}; + +struct cmd_node auth_enable_node = { + AUTH_ENABLE_NODE, + "Password: ", +}; + +struct cmd_node enable_node = { + ENABLE_NODE, + "%s# ", +}; + +struct cmd_node config_node = { + CONFIG_NODE, + "%s(config)# ", + 1 +}; + +/* Default motd string. */ +const char *default_motd = "\r\n\ +Hello, this is " QUAGGA_PROGNAME " (version " QUAGGA_VERSION ").\r\n\ +" QUAGGA_COPYRIGHT "\r\n\ +\r\n"; + +#if 0 +static struct facility_map { + int facility; + const char *name; + size_t match; +} syslog_facilities[] = { + { + LOG_KERN, "kern", 1}, { + LOG_USER, "user", 2}, { + LOG_MAIL, "mail", 1}, { + LOG_DAEMON, "daemon", 1}, { + LOG_AUTH, "auth", 1}, { + LOG_SYSLOG, "syslog", 1}, { + LOG_LPR, "lpr", 2}, { + LOG_NEWS, "news", 1}, { + LOG_UUCP, "uucp", 2}, { + LOG_CRON, "cron", 1}, +#ifdef LOG_FTP + { + LOG_FTP, "ftp", 1}, +#endif + { + LOG_LOCAL0, "local0", 6}, { + LOG_LOCAL1, "local1", 6}, { + LOG_LOCAL2, "local2", 6}, { + LOG_LOCAL3, "local3", 6}, { + LOG_LOCAL4, "local4", 6}, { + LOG_LOCAL5, "local5", 6}, { + LOG_LOCAL6, "local6", 6}, { + LOG_LOCAL7, "local7", 6}, { +0, NULL, 0},}; + +static const char *facility_name(int facility) +{ + struct facility_map *fm; + + for (fm = syslog_facilities; fm->name; fm++) + if (fm->facility == facility) + return fm->name; + return ""; +} + +static int facility_match(const char *str) +{ + struct facility_map *fm; + + for (fm = syslog_facilities; fm->name; fm++) + if (!strncmp(str, fm->name, fm->match)) + return fm->facility; + return -1; +} + +static int level_match(const char *s) +{ + int level; + + for (level = 0; zlog_priority[level] != NULL; level++) + if (!strncmp(s, zlog_priority[level], 2)) + return level; + return ZLOG_DISABLED; +} +#endif + +/* This is called from main when a daemon is invoked with -v or --version. */ +void print_version(const char *progname) +{ + printf("%s version %s\n", progname, QUAGGA_VERSION); + printf("%s\n", QUAGGA_COPYRIGHT); +} + +/* Utility function to concatenate argv argument into a single string + with inserting ' ' character between each argument. */ +char *argv_concat(const char **argv, int argc, int shift) +{ + int i; + size_t len; + char *str; + char *p; + + len = 0; + for (i = shift; i < argc; i++) + len += strlen(argv[i]) + 1; + if (!len) + return NULL; + p = str = malloc(len); + for (i = shift; i < argc; i++) { + size_t arglen; + memcpy(p, argv[i], (arglen = strlen(argv[i]))); + p += arglen; + *p++ = ' '; + } + *(p - 1) = '\0'; + return str; +} + +/* Install top node of command vector. */ +void install_node(struct cmd_node *node, int (*func) (struct vty *)) +{ + vector_set_index(cmdvec, node->node, node); + node->func = func; + node->cmd_vector = vector_init(VECTOR_MIN_SIZE); +} + +/* Compare two command's string. Used in sort_node (). */ +static int cmp_node(const void *p, const void *q) +{ + struct cmd_element *a = *(struct cmd_element **)p; + struct cmd_element *b = *(struct cmd_element **)q; + + return strcmp(a->string, b->string); +} + +static int cmp_desc(const void *p, const void *q) +{ + struct desc *a = *(struct desc **)p; + struct desc *b = *(struct desc **)q; + + return strcmp(a->cmd, b->cmd); +} + +/* Sort each node's command element according to command string. */ +void sort_node() +{ + unsigned int i, j; + struct cmd_node *cnode; + vector descvec; + struct cmd_element *cmd_element; + + for (i = 0; i < vector_active(cmdvec); i++) + if ((cnode = vector_slot(cmdvec, i)) != NULL) { + vector cmd_vector = cnode->cmd_vector; + qsort(cmd_vector->index, vector_active(cmd_vector), + sizeof(void *), cmp_node); + + for (j = 0; j < vector_active(cmd_vector); j++) + if ((cmd_element = + vector_slot(cmd_vector, j)) != NULL + && vector_active(cmd_element->strvec)) { + descvec = + vector_slot(cmd_element->strvec, + vector_active + (cmd_element->strvec) - + 1); + qsort(descvec->index, + vector_active(descvec), + sizeof(void *), cmp_desc); + } + } +} + +/* Breaking up string into each command piece. I assume given + character is separated by a space character. Return value is a + vector which includes char ** data element. */ +vector cmd_make_strvec(const char *string) +{ + const char *cp, *start; + char *token; + int strlen; + vector strvec; + + if (string == NULL) + return NULL; + + cp = string; + + /* Skip white spaces. */ + while (isspace((int)*cp) && *cp != '\0') + cp++; + + /* Return if there is only white spaces */ + if (*cp == '\0') + return NULL; + + if (*cp == '!' || *cp == '#') + return NULL; + + /* Prepare return vector. */ + strvec = vector_init(VECTOR_MIN_SIZE); + + /* Copy each command piece and set into vector. */ + while (1) { + start = cp; + while (!(isspace((int)*cp) || *cp == '\r' || *cp == '\n') && + *cp != '\0') + cp++; + strlen = cp - start; + token = malloc(strlen + 1); + memcpy(token, start, strlen); + *(token + strlen) = '\0'; + vector_set(strvec, token); + + while ((isspace((int)*cp) || *cp == '\n' || *cp == '\r') && + *cp != '\0') + cp++; + + if (*cp == '\0') + return strvec; + } +} + +/* Free allocated string vector. */ +void cmd_free_strvec(vector v) +{ + unsigned int i; + char *cp; + + if (!v) + return; + + for (i = 0; i < vector_active(v); i++) + if ((cp = vector_slot(v, i)) != NULL) + free(cp); + + vector_free(v); +} + +/* Fetch next description. Used in cmd_make_descvec(). */ +static char *cmd_desc_str(const char **string) +{ + const char *cp, *start; + char *token; + int strlen; + + cp = *string; + + if (cp == NULL) + return NULL; + + /* Skip white spaces. */ + while (isspace((int)*cp) && *cp != '\0') + cp++; + + /* Return if there is only white spaces */ + if (*cp == '\0') + return NULL; + + start = cp; + + while (!(*cp == '\r' || *cp == '\n') && *cp != '\0') + cp++; + + strlen = cp - start; + token = malloc(strlen + 1); + memcpy(token, start, strlen); + *(token + strlen) = '\0'; + + *string = cp; + + return token; +} + +/* New string vector. */ +static vector cmd_make_descvec(const char *string, const char *descstr) +{ + int multiple = 0; + const char *sp; + char *token; + int len; + const char *cp; + const char *dp; + vector allvec; + vector strvec = NULL; + struct desc *desc; + + cp = string; + dp = descstr; + + if (cp == NULL) + return NULL; + + allvec = vector_init(VECTOR_MIN_SIZE); + + while (1) { + while (isspace((int)*cp) && *cp != '\0') + cp++; + + if (*cp == '(') { + multiple = 1; + cp++; + } + if (*cp == ')') { + multiple = 0; + cp++; + } + if (*cp == '|') { + if (!multiple) { + fprintf(stderr, "Command parse error!: %s\n", + string); + exit(1); + } + cp++; + } + + while (isspace((int)*cp) && *cp != '\0') + cp++; + + if (*cp == '(') { + multiple = 1; + cp++; + } + + if (*cp == '\0') + return allvec; + + sp = cp; + + while (! + (isspace((int)*cp) || *cp == '\r' || *cp == '\n' + || *cp == ')' || *cp == '|') && *cp != '\0') + cp++; + + len = cp - sp; + + token = malloc(len + 1); + memcpy(token, sp, len); + *(token + len) = '\0'; + + desc = calloc(1, sizeof(struct desc)); + desc->cmd = token; + desc->str = cmd_desc_str(&dp); + + if (multiple) { + if (multiple == 1) { + strvec = vector_init(VECTOR_MIN_SIZE); + vector_set(allvec, strvec); + } + multiple++; + } else { + strvec = vector_init(VECTOR_MIN_SIZE); + vector_set(allvec, strvec); + } + vector_set(strvec, desc); + } +} + +/* Count mandantory string vector size. This is to determine inputed + command has enough command length. */ +static int cmd_cmdsize(vector strvec) +{ + unsigned int i; + int size = 0; + vector descvec; + struct desc *desc; + + for (i = 0; i < vector_active(strvec); i++) + if ((descvec = vector_slot(strvec, i)) != NULL) { + if ((vector_active(descvec)) == 1 + && (desc = vector_slot(descvec, 0)) != NULL) { + if (desc->cmd == NULL || CMD_OPTION(desc->cmd)) + return size; + else + size++; + } else + size++; + } + return size; +} + +/* Return prompt character of specified node. */ +const char *cmd_prompt(enum node_type node) +{ + struct cmd_node *cnode; + + cnode = vector_slot(cmdvec, node); + return cnode->prompt; +} + +/* Install a command into a node. */ +void install_element(enum node_type ntype, struct cmd_element *cmd) +{ + struct cmd_node *cnode; + + cnode = vector_slot(cmdvec, ntype); + + if (cnode == NULL) { + fprintf(stderr, + "Command node %d doesn't exist, please check it\n", + ntype); + exit(1); + } + + vector_set(cnode->cmd_vector, cmd); + + cmd->strvec = cmd_make_descvec(cmd->string, cmd->doc); + cmd->cmdsize = cmd_cmdsize(cmd->strvec); +} + +static unsigned char itoa64[] = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +static void to64(char *s, long v, int n) +{ + while (--n >= 0) { + *s++ = itoa64[v & 0x3f]; + v >>= 6; + } +} + +static char *zencrypt(const char *passwd) +{ + char salt[6]; + struct timeval tv; + char *crypt(const char *, const char *); + + gettimeofday(&tv, 0); + + to64(&salt[0], random(), 3); + to64(&salt[3], tv.tv_usec, 3); + salt[5] = '\0'; + + return crypt(passwd, salt); +} + +/* This function write configuration of this host. */ +static int config_write_host(struct vty *vty) +{ +#if 0 + if (host.name) + vty_out(vty, "hostname %s%s", host.name, VTY_NEWLINE); + + if (host.encrypt) { + if (host.password_encrypt) + vty_out(vty, "password 8 %s%s", host.password_encrypt, + VTY_NEWLINE); + if (host.enable_encrypt) + vty_out(vty, "enable password 8 %s%s", + host.enable_encrypt, VTY_NEWLINE); + } else { + if (host.password) + vty_out(vty, "password %s%s", host.password, + VTY_NEWLINE); + if (host.enable) + vty_out(vty, "enable password %s%s", host.enable, + VTY_NEWLINE); + } + + if (zlog_default->default_lvl != LOG_DEBUG) { + vty_out(vty, "! N.B. The 'log trap' command is deprecated.%s", + VTY_NEWLINE); + vty_out(vty, "log trap %s%s", + zlog_priority[zlog_default->default_lvl], VTY_NEWLINE); + } + + if (host.logfile + && (zlog_default->maxlvl[ZLOG_DEST_FILE] != ZLOG_DISABLED)) { + vty_out(vty, "log file %s", host.logfile); + if (zlog_default->maxlvl[ZLOG_DEST_FILE] != + zlog_default->default_lvl) + vty_out(vty, " %s", + zlog_priority[zlog_default-> + maxlvl[ZLOG_DEST_FILE]]); + vty_out(vty, "%s", VTY_NEWLINE); + } + + if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != ZLOG_DISABLED) { + vty_out(vty, "log stdout"); + if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != + zlog_default->default_lvl) + vty_out(vty, " %s", + zlog_priority[zlog_default-> + maxlvl[ZLOG_DEST_STDOUT]]); + vty_out(vty, "%s", VTY_NEWLINE); + } + + if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED) + vty_out(vty, "no log monitor%s", VTY_NEWLINE); + else if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] != + zlog_default->default_lvl) + vty_out(vty, "log monitor %s%s", + zlog_priority[zlog_default->maxlvl[ZLOG_DEST_MONITOR]], + VTY_NEWLINE); + + if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED) { + vty_out(vty, "log syslog"); + if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != + zlog_default->default_lvl) + vty_out(vty, " %s", + zlog_priority[zlog_default-> + maxlvl[ZLOG_DEST_SYSLOG]]); + vty_out(vty, "%s", VTY_NEWLINE); + } + + if (zlog_default->facility != LOG_DAEMON) + vty_out(vty, "log facility %s%s", + facility_name(zlog_default->facility), VTY_NEWLINE); + + if (zlog_default->record_priority == 1) + vty_out(vty, "log record-priority%s", VTY_NEWLINE); + + if (host.advanced) + vty_out(vty, "service advanced-vty%s", VTY_NEWLINE); + + if (host.encrypt) + vty_out(vty, "service password-encryption%s", VTY_NEWLINE); + + if (host.lines >= 0) + vty_out(vty, "service terminal-length %d%s", host.lines, + VTY_NEWLINE); + + if (host.motdfile) + vty_out(vty, "banner motd file %s%s", host.motdfile, + VTY_NEWLINE); + else if (!host.motd) + vty_out(vty, "no banner motd%s", VTY_NEWLINE); + +#endif + return 1; +} + +/* Utility function for getting command vector. */ +static vector cmd_node_vector(vector v, enum node_type ntype) +{ + struct cmd_node *cnode = vector_slot(v, ntype); + return cnode->cmd_vector; +} + +#if 0 +/* Filter command vector by symbol. This function is not actually used; + * should it be deleted? */ +static int cmd_filter_by_symbol(char *command, char *symbol) +{ + int i, lim; + + if (strcmp(symbol, "IPV4_ADDRESS") == 0) { + i = 0; + lim = strlen(command); + while (i < lim) { + if (! + (isdigit((int)command[i]) || command[i] == '.' + || command[i] == '/')) + return 1; + i++; + } + return 0; + } + if (strcmp(symbol, "STRING") == 0) { + i = 0; + lim = strlen(command); + while (i < lim) { + if (! + (isalpha((int)command[i]) || command[i] == '_' + || command[i] == '-')) + return 1; + i++; + } + return 0; + } + if (strcmp(symbol, "IFNAME") == 0) { + i = 0; + lim = strlen(command); + while (i < lim) { + if (!isalnum((int)command[i])) + return 1; + i++; + } + return 0; + } + return 0; +} +#endif + +/* Completion match types. */ +enum match_type { + no_match, + extend_match, + ipv4_prefix_match, + ipv4_match, + ipv6_prefix_match, + ipv6_match, + range_match, + vararg_match, + partly_match, + exact_match +}; + +static enum match_type cmd_ipv4_match(const char *str) +{ + const char *sp; + int dots = 0, nums = 0; + char buf[4]; + + if (str == NULL) + return partly_match; + + for (;;) { + memset(buf, 0, sizeof(buf)); + sp = str; + while (*str != '\0') { + if (*str == '.') { + if (dots >= 3) + return no_match; + + if (*(str + 1) == '.') + return no_match; + + if (*(str + 1) == '\0') + return partly_match; + + dots++; + break; + } + if (!isdigit((int)*str)) + return no_match; + + str++; + } + + if (str - sp > 3) + return no_match; + + strncpy(buf, sp, str - sp); + if (atoi(buf) > 255) + return no_match; + + nums++; + + if (*str == '\0') + break; + + str++; + } + + if (nums < 4) + return partly_match; + + return exact_match; +} + +static enum match_type cmd_ipv4_prefix_match(const char *str) +{ + const char *sp; + int dots = 0; + char buf[4]; + + if (str == NULL) + return partly_match; + + for (;;) { + memset(buf, 0, sizeof(buf)); + sp = str; + while (*str != '\0' && *str != '/') { + if (*str == '.') { + if (dots == 3) + return no_match; + + if (*(str + 1) == '.' || *(str + 1) == '/') + return no_match; + + if (*(str + 1) == '\0') + return partly_match; + + dots++; + break; + } + + if (!isdigit((int)*str)) + return no_match; + + str++; + } + + if (str - sp > 3) + return no_match; + + strncpy(buf, sp, str - sp); + if (atoi(buf) > 255) + return no_match; + + if (dots == 3) { + if (*str == '/') { + if (*(str + 1) == '\0') + return partly_match; + + str++; + break; + } else if (*str == '\0') + return partly_match; + } + + if (*str == '\0') + return partly_match; + + str++; + } + + sp = str; + while (*str != '\0') { + if (!isdigit((int)*str)) + return no_match; + + str++; + } + + if (atoi(sp) > 32) + return no_match; + + return exact_match; +} + +#define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%" +#define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/" +#define STATE_START 1 +#define STATE_COLON 2 +#define STATE_DOUBLE 3 +#define STATE_ADDR 4 +#define STATE_DOT 5 +#define STATE_SLASH 6 +#define STATE_MASK 7 + +#ifdef HAVE_IPV6 + +static enum match_type cmd_ipv6_match(const char *str) +{ + int state = STATE_START; + int colons = 0, nums = 0, double_colon = 0; + const char *sp = NULL; + struct sockaddr_in6 sin6_dummy; + int ret; + + if (str == NULL) + return partly_match; + + if (strspn(str, IPV6_ADDR_STR) != strlen(str)) + return no_match; + + /* use inet_pton that has a better support, + * for example inet_pton can support the automatic addresses: + * ::1.2.3.4 + */ + ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr); + + if (ret == 1) + return exact_match; + + while (*str != '\0') { + switch (state) { + case STATE_START: + if (*str == ':') { + if (*(str + 1) != ':' && *(str + 1) != '\0') + return no_match; + colons--; + state = STATE_COLON; + } else { + sp = str; + state = STATE_ADDR; + } + + continue; + case STATE_COLON: + colons++; + if (*(str + 1) == ':') + state = STATE_DOUBLE; + else { + sp = str + 1; + state = STATE_ADDR; + } + break; + case STATE_DOUBLE: + if (double_colon) + return no_match; + + if (*(str + 1) == ':') + return no_match; + else { + if (*(str + 1) != '\0') + colons++; + sp = str + 1; + state = STATE_ADDR; + } + + double_colon++; + nums++; + break; + case STATE_ADDR: + if (*(str + 1) == ':' || *(str + 1) == '\0') { + if (str - sp > 3) + return no_match; + + nums++; + state = STATE_COLON; + } + if (*(str + 1) == '.') + state = STATE_DOT; + break; + case STATE_DOT: + state = STATE_ADDR; + break; + default: + break; + } + + if (nums > 8) + return no_match; + + if (colons > 7) + return no_match; + + str++; + } + +#if 0 + if (nums < 11) + return partly_match; +#endif /* 0 */ + + return exact_match; +} + +static enum match_type cmd_ipv6_prefix_match(const char *str) +{ + int state = STATE_START; + int colons = 0, nums = 0, double_colon = 0; + int mask; + const char *sp = NULL; + char *endptr = NULL; + + if (str == NULL) + return partly_match; + + if (strspn(str, IPV6_PREFIX_STR) != strlen(str)) + return no_match; + + while (*str != '\0' && state != STATE_MASK) { + switch (state) { + case STATE_START: + if (*str == ':') { + if (*(str + 1) != ':' && *(str + 1) != '\0') + return no_match; + colons--; + state = STATE_COLON; + } else { + sp = str; + state = STATE_ADDR; + } + + continue; + case STATE_COLON: + colons++; + if (*(str + 1) == '/') + return no_match; + else if (*(str + 1) == ':') + state = STATE_DOUBLE; + else { + sp = str + 1; + state = STATE_ADDR; + } + break; + case STATE_DOUBLE: + if (double_colon) + return no_match; + + if (*(str + 1) == ':') + return no_match; + else { + if (*(str + 1) != '\0' && *(str + 1) != '/') + colons++; + sp = str + 1; + + if (*(str + 1) == '/') + state = STATE_SLASH; + else + state = STATE_ADDR; + } + + double_colon++; + nums += 1; + break; + case STATE_ADDR: + if (*(str + 1) == ':' || *(str + 1) == '.' + || *(str + 1) == '\0' || *(str + 1) == '/') { + if (str - sp > 3) + return no_match; + + for (; sp <= str; sp++) + if (*sp == '/') + return no_match; + + nums++; + + if (*(str + 1) == ':') + state = STATE_COLON; + else if (*(str + 1) == '.') + state = STATE_DOT; + else if (*(str + 1) == '/') + state = STATE_SLASH; + } + break; + case STATE_DOT: + state = STATE_ADDR; + break; + case STATE_SLASH: + if (*(str + 1) == '\0') + return partly_match; + + state = STATE_MASK; + break; + default: + break; + } + + if (nums > 11) + return no_match; + + if (colons > 7) + return no_match; + + str++; + } + + if (state < STATE_MASK) + return partly_match; + + mask = strtol(str, &endptr, 10); + if (*endptr != '\0') + return no_match; + + if (mask < 0 || mask > 128) + return no_match; + +/* I don't know why mask < 13 makes command match partly. + Forgive me to make this comments. I Want to set static default route + because of lack of function to originate default in ospf6d; sorry + yasu + if (mask < 13) + return partly_match; +*/ + + return exact_match; +} + +#endif /* HAVE_IPV6 */ + +#define DECIMAL_STRLEN_MAX 10 + +static int cmd_range_match(const char *range, const char *str) +{ + char *p; + char buf[DECIMAL_STRLEN_MAX + 1]; + char *endptr = NULL; + unsigned long min, max, val; + + if (str == NULL) + return 1; + + val = strtoul(str, &endptr, 10); + if (*endptr != '\0') + return 0; + + range++; + p = strchr(range, '-'); + if (p == NULL) + return 0; + if (p - range > DECIMAL_STRLEN_MAX) + return 0; + strncpy(buf, range, p - range); + buf[p - range] = '\0'; + min = strtoul(buf, &endptr, 10); + if (*endptr != '\0') + return 0; + + range = p + 1; + p = strchr(range, '>'); + if (p == NULL) + return 0; + if (p - range > DECIMAL_STRLEN_MAX) + return 0; + strncpy(buf, range, p - range); + buf[p - range] = '\0'; + max = strtoul(buf, &endptr, 10); + if (*endptr != '\0') + return 0; + + if (val < min || val > max) + return 0; + + return 1; +} + +/* Make completion match and return match type flag. */ +static enum match_type +cmd_filter_by_completion(char *command, vector v, unsigned int index) +{ + unsigned int i; + const char *str; + struct cmd_element *cmd_element; + enum match_type match_type; + vector descvec; + struct desc *desc; + + match_type = no_match; + + /* If command and cmd_element string does not match set NULL to vector */ + for (i = 0; i < vector_active(v); i++) + if ((cmd_element = vector_slot(v, i)) != NULL) { + if (index >= vector_active(cmd_element->strvec)) + vector_slot(v, i) = NULL; + else { + unsigned int j; + int matched = 0; + + descvec = + vector_slot(cmd_element->strvec, index); + + for (j = 0; j < vector_active(descvec); j++) + if ((desc = vector_slot(descvec, j))) { + str = desc->cmd; + + if (CMD_VARARG(str)) { + if (match_type < + vararg_match) + match_type = + vararg_match; + matched++; + } else if (CMD_RANGE(str)) { + if (cmd_range_match + (str, command)) { + if (match_type < + range_match) + match_type + = + range_match; + + matched++; + } + } +#ifdef HAVE_IPV6 + else if (CMD_IPV6(str)) { + if (cmd_ipv6_match + (command)) { + if (match_type < + ipv6_match) + match_type + = + ipv6_match; + + matched++; + } + } else if (CMD_IPV6_PREFIX(str)) { + if (cmd_ipv6_prefix_match(command)) { + if (match_type < + ipv6_prefix_match) + match_type + = + ipv6_prefix_match; + + matched++; + } + } +#endif /* HAVE_IPV6 */ + else if (CMD_IPV4(str)) { + if (cmd_ipv4_match + (command)) { + if (match_type < + ipv4_match) + match_type + = + ipv4_match; + + matched++; + } + } else if (CMD_IPV4_PREFIX(str)) { + if (cmd_ipv4_prefix_match(command)) { + if (match_type < + ipv4_prefix_match) + match_type + = + ipv4_prefix_match; + matched++; + } + } else + /* Check is this point's argument optional ? */ + if (CMD_OPTION(str) + || + CMD_VARIABLE(str)) { + if (match_type < + extend_match) + match_type = + extend_match; + matched++; + } else + if (strncmp + (command, str, + strlen(command)) == + 0) { + if (strcmp(command, str) + == 0) + match_type = + exact_match; + else { + if (match_type < + partly_match) + match_type + = + partly_match; + } + matched++; + } + } + if (!matched) + vector_slot(v, i) = NULL; + } + } + return match_type; +} + +/* Filter vector by command character with index. */ +static enum match_type +cmd_filter_by_string(char *command, vector v, unsigned int index) +{ + unsigned int i; + const char *str; + struct cmd_element *cmd_element; + enum match_type match_type; + vector descvec; + struct desc *desc; + + match_type = no_match; + + /* If command and cmd_element string does not match set NULL to vector */ + for (i = 0; i < vector_active(v); i++) + if ((cmd_element = vector_slot(v, i)) != NULL) { + /* If given index is bigger than max string vector of command, + set NULL */ + if (index >= vector_active(cmd_element->strvec)) + vector_slot(v, i) = NULL; + else { + unsigned int j; + int matched = 0; + + descvec = + vector_slot(cmd_element->strvec, index); + + for (j = 0; j < vector_active(descvec); j++) + if ((desc = vector_slot(descvec, j))) { + str = desc->cmd; + + if (CMD_VARARG(str)) { + if (match_type < + vararg_match) + match_type = + vararg_match; + matched++; + } else if (CMD_RANGE(str)) { + if (cmd_range_match + (str, command)) { + if (match_type < + range_match) + match_type + = + range_match; + matched++; + } + } +#ifdef HAVE_IPV6 + else if (CMD_IPV6(str)) { + if (cmd_ipv6_match + (command) == + exact_match) { + if (match_type < + ipv6_match) + match_type + = + ipv6_match; + matched++; + } + } else if (CMD_IPV6_PREFIX(str)) { + if (cmd_ipv6_prefix_match(command) == exact_match) { + if (match_type < + ipv6_prefix_match) + match_type + = + ipv6_prefix_match; + matched++; + } + } +#endif /* HAVE_IPV6 */ + else if (CMD_IPV4(str)) { + if (cmd_ipv4_match + (command) == + exact_match) { + if (match_type < + ipv4_match) + match_type + = + ipv4_match; + matched++; + } + } else if (CMD_IPV4_PREFIX(str)) { + if (cmd_ipv4_prefix_match(command) == exact_match) { + if (match_type < + ipv4_prefix_match) + match_type + = + ipv4_prefix_match; + matched++; + } + } else if (CMD_OPTION(str) + || CMD_VARIABLE(str)) + { + if (match_type < + extend_match) + match_type = + extend_match; + matched++; + } else { + if (strcmp(command, str) + == 0) { + match_type = + exact_match; + matched++; + } + } + } + if (!matched) + vector_slot(v, i) = NULL; + } + } + return match_type; +} + +/* Check ambiguous match */ +static int +is_cmd_ambiguous(char *command, vector v, int index, enum match_type type) +{ + unsigned int i; + unsigned int j; + const char *str = NULL; + struct cmd_element *cmd_element; + const char *matched = NULL; + vector descvec; + struct desc *desc; + + for (i = 0; i < vector_active(v); i++) + if ((cmd_element = vector_slot(v, i)) != NULL) { + int match = 0; + + descvec = vector_slot(cmd_element->strvec, index); + + for (j = 0; j < vector_active(descvec); j++) + if ((desc = vector_slot(descvec, j))) { + enum match_type ret; + + str = desc->cmd; + + switch (type) { + case exact_match: + if (! + (CMD_OPTION(str) + || CMD_VARIABLE(str)) +&& strcmp(command, str) == 0) + match++; + break; + case partly_match: + if (! + (CMD_OPTION(str) + || CMD_VARIABLE(str)) +&& strncmp(command, str, strlen(command)) == 0) { + if (matched + && strcmp(matched, + str) != 0) + return 1; /* There is ambiguous match. */ + else + matched = str; + match++; + } + break; + case range_match: + if (cmd_range_match + (str, command)) { + if (matched + && strcmp(matched, + str) != 0) + return 1; + else + matched = str; + match++; + } + break; +#ifdef HAVE_IPV6 + case ipv6_match: + if (CMD_IPV6(str)) + match++; + break; + case ipv6_prefix_match: + if ((ret = + cmd_ipv6_prefix_match + (command)) != no_match) { + if (ret == partly_match) + return 2; /* There is incomplete match. */ + + match++; + } + break; +#endif /* HAVE_IPV6 */ + case ipv4_match: + if (CMD_IPV4(str)) + match++; + break; + case ipv4_prefix_match: + if ((ret = + cmd_ipv4_prefix_match + (command)) != no_match) { + if (ret == partly_match) + return 2; /* There is incomplete match. */ + + match++; + } + break; + case extend_match: + if (CMD_OPTION(str) + || CMD_VARIABLE(str)) + match++; + break; + case no_match: + default: + break; + } + } + if (!match) + vector_slot(v, i) = NULL; + } + return 0; +} + +/* If src matches dst return dst string, otherwise return NULL */ +static const char *cmd_entry_function(const char *src, const char *dst) +{ + /* Skip variable arguments. */ + if (CMD_OPTION(dst) || CMD_VARIABLE(dst) || CMD_VARARG(dst) || + CMD_IPV4(dst) || CMD_IPV4_PREFIX(dst) || CMD_RANGE(dst)) + return NULL; + + /* In case of 'command \t', given src is NULL string. */ + if (src == NULL) + return dst; + + /* Matched with input string. */ + if (strncmp(src, dst, strlen(src)) == 0) + return dst; + + return NULL; +} + +/* If src matches dst return dst string, otherwise return NULL */ +/* This version will return the dst string always if it is + CMD_VARIABLE for '?' key processing */ +static const char *cmd_entry_function_desc(const char *src, const char *dst) +{ + if (CMD_VARARG(dst)) + return dst; + + if (CMD_RANGE(dst)) { + if (cmd_range_match(dst, src)) + return dst; + else + return NULL; + } +#ifdef HAVE_IPV6 + if (CMD_IPV6(dst)) { + if (cmd_ipv6_match(src)) + return dst; + else + return NULL; + } + + if (CMD_IPV6_PREFIX(dst)) { + if (cmd_ipv6_prefix_match(src)) + return dst; + else + return NULL; + } +#endif /* HAVE_IPV6 */ + + if (CMD_IPV4(dst)) { + if (cmd_ipv4_match(src)) + return dst; + else + return NULL; + } + + if (CMD_IPV4_PREFIX(dst)) { + if (cmd_ipv4_prefix_match(src)) + return dst; + else + return NULL; + } + + /* Optional or variable commands always match on '?' */ + if (CMD_OPTION(dst) || CMD_VARIABLE(dst)) + return dst; + + /* In case of 'command \t', given src is NULL string. */ + if (src == NULL) + return dst; + + if (strncmp(src, dst, strlen(src)) == 0) + return dst; + else + return NULL; +} + +/* Check same string element existence. If it isn't there return + 1. */ +static int cmd_unique_string(vector v, const char *str) +{ + unsigned int i; + char *match; + + for (i = 0; i < vector_active(v); i++) + if ((match = vector_slot(v, i)) != NULL) + if (strcmp(match, str) == 0) + return 0; + return 1; +} + +/* Compare string to description vector. If there is same string + return 1 else return 0. */ +static int desc_unique_string(vector v, const char *str) +{ + unsigned int i; + struct desc *desc; + + for (i = 0; i < vector_active(v); i++) + if ((desc = vector_slot(v, i)) != NULL) + if (strcmp(desc->cmd, str) == 0) + return 1; + return 0; +} + +static int cmd_try_do_shortcut(enum node_type node, char *first_word) +{ + if (first_word != NULL && + node != AUTH_NODE && + node != VIEW_NODE && + node != AUTH_ENABLE_NODE && + node != ENABLE_NODE && 0 == strcmp("do", first_word)) + return 1; + return 0; +} + +/* '?' describe command support. */ +static vector +cmd_describe_command_real(vector vline, struct vty *vty, int *status) +{ + unsigned int i; + vector cmd_vector; +#define INIT_MATCHVEC_SIZE 10 + vector matchvec; + struct cmd_element *cmd_element; + unsigned int index; + int ret; + enum match_type match; + char *command; + static struct desc desc_cr = { "", "" }; + + /* Set index. */ + if (vector_active(vline) == 0) { + *status = CMD_ERR_NO_MATCH; + return NULL; + } else + index = vector_active(vline) - 1; + + /* Make copy vector of current node's command vector. */ + cmd_vector = vector_copy(cmd_node_vector(cmdvec, vty->node)); + + /* Prepare match vector */ + matchvec = vector_init(INIT_MATCHVEC_SIZE); + + /* Filter commands. */ + /* Only words precedes current word will be checked in this loop. */ + for (i = 0; i < index; i++) + if ((command = vector_slot(vline, i))) { + match = + cmd_filter_by_completion(command, cmd_vector, i); + + if (match == vararg_match) { + struct cmd_element *cmd_element; + vector descvec; + unsigned int j, k; + + for (j = 0; j < vector_active(cmd_vector); j++) + if ((cmd_element = + vector_slot(cmd_vector, j)) != NULL + && + (vector_active + (cmd_element->strvec))) { + descvec = + vector_slot(cmd_element-> + strvec, + vector_active + (cmd_element-> + strvec) - 1); + for (k = 0; + k < vector_active(descvec); + k++) { + struct desc *desc = + vector_slot(descvec, + k); + vector_set(matchvec, + desc); + } + } + + vector_set(matchvec, &desc_cr); + vector_free(cmd_vector); + + return matchvec; + } + + if ((ret = + is_cmd_ambiguous(command, cmd_vector, i, + match)) == 1) { + vector_free(cmd_vector); + *status = CMD_ERR_AMBIGUOUS; + return NULL; + } else if (ret == 2) { + vector_free(cmd_vector); + *status = CMD_ERR_NO_MATCH; + return NULL; + } + } + + /* Prepare match vector */ + /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */ + + /* Make sure that cmd_vector is filtered based on current word */ + command = vector_slot(vline, index); + if (command) + match = cmd_filter_by_completion(command, cmd_vector, index); + + /* Make description vector. */ + for (i = 0; i < vector_active(cmd_vector); i++) + if ((cmd_element = vector_slot(cmd_vector, i)) != NULL) { + const char *string = NULL; + vector strvec = cmd_element->strvec; + + /* if command is NULL, index may be equal to vector_active */ + if (command && index >= vector_active(strvec)) + vector_slot(cmd_vector, i) = NULL; + else { + /* Check if command is completed. */ + if (command == NULL + && index == vector_active(strvec)) { + string = ""; + if (!desc_unique_string + (matchvec, string)) + vector_set(matchvec, &desc_cr); + } else { + unsigned int j; + vector descvec = + vector_slot(strvec, index); + struct desc *desc; + + for (j = 0; j < vector_active(descvec); + j++) + if ((desc = + vector_slot(descvec, j))) { + string = + cmd_entry_function_desc + (command, + desc->cmd); + if (string) { + /* Uniqueness check */ + if (!desc_unique_string(matchvec, string)) + vector_set + (matchvec, + desc); + } + } + } + } + } + vector_free(cmd_vector); + + if (vector_slot(matchvec, 0) == NULL) { + vector_free(matchvec); + *status = CMD_ERR_NO_MATCH; + } else + *status = CMD_SUCCESS; + + return matchvec; +} + +vector cmd_describe_command(vector vline, struct vty * vty, int *status) +{ + vector ret; + + if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0))) { + enum node_type onode; + vector shifted_vline; + unsigned int index; + + onode = vty->node; + vty->node = ENABLE_NODE; + /* We can try it on enable node, cos' the vty is authenticated */ + + shifted_vline = vector_init(vector_count(vline)); + /* use memcpy? */ + for (index = 1; index < vector_active(vline); index++) { + vector_set_index(shifted_vline, index - 1, + vector_lookup(vline, index)); + } + + ret = cmd_describe_command_real(shifted_vline, vty, status); + + vector_free(shifted_vline); + vty->node = onode; + return ret; + } + + return cmd_describe_command_real(vline, vty, status); +} + +/* Check LCD of matched command. */ +static int cmd_lcd(char **matched) +{ + int i; + int j; + int lcd = -1; + char *s1, *s2; + char c1, c2; + + if (matched[0] == NULL || matched[1] == NULL) + return 0; + + for (i = 1; matched[i] != NULL; i++) { + s1 = matched[i - 1]; + s2 = matched[i]; + + for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++) + if (c1 != c2) + break; + + if (lcd < 0) + lcd = j; + else { + if (lcd > j) + lcd = j; + } + } + return lcd; +} + +/* Command line completion support. */ +static char **cmd_complete_command_real(vector vline, struct vty *vty, + int *status) +{ + unsigned int i; + vector cmd_vector = vector_copy(cmd_node_vector(cmdvec, vty->node)); +#define INIT_MATCHVEC_SIZE 10 + vector matchvec; + struct cmd_element *cmd_element; + unsigned int index; + char **match_str; + struct desc *desc; + vector descvec; + char *command; + int lcd; + + if (vector_active(vline) == 0) { + *status = CMD_ERR_NO_MATCH; + return NULL; + } else + index = vector_active(vline) - 1; + + /* First, filter by preceeding command string */ + for (i = 0; i < index; i++) + if ((command = vector_slot(vline, i))) { + enum match_type match; + int ret; + + /* First try completion match, if there is exactly match return 1 */ + match = + cmd_filter_by_completion(command, cmd_vector, i); + + /* If there is exact match then filter ambiguous match else check + ambiguousness. */ + if ((ret = + is_cmd_ambiguous(command, cmd_vector, i, + match)) == 1) { + vector_free(cmd_vector); + *status = CMD_ERR_AMBIGUOUS; + return NULL; + } + /* + else if (ret == 2) + { + vector_free (cmd_vector); + *status = CMD_ERR_NO_MATCH; + return NULL; + } + */ + } + + /* Prepare match vector. */ + matchvec = vector_init(INIT_MATCHVEC_SIZE); + + /* Now we got into completion */ + for (i = 0; i < vector_active(cmd_vector); i++) + if ((cmd_element = vector_slot(cmd_vector, i))) { + const char *string; + vector strvec = cmd_element->strvec; + + /* Check field length */ + if (index >= vector_active(strvec)) + vector_slot(cmd_vector, i) = NULL; + else { + unsigned int j; + + descvec = vector_slot(strvec, index); + for (j = 0; j < vector_active(descvec); j++) + if ((desc = vector_slot(descvec, j))) { + if ((string = + cmd_entry_function + (vector_slot(vline, index), + desc->cmd))) + if (cmd_unique_string + (matchvec, string)) + vector_set + (matchvec, + strdup + (string)); + } + } + } + + /* We don't need cmd_vector any more. */ + vector_free(cmd_vector); + + /* No matched command */ + if (vector_slot(matchvec, 0) == NULL) { + vector_free(matchvec); + + /* In case of 'command \t' pattern. Do you need '?' command at + the end of the line. */ + if (vector_slot(vline, index) == '\0') + *status = CMD_ERR_NOTHING_TODO; + else + *status = CMD_ERR_NO_MATCH; + return NULL; + } + + /* Only one matched */ + if (vector_slot(matchvec, 1) == NULL) { + match_str = (char **)matchvec->index; + vector_only_wrapper_free(matchvec); + *status = CMD_COMPLETE_FULL_MATCH; + return match_str; + } + /* Make it sure last element is NULL. */ + vector_set(matchvec, NULL); + + /* Check LCD of matched strings. */ + if (vector_slot(vline, index) != NULL) { + lcd = cmd_lcd((char **)matchvec->index); + + if (lcd) { + int len = strlen(vector_slot(vline, index)); + + if (len < lcd) { + char *lcdstr; + + lcdstr = malloc(lcd + 1); + memcpy(lcdstr, matchvec->index[0], lcd); + lcdstr[lcd] = '\0'; + + /* match_str = (char **) &lcdstr; */ + + /* Free matchvec. */ + for (i = 0; i < vector_active(matchvec); i++) { + if (vector_slot(matchvec, i)) + free(vector_slot(matchvec, i)); + } + vector_free(matchvec); + + /* Make new matchvec. */ + matchvec = vector_init(INIT_MATCHVEC_SIZE); + vector_set(matchvec, lcdstr); + match_str = (char **)matchvec->index; + vector_only_wrapper_free(matchvec); + + *status = CMD_COMPLETE_MATCH; + return match_str; + } + } + } + + match_str = (char **)matchvec->index; + vector_only_wrapper_free(matchvec); + *status = CMD_COMPLETE_LIST_MATCH; + return match_str; +} + +char **cmd_complete_command(vector vline, struct vty *vty, int *status) +{ + char **ret; + + if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0))) { + enum node_type onode; + vector shifted_vline; + unsigned int index; + + onode = vty->node; + vty->node = ENABLE_NODE; + /* We can try it on enable node, cos' the vty is authenticated */ + + shifted_vline = vector_init(vector_count(vline)); + /* use memcpy? */ + for (index = 1; index < vector_active(vline); index++) { + vector_set_index(shifted_vline, index - 1, + vector_lookup(vline, index)); + } + + ret = cmd_complete_command_real(shifted_vline, vty, status); + + vector_free(shifted_vline); + vty->node = onode; + return ret; + } + + return cmd_complete_command_real(vline, vty, status); +} + +/* return parent node */ +/* MUST eventually converge on CONFIG_NODE */ +enum node_type node_parent(enum node_type node) +{ + enum node_type ret; + + assert(node > CONFIG_NODE); + + switch (node) { + case BGP_VPNV4_NODE: + case BGP_IPV4_NODE: + case BGP_IPV4M_NODE: + case BGP_IPV6_NODE: + ret = BGP_NODE; + break; + case KEYCHAIN_KEY_NODE: + ret = KEYCHAIN_NODE; + break; + default: + ret = CONFIG_NODE; + } + + return ret; +} + +/* Execute command by argument vline vector. */ +static int +cmd_execute_command_real(vector vline, struct vty *vty, + struct cmd_element **cmd) +{ + unsigned int i; + unsigned int index; + vector cmd_vector; + struct cmd_element *cmd_element; + struct cmd_element *matched_element; + unsigned int matched_count, incomplete_count; + int argc; + const char *argv[CMD_ARGC_MAX]; + enum match_type match = 0; + int varflag; + char *command; + + /* Make copy of command elements. */ + cmd_vector = vector_copy(cmd_node_vector(cmdvec, vty->node)); + + for (index = 0; index < vector_active(vline); index++) + if ((command = vector_slot(vline, index))) { + int ret; + + match = + cmd_filter_by_completion(command, cmd_vector, + index); + + if (match == vararg_match) + break; + + ret = + is_cmd_ambiguous(command, cmd_vector, index, match); + + if (ret == 1) { + vector_free(cmd_vector); + return CMD_ERR_AMBIGUOUS; + } else if (ret == 2) { + vector_free(cmd_vector); + return CMD_ERR_NO_MATCH; + } + } + + /* Check matched count. */ + matched_element = NULL; + matched_count = 0; + incomplete_count = 0; + + for (i = 0; i < vector_active(cmd_vector); i++) + if ((cmd_element = vector_slot(cmd_vector, i))) { + if (match == vararg_match + || index >= cmd_element->cmdsize) { + matched_element = cmd_element; +#if 0 + printf("DEBUG: %s\n", cmd_element->string); +#endif + matched_count++; + } else { + incomplete_count++; + } + } + + /* Finish of using cmd_vector. */ + vector_free(cmd_vector); + + /* To execute command, matched_count must be 1. */ + if (matched_count == 0) { + if (incomplete_count) + return CMD_ERR_INCOMPLETE; + else + return CMD_ERR_NO_MATCH; + } + + if (matched_count > 1) + return CMD_ERR_AMBIGUOUS; + + /* Argument treatment */ + varflag = 0; + argc = 0; + + for (i = 0; i < vector_active(vline); i++) { + if (varflag) + argv[argc++] = vector_slot(vline, i); + else { + vector descvec = + vector_slot(matched_element->strvec, i); + + if (vector_active(descvec) == 1) { + struct desc *desc = vector_slot(descvec, 0); + + if (CMD_VARARG(desc->cmd)) + varflag = 1; + + if (varflag || CMD_VARIABLE(desc->cmd) + || CMD_OPTION(desc->cmd)) + argv[argc++] = vector_slot(vline, i); + } else + argv[argc++] = vector_slot(vline, i); + } + + if (argc >= CMD_ARGC_MAX) + return CMD_ERR_EXEED_ARGC_MAX; + } + + /* For vtysh execution. */ + if (cmd) + *cmd = matched_element; + + if (matched_element->daemon) + return CMD_SUCCESS_DAEMON; + + /* Execute matched command. */ + return (*matched_element->func) (matched_element, vty, argc, argv); +} + +int +cmd_execute_command(vector vline, struct vty *vty, struct cmd_element **cmd, + int vtysh) +{ + int ret, saved_ret, tried = 0; + enum node_type onode, try_node; + + onode = try_node = vty->node; + + if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0))) { + vector shifted_vline; + unsigned int index; + + vty->node = ENABLE_NODE; + /* We can try it on enable node, cos' the vty is authenticated */ + + shifted_vline = vector_init(vector_count(vline)); + /* use memcpy? */ + for (index = 1; index < vector_active(vline); index++) { + vector_set_index(shifted_vline, index - 1, + vector_lookup(vline, index)); + } + + ret = cmd_execute_command_real(shifted_vline, vty, cmd); + + vector_free(shifted_vline); + vty->node = onode; + return ret; + } + + saved_ret = ret = cmd_execute_command_real(vline, vty, cmd); + + if (vtysh) + return saved_ret; + + /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */ + while (ret != CMD_SUCCESS && ret != CMD_WARNING + && vty->node > CONFIG_NODE) { + try_node = node_parent(try_node); + vty->node = try_node; + ret = cmd_execute_command_real(vline, vty, cmd); + tried = 1; + if (ret == CMD_SUCCESS || ret == CMD_WARNING) { + /* succesfull command, leave the node as is */ + return ret; + } + } + /* no command succeeded, reset the vty to the original node and + return the error for this node */ + if (tried) + vty->node = onode; + return saved_ret; +} + +/* Execute command by argument readline. */ +int +cmd_execute_command_strict(vector vline, struct vty *vty, + struct cmd_element **cmd) +{ + unsigned int i; + unsigned int index; + vector cmd_vector; + struct cmd_element *cmd_element; + struct cmd_element *matched_element; + unsigned int matched_count, incomplete_count; + int argc; + const char *argv[CMD_ARGC_MAX]; + int varflag; + enum match_type match = 0; + char *command; + + /* Make copy of command element */ + cmd_vector = vector_copy(cmd_node_vector(cmdvec, vty->node)); + + for (index = 0; index < vector_active(vline); index++) + if ((command = vector_slot(vline, index))) { + int ret; + + match = cmd_filter_by_string(vector_slot(vline, index), + cmd_vector, index); + + /* If command meets '.VARARG' then finish matching. */ + if (match == vararg_match) + break; + + ret = + is_cmd_ambiguous(command, cmd_vector, index, match); + if (ret == 1) { + vector_free(cmd_vector); + return CMD_ERR_AMBIGUOUS; + } + if (ret == 2) { + vector_free(cmd_vector); + return CMD_ERR_NO_MATCH; + } + } + + /* Check matched count. */ + matched_element = NULL; + matched_count = 0; + incomplete_count = 0; + for (i = 0; i < vector_active(cmd_vector); i++) + if (vector_slot(cmd_vector, i) != NULL) { + cmd_element = vector_slot(cmd_vector, i); + + if (match == vararg_match + || index >= cmd_element->cmdsize) { + matched_element = cmd_element; + matched_count++; + } else + incomplete_count++; + } + + /* Finish of using cmd_vector. */ + vector_free(cmd_vector); + + /* To execute command, matched_count must be 1. */ + if (matched_count == 0) { + if (incomplete_count) + return CMD_ERR_INCOMPLETE; + else + return CMD_ERR_NO_MATCH; + } + + if (matched_count > 1) + return CMD_ERR_AMBIGUOUS; + + /* Argument treatment */ + varflag = 0; + argc = 0; + + for (i = 0; i < vector_active(vline); i++) { + if (varflag) + argv[argc++] = vector_slot(vline, i); + else { + vector descvec = + vector_slot(matched_element->strvec, i); + + if (vector_active(descvec) == 1) { + struct desc *desc = vector_slot(descvec, 0); + + if (CMD_VARARG(desc->cmd)) + varflag = 1; + + if (varflag || CMD_VARIABLE(desc->cmd) + || CMD_OPTION(desc->cmd)) + argv[argc++] = vector_slot(vline, i); + } else + argv[argc++] = vector_slot(vline, i); + } + + if (argc >= CMD_ARGC_MAX) + return CMD_ERR_EXEED_ARGC_MAX; + } + + /* For vtysh execution. */ + if (cmd) + *cmd = matched_element; + + if (matched_element->daemon) + return CMD_SUCCESS_DAEMON; + + /* Now execute matched command */ + return (*matched_element->func) (matched_element, vty, argc, argv); +} + +#if 0 +/* Configration make from file. */ +int config_from_file(struct vty *vty, FILE * fp) +{ + int ret; + vector vline; + + while (fgets(vty->buf, VTY_BUFSIZ, fp)) { + vline = cmd_make_strvec(vty->buf); + + /* In case of comment line */ + if (vline == NULL) + continue; + /* Execute configuration command : this is strict match */ + ret = cmd_execute_command_strict(vline, vty, NULL); + + /* Try again with setting node to CONFIG_NODE */ + while (ret != CMD_SUCCESS && ret != CMD_WARNING + && ret != CMD_ERR_NOTHING_TODO + && vty->node != CONFIG_NODE) { + vty->node = node_parent(vty->node); + ret = cmd_execute_command_strict(vline, vty, NULL); + } + + cmd_free_strvec(vline); + + if (ret != CMD_SUCCESS && ret != CMD_WARNING + && ret != CMD_ERR_NOTHING_TODO) + return ret; + } + return CMD_SUCCESS; +} +#endif + +/* Configration from terminal */ +DEFUN(config_terminal, + config_terminal_cmd, + "configure terminal", + "Configuration from vty interface\n" "Configuration terminal\n") +{ + if (vty_config_lock(vty)) + vty->node = CONFIG_NODE; + else { + vty_out(vty, "VTY configuration is locked by other VTY%s", + VTY_NEWLINE); + return CMD_WARNING; + } + return CMD_SUCCESS; +} + +/* Enable command */ +DEFUN(enable, config_enable_cmd, "enable", "Turn on privileged mode command\n") +{ + /* If enable password is NULL, change to ENABLE_NODE */ + if ((host.enable == NULL && host.enable_encrypt == NULL) || + vty->type == VTY_SHELL_SERV) + vty->node = ENABLE_NODE; + else + vty->node = AUTH_ENABLE_NODE; + + return CMD_SUCCESS; +} + +/* Disable command */ +DEFUN(disable, + config_disable_cmd, "disable", "Turn off privileged mode command\n") +{ + if (vty->node == ENABLE_NODE) + vty->node = VIEW_NODE; + return CMD_SUCCESS; +} + +/* Down vty node level. */ +DEFUN(config_exit, + config_exit_cmd, "exit", "Exit current mode and down to previous mode\n") +{ + switch (vty->node) { + case RC632_NODE: + vty->node = VIEW_NODE; + break; + case VIEW_NODE: + case ENABLE_NODE: + if (0) //vty_shell (vty)) + exit(0); + else + vty->status = VTY_CLOSE; + break; + case CONFIG_NODE: + vty->node = ENABLE_NODE; + vty_config_unlock(vty); + break; + case INTERFACE_NODE: + case ZEBRA_NODE: + case BGP_NODE: + case RIP_NODE: + case RIPNG_NODE: + case OSPF_NODE: + case OSPF6_NODE: + case ISIS_NODE: + case KEYCHAIN_NODE: + case MASC_NODE: + case RMAP_NODE: + case VTY_NODE: + vty->node = CONFIG_NODE; + break; + case BGP_VPNV4_NODE: + case BGP_IPV4_NODE: + case BGP_IPV4M_NODE: + case BGP_IPV6_NODE: + vty->node = BGP_NODE; + break; + case KEYCHAIN_KEY_NODE: + vty->node = KEYCHAIN_NODE; + break; + default: + break; + } + return CMD_SUCCESS; +} + +/* quit is alias of exit. */ +ALIAS(config_exit, + config_quit_cmd, "quit", "Exit current mode and down to previous mode\n") + +/* End of configuration. */ + DEFUN(config_end, + config_end_cmd, "end", "End current mode and change to enable mode.") +{ + switch (vty->node) { + case VIEW_NODE: + case ENABLE_NODE: + /* Nothing to do. */ + break; + case CONFIG_NODE: + case INTERFACE_NODE: + case ZEBRA_NODE: + case RIP_NODE: + case RIPNG_NODE: + case BGP_NODE: + case BGP_VPNV4_NODE: + case BGP_IPV4_NODE: + case BGP_IPV4M_NODE: + case BGP_IPV6_NODE: + case RMAP_NODE: + case OSPF_NODE: + case OSPF6_NODE: + case ISIS_NODE: + case KEYCHAIN_NODE: + case KEYCHAIN_KEY_NODE: + case MASC_NODE: + case VTY_NODE: + vty_config_unlock(vty); + vty->node = ENABLE_NODE; + break; + default: + break; + } + return CMD_SUCCESS; +} + +/* Show version. */ +DEFUN(show_version, + show_version_cmd, "show version", SHOW_STR "Displays program version\n") +{ + vty_out(vty, "%s %s (%s).%s", QUAGGA_PROGNAME, QUAGGA_VERSION, + host.name ? host.name : "", VTY_NEWLINE); + vty_out(vty, "%s%s", QUAGGA_COPYRIGHT, VTY_NEWLINE); + + return CMD_SUCCESS; +} + +/* Help display function for all node. */ +DEFUN(config_help, + config_help_cmd, "help", "Description of the interactive help system\n") +{ + vty_out(vty, + "This VTY provides advanced help features. When you need help,%s\ +anytime at the command line please press '?'.%s\ +%s\ +If nothing matches, the help list will be empty and you must backup%s\ + until entering a '?' shows the available options.%s\ +Two styles of help are provided:%s\ +1. Full help is available when you are ready to enter a%s\ +command argument (e.g. 'show ?') and describes each possible%s\ +argument.%s\ +2. Partial help is provided when an abbreviated argument is entered%s\ + and you want to know what arguments match the input%s\ + (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, + VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + return CMD_SUCCESS; +} + +/* Help display function for all node. */ +DEFUN(config_list, config_list_cmd, "list", "Print command list\n") +{ + unsigned int i; + struct cmd_node *cnode = vector_slot(cmdvec, vty->node); + struct cmd_element *cmd; + + for (i = 0; i < vector_active(cnode->cmd_vector); i++) + if ((cmd = vector_slot(cnode->cmd_vector, i)) != NULL + && !(cmd->attr == CMD_ATTR_DEPRECATED + || cmd->attr == CMD_ATTR_HIDDEN)) + vty_out(vty, " %s%s", cmd->string, VTY_NEWLINE); + return CMD_SUCCESS; +} + +#if 0 +/* Write current configuration into file. */ +DEFUN(config_write_file, + config_write_file_cmd, + "write file", + "Write running configuration to memory, network, or terminal\n" + "Write to configuration file\n") +{ + unsigned int i; + int fd; + struct cmd_node *node; + char *config_file; + char *config_file_tmp = NULL; + char *config_file_sav = NULL; + struct vty *file_vty; + + /* Check and see if we are operating under vtysh configuration */ + if (host.config == NULL) { + vty_out(vty, "Can't save to configuration file, using vtysh.%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Get filename. */ + config_file = host.config; + + config_file_sav = + malloc(strlen(config_file) + strlen(CONF_BACKUP_EXT) + 1); + strcpy(config_file_sav, config_file); + strcat(config_file_sav, CONF_BACKUP_EXT); + + config_file_tmp = malloc(strlen(config_file) + 8); + sprintf(config_file_tmp, "%s.XXXXXX", config_file); + + /* Open file to configuration write. */ + fd = mkstemp(config_file_tmp); + if (fd < 0) { + vty_out(vty, "Can't open configuration file %s.%s", + config_file_tmp, VTY_NEWLINE); + free(config_file_tmp); + free(config_file_sav); + return CMD_WARNING; + } + + /* Make vty for configuration file. */ + file_vty = vty_new(); + file_vty->fd = fd; + file_vty->type = VTY_FILE; + + /* Config file header print. */ + vty_out(file_vty, "!\n! Zebra configuration saved from vty\n! "); + //vty_time_print (file_vty, 1); + vty_out(file_vty, "!\n"); + + for (i = 0; i < vector_active(cmdvec); i++) + if ((node = vector_slot(cmdvec, i)) && node->func) { + if ((*node->func) (file_vty)) + vty_out(file_vty, "!\n"); + } + vty_close(file_vty); + + if (unlink(config_file_sav) != 0) + if (errno != ENOENT) { + vty_out(vty, + "Can't unlink backup configuration file %s.%s", + config_file_sav, VTY_NEWLINE); + free(config_file_sav); + free(config_file_tmp); + unlink(config_file_tmp); + return CMD_WARNING; + } + if (link(config_file, config_file_sav) != 0) { + vty_out(vty, "Can't backup old configuration file %s.%s", + config_file_sav, VTY_NEWLINE); + free(config_file_sav); + free(config_file_tmp); + unlink(config_file_tmp); + return CMD_WARNING; + } + sync(); + if (unlink(config_file) != 0) { + vty_out(vty, "Can't unlink configuration file %s.%s", + config_file, VTY_NEWLINE); + free(config_file_sav); + free(config_file_tmp); + unlink(config_file_tmp); + return CMD_WARNING; + } + if (link(config_file_tmp, config_file) != 0) { + vty_out(vty, "Can't save configuration file %s.%s", config_file, + VTY_NEWLINE); + free(config_file_sav); + free(config_file_tmp); + unlink(config_file_tmp); + return CMD_WARNING; + } + unlink(config_file_tmp); + sync(); + + free(config_file_sav); + free(config_file_tmp); + + if (chmod(config_file, CONFIGFILE_MASK) != 0) { + vty_out(vty, "Can't chmod configuration file %s: %s (%d).%s", + config_file, safe_strerror(errno), errno, VTY_NEWLINE); + return CMD_WARNING; + } + + vty_out(vty, "Configuration saved to %s%s", config_file, VTY_NEWLINE); + return CMD_SUCCESS; +} + +ALIAS(config_write_file, + config_write_cmd, + "write", "Write running configuration to memory, network, or terminal\n") + + ALIAS(config_write_file, + config_write_memory_cmd, + "write memory", + "Write running configuration to memory, network, or terminal\n" + "Write configuration to the file (same as write file)\n") + + ALIAS(config_write_file, + copy_runningconfig_startupconfig_cmd, + "copy running-config startup-config", + "Copy configuration\n" + "Copy running config to... \n" + "Copy running config to startup config (same as write file)\n") + +/* Write current configuration into the terminal. */ + DEFUN(config_write_terminal, + config_write_terminal_cmd, + "write terminal", + "Write running configuration to memory, network, or terminal\n" + "Write to terminal\n") +{ + unsigned int i; + struct cmd_node *node; + + if (vty->type == VTY_SHELL_SERV) { + for (i = 0; i < vector_active(cmdvec); i++) + if ((node = vector_slot(cmdvec, i)) && node->func + && node->vtysh) { + if ((*node->func) (vty)) + vty_out(vty, "!%s", VTY_NEWLINE); + } + } else { + vty_out(vty, "%sCurrent configuration:%s", VTY_NEWLINE, + VTY_NEWLINE); + vty_out(vty, "!%s", VTY_NEWLINE); + + for (i = 0; i < vector_active(cmdvec); i++) + if ((node = vector_slot(cmdvec, i)) && node->func) { + if ((*node->func) (vty)) + vty_out(vty, "!%s", VTY_NEWLINE); + } + vty_out(vty, "end%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +/* Write current configuration into the terminal. */ +ALIAS(config_write_terminal, + show_running_config_cmd, + "show running-config", SHOW_STR "running configuration\n") + +/* Write startup configuration into the terminal. */ + DEFUN(show_startup_config, + show_startup_config_cmd, + "show startup-config", SHOW_STR "Contentes of startup configuration\n") +{ + char buf[BUFSIZ]; + FILE *confp; + + confp = fopen(host.config, "r"); + if (confp == NULL) { + vty_out(vty, "Can't open configuration file [%s]%s", + host.config, VTY_NEWLINE); + return CMD_WARNING; + } + + while (fgets(buf, BUFSIZ, confp)) { + char *cp = buf; + + while (*cp != '\r' && *cp != '\n' && *cp != '\0') + cp++; + *cp = '\0'; + + vty_out(vty, "%s%s", buf, VTY_NEWLINE); + } + + fclose(confp); + + return CMD_SUCCESS; +} +#endif + +/* Hostname configuration */ +DEFUN(config_hostname, + hostname_cmd, + "hostname WORD", + "Set system's network name\n" "This system's network name\n") +{ + if (!isalpha((int)*argv[0])) { + vty_out(vty, "Please specify string starting with alphabet%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if (host.name) + free(host.name); + + host.name = strdup(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(config_no_hostname, + no_hostname_cmd, + "no hostname [HOSTNAME]", + NO_STR "Reset system's network name\n" "Host name of this router\n") +{ + if (host.name) + free(host.name); + host.name = NULL; + return CMD_SUCCESS; +} + +/* VTY interface password set. */ +DEFUN(config_password, password_cmd, + "password (8|) WORD", + "Assign the terminal connection password\n" + "Specifies a HIDDEN password will follow\n" + "dummy string \n" "The HIDDEN line password string\n") +{ + /* Argument check. */ + if (argc == 0) { + vty_out(vty, "Please specify password.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (argc == 2) { + if (*argv[0] == '8') { + if (host.password) + free(host.password); + host.password = NULL; + if (host.password_encrypt) + free(host.password_encrypt); + host.password_encrypt = strdup(strdup(argv[1])); + return CMD_SUCCESS; + } else { + vty_out(vty, "Unknown encryption type.%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + if (!isalnum((int)*argv[0])) { + vty_out(vty, + "Please specify string starting with alphanumeric%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if (host.password) + free(host.password); + host.password = NULL; + + if (host.encrypt) { + if (host.password_encrypt) + free(host.password_encrypt); + host.password_encrypt = strdup(zencrypt(argv[0])); + } else + host.password = strdup(argv[0]); + + return CMD_SUCCESS; +} + +ALIAS(config_password, password_text_cmd, + "password LINE", + "Assign the terminal connection password\n" + "The UNENCRYPTED (cleartext) line password\n") + +/* VTY enable password set. */ + DEFUN(config_enable_password, enable_password_cmd, + "enable password (8|) WORD", + "Modify enable password parameters\n" + "Assign the privileged level password\n" + "Specifies a HIDDEN password will follow\n" + "dummy string \n" "The HIDDEN 'enable' password string\n") +{ + /* Argument check. */ + if (argc == 0) { + vty_out(vty, "Please specify password.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Crypt type is specified. */ + if (argc == 2) { + if (*argv[0] == '8') { + if (host.enable) + free(host.enable); + host.enable = NULL; + + if (host.enable_encrypt) + free(host.enable_encrypt); + host.enable_encrypt = strdup(argv[1]); + + return CMD_SUCCESS; + } else { + vty_out(vty, "Unknown encryption type.%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + if (!isalnum((int)*argv[0])) { + vty_out(vty, + "Please specify string starting with alphanumeric%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if (host.enable) + free(host.enable); + host.enable = NULL; + + /* Plain password input. */ + if (host.encrypt) { + if (host.enable_encrypt) + free(host.enable_encrypt); + host.enable_encrypt = strdup(zencrypt(argv[0])); + } else + host.enable = strdup(argv[0]); + + return CMD_SUCCESS; +} + +ALIAS(config_enable_password, + enable_password_text_cmd, + "enable password LINE", + "Modify enable password parameters\n" + "Assign the privileged level password\n" + "The UNENCRYPTED (cleartext) 'enable' password\n") + +/* VTY enable password delete. */ + DEFUN(no_config_enable_password, no_enable_password_cmd, + "no enable password", + NO_STR + "Modify enable password parameters\n" + "Assign the privileged level password\n") +{ + if (host.enable) + free(host.enable); + host.enable = NULL; + + if (host.enable_encrypt) + free(host.enable_encrypt); + host.enable_encrypt = NULL; + + return CMD_SUCCESS; +} + +DEFUN(service_password_encrypt, + service_password_encrypt_cmd, + "service password-encryption", + "Set up miscellaneous service\n" "Enable encrypted passwords\n") +{ + if (host.encrypt) + return CMD_SUCCESS; + + host.encrypt = 1; + + if (host.password) { + if (host.password_encrypt) + free(host.password_encrypt); + host.password_encrypt = strdup(zencrypt(host.password)); + } + if (host.enable) { + if (host.enable_encrypt) + free(host.enable_encrypt); + host.enable_encrypt = strdup(zencrypt(host.enable)); + } + + return CMD_SUCCESS; +} + +DEFUN(no_service_password_encrypt, + no_service_password_encrypt_cmd, + "no service password-encryption", + NO_STR "Set up miscellaneous service\n" "Enable encrypted passwords\n") +{ + if (!host.encrypt) + return CMD_SUCCESS; + + host.encrypt = 0; + + if (host.password_encrypt) + free(host.password_encrypt); + host.password_encrypt = NULL; + + if (host.enable_encrypt) + free(host.enable_encrypt); + host.enable_encrypt = NULL; + + return CMD_SUCCESS; +} + +DEFUN(config_terminal_length, config_terminal_length_cmd, + "terminal length <0-512>", + "Set terminal line parameters\n" + "Set number of lines on a screen\n" + "Number of lines on screen (0 for no pausing)\n") +{ + int lines; + char *endptr = NULL; + + lines = strtol(argv[0], &endptr, 10); + if (lines < 0 || lines > 512 || *endptr != '\0') { + vty_out(vty, "length is malformed%s", VTY_NEWLINE); + return CMD_WARNING; + } + vty->lines = lines; + + return CMD_SUCCESS; +} + +DEFUN(config_terminal_no_length, config_terminal_no_length_cmd, + "terminal no length", + "Set terminal line parameters\n" + NO_STR "Set number of lines on a screen\n") +{ + vty->lines = -1; + return CMD_SUCCESS; +} + +DEFUN(service_terminal_length, service_terminal_length_cmd, + "service terminal-length <0-512>", + "Set up miscellaneous service\n" + "System wide terminal length configuration\n" + "Number of lines of VTY (0 means no line control)\n") +{ + int lines; + char *endptr = NULL; + + lines = strtol(argv[0], &endptr, 10); + if (lines < 0 || lines > 512 || *endptr != '\0') { + vty_out(vty, "length is malformed%s", VTY_NEWLINE); + return CMD_WARNING; + } + host.lines = lines; + + return CMD_SUCCESS; +} + +DEFUN(no_service_terminal_length, no_service_terminal_length_cmd, + "no service terminal-length [<0-512>]", + NO_STR + "Set up miscellaneous service\n" + "System wide terminal length configuration\n" + "Number of lines of VTY (0 means no line control)\n") +{ + host.lines = -1; + return CMD_SUCCESS; +} + +DEFUN_HIDDEN(do_echo, + echo_cmd, + "echo .MESSAGE", + "Echo a message back to the vty\n" "The message to echo\n") +{ + char *message; + + vty_out(vty, "%s%s", + ((message = + argv_concat(argv, argc, 0)) ? message : ""), VTY_NEWLINE); + if (message) + free(message); + return CMD_SUCCESS; +} + +#if 0 +DEFUN(config_logmsg, + config_logmsg_cmd, + "logmsg " LOG_LEVELS " .MESSAGE", + "Send a message to enabled logging destinations\n" + LOG_LEVEL_DESC "The message to send\n") +{ + int level; + char *message; + + if ((level = level_match(argv[0])) == ZLOG_DISABLED) + return CMD_ERR_NO_MATCH; + + zlog(NULL, level, + ((message = argv_concat(argv, argc, 1)) ? message : "")); + if (message) + free(message); + return CMD_SUCCESS; +} + +DEFUN(show_logging, + show_logging_cmd, + "show logging", SHOW_STR "Show current logging configuration\n") +{ + struct zlog *zl = zlog_default; + + vty_out(vty, "Syslog logging: "); + if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED) + vty_out(vty, "disabled"); + else + vty_out(vty, "level %s, facility %s, ident %s", + zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]], + facility_name(zl->facility), zl->ident); + vty_out(vty, "%s", VTY_NEWLINE); + + vty_out(vty, "Stdout logging: "); + if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED) + vty_out(vty, "disabled"); + else + vty_out(vty, "level %s", + zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]); + vty_out(vty, "%s", VTY_NEWLINE); + + vty_out(vty, "Monitor logging: "); + if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED) + vty_out(vty, "disabled"); + else + vty_out(vty, "level %s", + zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]); + vty_out(vty, "%s", VTY_NEWLINE); + + vty_out(vty, "File logging: "); + if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) || !zl->fp) + vty_out(vty, "disabled"); + else + vty_out(vty, "level %s, filename %s", + zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]], + zl->filename); + vty_out(vty, "%s", VTY_NEWLINE); + + vty_out(vty, "Protocol name: %s%s", + zlog_proto_names[zl->protocol], VTY_NEWLINE); + vty_out(vty, "Record priority: %s%s", + (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE); + + return CMD_SUCCESS; +} + +DEFUN(config_log_stdout, + config_log_stdout_cmd, + "log stdout", "Logging control\n" "Set stdout logging level\n") +{ + zlog_set_level(NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl); + return CMD_SUCCESS; +} + +DEFUN(config_log_stdout_level, + config_log_stdout_level_cmd, + "log stdout " LOG_LEVELS, + "Logging control\n" "Set stdout logging level\n" LOG_LEVEL_DESC) +{ + int level; + + if ((level = level_match(argv[0])) == ZLOG_DISABLED) + return CMD_ERR_NO_MATCH; + zlog_set_level(NULL, ZLOG_DEST_STDOUT, level); + return CMD_SUCCESS; +} + +DEFUN(no_config_log_stdout, + no_config_log_stdout_cmd, + "no log stdout [LEVEL]", + NO_STR "Logging control\n" "Cancel logging to stdout\n" "Logging level\n") +{ + zlog_set_level(NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED); + return CMD_SUCCESS; +} + +DEFUN(config_log_monitor, + config_log_monitor_cmd, + "log monitor", + "Logging control\n" "Set terminal line (monitor) logging level\n") +{ + zlog_set_level(NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl); + return CMD_SUCCESS; +} + +DEFUN(config_log_monitor_level, + config_log_monitor_level_cmd, + "log monitor " LOG_LEVELS, + "Logging control\n" + "Set terminal line (monitor) logging level\n" LOG_LEVEL_DESC) +{ + int level; + + if ((level = level_match(argv[0])) == ZLOG_DISABLED) + return CMD_ERR_NO_MATCH; + zlog_set_level(NULL, ZLOG_DEST_MONITOR, level); + return CMD_SUCCESS; +} + +DEFUN(no_config_log_monitor, + no_config_log_monitor_cmd, + "no log monitor [LEVEL]", + NO_STR + "Logging control\n" + "Disable terminal line (monitor) logging\n" "Logging level\n") +{ + zlog_set_level(NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED); + return CMD_SUCCESS; +} + +static int set_log_file(struct vty *vty, const char *fname, int loglevel) +{ + int ret; + char *p = NULL; + const char *fullpath; + + /* Path detection. */ + if (!IS_DIRECTORY_SEP(*fname)) { + char cwd[MAXPATHLEN + 1]; + cwd[MAXPATHLEN] = '\0'; + + if (getcwd(cwd, MAXPATHLEN) == NULL) { + zlog_err("config_log_file: Unable to alloc mem!"); + return CMD_WARNING; + } + + if ((p = malloc(strlen(cwd) + strlen(fname) + 2)) + == NULL) { + zlog_err("config_log_file: Unable to alloc mem!"); + return CMD_WARNING; + } + sprintf(p, "%s/%s", cwd, fname); + fullpath = p; + } else + fullpath = fname; + + ret = zlog_set_file(NULL, fullpath, loglevel); + + if (p) + free(p); + + if (!ret) { + vty_out(vty, "can't open logfile %s\n", fname); + return CMD_WARNING; + } + + if (host.logfile) + free(host.logfile); + + host.logfile = strdup(fname); + + return CMD_SUCCESS; +} + +DEFUN(config_log_file, + config_log_file_cmd, + "log file FILENAME", + "Logging control\n" "Logging to file\n" "Logging filename\n") +{ + return set_log_file(vty, argv[0], zlog_default->default_lvl); +} + +DEFUN(config_log_file_level, + config_log_file_level_cmd, + "log file FILENAME " LOG_LEVELS, + "Logging control\n" + "Logging to file\n" "Logging filename\n" LOG_LEVEL_DESC) +{ + int level; + + if ((level = level_match(argv[1])) == ZLOG_DISABLED) + return CMD_ERR_NO_MATCH; + return set_log_file(vty, argv[0], level); +} + +DEFUN(no_config_log_file, + no_config_log_file_cmd, + "no log file [FILENAME]", + NO_STR + "Logging control\n" "Cancel logging to file\n" "Logging file name\n") +{ + zlog_reset_file(NULL); + + if (host.logfile) + free(host.logfile); + + host.logfile = NULL; + + return CMD_SUCCESS; +} + +ALIAS(no_config_log_file, + no_config_log_file_level_cmd, + "no log file FILENAME LEVEL", + NO_STR + "Logging control\n" + "Cancel logging to file\n" "Logging file name\n" "Logging level\n") + + DEFUN(config_log_syslog, + config_log_syslog_cmd, + "log syslog", "Logging control\n" "Set syslog logging level\n") +{ + zlog_set_level(NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl); + return CMD_SUCCESS; +} + +DEFUN(config_log_syslog_level, + config_log_syslog_level_cmd, + "log syslog " LOG_LEVELS, + "Logging control\n" "Set syslog logging level\n" LOG_LEVEL_DESC) +{ + int level; + + if ((level = level_match(argv[0])) == ZLOG_DISABLED) + return CMD_ERR_NO_MATCH; + zlog_set_level(NULL, ZLOG_DEST_SYSLOG, level); + return CMD_SUCCESS; +} + +DEFUN_DEPRECATED(config_log_syslog_facility, + config_log_syslog_facility_cmd, + "log syslog facility " LOG_FACILITIES, + "Logging control\n" + "Logging goes to syslog\n" + "(Deprecated) Facility parameter for syslog messages\n" + LOG_FACILITY_DESC) +{ + int facility; + + if ((facility = facility_match(argv[0])) < 0) + return CMD_ERR_NO_MATCH; + + zlog_set_level(NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl); + zlog_default->facility = facility; + return CMD_SUCCESS; +} + +DEFUN(no_config_log_syslog, + no_config_log_syslog_cmd, + "no log syslog [LEVEL]", + NO_STR "Logging control\n" "Cancel logging to syslog\n" "Logging level\n") +{ + zlog_set_level(NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED); + return CMD_SUCCESS; +} + +ALIAS(no_config_log_syslog, + no_config_log_syslog_facility_cmd, + "no log syslog facility " LOG_FACILITIES, + NO_STR + "Logging control\n" + "Logging goes to syslog\n" + "Facility parameter for syslog messages\n" LOG_FACILITY_DESC) + + DEFUN(config_log_facility, + config_log_facility_cmd, + "log facility " LOG_FACILITIES, + "Logging control\n" + "Facility parameter for syslog messages\n" LOG_FACILITY_DESC) +{ + int facility; + + if ((facility = facility_match(argv[0])) < 0) + return CMD_ERR_NO_MATCH; + zlog_default->facility = facility; + return CMD_SUCCESS; +} + +DEFUN(no_config_log_facility, + no_config_log_facility_cmd, + "no log facility [FACILITY]", + NO_STR + "Logging control\n" + "Reset syslog facility to default (daemon)\n" "Syslog facility\n") +{ + zlog_default->facility = LOG_DAEMON; + return CMD_SUCCESS; +} + +DEFUN_DEPRECATED(config_log_trap, + config_log_trap_cmd, + "log trap " LOG_LEVELS, + "Logging control\n" + "(Deprecated) Set logging level and default for all destinations\n" + LOG_LEVEL_DESC) +{ + int new_level; + int i; + + if ((new_level = level_match(argv[0])) == ZLOG_DISABLED) + return CMD_ERR_NO_MATCH; + + zlog_default->default_lvl = new_level; + for (i = 0; i < ZLOG_NUM_DESTS; i++) + if (zlog_default->maxlvl[i] != ZLOG_DISABLED) + zlog_default->maxlvl[i] = new_level; + return CMD_SUCCESS; +} + +DEFUN_DEPRECATED(no_config_log_trap, + no_config_log_trap_cmd, + "no log trap [LEVEL]", + NO_STR + "Logging control\n" + "Permit all logging information\n" "Logging level\n") +{ + zlog_default->default_lvl = LOG_DEBUG; + return CMD_SUCCESS; +} + +DEFUN(config_log_record_priority, + config_log_record_priority_cmd, + "log record-priority", + "Logging control\n" + "Log the priority of the message within the message\n") +{ + zlog_default->record_priority = 1; + return CMD_SUCCESS; +} + +DEFUN(no_config_log_record_priority, + no_config_log_record_priority_cmd, + "no log record-priority", + NO_STR + "Logging control\n" + "Do not log the priority of the message within the message\n") +{ + zlog_default->record_priority = 0; + return CMD_SUCCESS; +} +#endif + +DEFUN(banner_motd_file, + banner_motd_file_cmd, + "banner motd file [FILE]", + "Set banner\n" "Banner for motd\n" "Banner from a file\n" "Filename\n") +{ + if (host.motdfile) + free(host.motdfile); + host.motdfile = strdup(argv[0]); + + return CMD_SUCCESS; +} + +DEFUN(banner_motd_default, + banner_motd_default_cmd, + "banner motd default", + "Set banner string\n" "Strings for motd\n" "Default string\n") +{ + host.motd = default_motd; + return CMD_SUCCESS; +} + +DEFUN(no_banner_motd, + no_banner_motd_cmd, + "no banner motd", NO_STR "Set banner string\n" "Strings for motd\n") +{ + host.motd = NULL; + if (host.motdfile) + free(host.motdfile); + host.motdfile = NULL; + return CMD_SUCCESS; +} + +/* Set config filename. Called from vty.c */ +void host_config_set(char *filename) +{ + host.config = strdup(filename); +} + +void install_default(enum node_type node) +{ + install_element(node, &config_exit_cmd); + install_element(node, &config_quit_cmd); + install_element(node, &config_end_cmd); + install_element(node, &config_help_cmd); + install_element(node, &config_list_cmd); + +#if 0 + install_element(node, &config_write_terminal_cmd); + install_element(node, &config_write_file_cmd); + install_element(node, &config_write_memory_cmd); + install_element(node, &config_write_cmd); + install_element(node, &show_running_config_cmd); +#endif +} + +/* Initialize command interface. Install basic nodes and commands. */ +void cmd_init(int terminal) +{ + /* Allocate initial top vector of commands. */ + cmdvec = vector_init(VECTOR_MIN_SIZE); + + /* Default host value settings. */ + host.name = NULL; + //host.password = NULL; + host.password = "foo"; + host.enable = NULL; + host.logfile = NULL; + host.config = NULL; + host.lines = -1; + host.motd = default_motd; + host.motdfile = NULL; + + /* Install top nodes. */ + install_node(&view_node, NULL); + install_node(&enable_node, NULL); + install_node(&auth_node, NULL); + install_node(&auth_enable_node, NULL); + install_node(&config_node, config_write_host); + + /* Each node's basic commands. */ + install_element(VIEW_NODE, &show_version_cmd); + if (terminal) { + install_element(VIEW_NODE, &config_list_cmd); + install_element(VIEW_NODE, &config_exit_cmd); + install_element(VIEW_NODE, &config_quit_cmd); + install_element(VIEW_NODE, &config_help_cmd); + install_element(VIEW_NODE, &config_enable_cmd); + install_element(VIEW_NODE, &config_terminal_length_cmd); + install_element(VIEW_NODE, &config_terminal_no_length_cmd); + install_element(VIEW_NODE, &echo_cmd); + } + + if (terminal) { + install_default(ENABLE_NODE); + install_element(ENABLE_NODE, &config_disable_cmd); + install_element(ENABLE_NODE, &config_terminal_cmd); + //install_element (ENABLE_NODE, ©_runningconfig_startupconfig_cmd); + } + //install_element (ENABLE_NODE, &show_startup_config_cmd); + install_element(ENABLE_NODE, &show_version_cmd); + + if (terminal) { + install_element(ENABLE_NODE, &config_terminal_length_cmd); + install_element(ENABLE_NODE, &config_terminal_no_length_cmd); + install_element(ENABLE_NODE, &echo_cmd); + + install_default(CONFIG_NODE); + } + + install_element(CONFIG_NODE, &hostname_cmd); + install_element(CONFIG_NODE, &no_hostname_cmd); + + if (terminal) { + install_element(CONFIG_NODE, &password_cmd); + install_element(CONFIG_NODE, &password_text_cmd); + install_element(CONFIG_NODE, &enable_password_cmd); + install_element(CONFIG_NODE, &enable_password_text_cmd); + install_element(CONFIG_NODE, &no_enable_password_cmd); + + install_element(CONFIG_NODE, &service_password_encrypt_cmd); + install_element(CONFIG_NODE, &no_service_password_encrypt_cmd); + install_element(CONFIG_NODE, &banner_motd_default_cmd); + install_element(CONFIG_NODE, &banner_motd_file_cmd); + install_element(CONFIG_NODE, &no_banner_motd_cmd); + install_element(CONFIG_NODE, &service_terminal_length_cmd); + install_element(CONFIG_NODE, &no_service_terminal_length_cmd); + + } + srand(time(NULL)); +} diff --git a/host/zebvty/command.h b/host/zebvty/command.h new file mode 100644 index 0000000..5b79da4 --- /dev/null +++ b/host/zebvty/command.h @@ -0,0 +1,351 @@ +/* + * Zebra configuration command interface routine + * Copyright (C) 1997, 98 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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. + * + * GNU Zebra 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. + */ + +#ifndef _ZEBRA_COMMAND_H +#define _ZEBRA_COMMAND_H + +#include +#include "vector.h" +#include "vty.h" + +/* Host configuration variable */ +struct host { + /* Host name of this router. */ + char *name; + + /* Password for vty interface. */ + char *password; + char *password_encrypt; + + /* Enable password */ + char *enable; + char *enable_encrypt; + + /* System wide terminal lines. */ + int lines; + + /* Log filename. */ + char *logfile; + + /* config file name of this host */ + char *config; + + /* Flags for services */ + int advanced; + int encrypt; + + /* Banner configuration. */ + const char *motd; + char *motdfile; +}; + +/* There are some command levels which called from command node. */ +enum node_type { + RC632_NODE, + + AUTH_NODE, /* Authentication mode of vty interface. */ + VIEW_NODE, /* View node. Default mode of vty interface. */ + AUTH_ENABLE_NODE, /* Authentication mode for change enable. */ + ENABLE_NODE, /* Enable node. */ + CONFIG_NODE, /* Config node. Default mode of config file. */ + SERVICE_NODE, /* Service node. */ + DEBUG_NODE, /* Debug node. */ + AAA_NODE, /* AAA node. */ + KEYCHAIN_NODE, /* Key-chain node. */ + KEYCHAIN_KEY_NODE, /* Key-chain key node. */ + INTERFACE_NODE, /* Interface mode node. */ + ZEBRA_NODE, /* zebra connection node. */ + TABLE_NODE, /* rtm_table selection node. */ + RIP_NODE, /* RIP protocol mode node. */ + RIPNG_NODE, /* RIPng protocol mode node. */ + BGP_NODE, /* BGP protocol mode which includes BGP4+ */ + BGP_VPNV4_NODE, /* BGP MPLS-VPN PE exchange. */ + BGP_IPV4_NODE, /* BGP IPv4 unicast address family. */ + BGP_IPV4M_NODE, /* BGP IPv4 multicast address family. */ + BGP_IPV6_NODE, /* BGP IPv6 address family */ + OSPF_NODE, /* OSPF protocol mode */ + OSPF6_NODE, /* OSPF protocol for IPv6 mode */ + ISIS_NODE, /* ISIS protocol mode */ + MASC_NODE, /* MASC for multicast. */ + IRDP_NODE, /* ICMP Router Discovery Protocol mode. */ + IP_NODE, /* Static ip route node. */ + ACCESS_NODE, /* Access list node. */ + PREFIX_NODE, /* Prefix list node. */ + ACCESS_IPV6_NODE, /* Access list node. */ + PREFIX_IPV6_NODE, /* Prefix list node. */ + AS_LIST_NODE, /* AS list node. */ + COMMUNITY_LIST_NODE, /* Community list node. */ + RMAP_NODE, /* Route map node. */ + SMUX_NODE, /* SNMP configuration node. */ + DUMP_NODE, /* Packet dump node. */ + FORWARDING_NODE, /* IP forwarding node. */ + VTY_NODE /* Vty node. */ +}; + +/* Node which has some commands and prompt string and configuration + function pointer . */ +struct cmd_node { + /* Node index. */ + enum node_type node; + + /* Prompt character at vty interface. */ + const char *prompt; + + /* Is this node's configuration goes to vtysh ? */ + int vtysh; + + /* Node's configuration write function */ + int (*func) (struct vty *); + + /* Vector of this node's command list. */ + vector cmd_vector; +}; + +enum { + CMD_ATTR_DEPRECATED = 1, + CMD_ATTR_HIDDEN, +}; + +/* Structure of command element. */ +struct cmd_element { + const char *string; /* Command specification by string. */ + int (*func) (struct cmd_element *, struct vty *, int, const char *[]); + const char *doc; /* Documentation of this command. */ + int daemon; /* Daemon to which this command belong. */ + vector strvec; /* Pointing out each description vector. */ + unsigned int cmdsize; /* Command index count. */ + char *config; /* Configuration string */ + vector subconfig; /* Sub configuration string */ + u_char attr; /* Command attributes */ +}; + +/* Command description structure. */ +struct desc { + const char *cmd; /* Command string. */ + const char *str; /* Command's description. */ +}; + +/* Return value of the commands. */ +#define CMD_SUCCESS 0 +#define CMD_WARNING 1 +#define CMD_ERR_NO_MATCH 2 +#define CMD_ERR_AMBIGUOUS 3 +#define CMD_ERR_INCOMPLETE 4 +#define CMD_ERR_EXEED_ARGC_MAX 5 +#define CMD_ERR_NOTHING_TODO 6 +#define CMD_COMPLETE_FULL_MATCH 7 +#define CMD_COMPLETE_MATCH 8 +#define CMD_COMPLETE_LIST_MATCH 9 +#define CMD_SUCCESS_DAEMON 10 + +/* Argc max counts. */ +#define CMD_ARGC_MAX 25 + +/* Turn off these macros when uisng cpp with extract.pl */ +#ifndef VTYSH_EXTRACT_PL + +/* helper defines for end-user DEFUN* macros */ +#define DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attrs, dnum) \ + struct cmd_element cmdname = \ + { \ + .string = cmdstr, \ + .func = funcname, \ + .doc = helpstr, \ + .attr = attrs, \ + .daemon = dnum, \ + }; + +#define DEFUN_CMD_FUNC_DECL(funcname) \ + static int funcname (struct cmd_element *, struct vty *, int, const char *[]); \ + +#define DEFUN_CMD_FUNC_TEXT(funcname) \ + static int funcname \ + (struct cmd_element *self, struct vty *vty, int argc, const char *argv[]) + +/* DEFUN for vty command interafce. Little bit hacky ;-). */ +#define DEFUN(funcname, cmdname, cmdstr, helpstr) \ + DEFUN_CMD_FUNC_DECL(funcname) \ + DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0) \ + DEFUN_CMD_FUNC_TEXT(funcname) + +#define DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \ + DEFUN_CMD_FUNC_DECL(funcname) \ + DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) \ + DEFUN_CMD_FUNC_TEXT(funcname) + +#define DEFUN_HIDDEN(funcname, cmdname, cmdstr, helpstr) \ + DEFUN_ATTR (funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN) + +#define DEFUN_DEPRECATED(funcname, cmdname, cmdstr, helpstr) \ + DEFUN_ATTR (funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED) \ + +/* DEFUN_NOSH for commands that vtysh should ignore */ +#define DEFUN_NOSH(funcname, cmdname, cmdstr, helpstr) \ + DEFUN(funcname, cmdname, cmdstr, helpstr) + +/* DEFSH for vtysh. */ +#define DEFSH(daemon, cmdname, cmdstr, helpstr) \ + DEFUN_CMD_ELEMENT(NULL, cmdname, cmdstr, helpstr, 0, daemon) \ + +/* DEFUN + DEFSH */ +#define DEFUNSH(daemon, funcname, cmdname, cmdstr, helpstr) \ + DEFUN_CMD_FUNC_DECL(funcname) \ + DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, daemon) \ + DEFUN_CMD_FUNC_TEXT(funcname) + +/* DEFUN + DEFSH with attributes */ +#define DEFUNSH_ATTR(daemon, funcname, cmdname, cmdstr, helpstr, attr) \ + DEFUN_CMD_FUNC_DECL(funcname) \ + DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, daemon) \ + DEFUN_CMD_FUNC_TEXT(funcname) + +#define DEFUNSH_HIDDEN(daemon, funcname, cmdname, cmdstr, helpstr) \ + DEFUNSH_ATTR (daemon, funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN) + +#define DEFUNSH_DEPRECATED(daemon, funcname, cmdname, cmdstr, helpstr) \ + DEFUNSH_ATTR (daemon, funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED) + +/* ALIAS macro which define existing command's alias. */ +#define ALIAS(funcname, cmdname, cmdstr, helpstr) \ + DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0) + +#define ALIAS_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \ + DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) + +#define ALIAS_HIDDEN(funcname, cmdname, cmdstr, helpstr) \ + DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN, 0) + +#define ALIAS_DEPRECATED(funcname, cmdname, cmdstr, helpstr) \ + DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED, 0) + +#define ALIAS_SH(daemon, funcname, cmdname, cmdstr, helpstr) \ + DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, daemon) + +#define ALIAS_SH_HIDDEN(daemon, funcname, cmdname, cmdstr, helpstr) \ + DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN, daemon) + +#define ALIAS_SH_DEPRECATED(daemon, funcname, cmdname, cmdstr, helpstr) \ + DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED, daemon) + +#endif /* VTYSH_EXTRACT_PL */ + +/* Some macroes */ +#define CMD_OPTION(S) ((S[0]) == '[') +#define CMD_VARIABLE(S) (((S[0]) >= 'A' && (S[0]) <= 'Z') || ((S[0]) == '<')) +#define CMD_VARARG(S) ((S[0]) == '.') +#define CMD_RANGE(S) ((S[0] == '<')) + +#define CMD_IPV4(S) ((strcmp ((S), "A.B.C.D") == 0)) +#define CMD_IPV4_PREFIX(S) ((strcmp ((S), "A.B.C.D/M") == 0)) +#define CMD_IPV6(S) ((strcmp ((S), "X:X::X:X") == 0)) +#define CMD_IPV6_PREFIX(S) ((strcmp ((S), "X:X::X:X/M") == 0)) + +/* Common descriptions. */ +#define SHOW_STR "Show running system information\n" +#define IP_STR "IP information\n" +#define IPV6_STR "IPv6 information\n" +#define NO_STR "Negate a command or set its defaults\n" +#define CLEAR_STR "Reset functions\n" +#define RIP_STR "RIP information\n" +#define BGP_STR "BGP information\n" +#define OSPF_STR "OSPF information\n" +#define NEIGHBOR_STR "Specify neighbor router\n" +#define DEBUG_STR "Debugging functions (see also 'undebug')\n" +#define UNDEBUG_STR "Disable debugging functions (see also 'debug')\n" +#define ROUTER_STR "Enable a routing process\n" +#define AS_STR "AS number\n" +#define MBGP_STR "MBGP information\n" +#define MATCH_STR "Match values from routing table\n" +#define SET_STR "Set values in destination routing protocol\n" +#define OUT_STR "Filter outgoing routing updates\n" +#define IN_STR "Filter incoming routing updates\n" +#define V4NOTATION_STR "specify by IPv4 address notation(e.g. 0.0.0.0)\n" +#define OSPF6_NUMBER_STR "Specify by number\n" +#define INTERFACE_STR "Interface infomation\n" +#define IFNAME_STR "Interface name(e.g. ep0)\n" +#define IP6_STR "IPv6 Information\n" +#define OSPF6_STR "Open Shortest Path First (OSPF) for IPv6\n" +#define OSPF6_ROUTER_STR "Enable a routing process\n" +#define OSPF6_INSTANCE_STR "<1-65535> Instance ID\n" +#define SECONDS_STR "<1-65535> Seconds\n" +#define ROUTE_STR "Routing Table\n" +#define PREFIX_LIST_STR "Build a prefix list\n" +#define OSPF6_DUMP_TYPE_LIST \ +"(neighbor|interface|area|lsa|zebra|config|dbex|spf|route|lsdb|redistribute|hook|asbr|prefix|abr)" +#define ISIS_STR "IS-IS information\n" +#define AREA_TAG_STR "[area tag]\n" + +#define CONF_BACKUP_EXT ".sav" + +/* IPv4 only machine should not accept IPv6 address for peer's IP + address. So we replace VTY command string like below. */ +#ifdef HAVE_IPV6 +#define NEIGHBOR_CMD "neighbor (A.B.C.D|X:X::X:X) " +#define NO_NEIGHBOR_CMD "no neighbor (A.B.C.D|X:X::X:X) " +#define NEIGHBOR_ADDR_STR "Neighbor address\nIPv6 address\n" +#define NEIGHBOR_CMD2 "neighbor (A.B.C.D|X:X::X:X|WORD) " +#define NO_NEIGHBOR_CMD2 "no neighbor (A.B.C.D|X:X::X:X|WORD) " +#define NEIGHBOR_ADDR_STR2 "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" +#else +#define NEIGHBOR_CMD "neighbor A.B.C.D " +#define NO_NEIGHBOR_CMD "no neighbor A.B.C.D " +#define NEIGHBOR_ADDR_STR "Neighbor address\n" +#define NEIGHBOR_CMD2 "neighbor (A.B.C.D|WORD) " +#define NO_NEIGHBOR_CMD2 "no neighbor (A.B.C.D|WORD) " +#define NEIGHBOR_ADDR_STR2 "Neighbor address\nNeighbor tag\n" +#endif /* HAVE_IPV6 */ + +/* Prototypes. */ +void install_node(struct cmd_node *, int (*)(struct vty *)); +void install_default(enum node_type); +void install_element(enum node_type, struct cmd_element *); +void sort_node(); + +/* Concatenates argv[shift] through argv[argc-1] into a single NUL-terminated + string with a space between each element (allocated using + XMALLOC(MTYPE_TMP)). Returns NULL if shift >= argc. */ +char *argv_concat(const char **argv, int argc, int shift); + +vector cmd_make_strvec(const char *); +void cmd_free_strvec(vector); +vector cmd_describe_command(); +char **cmd_complete_command(); +const char *cmd_prompt(enum node_type); +int config_from_file(struct vty *, FILE *); +enum node_type node_parent(enum node_type); +int cmd_execute_command(vector, struct vty *, struct cmd_element **, int); +int cmd_execute_command_strict(vector, struct vty *, struct cmd_element **); +void config_replace_string(struct cmd_element *, char *, ...); +void cmd_init(int); + +/* Export typical functions. */ +extern struct cmd_element config_end_cmd; +extern struct cmd_element config_exit_cmd; +extern struct cmd_element config_quit_cmd; +extern struct cmd_element config_help_cmd; +extern struct cmd_element config_list_cmd; +char *host_config_file(); +void host_config_set(char *); + +void print_version(const char *); + +#endif /* _ZEBRA_COMMAND_H */ diff --git a/host/zebvty/vector.c b/host/zebvty/vector.c new file mode 100644 index 0000000..7158d23 --- /dev/null +++ b/host/zebvty/vector.c @@ -0,0 +1,186 @@ +/* Generic vector interface routine + * Copyright (C) 1997 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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. + * + * GNU Zebra 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 +#include + +#include "vector.h" +#include "memory.h" + +/* Initialize vector : allocate memory and return vector. */ +vector vector_init(unsigned int size) +{ + vector v = calloc(1, sizeof(struct _vector)); + if (!v) + return NULL; + + /* allocate at least one slot */ + if (size == 0) + size = 1; + + v->alloced = size; + v->active = 0; + v->index = calloc(1, sizeof(void *) * size); + if (!v->index) { + free(v); + return NULL; + } + return v; +} + +void vector_only_wrapper_free(vector v) +{ + free(v); +} + +void vector_only_index_free(void *index) +{ + free(index); +} + +void vector_free(vector v) +{ + free(v->index); + free(v); +} + +vector vector_copy(vector v) +{ + unsigned int size; + vector new = calloc(1, sizeof(struct _vector)); + if (!new) + return NULL; + + new->active = v->active; + new->alloced = v->alloced; + + size = sizeof(void *) * (v->alloced); + new->index = calloc(1, size); + if (!new->index) { + free(new); + return NULL; + } + memcpy(new->index, v->index, size); + + return new; +} + +/* Check assigned index, and if it runs short double index pointer */ +void vector_ensure(vector v, unsigned int num) +{ + if (v->alloced > num) + return; + + v->index = realloc(v->index, sizeof(void *) * (v->alloced * 2)); + memset(&v->index[v->alloced], 0, sizeof(void *) * v->alloced); + v->alloced *= 2; + + if (v->alloced <= num) + vector_ensure(v, num); +} + +/* This function only returns next empty slot index. It dose not mean + the slot's index memory is assigned, please call vector_ensure() + after calling this function. */ +int vector_empty_slot(vector v) +{ + unsigned int i; + + if (v->active == 0) + return 0; + + for (i = 0; i < v->active; i++) + if (v->index[i] == 0) + return i; + + return i; +} + +/* Set value to the smallest empty slot. */ +int vector_set(vector v, void *val) +{ + unsigned int i; + + i = vector_empty_slot(v); + vector_ensure(v, i); + + v->index[i] = val; + + if (v->active <= i) + v->active = i + 1; + + return i; +} + +/* Set value to specified index slot. */ +int vector_set_index(vector v, unsigned int i, void *val) +{ + vector_ensure(v, i); + + v->index[i] = val; + + if (v->active <= i) + v->active = i + 1; + + return i; +} + +/* Look up vector. */ +void *vector_lookup(vector v, unsigned int i) +{ + if (i >= v->active) + return NULL; + return v->index[i]; +} + +/* Lookup vector, ensure it. */ +void *vector_lookup_ensure(vector v, unsigned int i) +{ + vector_ensure(v, i); + return v->index[i]; +} + +/* Unset value at specified index slot. */ +void vector_unset(vector v, unsigned int i) +{ + if (i >= v->alloced) + return; + + v->index[i] = NULL; + + if (i + 1 == v->active) { + v->active--; + while (i && v->index[--i] == NULL && v->active--) ; /* Is this ugly ? */ + } +} + +/* Count the number of not emplty slot. */ +unsigned int vector_count(vector v) +{ + unsigned int i; + unsigned count = 0; + + for (i = 0; i < v->active; i++) + if (v->index[i] != NULL) + count++; + + return count; +} diff --git a/host/zebvty/vector.h b/host/zebvty/vector.h new file mode 100644 index 0000000..d438d27 --- /dev/null +++ b/host/zebvty/vector.h @@ -0,0 +1,62 @@ +/* + * Generic vector interface header. + * Copyright (C) 1997, 98 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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. + * + * GNU Zebra 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. + */ + +#ifndef _ZEBRA_VECTOR_H +#define _ZEBRA_VECTOR_H + +/* struct for vector */ +struct _vector { + unsigned int active; /* number of active slots */ + unsigned int alloced; /* number of allocated slot */ + void **index; /* index to data */ +}; +typedef struct _vector *vector; + +#define VECTOR_MIN_SIZE 1 + +/* (Sometimes) usefull macros. This macro convert index expression to + array expression. */ +/* Reference slot at given index, caller must ensure slot is active */ +#define vector_slot(V,I) ((V)->index[(I)]) +/* Number of active slots. + * Note that this differs from vector_count() as it the count returned + * will include any empty slots + */ +#define vector_active(V) ((V)->active) + +/* Prototypes. */ +vector vector_init(unsigned int size); +void vector_ensure(vector v, unsigned int num); +int vector_empty_slot(vector v); +int vector_set(vector v, void *val); +int vector_set_index(vector v, unsigned int i, void *val); +void vector_unset(vector v, unsigned int i); +unsigned int vector_count(vector v); +void vector_only_wrapper_free(vector v); +void vector_only_index_free(void *index); +void vector_free(vector v); +vector vector_copy(vector v); + +void *vector_lookup(vector, unsigned int); +void *vector_lookup_ensure(vector, unsigned int); + +#endif /* _ZEBRA_VECTOR_H */ diff --git a/host/zebvty/vty.c b/host/zebvty/vty.c new file mode 100644 index 0000000..ae41895 --- /dev/null +++ b/host/zebvty/vty.c @@ -0,0 +1,1515 @@ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "zebvty.h" +#include "vty.h" +#include "command.h" +#include "buffer.h" + +/* Vty events */ +enum event { + VTY_SERV, + VTY_READ, + VTY_WRITE, + VTY_TIMEOUT_RESET, +#ifdef VTYSH + VTYSH_SERV, + VTYSH_READ, + VTYSH_WRITE +#endif /* VTYSH */ +}; + +extern struct host host; + +/* Vector which store each vty structure. */ +static vector vtyvec; + +vector Vvty_serv_thread; + +char *vty_cwd = NULL; + +/* Configure lock. */ +static int vty_config; + +static int no_password_check = 1; + +static void vty_clear_buf(struct vty *vty) +{ + memset(vty->buf, 0, vty->max); +} + +/* Allocate new vty struct. */ +struct vty *vty_new() +{ + struct vty *new = malloc(sizeof(struct vty)); + + if (!new) + goto out; + + new->obuf = buffer_new(0); /* Use default buffer size. */ + if (!new->obuf) + goto out_new; + new->buf = calloc(1, VTY_BUFSIZ); + if (!new->buf) + goto out_obuf; + + new->max = VTY_BUFSIZ; + + return new; + +out_obuf: + free(new->obuf); +out_new: + free(new); + new = NULL; +out: + return new; +} + +/* Authentication of vty */ +static void vty_auth(struct vty *vty, char *buf) +{ + char *passwd = NULL; + enum node_type next_node = 0; + int fail; + char *crypt(const char *, const char *); + + switch (vty->node) { + case AUTH_NODE: + if (host.encrypt) + passwd = host.password_encrypt; + else + passwd = host.password; + if (host.advanced) + next_node = host.enable ? VIEW_NODE : ENABLE_NODE; + else + next_node = VIEW_NODE; + break; + case AUTH_ENABLE_NODE: + if (host.encrypt) + passwd = host.enable_encrypt; + else + passwd = host.enable; + next_node = ENABLE_NODE; + break; + } + + if (passwd) { + if (host.encrypt) + fail = strcmp(crypt(buf, passwd), passwd); + else + fail = strcmp(buf, passwd); + } else + fail = 1; + + if (!fail) { + vty->fail = 0; + vty->node = next_node; /* Success ! */ + } else { + vty->fail++; + if (vty->fail >= 3) { + if (vty->node == AUTH_NODE) { + vty_out(vty, + "%% Bad passwords, too many failures!%s", + VTY_NEWLINE); + vty->status = VTY_CLOSE; + } else { + /* AUTH_ENABLE_NODE */ + vty->fail = 0; + vty_out(vty, + "%% Bad enable passwords, too many failures!%s", + VTY_NEWLINE); + vty->node = VIEW_NODE; + } + } + } +} + +/* Close vty interface. */ +void vty_close(struct vty *vty) +{ + int i; + + /* Flush buffer. */ + buffer_flush_all(vty->obuf, vty->fd); + + /* Free input buffer. */ + buffer_free(vty->obuf); + + /* Free command history. */ + for (i = 0; i < VTY_MAXHIST; i++) + if (vty->hist[i]) + free(vty->hist[i]); + + /* Unset vector. */ + vector_unset(vtyvec, vty->fd); + + /* Close socket. */ + if (vty->fd > 0) + close(vty->fd); + + if (vty->buf) + free(vty->buf); + + /* Check configure. */ + vty_config_unlock(vty); + + /* OK free vty. */ + free(vty); +} + +int vty_shell(struct vty *vty) +{ + return vty->type == VTY_SHELL ? 1 : 0; +} + + +/* VTY standard output function. */ +int vty_out(struct vty *vty, const char *format, ...) +{ + va_list args; + int len = 0; + int size = 1024; + char buf[1024]; + char *p = NULL; + + if (vty_shell(vty)) { + va_start(args, format); + vprintf(format, args); + va_end(args); + } else { + /* Try to write to initial buffer. */ + va_start(args, format); + len = vsnprintf(buf, sizeof buf, format, args); + va_end(args); + + /* Initial buffer is not enough. */ + if (len < 0 || len >= size) { + while (1) { + if (len > -1) + size = len + 1; + else + size = size * 2; + + p = realloc(p, size); + if (!p) + return -1; + + va_start(args, format); + len = vsnprintf(p, size, format, args); + va_end(args); + + if (len > -1 && len < size) + break; + } + } + + /* When initial buffer is enough to store all output. */ + if (!p) + p = buf; + + /* Pointer p must point out buffer. */ + buffer_put(vty->obuf, (u_char *) p, len); + + /* If p is not different with buf, it is allocated buffer. */ + if (p != buf) + free(p); + } + + return len; +} + +int vty_out_newline(struct vty *vty) +{ + char *p = vty_newline(vty); + buffer_put(vty->obuf, p, strlen(p)); +} + +int vty_config_lock(struct vty *vty) +{ + if (vty_config == 0) { + vty->config = 1; + vty_config = 1; + } + return vty->config; +} + +int vty_config_unlock(struct vty *vty) +{ + if (vty_config == 1 && vty->config == 1) { + vty->config = 0; + vty_config = 0; + } + return vty->config; +} + +static void vty_event(enum event event, int sock, struct vty *vty) +{ + //fprintf(stdout, "vty_event(%d, %d, %p)\n", event, sock, vty); + buffer_flush_all(vty->obuf, sock); +} + +/* Say hello to vty interface. */ +void vty_hello(struct vty *vty) +{ + if (host.motdfile) { + FILE *f; + char buf[4096]; + + f = fopen(host.motdfile, "r"); + if (f) { + while (fgets(buf, sizeof(buf), f)) { + char *s; + /* work backwards to ignore trailling isspace() */ + for (s = buf + strlen(buf); + (s > buf) && isspace(*(s - 1)); s--) ; + *s = '\0'; + vty_out(vty, "%s%s", buf, VTY_NEWLINE); + } + fclose(f); + } else + vty_out(vty, "MOTD file not found%s", VTY_NEWLINE); + } else if (host.motd) + vty_out(vty, host.motd); +} + +/* Put out prompt and wait input from user. */ +static void vty_prompt(struct vty *vty) +{ + struct utsname names; + const char *hostname; + + if (vty->type == VTY_TERM) { + hostname = host.name; + if (!hostname) { + uname(&names); + hostname = names.nodename; + } + vty_out(vty, cmd_prompt(vty->node), hostname); + } +} + +/* Command execution over the vty interface. */ +static int vty_command(struct vty *vty, char *buf) +{ + int ret; + vector vline; + + /* Split readline string up into the vector */ + vline = cmd_make_strvec(buf); + + if (vline == NULL) + return CMD_SUCCESS; + + ret = cmd_execute_command(vline, vty, NULL, 0); + if (ret != CMD_SUCCESS) + switch (ret) { + case CMD_WARNING: + if (vty->type == VTY_FILE) + vty_out(vty, "Warning...%s", VTY_NEWLINE); + break; + case CMD_ERR_AMBIGUOUS: + vty_out(vty, "%% Ambiguous command.%s", VTY_NEWLINE); + break; + case CMD_ERR_NO_MATCH: + vty_out(vty, "%% Unknown command.%s", VTY_NEWLINE); + break; + case CMD_ERR_INCOMPLETE: + vty_out(vty, "%% Command incomplete.%s", VTY_NEWLINE); + break; + } + cmd_free_strvec(vline); + + return ret; +} + +static const char telnet_backward_char = 0x08; +static const char telnet_space_char = ' '; + +/* Basic function to write buffer to vty. */ +static void vty_write(struct vty *vty, const char *buf, size_t nbytes) +{ + if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE)) + return; + + /* Should we do buffering here ? And make vty_flush (vty) ? */ + buffer_put(vty->obuf, buf, nbytes); +} + +/* Ensure length of input buffer. Is buffer is short, double it. */ +static void vty_ensure(struct vty *vty, int length) +{ + if (vty->max <= length) { + vty->max *= 2; + vty->buf = realloc(vty->buf, vty->max); + // FIXME: check return + } +} + +/* Basic function to insert character into vty. */ +static void vty_self_insert(struct vty *vty, char c) +{ + int i; + int length; + + vty_ensure(vty, vty->length + 1); + length = vty->length - vty->cp; + memmove(&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length); + vty->buf[vty->cp] = c; + + vty_write(vty, &vty->buf[vty->cp], length + 1); + for (i = 0; i < length; i++) + vty_write(vty, &telnet_backward_char, 1); + + vty->cp++; + vty->length++; +} + +/* Self insert character 'c' in overwrite mode. */ +static void vty_self_insert_overwrite(struct vty *vty, char c) +{ + vty_ensure(vty, vty->length + 1); + vty->buf[vty->cp++] = c; + + if (vty->cp > vty->length) + vty->length++; + + if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE)) + return; + + vty_write(vty, &c, 1); +} + +/* Insert a word into vty interface with overwrite mode. */ +static void vty_insert_word_overwrite(struct vty *vty, char *str) +{ + int len = strlen(str); + vty_write(vty, str, len); + strcpy(&vty->buf[vty->cp], str); + vty->cp += len; + vty->length = vty->cp; +} + +/* Forward character. */ +static void vty_forward_char(struct vty *vty) +{ + if (vty->cp < vty->length) { + vty_write(vty, &vty->buf[vty->cp], 1); + vty->cp++; + } +} + +/* Backward character. */ +static void vty_backward_char(struct vty *vty) +{ + if (vty->cp > 0) { + vty->cp--; + vty_write(vty, &telnet_backward_char, 1); + } +} + +/* Move to the beginning of the line. */ +static void vty_beginning_of_line(struct vty *vty) +{ + while (vty->cp) + vty_backward_char(vty); +} + +/* Move to the end of the line. */ +static void vty_end_of_line(struct vty *vty) +{ + while (vty->cp < vty->length) + vty_forward_char(vty); +} + +/* Add current command line to the history buffer. */ +static void vty_hist_add(struct vty *vty) +{ + int index; + + if (vty->length == 0) + return; + + index = vty->hindex ? vty->hindex - 1 : VTY_MAXHIST - 1; + + /* Ignore the same string as previous one. */ + if (vty->hist[index]) + if (strcmp(vty->buf, vty->hist[index]) == 0) { + vty->hp = vty->hindex; + return; + } + + /* Insert history entry. */ + if (vty->hist[vty->hindex]) + free(vty->hist[vty->hindex]); + vty->hist[vty->hindex] = strdup(vty->buf); + + /* History index rotation. */ + vty->hindex++; + if (vty->hindex == VTY_MAXHIST) + vty->hindex = 0; + + vty->hp = vty->hindex; +} + +/* Execute current command line. */ +static int vty_execute(struct vty *vty) +{ + int ret; + + ret = CMD_SUCCESS; + + switch (vty->node) { + case AUTH_NODE: + case AUTH_ENABLE_NODE: + vty_auth(vty, vty->buf); + break; + default: + ret = vty_command(vty, vty->buf); + if (vty->type == VTY_TERM) + vty_hist_add(vty); + break; + } + + /* Clear command line buffer. */ + vty->cp = vty->length = 0; + vty_clear_buf(vty); + + if (vty->status != VTY_CLOSE) + vty_prompt(vty); + + return ret; +} + +static void vty_kill_line_from_beginning(struct vty *); +static void vty_redraw_line(struct vty *); + +/* Print command line history. This function is called from + vty_next_line and vty_previous_line. */ +static void vty_history_print(struct vty *vty) +{ + int length; + + vty_kill_line_from_beginning(vty); + + /* Get previous line from history buffer */ + length = strlen(vty->hist[vty->hp]); + memcpy(vty->buf, vty->hist[vty->hp], length); + vty->cp = vty->length = length; + + /* Redraw current line */ + vty_redraw_line(vty); +} + +/* Show next command line history. */ +static void vty_next_line(struct vty *vty) +{ + int try_index; + + if (vty->hp == vty->hindex) + return; + + /* Try is there history exist or not. */ + try_index = vty->hp; + if (try_index == (VTY_MAXHIST - 1)) + try_index = 0; + else + try_index++; + + /* If there is not history return. */ + if (vty->hist[try_index] == NULL) + return; + else + vty->hp = try_index; + + vty_history_print(vty); +} + +/* Show previous command line history. */ +static void vty_previous_line(struct vty *vty) +{ + int try_index; + + try_index = vty->hp; + if (try_index == 0) + try_index = VTY_MAXHIST - 1; + else + try_index--; + + if (vty->hist[try_index] == NULL) + return; + else + vty->hp = try_index; + + vty_history_print(vty); +} + +/* This function redraw all of the command line character. */ +static void vty_redraw_line(struct vty *vty) +{ + vty_write(vty, vty->buf, vty->length); + vty->cp = vty->length; +} + +/* Forward word. */ +static void vty_forward_word(struct vty *vty) +{ + while (vty->cp != vty->length && vty->buf[vty->cp] != ' ') + vty_forward_char(vty); + + while (vty->cp != vty->length && vty->buf[vty->cp] == ' ') + vty_forward_char(vty); +} + +/* Backward word without skipping training space. */ +static void vty_backward_pure_word(struct vty *vty) +{ + while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ') + vty_backward_char(vty); +} + +/* Backward word. */ +static void vty_backward_word(struct vty *vty) +{ + while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ') + vty_backward_char(vty); + + while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ') + vty_backward_char(vty); +} + +/* When '^D' is typed at the beginning of the line we move to the down + level. */ +static void vty_down_level(struct vty *vty) +{ + vty_out(vty, "%s", VTY_NEWLINE); + (*config_exit_cmd.func) (NULL, vty, 0, NULL); + vty_prompt(vty); + vty->cp = 0; +} + +/* When '^Z' is received from vty, move down to the enable mode. */ +static void vty_end_config(struct vty *vty) +{ + vty_out(vty, "%s", VTY_NEWLINE); + + switch (vty->node) { + case VIEW_NODE: + case ENABLE_NODE: + /* Nothing to do. */ + break; + case CONFIG_NODE: + case INTERFACE_NODE: + case ZEBRA_NODE: + case RIP_NODE: + case RIPNG_NODE: + case BGP_NODE: + case BGP_VPNV4_NODE: + case BGP_IPV4_NODE: + case BGP_IPV4M_NODE: + case BGP_IPV6_NODE: + case RMAP_NODE: + case OSPF_NODE: + case OSPF6_NODE: + case ISIS_NODE: + case KEYCHAIN_NODE: + case KEYCHAIN_KEY_NODE: + case MASC_NODE: + case VTY_NODE: + vty_config_unlock(vty); + vty->node = ENABLE_NODE; + break; + default: + /* Unknown node, we have to ignore it. */ + break; + } + + vty_prompt(vty); + vty->cp = 0; +} + +/* Delete a charcter at the current point. */ +static void vty_delete_char(struct vty *vty) +{ + int i; + int size; + + if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE) + return; + + if (vty->length == 0) { + vty_down_level(vty); + return; + } + + if (vty->cp == vty->length) + return; /* completion need here? */ + + size = vty->length - vty->cp; + + vty->length--; + memmove(&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1); + vty->buf[vty->length] = '\0'; + + vty_write(vty, &vty->buf[vty->cp], size - 1); + vty_write(vty, &telnet_space_char, 1); + + for (i = 0; i < size; i++) + vty_write(vty, &telnet_backward_char, 1); +} + +/* Delete a character before the point. */ +static void vty_delete_backward_char(struct vty *vty) +{ + if (vty->cp == 0) + return; + + vty_backward_char(vty); + vty_delete_char(vty); +} + +/* Kill rest of line from current point. */ +static void vty_kill_line(struct vty *vty) +{ + int i; + int size; + + size = vty->length - vty->cp; + + if (size == 0) + return; + + for (i = 0; i < size; i++) + vty_write(vty, &telnet_space_char, 1); + for (i = 0; i < size; i++) + vty_write(vty, &telnet_backward_char, 1); + + memset(&vty->buf[vty->cp], 0, size); + vty->length = vty->cp; +} + +/* Kill line from the beginning. */ +static void vty_kill_line_from_beginning(struct vty *vty) +{ + vty_beginning_of_line(vty); + vty_kill_line(vty); +} + +/* Delete a word before the point. */ +static void vty_forward_kill_word(struct vty *vty) +{ + while (vty->cp != vty->length && vty->buf[vty->cp] == ' ') + vty_delete_char(vty); + while (vty->cp != vty->length && vty->buf[vty->cp] != ' ') + vty_delete_char(vty); +} + +/* Delete a word before the point. */ +static void vty_backward_kill_word(struct vty *vty) +{ + while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ') + vty_delete_backward_char(vty); + while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ') + vty_delete_backward_char(vty); +} + +/* Transpose chars before or at the point. */ +static void vty_transpose_chars(struct vty *vty) +{ + char c1, c2; + + /* If length is short or point is near by the beginning of line then + return. */ + if (vty->length < 2 || vty->cp < 1) + return; + + /* In case of point is located at the end of the line. */ + if (vty->cp == vty->length) { + c1 = vty->buf[vty->cp - 1]; + c2 = vty->buf[vty->cp - 2]; + + vty_backward_char(vty); + vty_backward_char(vty); + vty_self_insert_overwrite(vty, c1); + vty_self_insert_overwrite(vty, c2); + } else { + c1 = vty->buf[vty->cp]; + c2 = vty->buf[vty->cp - 1]; + + vty_backward_char(vty); + vty_self_insert_overwrite(vty, c1); + vty_self_insert_overwrite(vty, c2); + } +} + +/* Do completion at vty interface. */ +static void vty_complete_command(struct vty *vty) +{ + int i; + int ret; + char **matched = NULL; + vector vline; + + if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE) + return; + + vline = cmd_make_strvec(vty->buf); + if (vline == NULL) + return; + + /* In case of 'help \t'. */ + if (isspace((int)vty->buf[vty->length - 1])) + vector_set(vline, '\0'); + + matched = cmd_complete_command(vline, vty, &ret); + + cmd_free_strvec(vline); + + vty_out(vty, "%s", VTY_NEWLINE); + switch (ret) { + case CMD_ERR_AMBIGUOUS: + vty_out(vty, "%% Ambiguous command.%s", VTY_NEWLINE); + vty_prompt(vty); + vty_redraw_line(vty); + break; + case CMD_ERR_NO_MATCH: + /* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */ + vty_prompt(vty); + vty_redraw_line(vty); + break; + case CMD_COMPLETE_FULL_MATCH: + vty_prompt(vty); + vty_redraw_line(vty); + vty_backward_pure_word(vty); + vty_insert_word_overwrite(vty, matched[0]); + vty_self_insert(vty, ' '); + free(matched[0]); + break; + case CMD_COMPLETE_MATCH: + vty_prompt(vty); + vty_redraw_line(vty); + vty_backward_pure_word(vty); + vty_insert_word_overwrite(vty, matched[0]); + free(matched[0]); + vector_only_index_free(matched); + return; + break; + case CMD_COMPLETE_LIST_MATCH: + for (i = 0; matched[i] != NULL; i++) { + if (i != 0 && ((i % 6) == 0)) + vty_out(vty, "%s", VTY_NEWLINE); + vty_out(vty, "%-10s ", matched[i]); + free(matched[i]); + } + vty_out(vty, "%s", VTY_NEWLINE); + + vty_prompt(vty); + vty_redraw_line(vty); + break; + case CMD_ERR_NOTHING_TODO: + vty_prompt(vty); + vty_redraw_line(vty); + break; + default: + break; + } + if (matched) + vector_only_index_free(matched); +} + +static void +vty_describe_fold(struct vty *vty, int cmd_width, + unsigned int desc_width, struct desc *desc) +{ + char *buf; + const char *cmd, *p; + int pos; + + cmd = desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd; + + if (desc_width <= 0) { + vty_out(vty, " %-*s %s%s", cmd_width, cmd, desc->str, + VTY_NEWLINE); + return; + } + + buf = calloc(1, strlen(desc->str) + 1); + if (!buf) + return; + + for (p = desc->str; strlen(p) > desc_width; p += pos + 1) { + for (pos = desc_width; pos > 0; pos--) + if (*(p + pos) == ' ') + break; + + if (pos == 0) + break; + + strncpy(buf, p, pos); + buf[pos] = '\0'; + vty_out(vty, " %-*s %s%s", cmd_width, cmd, buf, VTY_NEWLINE); + + cmd = ""; + } + + vty_out(vty, " %-*s %s%s", cmd_width, cmd, p, VTY_NEWLINE); + + free(buf); +} + +/* Describe matched command function. */ +static void vty_describe_command(struct vty *vty) +{ + int ret; + vector vline; + vector describe; + unsigned int i, width, desc_width; + struct desc *desc, *desc_cr = NULL; + + vline = cmd_make_strvec(vty->buf); + + /* In case of '> ?'. */ + if (vline == NULL) { + vline = vector_init(1); + vector_set(vline, '\0'); + } else if (isspace((int)vty->buf[vty->length - 1])) + vector_set(vline, '\0'); + + describe = cmd_describe_command(vline, vty, &ret); + + vty_out(vty, "%s", VTY_NEWLINE); + + /* Ambiguous error. */ + switch (ret) { + case CMD_ERR_AMBIGUOUS: + cmd_free_strvec(vline); + vty_out(vty, "%% Ambiguous command.%s", VTY_NEWLINE); + vty_prompt(vty); + vty_redraw_line(vty); + return; + break; + case CMD_ERR_NO_MATCH: + cmd_free_strvec(vline); + vty_out(vty, "%% There is no matched command.%s", VTY_NEWLINE); + vty_prompt(vty); + vty_redraw_line(vty); + return; + break; + } + + /* Get width of command string. */ + width = 0; + for (i = 0; i < vector_active(describe); i++) + if ((desc = vector_slot(describe, i)) != NULL) { + unsigned int len; + + if (desc->cmd[0] == '\0') + continue; + + len = strlen(desc->cmd); + if (desc->cmd[0] == '.') + len--; + + if (width < len) + width = len; + } + + /* Get width of description string. */ + desc_width = vty->width - (width + 6); + + /* Print out description. */ + for (i = 0; i < vector_active(describe); i++) + if ((desc = vector_slot(describe, i)) != NULL) { + if (desc->cmd[0] == '\0') + continue; + + if (strcmp(desc->cmd, "") == 0) { + desc_cr = desc; + continue; + } + + if (!desc->str) + vty_out(vty, " %-s%s", + desc->cmd[0] == + '.' ? desc->cmd + 1 : desc->cmd, + VTY_NEWLINE); + else if (desc_width >= strlen(desc->str)) + vty_out(vty, " %-*s %s%s", width, + desc->cmd[0] == + '.' ? desc->cmd + 1 : desc->cmd, + desc->str, VTY_NEWLINE); + else + vty_describe_fold(vty, width, desc_width, desc); + +#if 0 + vty_out(vty, " %-*s %s%s", width + desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, + desc->str ? desc->str : "", VTY_NEWLINE); +#endif /* 0 */ + } + + if ((desc = desc_cr)) { + if (!desc->str) + vty_out(vty, " %-s%s", + desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, + VTY_NEWLINE); + else if (desc_width >= strlen(desc->str)) + vty_out(vty, " %-*s %s%s", width, + desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, + desc->str, VTY_NEWLINE); + else + vty_describe_fold(vty, width, desc_width, desc); + } + + cmd_free_strvec(vline); + vector_free(describe); + + vty_prompt(vty); + vty_redraw_line(vty); +} + +/* ^C stop current input and do not add command line to the history. */ +static void vty_stop_input(struct vty *vty) +{ + vty->cp = vty->length = 0; + vty_clear_buf(vty); + vty_out(vty, "%s", VTY_NEWLINE); + + switch (vty->node) { + case VIEW_NODE: + case ENABLE_NODE: + /* Nothing to do. */ + break; + case CONFIG_NODE: + case INTERFACE_NODE: + case ZEBRA_NODE: + case RIP_NODE: + case RIPNG_NODE: + case BGP_NODE: + case RMAP_NODE: + case OSPF_NODE: + case OSPF6_NODE: + case ISIS_NODE: + case KEYCHAIN_NODE: + case KEYCHAIN_KEY_NODE: + case MASC_NODE: + case VTY_NODE: + vty_config_unlock(vty); + vty->node = ENABLE_NODE; + break; + default: + /* Unknown node, we have to ignore it. */ + break; + } + vty_prompt(vty); + + /* Set history pointer to the latest one. */ + vty->hp = vty->hindex; +} + +#define CONTROL(X) ((X) - '@') +#define VTY_NORMAL 0 +#define VTY_PRE_ESCAPE 1 +#define VTY_ESCAPE 2 + +/* Escape character command map. */ +static void vty_escape_map(unsigned char c, struct vty *vty) +{ + switch (c) { + case ('A'): + vty_previous_line(vty); + break; + case ('B'): + vty_next_line(vty); + break; + case ('C'): + vty_forward_char(vty); + break; + case ('D'): + vty_backward_char(vty); + break; + default: + break; + } + + /* Go back to normal mode. */ + vty->escape = VTY_NORMAL; +} + +/* Quit print out to the buffer. */ +static void vty_buffer_reset(struct vty *vty) +{ + buffer_reset(vty->obuf); + vty_prompt(vty); + vty_redraw_line(vty); +} + +/* Read data via vty socket. */ +int vty_read(struct vty *vty) +{ + int i; + int nbytes; + unsigned char buf[VTY_READ_BUFSIZ]; + + int vty_sock = 0; + + /* Read raw data from socket */ + if ((nbytes = read(vty->fd, buf, VTY_READ_BUFSIZ)) <= 0) { + if (nbytes < 0) { + if (ERRNO_IO_RETRY(errno)) { + vty_event(VTY_READ, vty_sock, vty); + return 0; + } + } + buffer_reset(vty->obuf); + vty->status = VTY_CLOSE; + } + + for (i = 0; i < nbytes; i++) { +#if 0 + if (buf[i] == IAC) { + if (!vty->iac) { + vty->iac = 1; + continue; + } else { + vty->iac = 0; + } + } + + if (vty->iac_sb_in_progress && !vty->iac) { + if (vty->sb_len < sizeof(vty->sb_buf)) + vty->sb_buf[vty->sb_len] = buf[i]; + vty->sb_len++; + continue; + } + + if (vty->iac) { + /* In case of telnet command */ + int ret = 0; + ret = vty_telnet_option(vty, buf + i, nbytes - i); + vty->iac = 0; + i += ret; + continue; + } +#endif + + if (vty->status == VTY_MORE) { + switch (buf[i]) { + case CONTROL('C'): + case 'q': + case 'Q': + vty_buffer_reset(vty); + break; +#if 0 /* More line does not work for "show ip bgp". */ + case '\n': + case '\r': + vty->status = VTY_MORELINE; + break; +#endif + default: + break; + } + continue; + } + + /* Escape character. */ + if (vty->escape == VTY_ESCAPE) { + vty_escape_map(buf[i], vty); + continue; + } + + /* Pre-escape status. */ + if (vty->escape == VTY_PRE_ESCAPE) { + switch (buf[i]) { + case '[': + vty->escape = VTY_ESCAPE; + break; + case 'b': + vty_backward_word(vty); + vty->escape = VTY_NORMAL; + break; + case 'f': + vty_forward_word(vty); + vty->escape = VTY_NORMAL; + break; + case 'd': + vty_forward_kill_word(vty); + vty->escape = VTY_NORMAL; + break; + case CONTROL('H'): + case 0x7f: + vty_backward_kill_word(vty); + vty->escape = VTY_NORMAL; + break; + default: + vty->escape = VTY_NORMAL; + break; + } + continue; + } + + switch (buf[i]) { + case CONTROL('A'): + vty_beginning_of_line(vty); + break; + case CONTROL('B'): + vty_backward_char(vty); + break; + case CONTROL('C'): + vty_stop_input(vty); + break; + case CONTROL('D'): + vty_delete_char(vty); + break; + case CONTROL('E'): + vty_end_of_line(vty); + break; + case CONTROL('F'): + vty_forward_char(vty); + break; + case CONTROL('H'): + case 0x7f: + vty_delete_backward_char(vty); + break; + case CONTROL('K'): + vty_kill_line(vty); + break; + case CONTROL('N'): + vty_next_line(vty); + break; + case CONTROL('P'): + vty_previous_line(vty); + break; + case CONTROL('T'): + vty_transpose_chars(vty); + break; + case CONTROL('U'): + vty_kill_line_from_beginning(vty); + break; + case CONTROL('W'): + vty_backward_kill_word(vty); + break; + case CONTROL('Z'): + vty_end_config(vty); + break; + case '\n': + case '\r': + vty_out(vty, "%s", VTY_NEWLINE); + vty_execute(vty); + break; + case '\t': + vty_complete_command(vty); + break; + case '?': + if (vty->node == AUTH_NODE + || vty->node == AUTH_ENABLE_NODE) + vty_self_insert(vty, buf[i]); + else + vty_describe_command(vty); + break; + case '\033': + if (i + 1 < nbytes && buf[i + 1] == '[') { + vty->escape = VTY_ESCAPE; + i++; + } else + vty->escape = VTY_PRE_ESCAPE; + break; + default: + if (buf[i] > 31 && buf[i] < 127) + vty_self_insert(vty, buf[i]); + break; + } + } + + /* Check status. */ + if (vty->status == VTY_CLOSE) + vty_close(vty); + else { + vty_event(VTY_WRITE, vty_sock, vty); + vty_event(VTY_READ, vty_sock, vty); + } + return 0; +} + +/* Create new vty structure. */ +struct vty * +vty_create (int vty_sock) +{ + struct vty *vty; + + struct termios t; + + tcgetattr(vty_sock, &t); + cfmakeraw(&t); + tcsetattr(vty_sock, TCSANOW, &t); + + /* Allocate new vty structure and set up default values. */ + vty = vty_new (); + vty->fd = vty_sock; + vty->type = VTY_TERM; + if (no_password_check) + { + if (host.advanced) + vty->node = ENABLE_NODE; + else + vty->node = VIEW_NODE; + } + else + vty->node = AUTH_NODE; + vty->fail = 0; + vty->cp = 0; + vty_clear_buf (vty); + vty->length = 0; + memset (vty->hist, 0, sizeof (vty->hist)); + vty->hp = 0; + vty->hindex = 0; + vector_set_index (vtyvec, vty_sock, vty); + vty->status = VTY_NORMAL; + if (host.lines >= 0) + vty->lines = host.lines; + else + vty->lines = -1; + + if (! no_password_check) + { + /* Vty is not available if password isn't set. */ + if (host.password == NULL && host.password_encrypt == NULL) + { + vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE); + vty->status = VTY_CLOSE; + vty_close (vty); + return NULL; + } + } + + /* Say hello to the world. */ + vty_hello (vty); + if (! no_password_check) + vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + +#if 0 + /* Setting up terminal. */ + vty_will_echo (vty); + vty_will_suppress_go_ahead (vty); + + vty_dont_linemode (vty); + vty_do_window_size (vty); + /* vty_dont_lflow_ahead (vty); */ +#endif + + vty_prompt (vty); + + /* Add read/write thread. */ + vty_event (VTY_WRITE, vty_sock, vty); + vty_event (VTY_READ, vty_sock, vty); + + return vty; +} + +DEFUN(config_who, config_who_cmd, "who", "Display who is on vty\n") +{ + unsigned int i; + struct vty *v; + + for (i = 0; i < vector_active(vtyvec); i++) + if ((v = vector_slot(vtyvec, i)) != NULL) + vty_out(vty, "%svty[%d] %s", + v->config ? "*" : " ", i, VTY_NEWLINE); + return CMD_SUCCESS; +} + +/* Move to vty configuration mode. */ +DEFUN(line_vty, + line_vty_cmd, + "line vty", "Configure a terminal line\n" "Virtual terminal\n") +{ + vty->node = VTY_NODE; + return CMD_SUCCESS; +} + +/* vty login. */ +DEFUN(vty_login, vty_login_cmd, "login", "Enable password checking\n") +{ + no_password_check = 0; + return CMD_SUCCESS; +} + +DEFUN(no_vty_login, + no_vty_login_cmd, "no login", NO_STR "Enable password checking\n") +{ + no_password_check = 1; + return CMD_SUCCESS; +} + +DEFUN(service_advanced_vty, + service_advanced_vty_cmd, + "service advanced-vty", + "Set up miscellaneous service\n" "Enable advanced mode vty interface\n") +{ + host.advanced = 1; + return CMD_SUCCESS; +} + +DEFUN(no_service_advanced_vty, + no_service_advanced_vty_cmd, + "no service advanced-vty", + NO_STR + "Set up miscellaneous service\n" "Enable advanced mode vty interface\n") +{ + host.advanced = 0; + return CMD_SUCCESS; +} + +DEFUN(terminal_monitor, + terminal_monitor_cmd, + "terminal monitor", + "Set terminal line parameters\n" + "Copy debug output to the current terminal line\n") +{ + vty->monitor = 1; + return CMD_SUCCESS; +} + +DEFUN(terminal_no_monitor, + terminal_no_monitor_cmd, + "terminal no monitor", + "Set terminal line parameters\n" + NO_STR "Copy debug output to the current terminal line\n") +{ + vty->monitor = 0; + return CMD_SUCCESS; +} + +DEFUN(show_history, + show_history_cmd, + "show history", SHOW_STR "Display the session command history\n") +{ + int index; + + for (index = vty->hindex + 1; index != vty->hindex;) { + if (index == VTY_MAXHIST) { + index = 0; + continue; + } + + if (vty->hist[index] != NULL) + vty_out(vty, " %s%s", vty->hist[index], VTY_NEWLINE); + + index++; + } + + return CMD_SUCCESS; +} + +/* Display current configuration. */ +static int vty_config_write(struct vty *vty) +{ + vty_out(vty, "line vty%s", VTY_NEWLINE); + + /* login */ + if (no_password_check) + vty_out(vty, " no login%s", VTY_NEWLINE); + + vty_out(vty, "!%s", VTY_NEWLINE); + + return CMD_SUCCESS; +} + +struct cmd_node vty_node = { + VTY_NODE, + "%s(config-line)# ", + 1, +}; + +/* Reset all VTY status. */ +void vty_reset() +{ + unsigned int i; + struct vty *vty; + struct thread *vty_serv_thread; + + for (i = 0; i < vector_active(vtyvec); i++) + if ((vty = vector_slot(vtyvec, i)) != NULL) { + buffer_reset(vty->obuf); + vty->status = VTY_CLOSE; + vty_close(vty); + } + + for (i = 0; i < vector_active(Vvty_serv_thread); i++) + if ((vty_serv_thread = + vector_slot(Vvty_serv_thread, i)) != NULL) { + //thread_cancel (vty_serv_thread); + vector_slot(Vvty_serv_thread, i) = NULL; + close(i); + } +} + +static void vty_save_cwd(void) +{ + char cwd[MAXPATHLEN]; + char *c; + + c = getcwd(cwd, MAXPATHLEN); + + if (!c) { + chdir(SYSCONFDIR); + getcwd(cwd, MAXPATHLEN); + } + + vty_cwd = malloc(strlen(cwd) + 1); + strcpy(vty_cwd, cwd); +} + +char *vty_get_cwd() +{ + return vty_cwd; +} + +int vty_shell_serv(struct vty *vty) +{ + return vty->type == VTY_SHELL_SERV ? 1 : 0; +} + +void vty_init_vtysh() +{ + vtyvec = vector_init(VECTOR_MIN_SIZE); +} + +/* Install vty's own commands like `who' command. */ +void vty_init() +{ + /* For further configuration read, preserve current directory. */ + vty_save_cwd(); + + vtyvec = vector_init(VECTOR_MIN_SIZE); + + /* Install bgp top node. */ + install_node(&vty_node, vty_config_write); + + install_element(VIEW_NODE, &config_who_cmd); + install_element(VIEW_NODE, &show_history_cmd); + install_element(ENABLE_NODE, &config_who_cmd); + install_element(CONFIG_NODE, &line_vty_cmd); + install_element(CONFIG_NODE, &service_advanced_vty_cmd); + install_element(CONFIG_NODE, &no_service_advanced_vty_cmd); + install_element(CONFIG_NODE, &show_history_cmd); + install_element(ENABLE_NODE, &terminal_monitor_cmd); + install_element(ENABLE_NODE, &terminal_no_monitor_cmd); + install_element(ENABLE_NODE, &show_history_cmd); + + install_default(VTY_NODE); +#if 0 + install_element(VTY_NODE, &vty_login_cmd); + install_element(VTY_NODE, &no_vty_login_cmd); +#endif +} diff --git a/host/zebvty/vty.h b/host/zebvty/vty.h new file mode 100644 index 0000000..ffa845b --- /dev/null +++ b/host/zebvty/vty.h @@ -0,0 +1,118 @@ +#ifndef _VTY_H +#define _VTY_H + +#include +#include + +/* GCC have printf type attribute check. */ +#ifdef __GNUC__ +#define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b))) +#else +#define PRINTF_ATTRIBUTE(a,b) +#endif /* __GNUC__ */ + +/* Does the I/O error indicate that the operation should be retried later? */ +#define ERRNO_IO_RETRY(EN) \ + (((EN) == EAGAIN) || ((EN) == EWOULDBLOCK) || ((EN) == EINTR)) + +/* Vty read buffer size. */ +#define VTY_READ_BUFSIZ 512 + +#define VTY_BUFSIZ 512 +#define VTY_MAXHIST 20 + +struct vty { + FILE *file; + + /* File descripter of this vty. */ + int fd; + + /* Is this vty connect to file or not */ + enum { VTY_TERM, VTY_FILE, VTY_SHELL, VTY_SHELL_SERV } type; + + /* Node status of this vty */ + int node; + + /* Failure count */ + int fail; + + /* Output buffer. */ + struct buffer *obuf; + + /* Command input buffer */ + char *buf; + + /* Command cursor point */ + int cp; + + /* Command length */ + int length; + + /* Command max length. */ + int max; + + /* Histry of command */ + char *hist[VTY_MAXHIST]; + + /* History lookup current point */ + int hp; + + /* History insert end point */ + int hindex; + + /* For current referencing point of interface, route-map, + access-list etc... */ + void *index; + + /* For multiple level index treatment such as key chain and key. */ + void *index_sub; + + /* For escape character. */ + unsigned char escape; + + /* Current vty status. */ + enum { VTY_NORMAL, VTY_CLOSE, VTY_MORE, VTY_MORELINE } status; + + /* Window width/height. */ + int width; + int height; + + /* Configure lines. */ + int lines; + + int monitor; + + /* In configure mode. */ + int config; +}; + +/* Small macro to determine newline is newline only or linefeed needed. */ +#define VTY_NEWLINE ((vty->type == VTY_TERM) ? "\r\n" : "\n") + +static inline char *vty_newline(struct vty *vty) +{ + return VTY_NEWLINE; +} + +/* Prototypes. */ +void vty_init (void); +void vty_init_vtysh (void); +void vty_reset (void); +struct vty *vty_new (void); +struct vty *vty_create (int vty_sock); +int vty_out (struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3); +int vty_out_newline(struct vty *); +int vty_read(struct vty *vty); +void vty_read_config (char *, char *); +void vty_time_print (struct vty *, int); +void vty_close (struct vty *); +char *vty_get_cwd (void); +void vty_log (const char *level, const char *proto, const char *fmt, va_list); +int vty_config_lock (struct vty *); +int vty_config_unlock (struct vty *); +int vty_shell (struct vty *); +int vty_shell_serv (struct vty *); +void vty_hello (struct vty *); + + +#endif diff --git a/host/zebvty/zebvty.h b/host/zebvty/zebvty.h new file mode 100644 index 0000000..a992bb2 --- /dev/null +++ b/host/zebvty/zebvty.h @@ -0,0 +1,5 @@ +#define QUAGGA_PROGNAME "opcd_shell" +#define QUAGGA_VERSION "0.01" +#define QUAGGA_COPYRIGHT "Harald Welte " +#define CONFIGFILE_MASK 022 +#define SYSCONFDIR "/etc" diff --git a/openpcd/opcd_test/Makefile b/openpcd/opcd_test/Makefile deleted file mode 100644 index 12edce0..0000000 --- a/openpcd/opcd_test/Makefile +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/make -LDFLAGS=-lusb -lcrypt #-lzebvty -Lzebvty/ -CFLAGS=-Wall - -all: opcd_test opcd_sh - -clean: - -rm -f *.o opcd_test - $(MAKE) -C ausb clean - -ausb/libausb.a: - $(MAKE) -C ausb libausb.a - -opcd_test: opcd_test.o opcd_usb.o ausb/libausb.a - $(CC) $(LDFLAGS) -o $@ $^ - -opcd_sh: opcd_sh.o opcd_usb.o ausb/libausb.a zebvty/libzebvty.a - $(CC) $(LDFLAGS) -o $@ $^ - - -%.o: %.c - $(CC) $(CFLAGS) -o $@ -c $< - -.PHONEY: all clean diff --git a/openpcd/opcd_test/ausb/Makefile b/openpcd/opcd_test/ausb/Makefile deleted file mode 100644 index 6269739..0000000 --- a/openpcd/opcd_test/ausb/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -#include ../../makevars - -OBJS=ausb.o usb.o -CFLAGS+=-fPIC - -all: libausb.a libausb.so - -libausb.a: $(OBJS) - $(AR) r $@ $^ - -libausb.so: $(OBJS) - $(LD) -x --shared -o $@ $^ - -%.o: %.c - $(CC) $(CFLAGS) -o $@ -c $^ - -ausb_test: ausb_test.o ausb.o - $(CC) $(CFLAGS) -lusb -o $@ $^ - -clean: - @rm -f *.o ausb_test libusb.a libausb.a libausb.so diff --git a/openpcd/opcd_test/ausb/ausb.c b/openpcd/opcd_test/ausb/ausb.c deleted file mode 100644 index 8b0117f..0000000 --- a/openpcd/opcd_test/ausb/ausb.c +++ /dev/null @@ -1,331 +0,0 @@ -/* Wrapper/Extension code to libusb-0.1 to support asynchronous requests - * on Linux platforns - * - * (C) 2004-2005 by Harald Welte - * - * Distributed and licensed under the terms of GNU LGPL, Version 2.1 - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ausb.h" -#include "usb.h" - -#ifdef DEBUG_AUSB -#define DEBUGP(x, args...) fprintf(stderr, "%s:%s():%u " x, __FILE__, \ - __FUNCTION__, __LINE__, ## args) -#else -#define DEBUGP(x, args...); -#endif - -#define SIGAUSB (SIGRTMIN+1) - -static int ausb_get_fd(ausb_dev_handle *ah) -{ - return *((int *)ah->uh); -} - - -static int kernel_2_5; - -/* FIXME: this has to go */ -static struct ausb_dev_handle *last_handle = NULL; - -static int is_kernel_2_5() -{ - struct utsname uts; - int ret; - - uname(&uts); - - ret = (strncmp(uts.release, "2.5.", 4) == 0) || - (strncmp(uts.release, "2.6.", 4) == 0); - - return ret; -} - -void ausb_dump_urb(struct usbdevfs_urb *uurb) -{ - DEBUGP("urb(%p): type=%u, endpoint=0x%x, status=%d, flags=0x%x, number_of_packets=%d, error_count=%d\n", uurb, uurb->type, uurb->endpoint, uurb->status, uurb->flags, uurb->number_of_packets, uurb->error_count); -} - -void ausb_fill_int_urb(struct usbdevfs_urb *uurb, unsigned char endpoint, - void *buffer, int buffer_length) - -{ - uurb->type = kernel_2_5 ? USBDEVFS_URB_TYPE_INTERRUPT : USBDEVFS_URB_TYPE_BULK; - uurb->endpoint = endpoint; /* | USB_DIR_IN; */ - uurb->flags = kernel_2_5 ? 0 : 1 ; /* USBDEVFS_URB_QUEUE_BULK; */ - uurb->buffer = buffer; - uurb->buffer_length = buffer_length; - uurb->signr = SIGAUSB; - uurb->start_frame = -1; -} - -int ausb_submit_urb(ausb_dev_handle *ah, struct usbdevfs_urb *uurb) -{ - int ret; - - DEBUGP("ah=%p\n", ah); - ausb_dump_urb(uurb); - - /* save ausb_dev_handle in opaque usercontext field */ - uurb->usercontext = ah; - - do { - ret = ioctl(ausb_get_fd(ah), USBDEVFS_SUBMITURB, uurb); - } while (ret < 0 && errno == EINTR); - - return ret; -} - -int ausb_discard_urb(ausb_dev_handle *ah, struct usbdevfs_urb *uurb) -{ - int ret; - - DEBUGP("ah=%p, uurb=%p\n"); - ausb_dump_urb(uurb); - - do { - ret = ioctl(ausb_get_fd(ah), USBDEVFS_DISCARDURB, uurb); - } while (ret < 0 && errno == EINTR); - - return ret; -} - -struct usbdevfs_urb *ausb_get_urb(ausb_dev_handle *ah) -{ - int ret; - struct usbdevfs_urb *uurb; - - DEBUGP("entering\n"); - - do { - ret = ioctl(ausb_get_fd(ah), USBDEVFS_REAPURBNDELAY, &uurb); - } while (ret < 0 && errno == EINTR); - - if (ret < 0 && errno == EAGAIN) { - DEBUGP("ioctl returned %d (errno=%s)\n", ret, - strerror(errno)); - return NULL; - } - - DEBUGP("returning %p\n", uurb); - return uurb; -} - -static void handle_urb(struct usbdevfs_urb *uurb) -{ - struct ausb_dev_handle *ah = uurb->usercontext; - - DEBUGP("called, ah=%p\n", ah); - - if (uurb->type >= AUSB_USBDEVFS_URB_TYPES) { - DEBUGP("unknown uurb type %u\n", uurb->type); - return; - } - - if (!ah) { - DEBUGP("cant't call handler because missing ah ptr\n"); - return; - } - - if (!ah->cb[uurb->type].handler) { - DEBUGP("received URB type %u, but no handler\n", uurb->type); - return; - } - ah->cb[uurb->type].handler(uurb, ah->cb[uurb->type].userdata); -} - -static void sigact_rtmin(int sig, siginfo_t *siginfo, void *v) -{ - int count; - struct usbdevfs_urb *urb; - - if (sig != SIGAUSB) - return; - - //DEBUGP("errno=%d, si_addr=%p\n", siginfo->errno, siginfo->si_addr); - - DEBUGP("last_handle=%p\n", last_handle); - - if (!last_handle) - return; - - for (count = 0; ; count++) { - urb = ausb_get_urb(last_handle); - - if (urb == NULL) { - DEBUGP("ausb_get_urb() returned urb==NULL\n"); - break; - } - - DEBUGP("calling handle_urb(%p)\n", urb); - handle_urb(urb); - } -} - - -int ausb_init(void) -{ - struct sigaction act; - - DEBUGP("entering\n"); - - memset(&act, 0, sizeof(act)); - act.sa_sigaction = sigact_rtmin; - sigemptyset(&act.sa_mask); - act.sa_flags = SA_SIGINFO; - - sigaction(SIGAUSB, &act, NULL); - - kernel_2_5 = is_kernel_2_5(); - - DEBUGP("kernel 2.5+ = %d\n", kernel_2_5); - - usb_init(); - usb_find_busses(); - usb_find_devices(); - return 1; -} - -ausb_dev_handle *ausb_open(struct usb_device *dev) -{ - ausb_dev_handle *dh = malloc(sizeof *dh); - - DEBUGP("entering, dh=%p\n", dh); - - memset(dh, 0, sizeof(*dh)); - - dh->uh = usb_open(dev); - - if (!dh->uh) { - DEBUGP("usb_open() failed\n"); - free(dh); - return NULL; - } - - last_handle = dh; - DEBUGP("last_handle = %p\n", last_handle); - - return dh; -} - -int ausb_register_callback(ausb_dev_handle *ah, unsigned char type, - void (*callback)(struct usbdevfs_urb *uurb, - void *userdata), - void *userdata) -{ - DEBUGP("registering callback for type %u:%p\n", type, callback); - - if (type >= AUSB_USBDEVFS_URB_TYPES) { - errno = EINVAL; - return -1; - } - - if (!kernel_2_5 && type == USBDEVFS_URB_TYPE_INTERRUPT) - type = USBDEVFS_URB_TYPE_BULK; - - ah->cb[type].handler = callback; - ah->cb[type].userdata = userdata; - - return 0; -} - -int ausb_claim_interface(ausb_dev_handle *ah, int interface) -{ - DEBUGP("entering\n"); - return usb_claim_interface(ah->uh, interface); -} - -int ausb_release_interface(ausb_dev_handle *ah, int interface) -{ - DEBUGP("entering\n"); - /* what the hell? */ - if (ah == last_handle) - last_handle = NULL; - return usb_release_interface(ah->uh, interface); -} - -int ausb_set_configuration(ausb_dev_handle *ah, int configuration) -{ - DEBUGP("entering\n"); - return usb_set_configuration(ah->uh, configuration); -} - -int ausb_bulk_write(ausb_dev_handle *ah, int ep, char *bytes, int size, int timeout) -{ - DEBUGP("entering (ah=%p, ep=0x%x, bytes=%p, size=%d, timeout=%d\n", - ah, ep, bytes, size, timeout); - return __usb_bulk_write(ah->uh, ep, bytes, size, timeout); -} - -int ausb_bulk_read(ausb_dev_handle *ah, int ep, char *bytes, int size, int timeout) -{ - DEBUGP("entering (ah=%p, ep=0x%x, bytes=%p, size=%d, timeout=%d\n", - ah, ep, bytes, size, timeout); - return __usb_bulk_read(ah->uh, ep, bytes, size, timeout); -} - -int ausb_clear_halt(ausb_dev_handle *ah, unsigned int ep) -{ - DEBUGP("entering (ah=%p, ep=0x%x)\n", ah, ep); - return usb_clear_halt(ah->uh, ep); -} - -int ausb_reset(ausb_dev_handle *ah) -{ - DEBUGP("entering (ah=%p)\n", ah); - return usb_reset(ah->uh); -} - -int ausb_resetep(ausb_dev_handle *ah, int ep) -{ - DEBUGP("entering (ah=%pm ep=0x%x)\n", ah, ep); - return usb_resetep(ah->uh, ep); -} - -#ifdef LIBUSB_HAS_GET_DRIVER_NP -int ausb_get_driver_np(ausb_dev_handle *ah, int interface, char *name, - unsigned int namelen) -{ - DEBUGP("entering\n"); - return usb_get_driver_np(ah->uh, interface, name, namelen); -} -#endif - -#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP -int ausb_detach_kernel_driver_np(ausb_dev_handle *ah, int interface) -{ - DEBUGP("entering\n"); - return usb_detach_kernel_driver_np(ah->uh, interface); -} -int ausb_reattach_kernel_driver_np(ausb_dev_handle *ah, int interface) -{ - DEBUGP("entering\n"); - return __usb_reattach_kernel_driver_np(ah->uh, interface); -} -#endif - -int ausb_close(struct ausb_dev_handle *ah) -{ - DEBUGP("entering\n"); - - if (ah == last_handle) - last_handle = NULL; - - return usb_close(ah->uh); -} - -void ausb_fini(void) -{ - DEBUGP("entering\n"); - sigaction(SIGAUSB, NULL, NULL); -} diff --git a/openpcd/opcd_test/ausb/ausb.h b/openpcd/opcd_test/ausb/ausb.h deleted file mode 100644 index 4d62cac..0000000 --- a/openpcd/opcd_test/ausb/ausb.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef _AUSB_H -#define _AUSB_H - -/* Wrapper/Extension code to libusb-0.1 to support asynchronous requests - * on Linux platforns - * - * (C) 2004 by Harald Welte - * - * Distributed under the terms of GNU LGPL, Version 2.1 - */ - - -#include -#include - -#define AUSB_USBDEVFS_URB_TYPES 4 - -/* structures */ -struct ausb_callback { - void (*handler)(struct usbdevfs_urb *uurb, void *userdata); - void *userdata; -}; - -struct ausb_dev_handle { - usb_dev_handle *uh; - struct ausb_callback cb[AUSB_USBDEVFS_URB_TYPES]; -}; - -typedef struct ausb_dev_handle ausb_dev_handle; - -/* intitialization */ -int ausb_init(void); -ausb_dev_handle *ausb_open(struct usb_device *dev); -int ausb_close(ausb_dev_handle *ah); -int ausb_register_callback(ausb_dev_handle *ah, unsigned char type, - void (*callback)(struct usbdevfs_urb *uurb, - void *userdata), - void *userdata); - -/* asynchronous URB related functions */ -void ausb_dump_urb(struct usbdevfs_urb *uurb); -void ausb_fill_int_urb(struct usbdevfs_urb *uurb, unsigned char endpoint, - void *buffer, int buffer_length); -int ausb_submit_urb(ausb_dev_handle *ah, struct usbdevfs_urb *uurb); -int ausb_discard_urb(ausb_dev_handle *ah, struct usbdevfs_urb *uurb); -struct usbdevfs_urb *ausb_get_urb(ausb_dev_handle *ah); - -/* synchronous functions, mostly wrappers for libusb */ -int ausb_claim_interface(ausb_dev_handle *ah, int interface); -int ausb_release_interface(ausb_dev_handle *ah, int interface); -int ausb_set_configuration(ausb_dev_handle *dev, int configuration); -int ausb_clear_halt(ausb_dev_handle *dev, unsigned int ep); -int ausb_reset(ausb_dev_handle *dev); -int ausb_resetep(ausb_dev_handle *dev, int ep); -int ausb_bulk_write(ausb_dev_handle *ah, int ep, char *bytes, int size, - int timeout); -int ausb_bulk_read(ausb_dev_handle *ah, int ep, char *bytes, int size, - int timeout); -#ifdef LIBUSB_HAS_GET_DRIVER_NP -int ausb_get_driver_np(ausb_dev_handle *ah, int interface, char *name, - unsigned int namelen); -#endif -#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP -int ausb_detach_kernel_driver_np(ausb_dev_handle *dev, int interface); -int ausb_reattach_kernel_driver_np(ausb_dev_handle *dev, int interface); -#endif - -#endif /* _AUSB_H */ diff --git a/openpcd/opcd_test/ausb/ausb_test.c b/openpcd/opcd_test/ausb/ausb_test.c deleted file mode 100644 index f7bfdee..0000000 --- a/openpcd/opcd_test/ausb/ausb_test.c +++ /dev/null @@ -1,95 +0,0 @@ -#include -#include -#include -#include - -#include "ausb.h" - -#define CJPPA_USB_VENDOR_ID 0x0c4b -#define CJPPA_USB_DEVICE_ID 0x0100 - -static struct usb_device *find_cj_usbdev(int num) -{ - struct usb_bus *busses, *bus; - struct usb_device *dev; - int found = 0; - - busses = usb_get_busses(); - - for (bus = busses; bus; bus = bus->next) { - for (dev = bus->devices; dev; dev = dev->next) { - if (dev->descriptor.idVendor == CJPPA_USB_VENDOR_ID && - dev->descriptor.idProduct == CJPPA_USB_DEVICE_ID) { - found++; - if (found == num) - return dev; - } - } - } - return NULL; -} - -static void int_cb(struct usbdevfs_urb *uurb) -{ - struct ausb_dev_handle *ah = uurb->usercontext; - - fprintf(stdout, __FUNCTION__ " called, "); - - ausb_dump_urb(uurb); - - if (ausb_submit_urb(ah, uurb)) - fprintf(stderr, "unable to resubmit urb\n"); -} - -int main(int argc, char **argv) -{ - struct usb_device *dev; - struct ausb_dev_handle *ah; - struct usbdevfs_urb *uurb; - char buffer[280]; - ausb_init(); - - uurb = malloc(sizeof(*uurb)); - - dev = find_cj_usbdev(1); - - if (!dev) { - fprintf(stderr, "unable to find matching usb device\n"); - exit(1); - } - - ah = ausb_open(dev); - if (!ah) { - fprintf(stderr, "error while opening usb device\n"); - exit(1); - } - - if (ausb_claim_interface(ah, 0)) { - fprintf(stderr, "unable to claim interface\n"); - ausb_close(ah); - exit(1); - } - - if (usb_set_configuration(ah->uh, 1)) { - fprintf(stderr, "unable to set configuration 1\n"); - ausb_close(ah); - exit(1); - } - -#if 1 - ausb_fill_int_urb(uurb, 0x81, buffer, sizeof(buffer)); - if (ausb_submit_urb(ah, uurb)) { - fprintf(stderr, "unable to submit urb\n"); - ausb_close(ah); - exit(1); - } - - while (1) { - sleep(10); - } -#endif - - ausb_close(ah); - - exit(0); -} diff --git a/openpcd/opcd_test/ausb/usb.c b/openpcd/opcd_test/ausb/usb.c deleted file mode 100644 index 1f1078d..0000000 --- a/openpcd/opcd_test/ausb/usb.c +++ /dev/null @@ -1,86 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#define MAX_READ_WRITE 4096 - -#define USB_ERROR_STR(ret, x, args...) return ret - -static int usb_get_fd(usb_dev_handle *uh) -{ - return *((int *)uh); -} - -int __usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int length, - int timeout) -{ - struct usbdevfs_bulktransfer bulk; - int ret, sent = 0; - - /* Ensure the endpoint address is correct */ - ep &= ~USB_ENDPOINT_IN; - - do { - bulk.ep = ep; - bulk.len = length - sent; - if (bulk.len > MAX_READ_WRITE) - bulk.len = MAX_READ_WRITE; - bulk.timeout = timeout; - bulk.data = (unsigned char *)bytes + sent; - - ret = ioctl(usb_get_fd(dev), USBDEVFS_BULK, &bulk); - if (ret < 0) - USB_ERROR_STR(ret, - "error writing to bulk endpoint %d: %s", - ep, strerror(errno)); - - sent += ret; - } while (ret > 0 && sent < length); - - return sent; -} - -int __usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size, - int timeout) -{ - struct usbdevfs_bulktransfer bulk; - int ret, retrieved = 0, requested; - - /* Ensure the endpoint address is correct */ - ep |= USB_ENDPOINT_IN; - - do { - bulk.ep = ep; - requested = size - retrieved; - if (requested > MAX_READ_WRITE) - requested = MAX_READ_WRITE; - bulk.len = requested; - bulk.timeout = timeout; - bulk.data = (unsigned char *)bytes + retrieved; - - ret = ioctl(usb_get_fd(dev), USBDEVFS_BULK, &bulk); - if (ret < 0) - USB_ERROR_STR(ret, - "error reading from bulk endpoint 0x%x: %s", - ep, strerror(errno)); - - retrieved += ret; - } while (ret > 0 && retrieved < size && ret == requested); - - return retrieved; -} - -int __usb_reattach_kernel_driver_np(usb_dev_handle *dev, int interface) -{ - struct usbdevfs_ioctl command; - - command.ifno = interface; - command.ioctl_code = USBDEVFS_CONNECT; - command.data = NULL; - - return ioctl(usb_get_fd(dev), USBDEVFS_IOCTL, &command); -} diff --git a/openpcd/opcd_test/ausb/usb.h b/openpcd/opcd_test/ausb/usb.h deleted file mode 100644 index 66be0ee..0000000 --- a/openpcd/opcd_test/ausb/usb.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _AUSB_USB_H -#define _AUSB_USB_H -int __usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int length, - int timeout); -int __usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int length, - int timeout); -int __usb_reattach_kernel_driver_np(usb_dev_handle *dev, int interface); -#endif diff --git a/openpcd/opcd_test/benchmark-20060824.txt b/openpcd/opcd_test/benchmark-20060824.txt deleted file mode 100644 index 9cf2c44..0000000 --- a/openpcd/opcd_test/benchmark-20060824.txt +++ /dev/null @@ -1,55 +0,0 @@ -laforge@rama%pts/8 (1:27) kommerz/bitmanufaktur/openpcd/opcd_test > for f in 1 2 4 8 16 32 64 128 255; do ./opcd_test -u $f; done -opcd_test - OpenPCD Test and Debug Program -(C) 2006 by Harald Welte - -starting DATA IN performance test (1 frames of 64 bytes) -TX: (4): f1 00 ff 01 -255 transfers (total 16320 bytes) in 508 miliseconds => 32125 bytes/sec -opcd_test - OpenPCD Test and Debug Program -(C) 2006 by Harald Welte - -starting DATA IN performance test (2 frames of 64 bytes) -TX: (4): f1 00 ff 02 -255 transfers (total 32640 bytes) in 510 miliseconds => 64000 bytes/sec -opcd_test - OpenPCD Test and Debug Program -(C) 2006 by Harald Welte - -starting DATA IN performance test (4 frames of 64 bytes) -TX: (4): f1 00 ff 04 -255 transfers (total 65280 bytes) in 508 miliseconds => 128503 bytes/sec -opcd_test - OpenPCD Test and Debug Program -(C) 2006 by Harald Welte - -starting DATA IN performance test (8 frames of 64 bytes) -TX: (4): f1 00 ff 08 -255 transfers (total 130560 bytes) in 510 miliseconds => 256000 bytes/sec -opcd_test - OpenPCD Test and Debug Program -(C) 2006 by Harald Welte - -starting DATA IN performance test (16 frames of 64 bytes) -TX: (4): f1 00 ff 10 -255 transfers (total 261120 bytes) in 764 miliseconds => 341780 bytes/sec -opcd_test - OpenPCD Test and Debug Program -(C) 2006 by Harald Welte - -starting DATA IN performance test (32 frames of 64 bytes) -TX: (4): f1 00 ff 20 -255 transfers (total 522240 bytes) in 1018 miliseconds => 513005 bytes/sec -opcd_test - OpenPCD Test and Debug Program -(C) 2006 by Harald Welte - -starting DATA IN performance test (64 frames of 64 bytes) -TX: (4): f1 00 ff 40 -255 transfers (total 1044480 bytes) in 2038 miliseconds => 512502 bytes/sec -opcd_test - OpenPCD Test and Debug Program -(C) 2006 by Harald Welte - -starting DATA IN performance test (128 frames of 64 bytes) -TX: (4): f1 00 ff 80 -255 transfers (total 2088960 bytes) in 3568 miliseconds => 585470 bytes/sec -opcd_test - OpenPCD Test and Debug Program -(C) 2006 by Harald Welte - -starting DATA IN performance test (255 frames of 64 bytes) -TX: (4): f1 00 ff ff -255 transfers (total 4161600 bytes) in 6119 miliseconds => 680111 bytes/sec diff --git a/openpcd/opcd_test/opcd_sh.c b/openpcd/opcd_test/opcd_sh.c deleted file mode 100644 index c9b38b4..0000000 --- a/openpcd/opcd_test/opcd_sh.c +++ /dev/null @@ -1,495 +0,0 @@ -#include -#include -#include -#include -#include - -#include "zebvty/vty.h" -#include "zebvty/command.h" - -#define MAX_BUFFER_SIZE 2048 -#define MAX_LENC MAX_BUFFER_SIZE -#define MAX_LENR MAX_LENC -#define MAX_COMMAND_SIZE 2048 - -static void strcompact(char *str) -{ - int i, j = 0; - - for (i = 0; i < strlen(str); i++) { - if (!isspace(str[i])) - str[j++] = tolower(str[i]); - } - str[j] = 0; -} - -static int strtobin(char *s, unsigned char *d, unsigned int *len) -{ - long l; - int i, ret; - - if (*s == ':') - s++; - - for (i = 0; i < (strlen(s) >> 1); i++) { - if (i >= MAX_LENC || i >> *len) - return 0; - ret = sscanf(s + (i << 1), "%2lx", &l); - if (ret != 1) - return 0; - d[i] = l & 0xff; - } - *len = i; - - return 1; -} - -DEFUN(rc632_reg_read, - rc632_reg_read_cmd, - "reg_read WORD", - "Read register of RC632\n") -{ -#if 0 - if (send_hex_command(vty, argv[0]) < 0) - return CMD_ERR_NO_MATCH; -#endif - return CMD_SUCCESS; -} - - -#if 0 -static int select_file(struct vty *v, int absolute, int path, - char *selector, unsigned int sellen, - unsigned char *rsp, unsigned int *rlen) -{ - unsigned char cmd[MAX_LENC]; - - cmd[0] = 0x00; - cmd[1] = 0xa4; - if (absolute) { - if (path) - cmd[2] = 0x08; - else - cmd[2] = 0x00; - } else { - if (path) - cmd[2] = 0x09; - else - cmd[2] = 0x02; - } - cmd[3] = 0x00; // FIXME: other templates - - cmd[4] = sellen & 0xff; - - memcpy(cmd[5], selector, sellen); - cmd[5+sellen] = 0x00; - - send_apdu(hCard, v, cmd, 5+cmd[4], rsp, rlen); - parse_selectfile_response(hCard, v, rsp, *rlen); - return CMD_SUCCESS; - -} - -DEFUN(send_7816_select_file_absolute_fid, - send_7816_select_file_absolute_fid_cmd, - "select file absolute fid WORD", - "Selects a file on the ICC\n") -{ - char *file = argv[0]; - unsigned char rsp[MAX_LENR]; - unsigned int lenr = MAX_LENR; - unsigned char selector[255]; - unsigned int sellen = 255; - - if (strtobin(file, selector, &sellen) < 0) - return CMD_ERR_NO_MATCH; - - return select_file(vty, 1, 0, selector, sellen, rsp, &lenr); -} - -DEFUN(send_7816_select_file_absolute_path, - send_7816_select_file_absolute_path_cmd, - "select file absolute path WORD", - "Selects a file on the ICC\n") -{ - char *file = argv[0]; - unsigned char rsp[MAX_LENR]; - unsigned int lenr = MAX_LENR; - unsigned char selector[255]; - unsigned int sellen = 255; - - if (strtobin(file, selector, &sellen) < 0) - return CMD_ERR_NO_MATCH; - - - return select_file(vty, 1, 1, selector, sellen, rsp, &lenr); -} - -DEFUN(send_7816_select_file_relative_fid, - send_7816_select_file_relative_fid_cmd, - "select file absolute fid WORD", - "Selects a file on the ICC\n") -{ - char *file = argv[0]; - unsigned char rsp[MAX_LENR]; - unsigned int lenr = MAX_LENR; - unsigned char selector[255]; - unsigned int sellen = 255; - - if (strtobin(file, selector, &sellen) < 0) - return CMD_ERR_NO_MATCH; - - - return select_file(vty, 0, 0, selector, sellen, rsp, &lenr); -} - - -DEFUN(send_7816_select_file_relative_path, - send_7816_select_file_relative_path_cmd, - "select file relative path WORD", - "Selects a file on the ICC\n") -{ - char *file = argv[0]; - unsigned char rsp[MAX_LENR]; - unsigned int lenr = MAX_LENR; - unsigned char selector[255]; - unsigned int sellen = 255; - - if (strtobin(file, selector, &sellen) < 0) - return CMD_ERR_NO_MATCH; - - - return select_file(vty, 0, 1, selector, sellen, rsp, &lenr); -} - -DEFUN(send_7816_select_dir, - send_7816_select_dir_cmd, - "select directory (MF|PARENT|CHILD) (FID|AID)", - "Selects a directory on the ICC\n") -{ - char *file = argv[1]; - char *type = argv[0]; - char cmd[22]; - char rsp[MAX_LENR]; - int len, lenr = MAX_LENR; - int empty = 0; - - if (!type) - return CMD_ERR_NO_MATCH; - - memset(cmd, 0, sizeof(cmd)); - cmd[1] = 0xa4; - - if (!strcmp(type, "MF")) { - cmd[2] = 0x00; - cmd[3] = 0x00; - cmd[4] = 2; /* length */ - cmd[5] = 0x3f; /* 3ff0 */ - cmd[6] = 0xf0; - empty = 1; - } else if (!strcmp(type, "PARENT")) { - cmd[2] = 0x03; - cmd[3] = 0x00; - cmd[4] = 0x00; - empty = 1; - } else if (!strcmp(file, "CHILD")) { - cmd[2] = 0x01; - cmd[3] = 0x00; - } else { - cmd[2] = 0x00; - cmd[3] = 0x00; - } - - if (!empty) { - len = 16; - /* convert hex string of identifier to bytecode */ - strtobin(file, &cmd[5], &len); - cmd[4] = len & 0xff; - } - send_apdu(hCard, vty, cmd, 5+cmd[4], rsp, &lenr); - parse_selectfile_response(hCard, vty, rsp, lenr); - return CMD_SUCCESS; -} - -DEFUN(send_7816_ls, - send_7816_ls_cmd, - "ls", - "Tries to list all files on a 7816-4 compliant ICC\n") -{ - return CMD_SUCCESS; -} - -DEFUN(send_7816_tree, - send_7816_tree_cmd, - "tree", - "Tries to list a full DF hiararchy tree on a 7816-4 compliant ICC\n") -{ - - return CMD_SUCCESS; -} - -DEFUN(send_7816_read_binary, - send_7816_read_binary_cmd, - "read binary OFFSET LENGTH", - "Read bytes form a previously selected EF\n") -{ - unsigned char cmd[] = { 0x00, 0xb0, 0x00, 0x00, 0x00 }; - unsigned char rsp[MAX_LENR]; // FIXME - unsigned int lenr = MAX_LENR; - - unsigned long datalen; - unsigned long offset; - - offset = strtoul(argv[0], NULL, 0); - if (offset == ULONG_MAX || offset > 0xffff) - return CMD_ERR_NO_MATCH; - - datalen = strtoul(argv[1], NULL, 0); - if (datalen == ULONG_MAX || datalen > 0xff) - return CMD_ERR_NO_MATCH; - - cmd[2] = (offset >> 8) & 0xff; - cmd[3] = offset & 0xff; - cmd[4] = datalen & 0xff; - - send_apdu(hCard, vty, cmd, 5+cmd[4], rsp, &lenr); - if (lenr < 2) - return CMD_SUCCESS; // FIXME - - parse_sw(vty, rsp[lenr-2], rsp[lenr-1]); - - return CMD_SUCCESS; -} - -DEFUN(send_7816_write_binary, - send_7816_write_binary_cmd, - "write binary OFFSET LENGTH DATA", - "Write bytes to a previously selected EF\n") -{ - unsigned char cmd[MAX_LENC]; - unsigned char rsp[MAX_LENR]; - unsigned int lenr; - - unsigned long datalen; - unsigned long offset; - - offset = strtoul(argv[0], NULL, 0); - if (offset == ULONG_MAX || offset > 0xffff) - return CMD_ERR_NO_MATCH; - - datalen = strtoul(argv[1], NULL, 0); - if (datalen == ULONG_MAX || datalen > 0xff) - return CMD_ERR_NO_MATCH; - - memset(cmd, 0, sizeof(cmd)); - - cmd[1] = 0xd0; - cmd[2] = (offset >> 8) & 0xff; - cmd[3] = offset & 0xff; - - if (!strtobin(argv[2], cmd+5, &datalen)) { - vty_out(vty, "command decoding error%s", vty_newline(vty)); - return -1; - } - - cmd[4] = datalen & 0xff; - - send_apdu(hCard, vty, cmd, 5+cmd[4], rsp, &lenr); - if (lenr < 2) - return CMD_SUCCESS; // FIXME - - parse_sw(vty, rsp[lenr-2], rsp[lenr-1]); - - return CMD_SUCCESS; - - return CMD_SUCCESS; -} - -DEFUN(send_7816_update_binary, - send_7816_update_binary_cmd, - "update binary OFFSET LENGTH DATA", - "Update bytes of a previously selected EF\n") -{ - unsigned char cmd[MAX_LENC]; - unsigned char rsp[MAX_LENR]; - unsigned int lenr; - - unsigned long datalen; - unsigned long offset; - - offset = strtoul(argv[0], NULL, 0); - if (offset == ULONG_MAX || offset > 0xffff) - return CMD_ERR_NO_MATCH; - - datalen = strtoul(argv[1], NULL, 0); - if (datalen == ULONG_MAX || datalen > 0xff) - return CMD_ERR_NO_MATCH; - - memset(cmd, 0, sizeof(cmd)); - - cmd[1] = 0xd6; - cmd[2] = (offset >> 8) & 0xff; - cmd[3] = offset & 0xff; - - if (!strtobin(argv[2], cmd+5, &datalen)) { - vty_out(vty, "command decoding error%s", vty_newline(vty)); - return -1; - } - - cmd[4] = datalen & 0xff; - - send_apdu(hCard, vty, cmd, 5+cmd[4], rsp, &lenr); - if (lenr < 2) - return CMD_SUCCESS; // FIXME - - parse_sw(vty, rsp[lenr-2], rsp[lenr-1]); - - return CMD_SUCCESS; -} - -DEFUN(send_7816_erase_binary, - send_7816_erase_binary_cmd, - "erase binary OFFSET LENGTH", - "Erase bytes of a previously selected EF\n") -{ - unsigned char cmd[8] = { 0x00, 0x0e, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 }; - unsigned char rsp[MAX_LENR]; - unsigned int lenr; - - unsigned long datalen; - unsigned long offset; - - offset = strtoul(argv[0], NULL, 0); - if (offset == ULONG_MAX || offset > 0xffff) - return CMD_ERR_NO_MATCH; - - datalen = strtoul(argv[1], NULL, 0); - if (datalen == ULONG_MAX || (offset+datalen > 0xffff)) - return CMD_ERR_NO_MATCH; - - cmd[2] = (offset >> 8) & 0xff; - cmd[3] = offset & 0xff; - cmd[4] = 0x02; - cmd[5] = ((offset+datalen) >> 8) & 0xff; - cmd[6] = (offset+datalen) & 0xff; - - send_apdu(hCard, vty, cmd, 5+cmd[4], rsp, &lenr); - if (lenr < 2) - return CMD_SUCCESS; // FIXME - - parse_sw(vty, rsp[lenr-2], rsp[lenr-1]); - - return CMD_SUCCESS; -} - -DEFUN(send_7816_get_response, - send_7816_get_response_cmd, - "get response LENGTH", - "Get more data from the ICC\n") -{ - unsigned char cmd[6] = { 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00 }; - unsigned char rsp[MAX_LENR]; - unsigned int lenr = MAX_LENR; - - unsigned long length; - - length = strtoul(argv[0], NULL, 0); - if (length == ULONG_MAX || length > 0xff) - return CMD_ERR_NO_MATCH; - - cmd[5] = length & 0xff; - - send_apdu(hCard, vty, cmd, 6, rsp, &lenr); - if (lenr < 2) - return CMD_SUCCESS; // FIXME - - parse_sw(vty, rsp[lenr-2], rsp[lenr-1]); - - return CMD_SUCCESS; - -} -#endif - -DEFUN(rc632, - rc632_cmd, - "rc632", "Commands related to low-level RC632 access\n") -{ - vty->node = RC632_NODE; - return CMD_SUCCESS; -} - -/* dummy */ -static int send_config_write(struct vty *v) -{ - return CMD_SUCCESS; -} - -struct cmd_node rc632_node = { - RC632_NODE, - "%s(rc632)# ", - 1, -}; - -static int opcdshell_init() -{ - cmd_init(1); - vty_init(); - - install_node(&rc632_node, send_config_write); - - install_element(RC632_NODE, &rc632_reg_read_cmd); - -#if 0 - install_element(RC632_NODE, &send_7816_select_file_absolute_fid_cmd); - install_element(RC632_NODE, &send_7816_select_file_absolute_path_cmd); - install_element(RC632_NODE, &send_7816_select_file_relative_fid_cmd); - install_element(RC632_NODE, &send_7816_select_file_relative_path_cmd); - - install_element(RC632_NODE, &send_7816_select_dir_cmd); - install_element(RC632_NODE, &send_7816_ls_cmd); - install_element(RC632_NODE, &send_7816_tree_cmd); - - install_element(RC632_NODE, &send_7816_read_binary_cmd); - install_element(RC632_NODE, &send_7816_write_binary_cmd); - install_element(RC632_NODE, &send_7816_update_binary_cmd); - install_element(RC632_NODE, &send_7816_erase_binary_cmd); - - install_element(RC632_NODE, &send_7816_get_response_cmd); -#endif - - install_default(RC632_NODE); - - install_element(VIEW_NODE, &rc632_cmd); - - return 0; -} - -static int opcdshell(void) -{ - struct vty *v; - - v = vty_create(0); - if (!v) - return -1; - while (1) { - vty_read(v); - } - return 0; -} - - -/*********************************************************************** - * main program, copied from pcsc-lite 'testpcsc.c' - ***********************************************************************/ - -int main(int argc, char **argv) -{ - opcdshell_init(); - - printf("\nopcd_shell (C) 2006 Harald Welte \n\n"); - - opcdshell(); - - return 0; -} diff --git a/openpcd/opcd_test/opcd_test.c b/openpcd/opcd_test/opcd_test.c deleted file mode 100644 index 37f3094..0000000 --- a/openpcd/opcd_test/opcd_test.c +++ /dev/null @@ -1,199 +0,0 @@ -/* opcd_test - Low-Level test program for OpenPCD - * (C) 2006 by Harald Welte - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#define _GNU_SOURCE -#include -#include - -#include -#include -#include -#include - -#include - -#include "../firmware/include/openpcd.h" -#include "opcd_usb.h" - -static int get_number(const char *optarg, unsigned int min, - unsigned int max, unsigned int *num) -{ - char *endptr; - unsigned long nbr = strtoul(optarg, &endptr, 0); - //fprintf(stderr, "trying to read `%s' as number\n", optarg); - - if (nbr == 0 && optarg == endptr) - return -EINVAL; - - if (nbr < min || nbr > max) - return -ERANGE; - - *num = nbr; - return 0; -} - -static void print_welcome(void) -{ - printf("opcd_test - OpenPCD Test and Debug Program\n" - "(C) 2006 by Harald Welte \n\n"); -} -static void print_help(void) -{ - printf( "\t-l\t--led-set\tled {0,1}\n" - "\t-w\t--reg-write\treg value\n" - "\t-r\t--reg-read\treg\n" - - "\t-s\t--set-bits\treg\tmask\n" - "\t-c\t--clear-bits\treg\tmask\n"); -} - - -static struct option opts[] = { - { "led-set", 1, 0, 'l' }, - { "reg-write", 1, 0, 'w' }, - { "reg-read", 1, 0, 'r' }, - { "fifo-write", 1, 0, 'W' }, - { "fifo-read", 1, 0, 'R' }, - { "set-bits", 1, 0, 's' }, - { "clear-bits", 1, 0, 'c' }, - { "usb-perf", 1, 0, 'u' }, - { "adc-read", 0, 0, 'a' }, - { "adc-loop", 0, 0, 'A' }, - { "ssc-read", 0, 0, 'S' }, - { "loop", 0, 0, 'L' }, - { "help", 0, 0, 'h'}, -}; - -int main(int argc, char **argv) -{ - struct opcd_handle *od; - int c; - static char buf[8192]; - int buf_len = sizeof(buf); - - print_welcome(); - - od = opcd_init(); - - while (1) { - int option_index = 0; - - c = getopt_long(argc, argv, "l:r:w:R:W:s:c:h?u:aASL", opts, - &option_index); - - if (c == -1) - break; - - switch (c) { - unsigned int i,j; - case 'l': - if (get_number(optarg, 1, 2, &i) < 0) - exit(2); - if (get_number(argv[optind], 0, 1, &j) < 0) - exit(2); - printf("setting LED %d to %s\n", i, j ? "on" : "off"); - opcd_send_command(od, OPENPCD_CMD_SET_LED, i, j, 0, NULL); - break; - case 'r': - if (get_number(optarg, 0x00, OPENPCD_REG_MAX, &i) < 0) - exit(2); - printf("reading register 0x%02x: "); - opcd_send_command(od, OPENPCD_CMD_READ_REG, i, 0, 0, NULL); - opcd_recv_reply(od, buf, buf_len); - break; - case 'w': - if (get_number(optarg, 0x00, OPENPCD_REG_MAX, &i) < 0) { - fprintf(stderr, "can't read register\n"); - exit(2); - } - if (get_number(argv[optind], 0x00, 0xff, &j) < 0) { - fprintf(stderr, "can't read value\n"); - exit(2); - } - fprintf(stdout, "setting register 0x%02x to 0x%02x\n", i, j); - opcd_send_command(od, OPENPCD_CMD_WRITE_REG, i, j, 0, NULL); - break; - case 'R': - if (get_number(optarg, 0x00, OPENPCD_REG_MAX, &i) < 0) - exit(2); - opcd_send_command(od, OPENPCD_CMD_READ_FIFO, 0, i, 0, NULL); - opcd_recv_reply(od, buf, buf_len); - break; - case 'W': - fprintf(stderr, "FIFO write not implemented yet\n"); - break; - case 's': - if (get_number(optarg, 0x00, OPENPCD_REG_MAX, &i) < 0) - exit(2); - if (get_number(argv[optind], 0x00, 0xff, &j) < 0) - exit(2); - opcd_send_command(od, OPENPCD_CMD_REG_BITS_SET, i, j, 0, NULL); - break; - case 'c': - if (get_number(optarg, 0x00, OPENPCD_REG_MAX, &i) < 0) - exit(2); - if (get_number(argv[optind], 0x00, 0xff, &j) < 0) - exit(2); - opcd_send_command(od, OPENPCD_CMD_REG_BITS_CLEAR, i, j, 0, NULL); - break; - case 'u': - if (get_number(optarg, 1, 255, &i) < 0) - exit(2); - opcd_usbperf(od, i); - break; - case 'a': - opcd_send_command(od, OPENPCD_CMD_ADC_READ, 0, 1, 0, NULL); - opcd_recv_reply(od, buf, buf_len); - /* FIXME: interpret and print ADC result */ - break; - case 'A': - while (1) { - opcd_send_command(od, OPENPCD_CMD_ADC_READ, 0, 1, 0, NULL); - opcd_recv_reply(od, buf, buf_len); - /* FIXME: interpret and print ADC result */ - } - break; - case 'S': - opcd_send_command(od, OPENPCD_CMD_SSC_READ, 0, 1, 0, NULL); - opcd_recv_reply(od, buf, buf_len); - /* FIXME: interpret and print ADC result */ - break; - case 'L': - while (1) - opcd_recv_reply(od, buf, buf_len); - break; - case 'h': - case '?': - print_help(); - exit(0); - break; - default: - fprintf(stderr, "unknown key `%c'\n", c); - print_help(); - exit(2); - break; - } - } - - sleep(1); - - exit(0); -} diff --git a/openpcd/opcd_test/opcd_usb.c b/openpcd/opcd_test/opcd_usb.c deleted file mode 100644 index d73289d..0000000 --- a/openpcd/opcd_test/opcd_usb.c +++ /dev/null @@ -1,235 +0,0 @@ -/* opcd_usb - Low-Level USB routines for OpenPCD USB protocol - * - * (C) 2006 by Harald Welte - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include - -#include - -#include "ausb/ausb.h" -#include "../firmware/include/openpcd.h" - -#include "opcd_usb.h" - -const char * -opcd_hexdump(const void *data, unsigned int len) -{ - static char string[65535]; - unsigned char *d = (unsigned char *) data; - unsigned int i, left, ofs; - - string[0] = '\0'; - ofs = snprintf(string, sizeof(string)-1, "(%u): ", len); - - left = sizeof(string) - ofs; - for (i = 0; len--; i += 3) { - if (i >= sizeof(string) -4) - break; - snprintf(string+ofs+i, 4, " %02x", *d++); - } - string[sizeof(string)-1] = '\0'; - return string; -} - -#define OPCD_VENDOR_ID 0x2342 -#define OPCD_PRODUCT_ID 0x0001 -#define OPCD_OUT_EP 0x01 -#define OPCD_IN_EP 0x82 -#define OPCD_INT_EP 0x83 - -static struct usb_device *find_opcd_handle(void) -{ - struct usb_bus *bus; - - for (bus = usb_busses; bus; bus = bus->next) { - struct usb_device *dev; - for (dev = bus->devices; dev; dev = dev->next) { - if (dev->descriptor.idVendor == OPCD_VENDOR_ID - && dev->descriptor.idProduct == OPCD_PRODUCT_ID - && dev->descriptor.iManufacturer == 0 - && dev->descriptor.iProduct == 0 - && dev->descriptor.bNumConfigurations == 1 - && dev->config->bNumInterfaces == 2 - && dev->config->iConfiguration == 0) - return dev; - } - } - return NULL; -} - -static void opcd_dump_hdr(struct openpcd_hdr *hdr) -{ - printf("IRQ: cmd=0x%02x, flags=0x%02x, reg=0x%02x, val=0x%02x\n", - hdr->cmd, hdr->flags, hdr->reg, hdr->val); -} - -static void handle_interrupt(struct usbdevfs_urb *uurb, void *userdata) -{ - struct opcd_handle *od = userdata; - ausb_dev_handle *ah; - struct openpcd_hdr *opcdh; - - if (!uurb) { - fprintf(stderr, "interrupt with no URB?!?\n"); - return; - } - - ah = uurb->usercontext; - - opcdh = (struct openpcd_hdr *)uurb->buffer; - opcd_dump_hdr(opcdh); - - if (ausb_submit_urb(ah, uurb)) - fprintf(stderr, "unable to resubmit interupt urb\n"); -} - -struct opcd_handle *opcd_init(void) -{ - struct opcd_handle *oh; - struct usb_device *dev; - - oh = malloc(sizeof(*oh)); - if (!oh) - return NULL; - - memset(oh, 0, sizeof(*oh)); - - ausb_init(); - - dev = find_opcd_handle(); - if (!dev) { - fprintf(stderr, "Cannot find OpenPCD device. " - "Are you sure it is connected?\n"); - exit(1); - } - - oh->hdl = ausb_open(dev); - if (!oh->hdl) { - fprintf(stderr, "Unable to open usb device: %s\n", - usb_strerror()); - exit(1); - } - - if (ausb_claim_interface(oh->hdl, 0) < 0) { - fprintf(stderr, "Unable to claim usb interface " - "1 of device: %s\n", usb_strerror()); - exit(1); - } - - ausb_fill_int_urb(&oh->int_urb, OPCD_INT_EP, oh->int_buf, - sizeof(oh->int_buf)); - if (ausb_register_callback(oh->hdl, USBDEVFS_URB_TYPE_INTERRUPT, - handle_interrupt, oh)) { - fprintf(stderr, "unable to submit interrupt urb"); - exit(1); - } - - return oh; -} - -void opcd_fini(struct opcd_handle *od) -{ - ausb_discard_urb(od->hdl, &od->int_urb); - ausb_close(od->hdl); -} - -int opcd_recv_reply(struct opcd_handle *od, char *buf, int len) -{ - int ret; - memset(buf, 0, sizeof(buf)); - - ret = ausb_bulk_read(od->hdl, OPCD_IN_EP, buf, len, 100000); - - if (ret < 0) { - fprintf(stderr, "bulk_read returns %d(%s)\n", ret, - usb_strerror()); - return ret; - } - - printf("RX: %s\n", opcd_hexdump(buf, ret)); - opcd_dump_hdr((struct openpcd_hdr *)buf); - - return ret; -} - - -int opcd_send_command(struct opcd_handle *od, u_int8_t cmd, - u_int8_t reg, u_int8_t val, u_int16_t len, - const unsigned char *data) -{ - unsigned char buf[128]; - struct openpcd_hdr *ohdr = (struct openpcd_hdr *)buf; - int cur = 0; - int ret; - - memset(buf, 0, sizeof(buf)); - - ohdr->cmd = cmd; - ohdr->reg = reg; - ohdr->val = val; - if (data && len) - memcpy(ohdr->data, data, len); - - cur = sizeof(*ohdr) + len; - - printf("TX: %s\n", opcd_hexdump(buf, cur)); - - ret = ausb_bulk_write(od->hdl, OPCD_OUT_EP, buf, cur, 0); - if (ret < 0) { - fprintf(stderr, "bulk_write returns %d(%s)\n", ret, - usb_strerror()); - } - - return ret; -} - -int opcd_usbperf(struct opcd_handle *od, unsigned int frames) -{ - int i; - char buf[256*64]; - struct timeval tv_start, tv_stop; - unsigned int num_xfer = 0; - unsigned int diff_msec; - unsigned int transfers = 255; - - printf("starting DATA IN performance test (%u frames of 64 bytes)\n", - frames); - opcd_send_command(od, OPENPCD_CMD_USBTEST_IN, transfers, frames, 0, NULL); - gettimeofday(&tv_start, NULL); - for (i = 0; i < transfers; i++) { - int ret; - ret = ausb_bulk_read(od->hdl, OPCD_IN_EP, buf, sizeof(buf), 0); - if (ret < 0) { - fprintf(stderr, "error receiving data in transaction\n"); - return ret; - } - num_xfer += ret; - } - gettimeofday(&tv_stop, NULL); - diff_msec = (tv_stop.tv_sec - tv_start.tv_sec)*1000; - diff_msec += (tv_stop.tv_usec - tv_start.tv_usec)/1000; - - printf("%u transfers (total %u bytes) in %u miliseconds => %u bytes/sec\n", - i, num_xfer, diff_msec, (num_xfer*1000)/diff_msec); - - return 0; -} diff --git a/openpcd/opcd_test/opcd_usb.h b/openpcd/opcd_test/opcd_usb.h deleted file mode 100644 index e9698f0..0000000 --- a/openpcd/opcd_test/opcd_usb.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef _OPCD_USB_H -#define _OPCD_USB_H - -#include "ausb/ausb.h" - -#define OPCD_INTBUF_SIZE 64 -struct opcd_handle { - struct ausb_dev_handle *hdl; - struct usbdevfs_urb int_urb; - u_int8_t int_buf[OPCD_INTBUF_SIZE]; -}; - -extern const char *opcd_hexdump(const void *data, unsigned int len); - -extern struct opcd_handle *opcd_init(void); -extern void opcd_fini(struct opcd_handle *od); - -extern int opcd_recv_reply(struct opcd_handle *od, char *buf, int len); -extern int opcd_send_command(struct opcd_handle *od, u_int8_t cmd, - u_int8_t reg, u_int8_t val, u_int16_t len, - const unsigned char *data); -extern int opcd_usbperf(struct opcd_handle *od, unsigned int frames); - -#endif diff --git a/openpcd/opcd_test/zebvty/Makefile b/openpcd/opcd_test/zebvty/Makefile deleted file mode 100644 index dcaf1a2..0000000 --- a/openpcd/opcd_test/zebvty/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -#include ../../makevars - -OBJS=vector.o command.o buffer.o vty.o -CFLAGS+=-fPIC -NAME=zebvty - -all: lib$(NAME).a lib$(NAME).so - -lib$(NAME).a: $(OBJS) - $(AR) r $@ $^ - -lib$(NAME).so: $(OBJS) - $(LD) -x --shared -o $@ $^ - -%.o: %.c - $(CC) $(CFLAGS) -o $@ -c $^ - -clean: - @rm -f *.o lib$(NAME).a lib$(NAME).so diff --git a/openpcd/opcd_test/zebvty/buffer.c b/openpcd/opcd_test/zebvty/buffer.c deleted file mode 100644 index 0610ebb..0000000 --- a/openpcd/opcd_test/zebvty/buffer.c +++ /dev/null @@ -1,460 +0,0 @@ -/* - * Buffering of output and input. - * Copyright (C) 1998 Kunihiro Ishiguro - * - * This file is part of GNU Zebra. - * - * GNU Zebra 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. - * - * GNU Zebra 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 -#include -#include -#include -#include -#include -#include - -#include "buffer.h" -#include "vty.h" - -/* Buffer master. */ -struct buffer { - /* Data list. */ - struct buffer_data *head; - struct buffer_data *tail; - - /* Size of each buffer_data chunk. */ - size_t size; -}; - -/* Data container. */ -struct buffer_data { - struct buffer_data *next; - - /* Location to add new data. */ - size_t cp; - - /* Pointer to data not yet flushed. */ - size_t sp; - - /* Actual data stream (variable length). */ - unsigned char data[0]; /* real dimension is buffer->size */ -}; - -/* It should always be true that: 0 <= sp <= cp <= size */ - -/* Default buffer size (used if none specified). It is rounded up to the - next page boundery. */ -#define BUFFER_SIZE_DEFAULT 4096 - -#define BUFFER_DATA_FREE(D) free((D)) - -/* Make new buffer. */ -struct buffer *buffer_new(size_t size) -{ - struct buffer *b; - - b = calloc(1, sizeof(struct buffer)); - - if (size) - b->size = size; - else { - static size_t default_size; - if (!default_size) { - long pgsz = sysconf(_SC_PAGESIZE); - default_size = - ((((BUFFER_SIZE_DEFAULT - 1) / pgsz) + 1) * pgsz); - } - b->size = default_size; - } - - return b; -} - -/* Free buffer. */ -void buffer_free(struct buffer *b) -{ - buffer_reset(b); - free(b); -} - -/* Make string clone. */ -char *buffer_getstr(struct buffer *b) -{ - size_t totlen = 0; - struct buffer_data *data; - char *s; - char *p; - - for (data = b->head; data; data = data->next) - totlen += data->cp - data->sp; - if (!(s = malloc(totlen + 1))) - return NULL; - p = s; - for (data = b->head; data; data = data->next) { - memcpy(p, data->data + data->sp, data->cp - data->sp); - p += data->cp - data->sp; - } - *p = '\0'; - return s; -} - -/* Return 1 if buffer is empty. */ -int buffer_empty(struct buffer *b) -{ - return (b->head == NULL); -} - -/* Clear and free all allocated data. */ -void buffer_reset(struct buffer *b) -{ - struct buffer_data *data; - struct buffer_data *next; - - for (data = b->head; data; data = next) { - next = data->next; - BUFFER_DATA_FREE(data); - } - b->head = b->tail = NULL; -} - -/* Add buffer_data to the end of buffer. */ -static struct buffer_data *buffer_add(struct buffer *b) -{ - struct buffer_data *d; - - d = malloc(offsetof(struct buffer_data, data[b->size])); - if (!d) - return NULL; - d->cp = d->sp = 0; - d->next = NULL; - - if (b->tail) - b->tail->next = d; - else - b->head = d; - b->tail = d; - - return d; -} - -/* Write data to buffer. */ -void buffer_put(struct buffer *b, const void *p, size_t size) -{ - struct buffer_data *data = b->tail; - const char *ptr = p; - - /* We use even last one byte of data buffer. */ - while (size) { - size_t chunk; - - /* If there is no data buffer add it. */ - if (data == NULL || data->cp == b->size) - data = buffer_add(b); - - chunk = - ((size <= - (b->size - data->cp)) ? size : (b->size - data->cp)); - memcpy((data->data + data->cp), ptr, chunk); - size -= chunk; - ptr += chunk; - data->cp += chunk; - } -} - -/* Insert character into the buffer. */ -void buffer_putc(struct buffer *b, u_char c) -{ - buffer_put(b, &c, 1); -} - -/* Put string to the buffer. */ -void buffer_putstr(struct buffer *b, const char *c) -{ - buffer_put(b, c, strlen(c)); -} - -/* Keep flushing data to the fd until the buffer is empty or an error is - encountered or the operation would block. */ -buffer_status_t buffer_flush_all(struct buffer *b, int fd) -{ - buffer_status_t ret; - struct buffer_data *head; - size_t head_sp; - - if (!b->head) - return BUFFER_EMPTY; - head_sp = (head = b->head)->sp; - /* Flush all data. */ - while ((ret = buffer_flush_available(b, fd)) == BUFFER_PENDING) { - if ((b->head == head) && (head_sp == head->sp) - && (errno != EINTR)) - /* No data was flushed, so kernel buffer must be full. */ - return ret; - head_sp = (head = b->head)->sp; - } - - return ret; -} - -#if 0 -/* Flush enough data to fill a terminal window of the given scene (used only - by vty telnet interface). */ -buffer_status_t -buffer_flush_window(struct buffer * b, int fd, int width, int height, - int erase_flag, int no_more_flag) -{ - int nbytes; - int iov_alloc; - int iov_index; - struct iovec *iov; - struct iovec small_iov[3]; - char more[] = " --More-- "; - char erase[] = - { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 - }; - struct buffer_data *data; - int column; - - if (!b->head) - return BUFFER_EMPTY; - - if (height < 1) { - zlog_warn - ("%s called with non-positive window height %d, forcing to 1", - __func__, height); - height = 1; - } else if (height >= 2) - height--; - if (width < 1) { - zlog_warn - ("%s called with non-positive window width %d, forcing to 1", - __func__, width); - width = 1; - } - - /* For erase and more data add two to b's buffer_data count. */ - if (b->head->next == NULL) { - iov_alloc = sizeof(small_iov) / sizeof(small_iov[0]); - iov = small_iov; - } else { - iov_alloc = ((height * (width + 2)) / b->size) + 10; - iov = XMALLOC(MTYPE_TMP, iov_alloc * sizeof(*iov)); - } - iov_index = 0; - - /* Previously print out is performed. */ - if (erase_flag) { - iov[iov_index].iov_base = erase; - iov[iov_index].iov_len = sizeof erase; - iov_index++; - } - - /* Output data. */ - column = 1; /* Column position of next character displayed. */ - for (data = b->head; data && (height > 0); data = data->next) { - size_t cp; - - cp = data->sp; - while ((cp < data->cp) && (height > 0)) { - /* Calculate lines remaining and column position after displaying - this character. */ - if (data->data[cp] == '\r') - column = 1; - else if ((data->data[cp] == '\n') || (column == width)) { - column = 1; - height--; - } else - column++; - cp++; - } - iov[iov_index].iov_base = (char *)(data->data + data->sp); - iov[iov_index++].iov_len = cp - data->sp; - data->sp = cp; - - if (iov_index == iov_alloc) - /* This should not ordinarily happen. */ - { - iov_alloc *= 2; - if (iov != small_iov) { - zlog_warn("%s: growing iov array to %d; " - "width %d, height %d, size %lu", - __func__, iov_alloc, width, height, - (u_long) b->size); - iov = - XREALLOC(MTYPE_TMP, iov, - iov_alloc * sizeof(*iov)); - } else { - /* This should absolutely never occur. */ - zlog_err - ("%s: corruption detected: iov_small overflowed; " - "head %p, tail %p, head->next %p", - __func__, b->head, b->tail, b->head->next); - iov = - XMALLOC(MTYPE_TMP, - iov_alloc * sizeof(*iov)); - memcpy(iov, small_iov, sizeof(small_iov)); - } - } - } - - /* In case of `more' display need. */ - if (b->tail && (b->tail->sp < b->tail->cp) && !no_more_flag) { - iov[iov_index].iov_base = more; - iov[iov_index].iov_len = sizeof more; - iov_index++; - } -#ifdef IOV_MAX - /* IOV_MAX are normally defined in , Posix.1g. - example: Solaris2.6 are defined IOV_MAX size at 16. */ - { - struct iovec *c_iov = iov; - nbytes = 0; /* Make sure it's initialized. */ - - while (iov_index > 0) { - int iov_size; - - iov_size = - ((iov_index > IOV_MAX) ? IOV_MAX : iov_index); - if ((nbytes = writev(fd, c_iov, iov_size)) < 0) { - zlog_warn("%s: writev to fd %d failed: %s", - __func__, fd, safe_strerror(errno)); - break; - } - - /* move pointer io-vector */ - c_iov += iov_size; - iov_index -= iov_size; - } - } -#else /* IOV_MAX */ - if ((nbytes = writev(fd, iov, iov_index)) < 0) - zlog_warn("%s: writev to fd %d failed: %s", - __func__, fd, safe_strerror(errno)); -#endif /* IOV_MAX */ - - /* Free printed buffer data. */ - while (b->head && (b->head->sp == b->head->cp)) { - struct buffer_data *del; - if (!(b->head = (del = b->head)->next)) - b->tail = NULL; - BUFFER_DATA_FREE(del); - } - - if (iov != small_iov) - XFREE(MTYPE_TMP, iov); - - return (nbytes < 0) ? BUFFER_ERROR : - (b->head ? BUFFER_PENDING : BUFFER_EMPTY); -} -#endif - -/* This function (unlike other buffer_flush* functions above) is designed -to work with non-blocking sockets. It does not attempt to write out -all of the queued data, just a "big" chunk. It returns 0 if it was -able to empty out the buffers completely, 1 if more flushing is -required later, or -1 on a fatal write error. */ -buffer_status_t buffer_flush_available(struct buffer * b, int fd) -{ - -/* These are just reasonable values to make sure a significant amount of -data is written. There's no need to go crazy and try to write it all -in one shot. */ -#ifdef IOV_MAX -#define MAX_CHUNKS ((IOV_MAX >= 16) ? 16 : IOV_MAX) -#else -#define MAX_CHUNKS 16 -#endif -#define MAX_FLUSH 131072 - - struct buffer_data *d; - size_t written; - struct iovec iov[MAX_CHUNKS]; - size_t iovcnt = 0; - size_t nbyte = 0; - - for (d = b->head; d && (iovcnt < MAX_CHUNKS) && (nbyte < MAX_FLUSH); - d = d->next, iovcnt++) { - iov[iovcnt].iov_base = d->data + d->sp; - nbyte += (iov[iovcnt].iov_len = d->cp - d->sp); - } - - if (!nbyte) - /* No data to flush: should we issue a warning message? */ - return BUFFER_EMPTY; - - /* only place where written should be sign compared */ - if ((ssize_t) (written = writev(fd, iov, iovcnt)) < 0) { - if (ERRNO_IO_RETRY(errno)) - /* Calling code should try again later. */ - return BUFFER_PENDING; - return BUFFER_ERROR; - } - - /* Free printed buffer data. */ - while (written > 0) { - struct buffer_data *d; - if (!(d = b->head)) - break; - if (written < d->cp - d->sp) { - d->sp += written; - return BUFFER_PENDING; - } - - written -= (d->cp - d->sp); - if (!(b->head = d->next)) - b->tail = NULL; - BUFFER_DATA_FREE(d); - } - - return b->head ? BUFFER_PENDING : BUFFER_EMPTY; - -#undef MAX_CHUNKS -#undef MAX_FLUSH -} - -buffer_status_t -buffer_write(struct buffer * b, int fd, const void *p, size_t size) -{ - ssize_t nbytes; - -#if 0 - /* Should we attempt to drain any previously buffered data? This could help reduce latency in pushing out the data if we are stuck in a long-running thread that is preventing the main select loop from calling the flush thread... */ - - if (b->head && (buffer_flush_available(b, fd) == BUFFER_ERROR)) - return BUFFER_ERROR; -#endif - if (b->head) - /* Buffer is not empty, so do not attempt to write the new data. */ - nbytes = 0; - else if ((nbytes = write(fd, p, size)) < 0) { - if (ERRNO_IO_RETRY(errno)) - nbytes = 0; - else - return BUFFER_ERROR; - } - /* Add any remaining data to the buffer. */ - { - size_t written = nbytes; - if (written < size) - buffer_put(b, ((const char *)p) + written, - size - written); - } - return b->head ? BUFFER_PENDING : BUFFER_EMPTY; -} diff --git a/openpcd/opcd_test/zebvty/buffer.h b/openpcd/opcd_test/zebvty/buffer.h deleted file mode 100644 index e564cf9..0000000 --- a/openpcd/opcd_test/zebvty/buffer.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Buffering to output and input. - * Copyright (C) 1998 Kunihiro Ishiguro - * - * This file is part of GNU Zebra. - * - * GNU Zebra 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. - * - * GNU Zebra 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. - */ - -#ifndef _ZEBRA_BUFFER_H -#define _ZEBRA_BUFFER_H - -/* Create a new buffer. Memory will be allocated in chunks of the given - size. If the argument is 0, the library will supply a reasonable - default size suitable for buffering socket I/O. */ -struct buffer *buffer_new(size_t); - -/* Free all data in the buffer. */ -void buffer_reset(struct buffer *); - -/* This function first calls buffer_reset to release all buffered data. - Then it frees the struct buffer itself. */ -void buffer_free(struct buffer *); - -/* Add the given data to the end of the buffer. */ -extern void buffer_put(struct buffer *, const void *, size_t); -/* Add a single character to the end of the buffer. */ -extern void buffer_putc(struct buffer *, u_char); -/* Add a NUL-terminated string to the end of the buffer. */ -extern void buffer_putstr(struct buffer *, const char *); - -/* Combine all accumulated (and unflushed) data inside the buffer into a - single NUL-terminated string allocated using XMALLOC(MTYPE_TMP). Note - that this function does not alter the state of the buffer, so the data - is still inside waiting to be flushed. */ -char *buffer_getstr(struct buffer *); - -/* Returns 1 if there is no pending data in the buffer. Otherwise returns 0. */ -int buffer_empty(struct buffer *); - -typedef enum { - /* An I/O error occurred. The buffer should be destroyed and the - file descriptor should be closed. */ - BUFFER_ERROR = -1, - - /* The data was written successfully, and the buffer is now empty - (there is no pending data waiting to be flushed). */ - BUFFER_EMPTY = 0, - - /* There is pending data in the buffer waiting to be flushed. Please - try flushing the buffer when select indicates that the file descriptor - is writeable. */ - BUFFER_PENDING = 1 -} buffer_status_t; - -/* Try to write this data to the file descriptor. Any data that cannot - be written immediately is added to the buffer queue. */ -extern buffer_status_t buffer_write(struct buffer *, int fd, - const void *, size_t); - -/* This function attempts to flush some (but perhaps not all) of - the queued data to the given file descriptor. */ -extern buffer_status_t buffer_flush_available(struct buffer *, int fd); - -/* The following 2 functions (buffer_flush_all and buffer_flush_window) - are for use in lib/vty.c only. They should not be used elsewhere. */ - -/* Call buffer_flush_available repeatedly until either all data has been - flushed, or an I/O error has been encountered, or the operation would - block. */ -extern buffer_status_t buffer_flush_all(struct buffer *, int fd); - -/* Attempt to write enough data to the given fd to fill a window of the - given width and height (and remove the data written from the buffer). - - If !no_more, then a message saying " --More-- " is appended. - If erase is true, then first overwrite the previous " --More-- " message - with spaces. - - Any write error (including EAGAIN or EINTR) will cause this function - to return -1 (because the logic for handling the erase and more features - is too complicated to retry the write later). -*/ -extern buffer_status_t buffer_flush_window(struct buffer *, int fd, int width, - int height, int erase, int no_more); - -#endif /* _ZEBRA_BUFFER_H */ diff --git a/openpcd/opcd_test/zebvty/command.c b/openpcd/opcd_test/zebvty/command.c deleted file mode 100644 index 7f3a6a5..0000000 --- a/openpcd/opcd_test/zebvty/command.c +++ /dev/null @@ -1,3384 +0,0 @@ -/* - $Id: command.c,v 1.47 2005/04/25 16:26:42 paul Exp $ - - Command interpreter routine for virtual terminal [aka TeletYpe] - Copyright (C) 1997, 98, 99 Kunihiro Ishiguro - -This file is part of GNU Zebra. - -GNU Zebra 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. - -GNU Zebra 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 "zebvty.h" - -#include -#include -#include -#include -#include -#define _XOPEN_SOURCE -#include -#include -#include -#include -#include - -//#include "memory.h" -//#include "log.h" -//#include -//#include "thread.h" -#include "vector.h" -#include "vty.h" -#include "command.h" -//#include "workqueue.h" - -/* Command vector which includes some level of command lists. Normally - each daemon maintains each own cmdvec. */ -vector cmdvec; - -/* Host information structure. */ -struct host host; - -/* Standard command node structures. */ -struct cmd_node auth_node = { - AUTH_NODE, - "Password: ", -}; - -struct cmd_node view_node = { - VIEW_NODE, - "%s> ", -}; - -struct cmd_node auth_enable_node = { - AUTH_ENABLE_NODE, - "Password: ", -}; - -struct cmd_node enable_node = { - ENABLE_NODE, - "%s# ", -}; - -struct cmd_node config_node = { - CONFIG_NODE, - "%s(config)# ", - 1 -}; - -/* Default motd string. */ -const char *default_motd = "\r\n\ -Hello, this is " QUAGGA_PROGNAME " (version " QUAGGA_VERSION ").\r\n\ -" QUAGGA_COPYRIGHT "\r\n\ -\r\n"; - -#if 0 -static struct facility_map { - int facility; - const char *name; - size_t match; -} syslog_facilities[] = { - { - LOG_KERN, "kern", 1}, { - LOG_USER, "user", 2}, { - LOG_MAIL, "mail", 1}, { - LOG_DAEMON, "daemon", 1}, { - LOG_AUTH, "auth", 1}, { - LOG_SYSLOG, "syslog", 1}, { - LOG_LPR, "lpr", 2}, { - LOG_NEWS, "news", 1}, { - LOG_UUCP, "uucp", 2}, { - LOG_CRON, "cron", 1}, -#ifdef LOG_FTP - { - LOG_FTP, "ftp", 1}, -#endif - { - LOG_LOCAL0, "local0", 6}, { - LOG_LOCAL1, "local1", 6}, { - LOG_LOCAL2, "local2", 6}, { - LOG_LOCAL3, "local3", 6}, { - LOG_LOCAL4, "local4", 6}, { - LOG_LOCAL5, "local5", 6}, { - LOG_LOCAL6, "local6", 6}, { - LOG_LOCAL7, "local7", 6}, { -0, NULL, 0},}; - -static const char *facility_name(int facility) -{ - struct facility_map *fm; - - for (fm = syslog_facilities; fm->name; fm++) - if (fm->facility == facility) - return fm->name; - return ""; -} - -static int facility_match(const char *str) -{ - struct facility_map *fm; - - for (fm = syslog_facilities; fm->name; fm++) - if (!strncmp(str, fm->name, fm->match)) - return fm->facility; - return -1; -} - -static int level_match(const char *s) -{ - int level; - - for (level = 0; zlog_priority[level] != NULL; level++) - if (!strncmp(s, zlog_priority[level], 2)) - return level; - return ZLOG_DISABLED; -} -#endif - -/* This is called from main when a daemon is invoked with -v or --version. */ -void print_version(const char *progname) -{ - printf("%s version %s\n", progname, QUAGGA_VERSION); - printf("%s\n", QUAGGA_COPYRIGHT); -} - -/* Utility function to concatenate argv argument into a single string - with inserting ' ' character between each argument. */ -char *argv_concat(const char **argv, int argc, int shift) -{ - int i; - size_t len; - char *str; - char *p; - - len = 0; - for (i = shift; i < argc; i++) - len += strlen(argv[i]) + 1; - if (!len) - return NULL; - p = str = malloc(len); - for (i = shift; i < argc; i++) { - size_t arglen; - memcpy(p, argv[i], (arglen = strlen(argv[i]))); - p += arglen; - *p++ = ' '; - } - *(p - 1) = '\0'; - return str; -} - -/* Install top node of command vector. */ -void install_node(struct cmd_node *node, int (*func) (struct vty *)) -{ - vector_set_index(cmdvec, node->node, node); - node->func = func; - node->cmd_vector = vector_init(VECTOR_MIN_SIZE); -} - -/* Compare two command's string. Used in sort_node (). */ -static int cmp_node(const void *p, const void *q) -{ - struct cmd_element *a = *(struct cmd_element **)p; - struct cmd_element *b = *(struct cmd_element **)q; - - return strcmp(a->string, b->string); -} - -static int cmp_desc(const void *p, const void *q) -{ - struct desc *a = *(struct desc **)p; - struct desc *b = *(struct desc **)q; - - return strcmp(a->cmd, b->cmd); -} - -/* Sort each node's command element according to command string. */ -void sort_node() -{ - unsigned int i, j; - struct cmd_node *cnode; - vector descvec; - struct cmd_element *cmd_element; - - for (i = 0; i < vector_active(cmdvec); i++) - if ((cnode = vector_slot(cmdvec, i)) != NULL) { - vector cmd_vector = cnode->cmd_vector; - qsort(cmd_vector->index, vector_active(cmd_vector), - sizeof(void *), cmp_node); - - for (j = 0; j < vector_active(cmd_vector); j++) - if ((cmd_element = - vector_slot(cmd_vector, j)) != NULL - && vector_active(cmd_element->strvec)) { - descvec = - vector_slot(cmd_element->strvec, - vector_active - (cmd_element->strvec) - - 1); - qsort(descvec->index, - vector_active(descvec), - sizeof(void *), cmp_desc); - } - } -} - -/* Breaking up string into each command piece. I assume given - character is separated by a space character. Return value is a - vector which includes char ** data element. */ -vector cmd_make_strvec(const char *string) -{ - const char *cp, *start; - char *token; - int strlen; - vector strvec; - - if (string == NULL) - return NULL; - - cp = string; - - /* Skip white spaces. */ - while (isspace((int)*cp) && *cp != '\0') - cp++; - - /* Return if there is only white spaces */ - if (*cp == '\0') - return NULL; - - if (*cp == '!' || *cp == '#') - return NULL; - - /* Prepare return vector. */ - strvec = vector_init(VECTOR_MIN_SIZE); - - /* Copy each command piece and set into vector. */ - while (1) { - start = cp; - while (!(isspace((int)*cp) || *cp == '\r' || *cp == '\n') && - *cp != '\0') - cp++; - strlen = cp - start; - token = malloc(strlen + 1); - memcpy(token, start, strlen); - *(token + strlen) = '\0'; - vector_set(strvec, token); - - while ((isspace((int)*cp) || *cp == '\n' || *cp == '\r') && - *cp != '\0') - cp++; - - if (*cp == '\0') - return strvec; - } -} - -/* Free allocated string vector. */ -void cmd_free_strvec(vector v) -{ - unsigned int i; - char *cp; - - if (!v) - return; - - for (i = 0; i < vector_active(v); i++) - if ((cp = vector_slot(v, i)) != NULL) - free(cp); - - vector_free(v); -} - -/* Fetch next description. Used in cmd_make_descvec(). */ -static char *cmd_desc_str(const char **string) -{ - const char *cp, *start; - char *token; - int strlen; - - cp = *string; - - if (cp == NULL) - return NULL; - - /* Skip white spaces. */ - while (isspace((int)*cp) && *cp != '\0') - cp++; - - /* Return if there is only white spaces */ - if (*cp == '\0') - return NULL; - - start = cp; - - while (!(*cp == '\r' || *cp == '\n') && *cp != '\0') - cp++; - - strlen = cp - start; - token = malloc(strlen + 1); - memcpy(token, start, strlen); - *(token + strlen) = '\0'; - - *string = cp; - - return token; -} - -/* New string vector. */ -static vector cmd_make_descvec(const char *string, const char *descstr) -{ - int multiple = 0; - const char *sp; - char *token; - int len; - const char *cp; - const char *dp; - vector allvec; - vector strvec = NULL; - struct desc *desc; - - cp = string; - dp = descstr; - - if (cp == NULL) - return NULL; - - allvec = vector_init(VECTOR_MIN_SIZE); - - while (1) { - while (isspace((int)*cp) && *cp != '\0') - cp++; - - if (*cp == '(') { - multiple = 1; - cp++; - } - if (*cp == ')') { - multiple = 0; - cp++; - } - if (*cp == '|') { - if (!multiple) { - fprintf(stderr, "Command parse error!: %s\n", - string); - exit(1); - } - cp++; - } - - while (isspace((int)*cp) && *cp != '\0') - cp++; - - if (*cp == '(') { - multiple = 1; - cp++; - } - - if (*cp == '\0') - return allvec; - - sp = cp; - - while (! - (isspace((int)*cp) || *cp == '\r' || *cp == '\n' - || *cp == ')' || *cp == '|') && *cp != '\0') - cp++; - - len = cp - sp; - - token = malloc(len + 1); - memcpy(token, sp, len); - *(token + len) = '\0'; - - desc = calloc(1, sizeof(struct desc)); - desc->cmd = token; - desc->str = cmd_desc_str(&dp); - - if (multiple) { - if (multiple == 1) { - strvec = vector_init(VECTOR_MIN_SIZE); - vector_set(allvec, strvec); - } - multiple++; - } else { - strvec = vector_init(VECTOR_MIN_SIZE); - vector_set(allvec, strvec); - } - vector_set(strvec, desc); - } -} - -/* Count mandantory string vector size. This is to determine inputed - command has enough command length. */ -static int cmd_cmdsize(vector strvec) -{ - unsigned int i; - int size = 0; - vector descvec; - struct desc *desc; - - for (i = 0; i < vector_active(strvec); i++) - if ((descvec = vector_slot(strvec, i)) != NULL) { - if ((vector_active(descvec)) == 1 - && (desc = vector_slot(descvec, 0)) != NULL) { - if (desc->cmd == NULL || CMD_OPTION(desc->cmd)) - return size; - else - size++; - } else - size++; - } - return size; -} - -/* Return prompt character of specified node. */ -const char *cmd_prompt(enum node_type node) -{ - struct cmd_node *cnode; - - cnode = vector_slot(cmdvec, node); - return cnode->prompt; -} - -/* Install a command into a node. */ -void install_element(enum node_type ntype, struct cmd_element *cmd) -{ - struct cmd_node *cnode; - - cnode = vector_slot(cmdvec, ntype); - - if (cnode == NULL) { - fprintf(stderr, - "Command node %d doesn't exist, please check it\n", - ntype); - exit(1); - } - - vector_set(cnode->cmd_vector, cmd); - - cmd->strvec = cmd_make_descvec(cmd->string, cmd->doc); - cmd->cmdsize = cmd_cmdsize(cmd->strvec); -} - -static unsigned char itoa64[] = - "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - -static void to64(char *s, long v, int n) -{ - while (--n >= 0) { - *s++ = itoa64[v & 0x3f]; - v >>= 6; - } -} - -static char *zencrypt(const char *passwd) -{ - char salt[6]; - struct timeval tv; - char *crypt(const char *, const char *); - - gettimeofday(&tv, 0); - - to64(&salt[0], random(), 3); - to64(&salt[3], tv.tv_usec, 3); - salt[5] = '\0'; - - return crypt(passwd, salt); -} - -/* This function write configuration of this host. */ -static int config_write_host(struct vty *vty) -{ -#if 0 - if (host.name) - vty_out(vty, "hostname %s%s", host.name, VTY_NEWLINE); - - if (host.encrypt) { - if (host.password_encrypt) - vty_out(vty, "password 8 %s%s", host.password_encrypt, - VTY_NEWLINE); - if (host.enable_encrypt) - vty_out(vty, "enable password 8 %s%s", - host.enable_encrypt, VTY_NEWLINE); - } else { - if (host.password) - vty_out(vty, "password %s%s", host.password, - VTY_NEWLINE); - if (host.enable) - vty_out(vty, "enable password %s%s", host.enable, - VTY_NEWLINE); - } - - if (zlog_default->default_lvl != LOG_DEBUG) { - vty_out(vty, "! N.B. The 'log trap' command is deprecated.%s", - VTY_NEWLINE); - vty_out(vty, "log trap %s%s", - zlog_priority[zlog_default->default_lvl], VTY_NEWLINE); - } - - if (host.logfile - && (zlog_default->maxlvl[ZLOG_DEST_FILE] != ZLOG_DISABLED)) { - vty_out(vty, "log file %s", host.logfile); - if (zlog_default->maxlvl[ZLOG_DEST_FILE] != - zlog_default->default_lvl) - vty_out(vty, " %s", - zlog_priority[zlog_default-> - maxlvl[ZLOG_DEST_FILE]]); - vty_out(vty, "%s", VTY_NEWLINE); - } - - if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != ZLOG_DISABLED) { - vty_out(vty, "log stdout"); - if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != - zlog_default->default_lvl) - vty_out(vty, " %s", - zlog_priority[zlog_default-> - maxlvl[ZLOG_DEST_STDOUT]]); - vty_out(vty, "%s", VTY_NEWLINE); - } - - if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED) - vty_out(vty, "no log monitor%s", VTY_NEWLINE); - else if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] != - zlog_default->default_lvl) - vty_out(vty, "log monitor %s%s", - zlog_priority[zlog_default->maxlvl[ZLOG_DEST_MONITOR]], - VTY_NEWLINE); - - if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED) { - vty_out(vty, "log syslog"); - if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != - zlog_default->default_lvl) - vty_out(vty, " %s", - zlog_priority[zlog_default-> - maxlvl[ZLOG_DEST_SYSLOG]]); - vty_out(vty, "%s", VTY_NEWLINE); - } - - if (zlog_default->facility != LOG_DAEMON) - vty_out(vty, "log facility %s%s", - facility_name(zlog_default->facility), VTY_NEWLINE); - - if (zlog_default->record_priority == 1) - vty_out(vty, "log record-priority%s", VTY_NEWLINE); - - if (host.advanced) - vty_out(vty, "service advanced-vty%s", VTY_NEWLINE); - - if (host.encrypt) - vty_out(vty, "service password-encryption%s", VTY_NEWLINE); - - if (host.lines >= 0) - vty_out(vty, "service terminal-length %d%s", host.lines, - VTY_NEWLINE); - - if (host.motdfile) - vty_out(vty, "banner motd file %s%s", host.motdfile, - VTY_NEWLINE); - else if (!host.motd) - vty_out(vty, "no banner motd%s", VTY_NEWLINE); - -#endif - return 1; -} - -/* Utility function for getting command vector. */ -static vector cmd_node_vector(vector v, enum node_type ntype) -{ - struct cmd_node *cnode = vector_slot(v, ntype); - return cnode->cmd_vector; -} - -#if 0 -/* Filter command vector by symbol. This function is not actually used; - * should it be deleted? */ -static int cmd_filter_by_symbol(char *command, char *symbol) -{ - int i, lim; - - if (strcmp(symbol, "IPV4_ADDRESS") == 0) { - i = 0; - lim = strlen(command); - while (i < lim) { - if (! - (isdigit((int)command[i]) || command[i] == '.' - || command[i] == '/')) - return 1; - i++; - } - return 0; - } - if (strcmp(symbol, "STRING") == 0) { - i = 0; - lim = strlen(command); - while (i < lim) { - if (! - (isalpha((int)command[i]) || command[i] == '_' - || command[i] == '-')) - return 1; - i++; - } - return 0; - } - if (strcmp(symbol, "IFNAME") == 0) { - i = 0; - lim = strlen(command); - while (i < lim) { - if (!isalnum((int)command[i])) - return 1; - i++; - } - return 0; - } - return 0; -} -#endif - -/* Completion match types. */ -enum match_type { - no_match, - extend_match, - ipv4_prefix_match, - ipv4_match, - ipv6_prefix_match, - ipv6_match, - range_match, - vararg_match, - partly_match, - exact_match -}; - -static enum match_type cmd_ipv4_match(const char *str) -{ - const char *sp; - int dots = 0, nums = 0; - char buf[4]; - - if (str == NULL) - return partly_match; - - for (;;) { - memset(buf, 0, sizeof(buf)); - sp = str; - while (*str != '\0') { - if (*str == '.') { - if (dots >= 3) - return no_match; - - if (*(str + 1) == '.') - return no_match; - - if (*(str + 1) == '\0') - return partly_match; - - dots++; - break; - } - if (!isdigit((int)*str)) - return no_match; - - str++; - } - - if (str - sp > 3) - return no_match; - - strncpy(buf, sp, str - sp); - if (atoi(buf) > 255) - return no_match; - - nums++; - - if (*str == '\0') - break; - - str++; - } - - if (nums < 4) - return partly_match; - - return exact_match; -} - -static enum match_type cmd_ipv4_prefix_match(const char *str) -{ - const char *sp; - int dots = 0; - char buf[4]; - - if (str == NULL) - return partly_match; - - for (;;) { - memset(buf, 0, sizeof(buf)); - sp = str; - while (*str != '\0' && *str != '/') { - if (*str == '.') { - if (dots == 3) - return no_match; - - if (*(str + 1) == '.' || *(str + 1) == '/') - return no_match; - - if (*(str + 1) == '\0') - return partly_match; - - dots++; - break; - } - - if (!isdigit((int)*str)) - return no_match; - - str++; - } - - if (str - sp > 3) - return no_match; - - strncpy(buf, sp, str - sp); - if (atoi(buf) > 255) - return no_match; - - if (dots == 3) { - if (*str == '/') { - if (*(str + 1) == '\0') - return partly_match; - - str++; - break; - } else if (*str == '\0') - return partly_match; - } - - if (*str == '\0') - return partly_match; - - str++; - } - - sp = str; - while (*str != '\0') { - if (!isdigit((int)*str)) - return no_match; - - str++; - } - - if (atoi(sp) > 32) - return no_match; - - return exact_match; -} - -#define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%" -#define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/" -#define STATE_START 1 -#define STATE_COLON 2 -#define STATE_DOUBLE 3 -#define STATE_ADDR 4 -#define STATE_DOT 5 -#define STATE_SLASH 6 -#define STATE_MASK 7 - -#ifdef HAVE_IPV6 - -static enum match_type cmd_ipv6_match(const char *str) -{ - int state = STATE_START; - int colons = 0, nums = 0, double_colon = 0; - const char *sp = NULL; - struct sockaddr_in6 sin6_dummy; - int ret; - - if (str == NULL) - return partly_match; - - if (strspn(str, IPV6_ADDR_STR) != strlen(str)) - return no_match; - - /* use inet_pton that has a better support, - * for example inet_pton can support the automatic addresses: - * ::1.2.3.4 - */ - ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr); - - if (ret == 1) - return exact_match; - - while (*str != '\0') { - switch (state) { - case STATE_START: - if (*str == ':') { - if (*(str + 1) != ':' && *(str + 1) != '\0') - return no_match; - colons--; - state = STATE_COLON; - } else { - sp = str; - state = STATE_ADDR; - } - - continue; - case STATE_COLON: - colons++; - if (*(str + 1) == ':') - state = STATE_DOUBLE; - else { - sp = str + 1; - state = STATE_ADDR; - } - break; - case STATE_DOUBLE: - if (double_colon) - return no_match; - - if (*(str + 1) == ':') - return no_match; - else { - if (*(str + 1) != '\0') - colons++; - sp = str + 1; - state = STATE_ADDR; - } - - double_colon++; - nums++; - break; - case STATE_ADDR: - if (*(str + 1) == ':' || *(str + 1) == '\0') { - if (str - sp > 3) - return no_match; - - nums++; - state = STATE_COLON; - } - if (*(str + 1) == '.') - state = STATE_DOT; - break; - case STATE_DOT: - state = STATE_ADDR; - break; - default: - break; - } - - if (nums > 8) - return no_match; - - if (colons > 7) - return no_match; - - str++; - } - -#if 0 - if (nums < 11) - return partly_match; -#endif /* 0 */ - - return exact_match; -} - -static enum match_type cmd_ipv6_prefix_match(const char *str) -{ - int state = STATE_START; - int colons = 0, nums = 0, double_colon = 0; - int mask; - const char *sp = NULL; - char *endptr = NULL; - - if (str == NULL) - return partly_match; - - if (strspn(str, IPV6_PREFIX_STR) != strlen(str)) - return no_match; - - while (*str != '\0' && state != STATE_MASK) { - switch (state) { - case STATE_START: - if (*str == ':') { - if (*(str + 1) != ':' && *(str + 1) != '\0') - return no_match; - colons--; - state = STATE_COLON; - } else { - sp = str; - state = STATE_ADDR; - } - - continue; - case STATE_COLON: - colons++; - if (*(str + 1) == '/') - return no_match; - else if (*(str + 1) == ':') - state = STATE_DOUBLE; - else { - sp = str + 1; - state = STATE_ADDR; - } - break; - case STATE_DOUBLE: - if (double_colon) - return no_match; - - if (*(str + 1) == ':') - return no_match; - else { - if (*(str + 1) != '\0' && *(str + 1) != '/') - colons++; - sp = str + 1; - - if (*(str + 1) == '/') - state = STATE_SLASH; - else - state = STATE_ADDR; - } - - double_colon++; - nums += 1; - break; - case STATE_ADDR: - if (*(str + 1) == ':' || *(str + 1) == '.' - || *(str + 1) == '\0' || *(str + 1) == '/') { - if (str - sp > 3) - return no_match; - - for (; sp <= str; sp++) - if (*sp == '/') - return no_match; - - nums++; - - if (*(str + 1) == ':') - state = STATE_COLON; - else if (*(str + 1) == '.') - state = STATE_DOT; - else if (*(str + 1) == '/') - state = STATE_SLASH; - } - break; - case STATE_DOT: - state = STATE_ADDR; - break; - case STATE_SLASH: - if (*(str + 1) == '\0') - return partly_match; - - state = STATE_MASK; - break; - default: - break; - } - - if (nums > 11) - return no_match; - - if (colons > 7) - return no_match; - - str++; - } - - if (state < STATE_MASK) - return partly_match; - - mask = strtol(str, &endptr, 10); - if (*endptr != '\0') - return no_match; - - if (mask < 0 || mask > 128) - return no_match; - -/* I don't know why mask < 13 makes command match partly. - Forgive me to make this comments. I Want to set static default route - because of lack of function to originate default in ospf6d; sorry - yasu - if (mask < 13) - return partly_match; -*/ - - return exact_match; -} - -#endif /* HAVE_IPV6 */ - -#define DECIMAL_STRLEN_MAX 10 - -static int cmd_range_match(const char *range, const char *str) -{ - char *p; - char buf[DECIMAL_STRLEN_MAX + 1]; - char *endptr = NULL; - unsigned long min, max, val; - - if (str == NULL) - return 1; - - val = strtoul(str, &endptr, 10); - if (*endptr != '\0') - return 0; - - range++; - p = strchr(range, '-'); - if (p == NULL) - return 0; - if (p - range > DECIMAL_STRLEN_MAX) - return 0; - strncpy(buf, range, p - range); - buf[p - range] = '\0'; - min = strtoul(buf, &endptr, 10); - if (*endptr != '\0') - return 0; - - range = p + 1; - p = strchr(range, '>'); - if (p == NULL) - return 0; - if (p - range > DECIMAL_STRLEN_MAX) - return 0; - strncpy(buf, range, p - range); - buf[p - range] = '\0'; - max = strtoul(buf, &endptr, 10); - if (*endptr != '\0') - return 0; - - if (val < min || val > max) - return 0; - - return 1; -} - -/* Make completion match and return match type flag. */ -static enum match_type -cmd_filter_by_completion(char *command, vector v, unsigned int index) -{ - unsigned int i; - const char *str; - struct cmd_element *cmd_element; - enum match_type match_type; - vector descvec; - struct desc *desc; - - match_type = no_match; - - /* If command and cmd_element string does not match set NULL to vector */ - for (i = 0; i < vector_active(v); i++) - if ((cmd_element = vector_slot(v, i)) != NULL) { - if (index >= vector_active(cmd_element->strvec)) - vector_slot(v, i) = NULL; - else { - unsigned int j; - int matched = 0; - - descvec = - vector_slot(cmd_element->strvec, index); - - for (j = 0; j < vector_active(descvec); j++) - if ((desc = vector_slot(descvec, j))) { - str = desc->cmd; - - if (CMD_VARARG(str)) { - if (match_type < - vararg_match) - match_type = - vararg_match; - matched++; - } else if (CMD_RANGE(str)) { - if (cmd_range_match - (str, command)) { - if (match_type < - range_match) - match_type - = - range_match; - - matched++; - } - } -#ifdef HAVE_IPV6 - else if (CMD_IPV6(str)) { - if (cmd_ipv6_match - (command)) { - if (match_type < - ipv6_match) - match_type - = - ipv6_match; - - matched++; - } - } else if (CMD_IPV6_PREFIX(str)) { - if (cmd_ipv6_prefix_match(command)) { - if (match_type < - ipv6_prefix_match) - match_type - = - ipv6_prefix_match; - - matched++; - } - } -#endif /* HAVE_IPV6 */ - else if (CMD_IPV4(str)) { - if (cmd_ipv4_match - (command)) { - if (match_type < - ipv4_match) - match_type - = - ipv4_match; - - matched++; - } - } else if (CMD_IPV4_PREFIX(str)) { - if (cmd_ipv4_prefix_match(command)) { - if (match_type < - ipv4_prefix_match) - match_type - = - ipv4_prefix_match; - matched++; - } - } else - /* Check is this point's argument optional ? */ - if (CMD_OPTION(str) - || - CMD_VARIABLE(str)) { - if (match_type < - extend_match) - match_type = - extend_match; - matched++; - } else - if (strncmp - (command, str, - strlen(command)) == - 0) { - if (strcmp(command, str) - == 0) - match_type = - exact_match; - else { - if (match_type < - partly_match) - match_type - = - partly_match; - } - matched++; - } - } - if (!matched) - vector_slot(v, i) = NULL; - } - } - return match_type; -} - -/* Filter vector by command character with index. */ -static enum match_type -cmd_filter_by_string(char *command, vector v, unsigned int index) -{ - unsigned int i; - const char *str; - struct cmd_element *cmd_element; - enum match_type match_type; - vector descvec; - struct desc *desc; - - match_type = no_match; - - /* If command and cmd_element string does not match set NULL to vector */ - for (i = 0; i < vector_active(v); i++) - if ((cmd_element = vector_slot(v, i)) != NULL) { - /* If given index is bigger than max string vector of command, - set NULL */ - if (index >= vector_active(cmd_element->strvec)) - vector_slot(v, i) = NULL; - else { - unsigned int j; - int matched = 0; - - descvec = - vector_slot(cmd_element->strvec, index); - - for (j = 0; j < vector_active(descvec); j++) - if ((desc = vector_slot(descvec, j))) { - str = desc->cmd; - - if (CMD_VARARG(str)) { - if (match_type < - vararg_match) - match_type = - vararg_match; - matched++; - } else if (CMD_RANGE(str)) { - if (cmd_range_match - (str, command)) { - if (match_type < - range_match) - match_type - = - range_match; - matched++; - } - } -#ifdef HAVE_IPV6 - else if (CMD_IPV6(str)) { - if (cmd_ipv6_match - (command) == - exact_match) { - if (match_type < - ipv6_match) - match_type - = - ipv6_match; - matched++; - } - } else if (CMD_IPV6_PREFIX(str)) { - if (cmd_ipv6_prefix_match(command) == exact_match) { - if (match_type < - ipv6_prefix_match) - match_type - = - ipv6_prefix_match; - matched++; - } - } -#endif /* HAVE_IPV6 */ - else if (CMD_IPV4(str)) { - if (cmd_ipv4_match - (command) == - exact_match) { - if (match_type < - ipv4_match) - match_type - = - ipv4_match; - matched++; - } - } else if (CMD_IPV4_PREFIX(str)) { - if (cmd_ipv4_prefix_match(command) == exact_match) { - if (match_type < - ipv4_prefix_match) - match_type - = - ipv4_prefix_match; - matched++; - } - } else if (CMD_OPTION(str) - || CMD_VARIABLE(str)) - { - if (match_type < - extend_match) - match_type = - extend_match; - matched++; - } else { - if (strcmp(command, str) - == 0) { - match_type = - exact_match; - matched++; - } - } - } - if (!matched) - vector_slot(v, i) = NULL; - } - } - return match_type; -} - -/* Check ambiguous match */ -static int -is_cmd_ambiguous(char *command, vector v, int index, enum match_type type) -{ - unsigned int i; - unsigned int j; - const char *str = NULL; - struct cmd_element *cmd_element; - const char *matched = NULL; - vector descvec; - struct desc *desc; - - for (i = 0; i < vector_active(v); i++) - if ((cmd_element = vector_slot(v, i)) != NULL) { - int match = 0; - - descvec = vector_slot(cmd_element->strvec, index); - - for (j = 0; j < vector_active(descvec); j++) - if ((desc = vector_slot(descvec, j))) { - enum match_type ret; - - str = desc->cmd; - - switch (type) { - case exact_match: - if (! - (CMD_OPTION(str) - || CMD_VARIABLE(str)) -&& strcmp(command, str) == 0) - match++; - break; - case partly_match: - if (! - (CMD_OPTION(str) - || CMD_VARIABLE(str)) -&& strncmp(command, str, strlen(command)) == 0) { - if (matched - && strcmp(matched, - str) != 0) - return 1; /* There is ambiguous match. */ - else - matched = str; - match++; - } - break; - case range_match: - if (cmd_range_match - (str, command)) { - if (matched - && strcmp(matched, - str) != 0) - return 1; - else - matched = str; - match++; - } - break; -#ifdef HAVE_IPV6 - case ipv6_match: - if (CMD_IPV6(str)) - match++; - break; - case ipv6_prefix_match: - if ((ret = - cmd_ipv6_prefix_match - (command)) != no_match) { - if (ret == partly_match) - return 2; /* There is incomplete match. */ - - match++; - } - break; -#endif /* HAVE_IPV6 */ - case ipv4_match: - if (CMD_IPV4(str)) - match++; - break; - case ipv4_prefix_match: - if ((ret = - cmd_ipv4_prefix_match - (command)) != no_match) { - if (ret == partly_match) - return 2; /* There is incomplete match. */ - - match++; - } - break; - case extend_match: - if (CMD_OPTION(str) - || CMD_VARIABLE(str)) - match++; - break; - case no_match: - default: - break; - } - } - if (!match) - vector_slot(v, i) = NULL; - } - return 0; -} - -/* If src matches dst return dst string, otherwise return NULL */ -static const char *cmd_entry_function(const char *src, const char *dst) -{ - /* Skip variable arguments. */ - if (CMD_OPTION(dst) || CMD_VARIABLE(dst) || CMD_VARARG(dst) || - CMD_IPV4(dst) || CMD_IPV4_PREFIX(dst) || CMD_RANGE(dst)) - return NULL; - - /* In case of 'command \t', given src is NULL string. */ - if (src == NULL) - return dst; - - /* Matched with input string. */ - if (strncmp(src, dst, strlen(src)) == 0) - return dst; - - return NULL; -} - -/* If src matches dst return dst string, otherwise return NULL */ -/* This version will return the dst string always if it is - CMD_VARIABLE for '?' key processing */ -static const char *cmd_entry_function_desc(const char *src, const char *dst) -{ - if (CMD_VARARG(dst)) - return dst; - - if (CMD_RANGE(dst)) { - if (cmd_range_match(dst, src)) - return dst; - else - return NULL; - } -#ifdef HAVE_IPV6 - if (CMD_IPV6(dst)) { - if (cmd_ipv6_match(src)) - return dst; - else - return NULL; - } - - if (CMD_IPV6_PREFIX(dst)) { - if (cmd_ipv6_prefix_match(src)) - return dst; - else - return NULL; - } -#endif /* HAVE_IPV6 */ - - if (CMD_IPV4(dst)) { - if (cmd_ipv4_match(src)) - return dst; - else - return NULL; - } - - if (CMD_IPV4_PREFIX(dst)) { - if (cmd_ipv4_prefix_match(src)) - return dst; - else - return NULL; - } - - /* Optional or variable commands always match on '?' */ - if (CMD_OPTION(dst) || CMD_VARIABLE(dst)) - return dst; - - /* In case of 'command \t', given src is NULL string. */ - if (src == NULL) - return dst; - - if (strncmp(src, dst, strlen(src)) == 0) - return dst; - else - return NULL; -} - -/* Check same string element existence. If it isn't there return - 1. */ -static int cmd_unique_string(vector v, const char *str) -{ - unsigned int i; - char *match; - - for (i = 0; i < vector_active(v); i++) - if ((match = vector_slot(v, i)) != NULL) - if (strcmp(match, str) == 0) - return 0; - return 1; -} - -/* Compare string to description vector. If there is same string - return 1 else return 0. */ -static int desc_unique_string(vector v, const char *str) -{ - unsigned int i; - struct desc *desc; - - for (i = 0; i < vector_active(v); i++) - if ((desc = vector_slot(v, i)) != NULL) - if (strcmp(desc->cmd, str) == 0) - return 1; - return 0; -} - -static int cmd_try_do_shortcut(enum node_type node, char *first_word) -{ - if (first_word != NULL && - node != AUTH_NODE && - node != VIEW_NODE && - node != AUTH_ENABLE_NODE && - node != ENABLE_NODE && 0 == strcmp("do", first_word)) - return 1; - return 0; -} - -/* '?' describe command support. */ -static vector -cmd_describe_command_real(vector vline, struct vty *vty, int *status) -{ - unsigned int i; - vector cmd_vector; -#define INIT_MATCHVEC_SIZE 10 - vector matchvec; - struct cmd_element *cmd_element; - unsigned int index; - int ret; - enum match_type match; - char *command; - static struct desc desc_cr = { "", "" }; - - /* Set index. */ - if (vector_active(vline) == 0) { - *status = CMD_ERR_NO_MATCH; - return NULL; - } else - index = vector_active(vline) - 1; - - /* Make copy vector of current node's command vector. */ - cmd_vector = vector_copy(cmd_node_vector(cmdvec, vty->node)); - - /* Prepare match vector */ - matchvec = vector_init(INIT_MATCHVEC_SIZE); - - /* Filter commands. */ - /* Only words precedes current word will be checked in this loop. */ - for (i = 0; i < index; i++) - if ((command = vector_slot(vline, i))) { - match = - cmd_filter_by_completion(command, cmd_vector, i); - - if (match == vararg_match) { - struct cmd_element *cmd_element; - vector descvec; - unsigned int j, k; - - for (j = 0; j < vector_active(cmd_vector); j++) - if ((cmd_element = - vector_slot(cmd_vector, j)) != NULL - && - (vector_active - (cmd_element->strvec))) { - descvec = - vector_slot(cmd_element-> - strvec, - vector_active - (cmd_element-> - strvec) - 1); - for (k = 0; - k < vector_active(descvec); - k++) { - struct desc *desc = - vector_slot(descvec, - k); - vector_set(matchvec, - desc); - } - } - - vector_set(matchvec, &desc_cr); - vector_free(cmd_vector); - - return matchvec; - } - - if ((ret = - is_cmd_ambiguous(command, cmd_vector, i, - match)) == 1) { - vector_free(cmd_vector); - *status = CMD_ERR_AMBIGUOUS; - return NULL; - } else if (ret == 2) { - vector_free(cmd_vector); - *status = CMD_ERR_NO_MATCH; - return NULL; - } - } - - /* Prepare match vector */ - /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */ - - /* Make sure that cmd_vector is filtered based on current word */ - command = vector_slot(vline, index); - if (command) - match = cmd_filter_by_completion(command, cmd_vector, index); - - /* Make description vector. */ - for (i = 0; i < vector_active(cmd_vector); i++) - if ((cmd_element = vector_slot(cmd_vector, i)) != NULL) { - const char *string = NULL; - vector strvec = cmd_element->strvec; - - /* if command is NULL, index may be equal to vector_active */ - if (command && index >= vector_active(strvec)) - vector_slot(cmd_vector, i) = NULL; - else { - /* Check if command is completed. */ - if (command == NULL - && index == vector_active(strvec)) { - string = ""; - if (!desc_unique_string - (matchvec, string)) - vector_set(matchvec, &desc_cr); - } else { - unsigned int j; - vector descvec = - vector_slot(strvec, index); - struct desc *desc; - - for (j = 0; j < vector_active(descvec); - j++) - if ((desc = - vector_slot(descvec, j))) { - string = - cmd_entry_function_desc - (command, - desc->cmd); - if (string) { - /* Uniqueness check */ - if (!desc_unique_string(matchvec, string)) - vector_set - (matchvec, - desc); - } - } - } - } - } - vector_free(cmd_vector); - - if (vector_slot(matchvec, 0) == NULL) { - vector_free(matchvec); - *status = CMD_ERR_NO_MATCH; - } else - *status = CMD_SUCCESS; - - return matchvec; -} - -vector cmd_describe_command(vector vline, struct vty * vty, int *status) -{ - vector ret; - - if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0))) { - enum node_type onode; - vector shifted_vline; - unsigned int index; - - onode = vty->node; - vty->node = ENABLE_NODE; - /* We can try it on enable node, cos' the vty is authenticated */ - - shifted_vline = vector_init(vector_count(vline)); - /* use memcpy? */ - for (index = 1; index < vector_active(vline); index++) { - vector_set_index(shifted_vline, index - 1, - vector_lookup(vline, index)); - } - - ret = cmd_describe_command_real(shifted_vline, vty, status); - - vector_free(shifted_vline); - vty->node = onode; - return ret; - } - - return cmd_describe_command_real(vline, vty, status); -} - -/* Check LCD of matched command. */ -static int cmd_lcd(char **matched) -{ - int i; - int j; - int lcd = -1; - char *s1, *s2; - char c1, c2; - - if (matched[0] == NULL || matched[1] == NULL) - return 0; - - for (i = 1; matched[i] != NULL; i++) { - s1 = matched[i - 1]; - s2 = matched[i]; - - for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++) - if (c1 != c2) - break; - - if (lcd < 0) - lcd = j; - else { - if (lcd > j) - lcd = j; - } - } - return lcd; -} - -/* Command line completion support. */ -static char **cmd_complete_command_real(vector vline, struct vty *vty, - int *status) -{ - unsigned int i; - vector cmd_vector = vector_copy(cmd_node_vector(cmdvec, vty->node)); -#define INIT_MATCHVEC_SIZE 10 - vector matchvec; - struct cmd_element *cmd_element; - unsigned int index; - char **match_str; - struct desc *desc; - vector descvec; - char *command; - int lcd; - - if (vector_active(vline) == 0) { - *status = CMD_ERR_NO_MATCH; - return NULL; - } else - index = vector_active(vline) - 1; - - /* First, filter by preceeding command string */ - for (i = 0; i < index; i++) - if ((command = vector_slot(vline, i))) { - enum match_type match; - int ret; - - /* First try completion match, if there is exactly match return 1 */ - match = - cmd_filter_by_completion(command, cmd_vector, i); - - /* If there is exact match then filter ambiguous match else check - ambiguousness. */ - if ((ret = - is_cmd_ambiguous(command, cmd_vector, i, - match)) == 1) { - vector_free(cmd_vector); - *status = CMD_ERR_AMBIGUOUS; - return NULL; - } - /* - else if (ret == 2) - { - vector_free (cmd_vector); - *status = CMD_ERR_NO_MATCH; - return NULL; - } - */ - } - - /* Prepare match vector. */ - matchvec = vector_init(INIT_MATCHVEC_SIZE); - - /* Now we got into completion */ - for (i = 0; i < vector_active(cmd_vector); i++) - if ((cmd_element = vector_slot(cmd_vector, i))) { - const char *string; - vector strvec = cmd_element->strvec; - - /* Check field length */ - if (index >= vector_active(strvec)) - vector_slot(cmd_vector, i) = NULL; - else { - unsigned int j; - - descvec = vector_slot(strvec, index); - for (j = 0; j < vector_active(descvec); j++) - if ((desc = vector_slot(descvec, j))) { - if ((string = - cmd_entry_function - (vector_slot(vline, index), - desc->cmd))) - if (cmd_unique_string - (matchvec, string)) - vector_set - (matchvec, - strdup - (string)); - } - } - } - - /* We don't need cmd_vector any more. */ - vector_free(cmd_vector); - - /* No matched command */ - if (vector_slot(matchvec, 0) == NULL) { - vector_free(matchvec); - - /* In case of 'command \t' pattern. Do you need '?' command at - the end of the line. */ - if (vector_slot(vline, index) == '\0') - *status = CMD_ERR_NOTHING_TODO; - else - *status = CMD_ERR_NO_MATCH; - return NULL; - } - - /* Only one matched */ - if (vector_slot(matchvec, 1) == NULL) { - match_str = (char **)matchvec->index; - vector_only_wrapper_free(matchvec); - *status = CMD_COMPLETE_FULL_MATCH; - return match_str; - } - /* Make it sure last element is NULL. */ - vector_set(matchvec, NULL); - - /* Check LCD of matched strings. */ - if (vector_slot(vline, index) != NULL) { - lcd = cmd_lcd((char **)matchvec->index); - - if (lcd) { - int len = strlen(vector_slot(vline, index)); - - if (len < lcd) { - char *lcdstr; - - lcdstr = malloc(lcd + 1); - memcpy(lcdstr, matchvec->index[0], lcd); - lcdstr[lcd] = '\0'; - - /* match_str = (char **) &lcdstr; */ - - /* Free matchvec. */ - for (i = 0; i < vector_active(matchvec); i++) { - if (vector_slot(matchvec, i)) - free(vector_slot(matchvec, i)); - } - vector_free(matchvec); - - /* Make new matchvec. */ - matchvec = vector_init(INIT_MATCHVEC_SIZE); - vector_set(matchvec, lcdstr); - match_str = (char **)matchvec->index; - vector_only_wrapper_free(matchvec); - - *status = CMD_COMPLETE_MATCH; - return match_str; - } - } - } - - match_str = (char **)matchvec->index; - vector_only_wrapper_free(matchvec); - *status = CMD_COMPLETE_LIST_MATCH; - return match_str; -} - -char **cmd_complete_command(vector vline, struct vty *vty, int *status) -{ - char **ret; - - if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0))) { - enum node_type onode; - vector shifted_vline; - unsigned int index; - - onode = vty->node; - vty->node = ENABLE_NODE; - /* We can try it on enable node, cos' the vty is authenticated */ - - shifted_vline = vector_init(vector_count(vline)); - /* use memcpy? */ - for (index = 1; index < vector_active(vline); index++) { - vector_set_index(shifted_vline, index - 1, - vector_lookup(vline, index)); - } - - ret = cmd_complete_command_real(shifted_vline, vty, status); - - vector_free(shifted_vline); - vty->node = onode; - return ret; - } - - return cmd_complete_command_real(vline, vty, status); -} - -/* return parent node */ -/* MUST eventually converge on CONFIG_NODE */ -enum node_type node_parent(enum node_type node) -{ - enum node_type ret; - - assert(node > CONFIG_NODE); - - switch (node) { - case BGP_VPNV4_NODE: - case BGP_IPV4_NODE: - case BGP_IPV4M_NODE: - case BGP_IPV6_NODE: - ret = BGP_NODE; - break; - case KEYCHAIN_KEY_NODE: - ret = KEYCHAIN_NODE; - break; - default: - ret = CONFIG_NODE; - } - - return ret; -} - -/* Execute command by argument vline vector. */ -static int -cmd_execute_command_real(vector vline, struct vty *vty, - struct cmd_element **cmd) -{ - unsigned int i; - unsigned int index; - vector cmd_vector; - struct cmd_element *cmd_element; - struct cmd_element *matched_element; - unsigned int matched_count, incomplete_count; - int argc; - const char *argv[CMD_ARGC_MAX]; - enum match_type match = 0; - int varflag; - char *command; - - /* Make copy of command elements. */ - cmd_vector = vector_copy(cmd_node_vector(cmdvec, vty->node)); - - for (index = 0; index < vector_active(vline); index++) - if ((command = vector_slot(vline, index))) { - int ret; - - match = - cmd_filter_by_completion(command, cmd_vector, - index); - - if (match == vararg_match) - break; - - ret = - is_cmd_ambiguous(command, cmd_vector, index, match); - - if (ret == 1) { - vector_free(cmd_vector); - return CMD_ERR_AMBIGUOUS; - } else if (ret == 2) { - vector_free(cmd_vector); - return CMD_ERR_NO_MATCH; - } - } - - /* Check matched count. */ - matched_element = NULL; - matched_count = 0; - incomplete_count = 0; - - for (i = 0; i < vector_active(cmd_vector); i++) - if ((cmd_element = vector_slot(cmd_vector, i))) { - if (match == vararg_match - || index >= cmd_element->cmdsize) { - matched_element = cmd_element; -#if 0 - printf("DEBUG: %s\n", cmd_element->string); -#endif - matched_count++; - } else { - incomplete_count++; - } - } - - /* Finish of using cmd_vector. */ - vector_free(cmd_vector); - - /* To execute command, matched_count must be 1. */ - if (matched_count == 0) { - if (incomplete_count) - return CMD_ERR_INCOMPLETE; - else - return CMD_ERR_NO_MATCH; - } - - if (matched_count > 1) - return CMD_ERR_AMBIGUOUS; - - /* Argument treatment */ - varflag = 0; - argc = 0; - - for (i = 0; i < vector_active(vline); i++) { - if (varflag) - argv[argc++] = vector_slot(vline, i); - else { - vector descvec = - vector_slot(matched_element->strvec, i); - - if (vector_active(descvec) == 1) { - struct desc *desc = vector_slot(descvec, 0); - - if (CMD_VARARG(desc->cmd)) - varflag = 1; - - if (varflag || CMD_VARIABLE(desc->cmd) - || CMD_OPTION(desc->cmd)) - argv[argc++] = vector_slot(vline, i); - } else - argv[argc++] = vector_slot(vline, i); - } - - if (argc >= CMD_ARGC_MAX) - return CMD_ERR_EXEED_ARGC_MAX; - } - - /* For vtysh execution. */ - if (cmd) - *cmd = matched_element; - - if (matched_element->daemon) - return CMD_SUCCESS_DAEMON; - - /* Execute matched command. */ - return (*matched_element->func) (matched_element, vty, argc, argv); -} - -int -cmd_execute_command(vector vline, struct vty *vty, struct cmd_element **cmd, - int vtysh) -{ - int ret, saved_ret, tried = 0; - enum node_type onode, try_node; - - onode = try_node = vty->node; - - if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0))) { - vector shifted_vline; - unsigned int index; - - vty->node = ENABLE_NODE; - /* We can try it on enable node, cos' the vty is authenticated */ - - shifted_vline = vector_init(vector_count(vline)); - /* use memcpy? */ - for (index = 1; index < vector_active(vline); index++) { - vector_set_index(shifted_vline, index - 1, - vector_lookup(vline, index)); - } - - ret = cmd_execute_command_real(shifted_vline, vty, cmd); - - vector_free(shifted_vline); - vty->node = onode; - return ret; - } - - saved_ret = ret = cmd_execute_command_real(vline, vty, cmd); - - if (vtysh) - return saved_ret; - - /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */ - while (ret != CMD_SUCCESS && ret != CMD_WARNING - && vty->node > CONFIG_NODE) { - try_node = node_parent(try_node); - vty->node = try_node; - ret = cmd_execute_command_real(vline, vty, cmd); - tried = 1; - if (ret == CMD_SUCCESS || ret == CMD_WARNING) { - /* succesfull command, leave the node as is */ - return ret; - } - } - /* no command succeeded, reset the vty to the original node and - return the error for this node */ - if (tried) - vty->node = onode; - return saved_ret; -} - -/* Execute command by argument readline. */ -int -cmd_execute_command_strict(vector vline, struct vty *vty, - struct cmd_element **cmd) -{ - unsigned int i; - unsigned int index; - vector cmd_vector; - struct cmd_element *cmd_element; - struct cmd_element *matched_element; - unsigned int matched_count, incomplete_count; - int argc; - const char *argv[CMD_ARGC_MAX]; - int varflag; - enum match_type match = 0; - char *command; - - /* Make copy of command element */ - cmd_vector = vector_copy(cmd_node_vector(cmdvec, vty->node)); - - for (index = 0; index < vector_active(vline); index++) - if ((command = vector_slot(vline, index))) { - int ret; - - match = cmd_filter_by_string(vector_slot(vline, index), - cmd_vector, index); - - /* If command meets '.VARARG' then finish matching. */ - if (match == vararg_match) - break; - - ret = - is_cmd_ambiguous(command, cmd_vector, index, match); - if (ret == 1) { - vector_free(cmd_vector); - return CMD_ERR_AMBIGUOUS; - } - if (ret == 2) { - vector_free(cmd_vector); - return CMD_ERR_NO_MATCH; - } - } - - /* Check matched count. */ - matched_element = NULL; - matched_count = 0; - incomplete_count = 0; - for (i = 0; i < vector_active(cmd_vector); i++) - if (vector_slot(cmd_vector, i) != NULL) { - cmd_element = vector_slot(cmd_vector, i); - - if (match == vararg_match - || index >= cmd_element->cmdsize) { - matched_element = cmd_element; - matched_count++; - } else - incomplete_count++; - } - - /* Finish of using cmd_vector. */ - vector_free(cmd_vector); - - /* To execute command, matched_count must be 1. */ - if (matched_count == 0) { - if (incomplete_count) - return CMD_ERR_INCOMPLETE; - else - return CMD_ERR_NO_MATCH; - } - - if (matched_count > 1) - return CMD_ERR_AMBIGUOUS; - - /* Argument treatment */ - varflag = 0; - argc = 0; - - for (i = 0; i < vector_active(vline); i++) { - if (varflag) - argv[argc++] = vector_slot(vline, i); - else { - vector descvec = - vector_slot(matched_element->strvec, i); - - if (vector_active(descvec) == 1) { - struct desc *desc = vector_slot(descvec, 0); - - if (CMD_VARARG(desc->cmd)) - varflag = 1; - - if (varflag || CMD_VARIABLE(desc->cmd) - || CMD_OPTION(desc->cmd)) - argv[argc++] = vector_slot(vline, i); - } else - argv[argc++] = vector_slot(vline, i); - } - - if (argc >= CMD_ARGC_MAX) - return CMD_ERR_EXEED_ARGC_MAX; - } - - /* For vtysh execution. */ - if (cmd) - *cmd = matched_element; - - if (matched_element->daemon) - return CMD_SUCCESS_DAEMON; - - /* Now execute matched command */ - return (*matched_element->func) (matched_element, vty, argc, argv); -} - -#if 0 -/* Configration make from file. */ -int config_from_file(struct vty *vty, FILE * fp) -{ - int ret; - vector vline; - - while (fgets(vty->buf, VTY_BUFSIZ, fp)) { - vline = cmd_make_strvec(vty->buf); - - /* In case of comment line */ - if (vline == NULL) - continue; - /* Execute configuration command : this is strict match */ - ret = cmd_execute_command_strict(vline, vty, NULL); - - /* Try again with setting node to CONFIG_NODE */ - while (ret != CMD_SUCCESS && ret != CMD_WARNING - && ret != CMD_ERR_NOTHING_TODO - && vty->node != CONFIG_NODE) { - vty->node = node_parent(vty->node); - ret = cmd_execute_command_strict(vline, vty, NULL); - } - - cmd_free_strvec(vline); - - if (ret != CMD_SUCCESS && ret != CMD_WARNING - && ret != CMD_ERR_NOTHING_TODO) - return ret; - } - return CMD_SUCCESS; -} -#endif - -/* Configration from terminal */ -DEFUN(config_terminal, - config_terminal_cmd, - "configure terminal", - "Configuration from vty interface\n" "Configuration terminal\n") -{ - if (vty_config_lock(vty)) - vty->node = CONFIG_NODE; - else { - vty_out(vty, "VTY configuration is locked by other VTY%s", - VTY_NEWLINE); - return CMD_WARNING; - } - return CMD_SUCCESS; -} - -/* Enable command */ -DEFUN(enable, config_enable_cmd, "enable", "Turn on privileged mode command\n") -{ - /* If enable password is NULL, change to ENABLE_NODE */ - if ((host.enable == NULL && host.enable_encrypt == NULL) || - vty->type == VTY_SHELL_SERV) - vty->node = ENABLE_NODE; - else - vty->node = AUTH_ENABLE_NODE; - - return CMD_SUCCESS; -} - -/* Disable command */ -DEFUN(disable, - config_disable_cmd, "disable", "Turn off privileged mode command\n") -{ - if (vty->node == ENABLE_NODE) - vty->node = VIEW_NODE; - return CMD_SUCCESS; -} - -/* Down vty node level. */ -DEFUN(config_exit, - config_exit_cmd, "exit", "Exit current mode and down to previous mode\n") -{ - switch (vty->node) { - case RC632_NODE: - vty->node = VIEW_NODE; - break; - case VIEW_NODE: - case ENABLE_NODE: - if (0) //vty_shell (vty)) - exit(0); - else - vty->status = VTY_CLOSE; - break; - case CONFIG_NODE: - vty->node = ENABLE_NODE; - vty_config_unlock(vty); - break; - case INTERFACE_NODE: - case ZEBRA_NODE: - case BGP_NODE: - case RIP_NODE: - case RIPNG_NODE: - case OSPF_NODE: - case OSPF6_NODE: - case ISIS_NODE: - case KEYCHAIN_NODE: - case MASC_NODE: - case RMAP_NODE: - case VTY_NODE: - vty->node = CONFIG_NODE; - break; - case BGP_VPNV4_NODE: - case BGP_IPV4_NODE: - case BGP_IPV4M_NODE: - case BGP_IPV6_NODE: - vty->node = BGP_NODE; - break; - case KEYCHAIN_KEY_NODE: - vty->node = KEYCHAIN_NODE; - break; - default: - break; - } - return CMD_SUCCESS; -} - -/* quit is alias of exit. */ -ALIAS(config_exit, - config_quit_cmd, "quit", "Exit current mode and down to previous mode\n") - -/* End of configuration. */ - DEFUN(config_end, - config_end_cmd, "end", "End current mode and change to enable mode.") -{ - switch (vty->node) { - case VIEW_NODE: - case ENABLE_NODE: - /* Nothing to do. */ - break; - case CONFIG_NODE: - case INTERFACE_NODE: - case ZEBRA_NODE: - case RIP_NODE: - case RIPNG_NODE: - case BGP_NODE: - case BGP_VPNV4_NODE: - case BGP_IPV4_NODE: - case BGP_IPV4M_NODE: - case BGP_IPV6_NODE: - case RMAP_NODE: - case OSPF_NODE: - case OSPF6_NODE: - case ISIS_NODE: - case KEYCHAIN_NODE: - case KEYCHAIN_KEY_NODE: - case MASC_NODE: - case VTY_NODE: - vty_config_unlock(vty); - vty->node = ENABLE_NODE; - break; - default: - break; - } - return CMD_SUCCESS; -} - -/* Show version. */ -DEFUN(show_version, - show_version_cmd, "show version", SHOW_STR "Displays program version\n") -{ - vty_out(vty, "%s %s (%s).%s", QUAGGA_PROGNAME, QUAGGA_VERSION, - host.name ? host.name : "", VTY_NEWLINE); - vty_out(vty, "%s%s", QUAGGA_COPYRIGHT, VTY_NEWLINE); - - return CMD_SUCCESS; -} - -/* Help display function for all node. */ -DEFUN(config_help, - config_help_cmd, "help", "Description of the interactive help system\n") -{ - vty_out(vty, - "This VTY provides advanced help features. When you need help,%s\ -anytime at the command line please press '?'.%s\ -%s\ -If nothing matches, the help list will be empty and you must backup%s\ - until entering a '?' shows the available options.%s\ -Two styles of help are provided:%s\ -1. Full help is available when you are ready to enter a%s\ -command argument (e.g. 'show ?') and describes each possible%s\ -argument.%s\ -2. Partial help is provided when an abbreviated argument is entered%s\ - and you want to know what arguments match the input%s\ - (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, - VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); - return CMD_SUCCESS; -} - -/* Help display function for all node. */ -DEFUN(config_list, config_list_cmd, "list", "Print command list\n") -{ - unsigned int i; - struct cmd_node *cnode = vector_slot(cmdvec, vty->node); - struct cmd_element *cmd; - - for (i = 0; i < vector_active(cnode->cmd_vector); i++) - if ((cmd = vector_slot(cnode->cmd_vector, i)) != NULL - && !(cmd->attr == CMD_ATTR_DEPRECATED - || cmd->attr == CMD_ATTR_HIDDEN)) - vty_out(vty, " %s%s", cmd->string, VTY_NEWLINE); - return CMD_SUCCESS; -} - -#if 0 -/* Write current configuration into file. */ -DEFUN(config_write_file, - config_write_file_cmd, - "write file", - "Write running configuration to memory, network, or terminal\n" - "Write to configuration file\n") -{ - unsigned int i; - int fd; - struct cmd_node *node; - char *config_file; - char *config_file_tmp = NULL; - char *config_file_sav = NULL; - struct vty *file_vty; - - /* Check and see if we are operating under vtysh configuration */ - if (host.config == NULL) { - vty_out(vty, "Can't save to configuration file, using vtysh.%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - /* Get filename. */ - config_file = host.config; - - config_file_sav = - malloc(strlen(config_file) + strlen(CONF_BACKUP_EXT) + 1); - strcpy(config_file_sav, config_file); - strcat(config_file_sav, CONF_BACKUP_EXT); - - config_file_tmp = malloc(strlen(config_file) + 8); - sprintf(config_file_tmp, "%s.XXXXXX", config_file); - - /* Open file to configuration write. */ - fd = mkstemp(config_file_tmp); - if (fd < 0) { - vty_out(vty, "Can't open configuration file %s.%s", - config_file_tmp, VTY_NEWLINE); - free(config_file_tmp); - free(config_file_sav); - return CMD_WARNING; - } - - /* Make vty for configuration file. */ - file_vty = vty_new(); - file_vty->fd = fd; - file_vty->type = VTY_FILE; - - /* Config file header print. */ - vty_out(file_vty, "!\n! Zebra configuration saved from vty\n! "); - //vty_time_print (file_vty, 1); - vty_out(file_vty, "!\n"); - - for (i = 0; i < vector_active(cmdvec); i++) - if ((node = vector_slot(cmdvec, i)) && node->func) { - if ((*node->func) (file_vty)) - vty_out(file_vty, "!\n"); - } - vty_close(file_vty); - - if (unlink(config_file_sav) != 0) - if (errno != ENOENT) { - vty_out(vty, - "Can't unlink backup configuration file %s.%s", - config_file_sav, VTY_NEWLINE); - free(config_file_sav); - free(config_file_tmp); - unlink(config_file_tmp); - return CMD_WARNING; - } - if (link(config_file, config_file_sav) != 0) { - vty_out(vty, "Can't backup old configuration file %s.%s", - config_file_sav, VTY_NEWLINE); - free(config_file_sav); - free(config_file_tmp); - unlink(config_file_tmp); - return CMD_WARNING; - } - sync(); - if (unlink(config_file) != 0) { - vty_out(vty, "Can't unlink configuration file %s.%s", - config_file, VTY_NEWLINE); - free(config_file_sav); - free(config_file_tmp); - unlink(config_file_tmp); - return CMD_WARNING; - } - if (link(config_file_tmp, config_file) != 0) { - vty_out(vty, "Can't save configuration file %s.%s", config_file, - VTY_NEWLINE); - free(config_file_sav); - free(config_file_tmp); - unlink(config_file_tmp); - return CMD_WARNING; - } - unlink(config_file_tmp); - sync(); - - free(config_file_sav); - free(config_file_tmp); - - if (chmod(config_file, CONFIGFILE_MASK) != 0) { - vty_out(vty, "Can't chmod configuration file %s: %s (%d).%s", - config_file, safe_strerror(errno), errno, VTY_NEWLINE); - return CMD_WARNING; - } - - vty_out(vty, "Configuration saved to %s%s", config_file, VTY_NEWLINE); - return CMD_SUCCESS; -} - -ALIAS(config_write_file, - config_write_cmd, - "write", "Write running configuration to memory, network, or terminal\n") - - ALIAS(config_write_file, - config_write_memory_cmd, - "write memory", - "Write running configuration to memory, network, or terminal\n" - "Write configuration to the file (same as write file)\n") - - ALIAS(config_write_file, - copy_runningconfig_startupconfig_cmd, - "copy running-config startup-config", - "Copy configuration\n" - "Copy running config to... \n" - "Copy running config to startup config (same as write file)\n") - -/* Write current configuration into the terminal. */ - DEFUN(config_write_terminal, - config_write_terminal_cmd, - "write terminal", - "Write running configuration to memory, network, or terminal\n" - "Write to terminal\n") -{ - unsigned int i; - struct cmd_node *node; - - if (vty->type == VTY_SHELL_SERV) { - for (i = 0; i < vector_active(cmdvec); i++) - if ((node = vector_slot(cmdvec, i)) && node->func - && node->vtysh) { - if ((*node->func) (vty)) - vty_out(vty, "!%s", VTY_NEWLINE); - } - } else { - vty_out(vty, "%sCurrent configuration:%s", VTY_NEWLINE, - VTY_NEWLINE); - vty_out(vty, "!%s", VTY_NEWLINE); - - for (i = 0; i < vector_active(cmdvec); i++) - if ((node = vector_slot(cmdvec, i)) && node->func) { - if ((*node->func) (vty)) - vty_out(vty, "!%s", VTY_NEWLINE); - } - vty_out(vty, "end%s", VTY_NEWLINE); - } - return CMD_SUCCESS; -} - -/* Write current configuration into the terminal. */ -ALIAS(config_write_terminal, - show_running_config_cmd, - "show running-config", SHOW_STR "running configuration\n") - -/* Write startup configuration into the terminal. */ - DEFUN(show_startup_config, - show_startup_config_cmd, - "show startup-config", SHOW_STR "Contentes of startup configuration\n") -{ - char buf[BUFSIZ]; - FILE *confp; - - confp = fopen(host.config, "r"); - if (confp == NULL) { - vty_out(vty, "Can't open configuration file [%s]%s", - host.config, VTY_NEWLINE); - return CMD_WARNING; - } - - while (fgets(buf, BUFSIZ, confp)) { - char *cp = buf; - - while (*cp != '\r' && *cp != '\n' && *cp != '\0') - cp++; - *cp = '\0'; - - vty_out(vty, "%s%s", buf, VTY_NEWLINE); - } - - fclose(confp); - - return CMD_SUCCESS; -} -#endif - -/* Hostname configuration */ -DEFUN(config_hostname, - hostname_cmd, - "hostname WORD", - "Set system's network name\n" "This system's network name\n") -{ - if (!isalpha((int)*argv[0])) { - vty_out(vty, "Please specify string starting with alphabet%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - if (host.name) - free(host.name); - - host.name = strdup(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(config_no_hostname, - no_hostname_cmd, - "no hostname [HOSTNAME]", - NO_STR "Reset system's network name\n" "Host name of this router\n") -{ - if (host.name) - free(host.name); - host.name = NULL; - return CMD_SUCCESS; -} - -/* VTY interface password set. */ -DEFUN(config_password, password_cmd, - "password (8|) WORD", - "Assign the terminal connection password\n" - "Specifies a HIDDEN password will follow\n" - "dummy string \n" "The HIDDEN line password string\n") -{ - /* Argument check. */ - if (argc == 0) { - vty_out(vty, "Please specify password.%s", VTY_NEWLINE); - return CMD_WARNING; - } - - if (argc == 2) { - if (*argv[0] == '8') { - if (host.password) - free(host.password); - host.password = NULL; - if (host.password_encrypt) - free(host.password_encrypt); - host.password_encrypt = strdup(strdup(argv[1])); - return CMD_SUCCESS; - } else { - vty_out(vty, "Unknown encryption type.%s", VTY_NEWLINE); - return CMD_WARNING; - } - } - - if (!isalnum((int)*argv[0])) { - vty_out(vty, - "Please specify string starting with alphanumeric%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - if (host.password) - free(host.password); - host.password = NULL; - - if (host.encrypt) { - if (host.password_encrypt) - free(host.password_encrypt); - host.password_encrypt = strdup(zencrypt(argv[0])); - } else - host.password = strdup(argv[0]); - - return CMD_SUCCESS; -} - -ALIAS(config_password, password_text_cmd, - "password LINE", - "Assign the terminal connection password\n" - "The UNENCRYPTED (cleartext) line password\n") - -/* VTY enable password set. */ - DEFUN(config_enable_password, enable_password_cmd, - "enable password (8|) WORD", - "Modify enable password parameters\n" - "Assign the privileged level password\n" - "Specifies a HIDDEN password will follow\n" - "dummy string \n" "The HIDDEN 'enable' password string\n") -{ - /* Argument check. */ - if (argc == 0) { - vty_out(vty, "Please specify password.%s", VTY_NEWLINE); - return CMD_WARNING; - } - - /* Crypt type is specified. */ - if (argc == 2) { - if (*argv[0] == '8') { - if (host.enable) - free(host.enable); - host.enable = NULL; - - if (host.enable_encrypt) - free(host.enable_encrypt); - host.enable_encrypt = strdup(argv[1]); - - return CMD_SUCCESS; - } else { - vty_out(vty, "Unknown encryption type.%s", VTY_NEWLINE); - return CMD_WARNING; - } - } - - if (!isalnum((int)*argv[0])) { - vty_out(vty, - "Please specify string starting with alphanumeric%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - if (host.enable) - free(host.enable); - host.enable = NULL; - - /* Plain password input. */ - if (host.encrypt) { - if (host.enable_encrypt) - free(host.enable_encrypt); - host.enable_encrypt = strdup(zencrypt(argv[0])); - } else - host.enable = strdup(argv[0]); - - return CMD_SUCCESS; -} - -ALIAS(config_enable_password, - enable_password_text_cmd, - "enable password LINE", - "Modify enable password parameters\n" - "Assign the privileged level password\n" - "The UNENCRYPTED (cleartext) 'enable' password\n") - -/* VTY enable password delete. */ - DEFUN(no_config_enable_password, no_enable_password_cmd, - "no enable password", - NO_STR - "Modify enable password parameters\n" - "Assign the privileged level password\n") -{ - if (host.enable) - free(host.enable); - host.enable = NULL; - - if (host.enable_encrypt) - free(host.enable_encrypt); - host.enable_encrypt = NULL; - - return CMD_SUCCESS; -} - -DEFUN(service_password_encrypt, - service_password_encrypt_cmd, - "service password-encryption", - "Set up miscellaneous service\n" "Enable encrypted passwords\n") -{ - if (host.encrypt) - return CMD_SUCCESS; - - host.encrypt = 1; - - if (host.password) { - if (host.password_encrypt) - free(host.password_encrypt); - host.password_encrypt = strdup(zencrypt(host.password)); - } - if (host.enable) { - if (host.enable_encrypt) - free(host.enable_encrypt); - host.enable_encrypt = strdup(zencrypt(host.enable)); - } - - return CMD_SUCCESS; -} - -DEFUN(no_service_password_encrypt, - no_service_password_encrypt_cmd, - "no service password-encryption", - NO_STR "Set up miscellaneous service\n" "Enable encrypted passwords\n") -{ - if (!host.encrypt) - return CMD_SUCCESS; - - host.encrypt = 0; - - if (host.password_encrypt) - free(host.password_encrypt); - host.password_encrypt = NULL; - - if (host.enable_encrypt) - free(host.enable_encrypt); - host.enable_encrypt = NULL; - - return CMD_SUCCESS; -} - -DEFUN(config_terminal_length, config_terminal_length_cmd, - "terminal length <0-512>", - "Set terminal line parameters\n" - "Set number of lines on a screen\n" - "Number of lines on screen (0 for no pausing)\n") -{ - int lines; - char *endptr = NULL; - - lines = strtol(argv[0], &endptr, 10); - if (lines < 0 || lines > 512 || *endptr != '\0') { - vty_out(vty, "length is malformed%s", VTY_NEWLINE); - return CMD_WARNING; - } - vty->lines = lines; - - return CMD_SUCCESS; -} - -DEFUN(config_terminal_no_length, config_terminal_no_length_cmd, - "terminal no length", - "Set terminal line parameters\n" - NO_STR "Set number of lines on a screen\n") -{ - vty->lines = -1; - return CMD_SUCCESS; -} - -DEFUN(service_terminal_length, service_terminal_length_cmd, - "service terminal-length <0-512>", - "Set up miscellaneous service\n" - "System wide terminal length configuration\n" - "Number of lines of VTY (0 means no line control)\n") -{ - int lines; - char *endptr = NULL; - - lines = strtol(argv[0], &endptr, 10); - if (lines < 0 || lines > 512 || *endptr != '\0') { - vty_out(vty, "length is malformed%s", VTY_NEWLINE); - return CMD_WARNING; - } - host.lines = lines; - - return CMD_SUCCESS; -} - -DEFUN(no_service_terminal_length, no_service_terminal_length_cmd, - "no service terminal-length [<0-512>]", - NO_STR - "Set up miscellaneous service\n" - "System wide terminal length configuration\n" - "Number of lines of VTY (0 means no line control)\n") -{ - host.lines = -1; - return CMD_SUCCESS; -} - -DEFUN_HIDDEN(do_echo, - echo_cmd, - "echo .MESSAGE", - "Echo a message back to the vty\n" "The message to echo\n") -{ - char *message; - - vty_out(vty, "%s%s", - ((message = - argv_concat(argv, argc, 0)) ? message : ""), VTY_NEWLINE); - if (message) - free(message); - return CMD_SUCCESS; -} - -#if 0 -DEFUN(config_logmsg, - config_logmsg_cmd, - "logmsg " LOG_LEVELS " .MESSAGE", - "Send a message to enabled logging destinations\n" - LOG_LEVEL_DESC "The message to send\n") -{ - int level; - char *message; - - if ((level = level_match(argv[0])) == ZLOG_DISABLED) - return CMD_ERR_NO_MATCH; - - zlog(NULL, level, - ((message = argv_concat(argv, argc, 1)) ? message : "")); - if (message) - free(message); - return CMD_SUCCESS; -} - -DEFUN(show_logging, - show_logging_cmd, - "show logging", SHOW_STR "Show current logging configuration\n") -{ - struct zlog *zl = zlog_default; - - vty_out(vty, "Syslog logging: "); - if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED) - vty_out(vty, "disabled"); - else - vty_out(vty, "level %s, facility %s, ident %s", - zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]], - facility_name(zl->facility), zl->ident); - vty_out(vty, "%s", VTY_NEWLINE); - - vty_out(vty, "Stdout logging: "); - if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED) - vty_out(vty, "disabled"); - else - vty_out(vty, "level %s", - zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]); - vty_out(vty, "%s", VTY_NEWLINE); - - vty_out(vty, "Monitor logging: "); - if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED) - vty_out(vty, "disabled"); - else - vty_out(vty, "level %s", - zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]); - vty_out(vty, "%s", VTY_NEWLINE); - - vty_out(vty, "File logging: "); - if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) || !zl->fp) - vty_out(vty, "disabled"); - else - vty_out(vty, "level %s, filename %s", - zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]], - zl->filename); - vty_out(vty, "%s", VTY_NEWLINE); - - vty_out(vty, "Protocol name: %s%s", - zlog_proto_names[zl->protocol], VTY_NEWLINE); - vty_out(vty, "Record priority: %s%s", - (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE); - - return CMD_SUCCESS; -} - -DEFUN(config_log_stdout, - config_log_stdout_cmd, - "log stdout", "Logging control\n" "Set stdout logging level\n") -{ - zlog_set_level(NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl); - return CMD_SUCCESS; -} - -DEFUN(config_log_stdout_level, - config_log_stdout_level_cmd, - "log stdout " LOG_LEVELS, - "Logging control\n" "Set stdout logging level\n" LOG_LEVEL_DESC) -{ - int level; - - if ((level = level_match(argv[0])) == ZLOG_DISABLED) - return CMD_ERR_NO_MATCH; - zlog_set_level(NULL, ZLOG_DEST_STDOUT, level); - return CMD_SUCCESS; -} - -DEFUN(no_config_log_stdout, - no_config_log_stdout_cmd, - "no log stdout [LEVEL]", - NO_STR "Logging control\n" "Cancel logging to stdout\n" "Logging level\n") -{ - zlog_set_level(NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED); - return CMD_SUCCESS; -} - -DEFUN(config_log_monitor, - config_log_monitor_cmd, - "log monitor", - "Logging control\n" "Set terminal line (monitor) logging level\n") -{ - zlog_set_level(NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl); - return CMD_SUCCESS; -} - -DEFUN(config_log_monitor_level, - config_log_monitor_level_cmd, - "log monitor " LOG_LEVELS, - "Logging control\n" - "Set terminal line (monitor) logging level\n" LOG_LEVEL_DESC) -{ - int level; - - if ((level = level_match(argv[0])) == ZLOG_DISABLED) - return CMD_ERR_NO_MATCH; - zlog_set_level(NULL, ZLOG_DEST_MONITOR, level); - return CMD_SUCCESS; -} - -DEFUN(no_config_log_monitor, - no_config_log_monitor_cmd, - "no log monitor [LEVEL]", - NO_STR - "Logging control\n" - "Disable terminal line (monitor) logging\n" "Logging level\n") -{ - zlog_set_level(NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED); - return CMD_SUCCESS; -} - -static int set_log_file(struct vty *vty, const char *fname, int loglevel) -{ - int ret; - char *p = NULL; - const char *fullpath; - - /* Path detection. */ - if (!IS_DIRECTORY_SEP(*fname)) { - char cwd[MAXPATHLEN + 1]; - cwd[MAXPATHLEN] = '\0'; - - if (getcwd(cwd, MAXPATHLEN) == NULL) { - zlog_err("config_log_file: Unable to alloc mem!"); - return CMD_WARNING; - } - - if ((p = malloc(strlen(cwd) + strlen(fname) + 2)) - == NULL) { - zlog_err("config_log_file: Unable to alloc mem!"); - return CMD_WARNING; - } - sprintf(p, "%s/%s", cwd, fname); - fullpath = p; - } else - fullpath = fname; - - ret = zlog_set_file(NULL, fullpath, loglevel); - - if (p) - free(p); - - if (!ret) { - vty_out(vty, "can't open logfile %s\n", fname); - return CMD_WARNING; - } - - if (host.logfile) - free(host.logfile); - - host.logfile = strdup(fname); - - return CMD_SUCCESS; -} - -DEFUN(config_log_file, - config_log_file_cmd, - "log file FILENAME", - "Logging control\n" "Logging to file\n" "Logging filename\n") -{ - return set_log_file(vty, argv[0], zlog_default->default_lvl); -} - -DEFUN(config_log_file_level, - config_log_file_level_cmd, - "log file FILENAME " LOG_LEVELS, - "Logging control\n" - "Logging to file\n" "Logging filename\n" LOG_LEVEL_DESC) -{ - int level; - - if ((level = level_match(argv[1])) == ZLOG_DISABLED) - return CMD_ERR_NO_MATCH; - return set_log_file(vty, argv[0], level); -} - -DEFUN(no_config_log_file, - no_config_log_file_cmd, - "no log file [FILENAME]", - NO_STR - "Logging control\n" "Cancel logging to file\n" "Logging file name\n") -{ - zlog_reset_file(NULL); - - if (host.logfile) - free(host.logfile); - - host.logfile = NULL; - - return CMD_SUCCESS; -} - -ALIAS(no_config_log_file, - no_config_log_file_level_cmd, - "no log file FILENAME LEVEL", - NO_STR - "Logging control\n" - "Cancel logging to file\n" "Logging file name\n" "Logging level\n") - - DEFUN(config_log_syslog, - config_log_syslog_cmd, - "log syslog", "Logging control\n" "Set syslog logging level\n") -{ - zlog_set_level(NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl); - return CMD_SUCCESS; -} - -DEFUN(config_log_syslog_level, - config_log_syslog_level_cmd, - "log syslog " LOG_LEVELS, - "Logging control\n" "Set syslog logging level\n" LOG_LEVEL_DESC) -{ - int level; - - if ((level = level_match(argv[0])) == ZLOG_DISABLED) - return CMD_ERR_NO_MATCH; - zlog_set_level(NULL, ZLOG_DEST_SYSLOG, level); - return CMD_SUCCESS; -} - -DEFUN_DEPRECATED(config_log_syslog_facility, - config_log_syslog_facility_cmd, - "log syslog facility " LOG_FACILITIES, - "Logging control\n" - "Logging goes to syslog\n" - "(Deprecated) Facility parameter for syslog messages\n" - LOG_FACILITY_DESC) -{ - int facility; - - if ((facility = facility_match(argv[0])) < 0) - return CMD_ERR_NO_MATCH; - - zlog_set_level(NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl); - zlog_default->facility = facility; - return CMD_SUCCESS; -} - -DEFUN(no_config_log_syslog, - no_config_log_syslog_cmd, - "no log syslog [LEVEL]", - NO_STR "Logging control\n" "Cancel logging to syslog\n" "Logging level\n") -{ - zlog_set_level(NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED); - return CMD_SUCCESS; -} - -ALIAS(no_config_log_syslog, - no_config_log_syslog_facility_cmd, - "no log syslog facility " LOG_FACILITIES, - NO_STR - "Logging control\n" - "Logging goes to syslog\n" - "Facility parameter for syslog messages\n" LOG_FACILITY_DESC) - - DEFUN(config_log_facility, - config_log_facility_cmd, - "log facility " LOG_FACILITIES, - "Logging control\n" - "Facility parameter for syslog messages\n" LOG_FACILITY_DESC) -{ - int facility; - - if ((facility = facility_match(argv[0])) < 0) - return CMD_ERR_NO_MATCH; - zlog_default->facility = facility; - return CMD_SUCCESS; -} - -DEFUN(no_config_log_facility, - no_config_log_facility_cmd, - "no log facility [FACILITY]", - NO_STR - "Logging control\n" - "Reset syslog facility to default (daemon)\n" "Syslog facility\n") -{ - zlog_default->facility = LOG_DAEMON; - return CMD_SUCCESS; -} - -DEFUN_DEPRECATED(config_log_trap, - config_log_trap_cmd, - "log trap " LOG_LEVELS, - "Logging control\n" - "(Deprecated) Set logging level and default for all destinations\n" - LOG_LEVEL_DESC) -{ - int new_level; - int i; - - if ((new_level = level_match(argv[0])) == ZLOG_DISABLED) - return CMD_ERR_NO_MATCH; - - zlog_default->default_lvl = new_level; - for (i = 0; i < ZLOG_NUM_DESTS; i++) - if (zlog_default->maxlvl[i] != ZLOG_DISABLED) - zlog_default->maxlvl[i] = new_level; - return CMD_SUCCESS; -} - -DEFUN_DEPRECATED(no_config_log_trap, - no_config_log_trap_cmd, - "no log trap [LEVEL]", - NO_STR - "Logging control\n" - "Permit all logging information\n" "Logging level\n") -{ - zlog_default->default_lvl = LOG_DEBUG; - return CMD_SUCCESS; -} - -DEFUN(config_log_record_priority, - config_log_record_priority_cmd, - "log record-priority", - "Logging control\n" - "Log the priority of the message within the message\n") -{ - zlog_default->record_priority = 1; - return CMD_SUCCESS; -} - -DEFUN(no_config_log_record_priority, - no_config_log_record_priority_cmd, - "no log record-priority", - NO_STR - "Logging control\n" - "Do not log the priority of the message within the message\n") -{ - zlog_default->record_priority = 0; - return CMD_SUCCESS; -} -#endif - -DEFUN(banner_motd_file, - banner_motd_file_cmd, - "banner motd file [FILE]", - "Set banner\n" "Banner for motd\n" "Banner from a file\n" "Filename\n") -{ - if (host.motdfile) - free(host.motdfile); - host.motdfile = strdup(argv[0]); - - return CMD_SUCCESS; -} - -DEFUN(banner_motd_default, - banner_motd_default_cmd, - "banner motd default", - "Set banner string\n" "Strings for motd\n" "Default string\n") -{ - host.motd = default_motd; - return CMD_SUCCESS; -} - -DEFUN(no_banner_motd, - no_banner_motd_cmd, - "no banner motd", NO_STR "Set banner string\n" "Strings for motd\n") -{ - host.motd = NULL; - if (host.motdfile) - free(host.motdfile); - host.motdfile = NULL; - return CMD_SUCCESS; -} - -/* Set config filename. Called from vty.c */ -void host_config_set(char *filename) -{ - host.config = strdup(filename); -} - -void install_default(enum node_type node) -{ - install_element(node, &config_exit_cmd); - install_element(node, &config_quit_cmd); - install_element(node, &config_end_cmd); - install_element(node, &config_help_cmd); - install_element(node, &config_list_cmd); - -#if 0 - install_element(node, &config_write_terminal_cmd); - install_element(node, &config_write_file_cmd); - install_element(node, &config_write_memory_cmd); - install_element(node, &config_write_cmd); - install_element(node, &show_running_config_cmd); -#endif -} - -/* Initialize command interface. Install basic nodes and commands. */ -void cmd_init(int terminal) -{ - /* Allocate initial top vector of commands. */ - cmdvec = vector_init(VECTOR_MIN_SIZE); - - /* Default host value settings. */ - host.name = NULL; - //host.password = NULL; - host.password = "foo"; - host.enable = NULL; - host.logfile = NULL; - host.config = NULL; - host.lines = -1; - host.motd = default_motd; - host.motdfile = NULL; - - /* Install top nodes. */ - install_node(&view_node, NULL); - install_node(&enable_node, NULL); - install_node(&auth_node, NULL); - install_node(&auth_enable_node, NULL); - install_node(&config_node, config_write_host); - - /* Each node's basic commands. */ - install_element(VIEW_NODE, &show_version_cmd); - if (terminal) { - install_element(VIEW_NODE, &config_list_cmd); - install_element(VIEW_NODE, &config_exit_cmd); - install_element(VIEW_NODE, &config_quit_cmd); - install_element(VIEW_NODE, &config_help_cmd); - install_element(VIEW_NODE, &config_enable_cmd); - install_element(VIEW_NODE, &config_terminal_length_cmd); - install_element(VIEW_NODE, &config_terminal_no_length_cmd); - install_element(VIEW_NODE, &echo_cmd); - } - - if (terminal) { - install_default(ENABLE_NODE); - install_element(ENABLE_NODE, &config_disable_cmd); - install_element(ENABLE_NODE, &config_terminal_cmd); - //install_element (ENABLE_NODE, ©_runningconfig_startupconfig_cmd); - } - //install_element (ENABLE_NODE, &show_startup_config_cmd); - install_element(ENABLE_NODE, &show_version_cmd); - - if (terminal) { - install_element(ENABLE_NODE, &config_terminal_length_cmd); - install_element(ENABLE_NODE, &config_terminal_no_length_cmd); - install_element(ENABLE_NODE, &echo_cmd); - - install_default(CONFIG_NODE); - } - - install_element(CONFIG_NODE, &hostname_cmd); - install_element(CONFIG_NODE, &no_hostname_cmd); - - if (terminal) { - install_element(CONFIG_NODE, &password_cmd); - install_element(CONFIG_NODE, &password_text_cmd); - install_element(CONFIG_NODE, &enable_password_cmd); - install_element(CONFIG_NODE, &enable_password_text_cmd); - install_element(CONFIG_NODE, &no_enable_password_cmd); - - install_element(CONFIG_NODE, &service_password_encrypt_cmd); - install_element(CONFIG_NODE, &no_service_password_encrypt_cmd); - install_element(CONFIG_NODE, &banner_motd_default_cmd); - install_element(CONFIG_NODE, &banner_motd_file_cmd); - install_element(CONFIG_NODE, &no_banner_motd_cmd); - install_element(CONFIG_NODE, &service_terminal_length_cmd); - install_element(CONFIG_NODE, &no_service_terminal_length_cmd); - - } - srand(time(NULL)); -} diff --git a/openpcd/opcd_test/zebvty/command.h b/openpcd/opcd_test/zebvty/command.h deleted file mode 100644 index 5b79da4..0000000 --- a/openpcd/opcd_test/zebvty/command.h +++ /dev/null @@ -1,351 +0,0 @@ -/* - * Zebra configuration command interface routine - * Copyright (C) 1997, 98 Kunihiro Ishiguro - * - * This file is part of GNU Zebra. - * - * GNU Zebra 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. - * - * GNU Zebra 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. - */ - -#ifndef _ZEBRA_COMMAND_H -#define _ZEBRA_COMMAND_H - -#include -#include "vector.h" -#include "vty.h" - -/* Host configuration variable */ -struct host { - /* Host name of this router. */ - char *name; - - /* Password for vty interface. */ - char *password; - char *password_encrypt; - - /* Enable password */ - char *enable; - char *enable_encrypt; - - /* System wide terminal lines. */ - int lines; - - /* Log filename. */ - char *logfile; - - /* config file name of this host */ - char *config; - - /* Flags for services */ - int advanced; - int encrypt; - - /* Banner configuration. */ - const char *motd; - char *motdfile; -}; - -/* There are some command levels which called from command node. */ -enum node_type { - RC632_NODE, - - AUTH_NODE, /* Authentication mode of vty interface. */ - VIEW_NODE, /* View node. Default mode of vty interface. */ - AUTH_ENABLE_NODE, /* Authentication mode for change enable. */ - ENABLE_NODE, /* Enable node. */ - CONFIG_NODE, /* Config node. Default mode of config file. */ - SERVICE_NODE, /* Service node. */ - DEBUG_NODE, /* Debug node. */ - AAA_NODE, /* AAA node. */ - KEYCHAIN_NODE, /* Key-chain node. */ - KEYCHAIN_KEY_NODE, /* Key-chain key node. */ - INTERFACE_NODE, /* Interface mode node. */ - ZEBRA_NODE, /* zebra connection node. */ - TABLE_NODE, /* rtm_table selection node. */ - RIP_NODE, /* RIP protocol mode node. */ - RIPNG_NODE, /* RIPng protocol mode node. */ - BGP_NODE, /* BGP protocol mode which includes BGP4+ */ - BGP_VPNV4_NODE, /* BGP MPLS-VPN PE exchange. */ - BGP_IPV4_NODE, /* BGP IPv4 unicast address family. */ - BGP_IPV4M_NODE, /* BGP IPv4 multicast address family. */ - BGP_IPV6_NODE, /* BGP IPv6 address family */ - OSPF_NODE, /* OSPF protocol mode */ - OSPF6_NODE, /* OSPF protocol for IPv6 mode */ - ISIS_NODE, /* ISIS protocol mode */ - MASC_NODE, /* MASC for multicast. */ - IRDP_NODE, /* ICMP Router Discovery Protocol mode. */ - IP_NODE, /* Static ip route node. */ - ACCESS_NODE, /* Access list node. */ - PREFIX_NODE, /* Prefix list node. */ - ACCESS_IPV6_NODE, /* Access list node. */ - PREFIX_IPV6_NODE, /* Prefix list node. */ - AS_LIST_NODE, /* AS list node. */ - COMMUNITY_LIST_NODE, /* Community list node. */ - RMAP_NODE, /* Route map node. */ - SMUX_NODE, /* SNMP configuration node. */ - DUMP_NODE, /* Packet dump node. */ - FORWARDING_NODE, /* IP forwarding node. */ - VTY_NODE /* Vty node. */ -}; - -/* Node which has some commands and prompt string and configuration - function pointer . */ -struct cmd_node { - /* Node index. */ - enum node_type node; - - /* Prompt character at vty interface. */ - const char *prompt; - - /* Is this node's configuration goes to vtysh ? */ - int vtysh; - - /* Node's configuration write function */ - int (*func) (struct vty *); - - /* Vector of this node's command list. */ - vector cmd_vector; -}; - -enum { - CMD_ATTR_DEPRECATED = 1, - CMD_ATTR_HIDDEN, -}; - -/* Structure of command element. */ -struct cmd_element { - const char *string; /* Command specification by string. */ - int (*func) (struct cmd_element *, struct vty *, int, const char *[]); - const char *doc; /* Documentation of this command. */ - int daemon; /* Daemon to which this command belong. */ - vector strvec; /* Pointing out each description vector. */ - unsigned int cmdsize; /* Command index count. */ - char *config; /* Configuration string */ - vector subconfig; /* Sub configuration string */ - u_char attr; /* Command attributes */ -}; - -/* Command description structure. */ -struct desc { - const char *cmd; /* Command string. */ - const char *str; /* Command's description. */ -}; - -/* Return value of the commands. */ -#define CMD_SUCCESS 0 -#define CMD_WARNING 1 -#define CMD_ERR_NO_MATCH 2 -#define CMD_ERR_AMBIGUOUS 3 -#define CMD_ERR_INCOMPLETE 4 -#define CMD_ERR_EXEED_ARGC_MAX 5 -#define CMD_ERR_NOTHING_TODO 6 -#define CMD_COMPLETE_FULL_MATCH 7 -#define CMD_COMPLETE_MATCH 8 -#define CMD_COMPLETE_LIST_MATCH 9 -#define CMD_SUCCESS_DAEMON 10 - -/* Argc max counts. */ -#define CMD_ARGC_MAX 25 - -/* Turn off these macros when uisng cpp with extract.pl */ -#ifndef VTYSH_EXTRACT_PL - -/* helper defines for end-user DEFUN* macros */ -#define DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attrs, dnum) \ - struct cmd_element cmdname = \ - { \ - .string = cmdstr, \ - .func = funcname, \ - .doc = helpstr, \ - .attr = attrs, \ - .daemon = dnum, \ - }; - -#define DEFUN_CMD_FUNC_DECL(funcname) \ - static int funcname (struct cmd_element *, struct vty *, int, const char *[]); \ - -#define DEFUN_CMD_FUNC_TEXT(funcname) \ - static int funcname \ - (struct cmd_element *self, struct vty *vty, int argc, const char *argv[]) - -/* DEFUN for vty command interafce. Little bit hacky ;-). */ -#define DEFUN(funcname, cmdname, cmdstr, helpstr) \ - DEFUN_CMD_FUNC_DECL(funcname) \ - DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0) \ - DEFUN_CMD_FUNC_TEXT(funcname) - -#define DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \ - DEFUN_CMD_FUNC_DECL(funcname) \ - DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) \ - DEFUN_CMD_FUNC_TEXT(funcname) - -#define DEFUN_HIDDEN(funcname, cmdname, cmdstr, helpstr) \ - DEFUN_ATTR (funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN) - -#define DEFUN_DEPRECATED(funcname, cmdname, cmdstr, helpstr) \ - DEFUN_ATTR (funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED) \ - -/* DEFUN_NOSH for commands that vtysh should ignore */ -#define DEFUN_NOSH(funcname, cmdname, cmdstr, helpstr) \ - DEFUN(funcname, cmdname, cmdstr, helpstr) - -/* DEFSH for vtysh. */ -#define DEFSH(daemon, cmdname, cmdstr, helpstr) \ - DEFUN_CMD_ELEMENT(NULL, cmdname, cmdstr, helpstr, 0, daemon) \ - -/* DEFUN + DEFSH */ -#define DEFUNSH(daemon, funcname, cmdname, cmdstr, helpstr) \ - DEFUN_CMD_FUNC_DECL(funcname) \ - DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, daemon) \ - DEFUN_CMD_FUNC_TEXT(funcname) - -/* DEFUN + DEFSH with attributes */ -#define DEFUNSH_ATTR(daemon, funcname, cmdname, cmdstr, helpstr, attr) \ - DEFUN_CMD_FUNC_DECL(funcname) \ - DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, daemon) \ - DEFUN_CMD_FUNC_TEXT(funcname) - -#define DEFUNSH_HIDDEN(daemon, funcname, cmdname, cmdstr, helpstr) \ - DEFUNSH_ATTR (daemon, funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN) - -#define DEFUNSH_DEPRECATED(daemon, funcname, cmdname, cmdstr, helpstr) \ - DEFUNSH_ATTR (daemon, funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED) - -/* ALIAS macro which define existing command's alias. */ -#define ALIAS(funcname, cmdname, cmdstr, helpstr) \ - DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0) - -#define ALIAS_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \ - DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) - -#define ALIAS_HIDDEN(funcname, cmdname, cmdstr, helpstr) \ - DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN, 0) - -#define ALIAS_DEPRECATED(funcname, cmdname, cmdstr, helpstr) \ - DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED, 0) - -#define ALIAS_SH(daemon, funcname, cmdname, cmdstr, helpstr) \ - DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, daemon) - -#define ALIAS_SH_HIDDEN(daemon, funcname, cmdname, cmdstr, helpstr) \ - DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN, daemon) - -#define ALIAS_SH_DEPRECATED(daemon, funcname, cmdname, cmdstr, helpstr) \ - DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED, daemon) - -#endif /* VTYSH_EXTRACT_PL */ - -/* Some macroes */ -#define CMD_OPTION(S) ((S[0]) == '[') -#define CMD_VARIABLE(S) (((S[0]) >= 'A' && (S[0]) <= 'Z') || ((S[0]) == '<')) -#define CMD_VARARG(S) ((S[0]) == '.') -#define CMD_RANGE(S) ((S[0] == '<')) - -#define CMD_IPV4(S) ((strcmp ((S), "A.B.C.D") == 0)) -#define CMD_IPV4_PREFIX(S) ((strcmp ((S), "A.B.C.D/M") == 0)) -#define CMD_IPV6(S) ((strcmp ((S), "X:X::X:X") == 0)) -#define CMD_IPV6_PREFIX(S) ((strcmp ((S), "X:X::X:X/M") == 0)) - -/* Common descriptions. */ -#define SHOW_STR "Show running system information\n" -#define IP_STR "IP information\n" -#define IPV6_STR "IPv6 information\n" -#define NO_STR "Negate a command or set its defaults\n" -#define CLEAR_STR "Reset functions\n" -#define RIP_STR "RIP information\n" -#define BGP_STR "BGP information\n" -#define OSPF_STR "OSPF information\n" -#define NEIGHBOR_STR "Specify neighbor router\n" -#define DEBUG_STR "Debugging functions (see also 'undebug')\n" -#define UNDEBUG_STR "Disable debugging functions (see also 'debug')\n" -#define ROUTER_STR "Enable a routing process\n" -#define AS_STR "AS number\n" -#define MBGP_STR "MBGP information\n" -#define MATCH_STR "Match values from routing table\n" -#define SET_STR "Set values in destination routing protocol\n" -#define OUT_STR "Filter outgoing routing updates\n" -#define IN_STR "Filter incoming routing updates\n" -#define V4NOTATION_STR "specify by IPv4 address notation(e.g. 0.0.0.0)\n" -#define OSPF6_NUMBER_STR "Specify by number\n" -#define INTERFACE_STR "Interface infomation\n" -#define IFNAME_STR "Interface name(e.g. ep0)\n" -#define IP6_STR "IPv6 Information\n" -#define OSPF6_STR "Open Shortest Path First (OSPF) for IPv6\n" -#define OSPF6_ROUTER_STR "Enable a routing process\n" -#define OSPF6_INSTANCE_STR "<1-65535> Instance ID\n" -#define SECONDS_STR "<1-65535> Seconds\n" -#define ROUTE_STR "Routing Table\n" -#define PREFIX_LIST_STR "Build a prefix list\n" -#define OSPF6_DUMP_TYPE_LIST \ -"(neighbor|interface|area|lsa|zebra|config|dbex|spf|route|lsdb|redistribute|hook|asbr|prefix|abr)" -#define ISIS_STR "IS-IS information\n" -#define AREA_TAG_STR "[area tag]\n" - -#define CONF_BACKUP_EXT ".sav" - -/* IPv4 only machine should not accept IPv6 address for peer's IP - address. So we replace VTY command string like below. */ -#ifdef HAVE_IPV6 -#define NEIGHBOR_CMD "neighbor (A.B.C.D|X:X::X:X) " -#define NO_NEIGHBOR_CMD "no neighbor (A.B.C.D|X:X::X:X) " -#define NEIGHBOR_ADDR_STR "Neighbor address\nIPv6 address\n" -#define NEIGHBOR_CMD2 "neighbor (A.B.C.D|X:X::X:X|WORD) " -#define NO_NEIGHBOR_CMD2 "no neighbor (A.B.C.D|X:X::X:X|WORD) " -#define NEIGHBOR_ADDR_STR2 "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" -#else -#define NEIGHBOR_CMD "neighbor A.B.C.D " -#define NO_NEIGHBOR_CMD "no neighbor A.B.C.D " -#define NEIGHBOR_ADDR_STR "Neighbor address\n" -#define NEIGHBOR_CMD2 "neighbor (A.B.C.D|WORD) " -#define NO_NEIGHBOR_CMD2 "no neighbor (A.B.C.D|WORD) " -#define NEIGHBOR_ADDR_STR2 "Neighbor address\nNeighbor tag\n" -#endif /* HAVE_IPV6 */ - -/* Prototypes. */ -void install_node(struct cmd_node *, int (*)(struct vty *)); -void install_default(enum node_type); -void install_element(enum node_type, struct cmd_element *); -void sort_node(); - -/* Concatenates argv[shift] through argv[argc-1] into a single NUL-terminated - string with a space between each element (allocated using - XMALLOC(MTYPE_TMP)). Returns NULL if shift >= argc. */ -char *argv_concat(const char **argv, int argc, int shift); - -vector cmd_make_strvec(const char *); -void cmd_free_strvec(vector); -vector cmd_describe_command(); -char **cmd_complete_command(); -const char *cmd_prompt(enum node_type); -int config_from_file(struct vty *, FILE *); -enum node_type node_parent(enum node_type); -int cmd_execute_command(vector, struct vty *, struct cmd_element **, int); -int cmd_execute_command_strict(vector, struct vty *, struct cmd_element **); -void config_replace_string(struct cmd_element *, char *, ...); -void cmd_init(int); - -/* Export typical functions. */ -extern struct cmd_element config_end_cmd; -extern struct cmd_element config_exit_cmd; -extern struct cmd_element config_quit_cmd; -extern struct cmd_element config_help_cmd; -extern struct cmd_element config_list_cmd; -char *host_config_file(); -void host_config_set(char *); - -void print_version(const char *); - -#endif /* _ZEBRA_COMMAND_H */ diff --git a/openpcd/opcd_test/zebvty/vector.c b/openpcd/opcd_test/zebvty/vector.c deleted file mode 100644 index 7158d23..0000000 --- a/openpcd/opcd_test/zebvty/vector.c +++ /dev/null @@ -1,186 +0,0 @@ -/* Generic vector interface routine - * Copyright (C) 1997 Kunihiro Ishiguro - * - * This file is part of GNU Zebra. - * - * GNU Zebra 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. - * - * GNU Zebra 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 -#include - -#include "vector.h" -#include "memory.h" - -/* Initialize vector : allocate memory and return vector. */ -vector vector_init(unsigned int size) -{ - vector v = calloc(1, sizeof(struct _vector)); - if (!v) - return NULL; - - /* allocate at least one slot */ - if (size == 0) - size = 1; - - v->alloced = size; - v->active = 0; - v->index = calloc(1, sizeof(void *) * size); - if (!v->index) { - free(v); - return NULL; - } - return v; -} - -void vector_only_wrapper_free(vector v) -{ - free(v); -} - -void vector_only_index_free(void *index) -{ - free(index); -} - -void vector_free(vector v) -{ - free(v->index); - free(v); -} - -vector vector_copy(vector v) -{ - unsigned int size; - vector new = calloc(1, sizeof(struct _vector)); - if (!new) - return NULL; - - new->active = v->active; - new->alloced = v->alloced; - - size = sizeof(void *) * (v->alloced); - new->index = calloc(1, size); - if (!new->index) { - free(new); - return NULL; - } - memcpy(new->index, v->index, size); - - return new; -} - -/* Check assigned index, and if it runs short double index pointer */ -void vector_ensure(vector v, unsigned int num) -{ - if (v->alloced > num) - return; - - v->index = realloc(v->index, sizeof(void *) * (v->alloced * 2)); - memset(&v->index[v->alloced], 0, sizeof(void *) * v->alloced); - v->alloced *= 2; - - if (v->alloced <= num) - vector_ensure(v, num); -} - -/* This function only returns next empty slot index. It dose not mean - the slot's index memory is assigned, please call vector_ensure() - after calling this function. */ -int vector_empty_slot(vector v) -{ - unsigned int i; - - if (v->active == 0) - return 0; - - for (i = 0; i < v->active; i++) - if (v->index[i] == 0) - return i; - - return i; -} - -/* Set value to the smallest empty slot. */ -int vector_set(vector v, void *val) -{ - unsigned int i; - - i = vector_empty_slot(v); - vector_ensure(v, i); - - v->index[i] = val; - - if (v->active <= i) - v->active = i + 1; - - return i; -} - -/* Set value to specified index slot. */ -int vector_set_index(vector v, unsigned int i, void *val) -{ - vector_ensure(v, i); - - v->index[i] = val; - - if (v->active <= i) - v->active = i + 1; - - return i; -} - -/* Look up vector. */ -void *vector_lookup(vector v, unsigned int i) -{ - if (i >= v->active) - return NULL; - return v->index[i]; -} - -/* Lookup vector, ensure it. */ -void *vector_lookup_ensure(vector v, unsigned int i) -{ - vector_ensure(v, i); - return v->index[i]; -} - -/* Unset value at specified index slot. */ -void vector_unset(vector v, unsigned int i) -{ - if (i >= v->alloced) - return; - - v->index[i] = NULL; - - if (i + 1 == v->active) { - v->active--; - while (i && v->index[--i] == NULL && v->active--) ; /* Is this ugly ? */ - } -} - -/* Count the number of not emplty slot. */ -unsigned int vector_count(vector v) -{ - unsigned int i; - unsigned count = 0; - - for (i = 0; i < v->active; i++) - if (v->index[i] != NULL) - count++; - - return count; -} diff --git a/openpcd/opcd_test/zebvty/vector.h b/openpcd/opcd_test/zebvty/vector.h deleted file mode 100644 index d438d27..0000000 --- a/openpcd/opcd_test/zebvty/vector.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Generic vector interface header. - * Copyright (C) 1997, 98 Kunihiro Ishiguro - * - * This file is part of GNU Zebra. - * - * GNU Zebra 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. - * - * GNU Zebra 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. - */ - -#ifndef _ZEBRA_VECTOR_H -#define _ZEBRA_VECTOR_H - -/* struct for vector */ -struct _vector { - unsigned int active; /* number of active slots */ - unsigned int alloced; /* number of allocated slot */ - void **index; /* index to data */ -}; -typedef struct _vector *vector; - -#define VECTOR_MIN_SIZE 1 - -/* (Sometimes) usefull macros. This macro convert index expression to - array expression. */ -/* Reference slot at given index, caller must ensure slot is active */ -#define vector_slot(V,I) ((V)->index[(I)]) -/* Number of active slots. - * Note that this differs from vector_count() as it the count returned - * will include any empty slots - */ -#define vector_active(V) ((V)->active) - -/* Prototypes. */ -vector vector_init(unsigned int size); -void vector_ensure(vector v, unsigned int num); -int vector_empty_slot(vector v); -int vector_set(vector v, void *val); -int vector_set_index(vector v, unsigned int i, void *val); -void vector_unset(vector v, unsigned int i); -unsigned int vector_count(vector v); -void vector_only_wrapper_free(vector v); -void vector_only_index_free(void *index); -void vector_free(vector v); -vector vector_copy(vector v); - -void *vector_lookup(vector, unsigned int); -void *vector_lookup_ensure(vector, unsigned int); - -#endif /* _ZEBRA_VECTOR_H */ diff --git a/openpcd/opcd_test/zebvty/vty.c b/openpcd/opcd_test/zebvty/vty.c deleted file mode 100644 index ae41895..0000000 --- a/openpcd/opcd_test/zebvty/vty.c +++ /dev/null @@ -1,1515 +0,0 @@ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "zebvty.h" -#include "vty.h" -#include "command.h" -#include "buffer.h" - -/* Vty events */ -enum event { - VTY_SERV, - VTY_READ, - VTY_WRITE, - VTY_TIMEOUT_RESET, -#ifdef VTYSH - VTYSH_SERV, - VTYSH_READ, - VTYSH_WRITE -#endif /* VTYSH */ -}; - -extern struct host host; - -/* Vector which store each vty structure. */ -static vector vtyvec; - -vector Vvty_serv_thread; - -char *vty_cwd = NULL; - -/* Configure lock. */ -static int vty_config; - -static int no_password_check = 1; - -static void vty_clear_buf(struct vty *vty) -{ - memset(vty->buf, 0, vty->max); -} - -/* Allocate new vty struct. */ -struct vty *vty_new() -{ - struct vty *new = malloc(sizeof(struct vty)); - - if (!new) - goto out; - - new->obuf = buffer_new(0); /* Use default buffer size. */ - if (!new->obuf) - goto out_new; - new->buf = calloc(1, VTY_BUFSIZ); - if (!new->buf) - goto out_obuf; - - new->max = VTY_BUFSIZ; - - return new; - -out_obuf: - free(new->obuf); -out_new: - free(new); - new = NULL; -out: - return new; -} - -/* Authentication of vty */ -static void vty_auth(struct vty *vty, char *buf) -{ - char *passwd = NULL; - enum node_type next_node = 0; - int fail; - char *crypt(const char *, const char *); - - switch (vty->node) { - case AUTH_NODE: - if (host.encrypt) - passwd = host.password_encrypt; - else - passwd = host.password; - if (host.advanced) - next_node = host.enable ? VIEW_NODE : ENABLE_NODE; - else - next_node = VIEW_NODE; - break; - case AUTH_ENABLE_NODE: - if (host.encrypt) - passwd = host.enable_encrypt; - else - passwd = host.enable; - next_node = ENABLE_NODE; - break; - } - - if (passwd) { - if (host.encrypt) - fail = strcmp(crypt(buf, passwd), passwd); - else - fail = strcmp(buf, passwd); - } else - fail = 1; - - if (!fail) { - vty->fail = 0; - vty->node = next_node; /* Success ! */ - } else { - vty->fail++; - if (vty->fail >= 3) { - if (vty->node == AUTH_NODE) { - vty_out(vty, - "%% Bad passwords, too many failures!%s", - VTY_NEWLINE); - vty->status = VTY_CLOSE; - } else { - /* AUTH_ENABLE_NODE */ - vty->fail = 0; - vty_out(vty, - "%% Bad enable passwords, too many failures!%s", - VTY_NEWLINE); - vty->node = VIEW_NODE; - } - } - } -} - -/* Close vty interface. */ -void vty_close(struct vty *vty) -{ - int i; - - /* Flush buffer. */ - buffer_flush_all(vty->obuf, vty->fd); - - /* Free input buffer. */ - buffer_free(vty->obuf); - - /* Free command history. */ - for (i = 0; i < VTY_MAXHIST; i++) - if (vty->hist[i]) - free(vty->hist[i]); - - /* Unset vector. */ - vector_unset(vtyvec, vty->fd); - - /* Close socket. */ - if (vty->fd > 0) - close(vty->fd); - - if (vty->buf) - free(vty->buf); - - /* Check configure. */ - vty_config_unlock(vty); - - /* OK free vty. */ - free(vty); -} - -int vty_shell(struct vty *vty) -{ - return vty->type == VTY_SHELL ? 1 : 0; -} - - -/* VTY standard output function. */ -int vty_out(struct vty *vty, const char *format, ...) -{ - va_list args; - int len = 0; - int size = 1024; - char buf[1024]; - char *p = NULL; - - if (vty_shell(vty)) { - va_start(args, format); - vprintf(format, args); - va_end(args); - } else { - /* Try to write to initial buffer. */ - va_start(args, format); - len = vsnprintf(buf, sizeof buf, format, args); - va_end(args); - - /* Initial buffer is not enough. */ - if (len < 0 || len >= size) { - while (1) { - if (len > -1) - size = len + 1; - else - size = size * 2; - - p = realloc(p, size); - if (!p) - return -1; - - va_start(args, format); - len = vsnprintf(p, size, format, args); - va_end(args); - - if (len > -1 && len < size) - break; - } - } - - /* When initial buffer is enough to store all output. */ - if (!p) - p = buf; - - /* Pointer p must point out buffer. */ - buffer_put(vty->obuf, (u_char *) p, len); - - /* If p is not different with buf, it is allocated buffer. */ - if (p != buf) - free(p); - } - - return len; -} - -int vty_out_newline(struct vty *vty) -{ - char *p = vty_newline(vty); - buffer_put(vty->obuf, p, strlen(p)); -} - -int vty_config_lock(struct vty *vty) -{ - if (vty_config == 0) { - vty->config = 1; - vty_config = 1; - } - return vty->config; -} - -int vty_config_unlock(struct vty *vty) -{ - if (vty_config == 1 && vty->config == 1) { - vty->config = 0; - vty_config = 0; - } - return vty->config; -} - -static void vty_event(enum event event, int sock, struct vty *vty) -{ - //fprintf(stdout, "vty_event(%d, %d, %p)\n", event, sock, vty); - buffer_flush_all(vty->obuf, sock); -} - -/* Say hello to vty interface. */ -void vty_hello(struct vty *vty) -{ - if (host.motdfile) { - FILE *f; - char buf[4096]; - - f = fopen(host.motdfile, "r"); - if (f) { - while (fgets(buf, sizeof(buf), f)) { - char *s; - /* work backwards to ignore trailling isspace() */ - for (s = buf + strlen(buf); - (s > buf) && isspace(*(s - 1)); s--) ; - *s = '\0'; - vty_out(vty, "%s%s", buf, VTY_NEWLINE); - } - fclose(f); - } else - vty_out(vty, "MOTD file not found%s", VTY_NEWLINE); - } else if (host.motd) - vty_out(vty, host.motd); -} - -/* Put out prompt and wait input from user. */ -static void vty_prompt(struct vty *vty) -{ - struct utsname names; - const char *hostname; - - if (vty->type == VTY_TERM) { - hostname = host.name; - if (!hostname) { - uname(&names); - hostname = names.nodename; - } - vty_out(vty, cmd_prompt(vty->node), hostname); - } -} - -/* Command execution over the vty interface. */ -static int vty_command(struct vty *vty, char *buf) -{ - int ret; - vector vline; - - /* Split readline string up into the vector */ - vline = cmd_make_strvec(buf); - - if (vline == NULL) - return CMD_SUCCESS; - - ret = cmd_execute_command(vline, vty, NULL, 0); - if (ret != CMD_SUCCESS) - switch (ret) { - case CMD_WARNING: - if (vty->type == VTY_FILE) - vty_out(vty, "Warning...%s", VTY_NEWLINE); - break; - case CMD_ERR_AMBIGUOUS: - vty_out(vty, "%% Ambiguous command.%s", VTY_NEWLINE); - break; - case CMD_ERR_NO_MATCH: - vty_out(vty, "%% Unknown command.%s", VTY_NEWLINE); - break; - case CMD_ERR_INCOMPLETE: - vty_out(vty, "%% Command incomplete.%s", VTY_NEWLINE); - break; - } - cmd_free_strvec(vline); - - return ret; -} - -static const char telnet_backward_char = 0x08; -static const char telnet_space_char = ' '; - -/* Basic function to write buffer to vty. */ -static void vty_write(struct vty *vty, const char *buf, size_t nbytes) -{ - if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE)) - return; - - /* Should we do buffering here ? And make vty_flush (vty) ? */ - buffer_put(vty->obuf, buf, nbytes); -} - -/* Ensure length of input buffer. Is buffer is short, double it. */ -static void vty_ensure(struct vty *vty, int length) -{ - if (vty->max <= length) { - vty->max *= 2; - vty->buf = realloc(vty->buf, vty->max); - // FIXME: check return - } -} - -/* Basic function to insert character into vty. */ -static void vty_self_insert(struct vty *vty, char c) -{ - int i; - int length; - - vty_ensure(vty, vty->length + 1); - length = vty->length - vty->cp; - memmove(&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length); - vty->buf[vty->cp] = c; - - vty_write(vty, &vty->buf[vty->cp], length + 1); - for (i = 0; i < length; i++) - vty_write(vty, &telnet_backward_char, 1); - - vty->cp++; - vty->length++; -} - -/* Self insert character 'c' in overwrite mode. */ -static void vty_self_insert_overwrite(struct vty *vty, char c) -{ - vty_ensure(vty, vty->length + 1); - vty->buf[vty->cp++] = c; - - if (vty->cp > vty->length) - vty->length++; - - if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE)) - return; - - vty_write(vty, &c, 1); -} - -/* Insert a word into vty interface with overwrite mode. */ -static void vty_insert_word_overwrite(struct vty *vty, char *str) -{ - int len = strlen(str); - vty_write(vty, str, len); - strcpy(&vty->buf[vty->cp], str); - vty->cp += len; - vty->length = vty->cp; -} - -/* Forward character. */ -static void vty_forward_char(struct vty *vty) -{ - if (vty->cp < vty->length) { - vty_write(vty, &vty->buf[vty->cp], 1); - vty->cp++; - } -} - -/* Backward character. */ -static void vty_backward_char(struct vty *vty) -{ - if (vty->cp > 0) { - vty->cp--; - vty_write(vty, &telnet_backward_char, 1); - } -} - -/* Move to the beginning of the line. */ -static void vty_beginning_of_line(struct vty *vty) -{ - while (vty->cp) - vty_backward_char(vty); -} - -/* Move to the end of the line. */ -static void vty_end_of_line(struct vty *vty) -{ - while (vty->cp < vty->length) - vty_forward_char(vty); -} - -/* Add current command line to the history buffer. */ -static void vty_hist_add(struct vty *vty) -{ - int index; - - if (vty->length == 0) - return; - - index = vty->hindex ? vty->hindex - 1 : VTY_MAXHIST - 1; - - /* Ignore the same string as previous one. */ - if (vty->hist[index]) - if (strcmp(vty->buf, vty->hist[index]) == 0) { - vty->hp = vty->hindex; - return; - } - - /* Insert history entry. */ - if (vty->hist[vty->hindex]) - free(vty->hist[vty->hindex]); - vty->hist[vty->hindex] = strdup(vty->buf); - - /* History index rotation. */ - vty->hindex++; - if (vty->hindex == VTY_MAXHIST) - vty->hindex = 0; - - vty->hp = vty->hindex; -} - -/* Execute current command line. */ -static int vty_execute(struct vty *vty) -{ - int ret; - - ret = CMD_SUCCESS; - - switch (vty->node) { - case AUTH_NODE: - case AUTH_ENABLE_NODE: - vty_auth(vty, vty->buf); - break; - default: - ret = vty_command(vty, vty->buf); - if (vty->type == VTY_TERM) - vty_hist_add(vty); - break; - } - - /* Clear command line buffer. */ - vty->cp = vty->length = 0; - vty_clear_buf(vty); - - if (vty->status != VTY_CLOSE) - vty_prompt(vty); - - return ret; -} - -static void vty_kill_line_from_beginning(struct vty *); -static void vty_redraw_line(struct vty *); - -/* Print command line history. This function is called from - vty_next_line and vty_previous_line. */ -static void vty_history_print(struct vty *vty) -{ - int length; - - vty_kill_line_from_beginning(vty); - - /* Get previous line from history buffer */ - length = strlen(vty->hist[vty->hp]); - memcpy(vty->buf, vty->hist[vty->hp], length); - vty->cp = vty->length = length; - - /* Redraw current line */ - vty_redraw_line(vty); -} - -/* Show next command line history. */ -static void vty_next_line(struct vty *vty) -{ - int try_index; - - if (vty->hp == vty->hindex) - return; - - /* Try is there history exist or not. */ - try_index = vty->hp; - if (try_index == (VTY_MAXHIST - 1)) - try_index = 0; - else - try_index++; - - /* If there is not history return. */ - if (vty->hist[try_index] == NULL) - return; - else - vty->hp = try_index; - - vty_history_print(vty); -} - -/* Show previous command line history. */ -static void vty_previous_line(struct vty *vty) -{ - int try_index; - - try_index = vty->hp; - if (try_index == 0) - try_index = VTY_MAXHIST - 1; - else - try_index--; - - if (vty->hist[try_index] == NULL) - return; - else - vty->hp = try_index; - - vty_history_print(vty); -} - -/* This function redraw all of the command line character. */ -static void vty_redraw_line(struct vty *vty) -{ - vty_write(vty, vty->buf, vty->length); - vty->cp = vty->length; -} - -/* Forward word. */ -static void vty_forward_word(struct vty *vty) -{ - while (vty->cp != vty->length && vty->buf[vty->cp] != ' ') - vty_forward_char(vty); - - while (vty->cp != vty->length && vty->buf[vty->cp] == ' ') - vty_forward_char(vty); -} - -/* Backward word without skipping training space. */ -static void vty_backward_pure_word(struct vty *vty) -{ - while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ') - vty_backward_char(vty); -} - -/* Backward word. */ -static void vty_backward_word(struct vty *vty) -{ - while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ') - vty_backward_char(vty); - - while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ') - vty_backward_char(vty); -} - -/* When '^D' is typed at the beginning of the line we move to the down - level. */ -static void vty_down_level(struct vty *vty) -{ - vty_out(vty, "%s", VTY_NEWLINE); - (*config_exit_cmd.func) (NULL, vty, 0, NULL); - vty_prompt(vty); - vty->cp = 0; -} - -/* When '^Z' is received from vty, move down to the enable mode. */ -static void vty_end_config(struct vty *vty) -{ - vty_out(vty, "%s", VTY_NEWLINE); - - switch (vty->node) { - case VIEW_NODE: - case ENABLE_NODE: - /* Nothing to do. */ - break; - case CONFIG_NODE: - case INTERFACE_NODE: - case ZEBRA_NODE: - case RIP_NODE: - case RIPNG_NODE: - case BGP_NODE: - case BGP_VPNV4_NODE: - case BGP_IPV4_NODE: - case BGP_IPV4M_NODE: - case BGP_IPV6_NODE: - case RMAP_NODE: - case OSPF_NODE: - case OSPF6_NODE: - case ISIS_NODE: - case KEYCHAIN_NODE: - case KEYCHAIN_KEY_NODE: - case MASC_NODE: - case VTY_NODE: - vty_config_unlock(vty); - vty->node = ENABLE_NODE; - break; - default: - /* Unknown node, we have to ignore it. */ - break; - } - - vty_prompt(vty); - vty->cp = 0; -} - -/* Delete a charcter at the current point. */ -static void vty_delete_char(struct vty *vty) -{ - int i; - int size; - - if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE) - return; - - if (vty->length == 0) { - vty_down_level(vty); - return; - } - - if (vty->cp == vty->length) - return; /* completion need here? */ - - size = vty->length - vty->cp; - - vty->length--; - memmove(&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1); - vty->buf[vty->length] = '\0'; - - vty_write(vty, &vty->buf[vty->cp], size - 1); - vty_write(vty, &telnet_space_char, 1); - - for (i = 0; i < size; i++) - vty_write(vty, &telnet_backward_char, 1); -} - -/* Delete a character before the point. */ -static void vty_delete_backward_char(struct vty *vty) -{ - if (vty->cp == 0) - return; - - vty_backward_char(vty); - vty_delete_char(vty); -} - -/* Kill rest of line from current point. */ -static void vty_kill_line(struct vty *vty) -{ - int i; - int size; - - size = vty->length - vty->cp; - - if (size == 0) - return; - - for (i = 0; i < size; i++) - vty_write(vty, &telnet_space_char, 1); - for (i = 0; i < size; i++) - vty_write(vty, &telnet_backward_char, 1); - - memset(&vty->buf[vty->cp], 0, size); - vty->length = vty->cp; -} - -/* Kill line from the beginning. */ -static void vty_kill_line_from_beginning(struct vty *vty) -{ - vty_beginning_of_line(vty); - vty_kill_line(vty); -} - -/* Delete a word before the point. */ -static void vty_forward_kill_word(struct vty *vty) -{ - while (vty->cp != vty->length && vty->buf[vty->cp] == ' ') - vty_delete_char(vty); - while (vty->cp != vty->length && vty->buf[vty->cp] != ' ') - vty_delete_char(vty); -} - -/* Delete a word before the point. */ -static void vty_backward_kill_word(struct vty *vty) -{ - while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ') - vty_delete_backward_char(vty); - while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ') - vty_delete_backward_char(vty); -} - -/* Transpose chars before or at the point. */ -static void vty_transpose_chars(struct vty *vty) -{ - char c1, c2; - - /* If length is short or point is near by the beginning of line then - return. */ - if (vty->length < 2 || vty->cp < 1) - return; - - /* In case of point is located at the end of the line. */ - if (vty->cp == vty->length) { - c1 = vty->buf[vty->cp - 1]; - c2 = vty->buf[vty->cp - 2]; - - vty_backward_char(vty); - vty_backward_char(vty); - vty_self_insert_overwrite(vty, c1); - vty_self_insert_overwrite(vty, c2); - } else { - c1 = vty->buf[vty->cp]; - c2 = vty->buf[vty->cp - 1]; - - vty_backward_char(vty); - vty_self_insert_overwrite(vty, c1); - vty_self_insert_overwrite(vty, c2); - } -} - -/* Do completion at vty interface. */ -static void vty_complete_command(struct vty *vty) -{ - int i; - int ret; - char **matched = NULL; - vector vline; - - if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE) - return; - - vline = cmd_make_strvec(vty->buf); - if (vline == NULL) - return; - - /* In case of 'help \t'. */ - if (isspace((int)vty->buf[vty->length - 1])) - vector_set(vline, '\0'); - - matched = cmd_complete_command(vline, vty, &ret); - - cmd_free_strvec(vline); - - vty_out(vty, "%s", VTY_NEWLINE); - switch (ret) { - case CMD_ERR_AMBIGUOUS: - vty_out(vty, "%% Ambiguous command.%s", VTY_NEWLINE); - vty_prompt(vty); - vty_redraw_line(vty); - break; - case CMD_ERR_NO_MATCH: - /* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */ - vty_prompt(vty); - vty_redraw_line(vty); - break; - case CMD_COMPLETE_FULL_MATCH: - vty_prompt(vty); - vty_redraw_line(vty); - vty_backward_pure_word(vty); - vty_insert_word_overwrite(vty, matched[0]); - vty_self_insert(vty, ' '); - free(matched[0]); - break; - case CMD_COMPLETE_MATCH: - vty_prompt(vty); - vty_redraw_line(vty); - vty_backward_pure_word(vty); - vty_insert_word_overwrite(vty, matched[0]); - free(matched[0]); - vector_only_index_free(matched); - return; - break; - case CMD_COMPLETE_LIST_MATCH: - for (i = 0; matched[i] != NULL; i++) { - if (i != 0 && ((i % 6) == 0)) - vty_out(vty, "%s", VTY_NEWLINE); - vty_out(vty, "%-10s ", matched[i]); - free(matched[i]); - } - vty_out(vty, "%s", VTY_NEWLINE); - - vty_prompt(vty); - vty_redraw_line(vty); - break; - case CMD_ERR_NOTHING_TODO: - vty_prompt(vty); - vty_redraw_line(vty); - break; - default: - break; - } - if (matched) - vector_only_index_free(matched); -} - -static void -vty_describe_fold(struct vty *vty, int cmd_width, - unsigned int desc_width, struct desc *desc) -{ - char *buf; - const char *cmd, *p; - int pos; - - cmd = desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd; - - if (desc_width <= 0) { - vty_out(vty, " %-*s %s%s", cmd_width, cmd, desc->str, - VTY_NEWLINE); - return; - } - - buf = calloc(1, strlen(desc->str) + 1); - if (!buf) - return; - - for (p = desc->str; strlen(p) > desc_width; p += pos + 1) { - for (pos = desc_width; pos > 0; pos--) - if (*(p + pos) == ' ') - break; - - if (pos == 0) - break; - - strncpy(buf, p, pos); - buf[pos] = '\0'; - vty_out(vty, " %-*s %s%s", cmd_width, cmd, buf, VTY_NEWLINE); - - cmd = ""; - } - - vty_out(vty, " %-*s %s%s", cmd_width, cmd, p, VTY_NEWLINE); - - free(buf); -} - -/* Describe matched command function. */ -static void vty_describe_command(struct vty *vty) -{ - int ret; - vector vline; - vector describe; - unsigned int i, width, desc_width; - struct desc *desc, *desc_cr = NULL; - - vline = cmd_make_strvec(vty->buf); - - /* In case of '> ?'. */ - if (vline == NULL) { - vline = vector_init(1); - vector_set(vline, '\0'); - } else if (isspace((int)vty->buf[vty->length - 1])) - vector_set(vline, '\0'); - - describe = cmd_describe_command(vline, vty, &ret); - - vty_out(vty, "%s", VTY_NEWLINE); - - /* Ambiguous error. */ - switch (ret) { - case CMD_ERR_AMBIGUOUS: - cmd_free_strvec(vline); - vty_out(vty, "%% Ambiguous command.%s", VTY_NEWLINE); - vty_prompt(vty); - vty_redraw_line(vty); - return; - break; - case CMD_ERR_NO_MATCH: - cmd_free_strvec(vline); - vty_out(vty, "%% There is no matched command.%s", VTY_NEWLINE); - vty_prompt(vty); - vty_redraw_line(vty); - return; - break; - } - - /* Get width of command string. */ - width = 0; - for (i = 0; i < vector_active(describe); i++) - if ((desc = vector_slot(describe, i)) != NULL) { - unsigned int len; - - if (desc->cmd[0] == '\0') - continue; - - len = strlen(desc->cmd); - if (desc->cmd[0] == '.') - len--; - - if (width < len) - width = len; - } - - /* Get width of description string. */ - desc_width = vty->width - (width + 6); - - /* Print out description. */ - for (i = 0; i < vector_active(describe); i++) - if ((desc = vector_slot(describe, i)) != NULL) { - if (desc->cmd[0] == '\0') - continue; - - if (strcmp(desc->cmd, "") == 0) { - desc_cr = desc; - continue; - } - - if (!desc->str) - vty_out(vty, " %-s%s", - desc->cmd[0] == - '.' ? desc->cmd + 1 : desc->cmd, - VTY_NEWLINE); - else if (desc_width >= strlen(desc->str)) - vty_out(vty, " %-*s %s%s", width, - desc->cmd[0] == - '.' ? desc->cmd + 1 : desc->cmd, - desc->str, VTY_NEWLINE); - else - vty_describe_fold(vty, width, desc_width, desc); - -#if 0 - vty_out(vty, " %-*s %s%s", width - desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, - desc->str ? desc->str : "", VTY_NEWLINE); -#endif /* 0 */ - } - - if ((desc = desc_cr)) { - if (!desc->str) - vty_out(vty, " %-s%s", - desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, - VTY_NEWLINE); - else if (desc_width >= strlen(desc->str)) - vty_out(vty, " %-*s %s%s", width, - desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, - desc->str, VTY_NEWLINE); - else - vty_describe_fold(vty, width, desc_width, desc); - } - - cmd_free_strvec(vline); - vector_free(describe); - - vty_prompt(vty); - vty_redraw_line(vty); -} - -/* ^C stop current input and do not add command line to the history. */ -static void vty_stop_input(struct vty *vty) -{ - vty->cp = vty->length = 0; - vty_clear_buf(vty); - vty_out(vty, "%s", VTY_NEWLINE); - - switch (vty->node) { - case VIEW_NODE: - case ENABLE_NODE: - /* Nothing to do. */ - break; - case CONFIG_NODE: - case INTERFACE_NODE: - case ZEBRA_NODE: - case RIP_NODE: - case RIPNG_NODE: - case BGP_NODE: - case RMAP_NODE: - case OSPF_NODE: - case OSPF6_NODE: - case ISIS_NODE: - case KEYCHAIN_NODE: - case KEYCHAIN_KEY_NODE: - case MASC_NODE: - case VTY_NODE: - vty_config_unlock(vty); - vty->node = ENABLE_NODE; - break; - default: - /* Unknown node, we have to ignore it. */ - break; - } - vty_prompt(vty); - - /* Set history pointer to the latest one. */ - vty->hp = vty->hindex; -} - -#define CONTROL(X) ((X) - '@') -#define VTY_NORMAL 0 -#define VTY_PRE_ESCAPE 1 -#define VTY_ESCAPE 2 - -/* Escape character command map. */ -static void vty_escape_map(unsigned char c, struct vty *vty) -{ - switch (c) { - case ('A'): - vty_previous_line(vty); - break; - case ('B'): - vty_next_line(vty); - break; - case ('C'): - vty_forward_char(vty); - break; - case ('D'): - vty_backward_char(vty); - break; - default: - break; - } - - /* Go back to normal mode. */ - vty->escape = VTY_NORMAL; -} - -/* Quit print out to the buffer. */ -static void vty_buffer_reset(struct vty *vty) -{ - buffer_reset(vty->obuf); - vty_prompt(vty); - vty_redraw_line(vty); -} - -/* Read data via vty socket. */ -int vty_read(struct vty *vty) -{ - int i; - int nbytes; - unsigned char buf[VTY_READ_BUFSIZ]; - - int vty_sock = 0; - - /* Read raw data from socket */ - if ((nbytes = read(vty->fd, buf, VTY_READ_BUFSIZ)) <= 0) { - if (nbytes < 0) { - if (ERRNO_IO_RETRY(errno)) { - vty_event(VTY_READ, vty_sock, vty); - return 0; - } - } - buffer_reset(vty->obuf); - vty->status = VTY_CLOSE; - } - - for (i = 0; i < nbytes; i++) { -#if 0 - if (buf[i] == IAC) { - if (!vty->iac) { - vty->iac = 1; - continue; - } else { - vty->iac = 0; - } - } - - if (vty->iac_sb_in_progress && !vty->iac) { - if (vty->sb_len < sizeof(vty->sb_buf)) - vty->sb_buf[vty->sb_len] = buf[i]; - vty->sb_len++; - continue; - } - - if (vty->iac) { - /* In case of telnet command */ - int ret = 0; - ret = vty_telnet_option(vty, buf + i, nbytes - i); - vty->iac = 0; - i += ret; - continue; - } -#endif - - if (vty->status == VTY_MORE) { - switch (buf[i]) { - case CONTROL('C'): - case 'q': - case 'Q': - vty_buffer_reset(vty); - break; -#if 0 /* More line does not work for "show ip bgp". */ - case '\n': - case '\r': - vty->status = VTY_MORELINE; - break; -#endif - default: - break; - } - continue; - } - - /* Escape character. */ - if (vty->escape == VTY_ESCAPE) { - vty_escape_map(buf[i], vty); - continue; - } - - /* Pre-escape status. */ - if (vty->escape == VTY_PRE_ESCAPE) { - switch (buf[i]) { - case '[': - vty->escape = VTY_ESCAPE; - break; - case 'b': - vty_backward_word(vty); - vty->escape = VTY_NORMAL; - break; - case 'f': - vty_forward_word(vty); - vty->escape = VTY_NORMAL; - break; - case 'd': - vty_forward_kill_word(vty); - vty->escape = VTY_NORMAL; - break; - case CONTROL('H'): - case 0x7f: - vty_backward_kill_word(vty); - vty->escape = VTY_NORMAL; - break; - default: - vty->escape = VTY_NORMAL; - break; - } - continue; - } - - switch (buf[i]) { - case CONTROL('A'): - vty_beginning_of_line(vty); - break; - case CONTROL('B'): - vty_backward_char(vty); - break; - case CONTROL('C'): - vty_stop_input(vty); - break; - case CONTROL('D'): - vty_delete_char(vty); - break; - case CONTROL('E'): - vty_end_of_line(vty); - break; - case CONTROL('F'): - vty_forward_char(vty); - break; - case CONTROL('H'): - case 0x7f: - vty_delete_backward_char(vty); - break; - case CONTROL('K'): - vty_kill_line(vty); - break; - case CONTROL('N'): - vty_next_line(vty); - break; - case CONTROL('P'): - vty_previous_line(vty); - break; - case CONTROL('T'): - vty_transpose_chars(vty); - break; - case CONTROL('U'): - vty_kill_line_from_beginning(vty); - break; - case CONTROL('W'): - vty_backward_kill_word(vty); - break; - case CONTROL('Z'): - vty_end_config(vty); - break; - case '\n': - case '\r': - vty_out(vty, "%s", VTY_NEWLINE); - vty_execute(vty); - break; - case '\t': - vty_complete_command(vty); - break; - case '?': - if (vty->node == AUTH_NODE - || vty->node == AUTH_ENABLE_NODE) - vty_self_insert(vty, buf[i]); - else - vty_describe_command(vty); - break; - case '\033': - if (i + 1 < nbytes && buf[i + 1] == '[') { - vty->escape = VTY_ESCAPE; - i++; - } else - vty->escape = VTY_PRE_ESCAPE; - break; - default: - if (buf[i] > 31 && buf[i] < 127) - vty_self_insert(vty, buf[i]); - break; - } - } - - /* Check status. */ - if (vty->status == VTY_CLOSE) - vty_close(vty); - else { - vty_event(VTY_WRITE, vty_sock, vty); - vty_event(VTY_READ, vty_sock, vty); - } - return 0; -} - -/* Create new vty structure. */ -struct vty * -vty_create (int vty_sock) -{ - struct vty *vty; - - struct termios t; - - tcgetattr(vty_sock, &t); - cfmakeraw(&t); - tcsetattr(vty_sock, TCSANOW, &t); - - /* Allocate new vty structure and set up default values. */ - vty = vty_new (); - vty->fd = vty_sock; - vty->type = VTY_TERM; - if (no_password_check) - { - if (host.advanced) - vty->node = ENABLE_NODE; - else - vty->node = VIEW_NODE; - } - else - vty->node = AUTH_NODE; - vty->fail = 0; - vty->cp = 0; - vty_clear_buf (vty); - vty->length = 0; - memset (vty->hist, 0, sizeof (vty->hist)); - vty->hp = 0; - vty->hindex = 0; - vector_set_index (vtyvec, vty_sock, vty); - vty->status = VTY_NORMAL; - if (host.lines >= 0) - vty->lines = host.lines; - else - vty->lines = -1; - - if (! no_password_check) - { - /* Vty is not available if password isn't set. */ - if (host.password == NULL && host.password_encrypt == NULL) - { - vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE); - vty->status = VTY_CLOSE; - vty_close (vty); - return NULL; - } - } - - /* Say hello to the world. */ - vty_hello (vty); - if (! no_password_check) - vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); - -#if 0 - /* Setting up terminal. */ - vty_will_echo (vty); - vty_will_suppress_go_ahead (vty); - - vty_dont_linemode (vty); - vty_do_window_size (vty); - /* vty_dont_lflow_ahead (vty); */ -#endif - - vty_prompt (vty); - - /* Add read/write thread. */ - vty_event (VTY_WRITE, vty_sock, vty); - vty_event (VTY_READ, vty_sock, vty); - - return vty; -} - -DEFUN(config_who, config_who_cmd, "who", "Display who is on vty\n") -{ - unsigned int i; - struct vty *v; - - for (i = 0; i < vector_active(vtyvec); i++) - if ((v = vector_slot(vtyvec, i)) != NULL) - vty_out(vty, "%svty[%d] %s", - v->config ? "*" : " ", i, VTY_NEWLINE); - return CMD_SUCCESS; -} - -/* Move to vty configuration mode. */ -DEFUN(line_vty, - line_vty_cmd, - "line vty", "Configure a terminal line\n" "Virtual terminal\n") -{ - vty->node = VTY_NODE; - return CMD_SUCCESS; -} - -/* vty login. */ -DEFUN(vty_login, vty_login_cmd, "login", "Enable password checking\n") -{ - no_password_check = 0; - return CMD_SUCCESS; -} - -DEFUN(no_vty_login, - no_vty_login_cmd, "no login", NO_STR "Enable password checking\n") -{ - no_password_check = 1; - return CMD_SUCCESS; -} - -DEFUN(service_advanced_vty, - service_advanced_vty_cmd, - "service advanced-vty", - "Set up miscellaneous service\n" "Enable advanced mode vty interface\n") -{ - host.advanced = 1; - return CMD_SUCCESS; -} - -DEFUN(no_service_advanced_vty, - no_service_advanced_vty_cmd, - "no service advanced-vty", - NO_STR - "Set up miscellaneous service\n" "Enable advanced mode vty interface\n") -{ - host.advanced = 0; - return CMD_SUCCESS; -} - -DEFUN(terminal_monitor, - terminal_monitor_cmd, - "terminal monitor", - "Set terminal line parameters\n" - "Copy debug output to the current terminal line\n") -{ - vty->monitor = 1; - return CMD_SUCCESS; -} - -DEFUN(terminal_no_monitor, - terminal_no_monitor_cmd, - "terminal no monitor", - "Set terminal line parameters\n" - NO_STR "Copy debug output to the current terminal line\n") -{ - vty->monitor = 0; - return CMD_SUCCESS; -} - -DEFUN(show_history, - show_history_cmd, - "show history", SHOW_STR "Display the session command history\n") -{ - int index; - - for (index = vty->hindex + 1; index != vty->hindex;) { - if (index == VTY_MAXHIST) { - index = 0; - continue; - } - - if (vty->hist[index] != NULL) - vty_out(vty, " %s%s", vty->hist[index], VTY_NEWLINE); - - index++; - } - - return CMD_SUCCESS; -} - -/* Display current configuration. */ -static int vty_config_write(struct vty *vty) -{ - vty_out(vty, "line vty%s", VTY_NEWLINE); - - /* login */ - if (no_password_check) - vty_out(vty, " no login%s", VTY_NEWLINE); - - vty_out(vty, "!%s", VTY_NEWLINE); - - return CMD_SUCCESS; -} - -struct cmd_node vty_node = { - VTY_NODE, - "%s(config-line)# ", - 1, -}; - -/* Reset all VTY status. */ -void vty_reset() -{ - unsigned int i; - struct vty *vty; - struct thread *vty_serv_thread; - - for (i = 0; i < vector_active(vtyvec); i++) - if ((vty = vector_slot(vtyvec, i)) != NULL) { - buffer_reset(vty->obuf); - vty->status = VTY_CLOSE; - vty_close(vty); - } - - for (i = 0; i < vector_active(Vvty_serv_thread); i++) - if ((vty_serv_thread = - vector_slot(Vvty_serv_thread, i)) != NULL) { - //thread_cancel (vty_serv_thread); - vector_slot(Vvty_serv_thread, i) = NULL; - close(i); - } -} - -static void vty_save_cwd(void) -{ - char cwd[MAXPATHLEN]; - char *c; - - c = getcwd(cwd, MAXPATHLEN); - - if (!c) { - chdir(SYSCONFDIR); - getcwd(cwd, MAXPATHLEN); - } - - vty_cwd = malloc(strlen(cwd) + 1); - strcpy(vty_cwd, cwd); -} - -char *vty_get_cwd() -{ - return vty_cwd; -} - -int vty_shell_serv(struct vty *vty) -{ - return vty->type == VTY_SHELL_SERV ? 1 : 0; -} - -void vty_init_vtysh() -{ - vtyvec = vector_init(VECTOR_MIN_SIZE); -} - -/* Install vty's own commands like `who' command. */ -void vty_init() -{ - /* For further configuration read, preserve current directory. */ - vty_save_cwd(); - - vtyvec = vector_init(VECTOR_MIN_SIZE); - - /* Install bgp top node. */ - install_node(&vty_node, vty_config_write); - - install_element(VIEW_NODE, &config_who_cmd); - install_element(VIEW_NODE, &show_history_cmd); - install_element(ENABLE_NODE, &config_who_cmd); - install_element(CONFIG_NODE, &line_vty_cmd); - install_element(CONFIG_NODE, &service_advanced_vty_cmd); - install_element(CONFIG_NODE, &no_service_advanced_vty_cmd); - install_element(CONFIG_NODE, &show_history_cmd); - install_element(ENABLE_NODE, &terminal_monitor_cmd); - install_element(ENABLE_NODE, &terminal_no_monitor_cmd); - install_element(ENABLE_NODE, &show_history_cmd); - - install_default(VTY_NODE); -#if 0 - install_element(VTY_NODE, &vty_login_cmd); - install_element(VTY_NODE, &no_vty_login_cmd); -#endif -} diff --git a/openpcd/opcd_test/zebvty/vty.h b/openpcd/opcd_test/zebvty/vty.h deleted file mode 100644 index ffa845b..0000000 --- a/openpcd/opcd_test/zebvty/vty.h +++ /dev/null @@ -1,118 +0,0 @@ -#ifndef _VTY_H -#define _VTY_H - -#include -#include - -/* GCC have printf type attribute check. */ -#ifdef __GNUC__ -#define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b))) -#else -#define PRINTF_ATTRIBUTE(a,b) -#endif /* __GNUC__ */ - -/* Does the I/O error indicate that the operation should be retried later? */ -#define ERRNO_IO_RETRY(EN) \ - (((EN) == EAGAIN) || ((EN) == EWOULDBLOCK) || ((EN) == EINTR)) - -/* Vty read buffer size. */ -#define VTY_READ_BUFSIZ 512 - -#define VTY_BUFSIZ 512 -#define VTY_MAXHIST 20 - -struct vty { - FILE *file; - - /* File descripter of this vty. */ - int fd; - - /* Is this vty connect to file or not */ - enum { VTY_TERM, VTY_FILE, VTY_SHELL, VTY_SHELL_SERV } type; - - /* Node status of this vty */ - int node; - - /* Failure count */ - int fail; - - /* Output buffer. */ - struct buffer *obuf; - - /* Command input buffer */ - char *buf; - - /* Command cursor point */ - int cp; - - /* Command length */ - int length; - - /* Command max length. */ - int max; - - /* Histry of command */ - char *hist[VTY_MAXHIST]; - - /* History lookup current point */ - int hp; - - /* History insert end point */ - int hindex; - - /* For current referencing point of interface, route-map, - access-list etc... */ - void *index; - - /* For multiple level index treatment such as key chain and key. */ - void *index_sub; - - /* For escape character. */ - unsigned char escape; - - /* Current vty status. */ - enum { VTY_NORMAL, VTY_CLOSE, VTY_MORE, VTY_MORELINE } status; - - /* Window width/height. */ - int width; - int height; - - /* Configure lines. */ - int lines; - - int monitor; - - /* In configure mode. */ - int config; -}; - -/* Small macro to determine newline is newline only or linefeed needed. */ -#define VTY_NEWLINE ((vty->type == VTY_TERM) ? "\r\n" : "\n") - -static inline char *vty_newline(struct vty *vty) -{ - return VTY_NEWLINE; -} - -/* Prototypes. */ -void vty_init (void); -void vty_init_vtysh (void); -void vty_reset (void); -struct vty *vty_new (void); -struct vty *vty_create (int vty_sock); -int vty_out (struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3); -int vty_out_newline(struct vty *); -int vty_read(struct vty *vty); -void vty_read_config (char *, char *); -void vty_time_print (struct vty *, int); -void vty_close (struct vty *); -char *vty_get_cwd (void); -void vty_log (const char *level, const char *proto, const char *fmt, va_list); -int vty_config_lock (struct vty *); -int vty_config_unlock (struct vty *); -int vty_shell (struct vty *); -int vty_shell_serv (struct vty *); -void vty_hello (struct vty *); - - -#endif diff --git a/openpcd/opcd_test/zebvty/zebvty.h b/openpcd/opcd_test/zebvty/zebvty.h deleted file mode 100644 index a992bb2..0000000 --- a/openpcd/opcd_test/zebvty/zebvty.h +++ /dev/null @@ -1,5 +0,0 @@ -#define QUAGGA_PROGNAME "opcd_shell" -#define QUAGGA_VERSION "0.01" -#define QUAGGA_COPYRIGHT "Harald Welte " -#define CONFIGFILE_MASK 022 -#define SYSCONFDIR "/etc" -- cgit v1.2.3