Get the SNMP code to compile.
[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_channel_bridge_peer(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                         ast_channel_unref(bridge);
306                 }
307                 break;
308         case ASTCHANMASQ:
309                 if (ast_channel_masq(chan) && !ast_strlen_zero(ast_channel_name(ast_channel_masq(chan)))) {
310                         ast_copy_string(string_ret, ast_channel_name(ast_channel_masq(chan)), sizeof(string_ret));
311                         *var_len = strlen(string_ret);
312                         ret = (u_char *)string_ret;
313                 }
314                 break;
315         case ASTCHANMASQR:
316                 if (ast_channel_masqr(chan) && !ast_strlen_zero(ast_channel_name(ast_channel_masqr(chan)))) {
317                         ast_copy_string(string_ret, ast_channel_name(ast_channel_masqr(chan)), sizeof(string_ret));
318                         *var_len = strlen(string_ret);
319                         ret = (u_char *)string_ret;
320                 }
321                 break;
322         case ASTCHANWHENHANGUP:
323                 if (!ast_tvzero(*ast_channel_whentohangup(chan))) {
324                         gettimeofday(&tval, NULL);
325                         long_ret = difftime(ast_channel_whentohangup(chan)->tv_sec, tval.tv_sec) * 100 - tval.tv_usec / 10000;
326                         ret= (u_char *)&long_ret;
327                 }
328                 break;
329         case ASTCHANAPP:
330                 if (ast_channel_appl(chan)) {
331                         ast_copy_string(string_ret, ast_channel_appl(chan), sizeof(string_ret));
332                         *var_len = strlen(string_ret);
333                         ret = (u_char *)string_ret;
334                 }
335                 break;
336         case ASTCHANDATA:
337                 if (ast_channel_data(chan)) {
338                         ast_copy_string(string_ret, ast_channel_data(chan), sizeof(string_ret));
339                         *var_len = strlen(string_ret);
340                         ret = (u_char *)string_ret;
341                 }
342                 break;
343         case ASTCHANCONTEXT:
344                 ast_copy_string(string_ret, ast_channel_context(chan), sizeof(string_ret));
345                 *var_len = strlen(string_ret);
346                 ret = (u_char *)string_ret;
347                 break;
348         case ASTCHANMACROCONTEXT:
349                 ast_copy_string(string_ret, ast_channel_macrocontext(chan), sizeof(string_ret));
350                 *var_len = strlen(string_ret);
351                 ret = (u_char *)string_ret;
352                 break;
353         case ASTCHANMACROEXTEN:
354                 ast_copy_string(string_ret, ast_channel_macroexten(chan), sizeof(string_ret));
355                 *var_len = strlen(string_ret);
356                 ret = (u_char *)string_ret;
357                 break;
358         case ASTCHANMACROPRI:
359                 long_ret = ast_channel_macropriority(chan);
360                 ret = (u_char *)&long_ret;
361                 break;
362         case ASTCHANEXTEN:
363                 ast_copy_string(string_ret, ast_channel_exten(chan), sizeof(string_ret));
364                 *var_len = strlen(string_ret);
365                 ret = (u_char *)string_ret;
366                 break;
367         case ASTCHANPRI:
368                 long_ret = ast_channel_priority(chan);
369                 ret = (u_char *)&long_ret;
370                 break;
371         case ASTCHANACCOUNTCODE:
372                 if (!ast_strlen_zero(ast_channel_accountcode(chan))) {
373                         ast_copy_string(string_ret, ast_channel_accountcode(chan), sizeof(string_ret));
374                         *var_len = strlen(string_ret);
375                         ret = (u_char *)string_ret;
376                 }
377                 break;
378         case ASTCHANFORWARDTO:
379                 if (!ast_strlen_zero(ast_channel_call_forward(chan))) {
380                         ast_copy_string(string_ret, ast_channel_call_forward(chan), sizeof(string_ret));
381                         *var_len = strlen(string_ret);
382                         ret = (u_char *)string_ret;
383                 }
384                 break;
385         case ASTCHANUNIQUEID:
386                 ast_copy_string(string_ret, ast_channel_uniqueid(chan), sizeof(string_ret));
387                 *var_len = strlen(string_ret);
388                 ret = (u_char *)string_ret;
389                 break;
390         case ASTCHANCALLGROUP:
391                 long_ret = ast_channel_callgroup(chan);
392                 ret = (u_char *)&long_ret;
393                 break;
394         case ASTCHANPICKUPGROUP:
395                 long_ret = ast_channel_pickupgroup(chan);
396                 ret = (u_char *)&long_ret;
397                 break;
398         case ASTCHANSTATE:
399                 long_ret = ast_channel_state(chan) & 0xffff;
400                 ret = (u_char *)&long_ret;
401                 break;
402         case ASTCHANMUTED:
403                 long_ret = ast_channel_state(chan) & AST_STATE_MUTE ? 1 : 2;
404                 ret = (u_char *)&long_ret;
405                 break;
406         case ASTCHANRINGS:
407                 long_ret = ast_channel_rings(chan);
408                 ret = (u_char *)&long_ret;
409                 break;
410         case ASTCHANCIDDNID:
411                 if (ast_channel_dialed(chan)->number.str) {
412                         ast_copy_string(string_ret, ast_channel_dialed(chan)->number.str, sizeof(string_ret));
413                         *var_len = strlen(string_ret);
414                         ret = (u_char *)string_ret;
415                 }
416                 break;
417         case ASTCHANCIDNUM:
418                 if (ast_channel_caller(chan)->id.number.valid && ast_channel_caller(chan)->id.number.str) {
419                         ast_copy_string(string_ret, ast_channel_caller(chan)->id.number.str, sizeof(string_ret));
420                         *var_len = strlen(string_ret);
421                         ret = (u_char *)string_ret;
422                 }
423                 break;
424         case ASTCHANCIDNAME:
425                 if (ast_channel_caller(chan)->id.name.valid && ast_channel_caller(chan)->id.name.str) {
426                         ast_copy_string(string_ret, ast_channel_caller(chan)->id.name.str, sizeof(string_ret));
427                         *var_len = strlen(string_ret);
428                         ret = (u_char *)string_ret;
429                 }
430                 break;
431         case ASTCHANCIDANI:
432                 if (ast_channel_caller(chan)->ani.number.valid && ast_channel_caller(chan)->ani.number.str) {
433                         ast_copy_string(string_ret, ast_channel_caller(chan)->ani.number.str, sizeof(string_ret));
434                         *var_len = strlen(string_ret);
435                         ret = (u_char *)string_ret;
436                 }
437                 break;
438         case ASTCHANCIDRDNIS:
439                 if (ast_channel_redirecting(chan)->from.number.valid && ast_channel_redirecting(chan)->from.number.str) {
440                         ast_copy_string(string_ret, ast_channel_redirecting(chan)->from.number.str, sizeof(string_ret));
441                         *var_len = strlen(string_ret);
442                         ret = (u_char *)string_ret;
443                 }
444                 break;
445         case ASTCHANCIDPRES:
446                 long_ret = ast_party_id_presentation(&ast_channel_caller(chan)->id);
447                 ret = (u_char *)&long_ret;
448                 break;
449         case ASTCHANCIDANI2:
450                 long_ret = ast_channel_caller(chan)->ani2;
451                 ret = (u_char *)&long_ret;
452                 break;
453         case ASTCHANCIDTON:
454                 long_ret = ast_channel_caller(chan)->id.number.plan;
455                 ret = (u_char *)&long_ret;
456                 break;
457         case ASTCHANCIDTNS:
458                 long_ret = ast_channel_dialed(chan)->transit_network_select;
459                 ret = (u_char *)&long_ret;
460                 break;
461         case ASTCHANAMAFLAGS:
462                 long_ret = ast_channel_amaflags(chan);
463                 ret = (u_char *)&long_ret;
464                 break;
465         case ASTCHANADSI:
466                 long_ret = ast_channel_adsicpe(chan);
467                 ret = (u_char *)&long_ret;
468                 break;
469         case ASTCHANTONEZONE:
470                 if (ast_channel_zone(chan)) {
471                         ast_copy_string(string_ret, ast_channel_zone(chan)->country, sizeof(string_ret));
472                         *var_len = strlen(string_ret);
473                         ret = (u_char *)string_ret;
474                 }
475                 break;
476         case ASTCHANHANGUPCAUSE:
477                 long_ret = ast_channel_hangupcause(chan);
478                 ret = (u_char *)&long_ret;
479                 break;
480         case ASTCHANVARIABLES:
481                 if (pbx_builtin_serialize_variables(chan, &out)) {
482                         *var_len = ast_str_strlen(out);
483                         ret = (u_char *)ast_str_buffer(out);
484                 }
485                 break;
486         case ASTCHANFLAGS:
487                 bits_ret[0] = 0;
488                 for (bit = 0; bit < 8; bit++)
489                         bits_ret[0] |= ((ast_channel_flags(chan)->flags & (1 << bit)) >> bit) << (7 - bit);
490                 bits_ret[1] = 0;
491                 for (bit = 0; bit < 8; bit++)
492                         bits_ret[1] |= (((ast_channel_flags(chan)->flags >> 8) & (1 << bit)) >> bit) << (7 - bit);
493                 *var_len = 2;
494                 ret = bits_ret;
495                 break;
496         case ASTCHANTRANSFERCAP:
497                 long_ret = ast_channel_transfercapability(chan);
498                 ret = (u_char *)&long_ret;
499         default:
500                 break;
501         }
502
503         ast_channel_unlock(chan);
504         chan = ast_channel_unref(chan);
505
506         return ret;
507 }
508
509 static u_char *ast_var_channel_types(struct variable *vp, oid *name, size_t *length,
510                                                                    int exact, size_t *var_len, WriteMethod **write_method)
511 {
512         static unsigned long long_ret;
513         struct ast_variable *channel_types, *next;
514
515         if (header_generic(vp, name, length, exact, var_len, write_method))
516                 return NULL;
517
518         if (vp->magic != ASTCHANTYPECOUNT)
519                 return NULL;
520
521         for (long_ret = 0, channel_types = next = ast_channeltype_list(); next; next = next->next)
522                 long_ret++;
523         ast_variables_destroy(channel_types);
524
525         return (u_char *)&long_ret;
526 }
527
528 static u_char *ast_var_channel_types_table(struct variable *vp, oid *name, size_t *length,
529                                                                                 int exact, size_t *var_len, WriteMethod **write_method)
530 {
531         const struct ast_channel_tech *tech = NULL;
532         struct ast_variable *channel_types, *next;
533         static unsigned long long_ret;
534         struct ast_channel *chan;
535         u_long i;
536
537         if (header_simple_table(vp, name, length, exact, var_len, write_method, -1))
538                 return NULL;
539
540         channel_types = ast_channeltype_list();
541         for (i = 1, next = channel_types; next && i != name[*length - 1]; next = next->next, i++)
542                 ;
543         if (next != NULL)
544                 tech = ast_get_channel_tech(next->name);
545         ast_variables_destroy(channel_types);
546         if (next == NULL || tech == NULL)
547                 return NULL;
548         
549         switch (vp->magic) {
550         case ASTCHANTYPEINDEX:
551                 long_ret = name[*length - 1];
552                 return (u_char *)&long_ret;
553         case ASTCHANTYPENAME:
554                 *var_len = strlen(tech->type);
555                 return (u_char *)tech->type;
556         case ASTCHANTYPEDESC:
557                 *var_len = strlen(tech->description);
558                 return (u_char *)tech->description;
559         case ASTCHANTYPEDEVSTATE:
560                 long_ret = tech->devicestate ? 1 : 2;
561                 return (u_char *)&long_ret;
562         case ASTCHANTYPEINDICATIONS:
563                 long_ret = tech->indicate ? 1 : 2;
564                 return (u_char *)&long_ret;
565         case ASTCHANTYPETRANSFER:
566                 long_ret = tech->transfer ? 1 : 2;
567                 return (u_char *)&long_ret;
568         case ASTCHANTYPECHANNELS:
569         {
570                 struct ast_channel_iterator *iter;
571
572                 long_ret = 0;
573
574                 if (!(iter = ast_channel_iterator_all_new())) {
575                         return NULL;
576                 }
577
578                 while ((chan = ast_channel_iterator_next(iter))) {
579                         if (ast_channel_tech(chan) == tech) {
580                                 long_ret++;
581                         }
582                         chan = ast_channel_unref(chan);
583                 }
584
585                 ast_channel_iterator_destroy(iter);
586
587                 return (u_char *)&long_ret;
588         }
589         default:
590                 break;
591         }
592         return NULL;
593 }
594
595 static u_char *ast_var_channel_bridge(struct variable *vp, oid *name, size_t *length,
596         int exact, size_t *var_len, WriteMethod **write_method)
597 {
598         static unsigned long long_ret;
599         struct ast_channel *chan = NULL;
600         struct ast_channel_iterator *iter;
601
602         long_ret = 0;
603
604         if (header_generic(vp, name, length, exact, var_len, write_method)) {
605                 return NULL;
606         }
607
608         if (!(iter = ast_channel_iterator_all_new())) {
609                 return NULL;
610         }
611
612         while ((chan = ast_channel_iterator_next(iter))) {
613                 ast_channel_lock(chan);
614                 if (ast_channel_is_bridged(chan)) {
615                         long_ret++;
616                 }
617                 ast_channel_unlock(chan);
618                 chan = ast_channel_unref(chan);
619         }
620
621         ast_channel_iterator_destroy(iter);
622
623         *var_len = sizeof(long_ret);
624
625         return (vp->magic == ASTCHANBRIDGECOUNT) ? (u_char *) &long_ret : NULL;
626 }
627
628 static u_char *ast_var_Config(struct variable *vp, oid *name, size_t *length,
629                                                          int exact, size_t *var_len, WriteMethod **write_method)
630 {
631         static unsigned long long_ret;
632         struct timeval tval;
633
634         if (header_generic(vp, name, length, exact, var_len, write_method))
635                 return NULL;
636
637         switch (vp->magic) {
638         case ASTCONFUPTIME:
639                 gettimeofday(&tval, NULL);
640                 long_ret = difftime(tval.tv_sec, ast_startuptime.tv_sec) * 100 + tval.tv_usec / 10000 - ast_startuptime.tv_usec / 10000;
641                 return (u_char *)&long_ret;
642         case ASTCONFRELOADTIME:
643                 gettimeofday(&tval, NULL);
644                 if (ast_lastreloadtime.tv_sec)
645                         long_ret = difftime(tval.tv_sec, ast_lastreloadtime.tv_sec) * 100 + tval.tv_usec / 10000 - ast_lastreloadtime.tv_usec / 10000;
646                 else
647                         long_ret = difftime(tval.tv_sec, ast_startuptime.tv_sec) * 100 + tval.tv_usec / 10000 - ast_startuptime.tv_usec / 10000;
648                 return (u_char *)&long_ret;
649         case ASTCONFPID:
650                 long_ret = getpid();
651                 return (u_char *)&long_ret;
652         case ASTCONFSOCKET:
653                 *var_len = strlen(ast_config_AST_SOCKET);
654                 return (u_char *)ast_config_AST_SOCKET;
655         case ASTCONFACTIVECALLS:
656                 long_ret = ast_active_calls();
657                 return (u_char *)&long_ret;
658         case ASTCONFPROCESSEDCALLS:
659                 long_ret = ast_processed_calls();
660                 return (u_char *)&long_ret;
661         default:
662                 break;
663         }
664         return NULL;
665 }
666
667 static u_char *ast_var_indications(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         static char ret_buf[128];
672         struct ast_tone_zone *tz = NULL;
673
674         if (header_generic(vp, name, length, exact, var_len, write_method))
675                 return NULL;
676
677         switch (vp->magic) {
678         case ASTINDCOUNT:
679         {
680                 struct ao2_iterator i;
681
682                 long_ret = 0;
683
684                 i = ast_tone_zone_iterator_init();
685                 while ((tz = ao2_iterator_next(&i))) {
686                         tz = ast_tone_zone_unref(tz);
687                         long_ret++;
688                 }
689                 ao2_iterator_destroy(&i);
690
691                 return (u_char *) &long_ret;
692         }
693         case ASTINDCURRENT:
694                 tz = ast_get_indication_zone(NULL);
695                 if (tz) {
696                         ast_copy_string(ret_buf, tz->country, sizeof(ret_buf));
697                         *var_len = strlen(ret_buf);
698                         tz = ast_tone_zone_unref(tz);
699                         return (u_char *) ret_buf;
700                 }
701                 *var_len = 0;
702                 return NULL;
703         default:
704                 break;
705         }
706         return NULL;
707 }
708
709 static u_char *ast_var_indications_table(struct variable *vp, oid *name, size_t *length,
710                                                                            int exact, size_t *var_len, WriteMethod **write_method)
711 {
712         static unsigned long long_ret;
713         static char ret_buf[256];
714         struct ast_tone_zone *tz = NULL;
715         int i;
716         struct ao2_iterator iter;
717
718         if (header_simple_table(vp, name, length, exact, var_len, write_method, -1)) {
719                 return NULL;
720         }
721
722         i = name[*length - 1] - 1;
723
724         iter = ast_tone_zone_iterator_init();
725
726         while ((tz = ao2_iterator_next(&iter)) && i) {
727                 tz = ast_tone_zone_unref(tz);
728                 i--;
729         }
730         ao2_iterator_destroy(&iter);
731
732         if (tz == NULL) {
733                 return NULL;
734         }
735
736         switch (vp->magic) {
737         case ASTINDINDEX:
738                 ast_tone_zone_unref(tz);
739                 long_ret = name[*length - 1];
740                 return (u_char *)&long_ret;
741         case ASTINDCOUNTRY:
742                 ast_copy_string(ret_buf, tz->country, sizeof(ret_buf));
743                 ast_tone_zone_unref(tz);
744                 *var_len = strlen(ret_buf);
745                 return (u_char *) ret_buf;
746         case ASTINDALIAS:
747                 /* No longer exists */
748                 ast_tone_zone_unref(tz);
749                 return NULL;
750         case ASTINDDESCRIPTION:
751                 ast_tone_zone_lock(tz);
752                 ast_copy_string(ret_buf, tz->description, sizeof(ret_buf));
753                 ast_tone_zone_unlock(tz);
754                 ast_tone_zone_unref(tz);
755                 *var_len = strlen(ret_buf);
756                 return (u_char *) ret_buf;
757         default:
758                 ast_tone_zone_unref(tz);
759                 break;
760         }
761         return NULL;
762 }
763
764 static int countmodule(const char *mod, const char *desc, int use, const char *status, const char *like)
765 {
766         return 1;
767 }
768
769 static u_char *ast_var_Modules(struct variable *vp, oid *name, size_t *length,
770                                                           int exact, size_t *var_len, WriteMethod **write_method)
771 {
772         static unsigned long long_ret;
773
774         if (header_generic(vp, name, length, exact, var_len, write_method))
775                 return NULL;
776
777         if (vp->magic != ASTMODCOUNT)
778                 return NULL;
779
780         long_ret = ast_update_module_list(countmodule, NULL);
781
782         return (u_char *)&long_ret;
783 }
784
785 static u_char *ast_var_Version(struct variable *vp, oid *name, size_t *length,
786                                                           int exact, size_t *var_len, WriteMethod **write_method)
787 {
788         static unsigned long long_ret;
789
790         if (header_generic(vp, name, length, exact, var_len, write_method))
791                 return NULL;
792
793         switch (vp->magic) {
794         case ASTVERSTRING:
795         {
796                 const char *version = ast_get_version();
797                 *var_len = strlen(version);
798                 return (u_char *)version;
799         }
800         case ASTVERTAG:
801                 sscanf(ast_get_version_num(), "%30lu", &long_ret);
802                 return (u_char *)&long_ret;
803         default:
804                 break;
805         }
806         return NULL;
807 }
808
809 static int term_asterisk_mib(int majorID, int minorID, void *serverarg, void *clientarg)
810 {
811         unregister_sysORTable(asterisk_oid, OID_LENGTH(asterisk_oid));
812         return 0;
813 }
814
815 static void init_asterisk_mib(void)
816 {
817         static struct variable4 asterisk_vars[] = {
818                 {ASTVERSTRING,           ASN_OCTET_STR, RONLY, ast_var_Version,             2, {ASTVERSION, ASTVERSTRING}},
819                 {ASTVERTAG,              ASN_UNSIGNED,  RONLY, ast_var_Version,             2, {ASTVERSION, ASTVERTAG}},
820                 {ASTCONFUPTIME,          ASN_TIMETICKS, RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFUPTIME}},
821                 {ASTCONFRELOADTIME,      ASN_TIMETICKS, RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFRELOADTIME}},
822                 {ASTCONFPID,             ASN_INTEGER,   RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFPID}},
823                 {ASTCONFSOCKET,          ASN_OCTET_STR, RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFSOCKET}},
824                 {ASTCONFACTIVECALLS,     ASN_GAUGE,     RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFACTIVECALLS}},
825                 {ASTCONFPROCESSEDCALLS,  ASN_COUNTER,   RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFPROCESSEDCALLS}},
826                 {ASTMODCOUNT,            ASN_INTEGER,   RONLY, ast_var_Modules ,            2, {ASTMODULES, ASTMODCOUNT}},
827                 {ASTINDCOUNT,            ASN_INTEGER,   RONLY, ast_var_indications,         2, {ASTINDICATIONS, ASTINDCOUNT}},
828                 {ASTINDCURRENT,          ASN_OCTET_STR, RONLY, ast_var_indications,         2, {ASTINDICATIONS, ASTINDCURRENT}},
829                 {ASTINDINDEX,            ASN_INTEGER,   RONLY, ast_var_indications_table,   4, {ASTINDICATIONS, ASTINDTABLE, 1, ASTINDINDEX}},
830                 {ASTINDCOUNTRY,          ASN_OCTET_STR, RONLY, ast_var_indications_table,   4, {ASTINDICATIONS, ASTINDTABLE, 1, ASTINDCOUNTRY}},
831                 {ASTINDALIAS,            ASN_OCTET_STR, RONLY, ast_var_indications_table,   4, {ASTINDICATIONS, ASTINDTABLE, 1, ASTINDALIAS}},
832                 {ASTINDDESCRIPTION,      ASN_OCTET_STR, RONLY, ast_var_indications_table,   4, {ASTINDICATIONS, ASTINDTABLE, 1, ASTINDDESCRIPTION}},
833                 {ASTCHANCOUNT,           ASN_GAUGE,     RONLY, ast_var_channels,            2, {ASTCHANNELS, ASTCHANCOUNT}},
834                 {ASTCHANINDEX,           ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANINDEX}},
835                 {ASTCHANNAME,            ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANNAME}},
836                 {ASTCHANLANGUAGE,        ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANLANGUAGE}},
837                 {ASTCHANTYPE,            ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANTYPE}},
838                 {ASTCHANMUSICCLASS,      ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMUSICCLASS}},
839                 {ASTCHANBRIDGE,          ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANBRIDGE}},
840                 {ASTCHANMASQ,            ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMASQ}},
841                 {ASTCHANMASQR,           ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMASQR}},
842                 {ASTCHANWHENHANGUP,      ASN_TIMETICKS, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANWHENHANGUP}},
843                 {ASTCHANAPP,             ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANAPP}},
844                 {ASTCHANDATA,            ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANDATA}},
845                 {ASTCHANCONTEXT,         ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCONTEXT}},
846                 {ASTCHANMACROCONTEXT,    ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMACROCONTEXT}},
847                 {ASTCHANMACROEXTEN,      ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMACROEXTEN}},
848                 {ASTCHANMACROPRI,        ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMACROPRI}},
849                 {ASTCHANEXTEN,           ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANEXTEN}},
850                 {ASTCHANPRI,             ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANPRI}},
851                 {ASTCHANACCOUNTCODE,     ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANACCOUNTCODE}},
852                 {ASTCHANFORWARDTO,       ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANFORWARDTO}},
853                 {ASTCHANUNIQUEID,        ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANUNIQUEID}},
854                 {ASTCHANCALLGROUP,       ASN_UNSIGNED,  RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCALLGROUP}},
855                 {ASTCHANPICKUPGROUP,     ASN_UNSIGNED,  RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANPICKUPGROUP}},
856                 {ASTCHANSTATE,           ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANSTATE}},
857                 {ASTCHANMUTED,           ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMUTED}},
858                 {ASTCHANRINGS,           ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANRINGS}},
859                 {ASTCHANCIDDNID,         ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDDNID}},
860                 {ASTCHANCIDNUM,          ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDNUM}},
861                 {ASTCHANCIDNAME,         ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDNAME}},
862                 {ASTCHANCIDANI,          ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDANI}},
863                 {ASTCHANCIDRDNIS,        ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDRDNIS}},
864                 {ASTCHANCIDPRES,         ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDPRES}},
865                 {ASTCHANCIDANI2,         ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDANI2}},
866                 {ASTCHANCIDTON,          ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDTON}},
867                 {ASTCHANCIDTNS,          ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDTNS}},
868                 {ASTCHANAMAFLAGS,        ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANAMAFLAGS}},
869                 {ASTCHANADSI,            ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANADSI}},
870                 {ASTCHANTONEZONE,        ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANTONEZONE}},
871                 {ASTCHANHANGUPCAUSE,     ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANHANGUPCAUSE}},
872                 {ASTCHANVARIABLES,       ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANVARIABLES}},
873                 {ASTCHANFLAGS,           ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANFLAGS}},
874                 {ASTCHANTRANSFERCAP,     ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANTRANSFERCAP}},
875                 {ASTCHANTYPECOUNT,       ASN_INTEGER,   RONLY, ast_var_channel_types,       2, {ASTCHANNELS, ASTCHANTYPECOUNT}},
876                 {ASTCHANTYPEINDEX,       ASN_INTEGER,   RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPEINDEX}},
877                 {ASTCHANTYPENAME,        ASN_OCTET_STR, RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPENAME}},
878                 {ASTCHANTYPEDESC,        ASN_OCTET_STR, RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPEDESC}},
879                 {ASTCHANTYPEDEVSTATE,    ASN_INTEGER,   RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPEDEVSTATE}},
880                 {ASTCHANTYPEINDICATIONS, ASN_INTEGER,   RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPEINDICATIONS}},
881                 {ASTCHANTYPETRANSFER,    ASN_INTEGER,   RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPETRANSFER}},
882                 {ASTCHANTYPECHANNELS,    ASN_GAUGE,     RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPECHANNELS}},
883                 {ASTCHANBRIDGECOUNT,     ASN_GAUGE,     RONLY, ast_var_channel_bridge,      3, {ASTCHANNELS, ASTCHANSCALARS, ASTCHANBRIDGECOUNT}},
884         };
885
886         register_sysORTable(asterisk_oid, OID_LENGTH(asterisk_oid),
887                         "ASTERISK-MIB implementation for Asterisk.");
888
889         REGISTER_MIB("res_snmp", asterisk_vars, variable4, asterisk_oid);
890
891         snmp_register_callback(SNMP_CALLBACK_LIBRARY,
892                            SNMP_CALLBACK_SHUTDOWN,
893                            term_asterisk_mib, NULL);
894 }
895
896 /*
897  * Local Variables:
898  * c-basic-offset: 4
899  * c-file-offsets: ((case-label . 0))
900  * tab-width: 4
901  * indent-tabs-mode: t
902  * End:
903  */