diff options
author | Harald Welte <laforge@gnumonks.org> | 2010-05-28 09:44:26 +0200 |
---|---|---|
committer | Harald Welte <laforge@gnumonks.org> | 2010-05-28 09:44:26 +0200 |
commit | bf51438a8aeaa67076e209587b83cafe6c4fa4d2 (patch) | |
tree | 23ccc827f6ad1a3fddd97fe66ed9b45342ea8df0 /libosmocore/src | |
parent | 900aeaf41539a0577f33b501b2cc0c525ce4ce34 (diff) |
remove libosmocore from openbsc.git
The idea was great, but it never really worked in reality...
Diffstat (limited to 'libosmocore/src')
28 files changed, 0 insertions, 11928 deletions
diff --git a/libosmocore/src/Makefile.am b/libosmocore/src/Makefile.am deleted file mode 100644 index 1a7d87f3e..000000000 --- a/libosmocore/src/Makefile.am +++ /dev/null @@ -1,19 +0,0 @@ -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 - -INCLUDES = $(all_includes) -I$(top_srcdir)/include -AM_CFLAGS = -fPIC -Wall - -lib_LTLIBRARIES = libosmocore.la - -libosmocore_la_SOURCES = timer.c select.c signal.c msgb.c rxlev_stat.c \ - tlv_parser.c bitvec.c comp128.c gsm_utils.c statistics.c \ - write_queue.c utils.c rsl.c gsm48.c gsm48_ie.c \ - logging.c gsm0808.c rate_ctr.c - -if ENABLE_TALLOC -libosmocore_la_SOURCES += talloc.c -endif diff --git a/libosmocore/src/bitvec.c b/libosmocore/src/bitvec.c deleted file mode 100644 index 04c465a8e..000000000 --- a/libosmocore/src/bitvec.c +++ /dev/null @@ -1,219 +0,0 @@ -/* bit vector utility routines */ - -/* (C) 2009 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 <errno.h> -#include <stdint.h> - -#include <osmocore/bitvec.h> - -#define BITNUM_FROM_COMP(byte, bit) ((byte*8)+bit) - -static inline unsigned int bytenum_from_bitnum(unsigned int bitnum) -{ - unsigned int bytenum = bitnum / 8; - - return bytenum; -} - -/* convert ZERO/ONE/L/H to a bitmask at given pos in a byte */ -static uint8_t bitval2mask(enum bit_value bit, uint8_t bitnum) -{ - int bitval; - - switch (bit) { - case ZERO: - bitval = (0 << bitnum); - break; - case ONE: - bitval = (1 << bitnum); - break; - case L: - bitval = ((0x2b ^ (0 << bitnum)) & (1 << bitnum)); - break; - case H: - bitval = ((0x2b ^ (1 << bitnum)) & (1 << bitnum)); - break; - default: - return 0; - } - return bitval; -} - -/* 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) -{ - 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(ONE, bitnum); - - if (bv->data[bytenum] & bitval) - return ONE; - - 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) -{ - unsigned int i, k = 0; - - for (i = 0; i < bv->data_len*8; i++) { - if (bitvec_get_bit_pos(bv, i) == ONE) { - k++; - if (k == n) - return i; - } - } - - return 0; -} - -/* set the bit at a given position inside a bitvec */ -int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnr, - enum bit_value bit) -{ - unsigned int bytenum = bytenum_from_bitnum(bitnr); - unsigned int bitnum = 7 - (bitnr % 8); - uint8_t bitval; - - if (bytenum >= bv->data_len) - return -EINVAL; - - /* first clear the bit */ - bitval = bitval2mask(ONE, bitnum); - bv->data[bytenum] &= ~bitval; - - /* then set it to desired value */ - bitval = bitval2mask(bit, bitnum); - bv->data[bytenum] |= bitval; - - return 0; -} - -/* set the next bit inside a bitvec */ -int bitvec_set_bit(struct bitvec *bv, enum bit_value bit) -{ - int rc; - - rc = bitvec_set_bit_pos(bv, bv->cur_bit, bit); - if (!rc) - bv->cur_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) -{ - int i, rc; - - for (i = 0; i < count; i++) { - rc = bitvec_set_bit(bv, bits[i]); - if (rc) - return rc; - } - - return 0; -} - -/* set multiple bits (based on numeric value) at current pos */ -int bitvec_set_uint(struct bitvec *bv, unsigned int ui, int num_bits) -{ - int i, rc; - - for (i = 0; i < num_bits; i++) { - int bit = 0; - if (ui & (1 << (num_bits - i - 1))) - bit = 1; - rc = bitvec_set_bit(bv, bit); - if (rc) - return rc; - } - - 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) -{ - unsigned int i; - - for (i = bv->cur_bit; i <= up_to_bit; i++) - bitvec_set_bit(bv, L); - - return 0; -} diff --git a/libosmocore/src/comp128.c b/libosmocore/src/comp128.c deleted file mode 100644 index 5d5680c72..000000000 --- a/libosmocore/src/comp128.c +++ /dev/null @@ -1,230 +0,0 @@ -/* - * COMP128 implementation - * - * - * This code is inspired by original code from : - * Marc Briceno <marc@scard.org>, Ian Goldberg <iang@cs.berkeley.edu>, - * and David Wagner <daw@cs.berkeley.edu> - * - * But it has been fully rewritten from various PDFs found online describing - * the algorithm because the licence of the code referenced above was unclear. - * A comment snippet from the original code is included below, it describes - * where the doc came from and how the algorithm was reverse engineered. - * - * - * (C) 2009 by Sylvain Munaut <tnt@246tNt.com> - * - * 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. - * - */ - -/* - * --- SNIP --- - * - * This code derived from a leaked document from the GSM standards. - * Some missing pieces were filled in by reverse-engineering a working SIM. - * We have verified that this is the correct COMP128 algorithm. - * - * The first page of the document identifies it as - * _Technical Information: GSM System Security Study_. - * 10-1617-01, 10th June 1988. - * The bottom of the title page is marked - * Racal Research Ltd. - * Worton Drive, Worton Grange Industrial Estate, - * Reading, Berks. RG2 0SB, England. - * Telephone: Reading (0734) 868601 Telex: 847152 - * The relevant bits are in Part I, Section 20 (pages 66--67). Enjoy! - * - * Note: There are three typos in the spec (discovered by - * reverse-engineering). - * First, "z = (2 * x[n] + x[n]) mod 2^(9-j)" should clearly read - * "z = (2 * x[m] + x[n]) mod 2^(9-j)". - * Second, the "k" loop in the "Form bits from bytes" section is severely - * botched: the k index should run only from 0 to 3, and clearly the range - * on "the (8-k)th bit of byte j" is also off (should be 0..7, not 1..8, - * to be consistent with the subsequent section). - * Third, SRES is taken from the first 8 nibbles of x[], not the last 8 as - * claimed in the document. (And the document doesn't specify how Kc is - * derived, but that was also easily discovered with reverse engineering.) - * All of these typos have been corrected in the following code. - * - * --- /SNIP --- - */ - -#include <string.h> -#include <stdint.h> - -/* The compression tables (just copied ...) */ -static const uint8_t table_0[512] = { - 102, 177, 186, 162, 2, 156, 112, 75, 55, 25, 8, 12, 251, 193, 246, 188, - 109, 213, 151, 53, 42, 79, 191, 115, 233, 242, 164, 223, 209, 148, 108, 161, - 252, 37, 244, 47, 64, 211, 6, 237, 185, 160, 139, 113, 76, 138, 59, 70, - 67, 26, 13, 157, 63, 179, 221, 30, 214, 36, 166, 69, 152, 124, 207, 116, - 247, 194, 41, 84, 71, 1, 49, 14, 95, 35, 169, 21, 96, 78, 215, 225, - 182, 243, 28, 92, 201, 118, 4, 74, 248, 128, 17, 11, 146, 132, 245, 48, - 149, 90, 120, 39, 87, 230, 106, 232, 175, 19, 126, 190, 202, 141, 137, 176, - 250, 27, 101, 40, 219, 227, 58, 20, 51, 178, 98, 216, 140, 22, 32, 121, - 61, 103, 203, 72, 29, 110, 85, 212, 180, 204, 150, 183, 15, 66, 172, 196, - 56, 197, 158, 0, 100, 45, 153, 7, 144, 222, 163, 167, 60, 135, 210, 231, - 174, 165, 38, 249, 224, 34, 220, 229, 217, 208, 241, 68, 206, 189, 125, 255, - 239, 54, 168, 89, 123, 122, 73, 145, 117, 234, 143, 99, 129, 200, 192, 82, - 104, 170, 136, 235, 93, 81, 205, 173, 236, 94, 105, 52, 46, 228, 198, 5, - 57, 254, 97, 155, 142, 133, 199, 171, 187, 50, 65, 181, 127, 107, 147, 226, - 184, 218, 131, 33, 77, 86, 31, 44, 88, 62, 238, 18, 24, 43, 154, 23, - 80, 159, 134, 111, 9, 114, 3, 91, 16, 130, 83, 10, 195, 240, 253, 119, - 177, 102, 162, 186, 156, 2, 75, 112, 25, 55, 12, 8, 193, 251, 188, 246, - 213, 109, 53, 151, 79, 42, 115, 191, 242, 233, 223, 164, 148, 209, 161, 108, - 37, 252, 47, 244, 211, 64, 237, 6, 160, 185, 113, 139, 138, 76, 70, 59, - 26, 67, 157, 13, 179, 63, 30, 221, 36, 214, 69, 166, 124, 152, 116, 207, - 194, 247, 84, 41, 1, 71, 14, 49, 35, 95, 21, 169, 78, 96, 225, 215, - 243, 182, 92, 28, 118, 201, 74, 4, 128, 248, 11, 17, 132, 146, 48, 245, - 90, 149, 39, 120, 230, 87, 232, 106, 19, 175, 190, 126, 141, 202, 176, 137, - 27, 250, 40, 101, 227, 219, 20, 58, 178, 51, 216, 98, 22, 140, 121, 32, - 103, 61, 72, 203, 110, 29, 212, 85, 204, 180, 183, 150, 66, 15, 196, 172, - 197, 56, 0, 158, 45, 100, 7, 153, 222, 144, 167, 163, 135, 60, 231, 210, - 165, 174, 249, 38, 34, 224, 229, 220, 208, 217, 68, 241, 189, 206, 255, 125, - 54, 239, 89, 168, 122, 123, 145, 73, 234, 117, 99, 143, 200, 129, 82, 192, - 170, 104, 235, 136, 81, 93, 173, 205, 94, 236, 52, 105, 228, 46, 5, 198, - 254, 57, 155, 97, 133, 142, 171, 199, 50, 187, 181, 65, 107, 127, 226, 147, - 218, 184, 33, 131, 86, 77, 44, 31, 62, 88, 18, 238, 43, 24, 23, 154, - 159, 80, 111, 134, 114, 9, 91, 3, 130, 16, 10, 83, 240, 195, 119, 253, -}, table_1[256] = { - 19, 11, 80, 114, 43, 1, 69, 94, 39, 18, 127, 117, 97, 3, 85, 43, - 27, 124, 70, 83, 47, 71, 63, 10, 47, 89, 79, 4, 14, 59, 11, 5, - 35, 107, 103, 68, 21, 86, 36, 91, 85, 126, 32, 50, 109, 94, 120, 6, - 53, 79, 28, 45, 99, 95, 41, 34, 88, 68, 93, 55, 110, 125, 105, 20, - 90, 80, 76, 96, 23, 60, 89, 64, 121, 56, 14, 74, 101, 8, 19, 78, - 76, 66, 104, 46, 111, 50, 32, 3, 39, 0, 58, 25, 92, 22, 18, 51, - 57, 65, 119, 116, 22, 109, 7, 86, 59, 93, 62, 110, 78, 99, 77, 67, - 12, 113, 87, 98, 102, 5, 88, 33, 38, 56, 23, 8, 75, 45, 13, 75, - 95, 63, 28, 49, 123, 120, 20, 112, 44, 30, 15, 98, 106, 2, 103, 29, - 82, 107, 42, 124, 24, 30, 41, 16, 108, 100, 117, 40, 73, 40, 7, 114, - 82, 115, 36, 112, 12, 102, 100, 84, 92, 48, 72, 97, 9, 54, 55, 74, - 113, 123, 17, 26, 53, 58, 4, 9, 69, 122, 21, 118, 42, 60, 27, 73, - 118, 125, 34, 15, 65, 115, 84, 64, 62, 81, 70, 1, 24, 111, 121, 83, - 104, 81, 49, 127, 48, 105, 31, 10, 6, 91, 87, 37, 16, 54, 116, 126, - 31, 38, 13, 0, 72, 106, 77, 61, 26, 67, 46, 29, 96, 37, 61, 52, - 101, 17, 44, 108, 71, 52, 66, 57, 33, 51, 25, 90, 2, 119, 122, 35, -}, table_2[128] = { - 52, 50, 44, 6, 21, 49, 41, 59, 39, 51, 25, 32, 51, 47, 52, 43, - 37, 4, 40, 34, 61, 12, 28, 4, 58, 23, 8, 15, 12, 22, 9, 18, - 55, 10, 33, 35, 50, 1, 43, 3, 57, 13, 62, 14, 7, 42, 44, 59, - 62, 57, 27, 6, 8, 31, 26, 54, 41, 22, 45, 20, 39, 3, 16, 56, - 48, 2, 21, 28, 36, 42, 60, 33, 34, 18, 0, 11, 24, 10, 17, 61, - 29, 14, 45, 26, 55, 46, 11, 17, 54, 46, 9, 24, 30, 60, 32, 0, - 20, 38, 2, 30, 58, 35, 1, 16, 56, 40, 23, 48, 13, 19, 19, 27, - 31, 53, 47, 38, 63, 15, 49, 5, 37, 53, 25, 36, 63, 29, 5, 7, -}, table_3[64] = { - 1, 5, 29, 6, 25, 1, 18, 23, 17, 19, 0, 9, 24, 25, 6, 31, - 28, 20, 24, 30, 4, 27, 3, 13, 15, 16, 14, 18, 4, 3, 8, 9, - 20, 0, 12, 26, 21, 8, 28, 2, 29, 2, 15, 7, 11, 22, 14, 10, - 17, 21, 12, 30, 26, 27, 16, 31, 11, 7, 13, 23, 10, 5, 22, 19, -}, table_4[32] = { - 15, 12, 10, 4, 1, 14, 11, 7, 5, 0, 14, 7, 1, 2, 13, 8, - 10, 3, 4, 9, 6, 0, 3, 2, 5, 6, 8, 9, 11, 13, 15, 12, -}; - -static const uint8_t *_comp128_table[5] = { table_0, table_1, table_2, table_3, table_4 }; - - -static inline void -_comp128_compression_round(uint8_t *x, int n, const uint8_t *tbl) -{ - int i, j, m, a, b, y, z; - m = 4 - n; - for (i=0; i<(1<<n); i++) - for (j=0; j<(1<<m); j++) { - a = j + i * (2<<m); - b = a + (1<<m); - y = (x[a] + (x[b]<<1)) & ((32<<m)-1); - z = ((x[a]<<1) + x[b]) & ((32<<m)-1); - x[a] = tbl[y]; - x[b] = tbl[z]; - } -} - -static inline void -_comp128_compression(uint8_t *x) -{ - int n; - for (n=0; n<5; n++) - _comp128_compression_round(x, n, _comp128_table[n]); -} - -static inline void -_comp128_bitsfrombytes(uint8_t *x, uint8_t *bits) -{ - int i; - memset(bits, 0x00, 128); - for (i=0; i<128; i++) - if (x[i>>2] & (1<<(3-(i&3)))) - bits[i] = 1; -} - -static inline void -_comp128_permutation(uint8_t *x, uint8_t *bits) -{ - int i; - memset(&x[16], 0x00, 16); - for (i=0; i<128; i++) - x[(i>>3)+16] |= bits[(i*17) & 127] << (7-(i&7)); -} - -void -comp128(uint8_t *ki, uint8_t *rand, uint8_t *sres, uint8_t *kc) -{ - int i; - uint8_t x[32], bits[128]; - - /* x[16-31] = RAND */ - memcpy(&x[16], rand, 16); - - /* Round 1-7 */ - for (i=0; i<7; i++) { - /* x[0-15] = Ki */ - memcpy(x, ki, 16); - - /* Compression */ - _comp128_compression(x); - - /* FormBitFromBytes */ - _comp128_bitsfrombytes(x, bits); - - /* Permutation */ - _comp128_permutation(x, bits); - } - - /* Round 8 (final) */ - /* x[0-15] = Ki */ - memcpy(x, ki, 16); - - /* Compression */ - _comp128_compression(x); - - /* Output stage */ - for (i=0; i<8; i+=2) - sres[i>>1] = x[i]<<4 | x[i+1]; - - for (i=0; i<12; i+=2) - kc[i>>1] = (x[i + 18] << 6) | - (x[i + 19] << 2) | - (x[i + 20] >> 2); - - kc[6] = (x[30]<<6) | (x[31]<<2); - kc[7] = 0; -} - diff --git a/libosmocore/src/gsm0808.c b/libosmocore/src/gsm0808.c deleted file mode 100644 index 1dc035b3c..000000000 --- a/libosmocore/src/gsm0808.c +++ /dev/null @@ -1,306 +0,0 @@ -/* (C) 2009,2010 by Holger Hans Peter Freyther <zecke@selfish.org> - * (C) 2009,2010 by On-Waves - * 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 <osmocore/gsm0808.h> -#include <osmocore/protocol/gsm_08_08.h> -#include <osmocore/gsm48.h> - -#include <arpa/inet.h> - -#define BSSMAP_MSG_SIZE 512 -#define BSSMAP_MSG_HEADROOM 128 - -struct msgb *gsm0808_create_layer3(struct msgb *msg_l3, uint16_t nc, uint16_t cc, int lac, int _ci) -{ - uint8_t *data; - uint16_t *ci; - struct msgb* msg; - struct gsm48_loc_area_id *lai; - - msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, - "bssmap cmpl l3"); - if (!msg) - return NULL; - - /* create the bssmap header */ - msg->l3h = msgb_put(msg, 2); - msg->l3h[0] = 0x0; - - /* create layer 3 header */ - data = msgb_put(msg, 1); - data[0] = BSS_MAP_MSG_COMPLETE_LAYER_3; - - /* create the cell header */ - data = msgb_put(msg, 3); - data[0] = GSM0808_IE_CELL_IDENTIFIER; - data[1] = 1 + sizeof(*lai) + 2; - data[2] = CELL_IDENT_WHOLE_GLOBAL; - - lai = (struct gsm48_loc_area_id *) msgb_put(msg, sizeof(*lai)); - gsm48_generate_lai(lai, cc, nc, lac); - - ci = (uint16_t *) msgb_put(msg, 2); - *ci = htons(_ci); - - /* copy the layer3 data */ - data = msgb_put(msg, msgb_l3len(msg_l3) + 2); - data[0] = GSM0808_IE_LAYER_3_INFORMATION; - data[1] = msgb_l3len(msg_l3); - memcpy(&data[2], msg_l3->l3h, data[1]); - - /* update the size */ - msg->l3h[1] = msgb_l3len(msg) - 2; - - return msg; -} - -struct msgb *gsm0808_create_reset(void) -{ - struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, - "bssmap: reset"); - if (!msg) - return NULL; - - msg->l3h = msgb_put(msg, 6); - msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT; - msg->l3h[1] = 0x04; - msg->l3h[2] = 0x30; - msg->l3h[3] = 0x04; - msg->l3h[4] = 0x01; - msg->l3h[5] = 0x20; - return msg; -} - -struct msgb *gsm0808_create_clear_complete(void) -{ - struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, - "bssmap: clear complete"); - if (!msg) - return NULL; - - msg->l3h = msgb_put(msg, 3); - msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT; - msg->l3h[1] = 1; - msg->l3h[2] = BSS_MAP_MSG_CLEAR_COMPLETE; - - return msg; -} - -struct msgb *gsm0808_create_cipher_complete(struct msgb *layer3, uint8_t alg_id) -{ - struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, - "cipher-complete"); - if (!msg) - return NULL; - - /* send response with BSS override for A5/1... cheating */ - msg->l3h = msgb_put(msg, 3); - msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT; - msg->l3h[1] = 0xff; - msg->l3h[2] = BSS_MAP_MSG_CIPHER_MODE_COMPLETE; - - /* include layer3 in case we have at least two octets */ - if (layer3 && msgb_l3len(layer3) > 2) { - msg->l4h = msgb_put(msg, msgb_l3len(layer3) + 2); - msg->l4h[0] = GSM0808_IE_LAYER_3_MESSAGE_CONTENTS; - msg->l4h[1] = msgb_l3len(layer3); - memcpy(&msg->l4h[2], layer3->l3h, msgb_l3len(layer3)); - } - - /* and the optional BSS message */ - msg->l4h = msgb_put(msg, 2); - msg->l4h[0] = GSM0808_IE_CHOSEN_ENCR_ALG; - msg->l4h[1] = alg_id; - - /* update the size */ - msg->l3h[1] = msgb_l3len(msg) - 2; - return msg; -} - -struct msgb *gsm0808_create_cipher_reject(uint8_t cause) -{ - struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, - "bssmap: clear complete"); - if (!msg) - return NULL; - - msg->l3h = msgb_put(msg, 3); - msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT; - msg->l3h[1] = 2; - msg->l3h[2] = BSS_MAP_MSG_CIPHER_MODE_REJECT; - msg->l3h[3] = cause; - - return msg; -} - -struct msgb *gsm0808_create_classmark_update(const uint8_t *classmark_data, uint8_t length) -{ - struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, - "classmark-update"); - if (!msg) - return NULL; - - msg->l3h = msgb_put(msg, 3); - msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT; - msg->l3h[1] = 0xff; - msg->l3h[2] = BSS_MAP_MSG_CLASSMARK_UPDATE; - - msg->l4h = msgb_put(msg, length); - memcpy(msg->l4h, classmark_data, length); - - /* update the size */ - msg->l3h[1] = msgb_l3len(msg) - 2; - return msg; -} - -struct msgb *gsm0808_create_sapi_reject(uint8_t link_id) -{ - struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, - "bssmap: sapi 'n' reject"); - if (!msg) - return NULL; - - msg->l3h = msgb_put(msg, 5); - msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT; - msg->l3h[1] = 3; - msg->l3h[2] = BSS_MAP_MSG_SAPI_N_REJECT; - msg->l3h[3] = link_id; - msg->l3h[4] = GSM0808_CAUSE_BSS_NOT_EQUIPPED; - - return msg; -} - -struct msgb *gsm0808_create_assignment_completed(struct gsm_lchan *lchan, uint8_t rr_cause, - uint8_t chosen_channel, uint8_t encr_alg_id, - uint8_t speech_mode) -{ - uint8_t *data; - - struct msgb *msg = msgb_alloc(35, "bssmap: ass compl"); - if (!msg) - return NULL; - - msg->l3h = msgb_put(msg, 3); - msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT; - msg->l3h[1] = 0xff; - msg->l3h[2] = BSS_MAP_MSG_ASSIGMENT_COMPLETE; - - /* write 3.2.2.22 */ - data = msgb_put(msg, 2); - data[0] = GSM0808_IE_RR_CAUSE; - data[1] = rr_cause; - - /* write cirtcuit identity code 3.2.2.2 */ - /* write cell identifier 3.2.2.17 */ - /* write chosen channel 3.2.2.33 when BTS picked it */ - data = msgb_put(msg, 2); - data[0] = GSM0808_IE_CHOSEN_CHANNEL; - data[1] = chosen_channel; - - /* write chosen encryption algorithm 3.2.2.44 */ - data = msgb_put(msg, 2); - data[0] = GSM0808_IE_CHOSEN_ENCR_ALG; - data[1] = encr_alg_id; - - /* write circuit pool 3.2.2.45 */ - /* write speech version chosen: 3.2.2.51 when BTS picked it */ - if (speech_mode != 0) { - data = msgb_put(msg, 2); - data[0] = GSM0808_IE_SPEECH_VERSION; - data[1] = speech_mode; - } - - /* write LSA identifier 3.2.2.15 */ - - - /* update the size */ - msg->l3h[1] = msgb_l3len(msg) - 2; - return msg; -} - -struct msgb *gsm0808_create_assignment_failure(uint8_t cause, uint8_t *rr_cause) -{ - uint8_t *data; - struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, - "bssmap: ass fail"); - if (!msg) - return NULL; - - msg->l3h = msgb_put(msg, 6); - msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT; - msg->l3h[1] = 0xff; - msg->l3h[2] = BSS_MAP_MSG_ASSIGMENT_FAILURE; - msg->l3h[3] = GSM0808_IE_CAUSE; - msg->l3h[4] = 1; - msg->l3h[5] = cause; - - /* RR cause 3.2.2.22 */ - if (rr_cause) { - data = msgb_put(msg, 2); - data[0] = GSM0808_IE_RR_CAUSE; - data[1] = *rr_cause; - } - - /* Circuit pool 3.22.45 */ - /* Circuit pool list 3.2.2.46 */ - - /* update the size */ - msg->l3h[1] = msgb_l3len(msg) - 2; - 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 }, - [GSM0808_IE_TMSI] = { TLV_TYPE_TLV }, - [GSM0808_IE_CELL_IDENTIFIER_LIST] = { TLV_TYPE_TLV }, - [GSM0808_IE_CHANNEL_NEEDED] = { TLV_TYPE_TV }, - [GSM0808_IE_EMLPP_PRIORITY] = { TLV_TYPE_TV }, - [GSM0808_IE_CHANNEL_TYPE] = { TLV_TYPE_TLV }, - [GSM0808_IE_PRIORITY] = { TLV_TYPE_TLV }, - [GSM0808_IE_CIRCUIT_IDENTITY_CODE] = { TLV_TYPE_TV }, - [GSM0808_IE_DOWNLINK_DTX_FLAG] = { TLV_TYPE_TV }, - [GSM0808_IE_INTERFERENCE_BAND_TO_USE] = { TLV_TYPE_TV }, - [GSM0808_IE_CLASSMARK_INFORMATION_T2] = { TLV_TYPE_TLV }, - [GSM0808_IE_GROUP_CALL_REFERENCE] = { TLV_TYPE_TLV }, - [GSM0808_IE_TALKER_FLAG] = { TLV_TYPE_T }, - [GSM0808_IE_CONFIG_EVO_INDI] = { TLV_TYPE_TV }, - [GSM0808_IE_LSA_ACCESS_CTRL_SUPPR] = { TLV_TYPE_TV }, - [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 }, - }, -}; - -const struct tlv_definition *gsm0808_att_tlvdef() -{ - return &bss_att_tlvdef; -} diff --git a/libosmocore/src/gsm48.c b/libosmocore/src/gsm48.c deleted file mode 100644 index d957aef60..000000000 --- a/libosmocore/src/gsm48.c +++ /dev/null @@ -1,353 +0,0 @@ -/* GSM Mobile Radio Interface Layer 3 messages - * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */ - -/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org> - * (C) 2008, 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 <stdint.h> -#include <stdio.h> -#include <string.h> - -#include <arpa/inet.h> - -#include <osmocore/utils.h> -#include <osmocore/tlv.h> -#include <osmocore/gsm48.h> - -#include <osmocore/protocol/gsm_04_08.h> - -const struct tlv_definition gsm48_att_tlvdef = { - .def = { - [GSM48_IE_MOBILE_ID] = { TLV_TYPE_TLV }, - [GSM48_IE_NAME_LONG] = { TLV_TYPE_TLV }, - [GSM48_IE_NAME_SHORT] = { TLV_TYPE_TLV }, - [GSM48_IE_UTC] = { TLV_TYPE_TV }, - [GSM48_IE_NET_TIME_TZ] = { TLV_TYPE_FIXED, 7 }, - [GSM48_IE_LSA_IDENT] = { TLV_TYPE_TLV }, - - [GSM48_IE_BEARER_CAP] = { TLV_TYPE_TLV }, - [GSM48_IE_CAUSE] = { TLV_TYPE_TLV }, - [GSM48_IE_CC_CAP] = { TLV_TYPE_TLV }, - [GSM48_IE_ALERT] = { TLV_TYPE_TLV }, - [GSM48_IE_FACILITY] = { TLV_TYPE_TLV }, - [GSM48_IE_PROGR_IND] = { TLV_TYPE_TLV }, - [GSM48_IE_AUX_STATUS] = { TLV_TYPE_TLV }, - [GSM48_IE_NOTIFY] = { TLV_TYPE_TV }, - [GSM48_IE_KPD_FACILITY] = { TLV_TYPE_TV }, - [GSM48_IE_SIGNAL] = { TLV_TYPE_TV }, - [GSM48_IE_CONN_BCD] = { TLV_TYPE_TLV }, - [GSM48_IE_CONN_SUB] = { TLV_TYPE_TLV }, - [GSM48_IE_CALLING_BCD] = { TLV_TYPE_TLV }, - [GSM48_IE_CALLING_SUB] = { TLV_TYPE_TLV }, - [GSM48_IE_CALLED_BCD] = { TLV_TYPE_TLV }, - [GSM48_IE_CALLED_SUB] = { TLV_TYPE_TLV }, - [GSM48_IE_REDIR_BCD] = { TLV_TYPE_TLV }, - [GSM48_IE_REDIR_SUB] = { TLV_TYPE_TLV }, - [GSM48_IE_LOWL_COMPAT] = { TLV_TYPE_TLV }, - [GSM48_IE_HIGHL_COMPAT] = { TLV_TYPE_TLV }, - [GSM48_IE_USER_USER] = { TLV_TYPE_TLV }, - [GSM48_IE_SS_VERS] = { TLV_TYPE_TLV }, - [GSM48_IE_MORE_DATA] = { TLV_TYPE_T }, - [GSM48_IE_CLIR_SUPP] = { TLV_TYPE_T }, - [GSM48_IE_CLIR_INVOC] = { TLV_TYPE_T }, - [GSM48_IE_REV_C_SETUP] = { TLV_TYPE_T }, - [GSM48_IE_REPEAT_CIR] = { TLV_TYPE_T }, - [GSM48_IE_REPEAT_SEQ] = { TLV_TYPE_T }, - /* FIXME: more elements */ - }, -}; - -static const struct value_string rr_cause_names[] = { - { GSM48_RR_CAUSE_NORMAL, "Normal event" }, - { GSM48_RR_CAUSE_ABNORMAL_UNSPEC, "Abnormal release, unspecified" }, - { GSM48_RR_CAUSE_ABNORMAL_UNACCT, "Abnormal release, channel unacceptable" }, - { GSM48_RR_CAUSE_ABNORMAL_TIMER, "Abnormal release, timer expired" }, - { GSM48_RR_CAUSE_ABNORMAL_NOACT, "Abnormal release, no activity on radio path" }, - { GSM48_RR_CAUSE_PREMPTIVE_REL, "Preemptive release" }, - { GSM48_RR_CAUSE_HNDOVER_IMP, "Handover impossible, timing advance out of range" }, - { GSM48_RR_CAUSE_CHAN_MODE_UNACCT, "Channel mode unacceptable" }, - { GSM48_RR_CAUSE_FREQ_NOT_IMPL, "Frequency not implemented" }, - { GSM48_RR_CAUSE_CALL_CLEARED, "Call already cleared" }, - { GSM48_RR_CAUSE_SEMANT_INCORR, "Semantically incorrect message" }, - { GSM48_RR_CAUSE_INVALID_MAND_INF, "Invalid mandatory information" }, - { GSM48_RR_CAUSE_MSG_TYPE_N, "Message type non-existant or not implemented" }, - { GSM48_RR_CAUSE_MSG_TYPE_N_COMPAT, "Message type not compatible with protocol state" }, - { GSM48_RR_CAUSE_COND_IE_ERROR, "Conditional IE error" }, - { GSM48_RR_CAUSE_NO_CELL_ALLOC_A, "No cell allocation available" }, - { GSM48_RR_CAUSE_PROT_ERROR_UNSPC, "Protocol error unspecified" }, - { 0, NULL }, -}; - -/* FIXME: convert to value_string */ -static const char *cc_state_names[33] = { - "NULL", - "INITIATED", - "MM_CONNECTION_PEND", - "MO_CALL_PROC", - "CALL_DELIVERED", - "illegal state 5", - "CALL_PRESENT", - "CALL_RECEIVED", - "CONNECT_REQUEST", - "MO_TERM_CALL_CONF", - "ACTIVE", - "DISCONNECT_REQ", - "DISCONNECT_IND", - "illegal state 13", - "illegal state 14", - "illegal state 15", - "illegal state 16", - "illegal state 17", - "illegal state 18", - "RELEASE_REQ", - "illegal state 20", - "illegal state 21", - "illegal state 22", - "illegal state 23", - "illegal state 24", - "illegal state 25", - "MO_ORIG_MODIFY", - "MO_TERM_MODIFY", - "CONNECT_IND", - "illegal state 29", - "illegal state 30", - "illegal state 31", -}; - -const char *gsm48_cc_state_name(uint8_t state) -{ - if (state < ARRAY_SIZE(cc_state_names)) - return cc_state_names[state]; - - return "invalid"; -} - -static const struct value_string cc_msg_names[] = { - { GSM48_MT_CC_ALERTING, "ALERTING" }, - { GSM48_MT_CC_CALL_PROC, "CALL_PROC" }, - { GSM48_MT_CC_PROGRESS, "PROGRESS" }, - { GSM48_MT_CC_ESTAB, "ESTAB" }, - { GSM48_MT_CC_SETUP, "SETUP" }, - { GSM48_MT_CC_ESTAB_CONF, "ESTAB_CONF" }, - { GSM48_MT_CC_CONNECT, "CONNECT" }, - { GSM48_MT_CC_CALL_CONF, "CALL_CONF" }, - { GSM48_MT_CC_START_CC, "START_CC" }, - { GSM48_MT_CC_RECALL, "RECALL" }, - { GSM48_MT_CC_EMERG_SETUP, "EMERG_SETUP" }, - { GSM48_MT_CC_CONNECT_ACK, "CONNECT_ACK" }, - { GSM48_MT_CC_USER_INFO, "USER_INFO" }, - { GSM48_MT_CC_MODIFY_REJECT, "MODIFY_REJECT" }, - { GSM48_MT_CC_MODIFY, "MODIFY" }, - { GSM48_MT_CC_HOLD, "HOLD" }, - { GSM48_MT_CC_HOLD_ACK, "HOLD_ACK" }, - { GSM48_MT_CC_HOLD_REJ, "HOLD_REJ" }, - { GSM48_MT_CC_RETR, "RETR" }, - { GSM48_MT_CC_RETR_ACK, "RETR_ACK" }, - { GSM48_MT_CC_RETR_REJ, "RETR_REJ" }, - { GSM48_MT_CC_MODIFY_COMPL, "MODIFY_COMPL" }, - { GSM48_MT_CC_DISCONNECT, "DISCONNECT" }, - { GSM48_MT_CC_RELEASE_COMPL, "RELEASE_COMPL" }, - { GSM48_MT_CC_RELEASE, "RELEASE" }, - { GSM48_MT_CC_STOP_DTMF, "STOP_DTMF" }, - { GSM48_MT_CC_STOP_DTMF_ACK, "STOP_DTMF_ACK" }, - { GSM48_MT_CC_STATUS_ENQ, "STATUS_ENQ" }, - { GSM48_MT_CC_START_DTMF, "START_DTMF" }, - { GSM48_MT_CC_START_DTMF_ACK, "START_DTMF_ACK" }, - { GSM48_MT_CC_START_DTMF_REJ, "START_DTMF_REJ" }, - { GSM48_MT_CC_CONG_CTRL, "CONG_CTRL" }, - { GSM48_MT_CC_FACILITY, "FACILITY" }, - { GSM48_MT_CC_STATUS, "STATUS" }, - { GSM48_MT_CC_NOTIFY, "NOTFIY" }, - { 0, NULL } -}; - -const char *gsm48_cc_msg_name(uint8_t msgtype) -{ - return get_value_string(cc_msg_names, msgtype); -} - -const char *rr_cause_name(uint8_t cause) -{ - return get_value_string(rr_cause_names, cause); -} - -static void to_bcd(uint8_t *bcd, uint16_t val) -{ - bcd[2] = val % 10; - val = val / 10; - bcd[1] = val % 10; - val = val / 10; - bcd[0] = val % 10; - val = val / 10; -} - -void gsm48_generate_lai(struct gsm48_loc_area_id *lai48, uint16_t mcc, - uint16_t mnc, uint16_t lac) -{ - uint8_t bcd[3]; - - to_bcd(bcd, mcc); - lai48->digits[0] = bcd[0] | (bcd[1] << 4); - lai48->digits[1] = bcd[2]; - - to_bcd(bcd, mnc); - /* FIXME: do we need three-digit MNC? See Table 10.5.3 */ -#if 0 - lai48->digits[1] |= bcd[2] << 4; - lai48->digits[2] = bcd[0] | (bcd[1] << 4); -#else - lai48->digits[1] |= 0xf << 4; - lai48->digits[2] = bcd[1] | (bcd[2] << 4); -#endif - - lai48->lac = htons(lac); -} - -int gsm48_generate_mid_from_tmsi(uint8_t *buf, uint32_t tmsi) -{ - uint32_t *tptr = (uint32_t *) &buf[3]; - - buf[0] = GSM48_IE_MOBILE_ID; - buf[1] = GSM48_TMSI_LEN; - buf[2] = 0xf0 | GSM_MI_TYPE_TMSI; - *tptr = htonl(tmsi); - - return 7; -} - -int gsm48_generate_mid_from_imsi(uint8_t *buf, const char *imsi) -{ - unsigned int length = strlen(imsi), i, off = 0; - uint8_t odd = (length & 0x1) == 1; - - buf[0] = GSM48_IE_MOBILE_ID; - buf[2] = char2bcd(imsi[0]) << 4 | GSM_MI_TYPE_IMSI | (odd << 3); - - /* if the length is even we will fill half of the last octet */ - if (odd) - buf[1] = (length + 1) >> 1; - else - buf[1] = (length + 2) >> 1; - - for (i = 1; i < buf[1]; ++i) { - uint8_t lower, upper; - - lower = char2bcd(imsi[++off]); - if (!odd && off + 1 == length) - upper = 0x0f; - else - upper = char2bcd(imsi[++off]) & 0x0f; - - buf[2 + i] = (upper << 4) | lower; - } - - return 2 + buf[1]; -} - -/* Convert Mobile Identity (10.5.1.4) to string */ -int gsm48_mi_to_string(char *string, const int str_len, const uint8_t *mi, - const int mi_len) -{ - int i; - uint8_t mi_type; - char *str_cur = string; - uint32_t tmsi; - - mi_type = mi[0] & GSM_MI_TYPE_MASK; - - switch (mi_type) { - case GSM_MI_TYPE_NONE: - break; - case GSM_MI_TYPE_TMSI: - /* Table 10.5.4.3, reverse generate_mid_from_tmsi */ - if (mi_len == GSM48_TMSI_LEN && mi[0] == (0xf0 | GSM_MI_TYPE_TMSI)) { - memcpy(&tmsi, &mi[1], 4); - tmsi = ntohl(tmsi); - return snprintf(string, str_len, "%u", tmsi); - } - break; - case GSM_MI_TYPE_IMSI: - case GSM_MI_TYPE_IMEI: - case GSM_MI_TYPE_IMEISV: - *str_cur++ = bcd2char(mi[0] >> 4); - - for (i = 1; i < mi_len; i++) { - if (str_cur + 2 >= string + str_len) - return str_cur - string; - *str_cur++ = bcd2char(mi[i] & 0xf); - /* skip last nibble in last input byte when GSM_EVEN */ - if( (i != mi_len-1) || (mi[0] & GSM_MI_ODD)) - *str_cur++ = bcd2char(mi[i] >> 4); - } - break; - default: - break; - } - *str_cur++ = '\0'; - - return str_cur - string; -} - -void gsm48_parse_ra(struct gprs_ra_id *raid, const uint8_t *buf) -{ - raid->mcc = (buf[0] & 0xf) * 100; - raid->mcc += (buf[0] >> 4) * 10; - raid->mcc += (buf[1] & 0xf) * 1; - - /* I wonder who came up with the stupidity of encoding the MNC - * differently depending on how many digits its decimal number has! */ - if ((buf[1] >> 4) == 0xf) { - raid->mnc = (buf[2] & 0xf) * 10; - raid->mnc += (buf[2] >> 4) * 1; - } else { - raid->mnc = (buf[2] & 0xf) * 100; - raid->mnc += (buf[2] >> 4) * 10; - raid->mnc += (buf[1] >> 4) * 1; - } - - raid->lac = ntohs(*(uint16_t *)(buf + 3)); - raid->rac = buf[5]; -} - -int gsm48_construct_ra(uint8_t *buf, const struct gprs_ra_id *raid) -{ - uint16_t mcc = raid->mcc; - uint16_t mnc = raid->mnc; - - buf[0] = ((mcc / 100) % 10) | (((mcc / 10) % 10) << 4); - buf[1] = (mcc % 10); - - /* I wonder who came up with the stupidity of encoding the MNC - * differently depending on how many digits its decimal number has! */ - if (mnc < 100) { - buf[1] |= 0xf0; - buf[2] = ((mnc / 10) % 10) | ((mnc % 10) << 4); - } else { - buf[1] |= (mnc % 10) << 4; - buf[2] = ((mnc / 100) % 10) | (((mcc / 10) % 10) << 4); - } - - *(uint16_t *)(buf+3) = htons(raid->lac); - - buf[5] = raid->rac; - - return 6; -} diff --git a/libosmocore/src/gsm48_ie.c b/libosmocore/src/gsm48_ie.c deleted file mode 100644 index 3c2a1f7b6..000000000 --- a/libosmocore/src/gsm48_ie.c +++ /dev/null @@ -1,659 +0,0 @@ -/* GSM Mobile Radio Interface Layer 3 messages - * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */ - -/* (C) 2008 by Harald Welte <laforge@gnumonks.org> - * (C) 2009-2010 by Andreas Eversberg - * - * 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 <string.h> -#include <errno.h> - -#include <osmocore/utils.h> -#include <osmocore/msgb.h> -#include <osmocore/tlv.h> -#include <osmocore/mncc.h> -#include <osmocore/protocol/gsm_04_08.h> - -static const char bcd_num_digits[] = { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', '*', '#', 'a', 'b', 'c', '\0' -}; - -/* decode a 'called/calling/connect party BCD number' as in 10.5.4.7 */ -int gsm48_decode_bcd_number(char *output, int output_len, - const uint8_t *bcd_lv, int h_len) -{ - uint8_t in_len = bcd_lv[0]; - int i; - - for (i = 1 + h_len; i <= in_len; i++) { - /* lower nibble */ - output_len--; - if (output_len <= 1) - break; - *output++ = bcd_num_digits[bcd_lv[i] & 0xf]; - - /* higher nibble */ - output_len--; - if (output_len <= 1) - break; - *output++ = bcd_num_digits[bcd_lv[i] >> 4]; - } - if (output_len >= 1) - *output++ = '\0'; - - return 0; -} - -/* convert a single ASCII character to call-control BCD */ -static int asc_to_bcd(const char asc) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(bcd_num_digits); i++) { - if (bcd_num_digits[i] == asc) - return i; - } - return -EINVAL; -} - -/* convert a ASCII phone number to 'called/calling/connect party BCD number' */ -int gsm48_encode_bcd_number(uint8_t *bcd_lv, uint8_t max_len, - int h_len, const char *input) -{ - int in_len = strlen(input); - int i; - uint8_t *bcd_cur = bcd_lv + 1 + h_len; - - /* two digits per byte, plus type byte */ - bcd_lv[0] = in_len/2 + h_len; - if (in_len % 2) - bcd_lv[0]++; - - if (bcd_lv[0] > max_len) - return -EIO; - - for (i = 0; i < in_len; i++) { - int rc = asc_to_bcd(input[i]); - if (rc < 0) - return rc; - if (i % 2 == 0) - *bcd_cur = rc; - else - *bcd_cur++ |= (rc << 4); - } - /* append padding nibble in case of odd length */ - if (i % 2) - *bcd_cur++ |= 0xf0; - - /* return how many bytes we used */ - return (bcd_cur - bcd_lv); -} - -/* decode 'bearer capability' */ -int gsm48_decode_bearer_cap(struct gsm_mncc_bearer_cap *bcap, - const uint8_t *lv) -{ - uint8_t in_len = lv[0]; - int i, s; - - if (in_len < 1) - return -EINVAL; - - bcap->speech_ver[0] = -1; /* end of list, of maximum 7 values */ - - /* octet 3 */ - bcap->transfer = lv[1] & 0x07; - bcap->mode = (lv[1] & 0x08) >> 3; - bcap->coding = (lv[1] & 0x10) >> 4; - bcap->radio = (lv[1] & 0x60) >> 5; - - if (bcap->transfer == GSM_MNCC_BCAP_SPEECH) { - i = 1; - s = 0; - while(!(lv[i] & 0x80)) { - i++; /* octet 3a etc */ - if (in_len < i) - return 0; - bcap->speech_ver[s++] = lv[i] & 0x0f; - bcap->speech_ver[s] = -1; /* end of list */ - if (i == 2) /* octet 3a */ - bcap->speech_ctm = (lv[i] & 0x20) >> 5; - if (s == 7) /* maximum speech versions + end of list */ - return 0; - } - } else { - i = 1; - while (!(lv[i] & 0x80)) { - i++; /* octet 3a etc */ - if (in_len < i) - return 0; - /* ignore them */ - } - /* FIXME: implement OCTET 4+ parsing */ - } - - return 0; -} - -/* encode 'bearer capability' */ -int gsm48_encode_bearer_cap(struct msgb *msg, int lv_only, - const struct gsm_mncc_bearer_cap *bcap) -{ - uint8_t lv[32 + 1]; - int i = 1, s; - - lv[1] = bcap->transfer; - lv[1] |= bcap->mode << 3; - lv[1] |= bcap->coding << 4; - lv[1] |= bcap->radio << 5; - - if (bcap->transfer == GSM_MNCC_BCAP_SPEECH) { - for (s = 0; bcap->speech_ver[s] >= 0; s++) { - i++; /* octet 3a etc */ - lv[i] = bcap->speech_ver[s]; - if (i == 2) /* octet 3a */ - lv[i] |= bcap->speech_ctm << 5; - } - lv[i] |= 0x80; /* last IE of octet 3 etc */ - } else { - /* FIXME: implement OCTET 4+ encoding */ - } - - lv[0] = i; - if (lv_only) - msgb_lv_put(msg, lv[0], lv+1); - else - msgb_tlv_put(msg, GSM48_IE_BEARER_CAP, lv[0], lv+1); - - return 0; -} - -/* decode 'call control cap' */ -int gsm48_decode_cccap(struct gsm_mncc_cccap *ccap, const uint8_t *lv) -{ - uint8_t in_len = lv[0]; - - if (in_len < 1) - return -EINVAL; - - /* octet 3 */ - ccap->dtmf = lv[1] & 0x01; - ccap->pcp = (lv[1] & 0x02) >> 1; - - return 0; -} - -/* encode 'call control cap' */ -int gsm48_encode_cccap(struct msgb *msg, - const struct gsm_mncc_cccap *ccap) -{ - uint8_t lv[2]; - - lv[0] = 1; - lv[1] = 0; - if (ccap->dtmf) - lv [1] |= 0x01; - if (ccap->pcp) - lv [1] |= 0x02; - - msgb_tlv_put(msg, GSM48_IE_CC_CAP, lv[0], lv+1); - - return 0; -} - -/* decode 'called party BCD number' */ -int gsm48_decode_called(struct gsm_mncc_number *called, - const uint8_t *lv) -{ - uint8_t in_len = lv[0]; - - if (in_len < 1) - return -EINVAL; - - /* octet 3 */ - called->plan = lv[1] & 0x0f; - called->type = (lv[1] & 0x70) >> 4; - - /* octet 4..N */ - gsm48_decode_bcd_number(called->number, sizeof(called->number), lv, 1); - - return 0; -} - -/* encode 'called party BCD number' */ -int gsm48_encode_called(struct msgb *msg, - const struct gsm_mncc_number *called) -{ - uint8_t lv[18]; - int ret; - - /* octet 3 */ - lv[1] = called->plan; - lv[1] |= called->type << 4; - - /* octet 4..N, octet 2 */ - ret = gsm48_encode_bcd_number(lv, sizeof(lv), 1, called->number); - if (ret < 0) - return ret; - - msgb_tlv_put(msg, GSM48_IE_CALLED_BCD, lv[0], lv+1); - - return 0; -} - -/* decode callerid of various IEs */ -int gsm48_decode_callerid(struct gsm_mncc_number *callerid, - const uint8_t *lv) -{ - uint8_t in_len = lv[0]; - int i = 1; - - if (in_len < 1) - return -EINVAL; - - /* octet 3 */ - callerid->plan = lv[1] & 0x0f; - callerid->type = (lv[1] & 0x70) >> 4; - - /* octet 3a */ - if (!(lv[1] & 0x80)) { - callerid->screen = lv[2] & 0x03; - callerid->present = (lv[2] & 0x60) >> 5; - i = 2; - } - - /* octet 4..N */ - gsm48_decode_bcd_number(callerid->number, sizeof(callerid->number), lv, i); - - return 0; -} - -/* encode callerid of various IEs */ -int gsm48_encode_callerid(struct msgb *msg, int ie, int max_len, - const struct gsm_mncc_number *callerid) -{ - uint8_t lv[max_len - 1]; - int h_len = 1; - int ret; - - /* octet 3 */ - lv[1] = callerid->plan; - lv[1] |= callerid->type << 4; - - if (callerid->present || callerid->screen) { - /* octet 3a */ - lv[2] = callerid->screen; - lv[2] |= callerid->present << 5; - lv[2] |= 0x80; - h_len++; - } else - lv[1] |= 0x80; - - /* octet 4..N, octet 2 */ - ret = gsm48_encode_bcd_number(lv, sizeof(lv), h_len, callerid->number); - if (ret < 0) - return ret; - - msgb_tlv_put(msg, ie, lv[0], lv+1); - - return 0; -} - -/* decode 'cause' */ -int gsm48_decode_cause(struct gsm_mncc_cause *cause, - const uint8_t *lv) -{ - uint8_t in_len = lv[0]; - int i; - - if (in_len < 2) - return -EINVAL; - - cause->diag_len = 0; - - /* octet 3 */ - cause->location = lv[1] & 0x0f; - cause->coding = (lv[1] & 0x60) >> 5; - - i = 1; - if (!(lv[i] & 0x80)) { - i++; /* octet 3a */ - if (in_len < i+1) - return 0; - cause->rec = 1; - cause->rec_val = lv[i] & 0x7f; - } - i++; - - /* octet 4 */ - cause->value = lv[i] & 0x7f; - i++; - - if (in_len < i) /* no diag */ - return 0; - - if (in_len - (i-1) > 32) /* maximum 32 octets */ - return 0; - - /* octet 5-N */ - memcpy(cause->diag, lv + i, in_len - (i-1)); - cause->diag_len = in_len - (i-1); - - return 0; -} - -/* encode 'cause' */ -int gsm48_encode_cause(struct msgb *msg, int lv_only, - const struct gsm_mncc_cause *cause) -{ - uint8_t lv[32+4]; - int i; - - if (cause->diag_len > 32) - return -EINVAL; - - /* octet 3 */ - lv[1] = cause->location; - lv[1] |= cause->coding << 5; - - i = 1; - if (cause->rec) { - i++; /* octet 3a */ - lv[i] = cause->rec_val; - } - lv[i] |= 0x80; /* end of octet 3 */ - - /* octet 4 */ - i++; - lv[i] = 0x80 | cause->value; - - /* octet 5-N */ - if (cause->diag_len) { - memcpy(lv + i, cause->diag, cause->diag_len); - i += cause->diag_len; - } - - lv[0] = i; - if (lv_only) - msgb_lv_put(msg, lv[0], lv+1); - else - msgb_tlv_put(msg, GSM48_IE_CAUSE, lv[0], lv+1); - - return 0; -} - -/* decode 'calling number' */ -int gsm48_decode_calling(struct gsm_mncc_number *calling, - const uint8_t *lv) -{ - return gsm48_decode_callerid(calling, lv); -} - -/* encode 'calling number' */ -int gsm48_encode_calling(struct msgb *msg, - const struct gsm_mncc_number *calling) -{ - return gsm48_encode_callerid(msg, GSM48_IE_CALLING_BCD, 14, calling); -} - -/* decode 'connected number' */ -int gsm48_decode_connected(struct gsm_mncc_number *connected, - const uint8_t *lv) -{ - return gsm48_decode_callerid(connected, lv); -} - -/* encode 'connected number' */ -int gsm48_encode_connected(struct msgb *msg, - const struct gsm_mncc_number *connected) -{ - return gsm48_encode_callerid(msg, GSM48_IE_CONN_BCD, 14, connected); -} - -/* decode 'redirecting number' */ -int gsm48_decode_redirecting(struct gsm_mncc_number *redirecting, - const uint8_t *lv) -{ - return gsm48_decode_callerid(redirecting, lv); -} - -/* encode 'redirecting number' */ -int gsm48_encode_redirecting(struct msgb *msg, - const struct gsm_mncc_number *redirecting) -{ - return gsm48_encode_callerid(msg, GSM48_IE_REDIR_BCD, 19, redirecting); -} - -/* decode 'facility' */ -int gsm48_decode_facility(struct gsm_mncc_facility *facility, - const uint8_t *lv) -{ - uint8_t in_len = lv[0]; - - if (in_len < 1) - return -EINVAL; - - if (in_len > sizeof(facility->info)) - return -EINVAL; - - memcpy(facility->info, lv+1, in_len); - facility->len = in_len; - - return 0; -} - -/* encode 'facility' */ -int gsm48_encode_facility(struct msgb *msg, int lv_only, - const struct gsm_mncc_facility *facility) -{ - uint8_t lv[GSM_MAX_FACILITY + 1]; - - if (facility->len < 1 || facility->len > GSM_MAX_FACILITY) - return -EINVAL; - - memcpy(lv+1, facility->info, facility->len); - lv[0] = facility->len; - if (lv_only) - msgb_lv_put(msg, lv[0], lv+1); - else - msgb_tlv_put(msg, GSM48_IE_FACILITY, lv[0], lv+1); - - return 0; -} - -/* decode 'notify' */ -int gsm48_decode_notify(int *notify, const uint8_t *v) -{ - *notify = v[0] & 0x7f; - - return 0; -} - -/* encode 'notify' */ -int gsm48_encode_notify(struct msgb *msg, int notify) -{ - msgb_v_put(msg, notify | 0x80); - - return 0; -} - -/* decode 'signal' */ -int gsm48_decode_signal(int *signal, const uint8_t *v) -{ - *signal = v[0]; - - return 0; -} - -/* encode 'signal' */ -int gsm48_encode_signal(struct msgb *msg, int signal) -{ - msgb_tv_put(msg, GSM48_IE_SIGNAL, signal); - - return 0; -} - -/* decode 'keypad' */ -int gsm48_decode_keypad(int *keypad, const uint8_t *lv) -{ - uint8_t in_len = lv[0]; - - if (in_len < 1) - return -EINVAL; - - *keypad = lv[1] & 0x7f; - - return 0; -} - -/* encode 'keypad' */ -int gsm48_encode_keypad(struct msgb *msg, int keypad) -{ - msgb_tv_put(msg, GSM48_IE_KPD_FACILITY, keypad); - - return 0; -} - -/* decode 'progress' */ -int gsm48_decode_progress(struct gsm_mncc_progress *progress, - const uint8_t *lv) -{ - uint8_t in_len = lv[0]; - - if (in_len < 2) - return -EINVAL; - - progress->coding = (lv[1] & 0x60) >> 5; - progress->location = lv[1] & 0x0f; - progress->descr = lv[2] & 0x7f; - - return 0; -} - -/* encode 'progress' */ -int gsm48_encode_progress(struct msgb *msg, int lv_only, - const struct gsm_mncc_progress *p) -{ - uint8_t lv[3]; - - lv[0] = 2; - lv[1] = 0x80 | ((p->coding & 0x3) << 5) | (p->location & 0xf); - lv[2] = 0x80 | (p->descr & 0x7f); - if (lv_only) - msgb_lv_put(msg, lv[0], lv+1); - else - msgb_tlv_put(msg, GSM48_IE_PROGR_IND, lv[0], lv+1); - - return 0; -} - -/* decode 'user-user' */ -int gsm48_decode_useruser(struct gsm_mncc_useruser *uu, - const uint8_t *lv) -{ - uint8_t in_len = lv[0]; - char *info = uu->info; - int info_len = sizeof(uu->info); - int i; - - if (in_len < 1) - return -EINVAL; - - uu->proto = lv[1]; - - for (i = 2; i <= in_len; i++) { - info_len--; - if (info_len <= 1) - break; - *info++ = lv[i]; - } - if (info_len >= 1) - *info++ = '\0'; - - return 0; -} - -/* encode 'useruser' */ -int gsm48_encode_useruser(struct msgb *msg, int lv_only, - const struct gsm_mncc_useruser *uu) -{ - uint8_t lv[GSM_MAX_USERUSER + 2]; - - if (strlen(uu->info) > GSM_MAX_USERUSER) - return -EINVAL; - - lv[0] = 1 + strlen(uu->info); - lv[1] = uu->proto; - memcpy(lv + 2, uu->info, strlen(uu->info)); - if (lv_only) - msgb_lv_put(msg, lv[0], lv+1); - else - msgb_tlv_put(msg, GSM48_IE_USER_USER, lv[0], lv+1); - - return 0; -} - -/* decode 'ss version' */ -int gsm48_decode_ssversion(struct gsm_mncc_ssversion *ssv, - const uint8_t *lv) -{ - uint8_t in_len = lv[0]; - - if (in_len < 1 || in_len < sizeof(ssv->info)) - return -EINVAL; - - memcpy(ssv->info, lv + 1, in_len); - ssv->len = in_len; - - return 0; -} - -/* encode 'ss version' */ -int gsm48_encode_ssversion(struct msgb *msg, - const struct gsm_mncc_ssversion *ssv) -{ - uint8_t lv[GSM_MAX_SSVERSION + 1]; - - if (ssv->len > GSM_MAX_SSVERSION) - return -EINVAL; - - lv[0] = ssv->len; - memcpy(lv + 1, ssv->info, ssv->len); - msgb_tlv_put(msg, GSM48_IE_SS_VERS, lv[0], lv+1); - - return 0; -} - -/* decode 'more data' does not require a function, because it has no value */ - -/* encode 'more data' */ -int gsm48_encode_more(struct msgb *msg) -{ - uint8_t *ie; - - ie = msgb_put(msg, 1); - ie[0] = GSM48_IE_MORE_DATA; - - return 0; -} - diff --git a/libosmocore/src/gsm_utils.c b/libosmocore/src/gsm_utils.c deleted file mode 100644 index b392fd37c..000000000 --- a/libosmocore/src/gsm_utils.c +++ /dev/null @@ -1,376 +0,0 @@ -/* - * (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de> - * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org> - * (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 <openbsc/gsm_data.h> -#include <osmocore/utils.h> -#include <osmocore/gsm_utils.h> - -#include <stdlib.h> -#include <stdint.h> -#include <string.h> -#include <stdio.h> -#include <errno.h> -#include <ctype.h> - -#include "../config.h" - -/* GSM 03.38 6.2.1 Charachter packing */ -int gsm_7bit_decode(char *text, const uint8_t *user_data, uint8_t length) -{ - int i = 0; - int l = 0; - - /* FIXME: We need to account for user data headers here */ - i += l; - for (; i < length; i ++) - *(text ++) = - ((user_data[(i * 7 + 7) >> 3] << - (7 - ((i * 7 + 7) & 7))) | - (user_data[(i * 7) >> 3] >> - ((i * 7) & 7))) & 0x7f; - *text = '\0'; - - return i - l; -} - - -/* GSM 03.38 6.2.1 Charachter packing */ -int gsm_7bit_encode(uint8_t *result, const char *data) -{ - int i,j = 0; - unsigned char ch1, ch2; - int shift = 0; - - for ( i=0; i<strlen(data); i++ ) { - - ch1 = data[i] & 0x7F; - ch1 = ch1 >> shift; - ch2 = data[(i+1)] & 0x7F; - ch2 = ch2 << (7-shift); - - ch1 = ch1 | ch2; - - result[j++] = ch1; - - shift++; - - if ((shift == 7) && (i+1<strlen(data))) { - shift = 0; - i++; - } - } - - return i; -} - -/* determine power control level for given dBm value, as indicated - * by the tables in chapter 4.1.1 of GSM TS 05.05 */ -int ms_pwr_ctl_lvl(enum gsm_band band, unsigned int dbm) -{ - switch (band) { - case GSM_BAND_450: - case GSM_BAND_480: - case GSM_BAND_750: - case GSM_BAND_900: - case GSM_BAND_810: - case GSM_BAND_850: - if (dbm >= 39) - return 0; - else if (dbm < 5) - return 19; - else { - /* we are guaranteed to have (5 <= dbm < 39) */ - return 2 + ((39 - dbm) / 2); - } - break; - case GSM_BAND_1800: - if (dbm >= 36) - return 29; - else if (dbm >= 34) - return 30; - else if (dbm >= 32) - return 31; - else if (dbm == 31) - return 0; - else { - /* we are guaranteed to have (0 <= dbm < 31) */ - return (30 - dbm) / 2; - } - break; - case GSM_BAND_1900: - if (dbm >= 33) - return 30; - else if (dbm >= 32) - return 31; - else if (dbm == 31) - return 0; - else { - /* we are guaranteed to have (0 <= dbm < 31) */ - return (30 - dbm) / 2; - } - break; - } - return -EINVAL; -} - -int ms_pwr_dbm(enum gsm_band band, uint8_t lvl) -{ - lvl &= 0x1f; - - switch (band) { - case GSM_BAND_450: - case GSM_BAND_480: - case GSM_BAND_750: - case GSM_BAND_900: - case GSM_BAND_810: - case GSM_BAND_850: - if (lvl < 2) - return 39; - else if (lvl < 20) - return 39 - ((lvl - 2) * 2) ; - else - return 5; - break; - case GSM_BAND_1800: - if (lvl < 16) - return 30 - (lvl * 2); - else if (lvl < 29) - return 0; - else - return 36 - ((lvl - 29) * 2); - break; - case GSM_BAND_1900: - if (lvl < 16) - return 30 - (lvl * 2); - else if (lvl < 30) - return -EINVAL; - else - return 33 - (lvl - 30); - break; - } - return -EINVAL; -} - -/* According to TS 08.05 Chapter 8.1.4 */ -int rxlev2dbm(uint8_t rxlev) -{ - if (rxlev > 63) - rxlev = 63; - - return -110 + rxlev; -} - -/* According to TS 08.05 Chapter 8.1.4 */ -uint8_t dbm2rxlev(int dbm) -{ - int rxlev = dbm + 110; - - if (rxlev > 63) - rxlev = 63; - else if (rxlev < 0) - rxlev = 0; - - return rxlev; -} - -const char *gsm_band_name(enum gsm_band band) -{ - switch (band) { - case GSM_BAND_450: - return "GSM450"; - case GSM_BAND_480: - return "GSM450"; - case GSM_BAND_750: - return "GSM750"; - case GSM_BAND_810: - return "GSM810"; - case GSM_BAND_850: - return "GSM850"; - case GSM_BAND_900: - return "GSM900"; - case GSM_BAND_1800: - return "DCS1800"; - case GSM_BAND_1900: - return "PCS1900"; - } - return "invalid"; -} - -enum gsm_band gsm_band_parse(const char* mhz) -{ - while (*mhz && !isdigit(*mhz)) - mhz++; - - if (*mhz == '\0') - return -EINVAL; - - switch (strtol(mhz, NULL, 10)) { - case 450: - return GSM_BAND_450; - case 480: - return GSM_BAND_480; - case 750: - return GSM_BAND_750; - case 810: - return GSM_BAND_810; - case 850: - return GSM_BAND_850; - case 900: - return GSM_BAND_900; - case 1800: - return GSM_BAND_1800; - case 1900: - return GSM_BAND_1900; - default: - return -EINVAL; - } -} - - -#ifdef HAVE_EXECINFO_H -#include <execinfo.h> -void generate_backtrace() -{ - int i, nptrs; - void *buffer[100]; - char **strings; - - nptrs = backtrace(buffer, ARRAY_SIZE(buffer)); - printf("backtrace() returned %d addresses\n", nptrs); - - strings = backtrace_symbols(buffer, nptrs); - if (!strings) - return; - - for (i = 1; i < nptrs; i++) - printf("%s\n", strings[i]); - - free(strings); -} -#endif - -enum gsm_band gsm_arfcn2band(uint16_t arfcn) -{ - if (arfcn & ARFCN_PCS) - return GSM_BAND_1900; - else if (arfcn <= 124) - return GSM_BAND_900; - else if (arfcn >= 955 && arfcn <= 1023) - return GSM_BAND_900; - else if (arfcn >= 128 && arfcn <= 251) - return GSM_BAND_850; - else if (arfcn >= 512 && arfcn <= 885) - return GSM_BAND_1800; - else if (arfcn >= 259 && arfcn <= 293) - return GSM_BAND_450; - else if (arfcn >= 306 && arfcn <= 340) - return GSM_BAND_480; - else if (arfcn >= 350 && arfcn <= 425) - return GSM_BAND_810; - else if (arfcn >= 438 && arfcn <= 511) - return GSM_BAND_750; - else - return GSM_BAND_1800; -} - -/* Convert an ARFCN to the frequency in MHz * 10 */ -uint16_t gsm_arfcn2freq10(uint16_t arfcn, int uplink) -{ - uint16_t freq10_ul; - uint16_t freq10_dl; - - if (arfcn & ARFCN_PCS) { - /* DCS 1900 */ - arfcn &= ~ARFCN_PCS; - freq10_ul = 18502 + 2 * (arfcn-512); - freq10_dl = freq10_ul + 800; - } else if (arfcn <= 124) { - /* Primary GSM + ARFCN 0 of E-GSM */ - freq10_ul = 8900 + 2 * arfcn; - freq10_dl = freq10_ul + 450; - } else if (arfcn >= 955 && arfcn <= 1023) { - /* E-GSM and R-GSM */ - freq10_ul = 8900 + 2 * (arfcn - 1024); - freq10_dl = freq10_ul + 450; - } else if (arfcn >= 128 && arfcn <= 251) { - /* GSM 850 */ - freq10_ul = 8242 + 2 * (arfcn - 128); - freq10_dl = freq10_ul + 450; - } else if (arfcn >= 512 && arfcn <= 885) { - /* DCS 1800 */ - freq10_ul = 17102 + 2 * (arfcn - 512); - freq10_dl = freq10_ul + 950; - } else if (arfcn >= 259 && arfcn <= 293) { - /* GSM 450 */ - freq10_ul = 4506 + 2 * (arfcn - 259); - freq10_dl = freq10_ul + 100; - } else if (arfcn >= 306 && arfcn <= 340) { - /* GSM 480 */ - freq10_ul = 4790 + 2 * (arfcn - 306); - freq10_dl = freq10_ul + 100; - } else if (arfcn >= 350 && arfcn <= 425) { - /* GSM 810 */ - freq10_ul = 8060 + 2 * (arfcn - 350); - freq10_dl = freq10_ul + 450; - } else if (arfcn >= 438 && arfcn <= 511) { - /* GSM 750 */ - freq10_ul = 7472 + 2 * (arfcn - 438); - freq10_dl = freq10_ul + 300; - } else - return 0xffff; - - if (uplink) - return freq10_ul; - else - return freq10_dl; -} - -void gsm_fn2gsmtime(struct gsm_time *time, uint32_t fn) -{ - time->fn = fn; - time->t1 = time->fn / (26*51); - time->t2 = time->fn % 26; - time->t3 = time->fn % 51; - time->tc = (time->fn / 51) % 8; -} - -uint32_t gsm_gsmtime2fn(struct gsm_time *time) -{ - /* TS 05.02 Chapter 4.3.3 TDMA frame number */ - return (51 * ((time->t3 - time->t2 + 26) % 26) + time->t3 + (26 * 51 * time->t1)); -} - -/* TS 03.03 Chapter 2.6 */ -int gprs_tlli_type(uint32_t tlli) -{ - if ((tlli & 0xc0000000) == 0xc0000000) - return TLLI_LOCAL; - else if ((tlli & 0xc0000000) == 0x80000000) - return TLLI_FOREIGN; - else if ((tlli & 0xf8000000) == 0x78000000) - return TLLI_RANDOM; - else if ((tlli & 0xf8000000) == 0x70000000) - return TLLI_AUXILIARY; - - return TLLI_RESERVED; -} diff --git a/libosmocore/src/logging.c b/libosmocore/src/logging.c deleted file mode 100644 index 1dc30db3a..000000000 --- a/libosmocore/src/logging.c +++ /dev/null @@ -1,419 +0,0 @@ -/* Debugging/Logging support code */ - -/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org> - * (C) 2008 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 "../config.h" - -#include <stdarg.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> - -#ifdef HAVE_STRINGS_H -#include <strings.h> -#endif -#include <time.h> -#include <errno.h> - -#include <osmocore/talloc.h> -#include <osmocore/utils.h> -#include <osmocore/logging.h> - -const struct log_info *osmo_log_info; - -static struct log_context log_context; -static void *tall_log_ctx = NULL; -static LLIST_HEAD(target_list); - -static const struct value_string loglevel_strs[] = { - { 0, "EVERYTHING" }, - { LOGL_DEBUG, "DEBUG" }, - { LOGL_INFO, "INFO" }, - { LOGL_NOTICE, "NOTICE" }, - { LOGL_ERROR, "ERROR" }, - { LOGL_FATAL, "FATAL" }, - { 0, NULL }, -}; - -int log_parse_level(const char *lvl) -{ - return get_string_value(loglevel_strs, lvl); -} - -const char *log_level_str(unsigned int lvl) -{ - return get_value_string(loglevel_strs, lvl); -} - -int log_parse_category(const char *category) -{ - int i; - - for (i = 0; i < osmo_log_info->num_cat; ++i) { - if (!strcasecmp(osmo_log_info->cat[i].name+1, category)) - return i; - } - - return -EINVAL; -} - -/* - * Parse the category mask. - * The format can be this: category1:category2:category3 - * or category1,2:category2,3:... - */ -void log_parse_category_mask(struct log_target* target, const char *_mask) -{ - int i = 0; - char *mask = strdup(_mask); - char *category_token = NULL; - - /* Disable everything to enable it afterwards */ - for (i = 0; i < ARRAY_SIZE(target->categories); ++i) - target->categories[i].enabled = 0; - - category_token = strtok(mask, ":"); - do { - 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(osmo_log_info->cat[i].name, - category_token, length) == 0) { - int level = 0; - - if (colon) - level = atoi(colon+1); - - target->categories[i].enabled = 1; - target->categories[i].loglevel = level; - } - } - } while ((category_token = strtok(NULL, ":"))); - - free(mask); -} - -static const char* color(int subsys) -{ - if (subsys < osmo_log_info->num_cat) - return osmo_log_info->cat[subsys].color; - - return NULL; -} - -static void _output(struct log_target *target, unsigned int subsys, - char *file, int line, int cont, const char *format, - va_list ap) -{ - char col[30]; - char sub[30]; - char tim[30]; - char buf[4096]; - char final[4096]; - - /* prepare the data */ - col[0] = '\0'; - sub[0] = '\0'; - tim[0] = '\0'; - buf[0] = '\0'; - - /* are we using color */ - if (target->use_color) { - const char *c = color(subsys); - if (c) { - snprintf(col, sizeof(col), "%s", color(subsys)); - col[sizeof(col)-1] = '\0'; - } - } - vsnprintf(buf, sizeof(buf), format, ap); - buf[sizeof(buf)-1] = '\0'; - - if (!cont) { - if (target->print_timestamp) { - char *timestr; - time_t tm; - tm = time(NULL); - timestr = ctime(&tm); - timestr[strlen(timestr)-1] = '\0'; - snprintf(tim, sizeof(tim), "%s ", timestr); - tim[sizeof(tim)-1] = '\0'; - } - snprintf(sub, sizeof(sub), "<%4.4x> %s:%d ", subsys, file, line); - sub[sizeof(sub)-1] = '\0'; - } - - snprintf(final, sizeof(final), "%s%s%s%s\033[0;m", col, tim, sub, buf); - final[sizeof(final)-1] = '\0'; - target->output(target, final); -} - - -static void _logp(unsigned int subsys, int level, char *file, int line, - int cont, const char *format, va_list ap) -{ - struct log_target *tar; - - llist_for_each_entry(tar, &target_list, entry) { - struct log_category *category; - int output = 0; - - category = &tar->categories[subsys]; - /* subsystem is not supposed to be logged */ - if (!category->enabled) - continue; - - /* Check the global log level */ - if (tar->loglevel != 0 && level < tar->loglevel) - continue; - - /* Check the category log level */ - if (tar->loglevel == 0 && category->loglevel != 0 && - level < category->loglevel) - continue; - - /* Apply filters here... if that becomes messy we will - * need to put filters in a list and each filter will - * say stop, continue, output */ - if ((tar->filter_map & LOG_FILTER_ALL) != 0) - output = 1; - else if (osmo_log_info->filter_fn) - output = osmo_log_info->filter_fn(&log_context, - tar); - - if (output) { - /* FIXME: copying the va_list is an ugly - * workaround against a bug hidden somewhere in - * _output. If we do not copy here, the first - * call to _output() will corrupt the va_list - * contents, and any further _output() calls - * with the same va_list will segfault */ - va_list bp; - va_copy(bp, ap); - _output(tar, subsys, file, line, cont, format, bp); - va_end(bp); - } - } -} - -void logp(unsigned int subsys, char *file, int line, int cont, - const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - _logp(subsys, LOGL_DEBUG, file, line, cont, format, ap); - va_end(ap); -} - -void logp2(unsigned int subsys, unsigned int level, char *file, int line, int cont, const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - _logp(subsys, level, file, line, cont, format, ap); - va_end(ap); -} - -static char hexd_buff[4096]; - -char *hexdump(const unsigned char *buf, int len) -{ - int i; - char *cur = hexd_buff; - - hexd_buff[0] = 0; - for (i = 0; i < len; i++) { - int len_remain = sizeof(hexd_buff) - (cur - hexd_buff); - int rc = snprintf(cur, len_remain, "%02x ", buf[i]); - if (rc <= 0) - break; - cur += rc; - } - hexd_buff[sizeof(hexd_buff)-1] = 0; - return hexd_buff; -} - -void log_add_target(struct log_target *target) -{ - llist_add_tail(&target->entry, &target_list); -} - -void log_del_target(struct log_target *target) -{ - llist_del(&target->entry); -} - -void log_reset_context(void) -{ - memset(&log_context, 0, sizeof(log_context)); -} - -int log_set_context(uint8_t ctx_nr, void *value) -{ - if (ctx_nr > LOG_MAX_CTX) - return -EINVAL; - - log_context.ctx[ctx_nr] = value; - - return 0; -} - -void log_set_all_filter(struct log_target *target, int all) -{ - if (all) - target->filter_map |= LOG_FILTER_ALL; - else - target->filter_map &= ~LOG_FILTER_ALL; -} - -void log_set_use_color(struct log_target *target, int use_color) -{ - target->use_color = use_color; -} - -void log_set_print_timestamp(struct log_target *target, int print_timestamp) -{ - target->print_timestamp = print_timestamp; -} - -void log_set_log_level(struct log_target *target, int log_level) -{ - target->loglevel = log_level; -} - -void log_set_category_filter(struct log_target *target, int category, - int enable, int level) -{ - if (category >= osmo_log_info->num_cat) - return; - target->categories[category].enabled = !!enable; - target->categories[category].loglevel = level; -} - -/* since C89/C99 says stderr is a macro, we can safely do this! */ -#ifdef stderr -static void _stderr_output(struct log_target *target, const char *log) -{ - fprintf(target->tgt_stdout.out, "%s", log); - fflush(target->tgt_stdout.out); -} -#endif - -struct log_target *log_target_create(void) -{ - struct log_target *target; - unsigned int i; - - target = talloc_zero(tall_log_ctx, struct log_target); - if (!target) - return NULL; - - INIT_LLIST_HEAD(&target->entry); - - /* initialize the per-category enabled/loglevel from defaults */ - for (i = 0; i < osmo_log_info->num_cat; i++) { - struct log_category *cat = &target->categories[i]; - cat->enabled = osmo_log_info->cat[i].enabled; - cat->loglevel = osmo_log_info->cat[i].loglevel; - } - - /* global settings */ - target->use_color = 1; - target->print_timestamp = 0; - - /* global log level */ - target->loglevel = 0; - return target; -} - -struct log_target *log_target_create_stderr(void) -{ -/* since C89/C99 says stderr is a macro, we can safely do this! */ -#ifdef stderr - struct log_target *target; - - target = log_target_create(); - if (!target) - return NULL; - - target->tgt_stdout.out = stderr; - target->output = _stderr_output; - return target; -#else - return NULL; -#endif /* stderr */ -} - -const char *log_vty_level_string(struct log_info *info) -{ - const struct value_string *vs; - unsigned int len = 3; /* ()\0 */ - char *str; - - for (vs = loglevel_strs; vs->value || vs->str; vs++) - len += strlen(vs->str) + 1; - - str = talloc_zero_size(NULL, len); - if (!str) - return NULL; - - str[0] = '('; - for (vs = loglevel_strs; vs->value || vs->str; vs++) { - strcat(str, vs->str); - strcat(str, "|"); - } - str[strlen(str)-1] = ')'; - - return str; -} - -const char *log_vty_category_string(struct log_info *info) -{ - unsigned int len = 3; /* "()\0" */ - unsigned int i; - char *str; - - for (i = 0; i < info->num_cat; i++) - len += strlen(info->cat[i].name) + 1; - - str = talloc_zero_size(NULL, len); - if (!str) - return NULL; - - str[0] = '('; - for (i = 0; i < info->num_cat; i++) { - strcat(str, info->cat[i].name+1); - strcat(str, "|"); - } - str[strlen(str)-1] = ')'; - - return str; -} - -void log_init(const struct log_info *cat) -{ - tall_log_ctx = talloc_named_const(NULL, 1, "logging"); - osmo_log_info = cat; -} diff --git a/libosmocore/src/msgb.c b/libosmocore/src/msgb.c deleted file mode 100644 index a60e2ffa5..000000000 --- a/libosmocore/src/msgb.c +++ /dev/null @@ -1,90 +0,0 @@ -/* (C) 2008 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 <unistd.h> -#include <string.h> -#include <stdlib.h> -#include <sys/types.h> - -#include <osmocore/msgb.h> -//#include <openbsc/gsm_data.h> -#include <osmocore/talloc.h> -//#include <openbsc/debug.h> - -void *tall_msgb_ctx; - -struct msgb *msgb_alloc(uint16_t size, const char *name) -{ - struct msgb *msg; - - msg = _talloc_zero(tall_msgb_ctx, sizeof(*msg) + size, name); - - if (!msg) { - //LOGP(DRSL, LOGL_FATAL, "unable to allocate msgb\n"); - return NULL; - } - - msg->data_len = size; - msg->len = 0; - msg->data = msg->_data; - msg->head = msg->_data; - msg->tail = msg->_data; - - return msg; -} - -void msgb_free(struct msgb *m) -{ - talloc_free(m); -} - -void msgb_enqueue(struct llist_head *queue, struct msgb *msg) -{ - llist_add_tail(&msg->list, queue); -} - -struct msgb *msgb_dequeue(struct llist_head *queue) -{ - struct llist_head *lh; - - if (llist_empty(queue)) - return NULL; - - lh = queue->next; - llist_del(lh); - - return llist_entry(lh, struct msgb, list); -} - -void msgb_reset(struct msgb *msg) -{ - msg->len = 0; - msg->data = msg->_data; - msg->head = msg->_data; - msg->tail = msg->_data; - - msg->trx = NULL; - msg->lchan = NULL; - msg->l2h = NULL; - msg->l3h = NULL; - msg->l4h = NULL; - - memset(&msg->cb, 0, sizeof(msg->cb)); -} diff --git a/libosmocore/src/rate_ctr.c b/libosmocore/src/rate_ctr.c deleted file mode 100644 index f58b5c4a1..000000000 --- a/libosmocore/src/rate_ctr.c +++ /dev/null @@ -1,128 +0,0 @@ -/* utility routines for keeping conters about events and the event rates */ - -/* (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 <string.h> - -#include <osmocore/utils.h> -#include <osmocore/linuxlist.h> -#include <osmocore/talloc.h> -#include <osmocore/timer.h> -#include <osmocore/rate_ctr.h> - -static LLIST_HEAD(rate_ctr_groups); - -static void *tall_rate_ctr_ctx; - -struct rate_ctr_group *rate_ctr_group_alloc(void *ctx, - const struct rate_ctr_group_desc *desc, - unsigned int idx) -{ - unsigned int size; - struct rate_ctr_group *group; - - size = sizeof(struct rate_ctr_group) + - desc->num_ctr * sizeof(struct rate_ctr); - - if (!ctx) - ctx = tall_rate_ctr_ctx; - - group = talloc_zero_size(ctx, size); - if (!group) - return NULL; - - group->desc = desc; - group->idx = idx; - - llist_add(&group->list, &rate_ctr_groups); - - return group; -} - -void rate_ctr_group_free(struct rate_ctr_group *grp) -{ - llist_del(&grp->list); - talloc_free(grp); -} - -void rate_ctr_add(struct rate_ctr *ctr, int inc) -{ - ctr->current += inc; -} - -static void interval_expired(struct rate_ctr *ctr, enum rate_ctr_intv intv) -{ - /* calculate rate over last interval */ - 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; -static uint64_t timer_ticks; - -/* The one-second interval has expired */ -static void rate_ctr_group_intv(struct rate_ctr_group *grp) -{ - unsigned int i; - - for (i = 0; i < grp->desc->num_ctr; i++) { - struct rate_ctr *ctr = &grp->ctr[i]; - - interval_expired(ctr, RATE_CTR_INTV_SEC); - if ((timer_ticks % 60) == 0) - interval_expired(ctr, RATE_CTR_INTV_MIN); - if ((timer_ticks % (60*60)) == 0) - interval_expired(ctr, RATE_CTR_INTV_HOUR); - if ((timer_ticks % (24*60*60)) == 0) - interval_expired(ctr, RATE_CTR_INTV_DAY); - } -} - -static void rate_ctr_timer_cb(void *data) -{ - struct rate_ctr_group *ctrg; - - /* Increment number of ticks before we calculate intervals, - * as a counter value of 0 would already wrap all counters */ - timer_ticks++; - - llist_for_each_entry(ctrg, &rate_ctr_groups, list) - rate_ctr_group_intv(ctrg); - - bsc_schedule_timer(&rate_ctr_timer, 1, 0); -} - -int rate_ctr_init(void *tall_ctx) -{ - tall_rate_ctr_ctx = tall_ctx; - rate_ctr_timer.cb = rate_ctr_timer_cb; - bsc_schedule_timer(&rate_ctr_timer, 1, 0); - - return 0; -} diff --git a/libosmocore/src/rsl.c b/libosmocore/src/rsl.c deleted file mode 100644 index c002d33e2..000000000 --- a/libosmocore/src/rsl.c +++ /dev/null @@ -1,329 +0,0 @@ -/* GSM Radio Signalling Link messages on the A-bis interface - * 3GPP TS 08.58 version 8.6.0 Release 1999 / ETSI TS 100 596 V8.6.0 */ - -/* (C) 2008-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 <errno.h> - -#include <osmocore/tlv.h> -#include <osmocore/rsl.h> - -#define RSL_ALLOC_SIZE 200 -#define RSL_ALLOC_HEADROOM 56 - -void rsl_init_rll_hdr(struct abis_rsl_rll_hdr *dh, uint8_t msg_type) -{ - dh->c.msg_discr = ABIS_RSL_MDISC_RLL; - dh->c.msg_type = msg_type; - dh->ie_chan = RSL_IE_CHAN_NR; - dh->ie_link_id = RSL_IE_LINK_IDENT; -} - -const struct tlv_definition rsl_att_tlvdef = { - .def = { - [RSL_IE_CHAN_NR] = { TLV_TYPE_TV }, - [RSL_IE_LINK_IDENT] = { TLV_TYPE_TV }, - [RSL_IE_ACT_TYPE] = { TLV_TYPE_TV }, - [RSL_IE_BS_POWER] = { TLV_TYPE_TV }, - [RSL_IE_CHAN_IDENT] = { TLV_TYPE_TLV }, - [RSL_IE_CHAN_MODE] = { TLV_TYPE_TLV }, - [RSL_IE_ENCR_INFO] = { TLV_TYPE_TLV }, - [RSL_IE_FRAME_NUMBER] = { TLV_TYPE_FIXED, 2 }, - [RSL_IE_HANDO_REF] = { TLV_TYPE_TV }, - [RSL_IE_L1_INFO] = { TLV_TYPE_FIXED, 2 }, - [RSL_IE_L3_INFO] = { TLV_TYPE_TL16V }, - [RSL_IE_MS_IDENTITY] = { TLV_TYPE_TLV }, - [RSL_IE_MS_POWER] = { TLV_TYPE_TV }, - [RSL_IE_PAGING_GROUP] = { TLV_TYPE_TV }, - [RSL_IE_PAGING_LOAD] = { TLV_TYPE_FIXED, 2 }, - [RSL_IE_PYHS_CONTEXT] = { TLV_TYPE_TLV }, - [RSL_IE_ACCESS_DELAY] = { TLV_TYPE_TV }, - [RSL_IE_RACH_LOAD] = { TLV_TYPE_TLV }, - [RSL_IE_REQ_REFERENCE] = { TLV_TYPE_FIXED, 3 }, - [RSL_IE_RELEASE_MODE] = { TLV_TYPE_TV }, - [RSL_IE_RESOURCE_INFO] = { TLV_TYPE_TLV }, - [RSL_IE_RLM_CAUSE] = { TLV_TYPE_TLV }, - [RSL_IE_STARTNG_TIME] = { TLV_TYPE_FIXED, 2 }, - [RSL_IE_TIMING_ADVANCE] = { TLV_TYPE_TV }, - [RSL_IE_UPLINK_MEAS] = { TLV_TYPE_TLV }, - [RSL_IE_CAUSE] = { TLV_TYPE_TLV }, - [RSL_IE_MEAS_RES_NR] = { TLV_TYPE_TV }, - [RSL_IE_MSG_ID] = { TLV_TYPE_TV }, - [RSL_IE_SYSINFO_TYPE] = { TLV_TYPE_TV }, - [RSL_IE_MS_POWER_PARAM] = { TLV_TYPE_TLV }, - [RSL_IE_BS_POWER_PARAM] = { TLV_TYPE_TLV }, - [RSL_IE_PREPROC_PARAM] = { TLV_TYPE_TLV }, - [RSL_IE_PREPROC_MEAS] = { TLV_TYPE_TLV }, - [RSL_IE_IMM_ASS_INFO] = { TLV_TYPE_TLV }, - [RSL_IE_SMSCB_INFO] = { TLV_TYPE_FIXED, 23 }, - [RSL_IE_MS_TIMING_OFFSET] = { TLV_TYPE_TV }, - [RSL_IE_ERR_MSG] = { TLV_TYPE_TLV }, - [RSL_IE_FULL_BCCH_INFO] = { TLV_TYPE_TLV }, - [RSL_IE_CHAN_NEEDED] = { TLV_TYPE_TV }, - [RSL_IE_CB_CMD_TYPE] = { TLV_TYPE_TV }, - [RSL_IE_SMSCB_MSG] = { TLV_TYPE_TLV }, - [RSL_IE_FULL_IMM_ASS_INFO] = { TLV_TYPE_TLV }, - [RSL_IE_SACCH_INFO] = { TLV_TYPE_TLV }, - [RSL_IE_CBCH_LOAD_INFO] = { TLV_TYPE_TV }, - [RSL_IE_SMSCB_CHAN_INDICATOR] = { TLV_TYPE_TV }, - [RSL_IE_GROUP_CALL_REF] = { TLV_TYPE_TLV }, - [RSL_IE_CHAN_DESC] = { TLV_TYPE_TLV }, - [RSL_IE_NCH_DRX_INFO] = { TLV_TYPE_TLV }, - [RSL_IE_CMD_INDICATOR] = { TLV_TYPE_TLV }, - [RSL_IE_EMLPP_PRIO] = { TLV_TYPE_TV }, - [RSL_IE_UIC] = { TLV_TYPE_TLV }, - [RSL_IE_MAIN_CHAN_REF] = { TLV_TYPE_TV }, - [RSL_IE_MR_CONFIG] = { TLV_TYPE_TLV }, - [RSL_IE_MR_CONTROL] = { TLV_TYPE_TV }, - [RSL_IE_SUP_CODEC_TYPES] = { TLV_TYPE_TLV }, - [RSL_IE_CODEC_CONFIG] = { TLV_TYPE_TLV }, - [RSL_IE_RTD] = { TLV_TYPE_TV }, - [RSL_IE_TFO_STATUS] = { TLV_TYPE_TV }, - [RSL_IE_LLP_APDU] = { TLV_TYPE_TLV }, - [RSL_IE_SIEMENS_MRPCI] = { TLV_TYPE_TV }, - [RSL_IE_IPAC_PROXY_UDP] = { TLV_TYPE_FIXED, 2 }, - [RSL_IE_IPAC_BSCMPL_TOUT] = { TLV_TYPE_TV }, - [RSL_IE_IPAC_REMOTE_IP] = { TLV_TYPE_FIXED, 4 }, - [RSL_IE_IPAC_REMOTE_PORT] = { TLV_TYPE_FIXED, 2 }, - [RSL_IE_IPAC_RTP_PAYLOAD] = { TLV_TYPE_TV }, - [RSL_IE_IPAC_LOCAL_PORT] = { TLV_TYPE_FIXED, 2 }, - [RSL_IE_IPAC_SPEECH_MODE] = { TLV_TYPE_TV }, - [RSL_IE_IPAC_LOCAL_IP] = { TLV_TYPE_FIXED, 4 }, - [RSL_IE_IPAC_CONN_ID] = { TLV_TYPE_FIXED, 2 }, - [RSL_IE_IPAC_RTP_CSD_FMT] = { TLV_TYPE_TV }, - [RSL_IE_IPAC_RTP_JIT_BUF] = { TLV_TYPE_FIXED, 2 }, - [RSL_IE_IPAC_RTP_COMPR] = { TLV_TYPE_TV }, - [RSL_IE_IPAC_RTP_PAYLOAD2] = { TLV_TYPE_TV }, - [RSL_IE_IPAC_RTP_MPLEX] = { TLV_TYPE_FIXED, 8 }, - [RSL_IE_IPAC_RTP_MPLEX_ID] = { TLV_TYPE_TV }, - }, -}; - -/* encode channel number as per Section 9.3.1 */ -uint8_t rsl_enc_chan_nr(uint8_t type, uint8_t subch, uint8_t timeslot) -{ - uint8_t ret; - - ret = (timeslot & 0x07) | type; - - switch (type) { - case RSL_CHAN_Lm_ACCHs: - subch &= 0x01; - break; - case RSL_CHAN_SDCCH4_ACCH: - subch &= 0x03; - break; - case RSL_CHAN_SDCCH8_ACCH: - subch &= 0x07; - break; - default: - /* no subchannels allowed */ - subch = 0x00; - break; - } - ret |= (subch << 3); - - return ret; -} - -int rsl_dec_chan_nr(uint8_t chan_nr, uint8_t *type, uint8_t *subch, uint8_t *timeslot) -{ - *timeslot = chan_nr & 0x7; - - if ((chan_nr & 0xf8) == RSL_CHAN_Bm_ACCHs) { - *type = RSL_CHAN_Bm_ACCHs; - *subch = 0; - } else if ((chan_nr & 0xf0) == RSL_CHAN_Lm_ACCHs) { - *type = RSL_CHAN_Lm_ACCHs; - *subch = (chan_nr >> 3) & 0x1; - } else if ((chan_nr & 0xe0) == RSL_CHAN_SDCCH4_ACCH) { - *type = RSL_CHAN_SDCCH4_ACCH; - *subch = (chan_nr >> 3) & 0x3; - } else if ((chan_nr & 0xc0) == RSL_CHAN_SDCCH8_ACCH) { - *type = RSL_CHAN_SDCCH8_ACCH; - *subch = (chan_nr >> 3) & 0x7; - } else if ((chan_nr & 0xf8) == RSL_CHAN_BCCH) { - *type = RSL_CHAN_BCCH; - *subch = 0; - } else if ((chan_nr & 0xf8) == RSL_CHAN_RACH) { - *type = RSL_CHAN_RACH; - *subch = 0; - } else if ((chan_nr & 0xf8) == RSL_CHAN_PCH_AGCH) { - *type = RSL_CHAN_PCH_AGCH; - *subch = 0; - } else - return -EINVAL; - - return 0; -} - -static const struct value_string rsl_err_vals[] = { - { RSL_ERR_RADIO_IF_FAIL, "Radio Interface Failure" }, - { RSL_ERR_RADIO_LINK_FAIL, "Radio Link Failure" }, - { RSL_ERR_HANDOVER_ACC_FAIL, "Handover Access Failure" }, - { RSL_ERR_TALKER_ACC_FAIL, "Talker Access Failure" }, - { RSL_ERR_OM_INTERVENTION, "O&M Intervention" }, - { RSL_ERR_NORMAL_UNSPEC, "Normal event, unspecified" }, - { RSL_ERR_T_MSRFPCI_EXP, "Siemens: T_MSRFPCI Expired" }, - { RSL_ERR_EQUIPMENT_FAIL, "Equipment Failure" }, - { RSL_ERR_RR_UNAVAIL, "Radio Resource not available" }, - { RSL_ERR_TERR_CH_FAIL, "Terrestrial Channel Failure" }, - { RSL_ERR_CCCH_OVERLOAD, "CCCH Overload" }, - { RSL_ERR_ACCH_OVERLOAD, "ACCH Overload" }, - { RSL_ERR_PROCESSOR_OVERLOAD, "Processor Overload" }, - { RSL_ERR_RES_UNAVAIL, "Resource not available, unspecified" }, - { RSL_ERR_TRANSC_UNAVAIL, "Transcoding not available" }, - { RSL_ERR_SERV_OPT_UNAVAIL, "Service or Option not available" }, - { RSL_ERR_ENCR_UNIMPL, "Encryption algorithm not implemented" }, - { RSL_ERR_SERV_OPT_UNIMPL, "Service or Option not implemented" }, - { RSL_ERR_RCH_ALR_ACTV_ALLOC, "Radio channel already activated" }, - { RSL_ERR_INVALID_MESSAGE, "Invalid Message, unspecified" }, - { RSL_ERR_MSG_DISCR, "Message Discriminator Error" }, - { RSL_ERR_MSG_TYPE, "Message Type Error" }, - { RSL_ERR_MSG_SEQ, "Message Sequence Error" }, - { RSL_ERR_IE_ERROR, "General IE error" }, - { RSL_ERR_MAND_IE_ERROR, "Mandatory IE error" }, - { RSL_ERR_OPT_IE_ERROR, "Optional IE error" }, - { RSL_ERR_IE_NONEXIST, "IE non-existent" }, - { RSL_ERR_IE_LENGTH, "IE length error" }, - { RSL_ERR_IE_CONTENT, "IE content error" }, - { RSL_ERR_PROTO, "Protocol error, unspecified" }, - { RSL_ERR_INTERWORKING, "Interworking error, unspecified" }, - { 0, NULL } -}; - -const char *rsl_err_name(uint8_t err) -{ - return get_value_string(rsl_err_vals, err); -} - -static const struct value_string rsl_rlm_cause_strs[] = { - { RLL_CAUSE_T200_EXPIRED, "Timer T200 expired (N200+1) times" }, - { RLL_CAUSE_REEST_REQ, "Re-establishment request" }, - { RLL_CAUSE_UNSOL_UA_RESP, "Unsolicited UA response" }, - { RLL_CAUSE_UNSOL_DM_RESP, "Unsolicited DM response" }, - { RLL_CAUSE_UNSOL_DM_RESP_MF, "Unsolicited DM response, multiple frame" }, - { RLL_CAUSE_UNSOL_SPRV_RESP, "Unsolicited supervisory response" }, - { RLL_CAUSE_SEQ_ERR, "Sequence Error" }, - { RLL_CAUSE_UFRM_INC_PARAM, "U-Frame with incorrect parameters" }, - { RLL_CAUSE_SFRM_INC_PARAM, "S-Frame with incorrect parameters" }, - { RLL_CAUSE_IFRM_INC_MBITS, "I-Frame with incorrect use of M bit" }, - { RLL_CAUSE_IFRM_INC_LEN, "I-Frame with incorrect length" }, - { RLL_CAUSE_FRM_UNIMPL, "Fraeme not implemented" }, - { RLL_CAUSE_SABM_MF, "SABM command, multiple frame established state" }, - { RLL_CAUSE_SABM_INFO_NOTALL, "SABM frame with information not allowed in this state" }, - { 0, NULL }, -}; - -const char *rsl_rlm_cause_name(uint8_t err) -{ - return get_value_string(rsl_rlm_cause_strs, err); -} - -/* Section 3.3.2.3 TS 05.02. I think this looks like a table */ -int rsl_ccch_conf_to_bs_cc_chans(int ccch_conf) -{ - switch (ccch_conf) { - case RSL_BCCH_CCCH_CONF_1_NC: - return 1; - case RSL_BCCH_CCCH_CONF_1_C: - return 1; - case RSL_BCCH_CCCH_CONF_2_NC: - return 2; - case RSL_BCCH_CCCH_CONF_3_NC: - return 3; - case RSL_BCCH_CCCH_CONF_4_NC: - return 4; - default: - return -1; - } -} - -/* Section 3.3.2.3 TS 05.02 */ -int rsl_ccch_conf_to_bs_ccch_sdcch_comb(int ccch_conf) -{ - switch (ccch_conf) { - case RSL_BCCH_CCCH_CONF_1_NC: - return 0; - case RSL_BCCH_CCCH_CONF_1_C: - return 1; - case RSL_BCCH_CCCH_CONF_2_NC: - return 0; - case RSL_BCCH_CCCH_CONF_3_NC: - return 0; - case RSL_BCCH_CCCH_CONF_4_NC: - return 0; - default: - return -1; - } -} - -/* Push a RSL RLL header with L3_INFO IE */ -void rsl_rll_push_l3(struct msgb *msg, uint8_t msg_type, uint8_t chan_nr, - uint8_t link_id, int transparent) -{ - uint8_t l3_len = msg->tail - (uint8_t *)msgb_l3(msg); - struct abis_rsl_rll_hdr *rh; - - /* construct a RSLms RLL message (DATA INDICATION, UNIT DATA - * INDICATION) and send it off via RSLms */ - - /* Push the L3 IE tag and lengh */ - msgb_tv16_push(msg, RSL_IE_L3_INFO, l3_len); - - /* Then push the RSL header */ - rh = (struct abis_rsl_rll_hdr *) msgb_push(msg, sizeof(*rh)); - rsl_init_rll_hdr(rh, msg_type); - if (transparent) - rh->c.msg_discr |= ABIS_RSL_MDISC_TRANSP; - rh->chan_nr = chan_nr; - rh->link_id = link_id; - - /* set the l2 header pointer */ - msg->l2h = (uint8_t *)rh; -} - -struct msgb *rsl_rll_simple(uint8_t msg_type, uint8_t chan_nr, - uint8_t link_id, int transparent) -{ - struct abis_rsl_rll_hdr *rh; - struct msgb *msg; - - msg = msgb_alloc_headroom(RSL_ALLOC_SIZE+RSL_ALLOC_HEADROOM, - RSL_ALLOC_HEADROOM, "rsl_rll_simple"); - - if (!msg) - return NULL; - - /* put the RSL header */ - rh = (struct abis_rsl_rll_hdr *) msgb_put(msg, sizeof(*rh)); - rsl_init_rll_hdr(rh, msg_type); - if (transparent) - rh->c.msg_discr |= ABIS_RSL_MDISC_TRANSP; - rh->chan_nr = chan_nr; - rh->link_id = link_id; - - /* set the l2 header pointer */ - msg->l2h = (uint8_t *)rh; - - return msg; -} diff --git a/libosmocore/src/rxlev_stat.c b/libosmocore/src/rxlev_stat.c deleted file mode 100644 index 1bfd6795a..000000000 --- a/libosmocore/src/rxlev_stat.c +++ /dev/null @@ -1,94 +0,0 @@ -/* Rx Level statistics */ - -/* (C) 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 <unistd.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <stdint.h> - -#include <osmocore/bitvec.h> -#include <osmocore/rxlev_stat.h> - -int bitvec_find_bit_pos(const struct bitvec *bv, unsigned int n, enum bit_value val) -{ - unsigned int i; - - for (i = n; i < bv->data_len*8; i++) { - if (bitvec_get_bit_pos(bv, i) == val) - return i; - } - - return -1; -} - -void rxlev_stat_input(struct rxlev_stats *st, uint16_t arfcn, uint8_t rxlev) -{ - struct bitvec bv; - - if (rxlev >= NUM_RXLEVS) - rxlev = NUM_RXLEVS-1; - - bv.data_len = NUM_ARFCNS/8; - bv.data = st->rxlev_buckets[rxlev]; - - bitvec_set_bit_pos(&bv, arfcn, ONE); -} - -/* get the next ARFCN that has the specified Rxlev */ -int16_t rxlev_stat_get_next(const struct rxlev_stats *st, uint8_t rxlev, int16_t arfcn) -{ - struct bitvec bv; - - if (rxlev >= NUM_RXLEVS) - rxlev = NUM_RXLEVS-1; - - bv.data_len = NUM_ARFCNS/8; - - if (arfcn < 0) - arfcn = -1; - - bv.data = st->rxlev_buckets[rxlev]; - - return bitvec_find_bit_pos(&bv, arfcn+1, ONE); -} - -void rxlev_stat_reset(struct rxlev_stats *st) -{ - memset(st, 0, sizeof(*st)); -} - -void rxlev_stat_dump(const struct rxlev_stats *st) -{ - int i; - - for (i = NUM_RXLEVS-1; i >= 0; i--) { - int16_t arfcn = -1; - - printf("ARFCN with RxLev %u: ", i); - while ((arfcn = rxlev_stat_get_next(st, i, arfcn)) >= 0) { - printf("%u ", arfcn); - } - printf("\n"); - } -} diff --git a/libosmocore/src/select.c b/libosmocore/src/select.c deleted file mode 100644 index 2f6afa7f5..000000000 --- a/libosmocore/src/select.c +++ /dev/null @@ -1,131 +0,0 @@ -/* select filedescriptor handling, taken from: - * userspace logging daemon for the iptables ULOG target - * of the linux 2.4 netfilter subsystem. - * - * (C) 2000-2009 by Harald Welte <laforge@gnumonks.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <fcntl.h> -#include <osmocore/select.h> -#include <osmocore/linuxlist.h> -#include <osmocore/timer.h> - -#include "../config.h" - -#ifdef HAVE_SYS_SELECT_H - -static int maxfd = 0; -static LLIST_HEAD(bsc_fds); -static int unregistered_count; - -int bsc_register_fd(struct bsc_fd *fd) -{ - int flags; - - /* make FD nonblocking */ - flags = fcntl(fd->fd, F_GETFL); - if (flags < 0) - return flags; - flags |= O_NONBLOCK; - flags = fcntl(fd->fd, F_SETFL, flags); - if (flags < 0) - return flags; - - /* Register FD */ - if (fd->fd > maxfd) - maxfd = fd->fd; - - llist_add_tail(&fd->list, &bsc_fds); - - return 0; -} - -void bsc_unregister_fd(struct bsc_fd *fd) -{ - unregistered_count++; - llist_del(&fd->list); -} - -int bsc_select_main(int polling) -{ - struct bsc_fd *ufd, *tmp; - fd_set readset, writeset, exceptset; - int work = 0, rc; - struct timeval no_time = {0, 0}; - - FD_ZERO(&readset); - FD_ZERO(&writeset); - FD_ZERO(&exceptset); - - /* prepare read and write fdsets */ - llist_for_each_entry(ufd, &bsc_fds, list) { - if (ufd->when & BSC_FD_READ) - FD_SET(ufd->fd, &readset); - - if (ufd->when & BSC_FD_WRITE) - FD_SET(ufd->fd, &writeset); - - if (ufd->when & BSC_FD_EXCEPT) - FD_SET(ufd->fd, &exceptset); - } - - bsc_timer_check(); - - if (!polling) - bsc_prepare_timers(); - rc = select(maxfd+1, &readset, &writeset, &exceptset, polling ? &no_time : bsc_nearest_timer()); - if (rc < 0) - return 0; - - /* fire timers */ - bsc_update_timers(); - - /* call registered callback functions */ -restart: - unregistered_count = 0; - llist_for_each_entry_safe(ufd, tmp, &bsc_fds, list) { - int flags = 0; - - if (FD_ISSET(ufd->fd, &readset)) { - flags |= BSC_FD_READ; - FD_CLR(ufd->fd, &readset); - } - - if (FD_ISSET(ufd->fd, &writeset)) { - flags |= BSC_FD_WRITE; - FD_CLR(ufd->fd, &writeset); - } - - if (FD_ISSET(ufd->fd, &exceptset)) { - flags |= BSC_FD_EXCEPT; - FD_CLR(ufd->fd, &exceptset); - } - - if (flags) { - work = 1; - ufd->cb(ufd, flags); - } - /* ugly, ugly hack. If more than one filedescriptors were - * unregistered, they might have been consecutive and - * llist_for_each_entry_safe() is no longer safe */ - /* this seems to happen with the last element of the list as well */ - if (unregistered_count >= 1) - goto restart; - } - return work; -} - -#endif /* _HAVE_SYS_SELECT_H */ diff --git a/libosmocore/src/signal.c b/libosmocore/src/signal.c deleted file mode 100644 index c7ca86c48..000000000 --- a/libosmocore/src/signal.c +++ /dev/null @@ -1,84 +0,0 @@ -/* Generic signalling/notification infrastructure */ -/* (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 <osmocore/signal.h> -#include <osmocore/talloc.h> -#include <osmocore/linuxlist.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> - -void *tall_sigh_ctx; -static LLIST_HEAD(signal_handler_list); - -struct signal_handler { - struct llist_head entry; - unsigned int subsys; - signal_cbfn *cbfn; - void *data; -}; - - -int register_signal_handler(unsigned int subsys, signal_cbfn *cbfn, void *data) -{ - struct signal_handler *sig_data; - - sig_data = talloc(tall_sigh_ctx, struct signal_handler); - if (!sig_data) - return -ENOMEM; - - memset(sig_data, 0, sizeof(*sig_data)); - - sig_data->subsys = subsys; - sig_data->data = data; - sig_data->cbfn = cbfn; - - /* FIXME: check if we already have a handler for this subsys/cbfn/data */ - - llist_add_tail(&sig_data->entry, &signal_handler_list); - - return 0; -} - -void unregister_signal_handler(unsigned int subsys, signal_cbfn *cbfn, void *data) -{ - struct signal_handler *handler; - - llist_for_each_entry(handler, &signal_handler_list, entry) { - if (handler->cbfn == cbfn && handler->data == data - && subsys == handler->subsys) { - llist_del(&handler->entry); - talloc_free(handler); - break; - } - } -} - - -void dispatch_signal(unsigned int subsys, unsigned int signal, void *signal_data) -{ - struct signal_handler *handler; - - llist_for_each_entry(handler, &signal_handler_list, entry) { - if (handler->subsys != subsys) - continue; - (*handler->cbfn)(subsys, signal, handler->data, signal_data); - } -} diff --git a/libosmocore/src/statistics.c b/libosmocore/src/statistics.c deleted file mode 100644 index 34e6a408e..000000000 --- a/libosmocore/src/statistics.c +++ /dev/null @@ -1,66 +0,0 @@ -/* utility routines for keeping some statistics */ - -/* (C) 2009 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 <sys/types.h> - -#include <osmocore/linuxlist.h> -#include <osmocore/talloc.h> -#include <osmocore/statistics.h> - -static LLIST_HEAD(counters); - -void *tall_ctr_ctx; - -struct counter *counter_alloc(const char *name) -{ - struct counter *ctr = talloc_zero(tall_ctr_ctx, struct counter); - - if (!ctr) - return NULL; - - ctr->name = name; - llist_add_tail(&ctr->list, &counters); - - return ctr; -} - -void counter_free(struct counter *ctr) -{ - llist_del(&ctr->list); - talloc_free(ctr); -} - -int counters_for_each(int (*handle_counter)(struct counter *, void *), void *data) -{ - struct counter *ctr; - int rc = 0; - - llist_for_each_entry(ctr, &counters, list) { - rc = handle_counter(ctr, data); - if (rc < 0) - return rc; - } - - return rc; -} - diff --git a/libosmocore/src/talloc.c b/libosmocore/src/talloc.c deleted file mode 100644 index 98c2ee097..000000000 --- a/libosmocore/src/talloc.c +++ /dev/null @@ -1,1805 +0,0 @@ -/* - Samba Unix SMB/CIFS implementation. - - Samba trivial allocation library - new interface - - NOTE: Please read talloc_guide.txt for full documentation - - Copyright (C) Andrew Tridgell 2004 - Copyright (C) Stefan Metzmacher 2006 - - ** NOTE! The following LGPL license applies to the talloc - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see <http://www.gnu.org/licenses/>. -*/ - -/* - inspired by http://swapped.cc/halloc/ -*/ - -#ifdef _SAMBA_BUILD_ -#include "version.h" -#if (SAMBA_VERSION_MAJOR<4) -#include "includes.h" -/* This is to circumvent SAMBA3's paranoid malloc checker. Here in this file - * we trust ourselves... */ -#ifdef malloc -#undef malloc -#endif -#ifdef realloc -#undef realloc -#endif -#define _TALLOC_SAMBA3 -#endif /* (SAMBA_VERSION_MAJOR<4) */ -#endif /* _SAMBA_BUILD_ */ - -#ifndef _TALLOC_SAMBA3 -//#include "replace.h" -#include <sys/types.h> -#include <unistd.h> -#include <stdio.h> -#include <stdbool.h> -#define __USE_GNU -#include <string.h> -#undef __USE_GNU -#include <osmocore/talloc.h> -#define MIN(x,y) ((x) < (y) ? (x) : (y)) -#endif /* not _TALLOC_SAMBA3 */ - -/* use this to force every realloc to change the pointer, to stress test - code that might not cope */ -#define ALWAYS_REALLOC 0 - - -#define MAX_TALLOC_SIZE 0x10000000 -#define TALLOC_MAGIC 0xe814ec70 -#define TALLOC_FLAG_FREE 0x01 -#define TALLOC_FLAG_LOOP 0x02 -#define TALLOC_FLAG_POOL 0x04 /* This is a talloc pool */ -#define TALLOC_FLAG_POOLMEM 0x08 /* This is allocated in a pool */ -#define TALLOC_MAGIC_REFERENCE ((const char *)1) - -/* by default we abort when given a bad pointer (such as when talloc_free() is called - on a pointer that came from malloc() */ -#ifndef TALLOC_ABORT -#define TALLOC_ABORT(reason) abort() -#endif - -#ifndef discard_const_p -#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) -# define discard_const_p(type, ptr) ((type *)((intptr_t)(ptr))) -#else -# define discard_const_p(type, ptr) ((type *)(ptr)) -#endif -#endif - -/* these macros gain us a few percent of speed on gcc */ -#if (__GNUC__ >= 3) -/* the strange !! is to ensure that __builtin_expect() takes either 0 or 1 - as its first argument */ -#ifndef likely -#define likely(x) __builtin_expect(!!(x), 1) -#endif -#ifndef unlikely -#define unlikely(x) __builtin_expect(!!(x), 0) -#endif -#else -#ifndef likely -#define likely(x) (x) -#endif -#ifndef unlikely -#define unlikely(x) (x) -#endif -#endif - -#ifdef __APPLE__ -/* taken from http://insanecoding.blogspot.com/2007/03/methods-for-safe-string-handling.html */ -size_t strnlen(const char *s, size_t n) -{ - const char *p = (const char *)memchr(s, 0, n); - return(p ? p-s : n); -} -#endif - -/* this null_context is only used if talloc_enable_leak_report() or - talloc_enable_leak_report_full() is called, otherwise it remains - NULL -*/ -static void *null_context; -static void *autofree_context; - -struct talloc_reference_handle { - struct talloc_reference_handle *next, *prev; - void *ptr; -}; - -typedef int (*talloc_destructor_t)(void *); - -struct talloc_chunk { - struct talloc_chunk *next, *prev; - struct talloc_chunk *parent, *child; - struct talloc_reference_handle *refs; - talloc_destructor_t destructor; - const char *name; - size_t size; - unsigned flags; - - /* - * "pool" has dual use: - * - * For the talloc pool itself (i.e. TALLOC_FLAG_POOL is set), "pool" - * marks the end of the currently allocated area. - * - * For members of the pool (i.e. TALLOC_FLAG_POOLMEM is set), "pool" - * is a pointer to the struct talloc_chunk of the pool that it was - * allocated from. This way children can quickly find the pool to chew - * from. - */ - void *pool; -}; - -/* 16 byte alignment seems to keep everyone happy */ -#define TC_HDR_SIZE ((sizeof(struct talloc_chunk)+15)&~15) -#define TC_PTR_FROM_CHUNK(tc) ((void *)(TC_HDR_SIZE + (char*)tc)) - -static void (*talloc_abort_fn)(const char *reason); - -void talloc_set_abort_fn(void (*abort_fn)(const char *reason)) -{ - talloc_abort_fn = abort_fn; -} - -static void talloc_abort(const char *reason) -{ - if (!talloc_abort_fn) { - TALLOC_ABORT(reason); - } - - talloc_abort_fn(reason); -} - -static void talloc_abort_double_free(void) -{ - talloc_abort("Bad talloc magic value - double free"); -} - -static void talloc_abort_unknown_value(void) -{ - talloc_abort("Bad talloc magic value - unknown value"); -} - -/* panic if we get a bad magic value */ -static inline struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr) -{ - const char *pp = (const char *)ptr; - struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, pp - TC_HDR_SIZE); - if (unlikely((tc->flags & (TALLOC_FLAG_FREE | ~0xF)) != TALLOC_MAGIC)) { - if (tc->flags & TALLOC_FLAG_FREE) { - talloc_abort_double_free(); - } else { - talloc_abort_unknown_value(); - } - } - return tc; -} - -/* hook into the front of the list */ -#define _TLIST_ADD(list, p) \ -do { \ - if (!(list)) { \ - (list) = (p); \ - (p)->next = (p)->prev = NULL; \ - } else { \ - (list)->prev = (p); \ - (p)->next = (list); \ - (p)->prev = NULL; \ - (list) = (p); \ - }\ -} while (0) - -/* remove an element from a list - element doesn't have to be in list. */ -#define _TLIST_REMOVE(list, p) \ -do { \ - if ((p) == (list)) { \ - (list) = (p)->next; \ - if (list) (list)->prev = NULL; \ - } else { \ - if ((p)->prev) (p)->prev->next = (p)->next; \ - if ((p)->next) (p)->next->prev = (p)->prev; \ - } \ - if ((p) && ((p) != (list))) (p)->next = (p)->prev = NULL; \ -} while (0) - - -/* - return the parent chunk of a pointer -*/ -static inline struct talloc_chunk *talloc_parent_chunk(const void *ptr) -{ - struct talloc_chunk *tc; - - if (unlikely(ptr == NULL)) { - return NULL; - } - - tc = talloc_chunk_from_ptr(ptr); - while (tc->prev) tc=tc->prev; - - return tc->parent; -} - -void *talloc_parent(const void *ptr) -{ - struct talloc_chunk *tc = talloc_parent_chunk(ptr); - return tc? TC_PTR_FROM_CHUNK(tc) : NULL; -} - -/* - find parents name -*/ -const char *talloc_parent_name(const void *ptr) -{ - struct talloc_chunk *tc = talloc_parent_chunk(ptr); - return tc? tc->name : NULL; -} - -/* - A pool carries an in-pool object count count in the first 16 bytes. - bytes. This is done to support talloc_steal() to a parent outside of the - pool. The count includes the pool itself, so a talloc_free() on a pool will - only destroy the pool if the count has dropped to zero. A talloc_free() of a - pool member will reduce the count, and eventually also call free(3) on the - pool memory. - - The object count is not put into "struct talloc_chunk" because it is only - relevant for talloc pools and the alignment to 16 bytes would increase the - memory footprint of each talloc chunk by those 16 bytes. -*/ - -#define TALLOC_POOL_HDR_SIZE 16 - -static unsigned int *talloc_pool_objectcount(struct talloc_chunk *tc) -{ - return (unsigned int *)((char *)tc + sizeof(struct talloc_chunk)); -} - -/* - Allocate from a pool -*/ - -static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent, - size_t size) -{ - struct talloc_chunk *pool_ctx = NULL; - size_t space_left; - struct talloc_chunk *result; - size_t chunk_size; - - if (parent == NULL) { - return NULL; - } - - if (parent->flags & TALLOC_FLAG_POOL) { - pool_ctx = parent; - } - else if (parent->flags & TALLOC_FLAG_POOLMEM) { - pool_ctx = (struct talloc_chunk *)parent->pool; - } - - if (pool_ctx == NULL) { - return NULL; - } - - space_left = ((char *)pool_ctx + TC_HDR_SIZE + pool_ctx->size) - - ((char *)pool_ctx->pool); - - /* - * Align size to 16 bytes - */ - chunk_size = ((size + 15) & ~15); - - if (space_left < chunk_size) { - return NULL; - } - - result = (struct talloc_chunk *)pool_ctx->pool; - -#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED) - VALGRIND_MAKE_MEM_UNDEFINED(result, size); -#endif - - pool_ctx->pool = (void *)((char *)result + chunk_size); - - result->flags = TALLOC_MAGIC | TALLOC_FLAG_POOLMEM; - result->pool = pool_ctx; - - *talloc_pool_objectcount(pool_ctx) += 1; - - return result; -} - -/* - Allocate a bit of memory as a child of an existing pointer -*/ -static inline void *__talloc(const void *context, size_t size) -{ - struct talloc_chunk *tc = NULL; - - if (unlikely(context == NULL)) { - context = null_context; - } - - if (unlikely(size >= MAX_TALLOC_SIZE)) { - return NULL; - } - - if (context != NULL) { - tc = talloc_alloc_pool(talloc_chunk_from_ptr(context), - TC_HDR_SIZE+size); - } - - if (tc == NULL) { - tc = (struct talloc_chunk *)malloc(TC_HDR_SIZE+size); - if (unlikely(tc == NULL)) return NULL; - tc->flags = TALLOC_MAGIC; - tc->pool = NULL; - } - - tc->size = size; - tc->destructor = NULL; - tc->child = NULL; - tc->name = NULL; - tc->refs = NULL; - - if (likely(context)) { - struct talloc_chunk *parent = talloc_chunk_from_ptr(context); - - if (parent->child) { - parent->child->parent = NULL; - tc->next = parent->child; - tc->next->prev = tc; - } else { - tc->next = NULL; - } - tc->parent = parent; - tc->prev = NULL; - parent->child = tc; - } else { - tc->next = tc->prev = tc->parent = NULL; - } - - return TC_PTR_FROM_CHUNK(tc); -} - -/* - * Create a talloc pool - */ - -void *talloc_pool(const void *context, size_t size) -{ - void *result = __talloc(context, size + TALLOC_POOL_HDR_SIZE); - struct talloc_chunk *tc; - - if (unlikely(result == NULL)) { - return NULL; - } - - tc = talloc_chunk_from_ptr(result); - - tc->flags |= TALLOC_FLAG_POOL; - tc->pool = (char *)result + TALLOC_POOL_HDR_SIZE; - - *talloc_pool_objectcount(tc) = 1; - -#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS) - VALGRIND_MAKE_MEM_NOACCESS(tc->pool, size); -#endif - - return result; -} - -/* - setup a destructor to be called on free of a pointer - the destructor should return 0 on success, or -1 on failure. - if the destructor fails then the free is failed, and the memory can - be continued to be used -*/ -void _talloc_set_destructor(const void *ptr, int (*destructor)(void *)) -{ - struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); - tc->destructor = destructor; -} - -/* - increase the reference count on a piece of memory. -*/ -int talloc_increase_ref_count(const void *ptr) -{ - if (unlikely(!talloc_reference(null_context, ptr))) { - return -1; - } - return 0; -} - -/* - helper for talloc_reference() - - this is referenced by a function pointer and should not be inline -*/ -static int talloc_reference_destructor(struct talloc_reference_handle *handle) -{ - struct talloc_chunk *ptr_tc = talloc_chunk_from_ptr(handle->ptr); - _TLIST_REMOVE(ptr_tc->refs, handle); - return 0; -} - -/* - more efficient way to add a name to a pointer - the name must point to a - true string constant -*/ -static inline void _talloc_set_name_const(const void *ptr, const char *name) -{ - struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); - tc->name = name; -} - -/* - internal talloc_named_const() -*/ -static inline void *_talloc_named_const(const void *context, size_t size, const char *name) -{ - void *ptr; - - ptr = __talloc(context, size); - if (unlikely(ptr == NULL)) { - return NULL; - } - - _talloc_set_name_const(ptr, name); - - return ptr; -} - -/* - make a secondary reference to a pointer, hanging off the given context. - the pointer remains valid until both the original caller and this given - context are freed. - - the major use for this is when two different structures need to reference the - same underlying data, and you want to be able to free the two instances separately, - and in either order -*/ -void *_talloc_reference(const void *context, const void *ptr) -{ - struct talloc_chunk *tc; - struct talloc_reference_handle *handle; - if (unlikely(ptr == NULL)) return NULL; - - tc = talloc_chunk_from_ptr(ptr); - handle = (struct talloc_reference_handle *)_talloc_named_const(context, - sizeof(struct talloc_reference_handle), - TALLOC_MAGIC_REFERENCE); - if (unlikely(handle == NULL)) return NULL; - - /* note that we hang the destructor off the handle, not the - main context as that allows the caller to still setup their - own destructor on the context if they want to */ - talloc_set_destructor(handle, talloc_reference_destructor); - handle->ptr = discard_const_p(void, ptr); - _TLIST_ADD(tc->refs, handle); - return handle->ptr; -} - - -/* - internal talloc_free call -*/ -static inline int _talloc_free(void *ptr) -{ - struct talloc_chunk *tc; - - if (unlikely(ptr == NULL)) { - return -1; - } - - tc = talloc_chunk_from_ptr(ptr); - - if (unlikely(tc->refs)) { - int is_child; - /* check this is a reference from a child or grantchild - * back to it's parent or grantparent - * - * in that case we need to remove the reference and - * call another instance of talloc_free() on the current - * pointer. - */ - is_child = talloc_is_parent(tc->refs, ptr); - _talloc_free(tc->refs); - if (is_child) { - return _talloc_free(ptr); - } - return -1; - } - - if (unlikely(tc->flags & TALLOC_FLAG_LOOP)) { - /* we have a free loop - stop looping */ - return 0; - } - - if (unlikely(tc->destructor)) { - talloc_destructor_t d = tc->destructor; - if (d == (talloc_destructor_t)-1) { - return -1; - } - tc->destructor = (talloc_destructor_t)-1; - if (d(ptr) == -1) { - tc->destructor = d; - return -1; - } - tc->destructor = NULL; - } - - if (tc->parent) { - _TLIST_REMOVE(tc->parent->child, tc); - if (tc->parent->child) { - tc->parent->child->parent = tc->parent; - } - } else { - if (tc->prev) tc->prev->next = tc->next; - if (tc->next) tc->next->prev = tc->prev; - } - - tc->flags |= TALLOC_FLAG_LOOP; - - while (tc->child) { - /* we need to work out who will own an abandoned child - if it cannot be freed. In priority order, the first - choice is owner of any remaining reference to this - pointer, the second choice is our parent, and the - final choice is the null context. */ - void *child = TC_PTR_FROM_CHUNK(tc->child); - const void *new_parent = null_context; - if (unlikely(tc->child->refs)) { - struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs); - if (p) new_parent = TC_PTR_FROM_CHUNK(p); - } - if (unlikely(_talloc_free(child) == -1)) { - if (new_parent == null_context) { - struct talloc_chunk *p = talloc_parent_chunk(ptr); - if (p) new_parent = TC_PTR_FROM_CHUNK(p); - } - talloc_steal(new_parent, child); - } - } - - tc->flags |= TALLOC_FLAG_FREE; - - if (tc->flags & (TALLOC_FLAG_POOL|TALLOC_FLAG_POOLMEM)) { - struct talloc_chunk *pool; - unsigned int *pool_object_count; - - pool = (tc->flags & TALLOC_FLAG_POOL) - ? tc : (struct talloc_chunk *)tc->pool; - - pool_object_count = talloc_pool_objectcount(pool); - - if (*pool_object_count == 0) { - talloc_abort("Pool object count zero!"); - } - - *pool_object_count -= 1; - - if (*pool_object_count == 0) { - free(pool); - } - } - else { - free(tc); - } - return 0; -} - -/* - move a lump of memory from one talloc context to another return the - ptr on success, or NULL if it could not be transferred. - passing NULL as ptr will always return NULL with no side effects. -*/ -void *_talloc_steal(const void *new_ctx, const void *ptr) -{ - struct talloc_chunk *tc, *new_tc; - - if (unlikely(!ptr)) { - return NULL; - } - - if (unlikely(new_ctx == NULL)) { - new_ctx = null_context; - } - - tc = talloc_chunk_from_ptr(ptr); - - if (unlikely(new_ctx == NULL)) { - if (tc->parent) { - _TLIST_REMOVE(tc->parent->child, tc); - if (tc->parent->child) { - tc->parent->child->parent = tc->parent; - } - } else { - if (tc->prev) tc->prev->next = tc->next; - if (tc->next) tc->next->prev = tc->prev; - } - - tc->parent = tc->next = tc->prev = NULL; - return discard_const_p(void, ptr); - } - - new_tc = talloc_chunk_from_ptr(new_ctx); - - if (unlikely(tc == new_tc || tc->parent == new_tc)) { - return discard_const_p(void, ptr); - } - - if (tc->parent) { - _TLIST_REMOVE(tc->parent->child, tc); - if (tc->parent->child) { - tc->parent->child->parent = tc->parent; - } - } else { - if (tc->prev) tc->prev->next = tc->next; - if (tc->next) tc->next->prev = tc->prev; - } - - tc->parent = new_tc; - if (new_tc->child) new_tc->child->parent = NULL; - _TLIST_ADD(new_tc->child, tc); - - return discard_const_p(void, ptr); -} - - - -/* - remove a secondary reference to a pointer. This undo's what - talloc_reference() has done. The context and pointer arguments - must match those given to a talloc_reference() -*/ -static inline int talloc_unreference(const void *context, const void *ptr) -{ - struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); - struct talloc_reference_handle *h; - - if (unlikely(context == NULL)) { - context = null_context; - } - - for (h=tc->refs;h;h=h->next) { - struct talloc_chunk *p = talloc_parent_chunk(h); - if (p == NULL) { - if (context == NULL) break; - } else if (TC_PTR_FROM_CHUNK(p) == context) { - break; - } - } - if (h == NULL) { - return -1; - } - - return _talloc_free(h); -} - -/* - remove a specific parent context from a pointer. This is a more - controlled varient of talloc_free() -*/ -int talloc_unlink(const void *context, void *ptr) -{ - struct talloc_chunk *tc_p, *new_p; - void *new_parent; - - if (ptr == NULL) { - return -1; - } - - if (context == NULL) { - context = null_context; - } - - if (talloc_unreference(context, ptr) == 0) { - return 0; - } - - if (context == NULL) { - if (talloc_parent_chunk(ptr) != NULL) { - return -1; - } - } else { - if (talloc_chunk_from_ptr(context) != talloc_parent_chunk(ptr)) { - return -1; - } - } - - tc_p = talloc_chunk_from_ptr(ptr); - - if (tc_p->refs == NULL) { - return _talloc_free(ptr); - } - - new_p = talloc_parent_chunk(tc_p->refs); - if (new_p) { - new_parent = TC_PTR_FROM_CHUNK(new_p); - } else { - new_parent = NULL; - } - - if (talloc_unreference(new_parent, ptr) != 0) { - return -1; - } - - talloc_steal(new_parent, ptr); - - return 0; -} - -/* - add a name to an existing pointer - va_list version -*/ -static inline const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0); - -static inline const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap) -{ - struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); - tc->name = talloc_vasprintf(ptr, fmt, ap); - if (likely(tc->name)) { - _talloc_set_name_const(tc->name, ".name"); - } - return tc->name; -} - -/* - add a name to an existing pointer -*/ -const char *talloc_set_name(const void *ptr, const char *fmt, ...) -{ - const char *name; - va_list ap; - va_start(ap, fmt); - name = talloc_set_name_v(ptr, fmt, ap); - va_end(ap); - return name; -} - - -/* - create a named talloc pointer. Any talloc pointer can be named, and - talloc_named() operates just like talloc() except that it allows you - to name the pointer. -*/ -void *talloc_named(const void *context, size_t size, const char *fmt, ...) -{ - va_list ap; - void *ptr; - const char *name; - - ptr = __talloc(context, size); - if (unlikely(ptr == NULL)) return NULL; - - va_start(ap, fmt); - name = talloc_set_name_v(ptr, fmt, ap); - va_end(ap); - - if (unlikely(name == NULL)) { - _talloc_free(ptr); - return NULL; - } - - return ptr; -} - -/* - return the name of a talloc ptr, or "UNNAMED" -*/ -const char *talloc_get_name(const void *ptr) -{ - struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); - if (unlikely(tc->name == TALLOC_MAGIC_REFERENCE)) { - return ".reference"; - } - if (likely(tc->name)) { - return tc->name; - } - return "UNNAMED"; -} - - -/* - check if a pointer has the given name. If it does, return the pointer, - otherwise return NULL -*/ -void *talloc_check_name(const void *ptr, const char *name) -{ - const char *pname; - if (unlikely(ptr == NULL)) return NULL; - pname = talloc_get_name(ptr); - if (likely(pname == name || strcmp(pname, name) == 0)) { - return discard_const_p(void, ptr); - } - return NULL; -} - -static void talloc_abort_type_missmatch(const char *location, - const char *name, - const char *expected) -{ - const char *reason; - - reason = talloc_asprintf(NULL, - "%s: Type mismatch: name[%s] expected[%s]", - location, - name?name:"NULL", - expected); - if (!reason) { - reason = "Type mismatch"; - } - - talloc_abort(reason); -} - -void *_talloc_get_type_abort(const void *ptr, const char *name, const char *location) -{ - const char *pname; - - if (unlikely(ptr == NULL)) { - talloc_abort_type_missmatch(location, NULL, name); - return NULL; - } - - pname = talloc_get_name(ptr); - if (likely(pname == name || strcmp(pname, name) == 0)) { - return discard_const_p(void, ptr); - } - - talloc_abort_type_missmatch(location, pname, name); - return NULL; -} - -/* - this is for compatibility with older versions of talloc -*/ -void *talloc_init(const char *fmt, ...) -{ - va_list ap; - void *ptr; - const char *name; - - /* - * samba3 expects talloc_report_depth_cb(NULL, ...) - * reports all talloc'ed memory, so we need to enable - * null_tracking - */ - talloc_enable_null_tracking(); - - ptr = __talloc(NULL, 0); - if (unlikely(ptr == NULL)) return NULL; - - va_start(ap, fmt); - name = talloc_set_name_v(ptr, fmt, ap); - va_end(ap); - - if (unlikely(name == NULL)) { - _talloc_free(ptr); - return NULL; - } - - return ptr; -} - -/* - this is a replacement for the Samba3 talloc_destroy_pool functionality. It - should probably not be used in new code. It's in here to keep the talloc - code consistent across Samba 3 and 4. -*/ -void talloc_free_children(void *ptr) -{ - struct talloc_chunk *tc; - - if (unlikely(ptr == NULL)) { - return; - } - - tc = talloc_chunk_from_ptr(ptr); - - while (tc->child) { - /* we need to work out who will own an abandoned child - if it cannot be freed. In priority order, the first - choice is owner of any remaining reference to this - pointer, the second choice is our parent, and the - final choice is the null context. */ - void *child = TC_PTR_FROM_CHUNK(tc->child); - const void *new_parent = null_context; - if (unlikely(tc->child->refs)) { - struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs); - if (p) new_parent = TC_PTR_FROM_CHUNK(p); - } - if (unlikely(_talloc_free(child) == -1)) { - if (new_parent == null_context) { - struct talloc_chunk *p = talloc_parent_chunk(ptr); - if (p) new_parent = TC_PTR_FROM_CHUNK(p); - } - talloc_steal(new_parent, child); - } - } - - if ((tc->flags & TALLOC_FLAG_POOL) - && (*talloc_pool_objectcount(tc) == 1)) { - tc->pool = ((char *)tc + TC_HDR_SIZE + TALLOC_POOL_HDR_SIZE); -#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS) - VALGRIND_MAKE_MEM_NOACCESS( - tc->pool, tc->size - TALLOC_POOL_HDR_SIZE); -#endif - } -} - -/* - Allocate a bit of memory as a child of an existing pointer -*/ -void *_talloc(const void *context, size_t size) -{ - return __talloc(context, size); -} - -/* - externally callable talloc_set_name_const() -*/ -void talloc_set_name_const(const void *ptr, const char *name) -{ - _talloc_set_name_const(ptr, name); -} - -/* - create a named talloc pointer. Any talloc pointer can be named, and - talloc_named() operates just like talloc() except that it allows you - to name the pointer. -*/ -void *talloc_named_const(const void *context, size_t size, const char *name) -{ - return _talloc_named_const(context, size, name); -} - -/* - free a talloc pointer. This also frees all child pointers of this - pointer recursively - - return 0 if the memory is actually freed, otherwise -1. The memory - will not be freed if the ref_count is > 1 or the destructor (if - any) returns non-zero -*/ -int talloc_free(void *ptr) -{ - return _talloc_free(ptr); -} - - - -/* - A talloc version of realloc. The context argument is only used if - ptr is NULL -*/ -void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name) -{ - struct talloc_chunk *tc; - void *new_ptr; - bool malloced = false; - - /* size zero is equivalent to free() */ - if (unlikely(size == 0)) { - _talloc_free(ptr); - return NULL; - } - - if (unlikely(size >= MAX_TALLOC_SIZE)) { - return NULL; - } - - /* realloc(NULL) is equivalent to malloc() */ - if (ptr == NULL) { - return _talloc_named_const(context, size, name); - } - - tc = talloc_chunk_from_ptr(ptr); - - /* don't allow realloc on referenced pointers */ - if (unlikely(tc->refs)) { - return NULL; - } - - /* don't let anybody try to realloc a talloc_pool */ - if (unlikely(tc->flags & TALLOC_FLAG_POOL)) { - return NULL; - } - - /* don't shrink if we have less than 1k to gain */ - if ((size < tc->size) && ((tc->size - size) < 1024)) { - tc->size = size; - return ptr; - } - - /* by resetting magic we catch users of the old memory */ - tc->flags |= TALLOC_FLAG_FREE; - -#if ALWAYS_REALLOC - new_ptr = malloc(size + TC_HDR_SIZE); - if (new_ptr) { - memcpy(new_ptr, tc, tc->size + TC_HDR_SIZE); - free(tc); - } -#else - if (tc->flags & TALLOC_FLAG_POOLMEM) { - - new_ptr = talloc_alloc_pool(tc, size + TC_HDR_SIZE); - *talloc_pool_objectcount((struct talloc_chunk *) - (tc->pool)) -= 1; - - if (new_ptr == NULL) { - new_ptr = malloc(TC_HDR_SIZE+size); - malloced = true; - } - - if (new_ptr) { - memcpy(new_ptr, tc, MIN(tc->size,size) + TC_HDR_SIZE); - } - } - else { - new_ptr = realloc(tc, size + TC_HDR_SIZE); - } -#endif - if (unlikely(!new_ptr)) { - tc->flags &= ~TALLOC_FLAG_FREE; - return NULL; - } - - tc = (struct talloc_chunk *)new_ptr; - tc->flags &= ~TALLOC_FLAG_FREE; - if (malloced) { - tc->flags &= ~TALLOC_FLAG_POOLMEM; - } - if (tc->parent) { - tc->parent->child = tc; - } - if (tc->child) { - tc->child->parent = tc; - } - - if (tc->prev) { - tc->prev->next = tc; - } - if (tc->next) { - tc->next->prev = tc; - } - - tc->size = size; - _talloc_set_name_const(TC_PTR_FROM_CHUNK(tc), name); - - return TC_PTR_FROM_CHUNK(tc); -} - -/* - a wrapper around talloc_steal() for situations where you are moving a pointer - between two structures, and want the old pointer to be set to NULL -*/ -void *_talloc_move(const void *new_ctx, const void *_pptr) -{ - const void **pptr = discard_const_p(const void *,_pptr); - void *ret = _talloc_steal(new_ctx, *pptr); - (*pptr) = NULL; - return ret; -} - -/* - return the total size of a talloc pool (subtree) -*/ -size_t talloc_total_size(const void *ptr) -{ - size_t total = 0; - struct talloc_chunk *c, *tc; - - if (ptr == NULL) { - ptr = null_context; - } - if (ptr == NULL) { - return 0; - } - - tc = talloc_chunk_from_ptr(ptr); - - if (tc->flags & TALLOC_FLAG_LOOP) { - return 0; - } - - tc->flags |= TALLOC_FLAG_LOOP; - - total = tc->size; - for (c=tc->child;c;c=c->next) { - total += talloc_total_size(TC_PTR_FROM_CHUNK(c)); - } - - tc->flags &= ~TALLOC_FLAG_LOOP; - - return total; -} - -/* - return the total number of blocks in a talloc pool (subtree) -*/ -size_t talloc_total_blocks(const void *ptr) -{ - size_t total = 0; - struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr); - - if (tc->flags & TALLOC_FLAG_LOOP) { - return 0; - } - - tc->flags |= TALLOC_FLAG_LOOP; - - total++; - for (c=tc->child;c;c=c->next) { - total += talloc_total_blocks(TC_PTR_FROM_CHUNK(c)); - } - - tc->flags &= ~TALLOC_FLAG_LOOP; - - return total; -} - -/* - return the number of external references to a pointer -*/ -size_t talloc_reference_count(const void *ptr) -{ - struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); - struct talloc_reference_handle *h; - size_t ret = 0; - - for (h=tc->refs;h;h=h->next) { - ret++; - } - return ret; -} - -/* - report on memory usage by all children of a pointer, giving a full tree view -*/ -void talloc_report_depth_cb(const void *ptr, int depth, int max_depth, - void (*callback)(const void *ptr, - int depth, int max_depth, - int is_ref, - void *private_data), - void *private_data) -{ - struct talloc_chunk *c, *tc; - - if (ptr == NULL) { - ptr = null_context; - } - if (ptr == NULL) return; - - tc = talloc_chunk_from_ptr(ptr); - - if (tc->flags & TALLOC_FLAG_LOOP) { - return; - } - - callback(ptr, depth, max_depth, 0, private_data); - - if (max_depth >= 0 && depth >= max_depth) { - return; - } - - tc->flags |= TALLOC_FLAG_LOOP; - for (c=tc->child;c;c=c->next) { - if (c->name == TALLOC_MAGIC_REFERENCE) { - struct talloc_reference_handle *h = (struct talloc_reference_handle *)TC_PTR_FROM_CHUNK(c); - callback(h->ptr, depth + 1, max_depth, 1, private_data); - } else { - talloc_report_depth_cb(TC_PTR_FROM_CHUNK(c), depth + 1, max_depth, callback, private_data); - } - } - tc->flags &= ~TALLOC_FLAG_LOOP; -} - -static void talloc_report_depth_FILE_helper(const void *ptr, int depth, int max_depth, int is_ref, void *_f) -{ - const char *name = talloc_get_name(ptr); - FILE *f = (FILE *)_f; - - if (is_ref) { - fprintf(f, "%*sreference to: %s\n", depth*4, "", name); - return; - } - - if (depth == 0) { - fprintf(f,"%stalloc report on '%s' (total %6lu bytes in %3lu blocks)\n", - (max_depth < 0 ? "full " :""), name, - (unsigned long)talloc_total_size(ptr), - (unsigned long)talloc_total_blocks(ptr)); - return; - } - - fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d) %p\n", - depth*4, "", - name, - (unsigned long)talloc_total_size(ptr), - (unsigned long)talloc_total_blocks(ptr), - (int)talloc_reference_count(ptr), ptr); - -#if 0 - fprintf(f, "content: "); - if (talloc_total_size(ptr)) { - int tot = talloc_total_size(ptr); - int i; - - for (i = 0; i < tot; i++) { - if ((((char *)ptr)[i] > 31) && (((char *)ptr)[i] < 126)) { - fprintf(f, "%c", ((char *)ptr)[i]); - } else { - fprintf(f, "~%02x", ((char *)ptr)[i]); - } - } - } - fprintf(f, "\n"); -#endif -} - -/* - report on memory usage by all children of a pointer, giving a full tree view -*/ -void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f) -{ - talloc_report_depth_cb(ptr, depth, max_depth, talloc_report_depth_FILE_helper, f); - fflush(f); -} - -/* - report on memory usage by all children of a pointer, giving a full tree view -*/ -void talloc_report_full(const void *ptr, FILE *f) -{ - talloc_report_depth_file(ptr, 0, -1, f); -} - -/* - report on memory usage by all children of a pointer -*/ -void talloc_report(const void *ptr, FILE *f) -{ - talloc_report_depth_file(ptr, 0, 1, f); -} - -/* - report on any memory hanging off the null context -*/ -static void talloc_report_null(void) -{ - if (talloc_total_size(null_context) != 0) { - talloc_report(null_context, stderr); - } -} - -/* - report on any memory hanging off the null context -*/ -static void talloc_report_null_full(void) -{ - if (talloc_total_size(null_context) != 0) { - talloc_report_full(null_context, stderr); - } -} - -/* - enable tracking of the NULL context -*/ -void talloc_enable_null_tracking(void) -{ - if (null_context == NULL) { - null_context = _talloc_named_const(NULL, 0, "null_context"); - } -} - -/* - disable tracking of the NULL context -*/ -void talloc_disable_null_tracking(void) -{ - _talloc_free(null_context); - null_context = NULL; -} - -/* - enable leak reporting on exit -*/ -void talloc_enable_leak_report(void) -{ - talloc_enable_null_tracking(); - atexit(talloc_report_null); -} - -/* - enable full leak reporting on exit -*/ -void talloc_enable_leak_report_full(void) -{ - talloc_enable_null_tracking(); - atexit(talloc_report_null_full); -} - -/* - talloc and zero memory. -*/ -void *_talloc_zero(const void *ctx, size_t size, const char *name) -{ - void *p = _talloc_named_const(ctx, size, name); - - if (p) { - memset(p, '\0', size); - } - - return p; -} - -/* - memdup with a talloc. -*/ -void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name) -{ - void *newp = _talloc_named_const(t, size, name); - - if (likely(newp)) { - memcpy(newp, p, size); - } - - return newp; -} - -static inline char *__talloc_strlendup(const void *t, const char *p, size_t len) -{ - char *ret; - - ret = (char *)__talloc(t, len + 1); - if (unlikely(!ret)) return NULL; - - memcpy(ret, p, len); - ret[len] = 0; - - _talloc_set_name_const(ret, ret); - return ret; -} - -/* - strdup with a talloc -*/ -char *talloc_strdup(const void *t, const char *p) -{ - if (unlikely(!p)) return NULL; - return __talloc_strlendup(t, p, strlen(p)); -} - -/* - strndup with a talloc -*/ -char *talloc_strndup(const void *t, const char *p, size_t n) -{ - if (unlikely(!p)) return NULL; - return __talloc_strlendup(t, p, strnlen(p, n)); -} - -static inline char *__talloc_strlendup_append(char *s, size_t slen, - const char *a, size_t alen) -{ - char *ret; - - ret = talloc_realloc(NULL, s, char, slen + alen + 1); - if (unlikely(!ret)) return NULL; - - /* append the string and the trailing \0 */ - memcpy(&ret[slen], a, alen); - ret[slen+alen] = 0; - - _talloc_set_name_const(ret, ret); - return ret; -} - -/* - * Appends at the end of the string. - */ -char *talloc_strdup_append(char *s, const char *a) -{ - if (unlikely(!s)) { - return talloc_strdup(NULL, a); - } - - if (unlikely(!a)) { - return s; - } - - return __talloc_strlendup_append(s, strlen(s), a, strlen(a)); -} - -/* - * Appends at the end of the talloc'ed buffer, - * not the end of the string. - */ -char *talloc_strdup_append_buffer(char *s, const char *a) -{ - size_t slen; - - if (unlikely(!s)) { - return talloc_strdup(NULL, a); - } - - if (unlikely(!a)) { - return s; - } - - slen = talloc_get_size(s); - if (likely(slen > 0)) { - slen--; - } - - return __talloc_strlendup_append(s, slen, a, strlen(a)); -} - -/* - * Appends at the end of the string. - */ -char *talloc_strndup_append(char *s, const char *a, size_t n) -{ - if (unlikely(!s)) { - return talloc_strdup(NULL, a); - } - - if (unlikely(!a)) { - return s; - } - - return __talloc_strlendup_append(s, strlen(s), a, strnlen(a, n)); -} - -/* - * Appends at the end of the talloc'ed buffer, - * not the end of the string. - */ -char *talloc_strndup_append_buffer(char *s, const char *a, size_t n) -{ - size_t slen; - - if (unlikely(!s)) { - return talloc_strdup(NULL, a); - } - - if (unlikely(!a)) { - return s; - } - - slen = talloc_get_size(s); - if (likely(slen > 0)) { - slen--; - } - - return __talloc_strlendup_append(s, slen, a, strnlen(a, n)); -} - -#ifndef HAVE_VA_COPY -#ifdef HAVE___VA_COPY -#define va_copy(dest, src) __va_copy(dest, src) -#else -#define va_copy(dest, src) (dest) = (src) -#endif -#endif - -char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) -{ - int len; - char *ret; - va_list ap2; - char c; - - /* this call looks strange, but it makes it work on older solaris boxes */ - va_copy(ap2, ap); - len = vsnprintf(&c, 1, fmt, ap2); - va_end(ap2); - if (unlikely(len < 0)) { - return NULL; - } - - ret = (char *)__talloc(t, len+1); - if (unlikely(!ret)) return NULL; - - va_copy(ap2, ap); - vsnprintf(ret, len+1, fmt, ap2); - va_end(ap2); - - _talloc_set_name_const(ret, ret); - return ret; -} - - -/* - Perform string formatting, and return a pointer to newly allocated - memory holding the result, inside a memory pool. - */ -char *talloc_asprintf(const void *t, const char *fmt, ...) -{ - va_list ap; - char *ret; - - va_start(ap, fmt); - ret = talloc_vasprintf(t, fmt, ap); - va_end(ap); - return ret; -} - -static inline char *__talloc_vaslenprintf_append(char *s, size_t slen, - const char *fmt, va_list ap) - PRINTF_ATTRIBUTE(3,0); - -static inline char *__talloc_vaslenprintf_append(char *s, size_t slen, - const char *fmt, va_list ap) -{ - ssize_t alen; - va_list ap2; - char c; - - va_copy(ap2, ap); - alen = vsnprintf(&c, 1, fmt, ap2); - va_end(ap2); - - if (alen <= 0) { - /* Either the vsnprintf failed or the format resulted in - * no characters being formatted. In the former case, we - * ought to return NULL, in the latter we ought to return - * the original string. Most current callers of this - * function expect it to never return NULL. - */ - return s; - } - - s = talloc_realloc(NULL, s, char, slen + alen + 1); - if (!s) return NULL; - - va_copy(ap2, ap); - vsnprintf(s + slen, alen + 1, fmt, ap2); - va_end(ap2); - - _talloc_set_name_const(s, s); - return s; -} - -/** - * Realloc @p s to append the formatted result of @p fmt and @p ap, - * and return @p s, which may have moved. Good for gradually - * accumulating output into a string buffer. Appends at the end - * of the string. - **/ -char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) -{ - if (unlikely(!s)) { - return talloc_vasprintf(NULL, fmt, ap); - } - - return __talloc_vaslenprintf_append(s, strlen(s), fmt, ap); -} - -/** - * Realloc @p s to append the formatted result of @p fmt and @p ap, - * and return @p s, which may have moved. Always appends at the - * end of the talloc'ed buffer, not the end of the string. - **/ -char *talloc_vasprintf_append_buffer(char *s, const char *fmt, va_list ap) -{ - size_t slen; - - if (unlikely(!s)) { - return talloc_vasprintf(NULL, fmt, ap); - } - - slen = talloc_get_size(s); - if (likely(slen > 0)) { - slen--; - } - - return __talloc_vaslenprintf_append(s, slen, fmt, ap); -} - -/* - Realloc @p s to append the formatted result of @p fmt and return @p - s, which may have moved. Good for gradually accumulating output - into a string buffer. - */ -char *talloc_asprintf_append(char *s, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - s = talloc_vasprintf_append(s, fmt, ap); - va_end(ap); - return s; -} - -/* - Realloc @p s to append the formatted result of @p fmt and return @p - s, which may have moved. Good for gradually accumulating output - into a buffer. - */ -char *talloc_asprintf_append_buffer(char *s, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - s = talloc_vasprintf_append_buffer(s, fmt, ap); - va_end(ap); - return s; -} - -/* - alloc an array, checking for integer overflow in the array size -*/ -void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name) -{ - if (count >= MAX_TALLOC_SIZE/el_size) { - return NULL; - } - return _talloc_named_const(ctx, el_size * count, name); -} - -/* - alloc an zero array, checking for integer overflow in the array size -*/ -void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name) -{ - if (count >= MAX_TALLOC_SIZE/el_size) { - return NULL; - } - return _talloc_zero(ctx, el_size * count, name); -} - -/* - realloc an array, checking for integer overflow in the array size -*/ -void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name) -{ - if (count >= MAX_TALLOC_SIZE/el_size) { - return NULL; - } - return _talloc_realloc(ctx, ptr, el_size * count, name); -} - -/* - a function version of talloc_realloc(), so it can be passed as a function pointer - to libraries that want a realloc function (a realloc function encapsulates - all the basic capabilities of an allocation library, which is why this is useful) -*/ -void *talloc_realloc_fn(const void *context, void *ptr, size_t size) -{ - return _talloc_realloc(context, ptr, size, NULL); -} - - -static int talloc_autofree_destructor(void *ptr) -{ - autofree_context = NULL; - return 0; -} - -static void talloc_autofree(void) -{ - _talloc_free(autofree_context); -} - -/* - return a context which will be auto-freed on exit - this is useful for reducing the noise in leak reports -*/ -void *talloc_autofree_context(void) -{ - if (autofree_context == NULL) { - autofree_context = _talloc_named_const(NULL, 0, "autofree_context"); - talloc_set_destructor(autofree_context, talloc_autofree_destructor); - atexit(talloc_autofree); - } - return autofree_context; -} - -size_t talloc_get_size(const void *context) -{ - struct talloc_chunk *tc; - - if (context == NULL) - return 0; - - tc = talloc_chunk_from_ptr(context); - - return tc->size; -} - -/* - find a parent of this context that has the given name, if any -*/ -void *talloc_find_parent_byname(const void *context, const char *name) -{ - struct talloc_chunk *tc; - - if (context == NULL) { - return NULL; - } - - tc = talloc_chunk_from_ptr(context); - while (tc) { - if (tc->name && strcmp(tc->name, name) == 0) { - return TC_PTR_FROM_CHUNK(tc); - } - while (tc && tc->prev) tc = tc->prev; - if (tc) { - tc = tc->parent; - } - } - return NULL; -} - -/* - show the parentage of a context -*/ -void talloc_show_parents(const void *context, FILE *file) -{ - struct talloc_chunk *tc; - - if (context == NULL) { - fprintf(file, "talloc no parents for NULL\n"); - return; - } - - tc = talloc_chunk_from_ptr(context); - fprintf(file, "talloc parents of '%s'\n", talloc_get_name(context)); - while (tc) { - fprintf(file, "\t'%s'\n", talloc_get_name(TC_PTR_FROM_CHUNK(tc))); - while (tc && tc->prev) tc = tc->prev; - if (tc) { - tc = tc->parent; - } - } - fflush(file); -} - -/* - return 1 if ptr is a parent of context -*/ -int talloc_is_parent(const void *context, const void *ptr) -{ - struct talloc_chunk *tc; - - if (context == NULL) { - return 0; - } - - tc = talloc_chunk_from_ptr(context); - while (tc) { - if (TC_PTR_FROM_CHUNK(tc) == ptr) return 1; - while (tc && tc->prev) tc = tc->prev; - if (tc) { - tc = tc->parent; - } - } - return 0; -} diff --git a/libosmocore/src/timer.c b/libosmocore/src/timer.c deleted file mode 100644 index 37d7d166b..000000000 --- a/libosmocore/src/timer.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * (C) 2008,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 <assert.h> -#include <string.h> -#include <osmocore/timer.h> - -static LLIST_HEAD(timer_list); -static struct timeval s_nearest_time; -static struct timeval s_select_time; - -#define MICRO_SECONDS 1000000LL - -#define TIME_SMALLER(left, right) \ - (left.tv_sec*MICRO_SECONDS+left.tv_usec) <= (right.tv_sec*MICRO_SECONDS+right.tv_usec) - -void bsc_add_timer(struct timer_list *timer) -{ - struct timer_list *list_timer; - - /* TODO: Optimize and remember the closest item... */ - timer->active = 1; - - /* this might be called from within update_timers */ - llist_for_each_entry(list_timer, &timer_list, entry) - if (timer == list_timer) - return; - - timer->in_list = 1; - llist_add(&timer->entry, &timer_list); -} - -void bsc_schedule_timer(struct timer_list *timer, int seconds, int microseconds) -{ - struct timeval current_time; - - gettimeofday(¤t_time, NULL); - unsigned long long currentTime = current_time.tv_sec * MICRO_SECONDS + current_time.tv_usec; - currentTime += seconds * MICRO_SECONDS + microseconds; - timer->timeout.tv_sec = currentTime / MICRO_SECONDS; - timer->timeout.tv_usec = currentTime % MICRO_SECONDS; - bsc_add_timer(timer); -} - -void bsc_del_timer(struct timer_list *timer) -{ - if (timer->in_list) { - timer->active = 0; - timer->in_list = 0; - llist_del(&timer->entry); - } -} - -int bsc_timer_pending(struct timer_list *timer) -{ - return timer->active; -} - -/* - * if we have a nearest time return the delta between the current - * time and the time of the nearest timer. - * If the nearest timer timed out return NULL and then we will - * dispatch everything after the select - */ -struct timeval *bsc_nearest_timer() -{ - struct timeval current_time; - - if (s_nearest_time.tv_sec == 0 && s_nearest_time.tv_usec == 0) - return NULL; - - if (gettimeofday(¤t_time, NULL) == -1) - return NULL; - - unsigned long long nearestTime = s_nearest_time.tv_sec * MICRO_SECONDS + s_nearest_time.tv_usec; - unsigned long long currentTime = current_time.tv_sec * MICRO_SECONDS + current_time.tv_usec; - - if (nearestTime < currentTime) { - s_select_time.tv_sec = 0; - s_select_time.tv_usec = 0; - } else { - s_select_time.tv_sec = (nearestTime - currentTime) / MICRO_SECONDS; - s_select_time.tv_usec = (nearestTime - currentTime) % MICRO_SECONDS; - } - - return &s_select_time; -} - -/* - * Find the nearest time and update s_nearest_time - */ -void bsc_prepare_timers() -{ - struct timer_list *timer, *nearest_timer = NULL; - llist_for_each_entry(timer, &timer_list, entry) { - if (!nearest_timer || TIME_SMALLER(timer->timeout, nearest_timer->timeout)) { - nearest_timer = timer; - } - } - - if (nearest_timer) { - s_nearest_time = nearest_timer->timeout; - } else { - memset(&s_nearest_time, 0, sizeof(struct timeval)); - } -} - -/* - * fire all timers... and remove them - */ -int bsc_update_timers() -{ - struct timeval current_time; - struct timer_list *timer, *tmp; - int work = 0; - - gettimeofday(¤t_time, NULL); - - /* - * The callbacks might mess with our list and in this case - * even llist_for_each_entry_safe is not safe to use. To allow - * del_timer, add_timer, schedule_timer to be called from within - * the callback we jump through some loops. - * - * First we set the handled flag of each active timer to zero, - * then we iterate over the list and execute the callbacks. As the - * list might have been changed (specially the next) from within - * the callback we have to start over again. Once every callback - * is dispatched we will remove the non-active from the list. - * - * TODO: If this is a performance issue we can poison a global - * variable in add_timer and del_timer and only then restart. - */ - llist_for_each_entry(timer, &timer_list, entry) { - timer->handled = 0; - } - -restart: - llist_for_each_entry(timer, &timer_list, entry) { - if (!timer->handled && TIME_SMALLER(timer->timeout, current_time)) { - timer->handled = 1; - timer->active = 0; - (*timer->cb)(timer->data); - work = 1; - goto restart; - } - } - - llist_for_each_entry_safe(timer, tmp, &timer_list, entry) { - timer->handled = 0; - if (!timer->active) { - bsc_del_timer(timer); - } - } - - return work; -} - -int bsc_timer_check(void) -{ - struct timer_list *timer; - int i = 0; - - llist_for_each_entry(timer, &timer_list, entry) { - i++; - } - return i; -} diff --git a/libosmocore/src/tlv_parser.c b/libosmocore/src/tlv_parser.c deleted file mode 100644 index 407e57aa2..000000000 --- a/libosmocore/src/tlv_parser.c +++ /dev/null @@ -1,171 +0,0 @@ -#include <stdio.h> -#include <stdint.h> -#include <osmocore/utils.h> -#include <osmocore/tlv.h> - -struct tlv_definition tvlv_att_def; - -int tlv_dump(struct tlv_parsed *dec) -{ - int i; - - for (i = 0; i <= 0xff; i++) { - if (!dec->lv[i].val) - continue; - printf("T=%02x L=%d\n", i, dec->lv[i].len); - } - return 0; -} - -/* o_tag: output: tag found - * o_len: output: length of the data - * o_val: output: pointer to the data - * def: input: a structure defining the valid TLV tags / configurations - * buf: input: the input data buffer to be parsed - * buf_len: input: the length of the input data buffer - * - * Also, returns the number of bytes consumed by the TLV entry - */ -int tlv_parse_one(uint8_t *o_tag, uint16_t *o_len, const uint8_t **o_val, - const struct tlv_definition *def, - const uint8_t *buf, int buf_len) -{ - uint8_t tag; - int len; - - tag = *buf; - *o_tag = tag; - - /* FIXME: use tables for knwon IEI */ - switch (def->def[tag].type) { - case TLV_TYPE_T: - /* GSM TS 04.07 11.2.4: Type 1 TV or Type 2 T */ - *o_val = buf; - *o_len = 0; - len = 1; - break; - case TLV_TYPE_TV: - *o_val = buf+1; - *o_len = 1; - len = 2; - break; - case TLV_TYPE_FIXED: - *o_val = buf+1; - *o_len = def->def[tag].fixed_len; - len = def->def[tag].fixed_len + 1; - break; - case TLV_TYPE_TLV: - /* GSM TS 04.07 11.2.4: Type 4 TLV */ - if (buf + 1 > buf + buf_len) - return -1; - *o_val = buf+2; - *o_len = *(buf+1); - len = *o_len + 2; - if (len > buf_len) - return -2; - break; - case TLV_TYPE_TvLV: - if (*(buf+1) & 0x80) { - /* like TLV, but without highest bit of len */ - if (buf + 1 > buf + buf_len) - return -1; - *o_val = buf+2; - *o_len = *(buf+1) & 0x7f; - len = *o_len + 2; - if (len > buf_len) - return -2; - break; - } - /* like TL16V, fallthrough */ - case TLV_TYPE_TL16V: - if (2 > buf_len) - return -1; - *o_val = buf+3; - *o_len = *(buf+1) << 8 | *(buf+2); - len = *o_len + 3; - if (len > buf_len) - return -2; - break; - default: - return -3; - } - - return len; -} - -/* dec: output: a caller-allocated pointer to a struct tlv_parsed, - * def: input: a structure defining the valid TLV tags / configurations - * buf: input: the input data buffer to be parsed - * buf_len: input: the length of the input data buffer - * lv_tag: input: an initial LV tag at the start of the buffer - * lv_tag2: input: a second initial LV tag following lv_tag - */ -int tlv_parse(struct tlv_parsed *dec, const struct tlv_definition *def, - const uint8_t *buf, int buf_len, uint8_t lv_tag, - uint8_t lv_tag2) -{ - int ofs = 0, num_parsed = 0; - uint16_t len; - - memset(dec, 0, sizeof(*dec)); - - if (lv_tag) { - if (ofs > buf_len) - return -1; - dec->lv[lv_tag].val = &buf[ofs+1]; - dec->lv[lv_tag].len = buf[ofs]; - len = dec->lv[lv_tag].len + 1; - if (ofs + len > buf_len) - return -2; - num_parsed++; - ofs += len; - } - if (lv_tag2) { - if (ofs > buf_len) - return -1; - dec->lv[lv_tag2].val = &buf[ofs+1]; - dec->lv[lv_tag2].len = buf[ofs]; - len = dec->lv[lv_tag2].len + 1; - if (ofs + len > buf_len) - return -2; - num_parsed++; - ofs += len; - } - - while (ofs < buf_len) { - int rv; - uint8_t tag; - const uint8_t *val; - - rv = tlv_parse_one(&tag, &len, &val, def, - &buf[ofs], buf_len-ofs); - if (rv < 0) - return rv; - dec->lv[tag].val = val; - dec->lv[tag].len = len; - ofs += rv; - num_parsed++; - } - //tlv_dump(dec); - return num_parsed; -} - -/* take a master (src) tlvdev and fill up all empty slots in 'dst' */ -void tlv_def_patch(struct tlv_definition *dst, const struct tlv_definition *src) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(dst->def); i++) { - if (src->def[i].type == TLV_TYPE_NONE) - continue; - if (dst->def[i].type == TLV_TYPE_NONE) - dst->def[i] = src->def[i]; - } -} - -static __attribute__((constructor)) void on_dso_load_tlv(void) -{ - int i; - for (i = 0; i < ARRAY_SIZE(tvlv_att_def.def); i++) - tvlv_att_def.def[i].type = TLV_TYPE_TvLV; -} diff --git a/libosmocore/src/utils.c b/libosmocore/src/utils.c deleted file mode 100644 index 4dab06455..000000000 --- a/libosmocore/src/utils.c +++ /dev/null @@ -1,50 +0,0 @@ - -#include <string.h> -#include <stdint.h> -#include <errno.h> -#include <stdio.h> - -#include <osmocore/utils.h> - -static char namebuf[255]; -const char *get_value_string(const struct value_string *vs, uint32_t val) -{ - int i; - - for (i = 0;; i++) { - if (vs[i].value == 0 && vs[i].str == NULL) - break; - if (vs[i].value == val) - return vs[i].str; - } - - snprintf(namebuf, sizeof(namebuf), "unknown 0x%x", val); - return namebuf; -} - -int get_string_value(const struct value_string *vs, const char *str) -{ - int i; - - for (i = 0;; i++) { - if (vs[i].value == 0 && vs[i].str == NULL) - break; - if (!strcasecmp(vs[i].str, str)) - return vs[i].value; - } - return -EINVAL; -} - -char bcd2char(uint8_t bcd) -{ - if (bcd < 0xa) - return '0' + bcd; - else - return 'A' + (bcd - 0xa); -} - -/* only works for numbers in ascci */ -uint8_t char2bcd(char c) -{ - return c - 0x30; -} diff --git a/libosmocore/src/vty/Makefile.am b/libosmocore/src/vty/Makefile.am deleted file mode 100644 index bc10a0f86..000000000 --- a/libosmocore/src/vty/Makefile.am +++ /dev/null @@ -1,11 +0,0 @@ -# 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 diff --git a/libosmocore/src/vty/buffer.c b/libosmocore/src/vty/buffer.c deleted file mode 100644 index a5655b93d..000000000 --- a/libosmocore/src/vty/buffer.c +++ /dev/null @@ -1,463 +0,0 @@ -/* - * Buffering of output and input. - * Copyright (C) 1998 Kunihiro Ishiguro - * - * This file is part of GNU Zebra. - * - * GNU Zebra is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * GNU Zebra is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Zebra; see the file COPYING. If not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include <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; -} diff --git a/libosmocore/src/vty/command.c b/libosmocore/src/vty/command.c deleted file mode 100644 index 21afa5c05..000000000 --- a/libosmocore/src/vty/command.c +++ /dev/null @@ -1,3177 +0,0 @@ -/* - $Id: command.c,v 1.47 2005/04/25 16:26:42 paul Exp $ - - Command interpreter routine for virtual terminal [aka TeletYpe] - Copyright (C) 1997, 98, 99 Kunihiro Ishiguro - -This file is part of GNU Zebra. - -GNU Zebra is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published -by the Free Software Foundation; either version 2, or (at your -option) any later version. - -GNU Zebra is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU Zebra; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <syslog.h> -#include <errno.h> -#define _XOPEN_SOURCE -#include <unistd.h> -#include <assert.h> -#include <ctype.h> -#include <time.h> -#include <sys/time.h> -#include <sys/stat.h> - -#include <osmocom/vty/vector.h> -#include <osmocom/vty/vty.h> -#include <osmocom/vty/command.h> - -#include <osmocore/talloc.h> - -#define CONFIGFILE_MASK 022 - -void *tall_vty_cmd_ctx; - -/* Command vector which includes some level of command lists. Normally - each daemon maintains each own cmdvec. */ -vector cmdvec; - -/* Host information structure. */ -struct host host; - -/* Standard command node structures. */ -struct cmd_node auth_node = { - AUTH_NODE, - "Password: ", -}; - -struct cmd_node view_node = { - VIEW_NODE, - "%s> ", -}; - -struct cmd_node auth_enable_node = { - AUTH_ENABLE_NODE, - "Password: ", -}; - -struct cmd_node enable_node = { - ENABLE_NODE, - "%s# ", -}; - -struct cmd_node config_node = { - CONFIG_NODE, - "%s(config)# ", - 1 -}; - -/* Default motd string. */ -const char *default_motd = ""; - -/* This is called from main when a daemon is invoked with -v or --version. */ -void print_version(int print_copyright) -{ - printf("%s version %s\n", host.app_info->name, host.app_info->version); - if (print_copyright) - printf("\n%s\n", host.app_info->copyright); -} - -/* Utility function to concatenate argv argument into a single string - with inserting ' ' character between each argument. */ -char *argv_concat(const char **argv, int argc, int shift) -{ - int i; - size_t len; - char *str; - char *p; - - len = 0; - for (i = shift; i < argc; i++) - len += strlen(argv[i]) + 1; - if (!len) - return NULL; - p = str = _talloc_zero(tall_vty_cmd_ctx, len, "arvg_concat"); - for (i = shift; i < argc; i++) { - size_t arglen; - memcpy(p, argv[i], (arglen = strlen(argv[i]))); - p += arglen; - *p++ = ' '; - } - *(p - 1) = '\0'; - return str; -} - -/* Install top node of command vector. */ -void install_node(struct cmd_node *node, int (*func) (struct vty *)) -{ - vector_set_index(cmdvec, node->node, node); - node->func = func; - node->cmd_vector = vector_init(VECTOR_MIN_SIZE); -} - -/* Compare two command's string. Used in sort_node (). */ -static int cmp_node(const void *p, const void *q) -{ - struct cmd_element *a = *(struct cmd_element **)p; - struct cmd_element *b = *(struct cmd_element **)q; - - return strcmp(a->string, b->string); -} - -static int cmp_desc(const void *p, const void *q) -{ - struct desc *a = *(struct desc **)p; - struct desc *b = *(struct desc **)q; - - return strcmp(a->cmd, b->cmd); -} - -/* Sort each node's command element according to command string. */ -void sort_node() -{ - unsigned int i, j; - struct cmd_node *cnode; - vector descvec; - struct cmd_element *cmd_element; - - for (i = 0; i < vector_active(cmdvec); i++) - if ((cnode = vector_slot(cmdvec, i)) != NULL) { - vector cmd_vector = cnode->cmd_vector; - qsort(cmd_vector->index, vector_active(cmd_vector), - sizeof(void *), cmp_node); - - for (j = 0; j < vector_active(cmd_vector); j++) - if ((cmd_element = - vector_slot(cmd_vector, j)) != NULL - && vector_active(cmd_element->strvec)) { - descvec = - vector_slot(cmd_element->strvec, - vector_active - (cmd_element->strvec) - - 1); - qsort(descvec->index, - vector_active(descvec), - sizeof(void *), cmp_desc); - } - } -} - -/* Breaking up string into each command piece. I assume given - character is separated by a space character. Return value is a - vector which includes char ** data element. */ -vector cmd_make_strvec(const char *string) -{ - const char *cp, *start; - char *token; - int strlen; - vector strvec; - - if (string == NULL) - return NULL; - - cp = string; - - /* Skip white spaces. */ - while (isspace((int)*cp) && *cp != '\0') - cp++; - - /* Return if there is only white spaces */ - if (*cp == '\0') - return NULL; - - if (*cp == '!' || *cp == '#') - return NULL; - - /* Prepare return vector. */ - strvec = vector_init(VECTOR_MIN_SIZE); - - /* Copy each command piece and set into vector. */ - while (1) { - start = cp; - while (!(isspace((int)*cp) || *cp == '\r' || *cp == '\n') && - *cp != '\0') - cp++; - strlen = cp - start; - token = _talloc_zero(tall_vty_cmd_ctx, strlen + 1, "make_strvec"); - memcpy(token, start, strlen); - *(token + strlen) = '\0'; - vector_set(strvec, token); - - while ((isspace((int)*cp) || *cp == '\n' || *cp == '\r') && - *cp != '\0') - cp++; - - if (*cp == '\0') - return strvec; - } -} - -/* Free allocated string vector. */ -void cmd_free_strvec(vector v) -{ - unsigned int i; - char *cp; - - if (!v) - return; - - for (i = 0; i < vector_active(v); i++) - if ((cp = vector_slot(v, i)) != NULL) - talloc_free(cp); - - vector_free(v); -} - -/* Fetch next description. Used in cmd_make_descvec(). */ -static char *cmd_desc_str(const char **string) -{ - const char *cp, *start; - char *token; - int strlen; - - cp = *string; - - if (cp == NULL) - return NULL; - - /* Skip white spaces. */ - while (isspace((int)*cp) && *cp != '\0') - cp++; - - /* Return if there is only white spaces */ - if (*cp == '\0') - return NULL; - - start = cp; - - while (!(*cp == '\r' || *cp == '\n') && *cp != '\0') - cp++; - - strlen = cp - start; - token = _talloc_zero(tall_vty_cmd_ctx, strlen + 1, "cmd_desc_str"); - memcpy(token, start, strlen); - *(token + strlen) = '\0'; - - *string = cp; - - return token; -} - -/* New string vector. */ -static vector cmd_make_descvec(const char *string, const char *descstr) -{ - int multiple = 0; - const char *sp; - char *token; - int len; - const char *cp; - const char *dp; - vector allvec; - vector strvec = NULL; - struct desc *desc; - - cp = string; - dp = descstr; - - if (cp == NULL) - return NULL; - - allvec = vector_init(VECTOR_MIN_SIZE); - - while (1) { - while (isspace((int)*cp) && *cp != '\0') - cp++; - - if (*cp == '(') { - multiple = 1; - cp++; - } - if (*cp == ')') { - multiple = 0; - cp++; - } - if (*cp == '|') { - if (!multiple) { - fprintf(stderr, "Command parse error!: %s\n", - string); - exit(1); - } - cp++; - } - - while (isspace((int)*cp) && *cp != '\0') - cp++; - - if (*cp == '(') { - multiple = 1; - cp++; - } - - if (*cp == '\0') - return allvec; - - sp = cp; - - while (! - (isspace((int)*cp) || *cp == '\r' || *cp == '\n' - || *cp == ')' || *cp == '|') && *cp != '\0') - cp++; - - len = cp - sp; - - token = _talloc_zero(tall_vty_cmd_ctx, len + 1, "cmd_make_descvec"); - memcpy(token, sp, len); - *(token + len) = '\0'; - - desc = talloc_zero(tall_vty_cmd_ctx, struct desc); - desc->cmd = token; - desc->str = cmd_desc_str(&dp); - - if (multiple) { - if (multiple == 1) { - strvec = vector_init(VECTOR_MIN_SIZE); - vector_set(allvec, strvec); - } - multiple++; - } else { - strvec = vector_init(VECTOR_MIN_SIZE); - vector_set(allvec, strvec); - } - vector_set(strvec, desc); - } -} - -/* Count mandantory string vector size. This is to determine inputed - command has enough command length. */ -static int cmd_cmdsize(vector strvec) -{ - unsigned int i; - int size = 0; - vector descvec; - struct desc *desc; - - for (i = 0; i < vector_active(strvec); i++) - if ((descvec = vector_slot(strvec, i)) != NULL) { - if ((vector_active(descvec)) == 1 - && (desc = vector_slot(descvec, 0)) != NULL) { - if (desc->cmd == NULL || CMD_OPTION(desc->cmd)) - return size; - else - size++; - } else - size++; - } - return size; -} - -/* Return prompt character of specified node. */ -const char *cmd_prompt(enum node_type node) -{ - struct cmd_node *cnode; - - cnode = vector_slot(cmdvec, node); - return cnode->prompt; -} - -/* Install a command into a node. */ -void install_element(enum node_type ntype, struct cmd_element *cmd) -{ - struct cmd_node *cnode; - - cnode = vector_slot(cmdvec, ntype); - - if (cnode == NULL) { - fprintf(stderr, - "Command node %d doesn't exist, please check it\n", - ntype); - exit(1); - } - - vector_set(cnode->cmd_vector, cmd); - - cmd->strvec = cmd_make_descvec(cmd->string, cmd->doc); - cmd->cmdsize = cmd_cmdsize(cmd->strvec); -} - -/* Install a command into VIEW and ENABLE node */ -void install_element_ve(struct cmd_element *cmd) -{ - install_element(VIEW_NODE, cmd); - install_element(ENABLE_NODE, cmd); -} - -#ifdef VTY_CRYPT_PW -static unsigned char itoa64[] = - "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - -static void to64(char *s, long v, int n) -{ - while (--n >= 0) { - *s++ = itoa64[v & 0x3f]; - v >>= 6; - } -} - -static char *zencrypt(const char *passwd) -{ - char salt[6]; - struct timeval tv; - char *crypt(const char *, const char *); - - gettimeofday(&tv, 0); - - to64(&salt[0], random(), 3); - to64(&salt[3], tv.tv_usec, 3); - salt[5] = '\0'; - - return crypt(passwd, salt); -} -#endif - -/* This function write configuration of this host. */ -static int config_write_host(struct vty *vty) -{ - if (host.name) - vty_out(vty, "hostname %s%s", host.name, VTY_NEWLINE); - - if (host.encrypt) { - if (host.password_encrypt) - vty_out(vty, "password 8 %s%s", host.password_encrypt, - VTY_NEWLINE); - if (host.enable_encrypt) - vty_out(vty, "enable password 8 %s%s", - host.enable_encrypt, VTY_NEWLINE); - } else { - if (host.password) - vty_out(vty, "password %s%s", host.password, - VTY_NEWLINE); - if (host.enable) - vty_out(vty, "enable password %s%s", host.enable, - VTY_NEWLINE); - } - - if (host.advanced) - vty_out(vty, "service advanced-vty%s", VTY_NEWLINE); - - if (host.encrypt) - vty_out(vty, "service password-encryption%s", VTY_NEWLINE); - - if (host.lines >= 0) - vty_out(vty, "service terminal-length %d%s", host.lines, - VTY_NEWLINE); - - if (host.motdfile) - vty_out(vty, "banner motd file %s%s", host.motdfile, - VTY_NEWLINE); - else if (!host.motd) - vty_out(vty, "no banner motd%s", VTY_NEWLINE); - - return 1; -} - -/* Utility function for getting command vector. */ -static vector cmd_node_vector(vector v, enum node_type ntype) -{ - struct cmd_node *cnode = vector_slot(v, ntype); - return cnode->cmd_vector; -} - -/* Completion match types. */ -enum match_type { - no_match, - extend_match, - ipv4_prefix_match, - ipv4_match, - ipv6_prefix_match, - ipv6_match, - range_match, - vararg_match, - partly_match, - exact_match -}; - -static enum match_type cmd_ipv4_match(const char *str) -{ - const char *sp; - int dots = 0, nums = 0; - char buf[4]; - - if (str == NULL) - return partly_match; - - for (;;) { - memset(buf, 0, sizeof(buf)); - sp = str; - while (*str != '\0') { - if (*str == '.') { - if (dots >= 3) - return no_match; - - if (*(str + 1) == '.') - return no_match; - - if (*(str + 1) == '\0') - return partly_match; - - dots++; - break; - } - if (!isdigit((int)*str)) - return no_match; - - str++; - } - - if (str - sp > 3) - return no_match; - - strncpy(buf, sp, str - sp); - if (atoi(buf) > 255) - return no_match; - - nums++; - - if (*str == '\0') - break; - - str++; - } - - if (nums < 4) - return partly_match; - - return exact_match; -} - -static enum match_type cmd_ipv4_prefix_match(const char *str) -{ - const char *sp; - int dots = 0; - char buf[4]; - - if (str == NULL) - return partly_match; - - for (;;) { - memset(buf, 0, sizeof(buf)); - sp = str; - while (*str != '\0' && *str != '/') { - if (*str == '.') { - if (dots == 3) - return no_match; - - if (*(str + 1) == '.' || *(str + 1) == '/') - return no_match; - - if (*(str + 1) == '\0') - return partly_match; - - dots++; - break; - } - - if (!isdigit((int)*str)) - return no_match; - - str++; - } - - if (str - sp > 3) - return no_match; - - strncpy(buf, sp, str - sp); - if (atoi(buf) > 255) - return no_match; - - if (dots == 3) { - if (*str == '/') { - if (*(str + 1) == '\0') - return partly_match; - - str++; - break; - } else if (*str == '\0') - return partly_match; - } - - if (*str == '\0') - return partly_match; - - str++; - } - - sp = str; - while (*str != '\0') { - if (!isdigit((int)*str)) - return no_match; - - str++; - } - - if (atoi(sp) > 32) - return no_match; - - return exact_match; -} - -#define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%" -#define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/" -#define STATE_START 1 -#define STATE_COLON 2 -#define STATE_DOUBLE 3 -#define STATE_ADDR 4 -#define STATE_DOT 5 -#define STATE_SLASH 6 -#define STATE_MASK 7 - -#ifdef HAVE_IPV6 - -static enum match_type cmd_ipv6_match(const char *str) -{ - int state = STATE_START; - int colons = 0, nums = 0, double_colon = 0; - const char *sp = NULL; - struct sockaddr_in6 sin6_dummy; - int ret; - - if (str == NULL) - return partly_match; - - if (strspn(str, IPV6_ADDR_STR) != strlen(str)) - return no_match; - - /* use inet_pton that has a better support, - * for example inet_pton can support the automatic addresses: - * ::1.2.3.4 - */ - ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr); - - if (ret == 1) - return exact_match; - - while (*str != '\0') { - switch (state) { - case STATE_START: - if (*str == ':') { - if (*(str + 1) != ':' && *(str + 1) != '\0') - return no_match; - colons--; - state = STATE_COLON; - } else { - sp = str; - state = STATE_ADDR; - } - - continue; - case STATE_COLON: - colons++; - if (*(str + 1) == ':') - state = STATE_DOUBLE; - else { - sp = str + 1; - state = STATE_ADDR; - } - break; - case STATE_DOUBLE: - if (double_colon) - return no_match; - - if (*(str + 1) == ':') - return no_match; - else { - if (*(str + 1) != '\0') - colons++; - sp = str + 1; - state = STATE_ADDR; - } - - double_colon++; - nums++; - break; - case STATE_ADDR: - if (*(str + 1) == ':' || *(str + 1) == '\0') { - if (str - sp > 3) - return no_match; - - nums++; - state = STATE_COLON; - } - if (*(str + 1) == '.') - state = STATE_DOT; - break; - case STATE_DOT: - state = STATE_ADDR; - break; - default: - break; - } - - if (nums > 8) - return no_match; - - if (colons > 7) - return no_match; - - str++; - } - -#if 0 - if (nums < 11) - return partly_match; -#endif /* 0 */ - - return exact_match; -} - -static enum match_type cmd_ipv6_prefix_match(const char *str) -{ - int state = STATE_START; - int colons = 0, nums = 0, double_colon = 0; - int mask; - const char *sp = NULL; - char *endptr = NULL; - - if (str == NULL) - return partly_match; - - if (strspn(str, IPV6_PREFIX_STR) != strlen(str)) - return no_match; - - while (*str != '\0' && state != STATE_MASK) { - switch (state) { - case STATE_START: - if (*str == ':') { - if (*(str + 1) != ':' && *(str + 1) != '\0') - return no_match; - colons--; - state = STATE_COLON; - } else { - sp = str; - state = STATE_ADDR; - } - - continue; - case STATE_COLON: - colons++; - if (*(str + 1) == '/') - return no_match; - else if (*(str + 1) == ':') - state = STATE_DOUBLE; - else { - sp = str + 1; - state = STATE_ADDR; - } - break; - case STATE_DOUBLE: - if (double_colon) - return no_match; - - if (*(str + 1) == ':') - return no_match; - else { - if (*(str + 1) != '\0' && *(str + 1) != '/') - colons++; - sp = str + 1; - - if (*(str + 1) == '/') - state = STATE_SLASH; - else - state = STATE_ADDR; - } - - double_colon++; - nums += 1; - break; - case STATE_ADDR: - if (*(str + 1) == ':' || *(str + 1) == '.' - || *(str + 1) == '\0' || *(str + 1) == '/') { - if (str - sp > 3) - return no_match; - - for (; sp <= str; sp++) - if (*sp == '/') - return no_match; - - nums++; - - if (*(str + 1) == ':') - state = STATE_COLON; - else if (*(str + 1) == '.') - state = STATE_DOT; - else if (*(str + 1) == '/') - state = STATE_SLASH; - } - break; - case STATE_DOT: - state = STATE_ADDR; - break; - case STATE_SLASH: - if (*(str + 1) == '\0') - return partly_match; - - state = STATE_MASK; - break; - default: - break; - } - - if (nums > 11) - return no_match; - - if (colons > 7) - return no_match; - - str++; - } - - if (state < STATE_MASK) - return partly_match; - - mask = strtol(str, &endptr, 10); - if (*endptr != '\0') - return no_match; - - if (mask < 0 || mask > 128) - return no_match; - -/* I don't know why mask < 13 makes command match partly. - Forgive me to make this comments. I Want to set static default route - because of lack of function to originate default in ospf6d; sorry - yasu - if (mask < 13) - return partly_match; -*/ - - return exact_match; -} - -#endif /* HAVE_IPV6 */ - -#define DECIMAL_STRLEN_MAX 10 - -static int cmd_range_match(const char *range, const char *str) -{ - char *p; - char buf[DECIMAL_STRLEN_MAX + 1]; - char *endptr = NULL; - unsigned long min, max, val; - - if (str == NULL) - return 1; - - val = strtoul(str, &endptr, 10); - if (*endptr != '\0') - return 0; - - range++; - p = strchr(range, '-'); - if (p == NULL) - return 0; - if (p - range > DECIMAL_STRLEN_MAX) - return 0; - strncpy(buf, range, p - range); - buf[p - range] = '\0'; - min = strtoul(buf, &endptr, 10); - if (*endptr != '\0') - return 0; - - range = p + 1; - p = strchr(range, '>'); - if (p == NULL) - return 0; - if (p - range > DECIMAL_STRLEN_MAX) - return 0; - strncpy(buf, range, p - range); - buf[p - range] = '\0'; - max = strtoul(buf, &endptr, 10); - if (*endptr != '\0') - return 0; - - if (val < min || val > max) - return 0; - - return 1; -} - -/* Make completion match and return match type flag. */ -static enum match_type -cmd_filter_by_completion(char *command, vector v, unsigned int index) -{ - unsigned int i; - const char *str; - struct cmd_element *cmd_element; - enum match_type match_type; - vector descvec; - struct desc *desc; - - match_type = no_match; - - /* If command and cmd_element string does not match set NULL to vector */ - for (i = 0; i < vector_active(v); i++) - if ((cmd_element = vector_slot(v, i)) != NULL) { - if (index >= vector_active(cmd_element->strvec)) - vector_slot(v, i) = NULL; - else { - unsigned int j; - int matched = 0; - - descvec = - vector_slot(cmd_element->strvec, index); - - for (j = 0; j < vector_active(descvec); j++) - if ((desc = vector_slot(descvec, j))) { - str = desc->cmd; - - if (CMD_VARARG(str)) { - if (match_type < - vararg_match) - match_type = - vararg_match; - matched++; - } else if (CMD_RANGE(str)) { - if (cmd_range_match - (str, command)) { - if (match_type < - range_match) - match_type - = - range_match; - - matched++; - } - } -#ifdef HAVE_IPV6 - else if (CMD_IPV6(str)) { - if (cmd_ipv6_match - (command)) { - if (match_type < - ipv6_match) - match_type - = - ipv6_match; - - matched++; - } - } else if (CMD_IPV6_PREFIX(str)) { - if (cmd_ipv6_prefix_match(command)) { - if (match_type < - ipv6_prefix_match) - match_type - = - ipv6_prefix_match; - - matched++; - } - } -#endif /* HAVE_IPV6 */ - else if (CMD_IPV4(str)) { - if (cmd_ipv4_match - (command)) { - if (match_type < - ipv4_match) - match_type - = - ipv4_match; - - matched++; - } - } else if (CMD_IPV4_PREFIX(str)) { - if (cmd_ipv4_prefix_match(command)) { - if (match_type < - ipv4_prefix_match) - match_type - = - ipv4_prefix_match; - matched++; - } - } else - /* Check is this point's argument optional ? */ - if (CMD_OPTION(str) - || - CMD_VARIABLE(str)) { - if (match_type < - extend_match) - match_type = - extend_match; - matched++; - } else - if (strncmp - (command, str, - strlen(command)) == - 0) { - if (strcmp(command, str) - == 0) - match_type = - exact_match; - else { - if (match_type < - partly_match) - match_type - = - partly_match; - } - matched++; - } - } - if (!matched) - vector_slot(v, i) = NULL; - } - } - return match_type; -} - -/* Filter vector by command character with index. */ -static enum match_type -cmd_filter_by_string(char *command, vector v, unsigned int index) -{ - unsigned int i; - const char *str; - struct cmd_element *cmd_element; - enum match_type match_type; - vector descvec; - struct desc *desc; - - match_type = no_match; - - /* If command and cmd_element string does not match set NULL to vector */ - for (i = 0; i < vector_active(v); i++) - if ((cmd_element = vector_slot(v, i)) != NULL) { - /* If given index is bigger than max string vector of command, - set NULL */ - if (index >= vector_active(cmd_element->strvec)) - vector_slot(v, i) = NULL; - else { - unsigned int j; - int matched = 0; - - descvec = - vector_slot(cmd_element->strvec, index); - - for (j = 0; j < vector_active(descvec); j++) - if ((desc = vector_slot(descvec, j))) { - str = desc->cmd; - - if (CMD_VARARG(str)) { - if (match_type < - vararg_match) - match_type = - vararg_match; - matched++; - } else if (CMD_RANGE(str)) { - if (cmd_range_match - (str, command)) { - if (match_type < - range_match) - match_type - = - range_match; - matched++; - } - } -#ifdef HAVE_IPV6 - else if (CMD_IPV6(str)) { - if (cmd_ipv6_match - (command) == - exact_match) { - if (match_type < - ipv6_match) - match_type - = - ipv6_match; - matched++; - } - } else if (CMD_IPV6_PREFIX(str)) { - if (cmd_ipv6_prefix_match(command) == exact_match) { - if (match_type < - ipv6_prefix_match) - match_type - = - ipv6_prefix_match; - matched++; - } - } -#endif /* HAVE_IPV6 */ - else if (CMD_IPV4(str)) { - if (cmd_ipv4_match - (command) == - exact_match) { - if (match_type < - ipv4_match) - match_type - = - ipv4_match; - matched++; - } - } else if (CMD_IPV4_PREFIX(str)) { - if (cmd_ipv4_prefix_match(command) == exact_match) { - if (match_type < - ipv4_prefix_match) - match_type - = - ipv4_prefix_match; - matched++; - } - } else if (CMD_OPTION(str) - || CMD_VARIABLE(str)) - { - if (match_type < - extend_match) - match_type = - extend_match; - matched++; - } else { - if (strcmp(command, str) - == 0) { - match_type = - exact_match; - matched++; - } - } - } - if (!matched) - vector_slot(v, i) = NULL; - } - } - return match_type; -} - -/* Check ambiguous match */ -static int -is_cmd_ambiguous(char *command, vector v, int index, enum match_type type) -{ - unsigned int i; - unsigned int j; - const char *str = NULL; - struct cmd_element *cmd_element; - const char *matched = NULL; - vector descvec; - struct desc *desc; - - for (i = 0; i < vector_active(v); i++) - if ((cmd_element = vector_slot(v, i)) != NULL) { - int match = 0; - - descvec = vector_slot(cmd_element->strvec, index); - - for (j = 0; j < vector_active(descvec); j++) - if ((desc = vector_slot(descvec, j))) { - enum match_type ret; - - str = desc->cmd; - - switch (type) { - case exact_match: - if (! - (CMD_OPTION(str) - || CMD_VARIABLE(str)) -&& strcmp(command, str) == 0) - match++; - break; - case partly_match: - if (! - (CMD_OPTION(str) - || CMD_VARIABLE(str)) -&& strncmp(command, str, strlen(command)) == 0) { - if (matched - && strcmp(matched, - str) != 0) - return 1; /* There is ambiguous match. */ - else - matched = str; - match++; - } - break; - case range_match: - if (cmd_range_match - (str, command)) { - if (matched - && strcmp(matched, - str) != 0) - return 1; - else - matched = str; - match++; - } - break; -#ifdef HAVE_IPV6 - case ipv6_match: - if (CMD_IPV6(str)) - match++; - break; - case ipv6_prefix_match: - if ((ret = - cmd_ipv6_prefix_match - (command)) != no_match) { - if (ret == partly_match) - return 2; /* There is incomplete match. */ - - match++; - } - break; -#endif /* HAVE_IPV6 */ - case ipv4_match: - if (CMD_IPV4(str)) - match++; - break; - case ipv4_prefix_match: - if ((ret = - cmd_ipv4_prefix_match - (command)) != no_match) { - if (ret == partly_match) - return 2; /* There is incomplete match. */ - - match++; - } - break; - case extend_match: - if (CMD_OPTION(str) - || CMD_VARIABLE(str)) - match++; - break; - case no_match: - default: - break; - } - } - if (!match) - vector_slot(v, i) = NULL; - } - return 0; -} - -/* If src matches dst return dst string, otherwise return NULL */ -static const char *cmd_entry_function(const char *src, const char *dst) -{ - /* Skip variable arguments. */ - if (CMD_OPTION(dst) || CMD_VARIABLE(dst) || CMD_VARARG(dst) || - CMD_IPV4(dst) || CMD_IPV4_PREFIX(dst) || CMD_RANGE(dst)) - return NULL; - - /* In case of 'command \t', given src is NULL string. */ - if (src == NULL) - return dst; - - /* Matched with input string. */ - if (strncmp(src, dst, strlen(src)) == 0) - return dst; - - return NULL; -} - -/* If src matches dst return dst string, otherwise return NULL */ -/* This version will return the dst string always if it is - CMD_VARIABLE for '?' key processing */ -static const char *cmd_entry_function_desc(const char *src, const char *dst) -{ - if (CMD_VARARG(dst)) - return dst; - - if (CMD_RANGE(dst)) { - if (cmd_range_match(dst, src)) - return dst; - else - return NULL; - } -#ifdef HAVE_IPV6 - if (CMD_IPV6(dst)) { - if (cmd_ipv6_match(src)) - return dst; - else - return NULL; - } - - if (CMD_IPV6_PREFIX(dst)) { - if (cmd_ipv6_prefix_match(src)) - return dst; - else - return NULL; - } -#endif /* HAVE_IPV6 */ - - if (CMD_IPV4(dst)) { - if (cmd_ipv4_match(src)) - return dst; - else - return NULL; - } - - if (CMD_IPV4_PREFIX(dst)) { - if (cmd_ipv4_prefix_match(src)) - return dst; - else - return NULL; - } - - /* Optional or variable commands always match on '?' */ - if (CMD_OPTION(dst) || CMD_VARIABLE(dst)) - return dst; - - /* In case of 'command \t', given src is NULL string. */ - if (src == NULL) - return dst; - - if (strncmp(src, dst, strlen(src)) == 0) - return dst; - else - return NULL; -} - -/* Check same string element existence. If it isn't there return - 1. */ -static int cmd_unique_string(vector v, const char *str) -{ - unsigned int i; - char *match; - - for (i = 0; i < vector_active(v); i++) - if ((match = vector_slot(v, i)) != NULL) - if (strcmp(match, str) == 0) - return 0; - return 1; -} - -/* Compare string to description vector. If there is same string - return 1 else return 0. */ -static int desc_unique_string(vector v, const char *str) -{ - unsigned int i; - struct desc *desc; - - for (i = 0; i < vector_active(v); i++) - if ((desc = vector_slot(v, i)) != NULL) - if (strcmp(desc->cmd, str) == 0) - return 1; - return 0; -} - -static int cmd_try_do_shortcut(enum node_type node, char *first_word) -{ - if (first_word != NULL && - node != AUTH_NODE && - node != VIEW_NODE && - node != AUTH_ENABLE_NODE && - node != ENABLE_NODE && 0 == strcmp("do", first_word)) - return 1; - return 0; -} - -/* '?' describe command support. */ -static vector -cmd_describe_command_real(vector vline, struct vty *vty, int *status) -{ - unsigned int i; - vector cmd_vector; -#define INIT_MATCHVEC_SIZE 10 - vector matchvec; - struct cmd_element *cmd_element; - unsigned int index; - int ret; - enum match_type match; - char *command; - static struct desc desc_cr = { "<cr>", "" }; - - /* Set index. */ - if (vector_active(vline) == 0) { - *status = CMD_ERR_NO_MATCH; - return NULL; - } else - index = vector_active(vline) - 1; - - /* Make copy vector of current node's command vector. */ - cmd_vector = vector_copy(cmd_node_vector(cmdvec, vty->node)); - - /* Prepare match vector */ - matchvec = vector_init(INIT_MATCHVEC_SIZE); - - /* Filter commands. */ - /* Only words precedes current word will be checked in this loop. */ - for (i = 0; i < index; i++) - if ((command = vector_slot(vline, i))) { - match = - cmd_filter_by_completion(command, cmd_vector, i); - - if (match == vararg_match) { - struct cmd_element *cmd_element; - vector descvec; - unsigned int j, k; - - for (j = 0; j < vector_active(cmd_vector); j++) - if ((cmd_element = - vector_slot(cmd_vector, j)) != NULL - && - (vector_active - (cmd_element->strvec))) { - descvec = - vector_slot(cmd_element-> - strvec, - vector_active - (cmd_element-> - strvec) - 1); - for (k = 0; - k < vector_active(descvec); - k++) { - struct desc *desc = - vector_slot(descvec, - k); - vector_set(matchvec, - desc); - } - } - - vector_set(matchvec, &desc_cr); - vector_free(cmd_vector); - - return matchvec; - } - - if ((ret = - is_cmd_ambiguous(command, cmd_vector, i, - match)) == 1) { - vector_free(cmd_vector); - *status = CMD_ERR_AMBIGUOUS; - return NULL; - } else if (ret == 2) { - vector_free(cmd_vector); - *status = CMD_ERR_NO_MATCH; - return NULL; - } - } - - /* Prepare match vector */ - /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */ - - /* Make sure that cmd_vector is filtered based on current word */ - command = vector_slot(vline, index); - if (command) - match = cmd_filter_by_completion(command, cmd_vector, index); - - /* Make description vector. */ - for (i = 0; i < vector_active(cmd_vector); i++) - if ((cmd_element = vector_slot(cmd_vector, i)) != NULL) { - const char *string = NULL; - vector strvec = cmd_element->strvec; - - /* if command is NULL, index may be equal to vector_active */ - if (command && index >= vector_active(strvec)) - vector_slot(cmd_vector, i) = NULL; - else { - /* Check if command is completed. */ - if (command == NULL - && index == vector_active(strvec)) { - string = "<cr>"; - if (!desc_unique_string - (matchvec, string)) - vector_set(matchvec, &desc_cr); - } else { - unsigned int j; - vector descvec = - vector_slot(strvec, index); - struct desc *desc; - - for (j = 0; j < vector_active(descvec); - j++) - if ((desc = - vector_slot(descvec, j))) { - string = - cmd_entry_function_desc - (command, - desc->cmd); - if (string) { - /* Uniqueness check */ - if (!desc_unique_string(matchvec, string)) - vector_set - (matchvec, - desc); - } - } - } - } - } - vector_free(cmd_vector); - - if (vector_slot(matchvec, 0) == NULL) { - vector_free(matchvec); - *status = CMD_ERR_NO_MATCH; - } else - *status = CMD_SUCCESS; - - return matchvec; -} - -vector cmd_describe_command(vector vline, struct vty * vty, int *status) -{ - vector ret; - - if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0))) { - enum node_type onode; - vector shifted_vline; - unsigned int index; - - onode = vty->node; - vty->node = ENABLE_NODE; - /* We can try it on enable node, cos' the vty is authenticated */ - - shifted_vline = vector_init(vector_count(vline)); - /* use memcpy? */ - for (index = 1; index < vector_active(vline); index++) { - vector_set_index(shifted_vline, index - 1, - vector_lookup(vline, index)); - } - - ret = cmd_describe_command_real(shifted_vline, vty, status); - - vector_free(shifted_vline); - vty->node = onode; - return ret; - } - - return cmd_describe_command_real(vline, vty, status); -} - -/* Check LCD of matched command. */ -static int cmd_lcd(char **matched) -{ - int i; - int j; - int lcd = -1; - char *s1, *s2; - char c1, c2; - - if (matched[0] == NULL || matched[1] == NULL) - return 0; - - for (i = 1; matched[i] != NULL; i++) { - s1 = matched[i - 1]; - s2 = matched[i]; - - for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++) - if (c1 != c2) - break; - - if (lcd < 0) - lcd = j; - else { - if (lcd > j) - lcd = j; - } - } - return lcd; -} - -/* Command line completion support. */ -static char **cmd_complete_command_real(vector vline, struct vty *vty, - int *status) -{ - unsigned int i; - vector cmd_vector = vector_copy(cmd_node_vector(cmdvec, vty->node)); -#define INIT_MATCHVEC_SIZE 10 - vector matchvec; - struct cmd_element *cmd_element; - unsigned int index; - char **match_str; - struct desc *desc; - vector descvec; - char *command; - int lcd; - - if (vector_active(vline) == 0) { - *status = CMD_ERR_NO_MATCH; - return NULL; - } else - index = vector_active(vline) - 1; - - /* First, filter by preceeding command string */ - for (i = 0; i < index; i++) - if ((command = vector_slot(vline, i))) { - enum match_type match; - int ret; - - /* First try completion match, if there is exactly match return 1 */ - match = - cmd_filter_by_completion(command, cmd_vector, i); - - /* If there is exact match then filter ambiguous match else check - ambiguousness. */ - if ((ret = - is_cmd_ambiguous(command, cmd_vector, i, - match)) == 1) { - vector_free(cmd_vector); - *status = CMD_ERR_AMBIGUOUS; - return NULL; - } - /* - else if (ret == 2) - { - vector_free (cmd_vector); - *status = CMD_ERR_NO_MATCH; - return NULL; - } - */ - } - - /* Prepare match vector. */ - matchvec = vector_init(INIT_MATCHVEC_SIZE); - - /* Now we got into completion */ - for (i = 0; i < vector_active(cmd_vector); i++) - if ((cmd_element = vector_slot(cmd_vector, i))) { - const char *string; - vector strvec = cmd_element->strvec; - - /* Check field length */ - if (index >= vector_active(strvec)) - vector_slot(cmd_vector, i) = NULL; - else { - unsigned int j; - - descvec = vector_slot(strvec, index); - for (j = 0; j < vector_active(descvec); j++) - if ((desc = vector_slot(descvec, j))) { - if ((string = cmd_entry_function(vector_slot(vline, index), desc->cmd))) - if (cmd_unique_string (matchvec, string)) - vector_set (matchvec, talloc_strdup(tall_vty_cmd_ctx, string)); - } - } - } - - /* We don't need cmd_vector any more. */ - vector_free(cmd_vector); - - /* No matched command */ - if (vector_slot(matchvec, 0) == NULL) { - vector_free(matchvec); - - /* In case of 'command \t' pattern. Do you need '?' command at - the end of the line. */ - if (vector_slot(vline, index) == '\0') - *status = CMD_ERR_NOTHING_TODO; - else - *status = CMD_ERR_NO_MATCH; - return NULL; - } - - /* Only one matched */ - if (vector_slot(matchvec, 1) == NULL) { - match_str = (char **)matchvec->index; - vector_only_wrapper_free(matchvec); - *status = CMD_COMPLETE_FULL_MATCH; - return match_str; - } - /* Make it sure last element is NULL. */ - vector_set(matchvec, NULL); - - /* Check LCD of matched strings. */ - if (vector_slot(vline, index) != NULL) { - lcd = cmd_lcd((char **)matchvec->index); - - if (lcd) { - int len = strlen(vector_slot(vline, index)); - - if (len < lcd) { - char *lcdstr; - - lcdstr = _talloc_zero(tall_vty_cmd_ctx, lcd + 1, - "complete-lcdstr"); - memcpy(lcdstr, matchvec->index[0], lcd); - lcdstr[lcd] = '\0'; - - /* match_str = (char **) &lcdstr; */ - - /* Free matchvec. */ - for (i = 0; i < vector_active(matchvec); i++) { - if (vector_slot(matchvec, i)) - talloc_free(vector_slot(matchvec, i)); - } - vector_free(matchvec); - - /* Make new matchvec. */ - matchvec = vector_init(INIT_MATCHVEC_SIZE); - vector_set(matchvec, lcdstr); - match_str = (char **)matchvec->index; - vector_only_wrapper_free(matchvec); - - *status = CMD_COMPLETE_MATCH; - return match_str; - } - } - } - - match_str = (char **)matchvec->index; - vector_only_wrapper_free(matchvec); - *status = CMD_COMPLETE_LIST_MATCH; - return match_str; -} - -char **cmd_complete_command(vector vline, struct vty *vty, int *status) -{ - char **ret; - - if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0))) { - enum node_type onode; - vector shifted_vline; - unsigned int index; - - onode = vty->node; - vty->node = ENABLE_NODE; - /* We can try it on enable node, cos' the vty is authenticated */ - - shifted_vline = vector_init(vector_count(vline)); - /* use memcpy? */ - for (index = 1; index < vector_active(vline); index++) { - vector_set_index(shifted_vline, index - 1, - vector_lookup(vline, index)); - } - - ret = cmd_complete_command_real(shifted_vline, vty, status); - - vector_free(shifted_vline); - vty->node = onode; - return ret; - } - - return cmd_complete_command_real(vline, vty, status); -} - -/* return parent node */ -/* MUST eventually converge on CONFIG_NODE */ -enum node_type vty_go_parent(struct vty *vty) -{ - assert(vty->node > CONFIG_NODE); - - if (host.app_info->go_parent_cb) - host.app_info->go_parent_cb(vty); - else - vty->node = CONFIG_NODE; - - return vty->node; -} - -/* Execute command by argument vline vector. */ -static int -cmd_execute_command_real(vector vline, struct vty *vty, - struct cmd_element **cmd) -{ - unsigned int i; - unsigned int index; - vector cmd_vector; - struct cmd_element *cmd_element; - struct cmd_element *matched_element; - unsigned int matched_count, incomplete_count; - int argc; - const char *argv[CMD_ARGC_MAX]; - enum match_type match = 0; - int varflag; - char *command; - - /* Make copy of command elements. */ - cmd_vector = vector_copy(cmd_node_vector(cmdvec, vty->node)); - - for (index = 0; index < vector_active(vline); index++) - if ((command = vector_slot(vline, index))) { - int ret; - - match = - cmd_filter_by_completion(command, cmd_vector, - index); - - if (match == vararg_match) - break; - - ret = - is_cmd_ambiguous(command, cmd_vector, index, match); - - if (ret == 1) { - vector_free(cmd_vector); - return CMD_ERR_AMBIGUOUS; - } else if (ret == 2) { - vector_free(cmd_vector); - return CMD_ERR_NO_MATCH; - } - } - - /* Check matched count. */ - matched_element = NULL; - matched_count = 0; - incomplete_count = 0; - - for (i = 0; i < vector_active(cmd_vector); i++) - if ((cmd_element = vector_slot(cmd_vector, i))) { - if (match == vararg_match - || index >= cmd_element->cmdsize) { - matched_element = cmd_element; -#if 0 - printf("DEBUG: %s\n", cmd_element->string); -#endif - matched_count++; - } else { - incomplete_count++; - } - } - - /* Finish of using cmd_vector. */ - vector_free(cmd_vector); - - /* To execute command, matched_count must be 1. */ - if (matched_count == 0) { - if (incomplete_count) - return CMD_ERR_INCOMPLETE; - else - return CMD_ERR_NO_MATCH; - } - - if (matched_count > 1) - return CMD_ERR_AMBIGUOUS; - - /* Argument treatment */ - varflag = 0; - argc = 0; - - for (i = 0; i < vector_active(vline); i++) { - if (varflag) - argv[argc++] = vector_slot(vline, i); - else { - vector descvec = - vector_slot(matched_element->strvec, i); - - if (vector_active(descvec) == 1) { - struct desc *desc = vector_slot(descvec, 0); - - if (CMD_VARARG(desc->cmd)) - varflag = 1; - - if (varflag || CMD_VARIABLE(desc->cmd) - || CMD_OPTION(desc->cmd)) - argv[argc++] = vector_slot(vline, i); - } else - argv[argc++] = vector_slot(vline, i); - } - - if (argc >= CMD_ARGC_MAX) - return CMD_ERR_EXEED_ARGC_MAX; - } - - /* For vtysh execution. */ - if (cmd) - *cmd = matched_element; - - if (matched_element->daemon) - return CMD_SUCCESS_DAEMON; - - /* Execute matched command. */ - return (*matched_element->func) (matched_element, vty, argc, argv); -} - -int -cmd_execute_command(vector vline, struct vty *vty, struct cmd_element **cmd, - int vtysh) -{ - int ret, saved_ret, tried = 0; - enum node_type onode; - void *oindex; - - onode = vty->node; - oindex = vty->index; - - if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0))) { - vector shifted_vline; - unsigned int index; - - vty->node = ENABLE_NODE; - /* We can try it on enable node, cos' the vty is authenticated */ - - shifted_vline = vector_init(vector_count(vline)); - /* use memcpy? */ - for (index = 1; index < vector_active(vline); index++) { - vector_set_index(shifted_vline, index - 1, - vector_lookup(vline, index)); - } - - ret = cmd_execute_command_real(shifted_vline, vty, cmd); - - vector_free(shifted_vline); - vty->node = onode; - return ret; - } - - saved_ret = ret = cmd_execute_command_real(vline, vty, cmd); - - if (vtysh) - return saved_ret; - - /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */ - while (ret != CMD_SUCCESS && ret != CMD_WARNING - && vty->node > CONFIG_NODE) { - vty_go_parent(vty); - ret = cmd_execute_command_real(vline, vty, cmd); - tried = 1; - if (ret == CMD_SUCCESS || ret == CMD_WARNING) { - /* succesfull command, leave the node as is */ - return ret; - } - } - /* no command succeeded, reset the vty to the original node and - return the error for this node */ - if (tried) { - vty->node = onode; - vty->index = oindex; - } - return saved_ret; -} - -/* Execute command by argument readline. */ -int -cmd_execute_command_strict(vector vline, struct vty *vty, - struct cmd_element **cmd) -{ - unsigned int i; - unsigned int index; - vector cmd_vector; - struct cmd_element *cmd_element; - struct cmd_element *matched_element; - unsigned int matched_count, incomplete_count; - int argc; - const char *argv[CMD_ARGC_MAX]; - int varflag; - enum match_type match = 0; - char *command; - - /* Make copy of command element */ - cmd_vector = vector_copy(cmd_node_vector(cmdvec, vty->node)); - - for (index = 0; index < vector_active(vline); index++) - if ((command = vector_slot(vline, index))) { - int ret; - - match = cmd_filter_by_string(vector_slot(vline, index), - cmd_vector, index); - - /* If command meets '.VARARG' then finish matching. */ - if (match == vararg_match) - break; - - ret = - is_cmd_ambiguous(command, cmd_vector, index, match); - if (ret == 1) { - vector_free(cmd_vector); - return CMD_ERR_AMBIGUOUS; - } - if (ret == 2) { - vector_free(cmd_vector); - return CMD_ERR_NO_MATCH; - } - } - - /* Check matched count. */ - matched_element = NULL; - matched_count = 0; - incomplete_count = 0; - for (i = 0; i < vector_active(cmd_vector); i++) - if (vector_slot(cmd_vector, i) != NULL) { - cmd_element = vector_slot(cmd_vector, i); - - if (match == vararg_match - || index >= cmd_element->cmdsize) { - matched_element = cmd_element; - matched_count++; - } else - incomplete_count++; - } - - /* Finish of using cmd_vector. */ - vector_free(cmd_vector); - - /* To execute command, matched_count must be 1. */ - if (matched_count == 0) { - if (incomplete_count) - return CMD_ERR_INCOMPLETE; - else - return CMD_ERR_NO_MATCH; - } - - if (matched_count > 1) - return CMD_ERR_AMBIGUOUS; - - /* Argument treatment */ - varflag = 0; - argc = 0; - - for (i = 0; i < vector_active(vline); i++) { - if (varflag) - argv[argc++] = vector_slot(vline, i); - else { - vector descvec = - vector_slot(matched_element->strvec, i); - - if (vector_active(descvec) == 1) { - struct desc *desc = vector_slot(descvec, 0); - - if (CMD_VARARG(desc->cmd)) - varflag = 1; - - if (varflag || CMD_VARIABLE(desc->cmd) - || CMD_OPTION(desc->cmd)) - argv[argc++] = vector_slot(vline, i); - } else - argv[argc++] = vector_slot(vline, i); - } - - if (argc >= CMD_ARGC_MAX) - return CMD_ERR_EXEED_ARGC_MAX; - } - - /* For vtysh execution. */ - if (cmd) - *cmd = matched_element; - - if (matched_element->daemon) - return CMD_SUCCESS_DAEMON; - - /* Now execute matched command */ - return (*matched_element->func) (matched_element, vty, argc, argv); -} - -/* Configration make from file. */ -int config_from_file(struct vty *vty, FILE * fp) -{ - int ret; - vector vline; - - while (fgets(vty->buf, VTY_BUFSIZ, fp)) { - vline = cmd_make_strvec(vty->buf); - - /* In case of comment line */ - if (vline == NULL) - continue; - /* Execute configuration command : this is strict match */ - ret = cmd_execute_command_strict(vline, vty, NULL); - - /* Try again with setting node to CONFIG_NODE */ - while (ret != CMD_SUCCESS && ret != CMD_WARNING - && ret != CMD_ERR_NOTHING_TODO - && vty->node != CONFIG_NODE) { - vty_go_parent(vty); - ret = cmd_execute_command_strict(vline, vty, NULL); - } - - cmd_free_strvec(vline); - - if (ret != CMD_SUCCESS && ret != CMD_WARNING - && ret != CMD_ERR_NOTHING_TODO) - return ret; - } - return CMD_SUCCESS; -} - -/* Configration from terminal */ -DEFUN(config_terminal, - config_terminal_cmd, - "configure terminal", - "Configuration from vty interface\n" "Configuration terminal\n") -{ - if (vty_config_lock(vty)) - vty->node = CONFIG_NODE; - else { - vty_out(vty, "VTY configuration is locked by other VTY%s", - VTY_NEWLINE); - return CMD_WARNING; - } - return CMD_SUCCESS; -} - -/* Enable command */ -DEFUN(enable, config_enable_cmd, "enable", "Turn on privileged mode command\n") -{ - /* If enable password is NULL, change to ENABLE_NODE */ - if ((host.enable == NULL && host.enable_encrypt == NULL) || - vty->type == VTY_SHELL_SERV) - vty->node = ENABLE_NODE; - else - vty->node = AUTH_ENABLE_NODE; - - return CMD_SUCCESS; -} - -/* Disable command */ -DEFUN(disable, - config_disable_cmd, "disable", "Turn off privileged mode command\n") -{ - if (vty->node == ENABLE_NODE) - vty->node = VIEW_NODE; - return CMD_SUCCESS; -} - -/* Down vty node level. */ -gDEFUN(config_exit, - config_exit_cmd, "exit", "Exit current mode and down to previous mode\n") -{ - switch (vty->node) { - case VIEW_NODE: - case ENABLE_NODE: - if (0) //vty_shell (vty)) - exit(0); - else - vty->status = VTY_CLOSE; - break; - case CONFIG_NODE: - vty->node = ENABLE_NODE; - vty_config_unlock(vty); - break; - case VTY_NODE: - vty->node = CONFIG_NODE; - break; - default: - break; - } - return CMD_SUCCESS; -} - -/* End of configuration. */ - gDEFUN(config_end, - config_end_cmd, "end", "End current mode and change to enable mode.") -{ - switch (vty->node) { - case VIEW_NODE: - case ENABLE_NODE: - /* Nothing to do. */ - break; - case CONFIG_NODE: - case VTY_NODE: - vty_config_unlock(vty); - vty->node = ENABLE_NODE; - break; - default: - break; - } - return CMD_SUCCESS; -} - -/* Show version. */ -DEFUN(show_version, - show_version_cmd, "show version", SHOW_STR "Displays program version\n") -{ - vty_out(vty, "%s %s (%s).%s", host.app_info->name, - host.app_info->version, - host.app_info->name ? host.app_info->name : "", VTY_NEWLINE); - vty_out(vty, "%s%s", host.app_info->copyright, VTY_NEWLINE); - - return CMD_SUCCESS; -} - -/* Help display function for all node. */ -gDEFUN(config_help, - config_help_cmd, "help", "Description of the interactive help system\n") -{ - vty_out(vty, - "This VTY provides advanced help features. When you need help,%s\ -anytime at the command line please press '?'.%s\ -%s\ -If nothing matches, the help list will be empty and you must backup%s\ - until entering a '?' shows the available options.%s\ -Two styles of help are provided:%s\ -1. Full help is available when you are ready to enter a%s\ -command argument (e.g. 'show ?') and describes each possible%s\ -argument.%s\ -2. Partial help is provided when an abbreviated argument is entered%s\ - and you want to know what arguments match the input%s\ - (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, - VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); - return CMD_SUCCESS; -} - -/* Help display function for all node. */ -gDEFUN(config_list, config_list_cmd, "list", "Print command list\n") -{ - unsigned int i; - struct cmd_node *cnode = vector_slot(cmdvec, vty->node); - struct cmd_element *cmd; - - for (i = 0; i < vector_active(cnode->cmd_vector); i++) - if ((cmd = vector_slot(cnode->cmd_vector, i)) != NULL - && !(cmd->attr == CMD_ATTR_DEPRECATED - || cmd->attr == CMD_ATTR_HIDDEN)) - vty_out(vty, " %s%s", cmd->string, VTY_NEWLINE); - return CMD_SUCCESS; -} - -/* Write current configuration into file. */ -DEFUN(config_write_file, - config_write_file_cmd, - "write file", - "Write running configuration to memory, network, or terminal\n" - "Write to configuration file\n") -{ - unsigned int i; - int fd; - struct cmd_node *node; - char *config_file; - char *config_file_tmp = NULL; - char *config_file_sav = NULL; - struct vty *file_vty; - - /* Check and see if we are operating under vtysh configuration */ - if (host.config == NULL) { - vty_out(vty, "Can't save to configuration file, using vtysh.%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - /* Get filename. */ - config_file = host.config; - - config_file_sav = - _talloc_zero(tall_vty_cmd_ctx, - strlen(config_file) + strlen(CONF_BACKUP_EXT) + 1, - "config_file_sav"); - strcpy(config_file_sav, config_file); - strcat(config_file_sav, CONF_BACKUP_EXT); - - config_file_tmp = _talloc_zero(tall_vty_cmd_ctx, strlen(config_file) + 8, - "config_file_tmp"); - sprintf(config_file_tmp, "%s.XXXXXX", config_file); - - /* Open file to configuration write. */ - fd = mkstemp(config_file_tmp); - if (fd < 0) { - vty_out(vty, "Can't open configuration file %s.%s", - config_file_tmp, VTY_NEWLINE); - talloc_free(config_file_tmp); - talloc_free(config_file_sav); - return CMD_WARNING; - } - - /* Make vty for configuration file. */ - file_vty = vty_new(); - file_vty->fd = fd; - file_vty->type = VTY_FILE; - - /* Config file header print. */ - vty_out(file_vty, "!\n! %s (%s) configuration saved from vty\n!", - host.app_info->name, host.app_info->version); - //vty_time_print (file_vty, 1); - vty_out(file_vty, "!\n"); - - for (i = 0; i < vector_active(cmdvec); i++) - if ((node = vector_slot(cmdvec, i)) && node->func) { - if ((*node->func) (file_vty)) - vty_out(file_vty, "!\n"); - } - vty_close(file_vty); - - if (unlink(config_file_sav) != 0) - if (errno != ENOENT) { - vty_out(vty, - "Can't unlink backup configuration file %s.%s", - config_file_sav, VTY_NEWLINE); - talloc_free(config_file_sav); - talloc_free(config_file_tmp); - unlink(config_file_tmp); - return CMD_WARNING; - } - if (link(config_file, config_file_sav) != 0) { - vty_out(vty, "Can't backup old configuration file %s.%s", - config_file_sav, VTY_NEWLINE); - talloc_free(config_file_sav); - talloc_free(config_file_tmp); - unlink(config_file_tmp); - return CMD_WARNING; - } - sync(); - if (unlink(config_file) != 0) { - vty_out(vty, "Can't unlink configuration file %s.%s", - config_file, VTY_NEWLINE); - talloc_free(config_file_sav); - talloc_free(config_file_tmp); - unlink(config_file_tmp); - return CMD_WARNING; - } - if (link(config_file_tmp, config_file) != 0) { - vty_out(vty, "Can't save configuration file %s.%s", config_file, - VTY_NEWLINE); - talloc_free(config_file_sav); - talloc_free(config_file_tmp); - unlink(config_file_tmp); - return CMD_WARNING; - } - unlink(config_file_tmp); - sync(); - - talloc_free(config_file_sav); - talloc_free(config_file_tmp); - - if (chmod(config_file, 0666 & ~CONFIGFILE_MASK) != 0) { - vty_out(vty, "Can't chmod configuration file %s: %s (%d).%s", - config_file, strerror(errno), errno, VTY_NEWLINE); - return CMD_WARNING; - } - - vty_out(vty, "Configuration saved to %s%s", config_file, VTY_NEWLINE); - return CMD_SUCCESS; -} - -ALIAS(config_write_file, - config_write_cmd, - "write", "Write running configuration to memory, network, or terminal\n") - - ALIAS(config_write_file, - config_write_memory_cmd, - "write memory", - "Write running configuration to memory, network, or terminal\n" - "Write configuration to the file (same as write file)\n") - - ALIAS(config_write_file, - copy_runningconfig_startupconfig_cmd, - "copy running-config startup-config", - "Copy configuration\n" - "Copy running config to... \n" - "Copy running config to startup config (same as write file)\n") - -/* Write current configuration into the terminal. */ - DEFUN(config_write_terminal, - config_write_terminal_cmd, - "write terminal", - "Write running configuration to memory, network, or terminal\n" - "Write to terminal\n") -{ - unsigned int i; - struct cmd_node *node; - - if (vty->type == VTY_SHELL_SERV) { - for (i = 0; i < vector_active(cmdvec); i++) - if ((node = vector_slot(cmdvec, i)) && node->func - && node->vtysh) { - if ((*node->func) (vty)) - vty_out(vty, "!%s", VTY_NEWLINE); - } - } else { - vty_out(vty, "%sCurrent configuration:%s", VTY_NEWLINE, - VTY_NEWLINE); - vty_out(vty, "!%s", VTY_NEWLINE); - - for (i = 0; i < vector_active(cmdvec); i++) - if ((node = vector_slot(cmdvec, i)) && node->func) { - if ((*node->func) (vty)) - vty_out(vty, "!%s", VTY_NEWLINE); - } - vty_out(vty, "end%s", VTY_NEWLINE); - } - return CMD_SUCCESS; -} - -/* Write current configuration into the terminal. */ -ALIAS(config_write_terminal, - show_running_config_cmd, - "show running-config", SHOW_STR "running configuration\n") - -/* Write startup configuration into the terminal. */ - DEFUN(show_startup_config, - show_startup_config_cmd, - "show startup-config", SHOW_STR "Contentes of startup configuration\n") -{ - char buf[BUFSIZ]; - FILE *confp; - - confp = fopen(host.config, "r"); - if (confp == NULL) { - vty_out(vty, "Can't open configuration file [%s]%s", - host.config, VTY_NEWLINE); - return CMD_WARNING; - } - - while (fgets(buf, BUFSIZ, confp)) { - char *cp = buf; - - while (*cp != '\r' && *cp != '\n' && *cp != '\0') - cp++; - *cp = '\0'; - - vty_out(vty, "%s%s", buf, VTY_NEWLINE); - } - - fclose(confp); - - return CMD_SUCCESS; -} - -/* Hostname configuration */ -DEFUN(config_hostname, - hostname_cmd, - "hostname WORD", - "Set system's network name\n" "This system's network name\n") -{ - if (!isalpha((int)*argv[0])) { - vty_out(vty, "Please specify string starting with alphabet%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - if (host.name) - talloc_free(host.name); - - host.name = talloc_strdup(tall_vty_cmd_ctx, argv[0]); - return CMD_SUCCESS; -} - -DEFUN(config_no_hostname, - no_hostname_cmd, - "no hostname [HOSTNAME]", - NO_STR "Reset system's network name\n" "Host name of this router\n") -{ - if (host.name) - talloc_free(host.name); - host.name = NULL; - return CMD_SUCCESS; -} - -/* VTY interface password set. */ -DEFUN(config_password, password_cmd, - "password (8|) WORD", - "Assign the terminal connection password\n" - "Specifies a HIDDEN password will follow\n" - "dummy string \n" "The HIDDEN line password string\n") -{ - /* Argument check. */ - if (argc == 0) { - vty_out(vty, "Please specify password.%s", VTY_NEWLINE); - return CMD_WARNING; - } - - if (argc == 2) { - if (*argv[0] == '8') { - if (host.password) - talloc_free(host.password); - host.password = NULL; - if (host.password_encrypt) - talloc_free(host.password_encrypt); - host.password_encrypt = talloc_strdup(tall_vty_cmd_ctx, argv[1]); - return CMD_SUCCESS; - } else { - vty_out(vty, "Unknown encryption type.%s", VTY_NEWLINE); - return CMD_WARNING; - } - } - - if (!isalnum((int)*argv[0])) { - vty_out(vty, - "Please specify string starting with alphanumeric%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - if (host.password) - talloc_free(host.password); - host.password = NULL; - -#ifdef VTY_CRYPT_PW - if (host.encrypt) { - if (host.password_encrypt) - talloc_free(host.password_encrypt); - host.password_encrypt = talloc_strdup(tall_vty_cmd_ctx, zencrypt(argv[0])); - } else -#endif - host.password = talloc_strdup(tall_vty_cmd_ctx, argv[0]); - - return CMD_SUCCESS; -} - -ALIAS(config_password, password_text_cmd, - "password LINE", - "Assign the terminal connection password\n" - "The UNENCRYPTED (cleartext) line password\n") - -/* VTY enable password set. */ - DEFUN(config_enable_password, enable_password_cmd, - "enable password (8|) WORD", - "Modify enable password parameters\n" - "Assign the privileged level password\n" - "Specifies a HIDDEN password will follow\n" - "dummy string \n" "The HIDDEN 'enable' password string\n") -{ - /* Argument check. */ - if (argc == 0) { - vty_out(vty, "Please specify password.%s", VTY_NEWLINE); - return CMD_WARNING; - } - - /* Crypt type is specified. */ - if (argc == 2) { - if (*argv[0] == '8') { - if (host.enable) - talloc_free(host.enable); - host.enable = NULL; - - if (host.enable_encrypt) - talloc_free(host.enable_encrypt); - host.enable_encrypt = talloc_strdup(tall_vty_cmd_ctx, argv[1]); - - return CMD_SUCCESS; - } else { - vty_out(vty, "Unknown encryption type.%s", VTY_NEWLINE); - return CMD_WARNING; - } - } - - if (!isalnum((int)*argv[0])) { - vty_out(vty, - "Please specify string starting with alphanumeric%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - if (host.enable) - talloc_free(host.enable); - host.enable = NULL; - - /* Plain password input. */ -#ifdef VTY_CRYPT_PW - if (host.encrypt) { - if (host.enable_encrypt) - talloc_free(host.enable_encrypt); - host.enable_encrypt = talloc_strdup(tall_vty_cmd_ctx, zencrypt(argv[0])); - } else -#endif - host.enable = talloc_strdup(tall_vty_cmd_ctx, argv[0]); - - return CMD_SUCCESS; -} - -ALIAS(config_enable_password, - enable_password_text_cmd, - "enable password LINE", - "Modify enable password parameters\n" - "Assign the privileged level password\n" - "The UNENCRYPTED (cleartext) 'enable' password\n") - -/* VTY enable password delete. */ - DEFUN(no_config_enable_password, no_enable_password_cmd, - "no enable password", - NO_STR - "Modify enable password parameters\n" - "Assign the privileged level password\n") -{ - if (host.enable) - talloc_free(host.enable); - host.enable = NULL; - - if (host.enable_encrypt) - talloc_free(host.enable_encrypt); - host.enable_encrypt = NULL; - - return CMD_SUCCESS; -} - -#ifdef VTY_CRYPT_PW -DEFUN(service_password_encrypt, - service_password_encrypt_cmd, - "service password-encryption", - "Set up miscellaneous service\n" "Enable encrypted passwords\n") -{ - if (host.encrypt) - return CMD_SUCCESS; - - host.encrypt = 1; - - if (host.password) { - if (host.password_encrypt) - talloc_free(host.password_encrypt); - host.password_encrypt = talloc_strdup(tall_vty_cmd_ctx, zencrypt(host.password)); - } - if (host.enable) { - if (host.enable_encrypt) - talloc_free(host.enable_encrypt); - host.enable_encrypt = talloc_strdup(tall_vty_cmd_ctx, zencrypt(host.enable)); - } - - return CMD_SUCCESS; -} - -DEFUN(no_service_password_encrypt, - no_service_password_encrypt_cmd, - "no service password-encryption", - NO_STR "Set up miscellaneous service\n" "Enable encrypted passwords\n") -{ - if (!host.encrypt) - return CMD_SUCCESS; - - host.encrypt = 0; - - if (host.password_encrypt) - talloc_free(host.password_encrypt); - host.password_encrypt = NULL; - - if (host.enable_encrypt) - talloc_free(host.enable_encrypt); - host.enable_encrypt = NULL; - - return CMD_SUCCESS; -} -#endif - -DEFUN(config_terminal_length, config_terminal_length_cmd, - "terminal length <0-512>", - "Set terminal line parameters\n" - "Set number of lines on a screen\n" - "Number of lines on screen (0 for no pausing)\n") -{ - int lines; - char *endptr = NULL; - - lines = strtol(argv[0], &endptr, 10); - if (lines < 0 || lines > 512 || *endptr != '\0') { - vty_out(vty, "length is malformed%s", VTY_NEWLINE); - return CMD_WARNING; - } - vty->lines = lines; - - return CMD_SUCCESS; -} - -DEFUN(config_terminal_no_length, config_terminal_no_length_cmd, - "terminal no length", - "Set terminal line parameters\n" - NO_STR "Set number of lines on a screen\n") -{ - vty->lines = -1; - return CMD_SUCCESS; -} - -DEFUN(service_terminal_length, service_terminal_length_cmd, - "service terminal-length <0-512>", - "Set up miscellaneous service\n" - "System wide terminal length configuration\n" - "Number of lines of VTY (0 means no line control)\n") -{ - int lines; - char *endptr = NULL; - - lines = strtol(argv[0], &endptr, 10); - if (lines < 0 || lines > 512 || *endptr != '\0') { - vty_out(vty, "length is malformed%s", VTY_NEWLINE); - return CMD_WARNING; - } - host.lines = lines; - - return CMD_SUCCESS; -} - -DEFUN(no_service_terminal_length, no_service_terminal_length_cmd, - "no service terminal-length [<0-512>]", - NO_STR - "Set up miscellaneous service\n" - "System wide terminal length configuration\n" - "Number of lines of VTY (0 means no line control)\n") -{ - host.lines = -1; - return CMD_SUCCESS; -} - -DEFUN_HIDDEN(do_echo, - echo_cmd, - "echo .MESSAGE", - "Echo a message back to the vty\n" "The message to echo\n") -{ - char *message; - - vty_out(vty, "%s%s", - ((message = - argv_concat(argv, argc, 0)) ? message : ""), VTY_NEWLINE); - if (message) - talloc_free(message); - return CMD_SUCCESS; -} - -#if 0 -DEFUN(config_logmsg, - config_logmsg_cmd, - "logmsg " LOG_LEVELS " .MESSAGE", - "Send a message to enabled logging destinations\n" - LOG_LEVEL_DESC "The message to send\n") -{ - int level; - char *message; - - if ((level = level_match(argv[0])) == ZLOG_DISABLED) - return CMD_ERR_NO_MATCH; - - zlog(NULL, level, - ((message = argv_concat(argv, argc, 1)) ? message : "")); - if (message) - talloc_free(message); - return CMD_SUCCESS; -} - -DEFUN(show_logging, - show_logging_cmd, - "show logging", SHOW_STR "Show current logging configuration\n") -{ - struct zlog *zl = zlog_default; - - vty_out(vty, "Syslog logging: "); - if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED) - vty_out(vty, "disabled"); - else - vty_out(vty, "level %s, facility %s, ident %s", - zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]], - facility_name(zl->facility), zl->ident); - vty_out(vty, "%s", VTY_NEWLINE); - - vty_out(vty, "Stdout logging: "); - if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED) - vty_out(vty, "disabled"); - else - vty_out(vty, "level %s", - zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]); - vty_out(vty, "%s", VTY_NEWLINE); - - vty_out(vty, "Monitor logging: "); - if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED) - vty_out(vty, "disabled"); - else - vty_out(vty, "level %s", - zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]); - vty_out(vty, "%s", VTY_NEWLINE); - - vty_out(vty, "File logging: "); - if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) || !zl->fp) - vty_out(vty, "disabled"); - else - vty_out(vty, "level %s, filename %s", - zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]], - zl->filename); - vty_out(vty, "%s", VTY_NEWLINE); - - vty_out(vty, "Protocol name: %s%s", - zlog_proto_names[zl->protocol], VTY_NEWLINE); - vty_out(vty, "Record priority: %s%s", - (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE); - - return CMD_SUCCESS; -} - -DEFUN(config_log_stdout, - config_log_stdout_cmd, - "log stdout", "Logging control\n" "Set stdout logging level\n") -{ - zlog_set_level(NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl); - return CMD_SUCCESS; -} - -DEFUN(config_log_stdout_level, - config_log_stdout_level_cmd, - "log stdout " LOG_LEVELS, - "Logging control\n" "Set stdout logging level\n" LOG_LEVEL_DESC) -{ - int level; - - if ((level = level_match(argv[0])) == ZLOG_DISABLED) - return CMD_ERR_NO_MATCH; - zlog_set_level(NULL, ZLOG_DEST_STDOUT, level); - return CMD_SUCCESS; -} - -DEFUN(no_config_log_stdout, - no_config_log_stdout_cmd, - "no log stdout [LEVEL]", - NO_STR "Logging control\n" "Cancel logging to stdout\n" "Logging level\n") -{ - zlog_set_level(NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED); - return CMD_SUCCESS; -} - -DEFUN(config_log_monitor, - config_log_monitor_cmd, - "log monitor", - "Logging control\n" "Set terminal line (monitor) logging level\n") -{ - zlog_set_level(NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl); - return CMD_SUCCESS; -} - -DEFUN(config_log_monitor_level, - config_log_monitor_level_cmd, - "log monitor " LOG_LEVELS, - "Logging control\n" - "Set terminal line (monitor) logging level\n" LOG_LEVEL_DESC) -{ - int level; - - if ((level = level_match(argv[0])) == ZLOG_DISABLED) - return CMD_ERR_NO_MATCH; - zlog_set_level(NULL, ZLOG_DEST_MONITOR, level); - return CMD_SUCCESS; -} - -DEFUN(no_config_log_monitor, - no_config_log_monitor_cmd, - "no log monitor [LEVEL]", - NO_STR - "Logging control\n" - "Disable terminal line (monitor) logging\n" "Logging level\n") -{ - zlog_set_level(NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED); - return CMD_SUCCESS; -} - -static int set_log_file(struct vty *vty, const char *fname, int loglevel) -{ - int ret; - char *p = NULL; - const char *fullpath; - - /* Path detection. */ - if (!IS_DIRECTORY_SEP(*fname)) { - char cwd[MAXPATHLEN + 1]; - cwd[MAXPATHLEN] = '\0'; - - if (getcwd(cwd, MAXPATHLEN) == NULL) { - zlog_err("config_log_file: Unable to alloc mem!"); - return CMD_WARNING; - } - - if ((p = _talloc_zero(tall_vcmd_ctx, - strlen(cwd) + strlen(fname) + 2), - "set_log_file") - == NULL) { - zlog_err("config_log_file: Unable to alloc mem!"); - return CMD_WARNING; - } - sprintf(p, "%s/%s", cwd, fname); - fullpath = p; - } else - fullpath = fname; - - ret = zlog_set_file(NULL, fullpath, loglevel); - - if (p) - talloc_free(p); - - if (!ret) { - vty_out(vty, "can't open logfile %s\n", fname); - return CMD_WARNING; - } - - if (host.logfile) - talloc_free(host.logfile); - - host.logfile = talloc_strdup(tall_vty_cmd_ctx, fname); - - return CMD_SUCCESS; -} - -DEFUN(config_log_file, - config_log_file_cmd, - "log file FILENAME", - "Logging control\n" "Logging to file\n" "Logging filename\n") -{ - return set_log_file(vty, argv[0], zlog_default->default_lvl); -} - -DEFUN(config_log_file_level, - config_log_file_level_cmd, - "log file FILENAME " LOG_LEVELS, - "Logging control\n" - "Logging to file\n" "Logging filename\n" LOG_LEVEL_DESC) -{ - int level; - - if ((level = level_match(argv[1])) == ZLOG_DISABLED) - return CMD_ERR_NO_MATCH; - return set_log_file(vty, argv[0], level); -} - -DEFUN(no_config_log_file, - no_config_log_file_cmd, - "no log file [FILENAME]", - NO_STR - "Logging control\n" "Cancel logging to file\n" "Logging file name\n") -{ - zlog_reset_file(NULL); - - if (host.logfile) - talloc_free(host.logfile); - - host.logfile = NULL; - - return CMD_SUCCESS; -} - -ALIAS(no_config_log_file, - no_config_log_file_level_cmd, - "no log file FILENAME LEVEL", - NO_STR - "Logging control\n" - "Cancel logging to file\n" "Logging file name\n" "Logging level\n") - - DEFUN(config_log_syslog, - config_log_syslog_cmd, - "log syslog", "Logging control\n" "Set syslog logging level\n") -{ - zlog_set_level(NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl); - return CMD_SUCCESS; -} - -DEFUN(config_log_syslog_level, - config_log_syslog_level_cmd, - "log syslog " LOG_LEVELS, - "Logging control\n" "Set syslog logging level\n" LOG_LEVEL_DESC) -{ - int level; - - if ((level = level_match(argv[0])) == ZLOG_DISABLED) - return CMD_ERR_NO_MATCH; - zlog_set_level(NULL, ZLOG_DEST_SYSLOG, level); - return CMD_SUCCESS; -} - -DEFUN_DEPRECATED(config_log_syslog_facility, - config_log_syslog_facility_cmd, - "log syslog facility " LOG_FACILITIES, - "Logging control\n" - "Logging goes to syslog\n" - "(Deprecated) Facility parameter for syslog messages\n" - LOG_FACILITY_DESC) -{ - int facility; - - if ((facility = facility_match(argv[0])) < 0) - return CMD_ERR_NO_MATCH; - - zlog_set_level(NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl); - zlog_default->facility = facility; - return CMD_SUCCESS; -} - -DEFUN(no_config_log_syslog, - no_config_log_syslog_cmd, - "no log syslog [LEVEL]", - NO_STR "Logging control\n" "Cancel logging to syslog\n" "Logging level\n") -{ - zlog_set_level(NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED); - return CMD_SUCCESS; -} - -ALIAS(no_config_log_syslog, - no_config_log_syslog_facility_cmd, - "no log syslog facility " LOG_FACILITIES, - NO_STR - "Logging control\n" - "Logging goes to syslog\n" - "Facility parameter for syslog messages\n" LOG_FACILITY_DESC) - - DEFUN(config_log_facility, - config_log_facility_cmd, - "log facility " LOG_FACILITIES, - "Logging control\n" - "Facility parameter for syslog messages\n" LOG_FACILITY_DESC) -{ - int facility; - - if ((facility = facility_match(argv[0])) < 0) - return CMD_ERR_NO_MATCH; - zlog_default->facility = facility; - return CMD_SUCCESS; -} - -DEFUN(no_config_log_facility, - no_config_log_facility_cmd, - "no log facility [FACILITY]", - NO_STR - "Logging control\n" - "Reset syslog facility to default (daemon)\n" "Syslog facility\n") -{ - zlog_default->facility = LOG_DAEMON; - return CMD_SUCCESS; -} - -DEFUN_DEPRECATED(config_log_trap, - config_log_trap_cmd, - "log trap " LOG_LEVELS, - "Logging control\n" - "(Deprecated) Set logging level and default for all destinations\n" - LOG_LEVEL_DESC) -{ - int new_level; - int i; - - if ((new_level = level_match(argv[0])) == ZLOG_DISABLED) - return CMD_ERR_NO_MATCH; - - zlog_default->default_lvl = new_level; - for (i = 0; i < ZLOG_NUM_DESTS; i++) - if (zlog_default->maxlvl[i] != ZLOG_DISABLED) - zlog_default->maxlvl[i] = new_level; - return CMD_SUCCESS; -} - -DEFUN_DEPRECATED(no_config_log_trap, - no_config_log_trap_cmd, - "no log trap [LEVEL]", - NO_STR - "Logging control\n" - "Permit all logging information\n" "Logging level\n") -{ - zlog_default->default_lvl = LOG_DEBUG; - return CMD_SUCCESS; -} - -DEFUN(config_log_record_priority, - config_log_record_priority_cmd, - "log record-priority", - "Logging control\n" - "Log the priority of the message within the message\n") -{ - zlog_default->record_priority = 1; - return CMD_SUCCESS; -} - -DEFUN(no_config_log_record_priority, - no_config_log_record_priority_cmd, - "no log record-priority", - NO_STR - "Logging control\n" - "Do not log the priority of the message within the message\n") -{ - zlog_default->record_priority = 0; - return CMD_SUCCESS; -} -#endif - -DEFUN(banner_motd_file, - banner_motd_file_cmd, - "banner motd file [FILE]", - "Set banner\n" "Banner for motd\n" "Banner from a file\n" "Filename\n") -{ - if (host.motdfile) - talloc_free(host.motdfile); - host.motdfile = talloc_strdup(tall_vty_cmd_ctx, argv[0]); - - return CMD_SUCCESS; -} - -DEFUN(banner_motd_default, - banner_motd_default_cmd, - "banner motd default", - "Set banner string\n" "Strings for motd\n" "Default string\n") -{ - host.motd = default_motd; - return CMD_SUCCESS; -} - -DEFUN(no_banner_motd, - no_banner_motd_cmd, - "no banner motd", NO_STR "Set banner string\n" "Strings for motd\n") -{ - host.motd = NULL; - if (host.motdfile) - talloc_free(host.motdfile); - host.motdfile = NULL; - return CMD_SUCCESS; -} - -/* Set config filename. Called from vty.c */ -void host_config_set(const char *filename) -{ - host.config = talloc_strdup(tall_vty_cmd_ctx, filename); -} - -void install_default(enum node_type node) -{ - install_element(node, &config_help_cmd); - install_element(node, &config_list_cmd); - - install_element(node, &config_write_terminal_cmd); - install_element(node, &config_write_file_cmd); - install_element(node, &config_write_memory_cmd); - install_element(node, &config_write_cmd); - install_element(node, &show_running_config_cmd); -} - -/* Initialize command interface. Install basic nodes and commands. */ -void cmd_init(int terminal) -{ - /* Allocate initial top vector of commands. */ - cmdvec = vector_init(VECTOR_MIN_SIZE); - - /* Default host value settings. */ - host.name = NULL; - host.password = NULL; - host.enable = NULL; - host.logfile = NULL; - host.config = NULL; - host.lines = -1; - host.motd = default_motd; - host.motdfile = NULL; - - /* Install top nodes. */ - install_node(&view_node, NULL); - install_node(&enable_node, NULL); - install_node(&auth_node, NULL); - install_node(&auth_enable_node, NULL); - install_node(&config_node, config_write_host); - - /* Each node's basic commands. */ - install_element(VIEW_NODE, &show_version_cmd); - if (terminal) { - install_element(VIEW_NODE, &config_list_cmd); - install_element(VIEW_NODE, &config_exit_cmd); - install_element(VIEW_NODE, &config_help_cmd); - install_element(VIEW_NODE, &config_enable_cmd); - install_element(VIEW_NODE, &config_terminal_length_cmd); - install_element(VIEW_NODE, &config_terminal_no_length_cmd); - install_element(VIEW_NODE, &echo_cmd); - } - - if (terminal) { - install_element(ENABLE_NODE, &config_exit_cmd); - install_default(ENABLE_NODE); - install_element(ENABLE_NODE, &config_disable_cmd); - install_element(ENABLE_NODE, &config_terminal_cmd); - install_element (ENABLE_NODE, ©_runningconfig_startupconfig_cmd); - } - install_element (ENABLE_NODE, &show_startup_config_cmd); - install_element(ENABLE_NODE, &show_version_cmd); - - if (terminal) { - install_element(ENABLE_NODE, &config_terminal_length_cmd); - install_element(ENABLE_NODE, &config_terminal_no_length_cmd); - install_element(ENABLE_NODE, &echo_cmd); - - install_default(CONFIG_NODE); - install_element(CONFIG_NODE, &config_exit_cmd); - } - - install_element(CONFIG_NODE, &hostname_cmd); - install_element(CONFIG_NODE, &no_hostname_cmd); - - if (terminal) { - install_element(CONFIG_NODE, &password_cmd); - install_element(CONFIG_NODE, &password_text_cmd); - install_element(CONFIG_NODE, &enable_password_cmd); - install_element(CONFIG_NODE, &enable_password_text_cmd); - install_element(CONFIG_NODE, &no_enable_password_cmd); - -#ifdef VTY_CRYPT_PW - install_element(CONFIG_NODE, &service_password_encrypt_cmd); - install_element(CONFIG_NODE, &no_service_password_encrypt_cmd); -#endif - install_element(CONFIG_NODE, &banner_motd_default_cmd); - install_element(CONFIG_NODE, &banner_motd_file_cmd); - install_element(CONFIG_NODE, &no_banner_motd_cmd); - install_element(CONFIG_NODE, &service_terminal_length_cmd); - install_element(CONFIG_NODE, &no_service_terminal_length_cmd); - - } - srand(time(NULL)); -} diff --git a/libosmocore/src/vty/logging_vty.c b/libosmocore/src/vty/logging_vty.c deleted file mode 100644 index 896d79a96..000000000 --- a/libosmocore/src/vty/logging_vty.c +++ /dev/null @@ -1,347 +0,0 @@ -/* 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); -} diff --git a/libosmocore/src/vty/telnet_interface.c b/libosmocore/src/vty/telnet_interface.c deleted file mode 100644 index 906909600..000000000 --- a/libosmocore/src/vty/telnet_interface.c +++ /dev/null @@ -1,203 +0,0 @@ -/* 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; - } -} - diff --git a/libosmocore/src/vty/utils.c b/libosmocore/src/vty/utils.c deleted file mode 100644 index e163526ee..000000000 --- a/libosmocore/src/vty/utils.c +++ /dev/null @@ -1,50 +0,0 @@ -/* 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); - }; -} diff --git a/libosmocore/src/vty/vector.c b/libosmocore/src/vty/vector.c deleted file mode 100644 index 0343163f6..000000000 --- a/libosmocore/src/vty/vector.c +++ /dev/null @@ -1,192 +0,0 @@ -/* Generic vector interface routine - * Copyright (C) 1997 Kunihiro Ishiguro - * - * This file is part of GNU Zebra. - * - * GNU Zebra is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * GNU Zebra is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Zebra; see the file COPYING. If not, write to the Free - * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include <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; -} diff --git a/libosmocore/src/vty/vty.c b/libosmocore/src/vty/vty.c deleted file mode 100644 index ff17abf61..000000000 --- a/libosmocore/src/vty/vty.c +++ /dev/null @@ -1,1683 +0,0 @@ - -#include <stdio.h> -#include <stdarg.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <ctype.h> -#include <termios.h> - -#include <sys/utsname.h> -#include <sys/param.h> - -#include <arpa/telnet.h> - -#include <osmocom/vty/vty.h> -#include <osmocom/vty/command.h> -#include <osmocom/vty/buffer.h> -#include <osmocore/talloc.h> - -#define SYSCONFDIR "/usr/local/etc" - -/* our callback, located in telnet_interface.c */ -void vty_event(enum event event, int sock, struct vty *vty); - -extern struct host host; - -/* Vector which store each vty structure. */ -static vector vtyvec; - -vector Vvty_serv_thread; - -char *vty_cwd = NULL; - -/* Configure lock. */ -static int vty_config; - -static int no_password_check = 1; - -void *tall_vty_ctx; - -static void vty_clear_buf(struct vty *vty) -{ - memset(vty->buf, 0, vty->max); -} - -/* Allocate new vty struct. */ -struct vty *vty_new() -{ - struct vty *new = talloc_zero(tall_vty_ctx, struct vty); - - if (!new) - goto out; - - new->obuf = buffer_new(new, 0); /* Use default buffer size. */ - if (!new->obuf) - goto out_new; - new->buf = _talloc_zero(new, VTY_BUFSIZ, "vty_new->buf"); - if (!new->buf) - goto out_obuf; - - new->max = VTY_BUFSIZ; - - return new; - -out_obuf: - buffer_free(new->obuf); -out_new: - talloc_free(new); - new = NULL; -out: - return new; -} - -/* Authentication of vty */ -static void vty_auth(struct vty *vty, char *buf) -{ - char *passwd = NULL; - enum node_type next_node = 0; - int fail; - char *crypt(const char *, const char *); - - switch (vty->node) { - case AUTH_NODE: -#ifdef VTY_CRYPT_PW - if (host.encrypt) - passwd = host.password_encrypt; - else -#endif - passwd = host.password; - if (host.advanced) - next_node = host.enable ? VIEW_NODE : ENABLE_NODE; - else - next_node = VIEW_NODE; - break; - case AUTH_ENABLE_NODE: -#ifdef VTY_CRYPT_PW - if (host.encrypt) - passwd = host.enable_encrypt; - else -#endif - passwd = host.enable; - next_node = ENABLE_NODE; - break; - } - - if (passwd) { -#ifdef VTY_CRYPT_PW - if (host.encrypt) - fail = strcmp(crypt(buf, passwd), passwd); - else -#endif - fail = strcmp(buf, passwd); - } else - fail = 1; - - if (!fail) { - vty->fail = 0; - vty->node = next_node; /* Success ! */ - } else { - vty->fail++; - if (vty->fail >= 3) { - if (vty->node == AUTH_NODE) { - vty_out(vty, - "%% Bad passwords, too many failures!%s", - VTY_NEWLINE); - vty->status = VTY_CLOSE; - } else { - /* AUTH_ENABLE_NODE */ - vty->fail = 0; - vty_out(vty, - "%% Bad enable passwords, too many failures!%s", - VTY_NEWLINE); - vty->node = VIEW_NODE; - } - } - } -} - -/* Close vty interface. */ -void vty_close(struct vty *vty) -{ - int i; - - if (vty->obuf) { - /* Flush buffer. */ - buffer_flush_all(vty->obuf, vty->fd); - - /* Free input buffer. */ - buffer_free(vty->obuf); - vty->obuf = NULL; - } - - /* Free command history. */ - for (i = 0; i < VTY_MAXHIST; i++) - if (vty->hist[i]) - talloc_free(vty->hist[i]); - - /* Unset vector. */ - vector_unset(vtyvec, vty->fd); - - /* Close socket. */ - if (vty->fd > 0) - close(vty->fd); - - if (vty->buf) { - talloc_free(vty->buf); - vty->buf = NULL; - } - - /* Check configure. */ - vty_config_unlock(vty); - - /* VTY_CLOSED is handled by the telnet_interface */ - vty_event(VTY_CLOSED, vty->fd, vty); - - /* OK free vty. */ - talloc_free(vty); -} - -int vty_shell(struct vty *vty) -{ - return vty->type == VTY_SHELL ? 1 : 0; -} - - -/* VTY standard output function. */ -int vty_out(struct vty *vty, const char *format, ...) -{ - va_list args; - int len = 0; - int size = 1024; - char buf[1024]; - char *p = NULL; - - if (vty_shell(vty)) { - va_start(args, format); - vprintf(format, args); - va_end(args); - } else { - /* Try to write to initial buffer. */ - va_start(args, format); - len = vsnprintf(buf, sizeof buf, format, args); - va_end(args); - - /* Initial buffer is not enough. */ - if (len < 0 || len >= size) { - while (1) { - if (len > -1) - size = len + 1; - else - size = size * 2; - - p = talloc_realloc_size(vty, p, size); - if (!p) - return -1; - - va_start(args, format); - len = vsnprintf(p, size, format, args); - va_end(args); - - if (len > -1 && len < size) - break; - } - } - - /* When initial buffer is enough to store all output. */ - if (!p) - p = buf; - - /* Pointer p must point out buffer. */ - buffer_put(vty->obuf, (u_char *) p, len); - - /* If p is not different with buf, it is allocated buffer. */ - if (p != buf) - talloc_free(p); - } - - vty_event(VTY_WRITE, vty->fd, vty); - - return len; -} - -int vty_out_newline(struct vty *vty) -{ - char *p = vty_newline(vty); - buffer_put(vty->obuf, p, strlen(p)); - return 0; -} - -int vty_config_lock(struct vty *vty) -{ - if (vty_config == 0) { - vty->config = 1; - vty_config = 1; - } - return vty->config; -} - -int vty_config_unlock(struct vty *vty) -{ - if (vty_config == 1 && vty->config == 1) { - vty->config = 0; - vty_config = 0; - } - return vty->config; -} - -/* Say hello to vty interface. */ -void vty_hello(struct vty *vty) -{ - if (host.motdfile) { - FILE *f; - char buf[4096]; - - f = fopen(host.motdfile, "r"); - if (f) { - while (fgets(buf, sizeof(buf), f)) { - char *s; - /* work backwards to ignore trailling isspace() */ - for (s = buf + strlen(buf); - (s > buf) && isspace(*(s - 1)); s--) ; - *s = '\0'; - vty_out(vty, "%s%s", buf, VTY_NEWLINE); - } - fclose(f); - } else - vty_out(vty, "MOTD file not found%s", VTY_NEWLINE); - } else if (host.motd) - vty_out(vty, "%s", host.motd); -} - -/* Put out prompt and wait input from user. */ -static void vty_prompt(struct vty *vty) -{ - struct utsname names; - const char *hostname; - - if (vty->type == VTY_TERM) { - hostname = host.name; - if (!hostname) { - uname(&names); - hostname = names.nodename; - } - vty_out(vty, cmd_prompt(vty->node), hostname); - } -} - -/* Command execution over the vty interface. */ -static int vty_command(struct vty *vty, char *buf) -{ - int ret; - vector vline; - - /* Split readline string up into the vector */ - vline = cmd_make_strvec(buf); - - if (vline == NULL) - return CMD_SUCCESS; - - ret = cmd_execute_command(vline, vty, NULL, 0); - if (ret != CMD_SUCCESS) - switch (ret) { - case CMD_WARNING: - if (vty->type == VTY_FILE) - vty_out(vty, "Warning...%s", VTY_NEWLINE); - break; - case CMD_ERR_AMBIGUOUS: - vty_out(vty, "%% Ambiguous command.%s", VTY_NEWLINE); - break; - case CMD_ERR_NO_MATCH: - vty_out(vty, "%% Unknown command.%s", VTY_NEWLINE); - break; - case CMD_ERR_INCOMPLETE: - vty_out(vty, "%% Command incomplete.%s", VTY_NEWLINE); - break; - } - cmd_free_strvec(vline); - - return ret; -} - -static const char telnet_backward_char = 0x08; -static const char telnet_space_char = ' '; - -/* Basic function to write buffer to vty. */ -static void vty_write(struct vty *vty, const char *buf, size_t nbytes) -{ - if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE)) - return; - - /* Should we do buffering here ? And make vty_flush (vty) ? */ - buffer_put(vty->obuf, buf, nbytes); -} - -/* Ensure length of input buffer. Is buffer is short, double it. */ -static void vty_ensure(struct vty *vty, int length) -{ - if (vty->max <= length) { - vty->max *= 2; - vty->buf = talloc_realloc_size(vty, vty->buf, vty->max); - // FIXME: check return - } -} - -/* Basic function to insert character into vty. */ -static void vty_self_insert(struct vty *vty, char c) -{ - int i; - int length; - - vty_ensure(vty, vty->length + 1); - length = vty->length - vty->cp; - memmove(&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length); - vty->buf[vty->cp] = c; - - vty_write(vty, &vty->buf[vty->cp], length + 1); - for (i = 0; i < length; i++) - vty_write(vty, &telnet_backward_char, 1); - - vty->cp++; - vty->length++; -} - -/* Self insert character 'c' in overwrite mode. */ -static void vty_self_insert_overwrite(struct vty *vty, char c) -{ - vty_ensure(vty, vty->length + 1); - vty->buf[vty->cp++] = c; - - if (vty->cp > vty->length) - vty->length++; - - if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE)) - return; - - vty_write(vty, &c, 1); -} - -/* Insert a word into vty interface with overwrite mode. */ -static void vty_insert_word_overwrite(struct vty *vty, char *str) -{ - int len = strlen(str); - vty_write(vty, str, len); - strcpy(&vty->buf[vty->cp], str); - vty->cp += len; - vty->length = vty->cp; -} - -/* Forward character. */ -static void vty_forward_char(struct vty *vty) -{ - if (vty->cp < vty->length) { - vty_write(vty, &vty->buf[vty->cp], 1); - vty->cp++; - } -} - -/* Backward character. */ -static void vty_backward_char(struct vty *vty) -{ - if (vty->cp > 0) { - vty->cp--; - vty_write(vty, &telnet_backward_char, 1); - } -} - -/* Move to the beginning of the line. */ -static void vty_beginning_of_line(struct vty *vty) -{ - while (vty->cp) - vty_backward_char(vty); -} - -/* Move to the end of the line. */ -static void vty_end_of_line(struct vty *vty) -{ - while (vty->cp < vty->length) - vty_forward_char(vty); -} - -/* Add current command line to the history buffer. */ -static void vty_hist_add(struct vty *vty) -{ - int index; - - if (vty->length == 0) - return; - - index = vty->hindex ? vty->hindex - 1 : VTY_MAXHIST - 1; - - /* Ignore the same string as previous one. */ - if (vty->hist[index]) - if (strcmp(vty->buf, vty->hist[index]) == 0) { - vty->hp = vty->hindex; - return; - } - - /* Insert history entry. */ - if (vty->hist[vty->hindex]) - talloc_free(vty->hist[vty->hindex]); - vty->hist[vty->hindex] = talloc_strdup(vty, vty->buf); - - /* History index rotation. */ - vty->hindex++; - if (vty->hindex == VTY_MAXHIST) - vty->hindex = 0; - - vty->hp = vty->hindex; -} - -/* Get telnet window size. */ -static int -vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes) -{ -#ifdef TELNET_OPTION_DEBUG - int i; - - for (i = 0; i < nbytes; i++) - { - switch (buf[i]) - { - case IAC: - vty_out (vty, "IAC "); - break; - case WILL: - vty_out (vty, "WILL "); - break; - case WONT: - vty_out (vty, "WONT "); - break; - case DO: - vty_out (vty, "DO "); - break; - case DONT: - vty_out (vty, "DONT "); - break; - case SB: - vty_out (vty, "SB "); - break; - case SE: - vty_out (vty, "SE "); - break; - case TELOPT_ECHO: - vty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE); - break; - case TELOPT_SGA: - vty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE); - break; - case TELOPT_NAWS: - vty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE); - break; - default: - vty_out (vty, "%x ", buf[i]); - break; - } - } - vty_out (vty, "%s", VTY_NEWLINE); - -#endif /* TELNET_OPTION_DEBUG */ - - switch (buf[0]) - { - case SB: - vty->sb_len = 0; - vty->iac_sb_in_progress = 1; - return 0; - break; - case SE: - { - if (!vty->iac_sb_in_progress) - return 0; - - if ((vty->sb_len == 0) || (vty->sb_buf[0] == '\0')) - { - vty->iac_sb_in_progress = 0; - return 0; - } - switch (vty->sb_buf[0]) - { - case TELOPT_NAWS: - if (vty->sb_len != TELNET_NAWS_SB_LEN) - vty_out(vty,"RFC 1073 violation detected: telnet NAWS option " - "should send %d characters, but we received %lu", - TELNET_NAWS_SB_LEN, (u_long)vty->sb_len); - else if (sizeof(vty->sb_buf) < TELNET_NAWS_SB_LEN) - vty_out(vty, "Bug detected: sizeof(vty->sb_buf) %lu < %d, " - "too small to handle the telnet NAWS option", - (u_long)sizeof(vty->sb_buf), TELNET_NAWS_SB_LEN); - else - { - vty->width = ((vty->sb_buf[1] << 8)|vty->sb_buf[2]); - vty->height = ((vty->sb_buf[3] << 8)|vty->sb_buf[4]); -#ifdef TELNET_OPTION_DEBUG - vty_out(vty, "TELNET NAWS window size negotiation completed: " - "width %d, height %d%s", - vty->width, vty->height, VTY_NEWLINE); -#endif - } - break; - } - vty->iac_sb_in_progress = 0; - return 0; - break; - } - default: - break; - } - return 1; -} - -/* Execute current command line. */ -static int vty_execute(struct vty *vty) -{ - int ret; - - ret = CMD_SUCCESS; - - switch (vty->node) { - case AUTH_NODE: - case AUTH_ENABLE_NODE: - vty_auth(vty, vty->buf); - break; - default: - ret = vty_command(vty, vty->buf); - if (vty->type == VTY_TERM) - vty_hist_add(vty); - break; - } - - /* Clear command line buffer. */ - vty->cp = vty->length = 0; - vty_clear_buf(vty); - - if (vty->status != VTY_CLOSE) - vty_prompt(vty); - - return ret; -} - -/* Send WILL TELOPT_ECHO to remote server. */ -static void -vty_will_echo (struct vty *vty) -{ - unsigned char cmd[] = { IAC, WILL, TELOPT_ECHO, '\0' }; - vty_out (vty, "%s", cmd); -} - -/* Make suppress Go-Ahead telnet option. */ -static void -vty_will_suppress_go_ahead (struct vty *vty) -{ - unsigned char cmd[] = { IAC, WILL, TELOPT_SGA, '\0' }; - vty_out (vty, "%s", cmd); -} - -/* Make don't use linemode over telnet. */ -static void -vty_dont_linemode (struct vty *vty) -{ - unsigned char cmd[] = { IAC, DONT, TELOPT_LINEMODE, '\0' }; - vty_out (vty, "%s", cmd); -} - -/* Use window size. */ -static void -vty_do_window_size (struct vty *vty) -{ - unsigned char cmd[] = { IAC, DO, TELOPT_NAWS, '\0' }; - vty_out (vty, "%s", cmd); -} - -static void vty_kill_line_from_beginning(struct vty *); -static void vty_redraw_line(struct vty *); - -/* Print command line history. This function is called from - vty_next_line and vty_previous_line. */ -static void vty_history_print(struct vty *vty) -{ - int length; - - vty_kill_line_from_beginning(vty); - - /* Get previous line from history buffer */ - length = strlen(vty->hist[vty->hp]); - memcpy(vty->buf, vty->hist[vty->hp], length); - vty->cp = vty->length = length; - - /* Redraw current line */ - vty_redraw_line(vty); -} - -/* Show next command line history. */ -static void vty_next_line(struct vty *vty) -{ - int try_index; - - if (vty->hp == vty->hindex) - return; - - /* Try is there history exist or not. */ - try_index = vty->hp; - if (try_index == (VTY_MAXHIST - 1)) - try_index = 0; - else - try_index++; - - /* If there is not history return. */ - if (vty->hist[try_index] == NULL) - return; - else - vty->hp = try_index; - - vty_history_print(vty); -} - -/* Show previous command line history. */ -static void vty_previous_line(struct vty *vty) -{ - int try_index; - - try_index = vty->hp; - if (try_index == 0) - try_index = VTY_MAXHIST - 1; - else - try_index--; - - if (vty->hist[try_index] == NULL) - return; - else - vty->hp = try_index; - - vty_history_print(vty); -} - -/* This function redraw all of the command line character. */ -static void vty_redraw_line(struct vty *vty) -{ - vty_write(vty, vty->buf, vty->length); - vty->cp = vty->length; -} - -/* Forward word. */ -static void vty_forward_word(struct vty *vty) -{ - while (vty->cp != vty->length && vty->buf[vty->cp] != ' ') - vty_forward_char(vty); - - while (vty->cp != vty->length && vty->buf[vty->cp] == ' ') - vty_forward_char(vty); -} - -/* Backward word without skipping training space. */ -static void vty_backward_pure_word(struct vty *vty) -{ - while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ') - vty_backward_char(vty); -} - -/* Backward word. */ -static void vty_backward_word(struct vty *vty) -{ - while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ') - vty_backward_char(vty); - - while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ') - vty_backward_char(vty); -} - -/* When '^D' is typed at the beginning of the line we move to the down - level. */ -static void vty_down_level(struct vty *vty) -{ - vty_out(vty, "%s", VTY_NEWLINE); - /* FIXME: we need to call the exit function of the specific node - * in question, not this generic one that doesn't know all nodes */ - (*config_exit_cmd.func) (NULL, vty, 0, NULL); - vty_prompt(vty); - vty->cp = 0; -} - -/* When '^Z' is received from vty, move down to the enable mode. */ -static void vty_end_config(struct vty *vty) -{ - vty_out(vty, "%s", VTY_NEWLINE); - - /* FIXME: we need to call the exit function of the specific node - * in question, not this generic one that doesn't know all nodes */ - switch (vty->node) { - case VIEW_NODE: - case ENABLE_NODE: - /* Nothing to do. */ - break; - case CONFIG_NODE: - case VTY_NODE: - vty_config_unlock(vty); - vty->node = ENABLE_NODE; - break; - default: - /* Unknown node, we have to ignore it. */ - break; - } - - vty_prompt(vty); - vty->cp = 0; -} - -/* Delete a charcter at the current point. */ -static void vty_delete_char(struct vty *vty) -{ - int i; - int size; - - if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE) - return; - - if (vty->length == 0) { - vty_down_level(vty); - return; - } - - if (vty->cp == vty->length) - return; /* completion need here? */ - - size = vty->length - vty->cp; - - vty->length--; - memmove(&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1); - vty->buf[vty->length] = '\0'; - - vty_write(vty, &vty->buf[vty->cp], size - 1); - vty_write(vty, &telnet_space_char, 1); - - for (i = 0; i < size; i++) - vty_write(vty, &telnet_backward_char, 1); -} - -/* Delete a character before the point. */ -static void vty_delete_backward_char(struct vty *vty) -{ - if (vty->cp == 0) - return; - - vty_backward_char(vty); - vty_delete_char(vty); -} - -/* Kill rest of line from current point. */ -static void vty_kill_line(struct vty *vty) -{ - int i; - int size; - - size = vty->length - vty->cp; - - if (size == 0) - return; - - for (i = 0; i < size; i++) - vty_write(vty, &telnet_space_char, 1); - for (i = 0; i < size; i++) - vty_write(vty, &telnet_backward_char, 1); - - memset(&vty->buf[vty->cp], 0, size); - vty->length = vty->cp; -} - -/* Kill line from the beginning. */ -static void vty_kill_line_from_beginning(struct vty *vty) -{ - vty_beginning_of_line(vty); - vty_kill_line(vty); -} - -/* Delete a word before the point. */ -static void vty_forward_kill_word(struct vty *vty) -{ - while (vty->cp != vty->length && vty->buf[vty->cp] == ' ') - vty_delete_char(vty); - while (vty->cp != vty->length && vty->buf[vty->cp] != ' ') - vty_delete_char(vty); -} - -/* Delete a word before the point. */ -static void vty_backward_kill_word(struct vty *vty) -{ - while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ') - vty_delete_backward_char(vty); - while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ') - vty_delete_backward_char(vty); -} - -/* Transpose chars before or at the point. */ -static void vty_transpose_chars(struct vty *vty) -{ - char c1, c2; - - /* If length is short or point is near by the beginning of line then - return. */ - if (vty->length < 2 || vty->cp < 1) - return; - - /* In case of point is located at the end of the line. */ - if (vty->cp == vty->length) { - c1 = vty->buf[vty->cp - 1]; - c2 = vty->buf[vty->cp - 2]; - - vty_backward_char(vty); - vty_backward_char(vty); - vty_self_insert_overwrite(vty, c1); - vty_self_insert_overwrite(vty, c2); - } else { - c1 = vty->buf[vty->cp]; - c2 = vty->buf[vty->cp - 1]; - - vty_backward_char(vty); - vty_self_insert_overwrite(vty, c1); - vty_self_insert_overwrite(vty, c2); - } -} - -/* Do completion at vty interface. */ -static void vty_complete_command(struct vty *vty) -{ - int i; - int ret; - char **matched = NULL; - vector vline; - - if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE) - return; - - vline = cmd_make_strvec(vty->buf); - if (vline == NULL) - return; - - /* In case of 'help \t'. */ - if (isspace((int)vty->buf[vty->length - 1])) - vector_set(vline, '\0'); - - matched = cmd_complete_command(vline, vty, &ret); - - cmd_free_strvec(vline); - - vty_out(vty, "%s", VTY_NEWLINE); - switch (ret) { - case CMD_ERR_AMBIGUOUS: - vty_out(vty, "%% Ambiguous command.%s", VTY_NEWLINE); - vty_prompt(vty); - vty_redraw_line(vty); - break; - case CMD_ERR_NO_MATCH: - /* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */ - vty_prompt(vty); - vty_redraw_line(vty); - break; - case CMD_COMPLETE_FULL_MATCH: - vty_prompt(vty); - vty_redraw_line(vty); - vty_backward_pure_word(vty); - vty_insert_word_overwrite(vty, matched[0]); - vty_self_insert(vty, ' '); - talloc_free(matched[0]); - break; - case CMD_COMPLETE_MATCH: - vty_prompt(vty); - vty_redraw_line(vty); - vty_backward_pure_word(vty); - vty_insert_word_overwrite(vty, matched[0]); - talloc_free(matched[0]); - break; - case CMD_COMPLETE_LIST_MATCH: - for (i = 0; matched[i] != NULL; i++) { - if (i != 0 && ((i % 6) == 0)) - vty_out(vty, "%s", VTY_NEWLINE); - vty_out(vty, "%-10s ", matched[i]); - talloc_free(matched[i]); - } - vty_out(vty, "%s", VTY_NEWLINE); - - vty_prompt(vty); - vty_redraw_line(vty); - break; - case CMD_ERR_NOTHING_TODO: - vty_prompt(vty); - vty_redraw_line(vty); - break; - default: - break; - } - if (matched) - vector_only_index_free(matched); -} - -static void -vty_describe_fold(struct vty *vty, int cmd_width, - unsigned int desc_width, struct desc *desc) -{ - char *buf; - const char *cmd, *p; - int pos; - - cmd = desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd; - - if (desc_width <= 0) { - vty_out(vty, " %-*s %s%s", cmd_width, cmd, desc->str, - VTY_NEWLINE); - return; - } - - buf = _talloc_zero(vty, strlen(desc->str) + 1, "describe_fold"); - if (!buf) - return; - - for (p = desc->str; strlen(p) > desc_width; p += pos + 1) { - for (pos = desc_width; pos > 0; pos--) - if (*(p + pos) == ' ') - break; - - if (pos == 0) - break; - - strncpy(buf, p, pos); - buf[pos] = '\0'; - vty_out(vty, " %-*s %s%s", cmd_width, cmd, buf, VTY_NEWLINE); - - cmd = ""; - } - - vty_out(vty, " %-*s %s%s", cmd_width, cmd, p, VTY_NEWLINE); - - talloc_free(buf); -} - -/* Describe matched command function. */ -static void vty_describe_command(struct vty *vty) -{ - int ret; - vector vline; - vector describe; - unsigned int i, width, desc_width; - struct desc *desc, *desc_cr = NULL; - - vline = cmd_make_strvec(vty->buf); - - /* In case of '> ?'. */ - if (vline == NULL) { - vline = vector_init(1); - vector_set(vline, '\0'); - } else if (isspace((int)vty->buf[vty->length - 1])) - vector_set(vline, '\0'); - - describe = cmd_describe_command(vline, vty, &ret); - - vty_out(vty, "%s", VTY_NEWLINE); - - /* Ambiguous error. */ - switch (ret) { - case CMD_ERR_AMBIGUOUS: - cmd_free_strvec(vline); - vty_out(vty, "%% Ambiguous command.%s", VTY_NEWLINE); - vty_prompt(vty); - vty_redraw_line(vty); - return; - break; - case CMD_ERR_NO_MATCH: - cmd_free_strvec(vline); - vty_out(vty, "%% There is no matched command.%s", VTY_NEWLINE); - vty_prompt(vty); - vty_redraw_line(vty); - return; - break; - } - - /* Get width of command string. */ - width = 0; - for (i = 0; i < vector_active(describe); i++) - if ((desc = vector_slot(describe, i)) != NULL) { - unsigned int len; - - if (desc->cmd[0] == '\0') - continue; - - len = strlen(desc->cmd); - if (desc->cmd[0] == '.') - len--; - - if (width < len) - width = len; - } - - /* Get width of description string. */ - desc_width = vty->width - (width + 6); - - /* Print out description. */ - for (i = 0; i < vector_active(describe); i++) - if ((desc = vector_slot(describe, i)) != NULL) { - if (desc->cmd[0] == '\0') - continue; - - if (strcmp(desc->cmd, "<cr>") == 0) { - desc_cr = desc; - continue; - } - - if (!desc->str) - vty_out(vty, " %-s%s", - desc->cmd[0] == - '.' ? desc->cmd + 1 : desc->cmd, - VTY_NEWLINE); - else if (desc_width >= strlen(desc->str)) - vty_out(vty, " %-*s %s%s", width, - desc->cmd[0] == - '.' ? desc->cmd + 1 : desc->cmd, - desc->str, VTY_NEWLINE); - else - vty_describe_fold(vty, width, desc_width, desc); - -#if 0 - vty_out(vty, " %-*s %s%s", width - desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, - desc->str ? desc->str : "", VTY_NEWLINE); -#endif /* 0 */ - } - - if ((desc = desc_cr)) { - if (!desc->str) - vty_out(vty, " %-s%s", - desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, - VTY_NEWLINE); - else if (desc_width >= strlen(desc->str)) - vty_out(vty, " %-*s %s%s", width, - desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, - desc->str, VTY_NEWLINE); - else - vty_describe_fold(vty, width, desc_width, desc); - } - - cmd_free_strvec(vline); - vector_free(describe); - - vty_prompt(vty); - vty_redraw_line(vty); -} - -/* ^C stop current input and do not add command line to the history. */ -static void vty_stop_input(struct vty *vty) -{ - vty->cp = vty->length = 0; - vty_clear_buf(vty); - vty_out(vty, "%s", VTY_NEWLINE); - - switch (vty->node) { - case VIEW_NODE: - case ENABLE_NODE: - /* Nothing to do. */ - break; - case CONFIG_NODE: - case VTY_NODE: - vty_config_unlock(vty); - vty->node = ENABLE_NODE; - break; - default: - /* Unknown node, we have to ignore it. */ - break; - } - vty_prompt(vty); - - /* Set history pointer to the latest one. */ - vty->hp = vty->hindex; -} - -#define CONTROL(X) ((X) - '@') -#define VTY_NORMAL 0 -#define VTY_PRE_ESCAPE 1 -#define VTY_ESCAPE 2 - -/* Escape character command map. */ -static void vty_escape_map(unsigned char c, struct vty *vty) -{ - switch (c) { - case ('A'): - vty_previous_line(vty); - break; - case ('B'): - vty_next_line(vty); - break; - case ('C'): - vty_forward_char(vty); - break; - case ('D'): - vty_backward_char(vty); - break; - default: - break; - } - - /* Go back to normal mode. */ - vty->escape = VTY_NORMAL; -} - -/* Quit print out to the buffer. */ -static void vty_buffer_reset(struct vty *vty) -{ - buffer_reset(vty->obuf); - vty_prompt(vty); - vty_redraw_line(vty); -} - -/* Read data via vty socket. */ -int vty_read(struct vty *vty) -{ - int i; - int nbytes; - unsigned char buf[VTY_READ_BUFSIZ]; - - int vty_sock = vty->fd; - - /* Read raw data from socket */ - if ((nbytes = read(vty->fd, buf, VTY_READ_BUFSIZ)) <= 0) { - if (nbytes < 0) { - if (ERRNO_IO_RETRY(errno)) { - vty_event(VTY_READ, vty_sock, vty); - return 0; - } - } - buffer_reset(vty->obuf); - vty->status = VTY_CLOSE; - } - - for (i = 0; i < nbytes; i++) { - if (buf[i] == IAC) { - if (!vty->iac) { - vty->iac = 1; - continue; - } else { - vty->iac = 0; - } - } - - if (vty->iac_sb_in_progress && !vty->iac) { - if (vty->sb_len < sizeof(vty->sb_buf)) - vty->sb_buf[vty->sb_len] = buf[i]; - vty->sb_len++; - continue; - } - - if (vty->iac) { - /* In case of telnet command */ - int ret = 0; - ret = vty_telnet_option(vty, buf + i, nbytes - i); - vty->iac = 0; - i += ret; - continue; - } - - if (vty->status == VTY_MORE) { - switch (buf[i]) { - case CONTROL('C'): - case 'q': - case 'Q': - vty_buffer_reset(vty); - break; -#if 0 /* More line does not work for "show ip bgp". */ - case '\n': - case '\r': - vty->status = VTY_MORELINE; - break; -#endif - default: - break; - } - continue; - } - - /* Escape character. */ - if (vty->escape == VTY_ESCAPE) { - vty_escape_map(buf[i], vty); - continue; - } - - /* Pre-escape status. */ - if (vty->escape == VTY_PRE_ESCAPE) { - switch (buf[i]) { - case '[': - vty->escape = VTY_ESCAPE; - break; - case 'b': - vty_backward_word(vty); - vty->escape = VTY_NORMAL; - break; - case 'f': - vty_forward_word(vty); - vty->escape = VTY_NORMAL; - break; - case 'd': - vty_forward_kill_word(vty); - vty->escape = VTY_NORMAL; - break; - case CONTROL('H'): - case 0x7f: - vty_backward_kill_word(vty); - vty->escape = VTY_NORMAL; - break; - default: - vty->escape = VTY_NORMAL; - break; - } - continue; - } - - switch (buf[i]) { - case CONTROL('A'): - vty_beginning_of_line(vty); - break; - case CONTROL('B'): - vty_backward_char(vty); - break; - case CONTROL('C'): - vty_stop_input(vty); - break; - case CONTROL('D'): - vty_delete_char(vty); - break; - case CONTROL('E'): - vty_end_of_line(vty); - break; - case CONTROL('F'): - vty_forward_char(vty); - break; - case CONTROL('H'): - case 0x7f: - vty_delete_backward_char(vty); - break; - case CONTROL('K'): - vty_kill_line(vty); - break; - case CONTROL('N'): - vty_next_line(vty); - break; - case CONTROL('P'): - vty_previous_line(vty); - break; - case CONTROL('T'): - vty_transpose_chars(vty); - break; - case CONTROL('U'): - vty_kill_line_from_beginning(vty); - break; - case CONTROL('W'): - vty_backward_kill_word(vty); - break; - case CONTROL('Z'): - vty_end_config(vty); - break; - case '\n': - case '\r': - vty_out(vty, "%s", VTY_NEWLINE); - vty_execute(vty); - break; - case '\t': - vty_complete_command(vty); - break; - case '?': - if (vty->node == AUTH_NODE - || vty->node == AUTH_ENABLE_NODE) - vty_self_insert(vty, buf[i]); - else - vty_describe_command(vty); - break; - case '\033': - if (i + 1 < nbytes && buf[i + 1] == '[') { - vty->escape = VTY_ESCAPE; - i++; - } else - vty->escape = VTY_PRE_ESCAPE; - break; - default: - if (buf[i] > 31 && buf[i] < 127) - vty_self_insert(vty, buf[i]); - break; - } - } - - /* Check status. */ - if (vty->status == VTY_CLOSE) - vty_close(vty); - else { - vty_event(VTY_WRITE, vty_sock, vty); - vty_event(VTY_READ, vty_sock, vty); - } - return 0; -} - -/* Read up configuration file */ -static int -vty_read_file(FILE *confp, void *priv) -{ - int ret; - struct vty *vty; - - vty = vty_new(); - vty->fd = 0; - vty->type = VTY_FILE; - vty->node = CONFIG_NODE; - vty->priv = priv; - - ret = config_from_file(vty, confp); - - if (ret != CMD_SUCCESS) { - switch (ret) { - case CMD_ERR_AMBIGUOUS: - fprintf(stderr, "Ambiguous command.\n"); - break; - case CMD_ERR_NO_MATCH: - fprintf(stderr, "There is no such command.\n"); - break; - } - fprintf(stderr, "Error occurred during reading below " - "line:\n%s\n", vty->buf); - vty_close(vty); - return -EINVAL; - } - - vty_close(vty); - return 0; -} - -/* Create new vty structure. */ -struct vty * -vty_create (int vty_sock, void *priv) -{ - struct vty *vty; - - struct termios t; - - tcgetattr(vty_sock, &t); - cfmakeraw(&t); - tcsetattr(vty_sock, TCSANOW, &t); - - /* Allocate new vty structure and set up default values. */ - vty = vty_new (); - vty->fd = vty_sock; - vty->priv = priv; - vty->type = VTY_TERM; - if (no_password_check) - { - if (host.advanced) - vty->node = ENABLE_NODE; - else - vty->node = VIEW_NODE; - } - else - vty->node = AUTH_NODE; - vty->fail = 0; - vty->cp = 0; - vty_clear_buf (vty); - vty->length = 0; - memset (vty->hist, 0, sizeof (vty->hist)); - vty->hp = 0; - vty->hindex = 0; - vector_set_index (vtyvec, vty_sock, vty); - vty->status = VTY_NORMAL; - if (host.lines >= 0) - vty->lines = host.lines; - else - vty->lines = -1; - - if (! no_password_check) - { - /* Vty is not available if password isn't set. */ - if (host.password == NULL && host.password_encrypt == NULL) - { - vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE); - vty->status = VTY_CLOSE; - vty_close (vty); - return NULL; - } - } - - /* Say hello to the world. */ - vty_hello (vty); - if (! no_password_check) - vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); - - /* Setting up terminal. */ - vty_will_echo (vty); - vty_will_suppress_go_ahead (vty); - - vty_dont_linemode (vty); - vty_do_window_size (vty); - /* vty_dont_lflow_ahead (vty); */ - - vty_prompt (vty); - - /* Add read/write thread. */ - vty_event (VTY_WRITE, vty_sock, vty); - vty_event (VTY_READ, vty_sock, vty); - - return vty; -} - -DEFUN(config_who, config_who_cmd, "who", "Display who is on vty\n") -{ - unsigned int i; - struct vty *v; - - for (i = 0; i < vector_active(vtyvec); i++) - if ((v = vector_slot(vtyvec, i)) != NULL) - vty_out(vty, "%svty[%d] %s", - v->config ? "*" : " ", i, VTY_NEWLINE); - return CMD_SUCCESS; -} - -/* Move to vty configuration mode. */ -DEFUN(line_vty, - line_vty_cmd, - "line vty", "Configure a terminal line\n" "Virtual terminal\n") -{ - vty->node = VTY_NODE; - return CMD_SUCCESS; -} - -/* vty login. */ -DEFUN(vty_login, vty_login_cmd, "login", "Enable password checking\n") -{ - no_password_check = 0; - return CMD_SUCCESS; -} - -DEFUN(no_vty_login, - no_vty_login_cmd, "no login", NO_STR "Enable password checking\n") -{ - no_password_check = 1; - return CMD_SUCCESS; -} - -DEFUN(service_advanced_vty, - service_advanced_vty_cmd, - "service advanced-vty", - "Set up miscellaneous service\n" "Enable advanced mode vty interface\n") -{ - host.advanced = 1; - return CMD_SUCCESS; -} - -DEFUN(no_service_advanced_vty, - no_service_advanced_vty_cmd, - "no service advanced-vty", - NO_STR - "Set up miscellaneous service\n" "Enable advanced mode vty interface\n") -{ - host.advanced = 0; - return CMD_SUCCESS; -} - -DEFUN(terminal_monitor, - terminal_monitor_cmd, - "terminal monitor", - "Set terminal line parameters\n" - "Copy debug output to the current terminal line\n") -{ - vty->monitor = 1; - return CMD_SUCCESS; -} - -DEFUN(terminal_no_monitor, - terminal_no_monitor_cmd, - "terminal no monitor", - "Set terminal line parameters\n" - NO_STR "Copy debug output to the current terminal line\n") -{ - vty->monitor = 0; - return CMD_SUCCESS; -} - -DEFUN(show_history, - show_history_cmd, - "show history", SHOW_STR "Display the session command history\n") -{ - int index; - - for (index = vty->hindex + 1; index != vty->hindex;) { - if (index == VTY_MAXHIST) { - index = 0; - continue; - } - - if (vty->hist[index] != NULL) - vty_out(vty, " %s%s", vty->hist[index], VTY_NEWLINE); - - index++; - } - - return CMD_SUCCESS; -} - -/* Display current configuration. */ -static int vty_config_write(struct vty *vty) -{ - vty_out(vty, "line vty%s", VTY_NEWLINE); - - /* login */ - if (no_password_check) - vty_out(vty, " no login%s", VTY_NEWLINE); - - vty_out(vty, "!%s", VTY_NEWLINE); - - return CMD_SUCCESS; -} - -struct cmd_node vty_node = { - VTY_NODE, - "%s(config-line)# ", - 1, -}; - -/* Reset all VTY status. */ -void vty_reset() -{ - unsigned int i; - struct vty *vty; - struct thread *vty_serv_thread; - - for (i = 0; i < vector_active(vtyvec); i++) - if ((vty = vector_slot(vtyvec, i)) != NULL) { - buffer_reset(vty->obuf); - vty->status = VTY_CLOSE; - vty_close(vty); - } - - for (i = 0; i < vector_active(Vvty_serv_thread); i++) - if ((vty_serv_thread = - vector_slot(Vvty_serv_thread, i)) != NULL) { - //thread_cancel (vty_serv_thread); - vector_slot(Vvty_serv_thread, i) = NULL; - close(i); - } -} - -static void vty_save_cwd(void) -{ - char cwd[MAXPATHLEN]; - char *c ; - - c = getcwd(cwd, MAXPATHLEN); - - if (!c) { - if (chdir(SYSCONFDIR) != 0) - perror("chdir failed"); - if (getcwd(cwd, MAXPATHLEN) == NULL) - perror("getcwd failed"); - } - - vty_cwd = _talloc_zero(tall_vty_ctx, strlen(cwd) + 1, "save_cwd"); - strcpy(vty_cwd, cwd); -} - -char *vty_get_cwd() -{ - return vty_cwd; -} - -int vty_shell_serv(struct vty *vty) -{ - return vty->type == VTY_SHELL_SERV ? 1 : 0; -} - -void vty_init_vtysh() -{ - vtyvec = vector_init(VECTOR_MIN_SIZE); -} - -extern void *tall_bsc_ctx; -/* Install vty's own commands like `who' command. */ -void vty_init(struct vty_app_info *app_info) -{ - tall_vty_ctx = talloc_named_const(app_info->tall_ctx, 0, "vty"); - tall_vty_vec_ctx = talloc_named_const(tall_vty_ctx, 0, "vty_vector"); - tall_vty_cmd_ctx = talloc_named_const(tall_vty_ctx, 0, "vty_command"); - - cmd_init(1); - - host.app_info = app_info; - - /* For further configuration read, preserve current directory. */ - vty_save_cwd(); - - vtyvec = vector_init(VECTOR_MIN_SIZE); - - /* Install bgp top node. */ - install_node(&vty_node, vty_config_write); - - install_element_ve(&config_who_cmd); - install_element_ve(&show_history_cmd); - install_element(CONFIG_NODE, &line_vty_cmd); - install_element(CONFIG_NODE, &service_advanced_vty_cmd); - install_element(CONFIG_NODE, &no_service_advanced_vty_cmd); - install_element(CONFIG_NODE, &show_history_cmd); - install_element(ENABLE_NODE, &terminal_monitor_cmd); - install_element(ENABLE_NODE, &terminal_no_monitor_cmd); - - install_default(VTY_NODE); - install_element(VTY_NODE, &vty_login_cmd); - install_element(VTY_NODE, &no_vty_login_cmd); -} - -int vty_read_config_file(const char *file_name, void *priv) -{ - FILE *cfile; - int rc; - - cfile = fopen(file_name, "r"); - if (!cfile) - return -ENOENT; - - rc = vty_read_file(cfile, priv); - fclose(cfile); - - host_config_set(file_name); - - return rc; -} diff --git a/libosmocore/src/write_queue.c b/libosmocore/src/write_queue.c deleted file mode 100644 index 618a8c0b3..000000000 --- a/libosmocore/src/write_queue.c +++ /dev/null @@ -1,88 +0,0 @@ -/* Generic write queue implementation */ -/* - * (C) 2010 by Holger Hans Peter Freyther - * (C) 2010 by On-Waves - * - * 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 <osmocore/write_queue.h> - -int write_queue_bfd_cb(struct bsc_fd *fd, unsigned int what) -{ - struct write_queue *queue; - - queue = container_of(fd, struct write_queue, bfd); - - if (what & BSC_FD_READ) - queue->read_cb(fd); - - if (what & BSC_FD_EXCEPT) - queue->except_cb(fd); - - if (what & BSC_FD_WRITE) { - struct msgb *msg; - - fd->when &= ~BSC_FD_WRITE; - msg = msgb_dequeue(&queue->msg_queue); - if (!msg) - return -1; - - --queue->current_length; - queue->write_cb(fd, msg); - msgb_free(msg); - - if (!llist_empty(&queue->msg_queue)) - fd->when |= BSC_FD_WRITE; - } - - return 0; -} - -void write_queue_init(struct write_queue *queue, int max_length) -{ - queue->max_length = max_length; - queue->current_length = 0; - queue->read_cb = NULL; - queue->write_cb = NULL; - queue->bfd.cb = write_queue_bfd_cb; - INIT_LLIST_HEAD(&queue->msg_queue); -} - -int write_queue_enqueue(struct write_queue *queue, struct msgb *data) -{ -// if (queue->current_length + 1 >= queue->max_length) -// LOGP(DMSC, LOGL_ERROR, "The queue is full. Dropping not yet implemented.\n"); - - ++queue->current_length; - msgb_enqueue(&queue->msg_queue, data); - queue->bfd.when |= BSC_FD_WRITE; - - return 0; -} - -void write_queue_clear(struct write_queue *queue) -{ - while (!llist_empty(&queue->msg_queue)) { - struct msgb *msg = msgb_dequeue(&queue->msg_queue); - msgb_free(msg); - } - - queue->current_length = 0; - queue->bfd.when &= ~BSC_FD_WRITE; -} |