1 #include <net-snmp/net-snmp-config.h>
2 #include <net-snmp/net-snmp-includes.h>
3 #include <net-snmp/agent/net-snmp-agent-includes.h>
4 #include <net-snmp/agent/net-snmp-agent-includes.h>
5 #include <net-snmp/agent/table_container.h>
6 #include <net-snmp/agent/agent_sysORTable.h>
7 #include <net-snmp/agent/sysORTable.h>
8 
9 #include "sysORTable.h"
10 #include "system_mib.h"
11 
12 #include <net-snmp/net-snmp-features.h>
13 
14 netsnmp_feature_require(table_container);
15 
16 
17 /** Typical data structure for a row entry */
18 typedef struct sysORTable_entry_s {
19     netsnmp_index            oid_index;
20     oid                      sysORIndex;
21     const struct sysORTable* data;
22 } sysORTable_entry;
23 
24 /*
25  * column number definitions for table sysORTable
26  */
27 #define COLUMN_SYSORINDEX	1
28 #define COLUMN_SYSORID		2
29 #define COLUMN_SYSORDESCR	3
30 #define COLUMN_SYSORUPTIME	4
31 
32 static netsnmp_container *table = NULL;
33 static u_long             sysORLastChange;
34 static oid                sysORNextIndex = 1;
35 
36 /** create a new row in the table */
37 static void
register_foreach(const struct sysORTable * data,void * dummy)38 register_foreach(const struct sysORTable* data, void* dummy)
39 {
40     sysORTable_entry *entry;
41 
42     sysORLastChange = data->OR_uptime;
43 
44     entry = SNMP_MALLOC_TYPEDEF(sysORTable_entry);
45     if (!entry) {
46 	snmp_log(LOG_ERR,
47 		 "could not allocate storage, sysORTable is inconsistent\n");
48     } else {
49 	const oid firstNext = sysORNextIndex;
50 	netsnmp_iterator* it = CONTAINER_ITERATOR(table);
51 
52 	do {
53 	    const sysORTable_entry* value;
54 	    const oid cur = sysORNextIndex;
55 
56 	    if (sysORNextIndex == SNMP_MIN(MAX_SUBID, 2147483647UL))
57 		sysORNextIndex = 1;
58 	    else
59 		++sysORNextIndex;
60 
61 	    for (value = (sysORTable_entry*)it->curr(it);
62 		 value && value->sysORIndex < cur;
63 		 value = (sysORTable_entry*)ITERATOR_NEXT(it)) {
64 	    }
65 
66 	    if (value && value->sysORIndex == cur) {
67 		if (sysORNextIndex < cur)
68 		    it->reset(it);
69 	    } else {
70 		entry->sysORIndex = cur;
71 		break;
72 	    }
73 	} while (firstNext != sysORNextIndex);
74 
75 	ITERATOR_RELEASE(it);
76 
77 	if(firstNext == sysORNextIndex) {
78             snmp_log(LOG_ERR, "Failed to locate a free index in sysORTable\n");
79             free(entry);
80 	} else {
81 	    entry->data = data;
82 	    entry->oid_index.len = 1;
83 	    entry->oid_index.oids = &entry->sysORIndex;
84 
85 	    CONTAINER_INSERT(table, entry);
86 	}
87     }
88 }
89 
90 static int
register_cb(int major,int minor,void * serv,void * client)91 register_cb(int major, int minor, void* serv, void* client)
92 {
93     DEBUGMSGTL(("mibII/sysORTable/register_cb",
94                 "register_cb(%d, %d, %p, %p)\n", major, minor, serv, client));
95     register_foreach((struct sysORTable*)serv, NULL);
96     return SNMP_ERR_NOERROR;
97 }
98 
99 /** remove a row from the table */
100 static int
unregister_cb(int major,int minor,void * serv,void * client)101 unregister_cb(int major, int minor, void* serv, void* client)
102 {
103     sysORTable_entry *value;
104     netsnmp_iterator* it = CONTAINER_ITERATOR(table);
105 
106     DEBUGMSGTL(("mibII/sysORTable/unregister_cb",
107                 "unregister_cb(%d, %d, %p, %p)\n", major, minor, serv, client));
108     sysORLastChange = ((struct sysORTable*)(serv))->OR_uptime;
109 
110     while ((value = (sysORTable_entry*)ITERATOR_NEXT(it)) && value->data != serv);
111     ITERATOR_RELEASE(it);
112     if(value) {
113 	CONTAINER_REMOVE(table, value);
114 	free(value);
115     }
116     return SNMP_ERR_NOERROR;
117 }
118 
119 /** handles requests for the sysORTable table */
120 static int
sysORTable_handler(netsnmp_mib_handler * handler,netsnmp_handler_registration * reginfo,netsnmp_agent_request_info * reqinfo,netsnmp_request_info * requests)121 sysORTable_handler(netsnmp_mib_handler *handler,
122                    netsnmp_handler_registration *reginfo,
123                    netsnmp_agent_request_info *reqinfo,
124                    netsnmp_request_info *requests)
125 {
126     netsnmp_request_info *request;
127 
128     DEBUGMSGTL(("mibII/sysORTable/sysORTable_handler",
129                 "sysORTable_handler called\n"));
130 
131     if (reqinfo->mode != MODE_GET) {
132 	snmp_log(LOG_ERR,
133 		 "Got unexpected operation for sysORTable\n");
134 	return SNMP_ERR_GENERR;
135     }
136 
137     /*
138      * Read-support (also covers GetNext requests)
139      */
140     request = requests;
141     while(request && request->processed)
142 	request = request->next;
143     while(request) {
144 	sysORTable_entry *table_entry;
145 	netsnmp_table_request_info *table_info;
146 
147 	if (NULL == (table_info = netsnmp_extract_table_info(request))) {
148 	    snmp_log(LOG_ERR,
149 		     "could not extract table info for sysORTable\n");
150 	    snmp_set_var_typed_value(
151 		    request->requestvb, SNMP_ERR_GENERR, NULL, 0);
152 	} else if(NULL == (table_entry = (sysORTable_entry *)
153 			   netsnmp_container_table_extract_context(request))) {
154 	    switch (table_info->colnum) {
155 	    case COLUMN_SYSORID:
156 	    case COLUMN_SYSORDESCR:
157 	    case COLUMN_SYSORUPTIME:
158 		netsnmp_set_request_error(reqinfo, request,
159 					  SNMP_NOSUCHINSTANCE);
160 		break;
161 	    default:
162 		netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHOBJECT);
163 		break;
164 	    }
165 	} else {
166 	    switch (table_info->colnum) {
167 	    case COLUMN_SYSORID:
168 		snmp_set_var_typed_value(
169 			request->requestvb, ASN_OBJECT_ID,
170 			(const u_char*)table_entry->data->OR_oid,
171                         table_entry->data->OR_oidlen * sizeof(oid));
172 		break;
173 	    case COLUMN_SYSORDESCR:
174 		snmp_set_var_typed_value(
175 			request->requestvb, ASN_OCTET_STR,
176 			(const u_char*)table_entry->data->OR_descr,
177 			strlen(table_entry->data->OR_descr));
178 		break;
179 	    case COLUMN_SYSORUPTIME:
180 		snmp_set_var_typed_integer(
181 			request->requestvb, ASN_TIMETICKS,
182                         table_entry->data->OR_uptime);
183 		break;
184 	    default:
185 		netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHOBJECT);
186 		break;
187 	    }
188 	}
189 	do {
190 	    request = request->next;
191 	} while(request && request->processed);
192     }
193     return SNMP_ERR_NOERROR;
194 }
195 
196 static netsnmp_handler_registration *sysORLastChange_reg;
197 static netsnmp_watcher_info sysORLastChange_winfo;
198 static netsnmp_handler_registration *sysORTable_reg;
199 static netsnmp_table_registration_info *sysORTable_table_info;
200 
201 /** Initializes the sysORTable module */
202 void
init_sysORTable(void)203 init_sysORTable(void)
204 {
205     const oid sysORLastChange_oid[] = { 1, 3, 6, 1, 2, 1, 1, 8 };
206     const oid sysORTable_oid[] = { 1, 3, 6, 1, 2, 1, 1, 9 };
207 
208     sysORTable_table_info =
209         SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
210 
211     table = netsnmp_container_find("sysORTable:table_container");
212 
213     if (sysORTable_table_info == NULL || table == NULL) {
214         SNMP_FREE(sysORTable_table_info);
215         CONTAINER_FREE(table);
216         return;
217     }
218     table->container_name = strdup("sysORTable");
219 
220     netsnmp_table_helper_add_indexes(sysORTable_table_info,
221                                      ASN_INTEGER, /** index: sysORIndex */
222                                      0);
223     sysORTable_table_info->min_column = COLUMN_SYSORID;
224     sysORTable_table_info->max_column = COLUMN_SYSORUPTIME;
225 
226     sysORLastChange_reg =
227         netsnmp_create_handler_registration(
228             "mibII/sysORLastChange", NULL,
229             sysORLastChange_oid, OID_LENGTH(sysORLastChange_oid),
230             HANDLER_CAN_RONLY);
231     netsnmp_init_watcher_info(
232 	    &sysORLastChange_winfo,
233             &sysORLastChange, sizeof(u_long),
234             ASN_TIMETICKS, WATCHER_FIXED_SIZE);
235     netsnmp_register_watched_scalar(sysORLastChange_reg,
236 				    &sysORLastChange_winfo);
237 
238     sysORTable_reg =
239         netsnmp_create_handler_registration(
240             "mibII/sysORTable", sysORTable_handler,
241             sysORTable_oid, OID_LENGTH(sysORTable_oid), HANDLER_CAN_RONLY);
242     netsnmp_container_table_register(sysORTable_reg, sysORTable_table_info,
243                                      table, TABLE_CONTAINER_KEY_NETSNMP_INDEX);
244 
245     sysORLastChange = netsnmp_get_agent_uptime();
246 
247     /*
248      * Initialise the contents of the table here
249      */
250     netsnmp_sysORTable_foreach(&register_foreach, NULL);
251 
252     /*
253      * Register callbacks
254      */
255     snmp_register_callback(SNMP_CALLBACK_APPLICATION,
256                            SNMPD_CALLBACK_REG_SYSOR, register_cb, NULL);
257     snmp_register_callback(SNMP_CALLBACK_APPLICATION,
258                            SNMPD_CALLBACK_UNREG_SYSOR, unregister_cb, NULL);
259 
260 #ifdef USING_MIBII_SYSTEM_MIB_MODULE
261     if (++system_module_count == 3)
262         REGISTER_SYSOR_TABLE(system_module_oid, system_module_oid_len,
263                              "The MIB module for SNMPv2 entities");
264 #endif
265 }
266 
267 void
shutdown_sysORTable(void)268 shutdown_sysORTable(void)
269 {
270 #ifdef USING_MIBII_SYSTEM_MIB_MODULE
271     if (system_module_count-- == 3)
272         UNREGISTER_SYSOR_TABLE(system_module_oid, system_module_oid_len);
273 #endif
274 
275     snmp_unregister_callback(SNMP_CALLBACK_APPLICATION,
276                              SNMPD_CALLBACK_UNREG_SYSOR, unregister_cb, NULL,
277                              1);
278     snmp_unregister_callback(SNMP_CALLBACK_APPLICATION,
279                              SNMPD_CALLBACK_REG_SYSOR, register_cb, NULL, 1);
280 
281     if (table)
282         CONTAINER_CLEAR(table, netsnmp_container_simple_free, NULL);
283     netsnmp_container_table_unregister(sysORTable_reg);
284     sysORTable_reg = NULL;
285     table = NULL;
286     netsnmp_table_registration_info_free(sysORTable_table_info);
287     sysORTable_table_info = NULL;
288     netsnmp_unregister_handler(sysORLastChange_reg);
289     sysORLastChange_reg = NULL;
290 }
291