1181834Sroberto/*
2181834Sroberto * Copyright (c) 2001-2002
3181834Sroberto *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4181834Sroberto * 	All rights reserved.
5181834Sroberto * Copyright (c) 2003-2004
6181834Sroberto *	Hartmut Brandt.
7181834Sroberto * 	All rights reserved.
8181834Sroberto *
9181834Sroberto * Author: Hartmut Brandt <harti@freebsd.org>
10181834Sroberto *
11181834Sroberto * Redistribution and use in source and binary forms, with or without
12181834Sroberto * modification, are permitted provided that the following conditions
13181834Sroberto * are met:
14181834Sroberto * 1. Redistributions of source code must retain the above copyright
15181834Sroberto *    notice, this list of conditions and the following disclaimer.
16181834Sroberto * 2. Redistributions in binary form must reproduce the above copyright
17181834Sroberto *    notice, this list of conditions and the following disclaimer in the
18181834Sroberto *    documentation and/or other materials provided with the distribution.
19181834Sroberto *
20181834Sroberto * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21181834Sroberto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22181834Sroberto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23181834Sroberto * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24181834Sroberto * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25181834Sroberto * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26181834Sroberto * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27181834Sroberto * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28181834Sroberto * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29181834Sroberto * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30181834Sroberto * SUCH DAMAGE.
31181834Sroberto */
32181834Sroberto
33181834Sroberto#include <sys/cdefs.h>
34181834Sroberto__FBSDID("$FreeBSD$");
35181834Sroberto
36181834Sroberto#include "atmconfig.h"
37181834Sroberto#include "atmconfig_device.h"
38181834Sroberto#include "private.h"
39181834Sroberto#include "oid.h"
40181834Sroberto
41181834Sroberto#include <bsnmp/asn1.h>
42181834Sroberto#include <bsnmp/snmp.h>
43181834Sroberto#include <bsnmp/snmpclient.h>
44181834Sroberto
45181834Sroberto/*
46181834Sroberto * Description of the begemotAtmIfTable
47181834Sroberto */
48181834Srobertostatic const struct snmp_table atmif_table = {
49181834Sroberto	OIDX_begemotAtmIfTable,
50181834Sroberto	OIDX_begemotAtmIfTableLastChange, 2,
51181834Sroberto	sizeof(struct atmif),
52181834Sroberto	1, 0x7ffULL,
53181834Sroberto	{
54181834Sroberto	  { 0,
55181834Sroberto	    SNMP_SYNTAX_INTEGER, offsetof(struct atmif, index) },
56181834Sroberto	  { OID_begemotAtmIfName,
57181834Sroberto	    SNMP_SYNTAX_OCTETSTRING, offsetof(struct atmif, ifname) },
58181834Sroberto	  { OID_begemotAtmIfPcr,
59181834Sroberto	    SNMP_SYNTAX_GAUGE, offsetof(struct atmif, pcr) },
60181834Sroberto	  { OID_begemotAtmIfMedia,
61181834Sroberto	    SNMP_SYNTAX_INTEGER, offsetof(struct atmif, media) },
62181834Sroberto	  { OID_begemotAtmIfVpiBits,
63181834Sroberto	    SNMP_SYNTAX_GAUGE, offsetof(struct atmif, vpi_bits) },
64181834Sroberto	  { OID_begemotAtmIfVciBits,
65181834Sroberto	    SNMP_SYNTAX_GAUGE, offsetof(struct atmif, vci_bits) },
66181834Sroberto	  { OID_begemotAtmIfMaxVpcs,
67181834Sroberto	    SNMP_SYNTAX_GAUGE, offsetof(struct atmif, max_vpcs) },
68181834Sroberto	  { OID_begemotAtmIfMaxVccs,
69181834Sroberto	    SNMP_SYNTAX_GAUGE, offsetof(struct atmif, max_vccs) },
70181834Sroberto	  { OID_begemotAtmIfEsi,
71181834Sroberto	    SNMP_SYNTAX_OCTETSTRING, offsetof(struct atmif, esi) },
72181834Sroberto	  { OID_begemotAtmIfCarrierStatus,
73181834Sroberto	    SNMP_SYNTAX_INTEGER, offsetof(struct atmif, carrier) },
74181834Sroberto	  { OID_begemotAtmIfMode,
75181834Sroberto	    SNMP_SYNTAX_INTEGER, offsetof(struct atmif, mode) },
76181834Sroberto          { 0, SNMP_SYNTAX_NULL, 0 }
77181834Sroberto	}
78181834Sroberto};
79181834Sroberto
80181834Sroberto/* List of all ATM interfaces */
81181834Srobertostruct atmif_list atmif_list = TAILQ_HEAD_INITIALIZER(atmif_list);
82181834Sroberto
83181834Sroberto/*
84181834Sroberto * ATM hardware table
85181834Sroberto */
86181834Srobertostruct atmhw {
87181834Sroberto	TAILQ_ENTRY(atmhw) link;
88181834Sroberto	uint64_t	found;
89181834Sroberto	int32_t		index;
90181834Sroberto	u_char		*vendor;
91181834Sroberto	size_t		vendorlen;
92181834Sroberto	u_char		*device;
93181834Sroberto	size_t		devicelen;
94181834Sroberto	uint32_t	serial;
95181834Sroberto	uint32_t	version;
96181834Sroberto	uint32_t	soft_version;
97181834Sroberto};
98181834SrobertoTAILQ_HEAD(atmhw_list, atmhw);
99181834Sroberto
100181834Sroberto/* list of ATM hardware */
101181834Srobertostatic struct atmhw_list atmhw_list;
102181834Sroberto
103181834Sroberto/*
104181834Sroberto * Read ATM hardware table
105181834Sroberto */
106181834Srobertostatic const struct snmp_table atmhw_table = {
107181834Sroberto	OIDX_begemotAtmHWTable,
108181834Sroberto	OIDX_begemotAtmIfTableLastChange, 2,
109181834Sroberto	sizeof(struct atmhw),
110181834Sroberto	1, 0x3fULL,
111181834Sroberto	{
112181834Sroberto	  { 0,
113181834Sroberto	    SNMP_SYNTAX_INTEGER, offsetof(struct atmhw, index) },
114181834Sroberto	  { OID_begemotAtmHWVendor,
115181834Sroberto	    SNMP_SYNTAX_OCTETSTRING, offsetof(struct atmhw, vendor) },
116181834Sroberto	  { OID_begemotAtmHWDevice,
117181834Sroberto	    SNMP_SYNTAX_OCTETSTRING, offsetof(struct atmhw, device) },
118181834Sroberto	  { OID_begemotAtmHWSerial,
119181834Sroberto	    SNMP_SYNTAX_GAUGE, offsetof(struct atmhw, serial) },
120181834Sroberto	  { OID_begemotAtmHWVersion,
121181834Sroberto	    SNMP_SYNTAX_GAUGE, offsetof(struct atmhw, version) },
122181834Sroberto	  { OID_begemotAtmHWSoftVersion,
123181834Sroberto	    SNMP_SYNTAX_GAUGE, offsetof(struct atmhw, soft_version) },
124181834Sroberto          { 0, SNMP_SYNTAX_NULL, 0 }
125181834Sroberto	}
126181834Sroberto};
127181834Sroberto
128181834Srobertostatic void device_status(int, char *[]);
129181834Srobertostatic void device_hardware(int, char *[]);
130181834Srobertostatic void device_modify(int, char *[]);
131181834Sroberto
132181834Srobertostatic const struct cmdtab device_tab[] = {
133181834Sroberto	{ "hardware",	NULL,	device_hardware },
134181834Sroberto 	{ "status",	NULL,	device_status },
135181834Sroberto 	{ "modify",	NULL,	device_modify },
136181834Sroberto	{ NULL,		NULL,	NULL }
137181834Sroberto};
138181834Sroberto
139181834Srobertostatic const struct cmdtab entry =
140181834Sroberto	{ "device",	device_tab,	NULL };
141181834Sroberto
142181834Srobertostatic DEF_MODULE(&entry);
143181834Sroberto
144181834Sroberto/*
145181834Sroberto * Carrier state to string
146181834Sroberto */
147181834Srobertostatic const struct penum strcarrier[] = {
148181834Sroberto	{ 1, "on" },
149181834Sroberto	{ 2, "off" },
150181834Sroberto	{ 3, "unknown" },
151181834Sroberto	{ 4, "none" },
152181834Sroberto	{ 0, NULL }
153181834Sroberto};
154181834Sroberto/*
155181834Sroberto * SUNI mode to string
156181834Sroberto */
157181834Srobertostatic const struct penum strsunimode[] = {
158181834Sroberto	{ 1, "sonet" },
159181834Sroberto	{ 2, "sdh" },
160181834Sroberto	{ 3, "unknown" },
161181834Sroberto	{ 0, NULL }
162181834Sroberto};
163181834Sroberto
164181834Sroberto/*
165181834Sroberto * OIDs
166181834Sroberto */
167181834Srobertostatic const struct asn_oid
168181834Sroberto	oid_begemotAtmIfMode = OIDX_begemotAtmIfMode;
169181834Sroberto
170181834Sroberto/*
171181834Sroberto * Print 1st status line
172181834Sroberto */
173181834Srobertostatic void
174181834Srobertodev_status1(const struct atmif *aif)
175181834Sroberto{
176181834Sroberto	char buf[100];
177181834Sroberto
178181834Sroberto	printf("%-5u %-8s %-6u %-4u %-5u %-4u %-5u "
179181834Sroberto	    "%02x:%02x:%02x:%02x:%02x:%02x %s\n", aif->index,
180181834Sroberto	    aif->ifname, aif->pcr,
181181834Sroberto	    (1 << aif->vpi_bits) - 1, (1 << aif->vci_bits) - 1,
182181834Sroberto	    aif->max_vpcs, aif->max_vccs, aif->esi[0],
183181834Sroberto	    aif->esi[1], aif->esi[2], aif->esi[3], aif->esi[4], aif->esi[5],
184181834Sroberto	    penum(aif->carrier, strcarrier, buf));
185181834Sroberto}
186181834Sroberto
187181834Sroberto/*
188181834Sroberto * Print 2nd status line
189181834Sroberto */
190181834Srobertostatic void
191181834Srobertodev_status2(const struct atmif *aif)
192181834Sroberto{
193181834Sroberto	char buf[100];
194181834Sroberto
195181834Sroberto	printf("%-5u %-8s %s\n", aif->index, aif->ifname,
196181834Sroberto	    penum(aif->mode, strsunimode, buf));
197181834Sroberto}
198181834Sroberto
199181834Sroberto/*
200181834Sroberto * Implement the 'device status' command
201181834Sroberto */
202181834Srobertostatic void
203181834Srobertodevice_status(int argc, char *argv[])
204181834Sroberto{
205181834Sroberto	int opt, i;
206181834Sroberto	struct atmif *aif;
207181834Sroberto	static const struct option opts[] = {
208181834Sroberto	    { NULL, 0, NULL }
209181834Sroberto	};
210181834Sroberto
211181834Sroberto	const char dev1[] =
212181834Sroberto	    "Interface             Max        Max\n"
213181834Sroberto	    "Index Name     PCR    VPI  VCI   VPCs VCCs  ESI               Carrier\n";
214181834Sroberto	const char dev2[] =
215181834Sroberto	    "Interface\n"
216181834Sroberto	    "Index Name     Mode\n";
217181834Sroberto
218181834Sroberto	while ((opt = parse_options(&argc, &argv, opts)) != -1)
219181834Sroberto		switch (opt) {
220181834Sroberto		}
221181834Sroberto
222181834Sroberto	snmp_open(NULL, NULL, NULL, NULL);
223181834Sroberto	atexit(snmp_close);
224181834Sroberto
225181834Sroberto	atmif_fetchtable();
226181834Sroberto
227181834Sroberto	if (TAILQ_EMPTY(&atmif_list))
228181834Sroberto		errx(1, "no ATM interfaces found");
229181834Sroberto
230181834Sroberto	if (argc > 0) {
231181834Sroberto		heading_init();
232181834Sroberto		for (i = 0; i < argc; i++) {
233181834Sroberto			if ((aif = atmif_find_name(argv[i])) == NULL) {
234181834Sroberto				warnx("%s: no such ATM interface", argv[i]);
235181834Sroberto				continue;
236181834Sroberto			}
237181834Sroberto			heading(dev1);
238181834Sroberto			dev_status1(aif);
239181834Sroberto		}
240181834Sroberto		heading_init();
241181834Sroberto		for (i = 0; i < argc; i++) {
242181834Sroberto			if ((aif = atmif_find_name(argv[i])) == NULL)
243181834Sroberto				continue;
244181834Sroberto			heading(dev2);
245181834Sroberto			dev_status2(aif);
246181834Sroberto		}
247181834Sroberto	} else {
248181834Sroberto		heading_init();
249181834Sroberto		TAILQ_FOREACH(aif, &atmif_list, link) {
250181834Sroberto			heading(dev1);
251181834Sroberto			dev_status1(aif);
252181834Sroberto		}
253181834Sroberto		heading_init();
254181834Sroberto		TAILQ_FOREACH(aif, &atmif_list, link) {
255181834Sroberto			heading(dev2);
256181834Sroberto			dev_status2(aif);
257181834Sroberto		}
258181834Sroberto	}
259181834Sroberto}
260181834Sroberto
261181834Sroberto/*
262181834Sroberto * Print hardware info line
263181834Sroberto */
264181834Srobertostatic void
265181834Srobertodev_hardware(const struct atmif *aif)
266181834Sroberto{
267181834Sroberto	const struct atmhw *hw;
268181834Sroberto
269181834Sroberto	TAILQ_FOREACH(hw, &atmhw_list, link)
270181834Sroberto		if (aif->index == hw->index)
271181834Sroberto			break;
272181834Sroberto	if (hw == NULL) {
273181834Sroberto		warnx("hardware info not found for '%s'", aif->ifname);
274181834Sroberto		return;
275181834Sroberto	}
276181834Sroberto
277181834Sroberto	printf("%-5u %-8s %-16s%-10s %-10u %-10u %u\n", aif->index,
278181834Sroberto	    aif->ifname, hw->vendor, hw->device, hw->serial,
279181834Sroberto	    hw->version, hw->soft_version);
280181834Sroberto}
281181834Sroberto
282181834Sroberto/*
283181834Sroberto * Show hardware configuration
284181834Sroberto */
285181834Srobertostatic void
286181834Srobertodevice_hardware(int argc, char *argv[])
287181834Sroberto{
288181834Sroberto	int opt, i;
289181834Sroberto	struct atmif *aif;
290181834Sroberto
291181834Sroberto	static const struct option opts[] = {
292181834Sroberto	    { NULL, 0, NULL }
293181834Sroberto	};
294181834Sroberto
295181834Sroberto	static const char headline[] =
296181834Sroberto	    "Interface      \n"
297181834Sroberto	    "Index Name     Vendor          Card       Serial     HW         SW\n";
298181834Sroberto
299181834Sroberto	while ((opt = parse_options(&argc, &argv, opts)) != -1)
300181834Sroberto		switch (opt) {
301181834Sroberto		}
302181834Sroberto
303181834Sroberto	snmp_open(NULL, NULL, NULL, NULL);
304181834Sroberto	atexit(snmp_close);
305181834Sroberto
306181834Sroberto	atmif_fetchtable();
307181834Sroberto
308181834Sroberto	if (snmp_table_fetch(&atmhw_table, &atmhw_list) != 0)
309181834Sroberto		errx(1, "AtmHW table: %s", snmp_client.error);
310181834Sroberto
311181834Sroberto	if (argc > 0) {
312181834Sroberto		heading_init();
313181834Sroberto		for (i = 0; i < argc; i++) {
314181834Sroberto			if ((aif = atmif_find_name(argv[i])) == NULL) {
315181834Sroberto				warnx("interface not found '%s'", argv[i]);
316181834Sroberto				continue;
317181834Sroberto			}
318181834Sroberto			heading(headline);
319181834Sroberto			dev_hardware(aif);
320181834Sroberto		}
321181834Sroberto	} else {
322181834Sroberto		heading_init();
323181834Sroberto		TAILQ_FOREACH(aif, &atmif_list, link) {
324181834Sroberto			heading(headline);
325181834Sroberto			dev_hardware(aif);
326181834Sroberto		}
327181834Sroberto	}
328181834Sroberto}
329181834Sroberto
330181834Sroberto/*
331181834Sroberto * Change device parameters
332181834Sroberto */
333181834Srobertostatic void
334181834Srobertodevice_modify(int argc, char *argv[])
335181834Sroberto{
336181834Sroberto	int opt;
337181834Sroberto	struct atmif *aif;
338181834Sroberto	int mode = 0;
339181834Sroberto	int n;
340181834Sroberto	struct snmp_pdu pdu, resp;
341181834Sroberto
342181834Sroberto	static const struct option opts[] = {
343181834Sroberto#define MODIFY_MODE	0
344181834Sroberto	    { "mode", OPT_STRING, NULL },
345181834Sroberto	    { NULL, 0, NULL }
346181834Sroberto	};
347181834Sroberto
348181834Sroberto	while ((opt = parse_options(&argc, &argv, opts)) != -1)
349181834Sroberto		switch (opt) {
350181834Sroberto
351181834Sroberto		  case MODIFY_MODE:
352181834Sroberto			if (pparse(&mode, strsunimode, optarg) == -1 ||
353181834Sroberto			    mode == 3)
354181834Sroberto				errx(1, "illegal mode for -m '%s'", optarg);
355181834Sroberto			break;
356181834Sroberto		}
357181834Sroberto
358181834Sroberto	if (argc != 1)
359181834Sroberto		errx(1, "device modify needs one argument");
360181834Sroberto
361181834Sroberto	snmp_open(NULL, NULL, NULL, NULL);
362181834Sroberto
363181834Sroberto	atexit(snmp_close);
364181834Sroberto	atmif_fetchtable();
365181834Sroberto
366181834Sroberto	if ((aif = atmif_find_name(argv[0])) == NULL)
367181834Sroberto		errx(1, "%s: no such ATM interface", argv[0]);
368181834Sroberto
369181834Sroberto	snmp_pdu_create(&pdu, SNMP_PDU_SET);
370181834Sroberto	if (mode != 0) {
371181834Sroberto		n = snmp_add_binding(&pdu,
372181834Sroberto		    &oid_begemotAtmIfMode, SNMP_SYNTAX_INTEGER,
373181834Sroberto		    NULL);
374181834Sroberto		snmp_oid_append(&pdu.bindings[n + 0].var, "i",
375181834Sroberto		    (asn_subid_t)aif->index);
376181834Sroberto		pdu.bindings[n + 0].v.integer = mode;
377181834Sroberto	}
378181834Sroberto
379181834Sroberto	if (pdu.nbindings == 0)
380181834Sroberto		errx(1, "must specify something to modify");
381181834Sroberto
382181834Sroberto	if (snmp_dialog(&pdu, &resp))
383181834Sroberto		errx(1, "No response from '%s': %s", snmp_client.chost,
384181834Sroberto		    snmp_client.error);
385181834Sroberto
386181834Sroberto	if (snmp_pdu_check(&pdu, &resp) <= 0)
387181834Sroberto		errx(1, "Error modifying device");
388181834Sroberto
389181834Sroberto	snmp_pdu_free(&resp);
390181834Sroberto	snmp_pdu_free(&pdu);
391181834Sroberto}
392181834Sroberto
393181834Sroberto/* XXX while this is compiled in */
394181834Srobertovoid
395181834Srobertodevice_register(void)
396181834Sroberto{
397181834Sroberto	register_module(&amodule_1);
398181834Sroberto}
399181834Sroberto
400181834Sroberto/*
401181834Sroberto * Fetch the ATM interface table
402181834Sroberto */
403181834Srobertovoid
404181834Srobertoatmif_fetchtable(void)
405181834Sroberto{
406181834Sroberto	struct atmif *aif;
407181834Sroberto
408181834Sroberto	while ((aif = TAILQ_FIRST(&atmif_list)) != NULL) {
409181834Sroberto		free(aif->ifname);
410181834Sroberto		free(aif->esi);
411181834Sroberto		TAILQ_REMOVE(&atmif_list, aif, link);
412181834Sroberto		free(aif);
413181834Sroberto	}
414181834Sroberto
415181834Sroberto	if (snmp_table_fetch(&atmif_table, &atmif_list) != 0)
416181834Sroberto		errx(1, "AtmIf table: %s", snmp_client.error);
417181834Sroberto}
418181834Sroberto
419181834Sroberto/*
420181834Sroberto * Find a named ATM interface
421181834Sroberto */
422181834Srobertostruct atmif *
423181834Srobertoatmif_find_name(const char *ifname)
424181834Sroberto{
425181834Sroberto	struct atmif *atmif;
426181834Sroberto
427181834Sroberto	TAILQ_FOREACH(atmif, &atmif_list, link)
428181834Sroberto		if (strcmp(atmif->ifname, ifname) == 0)
429181834Sroberto			return (atmif);
430181834Sroberto	return (NULL);
431181834Sroberto}
432181834Sroberto/*
433181834Sroberto * find an ATM interface by index
434181834Sroberto */
435181834Srobertostruct atmif *
436181834Srobertoatmif_find(u_int idx)
437181834Sroberto{
438181834Sroberto	struct atmif *atmif;
439181834Sroberto
440181834Sroberto	TAILQ_FOREACH(atmif, &atmif_list, link)
441181834Sroberto		if (atmif->index == (int32_t)idx)
442181834Sroberto			return (atmif);
443181834Sroberto	return (NULL);
444181834Sroberto}
445181834Sroberto