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