make netsmp build under AST_DEVMODE. Description, included in the source,
[asterisk/asterisk.git] / res / snmp / agent.c
1 /*
2  * Copyright (C) 2006 Voop as
3  * Thorsten Lockert <tholo@voop.as>
4  *
5  * This program is free software, distributed under the terms of
6  * the GNU General Public License Version 2. See the LICENSE file
7  * at the top of the source tree.
8  */
9
10 /*! \file
11  *
12  * \brief SNMP Agent / SubAgent support for Asterisk
13  *
14  * \author Thorsten Lockert <tholo@voop.as>
15  */
16
17 #include "asterisk.h"
18
19 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
20
21 /*
22  * There is some collision collision between netsmp and asterisk names,
23  * causing build under AST_DEVMODE to fail.
24  *
25  * The following PACKAGE_* macros are one place.
26  * Also netsnmp has an improper check for HAVE_DMALLOC_H, using
27  *    #if HAVE_DMALLOC_H   instead of #ifdef HAVE_DMALLOC_H
28  * As a countermeasure we define it to 0, however this will fail
29  * when the proper check is implemented.
30  */
31 #ifdef PACKAGE_NAME
32 #undef PACKAGE_NAME
33 #endif
34 #ifdef PACKAGE_BUGREPORT
35 #undef PACKAGE_BUGREPORT
36 #endif
37 #ifdef PACKAGE_STRING
38 #undef PACKAGE_STRING
39 #endif
40 #ifdef PACKAGE_TARNAME
41 #undef PACKAGE_TARNAME
42 #endif
43 #ifdef PACKAGE_VERSION
44 #undef PACKAGE_VERSION
45 #endif
46 #ifndef HAVE_DMALLOC_H
47 #define HAVE_DMALLOC_H 0        /* XXX we shouldn't do this */
48 #endif
49
50 #include <net-snmp/net-snmp-config.h>
51 #include <net-snmp/net-snmp-includes.h>
52 #include <net-snmp/agent/net-snmp-agent-includes.h>
53
54 #include "asterisk/channel.h"
55 #include "asterisk/logger.h"
56 #include "asterisk/options.h"
57 #include "asterisk/indications.h"
58 #include "asterisk/version.h"
59 #include "asterisk/pbx.h"
60
61 /* Colission between Net-SNMP and Asterisk */
62 #define unload_module ast_unload_module
63 #include "asterisk/module.h"
64 #undef unload_module
65
66 #include "agent.h"
67
68 /* Helper functions in Net-SNMP, header file not installed by default */
69 int header_generic(struct variable *, oid *, size_t *, int, size_t *, WriteMethod **);
70 int header_simple_table(struct variable *, oid *, size_t *, int, size_t *, WriteMethod **, int);
71 int register_sysORTable(oid *, size_t, const char *);
72 int unregister_sysORTable(oid *, size_t);
73
74 /* Not defined in header files */
75 extern char ast_config_AST_SOCKET[];
76
77 /* Forward declaration */
78 static void init_asterisk_mib(void);
79
80 /*
81  * Anchor for all the Asterisk MIB values
82  */
83 static oid asterisk_oid[] = { 1, 3, 6, 1, 4, 1, 22736, 1 };
84
85 /*
86  * MIB values -- these correspond to values in the Asterisk MIB,
87  * and MUST be kept in sync with the MIB for things to work as
88  * expected.
89  */
90 #define ASTVERSION                              1
91 #define         ASTVERSTRING                    1
92 #define         ASTVERTAG                               2
93
94 #define ASTCONFIGURATION                2
95 #define         ASTCONFUPTIME                   1
96 #define         ASTCONFRELOADTIME               2
97 #define         ASTCONFPID                              3
98 #define         ASTCONFSOCKET                   4
99 #define         ASTCONFACTIVECALLS      5
100 #define         ASTCONFPROCESSEDCALLS   6
101
102 #define ASTMODULES                              3
103 #define         ASTMODCOUNT                             1
104
105 #define ASTINDICATIONS                  4
106 #define         ASTINDCOUNT                             1
107 #define         ASTINDCURRENT                   2
108
109 #define         ASTINDTABLE                             3
110 #define                 ASTINDINDEX                             1
111 #define                 ASTINDCOUNTRY                   2
112 #define                 ASTINDALIAS                             3
113 #define                 ASTINDDESCRIPTION               4
114
115 #define ASTCHANNELS                             5
116 #define         ASTCHANCOUNT                    1
117
118 #define         ASTCHANTABLE                    2
119 #define                 ASTCHANINDEX                    1
120 #define                 ASTCHANNAME                             2
121 #define                 ASTCHANLANGUAGE                 3
122 #define                 ASTCHANTYPE                             4
123 #define                 ASTCHANMUSICCLASS               5
124 #define                 ASTCHANBRIDGE                   6
125 #define                 ASTCHANMASQ                             7
126 #define                 ASTCHANMASQR                    8
127 #define                 ASTCHANWHENHANGUP               9
128 #define                 ASTCHANAPP                              10
129 #define                 ASTCHANDATA                             11
130 #define                 ASTCHANCONTEXT                  12
131 #define                 ASTCHANMACROCONTEXT             13
132 #define                 ASTCHANMACROEXTEN               14
133 #define                 ASTCHANMACROPRI                 15
134 #define                 ASTCHANEXTEN                    16
135 #define                 ASTCHANPRI                              17
136 #define                 ASTCHANACCOUNTCODE              18
137 #define                 ASTCHANFORWARDTO                19
138 #define                 ASTCHANUNIQUEID                 20
139 #define                 ASTCHANCALLGROUP                21
140 #define                 ASTCHANPICKUPGROUP              22
141 #define                 ASTCHANSTATE                    23
142 #define                 ASTCHANMUTED                    24
143 #define                 ASTCHANRINGS                    25
144 #define                 ASTCHANCIDDNID                  26
145 #define                 ASTCHANCIDNUM                   27
146 #define                 ASTCHANCIDNAME                  28
147 #define                 ASTCHANCIDANI                   29
148 #define                 ASTCHANCIDRDNIS                 30
149 #define                 ASTCHANCIDPRES                  31
150 #define                 ASTCHANCIDANI2                  32
151 #define                 ASTCHANCIDTON                   33
152 #define                 ASTCHANCIDTNS                   34
153 #define                 ASTCHANAMAFLAGS                 35
154 #define                 ASTCHANADSI                             36
155 #define                 ASTCHANTONEZONE                 37
156 #define                 ASTCHANHANGUPCAUSE              38
157 #define                 ASTCHANVARIABLES                39
158 #define                 ASTCHANFLAGS                    40
159 #define                 ASTCHANTRANSFERCAP              41
160
161 #define         ASTCHANTYPECOUNT                3
162
163 #define         ASTCHANTYPETABLE                4
164 #define                 ASTCHANTYPEINDEX                1
165 #define                 ASTCHANTYPENAME                 2
166 #define                 ASTCHANTYPEDESC                 3
167 #define                 ASTCHANTYPEDEVSTATE             4
168 #define                 ASTCHANTYPEINDICATIONS  5
169 #define                 ASTCHANTYPETRANSFER             6
170 #define                 ASTCHANTYPECHANNELS             7
171
172 #define         ASTCHANSCALARS                  5
173 #define                 ASTCHANBRIDGECOUNT              1
174
175 void *agent_thread(void *arg)
176 {
177         ast_verb(2, "Starting %sAgent\n", res_snmp_agentx_subagent ? "Sub" : "");
178
179         snmp_enable_stderrlog();
180
181         if (res_snmp_agentx_subagent)
182                 netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
183                                                            NETSNMP_DS_AGENT_ROLE,
184                                                            1);
185
186         init_agent("asterisk");
187
188         init_asterisk_mib();
189
190         init_snmp("asterisk");
191
192         if (!res_snmp_agentx_subagent)
193                 init_master_agent();
194
195         while (res_snmp_dont_stop)
196                 agent_check_and_process(1);
197
198         snmp_shutdown("asterisk");
199
200         ast_verb(2, "Terminating %sAgent\n", res_snmp_agentx_subagent ? "Sub" : "");
201
202         return NULL;
203 }
204
205 static u_char *
206 ast_var_channels(struct variable *vp, oid *name, size_t *length,
207                                  int exact, size_t *var_len, WriteMethod **write_method)
208 {
209         static unsigned long long_ret;
210
211         if (header_generic(vp, name, length, exact, var_len, write_method))
212                 return NULL;
213
214         if (vp->magic != ASTCHANCOUNT)
215                 return NULL;
216
217         long_ret = ast_active_channels();
218
219         return (u_char *)&long_ret;
220 }
221
222 static u_char *ast_var_channels_table(struct variable *vp, oid *name, size_t *length,
223                                                                         int exact, size_t *var_len, WriteMethod **write_method)
224 {
225         static unsigned long long_ret;
226         static u_char bits_ret[2];
227         static char string_ret[256];
228         struct ast_channel *chan, *bridge;
229         struct timeval tval;
230         u_char *ret = NULL;
231         int i, bit;
232         struct ast_str *out = ast_str_alloca(2048);
233
234         if (header_simple_table(vp, name, length, exact, var_len, write_method, ast_active_channels()))
235                 return NULL;
236
237         i = name[*length - 1] - 1;
238         for (chan = ast_channel_walk_locked(NULL);
239                  chan && i;
240                  chan = ast_channel_walk_locked(chan), i--)
241                 ast_channel_unlock(chan);
242         if (chan == NULL)
243                 return NULL;
244         *var_len = sizeof(long_ret);
245
246         switch (vp->magic) {
247         case ASTCHANINDEX:
248                 long_ret = name[*length - 1];
249                 ret = (u_char *)&long_ret;
250                 break;
251         case ASTCHANNAME:
252                 if (!ast_strlen_zero(chan->name)) {
253                         strncpy(string_ret, chan->name, sizeof(string_ret));
254                         string_ret[sizeof(string_ret) - 1] = '\0';
255                         *var_len = strlen(string_ret);
256                         ret = (u_char *)string_ret;
257                 }
258                 break;
259         case ASTCHANLANGUAGE:
260                 if (!ast_strlen_zero(chan->language)) {
261                         strncpy(string_ret, chan->language, sizeof(string_ret));
262                         string_ret[sizeof(string_ret) - 1] = '\0';
263                         *var_len = strlen(string_ret);
264                         ret = (u_char *)string_ret;
265                 }
266                 break;
267         case ASTCHANTYPE:
268                 strncpy(string_ret, chan->tech->type, sizeof(string_ret));
269                 string_ret[sizeof(string_ret) - 1] = '\0';
270                 *var_len = strlen(string_ret);
271                 ret = (u_char *)string_ret;
272                 break;
273         case ASTCHANMUSICCLASS:
274                 if (!ast_strlen_zero(chan->musicclass)) {
275                         strncpy(string_ret, chan->musicclass, sizeof(string_ret));
276                         string_ret[sizeof(string_ret) - 1] = '\0';
277                         *var_len = strlen(string_ret);
278                         ret = (u_char *)string_ret;
279                 }
280                 break;
281         case ASTCHANBRIDGE:
282                 if ((bridge = ast_bridged_channel(chan)) != NULL) {
283                         strncpy(string_ret, bridge->name, sizeof(string_ret));
284                         string_ret[sizeof(string_ret) - 1] = '\0';
285                         *var_len = strlen(string_ret);
286                         ret = (u_char *)string_ret;
287                 }
288                 break;
289         case ASTCHANMASQ:
290                 if (chan->masq && !ast_strlen_zero(chan->masq->name)) {
291                         strncpy(string_ret, chan->masq->name, sizeof(string_ret));
292                         string_ret[sizeof(string_ret) - 1] = '\0';
293                         *var_len = strlen(string_ret);
294                         ret = (u_char *)string_ret;
295                 }
296                 break;
297         case ASTCHANMASQR:
298                 if (chan->masqr && !ast_strlen_zero(chan->masqr->name)) {
299                         strncpy(string_ret, chan->masqr->name, sizeof(string_ret));
300                         string_ret[sizeof(string_ret) - 1] = '\0';
301                         *var_len = strlen(string_ret);
302                         ret = (u_char *)string_ret;
303                 }
304                 break;
305         case ASTCHANWHENHANGUP:
306                 if (chan->whentohangup) {
307                         gettimeofday(&tval, NULL);
308                         long_ret = difftime(chan->whentohangup, tval.tv_sec) * 100 - tval.tv_usec / 10000;
309                         ret= (u_char *)&long_ret;
310                 }
311                 break;
312         case ASTCHANAPP:
313                 if (chan->appl) {
314                         strncpy(string_ret, chan->appl, sizeof(string_ret));
315                         string_ret[sizeof(string_ret) - 1] = '\0';
316                         *var_len = strlen(string_ret);
317                         ret = (u_char *)string_ret;
318                 }
319                 break;
320         case ASTCHANDATA:
321                 if (chan->data) {
322                         strncpy(string_ret, chan->data, sizeof(string_ret));
323                         string_ret[sizeof(string_ret) - 1] = '\0';
324                         *var_len = strlen(string_ret);
325                         ret = (u_char *)string_ret;
326                 }
327                 break;
328         case ASTCHANCONTEXT:
329                 strncpy(string_ret, chan->context, sizeof(string_ret));
330                 string_ret[sizeof(string_ret) - 1] = '\0';
331                 *var_len = strlen(string_ret);
332                 ret = (u_char *)string_ret;
333                 break;
334         case ASTCHANMACROCONTEXT:
335                 strncpy(string_ret, chan->macrocontext, sizeof(string_ret));
336                 string_ret[sizeof(string_ret) - 1] = '\0';
337                 *var_len = strlen(string_ret);
338                 ret = (u_char *)string_ret;
339                 break;
340         case ASTCHANMACROEXTEN:
341                 strncpy(string_ret, chan->macroexten, sizeof(string_ret));
342                 string_ret[sizeof(string_ret) - 1] = '\0';
343                 *var_len = strlen(string_ret);
344                 ret = (u_char *)string_ret;
345                 break;
346         case ASTCHANMACROPRI:
347                 long_ret = chan->macropriority;
348                 ret = (u_char *)&long_ret;
349                 break;
350         case ASTCHANEXTEN:
351                 strncpy(string_ret, chan->exten, sizeof(string_ret));
352                 string_ret[sizeof(string_ret) - 1] = '\0';
353                 *var_len = strlen(string_ret);
354                 ret = (u_char *)string_ret;
355                 break;
356         case ASTCHANPRI:
357                 long_ret = chan->priority;
358                 ret = (u_char *)&long_ret;
359                 break;
360         case ASTCHANACCOUNTCODE:
361                 if (!ast_strlen_zero(chan->accountcode)) {
362                         strncpy(string_ret, chan->accountcode, sizeof(string_ret));
363                         string_ret[sizeof(string_ret) - 1] = '\0';
364                         *var_len = strlen(string_ret);
365                         ret = (u_char *)string_ret;
366                 }
367                 break;
368         case ASTCHANFORWARDTO:
369                 if (!ast_strlen_zero(chan->call_forward)) {
370                         strncpy(string_ret, chan->call_forward, sizeof(string_ret));
371                         string_ret[sizeof(string_ret) - 1] = '\0';
372                         *var_len = strlen(string_ret);
373                         ret = (u_char *)string_ret;
374                 }
375                 break;
376         case ASTCHANUNIQUEID:
377                 strncpy(string_ret, chan->uniqueid, sizeof(string_ret));
378                 string_ret[sizeof(string_ret) - 1] = '\0';
379                 *var_len = strlen(string_ret);
380                 ret = (u_char *)string_ret;
381                 break;
382         case ASTCHANCALLGROUP:
383                 long_ret = chan->callgroup;
384                 ret = (u_char *)&long_ret;
385                 break;
386         case ASTCHANPICKUPGROUP:
387                 long_ret = chan->pickupgroup;
388                 ret = (u_char *)&long_ret;
389                 break;
390         case ASTCHANSTATE:
391                 long_ret = chan->_state & 0xffff;
392                 ret = (u_char *)&long_ret;
393                 break;
394         case ASTCHANMUTED:
395                 long_ret = chan->_state & AST_STATE_MUTE ? 1 : 2;
396                 ret = (u_char *)&long_ret;
397                 break;
398         case ASTCHANRINGS:
399                 long_ret = chan->rings;
400                 ret = (u_char *)&long_ret;
401                 break;
402         case ASTCHANCIDDNID:
403                 if (chan->cid.cid_dnid) {
404                         strncpy(string_ret, chan->cid.cid_dnid, sizeof(string_ret));
405                         string_ret[sizeof(string_ret) - 1] = '\0';
406                         *var_len = strlen(string_ret);
407                         ret = (u_char *)string_ret;
408                 }
409                 break;
410         case ASTCHANCIDNUM:
411                 if (chan->cid.cid_num) {
412                         strncpy(string_ret, chan->cid.cid_num, sizeof(string_ret));
413                         string_ret[sizeof(string_ret) - 1] = '\0';
414                         *var_len = strlen(string_ret);
415                         ret = (u_char *)string_ret;
416                 }
417                 break;
418         case ASTCHANCIDNAME:
419                 if (chan->cid.cid_name) {
420                         strncpy(string_ret, chan->cid.cid_name, sizeof(string_ret));
421                         string_ret[sizeof(string_ret) - 1] = '\0';
422                         *var_len = strlen(string_ret);
423                         ret = (u_char *)string_ret;
424                 }
425                 break;
426         case ASTCHANCIDANI:
427                 if (chan->cid.cid_ani) {
428                         strncpy(string_ret, chan->cid.cid_ani, sizeof(string_ret));
429                         string_ret[sizeof(string_ret) - 1] = '\0';
430                         *var_len = strlen(string_ret);
431                         ret = (u_char *)string_ret;
432                 }
433                 break;
434         case ASTCHANCIDRDNIS:
435                 if (chan->cid.cid_rdnis) {
436                         strncpy(string_ret, chan->cid.cid_rdnis, sizeof(string_ret));
437                         string_ret[sizeof(string_ret) - 1] = '\0';
438                         *var_len = strlen(string_ret);
439                         ret = (u_char *)string_ret;
440                 }
441                 break;
442         case ASTCHANCIDPRES:
443                 long_ret = chan->cid.cid_pres;
444                 ret = (u_char *)&long_ret;
445                 break;
446         case ASTCHANCIDANI2:
447                 long_ret = chan->cid.cid_ani2;
448                 ret = (u_char *)&long_ret;
449                 break;
450         case ASTCHANCIDTON:
451                 long_ret = chan->cid.cid_ton;
452                 ret = (u_char *)&long_ret;
453                 break;
454         case ASTCHANCIDTNS:
455                 long_ret = chan->cid.cid_tns;
456                 ret = (u_char *)&long_ret;
457                 break;
458         case ASTCHANAMAFLAGS:
459                 long_ret = chan->amaflags;
460                 ret = (u_char *)&long_ret;
461                 break;
462         case ASTCHANADSI:
463                 long_ret = chan->adsicpe;
464                 ret = (u_char *)&long_ret;
465                 break;
466         case ASTCHANTONEZONE:
467                 if (chan->zone) {
468                         strncpy(string_ret, chan->zone->country, sizeof(string_ret));
469                         string_ret[sizeof(string_ret) - 1] = '\0';
470                         *var_len = strlen(string_ret);
471                         ret = (u_char *)string_ret;
472                 }
473                 break;
474         case ASTCHANHANGUPCAUSE:
475                 long_ret = chan->hangupcause;
476                 ret = (u_char *)&long_ret;
477                 break;
478         case ASTCHANVARIABLES:
479                 if (pbx_builtin_serialize_variables(chan, &out)) {
480                         *var_len = strlen(out->str);
481                         ret = (u_char *)out->str;
482                 }
483                 break;
484         case ASTCHANFLAGS:
485                 bits_ret[0] = 0;
486                 for (bit = 0; bit < 8; bit++)
487                         bits_ret[0] |= ((chan->flags & (1 << bit)) >> bit) << (7 - bit);
488                 bits_ret[1] = 0;
489                 for (bit = 0; bit < 8; bit++)
490                         bits_ret[1] |= (((chan->flags >> 8) & (1 << bit)) >> bit) << (7 - bit);
491                 *var_len = 2;
492                 ret = bits_ret;
493                 break;
494         case ASTCHANTRANSFERCAP:
495                 long_ret = chan->transfercapability;
496                 ret = (u_char *)&long_ret;
497         default:
498                 break;
499         }
500         ast_channel_unlock(chan);
501         return ret;
502 }
503
504 static u_char *ast_var_channel_types(struct variable *vp, oid *name, size_t *length,
505                                                                    int exact, size_t *var_len, WriteMethod **write_method)
506 {
507         static unsigned long long_ret;
508         struct ast_variable *channel_types, *next;
509
510         if (header_generic(vp, name, length, exact, var_len, write_method))
511                 return NULL;
512
513         if (vp->magic != ASTCHANTYPECOUNT)
514                 return NULL;
515
516         for (long_ret = 0, channel_types = next = ast_channeltype_list(); next; next = next->next)
517                 long_ret++;
518         ast_variables_destroy(channel_types);
519
520         return (u_char *)&long_ret;
521 }
522
523 static u_char *ast_var_channel_types_table(struct variable *vp, oid *name, size_t *length,
524                                                                                 int exact, size_t *var_len, WriteMethod **write_method)
525 {
526         const struct ast_channel_tech *tech = NULL;
527         struct ast_variable *channel_types, *next;
528         static unsigned long long_ret;
529         struct ast_channel *chan;
530         u_long i;
531
532         if (header_simple_table(vp, name, length, exact, var_len, write_method, -1))
533                 return NULL;
534
535         channel_types = ast_channeltype_list();
536         for (i = 1, next = channel_types; next && i != name[*length - 1]; next = next->next, i++)
537                 ;
538         if (next != NULL)
539                 tech = ast_get_channel_tech(next->name);
540         ast_variables_destroy(channel_types);
541         if (next == NULL || tech == NULL)
542                 return NULL;
543         
544         switch (vp->magic) {
545         case ASTCHANTYPEINDEX:
546                 long_ret = name[*length - 1];
547                 return (u_char *)&long_ret;
548         case ASTCHANTYPENAME:
549                 *var_len = strlen(tech->type);
550                 return (u_char *)tech->type;
551         case ASTCHANTYPEDESC:
552                 *var_len = strlen(tech->description);
553                 return (u_char *)tech->description;
554         case ASTCHANTYPEDEVSTATE:
555                 long_ret = tech->devicestate ? 1 : 2;
556                 return (u_char *)&long_ret;
557         case ASTCHANTYPEINDICATIONS:
558                 long_ret = tech->indicate ? 1 : 2;
559                 return (u_char *)&long_ret;
560         case ASTCHANTYPETRANSFER:
561                 long_ret = tech->transfer ? 1 : 2;
562                 return (u_char *)&long_ret;
563         case ASTCHANTYPECHANNELS:
564                 long_ret = 0;
565                 for (chan = ast_channel_walk_locked(NULL); chan; chan = ast_channel_walk_locked(chan)) {
566                         ast_channel_unlock(chan);
567                         if (chan->tech == tech)
568                                 long_ret++;
569                 }
570                 return (u_char *)&long_ret;
571         default:
572                 break;
573         }
574         return NULL;
575 }
576
577 static u_char *ast_var_channel_bridge(struct variable *vp, oid *name, size_t *length,
578         int exact, size_t *var_len, WriteMethod **write_method)
579 {
580         static unsigned long long_ret;
581         struct ast_channel *chan = NULL;
582
583         long_ret = 0;
584         if (header_generic(vp, name, length, exact, var_len, write_method))
585                 return NULL;
586
587         while ((chan = ast_channel_walk_locked(chan))) {
588                 if (ast_bridged_channel(chan))
589                         long_ret++;
590                 ast_channel_unlock(chan);
591         }
592
593         *var_len = sizeof(long_ret);
594
595         return (vp->magic == ASTCHANBRIDGECOUNT) ? (u_char *) &long_ret : NULL;
596 }
597
598 static u_char *ast_var_Config(struct variable *vp, oid *name, size_t *length,
599                                                          int exact, size_t *var_len, WriteMethod **write_method)
600 {
601         static unsigned long long_ret;
602         struct timeval tval;
603
604         if (header_generic(vp, name, length, exact, var_len, write_method))
605                 return NULL;
606
607         switch (vp->magic) {
608         case ASTCONFUPTIME:
609                 gettimeofday(&tval, NULL);
610                 long_ret = difftime(tval.tv_sec, ast_startuptime.tv_sec) * 100 + tval.tv_usec / 10000 - ast_startuptime.tv_usec / 10000;
611                 return (u_char *)&long_ret;
612         case ASTCONFRELOADTIME:
613                 gettimeofday(&tval, NULL);
614                 if (ast_lastreloadtime.tv_sec)
615                         long_ret = difftime(tval.tv_sec, ast_lastreloadtime.tv_sec) * 100 + tval.tv_usec / 10000 - ast_lastreloadtime.tv_usec / 10000;
616                 else
617                         long_ret = difftime(tval.tv_sec, ast_startuptime.tv_sec) * 100 + tval.tv_usec / 10000 - ast_startuptime.tv_usec / 10000;
618                 return (u_char *)&long_ret;
619         case ASTCONFPID:
620                 long_ret = getpid();
621                 return (u_char *)&long_ret;
622         case ASTCONFSOCKET:
623                 *var_len = strlen(ast_config_AST_SOCKET);
624                 return (u_char *)ast_config_AST_SOCKET;
625         case ASTCONFACTIVECALLS:
626                 long_ret = ast_active_calls();
627                 return (u_char *)&long_ret;
628         case ASTCONFPROCESSEDCALLS:
629                 long_ret = ast_processed_calls();
630                 return (u_char *)&long_ret;
631         default:
632                 break;
633         }
634         return NULL;
635 }
636
637 static u_char *ast_var_indications(struct variable *vp, oid *name, size_t *length,
638                                                                   int exact, size_t *var_len, WriteMethod **write_method)
639 {
640         static unsigned long long_ret;
641         struct ind_tone_zone *tz = NULL;
642
643         if (header_generic(vp, name, length, exact, var_len, write_method))
644                 return NULL;
645
646         switch (vp->magic) {
647         case ASTINDCOUNT:
648                 long_ret = 0;
649                 while ( (tz = ast_walk_indications(tz)) )
650                         long_ret++;
651
652                 return (u_char *)&long_ret;
653         case ASTINDCURRENT:
654                 tz = ast_get_indication_zone(NULL);
655                 if (tz) {
656                         *var_len = strlen(tz->country);
657                         return (u_char *)tz->country;
658                 }
659                 *var_len = 0;
660                 return NULL;
661         default:
662                 break;
663         }
664         return NULL;
665 }
666
667 static u_char *ast_var_indications_table(struct variable *vp, oid *name, size_t *length,
668                                                                            int exact, size_t *var_len, WriteMethod **write_method)
669 {
670         static unsigned long long_ret;
671         struct ind_tone_zone *tz = NULL;
672         int i;
673
674         if (header_simple_table(vp, name, length, exact, var_len, write_method, -1))
675                 return NULL;
676
677         i = name[*length - 1] - 1;
678         while ( (tz = ast_walk_indications(tz)) && i )
679         i--;
680         if (tz == NULL)
681                 return NULL;
682
683         switch (vp->magic) {
684         case ASTINDINDEX:
685                 long_ret = name[*length - 1];
686                 return (u_char *)&long_ret;
687         case ASTINDCOUNTRY:
688                 *var_len = strlen(tz->country);
689                 return (u_char *)tz->country;
690         case ASTINDALIAS:
691                 if (tz->alias) {
692                         *var_len = strlen(tz->alias);
693                         return (u_char *)tz->alias;
694                 }
695                 return NULL;
696         case ASTINDDESCRIPTION:
697                 *var_len = strlen(tz->description);
698                 return (u_char *)tz->description;
699         default:
700                 break;
701         }
702         return NULL;
703 }
704
705 static int countmodule(const char *mod, const char *desc, int use, const char *like)
706 {
707         return 1;
708 }
709
710 static u_char *ast_var_Modules(struct variable *vp, oid *name, size_t *length,
711                                                           int exact, size_t *var_len, WriteMethod **write_method)
712 {
713         static unsigned long long_ret;
714
715         if (header_generic(vp, name, length, exact, var_len, write_method))
716                 return NULL;
717
718         if (vp->magic != ASTMODCOUNT)
719                 return NULL;
720
721         long_ret = ast_update_module_list(countmodule, NULL);
722
723         return (u_char *)&long_ret;
724 }
725
726 static u_char *ast_var_Version(struct variable *vp, oid *name, size_t *length,
727                                                           int exact, size_t *var_len, WriteMethod **write_method)
728 {
729         static unsigned long long_ret;
730
731         if (header_generic(vp, name, length, exact, var_len, write_method))
732                 return NULL;
733
734         switch (vp->magic) {
735         case ASTVERSTRING:
736                 *var_len = strlen(ASTERISK_VERSION);
737                 return (u_char *)ASTERISK_VERSION;
738         case ASTVERTAG:
739                 long_ret = ASTERISK_VERSION_NUM;
740                 return (u_char *)&long_ret;
741         default:
742                 break;
743         }
744         return NULL;
745 }
746
747 static int term_asterisk_mib(int majorID, int minorID, void *serverarg, void *clientarg)
748 {
749         unregister_sysORTable(asterisk_oid, OID_LENGTH(asterisk_oid));
750         return 0;
751 }
752
753 static void init_asterisk_mib(void)
754 {
755         static struct variable4 asterisk_vars[] = {
756                 {ASTVERSTRING,           ASN_OCTET_STR, RONLY, ast_var_Version,             2, {ASTVERSION, ASTVERSTRING}},
757                 {ASTVERTAG,              ASN_UNSIGNED,  RONLY, ast_var_Version,             2, {ASTVERSION, ASTVERTAG}},
758                 {ASTCONFUPTIME,          ASN_TIMETICKS, RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFUPTIME}},
759                 {ASTCONFRELOADTIME,      ASN_TIMETICKS, RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFRELOADTIME}},
760                 {ASTCONFPID,             ASN_INTEGER,   RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFPID}},
761                 {ASTCONFSOCKET,          ASN_OCTET_STR, RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFSOCKET}},
762                 {ASTCONFACTIVECALLS,     ASN_GAUGE,     RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFACTIVECALLS}},
763                 {ASTCONFPROCESSEDCALLS,  ASN_INTEGER,   RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFPROCESSEDCALLS}},
764                 {ASTMODCOUNT,            ASN_INTEGER,   RONLY, ast_var_Modules ,            2, {ASTMODULES, ASTMODCOUNT}},
765                 {ASTINDCOUNT,            ASN_INTEGER,   RONLY, ast_var_indications,         2, {ASTINDICATIONS, ASTINDCOUNT}},
766                 {ASTINDCURRENT,          ASN_OCTET_STR, RONLY, ast_var_indications,         2, {ASTINDICATIONS, ASTINDCURRENT}},
767                 {ASTINDINDEX,            ASN_INTEGER,   RONLY, ast_var_indications_table,   4, {ASTINDICATIONS, ASTINDTABLE, 1, ASTINDINDEX}},
768                 {ASTINDCOUNTRY,          ASN_OCTET_STR, RONLY, ast_var_indications_table,   4, {ASTINDICATIONS, ASTINDTABLE, 1, ASTINDCOUNTRY}},
769                 {ASTINDALIAS,            ASN_OCTET_STR, RONLY, ast_var_indications_table,   4, {ASTINDICATIONS, ASTINDTABLE, 1, ASTINDALIAS}},
770                 {ASTINDDESCRIPTION,      ASN_OCTET_STR, RONLY, ast_var_indications_table,   4, {ASTINDICATIONS, ASTINDTABLE, 1, ASTINDDESCRIPTION}},
771                 {ASTCHANCOUNT,           ASN_INTEGER,   RONLY, ast_var_channels,            2, {ASTCHANNELS, ASTCHANCOUNT}},
772                 {ASTCHANINDEX,           ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANINDEX}},
773                 {ASTCHANNAME,            ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANNAME}},
774                 {ASTCHANLANGUAGE,        ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANLANGUAGE}},
775                 {ASTCHANTYPE,            ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANTYPE}},
776                 {ASTCHANMUSICCLASS,      ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMUSICCLASS}},
777                 {ASTCHANBRIDGE,          ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANBRIDGE}},
778                 {ASTCHANMASQ,            ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMASQ}},
779                 {ASTCHANMASQR,           ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMASQR}},
780                 {ASTCHANWHENHANGUP,      ASN_TIMETICKS, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANWHENHANGUP}},
781                 {ASTCHANAPP,             ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANAPP}},
782                 {ASTCHANDATA,            ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANDATA}},
783                 {ASTCHANCONTEXT,         ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCONTEXT}},
784                 {ASTCHANMACROCONTEXT,    ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMACROCONTEXT}},
785                 {ASTCHANMACROEXTEN,      ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMACROEXTEN}},
786                 {ASTCHANMACROPRI,        ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMACROPRI}},
787                 {ASTCHANEXTEN,           ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANEXTEN}},
788                 {ASTCHANPRI,             ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANPRI}},
789                 {ASTCHANACCOUNTCODE,     ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANACCOUNTCODE}},
790                 {ASTCHANFORWARDTO,       ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANFORWARDTO}},
791                 {ASTCHANUNIQUEID,        ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANUNIQUEID}},
792                 {ASTCHANCALLGROUP,       ASN_UNSIGNED,  RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCALLGROUP}},
793                 {ASTCHANPICKUPGROUP,     ASN_UNSIGNED,  RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANPICKUPGROUP}},
794                 {ASTCHANSTATE,           ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANSTATE}},
795                 {ASTCHANMUTED,           ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMUTED}},
796                 {ASTCHANRINGS,           ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANRINGS}},
797                 {ASTCHANCIDDNID,         ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDDNID}},
798                 {ASTCHANCIDNUM,          ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDNUM}},
799                 {ASTCHANCIDNAME,         ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDNAME}},
800                 {ASTCHANCIDANI,          ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDANI}},
801                 {ASTCHANCIDRDNIS,        ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDRDNIS}},
802                 {ASTCHANCIDPRES,         ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDPRES}},
803                 {ASTCHANCIDANI2,         ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDANI2}},
804                 {ASTCHANCIDTON,          ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDTON}},
805                 {ASTCHANCIDTNS,          ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDTNS}},
806                 {ASTCHANAMAFLAGS,        ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANAMAFLAGS}},
807                 {ASTCHANADSI,            ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANADSI}},
808                 {ASTCHANTONEZONE,        ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANTONEZONE}},
809                 {ASTCHANHANGUPCAUSE,     ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANHANGUPCAUSE}},
810                 {ASTCHANVARIABLES,       ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANVARIABLES}},
811                 {ASTCHANFLAGS,           ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANFLAGS}},
812                 {ASTCHANTRANSFERCAP,     ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANTRANSFERCAP}},
813                 {ASTCHANTYPECOUNT,       ASN_INTEGER,   RONLY, ast_var_channel_types,       2, {ASTCHANNELS, ASTCHANTYPECOUNT}},
814                 {ASTCHANTYPEINDEX,       ASN_INTEGER,   RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPEINDEX}},
815                 {ASTCHANTYPENAME,        ASN_OCTET_STR, RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPENAME}},
816                 {ASTCHANTYPEDESC,        ASN_OCTET_STR, RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPEDESC}},
817                 {ASTCHANTYPEDEVSTATE,    ASN_INTEGER,   RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPEDEVSTATE}},
818                 {ASTCHANTYPEINDICATIONS, ASN_INTEGER,   RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPEINDICATIONS}},
819                 {ASTCHANTYPETRANSFER,    ASN_INTEGER,   RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPETRANSFER}},
820                 {ASTCHANTYPECHANNELS,    ASN_GAUGE,     RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPECHANNELS}},
821                 {ASTCHANBRIDGECOUNT,     ASN_GAUGE,     RONLY, ast_var_channel_bridge,      3, {ASTCHANNELS, ASTCHANSCALARS, ASTCHANBRIDGECOUNT}},
822         };
823
824         register_sysORTable(asterisk_oid, OID_LENGTH(asterisk_oid),
825                         "ASTERISK-MIB implementation for Asterisk.");
826
827         REGISTER_MIB("res_snmp", asterisk_vars, variable4, asterisk_oid);
828
829         snmp_register_callback(SNMP_CALLBACK_LIBRARY,
830                            SNMP_CALLBACK_SHUTDOWN,
831                            term_asterisk_mib, NULL);
832 }
833
834 /*
835  * Local Variables:
836  * c-basic-offset: 4
837  * c-file-offsets: ((case-label . 0))
838  * tab-width: 4
839  * indent-tabs-mode: t
840  * End:
841  */