mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
				synced 2025-11-04 05:53:26 +00:00 
			
		
		
		
	Merge commit '237f6241f2b91a81b928ce4e3fc1364f61f11eaa'
This commit is contained in:
		@@ -5,7 +5,7 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include
 | 
			
		||||
SUBDIRS = include src tests
 | 
			
		||||
 | 
			
		||||
pkgconfigdir = $(libdir)/pkgconfig
 | 
			
		||||
pkgconfig_DATA = libosmocore.pc
 | 
			
		||||
pkgconfig_DATA = libosmocore.pc libosmovty.pc
 | 
			
		||||
 | 
			
		||||
BUILT_SOURCES = $(top_srcdir)/.version
 | 
			
		||||
$(top_srcdir)/.version:
 | 
			
		||||
 
 | 
			
		||||
@@ -46,10 +46,14 @@ AM_CONDITIONAL(ENABLE_TESTS, test "x$enable_tests" = "x1")
 | 
			
		||||
 | 
			
		||||
AC_OUTPUT(
 | 
			
		||||
	libosmocore.pc
 | 
			
		||||
	libosmovty.pc
 | 
			
		||||
	include/osmocom/Makefile
 | 
			
		||||
	include/osmocom/vty/Makefile
 | 
			
		||||
	include/osmocore/Makefile
 | 
			
		||||
	include/osmocore/protocol/Makefile
 | 
			
		||||
	include/Makefile
 | 
			
		||||
	src/Makefile
 | 
			
		||||
	src/vty/Makefile
 | 
			
		||||
	tests/Makefile
 | 
			
		||||
	tests/timer/Makefile
 | 
			
		||||
	tests/sms/Makefile
 | 
			
		||||
 
 | 
			
		||||
@@ -1 +1 @@
 | 
			
		||||
SUBDIRS = osmocore
 | 
			
		||||
SUBDIRS = osmocom osmocore
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								libosmocore/include/osmocom/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								libosmocore/include/osmocom/Makefile.am
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
SUBDIRS = vty
 | 
			
		||||
							
								
								
									
										4
									
								
								libosmocore/include/osmocom/vty/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								libosmocore/include/osmocom/vty/Makefile.am
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
			
		||||
osmovty_HEADERS = buffer.h command.h vector.h vty.h \
 | 
			
		||||
	telnet_interface.h logging.h
 | 
			
		||||
 | 
			
		||||
osmovtydir = $(includedir)/osmocom/vty
 | 
			
		||||
							
								
								
									
										102
									
								
								libosmocore/include/osmocom/vty/buffer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								libosmocore/include/osmocom/vty/buffer.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,102 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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
 | 
			
		||||
 | 
			
		||||
#include <sys/types.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(void *ctx, 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 */
 | 
			
		||||
							
								
								
									
										388
									
								
								libosmocore/include/osmocom/vty/command.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										388
									
								
								libosmocore/include/osmocom/vty/command.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,388 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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 <stdio.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#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;
 | 
			
		||||
 | 
			
		||||
	const struct vty_app_info *app_info;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* There are some command levels which called from command node. */
 | 
			
		||||
enum node_type {
 | 
			
		||||
	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. */
 | 
			
		||||
#if 0
 | 
			
		||||
	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. */
 | 
			
		||||
#endif
 | 
			
		||||
	VTY_NODE,		/* Vty node. */
 | 
			
		||||
 | 
			
		||||
	GSMNET_NODE,
 | 
			
		||||
	BTS_NODE,
 | 
			
		||||
	TRX_NODE,
 | 
			
		||||
	TS_NODE,
 | 
			
		||||
	SUBSCR_NODE,
 | 
			
		||||
	MGCP_NODE,
 | 
			
		||||
	GBPROXY_NODE,
 | 
			
		||||
	SGSN_NODE,
 | 
			
		||||
	NS_NODE,
 | 
			
		||||
	BSSGP_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) \
 | 
			
		||||
  static struct cmd_element cmdname = \
 | 
			
		||||
  { \
 | 
			
		||||
    .string = cmdstr, \
 | 
			
		||||
    .func = funcname, \
 | 
			
		||||
    .doc = helpstr, \
 | 
			
		||||
    .attr = attrs, \
 | 
			
		||||
    .daemon = dnum, \
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
/* global (non static) cmd_element */
 | 
			
		||||
#define gDEFUN_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)
 | 
			
		||||
 | 
			
		||||
/* global (non static) cmd_element */
 | 
			
		||||
#define gDEFUN(funcname, cmdname, cmdstr, helpstr) \
 | 
			
		||||
  DEFUN_CMD_FUNC_DECL(funcname) \
 | 
			
		||||
  gDEFUN_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)
 | 
			
		||||
 | 
			
		||||
/* global (non static) cmd_element */
 | 
			
		||||
#define gALIAS(funcname, cmdname, cmdstr, helpstr) \
 | 
			
		||||
  gDEFUN_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 install_element_ve(struct cmd_element *cmd);
 | 
			
		||||
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_exit_cmd;
 | 
			
		||||
extern struct cmd_element config_help_cmd;
 | 
			
		||||
extern struct cmd_element config_list_cmd;
 | 
			
		||||
char *host_config_file();
 | 
			
		||||
void host_config_set(const char *);
 | 
			
		||||
 | 
			
		||||
/* This is called from main when a daemon is invoked with -v or --version. */
 | 
			
		||||
void print_version(int print_copyright);
 | 
			
		||||
 | 
			
		||||
extern void *tall_vty_cmd_ctx;
 | 
			
		||||
 | 
			
		||||
#endif				/* _ZEBRA_COMMAND_H */
 | 
			
		||||
							
								
								
									
										7
									
								
								libosmocore/include/osmocom/vty/logging.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								libosmocore/include/osmocom/vty/logging.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
#ifndef _VTY_LOGGING_H
 | 
			
		||||
#define _VTY_LOGGING_H
 | 
			
		||||
 | 
			
		||||
#define LOGGING_STR	"Configure log message to this terminal\n"
 | 
			
		||||
#define FILTER_STR	"Filter log messages\n"
 | 
			
		||||
 | 
			
		||||
#endif /* _VTY_LOGGING_H */
 | 
			
		||||
							
								
								
									
										40
									
								
								libosmocore/include/osmocom/vty/telnet_interface.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								libosmocore/include/osmocom/vty/telnet_interface.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
/* minimalistic telnet/network interface it might turn into a wire interface */
 | 
			
		||||
/* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
 | 
			
		||||
 * All Rights Reserved
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License along
 | 
			
		||||
 * with this program; if not, write to the Free Software Foundation, Inc.,
 | 
			
		||||
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef TELNET_INTERFACE_H
 | 
			
		||||
#define TELNET_INTERFACE_H
 | 
			
		||||
 | 
			
		||||
#include <osmocore/logging.h>
 | 
			
		||||
#include <osmocore/select.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/vty/vty.h>
 | 
			
		||||
 | 
			
		||||
struct telnet_connection {
 | 
			
		||||
	struct llist_head entry;
 | 
			
		||||
	void *priv;
 | 
			
		||||
	struct bsc_fd fd;
 | 
			
		||||
	struct vty *vty;
 | 
			
		||||
	struct log_target *dbg;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int telnet_init(void *tall_ctx, void *priv, int port);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										64
									
								
								libosmocore/include/osmocom/vty/vector.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								libosmocore/include/osmocom/vty/vector.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,64 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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);
 | 
			
		||||
 | 
			
		||||
extern void *tall_vty_vec_ctx;
 | 
			
		||||
 | 
			
		||||
#endif				/* _ZEBRA_VECTOR_H */
 | 
			
		||||
							
								
								
									
										159
									
								
								libosmocore/include/osmocom/vty/vty.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								libosmocore/include/osmocom/vty/vty.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,159 @@
 | 
			
		||||
#ifndef _VTY_H
 | 
			
		||||
#define _VTY_H
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
 | 
			
		||||
/* GCC have printf type attribute check.  */
 | 
			
		||||
#ifdef __GNUC__
 | 
			
		||||
#define VTY_PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
 | 
			
		||||
#else
 | 
			
		||||
#define VTY_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
 | 
			
		||||
 | 
			
		||||
/* Vty events */
 | 
			
		||||
enum event {
 | 
			
		||||
	VTY_SERV,
 | 
			
		||||
	VTY_READ,
 | 
			
		||||
	VTY_WRITE,
 | 
			
		||||
	VTY_CLOSED,
 | 
			
		||||
	VTY_TIMEOUT_RESET,
 | 
			
		||||
#ifdef VTYSH
 | 
			
		||||
	VTYSH_SERV,
 | 
			
		||||
	VTYSH_READ,
 | 
			
		||||
	VTYSH_WRITE
 | 
			
		||||
#endif				/* VTYSH */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct vty {
 | 
			
		||||
	FILE *file;
 | 
			
		||||
 | 
			
		||||
	/* private data, specified by creator */
 | 
			
		||||
	void *priv;
 | 
			
		||||
 | 
			
		||||
	/* 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;
 | 
			
		||||
 | 
			
		||||
	/* IAC handling: was the last character received the IAC
 | 
			
		||||
	 * (interpret-as-command) escape character (and therefore the next
 | 
			
		||||
	 * character will be the command code)?  Refer to Telnet RFC 854. */
 | 
			
		||||
	unsigned char iac;
 | 
			
		||||
 | 
			
		||||
	/* IAC SB (option subnegotiation) handling */
 | 
			
		||||
	unsigned char iac_sb_in_progress;
 | 
			
		||||
	/* At the moment, we care only about the NAWS (window size) negotiation,
 | 
			
		||||
	 * and that requires just a 5-character buffer (RFC 1073):
 | 
			
		||||
	 * <NAWS char> <16-bit width> <16-bit height> */
 | 
			
		||||
#define TELNET_NAWS_SB_LEN 5
 | 
			
		||||
	unsigned char sb_buf[TELNET_NAWS_SB_LEN];
 | 
			
		||||
	/* How many subnegotiation characters have we received?  We just drop
 | 
			
		||||
	 * those that do not fit in the buffer. */
 | 
			
		||||
	size_t sb_len;
 | 
			
		||||
 | 
			
		||||
	/* 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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct vty_app_info {
 | 
			
		||||
	char *name;
 | 
			
		||||
	char *version;
 | 
			
		||||
	char *copyright;
 | 
			
		||||
	void *tall_ctx;
 | 
			
		||||
	enum node_type (*go_parent_cb)(struct vty *vty);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Prototypes. */
 | 
			
		||||
void vty_init(struct vty_app_info *app_info);
 | 
			
		||||
int vty_read_config_file(const char *file_name, void *priv);
 | 
			
		||||
void vty_init_vtysh (void);
 | 
			
		||||
void vty_reset (void);
 | 
			
		||||
struct vty *vty_new (void);
 | 
			
		||||
struct vty *vty_create (int vty_sock, void *priv);
 | 
			
		||||
int vty_out (struct vty *, const char *, ...) VTY_PRINTF_ATTRIBUTE(2, 3);
 | 
			
		||||
int vty_out_newline(struct vty *);
 | 
			
		||||
int vty_read(struct vty *vty);
 | 
			
		||||
//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 *);
 | 
			
		||||
 | 
			
		||||
void *tall_vty_ctx;
 | 
			
		||||
#endif
 | 
			
		||||
@@ -42,6 +42,10 @@ struct bitvec {
 | 
			
		||||
/* check if the bit is 0 or 1 for a given position inside a bitvec */
 | 
			
		||||
enum bit_value bitvec_get_bit_pos(const struct bitvec *bv, unsigned int bitnr);
 | 
			
		||||
 | 
			
		||||
/* check if the bit is L or H for a given position inside a bitvec */
 | 
			
		||||
enum bit_value bitvec_get_bit_pos_high(const struct bitvec *bv,
 | 
			
		||||
					unsigned int bitnr);
 | 
			
		||||
 | 
			
		||||
/* get the Nth set bit inside the bit vector */
 | 
			
		||||
unsigned int bitvec_get_nth_set_bit(const struct bitvec *bv, unsigned int n);
 | 
			
		||||
 | 
			
		||||
@@ -52,12 +56,18 @@ int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnum,
 | 
			
		||||
/* Set the next bit in the vector */
 | 
			
		||||
int bitvec_set_bit(struct bitvec *bv, enum bit_value bit);
 | 
			
		||||
 | 
			
		||||
/* get the next bit (low/high) inside a bitvec */
 | 
			
		||||
int bitvec_get_bit_high(struct bitvec *bv);
 | 
			
		||||
 | 
			
		||||
/* Set multiple bits at the current position */
 | 
			
		||||
int bitvec_set_bits(struct bitvec *bv, enum bit_value *bits, int count);
 | 
			
		||||
 | 
			
		||||
/* Add an unsigned integer (of length count bits) to current position */
 | 
			
		||||
int bitvec_set_uint(struct bitvec *bv, unsigned int in, int count);
 | 
			
		||||
 | 
			
		||||
/* get multiple bits (based on numeric value) from current pos */
 | 
			
		||||
int bitvec_get_uint(struct bitvec *bv, int num_bits);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Pad the bit vector up to a certain bit position */
 | 
			
		||||
int bitvec_spare_padding(struct bitvec *bv, unsigned int up_to_bit);
 | 
			
		||||
 
 | 
			
		||||
@@ -36,6 +36,8 @@ struct msgb *gsm0808_create_assignment_completed(struct gsm_lchan *lchan, uint8_
 | 
			
		||||
						 uint8_t speech_mode);
 | 
			
		||||
struct msgb *gsm0808_create_assignment_failure(uint8_t cause, uint8_t *rr_cause);
 | 
			
		||||
 | 
			
		||||
void gsm0808_prepend_dtap_header(struct msgb *msg, uint8_t link_id);
 | 
			
		||||
 | 
			
		||||
const struct tlv_definition *gsm0808_att_tlvdef();
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -120,6 +120,15 @@ struct gsm48_imm_ass {
 | 
			
		||||
	uint8_t mob_alloc[0];
 | 
			
		||||
} __attribute__ ((packed));
 | 
			
		||||
 | 
			
		||||
/* Chapter 9.1.25 */
 | 
			
		||||
struct gsm48_pag_resp {
 | 
			
		||||
	uint8_t spare:4,
 | 
			
		||||
		 key_seq:4;
 | 
			
		||||
	uint32_t classmark2;
 | 
			
		||||
	uint8_t mi_len;
 | 
			
		||||
	uint8_t mi[0];
 | 
			
		||||
} __attribute__ ((packed));
 | 
			
		||||
 | 
			
		||||
/* Chapter 10.5.1.3 */
 | 
			
		||||
struct gsm48_loc_area_id {
 | 
			
		||||
	uint8_t digits[3];	/* BCD! */
 | 
			
		||||
 
 | 
			
		||||
@@ -34,13 +34,13 @@ struct rate_ctr_desc {
 | 
			
		||||
/* Describe a counter group class */
 | 
			
		||||
struct rate_ctr_group_desc {
 | 
			
		||||
	/* The prefix to the name of all counters in this group */
 | 
			
		||||
	char *group_name_prefix;
 | 
			
		||||
	const char *group_name_prefix;
 | 
			
		||||
	/* The human-readable description of the group */
 | 
			
		||||
	char *group_description;
 | 
			
		||||
	const char *group_description;
 | 
			
		||||
	/* The number of counters in this group */
 | 
			
		||||
	unsigned int num_ctr;
 | 
			
		||||
	const unsigned int num_ctr;
 | 
			
		||||
	/* Pointer to array of counter names */
 | 
			
		||||
	struct rate_ctr_desc *ctr_desc;
 | 
			
		||||
	const struct rate_ctr_desc *ctr_desc;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* One instance of a counter group class */
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								libosmocore/libosmovty.pc.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								libosmocore/libosmovty.pc.in
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
prefix=@prefix@
 | 
			
		||||
exec_prefix=@exec_prefix@
 | 
			
		||||
libdir=@libdir@
 | 
			
		||||
includedir=@includedir@
 | 
			
		||||
 | 
			
		||||
Name: Osmocom VTY Interface Library
 | 
			
		||||
Description: C Utility Library
 | 
			
		||||
Version: @VERSION@
 | 
			
		||||
Libs: -L${libdir} -losmovty
 | 
			
		||||
Cflags: -I${includedir}/
 | 
			
		||||
 | 
			
		||||
@@ -1,3 +1,5 @@
 | 
			
		||||
SUBDIRS=vty
 | 
			
		||||
 | 
			
		||||
# This is _NOT_ the library release version, it's an API version.
 | 
			
		||||
# Please read Chapter 6 "Library interface versions" of the libtool documentation before making any modification
 | 
			
		||||
LIBVERSION=0:0:0
 | 
			
		||||
 
 | 
			
		||||
@@ -77,6 +77,25 @@ enum bit_value bitvec_get_bit_pos(const struct bitvec *bv, unsigned int bitnr)
 | 
			
		||||
	return ZERO;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* check if the bit is L or H for a given position inside a bitvec */
 | 
			
		||||
enum bit_value bitvec_get_bit_pos_high(const struct bitvec *bv,
 | 
			
		||||
					unsigned int bitnr)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int bytenum = bytenum_from_bitnum(bitnr);
 | 
			
		||||
	unsigned int bitnum = 7 - (bitnr % 8);
 | 
			
		||||
	uint8_t bitval;
 | 
			
		||||
 | 
			
		||||
	if (bytenum >= bv->data_len)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	bitval = bitval2mask(H, bitnum);
 | 
			
		||||
 | 
			
		||||
	if (bv->data[bytenum] & bitval)
 | 
			
		||||
		return H;
 | 
			
		||||
 | 
			
		||||
	return L;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* get the Nth set bit inside the bit vector */
 | 
			
		||||
unsigned int bitvec_get_nth_set_bit(const struct bitvec *bv, unsigned int n)
 | 
			
		||||
{
 | 
			
		||||
@@ -127,6 +146,18 @@ int bitvec_set_bit(struct bitvec *bv, enum bit_value bit)
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* get the next bit (low/high) inside a bitvec */
 | 
			
		||||
int bitvec_get_bit_high(struct bitvec *bv)
 | 
			
		||||
{
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	rc = bitvec_get_bit_pos_high(bv, bv->cur_bit);
 | 
			
		||||
	if (rc >= 0)
 | 
			
		||||
		bv->cur_bit++;
 | 
			
		||||
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* set multiple bits (based on array of bitvals) at current pos */
 | 
			
		||||
int bitvec_set_bits(struct bitvec *bv, enum bit_value *bits, int count)
 | 
			
		||||
{
 | 
			
		||||
@@ -158,6 +189,24 @@ int bitvec_set_uint(struct bitvec *bv, unsigned int ui, int num_bits)
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* get multiple bits (based on numeric value) from current pos */
 | 
			
		||||
int bitvec_get_uint(struct bitvec *bv, int num_bits)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	unsigned int ui = 0;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < num_bits; i++) {
 | 
			
		||||
		int bit = bitvec_get_bit_pos(bv, bv->cur_bit);
 | 
			
		||||
		if (bit < 0)
 | 
			
		||||
			return bit;
 | 
			
		||||
		if (bit)
 | 
			
		||||
			ui |= (1 << (num_bits - i - 1));
 | 
			
		||||
		bv->cur_bit++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ui;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* pad all remaining bits up to num_bits */
 | 
			
		||||
int bitvec_spare_padding(struct bitvec *bv, unsigned int up_to_bit)
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -266,6 +266,14 @@ struct msgb *gsm0808_create_assignment_failure(uint8_t cause, uint8_t *rr_cause)
 | 
			
		||||
	return msg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void gsm0808_prepend_dtap_header(struct msgb *msg, uint8_t link_id)
 | 
			
		||||
{
 | 
			
		||||
	uint8_t *hh = msgb_push(msg, 3);
 | 
			
		||||
	hh[0] = BSSAP_MSG_DTAP;
 | 
			
		||||
	hh[1] = link_id;
 | 
			
		||||
	hh[2] = msg->len - 3;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct tlv_definition bss_att_tlvdef = {
 | 
			
		||||
	.def = {
 | 
			
		||||
		[GSM0808_IE_IMSI]		    = { TLV_TYPE_TLV },
 | 
			
		||||
@@ -286,6 +294,9 @@ static const struct tlv_definition bss_att_tlvdef = {
 | 
			
		||||
		[GSM0808_IE_SERVICE_HANDOVER]	    = { TLV_TYPE_TV},
 | 
			
		||||
		[GSM0808_IE_ENCRYPTION_INFORMATION] = { TLV_TYPE_TLV },
 | 
			
		||||
		[GSM0808_IE_CIPHER_RESPONSE_MODE]   = { TLV_TYPE_TV },
 | 
			
		||||
		[GSM0808_IE_CELL_IDENTIFIER]	    = { TLV_TYPE_TLV },
 | 
			
		||||
		[GSM0808_IE_CHOSEN_CHANNEL]	    = { TLV_TYPE_TV },
 | 
			
		||||
		[GSM0808_IE_LAYER_3_INFORMATION]    = { TLV_TYPE_TLV },
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -37,7 +37,7 @@
 | 
			
		||||
#include <osmocore/utils.h>
 | 
			
		||||
#include <osmocore/logging.h>
 | 
			
		||||
 | 
			
		||||
static const struct log_info *log_info;
 | 
			
		||||
const struct log_info *osmo_log_info;
 | 
			
		||||
 | 
			
		||||
static struct log_context log_context;
 | 
			
		||||
static void *tall_log_ctx = NULL;
 | 
			
		||||
@@ -67,8 +67,8 @@ int log_parse_category(const char *category)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < log_info->num_cat; ++i) {
 | 
			
		||||
		if (!strcasecmp(log_info->cat[i].name+1, category))
 | 
			
		||||
	for (i = 0; i < osmo_log_info->num_cat; ++i) {
 | 
			
		||||
		if (!strcasecmp(osmo_log_info->cat[i].name+1, category))
 | 
			
		||||
			return i;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -92,15 +92,15 @@ void log_parse_category_mask(struct log_target* target, const char *_mask)
 | 
			
		||||
 | 
			
		||||
	category_token = strtok(mask, ":");
 | 
			
		||||
	do {
 | 
			
		||||
		for (i = 0; i < log_info->num_cat; ++i) {
 | 
			
		||||
		for (i = 0; i < osmo_log_info->num_cat; ++i) {
 | 
			
		||||
			char* colon = strstr(category_token, ",");
 | 
			
		||||
			int length = strlen(category_token);
 | 
			
		||||
 | 
			
		||||
			if (colon)
 | 
			
		||||
			    length = colon - category_token;
 | 
			
		||||
 | 
			
		||||
			if (strncasecmp(log_info->cat[i].name, category_token,
 | 
			
		||||
					length) == 0) {
 | 
			
		||||
			if (strncasecmp(osmo_log_info->cat[i].name,
 | 
			
		||||
					category_token, length) == 0) {
 | 
			
		||||
				int level = 0;
 | 
			
		||||
 | 
			
		||||
				if (colon)
 | 
			
		||||
@@ -117,8 +117,8 @@ void log_parse_category_mask(struct log_target* target, const char *_mask)
 | 
			
		||||
 | 
			
		||||
static const char* color(int subsys)
 | 
			
		||||
{
 | 
			
		||||
	if (subsys < log_info->num_cat)
 | 
			
		||||
		return log_info->cat[subsys].color;
 | 
			
		||||
	if (subsys < osmo_log_info->num_cat)
 | 
			
		||||
		return osmo_log_info->cat[subsys].color;
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
@@ -198,8 +198,8 @@ static void _logp(unsigned int subsys, int level, char *file, int line,
 | 
			
		||||
		 * say stop, continue, output */
 | 
			
		||||
		if ((tar->filter_map & LOG_FILTER_ALL) != 0)
 | 
			
		||||
			output = 1;
 | 
			
		||||
		else if (log_info->filter_fn)
 | 
			
		||||
			output = log_info->filter_fn(&log_context,
 | 
			
		||||
		else if (osmo_log_info->filter_fn)
 | 
			
		||||
			output = osmo_log_info->filter_fn(&log_context,
 | 
			
		||||
						       tar);
 | 
			
		||||
 | 
			
		||||
		if (output) {
 | 
			
		||||
@@ -306,7 +306,7 @@ void log_set_log_level(struct log_target *target, int log_level)
 | 
			
		||||
void log_set_category_filter(struct log_target *target, int category,
 | 
			
		||||
			       int enable, int level)
 | 
			
		||||
{
 | 
			
		||||
	if (category >= log_info->num_cat)
 | 
			
		||||
	if (category >= osmo_log_info->num_cat)
 | 
			
		||||
		return;
 | 
			
		||||
	target->categories[category].enabled = !!enable;
 | 
			
		||||
	target->categories[category].loglevel = level;
 | 
			
		||||
@@ -333,10 +333,10 @@ struct log_target *log_target_create(void)
 | 
			
		||||
	INIT_LLIST_HEAD(&target->entry);
 | 
			
		||||
 | 
			
		||||
	/* initialize the per-category enabled/loglevel from defaults */
 | 
			
		||||
	for (i = 0; i < log_info->num_cat; i++) {
 | 
			
		||||
	for (i = 0; i < osmo_log_info->num_cat; i++) {
 | 
			
		||||
		struct log_category *cat = &target->categories[i];
 | 
			
		||||
		cat->enabled = log_info->cat[i].enabled;
 | 
			
		||||
		cat->loglevel = log_info->cat[i].loglevel;
 | 
			
		||||
		cat->enabled = osmo_log_info->cat[i].enabled;
 | 
			
		||||
		cat->loglevel = osmo_log_info->cat[i].loglevel;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* global settings */
 | 
			
		||||
@@ -415,5 +415,5 @@ const char *log_vty_category_string(struct log_info *info)
 | 
			
		||||
void log_init(const struct log_info *cat)
 | 
			
		||||
{
 | 
			
		||||
	tall_log_ctx = talloc_named_const(NULL, 1, "logging");
 | 
			
		||||
	log_info = cat;
 | 
			
		||||
	osmo_log_info = cat;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,7 @@
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocore/utils.h>
 | 
			
		||||
#include <osmocore/linuxlist.h>
 | 
			
		||||
#include <osmocore/talloc.h>
 | 
			
		||||
#include <osmocore/timer.h>
 | 
			
		||||
@@ -75,6 +76,11 @@ static void interval_expired(struct rate_ctr *ctr, enum rate_ctr_intv intv)
 | 
			
		||||
	ctr->intv[intv].rate = ctr->current - ctr->intv[intv].last;
 | 
			
		||||
	/* save current counter for next interval */
 | 
			
		||||
	ctr->intv[intv].last = ctr->current;
 | 
			
		||||
 | 
			
		||||
	/* update the rate of the next bigger interval.  This will
 | 
			
		||||
	 * be overwritten when that next larger interval expires */
 | 
			
		||||
	if (intv + 1 < ARRAY_SIZE(ctr->intv))
 | 
			
		||||
		ctr->intv[intv+1].rate += ctr->intv[intv].rate;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct timer_list rate_ctr_timer;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								libosmocore/src/vty/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								libosmocore/src/vty/Makefile.am
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
# This is _NOT_ the library release version, it's an API version.
 | 
			
		||||
# Please read Chapter 6 "Library interface versions" of the libtool documentation before making any modification
 | 
			
		||||
LIBVERSION=0:0:0
 | 
			
		||||
 | 
			
		||||
INCLUDES = $(all_includes) -I$(top_srcdir)/include
 | 
			
		||||
AM_CFLAGS = -fPIC -Wall
 | 
			
		||||
 | 
			
		||||
lib_LTLIBRARIES = libosmovty.la
 | 
			
		||||
 | 
			
		||||
libosmovty_la_SOURCES = buffer.c command.c vty.c vector.c utils.c \
 | 
			
		||||
			telnet_interface.c logging_vty.c
 | 
			
		||||
							
								
								
									
										463
									
								
								libosmocore/src/vty/buffer.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										463
									
								
								libosmocore/src/vty/buffer.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,463 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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 <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <sys/uio.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocore/talloc.h>
 | 
			
		||||
#include <osmocom/vty/buffer.h>
 | 
			
		||||
#include <osmocom/vty/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) talloc_free((D))
 | 
			
		||||
 | 
			
		||||
/* Make new buffer. */
 | 
			
		||||
struct buffer *buffer_new(void *ctx, size_t size)
 | 
			
		||||
{
 | 
			
		||||
	struct buffer *b;
 | 
			
		||||
 | 
			
		||||
	b = talloc_zero(ctx, 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);
 | 
			
		||||
	talloc_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 = _talloc_zero(tall_vty_ctx, (totlen + 1), "buffer_getstr")))
 | 
			
		||||
		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 = _talloc_zero(b,
 | 
			
		||||
			 offsetof(struct buffer_data, data[b->size]),
 | 
			
		||||
			 "buffer_add");
 | 
			
		||||
	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 <sys/uio.h> , 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;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										3177
									
								
								libosmocore/src/vty/command.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3177
									
								
								libosmocore/src/vty/command.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										347
									
								
								libosmocore/src/vty/logging_vty.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										347
									
								
								libosmocore/src/vty/logging_vty.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,347 @@
 | 
			
		||||
/* OpenBSC logging helper for the VTY */
 | 
			
		||||
/* (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
 | 
			
		||||
 * (C) 2009-2010 by Holger Hans Peter Freyther
 | 
			
		||||
 * All Rights Reserved
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License along
 | 
			
		||||
 * with this program; if not, write to the Free Software Foundation, Inc.,
 | 
			
		||||
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocore/talloc.h>
 | 
			
		||||
#include <osmocore/logging.h>
 | 
			
		||||
 | 
			
		||||
//#include <openbsc/vty.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/vty/command.h>
 | 
			
		||||
#include <osmocom/vty/buffer.h>
 | 
			
		||||
#include <osmocom/vty/vty.h>
 | 
			
		||||
#include <osmocom/vty/telnet_interface.h>
 | 
			
		||||
#include <osmocom/vty/logging.h>
 | 
			
		||||
 | 
			
		||||
extern const struct log_info *osmo_log_info;
 | 
			
		||||
 | 
			
		||||
static void _vty_output(struct log_target *tgt, const char *line)
 | 
			
		||||
{
 | 
			
		||||
	struct vty *vty = tgt->tgt_vty.vty;
 | 
			
		||||
	vty_out(vty, "%s", line);
 | 
			
		||||
	/* This is an ugly hack, but there is no easy way... */
 | 
			
		||||
	if (strchr(line, '\n'))
 | 
			
		||||
		vty_out(vty, "\r");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct log_target *log_target_create_vty(struct vty *vty)
 | 
			
		||||
{
 | 
			
		||||
	struct log_target *target;
 | 
			
		||||
 | 
			
		||||
	target = log_target_create();
 | 
			
		||||
	if (!target)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	target->tgt_vty.vty = vty;
 | 
			
		||||
	target->output = _vty_output;
 | 
			
		||||
	return target;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEFUN(enable_logging,
 | 
			
		||||
      enable_logging_cmd,
 | 
			
		||||
      "logging enable",
 | 
			
		||||
	LOGGING_STR
 | 
			
		||||
      "Enables logging to this vty\n")
 | 
			
		||||
{
 | 
			
		||||
	struct telnet_connection *conn;
 | 
			
		||||
 | 
			
		||||
	conn = (struct telnet_connection *) vty->priv;
 | 
			
		||||
	if (conn->dbg) {
 | 
			
		||||
		vty_out(vty, "Logging already enabled.%s", VTY_NEWLINE);
 | 
			
		||||
		return CMD_WARNING;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	conn->dbg = log_target_create_vty(vty);
 | 
			
		||||
	if (!conn->dbg)
 | 
			
		||||
		return CMD_WARNING;
 | 
			
		||||
 | 
			
		||||
	log_add_target(conn->dbg);
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEFUN(logging_fltr_all,
 | 
			
		||||
      logging_fltr_all_cmd,
 | 
			
		||||
      "logging filter all (0|1)",
 | 
			
		||||
	LOGGING_STR FILTER_STR
 | 
			
		||||
	"Do you want to log all messages?\n"
 | 
			
		||||
	"Only print messages matched by other filters\n"
 | 
			
		||||
	"Bypass filter and print all messages\n")
 | 
			
		||||
{
 | 
			
		||||
	struct telnet_connection *conn;
 | 
			
		||||
 | 
			
		||||
	conn = (struct telnet_connection *) vty->priv;
 | 
			
		||||
	if (!conn->dbg) {
 | 
			
		||||
		vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
 | 
			
		||||
		return CMD_WARNING;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_set_all_filter(conn->dbg, atoi(argv[0]));
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEFUN(logging_use_clr,
 | 
			
		||||
      logging_use_clr_cmd,
 | 
			
		||||
      "logging color (0|1)",
 | 
			
		||||
	LOGGING_STR "Configure color-printing for log messages\n"
 | 
			
		||||
      "Don't use color for printing messages\n"
 | 
			
		||||
      "Use color for printing messages\n")
 | 
			
		||||
{
 | 
			
		||||
	struct telnet_connection *conn;
 | 
			
		||||
 | 
			
		||||
	conn = (struct telnet_connection *) vty->priv;
 | 
			
		||||
	if (!conn->dbg) {
 | 
			
		||||
		vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
 | 
			
		||||
		return CMD_WARNING;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_set_use_color(conn->dbg, atoi(argv[0]));
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEFUN(logging_prnt_timestamp,
 | 
			
		||||
      logging_prnt_timestamp_cmd,
 | 
			
		||||
      "logging timestamp (0|1)",
 | 
			
		||||
	LOGGING_STR "Configure log message timestamping\n"
 | 
			
		||||
	"Don't prefix each log message\n"
 | 
			
		||||
	"Prefix each log message with current timestamp\n")
 | 
			
		||||
{
 | 
			
		||||
	struct telnet_connection *conn;
 | 
			
		||||
 | 
			
		||||
	conn = (struct telnet_connection *) vty->priv;
 | 
			
		||||
	if (!conn->dbg) {
 | 
			
		||||
		vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
 | 
			
		||||
		return CMD_WARNING;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_set_print_timestamp(conn->dbg, atoi(argv[0]));
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* FIXME: those have to be kept in sync with the log levels and categories */
 | 
			
		||||
#define VTY_DEBUG_CATEGORIES "(rll|cc|mm|rr|rsl|nm|sms|pag|mncc|inp|mi|mib|mux|meas|sccp|msc|mgcp|ho|db|ref|gprs|ns|bssgp|llc|sndcp|all)"
 | 
			
		||||
#define CATEGORIES_HELP	\
 | 
			
		||||
	"A-bis Radio Link Layer (RLL)\n"			\
 | 
			
		||||
	"Layer3 Call Control (CC)\n"				\
 | 
			
		||||
	"Layer3 Mobility Management (MM)\n"			\
 | 
			
		||||
	"Layer3 Radio Resource (RR)\n"				\
 | 
			
		||||
	"A-bis Radio Signalling Link (RSL)\n"			\
 | 
			
		||||
	"A-bis Network Management / O&M (NM/OML)\n"		\
 | 
			
		||||
	"Layer3 Short Messagaging Service (SMS)\n"		\
 | 
			
		||||
	"Paging Subsystem\n"					\
 | 
			
		||||
	"MNCC API for Call Control application\n"		\
 | 
			
		||||
	"A-bis Input Subsystem\n"				\
 | 
			
		||||
	"A-bis Input Driver for Signalling\n"			\
 | 
			
		||||
	"A-bis Input Driver for B-Channel (voice data)\n"	\
 | 
			
		||||
	"A-bis B-Channel / Sub-channel Multiplexer\n"		\
 | 
			
		||||
	"Radio Measurements\n"					\
 | 
			
		||||
	"SCCP\n"						\
 | 
			
		||||
	"Mobile Switching Center\n"				\
 | 
			
		||||
	"Media Gateway Control Protocol\n"			\
 | 
			
		||||
	"Hand-over\n"						\
 | 
			
		||||
	"Database Layer\n"					\
 | 
			
		||||
	"Reference Counting\n"					\
 | 
			
		||||
	"GPRS Core\n"						\
 | 
			
		||||
	"GPRS Network Service (NS)\n"				\
 | 
			
		||||
	"GPRS BSS Gateway Protocol (BSSGP)\n"			\
 | 
			
		||||
	"GPRS Logical Link Control Protocol (LLC)\n"		\
 | 
			
		||||
	"GPRS Sub-Network Dependent Control Protocol (SNDCP)\n"	\
 | 
			
		||||
	"Global setting for all subsytems\n"
 | 
			
		||||
 | 
			
		||||
#define VTY_DEBUG_LEVELS "(everything|debug|info|notice|error|fatal)"
 | 
			
		||||
#define LEVELS_HELP	\
 | 
			
		||||
	"Log simply everything\n"				\
 | 
			
		||||
	"Log debug messages and higher levels\n"		\
 | 
			
		||||
	"Log informational messages and higher levels\n"	\
 | 
			
		||||
	"Log noticable messages and higher levels\n"		\
 | 
			
		||||
	"Log error messages and higher levels\n"		\
 | 
			
		||||
	"Log only fatal messages\n"
 | 
			
		||||
DEFUN(logging_level,
 | 
			
		||||
      logging_level_cmd,
 | 
			
		||||
      "logging level " VTY_DEBUG_CATEGORIES " " VTY_DEBUG_LEVELS,
 | 
			
		||||
      LOGGING_STR
 | 
			
		||||
      "Set the log level for a specified category\n"
 | 
			
		||||
      CATEGORIES_HELP
 | 
			
		||||
      LEVELS_HELP)
 | 
			
		||||
{
 | 
			
		||||
	struct telnet_connection *conn;
 | 
			
		||||
	int category = log_parse_category(argv[0]);
 | 
			
		||||
	int level = log_parse_level(argv[1]);
 | 
			
		||||
 | 
			
		||||
	conn = (struct telnet_connection *) vty->priv;
 | 
			
		||||
	if (!conn->dbg) {
 | 
			
		||||
		vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
 | 
			
		||||
		return CMD_WARNING;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (level < 0) {
 | 
			
		||||
		vty_out(vty, "Invalid level `%s'%s", argv[1], VTY_NEWLINE);
 | 
			
		||||
		return CMD_WARNING;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Check for special case where we want to set global log level */
 | 
			
		||||
	if (!strcmp(argv[0], "all")) {
 | 
			
		||||
		log_set_log_level(conn->dbg, level);
 | 
			
		||||
		return CMD_SUCCESS;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (category < 0) {
 | 
			
		||||
		vty_out(vty, "Invalid category `%s'%s", argv[0], VTY_NEWLINE);
 | 
			
		||||
		return CMD_WARNING;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	conn->dbg->categories[category].enabled = 1;
 | 
			
		||||
	conn->dbg->categories[category].loglevel = level;
 | 
			
		||||
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEFUN(logging_set_category_mask,
 | 
			
		||||
      logging_set_category_mask_cmd,
 | 
			
		||||
      "logging set log mask MASK",
 | 
			
		||||
	LOGGING_STR
 | 
			
		||||
      "Decide which categories to output.\n")
 | 
			
		||||
{
 | 
			
		||||
	struct telnet_connection *conn;
 | 
			
		||||
 | 
			
		||||
	conn = (struct telnet_connection *) vty->priv;
 | 
			
		||||
	if (!conn->dbg) {
 | 
			
		||||
		vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
 | 
			
		||||
		return CMD_WARNING;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_parse_category_mask(conn->dbg, argv[0]);
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEFUN(diable_logging,
 | 
			
		||||
      disable_logging_cmd,
 | 
			
		||||
      "logging disable",
 | 
			
		||||
	LOGGING_STR
 | 
			
		||||
      "Disables logging to this vty\n")
 | 
			
		||||
{
 | 
			
		||||
	struct telnet_connection *conn;
 | 
			
		||||
 | 
			
		||||
	conn = (struct telnet_connection *) vty->priv;
 | 
			
		||||
	if (!conn->dbg) {
 | 
			
		||||
		vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
 | 
			
		||||
		return CMD_WARNING;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_del_target(conn->dbg);
 | 
			
		||||
	talloc_free(conn->dbg);
 | 
			
		||||
	conn->dbg = NULL;
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void vty_print_logtarget(struct vty *vty, const struct log_info *info,
 | 
			
		||||
				const struct log_target *tgt)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
 | 
			
		||||
	vty_out(vty, " Global Loglevel: %s%s",
 | 
			
		||||
		log_level_str(tgt->loglevel), VTY_NEWLINE);
 | 
			
		||||
	vty_out(vty, " Use color: %s, Print Timestamp: %s%s",
 | 
			
		||||
		tgt->use_color ? "On" : "Off",
 | 
			
		||||
		tgt->print_timestamp ? "On" : "Off", VTY_NEWLINE);
 | 
			
		||||
 | 
			
		||||
	vty_out(vty, " Log Level specific information:%s", VTY_NEWLINE);
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < info->num_cat; i++) {
 | 
			
		||||
		const struct log_category *cat = &tgt->categories[i];
 | 
			
		||||
		vty_out(vty, "  %-10s %-10s %-8s %s%s",
 | 
			
		||||
			info->cat[i].name+1, log_level_str(cat->loglevel),
 | 
			
		||||
			cat->enabled ? "Enabled" : "Disabled",
 | 
			
		||||
 			info->cat[i].description,
 | 
			
		||||
			VTY_NEWLINE);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define SHOW_LOG_STR "Show current logging configuration\n"
 | 
			
		||||
 | 
			
		||||
DEFUN(show_logging_vty,
 | 
			
		||||
      show_logging_vty_cmd,
 | 
			
		||||
      "show logging vty",
 | 
			
		||||
	SHOW_STR SHOW_LOG_STR
 | 
			
		||||
	"Show current logging configuration for this vty\n")
 | 
			
		||||
{
 | 
			
		||||
	struct telnet_connection *conn;
 | 
			
		||||
 | 
			
		||||
	conn = (struct telnet_connection *) vty->priv;
 | 
			
		||||
	if (!conn->dbg) {
 | 
			
		||||
		vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
 | 
			
		||||
		return CMD_WARNING;
 | 
			
		||||
	}
 | 
			
		||||
	vty_print_logtarget(vty, osmo_log_info, conn->dbg);
 | 
			
		||||
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gDEFUN(cfg_description, cfg_description_cmd,
 | 
			
		||||
	"description .TEXT",
 | 
			
		||||
	"Save human-readable decription of the object\n")
 | 
			
		||||
{
 | 
			
		||||
	char **dptr = vty->index_sub;
 | 
			
		||||
 | 
			
		||||
	if (!dptr) {
 | 
			
		||||
		vty_out(vty, "vty->index_sub == NULL%s", VTY_NEWLINE);
 | 
			
		||||
		return CMD_WARNING;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	*dptr = argv_concat(argv, argc, 0);
 | 
			
		||||
	if (!dptr)
 | 
			
		||||
		return CMD_WARNING;
 | 
			
		||||
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gDEFUN(cfg_no_description, cfg_no_description_cmd,
 | 
			
		||||
	"no description",
 | 
			
		||||
	NO_STR
 | 
			
		||||
	"Remove description of the object\n")
 | 
			
		||||
{
 | 
			
		||||
	char **dptr = vty->index_sub;
 | 
			
		||||
 | 
			
		||||
	if (!dptr) {
 | 
			
		||||
		vty_out(vty, "vty->index_sub == NULL%s", VTY_NEWLINE);
 | 
			
		||||
		return CMD_WARNING;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (*dptr) {
 | 
			
		||||
		talloc_free(*dptr);
 | 
			
		||||
		*dptr = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void logging_vty_add_cmds()
 | 
			
		||||
{
 | 
			
		||||
	install_element_ve(&enable_logging_cmd);
 | 
			
		||||
	install_element_ve(&disable_logging_cmd);
 | 
			
		||||
	install_element_ve(&logging_fltr_all_cmd);
 | 
			
		||||
	install_element_ve(&logging_use_clr_cmd);
 | 
			
		||||
	install_element_ve(&logging_prnt_timestamp_cmd);
 | 
			
		||||
	install_element_ve(&logging_set_category_mask_cmd);
 | 
			
		||||
	install_element_ve(&logging_level_cmd);
 | 
			
		||||
	install_element_ve(&show_logging_vty_cmd);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										203
									
								
								libosmocore/src/vty/telnet_interface.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								libosmocore/src/vty/telnet_interface.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,203 @@
 | 
			
		||||
/* minimalistic telnet/network interface it might turn into a wire interface */
 | 
			
		||||
/* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
 | 
			
		||||
 * All Rights Reserved
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License along
 | 
			
		||||
 * with this program; if not, write to the Free Software Foundation, Inc.,
 | 
			
		||||
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocore/msgb.h>
 | 
			
		||||
#include <osmocore/talloc.h>
 | 
			
		||||
#include <osmocore/logging.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/vty/telnet_interface.h>
 | 
			
		||||
#include <osmocom/vty/buffer.h>
 | 
			
		||||
 | 
			
		||||
/* per connection data */
 | 
			
		||||
LLIST_HEAD(active_connections);
 | 
			
		||||
 | 
			
		||||
static void *tall_telnet_ctx;
 | 
			
		||||
 | 
			
		||||
/* per network data */
 | 
			
		||||
static int telnet_new_connection(struct bsc_fd *fd, unsigned int what);
 | 
			
		||||
 | 
			
		||||
static struct bsc_fd server_socket = {
 | 
			
		||||
	.when	    = BSC_FD_READ,
 | 
			
		||||
	.cb	    = telnet_new_connection,
 | 
			
		||||
	.priv_nr    = 0,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int telnet_init(void *tall_ctx, void *priv, int port)
 | 
			
		||||
{
 | 
			
		||||
	struct sockaddr_in sock_addr;
 | 
			
		||||
	int fd, rc, on = 1;
 | 
			
		||||
 | 
			
		||||
	tall_telnet_ctx = talloc_named_const(tall_ctx, 1,
 | 
			
		||||
					     "telnet_connection");
 | 
			
		||||
 | 
			
		||||
	fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
 | 
			
		||||
 | 
			
		||||
	if (fd < 0) {
 | 
			
		||||
		LOGP(0, LOGL_ERROR, "Telnet interface socket creation failed\n");
 | 
			
		||||
		return fd;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
 | 
			
		||||
 | 
			
		||||
	memset(&sock_addr, 0, sizeof(sock_addr));
 | 
			
		||||
	sock_addr.sin_family = AF_INET;
 | 
			
		||||
	sock_addr.sin_port = htons(port);
 | 
			
		||||
	sock_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
 | 
			
		||||
 | 
			
		||||
	rc = bind(fd, (struct sockaddr*)&sock_addr, sizeof(sock_addr));
 | 
			
		||||
	if (bind < 0) {
 | 
			
		||||
		LOGP(0, LOGL_ERROR, "Telnet interface failed to bind\n");
 | 
			
		||||
		close(fd);
 | 
			
		||||
		return rc;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rc = listen(fd, 0);
 | 
			
		||||
	if (rc < 0) {
 | 
			
		||||
		LOGP(0, LOGL_ERROR, "Telnet interface failed to listen\n");
 | 
			
		||||
		close(fd);
 | 
			
		||||
		return rc;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	server_socket.data = priv;
 | 
			
		||||
	server_socket.fd = fd;
 | 
			
		||||
	bsc_register_fd(&server_socket);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern const char *openbsc_copyright;
 | 
			
		||||
 | 
			
		||||
static void print_welcome(int fd)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	static char *msg =
 | 
			
		||||
		"Welcome to the OpenBSC Control interface\n";
 | 
			
		||||
 | 
			
		||||
	ret = write(fd, msg, strlen(msg));
 | 
			
		||||
	ret = write(fd, openbsc_copyright, strlen(openbsc_copyright));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int telnet_close_client(struct bsc_fd *fd)
 | 
			
		||||
{
 | 
			
		||||
	struct telnet_connection *conn = (struct telnet_connection*)fd->data;
 | 
			
		||||
 | 
			
		||||
	close(fd->fd);
 | 
			
		||||
	bsc_unregister_fd(fd);
 | 
			
		||||
 | 
			
		||||
	if (conn->dbg) {
 | 
			
		||||
		log_del_target(conn->dbg);
 | 
			
		||||
		talloc_free(conn->dbg);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	llist_del(&conn->entry);
 | 
			
		||||
	talloc_free(conn);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int client_data(struct bsc_fd *fd, unsigned int what)
 | 
			
		||||
{
 | 
			
		||||
	struct telnet_connection *conn = fd->data;
 | 
			
		||||
	int rc = 0;
 | 
			
		||||
 | 
			
		||||
	if (what & BSC_FD_READ) {
 | 
			
		||||
		conn->fd.when &= ~BSC_FD_READ;
 | 
			
		||||
		rc = vty_read(conn->vty);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* vty might have been closed from vithin vty_read() */
 | 
			
		||||
	if (!conn->vty)
 | 
			
		||||
		return rc;
 | 
			
		||||
 | 
			
		||||
	if (what & BSC_FD_WRITE) {
 | 
			
		||||
		rc = buffer_flush_all(conn->vty->obuf, fd->fd);
 | 
			
		||||
		if (rc == BUFFER_EMPTY)
 | 
			
		||||
			conn->fd.when &= ~BSC_FD_WRITE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int telnet_new_connection(struct bsc_fd *fd, unsigned int what)
 | 
			
		||||
{
 | 
			
		||||
	struct telnet_connection *connection;
 | 
			
		||||
	struct sockaddr_in sockaddr;
 | 
			
		||||
	socklen_t len = sizeof(sockaddr);
 | 
			
		||||
	int new_connection = accept(fd->fd, (struct sockaddr*)&sockaddr, &len);
 | 
			
		||||
 | 
			
		||||
	if (new_connection < 0) {
 | 
			
		||||
		LOGP(0, LOGL_ERROR, "telnet accept failed\n");
 | 
			
		||||
		return new_connection;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	connection = talloc_zero(tall_telnet_ctx, struct telnet_connection);
 | 
			
		||||
	connection->priv = fd->data;
 | 
			
		||||
	connection->fd.data = connection;
 | 
			
		||||
	connection->fd.fd = new_connection;
 | 
			
		||||
	connection->fd.when = BSC_FD_READ;
 | 
			
		||||
	connection->fd.cb = client_data;
 | 
			
		||||
	bsc_register_fd(&connection->fd);
 | 
			
		||||
	llist_add_tail(&connection->entry, &active_connections);
 | 
			
		||||
 | 
			
		||||
	print_welcome(new_connection);
 | 
			
		||||
 | 
			
		||||
	connection->vty = vty_create(new_connection, connection);
 | 
			
		||||
	if (!connection->vty) {
 | 
			
		||||
		LOGP(0, LOGL_ERROR, "couldn't create VTY\n");
 | 
			
		||||
		close(new_connection);
 | 
			
		||||
		talloc_free(connection);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* callback from VTY code */
 | 
			
		||||
void vty_event(enum event event, int sock, struct vty *vty)
 | 
			
		||||
{
 | 
			
		||||
	struct telnet_connection *connection = vty->priv;
 | 
			
		||||
	struct bsc_fd *bfd = &connection->fd;
 | 
			
		||||
 | 
			
		||||
	if (vty->type != VTY_TERM)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	switch (event) {
 | 
			
		||||
	case VTY_READ:
 | 
			
		||||
		bfd->when |= BSC_FD_READ;
 | 
			
		||||
		break;
 | 
			
		||||
	case VTY_WRITE:
 | 
			
		||||
		bfd->when |= BSC_FD_WRITE;
 | 
			
		||||
		break;
 | 
			
		||||
	case VTY_CLOSED:
 | 
			
		||||
		/* vty layer is about to free() vty */
 | 
			
		||||
		connection->vty = NULL;
 | 
			
		||||
		telnet_close_client(bfd);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										50
									
								
								libosmocore/src/vty/utils.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								libosmocore/src/vty/utils.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
			
		||||
/* utility routines for printing common objects in the Osmocom world */
 | 
			
		||||
 | 
			
		||||
/* (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
 | 
			
		||||
 *
 | 
			
		||||
 * All Rights Reserved
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License along
 | 
			
		||||
 * with this program; if not, write to the Free Software Foundation, Inc.,
 | 
			
		||||
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocore/linuxlist.h>
 | 
			
		||||
#include <osmocore/talloc.h>
 | 
			
		||||
#include <osmocore/timer.h>
 | 
			
		||||
#include <osmocore/rate_ctr.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/vty/vty.h>
 | 
			
		||||
 | 
			
		||||
void vty_out_rate_ctr_group(struct vty *vty, const char *prefix,
 | 
			
		||||
			    struct rate_ctr_group *ctrg)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
 | 
			
		||||
	vty_out(vty, "%s%s:%s", prefix, ctrg->desc->group_description, VTY_NEWLINE);
 | 
			
		||||
	for (i = 0; i < ctrg->desc->num_ctr; i++) {
 | 
			
		||||
		struct rate_ctr *ctr = &ctrg->ctr[i];
 | 
			
		||||
		vty_out(vty, " %s%s: %8" PRIu64 " "
 | 
			
		||||
			"(%" PRIu64 "/s %" PRIu64 "/m %" PRIu64 "/h %" PRIu64 "/d)%s",
 | 
			
		||||
			prefix, ctrg->desc->ctr_desc[i].description, ctr->current,
 | 
			
		||||
			ctr->intv[RATE_CTR_INTV_SEC].rate,
 | 
			
		||||
			ctr->intv[RATE_CTR_INTV_MIN].rate,
 | 
			
		||||
			ctr->intv[RATE_CTR_INTV_HOUR].rate,
 | 
			
		||||
			ctr->intv[RATE_CTR_INTV_DAY].rate,
 | 
			
		||||
			VTY_NEWLINE);
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										192
									
								
								libosmocore/src/vty/vector.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								libosmocore/src/vty/vector.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,192 @@
 | 
			
		||||
/* 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 <stdlib.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/vty/vector.h>
 | 
			
		||||
#include <osmocom/vty/vty.h>
 | 
			
		||||
#include <osmocore/talloc.h>
 | 
			
		||||
#include <memory.h>
 | 
			
		||||
 | 
			
		||||
void *tall_vty_vec_ctx;
 | 
			
		||||
 | 
			
		||||
/* Initialize vector : allocate memory and return vector. */
 | 
			
		||||
vector vector_init(unsigned int size)
 | 
			
		||||
{
 | 
			
		||||
	vector v = talloc_zero(tall_vty_vec_ctx, struct _vector);
 | 
			
		||||
	if (!v)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	/* allocate at least one slot */
 | 
			
		||||
	if (size == 0)
 | 
			
		||||
		size = 1;
 | 
			
		||||
 | 
			
		||||
	v->alloced = size;
 | 
			
		||||
	v->active = 0;
 | 
			
		||||
	v->index = _talloc_zero(tall_vty_vec_ctx, sizeof(void *) * size,
 | 
			
		||||
				"vector_init:index");
 | 
			
		||||
	if (!v->index) {
 | 
			
		||||
		talloc_free(v);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	return v;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void vector_only_wrapper_free(vector v)
 | 
			
		||||
{
 | 
			
		||||
	talloc_free(v);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void vector_only_index_free(void *index)
 | 
			
		||||
{
 | 
			
		||||
	talloc_free(index);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void vector_free(vector v)
 | 
			
		||||
{
 | 
			
		||||
	talloc_free(v->index);
 | 
			
		||||
	talloc_free(v);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vector vector_copy(vector v)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int size;
 | 
			
		||||
	vector new = talloc_zero(tall_vty_vec_ctx, struct _vector);
 | 
			
		||||
	if (!new)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	new->active = v->active;
 | 
			
		||||
	new->alloced = v->alloced;
 | 
			
		||||
 | 
			
		||||
	size = sizeof(void *) * (v->alloced);
 | 
			
		||||
	new->index = _talloc_zero(tall_vty_vec_ctx, size, "vector_copy:index");
 | 
			
		||||
	if (!new->index) {
 | 
			
		||||
		talloc_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 = talloc_realloc_size(tall_vty_vec_ctx, 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;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1683
									
								
								libosmocore/src/vty/vty.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1683
									
								
								libosmocore/src/vty/vty.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Reference in New Issue
	
	Block a user