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 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 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  * $FreeBSD: stable/10/usr.sbin/bsnmpd/modules/snmp_atm/atm_sys.c 310903 2016-12-31 10:34:09Z ngie $
33  *
34  * SNMP module for ATM hardware interfaces - FreeBSD/Ng specific part.
35  */
36 
37 #include "atm.h"
38 #include "atm_tree.h"
39 #include "atm_oid.h"
40 
41 #include <stdlib.h>
42 #include <syslog.h>
43 #include <string.h>
44 
45 #include <net/if_atm.h>
46 
47 #include <bsnmp/snmp_netgraph.h>
48 #include <netgraph/ng_message.h>
49 #include <netgraph/atm/ng_atm.h>
50 
51 static const struct hwinfo {
52 	const char *device;
53 	const char *vendor;
54 } hwinfo[] = {
55 	ATM_DEVICE_NAMES
56 };
57 
58 struct atmif_sys {
59 	ng_ID_t		atm_node;
60 	void		*regc;	/* cookie registration */
61 };
62 
63 /*
64  * Find the interface for a given node
65  */
66 struct atmif *
atm_node2if(u_int node)67 atm_node2if(u_int node)
68 {
69 	struct atmif_priv *aif;
70 
71 	if (node != 0)
72 		TAILQ_FOREACH(aif, &atmif_list, link)
73 			if (aif->sys->atm_node == node)
74 				return (&aif->pub);
75 	return (NULL);
76 }
77 
78 u_int
atm_if2node(struct atmif * pub)79 atm_if2node(struct atmif *pub)
80 {
81 	struct atmif_priv *aif = (struct atmif_priv *)pub;
82 
83 	return (aif->sys->atm_node);
84 }
85 
86 /*
87  * Destroy system dependend stuff.
88  */
89 void
atmif_sys_destroy(struct atmif_priv * aif)90 atmif_sys_destroy(struct atmif_priv *aif)
91 {
92 
93 	ng_unregister_cookie(aif->sys->regc);
94 	free(aif->sys);
95 	free(aif->pub.mib);
96 }
97 
98 /*
99  * Handle a message from the ATM node
100  */
101 static void
handle_atm_message(const struct ng_mesg * mesg,const char * path __unused,ng_ID_t node,void * uarg)102 handle_atm_message(const struct ng_mesg *mesg, const char *path __unused,
103     ng_ID_t node, void *uarg)
104 {
105 	struct atmif_priv *aif = uarg;
106 	enum atmif_carrier_state ost;
107 
108 	switch (mesg->header.cmd) {
109 
110 	  case NGM_ATM_IF_CHANGE:
111 	    {
112 		const struct ngm_atm_if_change *arg;
113 
114 		ost = aif->pub.carrier;
115 		if (mesg->header.arglen != sizeof(*arg)) {
116 			syslog(LOG_ERR, "ATM_IF_CHANGE: wrong size");
117 			atmif_check_carrier(aif);
118 			return;
119 		}
120 		arg = (const struct ngm_atm_if_change *)
121 		    (const void *)mesg->data;
122 
123 		if (arg->carrier)
124 			aif->pub.carrier = ATMIF_CARRIER_ON;
125 		else
126 			aif->pub.carrier = ATMIF_CARRIER_OFF;
127 
128 		if (ost != aif->pub.carrier)
129 			atmif_send_notification(aif, ATMIF_NOTIFY_CARRIER,
130 			    (uintptr_t)ost);
131 		return;
132 	    }
133 
134 	  case NGM_ATM_VCC_CHANGE:
135 	    {
136 		const struct ngm_atm_vcc_change *arg;
137 
138 		if (mesg->header.arglen != sizeof(*arg)) {
139 			syslog(LOG_ERR, "ATM_VCC_CHANGE: wrong size");
140 			return;
141 		}
142 		arg = (const struct ngm_atm_vcc_change *)
143 		    (const void *)mesg->data;
144 		atmif_send_notification(aif, ATMIF_NOTIFY_VCC,
145 		    (uintptr_t)(((arg->vpi & 0xff) << 24) |
146 		    ((arg->vci & 0xffff) << 8) | (arg->state & 1)));
147 		return;
148 	    }
149 	}
150 	syslog(LOG_WARNING, "spurious message %u from node [%x]",
151 	    mesg->header.cmd, node);
152 }
153 
154 /*
155  * Attach to an ATM interface
156  */
157 int
atmif_sys_attach_if(struct atmif_priv * aif)158 atmif_sys_attach_if(struct atmif_priv *aif)
159 {
160 	struct ng_mesg *resp, *resp1;
161 	struct namelist *list;
162 	u_int i;
163 
164 	if ((aif->sys = malloc(sizeof(*aif->sys))) == NULL) {
165 		syslog(LOG_CRIT, "out of memory");
166 		return (-1);
167 	}
168 	memset(aif->sys, 0, sizeof(*aif->sys));
169 
170 	if ((aif->pub.mib = malloc(sizeof(*aif->pub.mib))) == NULL) {
171 		free(aif->sys);
172 		syslog(LOG_CRIT, "out of memory");
173 		return (-1);
174 	}
175 
176 	atmif_sys_fill_mib(aif);
177 
178 	/*
179 	 * Get ATM node Id. Must do it the hard way by scanning all nodes
180 	 * because the name may be wrong.
181 	 */
182 	if ((resp = ng_dialog_id(snmp_node, NGM_GENERIC_COOKIE, NGM_LISTNODES,
183 	    NULL, 0)) == NULL) {
184 		syslog(LOG_ERR, "cannot fetch node list: %m");
185 		free(aif->sys);
186 		return (-1);
187 	}
188 	list = (struct namelist *)(void *)resp->data;
189 
190 	for (i = 0; i < list->numnames; i++) {
191 		if (strcmp(list->nodeinfo[i].type, NG_ATM_NODE_TYPE) != 0)
192 			continue;
193 		if ((resp1 = ng_dialog_id(list->nodeinfo[i].id,
194 		    NGM_ATM_COOKIE, NGM_ATM_GET_IFNAME, NULL, 0)) == NULL)
195 			continue;
196 		if (strcmp(resp1->data, aif->pub.ifp->name) == 0) {
197 			free(resp1);
198 			break;
199 		}
200 		free(resp1);
201 	}
202 	if (i == list->numnames)
203 		aif->sys->atm_node = 0;
204 	else
205 		aif->sys->atm_node = list->nodeinfo[i].id;
206 
207 	free(resp);
208 
209 	if ((aif->sys->regc = ng_register_cookie(module, NGM_ATM_COOKIE,
210 	    aif->sys->atm_node, handle_atm_message, aif)) == NULL) {
211 		syslog(LOG_ERR, "cannot register cookie: %m");
212 		free(aif->sys);
213 		return (-1);
214 	}
215 	return (0);
216 }
217 
218 /*
219  * Table of all ATM interfaces - Ng part
220  */
221 int
op_atmif_ng(struct snmp_context * ctx __unused,struct snmp_value * value,u_int sub,u_int vindex __unused,enum snmp_op op)222 op_atmif_ng(struct snmp_context *ctx __unused, struct snmp_value *value,
223     u_int sub, u_int vindex __unused, enum snmp_op op)
224 {
225 	struct atmif_priv *aif;
226 	int err;
227 
228 	if ((err = atmif_get_aif(value, sub, op, &aif)) != SNMP_ERR_NOERROR)
229 		return (err);
230 
231 	if (op == SNMP_OP_SET) {
232 		switch (value->var.subs[sub - 1]) {
233 
234 		  default:
235 			return (SNMP_ERR_NOT_WRITEABLE);
236 		}
237 	}
238 
239 	switch (value->var.subs[sub - 1]) {
240 
241 	  case LEAF_begemotAtmIfNodeId:
242 		value->v.uint32 = aif->sys->atm_node;
243 		return (SNMP_ERR_NOERROR);
244 	}
245 	abort();
246 }
247 
248 /*
249  * Get vendor string
250  */
251 int
atm_sys_get_hw_vendor(struct atmif_priv * aif,struct snmp_value * value)252 atm_sys_get_hw_vendor(struct atmif_priv *aif, struct snmp_value *value)
253 {
254 
255 	if (aif->pub.mib->device >= sizeof(hwinfo) / sizeof(hwinfo[0]))
256 		return (string_get(value, "unknown", -1));
257 	return (string_get(value, hwinfo[aif->pub.mib->device].vendor, -1));
258 }
259 
260 /*
261  * Get device string
262  */
263 int
atm_sys_get_hw_device(struct atmif_priv * aif,struct snmp_value * value)264 atm_sys_get_hw_device(struct atmif_priv *aif, struct snmp_value *value)
265 {
266 
267 	if (aif->pub.mib->device >= sizeof(hwinfo) / sizeof(hwinfo[0]))
268 		return (string_get(value, "unknown", -1));
269 	return (string_get(value, hwinfo[aif->pub.mib->device].device, -1));
270 }
271 
272 /*
273  * Extract the ATM MIB from the interface's private MIB
274  */
275 void
atmif_sys_fill_mib(struct atmif_priv * aif)276 atmif_sys_fill_mib(struct atmif_priv *aif)
277 {
278 	struct ifatm_mib *mib;
279 
280 	if (aif->pub.ifp->specmiblen != sizeof(struct ifatm_mib)) {
281 		syslog(LOG_ERR, "atmif MIB has wrong size %zu",
282 		    aif->pub.ifp->specmiblen);
283 		memset(aif->pub.mib, 0, sizeof(*aif->pub.mib));
284 		aif->pub.mib->version = 0;
285 		return;
286 	}
287 	mib = (struct ifatm_mib *)aif->pub.ifp->specmib;
288 
289 	aif->pub.mib->device = mib->device;
290 	aif->pub.mib->serial = mib->serial;
291 	aif->pub.mib->hw_version = mib->hw_version;
292 	aif->pub.mib->sw_version = mib->sw_version;
293 	aif->pub.mib->media = mib->media;
294 
295 	memcpy(aif->pub.mib->esi, mib->esi, 6);
296 	aif->pub.mib->pcr = mib->pcr;
297 	aif->pub.mib->vpi_bits = mib->vpi_bits;
298 	aif->pub.mib->vci_bits = mib->vci_bits;
299 	aif->pub.mib->max_vpcs = mib->max_vpcs;
300 	aif->pub.mib->max_vccs = mib->max_vccs;
301 }
302