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