1/*
2 * Copyright (c) 2001-2002
3 *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4 * 	All rights reserved.
5 * Copyright (c) 2003-2004
6 *	Hartmut Brandt.
7 * 	All rights reserved.
8 *
9 * Author: Hartmut Brandt <harti@freebsd.org>
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD$");
35
36#include "atmconfig.h"
37#include "atmconfig_device.h"
38#include "private.h"
39#include "oid.h"
40
41#include <bsnmp/asn1.h>
42#include <bsnmp/snmp.h>
43#include <bsnmp/snmpclient.h>
44
45/*
46 * Description of the begemotAtmIfTable
47 */
48static const struct snmp_table atmif_table = {
49	OIDX_begemotAtmIfTable,
50	OIDX_begemotAtmIfTableLastChange, 2,
51	sizeof(struct atmif),
52	1, 0x7ffULL,
53	{
54	  { 0,
55	    SNMP_SYNTAX_INTEGER, offsetof(struct atmif, index) },
56	  { OID_begemotAtmIfName,
57	    SNMP_SYNTAX_OCTETSTRING, offsetof(struct atmif, ifname) },
58	  { OID_begemotAtmIfPcr,
59	    SNMP_SYNTAX_GAUGE, offsetof(struct atmif, pcr) },
60	  { OID_begemotAtmIfMedia,
61	    SNMP_SYNTAX_INTEGER, offsetof(struct atmif, media) },
62	  { OID_begemotAtmIfVpiBits,
63	    SNMP_SYNTAX_GAUGE, offsetof(struct atmif, vpi_bits) },
64	  { OID_begemotAtmIfVciBits,
65	    SNMP_SYNTAX_GAUGE, offsetof(struct atmif, vci_bits) },
66	  { OID_begemotAtmIfMaxVpcs,
67	    SNMP_SYNTAX_GAUGE, offsetof(struct atmif, max_vpcs) },
68	  { OID_begemotAtmIfMaxVccs,
69	    SNMP_SYNTAX_GAUGE, offsetof(struct atmif, max_vccs) },
70	  { OID_begemotAtmIfEsi,
71	    SNMP_SYNTAX_OCTETSTRING, offsetof(struct atmif, esi) },
72	  { OID_begemotAtmIfCarrierStatus,
73	    SNMP_SYNTAX_INTEGER, offsetof(struct atmif, carrier) },
74	  { OID_begemotAtmIfMode,
75	    SNMP_SYNTAX_INTEGER, offsetof(struct atmif, mode) },
76          { 0, SNMP_SYNTAX_NULL, 0 }
77	}
78};
79
80/* List of all ATM interfaces */
81struct atmif_list atmif_list = TAILQ_HEAD_INITIALIZER(atmif_list);
82
83/*
84 * ATM hardware table
85 */
86struct atmhw {
87	TAILQ_ENTRY(atmhw) link;
88	uint64_t	found;
89	int32_t		index;
90	u_char		*vendor;
91	size_t		vendorlen;
92	u_char		*device;
93	size_t		devicelen;
94	uint32_t	serial;
95	uint32_t	version;
96	uint32_t	soft_version;
97};
98TAILQ_HEAD(atmhw_list, atmhw);
99
100/* list of ATM hardware */
101static struct atmhw_list atmhw_list;
102
103/*
104 * Read ATM hardware table
105 */
106const struct snmp_table atmhw_table = {
107	OIDX_begemotAtmHWTable,
108	OIDX_begemotAtmIfTableLastChange, 2,
109	sizeof(struct atmhw),
110	1, 0x3fULL,
111	{
112	  { 0,
113	    SNMP_SYNTAX_INTEGER, offsetof(struct atmhw, index) },
114	  { OID_begemotAtmHWVendor,
115	    SNMP_SYNTAX_OCTETSTRING, offsetof(struct atmhw, vendor) },
116	  { OID_begemotAtmHWDevice,
117	    SNMP_SYNTAX_OCTETSTRING, offsetof(struct atmhw, device) },
118	  { OID_begemotAtmHWSerial,
119	    SNMP_SYNTAX_GAUGE, offsetof(struct atmhw, serial) },
120	  { OID_begemotAtmHWVersion,
121	    SNMP_SYNTAX_GAUGE, offsetof(struct atmhw, version) },
122	  { OID_begemotAtmHWSoftVersion,
123	    SNMP_SYNTAX_GAUGE, offsetof(struct atmhw, soft_version) },
124          { 0, SNMP_SYNTAX_NULL, 0 }
125	}
126};
127
128static void device_status(int, char *[]);
129static void device_hardware(int, char *[]);
130static void device_modify(int, char *[]);
131
132static const struct cmdtab device_tab[] = {
133	{ "hardware",	NULL,	device_hardware },
134 	{ "status",	NULL,	device_status },
135 	{ "modify",	NULL,	device_modify },
136	{ NULL,		NULL,	NULL }
137};
138
139static const struct cmdtab entry =
140	{ "device",	device_tab,	NULL };
141
142static DEF_MODULE(&entry);
143
144/*
145 * Carrier state to string
146 */
147static const struct penum strcarrier[] = {
148	{ 1, "on" },
149	{ 2, "off" },
150	{ 3, "unknown" },
151	{ 4, "none" },
152	{ 0, NULL }
153};
154/*
155 * SUNI mode to string
156 */
157static const struct penum strsunimode[] = {
158	{ 1, "sonet" },
159	{ 2, "sdh" },
160	{ 3, "unknown" },
161	{ 0, NULL }
162};
163
164/*
165 * OIDs
166 */
167static const struct asn_oid
168	oid_begemotAtmIfMode = OIDX_begemotAtmIfMode;
169
170/*
171 * Print 1st status line
172 */
173static void
174dev_status1(const struct atmif *aif)
175{
176	char buf[100];
177
178	printf("%-5u %-8s %-6u %-4u %-5u %-4u %-5u "
179	    "%02x:%02x:%02x:%02x:%02x:%02x %s\n", aif->index,
180	    aif->ifname, aif->pcr,
181	    (1 << aif->vpi_bits) - 1, (1 << aif->vci_bits) - 1,
182	    aif->max_vpcs, aif->max_vccs, aif->esi[0],
183	    aif->esi[1], aif->esi[2], aif->esi[3], aif->esi[4], aif->esi[5],
184	    penum(aif->carrier, strcarrier, buf));
185}
186
187/*
188 * Print 2nd status line
189 */
190static void
191dev_status2(const struct atmif *aif)
192{
193	char buf[100];
194
195	printf("%-5u %-8s %s\n", aif->index, aif->ifname,
196	    penum(aif->mode, strsunimode, buf));
197}
198
199/*
200 * Implement the 'device status' command
201 */
202static void
203device_status(int argc, char *argv[])
204{
205	int opt, i;
206	struct atmif *aif;
207	static const struct option opts[] = {
208	    { NULL, 0, NULL }
209	};
210
211	const char dev1[] =
212	    "Interface             Max        Max\n"
213	    "Index Name     PCR    VPI  VCI   VPCs VCCs  ESI               Carrier\n";
214	const char dev2[] =
215	    "Interface\n"
216	    "Index Name     Mode\n";
217
218	while ((opt = parse_options(&argc, &argv, opts)) != -1)
219		switch (opt) {
220		}
221
222	snmp_open(NULL, NULL, NULL, NULL);
223	atexit(snmp_close);
224
225	atmif_fetchtable();
226
227	if (TAILQ_EMPTY(&atmif_list))
228		errx(1, "no ATM interfaces found");
229
230	if (argc > 0) {
231		heading_init();
232		for (i = 0; i < argc; i++) {
233			if ((aif = atmif_find_name(argv[i])) == NULL) {
234				warnx("%s: no such ATM interface", argv[i]);
235				continue;
236			}
237			heading(dev1);
238			dev_status1(aif);
239		}
240		heading_init();
241		for (i = 0; i < argc; i++) {
242			if ((aif = atmif_find_name(argv[i])) == NULL)
243				continue;
244			heading(dev2);
245			dev_status2(aif);
246		}
247	} else {
248		heading_init();
249		TAILQ_FOREACH(aif, &atmif_list, link) {
250			heading(dev1);
251			dev_status1(aif);
252		}
253		heading_init();
254		TAILQ_FOREACH(aif, &atmif_list, link) {
255			heading(dev2);
256			dev_status2(aif);
257		}
258	}
259}
260
261/*
262 * Print hardware info line
263 */
264static void
265dev_hardware(const struct atmif *aif)
266{
267	const struct atmhw *hw;
268
269	TAILQ_FOREACH(hw, &atmhw_list, link)
270		if (aif->index == hw->index)
271			break;
272	if (hw == NULL) {
273		warnx("hardware info not found for '%s'", aif->ifname);
274		return;
275	}
276
277	printf("%-5u %-8s %-16s%-10s %-10u %-10u %u\n", aif->index,
278	    aif->ifname, hw->vendor, hw->device, hw->serial,
279	    hw->version, hw->soft_version);
280}
281
282/*
283 * Show hardware configuration
284 */
285static void
286device_hardware(int argc, char *argv[])
287{
288	int opt, i;
289	struct atmif *aif;
290
291	static const struct option opts[] = {
292	    { NULL, 0, NULL }
293	};
294
295	static const char headline[] =
296	    "Interface      \n"
297	    "Index Name     Vendor          Card       Serial     HW         SW\n";
298
299	while ((opt = parse_options(&argc, &argv, opts)) != -1)
300		switch (opt) {
301		}
302
303	snmp_open(NULL, NULL, NULL, NULL);
304	atexit(snmp_close);
305
306	atmif_fetchtable();
307
308	if (snmp_table_fetch(&atmhw_table, &atmhw_list) != 0)
309		errx(1, "AtmHW table: %s", snmp_client.error);
310
311	if (argc > 0) {
312		heading_init();
313		for (i = 0; i < argc; i++) {
314			if ((aif = atmif_find_name(argv[i])) == NULL) {
315				warnx("interface not found '%s'", argv[i]);
316				continue;
317			}
318			heading(headline);
319			dev_hardware(aif);
320		}
321	} else {
322		heading_init();
323		TAILQ_FOREACH(aif, &atmif_list, link) {
324			heading(headline);
325			dev_hardware(aif);
326		}
327	}
328}
329
330/*
331 * Change device parameters
332 */
333static void
334device_modify(int argc, char *argv[])
335{
336	int opt;
337	struct atmif *aif;
338	int mode = 0;
339	int n;
340	struct snmp_pdu pdu, resp;
341
342	static const struct option opts[] = {
343#define MODIFY_MODE	0
344	    { "mode", OPT_STRING, NULL },
345	    { NULL, 0, NULL }
346	};
347
348	while ((opt = parse_options(&argc, &argv, opts)) != -1)
349		switch (opt) {
350
351		  case MODIFY_MODE:
352			if (pparse(&mode, strsunimode, optarg) == -1 ||
353			    mode == 3)
354				errx(1, "illegal mode for -m '%s'", optarg);
355			break;
356		}
357
358	if (argc != 1)
359		errx(1, "device modify needs one argument");
360
361	snmp_open(NULL, NULL, NULL, NULL);
362
363	atexit(snmp_close);
364	atmif_fetchtable();
365
366	if ((aif = atmif_find_name(argv[0])) == NULL)
367		errx(1, "%s: no such ATM interface", argv[0]);
368
369	snmp_pdu_create(&pdu, SNMP_PDU_SET);
370	if (mode != 0) {
371		n = snmp_add_binding(&pdu,
372		    &oid_begemotAtmIfMode, SNMP_SYNTAX_INTEGER,
373		    NULL);
374		snmp_oid_append(&pdu.bindings[n + 0].var, "i",
375		    (asn_subid_t)aif->index);
376		pdu.bindings[n + 0].v.integer = mode;
377	}
378
379	if (pdu.nbindings == 0)
380		errx(1, "must specify something to modify");
381
382	if (snmp_dialog(&pdu, &resp))
383		errx(1, "No response from '%s': %s", snmp_client.chost,
384		    snmp_client.error);
385
386	if (snmp_pdu_check(&pdu, &resp) <= 0)
387		errx(1, "Error modifying device");
388
389	snmp_pdu_free(&resp);
390	snmp_pdu_free(&pdu);
391}
392
393/* XXX while this is compiled in */
394void
395device_register(void)
396{
397	register_module(&amodule_1);
398}
399
400/*
401 * Fetch the ATM interface table
402 */
403void
404atmif_fetchtable(void)
405{
406	struct atmif *aif;
407
408	while ((aif = TAILQ_FIRST(&atmif_list)) != NULL) {
409		free(aif->ifname);
410		free(aif->esi);
411		TAILQ_REMOVE(&atmif_list, aif, link);
412		free(aif);
413	}
414
415	if (snmp_table_fetch(&atmif_table, &atmif_list) != 0)
416		errx(1, "AtmIf table: %s", snmp_client.error);
417}
418
419/*
420 * Find a named ATM interface
421 */
422struct atmif *
423atmif_find_name(const char *ifname)
424{
425	struct atmif *atmif;
426
427	TAILQ_FOREACH(atmif, &atmif_list, link)
428		if (strcmp(atmif->ifname, ifname) == 0)
429			return (atmif);
430	return (NULL);
431}
432/*
433 * find an ATM interface by index
434 */
435struct atmif *
436atmif_find(u_int idx)
437{
438	struct atmif *atmif;
439
440	TAILQ_FOREACH(atmif, &atmif_list, link)
441		if (atmif->index == (int32_t)idx)
442			return (atmif);
443	return (NULL);
444}
445