xref: /onnv-gate/usr/src/cmd/picl/plugins/sun4v/snmp/snmpplugin.c (revision 3941:328be6a20f20)
1*3941Svenki /*
2*3941Svenki  * CDDL HEADER START
3*3941Svenki  *
4*3941Svenki  * The contents of this file are subject to the terms of the
5*3941Svenki  * Common Development and Distribution License (the "License").
6*3941Svenki  * You may not use this file except in compliance with the License.
7*3941Svenki  *
8*3941Svenki  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*3941Svenki  * or http://www.opensolaris.org/os/licensing.
10*3941Svenki  * See the License for the specific language governing permissions
11*3941Svenki  * and limitations under the License.
12*3941Svenki  *
13*3941Svenki  * When distributing Covered Code, include this CDDL HEADER in each
14*3941Svenki  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*3941Svenki  * If applicable, add the following below this CDDL HEADER, with the
16*3941Svenki  * fields enclosed by brackets "[]" replaced with your own identifying
17*3941Svenki  * information: Portions Copyright [yyyy] [name of copyright owner]
18*3941Svenki  *
19*3941Svenki  * CDDL HEADER END
20*3941Svenki  */
21*3941Svenki 
22*3941Svenki /*
23*3941Svenki  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24*3941Svenki  * Use is subject to license terms.
25*3941Svenki  */
26*3941Svenki 
27*3941Svenki #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*3941Svenki 
29*3941Svenki /*
30*3941Svenki  * The SNMP picl plugin connects to the agent on the SP and creates
31*3941Svenki  * and populates the /physical-platform subtree in picl tree for use
32*3941Svenki  * by picl consumers.
33*3941Svenki  */
34*3941Svenki 
35*3941Svenki #include <stdio.h>
36*3941Svenki #include <stdlib.h>
37*3941Svenki #include <string.h>
38*3941Svenki #include <syslog.h>
39*3941Svenki #include <stdarg.h>
40*3941Svenki #include <libgen.h>
41*3941Svenki #include <libintl.h>
42*3941Svenki #include <thread.h>
43*3941Svenki #include <synch.h>
44*3941Svenki #include <errno.h>
45*3941Svenki 
46*3941Svenki #include <picldefs.h>
47*3941Svenki #include <picl.h>
48*3941Svenki #include <picltree.h>
49*3941Svenki 
50*3941Svenki #include "picloids.h"
51*3941Svenki #include "libpiclsnmp.h"
52*3941Svenki #include "snmpplugin.h"
53*3941Svenki 
54*3941Svenki #pragma init(snmpplugin_register)	/* place in .init section */
55*3941Svenki 
56*3941Svenki picld_plugin_reg_t snmpplugin_reg = {
57*3941Svenki 	PICLD_PLUGIN_VERSION_1,
58*3941Svenki 	PICLD_PLUGIN_NON_CRITICAL,
59*3941Svenki 	"snmp_plugin",
60*3941Svenki 	snmpplugin_init,
61*3941Svenki 	snmpplugin_fini
62*3941Svenki };
63*3941Svenki 
64*3941Svenki static picl_snmphdl_t	hdl;
65*3941Svenki 
66*3941Svenki /*
67*3941Svenki  * The stale_tree_rwlp protects the stale_xxx vars. The 'stale_tree' flag
68*3941Svenki  * and the 'rebuild_tree' flag below are both initialized to B_TRUE to
69*3941Svenki  * let the tree_builder() thread build the initial tree without blocking.
70*3941Svenki  */
71*3941Svenki static rwlock_t		stale_tree_rwlp;
72*3941Svenki static boolean_t	stale_tree = B_TRUE;
73*3941Svenki 
74*3941Svenki /*
75*3941Svenki  * vol_props, volprop_ndx and n_vol_props are protected by the stale_tree
76*3941Svenki  * flag.  They are read only when the stale_tree flag is B_FALSE and written
77*3941Svenki  * to only when the flag is B_TRUE.
78*3941Svenki  *
79*3941Svenki  * The change_time (last changed time) is read by only one thread at a
80*3941Svenki  * time when stale_tree is B_FALSE (protected by stale_tree_rwlp).  It is
81*3941Svenki  * written by only one thread (the tree builder) when stale_tree is B_TRUE.
82*3941Svenki  *
83*3941Svenki  * Note that strictly speaking, change_time should be uint_t (timeticks32).
84*3941Svenki  * But keeping it as int is fine, since we don't do any arithmetic on it
85*3941Svenki  * except equality check.
86*3941Svenki  */
87*3941Svenki static vol_prophdl_t	*vol_props = NULL;
88*3941Svenki static int		volprop_ndx = 0, n_vol_props = 0;
89*3941Svenki static int		change_time = 0;
90*3941Svenki 
91*3941Svenki /*
92*3941Svenki  * The rebuild_tree_lock and cv are used by the tree builder thread.
93*3941Svenki  * rebuild_tree has to be initialized to B_TRUE to let the tree_builder
94*3941Svenki  * do the first build without blocking.
95*3941Svenki  */
96*3941Svenki static mutex_t		rebuild_tree_lock;
97*3941Svenki static cond_t		rebuild_tree_cv;
98*3941Svenki static boolean_t	rebuild_tree = B_TRUE;
99*3941Svenki 
100*3941Svenki /*
101*3941Svenki  * These two should really not be global
102*3941Svenki  */
103*3941Svenki static picl_nodehdl_t	*physplat_nodes = NULL;
104*3941Svenki static int		n_physplat_nodes = 0;
105*3941Svenki 
106*3941Svenki static char *group1[] = {
107*3941Svenki 	OID_entPhysicalDescr,
108*3941Svenki 	OID_entPhysicalContainedIn,
109*3941Svenki 	OID_entPhysicalClass,
110*3941Svenki 	OID_entPhysicalName,
111*3941Svenki 	OID_entPhysicalHardwareRev,
112*3941Svenki 	OID_entPhysicalFirmwareRev,
113*3941Svenki 	OID_entPhysicalSerialNum,
114*3941Svenki 	OID_entPhysicalMfgName,
115*3941Svenki 	OID_entPhysicalModelName,
116*3941Svenki 	OID_entPhysicalIsFRU,
117*3941Svenki 	0
118*3941Svenki };
119*3941Svenki 
120*3941Svenki static char *group2[] = {
121*3941Svenki 	OID_sunPlatEquipmentHolderAcceptableTypes,
122*3941Svenki 	OID_sunPlatCircuitPackReplaceable,
123*3941Svenki 	OID_sunPlatCircuitPackHotSwappable,
124*3941Svenki 	OID_sunPlatPhysicalClass,
125*3941Svenki 	OID_sunPlatSensorClass,
126*3941Svenki 	OID_sunPlatSensorType,
127*3941Svenki 	OID_sunPlatAlarmType,
128*3941Svenki 	OID_sunPlatPowerSupplyClass,
129*3941Svenki 	0
130*3941Svenki };
131*3941Svenki 
132*3941Svenki static char *volgroup1[] = {
133*3941Svenki 	OID_sunPlatBinarySensorCurrent,
134*3941Svenki 	OID_sunPlatBinarySensorExpected,
135*3941Svenki 	OID_sunPlatBinarySensorInterpretTrue,
136*3941Svenki 	OID_sunPlatBinarySensorInterpretFalse,
137*3941Svenki 	0
138*3941Svenki };
139*3941Svenki 
140*3941Svenki static char *volgroup2[] = {
141*3941Svenki 	OID_sunPlatNumericSensorBaseUnits,
142*3941Svenki 	OID_sunPlatNumericSensorExponent,
143*3941Svenki 	OID_sunPlatNumericSensorRateUnits,
144*3941Svenki 	OID_sunPlatNumericSensorCurrent,
145*3941Svenki 	OID_sunPlatNumericSensorLowerThresholdFatal,
146*3941Svenki 	OID_sunPlatNumericSensorLowerThresholdCritical,
147*3941Svenki 	OID_sunPlatNumericSensorLowerThresholdNonCritical,
148*3941Svenki 	OID_sunPlatNumericSensorUpperThresholdNonCritical,
149*3941Svenki 	OID_sunPlatNumericSensorUpperThresholdCritical,
150*3941Svenki 	OID_sunPlatNumericSensorUpperThresholdFatal,
151*3941Svenki 	0
152*3941Svenki };
153*3941Svenki 
154*3941Svenki /*
155*3941Svenki  * The following two items must match the Sun Platform MIB specification
156*3941Svenki  * in their indices and values.
157*3941Svenki  */
158*3941Svenki static char *sensor_baseunits[] = {
159*3941Svenki 	"", "other", "unknown", "degC", "degF", "degK", "volts", "amps",
160*3941Svenki 	"watts", "joules", "coulombs", "va", "nits", "lumens", "lux",
161*3941Svenki 	"candelas", "kPa", "psi", "newtons", "cfm", "rpm", "hertz",
162*3941Svenki 	"seconds", "minutes", "hours", "days", "weeks", "mils", "inches",
163*3941Svenki 	"feet", "cubicInches", "cubicFeet", "meters", "cubicCentimeters",
164*3941Svenki 	"cubicMeters", "liters", "fluidOunces", "radians", "steradians",
165*3941Svenki 	"revolutions", "cycles", "gravities", "ounces", "pounds", "footPounds",
166*3941Svenki 	"ounceInches", "gauss", "gilberts", "henries", "farads", "ohms",
167*3941Svenki 	"siemens", "moles", "becquerels", "ppm", "decibels", "dBA", "dbC",
168*3941Svenki 	"grays", "sieverts", "colorTemperatureDegK", "bits", "bytes", "words",
169*3941Svenki 	"doubleWords", "quadWords", "percentage"
170*3941Svenki };
171*3941Svenki static const int n_baseunits = sizeof (sensor_baseunits) / sizeof (char *);
172*3941Svenki 
173*3941Svenki static char *sensor_rateunits[] = {
174*3941Svenki 	"",
175*3941Svenki 	"none",
176*3941Svenki 	"perMicroSecond",
177*3941Svenki 	"perMilliSecond",
178*3941Svenki 	"perSecond",
179*3941Svenki 	"perMinute",
180*3941Svenki 	"perHour",
181*3941Svenki 	"perDay",
182*3941Svenki 	"perWeek",
183*3941Svenki 	"perMonth",
184*3941Svenki 	"perYear"
185*3941Svenki };
186*3941Svenki static const int n_rateunits = sizeof (sensor_rateunits) / sizeof (char *);
187*3941Svenki 
188*3941Svenki /*
189*3941Svenki  * Local declarations
190*3941Svenki  */
191*3941Svenki static void snmpplugin_register(void);
192*3941Svenki static void register_group(char **g, int is_volatile);
193*3941Svenki static void *tree_builder(void *arg);
194*3941Svenki static int build_physplat(picl_nodehdl_t *subtree_rootp);
195*3941Svenki static void free_resources(picl_nodehdl_t subtree_root);
196*3941Svenki 
197*3941Svenki static picl_nodehdl_t make_node(picl_nodehdl_t subtree_root, int row,
198*3941Svenki     int *snmp_syserr_p);
199*3941Svenki static void save_nodeh(picl_nodehdl_t nodeh, int row);
200*3941Svenki static picl_nodehdl_t lookup_nodeh(int row);
201*3941Svenki 
202*3941Svenki static void save_volprop(picl_prophdl_t prop, char *oidstr, int row,
203*3941Svenki     int proptype);
204*3941Svenki static void check_for_stale_data(void);
205*3941Svenki static int read_volprop(ptree_rarg_t *parg, void *buf);
206*3941Svenki 
207*3941Svenki static void threshold(picl_nodehdl_t node, char *oidstr, int row,
208*3941Svenki     char *propname, int *snmp_syserr_p);
209*3941Svenki static void add_thresholds(picl_nodehdl_t node, int row, int *snmp_syserr_p);
210*3941Svenki 
211*3941Svenki static char *get_slot_type(int row, int *snmp_syserr_p);
212*3941Svenki static int add_volatile_prop(picl_nodehdl_t nodeh, char *name,
213*3941Svenki     int type, int access, int size, int (*rdfunc)(ptree_rarg_t *, void *),
214*3941Svenki     int (*wrfunc)(ptree_warg_t *, const void *), picl_prophdl_t *propp);
215*3941Svenki static int add_string_prop(picl_nodehdl_t node, char *propname, char *propval);
216*3941Svenki static int add_void_prop(picl_nodehdl_t node, char *propname);
217*3941Svenki static int add_int_prop(picl_nodehdl_t node, char *propname, int val);
218*3941Svenki static void add_prop(picl_nodehdl_t nodeh, picl_prophdl_t *php, char *label,
219*3941Svenki     int row, sp_propid_t pp, int *snmp_syserr_p);
220*3941Svenki 
221*3941Svenki static void log_msg(int pri, const char *fmt, ...);
222*3941Svenki 
223*3941Svenki #ifdef SNMPPLUGIN_DEBUG
224*3941Svenki static mutex_t	snmpplugin_dbuf_lock;
225*3941Svenki static char	*snmpplugin_dbuf = NULL;
226*3941Svenki static char	*snmpplugin_dbuf_curp = NULL;
227*3941Svenki static int	snmpplugin_dbuf_sz = 0;
228*3941Svenki static int	snmpplugin_dbuf_overflow = 0;
229*3941Svenki static char	snmpplugin_lbuf[SNMPPLUGIN_DMAX_LINE];
230*3941Svenki 
231*3941Svenki static void	snmpplugin_log_init(void);
232*3941Svenki static void	snmpplugin_log(const char *fmt, ...);
233*3941Svenki static void	snmpplugin_log_append(void);
234*3941Svenki static void	snmpplugin_dbuf_realloc(void);
235*3941Svenki #endif
236*3941Svenki 
237*3941Svenki static void
238*3941Svenki snmpplugin_register(void)
239*3941Svenki {
240*3941Svenki 	(void) picld_plugin_register(&snmpplugin_reg);
241*3941Svenki }
242*3941Svenki 
243*3941Svenki static void
244*3941Svenki register_group(char **g, int is_volatile)
245*3941Svenki {
246*3941Svenki 	int	i, len = 0;
247*3941Svenki 	int	n_oids;
248*3941Svenki 	char	*p, *oidstrs;
249*3941Svenki 
250*3941Svenki 	for (i = 0; g[i]; i++)
251*3941Svenki 		len += strlen(g[i]) + 1;
252*3941Svenki 	n_oids = i;
253*3941Svenki 
254*3941Svenki 	if ((oidstrs = (char *)calloc(1, len)) == NULL)
255*3941Svenki 		return;
256*3941Svenki 
257*3941Svenki 	for (p = oidstrs, i = 0; g[i]; i++) {
258*3941Svenki 		(void) strcpy(p, g[i]);
259*3941Svenki 		p += strlen(g[i]) + 1;
260*3941Svenki 	}
261*3941Svenki 
262*3941Svenki 	snmp_register_group(hdl, oidstrs, n_oids, is_volatile);
263*3941Svenki }
264*3941Svenki 
265*3941Svenki void
266*3941Svenki snmpplugin_init(void)
267*3941Svenki {
268*3941Svenki 	int		ret;
269*3941Svenki 
270*3941Svenki 	(void) mutex_init(&rebuild_tree_lock, USYNC_THREAD, NULL);
271*3941Svenki 	(void) cond_init(&rebuild_tree_cv, USYNC_THREAD, NULL);
272*3941Svenki 	(void) rwlock_init(&stale_tree_rwlp, USYNC_THREAD, NULL);
273*3941Svenki 	LOGINIT();
274*3941Svenki 
275*3941Svenki 	/*
276*3941Svenki 	 * Create the tree-builder thread and let it take over
277*3941Svenki 	 */
278*3941Svenki 	LOGPRINTF("Tree-builder thread being created.\n");
279*3941Svenki 	if ((ret = thr_create(NULL, NULL, tree_builder, NULL,
280*3941Svenki 	    THR_BOUND, NULL)) < 0) {
281*3941Svenki 		log_msg(LOG_ERR, SNMPP_CANT_CREATE_TREE_BUILDER, ret);
282*3941Svenki 		snmp_fini(hdl);
283*3941Svenki 		return;
284*3941Svenki 	}
285*3941Svenki }
286*3941Svenki 
287*3941Svenki void
288*3941Svenki snmpplugin_fini(void)
289*3941Svenki {
290*3941Svenki 	snmp_fini(hdl);
291*3941Svenki 
292*3941Svenki 	(void) rwlock_destroy(&stale_tree_rwlp);
293*3941Svenki 	(void) cond_destroy(&rebuild_tree_cv);
294*3941Svenki 	(void) mutex_destroy(&rebuild_tree_lock);
295*3941Svenki }
296*3941Svenki 
297*3941Svenki /*ARGSUSED*/
298*3941Svenki static void *
299*3941Svenki tree_builder(void *arg)
300*3941Svenki {
301*3941Svenki 	int		ret, rv;
302*3941Svenki 	picl_nodehdl_t	root_node;
303*3941Svenki 	picl_nodehdl_t	physplat_root;
304*3941Svenki 	picl_nodehdl_t	old_physplat_root;
305*3941Svenki 
306*3941Svenki 	/*
307*3941Svenki 	 * Initialize SNMP service
308*3941Svenki 	 */
309*3941Svenki 	LOGPRINTF("Initializing SNMP service.\n");
310*3941Svenki 	if ((hdl = snmp_init()) == NULL) {
311*3941Svenki 		log_msg(LOG_ERR, SNMPP_CANT_INIT);
312*3941Svenki 		return ((void *)-1);
313*3941Svenki 	}
314*3941Svenki 
315*3941Svenki 	/*
316*3941Svenki 	 * Register OID groupings for BULKGET optimizations
317*3941Svenki 	 */
318*3941Svenki 	LOGPRINTF("Registering OID groups.\n");
319*3941Svenki 	register_group(group1, 0);
320*3941Svenki 	register_group(group2, 0);
321*3941Svenki 	register_group(volgroup1, 1);
322*3941Svenki 	register_group(volgroup2, 1);
323*3941Svenki 
324*3941Svenki 	(void) mutex_lock(&rebuild_tree_lock);
325*3941Svenki 
326*3941Svenki 	for (;;) {
327*3941Svenki 		LOGPRINTF("tree_builder: check whether to rebuild subtree\n");
328*3941Svenki 		while (rebuild_tree == B_FALSE)
329*3941Svenki 			(void) cond_wait(&rebuild_tree_cv, &rebuild_tree_lock);
330*3941Svenki 
331*3941Svenki 		LOGPRINTF("tree_builder: woke up\n");
332*3941Svenki 
333*3941Svenki 		old_physplat_root = NULL;
334*3941Svenki 		physplat_root = NULL;
335*3941Svenki 
336*3941Svenki 		LOGPRINTF("tree_builder: getting root node\n");
337*3941Svenki 		if ((ret = ptree_get_root(&root_node)) != PICL_SUCCESS) {
338*3941Svenki 			log_msg(LOG_ERR, SNMPP_NO_ROOT, ret);
339*3941Svenki 			return ((void *)-2);
340*3941Svenki 		}
341*3941Svenki 
342*3941Svenki 		LOGPRINTF("tree_builder: getting existing physplat node\n");
343*3941Svenki 		rv = ptree_find_node(root_node, PICL_PROP_NAME,
344*3941Svenki 		    PICL_PTYPE_CHARSTRING, PICL_NODE_PHYSPLAT,
345*3941Svenki 		    sizeof (PICL_NODE_PHYSPLAT), &old_physplat_root);
346*3941Svenki 
347*3941Svenki 		LOGPRINTF("tree_builder: building physical-platform\n");
348*3941Svenki 		if ((ret = build_physplat(&physplat_root)) < 0) {
349*3941Svenki 			log_msg(LOG_ERR, SNMPP_CANT_CREATE_PHYSPLAT, ret);
350*3941Svenki 			snmp_fini(hdl);
351*3941Svenki 			return ((void *)-3);
352*3941Svenki 		}
353*3941Svenki 
354*3941Svenki 		if (rv == PICL_SUCCESS && old_physplat_root != NULL) {
355*3941Svenki 			LOGPRINTF("tree_builder: destroying existing nodes\n");
356*3941Svenki 			ptree_delete_node(old_physplat_root);
357*3941Svenki 			ptree_destroy_node(old_physplat_root);
358*3941Svenki 		}
359*3941Svenki 
360*3941Svenki 		LOGPRINTF("tree_builder: attaching new subtree\n");
361*3941Svenki 		if ((ret = ptree_add_node(root_node, physplat_root)) < 0) {
362*3941Svenki 			free_resources(physplat_root);
363*3941Svenki 			log_msg(LOG_ERR, SNMPP_CANT_CREATE_PHYSPLAT, ret);
364*3941Svenki 			snmp_fini(hdl);
365*3941Svenki 			return ((void *)-4);
366*3941Svenki 		}
367*3941Svenki 
368*3941Svenki 		LOGPRINTF("tree_builder: setting stale_tree to FALSE\n");
369*3941Svenki 		(void) rw_wrlock(&stale_tree_rwlp);
370*3941Svenki 		stale_tree = B_FALSE;
371*3941Svenki 		(void) rw_unlock(&stale_tree_rwlp);
372*3941Svenki 
373*3941Svenki 		LOGPRINTF("tree_builder: setting rebuild_tree to FALSE\n");
374*3941Svenki 		rebuild_tree = B_FALSE;
375*3941Svenki 	}
376*3941Svenki 
377*3941Svenki 	/*NOTREACHED*/
378*3941Svenki 	return (NULL);
379*3941Svenki }
380*3941Svenki 
381*3941Svenki static int
382*3941Svenki build_physplat(picl_nodehdl_t *subtree_rootp)
383*3941Svenki {
384*3941Svenki 	int	change_time1;
385*3941Svenki 	int	row, nxtrow;
386*3941Svenki 	int	clr_linkreset = 0;
387*3941Svenki 	int	ret = 0;
388*3941Svenki 	int	snmp_syserr = 0;
389*3941Svenki 
390*3941Svenki retry:
391*3941Svenki 	(void) snmp_reinit(hdl, clr_linkreset);
392*3941Svenki 	clr_linkreset = 0;
393*3941Svenki 
394*3941Svenki 	/*
395*3941Svenki 	 * Record LastChangeTime before we start building the tree
396*3941Svenki 	 */
397*3941Svenki 	ret = snmp_get_int(hdl, OID_entLastChangeTime, 0,
398*3941Svenki 	    &change_time1, &snmp_syserr);
399*3941Svenki 	if (ret < 0) {
400*3941Svenki 		if (snmp_syserr == ECANCELED) {
401*3941Svenki 			log_msg(LOG_WARNING, SNMPP_LINK_RESET);
402*3941Svenki 			clr_linkreset = 1;
403*3941Svenki 			goto retry;
404*3941Svenki 		} else
405*3941Svenki 			log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, ret);
406*3941Svenki 	}
407*3941Svenki 
408*3941Svenki 	/*
409*3941Svenki 	 * Create the physical-platform node
410*3941Svenki 	 */
411*3941Svenki 	ret = ptree_create_node(PICL_NODE_PHYSPLAT, PICL_CLASS_PICL,
412*3941Svenki 	    subtree_rootp);
413*3941Svenki 	if (ret != PICL_SUCCESS)
414*3941Svenki 		return (-1);
415*3941Svenki 
416*3941Svenki 	/*
417*3941Svenki 	 * Scan entPhysicalTable and build the "physical-platform" subtree
418*3941Svenki 	 */
419*3941Svenki 	ret = 0;
420*3941Svenki 	for (row = -1; ret == 0; row = nxtrow) {
421*3941Svenki 		ret = snmp_get_nextrow(hdl, OID_entPhysicalDescr,
422*3941Svenki 		    row, &nxtrow, &snmp_syserr);
423*3941Svenki 		if (ret == 0) {
424*3941Svenki 			(void) make_node(*subtree_rootp, nxtrow, &snmp_syserr);
425*3941Svenki 		}
426*3941Svenki 
427*3941Svenki 		if (snmp_syserr == ECANCELED) {
428*3941Svenki 			/*
429*3941Svenki 			 * If we get this error, a link reset must've
430*3941Svenki 			 * happened and we need to throw away everything
431*3941Svenki 			 * we have now and rebuild the tree again.
432*3941Svenki 			 */
433*3941Svenki 			log_msg(LOG_WARNING, SNMPP_LINK_RESET);
434*3941Svenki 			free_resources(*subtree_rootp);
435*3941Svenki 			clr_linkreset = 1;
436*3941Svenki 			goto retry;
437*3941Svenki 		}
438*3941Svenki 	}
439*3941Svenki 
440*3941Svenki 	/*
441*3941Svenki 	 * Record LastChangeTime after we're done building the tree
442*3941Svenki 	 */
443*3941Svenki 	ret = snmp_get_int(hdl, OID_entLastChangeTime, 0,
444*3941Svenki 	    &change_time, &snmp_syserr);
445*3941Svenki 	if (ret < 0) {
446*3941Svenki 		if (snmp_syserr == ECANCELED) {
447*3941Svenki 			log_msg(LOG_WARNING, SNMPP_LINK_RESET);
448*3941Svenki 			free_resources(*subtree_rootp);
449*3941Svenki 			clr_linkreset = 1;
450*3941Svenki 			goto retry;
451*3941Svenki 		} else
452*3941Svenki 			log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, ret);
453*3941Svenki 	}
454*3941Svenki 
455*3941Svenki 	/*
456*3941Svenki 	 * If they don't match, some hotplugging must've happened,
457*3941Svenki 	 * free resources we've created and still holding, then go
458*3941Svenki 	 * back and retry
459*3941Svenki 	 */
460*3941Svenki 	if (change_time != change_time1) {
461*3941Svenki 		LOGPRINTF("build_physplat: entLastChangeTime has changed!\n");
462*3941Svenki 		free_resources(*subtree_rootp);
463*3941Svenki 		change_time1 = change_time;
464*3941Svenki 		goto retry;
465*3941Svenki 	}
466*3941Svenki 
467*3941Svenki 	/*
468*3941Svenki 	 * The physplat_nodes table is no longer needed, free it
469*3941Svenki 	 */
470*3941Svenki 	if (physplat_nodes) {
471*3941Svenki 		free(physplat_nodes);
472*3941Svenki 		physplat_nodes = NULL;
473*3941Svenki 		n_physplat_nodes = 0;
474*3941Svenki 	}
475*3941Svenki 
476*3941Svenki 	return (0);
477*3941Svenki }
478*3941Svenki 
479*3941Svenki /*
480*3941Svenki  * Destroy all resources that were created during the building
481*3941Svenki  * of the subtree
482*3941Svenki  */
483*3941Svenki static void
484*3941Svenki free_resources(picl_nodehdl_t subtree_root)
485*3941Svenki {
486*3941Svenki 	if (physplat_nodes) {
487*3941Svenki 		free(physplat_nodes);
488*3941Svenki 		physplat_nodes = NULL;
489*3941Svenki 		n_physplat_nodes = 0;
490*3941Svenki 	}
491*3941Svenki 
492*3941Svenki 	if (subtree_root) {
493*3941Svenki 		(void) ptree_delete_node(subtree_root);
494*3941Svenki 		(void) ptree_destroy_node(subtree_root);
495*3941Svenki 	}
496*3941Svenki 
497*3941Svenki 	if (vol_props) {
498*3941Svenki 		free(vol_props);
499*3941Svenki 		n_vol_props = 0;
500*3941Svenki 		volprop_ndx = 0;
501*3941Svenki 	}
502*3941Svenki }
503*3941Svenki 
504*3941Svenki static picl_nodehdl_t
505*3941Svenki make_node(picl_nodehdl_t subtree_root, int row, int *snmp_syserr_p)
506*3941Svenki {
507*3941Svenki 	picl_nodehdl_t	nodeh, parenth;
508*3941Svenki 	picl_prophdl_t	proph;
509*3941Svenki 	char	*phys_name, *node_name;
510*3941Svenki 	int	parent_row;
511*3941Svenki 	int	ent_physclass, sunplat_physclass;
512*3941Svenki 	int	sensor_class, sensor_type;
513*3941Svenki 	int	alarm_type;
514*3941Svenki 	int	ps_class;
515*3941Svenki 	int	ret;
516*3941Svenki 
517*3941Svenki 	/*
518*3941Svenki 	 * If we've already created this picl node, just return it
519*3941Svenki 	 */
520*3941Svenki 	if ((nodeh = lookup_nodeh(row)) != NULL)
521*3941Svenki 		return (nodeh);
522*3941Svenki 
523*3941Svenki 	/*
524*3941Svenki 	 * If we are creating it only now, make sure we have the parent
525*3941Svenki 	 * created first; if there's no parent, then parent it to the
526*3941Svenki 	 * subtree's root node
527*3941Svenki 	 */
528*3941Svenki 	ret = snmp_get_int(hdl, OID_entPhysicalContainedIn, row,
529*3941Svenki 	    &parent_row, snmp_syserr_p);
530*3941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
531*3941Svenki 	if (ret < 0 || parent_row <= 0)
532*3941Svenki 		parenth = subtree_root;
533*3941Svenki 	else {
534*3941Svenki 		parenth = make_node(subtree_root, parent_row, snmp_syserr_p);
535*3941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
536*3941Svenki 		if (parenth == NULL)
537*3941Svenki 			parenth = subtree_root;
538*3941Svenki 	}
539*3941Svenki 
540*3941Svenki 	/*
541*3941Svenki 	 * Figure out the physical-platform node name from entPhysicalName;
542*3941Svenki 	 * all rows in the MIB that have a valid entPhysicalIndex should
543*3941Svenki 	 * have a physical name.
544*3941Svenki 	 */
545*3941Svenki 	ret = snmp_get_str(hdl, OID_entPhysicalName, row,
546*3941Svenki 	    &phys_name, snmp_syserr_p);
547*3941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
548*3941Svenki 	if (ret < 0 || phys_name == NULL) {
549*3941Svenki 		log_msg(LOG_WARNING, SNMPP_NO_ENTPHYSNAME, row);
550*3941Svenki 		return (NULL);
551*3941Svenki 	}
552*3941Svenki 
553*3941Svenki 	node_name = basename(phys_name);
554*3941Svenki 
555*3941Svenki 	ret = snmp_get_int(hdl, OID_entPhysicalClass, row,
556*3941Svenki 	    &ent_physclass, snmp_syserr_p);
557*3941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
558*3941Svenki 	if (ret < 0) {
559*3941Svenki 		log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, ret);
560*3941Svenki 		free(phys_name);
561*3941Svenki 		return (NULL);
562*3941Svenki 	}
563*3941Svenki 
564*3941Svenki 	switch (ent_physclass) {
565*3941Svenki 	case SPC_OTHER:
566*3941Svenki 		ret = snmp_get_int(hdl, OID_sunPlatPhysicalClass, row,
567*3941Svenki 		    &sunplat_physclass, snmp_syserr_p);
568*3941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
569*3941Svenki 		if (ret < 0) {
570*3941Svenki 			log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, ret);
571*3941Svenki 			free(phys_name);
572*3941Svenki 			return (NULL);
573*3941Svenki 		}
574*3941Svenki 
575*3941Svenki 		if (sunplat_physclass == SSPC_ALARM) {
576*3941Svenki 			ret = snmp_get_int(hdl, OID_sunPlatAlarmType,
577*3941Svenki 			    row, &alarm_type, snmp_syserr_p);
578*3941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
579*3941Svenki 			if (ret < 0) {
580*3941Svenki 				log_msg(LOG_WARNING,
581*3941Svenki 				    SNMPP_CANT_FETCH_OBJECT_VAL, ret);
582*3941Svenki 				free(phys_name);
583*3941Svenki 				return (NULL);
584*3941Svenki 			}
585*3941Svenki 
586*3941Svenki 			if (alarm_type == SSAT_VISIBLE) {
587*3941Svenki 			    ADD_NODE(PICL_CLASS_LED)
588*3941Svenki 			} else {
589*3941Svenki 			    ADD_NODE(PICL_CLASS_ALARM)
590*3941Svenki 			}
591*3941Svenki 
592*3941Svenki 			add_prop(nodeh, &proph, node_name, row, PP_STATE,
593*3941Svenki 			    snmp_syserr_p);
594*3941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
595*3941Svenki 		} else {
596*3941Svenki 			ADD_NODE(PICL_CLASS_OTHER)
597*3941Svenki 		}
598*3941Svenki 
599*3941Svenki 		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
600*3941Svenki 		    snmp_syserr_p);
601*3941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
602*3941Svenki 		break;
603*3941Svenki 
604*3941Svenki 	case SPC_UNKNOWN:
605*3941Svenki 		ADD_NODE(PICL_CLASS_UNKNOWN)
606*3941Svenki 		break;
607*3941Svenki 
608*3941Svenki 	case SPC_CHASSIS:
609*3941Svenki 		ADD_NODE(PICL_CLASS_CHASSIS)
610*3941Svenki 		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
611*3941Svenki 		    snmp_syserr_p);
612*3941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
613*3941Svenki 		break;
614*3941Svenki 
615*3941Svenki 	case SPC_BACKPLANE:
616*3941Svenki 		ADD_NODE(PICL_CLASS_BACKPLANE)
617*3941Svenki 		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
618*3941Svenki 		    snmp_syserr_p);
619*3941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
620*3941Svenki 		break;
621*3941Svenki 
622*3941Svenki 	case SPC_CONTAINER:
623*3941Svenki 		ADD_NODE(PICL_CLASS_CONTAINER)
624*3941Svenki 
625*3941Svenki 		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
626*3941Svenki 		    snmp_syserr_p);
627*3941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
628*3941Svenki 
629*3941Svenki 		add_prop(nodeh, &proph, node_name, row, PP_SLOT_TYPE,
630*3941Svenki 		    snmp_syserr_p);
631*3941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
632*3941Svenki 		break;
633*3941Svenki 
634*3941Svenki 	case SPC_POWERSUPPLY:
635*3941Svenki 		ret = snmp_get_int(hdl, OID_sunPlatPowerSupplyClass,
636*3941Svenki 		    row, &ps_class, snmp_syserr_p);
637*3941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
638*3941Svenki 		if (ret < 0) {
639*3941Svenki 			log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, ret);
640*3941Svenki 			free(phys_name);
641*3941Svenki 			return (NULL);
642*3941Svenki 		}
643*3941Svenki 
644*3941Svenki 		if (ps_class == SSPSC_BATTERY) {
645*3941Svenki 			ADD_NODE(PICL_CLASS_BATTERY)
646*3941Svenki 			add_prop(nodeh, &proph, node_name, row,
647*3941Svenki 			    PP_BATT_STATUS, snmp_syserr_p);
648*3941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
649*3941Svenki 		} else {
650*3941Svenki 			ADD_NODE(PICL_CLASS_POWERSUPPLY)
651*3941Svenki 		}
652*3941Svenki 		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
653*3941Svenki 		    snmp_syserr_p);
654*3941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
655*3941Svenki 		break;
656*3941Svenki 
657*3941Svenki 	case SPC_FAN:
658*3941Svenki 		ADD_NODE(PICL_CLASS_FAN)
659*3941Svenki 		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
660*3941Svenki 		    snmp_syserr_p);
661*3941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
662*3941Svenki 		break;
663*3941Svenki 
664*3941Svenki 	case SPC_SENSOR:
665*3941Svenki 		ret = snmp_get_int(hdl, OID_sunPlatSensorClass,
666*3941Svenki 		    row, &sensor_class, snmp_syserr_p);
667*3941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
668*3941Svenki 		if (ret < 0) {
669*3941Svenki 			log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, ret);
670*3941Svenki 			free(phys_name);
671*3941Svenki 			return (NULL);
672*3941Svenki 		}
673*3941Svenki 
674*3941Svenki 		ret = snmp_get_int(hdl, OID_sunPlatSensorType,
675*3941Svenki 		    row, &sensor_type, snmp_syserr_p);
676*3941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
677*3941Svenki 		if (ret < 0) {
678*3941Svenki 			log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, ret);
679*3941Svenki 			free(phys_name);
680*3941Svenki 			return (NULL);
681*3941Svenki 		}
682*3941Svenki 
683*3941Svenki 		if (sensor_class == SSSC_NUMERIC) {
684*3941Svenki 			if (sensor_type == SSST_TEMPERATURE) {
685*3941Svenki 				ADD_NODE(PICL_CLASS_TEMPERATURE_SENSOR)
686*3941Svenki 				add_prop(nodeh, &proph, node_name, row,
687*3941Svenki 				    PP_TEMPERATURE, snmp_syserr_p);
688*3941Svenki 			} else if (sensor_type == SSST_VOLTAGE) {
689*3941Svenki 				ADD_NODE(PICL_CLASS_VOLTAGE_SENSOR)
690*3941Svenki 				add_prop(nodeh, &proph, node_name, row,
691*3941Svenki 				    PP_VOLTAGE, snmp_syserr_p);
692*3941Svenki 			} else if (sensor_type == SSST_CURRENT) {
693*3941Svenki 				ADD_NODE(PICL_CLASS_CURRENT_SENSOR)
694*3941Svenki 				add_prop(nodeh, &proph, node_name, row,
695*3941Svenki 				    PP_CURRENT, snmp_syserr_p);
696*3941Svenki 			} else if (sensor_type == SSST_TACHOMETER) {
697*3941Svenki 				ADD_NODE(PICL_CLASS_RPM_SENSOR)
698*3941Svenki 				add_prop(nodeh, &proph, node_name, row,
699*3941Svenki 				    PP_SPEED, snmp_syserr_p);
700*3941Svenki 			} else {
701*3941Svenki 				ADD_NODE(PICL_CLASS_SENSOR)
702*3941Svenki 				add_prop(nodeh, &proph, node_name, row,
703*3941Svenki 				    PP_SENSOR_VALUE, snmp_syserr_p);
704*3941Svenki 			}
705*3941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
706*3941Svenki 
707*3941Svenki 			add_prop(nodeh, &proph, node_name, row,
708*3941Svenki 			    PP_OPSTATUS, snmp_syserr_p);
709*3941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
710*3941Svenki 
711*3941Svenki 			add_prop(nodeh, &proph, node_name, row,
712*3941Svenki 			    PP_BASE_UNITS, snmp_syserr_p);
713*3941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
714*3941Svenki 
715*3941Svenki 			add_prop(nodeh, &proph, node_name, row,
716*3941Svenki 			    PP_EXPONENT, snmp_syserr_p);
717*3941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
718*3941Svenki 
719*3941Svenki 			add_prop(nodeh, &proph, node_name, row,
720*3941Svenki 			    PP_RATE_UNITS, snmp_syserr_p);
721*3941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
722*3941Svenki 
723*3941Svenki 			add_thresholds(nodeh, row, snmp_syserr_p);
724*3941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
725*3941Svenki 
726*3941Svenki 		} else if (sensor_class == SSSC_BINARY) {
727*3941Svenki 			if (sensor_type == SSST_TEMPERATURE) {
728*3941Svenki 				ADD_NODE(PICL_CLASS_TEMPERATURE_INDICATOR)
729*3941Svenki 			} else if (sensor_type == SSST_VOLTAGE) {
730*3941Svenki 				ADD_NODE(PICL_CLASS_VOLTAGE_INDICATOR)
731*3941Svenki 			} else if (sensor_type == SSST_CURRENT) {
732*3941Svenki 				ADD_NODE(PICL_CLASS_CURRENT_INDICATOR)
733*3941Svenki 			} else if (sensor_type == SSST_TACHOMETER) {
734*3941Svenki 				ADD_NODE(PICL_CLASS_RPM_INDICATOR)
735*3941Svenki 			} else if (sensor_type == SSST_PRESENCE) {
736*3941Svenki 				ADD_NODE(PICL_CLASS_PRESENCE_INDICATOR)
737*3941Svenki 			} else {
738*3941Svenki 				ADD_NODE(PICL_CLASS_INDICATOR)
739*3941Svenki 			}
740*3941Svenki 
741*3941Svenki 			add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
742*3941Svenki 			    snmp_syserr_p);
743*3941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
744*3941Svenki 
745*3941Svenki 			add_prop(nodeh, &proph, node_name, row, PP_CONDITION,
746*3941Svenki 			    snmp_syserr_p);
747*3941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
748*3941Svenki 
749*3941Svenki 			add_prop(nodeh, &proph, node_name, row, PP_EXPECTED,
750*3941Svenki 			    snmp_syserr_p);
751*3941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
752*3941Svenki 		} else {
753*3941Svenki 			log_msg(LOG_ERR,
754*3941Svenki 			    SNMPP_UNSUPP_SENSOR_CLASS, sensor_class, row);
755*3941Svenki 			return (NULL);
756*3941Svenki 		}
757*3941Svenki 		break;
758*3941Svenki 
759*3941Svenki 	case SPC_MODULE:
760*3941Svenki 		ADD_NODE(PICL_CLASS_MODULE)
761*3941Svenki 
762*3941Svenki 		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
763*3941Svenki 		    snmp_syserr_p);
764*3941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
765*3941Svenki 
766*3941Svenki 		add_prop(nodeh, &proph, node_name, row, PP_REPLACEABLE,
767*3941Svenki 		    snmp_syserr_p);
768*3941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
769*3941Svenki 
770*3941Svenki 		add_prop(nodeh, &proph, node_name, row, PP_HOTSWAPPABLE,
771*3941Svenki 		    snmp_syserr_p);
772*3941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
773*3941Svenki 		break;
774*3941Svenki 
775*3941Svenki 	case SPC_PORT:
776*3941Svenki 		ADD_NODE(PICL_CLASS_PORT)
777*3941Svenki 		break;
778*3941Svenki 
779*3941Svenki 	case SPC_STACK:
780*3941Svenki 		ADD_NODE(PICL_CLASS_STACK)
781*3941Svenki 		break;
782*3941Svenki 
783*3941Svenki 	default:
784*3941Svenki 		log_msg(LOG_WARNING,
785*3941Svenki 		    SNMPP_UNKNOWN_ENTPHYSCLASS, ent_physclass, row);
786*3941Svenki 		free(phys_name);
787*3941Svenki 		return (NULL);
788*3941Svenki 	}
789*3941Svenki 
790*3941Svenki 	add_prop(nodeh, &proph, node_name, row, PP_DESCRIPTION, snmp_syserr_p);
791*3941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
792*3941Svenki 
793*3941Svenki 	add_prop(nodeh, &proph, node_name, row, PP_LABEL, snmp_syserr_p);
794*3941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
795*3941Svenki 
796*3941Svenki 	add_prop(nodeh, &proph, node_name, row, PP_HW_REVISION, snmp_syserr_p);
797*3941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
798*3941Svenki 
799*3941Svenki 	add_prop(nodeh, &proph, node_name, row, PP_FW_REVISION, snmp_syserr_p);
800*3941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
801*3941Svenki 
802*3941Svenki 	add_prop(nodeh, &proph, node_name, row, PP_SERIAL_NUM, snmp_syserr_p);
803*3941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
804*3941Svenki 
805*3941Svenki 	add_prop(nodeh, &proph, node_name, row, PP_MFG_NAME, snmp_syserr_p);
806*3941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
807*3941Svenki 
808*3941Svenki 	add_prop(nodeh, &proph, node_name, row, PP_MODEL_NAME, snmp_syserr_p);
809*3941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
810*3941Svenki 
811*3941Svenki 	add_prop(nodeh, &proph, node_name, row, PP_IS_FRU, snmp_syserr_p);
812*3941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
813*3941Svenki 
814*3941Svenki 	free(phys_name);
815*3941Svenki 	save_nodeh(nodeh, row);
816*3941Svenki 
817*3941Svenki 	return (nodeh);
818*3941Svenki }
819*3941Svenki 
820*3941Svenki /*
821*3941Svenki  * Saves the node handle and the row id into physplat_nodes[]. If we're
822*3941Svenki  * doing this in response to a hotplug event, we should've freed the
823*3941Svenki  * old physplat_nodes before entering here to save the first node of the
824*3941Svenki  * new physplat subtree.
825*3941Svenki  */
826*3941Svenki static void
827*3941Svenki save_nodeh(picl_nodehdl_t nodeh, int row)
828*3941Svenki {
829*3941Svenki 	size_t		sz, count;
830*3941Svenki 	picl_nodehdl_t	*p;
831*3941Svenki 
832*3941Svenki 	if (row >= n_physplat_nodes) {
833*3941Svenki 		count = (((size_t)row >> NODE_BLOCK_SHIFT) + 1) *
834*3941Svenki 		    N_ELEMS_IN_NODE_BLOCK;
835*3941Svenki 		sz = count * sizeof (picl_nodehdl_t);
836*3941Svenki 
837*3941Svenki 		p = (picl_nodehdl_t *)calloc(count, sizeof (picl_nodehdl_t));
838*3941Svenki 		if (p == NULL) {
839*3941Svenki 			log_msg(LOG_ERR, SNMPP_NO_MEM, sz);
840*3941Svenki 			return;
841*3941Svenki 		}
842*3941Svenki 
843*3941Svenki 		if (physplat_nodes) {
844*3941Svenki 			(void) memcpy((void *) p, (void *) physplat_nodes,
845*3941Svenki 			    n_physplat_nodes * sizeof (picl_nodehdl_t));
846*3941Svenki 			free((void *) physplat_nodes);
847*3941Svenki 		}
848*3941Svenki 
849*3941Svenki 		physplat_nodes = p;
850*3941Svenki 		n_physplat_nodes = count;
851*3941Svenki 	}
852*3941Svenki 
853*3941Svenki 	physplat_nodes[row] = nodeh;
854*3941Svenki }
855*3941Svenki 
856*3941Svenki static picl_nodehdl_t
857*3941Svenki lookup_nodeh(int row)
858*3941Svenki {
859*3941Svenki 	if (row >= n_physplat_nodes)
860*3941Svenki 		return (NULL);
861*3941Svenki 
862*3941Svenki 	return (physplat_nodes[row]);
863*3941Svenki }
864*3941Svenki 
865*3941Svenki /*
866*3941Svenki  * We enter this routine only when we are building the physical-platform
867*3941Svenki  * subtree, whether for the first time or in response to a hotplug event.
868*3941Svenki  * If we're here for rebuilding the tree, we have already set stale_tree
869*3941Svenki  * to be B_TRUE, so no one else would be accessing vol_props, n_vol_props
870*3941Svenki  * or volprop_ndx. If we're here to build the tree for the first time,
871*3941Svenki  * picld hasn't yet created doors and is running single-threaded, so no
872*3941Svenki  * one else would be accessing them anyway.
873*3941Svenki  */
874*3941Svenki static void
875*3941Svenki save_volprop(picl_prophdl_t prop, char *oidstr, int row, int proptype)
876*3941Svenki {
877*3941Svenki 	vol_prophdl_t	*p;
878*3941Svenki 	int		count;
879*3941Svenki 
880*3941Svenki 	if (volprop_ndx == n_vol_props) {
881*3941Svenki 		count = n_vol_props + N_ELEMS_IN_VOLPROP_BLOCK;
882*3941Svenki 		p = (vol_prophdl_t *)calloc(count, sizeof (vol_prophdl_t));
883*3941Svenki 		if (p == NULL) {
884*3941Svenki 			log_msg(LOG_ERR, SNMPP_NO_MEM,
885*3941Svenki 			    count * sizeof (vol_prophdl_t));
886*3941Svenki 			return;
887*3941Svenki 		}
888*3941Svenki 
889*3941Svenki 		if (vol_props) {
890*3941Svenki 			(void) memcpy((void *) p, (void *) vol_props,
891*3941Svenki 			    n_vol_props * sizeof (vol_prophdl_t));
892*3941Svenki 			free((void *) vol_props);
893*3941Svenki 		}
894*3941Svenki 
895*3941Svenki 		vol_props = p;
896*3941Svenki 		n_vol_props += N_ELEMS_IN_VOLPROP_BLOCK;
897*3941Svenki 	}
898*3941Svenki 
899*3941Svenki 	vol_props[volprop_ndx].prop = prop;
900*3941Svenki 	vol_props[volprop_ndx].oidstr = oidstr;
901*3941Svenki 	vol_props[volprop_ndx].row = row;
902*3941Svenki 	vol_props[volprop_ndx].proptype = proptype;
903*3941Svenki 
904*3941Svenki 	volprop_ndx++;
905*3941Svenki }
906*3941Svenki 
907*3941Svenki static void
908*3941Svenki check_for_stale_data(void)
909*3941Svenki {
910*3941Svenki 	int	cur_change_time;
911*3941Svenki 	int	ret;
912*3941Svenki 	int	snmp_syserr;
913*3941Svenki 
914*3941Svenki 	(void) rw_wrlock(&stale_tree_rwlp);
915*3941Svenki 
916*3941Svenki 	/*
917*3941Svenki 	 * Check if some other thread beat us to it
918*3941Svenki 	 */
919*3941Svenki 	if (stale_tree == B_TRUE) {
920*3941Svenki 		(void) rw_unlock(&stale_tree_rwlp);
921*3941Svenki 		return;
922*3941Svenki 	}
923*3941Svenki 
924*3941Svenki 	/*
925*3941Svenki 	 * Check if mib data has changed (hotplug? link-reset?)
926*3941Svenki 	 */
927*3941Svenki 	ret = snmp_get_int(hdl, OID_entLastChangeTime, 0, &cur_change_time,
928*3941Svenki 	    &snmp_syserr);
929*3941Svenki 	if ((ret == 0) && (cur_change_time == change_time)) {
930*3941Svenki 		(void) rw_unlock(&stale_tree_rwlp);
931*3941Svenki 		return;
932*3941Svenki 	}
933*3941Svenki 
934*3941Svenki 	/*
935*3941Svenki 	 * If we can't read entLastChangeTime we assume we need to rebuild
936*3941Svenki 	 * the tree. This will also cover the case when we need to rebuild
937*3941Svenki 	 * the tree because a link reset had happened.
938*3941Svenki 	 */
939*3941Svenki 	LOGPRINTF2("check_for_stale_data: LastChange times have changed, "
940*3941Svenki 	    "(%#x != %#x)\n", change_time, cur_change_time);
941*3941Svenki 
942*3941Svenki 	/*
943*3941Svenki 	 * If the mib data has changed, we need to rebuild the physical-platform
944*3941Svenki 	 * subtree. To do this, we set a flag to mark the tree stale,
945*3941Svenki 	 * so that any future reads to get value of volatile properties will
946*3941Svenki 	 * return PICL_PROPVALUNAVAILABLE, until the stale_tree flag
947*3941Svenki 	 * is reset by the tree builder thread.
948*3941Svenki 	 */
949*3941Svenki 	stale_tree = B_TRUE;
950*3941Svenki 	if (vol_props) {
951*3941Svenki 		free(vol_props);
952*3941Svenki 	}
953*3941Svenki 	vol_props = NULL;
954*3941Svenki 	volprop_ndx = 0;
955*3941Svenki 	n_vol_props = 0;
956*3941Svenki 
957*3941Svenki 	(void) rw_unlock(&stale_tree_rwlp);
958*3941Svenki 
959*3941Svenki 	(void) mutex_lock(&rebuild_tree_lock);
960*3941Svenki 	rebuild_tree = B_TRUE;
961*3941Svenki 	(void) cond_signal(&rebuild_tree_cv);
962*3941Svenki 	LOGPRINTF("check_for_stale_data: signalled tree builder\n");
963*3941Svenki 	(void) mutex_unlock(&rebuild_tree_lock);
964*3941Svenki }
965*3941Svenki 
966*3941Svenki /*
967*3941Svenki  * This is the critical routine.  This callback is invoked by picl whenever
968*3941Svenki  * it needs to fetch the value of a volatile property. The first thing we
969*3941Svenki  * must do, however, is to see if there has been a hotplug or a link-reset
970*3941Svenki  * event since the last time we built the tree and whether we need to
971*3941Svenki  * rebuild the tree. If so, we do whatever is necessary to make that happen,
972*3941Svenki  * but return PICL_PROPVALUNAVAILABLE for now, without making any further
973*3941Svenki  * snmp requests or accessing any globals.
974*3941Svenki  */
975*3941Svenki static int
976*3941Svenki read_volprop(ptree_rarg_t *parg, void *buf)
977*3941Svenki {
978*3941Svenki 	char	*pstr;
979*3941Svenki 	int	propval;
980*3941Svenki 	int	i, ndx;
981*3941Svenki 	int	ret;
982*3941Svenki 	int	snmp_syserr = 0;
983*3941Svenki 
984*3941Svenki 	/*
985*3941Svenki 	 * First check for any event that would make us throw away
986*3941Svenki 	 * the existing /physical-platform subtree and rebuild
987*3941Svenki 	 * another one. If we are rebuilding the subtree, we just
988*3941Svenki 	 * return the stale value until the tree is fully built.
989*3941Svenki 	 */
990*3941Svenki 	check_for_stale_data();
991*3941Svenki 
992*3941Svenki 	(void) rw_rdlock(&stale_tree_rwlp);
993*3941Svenki 
994*3941Svenki 	if (stale_tree == B_TRUE) {
995*3941Svenki 		(void) rw_unlock(&stale_tree_rwlp);
996*3941Svenki 		return (PICL_PROPVALUNAVAILABLE);
997*3941Svenki 	}
998*3941Svenki 
999*3941Svenki 	for (i = 0; i < volprop_ndx; i++) {
1000*3941Svenki 		if (vol_props[i].prop == parg->proph) {
1001*3941Svenki 			ndx = i;
1002*3941Svenki 			break;
1003*3941Svenki 		}
1004*3941Svenki 	}
1005*3941Svenki 	if (i == volprop_ndx) {
1006*3941Svenki 		log_msg(LOG_ERR, SNMPP_CANT_FIND_VOLPROP, parg->proph);
1007*3941Svenki 		return (PICL_FAILURE);
1008*3941Svenki 	}
1009*3941Svenki 
1010*3941Svenki 	/*
1011*3941Svenki 	 * If we can't read the value, return failure. Even if this was
1012*3941Svenki 	 * due to a link reset, between the check for stale data and now,
1013*3941Svenki 	 * the next volatile callback by picl will initiate a tree-rebuild.
1014*3941Svenki 	 */
1015*3941Svenki 	ret = snmp_get_int(hdl, vol_props[ndx].oidstr, vol_props[ndx].row,
1016*3941Svenki 	    &propval, &snmp_syserr);
1017*3941Svenki 	if (ret < 0) {
1018*3941Svenki 		log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, ret);
1019*3941Svenki 		return (PICL_FAILURE);
1020*3941Svenki 	}
1021*3941Svenki 
1022*3941Svenki 	switch (vol_props[ndx].proptype) {
1023*3941Svenki 	case VPT_PLATOPSTATE:
1024*3941Svenki 		if (propval == SSOS_DISABLED) {
1025*3941Svenki 			(void) strlcpy(buf, STR_SSOS_DISABLED, MAX_OPSTATE_LEN);
1026*3941Svenki 		} else if (propval == SSOS_ENABLED) {
1027*3941Svenki 			(void) strlcpy(buf, STR_SSOS_ENABLED, MAX_OPSTATE_LEN);
1028*3941Svenki 		} else {
1029*3941Svenki 			log_msg(LOG_ERR, SNMPP_INV_PLAT_EQUIP_OPSTATE,
1030*3941Svenki 			    propval, vol_props[ndx].row);
1031*3941Svenki 			return (PICL_FAILURE);
1032*3941Svenki 		}
1033*3941Svenki 		break;
1034*3941Svenki 
1035*3941Svenki 	case VPT_NUMSENSOR:
1036*3941Svenki 		(void) memcpy(buf, &propval, sizeof (propval));
1037*3941Svenki 		break;
1038*3941Svenki 
1039*3941Svenki 	case VPT_BINSENSOR:
1040*3941Svenki 		if (propval == ST_TRUE) {
1041*3941Svenki 			ret = snmp_get_str(hdl,
1042*3941Svenki 			    OID_sunPlatBinarySensorInterpretTrue,
1043*3941Svenki 			    vol_props[ndx].row, &pstr, &snmp_syserr);
1044*3941Svenki 			if (snmp_syserr == ECANCELED)
1045*3941Svenki 				return (PICL_FAILURE);
1046*3941Svenki 			if (ret < 0 || pstr == NULL) {
1047*3941Svenki 				(void) strlcpy(buf, STR_ST_TRUE,
1048*3941Svenki 				    MAX_TRUTHVAL_LEN);
1049*3941Svenki 			} else {
1050*3941Svenki 				(void) strlcpy(buf, pstr, MAX_TRUTHVAL_LEN);
1051*3941Svenki 				free(pstr);
1052*3941Svenki 			}
1053*3941Svenki 		} else if (propval == ST_FALSE) {
1054*3941Svenki 			ret = snmp_get_str(hdl,
1055*3941Svenki 			    OID_sunPlatBinarySensorInterpretFalse,
1056*3941Svenki 			    vol_props[ndx].row, &pstr, &snmp_syserr);
1057*3941Svenki 			if (snmp_syserr == ECANCELED)
1058*3941Svenki 				return (PICL_FAILURE);
1059*3941Svenki 			if (ret < 0 || pstr == NULL) {
1060*3941Svenki 				(void) strlcpy(buf, STR_ST_FALSE,
1061*3941Svenki 				    MAX_TRUTHVAL_LEN);
1062*3941Svenki 			} else {
1063*3941Svenki 				(void) strlcpy(buf, pstr, MAX_TRUTHVAL_LEN);
1064*3941Svenki 				free(pstr);
1065*3941Svenki 			}
1066*3941Svenki 		} else {
1067*3941Svenki 			log_msg(LOG_ERR, SNMPP_INV_PLAT_BINSNSR_CURRENT,
1068*3941Svenki 			    propval, vol_props[ndx].row);
1069*3941Svenki 			return (PICL_FAILURE);
1070*3941Svenki 		}
1071*3941Svenki 		break;
1072*3941Svenki 
1073*3941Svenki 	case VPT_ALARMSTATE:
1074*3941Svenki 		if (propval == SSAS_OFF) {
1075*3941Svenki 			(void) strlcpy(buf, STR_SSAS_OFF, MAX_ALARMSTATE_LEN);
1076*3941Svenki 		} else if (propval == SSAS_STEADY) {
1077*3941Svenki 			(void) strlcpy(buf, STR_SSAS_STEADY,
1078*3941Svenki 			    MAX_ALARMSTATE_LEN);
1079*3941Svenki 		} else if (propval == SSAS_ALTERNATING) {
1080*3941Svenki 			(void) strlcpy(buf, STR_SSAS_ALTERNATING,
1081*3941Svenki 			    MAX_ALARMSTATE_LEN);
1082*3941Svenki 		} else {
1083*3941Svenki 			(void) strlcpy(buf, STR_SSAS_UNKNOWN,
1084*3941Svenki 			    MAX_ALARMSTATE_LEN);
1085*3941Svenki 		}
1086*3941Svenki 		break;
1087*3941Svenki 
1088*3941Svenki 	case VPT_BATTERYSTATUS:
1089*3941Svenki 		switch (propval) {
1090*3941Svenki 		case SSBS_OTHER:
1091*3941Svenki 			(void) strlcpy(buf, STR_SSBS_OTHER,
1092*3941Svenki 			    MAX_BATTERYSTATUS_LEN);
1093*3941Svenki 			break;
1094*3941Svenki 		case SSBS_FULLYCHARGED:
1095*3941Svenki 			(void) strlcpy(buf, STR_SSBS_FULLYCHARGED,
1096*3941Svenki 			    MAX_BATTERYSTATUS_LEN);
1097*3941Svenki 			break;
1098*3941Svenki 		case SSBS_LOW:
1099*3941Svenki 			(void) strlcpy(buf, STR_SSBS_LOW,
1100*3941Svenki 			    MAX_BATTERYSTATUS_LEN);
1101*3941Svenki 			break;
1102*3941Svenki 		case SSBS_CRITICAL:
1103*3941Svenki 			(void) strlcpy(buf, STR_SSBS_CRITICAL,
1104*3941Svenki 			    MAX_BATTERYSTATUS_LEN);
1105*3941Svenki 			break;
1106*3941Svenki 		case SSBS_CHARGING:
1107*3941Svenki 			(void) strlcpy(buf, STR_SSBS_CHARGING,
1108*3941Svenki 			    MAX_BATTERYSTATUS_LEN);
1109*3941Svenki 			break;
1110*3941Svenki 		case SSBS_CHARGING_AND_LOW:
1111*3941Svenki 			(void) strlcpy(buf, STR_SSBS_CHARGING_AND_LOW,
1112*3941Svenki 			    MAX_BATTERYSTATUS_LEN);
1113*3941Svenki 			break;
1114*3941Svenki 		case SSBS_CHARGING_AND_HIGH:
1115*3941Svenki 			(void) strlcpy(buf, STR_SSBS_CHARGING_AND_HIGH,
1116*3941Svenki 			    MAX_BATTERYSTATUS_LEN);
1117*3941Svenki 			break;
1118*3941Svenki 		case SSBS_CHARGING_AND_CRITICAL:
1119*3941Svenki 			(void) strlcpy(buf, STR_SSBS_CHARGING_AND_CRITICAL,
1120*3941Svenki 			    MAX_BATTERYSTATUS_LEN);
1121*3941Svenki 			break;
1122*3941Svenki 		case SSBS_UNDEFINED:
1123*3941Svenki 			(void) strlcpy(buf, STR_SSBS_UNDEFINED,
1124*3941Svenki 			    MAX_BATTERYSTATUS_LEN);
1125*3941Svenki 			break;
1126*3941Svenki 		case SSBS_PARTIALLY_CHARGED:
1127*3941Svenki 			(void) strlcpy(buf, STR_SSBS_PARTIALLY_CHARGED,
1128*3941Svenki 			    MAX_BATTERYSTATUS_LEN);
1129*3941Svenki 			break;
1130*3941Svenki 		case SSBS_UNKNOWN:
1131*3941Svenki 		default:
1132*3941Svenki 			(void) strlcpy(buf, STR_SSBS_UNKNOWN,
1133*3941Svenki 			    MAX_BATTERYSTATUS_LEN);
1134*3941Svenki 			break;
1135*3941Svenki 		}
1136*3941Svenki 		break;
1137*3941Svenki 	}
1138*3941Svenki 
1139*3941Svenki 	(void) rw_unlock(&stale_tree_rwlp);
1140*3941Svenki 
1141*3941Svenki 	return (PICL_SUCCESS);
1142*3941Svenki }
1143*3941Svenki 
1144*3941Svenki static void
1145*3941Svenki threshold(picl_nodehdl_t node, char *oidstr, int row, char *propname,
1146*3941Svenki     int *snmp_syserr_p)
1147*3941Svenki {
1148*3941Svenki 	picl_prophdl_t	prop;
1149*3941Svenki 	int		err;
1150*3941Svenki 	int		val;
1151*3941Svenki 
1152*3941Svenki 	if (snmp_get_int(hdl, oidstr, row, &val, snmp_syserr_p) != -1) {
1153*3941Svenki 		err = add_volatile_prop(node, propname, PICL_PTYPE_INT,
1154*3941Svenki 		    PICL_READ, sizeof (int), read_volprop, NULL, &prop);
1155*3941Svenki 		if (err == PICL_SUCCESS)
1156*3941Svenki 			save_volprop(prop, oidstr, row, VPT_NUMSENSOR);
1157*3941Svenki 	}
1158*3941Svenki }
1159*3941Svenki 
1160*3941Svenki static void
1161*3941Svenki add_thresholds(picl_nodehdl_t node, int row, int *snmp_syserr_p)
1162*3941Svenki {
1163*3941Svenki 	uchar_t	*bitstr = NULL;
1164*3941Svenki 	uchar_t	enabled;
1165*3941Svenki 	uint_t	nbytes;
1166*3941Svenki 	int	ret;
1167*3941Svenki 
1168*3941Svenki 	ret = snmp_get_bitstr(hdl, OID_sunPlatNumericSensorEnabledThresholds,
1169*3941Svenki 	    row, &bitstr, &nbytes, snmp_syserr_p);
1170*3941Svenki 	CHECK_LINKRESET_VOID(snmp_syserr_p)
1171*3941Svenki 
1172*3941Svenki 	if (ret < 0 || bitstr == NULL || nbytes > 2)
1173*3941Svenki 		enabled = 0xff;
1174*3941Svenki 	else if (nbytes == 1) {
1175*3941Svenki 		/*
1176*3941Svenki 		 * The ALOM snmp agent doesn't adhere to the BER rules for
1177*3941Svenki 		 * encoding bit strings. While the BER states that bitstrings
1178*3941Svenki 		 * must begin from the second octet after length, and the
1179*3941Svenki 		 * first octet after length must indicate the number of unused
1180*3941Svenki 		 * bits in the last octet, the snmp agent simply sends the
1181*3941Svenki 		 * bitstring data as if it were octet string -- that is, the
1182*3941Svenki 		 * "unused bits" octet is missing.
1183*3941Svenki 		 */
1184*3941Svenki 		enabled = bitstr[0];
1185*3941Svenki 	} else if (nbytes == 2)
1186*3941Svenki 		enabled = bitstr[1];
1187*3941Svenki 
1188*3941Svenki 	if (bitstr) {
1189*3941Svenki 		free(bitstr);
1190*3941Svenki 	}
1191*3941Svenki 
1192*3941Svenki 	if (enabled & LOWER_FATAL) {
1193*3941Svenki 		threshold(node,
1194*3941Svenki 		    OID_sunPlatNumericSensorLowerThresholdFatal, row,
1195*3941Svenki 		    PICL_PROP_LOW_POWER_OFF, snmp_syserr_p);
1196*3941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
1197*3941Svenki 	}
1198*3941Svenki 	if (enabled & LOWER_CRITICAL) {
1199*3941Svenki 		threshold(node,
1200*3941Svenki 		    OID_sunPlatNumericSensorLowerThresholdCritical, row,
1201*3941Svenki 		    PICL_PROP_LOW_SHUTDOWN, snmp_syserr_p);
1202*3941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
1203*3941Svenki 	}
1204*3941Svenki 	if (enabled & LOWER_NON_CRITICAL) {
1205*3941Svenki 		threshold(node,
1206*3941Svenki 		    OID_sunPlatNumericSensorLowerThresholdNonCritical, row,
1207*3941Svenki 		    PICL_PROP_LOW_WARNING, snmp_syserr_p);
1208*3941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
1209*3941Svenki 	}
1210*3941Svenki 	if (enabled & UPPER_NON_CRITICAL) {
1211*3941Svenki 		threshold(node,
1212*3941Svenki 		    OID_sunPlatNumericSensorUpperThresholdNonCritical, row,
1213*3941Svenki 		    PICL_PROP_HIGH_POWER_OFF, snmp_syserr_p);
1214*3941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
1215*3941Svenki 	}
1216*3941Svenki 	if (enabled & UPPER_CRITICAL) {
1217*3941Svenki 		threshold(node,
1218*3941Svenki 		    OID_sunPlatNumericSensorUpperThresholdCritical, row,
1219*3941Svenki 		    PICL_PROP_HIGH_SHUTDOWN, snmp_syserr_p);
1220*3941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
1221*3941Svenki 	}
1222*3941Svenki 	if (enabled & UPPER_FATAL) {
1223*3941Svenki 		threshold(node,
1224*3941Svenki 		    OID_sunPlatNumericSensorUpperThresholdFatal, row,
1225*3941Svenki 		    PICL_PROP_HIGH_WARNING, snmp_syserr_p);
1226*3941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
1227*3941Svenki 	}
1228*3941Svenki }
1229*3941Svenki 
1230*3941Svenki static char *
1231*3941Svenki get_slot_type(int row, int *snmp_syserr_p)
1232*3941Svenki {
1233*3941Svenki 	char	*p;
1234*3941Svenki 	char	*slott = NULL;
1235*3941Svenki 	int	ret;
1236*3941Svenki 
1237*3941Svenki 	ret = snmp_get_str(hdl, OID_sunPlatEquipmentHolderAcceptableTypes,
1238*3941Svenki 	    row, &p, snmp_syserr_p);
1239*3941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
1240*3941Svenki 
1241*3941Svenki 	if ((ret == 0) && p && *p) {
1242*3941Svenki 		slott = p;
1243*3941Svenki 		if ((p = strchr(slott, '\n')) != NULL)
1244*3941Svenki 			*p = 0;
1245*3941Svenki 	} else {
1246*3941Svenki 		log_msg(LOG_WARNING, SNMPP_NO_SLOT_TYPE, row);
1247*3941Svenki 		if (p) {
1248*3941Svenki 			free(p);
1249*3941Svenki 		}
1250*3941Svenki 	}
1251*3941Svenki 
1252*3941Svenki 	return (slott);
1253*3941Svenki }
1254*3941Svenki 
1255*3941Svenki /*
1256*3941Svenki  * Create and add the specified volatile property
1257*3941Svenki  */
1258*3941Svenki static int
1259*3941Svenki add_volatile_prop(picl_nodehdl_t node, char *name, int type, int access,
1260*3941Svenki     int size, int (*rdfunc)(ptree_rarg_t *, void *),
1261*3941Svenki     int (*wrfunc)(ptree_warg_t *, const void *), picl_prophdl_t *propp)
1262*3941Svenki {
1263*3941Svenki 	ptree_propinfo_t	propinfo;
1264*3941Svenki 	picl_prophdl_t		prop;
1265*3941Svenki 	int			err;
1266*3941Svenki 
1267*3941Svenki 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1268*3941Svenki 	    type, (access|PICL_VOLATILE), size, name, rdfunc, wrfunc);
1269*3941Svenki 	if (err != PICL_SUCCESS) {
1270*3941Svenki 		log_msg(LOG_ERR, SNMPP_CANT_INIT_PROPINFO, err);
1271*3941Svenki 		return (err);
1272*3941Svenki 	}
1273*3941Svenki 
1274*3941Svenki 	err = ptree_create_and_add_prop(node, &propinfo, NULL, &prop);
1275*3941Svenki 	if (err != PICL_SUCCESS) {
1276*3941Svenki 		log_msg(LOG_ERR, SNMPP_CANT_ADD_PROP, err, node);
1277*3941Svenki 		return (err);
1278*3941Svenki 	}
1279*3941Svenki 
1280*3941Svenki 	if (propp)
1281*3941Svenki 		*propp = prop;
1282*3941Svenki 
1283*3941Svenki 	return (PICL_SUCCESS);
1284*3941Svenki }
1285*3941Svenki 
1286*3941Svenki /*
1287*3941Svenki  * Add the specified string property to the node
1288*3941Svenki  */
1289*3941Svenki static int
1290*3941Svenki add_string_prop(picl_nodehdl_t node, char *propname, char *propval)
1291*3941Svenki {
1292*3941Svenki 	ptree_propinfo_t	propinfo;
1293*3941Svenki 	int			err;
1294*3941Svenki 
1295*3941Svenki 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1296*3941Svenki 	    PICL_PTYPE_CHARSTRING, PICL_READ, strlen(propval) + 1,
1297*3941Svenki 	    propname, NULL, NULL);
1298*3941Svenki 	if (err != PICL_SUCCESS) {
1299*3941Svenki 		log_msg(LOG_ERR, SNMPP_CANT_INIT_STR_PROPINFO, err);
1300*3941Svenki 		return (err);
1301*3941Svenki 	}
1302*3941Svenki 
1303*3941Svenki 	err = ptree_create_and_add_prop(node, &propinfo, propval, NULL);
1304*3941Svenki 	if (err != PICL_SUCCESS) {
1305*3941Svenki 		log_msg(LOG_ERR, SNMPP_CANT_ADD_STR_PROP, err, node);
1306*3941Svenki 		return (err);
1307*3941Svenki 	}
1308*3941Svenki 
1309*3941Svenki 	return (PICL_SUCCESS);
1310*3941Svenki }
1311*3941Svenki 
1312*3941Svenki /*
1313*3941Svenki  * Add the specified void property to the node
1314*3941Svenki  */
1315*3941Svenki static int
1316*3941Svenki add_void_prop(picl_nodehdl_t node, char *propname)
1317*3941Svenki {
1318*3941Svenki 	ptree_propinfo_t	propinfo;
1319*3941Svenki 	int			err;
1320*3941Svenki 
1321*3941Svenki 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1322*3941Svenki 	    PICL_PTYPE_VOID, PICL_READ, 0, propname, NULL, NULL);
1323*3941Svenki 	if (err != PICL_SUCCESS) {
1324*3941Svenki 		log_msg(LOG_ERR, SNMPP_CANT_INIT_VOID_PROPINFO, err);
1325*3941Svenki 		return (err);
1326*3941Svenki 	}
1327*3941Svenki 
1328*3941Svenki 	err = ptree_create_and_add_prop(node, &propinfo, NULL, NULL);
1329*3941Svenki 	if (err != PICL_SUCCESS) {
1330*3941Svenki 		log_msg(LOG_ERR, SNMPP_CANT_ADD_VOID_PROP, err, node);
1331*3941Svenki 		return (err);
1332*3941Svenki 	}
1333*3941Svenki 
1334*3941Svenki 	return (PICL_SUCCESS);
1335*3941Svenki }
1336*3941Svenki 
1337*3941Svenki static int
1338*3941Svenki add_int_prop(picl_nodehdl_t node, char *propname, int val)
1339*3941Svenki {
1340*3941Svenki 	ptree_propinfo_t	propinfo;
1341*3941Svenki 	int			propval = val;
1342*3941Svenki 	int			err;
1343*3941Svenki 
1344*3941Svenki 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1345*3941Svenki 	    PICL_PTYPE_INT, PICL_READ, sizeof (int),
1346*3941Svenki 	    propname, NULL, NULL);
1347*3941Svenki 	if (err != PICL_SUCCESS) {
1348*3941Svenki 		log_msg(LOG_ERR, SNMPP_CANT_INIT_INT_PROPINFO, err);
1349*3941Svenki 		return (err);
1350*3941Svenki 	}
1351*3941Svenki 
1352*3941Svenki 	err = ptree_create_and_add_prop(node, &propinfo, &propval, NULL);
1353*3941Svenki 	if (err != PICL_SUCCESS) {
1354*3941Svenki 		log_msg(LOG_ERR, SNMPP_CANT_ADD_INT_PROP, err, node);
1355*3941Svenki 		return (err);
1356*3941Svenki 	}
1357*3941Svenki 
1358*3941Svenki 	return (PICL_SUCCESS);
1359*3941Svenki }
1360*3941Svenki 
1361*3941Svenki static void
1362*3941Svenki add_prop(picl_nodehdl_t nodeh, picl_prophdl_t *php, char *label,
1363*3941Svenki     int row, sp_propid_t pp, int *snmp_syserr_p)
1364*3941Svenki {
1365*3941Svenki 	char	*serial_num;
1366*3941Svenki 	char	*slot_type;
1367*3941Svenki 	char	*fw_revision, *hw_revision;
1368*3941Svenki 	char	*mfg_name, *model_name;
1369*3941Svenki 	char	*phys_descr;
1370*3941Svenki 	int	val;
1371*3941Svenki 	int	ret;
1372*3941Svenki 
1373*3941Svenki 	switch (pp) {
1374*3941Svenki 	case PP_SERIAL_NUM:
1375*3941Svenki 		ret = snmp_get_str(hdl, OID_entPhysicalSerialNum,
1376*3941Svenki 		    row, &serial_num, snmp_syserr_p);
1377*3941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
1378*3941Svenki 		if ((ret == 0) && serial_num && *serial_num) {
1379*3941Svenki 			(void) add_string_prop(nodeh,
1380*3941Svenki 			    PICL_PROP_SERIAL_NUMBER, serial_num);
1381*3941Svenki 			free((void *) serial_num);
1382*3941Svenki 		}
1383*3941Svenki 		break;
1384*3941Svenki 
1385*3941Svenki 	case PP_SLOT_TYPE:
1386*3941Svenki 		if ((slot_type = get_slot_type(row, snmp_syserr_p)) == NULL) {
1387*3941Svenki 			CHECK_LINKRESET_VOID(snmp_syserr_p)
1388*3941Svenki 			(void) add_string_prop(nodeh,
1389*3941Svenki 			    PICL_PROP_SLOT_TYPE, DEFAULT_SLOT_TYPE);
1390*3941Svenki 		} else {
1391*3941Svenki 			(void) add_string_prop(nodeh,
1392*3941Svenki 			    PICL_PROP_SLOT_TYPE, slot_type);
1393*3941Svenki 			free((void *) slot_type);
1394*3941Svenki 		}
1395*3941Svenki 		break;
1396*3941Svenki 
1397*3941Svenki 	case PP_STATE:
1398*3941Svenki 		ret = add_volatile_prop(nodeh, PICL_PROP_STATE,
1399*3941Svenki 		    PICL_PTYPE_CHARSTRING, PICL_READ, MAX_ALARMSTATE_LEN,
1400*3941Svenki 		    read_volprop, NULL, php);
1401*3941Svenki 		if (ret == PICL_SUCCESS) {
1402*3941Svenki 			save_volprop(*php, OID_sunPlatAlarmState, row,
1403*3941Svenki 			    VPT_ALARMSTATE);
1404*3941Svenki 		}
1405*3941Svenki 		break;
1406*3941Svenki 
1407*3941Svenki 	case PP_OPSTATUS:
1408*3941Svenki 		ret = add_volatile_prop(nodeh, PICL_PROP_OPERATIONAL_STATUS,
1409*3941Svenki 		    PICL_PTYPE_CHARSTRING, PICL_READ, MAX_OPSTATE_LEN,
1410*3941Svenki 		    read_volprop, NULL, php);
1411*3941Svenki 		if (ret == PICL_SUCCESS) {
1412*3941Svenki 			save_volprop(*php,
1413*3941Svenki 			    OID_sunPlatEquipmentOperationalState, row,
1414*3941Svenki 			    VPT_PLATOPSTATE);
1415*3941Svenki 		}
1416*3941Svenki 		break;
1417*3941Svenki 
1418*3941Svenki 	case PP_BATT_STATUS:
1419*3941Svenki 		ret = add_volatile_prop(nodeh, PICL_PROP_BATTERY_STATUS,
1420*3941Svenki 			PICL_PTYPE_CHARSTRING, PICL_READ, MAX_BATTERYSTATUS_LEN,
1421*3941Svenki 			read_volprop, NULL, php);
1422*3941Svenki 		if (ret == PICL_SUCCESS) {
1423*3941Svenki 			save_volprop(*php, OID_sunPlatBatteryStatus, row,
1424*3941Svenki 			    VPT_BATTERYSTATUS);
1425*3941Svenki 		}
1426*3941Svenki 		break;
1427*3941Svenki 
1428*3941Svenki 	case PP_TEMPERATURE:
1429*3941Svenki 		ret = add_volatile_prop(nodeh, PICL_PROP_TEMPERATURE,
1430*3941Svenki 		    PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop,
1431*3941Svenki 		    NULL, php);
1432*3941Svenki 		if (ret == PICL_SUCCESS) {
1433*3941Svenki 			save_volprop(*php, OID_sunPlatNumericSensorCurrent,
1434*3941Svenki 			    row, VPT_NUMSENSOR);
1435*3941Svenki 		}
1436*3941Svenki 		break;
1437*3941Svenki 
1438*3941Svenki 	case PP_VOLTAGE:
1439*3941Svenki 		ret = add_volatile_prop(nodeh, PICL_PROP_VOLTAGE,
1440*3941Svenki 		    PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop,
1441*3941Svenki 		    NULL, php);
1442*3941Svenki 		if (ret == PICL_SUCCESS) {
1443*3941Svenki 			save_volprop(*php, OID_sunPlatNumericSensorCurrent,
1444*3941Svenki 			    row, VPT_NUMSENSOR);
1445*3941Svenki 		}
1446*3941Svenki 		break;
1447*3941Svenki 
1448*3941Svenki 	case PP_CURRENT:
1449*3941Svenki 		ret = add_volatile_prop(nodeh, PICL_PROP_CURRENT,
1450*3941Svenki 		    PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop,
1451*3941Svenki 		    NULL, php);
1452*3941Svenki 		if (ret == PICL_SUCCESS) {
1453*3941Svenki 			save_volprop(*php, OID_sunPlatNumericSensorCurrent,
1454*3941Svenki 			    row, VPT_NUMSENSOR);
1455*3941Svenki 		}
1456*3941Svenki 		break;
1457*3941Svenki 
1458*3941Svenki 	case PP_SPEED:
1459*3941Svenki 		ret = add_volatile_prop(nodeh, PICL_PROP_SPEED, PICL_PTYPE_INT,
1460*3941Svenki 		    PICL_READ, sizeof (int), read_volprop, NULL, php);
1461*3941Svenki 		if (ret == PICL_SUCCESS) {
1462*3941Svenki 			save_volprop(*php, OID_sunPlatNumericSensorCurrent,
1463*3941Svenki 			    row, VPT_NUMSENSOR);
1464*3941Svenki 		}
1465*3941Svenki 		break;
1466*3941Svenki 
1467*3941Svenki 	case PP_SENSOR_VALUE:
1468*3941Svenki 		ret = add_volatile_prop(nodeh, PICL_PROP_SENSOR_VALUE,
1469*3941Svenki 		    PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop,
1470*3941Svenki 		    NULL, php);
1471*3941Svenki 		if (ret == PICL_SUCCESS) {
1472*3941Svenki 			save_volprop(*php, OID_sunPlatNumericSensorCurrent,
1473*3941Svenki 			    row, VPT_NUMSENSOR);
1474*3941Svenki 		}
1475*3941Svenki 		break;
1476*3941Svenki 
1477*3941Svenki 	case PP_CONDITION:
1478*3941Svenki 		ret = add_volatile_prop(nodeh, PICL_PROP_CONDITION,
1479*3941Svenki 		    PICL_PTYPE_CHARSTRING, PICL_READ, MAX_TRUTHVAL_LEN,
1480*3941Svenki 		    read_volprop, NULL, php);
1481*3941Svenki 		if (ret == PICL_SUCCESS) {
1482*3941Svenki 			save_volprop(*php, OID_sunPlatBinarySensorCurrent,
1483*3941Svenki 			    row, VPT_BINSENSOR);
1484*3941Svenki 		}
1485*3941Svenki 		break;
1486*3941Svenki 
1487*3941Svenki 	case PP_EXPECTED:
1488*3941Svenki 		ret = add_volatile_prop(nodeh, PICL_PROP_EXPECTED,
1489*3941Svenki 		    PICL_PTYPE_CHARSTRING, PICL_READ, MAX_TRUTHVAL_LEN,
1490*3941Svenki 		    read_volprop, NULL, php);
1491*3941Svenki 		if (ret == PICL_SUCCESS) {
1492*3941Svenki 			save_volprop(*php, OID_sunPlatBinarySensorExpected,
1493*3941Svenki 			    row, VPT_BINSENSOR);
1494*3941Svenki 		}
1495*3941Svenki 		break;
1496*3941Svenki 
1497*3941Svenki 	case PP_REPLACEABLE:
1498*3941Svenki 		ret = snmp_get_int(hdl, OID_sunPlatCircuitPackReplaceable,
1499*3941Svenki 		    row, &val, snmp_syserr_p);
1500*3941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
1501*3941Svenki 		if ((ret == 0) && (val == ST_TRUE))
1502*3941Svenki 			(void) add_void_prop(nodeh, PICL_PROP_IS_REPLACEABLE);
1503*3941Svenki 		break;
1504*3941Svenki 
1505*3941Svenki 	case PP_HOTSWAPPABLE:
1506*3941Svenki 		ret = snmp_get_int(hdl, OID_sunPlatCircuitPackHotSwappable,
1507*3941Svenki 		    row, &val, snmp_syserr_p);
1508*3941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
1509*3941Svenki 		if ((ret == 0) && (val == ST_TRUE))
1510*3941Svenki 			(void) add_void_prop(nodeh, PICL_PROP_IS_HOT_SWAPPABLE);
1511*3941Svenki 		break;
1512*3941Svenki 
1513*3941Svenki 	case PP_IS_FRU:
1514*3941Svenki 		ret = snmp_get_int(hdl, OID_entPhysicalIsFRU, row,
1515*3941Svenki 		    &val, snmp_syserr_p);
1516*3941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
1517*3941Svenki 		if ((ret == 0) && (val == ST_TRUE))
1518*3941Svenki 			(void) add_void_prop(nodeh, PICL_PROP_IS_FRU);
1519*3941Svenki 		break;
1520*3941Svenki 
1521*3941Svenki 	case PP_HW_REVISION:
1522*3941Svenki 		ret = snmp_get_str(hdl, OID_entPhysicalHardwareRev,
1523*3941Svenki 		    row, &hw_revision, snmp_syserr_p);
1524*3941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
1525*3941Svenki 		if ((ret == 0) && hw_revision && *hw_revision) {
1526*3941Svenki 			(void) add_string_prop(nodeh,
1527*3941Svenki 			    PICL_PROP_HW_REVISION, hw_revision);
1528*3941Svenki 			free((void *) hw_revision);
1529*3941Svenki 		}
1530*3941Svenki 		break;
1531*3941Svenki 
1532*3941Svenki 	case PP_FW_REVISION:
1533*3941Svenki 		ret = snmp_get_str(hdl, OID_entPhysicalFirmwareRev,
1534*3941Svenki 		    row, &fw_revision, snmp_syserr_p);
1535*3941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
1536*3941Svenki 		if ((ret == 0) && fw_revision && *fw_revision) {
1537*3941Svenki 			(void) add_string_prop(nodeh,
1538*3941Svenki 			    PICL_PROP_FW_REVISION, fw_revision);
1539*3941Svenki 			free((void *) fw_revision);
1540*3941Svenki 		}
1541*3941Svenki 		break;
1542*3941Svenki 
1543*3941Svenki 	case PP_MFG_NAME:
1544*3941Svenki 		ret = snmp_get_str(hdl, OID_entPhysicalMfgName,
1545*3941Svenki 		    row, &mfg_name, snmp_syserr_p);
1546*3941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
1547*3941Svenki 		if ((ret == 0) && mfg_name && *mfg_name) {
1548*3941Svenki 			(void) add_string_prop(nodeh,
1549*3941Svenki 			    PICL_PROP_MFG_NAME, mfg_name);
1550*3941Svenki 			free((void *) mfg_name);
1551*3941Svenki 		}
1552*3941Svenki 		break;
1553*3941Svenki 
1554*3941Svenki 	case PP_MODEL_NAME:
1555*3941Svenki 		ret = snmp_get_str(hdl, OID_entPhysicalModelName,
1556*3941Svenki 		    row, &model_name, snmp_syserr_p);
1557*3941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
1558*3941Svenki 		if ((ret == 0) && model_name && *model_name) {
1559*3941Svenki 			(void) add_string_prop(nodeh,
1560*3941Svenki 			    PICL_PROP_MODEL_NAME, model_name);
1561*3941Svenki 			free((void *) model_name);
1562*3941Svenki 		}
1563*3941Svenki 		break;
1564*3941Svenki 
1565*3941Svenki 	case PP_DESCRIPTION:
1566*3941Svenki 		ret = snmp_get_str(hdl, OID_entPhysicalDescr,
1567*3941Svenki 		    row, &phys_descr, snmp_syserr_p);
1568*3941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
1569*3941Svenki 		if ((ret == 0) && phys_descr && *phys_descr) {
1570*3941Svenki 		    (void) add_string_prop(nodeh,
1571*3941Svenki 			PICL_PROP_PHYS_DESCRIPTION, phys_descr);
1572*3941Svenki 		    free((void *) phys_descr);
1573*3941Svenki 		}
1574*3941Svenki 		break;
1575*3941Svenki 
1576*3941Svenki 	case PP_LABEL:
1577*3941Svenki 		if (label && *label)
1578*3941Svenki 			(void) add_string_prop(nodeh, PICL_PROP_LABEL, label);
1579*3941Svenki 		break;
1580*3941Svenki 
1581*3941Svenki 	case PP_BASE_UNITS:
1582*3941Svenki 		ret = snmp_get_int(hdl, OID_sunPlatNumericSensorBaseUnits,
1583*3941Svenki 		    row, &val, snmp_syserr_p);
1584*3941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
1585*3941Svenki 		if ((ret == 0) && (val > 0) && (val < n_baseunits)) {
1586*3941Svenki 			(void) add_string_prop(nodeh,
1587*3941Svenki 			    PICL_PROP_BASE_UNITS, sensor_baseunits[val]);
1588*3941Svenki 		}
1589*3941Svenki 		break;
1590*3941Svenki 
1591*3941Svenki 	case PP_RATE_UNITS:
1592*3941Svenki 		ret = snmp_get_int(hdl, OID_sunPlatNumericSensorRateUnits,
1593*3941Svenki 		    row, &val, snmp_syserr_p);
1594*3941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
1595*3941Svenki 		if ((ret == 0) && (val > 0) && (val < n_rateunits)) {
1596*3941Svenki 			(void) add_string_prop(nodeh,
1597*3941Svenki 			    PICL_PROP_RATE_UNITS, sensor_rateunits[val]);
1598*3941Svenki 		}
1599*3941Svenki 		break;
1600*3941Svenki 
1601*3941Svenki 	case PP_EXPONENT:
1602*3941Svenki 		ret = snmp_get_int(hdl, OID_sunPlatNumericSensorExponent,
1603*3941Svenki 		    row, &val, snmp_syserr_p);
1604*3941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
1605*3941Svenki 		if (ret == 0)
1606*3941Svenki 			(void) add_int_prop(nodeh, PICL_PROP_EXPONENT, val);
1607*3941Svenki 		break;
1608*3941Svenki 	}
1609*3941Svenki }
1610*3941Svenki 
1611*3941Svenki /*VARARGS2*/
1612*3941Svenki static void
1613*3941Svenki log_msg(int pri, const char *fmt, ...)
1614*3941Svenki {
1615*3941Svenki 	va_list ap;
1616*3941Svenki 
1617*3941Svenki 	va_start(ap, fmt);
1618*3941Svenki 	vsyslog(pri, fmt, ap);
1619*3941Svenki 	va_end(ap);
1620*3941Svenki }
1621*3941Svenki 
1622*3941Svenki #ifdef SNMPPLUGIN_DEBUG
1623*3941Svenki 
1624*3941Svenki static void
1625*3941Svenki snmpplugin_log_init(void)
1626*3941Svenki {
1627*3941Svenki 	(void) mutex_init(&snmpplugin_dbuf_lock, USYNC_THREAD, NULL);
1628*3941Svenki }
1629*3941Svenki 
1630*3941Svenki static void
1631*3941Svenki snmpplugin_log(const char *fmt, ...)
1632*3941Svenki {
1633*3941Svenki 	va_list	ap;
1634*3941Svenki 
1635*3941Svenki 	(void) mutex_lock(&snmpplugin_dbuf_lock);
1636*3941Svenki 
1637*3941Svenki 	va_start(ap, fmt);
1638*3941Svenki 	(void) vsnprintf(snmpplugin_lbuf, SNMPPLUGIN_DMAX_LINE, fmt, ap);
1639*3941Svenki 	snmpplugin_log_append();
1640*3941Svenki 	va_end(ap);
1641*3941Svenki 
1642*3941Svenki 	(void) mutex_unlock(&snmpplugin_dbuf_lock);
1643*3941Svenki }
1644*3941Svenki 
1645*3941Svenki static void
1646*3941Svenki snmpplugin_log_append(void)
1647*3941Svenki {
1648*3941Svenki 	int	len;
1649*3941Svenki 
1650*3941Svenki 	len = strlen(snmpplugin_lbuf);
1651*3941Svenki 
1652*3941Svenki 	if ((snmpplugin_dbuf_curp + len) >=
1653*3941Svenki 	    (snmpplugin_dbuf + snmpplugin_dbuf_sz)) {
1654*3941Svenki 		snmpplugin_dbuf_realloc();
1655*3941Svenki 		if (snmpplugin_dbuf == NULL) {
1656*3941Svenki 			(void) mutex_unlock(&snmpplugin_dbuf_lock);
1657*3941Svenki 			return;
1658*3941Svenki 		}
1659*3941Svenki 	}
1660*3941Svenki 
1661*3941Svenki 	(void) strcpy(snmpplugin_dbuf_curp, snmpplugin_lbuf);
1662*3941Svenki 	snmpplugin_dbuf_curp += len;
1663*3941Svenki }
1664*3941Svenki 
1665*3941Svenki static void
1666*3941Svenki snmpplugin_dbuf_realloc(void)
1667*3941Svenki {
1668*3941Svenki 	char	*p;
1669*3941Svenki 	size_t	offset = 0;
1670*3941Svenki 	size_t	count;
1671*3941Svenki 
1672*3941Svenki 	count = snmpplugin_dbuf_sz + SNMPPLUGIN_DBLOCK_SZ;
1673*3941Svenki 	if ((p = (char *)calloc(count, 1)) == NULL) {
1674*3941Svenki 		snmpplugin_dbuf_overflow++;
1675*3941Svenki 		snmpplugin_dbuf_curp = snmpplugin_dbuf;
1676*3941Svenki 		return;
1677*3941Svenki 	}
1678*3941Svenki 
1679*3941Svenki 	if (snmpplugin_dbuf) {
1680*3941Svenki 		offset = snmpplugin_dbuf_curp - snmpplugin_dbuf;
1681*3941Svenki 		(void) memcpy(p, snmpplugin_dbuf, snmpplugin_dbuf_sz);
1682*3941Svenki 		free(snmpplugin_dbuf);
1683*3941Svenki 	}
1684*3941Svenki 
1685*3941Svenki 	snmpplugin_dbuf = p;
1686*3941Svenki 	snmpplugin_dbuf_sz += SNMPPLUGIN_DBLOCK_SZ;
1687*3941Svenki 
1688*3941Svenki 	snmpplugin_dbuf_curp = snmpplugin_dbuf + offset;
1689*3941Svenki }
1690*3941Svenki #endif
1691